Merge commit '11ced9f05a' into develop

This commit is contained in:
DESKTOP-1R2VSQH\Lenovo ThinkPad E490 2024-04-22 12:56:37 +07:00
commit 95ac852446
30 changed files with 5978 additions and 357 deletions

View file

@ -0,0 +1,11 @@
import env from "../index";
const development = `${env.API_URI}/development`;
const developmentScholarshipReport = `${env.API_URI}/development/report/scholarship`;
const developmentSalaryFile = `${env.API_URI}/salary/file`;
export default {
developmentScholarshipReport,
developmentScholarship: `${development}/scholarship`,
developmentSalaryFile: (name: string, group: string, id: string) => `${developmentSalaryFile}/${name}/${group}/${id}`,
};

View file

@ -9,6 +9,7 @@ import message from "./api/api.message";
import evaluate from "./api/evaluate/api.evaluate";
import support from "./api/support/api.support";
import org from "./api/org/api.org";
import scholarship from "./api/scholarship/api.scholarship";
const API = {
...testtest,
@ -19,6 +20,7 @@ const API = {
...appeal,
...support,
...org,
...scholarship,
};
export default {

View file

@ -81,6 +81,30 @@ const items = ref<any>([
path: "/appeal-complain",
active: false,
},
{
icon: "mdi-account-box-outline",
title: "ขอรับการประเมิน (KPI)",
sub: "ประเมินผลการปฏิบัติหน้าที่ราชการ",
color: "red-2",
path: "/KPI",
active: false,
},
{
icon: "mdi-elevator",
title: "ทำการประเมิน (KPI)",
sub: "ประเมินผลการปฏิบัติหน้าที่ราชการ",
color: "red-2",
path: "/KPI-evaluator",
active: false,
},
{
icon: "mdi-school",
title: "ทุนการศึกษา/ฝึกอบรม",
sub: "รายการทุนการศึกษา/ฝึกอบรม",
color: "teal-2",
path: "/scholarship",
active: false,
},
]);
onMounted(async () => {
await fetchlistInbox(1);

View file

@ -1,425 +1,584 @@
<script setup lang="ts">
import { ref, onMounted } from "vue"
import { useQuasar } from "quasar"
import { useRouter, useRoute } from "vue-router"
import { useCounterMixin } from "@/stores/mixin"
import http from "@/plugins/http"
import config from "@/app.config"
import type { QForm } from "quasar"
import Dialog from '@/modules/03_retire/views/DialogRetire.vue'
import { ref, onMounted } from "vue";
import { useQuasar } from "quasar";
import { useRouter, useRoute } from "vue-router";
import { useCounterMixin } from "@/stores/mixin";
import http from "@/plugins/http";
import config from "@/app.config";
import type { QForm } from "quasar";
import Dialog from "@/modules/03_retire/views/DialogRetire.vue";
const mixin = useCounterMixin()
const { date2Thai, dateToISO, success, messageError, showLoader, hideLoader, fails } = mixin
const router = useRouter()
const route = useRoute()
const $q = useQuasar()
const routeName = router.currentRoute.value.name
const mixin = useCounterMixin();
const {
date2Thai,
dateToISO,
success,
messageError,
showLoader,
hideLoader,
fails,
} = mixin;
const router = useRouter();
const route = useRoute();
const $q = useQuasar();
const routeName = router.currentRoute.value.name;
/**
* วแปรทใชงาน
*/
const id = ref<string>("")
const myform = ref<QForm | null>(null)
const tranferOrg = ref("")
const dateCommand = ref<Date>(new Date())
const dateLeave = ref<Date>(new Date())
const noteReason = ref("")
const modal = ref<boolean>(false)
const id = ref<string>("");
const myform = ref<QForm | null>(null);
const tranferOrg = ref("");
const dateCommand = ref<Date>(new Date());
const dateLeave = ref<Date>(new Date());
const noteReason = ref("");
const modal = ref<boolean>(false);
/** ข้อมูล v-model ของฟอร์ม */
const dataDetail = ref<any>({
datetext: "",
activeDate: new Date(),
createdAt: new Date(),
firstName: "",
id: "",
isActive: true,
lastName: "",
location: "",
organizationPositionOld: "",
positionLevelOld: "",
positionNumberOld: "",
positionTypeOld: "",
prefix: "",
profileId: "",
reason: "",
salary: 0,
sendDate: new Date(),
status: "",
statustext: "",
fullname: "",
})
datetext: "",
activeDate: new Date(),
createdAt: new Date(),
firstName: "",
id: "",
isActive: true,
lastName: "",
location: "",
organizationPositionOld: "",
positionLevelOld: "",
positionNumberOld: "",
positionTypeOld: "",
prefix: "",
profileId: "",
reason: "",
salary: 0,
sendDate: new Date(),
status: "",
statustext: "",
fullname: "",
});
/**
* งกนยอนกลบไปยงหนารายการลาออก
*/
const clickBack = () => {
router.push(`/retire`)
}
router.push(`/retire`);
};
/**
* งกนเปลยนเป string ของ status
* @param val value ของ status true/false
*/
const statusOrder = (val: boolean) => {
switch (val) {
case true:
return "ยับยั้งการลาออก"
case false:
return "อนุมัติการลาออก"
}
}
switch (val) {
case true:
return "ยับยั้งการลาออก";
case false:
return "อนุมัติการลาออก";
}
};
/**
* เรยกฟงกนทงหมดตอนเรยกใชไฟล
*/
onMounted(() => {
if (route.params.id !== undefined) {
id.value = route.params.id.toString()
fectDataresign(id.value)
}
})
if (route.params.id !== undefined) {
id.value = route.params.id.toString();
fectDataresign(id.value);
}
});
/**
* นทกขอมลการลาออก
*/
const saveData = async () => {
if (myform.value != null) {
await myform.value.validate().then(async (saveDataTest: Boolean) => {
if (saveDataTest) {
saveResing()
}
})
}
}
if (myform.value != null) {
await myform.value.validate().then(async (saveDataTest: Boolean) => {
if (saveDataTest) {
saveResing();
}
});
}
};
/**
* งกนดาวโหลดอพโหลดไฟล
*/
const filesNull = () => {
files.value = null
}
const nameFile = ref<string>("")
const fileDocDataUpload = ref<File[]>([])
const files = ref<any>()
files.value = null;
};
const nameFile = ref<string>("");
const fileDocDataUpload = ref<File[]>([]);
const files = ref<any>();
//
const fileUploadDoc = async (file: any) => {
fileDocDataUpload.value.push(file)
nameFile.value = file[0].name
files.value = file
}
fileDocDataUpload.value.push(file);
nameFile.value = file[0].name;
files.value = file;
};
/**
* งกนเซฟขอมลลาออกเเลวเรยกใชงานApi
*/
const saveResing = () => {
$q.dialog({
title: "ยืนยันการยื่นข้อมูลลาออก",
message: "ต้องการยื่นข้อมูลลาออกนี้ใช่หรือไม่?",
cancel: {
flat: true,
color: "negative",
},
persistent: true,
})
.onOk(() => {
createFormresign()
})
.onCancel(() => {})
.onDismiss(() => {})
}
$q.dialog({
title: "ยืนยันการยื่นข้อมูลลาออก",
message: "ต้องการยื่นข้อมูลลาออกนี้ใช่หรือไม่?",
cancel: {
flat: true,
color: "negative",
},
persistent: true,
})
.onOk(() => {
createFormresign();
})
.onCancel(() => {})
.onDismiss(() => {});
};
//
const cancelResing = () => {
modal.value = true
}
modal.value = true;
};
/**
* งกนลบ
* @param id ไอดของขอมลการลาออก
*/
const deleteResting = async (id: string) => {
showLoader()
await http
.delete(config.API.resingByid(id))
.then(() => {
success($q, "ยกเลิกการลาออกขอสำเร็จ")
})
.catch(e => {
messageError($q, e)
})
.finally(() => {
hideLoader()
clickBack()
})
}
showLoader();
await http
.delete(config.API.resingByid(id))
.then(() => {
success($q, "ยกเลิกการลาออกขอสำเร็จ");
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
clickBack();
});
};
//
const createFormresign = async () => {
const formData = new FormData()
if (files.value > 0) {
const blob = files.value.slice(0, files.value[0].size)
const newFile = new File(blob, nameFile.value, {
type: files.value[0].type,
})
formData.append("file", newFile)
}
const formData = new FormData();
if (files.value.length > 0) {
const blob = files.value.slice(0, files.value[0].size);
const newFile = new File(blob, nameFile.value, {
type: files.value[0].type,
});
formData.append("file", newFile);
}
formData.append("Location", tranferOrg.value)
formData.append("SendDate", dateToISO(dateCommand.value))
formData.append("ActiveDate", dateToISO(dateLeave.value))
formData.append("Reason", noteReason.value)
formData.append("Location", tranferOrg.value);
formData.append("SendDate", dateToISO(dateCommand.value));
formData.append("ActiveDate", dateToISO(dateLeave.value));
formData.append("Reason", noteReason.value);
await http
.post(config.API.listResign(), formData)
.then((res: any) => {
let data = res.data.result.id
success($q, "บันทึกข้อมูลสำเร็จ")
router.push(`/retire/result/${data}`)
})
.catch((e: any) => {
messageError($q, e)
})
}
await http
.post(config.API.listResign(), formData)
.then((res: any) => {
let data = res.data.result.id;
success($q, "บันทึกข้อมูลสำเร็จ");
router.push(`/retire/result/${data}`);
})
.catch((e: any) => {
messageError($q, e);
});
};
/**
* งกนเรยกขอมลจาก Api
* @param id ไอดของขอม
*/
const fectDataresign = async (id: string) => {
showLoader()
await http
.get(config.API.resingByid(id))
.then((res: any) => {
let data = res.data.result
;(tranferOrg.value = data.location),
(dateCommand.value = data.sendDate),
(dateLeave.value = data.activeDate),
(noteReason.value = data.reason),
(files.value = data.docs),
(dataDetail.value = data)
})
.catch((e: any) => {
messageError($q, e)
})
.finally(() => {
hideLoader()
})
showLoader();
await http
.get(config.API.resingByid(id))
.then((res: any) => {
let data = res.data.result;
(tranferOrg.value = data.location),
(dateCommand.value = data.sendDate),
(dateLeave.value = data.activeDate),
(noteReason.value = data.reason),
(files.value = data.docs),
(dataDetail.value = data);
})
.catch((e: any) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
};
function downloadFile(data: string) {
window.open(data, "_blank");
}
</script>
<template>
<div class="col-12 row justify-center">
<div class="col-xs-12 col-sm-12 col-md-11">
<div class="toptitle text-white col-12 row items-center">
<q-btn icon="mdi-arrow-left" unelevated round dense flat color="primary" class="q-mr-sm" @click="router.go(-1)" />
<div v-if="routeName == 'AddRetire'">เพิ่มเรื่องลาออก</div>
<div v-else>รายละเอียดเรื่องลาออก</div>
</div>
<q-form ref="myform" class="col-12">
<q-card bordered>
<div class="col-12 row q-col-gutter-md q-pa-md">
<div class="col-xs-12 col-sm-12">
<div class="col-12 row q-pa-sm q-col-gutter-sm">
<q-input
class="col-8"
dense
outlined
v-model="tranferOrg"
label="สถานที่ยื่นขอลาออกจากราชการ"
:readonly="routeName != 'AddRetire'"
:rules="[(val:string) => !!val || `${'กรุณากรอกสถานที่ยื่นขอลาออกจากราชการ'}`]"
/>
<datepicker class="col-2" menu-class-name="modalfix" v-model="dateCommand" :locale="'th'" autoApply readonly 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
outlined
readonly
dense
hide-bottom-space
class="full-width datepicker"
:model-value="dateCommand != null ? date2Thai(dateCommand) : null"
:label="`${'วันที่ยื่นขอลาออกจากราชการ'}`"
:rules="[val => !!val || `${'กรุณาเลือกวันที่ยื่นขอลาออกจากราชการ'}`]"
>
<template v-slot:prepend>
<q-icon name="event" class="cursor-pointer" style="color: var(--q-primary)"> </q-icon>
</template>
</q-input>
</template>
</datepicker>
<datepicker
class="col-2"
menu-class-name="modalfix"
v-model="dateLeave"
:locale="'th'"
autoApply
borderless
:enableTimePicker="false"
week-start="0"
:readonly="routeName != 'AddRetire'"
>
<template #year="{ year }">
{{ year + 543 }}
</template>
<template #year-overlay-value="{ value }">
{{ parseInt(value + 543) }}
</template>
<template #trigger>
<q-input
outlined
dense
hide-bottom-space
:readonly="routeName != 'AddRetire'"
class="full-width datepicker"
:model-value="dateLeave != null ? date2Thai(dateLeave) : null"
:label="`${'วันที่ขอลาออกจากราชการ'}`"
:rules="[val => !!val || `${'กรุณาเลือกวันที่ขอลาออกจากราชการ'}`]"
>
<template v-slot:prepend>
<q-icon name="event" class="cursor-pointer" style="color: var(--q-primary)"> </q-icon>
</template>
</q-input>
</template>
</datepicker>
<q-input
class="col-12"
dense
outlined
v-model="noteReason"
label="เหตุผลที่ลาออกจากราชการ"
type="textarea"
:readonly="routeName != 'AddRetire'"
:rules="[val => !!val || `${'กรุณากรอกเหตุผลที่ลาออกจากราชการ'}`]"
/>
<div class="col-12 row justify-center">
<div class="col-xs-12 col-sm-12 col-md-11">
<div class="toptitle text-white col-12 row items-center">
<q-btn
icon="mdi-arrow-left"
unelevated
round
dense
flat
color="primary"
class="q-mr-sm"
@click="router.go(-1)"
/>
<div v-if="routeName == 'AddRetire'">เพิ่มเรื่องลาออก</div>
<div v-else>รายละเอียดเรื่องลาออก</div>
</div>
<q-form ref="myform" class="col-12">
<q-card bordered>
<div class="col-12 row q-col-gutter-sm q-pa-md">
<div class="col-xs-12 col-sm-12">
<div class="col-12 row q-pa-sm q-col-gutter-sm">
<q-input
class="col-8"
dense
outlined
v-model="tranferOrg"
hide-bottom-space
label="สถานที่ยื่นขอลาออกจากราชการ"
:readonly="routeName != 'AddRetire'"
:rules="[(val:string) => !!val || `${'กรุณากรอกสถานที่ยื่นขอลาออกจากราชการ'}`]"
/>
<datepicker
class="col-2"
menu-class-name="modalfix"
v-model="dateCommand"
:locale="'th'"
autoApply
readonly
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
outlined
readonly
dense
hide-bottom-space
class="full-width datepicker"
:model-value="
dateCommand != null ? date2Thai(dateCommand) : null
"
:label="`${'วันที่ยื่นขอลาออกจากราชการ'}`"
:rules="[
(val) =>
!!val || `${'กรุณาเลือกวันที่ยื่นขอลาออกจากราชการ'}`,
]"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
style="color: var(--q-primary)"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
<datepicker
class="col-2"
menu-class-name="modalfix"
v-model="dateLeave"
:locale="'th'"
autoApply
borderless
:enableTimePicker="false"
week-start="0"
:readonly="routeName != 'AddRetire'"
>
<template #year="{ year }">
{{ year + 543 }}
</template>
<template #year-overlay-value="{ value }">
{{ parseInt(value + 543) }}
</template>
<template #trigger>
<q-input
outlined
dense
hide-bottom-space
:readonly="routeName != 'AddRetire'"
class="full-width datepicker"
:model-value="
dateLeave != null ? date2Thai(dateLeave) : null
"
:label="`${'วันที่ขอลาออกจากราชการ'}`"
:rules="[
(val) =>
!!val || `${'กรุณาเลือกวันที่ขอลาออกจากราชการ'}`,
]"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
style="color: var(--q-primary)"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
<q-input
class="col-12"
dense
outlined
v-model="noteReason"
label="เหตุผลที่ลาออกจากราชการ"
type="textarea"
hide-bottom-space
:readonly="routeName != 'AddRetire'"
:rules="[
(val) => !!val || `${'กรุณากรอกเหตุผลที่ลาออกจากราชการ'}`,
]"
/>
<div class="col-12 row" v-if="routeName == 'AddRetire'">
<q-uploader
flat
bordered
class="col-xs-12 col-sm-12"
accept=".jpg,.png,.pdf,.csv,.doc"
url="http://localhost:4444/upload"
label="เอกสารเพิ่มเติม"
type="file"
@added="fileUploadDoc"
@removed="filesNull"
style="max-width: px"
/>
</div>
<div class="col-12 row" v-if="routeName != 'AddRetire'">
<div class="bg-grey-1 q-pa-sm col-12 row items-center text-primary">
<div class="q-pl-sm text-weight-bold text-dark">เอกสารเพมเต</div>
</div>
<q-card bordered flat class="full-width">
<q-list separator>
<q-item v-for="file in files" :key="file.key" class="q-my-xs">
<q-item-section>
<q-item-label class="full-width ellipsis">
{{ file.fileName }}
</q-item-label>
<div class="col-12 row" v-if="routeName == 'AddRetire'">
<q-uploader
flat
bordered
class="col-xs-12 col-sm-12"
accept=".jpg,.png,.pdf,.csv,.doc"
url="http://localhost:4444/upload"
label="เอกสารเพิ่มเติม"
type="file"
@added="fileUploadDoc"
@removed="filesNull"
style="max-width: px"
/>
</div>
<div class="col-12 row">
<q-card
bordered
flat
class="row col-12 text-dark q-mt-sm"
v-if="routeName != 'AddRetire'"
>
<div
class="bg-grey-1 q-pa-sm col-12 row items-center text-primary"
>
<div class="q-pl-sm text-weight-bold text-dark">
เอกสารเพมเต
</div>
</div>
<q-list class="col-12">
<q-item
v-for="file in files"
:key="file.key"
class="q-my-xs"
>
<q-item-section>
<q-item-label class="full-width ellipsis">
{{ file.fileName }}
</q-item-label>
<q-item-label caption> </q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-card>
</div>
</div>
<q-card bordered class="row col-12 text-dark q-mt-sm" v-if="routeName != 'AddRetire'">
<div class="bg-grey-1 q-pa-sm col-12 row items-center text-primary">
<div class="q-pl-sm text-weight-bold text-dark">ผลการพจารณาของผงคบบญชา</div>
</div>
<q-separator />
<div class="row col-12 q-pa-md">
<div class="col-12 row bg-white q-col-gutter-md">
<div class="col-xs-6 row items-start">
<div class="col-12 text-top">สถานะ</div>
<div class="col-12 text-detail">
{{ dataDetail.commanderReject !== null ? statusOrder(dataDetail.commanderReject) : "-" }}
</div>
</div>
<div class="col-xs-6 row items-start">
<div class="col-12 text-top">นสดทายทบย</div>
<div class="col-12 text-detail">
{{ dataDetail.commanderRejectDate !== null ? date2Thai(dataDetail.commanderRejectDate) : "-" }}
</div>
</div>
<div class="col-xs-12 row items-start">
<div class="col-12 text-top">ความคดเหนและเหตผล</div>
<div class="col-12 text-detail" v-if="dataDetail.commanderReject === false">
{{ dataDetail.commanderApproveReason !== null ? dataDetail.commanderApproveReason : "-" }}
</div>
<div class="col-12 text-detail" v-if="dataDetail.commanderReject === true">
{{ dataDetail.commanderRejectReason !== null ? dataDetail.commanderRejectReason : "-" }}
</div>
</div>
</div>
</div>
</q-card>
<q-item-label caption> </q-item-label>
</q-item-section>
<q-space />
<q-card bordered class="row col-12 text-dark q-mt-sm" v-if="routeName != 'AddRetire'">
<div class="bg-grey-1 q-pa-sm col-12 row items-center text-primary">
<div class="q-pl-sm text-weight-bold text-dark">ผลการพจารณาของผอำนาจ</div>
</div>
<q-separator />
<div class="row col-12 q-pa-md">
<div class="col-12 row bg-white q-col-gutter-md">
<div class="col-xs-6 row items-start">
<div class="col-12 text-top">สถานะ</div>
<div class="col-12 text-detail">
{{ dataDetail.oligarchReject !== null ? statusOrder(dataDetail.oligarchReject) : "-" }}
</div>
</div>
<div class="col-xs-6 row items-start">
<div class="col-12 text-top">นสดทายทบย</div>
<div class="col-12 text-detail">
{{ dataDetail.oligarchRejectDate !== null ? date2Thai(dataDetail.oligarchRejectDate) : "-" }}
</div>
</div>
<div class="col-xs-12 row items-start">
<div class="col-12 text-top">ความคดเหนและเหตผล</div>
<div class="col-12 text-detail" v-if="dataDetail.oligarchReject == false">
{{ dataDetail.oligarchApproveReason !== null ? dataDetail.oligarchApproveReason : "-" }}
</div>
<div class="col-12 text-detail" v-else-if="dataDetail.oligarchReject == true">
{{ dataDetail.oligarchRejectReason !== null ? dataDetail.oligarchRejectReason : "-" }}
</div>
</div>
</div>
</div>
</q-card>
</div>
<q-btn
size="12px"
flat
round
dense
color="blue"
icon="mdi-download"
@click="downloadFile(file.pathName)"
><q-tooltip>ดาวนโหลดไฟล</q-tooltip></q-btn
>
</q-item>
</q-list>
</q-card>
</div>
<div class="col-12 row">
<q-card
bordered
class="row col-12 text-dark q-mt-sm"
v-if="routeName != 'AddRetire'"
>
<div
class="bg-grey-1 q-pa-sm col-12 row items-center text-primary"
>
<div class="q-pl-sm text-weight-bold text-dark">
ผลการพจารณาของผงคบบญชา
</div>
</div>
<q-separator />
<div class="row col-12 q-pa-md">
<div class="col-12 row bg-white q-col-gutter-md">
<div class="col-xs-6 row items-start">
<div class="col-12 text-top">สถานะ</div>
<div class="col-12 text-detail">
{{
dataDetail.commanderReject !== null
? statusOrder(dataDetail.commanderReject)
: "-"
}}
</div>
</div>
<div class="col-xs-6 row items-start">
<div class="col-12 text-top">
นสดทายทบย
</div>
<div class="col-12 text-detail">
{{
dataDetail.commanderRejectDate !== null
? date2Thai(dataDetail.commanderRejectDate)
: "-"
}}
</div>
</div>
<div class="col-xs-12 row items-start">
<div class="col-12 text-top">
ความคดเหนและเหตผล
</div>
<div
class="col-12 text-detail"
v-if="dataDetail.commanderReject === false"
>
{{
dataDetail.commanderApproveReason !== null
? dataDetail.commanderApproveReason
: "-"
}}
</div>
<div
class="col-12 text-detail"
v-if="dataDetail.commanderReject === true"
>
{{
dataDetail.commanderRejectReason !== null
? dataDetail.commanderRejectReason
: "-"
}}
</div>
</div>
</div>
</div>
</q-card>
</div>
<div class="col-12 row">
<q-card
bordered
class="row col-12 text-dark q-mt-sm"
v-if="routeName != 'AddRetire'"
>
<div
class="bg-grey-1 q-pa-sm col-12 row items-center text-primary"
>
<div class="q-pl-sm text-weight-bold text-dark">
ผลการพจารณาของผอำนาจ
</div>
</div>
<q-separator />
<div class="row col-12 q-pa-md">
<div class="col-12 row bg-white q-col-gutter-md">
<div class="col-xs-6 row items-start">
<div class="col-12 text-top">สถานะ</div>
<div class="col-12 text-detail">
{{
dataDetail.oligarchReject !== null
? statusOrder(dataDetail.oligarchReject)
: "-"
}}
</div>
</div>
<div class="col-xs-6 row items-start">
<div class="col-12 text-top">
นสดทายทบย
</div>
<div class="col-12 text-detail">
{{
dataDetail.oligarchRejectDate !== null
? date2Thai(dataDetail.oligarchRejectDate)
: "-"
}}
</div>
</div>
<div class="col-xs-12 row items-start">
<div class="col-12 text-top">
ความคดเหนและเหตผล
</div>
<div
class="col-12 text-detail"
v-if="dataDetail.oligarchReject == false"
>
{{
dataDetail.oligarchApproveReason !== null
? dataDetail.oligarchApproveReason
: "-"
}}
</div>
<div
class="col-12 text-detail"
v-else-if="dataDetail.oligarchReject == true"
>
{{
dataDetail.oligarchRejectReason !== null
? dataDetail.oligarchRejectReason
: "-"
}}
</div>
</div>
</div>
</div>
</q-card>
</div>
</div>
</div>
<div class="row col-12 q-pa-md" v-if="routeName != 'AddRetire'">
<q-space />
<q-btn
v-if="dataDetail.status !== 'DELETE' && dataDetail.status !== 'DONE'"
unelevated
dense
class="q-px-md items-center"
color="orange"
label="ยกเลิกการลาออก"
@click="cancelResing"
:disable="tranferOrg == '' && noteReason == ''"
/>
</div>
</div>
<q-separator v-if="routeName == 'AddRetire'" />
<div class="row col-12 q-pa-md" v-if="routeName == 'AddRetire'">
<q-space />
<q-btn unelevated dense class="q-px-md items-center" color="primary" label="ยื่นเรื่องขอลาออก" @click="saveData" :disable="tranferOrg == '' && noteReason == ''" />
</div>
</q-card>
</q-form>
</div>
</div>
<div class="row col-12 q-pa-md" v-if="routeName != 'AddRetire'">
<q-space />
<q-btn
v-if="
dataDetail.status !== 'DELETE' && dataDetail.status !== 'DONE'
"
unelevated
dense
class="q-px-md items-center"
color="orange"
label="ยกเลิกการลาออก"
@click="cancelResing"
:disable="tranferOrg == '' && noteReason == ''"
/>
</div>
</div>
<q-separator v-if="routeName == 'AddRetire'" />
<div class="row col-12 q-pa-md" v-if="routeName == 'AddRetire'">
<q-space />
<q-btn
unelevated
dense
class="q-px-md items-center"
color="primary"
label="ยื่นเรื่องขอลาออก"
@click="saveData"
:disable="tranferOrg == '' && noteReason == ''"
/>
</div>
</q-card>
</q-form>
</div>
</div>
<Dialog
v-model:modal="modal"
/>
<Dialog v-model:modal="modal" />
</template>

