hrms-mgt/src/modules/03_recruiting/views/02_qualify/PeriodAdd.vue
2025-07-07 15:18:37 +07:00

2407 lines
98 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- page:ดการรอบการสอบ สรรหา -->
<script setup lang="ts">
import type { QTableProps } from "quasar";
import { onMounted, ref, watch } from "vue";
import { useQuasar, QForm } from "quasar";
import { useRouter, useRoute } from "vue-router";
import http from "@/plugins/http";
import config from "@/app.config";
import { useCounterMixin } from "@/stores/mixin";
import type {
RequestPosition,
RequestPayment,
} from "@/modules/03_recruiting/interface/request/Period";
import type {
ResponsePosition,
ResponsePayment,
} from "@/modules/03_recruiting/interface/response/Period";
import type {
DataOption2,
UploadType,
} from "@/modules/02_organization/interface/index/Main";
import type {
ResponesePosType,
DataPosLevel,
ResponesePosition,
} from "@/modules/03_recruiting/interface/response/Main";
import ProfileTable from "@/modules/03_recruiting/components/Table1.vue";
const $q = useQuasar(); // show dialog
const mixin = useCounterMixin();
const router = useRouter();
const route = useRoute();
const {
date2Thai,
success,
messageError,
showLoader,
hideLoader,
convertDateToAPI,
} = mixin;
const checkRoutePermisson = ref<boolean>(
route.name == "qualifyPeriodEditDetail"
); //เช็คชื่อ route
const myForm = ref<QForm | null>(null); //form data input
const name = ref<string>("");
const note = ref<string>("");
const editor = ref<string>("");
const editorCondition = ref<string>(
`<div style="text-align: center;"><span style="color: rgb(193, 0, 21); font-weight: 700; letter-spacing: 0.14992px;">ข้อกำหนดและเงื่อนไขฉบับนี้ ถือเป็นข้อตกลงในการเก็บข้อมูล</span><br></div><div style="text-align: center;"><span style="color: rgb(193, 0, 21); font-weight: 700; letter-spacing: 0.14992px;"><br></span></div><div><p style="margin-bottom: 16px;"><span style="font-size: 14px;">&nbsp; &nbsp;&nbsp;ข้าพเจ้าได้ศึกษาและทำความเข้าใจพระราชบัญญัติคุ้มครองข้อมูลส่วนบุคคล พ.ศ. 2562 ตลอดจนประกาศและระเบียบที่เกี่ยวข้องโดยละเอียดครบถ้วนแล้ว ข้าพเจ้ายินยอมให้หน่วยงานหรือบุคคลที่เกี่ยวข้องกับการดำเนินการสรรหา สามารถเก็บ รวบรวม ใช้และเปิดเผยข้อมูลส่วนบุคคลที่เกี่ยวข้องกับข้าพเจ้า เพื่อประโยชน์ของทางราชการตามกฎหมายที่เกี่ยวข้อง</span></p></div>`
);
const editorConfirm = ref<string>(
`<div style="text-align: center;"><span style="color: rgb(93, 190, 21); font-weight: 700; letter-spacing: 0.14992px;">คำรับรอง</span><br></div><div><div style=""><div style=""><font color="#35473c"><span style="font-size: 14px;"><br></span></font></div><div style=""><font color="#35473c"><span style="font-size: 14px;">1.<span style="white-space: pre;"> </span>ข้าพเจ้าขอให้คำรับรองว่า ข้อความดังกล่าวข้างต้นเป็นจริงทุกประการ และข้าพเจ้ามีคุณสมบัติทั่วไปและไม่มีลักษณะต้องห้ามตามมาตรา 43 แห่งพระราชบัญญัติระเบียบข้าราชการกรุงเทพมหานครและบุคลากรกรุงเทพมหานคร พ.ศ. 2554 และมีคุณสมบัติเฉพาะสำหรับตำแหน่งที่สมัครตรงตามประกาศรับสมัคร</span></font></div><div style=""><font color="#35473c"><span style="font-size: 14px;">2.<span style="white-space:pre"> </span>กรณีข้าพเจ้ามีลักษณะต้องห้าม ตามมาตรา 43 ข. แห่งพระราชบัญญัติระเบียบข้าราชการกรุงเทพมหานครและบุคลากรกรุงเทพมหานคร พ.ศ. 2554 และประสงค์จะยื่นคำขอยกเว้นเข้ารับราชการฯ ต่อสำนักงาน ก.ก. ตามระเบียบ ก.ก. ว่าด้วยการยกเว้นให้ผู้มีลักษณะต้องห้ามเข้ารับราชการเป็นข้าราชการกรุงเทพมหานคร พ.ศ. 2556 ตามมติ ก.ก. ครั้งที่ 7/2556 เมื่อวันที่ 15 สิงหาคม 2556 ข้าพเจ้าจะยื่นคำขอยกเว้นฯ ภายในวันปิดรับสมัคร ทั้งนี้ หากยื่นภายหลังกำหนด สำนักงาน ก.ก. จะไม่รับคำขอดังกล่าว</span></font></div><div style=""><font color="#35473c"><span style="font-size: 14px;">3.<span style="white-space:pre"> </span>ข้าพเจ้าจะยื่นหลักฐานและเอกสารที่แสดงว่า เป็นผู้มีคุณสมบัติทั่วไปและมีคุณสมบัติเฉพาะสำหรับตำแหน่งที่สมัครตรงตามประกาศรับสมัครภายในระยะเวลาที่กำหนดตามประกาศฯ หากมีการตรวจสอบหลักฐานและเอกสาร และหรือคุณวุฒิการศึกษาของข้าพเจ้าในภายหลังปรากฏว่าข้าพเจ้ามีคุณสมบัติไม่ตรงหรือมีลักษณะต้องห้ามตามประกาศรับสมัครหรือไม่ได้รับการยกเว้นให้ถือว่า ข้าพเจ้าเป็นผู้ขาดคุณสมบัติในการสมัครครั้งนี้มาตั้งแต่ต้น และไม่มีสิทธิได้รับการบรรจุและแต่งตั้งให้ดำรงตำแหน่ง และข้าพเจ้าจะไม่มีสิทธิเรียกร้องใดๆ ทั้งสิ้น และหากข้าพเจ้าจงใจกรอกข้อความอันเป็นเท็จ อาจมีความผิดทางอาญาฐานแจ้งความเท็จต่อเจ้าพนักงาน ตามประมวลกฎหมายอาญา มาตรา 137</span></font></div><div style=""><font color="#35473c"><span style="font-size: 14px;">4.<span style="white-space:pre"> </span>ข้าพเจ้าได้ศึกษาและทำความเข้าใจพระราชบัญญัติคุ้มครองข้อมูลส่วนบุคคล พ.ศ. 2562 ตลอดจนประกาศและระเบียบที่เกี่ยวข้องโดยละเอียดครบถ้วนแล้ว ข้าพเจ้าขอแสดงความยินยอมให้หน่วยงานหรือบุคคลที่เกี่ยวข้องกับการดำเนินการสรรหา สามารถเก็บ รวบรวม ใช้และเปิดเผยข้อมูลส่วนบุคคลที่เกี่ยวข้องกับข้าพเจ้า เพื่อประโยชน์ของทางราชการตามกฎหมายที่เกี่ยวข้อง</span></font></div><div style=""><font color="#35473c"><span style="font-size: 14px;">5.<span style="white-space:pre"> </span>ข้าพเจ้ารับทราบว่าการส่งใบสมัครคัดเลือกฯ พร้อมเอกสารนี้ ยังไม่ได้รับการตรวจสอบคุณสมบัติตามหลักเกณฑ์ ประกาศรับสมัครคัดเลือก และเงื่อนไขต่างๆ โดยจะได้รับการตรวจสอบคุณสมบัติเมื่อเป็นผู้สอบผ่านข้อเขียนภาคความรู้ความสามารถที่ใช้เฉพาะตำแหน่งแล้วเท่านั้น</span></font></div></div>`
);
const fee = ref<number>(0);
const remark = ref<string>("");
const companyCode = ref<string>("");
const reason = ref<string>("");
const refNo1 = ref<string>("");
const qrCodes = ref<File | any>(null);
const barCodes = ref<File | any>(null);
const qrCodesFile = ref<UploadType[]>([]);
const barCodesFile = ref<UploadType[]>([]);
const checkDocument = ref<boolean>(false);
const checkDisability = ref<boolean>(false);
const announcementExam = ref<boolean>(true);
const round = ref<number>(1);
const yearly = ref<number>(new Date().getFullYear());
const nameRaw = ref<number | null>(null);
const roundRaw = ref<number | null>(null);
const yearlyRaw = ref<number | null>(null);
const dateRegister = ref<[Date, Date] | null>(null); //วันที่สมัคร
const datePayment = ref<[Date, Date] | null>(null); //วันที่จ่ายเงิน
const dateAnnouncement = ref<[Date, Date] | null>(null); //วันที่ประกาศ
const dateAnnounce = ref<Date | null>(null); //วันประกาศผลสอบ
const dateExam = ref<Date | null>(null); //วันที่สอบ
const myFormPayment = ref<any>();
const myFormPosition = ref<any>();
const organizationShortName = ref<DataOption2>();
const organizationName = ref<DataOption2>();
const examTypeOptions = [
{ name: "ทั่วไป", id: "normol" },
{ name: "แพทย์", id: "docter" },
];
const category = ref<string>("");
const fileDocDataUpload = ref<File[]>([]);
const fileDocs = ref<UploadType[]>([]);
const fileImgDataUpload = ref<File[]>([]);
const fileImgs = ref<UploadType[]>([]);
const id = ref<string>("");
const pay = ref<string>("payment1");
const filterPayment = ref<string>(""); //search data table
const filterPosition = ref<string>(""); //search data table
const edit = ref<boolean>(false);
const rowsPayment = ref<ResponsePayment[]>([]);
const rowsPosition = ref<any>([]);
const visibleColumnsPayment = ref<String[]>([
"accountNumber",
"bankName",
"accountName",
]);
const columnsPayment = ref<QTableProps["columns"]>([
{
name: "accountNumber",
align: "left",
label: "เลขบัญชี",
sortable: true,
field: "accountNumber",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "bankName",
align: "left",
label: "ธนาคาร",
sortable: true,
field: "bankName",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "accountName",
align: "left",
label: "ชื่อบัญชี",
sortable: true,
field: "accountName",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
]);
const visibleColumnsPosition = ref<String[]>([
"code",
"position",
"level",
"type",
"highDegree",
]);
const columnsPosition = ref<QTableProps["columns"]>([
{
name: "code",
align: "left",
label: "รหัสประจำตำแหน่งที่สอบ",
sortable: true,
field: "code",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "highDegree",
align: "left",
label: "ประเภทตำแหน่ง",
sortable: true,
field: "highDegree",
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: "position",
align: "left",
label: "ตำแหน่ง",
sortable: true,
field: "position",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "type",
align: "left",
label: "ประเภทแบบฟอร์ม",
sortable: true,
field: "type",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
]);
/** ย้อนกลับไปหน้าหลัก */
function clickBack() {
router.push({ name: "qualifyPeriod" });
}
/** ดึงข้อมูล */
async function fetchData() {
showLoader();
await http
.get(config.API.periodExamId(id.value))
.then((res) => {
const data = res.data.result;
const positionData: ResponsePosition[] = [];
data.positionExam.map((r: RequestPosition) => {
positionData.push({
id: r.id,
position: {
id: r.positionId,
name: r.positionName,
},
level: {
id: r.positionLevelId,
name: r.positionLevelName,
},
type: {
id: r.typeId,
name: r.typeName,
},
code: r.code,
highDegree: r.highDegree == true ? "1" : "0",
});
});
const bankData: ResponsePayment[] = [];
data.bankExam.map((r: RequestPayment) => {
bankData.push({
id: r.id,
accountNumber: r.accountNumber,
bankName: r.bankName,
accountName: r.accountName,
});
});
id.value = data.id;
name.value = data.name;
nameRaw.value = data.name;
checkDocument.value = data.checkDocument;
checkDisability.value = data.checkDisability;
announcementExam.value = data.announcementExam;
round.value = data.round;
yearly.value = data.year;
roundRaw.value = data.round;
yearlyRaw.value = data.year;
fee.value = data.fee;
dateAnnounce.value =
data.announcementDate != null ? new Date(data.announcementDate) : null;
dateAnnouncement.value =
data.announcementStartDate != null && data.announcementEndDate != null
? [
new Date(data.announcementStartDate),
new Date(data.announcementEndDate),
]
: null;
dateExam.value = data.examDate != null ? new Date(data.examDate) : null;
dateRegister.value =
data.registerStartDate != null && data.registerEndDate != null
? [new Date(data.registerStartDate), new Date(data.registerEndDate)]
: null;
if (data.fee == 0) {
data.paymentStartDate = null;
data.paymentEndDate = null;
}
datePayment.value =
data.paymentStartDate != null && data.paymentEndDate != null
? [new Date(data.paymentStartDate), new Date(data.paymentEndDate)]
: null;
if (data.organizationCodeId != null) {
organizationShortName.value = {
id: data.organizationCodeId,
name: data.organizationCodeName,
};
}
if (data.organizationId != null) {
organizationName.value = {
id: data.organizationId,
name: data.organizationName,
};
}
rowsPosition.value = positionData;
pay.value = data.paymentKrungThai;
rowsPayment.value = bankData;
editor.value = data.detail;
editorCondition.value = data.editorCondition;
editorConfirm.value = data.editorConfirm;
note.value = data.note;
fileDocs.value = data.documents;
fileImgs.value = data.images;
qrCodesFile.value = data.qrCodes;
barCodesFile.value = data.barCodes;
category.value = data.category;
remark.value = data.remark;
companyCode.value = data.companyCode;
refNo1.value = data.refNo1;
reason.value = data.reason;
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
}
/**
* ฟังชั่น filter
* @param val input
* @param update Function #quasar
* @param refData เเยก case
*/
function filterSelector(val: string, update: Function, refData: string) {
switch (refData) {
case "positionLevel1":
update(() => {
optionPosLevel1.value = filterOptionPosLevel1.value.filter(
(v: DataOption2) => v.name.indexOf(val) > -1
);
});
break;
case "positionLevel2":
update(() => {
optionPosLevel2.value = filterOptionPosLevel2.value.filter(
(v: DataOption2) => v.name.indexOf(val) > -1
);
});
break;
case "position1":
update(() => {
optionPosType1.value = filterOptionPosType1.value.filter(
(v: DataOption2) => v.name.indexOf(val) > -1
);
});
break;
case "position2":
update(() => {
optionPosType2.value = filterOptionPosType2.value.filter(
(v: DataOption2) => v.name.indexOf(val) > -1
);
});
break;
default:
break;
}
}
/**
* update ปี
* @param e ปี
*/
async function updateYear(e: number) {
yearly.value = e;
}
/** saveข้อมูล เพิ่ม แก้ไข */
async function checkSave() {
if (myForm.value !== null) {
myForm.value.validate().then(async (success) => {
if (success) {
if (edit.value) {
await editData(id.value);
} else {
await addData();
}
}
});
}
}
/** body สำหรับ save ข้อมูล */
function sendData() {
const positionData: RequestPosition[] = [];
rowsPosition.value.map((r: ResponsePosition) => {
positionData.push({
id: r.id,
positionId: r.position.id,
positionName: r.position.name,
positionLevelId: r.level.id,
positionLevelName: r.level.name,
typeId: r.type.id,
typeName: r.type.name,
code: r.code,
highDegree: r.highDegree == "1" ? true : false,
});
});
if (fee.value == 0) {
datePayment.value = null;
}
const valueData: any = {
announcementDate:
dateAnnounce.value != null ? convertDateToAPI(dateAnnounce.value) : null,
announcementEndDate:
dateAnnouncement.value != null
? convertDateToAPI(dateAnnouncement.value[1])
: null,
announcementStartDate:
dateAnnouncement.value != null
? convertDateToAPI(dateAnnouncement.value[0])
: null,
examDate: dateExam.value != null ? convertDateToAPI(dateExam.value) : null,
bankExam: rowsPayment.value,
checkDisability: checkDisability.value,
announcementExam: announcementExam.value,
checkDocument: checkDocument.value,
detail: editor.value,
editorCondition: editorCondition.value,
editorConfirm: editorConfirm.value,
fee: fee.value,
id: "",
isActive: true,
name: name.value,
note: note.value,
organizationCodeId: organizationShortName.value?.id,
organizationCodeName: organizationShortName.value?.name,
organizationId: organizationName.value?.id,
organizationName: organizationName.value?.name,
paymentEndDate:
datePayment.value != null ? convertDateToAPI(datePayment.value[1]) : null,
paymentKrungThai: pay.value,
paymentStartDate:
datePayment.value != null ? convertDateToAPI(datePayment.value[0]) : null,
positionExam: positionData,
registerEndDate:
dateRegister.value != null
? convertDateToAPI(dateRegister.value[1])
: null,
registerStartDate:
dateRegister.value != null
? convertDateToAPI(dateRegister.value[0])
: null,
round: round.value,
year: yearly.value,
category: category.value,
remark: remark.value,
companyCode: companyCode.value,
refNo1: refNo1.value,
reason: reason.value,
};
return valueData;
}
/** เพิ่มข้อมูล */
async function addData() {
showLoader();
await http
.post(config.API.periodExam, sendData())
.then(async (res) => {
const data = res.data.result;
id.value = data;
await uploadImgData();
await uploadDocData();
await uploadBarCodes();
await uploadQrCodes();
hideLoader();
success($q, "บันทึกรอบคัดเลือกสำเร็จ");
setTimeout(async () => {
await clickBack();
}, 1200);
})
.catch((e) => {
messageError($q, e);
hideLoader();
})
.finally(async () => {});
}
/**
* แก้ไข ข้อมูล
* @param id id จัดการรอบคัดเลือก
*/
async function editData(id: string) {
showLoader();
await http
.put(config.API.periodExamId(id), sendData())
.then(async () => {
await uploadImgData();
await uploadDocData();
await uploadBarCodes();
await uploadQrCodes();
hideLoader();
success($q, "แก้ไขรอบคัดเลือกสำเร็จ");
setTimeout(async () => {
await clickBack();
}, 1200);
})
.catch((e) => {
messageError($q, e);
hideLoader();
})
.finally(() => {});
}
/**
* เก็บไฟล์เป็นอาเรย์
* @param files ไฟล์
*/
async function fileUploadDoc(files: any) {
files.forEach((file: any) => {
fileDocDataUpload.value.push(file);
});
}
/**
* ลบไฟล์จาก array
* @param files ไฟล์
*/
async function fileRemoveDoc(files: any) {
files.forEach((file: any) => {
const index = fileDocDataUpload.value.findIndex(
(x: any) => x.__key == file.__key
);
if (index > -1) {
fileDocDataUpload.value.splice(index, 1);
}
});
}
/** อัปโหลดไฟล์เอกสาร */
async function uploadDocData() {
const formData = new FormData();
if (fileDocDataUpload.value.length > 0) {
fileDocDataUpload.value.forEach((file: any) => {
formData.append("", file);
});
showLoader();
await http
.put(config.API.periodExamDoc(id.value), formData)
.then((res) => {})
.catch((e) => {})
.finally(async () => {
hideLoader();
});
}
}
/** อัปโหลดไฟล์เอกสาร */
async function uploadBarCodes() {
const formData = new FormData();
if (barCodes.value !== null) {
formData.append("", barCodes.value);
showLoader();
await http
.put(config.API.periodExambarcode(id.value), formData)
.then((res) => {
console.log(1);
})
.catch((e) => {})
.finally(async () => {
hideLoader();
});
}
}
/** อัปโหลดไฟล์เอกสาร */
async function uploadQrCodes() {
const formData = new FormData();
if (qrCodes.value !== null) {
formData.append("", qrCodes.value);
showLoader();
await http
.put(config.API.periodExamqrcode(id.value), formData)
.then((res) => {
console.log(2);
})
.catch((e) => {})
.finally(async () => {
hideLoader();
});
}
}
/**
* ฟังชั่นเก็บ รูปเป็น array
* @param files ไฟล์รูป
*/
async function fileUploadImg(files: any) {
files.forEach((file: any) => {
fileImgDataUpload.value.push(file);
});
}
/**
* ลบไฟล์รูปจาก array
* @param files รูป
*/
async function fileRemoveImg(files: any) {
files.forEach((file: any) => {
const index = fileImgDataUpload.value.findIndex(
(x: any) => x.__key == file.__key
);
if (index > -1) {
fileImgDataUpload.value.splice(index, 1);
}
});
}
/** อัปโหลดรูป */
async function uploadImgData() {
if (fileImgDataUpload.value.length > 0) {
const formData = new FormData();
fileImgDataUpload.value.forEach((file: any) => {
formData.append("", file);
});
showLoader();
await http
.put(config.API.periodExamImg(id.value), formData)
.then((res) => {})
.catch((e) => {})
.finally(async () => {
hideLoader();
});
}
}
/**
* ลบไฟล์
* @param docId ไฟล์ id
*/
async function deleteDocData(docId: string) {
const params = {
documentId: docId,
};
showLoader();
await http
.delete(config.API.periodExamDoc(id.value.toString()), {
params,
})
.then((res) => {})
.catch((e) => {})
.finally(async () => {
await fetchData();
});
}
/**
* ดาวห์โหลดไฟล์
* @param path ลิงก์
*/
async function downloadData(path: string) {
window.open(path);
}
/** เพิ่มวิธีการชำระเงิน */
function clickAddPayment() {
myFormPayment.value.validate().then(async (result: boolean) => {
if (result) {
rowsPayment.value.push({
id: "00000000-0000-0000-0000-000000000000",
accountNumber: "",
bankName: "",
accountName: "",
});
}
});
}
/** ลบวิธีการชำระ */
function clickDeletePayment(row: any) {
const index = rowsPayment.value.indexOf(row);
if (index > -1) {
rowsPayment.value.splice(index, 1);
}
}
/** เพิ่มตำแหน่ง */
function clickAddPosition() {
myFormPosition.value.validate().then(async (result: boolean) => {
if (result) {
rowsPosition.value.push({
id: "00000000-0000-0000-0000-000000000000",
position: null,
type: { id: "normol", name: "ทั่วไป" },
code: null,
highDegree: "",
});
}
});
}
/** ลบตำแหน่ง */
function clickDeletePosition(row: any) {
const index = rowsPosition.value.indexOf(row);
if (index > -1) {
rowsPosition.value.splice(index, 1);
}
}
/**
* แปลงช่วงวันที่ถ้า2ค่าเป็นวันเดียวกันจะโชววันเดียวแต่ถ้าไม่เท่ากันจะแสดงเป็นช่วง
* @param val ช่วงวันที่
*/
function dateThaiRange(val: [Date, Date] | null) {
if (val === null) {
return "";
} else if (date2Thai(val[0], true) === date2Thai(val[1], true)) {
return `${date2Thai(val[0], true)}`;
} else {
return `${date2Thai(val[0], true)} - ${date2Thai(val[1], true)}`;
}
}
/** clear วันที่สอบ*/
function clearDateExam() {
dateExam.value = null;
}
/** clear วันที่สมัคร*/
function clearDateRegister() {
dateRegister.value = null;
}
/** clear วันที่ชำระเงิน*/
function clearDatePayment() {
datePayment.value = null;
}
/** clear วันประกาศผลสอบ*/
function clearDateAnnounce() {
dateAnnounce.value = null;
}
const mainDataPosLevel = ref<ResponesePosType[]>([]); //ข้อมูลรายการประเภทตำแหน่ง
const optionPosLevel1 = ref<DataOption2[]>([]); // ตัวเลือกระดับประเภททั่วไป
const filterOptionPosLevel1 = ref<DataOption2[]>([]); //ข้อมูลตัวเลือกระดับประเภททั่วไป
const optionPosLevel2 = ref<DataOption2[]>([]); //ตัวเลือกระดับประเภทวิชาการ
const filterOptionPosLevel2 = ref<DataOption2[]>([]); //ข้อมูลตัวเลือกระดับประเภทวิชาการ
const optionPosType1 = ref<DataOption2[]>([]); //ตัวเลือกตำแหน่งของระดับปฏิบัติงาน
const filterOptionPosType1 = ref<DataOption2[]>([]); //ข้อมูลตัวเลือกตำแหน่งของระดับปฏิบัติงาน
const optionPosType2 = ref<DataOption2[]>([]); //ตัวเลือกตำแหน่งของระดับปฏิบัติการ
const filterOptionPosType2 = ref<DataOption2[]>([]); //ข้อมูลตัวเลือกตำแหน่งของระดับปฏิบัติการ
/** ฟังก์ชันเรียกข้อมูล ประเภทตำแหน่ง*/
async function fetchPositionType() {
http
.get(config.API.orgPosType)
.then((res) => {
mainDataPosLevel.value = res.data.result.filter(
(e: ResponesePosType) => e.posTypeRank <= 2
);
const getDataByRank = (rank: number) => {
const data =
res.data.result.find((e: ResponesePosType) => e.posTypeRank === rank)
?.posLevels || [];
return data
.filter((e: DataPosLevel) => e.posLevelRank === 1)
.map((e: DataPosLevel) => ({
id: e.id.toString(),
name: e.posLevelName.toString(),
level: e.posLevelRank,
}));
};
optionPosLevel1.value = getDataByRank(1);
filterOptionPosLevel1.value = getDataByRank(1);
optionPosLevel2.value = getDataByRank(2);
filterOptionPosLevel2.value = getDataByRank(2);
fetchPosition(1);
fetchPosition(2);
})
.catch((err) => {
messageError($q, err);
});
}
/**
* ฟังก์ชันเรียกข้อมูลตำแหน่ง
* @param level ระดับข้องประเภทตำแหน่ง
*/
function fetchPosition(level: number) {
http
.post(config.API.orgPosTypeSearch, {
posType:
mainDataPosLevel.value?.find(
(e: ResponesePosType) => e.posTypeRank === level
)?.id ?? null,
posLevel:
level === 1 ? optionPosLevel1.value[0].id : optionPosLevel2.value[0].id,
})
.then((res) => {
const option: DataOption2[] = res.data.result.map(
(r: ResponesePosition) => ({
id: r.id.toString(),
name: r.positionName.toString(),
})
);
if (level === 1) {
optionPosType1.value = option;
filterOptionPosType1.value = option;
} else if (level === 2) {
optionPosType2.value = option;
filterOptionPosType2.value = option;
}
})
.catch((err) => {
messageError($q, err);
});
}
/**
* ฟังก์ชันเปลี่ยนประเภทตำแหน่ง
* @param val ค่าประเภทตำแหน่ง 0 = ประเภททั่วไป ,1 = ประเภทวิชาการ
* @param index ตำแหน่งของข้อมูล
*/
function onUpdateHighDegree(val: string, index: string) {
rowsPosition.value[index].position = null;
rowsPosition.value[index].level =
val === "0" ? optionPosLevel1.value[0] : optionPosLevel2.value[0];
}
watch(fee, () => {
if (fee.value <= 0) {
pay.value = "";
remark.value = "";
} else if (fee.value > 0) {
remark.value = `*ค่าธรรมเนียมการสมัครคัดเลือก จำนวน ${
fee.value
} บาท ประกอบไปด้วย ค่าธรรมเนียมสอบ จำนวน ${
fee.value > 30 ? fee.value - 30 : "..."
} บาท และค่าธรรมเนียมธนาคารรวมค่าบริการอินเทอร์เน็ตจำนวน ${
fee.value > 30 ? "30" : "..."
} บาท โดยค่าธรรมเนียมดังกล่าวจะไม่จ่ายคืนให้ไม่ว่ากรณีใดๆ ทั้งสิ้น`;
}
});
pay.value;
watch(
() => ({ datePayment: datePayment.value, pay: pay.value }),
({ datePayment, pay }) => {
if (datePayment) {
reason.value = `โปรดนำแบบฟอร์มการชำระเงินฉบับนี้ พร้อมเงินสดไปยื่นขำระเงินที่เคาน์เตอร์ บมจ.ธนาคารกรุงไทย
ได้ทุกสาขาทั่วประเทศ ตั้งแต่วันที่ ${dateThaiRange(
datePayment
)} ภายในวันเวลาทำการของธนาคาร
หรือผ่านระบบ Internet payment (Krungthai NEXT/เป๋าตัง) ตลอด 24 ชั่วโมง
ตั้งแต่วันที่ ${date2Thai(
datePayment[0]
)} เปิดชำระเงิน เวลา 08.30 น. ${date2Thai(
datePayment[1]
)} ปิดชำระเงินเวลา 22.00 น.
`;
}
if (pay == "payment1" && datePayment == null) {
reason.value = `โปรดนำแบบฟอร์มการชำระเงินฉบับนี้ พร้อมเงินสดไปยื่นขำระเงินที่เคาน์เตอร์ บมจ.ธนาคารกรุงไทย
ได้ทุกสาขาทั่วประเทศ ตั้งแต่วันที่ ... ... ภายในวันเวลาทำการของธนาคาร
หรือผ่านระบบ Internet payment (Krungthai NEXT/เป๋าตัง) ตลอด 24 ชั่วโมง
ตั้งแต่วันที่ ... เปิดชำระเงิน เวลา ... น. ... ปิดชำระเงินเวลา ... น.
`;
}
}
);
onMounted(async () => {
hideLoader();
if (route.params.id != undefined) {
edit.value = true;
id.value = route.params.id.toString();
await fetchData();
} else {
pay.value = "";
edit.value = false;
}
await fetchPositionType();
});
</script>
<template>
<div class="toptitle text-dark col-12 row items-center">
<q-btn
icon="mdi-arrow-left"
unelevated
round
dense
flat
color="primary"
class="q-mr-sm"
@click="clickBack"
/>
{{
checkRoutePermisson
? "รายละเอียด"
: edit
? `แก้ไขรอบ`
: "เพิ่มรอบคัดเลือก"
}}
{{
edit && announcementExam
? `${name} ครั้งที่ ${roundRaw}/${
yearlyRaw == null ? "" : yearlyRaw + 543
}`
: ""
}}
</div>
<q-card flat bordered class="col-12 q-my-sm q-pt-sm">
<q-form ref="myForm">
<q-card-section class="q-pa-md">
<div class="col-xs-12 col-sm-8 items-top q-pb-md">
<q-toggle
v-model="announcementExam"
:false-value="true"
:true-value="false"
color="primary"
label="ประกาศข่าวทั่วไป"
v-if="!edit"
/>
</div>
<div class="col-12 row items-top q-col-gutter-x-sm">
<div class="col-xs-12 col-sm-6 col-sm-5">
<q-input
outlined
v-model="name"
label="ชื่อรอบคัดเลือก/ชื่อประกาศ"
dense
:readonly="checkRoutePermisson"
lazy-rules
:rules="[
(val:string) => !!val || `${'กรุณากรอกชื่อรอบคัดเลือก/ชื่อประกาศ'}`,
]"
></q-input>
</div>
<div class="col-xs-12 col-sm-4 col-md-1" v-if="announcementExam">
<q-input
outlined
v-model="round"
:readonly="checkRoutePermisson"
type="number"
label="รอบการสอบ(ครั้ง)"
dense
lazy-rules
:rules="[(val:number) => val > 0 || `${'กรุณากรอกรอบการสอบให้ถูกต้อง'}`]"
></q-input>
</div>
<div class="col-xs-12 col-sm-4 col-md-1" v-if="announcementExam">
<q-input
outlined
v-model="fee"
:readonly="checkRoutePermisson"
type="number"
label="ค่าธรรมเนียม"
dense
lazy-rules
input-class="text-right"
:rules="[
(val:number) => val >= 0 || `${'กรุณากรอกค่าธรรมเนียมให้ถูกต้อง'}`,
]"
></q-input>
</div>
<div class="col-xs-12 col-sm-4 col-md-1" v-if="announcementExam">
<datepicker
v-model="yearly"
:locale="'th'"
:readonly="checkRoutePermisson"
autoApply
year-picker
:enableTimePicker="false"
@update:modelValue="updateYear"
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
dense
outlined
:readonly="checkRoutePermisson"
:model-value="yearly + 543"
:rules="[(val:string) => !!val || `${'กรุณาเลือกปีงบประมาณ'}`]"
:label="`${'ปีงบประมาณ'}`"
>
</q-input>
</template>
</datepicker>
</div>
<div class="col-xs-12 col-sm-3 col-md-3" v-if="announcementExam">
<datepicker
v-model="dateExam"
:locale="'th'"
autoApply
borderless
:readonly="checkRoutePermisson"
: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
dense
:readonly="checkRoutePermisson"
class="full-width datepicker q-mb-md"
:model-value="dateExam != null ? date2Thai(dateExam) : null"
:label="`${'วันที่สอบ'}`"
clearable
@clear="clearDateExam"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
style="color: var(--q-primary)"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<div class="col-xs-12 col-sm-3 col-md-3">
<datepicker
v-model="dateAnnouncement"
:locale="'th'"
:readonly="checkRoutePermisson"
autoApply
borderless
range
: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
dense
:readonly="checkRoutePermisson"
class="full-width datepicker q-mb-md"
:model-value="dateThaiRange(dateAnnouncement)"
:label="`${'วันที่ประกาศ'}`"
: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-xs-12 col-sm-3 col-md-3" v-if="announcementExam">
<datepicker
v-model="dateRegister"
:locale="'th'"
autoApply
clearValue
:readonly="checkRoutePermisson"
borderless
range
: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
dense
:readonly="checkRoutePermisson"
class="full-width datepicker q-mb-md"
:model-value="dateThaiRange(dateRegister)"
:label="`${'วันที่สมัคร'}`"
clearable
@clear="clearDateRegister"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
style="color: var(--q-primary)"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<div
class="col-xs-12 col-sm-3 col-md-3"
v-if="announcementExam && fee != 0"
>
<datepicker
v-model="datePayment"
:readonly="checkRoutePermisson"
:locale="'th'"
autoApply
borderless
range
:enableTimePicker="false"
week-start="0"
>
<template #year="{ year }">
{{ year + 543 }}
</template>
<template #year-overlay-value="{ value }">
{{ parseInt(value + 543) }}
</template>
<template #trigger>
<q-input
:readonly="checkRoutePermisson"
outlined
dense
class="full-width datepicker q-mb-md"
:model-value="dateThaiRange(datePayment)"
:label="`${'วันที่ชำระเงิน'}`"
clearable
@clear="clearDatePayment"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
style="color: var(--q-primary)"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<div class="col-xs-12 col-sm-3 col-md-3" v-if="announcementExam">
<datepicker
v-model="dateAnnounce"
:locale="'th'"
autoApply
:readonly="checkRoutePermisson"
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="checkRoutePermisson"
dense
class="full-width datepicker q-mb-md"
:model-value="
dateAnnounce != null ? date2Thai(dateAnnounce) : null
"
:label="`${'วันประกาศผลสอบ'}`"
clearable
@clear="clearDateAnnounce"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
style="color: var(--q-primary)"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<div class="col-12" v-if="announcementExam">
<div class="col-12 q-mb-sm">
<q-separator size="5px" color="grey-2" />
</div>
<q-form ref="myFormPosition">
<ProfileTable
:rows="rowsPosition"
:columns="columnsPosition"
:filter="filterPosition"
:visible-columns="visibleColumnsPosition"
v-model:inputfilter="filterPosition"
v-model:inputvisible="visibleColumnsPosition"
:add="clickAddPosition"
name="ตำแหน่ง"
icon=""
:statusEdit="false"
:headerShow="false"
:icon-left="true"
>
<template #columns="props">
<q-tr :props="props">
<q-td auto-width>
<q-btn
color="red"
flat
v-if="!checkRoutePermisson"
dense
round
size="14px"
icon="mdi-delete"
@click="clickDeletePosition(props.row)"
/>
</q-td>
<q-td key="code" :props="props">
<q-input
outlined
dense
:readonly="checkRoutePermisson"
lazy-rules
v-model="props.row.code"
:rules="[
(val:string) => !!val || `${'กรุณากรอกรหัสประจำตำแหน่งที่สอบ'}`,
(val:any) =>
val.length >= 3 ||
`${'กรุณากรอกรหัสประจำตำแหน่งที่สอบ'}`,
]"
:label="`${'รหัสประจำตำแหน่งที่สอบ'}`"
hide-bottom-space
mask="###"
/>
</q-td>
<q-td key="highDegree" :props="props">
<q-radio
v-model="props.row.highDegree"
label="ประเภททั่วไป"
color="teal"
:disable="checkRoutePermisson"
val="0"
@update:model-value="
onUpdateHighDegree(
props.row.highDegree,
props.rowIndex
)
"
/>
<q-radio
v-model="props.row.highDegree"
label="ประเภทวิชาการ"
color="teal"
:disable="checkRoutePermisson"
val="1"
@update:model-value="
onUpdateHighDegree(
props.row.highDegree,
props.rowIndex
)
"
/>
</q-td>
<q-td key="level" :props="props">
<selector
:disable="props.row.highDegree === ''"
class=""
outlined
use-input
v-model="props.row.level"
:readonly="checkRoutePermisson"
:options="
props.row.highDegree === '0'
? optionPosLevel1
: optionPosLevel2
"
option-value="id"
option-label="name"
input-debounce="0"
dense
hide-bottom-space
lazy-rules
:rules="[(val:any) => !!val || `${'กรุณาเลือกระดับ'}`]"
@filter="(inputValue:string,
doneFn:Function) => filterSelector(inputValue, doneFn, props.row.highDegree === '0' ? 'positionLevel1':'positionLevel2'
) "
>
<template v-slot:option="scope">
<q-item v-bind="scope.itemProps">
<q-item-section>
<q-item-label>{{ scope.opt.name }}</q-item-label>
</q-item-section>
</q-item>
</template>
</selector>
</q-td>
<q-td key="position" :props="props">
<selector
:disable="props.row.highDegree === ''"
class=""
outlined
:readonly="checkRoutePermisson"
use-input
v-model="props.row.position"
:options="
props.row.highDegree === '0'
? optionPosType1
: optionPosType2
"
option-value="id"
option-label="name"
input-debounce="0"
dense
hide-bottom-space
lazy-rules
:rules="[(val:any) => !!val || `${'กรุณาเลือกตำแหน่ง'}`]"
@filter="(inputValue:string,
doneFn:Function) => filterSelector(inputValue, doneFn, props.row.highDegree === '0' ? 'position1' :'position2'
) "
>
<template v-slot:option="scope">
<q-item v-bind="scope.itemProps">
<q-item-section>
<q-item-label>{{ scope.opt.name }}</q-item-label>
</q-item-section>
</q-item>
</template>
</selector>
</q-td>
<q-td key="type" :props="props">
<selector
class=""
outlined
v-model="props.row.type"
:options="examTypeOptions"
:readonly="checkRoutePermisson"
option-value="id"
option-label="name"
dense
hide-bottom-space
lazy-rules
:rules="[(val:any) => !!val || `${'กรุณาเลือกประเภทแบบฟอร์ม'}`]"
></selector>
</q-td>
</q-tr>
</template>
</ProfileTable>
</q-form>
</div>
<div class="col-12" v-if="announcementExam && fee != 0">
<q-separator size="5px" color="grey-2" class="q-mt-lg" />
</div>
<div class="col-12 q-mt-lg" v-if="announcementExam && fee != 0">
<div class="text-bold text-subtitle2 q-pb-md">
เลือกวิธีการชำระเงิน
</div>
<div class="row col-12 q-gutter-y-md q-mb-md">
<q-list dense bordered class="col-12 rounded-borders">
<q-item tag="label" v-ripple class="q-pa-md">
<q-radio
v-model="pay"
val="payment1"
color="blue"
class="q-mr-md"
:disable="fee <= 0 || checkRoutePermisson"
/>
<q-item-section avatar>
<q-avatar size="28px">
<q-img src="@/assets/krungthai.png" class="col-12" />
</q-avatar>
</q-item-section>
<q-item-section>
<q-item-label class="text-weight-medium text-subtitle1"
>ชำระเงินค่าสมัครสอบผ่านธนาคารกรุงไทย</q-item-label
>
</q-item-section>
</q-item>
<q-slide-transition :duration="100">
<div v-show="pay == 'payment1'" class="q-py-sm bg-grey-1">
<div class="row q-col-gutter-sm">
<div class="col-12">
<q-separator />
</div>
<div
class="col-12 text-weight-medium text-subtitle1 q-px-md"
>
รายละเอียดการชำระ
</div>
<div class="col-12">
<q-separator />
</div>
<div class="col-12">
<div class="row q-col-gutter-sm q-pa-sm">
<div class="col-12">
<q-input
label="ข้อความส่วนหัว"
outlined
dense
type="textarea"
rows="2"
:readonly="checkRoutePermisson"
bg-color="white"
v-model="remark"
:rules="[(val:string) => !!val || `${'กรุณากรอกข้อความส่วนหัว'}`]"
hide-bottom-space
>
</q-input>
</div>
<div class="col-6">
<q-input
label="Company Code"
outlined
dense
bg-color="white"
:readonly="checkRoutePermisson"
v-model="companyCode"
:rules="[(val:string) => !!val || `${'กรุณากรอก Company Code'}`]"
hide-bottom-space
>
</q-input>
</div>
<div class="col-6">
<q-input
label="refNo1."
outlined
dense
bg-color="white"
:readonly="checkRoutePermisson"
v-model="refNo1"
:rules="[(val:string) => !!val || `${'กรุณากรอก refNo1.'}`]"
hide-bottom-space
>
</q-input>
</div>
<div class="col-12">
<q-input
label="หมายเหตุ"
outlined
dense
:readonly="checkRoutePermisson"
bg-color="white"
v-model="reason"
type="textarea"
rows="4"
>
</q-input>
</div>
<div class="row col-12 items-top q-col-gutter-x-sm">
<div class="col-xs-12 col-sm-6">
<div class="text-bold text-subtitle2 q-pb-sm">
อัปโหลดบาร์โค้ด
</div>
<div class="row justify-center row col-12">
<q-uploader
v-model="qrCodes"
color="gray"
type="file"
flat
:readonly="checkRoutePermisson"
ref="uploader"
class="full-width"
text-color="dark"
:max-size="10000000"
accept=".jpg,.png"
bordered
label="[ไฟล์ jpg,png ขนาดไม่เกิน 10MB]"
@removed="qrCodes = null"
@added="(v:any) => (qrCodes = v[0])"
>
<template v-slot:header="scope">
<div
class="row no-wrap items-center q-pa-sm q-gutter-xs text-white"
>
<q-btn
v-if="
scope.queuedFiles.length > 0 &&
!checkRoutePermisson
"
icon="clear_all"
@click="scope.removeQueuedFiles"
round
dense
flat
>
<q-tooltip>ลบทั้งหมด</q-tooltip>
</q-btn>
<q-btn
v-if="
scope.uploadedFiles.length > 0 &&
!checkRoutePermisson
"
icon="done_all"
@click="scope.removeUploadedFiles"
round
dense
flat
>
<q-tooltip>ลบไฟล์ที่อัปโหลด</q-tooltip>
</q-btn>
<q-spinner
v-if="scope.isUploading"
class="q-uploader__spinner"
/>
<div class="col">
<div class="q-uploader__title">
{{
"[ไฟล์ jpg,png ขนาดไม่เกิน 10MB]"
}}
</div>
<div class="q-uploader__subtitle">
{{ scope.uploadSizeLabel }}
/
{{ scope.uploadProgressLabel }}
</div>
</div>
<q-btn
v-if="
scope.canAddFiles &&
!checkRoutePermisson
"
type="a"
icon="add_box"
@click="scope.pickFiles"
round
dense
flat
>
<q-uploader-add-trigger />
<q-tooltip>เลือกไฟล์</q-tooltip>
</q-btn>
<q-btn
v-if="
scope.isUploading &&
!checkRoutePermisson
"
icon="clear"
@click="scope.abort"
round
dense
flat
>
<q-tooltip>ยกเลิกการอัปโหลด</q-tooltip>
</q-btn>
</div>
</template>
</q-uploader>
</div>
<q-card
bordered
flat
class="full-width q-my-md"
v-if="qrCodesFile.length != 0"
>
<q-list separator>
<q-item
v-for="file in qrCodesFile"
:key="file.id"
class="q-my-xs"
>
<q-item-section>
<q-item-label class="full-width ellipsis">
{{ file.fileName }}
</q-item-label>
<q-item-label caption>
สถานะ: {{ file.fileType }} /
{{ file.fileSize }}
</q-item-label>
</q-item-section>
<q-item-section top side>
<div class="q-gutter-sm">
<q-btn
size="12px"
flat
dense
round
color="blue"
icon="mdi-download-outline"
@click="downloadData(file.detail)"
>
<q-tooltip>ดาวน์โหลด</q-tooltip>
</q-btn>
<q-btn
size="12px"
flat
dense
round
color="red"
icon="mdi-delete-outline"
v-if="edit && !checkRoutePermisson"
@click="deleteDocData(file.id)"
>
<q-tooltip>ลบไฟล์</q-tooltip>
</q-btn>
</div>
</q-item-section>
</q-item>
</q-list>
</q-card>
</div>
<div class="col-xs-12 col-sm-6">
<div class="text-bold text-subtitle2 q-pb-sm">
อัปโหลดคิวอาร์โค้ด
</div>
<div class="row justify-center row col-12">
<q-uploader
color="gray"
type="file"
flat
ref="uploader"
class="full-width"
:readonly="checkRoutePermisson"
text-color="dark"
:max-size="10000000"
accept=".jpg,.png"
bordered
label="[ไฟล์ jpg,png ขนาดไม่เกิน 10MB]"
@removed="barCodes = null"
@added="(v:any) => (barCodes = v[0])"
>
<template v-slot:header="scope">
<div
class="row no-wrap items-center q-pa-sm q-gutter-xs text-white"
>
<q-btn
v-if="
scope.queuedFiles.length > 0 &&
!checkRoutePermisson
"
icon="clear_all"
@click="scope.removeQueuedFiles"
round
dense
flat
>
<q-tooltip>ลบทั้งหมด</q-tooltip>
</q-btn>
<q-btn
v-if="
scope.uploadedFiles.length > 0 &&
!checkRoutePermisson
"
icon="done_all"
@click="scope.removeUploadedFiles"
round
dense
flat
>
<q-tooltip>ลบไฟล์ที่อัปโหลด</q-tooltip>
</q-btn>
<q-spinner
v-if="scope.isUploading"
class="q-uploader__spinner"
/>
<div class="col">
<div class="q-uploader__title">
{{
"[ไฟล์ jpg,png ขนาดไม่เกิน 10MB]"
}}
</div>
<div class="q-uploader__subtitle">
{{ scope.uploadSizeLabel }}
/
{{ scope.uploadProgressLabel }}
</div>
</div>
<q-btn
v-if="
scope.canAddFiles &&
!checkRoutePermisson
"
type="a"
icon="add_box"
@click="scope.pickFiles"
round
dense
flat
>
<q-uploader-add-trigger />
<q-tooltip>เลือกไฟล์</q-tooltip>
</q-btn>
<q-btn
v-if="
scope.isUploading &&
!checkRoutePermisson
"
icon="clear"
@click="scope.abort"
round
dense
flat
>
<q-tooltip>ยกเลิกการอัปโหลด</q-tooltip>
</q-btn>
</div>
</template>
</q-uploader>
</div>
<q-card
bordered
flat
class="full-width q-my-md"
v-if="barCodesFile.length != 0"
>
<q-list separator>
<q-item
v-for="file in barCodesFile"
:key="file.id"
class="q-my-xs"
>
<q-item-section>
<q-item-label class="full-width ellipsis">
{{ file.fileName }}
</q-item-label>
<q-item-label caption>
สถานะ: {{ file.fileType }} /
{{ file.fileSize }}
</q-item-label>
</q-item-section>
<q-item-section top side>
<div class="q-gutter-sm">
<q-btn
size="12px"
flat
dense
round
color="blue"
icon="mdi-download-outline"
@click="downloadData(file.detail)"
>
<q-tooltip>ดาวน์โหลด</q-tooltip>
</q-btn>
<q-btn
size="12px"
flat
dense
round
color="red"
icon="mdi-delete-outline"
v-if="edit && !checkRoutePermisson"
@click="deleteDocData(file.id)"
>
<q-tooltip>ลบไฟล์</q-tooltip>
</q-btn>
</div>
</q-item-section>
</q-item>
</q-list>
</q-card>
</div>
</div>
</div>
</div>
</div>
</div>
</q-slide-transition>
</q-list>
<q-list dense bordered class="col-12 rounded-borders">
<q-item tag="label" v-ripple class="q-py-lg">
<q-radio
v-model="pay"
val="payment2"
color="blue"
class="q-mr-md"
:disable="fee <= 0 || checkRoutePermisson"
/>
<q-item-section avatar>
<q-icon name="mdi-cash" color="positive" size="33px" />
</q-item-section>
<q-item-section>
<q-item-label class="text-weight-medium text-subtitle1"
>ชำระเงินค่าสมัครสอบผ่านสำนัก/หน่วยงาน</q-item-label
>
</q-item-section>
</q-item>
<q-slide-transition :duration="100">
<div v-show="pay == 'payment2'" class="q-pa-sm bg-grey-1">
<q-form ref="myFormPayment">
<ProfileTable
:rows="rowsPayment"
:columns="columnsPayment"
:filter="filterPayment"
:visible-columns="visibleColumnsPayment"
v-model:inputfilter="filterPayment"
v-model:inputvisible="visibleColumnsPayment"
:add="clickAddPayment"
name="วิธีการชำระ"
icon=""
:statusEdit="false"
:headerShow="false"
>
<template #columns="props">
<q-tr :props="props">
<q-td key="accountNumber" :props="props">
<q-input
class=""
outlined
hide-bottom-space
:readonly="checkRoutePermisson"
v-model="props.row.accountNumber"
dense
lazy-rules
mask="###-#-#####-#"
:rules="[
(val:any) =>
(val && val.length > 0) ||
'กรุณากรอกข้อมูลให้ครบ',
]"
></q-input>
</q-td>
<q-td key="bankName" :props="props">
<q-input
class=""
outlined
hide-bottom-space
:readonly="checkRoutePermisson"
v-model="props.row.bankName"
dense
lazy-rules
:rules="[
(val:any) =>
(val && val.length > 0) ||
'กรุณากรอกข้อมูลให้ครบ',
]"
></q-input>
</q-td>
<q-td key="accountName" :props="props">
<q-input
class=""
outlined
:readonly="checkRoutePermisson"
hide-bottom-space
v-model="props.row.accountName"
dense
lazy-rules
:rules="[
(val:any) =>
(val && val.length > 0) ||
'กรุณากรอกข้อมูลให้ครบ',
]"
></q-input>
</q-td>
<q-td auto-width>
<q-btn
v-if="!checkRoutePermisson"
color="red"
flat
dense
round
size="14px"
icon="mdi-delete"
@click="clickDeletePayment(props.row)"
/>
</q-td>
</q-tr>
</template>
</ProfileTable>
</q-form>
</div>
</q-slide-transition>
</q-list>
</div>
</div>
<div class="col-12" v-if="announcementExam">
<q-separator size="5px" color="grey-2" class="q-mt-md q-mb-lg" />
</div>
<div class="row col-12 items-top q-col-gutter-x-sm">
<div class="col-xs-12 col-sm-6">
<div class="text-bold text-subtitle2 q-pb-sm">รูปภาพประกอบ</div>
<div class="row justify-center row col-12">
<q-uploader
color="gray"
type="file"
flat
:readonly="checkRoutePermisson"
ref="uploader"
class="full-width"
text-color="dark"
:max-size="10000000"
accept=".jpg,.png,.pdf,.csv,.doc,.docx"
bordered
label="[ไฟล์ jpg,png,pdf,csv,doc,docx ขนาดไม่เกิน 10MB]"
multiple
@added="fileUploadImg"
@removed="fileRemoveImg"
>
<template v-slot:header="scope">
<div
class="row no-wrap items-center q-pa-sm q-gutter-xs text-white"
>
<q-btn
v-if="
scope.queuedFiles.length > 0 && !checkRoutePermisson
"
icon="clear_all"
@click="scope.removeQueuedFiles"
round
dense
flat
>
<q-tooltip>ลบทั้งหมด</q-tooltip>
</q-btn>
<q-btn
v-if="
scope.uploadedFiles.length > 0 && !checkRoutePermisson
"
icon="done_all"
@click="scope.removeUploadedFiles"
round
dense
flat
>
<q-tooltip>ลบไฟล์ที่อัปโหลด</q-tooltip>
</q-btn>
<q-spinner
v-if="scope.isUploading"
class="q-uploader__spinner"
/>
<div class="col">
<div class="q-uploader__title">
{{
"[ไฟล์ jpg,png,pdf,csv,doc,docx ขนาดไม่เกิน 10MB]"
}}
</div>
<div class="q-uploader__subtitle">
{{ scope.uploadSizeLabel }}
/
{{ scope.uploadProgressLabel }}
</div>
</div>
<q-btn
v-if="scope.canAddFiles && !checkRoutePermisson"
type="a"
icon="add_box"
@click="scope.pickFiles"
round
dense
flat
>
<q-uploader-add-trigger />
<q-tooltip>เลือกไฟล์</q-tooltip>
</q-btn>
<q-btn
v-if="scope.isUploading && !checkRoutePermisson"
icon="clear"
@click="scope.abort"
round
dense
flat
>
<q-tooltip>ยกเลิกการอัปโหลด</q-tooltip>
</q-btn>
</div>
</template>
</q-uploader>
</div>
<q-card
bordered
flat
class="full-width q-my-md"
v-if="fileImgs.length != 0"
>
<q-list separator>
<q-item
v-for="file in fileImgs"
:key="file.id"
class="q-my-xs"
>
<q-item-section>
<q-item-label class="full-width ellipsis">
{{ file.fileName }}
</q-item-label>
<q-item-label caption>
สถานะ: {{ file.fileType }} /
{{ file.fileSize }}
</q-item-label>
</q-item-section>
<q-item-section top side>
<div class="q-gutter-sm">
<q-btn
size="12px"
flat
dense
round
color="blue"
icon="mdi-download-outline"
@click="downloadData(file.detail)"
>
<q-tooltip>ดาวน์โหลด</q-tooltip>
</q-btn>
<q-btn
size="12px"
flat
dense
round
color="red"
icon="mdi-delete-outline"
v-if="edit && !checkRoutePermisson"
@click="deleteDocData(file.id)"
>
<q-tooltip>ลบไฟล์</q-tooltip>
</q-btn>
</div>
</q-item-section>
</q-item>
</q-list>
</q-card>
</div>
<div class="col-xs-12 col-sm-6">
<div class="text-bold text-subtitle2 q-pb-sm">เอกสารประกอบ</div>
<div class="row justify-center row col-12">
<q-uploader
color="gray"
type="file"
flat
ref="uploader"
class="full-width"
:readonly="checkRoutePermisson"
text-color="dark"
:max-size="10000000"
accept=".jpg,.png,.pdf,.csv,.doc,.docx"
bordered
label="[ไฟล์ jpg,png,pdf,csv,doc,docx ขนาดไม่เกิน 10MB]"
multiple
@added="fileUploadDoc"
@removed="fileRemoveDoc"
>
<template v-slot:header="scope">
<div
class="row no-wrap items-center q-pa-sm q-gutter-xs text-white"
>
<q-btn
v-if="
scope.queuedFiles.length > 0 && !checkRoutePermisson
"
icon="clear_all"
@click="scope.removeQueuedFiles"
round
dense
flat
>
<q-tooltip>ลบทั้งหมด</q-tooltip>
</q-btn>
<q-btn
v-if="
scope.uploadedFiles.length > 0 && !checkRoutePermisson
"
icon="done_all"
@click="scope.removeUploadedFiles"
round
dense
flat
>
<q-tooltip>ลบไฟล์ที่อัปโหลด</q-tooltip>
</q-btn>
<q-spinner
v-if="scope.isUploading"
class="q-uploader__spinner"
/>
<div class="col">
<div class="q-uploader__title">
{{
"[ไฟล์ jpg,png,pdf,csv,doc,docx ขนาดไม่เกิน 10MB]"
}}
</div>
<div class="q-uploader__subtitle">
{{ scope.uploadSizeLabel }}
/
{{ scope.uploadProgressLabel }}
</div>
</div>
<q-btn
v-if="scope.canAddFiles && !checkRoutePermisson"
type="a"
icon="add_box"
@click="scope.pickFiles"
round
dense
flat
>
<q-uploader-add-trigger />
<q-tooltip>เลือกไฟล์</q-tooltip>
</q-btn>
<q-btn
v-if="scope.isUploading && !checkRoutePermisson"
icon="clear"
@click="scope.abort"
round
dense
flat
>
<q-tooltip>ยกเลิกการอัปโหลด</q-tooltip>
</q-btn>
</div>
</template>
</q-uploader>
</div>
<q-card
bordered
flat
class="full-width q-my-md"
v-if="fileDocs.length != 0"
>
<q-list separator>
<q-item
v-for="file in fileDocs"
:key="file.id"
class="q-my-xs"
>
<q-item-section>
<q-item-label class="full-width ellipsis">
{{ file.fileName }}
</q-item-label>
<q-item-label caption>
สถานะ: {{ file.fileType }} /
{{ file.fileSize }}
</q-item-label>
</q-item-section>
<q-item-section top side>
<div class="q-gutter-sm">
<q-btn
size="12px"
flat
dense
round
color="blue"
icon="mdi-download-outline"
@click="downloadData(file.detail)"
>
<q-tooltip>ดาวน์โหลด</q-tooltip>
</q-btn>
<q-btn
size="12px"
flat
dense
round
color="red"
icon="mdi-delete-outline"
v-if="edit && !checkRoutePermisson"
@click="deleteDocData(file.id)"
>
<q-tooltip>ลบไฟล์</q-tooltip>
</q-btn>
</div>
</q-item-section>
</q-item>
</q-list>
</q-card>
</div>
</div>
<div class="col-12">
<q-separator size="5px" color="grey-2" class="q-my-lg" />
</div>
<div class="col-12">
<div class="text-bold text-subtitle2 q-pb-sm">รายละเอียด</div>
<q-editor
v-model="editor"
:dense="$q.screen.lt.md"
toolbar-text-color="blue-grey-10"
toolbar-bg="blue-grey-2"
:readonly="checkRoutePermisson"
toolbar-toggle-color="blue-grey-8"
class="editor"
:toolbar="[
['left', 'center', 'right', 'justify'],
[
'bold',
'italic',
'strike',
'underline',
'subscript',
'superscript',
],
['token', 'hr', 'link', 'custom_btn'],
['print', 'fullscreen'],
[
{
label: $q.lang.editor.formatting,
icon: $q.iconSet.editor.formatting,
list: 'no-icons',
options: ['p', 'h1', 'h2', 'h3'],
},
{
label: $q.lang.editor.defaultFont,
icon: $q.iconSet.editor.font,
fixedIcon: true,
list: 'no-icons',
options: [
'default_font',
'arial',
'arial_black',
'comic_sans',
'courier_new',
'impact',
'lucida_grande',
'times_new_roman',
'verdana',
],
},
'removeFormat',
],
['undo', 'redo'],
['viewsource'],
]"
:fonts="{
arial: 'Arial',
arial_black: 'Arial Black',
comic_sans: 'Comic Sans MS',
courier_new: 'Courier New',
impact: 'Impact',
lucida_grande: 'Lucida Grande',
times_new_roman: 'Times New Roman',
verdana: 'Verdana',
}"
/>
</div>
<div class="col-12 q-mt-md">
<q-input
outlined
:readonly="checkRoutePermisson"
v-model="note"
label="หมายเหตุ"
dense
lazy-rules
type="textarea"
/>
</div>
<div class="col-12" v-if="announcementExam">
<q-separator size="5px" color="grey-2" class="q-my-lg" />
</div>
<div class="col-12" v-if="announcementExam">
<div class="text-bold text-subtitle2 q-pb-sm">
ข้อกำหนดและเงื่อนไข
</div>
<q-editor
v-model="editorCondition"
:dense="$q.screen.lt.md"
toolbar-text-color="blue-grey-10"
toolbar-bg="blue-grey-2"
:readonly="checkRoutePermisson"
toolbar-toggle-color="blue-grey-8"
class="editor"
:toolbar="[
['left', 'center', 'right', 'justify'],
[
'bold',
'italic',
'strike',
'underline',
'subscript',
'superscript',
],
['token', 'hr', 'link', 'custom_btn'],
['print', 'fullscreen'],
[
{
label: $q.lang.editor.formatting,
icon: $q.iconSet.editor.formatting,
list: 'no-icons',
options: ['p', 'h1', 'h2', 'h3'],
},
{
label: $q.lang.editor.defaultFont,
icon: $q.iconSet.editor.font,
fixedIcon: true,
list: 'no-icons',
options: [
'default_font',
'arial',
'arial_black',
'comic_sans',
'courier_new',
'impact',
'lucida_grande',
'times_new_roman',
'verdana',
],
},
'removeFormat',
],
['undo', 'redo'],
['viewsource'],
]"
:fonts="{
arial: 'Arial',
arial_black: 'Arial Black',
comic_sans: 'Comic Sans MS',
courier_new: 'Courier New',
impact: 'Impact',
lucida_grande: 'Lucida Grande',
times_new_roman: 'Times New Roman',
verdana: 'Verdana',
}"
/>
</div>
<div class="col-12" v-if="announcementExam">
<q-separator size="5px" color="grey-2" class="q-my-lg" />
</div>
<div class="col-12" v-if="announcementExam">
<div class="text-bold text-subtitle2 q-pb-sm">คำรับรอง</div>
<q-editor
v-model="editorConfirm"
:dense="$q.screen.lt.md"
toolbar-text-color="blue-grey-10"
:readonly="checkRoutePermisson"
toolbar-bg="blue-grey-2"
toolbar-toggle-color="blue-grey-8"
class="editor"
:toolbar="[
['left', 'center', 'right', 'justify'],
[
'bold',
'italic',
'strike',
'underline',
'subscript',
'superscript',
],
['token', 'hr', 'link', 'custom_btn'],
['print', 'fullscreen'],
[
{
label: $q.lang.editor.formatting,
icon: $q.iconSet.editor.formatting,
list: 'no-icons',
options: ['p', 'h1', 'h2', 'h3'],
},
{
label: $q.lang.editor.defaultFont,
icon: $q.iconSet.editor.font,
fixedIcon: true,
list: 'no-icons',
options: [
'default_font',
'arial',
'arial_black',
'comic_sans',
'courier_new',
'impact',
'lucida_grande',
'times_new_roman',
'verdana',
],
},
'removeFormat',
],
['undo', 'redo'],
['viewsource'],
]"
:fonts="{
arial: 'Arial',
arial_black: 'Arial Black',
comic_sans: 'Comic Sans MS',
courier_new: 'Courier New',
impact: 'Impact',
lucida_grande: 'Lucida Grande',
times_new_roman: 'Times New Roman',
verdana: 'Verdana',
}"
/>
</div>
</div>
</q-card-section>
<q-separator v-if="!checkRoutePermisson" />
<q-card-actions class="text-primary q-py-sm">
<q-space />
<q-btn
v-if="!checkRoutePermisson"
flat
round
color="public"
@click="checkSave"
icon="mdi-content-save-outline"
>
<q-tooltip>{{ edit ? "แก้ไขข้อมูล" : "บันทึกข้อมูล" }}</q-tooltip>
</q-btn>
</q-card-actions>
</q-form>
</q-card>
</template>
<style></style>