View file

@ -0,0 +1,84 @@
<script setup lang="ts">
import { useQuasar, type QTableProps } from "quasar";
import { ref, onMounted } from "vue";
import Work from "@/modules/08_KPI/components/Tab/Topic/01_Template.vue";
import Capacity from "@/modules/08_KPI/components/Tab/Topic/02_Template.vue";
const rows_01 = ref<any[]>();
const rows_02 = ref<any[]>();
const rows_03 = ref<any[]>();
const rows_04 = ref<any[]>();
const rows_05 = ref<any[]>();
const total = ref<number>(0);
const resultWork = ref<number>(0);
const resultEvaluation = ref<number>(0);
function getList() {
const data = [
{
indicators: "ตัวชี้วัด 1",
target: null,
scoreLevel: "4",
weight: "50",
workResult: "ระดับ 5",
evaluationResults: "50",
},
];
rows_01.value = data;
}
onMounted(() => {
getList();
});
</script>
<template>
<q-scroll-area style="height: 56vh" class="bg-white row col-12 text-dark q-pa-md">
<div class="text-weight-bold text-body2">
<span class="txt-under text-blue-6">องคประกอบท 1</span>
<span class="q-ml-sm"> ผลสมฤทธของงาน</span>
</div>
<div class="q-gutter-md q-mt-sm">
<!-- องคประกอบท 1 -->
<Work v-model:data="rows_01" :title="`1. งานตามแผนปฏิบัติราชการประจำปี`" :page="1" />
<Work v-model:data="rows_02" :title="`2. งานตามหน้าที่ความรับผิดชอบหลัก`" :page="2" />
<Work v-model:data="rows_03" :title="`3. งานที่ได้รับมอบหมาย`" :page="3" />
<div class="row text-body2 text-weight-bold">
<div class="col-6 text-center row justify-center">
<span>รวมผลการประเม (อยละ) 100</span>
<div class="text-primary q-pl-md">{{ total }}</div>
</div>
<div class="col-6 text-center row justify-center">
<span>สรปผลการประเมนผลสมฤทธของงาน (คะแนนเต 70 คะแนน)</span>
<div class="text-primary q-pl-md">{{ resultWork }}</div>
</div>
</div>
<q-separator size="3px" class="q-my-lg" />
<!-- องคประกอบท 2 -->
<div class="text-weight-bold text-body2 q-mb-sm">
<span class="txt-under text-blue-6">องคประกอบท 2</span>
<span class="q-ml-sm"> พฤตกรรมการปฎราชการ (สมรรถนะ)</span>
</div>
<Capacity v-model:data="rows_04" :title="`1. สมรรถนะหลัก`" :page="1" />
<Capacity v-model:data="rows_05" :title="`2. สมรรถนะประจำกลุ่ม`" :page="2" />
<div class="row text-body2 text-weight-bold justify-center">
<span>ผลการประเมนสมรรถนะ (20 คะแนน)</span>
<div class="text-primary q-pl-md">{{ resultEvaluation }}</div>
</div>
</div>
</q-scroll-area>
</template>
<style scoped>
.txt-under {
text-decoration: underline;
}
</style>

View file

@ -0,0 +1,3 @@
<template>
<div class="q-pa-md">2</div>
</template>

View file

@ -0,0 +1,3 @@
<template>
<div class="q-pa-md">3</div>
</template>

View file

@ -0,0 +1,3 @@
<template>
<div class="q-pa-md">4</div>
</template>

View file

@ -0,0 +1,288 @@
<script setup lang="ts">
import { ref, reactive } from "vue";
import DialogHeader from "@/components/DialogHeader.vue";
const modal = defineModel<boolean>("modal", { required: true });
const numpage = defineModel<number>("numpage", { required: true });
const splitterModel = ref<number>(25);
const search = ref<string>("");
const define = ref<string>("");
const formula = ref<string>("");
const listCheck = ref<number | null>();
const listTarget = ref<any>([
{
id: "ID1",
metricCode: "1กก",
indicatorName: "ตัวชี้วัด 1",
},
{
id: "ID2",
metricCode: "2กก",
indicatorName: "ตัวชี้วัด 2",
},
]);
const formDetail = reactive<any>({
oc: `สำนักงานคณะกรรมการข้าราชการกรุงเทพมหานคร/กองบริหารทั่วไป/กลุ่มงานช่วยนักบริหาร`,
indicators: "1",
code: "1กก",
name: "ตัวชี้วัด 1",
target: "",
unit: "",
weight: "100",
});
const formScore = reactive<any>({
score5: "5",
score4: "4",
score3: "3",
score2: "2",
score1: "1",
});
const fieldDetailLabels = {
oc: "หน่วยงาน/ส่วนราชการ",
indicators: "ลำดับตัวชี้วัด",
code: "รหัสตัวชี้วัด",
name: "ชื่อตัวชี้วัด",
target: "ค่าเป้าหมาย",
unit: "หน่วยนับ",
weight: "น้ำหนัก (ร้อยละ)",
};
const fieldLabels = {
score5: "5",
score4: "4",
score3: "3",
score2: "2",
score1: "1",
};
function clickList(index: number, data: any) {
listCheck.value = index;
// dataList.value = data.map((i: any) => ({
// commandNo: i.commandNo,
// duty: i.duty,
// prefix: i.prefix,
// firstName: i.firstName,
// lastName: i.lastName,
// fullName:`${i.prefix}${i.firstName} ${i.lastName}`
// }));
}
/** ปิด dialog */
function closeDialog() {
modal.value = false;
search.value = ''
define.value = ''
formula.value = ''
}
/** เรียกใช้ class */
function getclass() {
return "inputgreen";
}
function onSubmit() {}
</script>
<template>
<q-dialog v-model="modal" persistent>
<q-card class="col-12" style="width: 85%">
<q-form greedy @submit.prevent @validation-success="onSubmit">
<DialogHeader
:tittle="
numpage == 1
? 'เพิ่มตัวชี้วัดตามแผนปฏิบัติราชการประจําปี'
: 'เพิ่มตัวชี้วัดตามหน้าที่ความรับผิดชอบ'
"
:close="closeDialog"
/>
<q-separator />
<q-card-section class="q-pa-none scroll" style="max-height: 80vh">
<div class="col-12 row">
<div class="bg-grey-1 q-pa-md col-xs-12 col-sm-4 col-md-3 row lineRight">
<div class="col-12 fit">
<div class="col-12 ">
<q-input
v-model="search"
outlined
dense
label="ค้นหา"
:class="getclass()"
>
<template v-slot:append>
<q-icon v-if="search == ''" name="search" />
<q-icon
v-if="search !== ''"
name="clear"
class="cursor-pointer"
@click="search = ''"
/>
</template>
</q-input>
</div>
<q-card bordered flat class="q-mt-sm no-shadow bg-white col-12">
<div class="row q-px-md q-py-sm items-center bg-grey-1">
<div class="col-4">
<span>รหสตวช</span>
</div>
<div class="col-4">
<span>อตวช</span>
</div>
</div>
<q-separator/>
<q-card-section class="q-pa-none">
<q-list
separator
dense
>
<q-item
v-for="(item, index) in listTarget"
:key="index"
clickable
v-ripple
:active="listCheck === index"
active-class="my-menu-link"
@click="clickList(index, item.id)"
>
<q-item-section class="q-pa-none">
<div class="row items-center" style="height: 20px">
<div class="col-4">
<span>{{ item.metricCode }}</span>
</div>
<div class="col-4">
<span>{{ item.indicatorName }}</span>
</div>
</div>
</q-item-section>
</q-item>
</q-list>
</q-card-section>
</q-card>
</div>
</div>
<div class="col-xs-12 col-sm-8 col-md-9 row">
<div class="row q-pa-md q-col-gutter-sm">
<div class="col-12">
<span class="text-body2 text-weight-medium"
>รายละเอยดตวช</span
>
</div>
<div class="col-8">
<q-card bordered class="full-height q-pa-sm">
<div
v-for="(field, index) in Object.keys(fieldDetailLabels)"
:key="index + 1"
>
<div class="row q-pa-sm q-col-gutter-lg col-12">
<div class="col-4 text-grey-6">
{{
fieldDetailLabels[
field as keyof typeof fieldDetailLabels
]
}}
</div>
<div class="col-8">
<span>{{
formDetail[field] ? formDetail[field] : "-"
}}</span>
</div>
</div>
</div>
</q-card>
</div>
<div class="col-4 row ">
<div class="row col-12 card-box">
<div class="col-12 bg-grey-2 row items-center text-weight-medium">
<div class="col-6 text-center">ระดบคะแนน</div>
<div class="col-6 text-center">ผลสำเรจของงาน</div>
</div>
<div
v-for="(field, index) in Object.keys(fieldLabels)"
:key="index + 1"
class="row col-12 items-center lineTop"
>
<div
class="col-6 text-center text-body2"
>
{{ fieldLabels[field as keyof typeof fieldLabels] }}
</div>
<div class="col-6 text-center text-primary">
<span>{{
formScore[field] ? formScore[field] : "-"
}}</span>
</div>
</div>
</div>
</div>
<div class="col-12">
<q-input
v-model="define"
label="นิยามหรือความหมายของตัวชี้วัด"
type="textarea"
outlined
autogrow
dense
:rules="[(val:string) => !!val || `${'กรุณากรอกตัวชี้วัด'}`,]"
hide-bottom-space
:class="getclass()"
/>
</div>
<div class="col-12">
<q-input
v-model="formula"
label="สูตรคำนวณ"
type="textarea"
outlined
autogrow
dense
:rules="[(val:string) => !!val || `${'กรุณากรอกตัวชี้วัด'}`,]"
hide-bottom-space
:class="getclass()"
/>
</div>
</div>
</div>
</div>
</q-card-section>
<q-separator />
<q-card-actions align="right" class="bg-white text-teal">
<q-btn
label="บันทึก"
color="secondary"
type="submit"
><q-tooltip>นทกขอม</q-tooltip></q-btn
>
</q-card-actions>
</q-form>
</q-card>
</q-dialog>
</template>
<style scoped>
.my-menu-link {
background: #ebf9f7 !important;
color: #1bb19ab8 !important;
}
.no-shadow{
box-shadow:none !important;
}
.lineRight{
border-right: 1px solid #EDEDED !important;
}
.lineTop{
border-top: 1px solid #EDEDED !important;
}
.card-box{
border: 1px solid #EDEDED !important;
border-radius: 8px;
}
</style>

View file

@ -0,0 +1,122 @@
<script setup lang="ts">
import { ref, reactive } from "vue";
import DialogHeader from "@/components/DialogHeader.vue";
import type { FormDataAssigned } from '@/modules/08_KPI/interface/request/index'
const modal = defineModel<boolean>("modal", { required: true });
const formData = reactive<FormDataAssigned>({
indicator:'',//
target:'',//
unit:'',//
weigth:'',// ()
definition:'',//
})
/** ปิด dialog */
function closeDialog() {
modal.value = false;
formData.indicator = ''
formData.target = ''
formData.unit = ''
formData.weigth = ''
formData.definition = ''
}
/** เรียกใช้ class */
function getclass() {
return "inputgreen";
}
function onSubmit() {}
</script>
<template>
<q-dialog v-model="modal" persistent>
<q-card class="col-12" style="width: 50%">
<q-form greedy @submit.prevent @validation-success="onSubmit">
<DialogHeader
:tittle="`เพิ่มตัวชี้วัดที่ได้รับมอบหมาย`"
:close="closeDialog"
/>
<q-separator />
<q-card-section >
<div class="row q-col-gutter-sm">
<div class="col-12">
<q-input
v-model="formData.indicator"
label="ชื่อตัวชี้วัด"
outlined
dense
:rules="[(val:string) => !!val || `${'กรุณากรอกชื่อตัวชี้วัด'}`,]"
hide-bottom-space
:class="getclass()"
/>
</div>
<div class="col-4">
<q-input
v-model="formData.target"
label="ค่าเป้าหมาย"
outlined
dense
:rules="[(val:string) => !!val || `${'กรุณากรอกค่าเป้าหมาย'}`,]"
hide-bottom-space
:class="getclass()"
/>
</div>
<div class="col-4">
<q-input
v-model="formData.unit"
label="หน่วยนับ"
outlined
dense
:rules="[(val:string) => !!val || `${'กรุณากรอกหน่วยนับ'}`,]"
hide-bottom-space
:class="getclass()"
/>
</div>
<div class="col-4">
<q-input
v-model="formData.weigth"
label="น้ำหนัก (ร้อยละ)"
outlined
dense
:rules="[(val:string) => !!val || `${'กรุณากรอกน้ำหนัก (ร้อยละ)'}`,]"
hide-bottom-space
:class="getclass()"
/>
</div>
<div class="col-12">
<q-input
v-model="formData.definition"
label="นิยามหรือความหมายของตัวชี้วัด"
outlined
dense
type="textarea"
:rules="[(val:string) => !!val || `${'กรุณากรอกนิยามหรือความหมายของตัวชี้วัด'}`,]"
hide-bottom-space
:class="getclass()"
/>
</div>
</div>
</q-card-section>
<q-separator />
<q-card-actions align="right" class="bg-white text-teal">
<q-btn
label="บันทึก"
color="secondary"
type="submit"
><q-tooltip>นทกขอม</q-tooltip></q-btn
>
</q-card-actions>
</q-form>
</q-card>
</q-dialog>
</template>
<style scoped>
.my-menu-link {
background: #ebf9f7 !important;
color: #1bb19ab8 !important;
}
</style>

View file

@ -0,0 +1,297 @@
<script setup lang="ts">
import { ref, reactive } from "vue";
import DialogHeader from "@/components/DialogHeader.vue";
import type { DataOptions } from "@/modules/08_KPI/interface/index/Main";
const modal = defineModel<boolean>("modal", { required: true });
const numpage = defineModel<number>("numpage", { required: true });
const splitterModel = ref<number>(30);
const search = ref<string>("");
const define = ref<string>("");
const formula = ref<string>("");
const type = ref<string>("");
const listCheck = ref<number | null>();
const listTarget = ref<any>([
{
id: "ID1",
metricCode: "1กก",
indicatorName: "ตัวชี้วัด 1",
},
{
id: "ID2",
metricCode: "2กก",
indicatorName: "ตัวชี้วัด 2",
},
]);
const formDetail = reactive<any>({
type: "สมรรถนะหลัก",
name: "สมรรถนะ 1",
definition: "",
criteria: "",
});
const formScore = reactive<any>({
score1: "1",
score2: "2",
score3: "3",
score4: "",
score5: "5",
});
const fieldDetailLabels = {
type: "ประเภทสมรรถนะ",
name: "ชื่อสมรรถนะ",
definition: "คำจำกัดความ",
criteria: "กำหนดเกณฑ์การประเมิน",
};
const fieldLabels = {
score1: "1",
score2: "2",
score3: "3",
score4: "4",
score5: "5",
};
const competencyTypeOp = ref<DataOptions[]>([
{
id: "ID1",
name: "สมรรถนะหลัก",
},
{
id: "ID2",
name: "สมรรถนะประจำกลุ่มงาน",
},
{
id: "ID3",
name: "สมรรถนะประจำกลุ่มงาน",
},
{
id: "ID4",
name: "สมรรถนะประจำผู้บริหารกรุงเทพมหานคร",
},
{
id: "ID5",
name: "สมรรถนะเฉพาะสำหรับตำแหน่ง ผอ.เขต ผช.ผอ.เขต และหัวหน้าฝ่ายในสังกัด สนง.เขต",
},
{
id: "ID6",
name: "สมรรถนะเฉพาะสำหรับตำแหน่งผู้ตรวจราชการ กทม. และผู้ตรวจราชการ",
},
]);
function clickList(index: number, data: any) {
listCheck.value = index;
// dataList.value = data.map((i: any) => ({
// commandNo: i.commandNo,
// duty: i.duty,
// prefix: i.prefix,
// firstName: i.firstName,
// lastName: i.lastName,
// fullName:`${i.prefix}${i.firstName} ${i.lastName}`
// }));
}
/** ปิด dialog */
function closeDialog() {
modal.value = false;
type.value = ''
search.value = ''
}
/** เรียกใช้ class */
function getclass() {
return "inputgreen";
}
function onSubmit() {}
</script>
<template>
<q-dialog v-model="modal" persistent>
<q-card class="col-12" style="width: 85%">
<q-form greedy @submit.prevent @validation-success="onSubmit">
<DialogHeader :tittle="`เพิ่มสมรรถนะ`" :close="closeDialog" />
<q-separator />
<q-card-section class="q-pa-none scroll" style="max-height: 80vh">
<div class="col-12 row">
<div class="bg-grey-1 q-pa-md col-xs-12 col-sm-4 col-md-3 row lineRight">
<div class="col-12 q-col-gutter-sm fit">
<div class="col-12 ">
<q-select
v-model="type"
outlined
label="ประเภทสมรรถนะ"
dense
bg-color="white"
option-label="name"
option-value="id"
:options="competencyTypeOp"
emit-value
:class="getclass()"
map-options
/>
</div>
<div class="col-12 ">
<q-input
v-model="search"
outlined
dense
label="ค้นหา"
bg-color="white"
:class="getclass()"
>
<template v-slot:append>
<q-icon v-if="search == ''" name="search" />
<q-icon
v-if="search !== ''"
name="clear"
class="cursor-pointer"
@click="search = ''"
/>
</template>
</q-input>
</div>
<div class="col-12 ">
<q-card bordered flat class="no-shadow bg-white col-12">
<div class="row q-px-md q-py-sm items-center bg-grey-1">
<div class="col-4">
<span>รหสตวช</span>
</div>
<div class="col-4">
<span>อตวช</span>
</div>
</div>
<q-separator />
<q-card-section class="q-pa-none">
<q-list
separator
dense
>
<q-item
v-for="(item, index) in listTarget"
:key="index"
clickable
v-ripple
:active="listCheck === index"
active-class="my-menu-link"
@click="clickList(index, item.id)"
>
<q-item-section class="q-pa-none">
<div class="row items-center" style="height: 20px">
<div class="col-4">
<span>{{ item.metricCode }}</span>
</div>
<div class="col-4">
<span>{{ item.indicatorName }}</span>
</div>
</div>
</q-item-section>
</q-item>
</q-list>
</q-card-section>
</q-card>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-8 col-md-9 row">
<div class="row col-12 q-pa-md q-col-gutter-sm">
<div class="col-12">
<span class="text-body2 text-weight-medium"
>รายละเอยดตวช</span
>
</div>
<div class="col-8 row">
<q-card bordered class="fit q-pa-sm no-shadow">
<div
v-for="(field, index) in Object.keys(fieldDetailLabels)"
:key="index + 1"
>
<div class="row q-pa-sm q-col-gutter-lg col-12">
<div class="col-4 text-grey-6">
{{
fieldDetailLabels[
field as keyof typeof fieldDetailLabels
]
}}
</div>
<div class="col-8">
<span>{{
formDetail[field] ? formDetail[field] : "-"
}}</span>
</div>
</div>
</div>
</q-card>
</div>
<div class="col-4 row ">
<q-card bordered class="col-12 row no-shadow">
<div class="bg-grey-2 row q-py-sm text-weight-bold col-12">
<div class="col-6 text-center">ระดบคะแนน</div>
<div class="col-6 text-center">ผลสำเรจของงาน</div>
</div>
<div
v-for="(field, index) in Object.keys(fieldLabels)"
:key="index + 1"
class="col-12"
>
<div class="row col-12 q-py-sm">
<div
class="col-6 text-center text-body2"
>
{{ fieldLabels[field as keyof typeof fieldLabels] }}
</div>
<div class="col-6 text-center">
<span>{{
formScore[field] ? formScore[field] : "-"
}}</span>
</div>
</div>
<div
class="col-12"
v-if="index !== Object.keys(fieldLabels).length - 1"
>
<q-separator />
</div>
</div>
</q-card>
</div>
</div>
</div>
</div>
</q-card-section>
<q-separator />
<q-card-actions align="right" class="bg-white text-teal">
<q-btn label="บันทึก" color="secondary" type="submit"
><q-tooltip>นทกขอม</q-tooltip></q-btn
>
</q-card-actions>
</q-form>
</q-card>
</q-dialog>
</template>
<style scoped>
.my-menu-link {
background: #ebf9f7 !important;
color: #1bb19ab8 !important;
}
.no-shadow{
box-shadow:none !important;
}
.lineRight{
border-right: 1px solid #EDEDED !important;
}
.lineTop{
border-top: 1px solid #EDEDED !important;
}
.card-box{
border: 1px solid #EDEDED !important;
border-radius: 8px;
}
</style>

View file

@ -0,0 +1,206 @@
<script setup lang="ts">
import { ref } from "vue";
import Dialog from "@/modules/08_KPI/components/Tab/Dialog/01_Dialog.vue";
import Dialog03 from "@/modules/08_KPI/components/Tab/Dialog/03_Dialog.vue";
import type { QTableProps } from "quasar";
import { useCounterMixin } from "@/stores/mixin";
const title = defineModel<string>('title',{required:true})
const rows = defineModel<any>('data',{required:true})
const numpage = defineModel<number>('page',{required:true})
const mixin = useCounterMixin();
const { date2Thai } = mixin;
const filterKeyword = ref<string>("");
const modal = ref<boolean>(false);
const modalAssigned = ref<boolean>(false);
const visibleColumns = ref<string[]>([
"indicators",
"target",
"scoreLevel",
"weight",
"workResult",
"evaluationResults",
]);
const columns = ref<QTableProps["columns"]>([
{
name: "indicators",
align: "left",
label: "ตัวชี้วัด",
sortable: true,
field: "indicators",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "target",
align: "left",
label: "ค่าเป้าหมาย",
sortable: true,
field: "target",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "scoreLevel",
align: "left",
label: "ระดับคะแนนตามเกณฑ์การประเมิน",
sortable: true,
field: "scoreLevel",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "weight",
align: "left",
label: "น้ำหนัก (ร้อยละ)",
sortable: true,
field: "weight",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "workResult",
align: "left",
label: "ผลสำเร็จของงาน",
sortable: true,
field: "workResult",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "evaluationResults",
align: "left",
label: "ผลการประเมิน",
sortable: true,
field: "evaluationResults",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
]);
function onAdd() {
if(numpage.value !== 3){
modal.value = true;
}else if(numpage.value == 3){
modalAssigned.value = true
}
}
</script>
<template>
<q-card bordered style="border-radius: 5px" class="no-shadow">
<q-card-section class="bg-grey-2 q-py-sm">
<span class="text-weight-medium">{{ title }}</span>
<q-btn
class="q-ml-xs"
flat
round
icon="mdi-plus"
color="primary"
size="12px"
dense
@click="onAdd"
>
<q-tooltip>เพมขอม</q-tooltip>
</q-btn>
</q-card-section>
<q-separator/>
<q-card-section class="q-pa-sm">
<q-table
ref="table"
:columns="columns"
:rows="rows"
:filter="filterKeyword"
row-key="id"
flat
bordered
:paging="true"
dense
hide-pagination
class="custom-table2"
:visible-columns="visibleColumns"
no-data-label="ยังไม่มีข้อมูลแสดงในตารางนี้"
>
<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-tr>
</template>
<template v-slot:body="props">
<q-tr :props="props" class="cursor-pointer">
<q-td v-for="col in props.cols" :key="col.id">
<div v-if="col.name == 'createDate'">
{{ col.value ? date2Thai(col.value) : "-" }}
</div>
<div v-else>
{{ col.value ? col.value : "-" }}
</div>
</q-td>
</q-tr>
</template>
</q-table>
</q-card-section>
</q-card>
<Dialog v-model:modal="modal" :numpage="numpage"/>
<Dialog03 v-model:modal="modalAssigned" :numpage="numpage"/>
</template>
<style scoped>
.custom-table2 {
max-height: 64vh;
.q-table tr:nth-child(odd) td {
background: white;
}
.q-table tr:nth-child(even) td {
background: #f8f8f8;
}
.q-table thead tr {
background: #ecebeb;
}
.q-table thead tr th {
position: sticky;
}
.q-table td:nth-of-type(2) {
z-index: 3 !important;
}
.q-table th:nth-of-type(2),
.q-table td:nth-of-type(2) {
position: sticky;
left: 0;
z-index: 1;
}
/* this will be the loading indicator */
.q-table thead tr:last-child th {
/* height of all previous header rows */
top: 48px;
}
.q-table thead tr:first-child th {
top: 0;
}
}
</style>

View file

@ -0,0 +1,188 @@
<script setup lang="ts">
import { ref } from "vue";
import Dialog from "@/modules/08_KPI/components/Tab/Dialog/04_Dialog.vue";
import type { QTableProps } from "quasar";
import { useCounterMixin } from "@/stores/mixin";
const title = defineModel<string>('title',{required:true})
const rows = defineModel<any>('data',{required:true})
const numpage = defineModel<number>('page',{required:true})
const mixin = useCounterMixin();
const { date2Thai } = mixin;
const filterKeyword = ref<string>("");
const modal = ref<boolean>(false);
const modalAssigned = ref<boolean>(false);
const visibleColumns = ref<string[]>([
"capacity",
"level",
"scoreLevel",
"weight",
"evaluationResults",
]);
const columns = ref<QTableProps["columns"]>([
{
name: "capacity",
align: "left",
label: "รายการสมรรถนะ",
sortable: true,
field: "capacity",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "level",
align: "left",
label: "ระดับที่คาดหวัง",
sortable: true,
field: "level",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "scoreLevel",
align: "left",
label: "ระดับคะแนนตามเกณฑ์การประเมิน",
sortable: true,
field: "scoreLevel",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "weight",
align: "left",
label: "น้ำหนัก (ร้อยละ)",
sortable: true,
field: "weight",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "evaluationResults",
align: "left",
label: "ผลการประเมิน",
sortable: true,
field: "evaluationResults",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
]);
function onAdd() {
modal.value = true;
}
</script>
<template>
<q-card bordered style="border-radius: 5px" class="no-shadow">
<q-card-section class="bg-grey-3 q-py-sm">
<span class="text-weight-medium">{{ title }}</span>
<q-btn
class="q-ml-xs"
flat
round
icon="mdi-plus"
color="primary"
size="12px"
dense
@click="onAdd"
>
<q-tooltip>เพมขอม</q-tooltip>
</q-btn>
</q-card-section>
<q-card-section class="q-pa-sm">
<q-table
ref="table"
:columns="columns"
:rows="rows"
:filter="filterKeyword"
row-key="id"
flat
bordered
:paging="true"
dense
hide-pagination
class="custom-table2"
:visible-columns="visibleColumns"
no-data-label="ยังไม่มีข้อมูลแสดงในตารางนี้"
>
<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-tr>
</template>
<template v-slot:body="props">
<q-tr :props="props" class="cursor-pointer">
<q-td v-for="col in props.cols" :key="col.id">
<div v-if="col.name == 'createDate'">
{{ col.value ? date2Thai(col.value) : "-" }}
</div>
<div v-else>
{{ col.value ? col.value : "-" }}
</div>
</q-td>
</q-tr>
</template>
</q-table>
</q-card-section>
</q-card>
<Dialog v-model:modal="modal" :numpage="numpage"/>
</template>
<style scoped>
.custom-table2 {
max-height: 64vh;
.q-table tr:nth-child(odd) td {
background: white;
}
.q-table tr:nth-child(even) td {
background: #f8f8f8;
}
.q-table thead tr {
background: #ecebeb;
}
.q-table thead tr th {
position: sticky;
}
.q-table td:nth-of-type(2) {
z-index: 3 !important;
}
.q-table th:nth-of-type(2),
.q-table td:nth-of-type(2) {
position: sticky;
left: 0;
z-index: 1;
}
/* this will be the loading indicator */
.q-table thead tr:last-child th {
/* height of all previous header rows */
top: 48px;
}
.q-table thead tr:first-child th {
top: 0;
}
}
</style>

View file

@ -0,0 +1,8 @@
interface DataOptions {
id:string
name:string
}
export type {
DataOptions
}

View file

@ -0,0 +1,22 @@
interface FormProfile {
fullName: string;
prefix: string;
firstName: string;
lastName: string;
position: string;
type: string;
level: string;
status: string;
score: string;
avartar:string
}
interface FormDataAssigned{
indicator:string
target:string
unit:string
weigth:string
definition:string
}
export type { FormProfile ,FormDataAssigned};

View file

@ -0,0 +1,55 @@
/**
* Router
*/
const KPIPage = () => import("@/modules/08_KPI/views/main.vue");
const FormPage = () => import("@/modules/08_KPI/views/form.vue");
const KPIMainEvaluator = () => import("@/modules/08_KPI/views/mainEvaluator.vue");
export default [
{
path: "/KPI",
name: "KPIMain",
component: KPIPage,
meta: {
Auth: true,
Key: [8],
},
},
{
path: "/KPI/add",
name: "KPIAdd",
component: FormPage,
meta: {
Auth: true,
Key: [8.1],
},
},
{
path: "/KPI/:id",
name: "KPIEdit",
component: FormPage,
meta: {
Auth: true,
Key: [8.2],
},
},
{
path: "/KPI-evaluator",
name: "KPIMainEvaluator",
component: KPIMainEvaluator,
meta: {
Auth: true,
Key: [8.3],
},
},
{
path: "/KPI-evaluator/:id",
name: "KPIEditEvaluator",
component: FormPage,
meta: {
Auth: true,
Key: [8.4],
},
},
];

View file

@ -0,0 +1,7 @@
import { defineStore } from "pinia";
import { ref } from "vue";
export const useKpiDataStore = defineStore("KPIDate", () => {
const tabMain = ref<string>("1");
return {tabMain};
});

View file

@ -0,0 +1,86 @@
<script setup lang="ts">
import { ref } from "vue";
import { useKpiDataStore } from '@/modules/08_KPI/store'
import Assessment from '@/modules/08_KPI/components/Tab/01_Assessment.vue'
import CommanderAbove from '@/modules/08_KPI/components/Tab/02_CommanderAbove.vue'
import CommanderAboveOneStep from '@/modules/08_KPI/components/Tab/03_CommanderAboveOneStep.vue'
import File from '@/modules/08_KPI/components/Tab/04_File.vue'
const store = useKpiDataStore()
const itemsTab = ref<any>([
{
name: "1",
label: "ผู้ขอรับการประเมิน",
},
{
name: "2",
label: "ผู้บังคับบัญชาเหนือขึ้นไป",
},
{
name: "3",
label: "ผู้บังคับบัญชาเหนือขึ้นไปอีกหนึ่งขั้น",
},
{
name: "4",
label: "ไฟล์เอกสาร",
},
]);
const splitterModel = ref<number>(12);
</script>
<template>
<q-splitter v-model="splitterModel" disable>
<template v-slot:before>
<q-tabs v-model="store.tabMain" vertical class="text-grey-7 text-weight-light" active-class="bg-blue-1 text-blue-8 text-weight-bold">
<!-- <q-tab
class="hover-tab"
v-for="(tab, index) in itemsTab"
:key="index"
:name="tab.name"
:icon="tab.icon"
:label="tab.label"
/> -->
<q-tab name="1" label="ผู้ขอรับการประเมิน" />
<q-tab name="2" label="ผู้บังคับบัญชา">
<div class="text-caption">เหนอขนไป</div>
</q-tab>
<q-tab name="3" label="ผู้บังคับบัญชา">
<div class="text-caption">เหนอขนไปอกหนงข</div>
</q-tab>
<q-tab name="4" label="ไฟล์เอกสาร" />
</q-tabs>
</template>
<template v-slot:after>
<q-tab-panels
v-model="store.tabMain"
animated
swipeable
vertical
transition-prev="jump-up"
transition-next="jump-up"
>
<q-tab-panel
v-for="(tab, index) in itemsTab"
:key="index"
:name="tab.name"
class="q-pa-none"
>
<Assessment v-if="store.tabMain === '1'" />
<CommanderAbove v-if="store.tabMain === '2'" />
<CommanderAboveOneStep v-if="store.tabMain === '3'" />
<File v-if="store.tabMain === '4'" />
</q-tab-panel>
</q-tab-panels>
</template>
</q-splitter>
</template>
<style scoped>
.hover-tab:hover {
background-color: #0793f1;
color: white !important;
opacity: 1 !important;
}
</style>

View file

@ -0,0 +1,185 @@
<script setup lang="ts">
import { ref, onMounted, reactive } from "vue";
import { useRoute, useRouter } from "vue-router";
import TabMain from "@/modules/08_KPI/views/TabMain.vue";
import http from "@/plugins/http";
import config from "@/app.config";
import { useCounterMixin } from "@/stores/mixin";
import { useQuasar } from "quasar";
import type { FormProfile } from "@/modules/08_KPI/interface/request/index";
const route = useRoute();
const id = route.params.id as string;
const $q = useQuasar();
const mixin = useCounterMixin();
const { showLoader, hideLoader, messageError } = mixin;
const formProfile = reactive<FormProfile>({
fullName: "นางสาวกัณฐิมา กาฬสินธุ์",
prefix: "นางสาว",
firstName: "กัณฐิมา",
lastName: "กาฬสินธุ์",
position: "หัวหน้าสำนักงาน",
type: "บริหาร",
level: "ชำนาญการพิเศษ",
status: "จัดเตรียมข้อมูล",
score: "100",
avartar:
"https://cdn.quasar.dev/img/boy-avatar.png",
});
const router = useRouter();
function getProfile() {
showLoader();
http
.get(config.API.profileBykeycloak())
.then((res) => {
const data = res.data.result;
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
}
/** save */
function onSave() {}
onMounted(() => {
getProfile();
});
</script>
<template>
<div class="col-12 row justify-center">
<div class="col-xs-12 col-sm-12 col-md-11">
<div class="toptitle text-white col-12 row items-center">
<q-btn
icon="mdi-arrow-left"
unelevated
round
dense
flat
color="primary"
class="q-mr-sm"
@click="router.push(`/KPI`)"
/>
{{ id ? `แก้ไขแบบประเมิน` : `เพิ่มแบบประเมิน` }}
<q-space />
<q-btn label="บันทึก" color="secondary" unelevated @click="onSave"
><q-tooltip>นท</q-tooltip></q-btn
>
</div>
<div class="col-12">
<q-card bordered flat class="relative-position">
<div
class="absolute"
style="left: 2%; top: 50%; transform: translateY(-50%)"
>
<q-avatar size="95px">
<q-img :src="formProfile.avartar" />
</q-avatar>
</div>
<div class="row col-12">
<div class="row items-center col-12 q-pa-sm">
<div class="col-12" style="padding-left: 12%;">
<div class="row col-12 items-center">
<span class="text-h6 text-weight-medium text-primary">{{
formProfile.fullName ? formProfile.fullName : "-"
}}</span>
<q-space />
<div class="q-gutter-x-sm">
<q-btn
unelevated
round
icon="mdi-file-eye-outline"
color="grey-2"
text-color="primary"
size="md"
>
<q-tooltip>อมลการชวยราชการ</q-tooltip>
</q-btn>
<q-btn
unelevated
round
color="grey-2"
text-color="blue-5"
icon="mdi-file-eye-outline"
size="md"
>
<q-tooltip>อมลการทดลองงาน</q-tooltip>
</q-btn>
</div>
</div>
</div>
</div>
<div class="row items-center bg-toolbar col-12 q-pa-sm">
<div class="col-12 q-py-xs" style="padding-left: 12%;">
<div class="row no-wrap">
<div class="col-2">
<div class="column">
<span class="text-grey-6">ตำแหนงในสายงาน</span>
<span class="text-weight-medium text-dark">{{
formProfile.position
}}</span>
</div>
</div>
<div class="col-2">
<div class="column">
<span class="text-grey-6">ประเภท</span>
<span class="text-weight-medium text-dark">{{
formProfile.type
}}</span>
</div>
</div>
<div class="col-2">
<div class="column">
<span class="text-grey-6">ระดบชนงาน</span>
<span class="text-weight-medium text-dark">{{
formProfile.level
}}</span>
</div>
</div>
<div class="col-2">
<div class="column">
<span class="text-grey-6">สถานะการประเม</span>
<span class="text-weight-medium text-dark">{{
formProfile.status
}}</span>
</div>
</div>
<div class="col-2">
<div class="column">
<span class="text-grey-6">คะแนนประเม</span>
<span class="text-weight-medium text-primary">{{
formProfile.score
}}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</q-card>
<q-card class="q-mt-md rounded">
<TabMain />
</q-card>
</div>
</div>
</div>
</template>
<style>
.bg-toolbar{
background-color: #F2FBFA;
}
</style>

View file

@ -0,0 +1,245 @@
<script setup lang="ts">
import { ref, onMounted } from "vue";
import { useRouter } from "vue-router";
import type { DataOptions } from "@/modules/08_KPI/interface/index/Main";
import type { QTableProps } from "quasar";
import { useCounterMixin } from "@/stores/mixin";
const mixin = useCounterMixin()
const { date2Thai } = mixin
const router = useRouter();
const filterKeyword = ref<string>("");
const rows = ref<any>();
const round = ref<string>("ID1");
const roundOp = ref<DataOptions[]>([
{
id: "ID1",
name: "รอบเมษา",
},
]);
const visibleColumns = ref<string[]>(["createDate", "status", "result"]);
const columns = ref<QTableProps["columns"]>([
{
name: "createDate",
align: "left",
label: "วันที่สร้างแบบประเมิน",
sortable: true,
field: "createDate",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "status",
align: "left",
label: "สถานะการประเมิน",
sortable: true,
field: "status",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "result",
align: "left",
label: "ผลการประเมิน",
sortable: true,
field: "result",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
]);
/** ดึงข้อมูล */
function getData() {
const data = [
{
id: "ID1",
createDate: '2024-02-16T06:01:00.000Z',
status: "รอดำเนินการ",
result: "ผ่านเกณฑ์การประเมิน",
},
{
id: "ID1",
createDate: '2024-02-16T06:01:00.000Z',
status: "รอดำเนินการ",
result: "ผ่านเกณฑ์การประเมิน",
},
];
rows.value = data;
// showLoader();
// await http
// .get(config.API.orgPrefix)
// .then(async (res) => {
// })
// .catch((err) => {
// messageError($q, err);
// })
// .finally(() => {
// hideLoader();
// });
}
function onEdit(id:string){
router.push(`/KPI/${id}`)
}
onMounted(async () => {
getData();
});
</script>
<template>
<div class="col-12 row justify-center">
<div class="col-xs-12 col-sm-12 col-md-11">
<div class="toptitle text-white col-12 row items-center">
<q-btn
icon="mdi-arrow-left"
unelevated
round
dense
flat
color="primary"
class="q-mr-sm"
@click="router.push(`/`)"
/>
รายการขอรบประเมนผลการปฏราชการระดบบคคล
</div>
<div class="col-12">
<q-card bordered class="q-pa-md">
<q-toolbar style="padding: 0">
<q-select
v-model="round"
outlined
label="รอบการประเมิน"
dense
option-label="name"
option-value="id"
:options="roundOp"
style="min-width: 200px"
emit-value
map-options
/>
<q-btn class="q-ml-sm" flat round color="primary" icon="add" @click="router.push(`/KPI/add`)">
<q-tooltip> เพมขอม </q-tooltip>
</q-btn>
<q-space />
<div class="row q-gutter-sm">
<q-input
outlined
dense
v-model="filterKeyword"
label="ค้นหา"
></q-input>
<q-select
v-model="visibleColumns"
multiple
outlined
dense
options-dense
:display-value="$q.lang.table.columns"
emit-value
map-options
:options="columns"
option-value="name"
options-cover
style="min-width: 150px"
/>
</div>
</q-toolbar>
<q-table
ref="table"
:columns="columns"
:rows="rows"
:filter="filterKeyword"
row-key="id"
flat
bordered
:paging="true"
dense
class="custom-table2"
:visible-columns="visibleColumns"
>
<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-tr>
</template>
<template v-slot:body="props">
<q-tr :props="props" class="cursor-pointer">
<q-td v-for="col in props.cols" :key="col.id" @click="onEdit(props.row.id)">
<div v-if="col.name == 'createDate'">
{{ col.value ? date2Thai(col.value):'-' }}
</div>
<div v-else>
{{ col.value }}
</div>
</q-td>
</q-tr>
</template>
</q-table>
</q-card>
</div>
</div>
</div>
</template>
<style scoped lang="scss">
.icon-color {
color: #4154b3;
}
.custom-table2 {
max-height: 64vh;
.q-table tr:nth-child(odd) td {
background: white;
}
.q-table tr:nth-child(even) td {
background: #f8f8f8;
}
.q-table thead tr {
background: #ecebeb;
}
.q-table thead tr th {
position: sticky;
}
.q-table td:nth-of-type(2) {
z-index: 3 !important;
}
.q-table th:nth-of-type(2),
.q-table td:nth-of-type(2) {
position: sticky;
left: 0;
z-index: 1;
}
/* this will be the loading indicator */
.q-table thead tr:last-child th {
/* height of all previous header rows */
top: 48px;
}
.q-table thead tr:first-child th {
top: 0;
}
}
</style>

View file

@ -0,0 +1,255 @@
<script setup lang="ts">
import { ref, onMounted } from "vue";
import { useRouter } from "vue-router";
import type { DataOptions } from "@/modules/08_KPI/interface/index/Main";
import type { QTableProps } from "quasar";
import { useCounterMixin } from "@/stores/mixin";
const mixin = useCounterMixin()
const { date2Thai } = mixin
const router = useRouter();
const filterKeyword = ref<string>("");
const rows = ref<any>();
const round = ref<string>("ID1");
const roundOp = ref<DataOptions[]>([
{
id: "ID1",
name: "รอบเมษา",
},
]);
const visibleColumns = ref<string[]>(["name", "createDate", "status", "result"]);
const columns = ref<QTableProps["columns"]>([
{
name: "name",
align: "left",
label: "ผู้ขอรับการประเมิน",
sortable: true,
field: "name",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "createDate",
align: "left",
label: "วันที่สร้างแบบประเมิน",
sortable: true,
field: "createDate",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "status",
align: "left",
label: "สถานะการประเมิน",
sortable: true,
field: "status",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "result",
align: "left",
label: "ผลการประเมิน",
sortable: true,
field: "result",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
]);
/** ดึงข้อมูล */
function getData() {
const data = [
{
id: "ID1",
name: "สมศรี ใจดี",
createDate: '2024-02-16T06:01:00.000Z',
status: "รอดำเนินการ",
result: "ผ่านเกณฑ์การประเมิน",
},
{
id: "ID1",
name: "สมจิตร ใจดี",
createDate: '2024-02-16T06:01:00.000Z',
status: "รอดำเนินการ",
result: "ผ่านเกณฑ์การประเมิน",
},
];
rows.value = data;
// showLoader();
// await http
// .get(config.API.orgPrefix)
// .then(async (res) => {
// })
// .catch((err) => {
// messageError($q, err);
// })
// .finally(() => {
// hideLoader();
// });
}
function onEdit(id:string){
router.push(`/KPI-evaluator/${id}`)
}
onMounted(async () => {
getData();
});
</script>
<template>
<div class="col-12 row justify-center">
<div class="col-xs-12 col-sm-12 col-md-11">
<div class="toptitle text-white col-12 row items-center">
<q-btn
icon="mdi-arrow-left"
unelevated
round
dense
flat
color="primary"
class="q-mr-sm"
@click="router.push(`/`)"
/>
รายการการประเมนผลการปฏราชการระดบบคคล
</div>
<div class="col-12">
<q-card bordered class="q-pa-md">
<q-toolbar style="padding: 0">
<q-select
v-model="round"
outlined
label="รอบการประเมิน"
dense
option-label="name"
option-value="id"
:options="roundOp"
style="min-width: 200px"
emit-value
map-options
/>
<q-space />
<div class="row q-gutter-sm">
<q-input
outlined
dense
v-model="filterKeyword"
label="ค้นหา"
></q-input>
<q-select
v-model="visibleColumns"
multiple
outlined
dense
options-dense
:display-value="$q.lang.table.columns"
emit-value
map-options
:options="columns"
option-value="name"
options-cover
style="min-width: 150px"
/>
</div>
</q-toolbar>
<q-table
ref="table"
:columns="columns"
:rows="rows"
:filter="filterKeyword"
row-key="id"
flat
bordered
:paging="true"
dense
class="custom-table2"
:visible-columns="visibleColumns"
>
<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-tr>
</template>
<template v-slot:body="props">
<q-tr :props="props" class="cursor-pointer">
<q-td v-for="col in props.cols" :key="col.id" @click="onEdit(props.row.id)">
<div v-if="col.name == 'createDate'">
{{ col.value ? date2Thai(col.value):'-' }}
</div>
<div v-else>
{{ col.value }}
</div>
</q-td>
</q-tr>
</template>
</q-table>
</q-card>
</div>
</div>
</div>
</template>
<style scoped lang="scss">
.icon-color {
color: #4154b3;
}
.custom-table2 {
max-height: 64vh;
.q-table tr:nth-child(odd) td {
background: white;
}
.q-table tr:nth-child(even) td {
background: #f8f8f8;
}
.q-table thead tr {
background: #ecebeb;
}
.q-table thead tr th {
position: sticky;
}
.q-table td:nth-of-type(2) {
z-index: 3 !important;
}
.q-table th:nth-of-type(2),
.q-table td:nth-of-type(2) {
position: sticky;
left: 0;
z-index: 1;
}
/* this will be the loading indicator */
.q-table thead tr:last-child th {
/* height of all previous header rows */
top: 48px;
}
.q-table thead tr:first-child th {
top: 0;
}
}
</style>

View file

@ -0,0 +1,327 @@
<script setup lang="ts">
import { ref, watch } from "vue";
import DialogHeader from "@/components/DialogHeader.vue";
import { useCounterMixin } from "@/stores/mixin";
import { useQuasar } from "quasar";
import http from "@/plugins/http";
import config from "@/app.config";
import { useRoute } from "vue-router";
const route = useRoute();
const id = ref<string>(route.params.id.toLocaleString());
const $q = useQuasar();
const mixin = useCounterMixin();
const {
date2Thai,
dialogMessageNotify,
showLoader,
hideLoader,
messageError,
dialogConfirm,
success,
} = mixin;
const modal = defineModel<boolean>("modal", { required: true });
const governmentDate = ref<any>(null);
const graduatedDate = ref<any>(null);
const isGraduated = ref<any>(null);
const graduatedReason = ref<string>("");
const bookNumber = ref<string>("");
const bookDate = ref<any>(null);
const governmentEndDate = ref<any>(null);
function close() {
modal.value = false;
bookNumber.value = "";
bookDate.value = null;
governmentDate.value = null;
governmentEndDate.value = null;
isGraduated.value = null;
graduatedDate.value = null;
graduatedReason.value = "";
}
function onSubmit() {
if (isGraduated.value == null) {
dialogMessageNotify($q, "กรุณาเลือกสำเร็จการศึกษาตามที่หลักสูตรกำหนด");
} else {
dialogConfirm($q, () => {
showLoader();
http
.put(config.API.developmentScholarship + `/user/detail/${id.value}`, {
bookNumber: bookNumber.value,
bookDate: bookDate.value,
governmentDate: governmentDate.value,
governmentEndDate: governmentEndDate.value,
isGraduated: isGraduated.value,
graduatedDate: isGraduated.value == 'true' ? graduatedDate.value : null,
graduatedReason: isGraduated.value == 'false' ? graduatedReason.value : null,
})
.then((res) => {
success($q, "บันทึกสำเร็จ");
close();
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
});
}
}
watch(
() => modal.value,
() => {
if (modal.value == true) {
showLoader();
http
.get(config.API.developmentScholarship + `/user/detail/${id.value}`)
.then((res) => {
const data = res.data.result;
bookNumber.value = data.bookNumber;
bookDate.value = data.bookDate;
governmentDate.value = data.governmentDate;
governmentEndDate.value = data.governmentEndDate;
isGraduated.value = data.isGraduated.toLocaleString();
graduatedDate.value = data.graduatedDate;
graduatedReason.value = data.graduatedReason;
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
}
}
);
</script>
<template>
<q-dialog v-model="modal">
<q-card flat style="min-width: 30vw">
<q-form greedy @submit.prevent @validation-success="onSubmit">
<DialogHeader tittle="รายงานตัวกลับเข้ารับราชการ" :close="close" />
<q-separator />
<q-card-section>
<div class="row q-col-gutter-sm">
<div class="col-6">
<q-input
label="เลขที่หนังสือรายงานตัวกลับเข้าปฏิบัติราชการ"
v-model="bookNumber"
outlined
lazy-rules
dense
hide-bottom-space
:rules="[
(val:string) =>
!!val || `${'กรุณากรอกเลขที่หนังสือรายงานตัวกลับเข้าปฏิบัติราชการ'}`,
]"
class="inputgreen"
/>
</div>
<div class="col-6">
<datepicker
menu-class-name="modalfix"
v-model="bookDate"
:locale="'th'"
autoApply
:enableTimePicker="false"
week-start="0"
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
dense
outlined
:model-value="bookDate ? date2Thai(bookDate) : null"
:label="`${'หนังสือรายงานตัวกลับเข้าปฏิบัติราชการลงวันที่'}`"
hide-bottom-space
class="inputgreen"
:rules="[
(val:string) =>
!!val || `${'กรุณากรอกหนังสือรายงานตัวกลับเข้าปฏิบัติราชการลงวันที่'}`,
]"
>
<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-6">
<datepicker
menu-class-name="modalfix"
v-model="governmentDate"
:locale="'th'"
autoApply
:enableTimePicker="false"
week-start="0"
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
dense
outlined
:model-value="
governmentDate ? date2Thai(governmentDate) : null
"
:label="`${'วันที่กลับเข้าปฏิบัติราชการ'}`"
hide-bottom-space
class="inputgreen"
:rules="[
(val:string) =>
!!val || `${'กรุณากรอกวันที่กลับเข้าปฏิบัติราชการ'}`,
]"
>
<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-6">
<datepicker
menu-class-name="modalfix"
v-model="governmentEndDate"
:locale="'th'"
autoApply
:enableTimePicker="false"
week-start="0"
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
dense
outlined
:model-value="
governmentEndDate ? date2Thai(governmentEndDate) : null
"
:label="`${' วันสิ้นสุดภาระผูกพัน'}`"
hide-bottom-space
class="inputgreen"
:rules="[
(val:string) =>
!!val || `${'กรุณากรอก วันสิ้นสุดภาระผูกพัน'}`,
]"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
style="color: var(--q-primary)"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<q-radio
v-model="isGraduated"
checked-icon="task_alt"
unchecked-icon="panorama_fish_eye"
val="true"
label="สำเร็จการศึกษาตามที่หลักสูตรกำหนด"
/>
<q-radio
v-model="isGraduated"
checked-icon="task_alt"
unchecked-icon="panorama_fish_eye"
val="false"
label="เสร็จสิ้นการศึกษาตามที่หลักสูตรกำหนดแล้วแต่ยังไม่สำเร็จการศึกษา"
/>
<div v-if="isGraduated == 'true'" class="col-12">
<datepicker
menu-class-name="modalfix"
v-model="graduatedDate"
:locale="'th'"
autoApply
:enableTimePicker="false"
week-start="0"
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
dense
outlined
:model-value="
graduatedDate ? date2Thai(graduatedDate) : null
"
:label="`${'ตั้งแต่ (วันที่)'}`"
hide-bottom-space
class="inputgreen"
:rules="[
(val:string) =>
!!val || `${'กรุณากรอกตั้งแต่ (วันที่)'}`,
]"
>
<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 v-if="isGraduated == 'false'" class="col-12">
<q-input
v-model="graduatedReason"
type="textarea"
dense
outlined
hide-bottom-space
class="inputgreen"
:rules="[
(val:string) =>
!!val || `${'กรุณากรอก เนื่องจาก'}`,
]"
label="เนื่องจาก"
/>
</div>
</div>
</q-card-section>
<q-separator />
<q-card-actions align="right">
<q-btn label="บันทึก" color="secondary" type="submit"
><q-tooltip>นทกขอม</q-tooltip></q-btn
>
</q-card-actions>
</q-form>
</q-card>
</q-dialog>
</template>

View file

@ -0,0 +1,8 @@
interface DataOptions {
id:string
name:string
}
export type {
DataOptions
}

View file

@ -0,0 +1,132 @@
interface FormsSholarship {
profileId: string;
rank: string; //ยศ
prefix: string; //คำนำหน้าชื่อ
firstName: string; //ชื่อ
lastName: string; //นามสกุล
citizenId: string; //เลขประจำตัวประชาชน
position: string; //ตำแหน่ง
posExecutive: string; //ชื่อตำแหน่งทางการบริหาร
posLevelId: string | null; //ไอดีระดับตำแหน่ง
posTypeId: string | null; //ไอดีประเภทตำแหน่ง
org: string;
rootId: string | null;
root: string;
orgRootShortName: string;
orgRevisionId: string | null;
guarantorRank: string; //ยศ(ผู้ค้ำ)
guarantorPrefix: string; //คำนำหน้าชื่อ(ผู้ค้ำ)
guarantorFirstName: string; //ชื่อ(ผู้ค้ำ)
guarantorLastName: string; //นามสกุล(ผู้ค้ำ)
guarantorCitizenId: string; //เลขประจำตัวประชาชน(ผู้ค้ำ)
guarantorPosition: string; //ตำแหน่ง(ผู้ค้ำ)
guarantorPosExecutive: string; //ชื่อตำแหน่งทางการบริหาร(ผู้ค้ำ)
guarantorOrg: string;
guarantorRootId: string | null;
guarantorRoot: string;
guarantorOrgRootShortName: string;
guarantorOrgRevisionId: string | null;
posLevelguarantorId: string | null; //ไอดีระดับตำแหน่ง(ผู้ค้ำ)
posTypeguarantorId: string | null; //ไอดีประเภทตำแหน่ง(ผู้ค้ำ)
scholarshipYear: number | null; //ปีงบประมาณที่ได้รับทุน
budgetSource: string; //แหล่งงบประมาณ
budgetApprove: number | string | null; //งบประมาณที่ได้รับอนุมัติตลอดหลักสูตร
bookNo: string; //เลขที่หนังสืออนุมัติ
bookNoDate: Date | null; //ลงวันที่(หนังสือ)
bookApproveDate: Date | null; //หนังสืออนุมัติเมื่อวันที่
useOfficialTime: boolean; //ใช้เวลาราชการ
changeDetail: string; //เปลี่ยนแปลงรายละเอียด
scholarshipType: string; //เลือกประเภททุน
fundType: string; //ประเภททุน
contractNo: string; //เลขที่สัญญา
contractDate: Date | null; //ลงวันที่(เลขที่สัญญา)
reportBackNo: string; //เลขที่หนังสือรายงานตัวกลับ
reportBackNoDate: Date | null; //ลงวันที่(เลขที่หนังสือรายงานตัวกลับ)
reportBackDate: Date | null; //รายงานตัวกลับวันที่
degreeLevel: string; //ระดับปริญญา
course: string; //หลักสูตรการศึกษา/หลักสูตรการฝึกอบรม
field: string; //สาขาวิชา/สาขา
faculty: string; //คณะ
educationalInstitution: string; //สถาบันการศึกษา/สถาบันการศึกษา_หน่วยงานผู้จัดการฝึกอบรม/สถานที่ไปศึกษาดูงานในประเทศ
startDate: Date | null; //วันเริ่มต้นการศึกษา/วันเริ่มต้นการฝึกอบรม/วันเริ่มต้นการศึกษาดูงานในประเทศ
endDate: Date | null; //วันสิ้นสุดการศึกษา/วันสิ้นสุดการฝึกอบรม/วันสิ้นสุดการศึกษาดูงานในประเทศ
studyPlace: string; //สถานที่ไปศึกษาดูงาน
studyTopic: string; //หัวข้อการไปศึกษาดูงาน/หัวข้อการไปศึกษาดูงานในประเทศ
studyStartDate: Date | null; //วันเริ่มต้นการศึกษาดูงาน
studyEndDate: Date | null; //วันสิ้นสุดการศึกษาดูงาน
studyCountry: string; //ประเทศที่เดินทางไปศึกษาดูงาน
studyAbroadTopic: string; //หัวข้อการไปศึกษาดูงานต่างประเทศ
studyAbroadStartDate: Date | null; //วันเริ่มต้นการศึกษาดูงานต่างประเทศ
studyAbroadEndDate: Date | null; //วันสิ้นสุดการศึกษาดูงานต่างประเทศ
totalPeriod: string; //รวมระยะเวลาในการศึกษา/รวมระยะเวลาในการฝึกอบรม
planType: string; // INPLAN ในแผนฯ, OUTPLAN นอกแผนฯ
isNoUseBudget: boolean; //
}
interface DataSholarship {
rank: string; //ยศ
prefix: string; //คำนำหน้าชื่อ
firstName: string; //ชื่อ
lastName: string; //นามสกุล
citizenId: string; //เลขประจำตัวประชาชน
position: string; //ตำแหน่ง
posExecutive: string; //ชื่อตำแหน่งทางการบริหาร
posLevelId: string; //ไอดีระดับตำแหน่ง
posTypeId: string; //ไอดีประเภทตำแหน่ง
posTypeName: string; //ไอดีระดับตำแหน่ง
posLevelName: string; //ไอดีประเภทตำแหน่ง
org: string;
guarantorRank: string; //ยศ(ผู้ค้ำ)
guarantorPrefix: string; //คำนำหน้าชื่อ(ผู้ค้ำ)
guarantorFirstName: string; //ชื่อ(ผู้ค้ำ)
guarantorLastName: string; //นามสกุล(ผู้ค้ำ)
guarantorCitizenId: string; //เลขประจำตัวประชาชน(ผู้ค้ำ)
guarantorPosition: string; //ตำแหน่ง(ผู้ค้ำ)
guarantorPosExecutive: string; //ชื่อตำแหน่งทางการบริหาร(ผู้ค้ำ)
guarantorOrg: string;
guarantorRootId: string | null;
guarantorRoot: string;
guarantorOrgRootShortName: string;
guarantorOrgRevisionId: string | null;
posLevelguarantorId: string; //ไอดีระดับตำแหน่ง(ผู้ค้ำ)
posTypeguarantorId: string; //ไอดีประเภทตำแหน่ง(ผู้ค้ำ)
posTypeguarantorName: string; //ไอดีระดับตำแหน่ง(ผู้ค้ำ)
posLevelguarantorName: string; //ไอดีประเภทตำแหน่ง(ผู้ค้ำ)
scholarshipYear: number | null; //ปีงบประมาณที่ได้รับทุน
budgetSource: string; //แหล่งงบประมาณ
budgetApprove: number | null; //งบประมาณที่ได้รับอนุมัติตลอดหลักสูตร
bookNo: string; //เลขที่หนังสืออนุมัติ
bookNoDate: Date | null; //ลงวันที่(หนังสือ)
bookApproveDate: Date | null; //หนังสืออนุมัติเมื่อวันที่
useOfficialTime: boolean; //ใช้เวลาราชการ
changeDetail: string; //เปลี่ยนแปลงรายละเอียด
scholarshipType: string; //เลือกประเภททุน
fundType: string; //ประเภททุน
contractNo: string; //เลขที่สัญญา
contractDate: Date | null; //ลงวันที่(เลขที่สัญญา)
reportBackNo: string; //เลขที่หนังสือรายงานตัวกลับ
reportBackNoDate: Date | null; //ลงวันที่(เลขที่หนังสือรายงานตัวกลับ)
reportBackDate: Date | null; //รายงานตัวกลับวันที่
degreeLevel: string; //ระดับปริญญา
course: string; //หลักสูตรการศึกษา/หลักสูตรการฝึกอบรม
field: string; //สาขาวิชา/สาขา
faculty: string; //คณะ
educationalInstitution: string; //สถาบันการศึกษา/สถาบันการศึกษา_หน่วยงานผู้จัดการฝึกอบรม/สถานที่ไปศึกษาดูงานในประเทศ
startDate: Date | null; //วันเริ่มต้นการศึกษา/วันเริ่มต้นการฝึกอบรม/วันเริ่มต้นการศึกษาดูงานในประเทศ
endDate: Date | null; //วันสิ้นสุดการศึกษา/วันสิ้นสุดการฝึกอบรม/วันสิ้นสุดการศึกษาดูงานในประเทศ
studyPlace: string; //สถานที่ไปศึกษาดูงาน
studyTopic: string; //หัวข้อการไปศึกษาดูงาน/หัวข้อการไปศึกษาดูงานในประเทศ
studyStartDate: Date | null; //วันเริ่มต้นการศึกษาดูงาน
studyEndDate: Date | null; //วันสิ้นสุดการศึกษาดูงาน
studyCountry: string; //ประเทศที่เดินทางไปศึกษาดูงาน
studyAbroadTopic: string; //หัวข้อการไปศึกษาดูงานต่างประเทศ
studyAbroadStartDate: Date | null; //วันเริ่มต้นการศึกษาดูงานต่างประเทศ
studyAbroadEndDate: Date | null; //วันสิ้นสุดการศึกษาดูงานต่างประเทศ
totalPeriod: string; //รวมระยะเวลาในการศึกษา/รวมระยะเวลาในการฝึกอบรม
status: string;
planType: string; // INPLAN ในแผนฯ, OUTPLAN นอกแผนฯ
isNoUseBudget: boolean; // ไม่ใช้งบประมาณ
}
export type { FormsSholarship,DataSholarship };

View file

@ -0,0 +1,26 @@
/**
* Router
*/
const scholarshipPage = () => import("@/modules/09_scholarship/views/main.vue");
const scholarshipDetail = () => import('@/modules/09_scholarship/views/detail.vue')
export default [
{
path: "/scholarship",
name: "scholarshipMain",
component: scholarshipPage,
meta: {
Auth: true,
Key: [9],
},
},
{
path: "/scholarship/:id",
name: "scholarshipDetail",
component: scholarshipDetail,
meta: {
Auth: true,
Key: [9],
},
},
];

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,363 @@
<script setup lang="ts">
import { ref, onMounted, watch } from "vue";
import { useRouter } from "vue-router";
import { useQuasar, type QTableProps } from "quasar";
import { useCounterMixin } from "@/stores/mixin";
import type { DataOptions } from "@/modules/09_scholarship/interface/index/Main";
import http from "@/plugins/http";
import config from "@/app.config";
const mixin = useCounterMixin();
const { date2Thai, showLoader, hideLoader, messageError } = mixin;
const router = useRouter();
const $q = useQuasar();
const filterKeyword = ref<string>("");
const profilId = ref<string>("");
const currentPage = ref<number>(1);
const maxPage = ref<number>(1);
const page = ref<number>(1);
const rowsPerPage = ref<number>(10);
const rows = ref<any>();
const year = ref<number>(0);
const type = ref<string>("DOMESTICE");
const scholarshipTypeOp = ref<DataOptions[]>([
{ id: "DOMESTICE", name: "การศึกษาในประเทศ" },
{
id: "NOABROAD",
name: "ฝึกอบรมในประเทศที่ส่งไปพัฒนากับหน่วยงานภายนอก (หลักสูตรที่ไม่มีการไปต่างประเทศ)",
},
{
id: "ABROAD",
name: "ฝึกอบรมในประเทศที่ส่งไปพัฒนากับหน่วยงานภายนอก (หลักสูตรที่มีการไปต่างประเทศ)",
},
{
id: "EXECUTIVE",
name: " ฝึกอบรมในประเทศที่ส่งไปพัฒนากับหน่วยงานภายนอก (หลักสูตรประเภทนักบริหาร)",
},
{
id: "RESEARCH",
name: "ศึกษา ฝึกอบรม ประชุม ดูงาน และปฏิบัติการวิจัย ณ ต่างประเทศ",
},
]);
/**
* งค pagination
*/
const pagination = ref({
sortBy: "lastUpdatedAt",
descending: true,
page: page.value,
rowsPerPage: rowsPerPage.value,
});
const columns = ref<QTableProps["columns"]>([
{
name: "scholarshipYear",
align: "left",
label: "ปีงบประมาณที่ได้รับทุน ",
sortable: true,
field: "scholarshipYear",
headerStyle: "font-size: 14px ;width:20%",
style: "font-size: 14px",
},
{
name: "scholarshipType",
align: "left",
label: "ประเภททุน",
sortable: true,
field: "scholarshipType",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
]);
const visibleColumns = ref<string[]>(["scholarshipYear", "scholarshipType"]);
/** ดึงข้อมูล */
function getData() {
http
.get(config.API.developmentScholarship + `/user/${profilId.value}?year=${year.value}&type=${type.value}`)
.then((res) => {
rows.value = res.data.result;
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {});
}
function onEdit(id: string) {
router.push(`/scholarship/${id}`);
}
watch(
() => currentPage.value,
() => {
rowsPerPage.value = pagination.value.rowsPerPage;
getData();
}
);
watch(
() => pagination.value.rowsPerPage,
() => {
rowsPerPage.value = pagination.value.rowsPerPage;
currentPage.value = 1;
getData();
}
);
function getProfileId() {
showLoader();
http
.get(config.API.profilePosition())
.then((res) => {
profilId.value = res.data.result.profileId;
getData();
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
}
function convertType(val: string) {
switch (val) {
case "DOMESTICE":
return "การศึกษาในประเทศ";
case "NOABROAD":
return "ฝึกอบรมในประเทศที่ส่งไปพัฒนากับหน่วยวงานภายนอก (หลักสูตรที่ไม่มีการไปต่างประเทศ)";
case "ABROAD":
return "ฝึกอบรมในประเทศที่ส่งไปพัฒนากับหน่วยวงานภายนอก (หลักสูตรที่มีการไปต่างประเทศ)";
case "EXECUTIVE":
return "ฝึกอบรมในประเทศที่ส่งไปพัฒนากับหน่วยวงานภายนอก (หลักสูตรประเภทนักบริหาร)";
case "RESEARCH":
return "ศึกษา ฝึกอบรม ประชุม ดูงาน และปฏิบัติการวิจัย ณ ต่างประเทศ";
}
}
onMounted(async () => {
getProfileId();
});
</script>
<template>
<div class="col-12 row justify-center">
<div class="col-xs-12 col-sm-12 col-md-11">
<div class="toptitle text-white col-12 row items-center">
<q-btn
icon="mdi-arrow-left"
unelevated
round
dense
flat
color="primary"
class="q-mr-sm"
@click="router.push(`/`)"
/>
รายการทนการศกษา/กอบรม
</div>
<div class="col-12">
<q-card bordered class="q-pa-md">
<q-toolbar style="padding: 0">
<div class="row q-gutter-sm">
<datepicker
style="width: 150px"
menu-class-name="modalfix"
v-model="year"
:locale="'th'"
autoApply
year-picker
:enableTimePicker="false"
@update:model-value="getData()"
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
dense
lazy-rules
outlined
:model-value="year === 0 ? 'ทั้งหมด' : Number(year) + 543"
:label="`${'ปีงบประมาณ'}`"
>
<template v-if="year" v-slot:append>
<q-icon
name="cancel"
@click.stop.prevent="(year = 0), getData()"
class="cursor-pointer"
/>
</template>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
style="color: var(--q-primary)"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
<q-select
dense
outlined
v-model="type"
:options="scholarshipTypeOp"
emit-value
map-options
option-value="id"
option-label="name"
label="เลือกประเภททุน"
@update:model-value="getData()"
style="width: 350px"
/>
<!-- <q-btn
flat
round
color="primary"
icon="add"
@click="router.push(`/KPI/add`)"
>
<q-tooltip> เพมขอม </q-tooltip>
</q-btn> -->
</div>
<q-space />
<div class="row q-gutter-sm">
<q-input
outlined
dense
v-model="filterKeyword"
label="ค้นหา"
></q-input>
<q-select
v-model="visibleColumns"
multiple
outlined
dense
options-dense
:display-value="$q.lang.table.columns"
emit-value
map-options
:options="columns"
option-value="name"
options-cover
style="min-width: 150px"
/>
</div>
</q-toolbar>
<q-table
ref="table"
:columns="columns"
:rows="rows"
:filter="filterKeyword"
row-key="id"
flat
bordered
:paging="true"
dense
hide-pagination
class="custom-table2"
:visible-columns="visibleColumns"
v-model:pagination="pagination"
:rows-per-page-options="[10, 25, 50, 100]"
>
<template v-slot:pagination="scope">
<q-pagination
v-model="currentPage"
active-color="primary"
color="dark"
:max="Number(maxPage)"
size="sm"
boundary-links
direction-links
></q-pagination>
</template>
<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" class="cursor-pointer">
<q-td
v-for="col in props.cols"
:key="col.id"
@click="onEdit(props.row.id)"
>
<div v-if="col.name == 'scholarshipYear'">
{{ col.value ? col.value + 543 : "-" }}
</div>
<div v-else-if="col.name == 'scholarshipType'">
{{ col.value ? convertType(col.value) : "-" }}
</div>
<div v-else>
{{ col.value ? col.value : "-" }}
</div>
</q-td>
</q-tr>
</template>
</q-table>
</q-card>
</div>
</div>
</div>
</template>
<style scoped lang="scss">
.icon-color {
color: #4154b3;
}
.custom-table2 {
max-height: 64vh;
.q-table tr:nth-child(odd) td {
background: white;
}
.q-table tr:nth-child(even) td {
background: #f8f8f8;
}
.q-table thead tr {
background: #ecebeb;
}
.q-table thead tr th {
position: sticky;
}
.q-table td:nth-of-type(2) {
z-index: 3 !important;
}
.q-table th:nth-of-type(2),
.q-table td:nth-of-type(2) {
position: sticky;
left: 0;
z-index: 1;
}
/* this will be the loading indicator */
.q-table thead tr:last-child th {
/* height of all previous header rows */
top: 48px;
}
.q-table thead tr:first-child th {
top: 0;
}
}
</style>

View file

@ -11,6 +11,8 @@ import ModuleLeave from "@/modules/05_leave/router";
import ModuEvaluate from "@/modules/06_evaluate/router";
import ModuAppealComplain from "@/modules/07_appealComplain/router";
import ModuleSupport from "@/modules/00_support/router";
import ModuleKPI from "@/modules/08_KPI/router";
import ModuleScholarship from "@/modules/09_scholarship/router";
// TODO: ใช้หรือไม่?
import keycloak from "@/plugins/keycloak";
@ -47,6 +49,8 @@ const router = createRouter({
...ModuEvaluate,
...ModuAppealComplain,
...ModuleSupport,
...ModuleKPI,
...ModuleScholarship,
],
},
],

View file

@ -988,7 +988,7 @@ export const useCounterMixin = defineStore("mixin", () => {
* @param endDate format MM-DD-YYYY"
* @returns 1 10 5
*/
function calculateDurationYmd(startDate: string, endDate: string) {
function calculateDurationYmd(startDate: any, endDate: any) {
if (startDate && endDate) {
const start = new Date(startDate);
const end = new Date(endDate);

View file

@ -90,7 +90,7 @@ const fetchlistNotification = async (index: number, type: string) => {
const doLogout = () => {
$q.dialog({
title: "ยืนยันการออกจากระบบ",
message: `ต้องการออกจากระบบใชหรือไม่?`,
message: `ต้องการออกจากระบบใชหรือไม่?`,
cancel: "ยกเลิก",
ok: "ยืนยัน",
persistent: true,