Merge branch 'develop'

* develop: (142 commits)
  แก้คำ
  report evaluate
  fix orgSub
  report evaluate
  ปรับ width Dialog
  แก้ไขหน้าฟอร์มแบบร่างโครงสร้างอัตรากำลัง
  fix load
  รายงาน
  fix รายชื่อผู้สอบ ออกคำสั่ง
  fix loading
  fix
  แก้โหลดไฟล์/วินัยเเก้ เพิ่มฟิล dna
  report placement
  fix bug
  fix report orgTreeDnaId => nodeId
  fix Snap Display
  fix report placement
  fix bug filter รายการสอบแข่งขัน/คัดเลือก
  fix
  layout ทดลองปฏิบัติหน้าที่ราชการ
  ...
This commit is contained in:
Warunee Tamkoo 2025-02-11 13:47:25 +07:00
commit 7369708c25
198 changed files with 11754 additions and 1241 deletions

View file

@ -6,4 +6,14 @@ VITE_API_REPORT_URL=VITE_API_REPORT_URL
VITE_MANUAL_URL=VITE_MANUAL_URL VITE_MANUAL_URL=VITE_MANUAL_URL
VITE_URL_SSO=VITE_URL_SSO VITE_URL_SSO=VITE_URL_SSO
VITE_API_URI_CONFIG=VITE_API_URI_CONFIG VITE_API_URI_CONFIG=VITE_API_URI_CONFIG
VITE_API_URI_REPORT_CONFIG=VITE_API_URI_REPORT_CONFIG VITE_API_URI_REPORT_CONFIG=VITE_API_URI_REPORT_CONFIG
VITE_DASHBOARD_PANEL=VITE_DASHBOARD_PANEL
VITE_DASHBOARDID_ORG=VITE_DASHBOARDID_ORG
VITE_DASHBOARDID_REGISTRY=VITE_DASHBOARDID_REGISTRY
VITE_DASHBOARDID_LEAVE=VITE_DASHBOARDID_LEAVE
VITE_DASHBOARDID_PLACEMENT=VITE_DASHBOARDID_PLACEMENT
VITE_DASHBOARDID_RETIRE=VITE_DASHBOARDID_RETIRE
VITE_DASHBOARDID_DISCIPLINE=VITE_DASHBOARDID_DISCIPLINE
VITE_DASHBOARDID_DEVELOP=VITE_DASHBOARDID_DEVELOP
VITE_DASHBOARDID_SALARY=VITE_DASHBOARDID_SALARY
VITE_DASHBOARDID_KPI=VITE_DASHBOARDID_KPI

View file

@ -17,6 +17,17 @@ do
sed -i 's|VITE_URL_SSO|'${VITE_URL_SSO}'|g' $file sed -i 's|VITE_URL_SSO|'${VITE_URL_SSO}'|g' $file
sed -i 's|VITE_API_URI_CONFIG|'${VITE_API_URI_CONFIG}'|g' $file sed -i 's|VITE_API_URI_CONFIG|'${VITE_API_URI_CONFIG}'|g' $file
sed -i 's|VITE_API_URI_REPORT_CONFIG|'${VITE_API_URI_REPORT_CONFIG}'|g' $file sed -i 's|VITE_API_URI_REPORT_CONFIG|'${VITE_API_URI_REPORT_CONFIG}'|g' $file
sed -i 's|VITE_DASHBOARD_PANEL|'${VITE_DASHBOARD_PANEL}'|g' $file
sed -i 's|VITE_DASHBOARDID_ORG|'${VITE_DASHBOARDID_ORG}'|g' $file
sed -i 's|VITE_DASHBOARDID_REGISTRY|'${VITE_DASHBOARDID_REGISTRY}'|g' $file
sed -i 's|VITE_DASHBOARDID_LEAVE|'${VITE_DASHBOARDID_LEAVE}'|g' $file
sed -i 's|VITE_DASHBOARDID_PLACEMENT|'${VITE_DASHBOARDID_PLACEMENT}'|g' $file
sed -i 's|VITE_DASHBOARDID_RETIRE|'${VITE_DASHBOARDID_RETIRE}'|g' $file
sed -i 's|VITE_DASHBOARDID_DISCIPLINE|'${VITE_DASHBOARDID_DISCIPLINE}'|g' $file
sed -i 's|VITE_DASHBOARDID_DEVELOP|'${VITE_DASHBOARDID_DEVELOP}'|g' $file
sed -i 's|VITE_DASHBOARDID_SALARY|'${VITE_DASHBOARDID_SALARY}'|g' $file
sed -i 's|VITE_DASHBOARDID_KPI|'${VITE_DASHBOARDID_KPI}'|g' $file
done done

View file

@ -97,4 +97,10 @@ export default {
//รายงาน //รายงาน
probationReport: `${report}`, probationReport: `${report}`,
probationSurvey: `${probation}/survey/admin`,
//ราชชื่อเลือกผู้มีอำนาจออกคำสั่ง
probationCommanderDirector : `${orgProfile}/profile/commander-director-position`,
}; };

View file

@ -105,4 +105,6 @@ export default {
// สกจ. ตีกลับให้หัวหน้าเขต // สกจ. ตีกลับให้หัวหน้าเขต
rejectRequest: (id: string, ocId: string) => rejectRequest: (id: string, ocId: string) =>
`${insignia}/request/head/reject/${id}/${ocId}`, `${insignia}/request/head/reject/${id}/${ocId}`,
reportInsigniaNew: `${insignia}/report`,
}; };

View file

@ -45,5 +45,7 @@ export default {
leaveReportTimeLate: (type: string) => `${leaveReport}/late/${type}`, leaveReportTimeLate: (type: string) => `${leaveReport}/late/${type}`,
leaveReportLeaveday: (type: string) => `${leaveReport}/leaveday/${type}`, leaveReportLeaveday: (type: string) => `${leaveReport}/leaveday/${type}`,
leaveReportLeavedayRetire: () => `${leaveReport}/leavedayRetire`,
leaveReportLeave2: (type: string) => `${leaveReport}/leave2/${type}`, leaveReportLeave2: (type: string) => `${leaveReport}/leave2/${type}`,
}; };

View file

@ -6,6 +6,7 @@ export const apiUrlConfig = import.meta.env.VITE_API_URI_CONFIG;
export const apiUrlConfigPublish = import.meta.env.VITE_API_PUBLISH_URL; export const apiUrlConfigPublish = import.meta.env.VITE_API_PUBLISH_URL;
export const apiUrlConfigReport = import.meta.env.VITE_API_REPORT_URL; export const apiUrlConfigReport = import.meta.env.VITE_API_REPORT_URL;
export const apiUrlConfigReport2 = import.meta.env.VITE_API_URI_REPORT_CONFIG; export const apiUrlConfigReport2 = import.meta.env.VITE_API_URI_REPORT_CONFIG;
export const dashboardPanelUrl = import.meta.env.VITE_DASHBOARD_PANEL;
// if (process.env.VUE_APP_TEST) { // if (process.env.VUE_APP_TEST) {
// env = "test"; // env = "test";
// } // }
@ -38,6 +39,33 @@ const config = ref<any>({
API_REPORT_TEMPLATE_URI: API_REPORT_TEMPLATE_URI:
"https://report-server.frappet.synology.me/api/v1/report-template", "https://report-server.frappet.synology.me/api/v1/report-template",
API_SUPPORT_URI: "https://bma-ehr.frappet.synology.me/api/v1/support", API_SUPPORT_URI: "https://bma-ehr.frappet.synology.me/api/v1/support",
DASHBOARD_ORG_URL: `${dashboardPanelUrl}/${
import.meta.env.VITE_DASHBOARDID_ORG
}`,
DASHBOARD_REGISTRY_URL: `${dashboardPanelUrl}/${
import.meta.env.VITE_DASHBOARDID_REGISTRY
}`,
DASHBOARD_LEAVE_URL: `${dashboardPanelUrl}/${
import.meta.env.VITE_DASHBOARDID_LEAVE
}`,
DASHBOARD_PLACEMENT_URL: `${dashboardPanelUrl}/${
import.meta.env.VITE_DASHBOARDID_PLACEMENT
}`,
DASHBOARD_RETIRE_URL: `${dashboardPanelUrl}/${
import.meta.env.VITE_DASHBOARDID_RETIRE
}`,
DASHBOARD_DISCIPLINE_URL: `${dashboardPanelUrl}/${
import.meta.env.VITE_DASHBOARDID_DISCIPLINE
}`,
DASHBOARD_DEVELOP_URL: `${dashboardPanelUrl}/${
import.meta.env.VITE_DASHBOARDID_DEVELOP
}`,
DASHBOARD_SALARY_URL: `${dashboardPanelUrl}/${
import.meta.env.VITE_DASHBOARDID_SALARY
}`,
DASHBOARD_KPI_URL: `${dashboardPanelUrl}/${
import.meta.env.VITE_DASHBOARDID_KPI
}`,
}, },
test: { test: {
API_URI: "http://localhost:5010/api/v1", API_URI: "http://localhost:5010/api/v1",
@ -63,6 +91,33 @@ const config = ref<any>({
LINK_EVALUATE_PUBLISH: apiUrlConfigPublish, LINK_EVALUATE_PUBLISH: apiUrlConfigPublish,
API_REPORT_TEMPLATE_URI: apiUrlConfigReport, API_REPORT_TEMPLATE_URI: apiUrlConfigReport,
API_SUPPORT_URI: `${apiUrlConfigPublish}/support`, API_SUPPORT_URI: `${apiUrlConfigPublish}/support`,
DASHBOARD_ORG_URL: `${dashboardPanelUrl}/${
import.meta.env.VITE_DASHBOARDID_ORG
}`,
DASHBOARD_REGISTRY_URL: `${dashboardPanelUrl}/${
import.meta.env.VITE_DASHBOARDID_REGISTRY
}`,
DASHBOARD_LEAVE_URL: `${dashboardPanelUrl}/${
import.meta.env.VITE_DASHBOARDID_LEAVE
}`,
DASHBOARD_PLACEMENT_URL: `${dashboardPanelUrl}/${
import.meta.env.VITE_DASHBOARDID_PLACEMENT
}`,
DASHBOARD_RETIRE_URL: `${dashboardPanelUrl}/${
import.meta.env.VITE_DASHBOARDID_RETIRE
}`,
DASHBOARD_DISCIPLINE_URL: `${dashboardPanelUrl}/${
import.meta.env.VITE_DASHBOARDID_DISCIPLINE
}`,
DASHBOARD_DEVELOP_URL: `${dashboardPanelUrl}/${
import.meta.env.VITE_DASHBOARDID_DEVELOP
}`,
DASHBOARD_SALARY_URL: `${dashboardPanelUrl}/${
import.meta.env.VITE_DASHBOARDID_SALARY
}`,
DASHBOARD_KPI_URL: `${dashboardPanelUrl}/${
import.meta.env.VITE_DASHBOARDID_KPI
}`,
}, },
}); });
@ -100,6 +155,34 @@ const API_REPORT_TEMPLATE_URI = ref<string>(
config.value[env.value].API_REPORT_TEMPLATE_URI config.value[env.value].API_REPORT_TEMPLATE_URI
); );
const DASHBOARD_ORG_URL = ref<string>(
config.value[env.value].DASHBOARD_ORG_URL
);
const DASHBOARD_REGISTRY_URL = ref<string>(
config.value[env.value].DASHBOARD_REGISTRY_URL
);
const DASHBOARD_LEAVE_URL = ref<string>(
config.value[env.value].DASHBOARD_LEAVE_URL
);
const DASHBOARD_PLACEMENT_URL = ref<string>(
config.value[env.value].DASHBOARD_PLACEMENT_URL
);
const DASHBOARD_RETIRE_URL = ref<string>(
config.value[env.value].DASHBOARD_RETIRE_URL
);
const DASHBOARD_DISCIPLINE_URL = ref<string>(
config.value[env.value].DASHBOARD_DISCIPLINE_URL
);
const DASHBOARD_DEVELOP_URL = ref<string>(
config.value[env.value].DASHBOARD_DEVELOP_URL
);
const DASHBOARD_SALARY_URL = ref<string>(
config.value[env.value].DASHBOARD_SALARY_URL
);
const DASHBOARD_KPI_URL = ref<string>(
config.value[env.value].DASHBOARD_KPI_URL
);
export default { export default {
env: env.value, env: env.value,
config: config.value, config: config.value,
@ -118,4 +201,13 @@ export default {
LINK_EVALUATE_PUBLISH: LINK_EVALUATE_PUBLISH.value, LINK_EVALUATE_PUBLISH: LINK_EVALUATE_PUBLISH.value,
API_REPORT_TEMPLATE_URI: API_REPORT_TEMPLATE_URI.value, API_REPORT_TEMPLATE_URI: API_REPORT_TEMPLATE_URI.value,
API_SUPPORT_URI: API_SUPPORT_URI.value, API_SUPPORT_URI: API_SUPPORT_URI.value,
DASHBOARD_ORG_URL: DASHBOARD_ORG_URL.value,
DASHBOARD_REGISTRY_URL: DASHBOARD_REGISTRY_URL.value,
DASHBOARD_LEAVE_URL: DASHBOARD_LEAVE_URL.value,
DASHBOARD_PLACEMENT_URL: DASHBOARD_PLACEMENT_URL.value,
DASHBOARD_RETIRE_URL: DASHBOARD_RETIRE_URL.value,
DASHBOARD_DISCIPLINE_URL: DASHBOARD_DISCIPLINE_URL.value,
DASHBOARD_DEVELOP_URL: DASHBOARD_DEVELOP_URL.value,
DASHBOARD_SALARY_URL: DASHBOARD_SALARY_URL.value,
DASHBOARD_KPI_URL: DASHBOARD_KPI_URL.value,
}; };

View file

@ -28,6 +28,8 @@ export default {
periodExamId: (examId: string) => `${periodExam}${examId}`, periodExamId: (examId: string) => `${periodExam}${examId}`,
periodExamDoc: (examId: string) => `${periodExam}doc/${examId}`, periodExamDoc: (examId: string) => `${periodExam}doc/${examId}`,
periodExamImg: (examId: string) => `${periodExam}img/${examId}`, periodExamImg: (examId: string) => `${periodExam}img/${examId}`,
periodExambarcode: (examId: string) => `${periodExam}barcode/${examId}`,
periodExamqrcode: (examId: string) => `${periodExam}qrcode/${examId}`,
periodExamStatus: (examId: string) => `${periodExam}status-payment/${examId}`, periodExamStatus: (examId: string) => `${periodExam}status-payment/${examId}`,
countDashbordPeriodExam: (examId: string) => countDashbordPeriodExam: (examId: string) =>

View file

@ -1,6 +1,7 @@
import env from "../index"; import env from "../index";
const registryNew = `${env.API_URI}/org/profile`; const registryNew = `${env.API_URI}/org/profile`;
const org = `${env.API_URI}/org`;
const metadata = `${env.API_URI}/org/metadata/`; const metadata = `${env.API_URI}/org/metadata/`;
export default { export default {
@ -42,6 +43,10 @@ export default {
profileNewInsign: (type: string) => `${registryNew}${type}/insignia`, profileNewInsign: (type: string) => `${registryNew}${type}/insignia`,
profileNewInsignByProfileId: (profileId: string, type: string) => profileNewInsignByProfileId: (profileId: string, type: string) =>
`${registryNew}${type}/insignia/${profileId}`, `${registryNew}${type}/insignia/${profileId}`,
orgInsigniaActive: () =>
`${org}/insignia/insignia-type/active`,
profileNewInsignById: (dataId: string, type: string) => profileNewInsignById: (dataId: string, type: string) =>
`${registryNew}${type}/insignia/${dataId}`, `${registryNew}${type}/insignia/${dataId}`,
profileNewInsignHisById: (dataId: string, type: string) => profileNewInsignHisById: (dataId: string, type: string) =>
@ -207,4 +212,16 @@ export default {
requestInformationbyType: (type: string, id: string) => requestInformationbyType: (type: string, id: string) =>
`${registryNew}/request-edit/${type}/${id}`, `${registryNew}/request-edit/${type}/${id}`,
// รักษาการในตำแหน่ง
profileActposition: (type: string, id: string) =>
`${registryNew}${type}/actposition/${id}`,
profileActpositionHistory: (id: string, type: string) =>
`${registryNew}${type}/actposition/history/${id}`,
//ช่วยราชการ
profileAssistance: (type: string, id: string) =>
`${registryNew}${type}/assistance/${id}`,
profileAssistanceHistory: (id: string, type: string) =>
`${registryNew}${type}/assistance/history/${id}`,
}; };

View file

@ -0,0 +1,14 @@
/*** dashboard panel url */
import env from "../index";
export default {
dashboardPanelOrg: `${env.DASHBOARD_ORG_URL}`,
dashboardPanelRegistry: `${env.DASHBOARD_REGISTRY_URL}`,
dashboardPanelLeave: `${env.DASHBOARD_LEAVE_URL}`,
dashboardPanelPlacement: `${env.DASHBOARD_PLACEMENT_URL}`,
dashboardPanelRetire: `${env.DASHBOARD_RETIRE_URL}`,
dashboardPanelDiscipline: `${env.DASHBOARD_DISCIPLINE_URL}`,
dashboardPanelDevelop: `${env.DASHBOARD_DEVELOP_URL}`,
dashboardPanelSalary: `${env.DASHBOARD_SALARY_URL}`,
dashboardPanelKPI: `${env.DASHBOARD_KPI_URL}`,
};

View file

@ -3,11 +3,11 @@
*/ */
import env from "../index"; import env from "../index";
const reportOrder = `${env.API_REPORT2_URI}/report/order`; const reportOrder = `${env.API_REPORT2_URI}/report/order`;
const reportRetire = `${env.API_REPORT2_URI}/report/retire`; const reportRetire = `${env.API_REPORT_URI}/retirement`;
const reportProbation = `${env.API_REPORT2_URI}/report/probation`; const reportProbation = `${env.API_REPORT_URI}/placement/probation`;
const reportResign = `${env.API_REPORT2_URI}/report/resign/33`; const reportResign = `${env.API_REPORT_URI}/retirement/resign/33`;
const reportTransfer = `${env.API_REPORT2_URI}/report/transfer`; const reportTransfer = `${env.API_REPORT_URI}/placement/transfer`;
const reportDeceased = `${env.API_REPORT2_URI}/report/deceased`; const reportDeceased = `${env.API_REPORT_URI}/retirement/deceased`;
const reportTemplate = `${env.API_REPORT_TEMPLATE_URI}`; const reportTemplate = `${env.API_REPORT_TEMPLATE_URI}`;
export default { export default {

View file

@ -72,6 +72,8 @@ import command from "./api/18_command/api.command";
import file from "./api/file/api.file"; import file from "./api/file/api.file";
import dashboard from "./api/reports/api.dashboard";
// environment variables // environment variables
export const compettitivePanel = import.meta.env.VITE_COMPETITIVE_EXAM_PANEL; export const compettitivePanel = import.meta.env.VITE_COMPETITIVE_EXAM_PANEL;
export const qualifyDisableExamPanel = import.meta.env export const qualifyDisableExamPanel = import.meta.env
@ -140,6 +142,8 @@ const API = {
/*file*/ /*file*/
...file, ...file,
...dashboard,
}; };
const path = import.meta.env.VITE_MANUAL_URL ?? ""; const path = import.meta.env.VITE_MANUAL_URL ?? "";

View file

@ -175,6 +175,7 @@ watch(
:id="profile.id" :id="profile.id"
@update:modal="updatemodalPersonal" @update:modal="updatemodalPersonal"
:type="props.type" :type="props.type"
:is-employee="props.type"
/> />
</template> </template>

View file

@ -189,6 +189,12 @@ async function getSearch() {
posTypeName: e.posTypeName, posTypeName: e.posTypeName,
posLevelId: e.posLevelId, posLevelId: e.posLevelId,
posLevelName: e.posLevelName, posLevelName: e.posLevelName,
rootDnaId: e.rootDnaId,
child1DnaId: e.child1DnaId,
child2DnaId: e.child2DnaId,
child3DnaId: e.child3DnaId,
child4DnaId: e.child4DnaId,
})); }));
rows.value = list; rows.value = list;

View file

@ -292,6 +292,7 @@ async function getDataTable(id: string, level: number = 0) {
node: e.node, node: e.node,
nodeId: e.nodeId, nodeId: e.nodeId,
isCondition: e.isCondition, isCondition: e.isCondition,
isDirector: e.isDirector,
})); }));
positionNo.value = listPosNo; positionNo.value = listPosNo;
@ -725,7 +726,9 @@ onMounted(async () => {
name="mdi-star" name="mdi-star"
color="primary" color="primary"
v-if="props.row.isDirector" v-if="props.row.isDirector"
/> >
<q-tooltip>อำนวยการ/วหน</q-tooltip>
</q-icon>
</div> </div>
<div v-else-if="col.name === 'isPosition'"> <div v-else-if="col.name === 'isPosition'">
<div v-if="col.value"> <div v-if="col.value">

View file

@ -277,6 +277,7 @@ async function getDataTable(id: string, level: number = 0) {
node: e.node, node: e.node,
nodeId: e.nodeId, nodeId: e.nodeId,
isCondition: e.isCondition, isCondition: e.isCondition,
isDirector: e.isDirector,
})); }));
positionNo.value = listPosNo; positionNo.value = listPosNo;
@ -700,7 +701,9 @@ onMounted(() => {
name="mdi-star" name="mdi-star"
color="primary" color="primary"
v-if="props.row.isDirector" v-if="props.row.isDirector"
/> >
<q-tooltip>อำนวยการ/วหน</q-tooltip>
</q-icon>
</div> </div>
<div v-else-if="col.name === 'isPosition'"> <div v-else-if="col.name === 'isPosition'">
<div v-if="col.value"> <div v-if="col.value">

View file

@ -99,7 +99,7 @@ async function fetchInformation(id: string) {
.get( .get(
config.API.orgProfileById( config.API.orgProfileById(
id, id,
`${empType.value == "employee" ? `-${empType.value}` : ""}` `${props.type == "employee" ? `-${props.type}` : ""}`
) )
) )
.then(async (res) => { .then(async (res) => {
@ -143,7 +143,7 @@ async function fetchProfileGov(id: string) {
.get( .get(
config.API.profileNewGovernmentCard( config.API.profileNewGovernmentCard(
id, id,
`${empType.value == "employee" ? `-${empType.value}` : ""}` `${props.type == "employee" ? `-${props.type}` : ""}`
) )
) )
.then(async (res) => { .then(async (res) => {
@ -172,7 +172,7 @@ async function fetchProfileGov(id: string) {
} }
function redirecToRegistry() { function redirecToRegistry() {
router.push(`/registry-${empType.value}/${props.id}`); router.push(`/registry-${props.type == 'employee' ? 'employee':'officer'}/${props.id}`);
modal.value = false; modal.value = false;
} }
@ -422,7 +422,7 @@ async function fetchProfile(id: string, avatarName: string) {
:model-value=" :model-value="
goverment.positionType ? goverment.positionType : '-' goverment.positionType ? goverment.positionType : '-'
" "
label="ประเภทตำแหน่ง" :label="props.type == 'employee' ? 'กลุ่มงาน':'ประเภทตำแหน่ง'"
/> />
</div> </div>
<div class="col-xs-6 col-md-6"> <div class="col-xs-6 col-md-6">
@ -434,7 +434,7 @@ async function fetchProfile(id: string, avatarName: string) {
? goverment.positionLevel ? goverment.positionLevel
: '-' : '-'
" "
label="ระดับตำแหน่ง" :label="props.type == 'employee' ? 'ระดับชั้นงาน':'ระดับตำแหน่ง'"
/> />
</div> </div>
<div <div

View file

@ -370,7 +370,7 @@ const previous = ref<boolean>(); //แสดงปุ่มดูข้อมู
const next = ref<boolean>(); // const next = ref<boolean>(); //
const editRow = ref<boolean>(false); // const editRow = ref<boolean>(false); //
const rowsHistory = ref<RequestItemsObject[]>([]); //select data history const rowsHistory = ref<RequestItemsObject[]>([]); //select data history
const tittleHistory = ref<string>("ประวัติแก้ไขประวัติการเปลี่ยนชื่อ-นามสกุล"); // const tittleHistory = ref<string>("ประวัติแก้ไขประวัติการเปลี่ยนชื่อ - นามสกุล"); //
const filterHistory = ref<string>(""); //search data table history const filterHistory = ref<string>(""); //search data table history
const modalHistory = ref<boolean>(false); //modal const modalHistory = ref<boolean>(false); //modal
const checkValidate = ref<boolean>(false); //validate data const checkValidate = ref<boolean>(false); //validate data

View file

@ -73,6 +73,7 @@ interface PositionMain {
node: number; node: number;
nodeId: string; nodeId: string;
isCondition: boolean; isCondition: boolean;
isDirector: boolean;
} }
interface PositionNo { interface PositionNo {

View file

@ -70,6 +70,7 @@ const roundOp = ref<DataOption[]>([
{ id: "OCT", name: "รอบตุลาคม" }, { id: "OCT", name: "รอบตุลาคม" },
]); ]);
const nodeDnaId = ref<string>("");
const nodeplan = ref<NodePlan[]>([]); const nodeplan = ref<NodePlan[]>([]);
const nodeAgency = ref<OrgTreeNode[]>([]); const nodeAgency = ref<OrgTreeNode[]>([]);
const filter = ref<string>(""); const filter = ref<string>("");
@ -117,6 +118,7 @@ async function fetchDataById(id: string) {
planData.strategy = data.strategy; planData.strategy = data.strategy;
planData.strategyId = data.strategyId; planData.strategyId = data.strategyId;
planData.documentInfoEvidence = data.documentInfoEvidence; planData.documentInfoEvidence = data.documentInfoEvidence;
nodeDnaId.value = data.nodeDnaId;
// / // /
const arrayexpandedAgency = [ const arrayexpandedAgency = [
@ -168,6 +170,7 @@ function updateSelectedAgency(data: any, isUpdate: boolean = false) {
} else { } else {
planData.node = data.orgLevel; planData.node = data.orgLevel;
planData.nodeId = data.orgTreeId; planData.nodeId = data.orgTreeId;
nodeDnaId.value = data.orgTreeDnaId;
} }
planData.orgRevisionId = data.orgRevisionId; planData.orgRevisionId = data.orgRevisionId;
} }
@ -185,7 +188,7 @@ function onSubmit() {
async () => { async () => {
const body = { const body = {
year: year.value == 0 ? null : year.value?.toString(), year: year.value == 0 ? null : year.value?.toString(),
period: planData.period, period: planData.period ? planData.period : null,
includingName: planData.includingName, includingName: planData.includingName,
target: planData.target, target: planData.target,
unit: planData.unit, unit: planData.unit,
@ -304,7 +307,6 @@ onMounted(async () => {
<template v-slot:append> <template v-slot:append>
<q-icon <q-icon
v-if="year && !checkRoute" v-if="year && !checkRoute"
name="cancel" name="cancel"
class="cursor-pointer" class="cursor-pointer"
@click.stop.prevent="year = 0" @click.stop.prevent="year = 0"
@ -551,7 +553,7 @@ onMounted(async () => {
<q-item <q-item
:clickable="!checkRoute" :clickable="!checkRoute"
@click.stop="updateSelectedAgency(prop.node)" @click.stop="updateSelectedAgency(prop.node)"
:active="planData.nodeId == prop.node.orgTreeId" :active="nodeDnaId == prop.node.orgTreeDnaId"
active-class="my-list-link text-primary text-weight-medium" active-class="my-list-link text-primary text-weight-medium"
class="row col-12 items-center text-dark q-py-xs q-pl-sm rounded-borders my-list" class="row col-12 items-center text-dark q-py-xs q-pl-sm rounded-borders my-list"
> >

View file

@ -79,6 +79,7 @@ const formScore = reactive<any>({
const positionOp = ref<DataOption[]>([]); const positionOp = ref<DataOption[]>([]);
const positionMainOp = ref<DataOption[]>([]); const positionMainOp = ref<DataOption[]>([]);
const nodeDnaId = ref<string>("");
/** Option รอบการประเมิน*/ /** Option รอบการประเมิน*/
const roundOp = ref<DataOption[]>([ const roundOp = ref<DataOption[]>([
@ -184,8 +185,6 @@ function onSubmit() {
} }
} }
//
//
async function getDetail() { async function getDetail() {
showLoader(); showLoader();
await http await http
@ -203,6 +202,7 @@ async function getDetail() {
form.meaning = data.meaning; form.meaning = data.meaning;
form.formula = data.formula; form.formula = data.formula;
form.documentInfoEvidence = data.documentInfoEvidence; form.documentInfoEvidence = data.documentInfoEvidence;
nodeDnaId.value = data.nodeDnaId;
formScore.score1 = data.achievement1; formScore.score1 = data.achievement1;
formScore.score2 = data.achievement2; formScore.score2 = data.achievement2;
@ -240,6 +240,7 @@ function updateSelected(data: any) {
form.node = data.orgLevel; form.node = data.orgLevel;
form.nodeId = data.orgTreeId; form.nodeId = data.orgTreeId;
form.orgRevisionId = data.orgRevisionId; form.orgRevisionId = data.orgRevisionId;
nodeDnaId.value = data.orgTreeDnaId;
} }
function onResize(size: any) { function onResize(size: any) {
@ -470,7 +471,7 @@ onMounted(() => {
<q-item <q-item
:clickable="!checkRoute" :clickable="!checkRoute"
@click.stop="updateSelected(prop.node)" @click.stop="updateSelected(prop.node)"
:active="form.nodeId === prop.node.orgTreeId" :active="nodeDnaId == prop.node.orgTreeDnaId"
active-class="my-list-link text-primary text-weight-medium" active-class="my-list-link text-primary text-weight-medium"
class="row col-12 items-center text-dark q-py-xs q-pl-sm rounded-borders my-list" class="row col-12 items-center text-dark q-py-xs q-pl-sm rounded-borders my-list"
> >

View file

@ -139,7 +139,7 @@ function updateSelectedTreeMain(data: any) {
nodeData.nodeId = null; nodeData.nodeId = null;
} else { } else {
nodeData.node = data.orgLevel; nodeData.node = data.orgLevel;
nodeData.nodeId = data.orgTreeId; nodeData.nodeId = data.orgTreeDnaId;
} }
getSearch(); getSearch();
} }
@ -246,7 +246,7 @@ onMounted(() => {
<q-item <q-item
clickable clickable
@click.stop="updateSelectedTreeMain(prop.node)" @click.stop="updateSelectedTreeMain(prop.node)"
:active="nodeData.nodeId === prop.node.orgTreeId" :active="nodeData.nodeId === prop.node.orgTreeDnaId"
active-class="my-list-link text-primary text-weight-medium" active-class="my-list-link text-primary text-weight-medium"
class="row col-12 items-center text-dark q-py-xs q-pl-sm rounded-borders my-list" class="row col-12 items-center text-dark q-py-xs q-pl-sm rounded-borders my-list"
> >
@ -352,6 +352,7 @@ onMounted(() => {
<q-space /> <q-space />
<q-checkbox <q-checkbox
:disable="nodeData.nodeId === null"
keep-color keep-color
v-model="isAll" v-model="isAll"
label="แสดงทั้งหมด" label="แสดงทั้งหมด"

View file

@ -191,7 +191,7 @@ function filterOption(val: any, update: Function) {
/** ดึงข้อมูลตำแหน่ง */ /** ดึงข้อมูลตำแหน่ง */
async function getOptions() { async function getOptions() {
showLoader(); // showLoader();
await http await http
.get(config.API.orgSalaryPosition) .get(config.API.orgSalaryPosition)
.then(async (res) => { .then(async (res) => {
@ -218,14 +218,10 @@ async function getOptions() {
messageError($q, err); messageError($q, err);
}) })
.finally(() => { .finally(() => {
hideLoader(); // hideLoader();
}); });
} }
function setModel(val: string) {
formFilter.position = val;
}
/** /**
* เป dialog history * เป dialog history
* @param id * @param id
@ -248,7 +244,7 @@ function onClickHistory(id: string) {
} }
async function getTotal() { async function getTotal() {
showLoader(); // showLoader();
await http await http
.post(config.API.indicatorSummary) .post(config.API.indicatorSummary)
.then(async (res) => { .then(async (res) => {
@ -264,12 +260,15 @@ async function getTotal() {
messageError($q, e); messageError($q, e);
}) })
.finally(() => { .finally(() => {
hideLoader(); // hideLoader();
}); });
} }
onMounted(async () => { onMounted(async () => {
await Promise.all([getTotal(), getOptions(), fetchList()]); showLoader();
await Promise.all([getTotal(), getOptions(), fetchList()]).finally(() => {
hideLoader();
});
}); });
</script> </script>
@ -572,7 +571,7 @@ onMounted(async () => {
}} }}
</div> </div>
<div v-else > <div v-else>
{{ col.value ? col.value : "-" }} {{ col.value ? col.value : "-" }}
</div> </div>
</q-td> </q-td>

View file

@ -58,9 +58,9 @@ const props = defineProps({
// //
const orgLevelOptionMain = ref<DataOption[]>([ const orgLevelOptionMain = ref<DataOption[]>([
{ name: "ระดับสำนัก", id: "DEPARTMENT" }, { name: "หน่วยงาน", id: "DEPARTMENT" },
{ {
name: "ระดับกอง/สำนักงาน/ส่วนราชการ/โรงพยาบาล/เทียบเท่ากอง", name: "ระดับกองหรือเทียบเท่า",
id: "OFFICE", id: "OFFICE",
}, },
{ name: "ระดับส่วน/กลุ่มภารกิจ", id: "DIVISION" }, { name: "ระดับส่วน/กลุ่มภารกิจ", id: "DIVISION" },
@ -82,6 +82,13 @@ const formData = reactive<FormDataAgency>({
responsibility: "", responsibility: "",
isOfficer: false, isOfficer: false,
isDeputy: false, isDeputy: false,
isCommission: false,
isInformation: false,
misId: "",
DEPARTMENT_CODE: "",
DIVISION_CODE: "",
SECTION_CODE: "",
JOB_CODE: "",
}); });
/** /**
@ -120,27 +127,42 @@ function onSubmit() {
["org" + type + "Fax"]: formData.orgFax, ["org" + type + "Fax"]: formData.orgFax,
["org" + type + "Rank"]: formData.orgLevel, ["org" + type + "Rank"]: formData.orgLevel,
["org" + type + "RankSub"]: formData.orgLevelSub, ["org" + type + "RankSub"]: formData.orgLevelSub,
misId: formData.misId ? formData.misId : "",
isDeputy:
type === "Root"
? formData.isDeputy
? formData.isDeputy
: false
: undefined,
isCommission:
type === "Root"
? formData.isCommission
? formData.isCommission
: false
: undefined,
isOfficer:
type === "Child1"
? formData.isOfficer
? formData.isOfficer
: false
: undefined,
isInformation:
type === "Child1"
? formData.isInformation
? formData.isInformation
: false
: undefined,
[nameId]: rootId, [nameId]: rootId,
responsibility: responsibility:
formData.responsibility != null ? formData.responsibility : "", formData.responsibility != null ? formData.responsibility : "",
DEPARTMENT_CODE: formData.DEPARTMENT_CODE,
DIVISION_CODE: formData.DIVISION_CODE,
SECTION_CODE: formData.SECTION_CODE,
JOB_CODE: formData.JOB_CODE,
}; };
if (type === "Root") { //
body = {
...body,
isDeputy:
formData.isDeputy !== undefined ? String(formData.isDeputy) : "",
};
}
if (type === "Child1") {
body = {
...body,
isOfficer:
formData.isOfficer !== undefined ? String(formData.isOfficer) : "",
};
}
//
if (actionType.value === "ADD") { if (actionType.value === "ADD") {
await http await http
.post(config.API.createOrgLevel(type.toLocaleLowerCase()), body) .post(config.API.createOrgLevel(type.toLocaleLowerCase()), body)
@ -205,6 +227,14 @@ function closeClear() {
formData.orgLevel = ""; formData.orgLevel = "";
formData.responsibility = ""; formData.responsibility = "";
formData.isOfficer = false; formData.isOfficer = false;
formData.isDeputy = false;
formData.isCommission = false;
formData.isInformation = false;
formData.misId = "";
formData.DEPARTMENT_CODE = "";
formData.DIVISION_CODE = "";
formData.SECTION_CODE = "";
formData.JOB_CODE = "";
props.close?.(); props.close?.();
} }
@ -232,9 +262,12 @@ function selectOrgLevele(val: string, status: boolean = true) {
name: "สำนักงาน", name: "สำนักงาน",
id: "OFFICE", id: "OFFICE",
}, },
{ name: "ส่วนราชการ", id: "GOVERNMENT" }, { name: "สถาบัน", id: "INSTITUTION" },
{ name: "โรงพยาบาล", id: "HOSPITAL" }, { name: "โรงพยาบาล", id: "HOSPITAL" },
{ name: "เทียบเท่ากอง", id: "EQUIVALENT" }, { name: "ศูนย์", id: "CENTER" },
{ name: "ศูนย์บริการการแพทย์", id: "MEDICAL" },
{ name: "ศูนย์บริการสาธารณสุข", id: "HEALTHMAJOR" },
{ name: "หน่วย", id: "UNIT" },
]; ];
break; break;
@ -252,15 +285,47 @@ function selectOrgLevele(val: string, status: boolean = true) {
{ name: "ฝ่าย", id: "FACTION" }, { name: "ฝ่าย", id: "FACTION" },
{ {
name: "กลุ่มงาน", name: "กลุ่มงาน",
id: "WORK", id: "GROUPWORK",
}, },
{ {
name: "สถานีดับเพลิงและกู้ภัย", name: "ศูนย์",
id: "CENTER",
},
{
name: "ศูนย์บริการสาธารณสุขสาขา",
id: "HEALTHBRANCH",
},
{
name: "ศูนย์ฝึกอาชีพ",
id: "TRAINING",
},
{
name: "โรงเรียนฝึกอาชีพ",
id: "SCHOOL",
},
{
name: "บ้านพักผู้สูงอายุ",
id: "ELDERLY",
},
{
name: "สวนสาธารณะ",
id: "PARK",
},
{
name: "สถานีดับเพลิง",
id: "FIRESTATION", id: "FIRESTATION",
}, },
{ {
name: "โรงเรียน", name: "งาน",
id: "SCHOOL", id: "WORK",
},
{
name: "โรงเรียนประถมศึกษา",
id: "PRIMARYSCHOOL",
},
{
name: "โรงเรียนมัธยมศึกษา",
id: "SECONDARYSCHOOL",
}, },
]; ];
@ -402,6 +467,13 @@ watch(
formData.responsibility = props.dataNode.responsibility; formData.responsibility = props.dataNode.responsibility;
formData.isOfficer = props.dataNode.isOfficer ?? false; formData.isOfficer = props.dataNode.isOfficer ?? false;
formData.isDeputy = props.dataNode.isDeputy ?? false; formData.isDeputy = props.dataNode.isDeputy ?? false;
formData.isCommission = props.dataNode.isCommission ?? false;
formData.isInformation = props.dataNode.isInformation ?? false;
formData.misId = props.dataNode.misId;
formData.DEPARTMENT_CODE = props.dataNode.DEPARTMENT_CODE;
formData.DIVISION_CODE = props.dataNode.DIVISION_CODE;
formData.SECTION_CODE = props.dataNode.SECTION_CODE;
formData.JOB_CODE = props.dataNode.JOB_CODE;
orgLevelOption.value = orgLevelOption.value =
props.dataNode.orgTreeRank === "DEPARTMENT" props.dataNode.orgTreeRank === "DEPARTMENT"
? orgLevelOptionMain.value ? orgLevelOptionMain.value
@ -552,7 +624,7 @@ watch(
emit-value emit-value
map-options map-options
v-model="formData.orgLevelSub" v-model="formData.orgLevelSub"
:options="orgLevelSubOptionMain" :options="formData.orgLevel == 'DIVISION' ? orgLevelSubOptionMain.filter((item:any)=> item.id !== 'FACTION'):orgLevelSubOptionMain"
label="ระดับของส่วนราชการ(ซับ)" label="ระดับของส่วนราชการ(ซับ)"
:rules="[ :rules="[
(val:string) => !!val || 'กรุณาเลือกระดับของส่วนราชการ (ซับ)', (val:string) => !!val || 'กรุณาเลือกระดับของส่วนราชการ (ซับ)',
@ -596,6 +668,66 @@ watch(
:class="classInput(false)" :class="classInput(false)"
/> />
</div> </div>
<div class="col-4">
<q-input
v-model="formData.misId"
ref="orgMisIdRef"
dense
outlined
for="#misId"
label="MisId"
hide-bottom-space
:class="classInput(false)"
/>
</div>
<div class="col-12">
<div class="col-12 row q-col-gutter-sm">
<div class="col-3">
<q-input
v-model="formData.DEPARTMENT_CODE"
dense
outlined
label="DEPARTMENT CODE"
hide-bottom-space
:class="classInput(false)"
mask="##"
/>
</div>
<div class="col-3">
<q-input
v-model="formData.DIVISION_CODE"
dense
outlined
label="DIVISION CODE"
hide-bottom-space
:class="classInput(false)"
mask="##"
/>
</div>
<div class="col-3">
<q-input
v-model="formData.SECTION_CODE"
dense
outlined
label="SECTION CODE"
hide-bottom-space
:class="classInput(false)"
mask="##"
/>
</div>
<div class="col-3">
<q-input
v-model="formData.JOB_CODE"
dense
outlined
label="JOB CODE"
hide-bottom-space
:class="classInput(false)"
mask="##"
/>
</div>
</div>
</div>
<div class="col-12"> <div class="col-12">
<q-input <q-input
v-model="formData.responsibility" v-model="formData.responsibility"
@ -626,6 +758,15 @@ watch(
class="q-ml-sm" class="q-ml-sm"
@update:model-value="onChangeIsOfficer" @update:model-value="onChangeIsOfficer"
/> />
<q-checkbox
keep-color
color="primary"
dense
v-model="formData.isInformation"
label="ศูนย์สารสนเทศทรัพยากรบุคคล"
class="q-ml-sm"
@update:model-value="onChangeIsOfficer"
/>
</div> </div>
<div <div
v-if=" v-if="
@ -643,6 +784,15 @@ watch(
class="q-ml-sm" class="q-ml-sm"
@update:model-value="onChangeIsDeputy" @update:model-value="onChangeIsDeputy"
/> />
<q-checkbox
keep-color
color="primary"
dense
v-model="formData.isCommission"
label="สำนักงาน กก."
class="q-ml-sm"
@update:model-value="onChangeIsDeputy"
/>
</div> </div>
</div> </div>
</q-card-section> </q-card-section>

View file

@ -697,6 +697,8 @@ watch(
outlined outlined
for="#positionSign" for="#positionSign"
label="ตำแหน่งใต้ลายเซ็น" label="ตำแหน่งใต้ลายเซ็น"
:row="2"
type="textarea"
/> />
</div> </div>
</div> </div>

View file

@ -118,7 +118,7 @@ watch(
<template> <template>
<template> <template>
<q-dialog v-model="modal" persistent> <q-dialog v-model="modal" persistent>
<q-card style="min-width: 40vw"> <q-card style="min-width: 70%">
<DialogHeader <DialogHeader
:tittle="type == 0 ? `ประวัติหน่วยงาน` : `ประวัติส่วนราชการ`" :tittle="type == 0 ? `ประวัติหน่วยงาน` : `ประวัติส่วนราชการ`"
:close="() => (modal = false)" :close="() => (modal = false)"
@ -166,7 +166,10 @@ watch(
:key="col.name" :key="col.name"
:props="props" :props="props"
> >
<div> <div class="table_ellipsis2" v-if="col.name == 'name'">
{{ col.value ?? "-" }}
</div>
<div v-else>
{{ col.value ?? "-" }} {{ col.value ?? "-" }}
</div> </div>
</q-td> </q-td>

View file

@ -179,7 +179,7 @@ watch(
</script> </script>
<template> <template>
<q-dialog v-model="modal" persistent> <q-dialog v-model="modal" persistent>
<q-card style="width: 1000px; max-width: 100vw"> <q-card style="min-width: 80%">
<Header <Header
:tittle="'ประวัติตำแหน่ง'" :tittle="'ประวัติตำแหน่ง'"
:close=" :close="

View file

@ -439,16 +439,25 @@ watch(
<div> <div>
<div <div
:class=" :class="
prop.node.isOfficer prop.node.isOfficer || prop.node.isInformation
? 'text-weight-medium text-blue' ? 'text-weight-medium text-blue'
: 'text-weight-medium' : 'text-weight-medium'
" "
> >
<div <div
v-if="prop.node.isDeputy == true && prop.node.orgLevel == 0" v-if="
(prop.node.isDeputy == true && prop.node.orgLevel == 0) ||
(prop.node.isCommission == true &&
prop.node.orgLevel == 0)
"
class="text-info" class="text-info"
> >
{{ prop.node.orgTreeName }} {{ prop.node.orgTreeName
}}{{
prop.node.isCommission == true && prop.node.orgLevel == 0
? ` (กก.)`
: ""
}}
</div> </div>
<div v-else> <div v-else>
{{ prop.node.orgTreeName }} {{ prop.node.orgTreeName }}

View file

@ -37,6 +37,13 @@ interface FormDataAgency {
responsibility: string; responsibility: string;
isOfficer?: boolean; isOfficer?: boolean;
isDeputy?: boolean; isDeputy?: boolean;
isInformation?: boolean;
isCommission?: boolean;
misId: string;
DEPARTMENT_CODE: string;
DIVISION_CODE: string;
SECTION_CODE: string;
JOB_CODE: string;
} }
interface FormDataPosition { interface FormDataPosition {

View file

@ -365,8 +365,10 @@ async function clickPassExam() {
showLoader(); showLoader();
await http await http
.get(config.API.exportExamPassExamList(examId.value)) .get(config.API.exportExamPassExamList(examId.value))
.then(() => { .then(async(res) => {
window.open(config.API.exportExamPassExamList(examId.value)); const data = res.data.result;
data.reportName = `Candidate_Dashboard_${dateToISO(new Date())}`;
await genReport(data, data.reportName,'pdf');
}) })
.catch((e) => { .catch((e) => {
messageError($q, e); messageError($q, e);
@ -380,8 +382,10 @@ async function clickCandidateList() {
showLoader(); showLoader();
await http await http
.get(config.API.exportExamCandidateList(examId.value)) .get(config.API.exportExamCandidateList(examId.value))
.then(() => { .then(async(res) => {
window.open(config.API.exportExamCandidateList(examId.value)); const data = res.data.result;
data.reportName = `Candidate_Dashboard_${dateToISO(new Date())}`;
await genReport(data, data.reportName,'pdf');
}) })
.catch((e) => { .catch((e) => {
messageError($q, e); messageError($q, e);

View file

@ -24,7 +24,8 @@ import HistoryTable from "@/components/TableHistory.vue";
const $q = useQuasar(); // show dialog const $q = useQuasar(); // show dialog
const router = useRouter(); const router = useRouter();
const mixin = useCounterMixin(); const mixin = useCounterMixin();
const { success, dateText, messageError, showLoader, hideLoader } = mixin; const { success, dateText, messageError, showLoader, hideLoader, date2Thai } =
mixin;
const name = ref<string>(""); const name = ref<string>("");
const year = ref<number>(new Date().getFullYear() + 543); const year = ref<number>(new Date().getFullYear() + 543);
@ -41,6 +42,7 @@ const tittleHistory = ref<string>("ประวัติการนำเข้
const modalHistory = ref<boolean>(false); //modal const modalHistory = ref<boolean>(false); //modal
const rows = ref<any[]>([]); const rows = ref<any[]>([]);
const filter = ref<string>(""); //search data table const filter = ref<string>(""); //search data table
const filterHistory = ref<string>(""); //search data table
const textTittle = ref<string>(""); const textTittle = ref<string>("");
const textTittleScore = ref<string>(""); const textTittleScore = ref<string>("");
const textTittleCandidate = ref<string>(""); const textTittleCandidate = ref<string>("");
@ -92,6 +94,9 @@ const columns = ref<QTableProps["columns"]>([
field: "year", field: "year",
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
style: "font-size: 14px", style: "font-size: 14px",
format(val, row) {
return `${row.year + 543}`;
},
}, },
{ {
name: "examCount", name: "examCount",
@ -125,12 +130,15 @@ const columnsHistory = ref<QTableProps["columns"]>([
}, },
{ {
name: "createdAt", name: "createdAt",
align: "center", align: "left",
label: "วันที่ดำเนินการ", label: "วันที่ดำเนินการ",
sortable: true, sortable: true,
field: "createdAt", field: "createdAt",
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
style: "font-size: 14px", style: "font-size: 14px",
format(val, row) {
return `${date2Thai(row.createdAt)}`;
},
}, },
{ {
name: "createdFullName", name: "createdFullName",
@ -504,9 +512,6 @@ onMounted(async () => {
<div v-else-if="col.name == 'name'" class="table_ellipsis2"> <div v-else-if="col.name == 'name'" class="table_ellipsis2">
{{ col.value }} {{ col.value }}
</div> </div>
<div v-else-if="col.name == 'year'" class="table_ellipsis2">
{{ col.value + 543 }}
</div>
<div v-else-if="col.name == 'scoreCount'" class="table_ellipsis2"> <div v-else-if="col.name == 'scoreCount'" class="table_ellipsis2">
<q-btn <q-btn
flat flat
@ -617,6 +622,8 @@ onMounted(async () => {
v-model:modal="modalHistory" v-model:modal="modalHistory"
v-model:inputvisible="visibleColumnsHistory" v-model:inputvisible="visibleColumnsHistory"
v-model:tittle="tittleHistory" v-model:tittle="tittleHistory"
v-model:inputfilter="filterHistory"
:filter="filterHistory"
> >
<template #columns="props"> <template #columns="props">
<q-tr :props="props"> <q-tr :props="props">
@ -630,9 +637,6 @@ onMounted(async () => {
/> />
<q-icon v-else name="mdi-check" color="positive" class="text-h5" /> <q-icon v-else name="mdi-check" color="positive" class="text-h5" />
</div> </div>
<div v-else-if="col.name == 'createdAt'" class="">
{{ textDate(col.value) }}
</div>
<div v-else class=""> <div v-else class="">
{{ col.value }} {{ col.value }}

View file

@ -71,12 +71,15 @@ const columns = ref<QTableProps["columns"]>([
}, },
{ {
name: "yearly", name: "yearly",
align: "center", align: "left",
label: "รอบ/ปีงบประมาณ", label: "รอบ/ปีงบประมาณ",
sortable: true, sortable: true,
field: "yearly", field: "yearly",
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
style: "font-size: 14px", style: "font-size: 14px",
format(val, row) {
return `${row.round}/${row.yearly + 543}`;
},
}, },
// { // {
// name: "category", // name: "category",
@ -98,7 +101,7 @@ const columns = ref<QTableProps["columns"]>([
}, },
{ {
name: "fee", name: "fee",
align: "right", align: "left",
label: "ค่าธรรมเนียม", label: "ค่าธรรมเนียม",
sortable: true, sortable: true,
field: "fee", field: "fee",
@ -351,9 +354,7 @@ onMounted(async () => {
<div v-if="col.name == 'no'" class="table_ellipsis2"> <div v-if="col.name == 'no'" class="table_ellipsis2">
{{ props.rowIndex + 1 }} {{ props.rowIndex + 1 }}
</div> </div>
<div v-else-if="col.name == 'yearly'" class="table_ellipsis2">
{{ props.row.round }}/{{ col.value + 543 }}
</div>
<div <div
v-else-if=" v-else-if="
col.name == 'dateRegister' || col.name == 'dateRegister' ||

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,97 @@
<script setup lang="ts">
import { ref, watch } from "vue";
import { useCounterMixin } from "@/stores/mixin";
import { useRegistryNewDataStore } from "@/modules/04_registryPerson/store";
import type { DataLeave } from "@/modules/04_registryPerson/interface/index/leave";
import DialogHeader from "@/components/DialogHeader.vue";
const storeRegistry = useRegistryNewDataStore();
const modal = defineModel<boolean>("modal", { required: true });
const mixin = useCounterMixin();
const { date2Thai } = mixin;
const props = defineProps({
data: {
type: Object,
default: () => ({
leaveDate: null,
leaveType: "",
leaveReason: "",
leaveCommandNo: "",
}),
},
});
const data = ref<DataLeave>({
date: null,
type: "",
reson: "",
document: "",
});
watch(modal, (val) => {
if (val) {
data.value = {
date: props.data?.leaveDate,
type: storeRegistry.convertTypeRetired(props.data?.leaveType),
reson: props.data?.leaveReason,
document: props.data?.leaveCommandNo,
};
} else {
data.value = {
date: null,
type: "",
reson: "",
document: "",
};
}
});
</script>
<template>
<q-dialog v-model="modal" persistent>
<q-card style="min-width: 30%">
<DialogHeader
tittle="ข้อมูลการพ้นจากราชการ"
:close="() => (modal = false)"
/>
<q-separator />
<q-card-section>
<div class="row">
<div class="col-12 column justify-center no-wrap">
<div class="row text-grey-6">
<div class="col-6">นเดอนปนจากราชการ</div>
<div class="col-6">ประเภทการพนจากราชการ</div>
</div>
<div class="row">
<div class="col-6">
{{ data.date ? date2Thai(data.date) : "-" }}
</div>
<div class="col-6">{{ data.type ? data.type : "-" }}</div>
</div>
<div class="row q-mt-md text-grey-6">
<div class="col-12">สาเหต/เหตผล</div>
</div>
<div class="row">
<div class="col-12">{{ data.reson ? data.reson : "-" }}</div>
</div>
<div class="row q-mt-md text-grey-6">
<div class="col-12">คำส/เอกสารอางอ</div>
</div>
<div class="row">
<div class="col-12">
{{ data.document ? data.document : "-" }}
</div>
</div>
</div>
</div>
</q-card-section>
</q-card>
</q-dialog>
</template>

View file

@ -1,6 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, ref, reactive } from "vue"; import { onMounted, ref, reactive } from "vue";
import { useQuasar } from "quasar"; import { useQuasar } from "quasar";
import axios from "axios";
import { checkPermission } from "@/utils/permissions"; import { checkPermission } from "@/utils/permissions";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
@ -14,6 +15,9 @@ import type {
DataOption, DataOption,
DataOptionInsignia, DataOptionInsignia,
InsigniaOps, InsigniaOps,
InsigniasType,
InsigniasTypeSub,
ResFileData,
} from "@/modules/04_registryPerson/interface/index/Main"; } from "@/modules/04_registryPerson/interface/index/Main";
import type { RequestItemsObject } from "@/modules/04_registryPerson/interface/request/Insignia"; import type { RequestItemsObject } from "@/modules/04_registryPerson/interface/request/Insignia";
import type { ResponseObject } from "@/modules/04_registryPerson/interface/response/Insignia"; import type { ResponseObject } from "@/modules/04_registryPerson/interface/response/Insignia";
@ -36,6 +40,10 @@ const {
onSearchDataTable, onSearchDataTable,
} = mixin; } = mixin;
const isUpload = ref<boolean>(false);
const fileUpload = ref<File | null>(null);
const fileData = ref<ResFileData | null>(null);
const uploadUrl = ref<string>("");
/** props*/ /** props*/
const isLeave = defineModel<boolean>("isLeave", { const isLeave = defineModel<boolean>("isLeave", {
required: true, required: true,
@ -73,7 +81,10 @@ const OpsFilter = ref<InsigniaOps>({
insigniaOptions: [], insigniaOptions: [],
}); });
const insigniaOptions = ref<any[]>([]); const insigniaOptions = ref<InsigniasType[]>([]);
const insigniaOptionsMain = ref<InsigniasType[]>([]);
const insigniaOptionsName = ref<InsigniasTypeSub[]>([]);
const insigniaOptionsNameMain = ref<InsigniasTypeSub[]>([]);
// //
const Ops = ref<InsigniaOps>({ const Ops = ref<InsigniaOps>({
insigniaOptions: [], insigniaOptions: [],
@ -114,7 +125,7 @@ const columns = ref<QTableProps["columns"]>([
field: "insigniaId", field: "insigniaId",
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
style: "font-size: 14px", style: "font-size: 14px",
format: (v) => Ops.value.insigniaOptions.find((r) => r.id === v)?.name, format: (v) => store.allNameInsignia.find((r) => r.id === v)?.name,
sort: (a: string, b: string) => sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }), a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
}, },
@ -301,7 +312,7 @@ const columnsHistory = ref<QTableProps["columns"]>([
field: "insigniaId", field: "insigniaId",
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
style: "font-size: 14px", style: "font-size: 14px",
format: (v) => Ops.value.insigniaOptions.find((r) => r.id === v)?.name, format: (v) => store.allNameInsignia.find((r) => r.id === v)?.name,
sort: (a: string, b: string) => sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }), a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
}, },
@ -483,18 +494,21 @@ async function fetchData() {
} }
} }
/** fetch ข้อมูลเครื่องราชอิสริยาภรณ์*/ /** ดึง */
async function fetchInsignia() { async function getInsigniaActive() {
showLoader(); showLoader();
try { http
const res = await http.get(config.API.insigniaOrg); .get(config.API.orgInsigniaActive())
const data = res.data.result; .then((res) => {
mapInsigniaOption(data); const data = res.data.result;
} catch (error) { mapInsigniaOption(data);
messageError($q, error); })
} finally { .catch((e) => {
hideLoader(); messageError($q, e);
} })
.finally(() => {
hideLoader();
});
} }
/** /**
@ -510,13 +524,21 @@ async function addEditData(editStatus: boolean = false) {
const method = editStatus ? "patch" : "post"; const method = editStatus ? "patch" : "post";
const reqBody: RequestItemsObject = { const reqBody: RequestItemsObject = {
...insigniaForm, ...insigniaForm,
isUpload: !isEdit.value ? undefined : isUpload.value,
profileEmployeeId: profileEmployeeId:
!editStatus && empType.value !== "" ? profileId.value : undefined, !editStatus && empType.value !== "" ? profileId.value : undefined,
profileId: profileId:
!editStatus && empType.value === "" ? profileId.value : undefined, !editStatus && empType.value === "" ? profileId.value : undefined,
}; };
try { try {
await http[method](url, reqBody); await http[method](url, reqBody).then(async (res) => {
if ((fileUpload.value && id.value) || res.data.result) {
await uploadProfile(editStatus ? id.value:res.data.result);
}
});
await fetchData(); await fetchData();
await success($q, "บันทึกข้อมูลสำเร็จ"); await success($q, "บันทึกข้อมูลสำเร็จ");
modal.value = false; modal.value = false;
@ -527,6 +549,101 @@ async function addEditData(editStatus: boolean = false) {
} }
} }
/**
* งกนสราง Path ปโหลดไฟล
* @param id
*/
async function uploadProfile(id: string) {
await http
.post(
config.API.subFile("ทะเบียนประวัติ", "เครื่องราชฯ", profileId.value, id),
{
replace: true,
fileList: [
{
fileName: "เอกสารหลักฐาน",
},
],
}
)
.then(async (res) => {
uploadUrl.value = res.data["เอกสารหลักฐาน"].uploadUrl;
await uploadFileURL(uploadUrl.value, fileUpload.value,id);
})
.catch((err) => {
messageError($q, err);
});
}
/**
* งกนอปโหลดำไฟล
* @param uploadUrl Path ปโหลดไฟล
* @param file ไฟลเอกสาร
*/
async function uploadFileURL(uploadUrl: string, file: any,id:string) {
await axios
.put(uploadUrl, file, {
headers: {
"Content-Type": file.type,
},
})
.then(async (res) => {
if (res.status == 200) {
await isUploadFn(id);
}
fileUpload.value = null;
})
.catch((err) => {
messageError($q, err);
});
}
async function isUploadFn(id:string) {
await http
.patch(config.API.profileNewInsignById(id, empType.value), {
isUpload: fileUpload.value ? true : false,
})
.then(async (res) => {})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
}
/**
* งกนโหลไฟลเอกสารหลกฐาน
* @param id รายการทองการโหลด
*/
async function onDownloadFile(id: string, isLoad: boolean = true) {
showLoader();
await http
.get(
config.API.subFileByFileName(
"ทะเบียนประวัติ",
"เครื่องราชฯ",
profileId.value,
id,
"เอกสารหลักฐาน"
)
)
.then(async (res) => {
const data = res.data;
fileData.value = data;
if (isLoad) {
window.open(data.downloadUrl, "_blank");
}
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
/** เปิด form ข้อมูลเครื่องราชอิสริยาภรณ์*/ /** เปิด form ข้อมูลเครื่องราชอิสริยาภรณ์*/
function onClickOpenDialog(editStatus: boolean = false, row?: ResponseObject) { function onClickOpenDialog(editStatus: boolean = false, row?: ResponseObject) {
modal.value = true; modal.value = true;
@ -534,7 +651,7 @@ function onClickOpenDialog(editStatus: boolean = false, row?: ResponseObject) {
if (editStatus && row) { if (editStatus && row) {
id.value = row.id; id.value = row.id;
insigniaType.value = row.insignia.insigniaType.name; insigniaType.value = row.insignia.insigniaType.id;
insigniaForm.year = row.year; insigniaForm.year = row.year;
insigniaForm.no = row.no; insigniaForm.no = row.no;
insigniaForm.volume = row.volume; insigniaForm.volume = row.volume;
@ -548,6 +665,29 @@ function onClickOpenDialog(editStatus: boolean = false, row?: ResponseObject) {
insigniaForm.refCommandDate = row.refCommandDate; insigniaForm.refCommandDate = row.refCommandDate;
insigniaForm.refCommandNo = row.refCommandNo; insigniaForm.refCommandNo = row.refCommandNo;
insigniaForm.note = row.note; insigniaForm.note = row.note;
isUpload.value = row.isUpload;
if (isUpload.value) {
onDownloadFile(row.id, false);
}
const list = store.insigniaTypeOpMain;
const insigniaTypeFilter = list.filter(
(r: InsigniasType) => r.id === insigniaType.value
);
if (insigniaTypeFilter.length > 0) {
const type = insigniaTypeFilter;
const name = insigniaTypeFilter[0].insignias.map(
(item: InsigniasTypeSub) => ({
...item,
name: `${item.name} (${item.shortName})`,
})
);
insigniaOptions.value = type;
insigniaOptionsMain.value = type;
insigniaOptionsName.value = name;
insigniaOptionsNameMain.value = name;
}
} else { } else {
clearData(); clearData();
} }
@ -596,26 +736,46 @@ function onSubmit() {
* @param refData type กำหนด ของ input นๆ * @param refData type กำหนด ของ input นๆ
*/ */
function filterSelector(val: string, update: Function, refData: string) { function filterSelector(val: string, update: Function, refData: string) {
switch (refData) { if (refData == "type") {
case "insigniaOptions": update(() => {
update(() => { insigniaOptions.value = store.insigniaTypeOpMain.filter(
insigniaOptions.value = OpsFilter.value.insigniaOptions.filter( (v: DataOption) => v.name.indexOf(val) > -1
(v: DataOption) => v.name.indexOf(val) > -1 );
); });
}); } else if (refData == "insigniaOptions") {
break; update(() => {
default: insigniaOptionsName.value = insigniaOptionsNameMain.value.filter(
break; (v: DataOption) => v.name.indexOf(val) > -1
);
});
} }
} }
/** ค้นหาลำดับชั้น*/ /** ค้นหาลำดับชั้น*/
function insigniaTypeSelection() { function insigniaTypeSelection(check: boolean, id: string) {
const insigniaTypeFilter = Ops.value.insigniaOptions.filter( if (check) {
(r: DataOptionInsignia) => r.id === insigniaForm.insigniaId insigniaForm.insigniaId = "";
); const data = store.insigniaTypeOpMain.find(
if (insigniaTypeFilter.length > 0) { (item: InsigniasType) => item.id == id
insigniaType.value = insigniaTypeFilter[0].typeName; );
if (data) {
const listData = data.insignias.map((item: InsigniasTypeSub) => ({
id: item.id,
createdAt: item.createdAt,
createdUserId: item.createdUserId,
lastUpdatedAt: item.lastUpdatedAt,
lastUpdateUserId: item.lastUpdateUserId,
createdFullName: item.createdFullName,
lastUpdateFullName: item.lastUpdateFullName,
name: `${item.name} (${item.shortName})`,
shortName: item.shortName,
level: item.level,
isActive: item.isActive,
note: item.note,
insigniaTypeId: item.insigniaTypeId,
}));
insigniaOptionsNameMain.value = listData;
}
} }
} }
@ -635,6 +795,9 @@ function clearData() {
insigniaForm.refCommandNo = ""; insigniaForm.refCommandNo = "";
insigniaForm.refCommandDate = null; insigniaForm.refCommandDate = null;
insigniaForm.note = ""; insigniaForm.note = "";
fileUpload.value = null;
isUpload.value = false;
fileData.value = null;
} }
function serchDataTable() { function serchDataTable() {
@ -656,9 +819,9 @@ function serchDataTableHistory() {
/** ทำงานเมื่อ Components ถูกเรียกใช้งาน*/ /** ทำงานเมื่อ Components ถูกเรียกใช้งาน*/
onMounted(async () => { onMounted(async () => {
await fetchData(); await fetchData();
store.insigniaOption.length === 0 ? await fetchInsignia() : ""; store.insigniaTypeOpMain.length === 0 ? await getInsigniaActive() : "";
Ops.value.insigniaOptions = store.insigniaOption;
OpsFilter.value.insigniaOptions = store.insigniaOption; insigniaOptionsMain.value = store.insigniaTypeOpMain;
insigniaOptions.value = store.insigniaOption; insigniaOptions.value = store.insigniaOption;
}); });
</script> </script>
@ -755,6 +918,7 @@ onMounted(async () => {
<q-th v-for="col in props.cols" :key="col.name" :props="props"> <q-th v-for="col in props.cols" :key="col.name" :props="props">
<span class="text-weight-medium">{{ col.label }}</span> <span class="text-weight-medium">{{ col.label }}</span>
</q-th> </q-th>
<q-th auto-width></q-th>
</q-tr> </q-tr>
</template> </template>
@ -789,6 +953,19 @@ onMounted(async () => {
{{ col.value ? col.value : "-" }} {{ col.value ? col.value : "-" }}
</div> </div>
</q-td> </q-td>
<q-td auto-width>
<q-btn
v-if="props.row.isUpload == true"
color="green"
flat
dense
round
icon="mdi-file-document-outline"
@click="onDownloadFile(props.row.id)"
>
<q-tooltip>ดาวนโหลด</q-tooltip>
</q-btn>
</q-td>
</q-tr> </q-tr>
</template> </template>
@ -951,15 +1128,15 @@ onMounted(async () => {
option-value="id" option-value="id"
input-debounce="0" input-debounce="0"
option-label="name" option-label="name"
v-model="insigniaForm.insigniaId" v-model="insigniaType"
class="inputgreen" class="inputgreen"
:label="`${'ชื่อเครื่องราชฯ'}`" :label="`${'ลำดับชั้น'}`"
:options="insigniaOptions" :options="insigniaOptions"
:rules="[(val:string) => !!val || `${'กรุณาเลือกชื่อเครื่องราชฯ'}`]" :rules="[(val:string) => !!val || `${'กรุณาเลือกลำดับชั้น'}`]"
@filter="(inputValue:string, @filter="(inputValue:string,
doneFn:Function) => filterSelector(inputValue, doneFn,'insigniaOptions' doneFn:Function) => filterSelector(inputValue, doneFn,'type'
) " ) "
@update:modelValue="insigniaTypeSelection" @update:modelValue="(val:any)=>insigniaTypeSelection(true,val)"
> >
<template v-slot:no-option> <template v-slot:no-option>
<q-item> <q-item>
@ -971,16 +1148,39 @@ onMounted(async () => {
</q-select> </q-select>
</div> </div>
<div class="col-xs-6 col-sm-6 col-md-6"> <div class="col-xs-6 col-sm-6 col-md-6">
<q-input <q-select
dense dense
readonly
outlined outlined
:readonly="insigniaType == ''"
use-input
hide-selected
fill-input
emit-value
lazy-rules lazy-rules
map-options
hide-bottom-space hide-bottom-space
v-model="insigniaType" option-value="id"
:label="`${'ลำดับชั้น'}`" input-debounce="0"
/> option-label="name"
v-model="insigniaForm.insigniaId"
class="inputgreen"
:label="`${'ชื่อเครื่องราชฯ'}`"
:options="insigniaOptionsName"
:rules="[(val:string) => !!val || `${'กรุณาเลือกชื่อเครื่องราชฯ'}`]"
@filter="(inputValue:string,
doneFn:Function) => filterSelector(inputValue, doneFn,'insigniaOptions'
) "
>
<template v-slot:no-option>
<q-item>
<q-item-section class="text-grey">
ไมอม
</q-item-section>
</q-item>
</template>
</q-select>
</div> </div>
<div class="col-xs-6 col-sm-6 col-md-6"> <div class="col-xs-6 col-sm-6 col-md-6">
<q-input <q-input
dense dense
@ -1152,6 +1352,109 @@ onMounted(async () => {
label="หมายเหตุ" label="หมายเหตุ"
/> />
</div> </div>
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="row">
<q-uploader
v-if="!isUpload"
color="gray"
type="file"
flat
ref="uploader"
class="full-width"
text-color="white"
:max-size="10000000"
accept=".pdf"
bordered
label="[ไฟล์ pdf ขนาดไม่เกิน 10MB]"
@added="(v:any) => (fileUpload = v[0])"
>
<template v-slot:header="scope">
<div class="row no-wrap items-center q-pa-sm q-gutter-xs">
<q-btn
v-if="scope.queuedFiles.length > 0"
icon="clear_all"
@click="scope.removeQueuedFiles"
round
dense
flat
>
<q-tooltip>ลบทงหมด</q-tooltip>
</q-btn>
<q-btn
v-if="scope.uploadedFiles.length > 0"
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">
{{ "[ไฟล์ .pdf ขนาดไม่เกิน 10MB]" }}
</div>
<div class="q-uploader__subtitle">
{{ scope.uploadSizeLabel }} /
{{ scope.uploadProgressLabel }}
</div>
</div>
<q-btn
v-if="scope.canAddFiles"
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"
icon="clear"
@click="scope.abort"
round
dense
flat
>
<q-tooltip>ยกเลกการอปโหลด</q-tooltip>
</q-btn>
</div>
</template>
</q-uploader>
<q-list bordered dense separator v-else class="full-width">
<q-item>
<q-item-section> {{ fileData?.fileName }}</q-item-section>
<q-item-section avatar>
<div class="row">
<q-btn
flat
round
color="primary"
icon="mdi-download"
@click="onDownloadFile(id)"
/>
<q-btn
flat
round
color="grey"
icon="close"
@click="isUpload = false"
/>
</div>
</q-item-section>
</q-item>
</q-list>
</div>
</div>
</div> </div>
</q-card-section> </q-card-section>
<q-separator /> <q-separator />

View file

@ -1,6 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, reactive } from "vue"; import { ref, onMounted, reactive } from "vue";
import { useQuasar } from "quasar"; import { useQuasar } from "quasar";
import axios from "axios";
import { checkPermission } from "@/utils/permissions"; import { checkPermission } from "@/utils/permissions";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
@ -10,6 +11,10 @@ import config from "@/app.config";
import type { QTableProps } from "quasar"; import type { QTableProps } from "quasar";
import type { RequestItemsObject } from "@/modules/04_registryPerson/interface/request/DeclarationHonor"; import type { RequestItemsObject } from "@/modules/04_registryPerson/interface/request/DeclarationHonor";
import type {
DataOption,
ResFileData,
} from "@/modules/04_registryPerson/interface/index/Main";
import type { ResponseObject } from "@/modules/04_registryPerson/interface/response/DeclarationHonor"; import type { ResponseObject } from "@/modules/04_registryPerson/interface/response/DeclarationHonor";
import DialogHeader from "@/components/DialogHeader.vue"; import DialogHeader from "@/components/DialogHeader.vue";
@ -32,15 +37,31 @@ const profileId = ref<string>(
route.params.id ? route.params.id.toString() : "" route.params.id ? route.params.id.toString() : ""
); );
const empType = ref<string>(pathRegistryEmp(route.name?.toString() ?? "")); const empType = ref<string>(pathRegistryEmp(route.name?.toString() ?? ""));
const isUpload = ref<boolean>(false);
const fileUpload = ref<File | null>(null);
const fileData = ref<ResFileData | null>(null);
/** props*/ /** props*/
const isLeave = defineModel<boolean>("isLeave", { const isLeave = defineModel<boolean>("isLeave", {
required: true, required: true,
}); });
const uploadUrl = ref<string>("");
const typeOp = ref<DataOption[]>([
{
id: "CER_RETIRE",
name: "ประกาศเกียรติคุณประเภทที่ 4 ชั้นที่ 1 (เกษียณอายุราชการ)",
},
{
id: "CER_20YEAR",
name: "ประกาศเกียรติคุณประเภทที่ 4 ชั้นที่ 2 (ปฏิบัติหน้าที่ราชการครบ 20 ปีบริบูรณ์)",
},
{ id: "OUTSTAND", name: "ข้าราชการกรุงเทพมหานครสามัญดีเด่น" },
]);
const id = ref<string>(""); //id const id = ref<string>(""); //id
const issueDateYear = ref<number>(0); // const issueDateYear = ref<number>(0); //
const declHonorForm = reactive<RequestItemsObject>({ const declHonorForm = reactive<RequestItemsObject>({
type: "", //
isDate: "false", // isDate: "false", //
issuer: "", // issuer: "", //
detail: "", // detail: "", //
@ -265,6 +286,7 @@ async function addEditData(editStatus: boolean = false) {
const method = editStatus ? "patch" : "post"; const method = editStatus ? "patch" : "post";
const reqBody: RequestItemsObject = { const reqBody: RequestItemsObject = {
...declHonorForm, ...declHonorForm,
isUpload: !isEdit.value ? undefined : isUpload.value,
profileEmployeeId: profileEmployeeId:
!editStatus && empType.value !== "" ? profileId.value : undefined, !editStatus && empType.value !== "" ? profileId.value : undefined,
profileId: profileId:
@ -277,7 +299,11 @@ async function addEditData(editStatus: boolean = false) {
}; };
try { try {
await http[method](url, reqBody); await http[method](url, reqBody).then(async (res) => {
if ((fileUpload.value && id.value) || res.data.result) {
await uploadProfile(editStatus ? id.value:res.data.result);
}
});
await fetchData(); await fetchData();
await success($q, "บันทึกข้อมูลสำเร็จ"); await success($q, "บันทึกข้อมูลสำเร็จ");
modal.value = false; modal.value = false;
@ -288,6 +314,107 @@ async function addEditData(editStatus: boolean = false) {
} }
} }
/**
* งกนสราง Path ปโหลดไฟล
* @param id
*/
async function uploadProfile(id: string) {
await http
.post(
config.API.subFile(
"ทะเบียนประวัติ",
"ประกาศเกียรติคุณ",
profileId.value,
id
),
{
replace: true,
fileList: [
{
fileName: "เอกสารหลักฐาน",
},
],
}
)
.then(async (res) => {
uploadUrl.value = res.data["เอกสารหลักฐาน"].uploadUrl;
await uploadFileURL(uploadUrl.value, fileUpload.value,id);
})
.catch((err) => {
messageError($q, err);
});
}
/**
* งกนอปโหลดำไฟล
* @param uploadUrl Path ปโหลดไฟล
* @param file ไฟลเอกสาร
*/
async function uploadFileURL(uploadUrl: string, file: any,id:string) {
await axios
.put(uploadUrl, file, {
headers: {
"Content-Type": file.type,
},
})
.then(async (res) => {
if (res.status == 200) {
await isUploadFn(id);
}
fileUpload.value = null;
})
.catch((err) => {
messageError($q, err);
});
}
async function isUploadFn(id:string) {
await http
.patch(config.API.profileNewHonorById(id, empType.value), {
isUpload: fileUpload.value ? true : false,
isDate: declHonorForm.isDate === "true" ? true : false,
})
.then(async (res) => {})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
}
/**
* งกนโหลไฟลเอกสารหลกฐาน
* @param id รายการทองการโหลด
*/
async function onDownloadFile(id: string, isLoad: boolean = true) {
showLoader();
await http
.get(
config.API.subFileByFileName(
"ทะเบียนประวัติ",
"ประกาศเกียรติคุณ",
profileId.value,
id,
"เอกสารหลักฐาน"
)
)
.then(async (res) => {
const data = res.data;
fileData.value = data;
if (isLoad) {
window.open(data.downloadUrl, "_blank");
}
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
/** เปิด form ข้อมูลประกาศเกียรติคุณ*/ /** เปิด form ข้อมูลประกาศเกียรติคุณ*/
function onClickOpenDialog(editStatus: boolean = false, row?: ResponseObject) { function onClickOpenDialog(editStatus: boolean = false, row?: ResponseObject) {
modal.value = true; modal.value = true;
@ -302,7 +429,14 @@ function onClickOpenDialog(editStatus: boolean = false, row?: ResponseObject) {
declHonorForm.issueDate = row.issueDate; declHonorForm.issueDate = row.issueDate;
declHonorForm.refCommandNo = row.refCommandNo; declHonorForm.refCommandNo = row.refCommandNo;
declHonorForm.refCommandDate = row.refCommandDate; declHonorForm.refCommandDate = row.refCommandDate;
declHonorForm.type = row.type;
declHonorForm.isDate = row.isDate ? "true" : "false"; declHonorForm.isDate = row.isDate ? "true" : "false";
isUpload.value = row.isUpload;
if (isUpload.value) {
onDownloadFile(row.id, false);
}
} else { } else {
clearData(); clearData();
} }
@ -352,8 +486,13 @@ function clearData() {
declHonorForm.detail = ""; declHonorForm.detail = "";
declHonorForm.issueDate = new Date(); declHonorForm.issueDate = new Date();
declHonorForm.refCommandNo = ""; declHonorForm.refCommandNo = "";
declHonorForm.type = "";
declHonorForm.refCommandDate = null; declHonorForm.refCommandDate = null;
declHonorForm.isDate = "false"; declHonorForm.isDate = "false";
fileUpload.value = null;
isUpload.value = false;
fileData.value = null;
} }
function serchDataTable() { function serchDataTable() {
@ -469,6 +608,7 @@ onMounted(() => {
<q-th v-for="col in props.cols" :key="col.name" :props="props"> <q-th v-for="col in props.cols" :key="col.name" :props="props">
<span class="text-weight-medium">{{ col.label }}</span> <span class="text-weight-medium">{{ col.label }}</span>
</q-th> </q-th>
<q-th auto-width />
</q-tr> </q-tr>
</template> </template>
@ -502,6 +642,19 @@ onMounted(() => {
{{ col.value ? col.value : "-" }} {{ col.value ? col.value : "-" }}
</div> </div>
</q-td> </q-td>
<q-td auto-width>
<q-btn
v-if="props.row.isUpload == true"
color="green"
flat
dense
round
icon="mdi-file-document-outline"
@click="onDownloadFile(props.row.id)"
>
<q-tooltip>ดาวนโหลด</q-tooltip>
</q-btn>
</q-td>
</q-tr> </q-tr>
</template> </template>
@ -687,6 +840,21 @@ onMounted(() => {
:label="`${'ผู้มีอำนาจลงนาม'}`" :label="`${'ผู้มีอำนาจลงนาม'}`"
/> />
</div> </div>
<div class="col-12">
<q-select
outlined
dense
label="ประเภท"
v-model="declHonorForm.type"
:options="typeOp"
option-label="name"
option-value="id"
class="inputgreen"
emit-value
map-options
>
</q-select>
</div>
<div class="col-12"> <div class="col-12">
<q-input <q-input
dense dense
@ -756,6 +924,109 @@ onMounted(() => {
</template> </template>
</datepicker> </datepicker>
</div> </div>
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="row">
<q-uploader
v-if="!isUpload"
color="gray"
type="file"
flat
ref="uploader"
class="full-width"
text-color="white"
:max-size="10000000"
accept=".pdf"
bordered
label="[ไฟล์ pdf ขนาดไม่เกิน 10MB]"
@added="(v:any) => (fileUpload = v[0])"
>
<template v-slot:header="scope">
<div class="row no-wrap items-center q-pa-sm q-gutter-xs">
<q-btn
v-if="scope.queuedFiles.length > 0"
icon="clear_all"
@click="scope.removeQueuedFiles"
round
dense
flat
>
<q-tooltip>ลบทงหมด</q-tooltip>
</q-btn>
<q-btn
v-if="scope.uploadedFiles.length > 0"
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">
{{ "[ไฟล์ .pdf ขนาดไม่เกิน 10MB]" }}
</div>
<div class="q-uploader__subtitle">
{{ scope.uploadSizeLabel }} /
{{ scope.uploadProgressLabel }}
</div>
</div>
<q-btn
v-if="scope.canAddFiles"
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"
icon="clear"
@click="scope.abort"
round
dense
flat
>
<q-tooltip>ยกเลกการอปโหลด</q-tooltip>
</q-btn>
</div>
</template>
</q-uploader>
<q-list bordered dense separator v-else class="full-width">
<q-item>
<q-item-section> {{ fileData?.fileName }}</q-item-section>
<q-item-section avatar>
<div class="row">
<q-btn
flat
round
color="primary"
icon="mdi-download"
@click="onDownloadFile(id)"
/>
<q-btn
flat
round
color="grey"
icon="close"
@click="isUpload = false"
/>
</div>
</q-item-section>
</q-item>
</q-list>
</div>
</div>
</div> </div>
</q-card-section> </q-card-section>
<q-separator color="grey-4" /> <q-separator color="grey-4" />

View file

@ -10,7 +10,10 @@ import http from "@/plugins/http";
import config from "@/app.config"; import config from "@/app.config";
import type { QTableProps } from "quasar"; import type { QTableProps } from "quasar";
import type { RequestItemsObject } from "@/modules/04_registryPerson/interface/request/ResultsPerformance"; import type {
RequestItemsObject,
DataOptions,
} from "@/modules/04_registryPerson/interface/request/ResultsPerformance";
import type { ResponseObject } from "@/modules/04_registryPerson/interface/response/ResultsPerformance"; import type { ResponseObject } from "@/modules/04_registryPerson/interface/response/ResultsPerformance";
import DialogHeader from "@/components/DialogHeader.vue"; import DialogHeader from "@/components/DialogHeader.vue";
@ -36,9 +39,9 @@ const profileId = ref<string>(
route.params.id ? route.params.id.toString() : "" route.params.id ? route.params.id.toString() : ""
); );
const empType = ref<string>(pathRegistryEmp(route.name?.toString() ?? "")); const empType = ref<string>(pathRegistryEmp(route.name?.toString() ?? ""));
const year = ref<number | null>(new Date().getFullYear()); //
const id = ref<string>(""); //id const id = ref<string>(""); //id
const typeIDP = ref<string>('') const typeIDP = ref<string>("");
const isEdit = ref<boolean>(false); // const isEdit = ref<boolean>(false); //
const modal = ref<boolean>(false); // popup const modal = ref<boolean>(false); // popup
const modalDevelop = ref<boolean>(false); // popup const modalDevelop = ref<boolean>(false); // popup
@ -46,7 +49,11 @@ const modeView = ref<string>("table"); //การแสดงผล Table,Card
const modeViewPlan = ref<string>("table"); // Table,Card const modeViewPlan = ref<string>("table"); // Table,Card
const modalHistory = ref<boolean>(false); // popup const modalHistory = ref<boolean>(false); // popup
const kpiDevelopmentId = ref<string>(""); // id const kpiDevelopmentId = ref<string>(""); // id
const period = ref<string | null>(null);
const periodOp = ref<DataOptions[]>([
{ id: "OCT", name: "ตุลาคม" },
{ id: "APR", name: "เมษายน" },
]);
/** props*/ /** props*/
const isLeave = defineModel<boolean>("isLeave", { const isLeave = defineModel<boolean>("isLeave", {
required: true, required: true,
@ -87,10 +94,36 @@ const columns = ref<QTableProps["columns"]>([
style: "font-size: 14px", style: "font-size: 14px",
format: (v) => date2Thai(v), format: (v) => date2Thai(v),
}, },
{
name: "year",
align: "left",
label: "ปีงบประมาณ",
sortable: true,
field: "year",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
format: (v) => {
return `${v ? Number(v) + 543 : "-"}`;
},
},
{
name: "period",
align: "left",
label: "รอบการประเมิน",
sortable: true,
field: "period",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
format: (v) => {
return (
periodOp.value.find((item: DataOptions) => item.id === v)?.name || "-"
);
},
},
{ {
name: "point1Total", name: "point1Total",
align: "left", align: "left",
label: "ส่วนที่1 (น้ำหนัก)", label: "ส่วนที่ 1 (น้ำหนัก)",
sortable: true, sortable: true,
field: "point1Total", field: "point1Total",
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
@ -101,7 +134,7 @@ const columns = ref<QTableProps["columns"]>([
{ {
name: "point1", name: "point1",
align: "left", align: "left",
label: "ผลประเมินส่วนที่1 (คะแนน)", label: "ผลประเมินส่วนที่ 1 (คะแนน)",
sortable: true, sortable: true,
field: "point1", field: "point1",
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
@ -112,7 +145,7 @@ const columns = ref<QTableProps["columns"]>([
{ {
name: "point2Total", name: "point2Total",
align: "left", align: "left",
label: "ส่วนที่2 (น้ำหนัก)", label: "ส่วนที่ 2 (น้ำหนัก)",
sortable: true, sortable: true,
field: "point2Total", field: "point2Total",
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
@ -123,7 +156,7 @@ const columns = ref<QTableProps["columns"]>([
{ {
name: "point2", name: "point2",
align: "left", align: "left",
label: "ผลประเมินส่วนที่2 (คะแนน)", label: "ผลประเมินส่วนที่ 2 (คะแนน)",
sortable: true, sortable: true,
field: "point2", field: "point2",
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
@ -170,6 +203,8 @@ const columns = ref<QTableProps["columns"]>([
]); ]);
const visibleColumns = ref<String[]>([ const visibleColumns = ref<String[]>([
"point1Total", "point1Total",
"year",
"period",
"point1", "point1",
"point2Total", "point2Total",
"point2", "point2",
@ -277,10 +312,36 @@ const columnsHistory = ref<QTableProps["columns"]>([
style: "font-size: 14px", style: "font-size: 14px",
format: (v) => date2Thai(v), format: (v) => date2Thai(v),
}, },
{
name: "year",
align: "left",
label: "ปีงบประมาณ",
sortable: true,
field: "year",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
format: (v) => {
return `${v ? Number(v) + 543 : "-"}`;
},
},
{
name: "period",
align: "left",
label: "รอบการประเมิน",
sortable: true,
field: "period",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
format: (v) => {
return (
periodOp.value.find((item: DataOptions) => item.id === v)?.name || "-"
);
},
},
{ {
name: "point1Total", name: "point1Total",
align: "left", align: "left",
label: "ส่วนที่1 (น้ำหนัก)", label: "ส่วนที่ 1 (น้ำหนัก)",
sortable: true, sortable: true,
field: "point1Total", field: "point1Total",
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
@ -289,7 +350,7 @@ const columnsHistory = ref<QTableProps["columns"]>([
{ {
name: "point1", name: "point1",
align: "left", align: "left",
label: "ผลประเมินส่วนที่1 (คะแนน)", label: "ผลประเมินส่วนที่ 1 (คะแนน)",
sortable: true, sortable: true,
field: "point1", field: "point1",
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
@ -300,7 +361,7 @@ const columnsHistory = ref<QTableProps["columns"]>([
{ {
name: "point2Total", name: "point2Total",
align: "left", align: "left",
label: "ส่วนที่2 (น้ำหนัก)", label: "ส่วนที่ 2 (น้ำหนัก)",
sortable: true, sortable: true,
field: "point2Total", field: "point2Total",
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
@ -311,7 +372,7 @@ const columnsHistory = ref<QTableProps["columns"]>([
{ {
name: "point2", name: "point2",
align: "left", align: "left",
label: "ผลประเมินส่วนที่2 (คะแนน)", label: "ผลประเมินส่วนที่ 2 (คะแนน)",
sortable: true, sortable: true,
field: "point2", field: "point2",
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
@ -381,6 +442,8 @@ const columnsHistory = ref<QTableProps["columns"]>([
]); ]);
const visibleColumnsHistory = ref<String[]>([ const visibleColumnsHistory = ref<String[]>([
"point1Total", "point1Total",
"year",
"period",
"point1", "point1",
"point2Total", "point2Total",
"point2", "point2",
@ -459,6 +522,8 @@ async function addEditData(editStatus: boolean = false) {
const method = editStatus ? "patch" : "post"; const method = editStatus ? "patch" : "post";
const reqBody: RequestItemsObject = { const reqBody: RequestItemsObject = {
...resPerformForm, ...resPerformForm,
period: period.value,
year: year.value,
profileEmployeeId: profileEmployeeId:
!editStatus && empType.value !== "" ? profileId.value : undefined, !editStatus && empType.value !== "" ? profileId.value : undefined,
profileId: profileId:
@ -491,6 +556,8 @@ function onClickOpenDialog(editStatus: boolean = false, row?: ResponseObject) {
resPerformForm.pointSumTotal = row.pointSumTotal; resPerformForm.pointSumTotal = row.pointSumTotal;
resPerformForm.pointSum = row.pointSum; resPerformForm.pointSum = row.pointSum;
resPerformForm.date = row.date; resPerformForm.date = row.date;
year.value = row.year ? row.year : null;
period.value = row.period ? row.period : null;
} else { } else {
clearData(); clearData();
} }
@ -535,15 +602,16 @@ function onSubmit() {
/** เคลียร์ formDฟta */ /** เคลียร์ formDฟta */
function clearData() { function clearData() {
(id.value = ""), id.value = "";
(resPerformForm.name = ""), resPerformForm.name = "";
(resPerformForm.point1Total = 0), resPerformForm.point1Total = 0;
(resPerformForm.point1 = 0), resPerformForm.point1 = 0;
(resPerformForm.point2Total = 0), resPerformForm.point2Total = 0;
(resPerformForm.point2 = 0), resPerformForm.point2 = 0;
(resPerformForm.pointSumTotal = 0), resPerformForm.pointSumTotal = 0;
(resPerformForm.pointSum = 0), resPerformForm.pointSum = 0;
(resPerformForm.date = null); resPerformForm.date = null;
year.value = new Date().getFullYear();
} }
/** /**
@ -553,7 +621,7 @@ function clearData() {
function openDialogDevelop(data: any) { function openDialogDevelop(data: any) {
modalDevelop.value = true; modalDevelop.value = true;
kpiDevelopmentId.value = data.kpiDevelopmentId; kpiDevelopmentId.value = data.kpiDevelopmentId;
typeIDP.value = data.type typeIDP.value = data.type;
} }
function updatePaginationIdp(newPagination: any) { function updatePaginationIdp(newPagination: any) {
@ -1094,6 +1162,69 @@ onMounted(async () => {
</template> </template>
</datepicker> </datepicker>
</div> </div>
<div class="col-6">
<datepicker
menu-class-name="modalfix"
v-model="year"
:locale="'th'"
autoApply
year-picker
:enableTimePicker="false"
class="inputgreen"
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
dense
outlined
hide-bottom-space
:model-value="year === null ? null : Number(year) + 543"
:label="`${'ปีงบประมาณ'}`"
>
<template v-if="year !== null" v-slot:append>
<q-icon
name="cancel"
@click.stop.prevent="year = null"
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>
</div>
<div class="col-6">
<q-select
outlined
dense
label="รอบการประเมิน"
v-model="period"
:options="periodOp"
option-value="id"
option-label="name"
emit-value
map-options
class="inputgreen"
>
<template v-if="period" v-slot:append>
<q-icon
name="cancel"
@click.stop.prevent="period = null"
class="cursor-pointer"
/> </template
></q-select>
</div>
<div class="col-xs-6 col-sm-6 col-md-6"> <div class="col-xs-6 col-sm-6 col-md-6">
<q-input <q-input
dense dense
@ -1273,7 +1404,11 @@ onMounted(async () => {
</q-card> </q-card>
</q-dialog> </q-dialog>
<DialogDevelop v-model:modal="modalDevelop" v-model:id="kpiDevelopmentId" :type="typeIDP"/> <DialogDevelop
v-model:modal="modalDevelop"
v-model:id="kpiDevelopmentId"
:type="typeIDP"
/>
</template> </template>
<style scoped> <style scoped>

View file

@ -162,7 +162,13 @@ const Ops = ref<DisciplineOps>({
{ id: "4", name: "ร้ายแรง", disable: true }, { id: "4", name: "ร้ายแรง", disable: true },
{ id: "ปลดออก", name: "ปลดออก", disable: false }, { id: "ปลดออก", name: "ปลดออก", disable: false },
{ id: "ไล่ออก", name: "ไล่ออก", disable: false }, { id: "ไล่ออก", name: "ไล่ออก", disable: false },
{ id: "อื่นๆ", name: "อื่นๆ", disable: false }, { id: "5", name: "อื่นๆ", disable: true },
{ id: "พักราชการ", name: "พักราชการ", disable: false },
{
id: "ให้ออกจากราชการไว้ก่อน",
name: "ให้ออกจากราชการไว้ก่อน",
disable: false,
},
], ],
}); });
const OpsFilter = ref<DisciplineOps>({ const OpsFilter = ref<DisciplineOps>({
@ -182,7 +188,13 @@ const OpsFilter = ref<DisciplineOps>({
{ id: "4", name: "ร้ายแรง", disable: true }, { id: "4", name: "ร้ายแรง", disable: true },
{ id: "ปลดออก", name: "ปลดออก", disable: false }, { id: "ปลดออก", name: "ปลดออก", disable: false },
{ id: "ไล่ออก", name: "ไล่ออก", disable: false }, { id: "ไล่ออก", name: "ไล่ออก", disable: false },
{ id: "อื่นๆ", name: "อื่นๆ", disable: false }, { id: "5", name: "อื่นๆ", disable: true },
{ id: "พักราชการ", name: "พักราชการ", disable: false },
{
id: "ให้ออกจากราชการไว้ก่อน",
name: "ให้ออกจากราชการไว้ก่อน",
disable: false,
},
], ],
}); });

View file

@ -1,6 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, onMounted } from "vue"; import { ref, reactive, onMounted } from "vue";
import { useQuasar, type QTableProps } from "quasar"; import { useQuasar, type QTableProps } from "quasar";
import axios from "axios";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { checkPermission } from "@/utils/permissions"; import { checkPermission } from "@/utils/permissions";
@ -9,6 +10,7 @@ import http from "@/plugins/http";
import config from "@/app.config"; import config from "@/app.config";
import type { RequestItemsObject } from "@/modules/04_registryPerson/interface/index/performSpecialWork"; import type { RequestItemsObject } from "@/modules/04_registryPerson/interface/index/performSpecialWork";
import type { ResFileData } from "@/modules/04_registryPerson/interface/index/Main";
import DialogHeader from "@/components/DialogHeader.vue"; import DialogHeader from "@/components/DialogHeader.vue";
import DialogHistory from "@/modules/04_registryPerson/components/detail/GovernmentInformation/04_PerformSpecialWorkHistory.vue"; import DialogHistory from "@/modules/04_registryPerson/components/detail/GovernmentInformation/04_PerformSpecialWorkHistory.vue";
@ -33,6 +35,12 @@ const profileId = ref<string>(
); );
const empType = ref<string>(pathRegistryEmp(route.name?.toString() ?? "")); const empType = ref<string>(pathRegistryEmp(route.name?.toString() ?? ""));
const uploadUrl = ref<string>("");
const isUpload = ref<boolean>(false);
const fileUpload = ref<File | null>(null);
const fileData = ref<ResFileData | null>(null);
/** props*/ /** props*/
const isLeave = defineModel<boolean>("isLeave", { const isLeave = defineModel<boolean>("isLeave", {
required: true, required: true,
@ -49,7 +57,8 @@ const dutyData = reactive<RequestItemsObject>({
detail: "", // detail: "", //
reference: "", // reference: "", //
refCommandNo: "", // refCommandNo: "", //
refCommandDate: null, //' ()' refCommandDate: null, //' ()',
isUpload: false,
}); });
const mode = ref<string>("table"); // Table card const mode = ref<string>("table"); // Table card
@ -156,6 +165,12 @@ function openDialogEdit(props: RequestItemsObject) {
dutyData.reference = props.reference; dutyData.reference = props.reference;
dutyData.refCommandNo = props.refCommandNo; dutyData.refCommandNo = props.refCommandNo;
dutyData.refCommandDate = props.refCommandDate; dutyData.refCommandDate = props.refCommandDate;
isUpload.value = props.isUpload;
if (isUpload.value && props.id) {
onDownloadFile(props.id, false);
}
} }
/** /**
@ -177,6 +192,11 @@ function closeDialog() {
dutyData.reference = ""; dutyData.reference = "";
dutyData.refCommandNo = ""; dutyData.refCommandNo = "";
dutyData.refCommandDate = null; dutyData.refCommandDate = null;
fileUpload.value = null;
fileUpload.value = null;
isUpload.value = false;
fileData.value = null;
} }
/** fetch ข้อมูลรายการพิเศษ*/ /** fetch ข้อมูลรายการพิเศษ*/
@ -211,7 +231,10 @@ function addData() {
}; };
http http
.post(config.API.profileNewDuty(empType.value), body) .post(config.API.profileNewDuty(empType.value), body)
.then(async () => { .then(async (res) => {
if (fileUpload.value && res.data.result) {
await uploadProfile(res.data.result);
}
await fetchData(profileId.value); await fetchData(profileId.value);
await success($q, "บันทึกข้อมูลสำเร็จ"); await success($q, "บันทึกข้อมูลสำเร็จ");
closeDialog(); closeDialog();
@ -231,8 +254,12 @@ function editData(idData: string) {
.patch(config.API.profileNewDutyByDutyId(idData, empType.value), { .patch(config.API.profileNewDutyByDutyId(idData, empType.value), {
...dutyData, ...dutyData,
profileId: undefined, profileId: undefined,
isUpload: !edit.value ? undefined : isUpload.value,
}) })
.then(async () => { .then(async (res) => {
if (fileUpload.value && idData) {
await uploadProfile(idData);
}
await fetchData(profileId.value); await fetchData(profileId.value);
await success($q, "บันทึกข้อมูลสำเร็จ"); await success($q, "บันทึกข้อมูลสำเร็จ");
closeDialog(); closeDialog();
@ -245,6 +272,106 @@ function editData(idData: string) {
}); });
} }
/**
* งกนสราง Path ปโหลดไฟล
* @param id
*/
async function uploadProfile(id: string) {
await http
.post(
config.API.subFile(
"ทะเบียนประวัติ",
"ประกาศเกียรติคุณ",
profileId.value,
id
),
{
replace: true,
fileList: [
{
fileName: "เอกสารหลักฐาน",
},
],
}
)
.then(async (res) => {
uploadUrl.value = res.data["เอกสารหลักฐาน"].uploadUrl;
await uploadFileURL(uploadUrl.value, fileUpload.value,id);
})
.catch((err) => {
messageError($q, err);
});
}
/**
* งกนอปโหลดำไฟล
* @param uploadUrl Path ปโหลดไฟล
* @param file ไฟลเอกสาร
*/
async function uploadFileURL(uploadUrl: string, file: any,id:string) {
await axios
.put(uploadUrl, file, {
headers: {
"Content-Type": file.type,
},
})
.then(async (res) => {
if (res.status == 200) {
await isUploadFn(id);
}
fileUpload.value = null;
})
.catch((err) => {
messageError($q, err);
});
}
async function isUploadFn(id:string) {
await http
.patch(config.API.profileNewDutyByDutyId(id, empType.value), {
isUpload: fileUpload.value ? true : false,
})
.then(async (res) => {})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
}
/**
* งกนโหลไฟลเอกสารหลกฐาน
* @param id รายการทองการโหลด
*/
async function onDownloadFile(id: string, isLoad: boolean = true) {
showLoader();
await http
.get(
config.API.subFileByFileName(
"ทะเบียนประวัติ",
"ประกาศเกียรติคุณ",
profileId.value,
id,
"เอกสารหลักฐาน"
)
)
.then(async (res) => {
const data = res.data;
fileData.value = data;
if (isLoad) {
window.open(data.downloadUrl, "_blank");
}
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
/** ยืนยันการบันทึกข้อมูล*/ /** ยืนยันการบันทึกข้อมูล*/
function onSubmit() { function onSubmit() {
dialogConfirm( dialogConfirm(
@ -364,6 +491,7 @@ onMounted(() => {
<q-th v-for="col in props.cols" :key="col.name" :props="props"> <q-th v-for="col in props.cols" :key="col.name" :props="props">
<span class="text-weight-medium">{{ col.label }}</span> <span class="text-weight-medium">{{ col.label }}</span>
</q-th> </q-th>
<q-th auto-width />
</q-tr> </q-tr>
</template> </template>
<template v-slot:body="props" v-if="mode === 'table'"> <template v-slot:body="props" v-if="mode === 'table'">
@ -397,6 +525,19 @@ onMounted(() => {
{{ col.value ? col.value : "-" }} {{ col.value ? col.value : "-" }}
</div> </div>
</q-td> </q-td>
<q-td auto-width>
<q-btn
v-if="props.row.isUpload == true"
color="green"
flat
dense
round
icon="mdi-file-document-outline"
@click="onDownloadFile(props.row.id)"
>
<q-tooltip>ดาวนโหลด</q-tooltip>
</q-btn>
</q-td>
</q-tr> </q-tr>
</template> </template>
<template v-slot:item="props" v-else> <template v-slot:item="props" v-else>
@ -651,6 +792,109 @@ onMounted(() => {
</template> </template>
</datepicker> </datepicker>
</div> </div>
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="row">
<q-uploader
v-if="!isUpload"
color="gray"
type="file"
flat
ref="uploader"
class="full-width"
text-color="white"
:max-size="10000000"
accept=".pdf"
bordered
label="[ไฟล์ pdf ขนาดไม่เกิน 10MB]"
@added="(v:any) => (fileUpload = v[0])"
>
<template v-slot:header="scope">
<div class="row no-wrap items-center q-pa-sm q-gutter-xs">
<q-btn
v-if="scope.queuedFiles.length > 0"
icon="clear_all"
@click="scope.removeQueuedFiles"
round
dense
flat
>
<q-tooltip>ลบทงหมด</q-tooltip>
</q-btn>
<q-btn
v-if="scope.uploadedFiles.length > 0"
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">
{{ "[ไฟล์ .pdf ขนาดไม่เกิน 10MB]" }}
</div>
<div class="q-uploader__subtitle">
{{ scope.uploadSizeLabel }} /
{{ scope.uploadProgressLabel }}
</div>
</div>
<q-btn
v-if="scope.canAddFiles"
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"
icon="clear"
@click="scope.abort"
round
dense
flat
>
<q-tooltip>ยกเลกการอปโหลด</q-tooltip>
</q-btn>
</div>
</template>
</q-uploader>
<q-list bordered dense separator v-else class="full-width">
<q-item>
<q-item-section> {{ fileData?.fileName }}</q-item-section>
<q-item-section avatar>
<div class="row">
<q-btn
flat
round
color="primary"
icon="mdi-download"
@click="onDownloadFile(id)"
/>
<q-btn
flat
round
color="grey"
icon="close"
@click="isUpload = false"
/>
</div>
</q-item-section>
</q-item>
</q-list>
</div>
</div>
</div> </div>
</q-card-section> </q-card-section>
<q-separator /> <q-separator />

View file

@ -0,0 +1,600 @@
<script setup lang="ts">
import { ref, onMounted, reactive } from "vue";
import { useQuasar } from "quasar";
import { useRoute } from "vue-router";
import { checkPermission } from "@/utils/permissions";
import { useCounterMixin } from "@/stores/mixin";
import http from "@/plugins/http";
import config from "@/app.config";
import type { QTableProps } from "quasar";
import type { DataActing } from "@/modules/04_registryPerson/interface/request/Government";
import type { ResActingPosData } from "@/modules/04_registryPerson/interface/response/Government";
import DialogHeader from "@/components/DialogHeader.vue";
import DialogHistory from "@/modules/04_registryPerson/components/detail/GovernmentInformation/05_ActingPosHistory.vue";
import DialogPreviewCommand from "@/modules/18_command/components/DialogPreviewCommand.vue";
const route = useRoute();
const $q = useQuasar();
const mixin = useCounterMixin();
const {
date2Thai,
dialogConfirm,
showLoader,
hideLoader,
messageError,
success,
pathRegistryEmp,
onSearchDataTable,
} = mixin;
const profileId = ref<string>(
route.params.id ? route.params.id.toString() : ""
);
const empType = ref<string>(pathRegistryEmp(route.name?.toString() ?? ""));
/** props*/
const isLeave = defineModel<boolean>("isLeave", {
required: true,
});
/** Table*/
const rows = ref<ResActingPosData[]>([]); //
const rowsMain = ref<ResActingPosData[]>([]); //
const mode = ref<string>("table"); // Table card
const filterKeyword = ref<string>(""); //
const columns = ref<QTableProps["columns"]>([
{
name: "dateStart",
align: "left",
label: "วันที่เริ่มต้น",
sortable: true,
field: "dateStart",
format: (v) => date2Thai(v),
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "dateEnd",
align: "left",
label: "วันที่สิ้นสุด",
sortable: true,
field: "dateEnd",
format: (v) => date2Thai(v),
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "posNo",
align: "left",
label: "ตำแหน่งเลขที่",
sortable: true,
field: "posNo",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "position",
align: "left",
label: "ตำแหน่ง",
sortable: true,
field: "position",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "refCommandNo",
align: "left",
label: "เลขที่คำสั่ง",
sortable: true,
field: "refCommandNo",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "status",
align: "left",
label: "สถานะ",
sortable: true,
field: "status",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
format(val, row) {
return row.status ? "Active" : "-";
},
},
]);
const visibleColumns = ref<String[]>([
"dateStart",
"dateEnd",
"posNo",
"position",
"refCommandNo",
"status",
]);
/** Dialog*/
const isStatusEdit = ref<boolean>(false);
const modal = ref<boolean>(false);
const modalHistory = ref<boolean>(false);
const rowId = ref<string>("");
const modalCommand = ref<boolean>(false);
const command = ref<string>("");
const commandId = ref<string>("");
const formData = reactive<DataActing>({
dateStart: null,
dateEnd: null,
posNo: "",
position: "",
status: false,
});
/** ฟังก์ค้นหาข้อมูลรายการ */
function serchDataTable() {
rows.value = onSearchDataTable(
filterKeyword.value,
rowsMain.value,
columns.value ? columns.value : []
);
}
async function fetchData() {
showLoader();
await http
.get(config.API.profileActposition(empType.value, profileId.value))
.then((res) => {
const data = res.data.result;
rows.value = data;
rowsMain.value = data;
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
function onSubmit() {
dialogConfirm($q, async () => {
showLoader();
const body = {
...formData,
profileId: isStatusEdit.value ? undefined : profileId.value,
};
const method = isStatusEdit.value ? "patch" : "post";
await http[method](
config.API.profileActposition(
empType.value,
isStatusEdit.value ? rowId.value : ""
),
body
)
.then(async () => {
await fetchData();
success($q, "บันทึกข้อมูลสำเร็จ");
closeDialogForm();
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
});
}
function openEditDialog(data: ResActingPosData) {
modal.value = true;
isStatusEdit.value = true;
rowId.value = data.id;
formData.dateStart = data.dateStart;
formData.dateEnd = data.dateEnd;
formData.posNo = data.posNo;
formData.position = data.position;
formData.status = data.status;
}
function showHistoryDialog(id: string) {
modalHistory.value = true;
rowId.value = id;
}
function openViewCommand(data: ResActingPosData) {
command.value = data.refCommandNo;
commandId.value = data.commandId;
modalCommand.value = true;
}
function closeDialogForm() {
modal.value = false;
isStatusEdit.value = false;
rowId.value = "";
formData.dateStart = null;
formData.dateEnd = null;
formData.posNo = "";
formData.position = "";
formData.status = false;
}
onMounted(() => {
fetchData();
});
</script>
<template>
<div class="row items-center q-gutter-x-sm q-pb-sm">
<q-btn
v-if="!isLeave && checkPermission($route)?.attrIsUpdate"
dense
color="primary"
icon="add"
flat
round
@click.stop.prevent="modal = true"
>
<q-tooltip>เพมขอม</q-tooltip>
</q-btn>
<q-space />
<q-input
standout
dense
v-model="filterKeyword"
ref="filterRef"
outlined
placeholder="ค้นหา"
@keydown.enter.pervent="serchDataTable"
>
<template v-slot:append>
<q-icon name="search" />
</template>
</q-input>
<q-select
v-if="mode == 'table'"
v-model="visibleColumns"
multiple
outlined
dense
options-dense
:display-value="$q.lang.table.columns"
emit-value
map-options
:options="columns"
option-value="name"
style="min-width: 140px"
/>
<q-btn-toggle
v-model="mode"
dense
class="no-shadow toggle-borderd"
toggle-color="grey-4"
:options="[
{ value: 'table', slot: 'table' },
{ value: 'card', slot: 'card' },
]"
>
<template v-slot:table>
<q-icon
name="format_list_bulleted"
size="24px"
:style="{
color: mode === 'table' ? '#787B7C' : '#C9D3DB',
}"
/>
</template>
<template v-slot:card>
<q-icon
name="mdi-view-grid-outline"
size="24px"
:style="{
color: mode === 'card' ? '#787B7C' : '#C9D3DB',
}"
/>
</template>
</q-btn-toggle>
</div>
<d-table
:card-container-class="mode === 'card' ? 'q-col-gutter-md' : ''"
:grid="mode === 'card'"
ref="table"
row-key="id"
flat
bordered
dense
:columns="columns"
:rows="rows"
:paging="true"
:rows-per-page-options="[10, 25, 50, 100]"
:visible-columns="visibleColumns"
>
>
<template v-slot:header="props">
<q-tr :props="props">
<q-th auto-width></q-th>
<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" v-if="mode === 'table'">
<q-tr :props="props">
<q-td auto-width>
<q-btn
flat
dense
round
color="deep-purple"
icon="mdi-history"
@click.stop.prevent="showHistoryDialog(props.row.id)"
>
<q-tooltip>ประวแกไขรกษาการในตำแหน</q-tooltip>
</q-btn>
<q-btn
v-if="!isLeave && checkPermission($route)?.attrIsUpdate"
flat
dense
round
:color="props.row.commandId ? 'grey-5' : 'edit'"
:disable="props.row.commandId !== null"
icon="edit"
@click.stop.prevent="openEditDialog(props.row)"
>
<q-tooltip>แกไขขอม</q-tooltip>
</q-btn>
</q-td>
<q-td v-for="col in props.cols" :key="col.id">
<div
v-if="col.name == 'refCommandNo' && props.row.commandId"
@click="col.value ? openViewCommand(props.row) : null"
:class="
col.value
? 'table_ellipsis text-blue cursor-pointer'
: 'table_ellipsis'
"
>
{{ col.value ? col.value : "-" }}
<q-tooltip v-if="col.value">ดูคำสั่ง</q-tooltip>
</div>
<div v-else>
{{ col.value ? col.value : "-" }}
</div>
</q-td>
</q-tr>
</template>
<template v-slot:item="props" v-else>
<div class="col-xs-12 col-sm-6 col-md-6">
<q-card flat bordered class="q-pa-none">
<div class="row bg-grey-3">
<q-space />
<div>
<q-btn
color="deep-purple"
icon="mdi-history"
flat
round
@click.stop.prevent="showHistoryDialog(props.row.id)"
>
<q-tooltip>ประวแกไขรกษาการในตำแหน</q-tooltip>
</q-btn>
<q-btn
v-if="
isLeave === false && checkPermission($route)?.attrIsUpdate
"
:color="props.row.commandId ? 'grey-5' : 'edit'"
:disable="props.row.commandId !== null"
icon="edit"
flat
round
@click.stop.prevent="openEditDialog(props.row)"
>
<q-tooltip>แกไขขอม</q-tooltip>
</q-btn>
</div>
</div>
<q-separator />
<q-card-section class="q-pa-none">
<div class="row q-pa-sm">
<div class="col-3 text-grey-6 text-weight-medium">
นทเรมต
</div>
<div class="col-3">
{{ props.row.dateStart ? date2Thai(props.row.dateStart) : "-" }}
</div>
<div class="col-3 text-grey-6 text-weight-medium">
นทนส
</div>
<div class="col-3">
{{ props.row.dateEnd ? date2Thai(props.row.dateEnd) : "-" }}
</div>
</div>
<q-separator />
<div class="row q-pa-sm bg-grey-2">
<div class="col-3 text-grey-6 text-weight-medium">
ตำแหนงเลขท
</div>
<div class="col-3">
{{ props.row.posNo ? props.row.posNo : "-" }}
</div>
<div class="col-3 text-grey-6 text-weight-medium">ตำแหน</div>
<div class="col-3">
{{ props.row.position ? props.row.position : "-" }}
</div>
</div>
<q-separator />
<div class="row q-pa-sm">
<div class="col-3 text-grey-6 text-weight-medium">
เลขทคำส
</div>
<div
v-if="props.row.commandId"
@click="openViewCommand(props.row)"
class="col-3 text-blue"
>
{{ props.row.refCommandNo }}
<q-tooltip v-if="props.row.commandId">ดูคำสั่ง</q-tooltip>
</div>
<div class="col-3" v-else>-</div>
<div class="col-3 text-grey-6 text-weight-medium">สถานะ</div>
<div class="col-3">
{{ props.row.status ? "Active" : "-" }}
</div>
</div>
<q-separator />
</q-card-section>
</q-card>
</div>
</template>
</d-table>
<q-dialog v-model="modal" persistent>
<q-card style="width: 700px; max-width: 80vw">
<q-form @submit.prevent greedy @validation-success="onSubmit()">
<DialogHeader
:tittle="
isStatusEdit
? 'แก้ไขข้อมูลรายการรักษาการในตำแหน่ง'
: 'เพิ่มข้อมูลรายการรักษาการในตำแหน่ง'
"
:close="closeDialogForm"
/>
<q-separator />
<q-card-section style="max-height: 50vh">
<div class="row col-12 q-col-gutter-x-xs q-col-gutter-y-xs">
<div class="col-xs-12 col-sm-6 col-md-6">
<datepicker
menu-class-name="modalfix"
v-model="formData.dateStart"
:locale="'th'"
autoApply
:enableTimePicker="false"
week-start="0"
:max-date="formData.dateEnd"
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
ref="dateRef"
class="full-width inputgreen cursor-pointer"
outlined
dense
:model-value="date2Thai(formData.dateStart)"
:rules="[(val:string) => !!val || `${'กรุณาเลือก วันที่เริ่มต้น'}`]"
hide-bottom-space
:label="`${'วันที่เริ่มต้น'}`"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
color="primary"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<div class="col-xs-12 col-sm-6 col-md-6">
<datepicker
menu-class-name="modalfix"
v-model="formData.dateEnd"
:locale="'th'"
autoApply
:enableTimePicker="false"
week-start="0"
:min-date="formData.dateStart"
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
ref="dateRef"
class="full-width inputgreen cursor-pointer"
outlined
dense
:model-value="date2Thai(formData.dateEnd)"
:rules="[(val:string) => !!val || `${'กรุณาเลือก วันที่สิ้นสุด'}`]"
hide-bottom-space
:label="`${'วันที่สิ้นสุด'}`"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
color="primary"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<div class="col-xs-12 col-sm-6 col-md-6">
<q-input
class="full-width inputgreen cursor-pointer"
outlined
dense
lazy-rules
v-model="formData.posNo"
:rules="[(val:string) => !!val || `${'กรุณากรอกตำแหน่งเลขที่'}`]"
hide-bottom-space
:label="`${'ตำแหน่งเลขที่'}`"
/>
</div>
<div class="col-xs-12 col-sm-6 col-md-6">
<q-input
class="full-width inputgreen cursor-pointer"
outlined
dense
lazy-rules
v-model="formData.position"
:rules="[(val:string) => !!val || `${'กรุณากรอกตำแหน่ง'}`]"
hide-bottom-space
:label="`${'ตำแหน่ง'}`"
/>
</div>
<div class="col-xs-12 col-sm-6 col-md-6">
<q-checkbox
disable
v-model="formData.status"
label="Active"
keep-color="primary"
/>
</div>
</div>
</q-card-section>
<q-separator />
<q-card-actions align="right">
<q-btn label="บันทึก" id="onSubmit" type="submit" color="public">
<q-tooltip>นทกขอม</q-tooltip>
</q-btn>
</q-card-actions>
</q-form>
</q-card>
</q-dialog>
<DialogHistory v-model:modal="modalHistory" v-model:id="rowId" />
<DialogPreviewCommand
v-model:modal="modalCommand"
v-model:command="command"
v-model:command-id="commandId"
/>
</template>
<style scoped></style>

View file

@ -0,0 +1,231 @@
<script setup lang="ts">
import { ref, watch } from "vue";
import DialogHeader from "@/components/DialogHeader.vue";
import { useCounterMixin } from "@/stores/mixin";
import { useQuasar, type QTableProps } from "quasar";
import http from "@/plugins/http";
import config from "@/app.config";
import type { ResponseObject } from "@/modules/04_registryPerson/interface/index/performSpecialWork";
import { useRoute } from "vue-router";
const modal = defineModel<boolean>("modal", { required: true });
const id = defineModel<string>("id", { required: true });
const route = useRoute();
const $q = useQuasar();
const mixin = useCounterMixin();
const {
showLoader,
hideLoader,
messageError,
date2Thai,
pathRegistryEmp,
onSearchDataTable,
} = mixin;
const empType = ref<string>(pathRegistryEmp(route.name?.toString() ?? ""));
const filterKeyword = ref<string>(""); //
const rows = ref<ResponseObject[]>([]); //data history
const rowsMain = ref<ResponseObject[]>([]); //data history
const columns = ref<QTableProps["columns"]>([
{
name: "dateStart",
align: "left",
label: "วันที่เริ่มต้น",
sortable: true,
field: "dateStart",
format: (v) => date2Thai(v),
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "dateEnd",
align: "left",
label: "วันที่สิ้นสุด",
sortable: true,
field: "dateEnd",
format: (v) => date2Thai(v),
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "posNo",
align: "left",
label: "ตำแหน่งเลขที่",
sortable: true,
field: "posNo",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "position",
align: "left",
label: "ตำแหน่ง",
sortable: true,
field: "position",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "status",
align: "left",
label: "สถานะ",
sortable: true,
field: "status",
format(val, row) {
return row.status ? "Active" : "-";
},
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "lastUpdateFullName",
align: "left",
label: "ผู้ดำเนินการ",
sortable: true,
field: "lastUpdateFullName",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "lastUpdatedAt",
align: "left",
label: "วันที่แก้ไข",
sortable: true,
field: "lastUpdatedAt",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
format: (v) => date2Thai(v, false, true),
},
]);
const visibleColumns = ref<String[]>([
"dateStart",
"dateEnd",
"posNo",
"position",
"status",
"lastUpdateFullName",
"lastUpdatedAt",
]);
const historyPagination = ref({
page: 1,
rowsPerPage: 10,
});
/** function fetch ข้อมูลประวติการแก้ไขข้อมูล*/
function fetchDataHistory() {
showLoader();
http
.get(config.API.profileActpositionHistory(id.value, empType.value))
.then((res) => {
let data = res.data.result;
rows.value = data;
rowsMain.value = data;
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
}
function serchDataTable() {
rows.value = onSearchDataTable(
filterKeyword.value,
rowsMain.value,
columns.value ? columns.value : []
);
}
/**
* การเปลยนแปลงของ modal
* modal เป true เรยก fetchDataHistory เพอดงขอมลประวการแกไข
*/
watch(modal, (status) => {
if (status == true) {
fetchDataHistory();
filterKeyword.value = "";
} else {
filterKeyword.value = "";
rows.value = [];
rowsMain.value = [];
}
});
</script>
<template>
<q-dialog v-model="modal" persistent>
<q-card style="min-width: 80%">
<DialogHeader
tittle="ประวัติแก้ไขรักษาการในตำแหน่ง"
:close="() => ((modal = false), (rows = []))"
/>
<q-separator />
<q-card-section style="max-height: 60vh" class="scroll">
<div class="row q-gutter-sm q-mb-sm">
<q-space />
<q-input
standout
dense
v-model="filterKeyword"
ref="filterRef"
outlined
placeholder="ค้นหา"
@keydown.enter.pervent="serchDataTable"
>
<template v-slot:append>
<q-icon name="search" />
</template>
</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"
style="min-width: 140px"
/>
</div>
<d-table
ref="table"
flat
bordered
dense
:columns="columns"
:rows="rows"
:paging="true"
v-model:pagination="historyPagination"
:rows-per-page-options="[10, 25, 50, 100]"
: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-tr>
</template>
<template v-slot:body="props">
<q-tr :props="props">
<q-td v-for="col in props.cols" :key="col.id">
<div class="table_ellipsis">
{{ col.value ? col.value : "-" }}
</div>
</q-td>
</q-tr>
</template>
</d-table>
</q-card-section>
</q-card>
</q-dialog>
</template>

View file

@ -0,0 +1,811 @@
<script setup lang="ts">
import { ref, onMounted, reactive } from "vue";
import { useQuasar } from "quasar";
import axios from "axios";
import { useRoute } from "vue-router";
import { checkPermission } from "@/utils/permissions";
import { useCounterMixin } from "@/stores/mixin";
import http from "@/plugins/http";
import config from "@/app.config";
import type { QTableProps } from "quasar";
import type { DatAssistance } from "@/modules/04_registryPerson/interface/request/Government";
import type {
ResAssistanceData,
ResFileData,
} from "@/modules/04_registryPerson/interface/response/Government";
import DialogHeader from "@/components/DialogHeader.vue";
import DialogHistory from "@/modules/04_registryPerson/components/detail/GovernmentInformation/06_HelpGovernmentHistory.vue";
import DialogPreviewCommand from "@/modules/18_command/components/DialogPreviewCommand.vue";
const route = useRoute();
const $q = useQuasar();
const mixin = useCounterMixin();
const {
date2Thai,
dialogConfirm,
showLoader,
hideLoader,
messageError,
success,
pathRegistryEmp,
onSearchDataTable,
} = mixin;
const profileId = ref<string>(
route.params.id ? route.params.id.toString() : ""
);
const empType = ref<string>(pathRegistryEmp(route.name?.toString() ?? ""));
/** props*/
const isLeave = defineModel<boolean>("isLeave", {
required: true,
});
/** Table*/
const rows = ref<ResAssistanceData[]>([]); //
const rowsMain = ref<ResAssistanceData[]>([]); //
const mode = ref<string>("table"); // Table card
const filterKeyword = ref<string>(""); //
const columns = ref<QTableProps["columns"]>([
{
name: "agency",
align: "left",
label: "หน่วยงานที่ให้ช่วยราชการ",
sortable: true,
field: "agency",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "dateStart",
align: "left",
label: "วันเริ่มช่วยราชการ",
sortable: true,
field: "dateStart",
format: (v) => date2Thai(v),
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "dateEnd",
align: "left",
label: "วันสิ้นสุดการช่วยราชการ",
sortable: true,
field: "dateEnd",
format: (v) => date2Thai(v),
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "commandNo",
align: "left",
label: "เลขที่คำสั่ง",
sortable: true,
field: "commandNo",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "document",
align: "left",
label: "เอกสารอ้างอิง",
sortable: true,
field: "document",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
]);
const visibleColumns = ref<String[]>([
"agency",
"dateStart",
"dateEnd",
"commandNo",
"document",
]);
/** Dialog*/
const isStatusEdit = ref<boolean>(false);
const isUpload = ref<boolean>(false);
const rowId = ref<string>("");
const modal = ref<boolean>(false);
const modalHistory = ref<boolean>(false);
const modalCommand = ref<boolean>(false);
const command = ref<string>("");
const commandId = ref<string>("");
const formData = reactive<DatAssistance>({
agency: "",
dateStart: null,
dateEnd: null,
commandNo: "",
document: "",
// isUpload: false,
});
const fileUpload = ref<File>();
const fileData = ref<ResFileData>();
/** ฟังก์ค้นหาข้อมูลรายการ */
function serchDataTable() {
rows.value = onSearchDataTable(
filterKeyword.value,
rowsMain.value,
columns.value ? columns.value : []
);
}
async function fetchData() {
showLoader();
await http
.get(config.API.profileAssistance(empType.value, profileId.value))
.then((res) => {
const data = res.data.result;
rows.value = data;
rowsMain.value = data;
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
function onSubmit() {
dialogConfirm($q, async () => {
showLoader();
const body = {
...formData,
profileId: isStatusEdit.value ? undefined : profileId.value,
isUpload: !isStatusEdit.value ? undefined : isUpload.value,
};
const method = isStatusEdit.value ? "patch" : "post";
await http[method](
config.API.profileAssistance(
empType.value,
isStatusEdit.value ? rowId.value : ""
),
body
)
.then(async (res) => {
if (fileUpload.value) {
const id = isStatusEdit.value ? rowId.value : res.data.result;
await uploadProfile(id);
}
await fetchData();
success($q, "บันทึกข้อมูลสำเร็จ");
closeDialogForm();
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
});
}
/**
* งกนสราง Path ปโหลดไฟล
* @param id
*/
async function uploadProfile(id: string) {
await http
.post(
config.API.subFile("ทะเบียนประวัติ", "ช่วยราชการ", profileId.value, id),
{
replace: true,
fileList: [
{
fileName: "เอกสารหลักฐาน",
},
],
}
)
.then(async (res) => {
const uploadUrl = res.data["เอกสารหลักฐาน"].uploadUrl;
await uploadFileURL(uploadUrl, fileUpload.value, id);
})
.catch((err) => {
messageError($q, err);
});
}
/**
* งกนอปโหลไฟล
* @param uploadUrl Path ปโหลดไฟล
* @param file ไฟลเอกสาร
*/
async function uploadFileURL(uploadUrl: string, file: any, id: string) {
await axios
.put(uploadUrl, file, {
headers: {
"Content-Type": file.type,
},
})
.then(async () => {
await updateIsUpload(id, true);
fileUpload.value = undefined;
})
.catch(async (err) => {
await updateIsUpload(id, false);
messageError($q, err);
});
}
async function updateIsUpload(id: string, val: boolean) {
await http
.patch(config.API.profileAssistance(empType.value, id), { isUpload: val })
.then(async (res) => {})
.catch((err) => {
messageError($q, err);
});
}
/**
* งกนโหลไฟลเอกสารหลกฐาน
* @param id รายการทองการโหลด
*/
async function onDownloadFile(id: string, isLoad: boolean = true) {
showLoader();
await http
.get(
config.API.subFileByFileName(
"ทะเบียนประวัติ",
"ช่วยราชการ",
profileId.value,
id,
"เอกสารหลักฐาน"
)
)
.then(async (res) => {
const data = res.data;
fileData.value = data;
if (isLoad) {
window.open(data.downloadUrl, "_blank");
}
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
function openEditDialog(data: ResAssistanceData) {
modal.value = true;
isStatusEdit.value = true;
rowId.value = data.id;
formData.agency = data.agency;
formData.dateStart = data.dateStart;
formData.dateEnd = data.dateEnd;
formData.commandNo = data.commandNo;
formData.document = data.document;
isUpload.value = data.isUpload;
if (isUpload.value) {
onDownloadFile(data.id, false);
}
}
function showHistoryDialog(id: string) {
modalHistory.value = true;
rowId.value = id;
}
function openViewCommand(data: ResAssistanceData) {
command.value = data.commandNo;
commandId.value = data.commandId;
modalCommand.value = true;
}
function closeDialogForm() {
modal.value = false;
isStatusEdit.value = false;
rowId.value = "";
formData.agency = "";
formData.dateStart = null;
formData.dateEnd = null;
formData.commandNo = "";
formData.document = "";
isUpload.value = false;
fileUpload.value = undefined;
}
onMounted(() => {
fetchData();
});
</script>
<template>
<div class="row items-center q-gutter-x-sm q-pb-sm">
<q-btn
v-if="!isLeave && checkPermission($route)?.attrIsUpdate"
dense
color="primary"
icon="add"
flat
round
@click.stop.prevent="modal = true"
>
<q-tooltip>เพมขอม</q-tooltip>
</q-btn>
<q-space />
<q-input
standout
dense
v-model="filterKeyword"
ref="filterRef"
outlined
placeholder="ค้นหา"
@keydown.enter.pervent="serchDataTable"
>
<template v-slot:append>
<q-icon name="search" />
</template>
</q-input>
<q-select
v-if="mode == 'table'"
v-model="visibleColumns"
multiple
outlined
dense
options-dense
:display-value="$q.lang.table.columns"
emit-value
map-options
:options="columns"
option-value="name"
style="min-width: 140px"
/>
<q-btn-toggle
v-model="mode"
dense
class="no-shadow toggle-borderd"
toggle-color="grey-4"
:options="[
{ value: 'table', slot: 'table' },
{ value: 'card', slot: 'card' },
]"
>
<template v-slot:table>
<q-icon
name="format_list_bulleted"
size="24px"
:style="{
color: mode === 'table' ? '#787B7C' : '#C9D3DB',
}"
/>
</template>
<template v-slot:card>
<q-icon
name="mdi-view-grid-outline"
size="24px"
:style="{
color: mode === 'card' ? '#787B7C' : '#C9D3DB',
}"
/>
</template>
</q-btn-toggle>
</div>
<d-table
:card-container-class="mode === 'card' ? 'q-col-gutter-md' : ''"
:grid="mode === 'card'"
ref="table"
row-key="id"
flat
bordered
dense
:columns="columns"
:rows="rows"
:paging="true"
:rows-per-page-options="[10, 25, 50, 100]"
:visible-columns="visibleColumns"
>
>
<template v-slot:header="props">
<q-tr :props="props">
<q-th auto-width />
<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" v-if="mode === 'table'">
<q-tr :props="props">
<q-td auto-width>
<q-btn
flat
dense
round
color="deep-purple"
icon="mdi-history"
@click.stop.prevent="showHistoryDialog(props.row.id)"
>
<q-tooltip>ประวแกไขรายการชวยราชการ</q-tooltip>
</q-btn>
<q-btn
v-if="!isLeave && checkPermission($route)?.attrIsUpdate"
flat
dense
round
:color="props.row.commandId ? 'grey-5' : 'edit'"
:disable="props.row.commandId !== null"
icon="edit"
@click.stop.prevent="openEditDialog(props.row)"
>
<q-tooltip>แกไขขอม</q-tooltip>
</q-btn>
</q-td>
<q-td v-for="col in props.cols" :key="col.id">
<div
v-if="col.name == 'commandNo' && props.row.commandId"
@click="col.value ? openViewCommand(props.row) : null"
:class="
col.value
? 'table_ellipsis text-blue cursor-pointer'
: 'table_ellipsis'
"
>
{{ col.value ? col.value : "-" }}
<q-tooltip v-if="col.value">ดูคำสั่ง</q-tooltip>
</div>
<div v-else>
{{ col.value ? col.value : "-" }}
</div>
</q-td>
<q-td auto-width>
<q-btn
flat
dense
round
color="green"
icon="mdi-file-document-outline"
v-if="props.row.isUpload"
@click="onDownloadFile(props.row.id)"
>
<q-tooltip>ดาวนโหลด</q-tooltip>
</q-btn>
</q-td>
</q-tr>
</template>
<template v-slot:item="props" v-else>
<div class="col-xs-12 col-sm-6 col-md-6">
<q-card flat bordered class="q-pa-none">
<div class="row bg-grey-3">
<q-space />
<div>
<q-btn
color="deep-purple"
icon="mdi-history"
flat
round
@click.stop.prevent="showHistoryDialog(props.row.id)"
>
<q-tooltip>ประวแกไขรายการชวยราชการ</q-tooltip>
</q-btn>
<q-btn
v-if="!isLeave && checkPermission($route)?.attrIsUpdate"
:color="props.row.commandId ? 'grey-5' : 'edit'"
:disable="props.row.commandId !== null"
icon="edit"
flat
round
@click.stop.prevent="openEditDialog(props.row)"
>
<q-tooltip>แกไขขอม</q-tooltip>
</q-btn>
</div>
</div>
<q-separator />
<q-card-section class="q-pa-none">
<div class="row q-pa-sm">
<div class="col-3 text-grey-6 text-weight-medium">
หนวยงานทใหวยราชการ
</div>
<div class="col-9">
{{ props.row.agency ? props.row.agency : "-" }}
</div>
</div>
<div class="row q-pa-sm bg-grey-2">
<div class="col-3 text-grey-6 text-weight-medium">
นทเรมต
</div>
<div class="col-3">
{{ props.row.dateStart ? date2Thai(props.row.dateStart) : "-" }}
</div>
<div class="col-3 text-grey-6 text-weight-medium">
นทนส
</div>
<div class="col-3">
{{ props.row.dateEnd ? date2Thai(props.row.dateEnd) : "-" }}
</div>
</div>
<q-separator />
<div class="row q-pa-sm">
<div class="col-3 text-grey-6 text-weight-medium">
เลขทคำส
</div>
<div
v-if="props.row.commandId"
@click="openViewCommand(props.row)"
class="col-9 text-blue"
>
{{ props.row.commandNo }}
<q-tooltip v-if="props.row.commandId">ดูคำสั่ง</q-tooltip>
</div>
<div class="col-9" v-else>
{{ props.row.commandNo ? props.row.commandNo : "-" }}
</div>
</div>
<q-separator />
<div class="row q-pa-sm">
<div class="col-3 text-grey-6 text-weight-medium">
เอกสารอางอ
</div>
<div class="col-9">
{{ props.row.document ? props.row.document : "-" }}
</div>
</div>
<q-separator />
</q-card-section>
</q-card>
</div>
</template>
</d-table>
<q-dialog v-model="modal" persistent>
<q-card style="width: 700px; max-width: 80vw">
<q-form @submit.prevent greedy @validation-success="onSubmit()">
<DialogHeader
:tittle="
isStatusEdit
? 'แก้ไขข้อมูลรายการช่วยราชการ'
: 'เพิ่มข้อมูลรายการช่วยราชการ'
"
:close="closeDialogForm"
/>
<q-separator />
<q-card-section style="max-height: 50vh">
<div class="row col-12 q-col-gutter-x-xs q-col-gutter-y-xs">
<div class="col-xs-12 col-sm-12 col-md-12">
<q-input
class="full-width inputgreen cursor-pointer"
outlined
dense
lazy-rules
v-model="formData.agency"
:rules="[(val:string) => !!val || `${'กรุณากรอกหน่วยงานที่ให้ช่วยราชการ'}`]"
hide-bottom-space
:label="`${'หน่วยงานที่ให้ช่วยราชการ'}`"
/>
</div>
<div class="col-xs-12 col-sm-6 col-md-6">
<datepicker
menu-class-name="modalfix"
v-model="formData.dateStart"
:locale="'th'"
autoApply
:enableTimePicker="false"
week-start="0"
:max-date="formData.dateEnd"
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
ref="dateRef"
class="full-width inputgreen cursor-pointer"
outlined
dense
:model-value="date2Thai(formData.dateStart)"
:rules="[(val:string) => !!val || `${'กรุณาเลือก วันที่เริ่มต้น'}`]"
hide-bottom-space
:label="`${'วันที่เริ่มต้น'}`"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
color="primary"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<div class="col-xs-12 col-sm-6 col-md-6">
<datepicker
menu-class-name="modalfix"
v-model="formData.dateEnd"
:locale="'th'"
autoApply
:enableTimePicker="false"
week-start="0"
:min-date="formData.dateStart"
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
ref="dateRef"
class="full-width inputgreen cursor-pointer"
outlined
dense
:model-value="date2Thai(formData.dateEnd)"
:rules="[(val:string) => !!val || `${'กรุณาเลือก วันที่สิ้นสุด'}`]"
hide-bottom-space
:label="`${'วันที่สิ้นสุด'}`"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
color="primary"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<div class="col-xs-12 col-sm-12 col-md-12">
<q-input
class="full-width inputgreen cursor-pointer"
outlined
dense
lazy-rules
v-model="formData.commandNo"
:rules="[(val:string) => !!val || `${'กรุณากรอกเลขที่คำสั่ง'}`]"
hide-bottom-space
:label="`${'เลขที่คำสั่ง'}`"
/>
</div>
<div class="col-xs-12 col-sm-12 col-md-12">
<q-input
class="full-width inputgreen cursor-pointer"
outlined
dense
lazy-rules
v-model="formData.document"
hide-bottom-space
:label="`${'เอกสารอ้างอิง'}`"
/>
</div>
<div class="col-xs-12 col-sm-12 col-md-12">
<q-uploader
v-if="!isUpload"
color="gray"
type="file"
flat
ref="uploader"
class="full-width"
text-color="white"
:max-size="10000000"
accept=".pdf,"
bordered
label="[ไฟล์ pdf ขนาดไม่เกิน 10MB]"
@added="(v:any) => (fileUpload = v[0])"
>
<template v-slot:header="scope">
<div class="row no-wrap items-center q-pa-sm q-gutter-xs">
<q-btn
v-if="scope.queuedFiles.length > 0"
icon="clear_all"
@click="scope.removeQueuedFiles"
round
dense
flat
>
<q-tooltip>ลบทงหมด</q-tooltip>
</q-btn>
<q-btn
v-if="scope.uploadedFiles.length > 0"
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">
{{ "[ไฟล์ pdf ขนาดไม่เกิน 10MB]" }}
</div>
<div class="q-uploader__subtitle">
{{ scope.uploadSizeLabel }} /
{{ scope.uploadProgressLabel }}
</div>
</div>
<q-btn
v-if="scope.canAddFiles"
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"
icon="clear"
@click="scope.abort"
round
dense
flat
>
<q-tooltip>ยกเลกการอปโหลด</q-tooltip>
</q-btn>
</div>
</template>
</q-uploader>
<q-list bordered dense separator v-else>
<q-item>
<q-item-section> {{ fileData?.fileName }}</q-item-section>
<q-item-section avatar>
<div class="row">
<q-btn
flat
round
color="primary"
icon="mdi-download"
@click="onDownloadFile(rowId)"
/>
<q-btn
flat
round
color="grey"
icon="close"
@click="isUpload = false"
/>
</div>
</q-item-section>
</q-item>
</q-list>
</div>
</div>
</q-card-section>
<q-separator />
<q-card-actions align="right">
<q-btn label="บันทึก" id="onSubmit" type="submit" color="public">
<q-tooltip>นทกขอม</q-tooltip>
</q-btn>
</q-card-actions>
</q-form>
</q-card>
</q-dialog>
<DialogHistory v-model:modal="modalHistory" v-model:id="rowId" />
<DialogPreviewCommand
v-model:modal="modalCommand"
v-model:command="command"
v-model:command-id="commandId"
/>
</template>
<style scoped></style>

View file

@ -0,0 +1,226 @@
<script setup lang="ts">
import { ref, watch } from "vue";
import DialogHeader from "@/components/DialogHeader.vue";
import { useCounterMixin } from "@/stores/mixin";
import { useQuasar, type QTableProps } from "quasar";
import http from "@/plugins/http";
import config from "@/app.config";
import type { ResponseObject } from "@/modules/04_registryPerson/interface/index/performSpecialWork";
import { useRoute } from "vue-router";
const modal = defineModel<boolean>("modal", { required: true });
const id = defineModel<string>("id", { required: true });
const route = useRoute();
const $q = useQuasar();
const mixin = useCounterMixin();
const {
showLoader,
hideLoader,
messageError,
date2Thai,
pathRegistryEmp,
onSearchDataTable,
} = mixin;
const empType = ref<string>(pathRegistryEmp(route.name?.toString() ?? ""));
const filterKeyword = ref<string>(""); //
const rows = ref<ResponseObject[]>([]); //data history
const rowsMain = ref<ResponseObject[]>([]); //data history
const columns = ref<QTableProps["columns"]>([
{
name: "agency",
align: "left",
label: "หน่วยงานที่ให้ช่วยราชการ",
sortable: true,
field: "agency",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "dateStart",
align: "left",
label: "วันเริ่มช่วยราชการ",
sortable: true,
field: "dateStart",
format: (v) => date2Thai(v),
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "dateEnd",
align: "left",
label: "วันสิ้นสุดการช่วยราชการ",
sortable: true,
field: "dateEnd",
format: (v) => date2Thai(v),
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "commandNo",
align: "left",
label: "เลขที่คำสั่ง",
sortable: true,
field: "commandNo",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "document",
align: "left",
label: "เอกสารอ้างอิง",
sortable: true,
field: "document",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "lastUpdateFullName",
align: "left",
label: "ผู้ดำเนินการ",
sortable: true,
field: "lastUpdateFullName",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "lastUpdatedAt",
align: "left",
label: "วันที่แก้ไข",
sortable: true,
field: "lastUpdatedAt",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
format: (v) => date2Thai(v, false, true),
},
]);
const visibleColumns = ref<String[]>([
"agency",
"dateStart",
"dateEnd",
"commandNo",
"document",
"lastUpdateFullName",
"lastUpdatedAt",
]);
const historyPagination = ref({
page: 1,
rowsPerPage: 10,
});
/** function fetch ข้อมูลประวติการแก้ไขข้อมูล*/
function fetchDataHistory() {
showLoader();
http
.get(config.API.profileAssistanceHistory(id.value, empType.value))
.then((res) => {
let data = res.data.result;
rows.value = data;
rowsMain.value = rows.value;
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
}
function serchDataTable() {
rows.value = onSearchDataTable(
filterKeyword.value,
rowsMain.value,
columns.value ? columns.value : []
);
}
/**
* การเปลยนแปลงของ modal
* modal เป true เรยก fetchDataHistory เพอดงขอมลประวการแกไข
*/
watch(modal, (status) => {
if (status == true) {
fetchDataHistory();
filterKeyword.value = "";
} else {
filterKeyword.value = "";
}
});
</script>
<template>
<q-dialog v-model="modal" persistent>
<q-card style="min-width: 80%">
<DialogHeader
tittle="ประวัติแก้ไขรายการช่วยราชการ"
:close="() => ((modal = false), (rows = []))"
/>
<q-separator />
<q-card-section style="max-height: 60vh" class="scroll">
<div class="row q-gutter-sm q-mb-sm">
<q-space />
<q-input
standout
dense
v-model="filterKeyword"
ref="filterRef"
outlined
placeholder="ค้นหา"
@keydown.enter.pervent="serchDataTable"
>
<template v-slot:append>
<q-icon name="search" />
</template>
</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"
style="min-width: 140px"
/>
</div>
<d-table
ref="table"
flat
bordered
dense
:columns="columns"
:rows="rows"
:paging="true"
v-model:pagination="historyPagination"
:rows-per-page-options="[10, 25, 50, 100]"
: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-tr>
</template>
<template v-slot:body="props">
<q-tr :props="props">
<q-td v-for="col in props.cols" :key="col.id">
<div class="table_ellipsis">
{{ col.value ? col.value : "-" }}
</div>
</q-td>
</q-tr>
</template>
</d-table>
</q-card-section>
</q-card>
</q-dialog>
</template>

View file

@ -6,6 +6,8 @@ import Info from "@/modules/04_registryPerson/components/detail/GovernmentInform
import Discipline from "@/modules/04_registryPerson/components/detail/GovernmentInformation/02_Discipline.vue"; // import Discipline from "@/modules/04_registryPerson/components/detail/GovernmentInformation/02_Discipline.vue"; //
import Leave from "@/modules/04_registryPerson/components/detail/GovernmentInformation/03_Leave.vue"; // import Leave from "@/modules/04_registryPerson/components/detail/GovernmentInformation/03_Leave.vue"; //
import PerformSpecialWork from "@/modules/04_registryPerson/components/detail/GovernmentInformation/04_PerformSpecialWork.vue"; // import PerformSpecialWork from "@/modules/04_registryPerson/components/detail/GovernmentInformation/04_PerformSpecialWork.vue"; //
import ActingPos from "@/modules/04_registryPerson/components/detail/GovernmentInformation/05_ActingPos.vue"; //
import HelpGovernmentDetail from "@/modules/04_registryPerson/components/detail/GovernmentInformation/06_HelpGovernment.vue"; //
import { useRegistryNewDataStore } from "@/modules/04_registryPerson/store"; import { useRegistryNewDataStore } from "@/modules/04_registryPerson/store";
@ -35,21 +37,29 @@ const storeRegistry = useRegistryNewDataStore();
<q-tab name="2" label="วินัย" /> <q-tab name="2" label="วินัย" />
<q-tab name="3" label="การลา" /> <q-tab name="3" label="การลา" />
<q-tab name="4" label="ปฏิบัติราชการพิเศษ" /> <q-tab name="4" label="ปฏิบัติราชการพิเศษ" />
<q-tab name="5" label="รักษาการในตำแหน่ง" />
<q-tab name="6" label="ช่วยราชการ" />
</q-tabs> </q-tabs>
<q-separator /> <q-separator />
<q-tab-panels v-model="tab" animated> <q-tab-panels v-model="tab" animated>
<q-tab-panel name="1"> <q-tab-panel name="1">
<Info :is-leave="storeRegistry.isLeave"/> <Info :is-leave="storeRegistry.isLeave" />
</q-tab-panel> </q-tab-panel>
<q-tab-panel name="2"> <q-tab-panel name="2">
<Discipline :is-leave="storeRegistry.isLeave"/> <Discipline :is-leave="storeRegistry.isLeave" />
</q-tab-panel> </q-tab-panel>
<q-tab-panel name="3"> <q-tab-panel name="3">
<Leave :is-leave="storeRegistry.isLeave"/> <Leave :is-leave="storeRegistry.isLeave" />
</q-tab-panel> </q-tab-panel>
<q-tab-panel name="4"> <q-tab-panel name="4">
<PerformSpecialWork :is-leave="storeRegistry.isLeave"/> <PerformSpecialWork :is-leave="storeRegistry.isLeave" />
</q-tab-panel>
<q-tab-panel name="5">
<ActingPos :is-leave="storeRegistry.isLeave" />
</q-tab-panel>
<q-tab-panel name="6">
<HelpGovernmentDetail :is-leave="storeRegistry.isLeave" />
</q-tab-panel> </q-tab-panel>
</q-tab-panels> </q-tab-panels>
</template> </template>

View file

@ -0,0 +1,275 @@
<script setup lang="ts">
import { ref, onMounted } from "vue";
import { useQuasar } from "quasar";
import axios from "axios";
import { checkPermission } from "@/utils/permissions";
import { useRoute } from "vue-router";
import http from "@/plugins/http";
import config from "@/app.config";
import { useCounterMixin } from "@/stores/mixin";
import type { ArrayFileList } from "@/modules/04_registryPerson/interface/index/document";
const $q = useQuasar();
const route = useRoute();
const mixin = useCounterMixin();
const {
success,
messageError,
showLoader,
hideLoader,
dialogConfirm,
dialogRemove,
} = mixin;
/**
* props
*/
const isLeave = defineModel<boolean>("isLeave", {
required: true,
});
const profileId = ref<string>(
route.params.id ? route.params.id.toString() : ""
);
const documentFile = ref<any>(null);
const fileList = ref<ArrayFileList[]>([]); //
/**
* งกนดงขอมลรายการเอกสารหลกฐาน
*/
async function getData() {
showLoader();
await http
.get(
config.API.file("ระบบทะเบียนประวัติ", "เอกสารหลักฐานเพิ่มเติม", profileId.value)
)
.then((res) => {
console.log("ระบบทะเบียนประวัติ", "เอกสารหลักฐานเพิ่มเติม", profileId.value)
fileList.value = res.data;
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
}
/**
* งกนสราง Path สำหรบอพโหลดไฟลเอกสารหลกฐาน
*/
function clickUpload(file: any) {
const fileName = { fileName: file.name };
dialogConfirm(
$q,
async () => {
showLoader();
const selectedFile = file;
const formdata = new FormData();
formdata.append("file", selectedFile);
await http
.post(
config.API.file(
"ระบบทะเบียนประวัติ",
"เอกสารหลักฐานเพิ่มเติม",
profileId.value
),
{
replace: false,
fileList: fileName,
}
)
.then(async (res) => {
const foundKey: string | undefined = Object.keys(res.data).find(
(key) =>
res.data[key]?.fileName !== undefined &&
res.data[key]?.fileName !== ""
);
foundKey &&
uploadFileDoc(res.data[foundKey]?.uploadUrl, documentFile.value);
})
.catch((err) => {
messageError($q, err);
});
},
"ยืนยันการอัปโหลดไฟล์",
"ต้องการยืนยันการอัปโหลดไฟล์นี้หรือไม่ ?"
);
}
/**
* งกนสำหรบอพโหลดไฟลเอกสารหลกฐาน
*/
async function uploadFileDoc(uploadUrl: string, file: any) {
const Data = new FormData();
Data.append("file", documentFile.value);
showLoader();
await axios
.put(uploadUrl, file, {
headers: {
"Content-Type": file.type,
},
})
.then(async () => {
await getData();
success($q, "อัปโหลดไฟล์สำเร็จ");
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
documentFile.value = null;
});
}
/**
* ดาวนโหลดลงกไฟล
* @param fileName file name
*/
function downloadFile(fileName: string) {
showLoader();
http
.get(
config.API.fileByFile(
"ระบบทะเบียนประวัติ",
"เอกสารหลักฐานเพิ่มเติม",
profileId.value,
fileName
)
)
.then((res) => {
const data = res.data.downloadUrl;
window.open(data, "_blank");
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
hideLoader();
});
}
/**
* ลบไฟล
* @param fileName file name
*/
function deleteFile(fileName: string) {
dialogRemove($q, async () => {
showLoader();
http
.delete(
config.API.fileByFile(
"ระบบทะเบียนประวัติ",
"เอกสารหลักฐานเพิ่มเติม",
profileId.value,
fileName
)
)
.then(async () => {
await setTimeout(async () => {
await getData();
await success($q, `ลบไฟล์สำเร็จ`);
}, 1500);
})
.catch((e) => {
messageError($q, e);
hideLoader();
});
});
}
onMounted(() => {
getData();
});
</script>
<template>
<q-card bordered class="row col-12" style="border: 1px solid #d6dee1">
<div class="col-12 text-weight-medium bg-grey-1 q-py-sm q-px-md">
ปโหลดไฟลเอกสาร ..7
</div>
<div class="col-12"><q-separator /></div>
<div class="row col-12 q-col-gutter-y-sm q-pa-sm">
<div class="col-12 row">
<q-file
v-if="isLeave == false && checkPermission($route)?.attrIsUpdate"
for="inputFiles"
class="col-12"
outlined
dense
v-model="documentFile"
label="ไฟล์เอกสาร ก.พ.7"
hide-bottom-space
accept=".pdf,.xlsx,.docx,.png,.jpg"
clearable
>
<template v-slot:prepend>
<q-icon name="attach_file" color="primary" />
</template>
<template v-slot:after>
<q-btn
size="14px"
v-if="documentFile"
flat
round
dense
color="primary"
icon="mdi-upload"
@click="clickUpload(documentFile)"
><q-tooltip>ปโหลดไฟล</q-tooltip></q-btn
>
</template>
</q-file>
<!-- <div class="col-1 self-center" v-if="formData.documentFile"></div> -->
</div>
<div v-if="fileList.length > 0" class="col-xs-12 row">
<q-list class="full-width rounded-borders" bordered separator>
<q-item
clickable
v-ripple
v-for="data in fileList"
:key="data.id"
class="items-center"
>
<q-item-section>{{ data.fileName }}</q-item-section>
<q-space />
<div>
<q-btn
size="12px"
flat
round
dense
color="blue"
icon="mdi-download"
@click="downloadFile(data.fileName)"
><q-tooltip>ดาวนโหลดไฟล</q-tooltip></q-btn
>
<q-btn
v-if="isLeave == false"
size="12px"
flat
round
dense
color="red"
class="q-ml-sm"
icon="mdi-delete-outline"
@click="deleteFile(data.fileName)"
><q-tooltip>ลบไฟล</q-tooltip></q-btn
>
</div>
</q-item>
</q-list>
</div>
<div class="col-12" v-else>
<q-card class="q-pa-md" bordered> ไมรายการเอกสาร </q-card>
</div>
</div>
</q-card>
</template>
<style scoped></style>

View file

@ -6,6 +6,7 @@ import { useRegistryNewDataStore } from "@/modules/04_registryPerson/store";
/** importComponents*/ /** importComponents*/
import OtherInformation from "@/modules/04_registryPerson/components/detail/Other/01_OtherInformation.vue"; import OtherInformation from "@/modules/04_registryPerson/components/detail/Other/01_OtherInformation.vue";
import Documentipline from "@/modules/04_registryPerson/components/detail/Other/02_Document.vue"; import Documentipline from "@/modules/04_registryPerson/components/detail/Other/02_Document.vue";
import Document7 from "@/modules/04_registryPerson/components/detail/Other/03_Document7.vue";
const storeRegistry = useRegistryNewDataStore(); const storeRegistry = useRegistryNewDataStore();
@ -32,6 +33,7 @@ const tab = ref<string>("1");
> >
<q-tab name="1" label="ข้อมูลอื่นๆ" /> <q-tab name="1" label="ข้อมูลอื่นๆ" />
<q-tab name="2" label="เอกสารหลักฐาน" /> <q-tab name="2" label="เอกสารหลักฐาน" />
<q-tab name="3" label="เอกสาร ก.พ.7" />
</q-tabs> </q-tabs>
<q-separator /> <q-separator />
@ -42,6 +44,9 @@ const tab = ref<string>("1");
<q-tab-panel name="2"> <q-tab-panel name="2">
<Documentipline :is-leave="storeRegistry.isLeave" /> <Documentipline :is-leave="storeRegistry.isLeave" />
</q-tab-panel> </q-tab-panel>
<q-tab-panel name="3">
<Document7 :is-leave="storeRegistry.isLeave" />
</q-tab-panel>
</q-tab-panels> </q-tab-panels>
</template> </template>

View file

@ -17,7 +17,7 @@ import type { DataProfile } from "@/modules/04_registryPerson/interface/response
import type { FormChangeName } from "@/modules/04_registryPerson/interface/request/Main"; import type { FormChangeName } from "@/modules/04_registryPerson/interface/request/Main";
/** importComponents*/ /** importComponents*/
import dialogHeader from "@/components/DialogHeader.vue"; import DialogHeader from "@/components/DialogHeader.vue";
/** use*/ /** use*/
const $q = useQuasar(); const $q = useQuasar();
@ -314,11 +314,11 @@ async function addData() {
.then(async (res) => { .then(async (res) => {
subId.value = await res.data.result; subId.value = await res.data.result;
await uploadProfile(res.data.result); await uploadProfile(res.data.result);
closeDialog(); await fetchData(profileId.value);
await props?.fetchDataPersonal?.();
await fetchDataPersonal();
success($q, "บันทึกข้อมูลสำเร็จ"); success($q, "บันทึกข้อมูลสำเร็จ");
fetchData(profileId.value); closeDialog();
props?.fetchDataPersonal?.();
fetchDataPersonal();
}) })
.catch((err) => { .catch((err) => {
messageError($q, err); messageError($q, err);
@ -344,11 +344,11 @@ function editData(idData: string) {
) )
.then(async () => { .then(async () => {
await uploadProfile(subId.value); await uploadProfile(subId.value);
closeDialog();
success($q, "บันทึกข้อมูลสำเร็จ"); success($q, "บันทึกข้อมูลสำเร็จ");
fetchData(profileId.value); await fetchData(profileId.value);
props.fetchDataPersonal?.(); await props.fetchDataPersonal?.();
fetchDataPersonal(); await fetchDataPersonal();
closeDialog();
}) })
.catch((err) => { .catch((err) => {
messageError($q, err); messageError($q, err);
@ -553,7 +553,7 @@ onMounted(async () => {
<q-dialog v-model="dialog" persistent> <q-dialog v-model="dialog" persistent>
<q-card> <q-card>
<q-form @submit.prevent greedy @validation-success="onSubmit()"> <q-form @submit.prevent greedy @validation-success="onSubmit()">
<dialog-header tittle="เปลี่ยนชื่อ-นามสกุล" :close="closeDialog" /> <DialogHeader tittle="เปลี่ยนชื่อ - นามสกุล" :close="closeDialog" />
<q-separator /> <q-separator />
<q-card-section> <q-card-section>
<div class="row q-mb-sm"> <div class="row q-mb-sm">

View file

@ -567,7 +567,7 @@ onMounted(async () => {
</div> </div>
</div> </div>
<div class="row items-start"> <div class="row items-start">
<div class="col-2 text-grey-6 text-weight-medium">-นามสก</div> <div class="col-2 text-grey-6 text-weight-medium"> - นามสก</div>
<div class="col-6"> <div class="col-6">
{{ {{
fatherData.prefix || fatherData.firstName || fatherData.lastName fatherData.prefix || fatherData.firstName || fatherData.lastName
@ -641,7 +641,7 @@ onMounted(async () => {
</div> </div>
</div> </div>
<div class="row items-start"> <div class="row items-start">
<div class="col-2 text-grey-6 text-weight-medium">-นามสก</div> <div class="col-2 text-grey-6 text-weight-medium"> - นามสก</div>
<div class="col-6"> <div class="col-6">
{{ {{
motherData.prefix || motherData.firstName || motherData.lastName motherData.prefix || motherData.firstName || motherData.lastName
@ -739,7 +739,7 @@ onMounted(async () => {
</div> </div>
</div> </div>
<div class="row items-start"> <div class="row items-start">
<div class="col-2 text-grey-6 text-weight-medium">-นามสก</div> <div class="col-2 text-grey-6 text-weight-medium"> - นามสก</div>
<div class="col-6"> <div class="col-6">
{{ {{
coupleData.prefix || coupleData.firstName || coupleData.lastName coupleData.prefix || coupleData.firstName || coupleData.lastName
@ -840,7 +840,7 @@ onMounted(async () => {
</div> </div>
<div class="row items-start"> <div class="row items-start">
<div class="col-2 text-grey-6 text-weight-medium"> <div class="col-2 text-grey-6 text-weight-medium">
-นามสก - นามสก
</div> </div>
<div class="col-6"> <div class="col-6">
{{ {{

View file

@ -19,7 +19,7 @@ import type {
DataEducationLevel, DataEducationLevel,
} from "@/modules/04_registryPerson/interface/response/Education"; } from "@/modules/04_registryPerson/interface/response/Education";
import dialogHeader from "@/components/DialogHeader.vue"; import DialogHeader from "@/components/DialogHeader.vue";
import DialogSortEducation from "@/modules/04_registryPerson/components/detail/PersonalInformation/DialogSortEducation.vue"; import DialogSortEducation from "@/modules/04_registryPerson/components/detail/PersonalInformation/DialogSortEducation.vue";
const $q = useQuasar(); const $q = useQuasar();
@ -1046,7 +1046,7 @@ onMounted(async () => {
<q-dialog v-model="dialog" class="dialog" persistent> <q-dialog v-model="dialog" class="dialog" persistent>
<q-card> <q-card>
<q-form @submit.prevent greedy @validation-success="onSubmit()"> <q-form @submit.prevent greedy @validation-success="onSubmit()">
<dialog-header <DialogHeader
:tittle=" :tittle="
dialogStatus == 'edit' dialogStatus == 'edit'
? 'แก้ไขข้อมูลประวัติการศึกษา' ? 'แก้ไขข้อมูลประวัติการศึกษา'
@ -1481,7 +1481,7 @@ onMounted(async () => {
<!-- ประวแกไขประวการศกษา --> <!-- ประวแกไขประวการศกษา -->
<q-dialog v-model="historyDialog" class="dialog" persistent> <q-dialog v-model="historyDialog" class="dialog" persistent>
<q-card style="min-width: 80%"> <q-card style="min-width: 80%">
<dialog-header <DialogHeader
tittle="ประวัติแก้ไขประวัติการศึกษา" tittle="ประวัติแก้ไขประวัติการศึกษา"
:close="closeHistoryDialog" :close="closeHistoryDialog"
/> />

View file

@ -1,5 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, onMounted } from "vue"; import { ref, reactive, onMounted } from "vue";
import axios from "axios";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import http from "@/plugins/http"; import http from "@/plugins/http";
@ -12,6 +13,7 @@ import { useCounterMixin } from "@/stores/mixin";
import type { QTableProps } from "quasar"; import type { QTableProps } from "quasar";
import type { RequestItemsObject } from "@/modules/04_registryPerson/interface/request/SpecialSkill"; import type { RequestItemsObject } from "@/modules/04_registryPerson/interface/request/SpecialSkill";
import type { ResponseObject } from "@/modules/04_registryPerson/interface/response/SpecialSkill"; import type { ResponseObject } from "@/modules/04_registryPerson/interface/response/SpecialSkill";
import type { ResFileData } from "@/modules/04_registryPerson/interface/index/Main";
import dialogHeader from "@/components/DialogHeader.vue"; import dialogHeader from "@/components/DialogHeader.vue";
@ -30,8 +32,16 @@ const {
} = mixin; } = mixin;
const id = ref<string>(route.params.id.toString()); //id profile const id = ref<string>(route.params.id.toString()); //id profile
const profileId = ref<string>(
route.params.id ? route.params.id.toString() : ""
);
const empType = ref<string>(pathRegistryEmp(route.name?.toString() ?? "")); const empType = ref<string>(pathRegistryEmp(route.name?.toString() ?? ""));
const uploadUrl = ref<string>("");
const isUpload = ref<boolean>(false);
const fileUpload = ref<File | null>(null);
const fileData = ref<ResFileData | null>(null);
const isEdit = ref<boolean>(false);
const mode = ref<string>("table"); // Table card const mode = ref<string>("table"); // Table card
/** /**
* props * props
@ -221,6 +231,11 @@ function clearForm() {
specialSkill.field = ""; specialSkill.field = "";
specialSkill.reference = ""; specialSkill.reference = "";
specialSkill.remark = ""; specialSkill.remark = "";
isEdit.value = false;
fileUpload.value = null;
isUpload.value = false;
fileData.value = null;
} }
/** /**
@ -235,6 +250,12 @@ function editForm(row: any) {
specialSkill.reference = row.reference; specialSkill.reference = row.reference;
specialSkill.remark = row.remark; specialSkill.remark = row.remark;
dialog.value = true; dialog.value = true;
isEdit.value = true;
isUpload.value = row.isUpload;
if (isUpload.value) {
onDownloadFile(row.id, false);
}
} }
/** function fetch ข้อมูลความสามรรถพิเศษ*/ /** function fetch ข้อมูลความสามรรถพิเศษ*/
@ -285,7 +306,10 @@ async function addData() {
profileId: empType.value === "" ? id.value : undefined, profileId: empType.value === "" ? id.value : undefined,
profileEmployeeId: empType.value !== "" ? id.value : undefined, profileEmployeeId: empType.value !== "" ? id.value : undefined,
}) })
.then(async () => { .then(async (res) => {
if (fileUpload.value && res.data.result) {
await uploadProfile(res.data.result);
}
await fetchData(id.value); await fetchData(id.value);
await success($q, "บันทึกข้อมูลสำเร็จ"); await success($q, "บันทึกข้อมูลสำเร็จ");
closeDialog(); closeDialog();
@ -310,8 +334,12 @@ async function editData(idData: string) {
dateStart: null, dateStart: null,
dateEnd: null, dateEnd: null,
profileId: undefined, profileId: undefined,
isUpload: !isEdit.value ? undefined : isUpload.value,
}) })
.then(async () => { .then(async (res) => {
if (fileUpload.value && idData) {
await uploadProfile(idData);
}
await fetchData(id.value); await fetchData(id.value);
await success($q, "บันทึกข้อมูลสำเร็จ"); await success($q, "บันทึกข้อมูลสำเร็จ");
closeDialog(); closeDialog();
@ -324,9 +352,110 @@ async function editData(idData: string) {
}); });
} }
/**
* งกนสราง Path ปโหลดไฟล
* @param id
*/
async function uploadProfile(id: string) {
await http
.post(
config.API.subFile(
"ทะเบียนประวัติ",
"ประกาศเกียรติคุณ",
profileId.value,
id
),
{
replace: true,
fileList: [
{
fileName: "เอกสารหลักฐาน",
},
],
}
)
.then(async (res) => {
uploadUrl.value = res.data["เอกสารหลักฐาน"].uploadUrl;
await uploadFileURL(uploadUrl.value, fileUpload.value, id);
})
.catch((err) => {
messageError($q, err);
});
}
/**
* งกนอปโหลดำไฟล
* @param uploadUrl Path ปโหลดไฟล
* @param file ไฟลเอกสาร
*/
async function uploadFileURL(uploadUrl: string, file: any, id: string) {
await axios
.put(uploadUrl, file, {
headers: {
"Content-Type": file.type,
},
})
.then(async (res) => {
if (res.status == 200) {
await isUploadFn(id);
}
fileUpload.value = null;
})
.catch((err) => {
messageError($q, err);
});
}
async function isUploadFn(id: string) {
await http
.patch(config.API.profileNewAbilityByAbilityId(id, empType.value), {
isUpload: fileUpload.value ? true : false,
})
.then(async (res) => {})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
}
/**
* งกนโหลไฟลเอกสารหลกฐาน
* @param id รายการทองการโหลด
*/
async function onDownloadFile(id: string, isLoad: boolean = true) {
showLoader();
await http
.get(
config.API.subFileByFileName(
"ทะเบียนประวัติ",
"ประกาศเกียรติคุณ",
profileId.value,
id,
"เอกสารหลักฐาน"
)
)
.then(async (res) => {
const data = res.data;
fileData.value = data;
if (isLoad) {
window.open(data.downloadUrl, "_blank");
}
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
/** function ปิด popup ข้อมูลความสามารถพิเศษ*/ /** function ปิด popup ข้อมูลความสามารถพิเศษ*/
function closeDialog() { function closeDialog() {
dialog.value = false; dialog.value = false;
clearForm();
} }
/** function ปิด popup รายการประวัติ*/ /** function ปิด popup รายการประวัติ*/
@ -452,6 +581,7 @@ onMounted(() => {
<q-th v-for="col in props.cols" :key="col.name" :props="props"> <q-th v-for="col in props.cols" :key="col.name" :props="props">
<span class="text-weight-medium">{{ col.label }}</span> <span class="text-weight-medium">{{ col.label }}</span>
</q-th> </q-th>
<q-th auto-width />
</q-tr> </q-tr>
</template> </template>
<template v-slot:body="props" v-if="mode === 'table'"> <template v-slot:body="props" v-if="mode === 'table'">
@ -489,6 +619,19 @@ onMounted(() => {
<q-td v-for="col in props.cols" :key="col.id"> <q-td v-for="col in props.cols" :key="col.id">
<div>{{ col.value ? col.value : "-" }}</div> <div>{{ col.value ? col.value : "-" }}</div>
</q-td> </q-td>
<q-td auto-width>
<q-btn
v-if="props.row.isUpload == true"
color="green"
flat
dense
round
icon="mdi-file-document-outline"
@click="onDownloadFile(props.row.profileId)"
>
<q-tooltip>ดาวนโหลด</q-tooltip>
</q-btn>
</q-td>
</q-tr> </q-tr>
</template> </template>
<template v-slot:item="props" v-else> <template v-slot:item="props" v-else>
@ -604,6 +747,109 @@ onMounted(() => {
label="เอกสารอ้างอิง" label="เอกสารอ้างอิง"
/> />
</div> </div>
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="row">
<q-uploader
v-if="!isUpload"
color="gray"
type="file"
flat
ref="uploader"
class="full-width"
text-color="white"
:max-size="10000000"
accept=".pdf"
bordered
label="[ไฟล์ pdf ขนาดไม่เกิน 10MB]"
@added="(v:any) => (fileUpload = v[0])"
>
<template v-slot:header="scope">
<div class="row no-wrap items-center q-pa-sm q-gutter-xs">
<q-btn
v-if="scope.queuedFiles.length > 0"
icon="clear_all"
@click="scope.removeQueuedFiles"
round
dense
flat
>
<q-tooltip>ลบทงหมด</q-tooltip>
</q-btn>
<q-btn
v-if="scope.uploadedFiles.length > 0"
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">
{{ "[ไฟล์ .pdf ขนาดไม่เกิน 10MB]" }}
</div>
<div class="q-uploader__subtitle">
{{ scope.uploadSizeLabel }} /
{{ scope.uploadProgressLabel }}
</div>
</div>
<q-btn
v-if="scope.canAddFiles"
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"
icon="clear"
@click="scope.abort"
round
dense
flat
>
<q-tooltip>ยกเลกการอปโหลด</q-tooltip>
</q-btn>
</div>
</template>
</q-uploader>
<q-list bordered dense separator v-else class="full-width">
<q-item>
<q-item-section> {{ fileData?.fileName }}</q-item-section>
<q-item-section avatar>
<div class="row">
<q-btn
flat
round
color="primary"
icon="mdi-download"
@click="onDownloadFile(id)"
/>
<q-btn
flat
round
color="grey"
icon="close"
@click="isUpload = false"
/>
</div>
</q-item-section>
</q-item>
</q-list>
</div>
</div>
</div> </div>
</q-card-section> </q-card-section>

View file

@ -108,18 +108,7 @@ const columns = ref<QTableProps["columns"]>([
sort: (a: string, b: string) => sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }), a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
}, },
{
name: "isEducation",
align: "left",
label: "เป็นวุฒิการศึกษาในตำแหน่ง",
sortable: true,
field: "isEducation",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
format: (v) => (v === true ? "ใช่" : "ไม่ใช่"),
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{ {
name: "degree", name: "degree",
align: "left", align: "left",
@ -143,82 +132,94 @@ const columns = ref<QTableProps["columns"]>([
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }), a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
}, },
{ {
name: "fundName", name: "isEducation",
align: "left", align: "left",
label: "ทุน", label: "เป็นวุฒิการศึกษาในตำแหน่ง",
sortable: true, sortable: true,
field: "fundName", field: "isEducation",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "gpa",
align: "left",
label: "เกรดเฉลี่ย",
sortable: true,
field: "gpa",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "country",
align: "left",
label: "ประเทศ",
sortable: true,
field: "country",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "other",
align: "left",
label: "ข้อมูลการติดต่อ",
sortable: true,
field: "other",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "duration",
align: "left",
label: "ระยะเวลา",
sortable: true,
field: "duration",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "durationYear",
align: "left",
label: "ระยะเวลาหลักสูตร (ปี)",
sortable: true,
field: "durationYear",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "note",
align: "left",
label: "หมายเหตุ",
sortable: true,
field: "note",
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
style: "font-size: 14px", style: "font-size: 14px",
format: (v) => (v === true ? "ใช่" : "ไม่ใช่"),
sort: (a: string, b: string) => sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }), a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
}, },
// {
// name: "fundName",
// align: "left",
// label: "",
// sortable: true,
// field: "fundName",
// headerStyle: "font-size: 14px",
// style: "font-size: 14px",
// sort: (a: string, b: string) =>
// a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
// },
// {
// name: "gpa",
// align: "left",
// label: "",
// sortable: true,
// field: "gpa",
// headerStyle: "font-size: 14px",
// style: "font-size: 14px",
// sort: (a: string, b: string) =>
// a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
// },
// {
// name: "country",
// align: "left",
// label: "",
// sortable: true,
// field: "country",
// headerStyle: "font-size: 14px",
// style: "font-size: 14px",
// sort: (a: string, b: string) =>
// a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
// },
// {
// name: "other",
// align: "left",
// label: "",
// sortable: true,
// field: "other",
// headerStyle: "font-size: 14px",
// style: "font-size: 14px",
// sort: (a: string, b: string) =>
// a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
// },
// {
// name: "duration",
// align: "left",
// label: "",
// sortable: true,
// field: "duration",
// headerStyle: "font-size: 14px",
// style: "font-size: 14px",
// sort: (a: string, b: string) =>
// a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
// },
// {
// name: "durationYear",
// align: "left",
// label: " ()",
// sortable: true,
// field: "durationYear",
// headerStyle: "font-size: 14px",
// style: "font-size: 14px",
// sort: (a: string, b: string) =>
// a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
// },
// {
// name: "note",
// align: "left",
// label: "",
// sortable: true,
// field: "note",
// headerStyle: "font-size: 14px",
// style: "font-size: 14px",
// sort: (a: string, b: string) =>
// a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
// },
]); ]);
/** /**
* fiunction ดลำด * fiunction ดลำด
@ -226,7 +227,7 @@ const columns = ref<QTableProps["columns"]>([
* @param to ตำแหนงทจะยายไป * @param to ตำแหนงทจะยายไป
*/ */
function onDrop(from: number, to: number) { function onDrop(from: number, to: number) {
rows.value.splice(to, 0, rows.value.splice(from, 1)[0]); rows.value.splice(to - 1, 0, rows.value.splice(from - 1, 1)[0]);
selected.value.push(rows.value[0]); selected.value.push(rows.value[0]);
} }
@ -295,18 +296,11 @@ watch(modal, async () => {
row-key="id" row-key="id"
hide-bottom hide-bottom
hide-pagination hide-pagination
hide-header
selection="multiple" selection="multiple"
class="custom-header-table"
v-model:selected="selected" v-model:selected="selected"
> >
<template v-slot:header-selection="scope"> <template v-slot:header-selection="scope"> </template>
<q-checkbox
keep-color
color="primary"
dense
v-model="scope.checkBox"
/>
</template>
<template v-slot:body="props"> <template v-slot:body="props">
<q-tr :props="props"> <q-tr :props="props">
<q-td> <q-td>

View file

@ -1,15 +1,51 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from "vue"; import { ref, defineAsyncComponent } from "vue";
import { useRegistryNewDataStore } from "@/modules/04_registryPerson/store"; import { useRegistryNewDataStore } from "@/modules/04_registryPerson/store";
/** importComponents*/ /** importComponents*/
import Profile from "@/modules/04_registryPerson/components/detail/PersonalInformation/01_Profile.vue"; // //
import NameChangeHistory from "@/modules/04_registryPerson/components/detail/PersonalInformation/02_NameChangeHistory.vue"; // const Profile = defineAsyncComponent(
import Address from "@/modules/04_registryPerson/components/detail/PersonalInformation/03_Address.vue"; // () =>
import FamilyNew from "@/modules/04_registryPerson/components/detail/PersonalInformation/04_FamilyNew.vue"; // import(
import Education from "@/modules/04_registryPerson/components/detail/PersonalInformation/05_Education.vue"; // "@/modules/04_registryPerson/components/detail/PersonalInformation/01_Profile.vue"
import SpecialSkill from "@/modules/04_registryPerson/components/detail/PersonalInformation/06_SpecialSkill.vue"; // )
);
//
const NameChangeHistory = defineAsyncComponent(
() =>
import(
"@/modules/04_registryPerson/components/detail/PersonalInformation/02_NameChangeHistory.vue"
)
);
//
const Address = defineAsyncComponent(
() =>
import(
"@/modules/04_registryPerson/components/detail/PersonalInformation/03_Address.vue"
)
);
//
const FamilyNew = defineAsyncComponent(
() =>
import(
"@/modules/04_registryPerson/components/detail/PersonalInformation/04_FamilyNew.vue"
)
);
//
const Education = defineAsyncComponent(
() =>
import(
"@/modules/04_registryPerson/components/detail/PersonalInformation/05_Education.vue"
)
);
//
const SpecialSkill = defineAsyncComponent(
() =>
import(
"@/modules/04_registryPerson/components/detail/PersonalInformation/06_SpecialSkill.vue"
)
);
const storeRegistry = useRegistryNewDataStore(); const storeRegistry = useRegistryNewDataStore();
@ -39,7 +75,7 @@ const props = defineProps({
class="text-grey q-pl-sm" class="text-grey q-pl-sm"
> >
<q-tab name="1" label="ประวัติส่วนตัว" /> <q-tab name="1" label="ประวัติส่วนตัว" />
<q-tab name="2" label="ประวัติการเปลี่ยนชื่อ-นามสกุล" /> <q-tab name="2" label="ประวัติการเปลี่ยนชื่อ - นามสกุล" />
<q-tab name="3" label="ข้อมูลที่อยู่" /> <q-tab name="3" label="ข้อมูลที่อยู่" />
<q-tab name="4" label="ข้อมูลครอบครัว" /> <q-tab name="4" label="ข้อมูลครอบครัว" />
<q-tab name="5" label="ประวัติการศึกษา" /> <q-tab name="5" label="ประวัติการศึกษา" />

View file

@ -109,7 +109,15 @@ const baseColumns = ref<QTableProps["columns"]>([
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
style: "font-size: 14px", style: "font-size: 14px",
}, },
{
name: "position",
align: "left",
label: "ตำแหน่ง",
sortable: true,
field: "position",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{ {
name: "positionType", name: "positionType",
align: "left", align: "left",
@ -166,6 +174,7 @@ const visibleColumns = ref<string[]>([
"positionSalaryAmount", "positionSalaryAmount",
"mouthSalaryAmount", "mouthSalaryAmount",
"posNo", "posNo",
"position",
"positionType", "positionType",
"positionLevel", "positionLevel",
"templateDoc", "templateDoc",
@ -718,7 +727,9 @@ onMounted(() => {
<q-btn <q-btn
v-if="isLeave == false && checkPermission($route)?.attrIsUpdate" v-if="isLeave == false && checkPermission($route)?.attrIsUpdate"
flat flat
:disable="props.row.commandId !== null && props.row.commandId !== ''" :disable="
props.row.commandId !== null && props.row.commandId !== ''
"
:color="props.row.commandId ? 'grey' : 'edit'" :color="props.row.commandId ? 'grey' : 'edit'"
dense dense
round round
@ -1136,8 +1147,6 @@ onMounted(() => {
label="เงินค่าตอบแทนพิเศษ" label="เงินค่าตอบแทนพิเศษ"
mask="###,###,###,###" mask="###,###,###,###"
reverse-fill-mask reverse-fill-mask
:rules="empType !== '-temp'? [(val:string) => !!val || `${'กรุณากรอกเงินค่าตอบแทนพิเศษ'}`]:[]"
lazy-rules
hide-bottom-space hide-bottom-space
/> />
</div> </div>
@ -1198,13 +1207,10 @@ onMounted(() => {
ref="docRef" ref="docRef"
outlined outlined
dense dense
lazy-rules
borderless borderless
v-model="formDataSalary.doc" v-model="formDataSalary.doc"
:label="`${'เอกสารอ้างอิง'}`" :label="`${'เอกสารอ้างอิง'}`"
type="textarea" type="textarea"
hide-bottom-space
:rules="empType !== '-temp'? [(val: number) => !!val || `${'กรุณากรอกเอกสารอ้างอิง'}`]:[]"
/> />
</div> </div>
</div> </div>

View file

@ -1,17 +1,43 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from "vue"; import { ref, defineAsyncComponent } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { useRegistryDetailNewDataStore } from "@/modules/04_registryPerson/stores/DetailMain"; import { useRegistryDetailNewDataStore } from "@/modules/04_registryPerson/stores/DetailMain";
import type { ItemTab } from "@/modules/04_registryPerson/interface/index/Main"; import type { ItemTab } from "@/modules/04_registryPerson/interface/index/Main";
import PersonalInformationMain from "@/modules/04_registryPerson/components/detail/PersonalInformation/Main.vue"; // //
import GovernmentInformationMain from "@/modules/04_registryPerson/components/detail/GovernmentInformation/Main.vue"; // const PersonalInformationMain = defineAsyncComponent(
import salaryMain from "@/modules/04_registryPerson/components/detail/Salary/Main.vue"; /// () =>
import AchievementMain from "@/modules/04_registryPerson/components/detail/Achievement/Main.vue"; // import(
import OtherMaim from "@/modules/04_registryPerson/components/detail/Other/Main.vue"; // "@/modules/04_registryPerson/components/detail/PersonalInformation/Main.vue"
import EmployeeMain from "@/modules/04_registryPerson/components/detail/Employee/Main.vue"; // )
);
//
const GovernmentInformationMain = defineAsyncComponent(
() =>
import(
"@/modules/04_registryPerson/components/detail/GovernmentInformation/Main.vue"
)
);
///
const salaryMain = defineAsyncComponent(
() => import("@/modules/04_registryPerson/components/detail/Salary/Main.vue")
);
//
const AchievementMain = defineAsyncComponent(
() =>
import("@/modules/04_registryPerson/components/detail/Achievement/Main.vue")
);
//
const OtherMaim = defineAsyncComponent(
() => import("@/modules/04_registryPerson/components/detail/Other/Main.vue")
);
//
const EmployeeMain = defineAsyncComponent(
() =>
import("@/modules/04_registryPerson/components/detail/Employee/Main.vue")
);
const route = useRoute(); const route = useRoute();

View file

@ -19,6 +19,7 @@ interface DataOptionSys {
interface DataOptionInsignia { interface DataOptionInsignia {
id: string; id: string;
name: string; name: string;
typeId: string;
typeName: string; typeName: string;
} }
@ -82,6 +83,41 @@ interface Request {
topic: string; topic: string;
} }
interface InsigniasType {
id: string;
createdAt: Date;
createdUserId: string;
lastUpdatedAt: Date;
lastUpdateUserId: string;
createdFullName: string;
lastUpdateFullName: string;
name: string;
isActive: boolean;
insignias: InsigniasTypeSub[];
}
interface InsigniasTypeSub {
id:string;
createdAt:Date;
createdUserId:string;
lastUpdatedAt:Date;
lastUpdateUserId:string;
createdFullName:string;
lastUpdateFullName:string;
name:string;
shortName:string;
level:string;
isActive:string;
note:string;
insigniaTypeId:string;
}
interface ResFileData {
downloadUrl: string;
fileName: string;
path: string;
pathname: string;
}
export type { export type {
Pagination, Pagination,
DataOption, DataOption,
@ -96,4 +132,8 @@ export type {
DataOptionEducation, DataOptionEducation,
DataOptionEducationLevel, DataOptionEducationLevel,
Request, Request,
InsigniasType,
InsigniasTypeSub,
ResFileData
}; };

View file

@ -53,6 +53,13 @@ interface MyObjectRef {
[key: string]: any; [key: string]: any;
} }
interface DataLeave {
date: Date | null;
type: string;
reson: string;
document: string;
}
export type { export type {
DetailData, DetailData,
FormFilter, FormFilter,
@ -60,4 +67,5 @@ export type {
DataOption, DataOption,
ResponseTotalObject, ResponseTotalObject,
MyObjectRef, MyObjectRef,
DataLeave,
}; };

View file

@ -21,6 +21,7 @@ interface RequestItemsObject {
reference: string; reference: string;
refCommandNo: string; refCommandNo: string;
refCommandDate: Date | null; refCommandDate: Date | null;
isUpload: boolean;
} }
interface MyObjectRef { interface MyObjectRef {

View file

@ -6,7 +6,9 @@ interface RequestItemsObject {
issuer: string; issuer: string;
refCommandDate: Date | null; refCommandDate: Date | null;
refCommandNo: string; refCommandNo: string;
type: string;
isDate: boolean | string; isDate: boolean | string;
isUpload?: boolean|undefined;
} }
export type { RequestItemsObject }; export type { RequestItemsObject };

View file

@ -0,0 +1,18 @@
interface DataActing {
dateStart: null | Date;
dateEnd: null | Date;
posNo: string;
position: string;
status: boolean;
}
interface DatAssistance {
dateStart: Date | null;
dateEnd: Date | null;
agency: string;
commandNo: string;
document: string;
// isUpload: boolean;
}
export type { DataActing, DatAssistance };

View file

@ -14,6 +14,7 @@ interface RequestItemsObject {
refCommandNo: string; refCommandNo: string;
note: string; note: string;
profileEmployeeId?: string | null; profileEmployeeId?: string | null;
isUpload?: boolean | undefined;
} }
export type { RequestItemsObject }; export type { RequestItemsObject };

View file

@ -13,6 +13,7 @@ interface FormFilter {
isAll?: boolean; isAll?: boolean;
nodeId?: string | null; nodeId?: string | null;
node?: string | null | number; node?: string | null | number;
retireType?: null | string;
} }
interface FormAddPerson { interface FormAddPerson {
@ -54,6 +55,7 @@ interface QueryParams {
node?: number | string | null | undefined; node?: number | string | null | undefined;
nodeId?: string; nodeId?: string;
isAll?: boolean; isAll?: boolean;
retireType?: string | null;
} }
interface FormChangeName { interface FormChangeName {
@ -81,9 +83,9 @@ interface FormDataIDP {
createdAt?: Date | null; createdAt?: Date | null;
} }
interface RangeAge{ interface RangeAge {
min:number min: number;
max:number max: number;
} }
export type { export type {
FormFilter, FormFilter,
@ -93,5 +95,5 @@ export type {
QueryParams, QueryParams,
FormChangeName, FormChangeName,
FormDataIDP, FormDataIDP,
RangeAge RangeAge,
}; };

View file

@ -1,6 +1,8 @@
interface RequestItemsObject { interface RequestItemsObject {
profileId?: string; profileId?: string;
profileEmployeeId?: string; profileEmployeeId?: string;
period?: string|null;
year?: number|null;
name: string; name: string;
date: Date | null; date: Date | null;
point1: number; point1: number;
@ -11,4 +13,8 @@ interface RequestItemsObject {
pointSumTotal: number; pointSumTotal: number;
} }
export type { RequestItemsObject }; interface DataOptions{
id:string
name:string
}
export type { RequestItemsObject,DataOptions };

View file

@ -12,7 +12,9 @@ interface ResponseObject {
lastUpdateUserId: string; lastUpdateUserId: string;
lastUpdatedAt: Date; lastUpdatedAt: Date;
profileId: string; profileId: string;
type: string;
refCommandDate: Date; refCommandDate: Date;
isUpload: boolean;
refCommandNo: string; refCommandNo: string;
} }

View file

@ -0,0 +1,46 @@
interface ResActingPosData {
createdAt: string;
createdFullName: string;
createdUserId: string;
dateEnd: Date | null;
dateStart: Date | null;
id: string;
lastUpdateFullName: string;
lastUpdateUserId: string;
lastUpdatedAt: string;
posNo: string;
position: string;
profileEmployeeId: string;
profileId: string;
status: boolean;
refCommandNo: string;
commandId: string;
}
interface ResAssistanceData {
agency: string;
commandNo: string;
commandId: string;
createdAt: Date | null;
createdFullName: string;
createdUserId: string;
dateEnd: Date | null;
dateStart: Date | null;
document: string;
id: string;
isUpload: false;
lastUpdateFullName: string;
lastUpdateUserId: string;
lastUpdatedAt: string;
profileEmployeeId: string;
profileId: string;
}
interface ResFileData {
downloadUrl: string;
fileName: string;
path: string;
pathname: string;
}
export type { ResActingPosData, ResAssistanceData, ResFileData };

View file

@ -20,6 +20,7 @@ interface ResponseObject {
volumeNo: string; volumeNo: string;
refCommandDate: Date | null; refCommandDate: Date | null;
refCommandNo: string; refCommandNo: string;
isUpload: boolean;
note: string; note: string;
} }

View file

@ -33,6 +33,7 @@ interface ResponseObject {
religion: string | null; religion: string | null;
telephoneNumber: string | null; telephoneNumber: string | null;
prefixMain: string; prefixMain: string;
statusEmail: string;
} }
interface Religion { interface Religion {

View file

@ -16,6 +16,8 @@ interface ResponseObject {
pointSum: number; pointSum: number;
pointSumTotal: number; pointSumTotal: number;
profileId: string; profileId: string;
year: number|null;
period: string|null;
} }
export type { ResponseObject }; export type { ResponseObject };

View file

@ -71,6 +71,7 @@ export const useRegistryNewDataStore = defineStore("registryNew", () => {
nodeId: null, nodeId: null,
node: null, node: null,
searchType: "fullName", searchType: "fullName",
retireType: null,
}); });
const labelOption = reactive({ const labelOption = reactive({
@ -79,8 +80,55 @@ export const useRegistryNewDataStore = defineStore("registryNew", () => {
posLevel: "ทั้งหมด", posLevel: "ทั้งหมด",
retireYear: "", retireYear: "",
node: "เลือกหน่วยงาน", node: "เลือกหน่วยงาน",
retireType: "ทั้งหมด",
}); });
function convertTypeRetired(val: string) {
const newVal = val?.toLocaleUpperCase();
switch (newVal) {
case "RETIRE":
return "เกษียณ ";
case "RETIRE_RESIGN":
return "ลาออก ";
case "RETIRE_DECEASED":
return "ถึงแก่กรรม ";
case "RETIRE_OUT":
return "ให้ออกจากราชการ ";
case "DISCIPLINE_RESULT_REMOVE":
return "ปลดออกจากราชการ ";
case "DISCIPLINE_RESULT_DISMISS":
return "ไล่ออกจากราชการ ";
case "DISCIPLINE_SUSPEND":
return "ถูกพักจากราชการ ";
case "PROBATION_REPORT":
return "ไม่ผ่านทดลองงาน ";
case "PLACEMENT_TRANSFER":
return "โอนออก ";
case "RETIRE_RESIGN_EMP":
return "ให้ออกจากราชการ(ลูกจ้าง)";
default:
return "";
}
}
const retireTypeOps = ref<DataOption[]>([
{ id: "RETIRE", name: "เกษียณ" },
{ id: "RETIRE_RESIGN", name: "ลาออก" },
{ id: "RETIRE_DECEASED", name: "ถึงแก่กรรม" },
{ id: "RETIRE_OUT", name: "ให้ออกจากราชการ" },
{ id: "DISCIPLINE_RESULT_REMOVE", name: "ปลดออกจากราชการ" },
{ id: "DISCIPLINE_RESULT_DISMISS", name: "ไล่ออกจากราชการ" },
{ id: "DISCIPLINE_SUSPEND", name: "ถูกพักจากราชการ" },
{ id: "PROBATION_REPORT", name: "ไม่ผ่านทดลองงาน" },
]);
const retireTypeEmpOps = ref<DataOption[]>([
{ id: "RETIRE", name: "เกษียณ" },
{ id: "RETIRE_RESIGN", name: "ลาออก" },
{ id: "RETIRE_DECEASED", name: "ถึงแก่กรรม" },
{ id: "RETIRE_RESIGN_EMP", name: "ให้ออกจากราชการ" },
]);
return { return {
fetchType, fetchType,
fetchLevel, fetchLevel,
@ -96,5 +144,8 @@ export const useRegistryNewDataStore = defineStore("registryNew", () => {
isLeave, isLeave,
tabs, tabs,
tabsManu, tabsManu,
convertTypeRetired,
retireTypeOps,
retireTypeEmpOps,
}; };
}); });

View file

@ -1,21 +1,37 @@
import { ref, computed } from "vue"; import { ref, computed } from "vue";
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import type { DataOptionInsignia } from "@/modules/04_registryPerson/interface/index/Main"; import type {
DataOptionInsignia,
DataOption,
InsigniasType,
InsigniasTypeSub,
} from "@/modules/04_registryPerson/interface/index/Main";
import type { ResponseObject as Insignia } from "@/modules/07_insignia/interface/response/Main"; import type { ResponseObject as Insignia } from "@/modules/07_insignia/interface/response/Main";
export const useInsigniaDataStore = defineStore("insigniaDataStore", () => { export const useInsigniaDataStore = defineStore("insigniaDataStore", () => {
const insigniaOption = ref<DataOptionInsignia[]>([]); const insigniaOption = ref<InsigniasType[]>([]);
function mapInsigniaOption(resData: any) { const insigniaTypeOp = ref<InsigniasType[]>([]);
insigniaOption.value = []; const insigniaTypeOpMain = ref<InsigniasType[]>([]);
resData.map((r: Insignia) => { const allNameInsignia = ref<InsigniasTypeSub[]>([]);
insigniaOption.value.push({
id: r.id.toString(), function mapInsigniaOption(resData: InsigniasType[]) {
name: r.name.toString() + ` (${r.shortName})`, insigniaTypeOpMain.value = resData;
typeName: r.insigniaTypeName.toString(), insigniaTypeOp.value = resData;
});
}); allNameInsignia.value = resData
.flatMap((item: InsigniasType) => item.insignias)
.map((i: InsigniasTypeSub) => ({
...i,
name: `${i.name} (${i.shortName})`,
}));
} }
return { insigniaOption, mapInsigniaOption }; return {
insigniaOption,
mapInsigniaOption,
insigniaTypeOp,
insigniaTypeOpMain,
allNameInsignia,
};
}); });

View file

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, computed } from "vue"; import { ref, onMounted, computed, defineAsyncComponent } from "vue";
import { useQuasar } from "quasar"; import { useQuasar } from "quasar";
import { useRoute, useRouter } from "vue-router"; import { useRoute, useRouter } from "vue-router";
@ -16,25 +16,29 @@ import axios from "axios";
import genReport from "@/plugins/genreport"; import genReport from "@/plugins/genreport";
import avatar from "@/assets/avatar_user.jpg"; import avatar from "@/assets/avatar_user.jpg";
/** /** importType*/
* importType
*/
import type { import type {
DataOption, DataOption,
DataOptionSys, DataOptionSys,
} from "@/modules/04_registryPerson/interface/index/Main"; } from "@/modules/04_registryPerson/interface/index/Main";
import type { ResponseObject } from "@/modules/04_registryPerson/interface/response/Profile"; import type { ResponseObject } from "@/modules/04_registryPerson/interface/response/Profile";
/** /** importComponents*/
* importComponents const CardNotPermission = defineAsyncComponent(
*/ () => import("@/components/CardNotPermission.vue")
import CardNotPermission from "@/components/CardNotPermission.vue"; );
import DialogHeader from "@/components/DialogHeader.vue"; const DialogHeader = defineAsyncComponent(
import TabMain from "@/modules/04_registryPerson/components/detail/TabMain.vue"; () => import("@/components/DialogHeader.vue")
);
const TabMain = defineAsyncComponent(
() => import("@/modules/04_registryPerson/components/detail/TabMain.vue")
);
/** const DialogRetired = defineAsyncComponent(
* use () => import("@/modules/04_registryPerson/components/DialogRetired.vue")
*/ );
/** use*/
const $q = useQuasar(); const $q = useQuasar();
const router = useRouter(); const router = useRouter();
const route = useRoute(); const route = useRoute();
@ -67,6 +71,8 @@ const reasonDeath = ref(""); //เหตุผลการเสียชีว
const dialogImage = ref<boolean>(false); // const dialogImage = ref<boolean>(false); //
const formDetail = ref<ResponseObject>(); // const formDetail = ref<ResponseObject>(); //
const modalDialogRetired = ref<boolean>(false);
// //
const baseItemsMenu = ref<DataOptionSys[]>([ const baseItemsMenu = ref<DataOptionSys[]>([
{ {
@ -104,10 +110,10 @@ const baseItemsMenu = ref<DataOptionSys[]>([
const itemsMenu = computed(() => { const itemsMenu = computed(() => {
if ( if (
leaveReason.value === leaveReason.value ===
"(พ้นจากราชการด้วยสาเหตุ: ได้รับโทษทางวินัย ให้ออกจากราชการไว้ก่อน)" || "(พ้นจากราชการด้วยสาเหตุ : ได้รับโทษทางวินัย ให้ออกจากราชการไว้ก่อน)" ||
leaveReason.value === "(พ้นจากราชการด้วยสาเหตุ: ลาออกจากราชการ)" || leaveReason.value === "(พ้นจากราชการด้วยสาเหตุ : ลาออกจากราชการ)" ||
leaveReason.value === leaveReason.value ===
"(พ้นจากราชการด้วยสาเหตุ: ได้รับโทษทางวินัย พักจากราชการ)" "(พ้นจากราชการด้วยสาเหตุ : ได้รับโทษทางวินัย พักจากราชการ)"
) { ) {
return ( return (
baseItemsMenu.value?.filter( baseItemsMenu.value?.filter(
@ -118,6 +124,7 @@ const itemsMenu = computed(() => {
return baseItemsMenu.value || []; return baseItemsMenu.value || [];
} }
}); });
// //
const itemsMenuEmployee = ref<DataOptionSys[]>([ const itemsMenuEmployee = ref<DataOptionSys[]>([
{ {
@ -130,6 +137,11 @@ const itemsMenuEmployee = ref<DataOptionSys[]>([
name: "ถึงแก่กรรม", name: "ถึงแก่กรรม",
system: "SYS_PASSAWAY", system: "SYS_PASSAWAY",
}, },
{
id: "3",
name: "ให้ออกจากราชการ",
system: "SYS_DISMISS_EMP",
},
]); ]);
const uploadUrl = ref<string>(""); //URL const uploadUrl = ref<string>(""); //URL
@ -157,7 +169,10 @@ function imageActive(n: any) {
activeImage.value = n; activeImage.value = n;
} }
// /**
* งกนสำหรบปรบขนาดภาพ
* @param file ไฟล
*/
function resizeImage(file: File): Promise<File> { function resizeImage(file: File): Promise<File> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const img = new Image(); const img = new Image();
@ -168,8 +183,8 @@ function resizeImage(file: File): Promise<File> {
img.onload = () => { img.onload = () => {
const canvas = document.createElement("canvas"); const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d"); const ctx = canvas.getContext("2d");
const width = 150; const width = 354;
const height = 200; const height = 472;
// //
canvas.width = width; canvas.width = width;
@ -219,9 +234,7 @@ function resizeImage(file: File): Promise<File> {
const newProfileFile = ref<any>(null); const newProfileFile = ref<any>(null);
/** /** ฟังก์ชันอัปโหลด*/
* งกนอปโหลด
*/
async function uploadImg() { async function uploadImg() {
showLoader(); showLoader();
newProfileFile.value = await resizeImage(profileFile.value); newProfileFile.value = await resizeImage(profileFile.value);
@ -261,6 +274,8 @@ async function uploadProfile(path: string) {
}) })
.catch((err) => { .catch((err) => {
messageError($q, err); messageError($q, err);
})
.finally(() => {
hideLoader(); hideLoader();
}); });
} }
@ -342,16 +357,13 @@ const reasonOptions = ref<DataOption[]>([
}, },
]); ]);
/** /** ฟังก์ชันดึงข้อมูลส่วนต้ว*/
* งกนดงขอมลสวนต
*/
async function fetchDataPersonal() { async function fetchDataPersonal() {
showLoader(); showLoader();
await http await http
.get(config.API.registryNewByProfileId(profileId.value, empType.value)) .get(config.API.registryNewByProfileId(profileId.value, empType.value))
.then(async (res) => { .then(async (res) => {
formDetail.value = res.data.result; formDetail.value = await res.data.result;
storeRegistry.isLeave = res.data.result.isLeave; storeRegistry.isLeave = res.data.result.isLeave;
if (res.data.result.leaveReason) { if (res.data.result.leaveReason) {
@ -360,12 +372,12 @@ async function fetchDataPersonal() {
(r: DataOption) => r.id == res.data.result.leaveReason (r: DataOption) => r.id == res.data.result.leaveReason
); );
if (reason.length > 0) { if (reason.length > 0) {
leaveReason.value = `(พ้นจากราชการด้วยสาเหตุ: ${reason[0].name})`; leaveReason.value = `(พ้นจากราชการด้วยสาเหตุ : ${reason[0].name})`;
} else if ( } else if (
res.data.result.leaveReason !== null && res.data.result.leaveReason !== null &&
res.data.result.leaveReason !== "" res.data.result.leaveReason !== ""
) { ) {
leaveReason.value = `(พ้นจากราชการด้วยสาเหตุ: ${res.data.result.leaveReason})`; leaveReason.value = `(พ้นจากราชการด้วยสาเหตุ : ${res.data.result.leaveReason})`;
} }
reasonStatus.value = reason.length > 0 ? true : false; reasonStatus.value = reason.length > 0 ? true : false;
} }
@ -386,16 +398,13 @@ async function fetchDataPersonal() {
} else { } else {
messageError($q, err); messageError($q, err);
} }
}) hideLoader();
.finally(() => {
setTimeout(() => {
hideLoader();
}, 2800);
}); });
} }
/** /**
* งกนดาวนโหลดไฟล "..7/..1 หร ประวแบบย * งกนดาวนโหลดไฟล "..7/..1 และประวแบบย
* @param type full === 'ก.พ.7/ก.ก.1', SHORT === 'ประวัติแบบย่อ'
*/ */
async function onClickDownloadKp7(type: string) { async function onClickDownloadKp7(type: string) {
showLoader(); showLoader();
@ -423,9 +432,7 @@ async function onClickDownloadKp7(type: string) {
}); });
} }
/** /** ฟังก์ชันออกคำสั่งช่วยราชการ*/
* งกนออกคำสงชวยราชการ
*/
function helpPost() { function helpPost() {
const formData = new FormData(); const formData = new FormData();
formData.append("id", profileId.value); formData.append("id", profileId.value);
@ -446,9 +453,7 @@ function helpPost() {
}); });
} }
/** /** ฟังก์ชันออกคำสั่งส่งตัวกลับ*/
* งกนออกคำสงสงตวกล
*/
function repatriationPost() { function repatriationPost() {
const formData = new FormData(); const formData = new FormData();
formData.append("id", profileId.value); formData.append("id", profileId.value);
@ -469,9 +474,7 @@ function repatriationPost() {
}); });
} }
/** /** ฟังก์ชันออกคำสั่งแต่งตังเลื่อน*/
* งกนออกคำสงแตงตงเลอน
*/
function appointPost() { function appointPost() {
const formData = new FormData(); const formData = new FormData();
formData.append("id", profileId.value); formData.append("id", profileId.value);
@ -492,9 +495,7 @@ function appointPost() {
}); });
} }
/** /** ฟังก์ชันออกคำสั่งถึงเเก่กรรม*/
* งกนออกคำสงถงเเกกรรม
*/
function clickPassaway() { function clickPassaway() {
dialogPassaway.value = true; dialogPassaway.value = true;
filePassaway.value = null; filePassaway.value = null;
@ -504,18 +505,26 @@ function clickPassaway() {
reasonDeath.value = ""; reasonDeath.value = "";
} }
/** /** ฟังก์ชันออกคำสั่งให้ออกจากราชการ*/
* งกนออกคำสงใหออกจากราชการ
*/
function outPost() { function outPost() {
const formData = new FormData(); const formData = new FormData();
formData.append("id", profileId.value); formData.append("id", profileId.value);
formData.append(
"ProfileType",
empType.value === "-employee" ? "EMPLOYEE" : "OFFICER"
);
dialogConfirm($q, async () => { dialogConfirm($q, async () => {
showLoader(); showLoader();
await http await http
.post(config.API.retirementOut, formData) .post(config.API.retirementOut, formData)
.then(async () => { .then(async () => {
await router.push("/retirement/dismiss-order"); await router.push(
`${
empType.value === "-employee"
? `/retirementEmployee`
: `/retirement/dismiss-order`
}`
);
await success($q, "ดำเนินการสำเร็จ"); await success($q, "ดำเนินการสำเร็จ");
}) })
.catch((e) => { .catch((e) => {
@ -527,12 +536,14 @@ function outPost() {
}); });
} }
/** /** ฟังก์ชันออกคำสั่งอื่นๆ*/
* งกนออกคำสงอนๆ
*/
function otherPost() { function otherPost() {
const formData = new FormData(); const formData = new FormData();
formData.append("id", profileId.value); formData.append("id", profileId.value);
formData.append(
"ProfileType",
empType.value === "-employee" ? "EMPLOYEE" : "OFFICER"
);
dialogConfirm($q, async () => { dialogConfirm($q, async () => {
showLoader(); showLoader();
await http await http
@ -550,9 +561,7 @@ function otherPost() {
}); });
} }
/** /** ฟังก์ชันออกคำสั่งปรับระดับชั้นงาน - ย้าย*/
* งกนออกคำสงปรบระดบชนงาน - าย
*/
function appointEmployeePost() { function appointEmployeePost() {
const formData = new FormData(); const formData = new FormData();
formData.append("id", profileId.value); formData.append("id", profileId.value);
@ -573,9 +582,7 @@ function appointEmployeePost() {
}); });
} }
/** /** ฟังก์ชันยืนยันบันทึกข้อมูลถึงแก่กรรม*/
* งกนยนยนบนทกขอมลถงแกกรรม
*/
function clickSaveDeceased() { function clickSaveDeceased() {
dialogConfirm($q, async () => { dialogConfirm($q, async () => {
showLoader(); showLoader();
@ -586,6 +593,11 @@ function clickSaveDeceased() {
formData.append("Location", placeDeathCertificate.value); formData.append("Location", placeDeathCertificate.value);
formData.append("Reason", reasonDeath.value); formData.append("Reason", reasonDeath.value);
formData.append("ProfileId", profileId.value); formData.append("ProfileId", profileId.value);
formData.append(
"ProfileType",
empType.value === "-employee" ? "EMPLOYEE" : "OFFICER"
);
await http await http
.post(config.API.listDeceased(), formData) .post(config.API.listDeceased(), formData)
.then(async () => { .then(async () => {
@ -601,38 +613,35 @@ function clickSaveDeceased() {
}); });
} }
/** /** ฟังก์ชันปืด popup ถึงแก่กรรม*/
* งกนป popup งแกกรรม
*/
function closePassaway() { function closePassaway() {
dialogPassaway.value = false; dialogPassaway.value = false;
} }
/** /** ฟังก์ชันเปืด popup เลือกรูปภาพ*/
* งกนเป popup เลอกรปภาพ
*/
function openDialogImg() { function openDialogImg() {
dialogImage.value = true; dialogImage.value = true;
getImage(); getImage();
} }
/** /** ฟังก์ชันเรียกข้อมูลรูป*/
* งกนเรยกขอมลร async function getImage() {
*/
function getImage() {
showLoader(); showLoader();
http http
.get(config.API.orgProfileAvatar + `/${profileId.value}`) .get(config.API.orgProfileAvatar + `/${profileId.value}`)
.then(async (res) => { .then(async (res) => {
let data = res.data.result; let data = res.data.result;
imagesAlldata.value = data; if (!data || !Array.isArray(data)) {
return;
}
for (let i = 0; i < data.length; i++) { imagesAlldata.value = data;
await getImg(data[i]); for (const img of data) {
await getImg(img);
} }
}) })
.catch((e) => { .catch((e) => {
// messageError($q, e); messageError($q, e);
}) })
.finally(() => { .finally(() => {
hideLoader(); hideLoader();
@ -640,8 +649,8 @@ function getImage() {
} }
/** /**
* งกนเรยกขอมลร * งกนเรยกขอมลรายการร
* @param dataList * @param dataList อม
*/ */
async function getImg(dataList: any) { async function getImg(dataList: any) {
await http await http
@ -653,16 +662,15 @@ async function getImg(dataList: any) {
isActive: dataList.isActive, isActive: dataList.isActive,
...data, ...data,
}; };
images.value = [...images.value, newData];
images.value.push(newData);
}) })
.catch((e) => { .catch((e) => {
// messageError($q, e); messageError($q, e);
}); });
} }
/** /** ฟังก์ชันปิด Popup เลือกรูปภาพ*/
* งกนป Popup เลอกรปภาพ
*/
function closeImage() { function closeImage() {
dialogImage.value = false; dialogImage.value = false;
images.value = []; images.value = [];
@ -680,10 +688,10 @@ function deletePhoto(id: string) {
showLoader(); showLoader();
http http
.delete(config.API.orgProfileAvatar + `/${id}`) .delete(config.API.orgProfileAvatar + `/${id}`)
.then((res) => { .then(async () => {
await getImage();
images.value = []; images.value = [];
imagesAlldata.value = []; imagesAlldata.value = [];
getImage();
}) })
.catch((e) => { .catch((e) => {
messageError($q, e); messageError($q, e);
@ -696,9 +704,7 @@ function deletePhoto(id: string) {
); );
} }
/** /** ฟังก์ชันยืนยันการเลือกรูป*/
* งกนยนยนการเลอกร
*/
function selectAvatarHistory() { function selectAvatarHistory() {
if (activeImage.value == null) { if (activeImage.value == null) {
dialogMessageNotify($q, "กรุณาเลือกรูปที่ต้องการเปลี่ยน"); dialogMessageNotify($q, "กรุณาเลือกรูปที่ต้องการเปลี่ยน");
@ -765,7 +771,7 @@ onMounted(async () => {
/> />
{{ {{
route.name === "registry-employeeId" route.name === "registry-employeeId"
? " ทะเบียนประวัติลูกจ้างชั่วคราว" ? "ทะเบียนประวัติลูกจ้างชั่วคราว"
: "ทะเบียนประวัติ" : "ทะเบียนประวัติ"
}} }}
</div> </div>
@ -773,7 +779,6 @@ onMounted(async () => {
<div v-if="isPermission"> <div v-if="isPermission">
<!-- list menu ของขาราชการฯ --> <!-- list menu ของขาราชการฯ -->
<q-btn-dropdown <q-btn-dropdown
v-if=" v-if="
(!storeRegistry.isLeave && (!storeRegistry.isLeave &&
@ -787,10 +792,10 @@ onMounted(async () => {
'SYS_PLACEMENT_OTHER', 'SYS_PLACEMENT_OTHER',
])) || ])) ||
leaveReason === leaveReason ===
'(พ้นจากราชการด้วยสาเหตุ: ได้รับโทษทางวินัย ให้ออกจากราชการไว้ก่อน)' || '(พ้นจากราชการด้วยสาเหตุ : ได้รับโทษทางวินัย ให้ออกจากราชการไว้ก่อน)' ||
leaveReason === '(พ้นจากราชการด้วยสาเหตุ: ลาออกจากราชการ)' || leaveReason === '(พ้นจากราชการด้วยสาเหตุ : ลาออกจากราชการ)' ||
leaveReason === leaveReason ===
'(พ้นจากราชการด้วยสาเหตุ: ได้รับโทษทางวินัย พักจากราชการ)' '(พ้นจากราชการด้วยสาเหตุ : ได้รับโทษทางวินัย พักจากราชการ)'
" "
size="md" size="md"
rounded rounded
@ -831,7 +836,11 @@ onMounted(async () => {
v-if=" v-if="
!storeRegistry.isLeave && !storeRegistry.isLeave &&
empType === '-employee' && empType === '-employee' &&
checkPermissionList(['SYS_PROMOTION_EMP', 'SYS_PASSAWAY']) checkPermissionList([
'SYS_PROMOTION_EMP',
'SYS_PASSAWAY',
'SYS_DISMISS_EMP',
])
" "
size="md" size="md"
rounded rounded
@ -850,6 +859,8 @@ onMounted(async () => {
? appointEmployeePost() ? appointEmployeePost()
: item.name == 'ถึงแก่กรรม' : item.name == 'ถึงแก่กรรม'
? clickPassaway() ? clickPassaway()
: item.name == 'ให้ออกจากราชการ'
? outPost()
: null : null
" "
v-close-popup v-close-popup
@ -912,6 +923,16 @@ onMounted(async () => {
}${formDetail.firstName} ${formDetail.lastName}` }${formDetail.firstName} ${formDetail.lastName}`
}} }}
<span class="text-red"> {{ leaveReason }}</span> <span class="text-red"> {{ leaveReason }}</span>
<q-btn
v-if="leaveReason"
flat
round
color="info"
icon="info"
@click.stop.prevent="modalDialogRetired = true"
>
<q-tooltip>อมลการพนจากราชการ</q-tooltip>
</q-btn>
</h2> </h2>
</div> </div>
</div> </div>
@ -1111,7 +1132,7 @@ onMounted(async () => {
<q-dialog v-model="dialogImage" persistent> <q-dialog v-model="dialogImage" persistent>
<q-card style="width: 100vw; max-width: 60vw"> <q-card style="width: 100vw; max-width: 60vw">
<DialogHeader <DialogHeader
:tittle="'เลือกรูปภาพ (150 x 200 px)'" :tittle="'เลือกรูปภาพ (354 x 472 px)'"
:close="closeImage" :close="closeImage"
/> />
@ -1179,6 +1200,9 @@ onMounted(async () => {
</q-card-actions> </q-card-actions>
</q-card> </q-card>
</q-dialog> </q-dialog>
<!-- Dialog อมลการพนจากราชการ -->
<DialogRetired v-model:modal="modalDialogRetired" :data="formDetail" />
</template> </template>
<style scoped> <style scoped>

View file

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, onMounted, watch } from "vue"; import { ref, reactive, onMounted, watch, defineAsyncComponent } from "vue";
import { useQuasar } from "quasar"; import { useQuasar } from "quasar";
import http from "@/plugins/http"; import http from "@/plugins/http";
@ -23,7 +23,9 @@ import type {
} from "@/modules/04_registryPerson/interface/response/Main"; } from "@/modules/04_registryPerson/interface/response/Main";
/** importComponents*/ /** importComponents*/
import TableView from "@/modules/04_registryPerson/components/TableView.vue"; const TableView = defineAsyncComponent(
() => import("@/modules/04_registryPerson/components/TableView.vue")
);
import DialogHeader from "@/components/DialogHeader.vue"; import DialogHeader from "@/components/DialogHeader.vue";
const $q = useQuasar(); const $q = useQuasar();
@ -32,7 +34,6 @@ const { fetchStructureTree } = useStructureTree();
const { showLoader, hideLoader, messageError } = useCounterMixin(); const { showLoader, hideLoader, messageError } = useCounterMixin();
const route = useRoute(); const route = useRoute();
const mode = ref<"table" | "card">("table"); //
const empType = ref<string>("officer"); // officer / employee / perm const empType = ref<string>("officer"); // officer / employee / perm
const dataPersonMain = ref<DataPerson[]>([]); // const dataPersonMain = ref<DataPerson[]>([]); //
const maxPage = ref<number>(1); // const maxPage = ref<number>(1); //
@ -51,9 +52,7 @@ const nodeData = reactive<DataNodeData>({
node: null, node: null,
}); });
/** /** function เรียกข้อมูลตำแหน่งประเภท*/
* function เรยกขอมลตำแหนงประเภท
*/
function fetchType() { function fetchType() {
http http
.get(config.API.orgPosType) .get(config.API.orgPosType)
@ -65,9 +64,7 @@ function fetchType() {
}); });
} }
/** /** function เรียกข้อมูลกลุ่มงาน*/
* function เรยกขอมลกลมงาน
*/
function fetchOptionGroup() { function fetchOptionGroup() {
http http
.get(config.API.orgEmployeeType) .get(config.API.orgEmployeeType)
@ -79,9 +76,7 @@ function fetchOptionGroup() {
}); });
} }
/** /** function fetch รายชื่อข้อมูลทะเบียนประวัติ*/
* function fetch รายชอขอมลทะเบยนประว
*/
async function fetchDataPerson() { async function fetchDataPerson() {
showLoader(); showLoader();
dataPersonMain.value = []; dataPersonMain.value = [];
@ -115,6 +110,9 @@ async function fetchDataPerson() {
if (store.formFilter.isShowRetire != null) { if (store.formFilter.isShowRetire != null) {
queryParams.isRetire = store.formFilter.isShowRetire; queryParams.isRetire = store.formFilter.isShowRetire;
queryParams.retireType = queryParams.isRetire
? store.formFilter.retireType
: undefined;
} }
if (empType.value !== "officer") { if (empType.value !== "officer") {
@ -137,10 +135,11 @@ async function fetchDataPerson() {
) )
.then(async (res) => { .then(async (res) => {
const dataList = await res.data.result.data; const dataList = await res.data.result.data;
dataPersonMain.value = dataList;
maxPage.value = Math.ceil( maxPage.value = Math.ceil(
res.data.result.total / store.formFilter.pageSize res.data.result.total / store.formFilter.pageSize
); );
dataPersonMain.value = dataList;
total.value = res.data.result.total; total.value = res.data.result.total;
isShowBtnFilter.value = true; isShowBtnFilter.value = true;
if (dataList) { if (dataList) {
@ -193,9 +192,7 @@ async function insertAvatar(items: DataPerson[]) {
); );
} }
/** /** funciotn ค้นหาข้อมูล */
* funciotn นหาขอม
*/
function onclickSearch() { function onclickSearch() {
store.formFilter.page = 1; store.formFilter.page = 1;
store.formFilter.keyword = store.formFilter.keyword =
@ -209,16 +206,16 @@ function onclickSearch() {
*/ */
function selectType() { function selectType() {
empType.value = route.name == "registryNew" ? "officer" : "perm"; empType.value = route.name == "registryNew" ? "officer" : "perm";
store.formFilter.isShowRetire = false;
store.labelOption.retireType = "ทั้งหมด";
store.formFilter.retireType = null;
store.formFilter.keyword = "";
if (empType.value !== "officer") { if (empType.value !== "officer") {
store.formFilter.isShowRetire = null;
store.formFilter.isProbation = null; store.formFilter.isProbation = null;
store.formFilter.keyword = "";
fetchOptionGroup(); fetchOptionGroup();
} else { } else {
store.formFilter.isShowRetire = false;
store.formFilter.isProbation = false; store.formFilter.isProbation = false;
store.formFilter.keyword = "";
fetchType(); fetchType();
} }
@ -274,6 +271,17 @@ function selectPosLevel(item: DataOption) {
fetchDataPerson(); fetchDataPerson();
} }
/**
* function เลอกประเภทตำแหน
* @param item ประเภทระด
*/
function selectRetireType(item: DataOption) {
store.labelOption.retireType = item.name;
store.formFilter.page = 1;
store.formFilter.retireType = item.id;
fetchDataPerson();
}
/** /**
* function เคลวเลอก * function เคลวเลอก
* @param t ประเภทตวเลอก * @param t ประเภทตวเลอก
@ -298,6 +306,9 @@ function clearSelect(t: string) {
empType.value === "officer" empType.value === "officer"
? "เลือกหน่วยงาน/ส่วนราชการ" ? "เลือกหน่วยงาน/ส่วนราชการ"
: "เลือกหน่วยงาน"; : "เลือกหน่วยงาน";
} else if (t === "retireType") {
store.labelOption.retireType = "ทั้งหมด";
store.formFilter.retireType = null;
} }
store.formFilter.page = 1; store.formFilter.page = 1;
fetchDataPerson(); fetchDataPerson();
@ -317,9 +328,7 @@ async function fetchTree() {
} }
} }
/** /** ค้นหาข้อมูลรายชื่อข้อมูลทะเบียนประวัติตามหน่วยงาน/ส่วนราชการ*/
* นหาขอมลรายชอขอมลทะเบยนประวตามหนวยงาน/วนราชการ
*/
function sendNode() { function sendNode() {
nodeData.node = store.formFilter.node; nodeData.node = store.formFilter.node;
nodeData.nodeId = store.formFilter.nodeId; nodeData.nodeId = store.formFilter.nodeId;
@ -331,7 +340,6 @@ function sendNode() {
/** /**
* งกนเลอกหนวยงาน/วนราชการ * งกนเลอกหนวยงาน/วนราชการ
* @param data อมลหนวยงาน/วนราชการทองการคนหาร * @param data อมลหนวยงาน/วนราชการทองการคนหาร
*
* เพอคนหาขอมลตามหนวยงาน/วนราชการ * เพอคนหาขอมลตามหนวยงาน/วนราชการ
*/ */
function updateSelectedTreeMain(data: DataStructureTree) { function updateSelectedTreeMain(data: DataStructureTree) {
@ -354,14 +362,12 @@ watch(selectNode, () => {
isLoad.value && hideLoader(); isLoad.value && hideLoader();
}); });
/** /** hook เมื่อมีการเรียกใช้ Components*/
* hook เมอมการเรยกใช Components
*/
function getSearch() { function getSearch() {
store.formFilter.page = 1; store.formFilter.page = 1;
fetchDataPerson(); fetchDataPerson();
} }
onMounted(async () => { onMounted(async () => {
await Promise.all([selectType(), fetchTree()]); await Promise.all([selectType(), fetchTree()]);
}); });
@ -566,6 +572,57 @@ onMounted(async () => {
@update:model-value="getSearch" @update:model-value="getSearch"
/> />
</div> </div>
<div
class="row q-gutter-sm justify-center"
v-if="empType !== 'officer'"
>
<q-toggle
v-model="store.formFilter.isShowRetire"
color="primary"
label="แสดงข้อมูลผู้พ้นจากราชการ"
@update:model-value="getSearch"
/>
<q-btn-dropdown
v-if="store.formFilter.isShowRetire"
rounded
flat
dense
label-color="white"
dropdown-icon="mdi-chevron-down"
class="q-px-sm"
>
<template v-slot:label>
{{
store.labelOption.retireType !== "ทั้งหมด"
? store.labelOption.retireType
: `ประเภท${store.labelOption.retireType}`
}}
<q-btn
v-if="store.labelOption.retireType !== 'ทั้งหมด'"
size="10px"
flat
round
color="white"
icon="close"
@click.stop.prevent="clearSelect('retireType')"
/>
</template>
<q-list>
<q-item
v-for="(item, index) in store.retireTypeEmpOps"
:key="index"
clickable
v-close-popup
@click="selectRetireType(item)"
>
<q-item-section>
<q-item-label>{{ item.name }}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
</div>
<div <div
v-if="empType === 'officer'" v-if="empType === 'officer'"
@ -590,6 +647,46 @@ onMounted(async () => {
label="แสดงตำแหน่งทั้งหมด" label="แสดงตำแหน่งทั้งหมด"
@update:model-value="getSearch" @update:model-value="getSearch"
/> />
<q-btn-dropdown
v-if="store.formFilter.isShowRetire"
rounded
flat
dense
label-color="white"
dropdown-icon="mdi-chevron-down"
class="q-px-sm"
>
<template v-slot:label>
{{
store.labelOption.retireType !== "ทั้งหมด"
? store.labelOption.retireType
: `ประเภทการพ้นจากราชการ${store.labelOption.retireType}`
}}
<q-btn
v-if="store.labelOption.retireType !== 'ทั้งหมด'"
size="10px"
flat
round
color="white"
icon="close"
@click.stop.prevent="clearSelect('retireType')"
/>
</template>
<q-list>
<q-item
v-for="(item, index) in store.retireTypeOps"
:key="index"
clickable
v-close-popup
@click="selectRetireType(item)"
>
<q-item-section>
<q-item-label>{{ item.name }}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
</div> </div>
</div> </div>
</div> </div>

View file

@ -48,6 +48,9 @@ const dataMapToSend = computed(() => {
citizenId: i.citizenId, citizenId: i.citizenId,
rootId: i.rootId, rootId: i.rootId,
remarkVertical: i.reason, remarkVertical: i.reason,
position: i.position,
posType: i.posTypeName,
posLevel: i.posLevelName,
})); }));
}); });
const visibleColumns2 = ref<string[]>([ const visibleColumns2 = ref<string[]>([

View file

@ -57,6 +57,9 @@ const dataMapToSend = computed(() => {
citizenId: i.citizenId, citizenId: i.citizenId,
rootId: i.rootId, rootId: i.rootId,
remarkVertical: i.reason, remarkVertical: i.reason,
position: i.position,
posType: i.posTypeName,
posLevel: i.posLevelName,
})); }));
}); });
const visibleColumns2 = ref<string[]>([ const visibleColumns2 = ref<string[]>([

View file

@ -16,8 +16,13 @@ import DialogCreateCommand from "@/modules/18_command/components/DialogCreateCom
/** use*/ /** use*/
const $q = useQuasar(); const $q = useQuasar();
const { statusText } = useTransferDataStore(); const { statusText } = useTransferDataStore();
const { dialogConfirm, findOrgNameOld, findPosMasterNoOld, date2Thai,onSearchDataTable } = const {
useCounterMixin(); dialogConfirm,
findOrgNameOld,
findPosMasterNoOld,
date2Thai,
onSearchDataTable,
} = useCounterMixin();
/** props*/ /** props*/
const props = defineProps({ const props = defineProps({
@ -26,9 +31,11 @@ const props = defineProps({
getData: Function, getData: Function,
}); });
const rows2 = defineModel<any[]>('rows2',{required:true}) const rows2 = defineModel<any[]>("rows2", { required: true });
const rows2Data = defineModel<any[]>('rows2Data',{required:true}) const rows2Data = defineModel<any[]>("rows2Data", { required: true });
const filterKeyword2 = defineModel<string>('filterKeyword2',{required:true}) const filterKeyword2 = defineModel<string>("filterKeyword2", {
required: true,
});
const emit = defineEmits(["update:filterKeyword2", "update:selected"]); const emit = defineEmits(["update:filterKeyword2", "update:selected"]);
@ -180,6 +187,9 @@ const dataMapToSend = computed(() => {
lastName: i.lastName, lastName: i.lastName,
citizenId: i.citizenId, citizenId: i.citizenId,
remarkVertical: i.reason, remarkVertical: i.reason,
position: i.positionOld,
posType: i.posTypeNameOld,
posLevel: i.posLevelNameOld,
})); }));
}); });
const modalCommand = ref<boolean>(false); const modalCommand = ref<boolean>(false);
@ -219,10 +229,10 @@ watch(
); );
function onSearch() { function onSearch() {
rows2.value= onSearchDataTable( rows2.value = onSearchDataTable(
filterKeyword2.value, filterKeyword2.value,
rows2Data.value, rows2Data.value,
columns2.value? columns2.value: [] columns2.value ? columns2.value : []
); );
} }
</script> </script>

View file

@ -53,6 +53,9 @@ const dataMapToSend = computed(() => {
lastName: i.lastName, lastName: i.lastName,
citizenId: i.citizenId, citizenId: i.citizenId,
remarkVertical: i.reason, remarkVertical: i.reason,
position: i.positionOld,
posType: i.positionTypeOld,
posLevel: i.positionLevelOld,
})); }));
}); });
const visibleColumns2 = ref<string[]>([ const visibleColumns2 = ref<string[]>([

View file

@ -224,22 +224,22 @@ async function fetchData() {
data.education.map((row: any) => { data.education.map((row: any) => {
listRow.push({ listRow.push({
id: guidCheck(row.id) ?? "", id: guidCheck(row.id) ?? "",
educationLevel: row.educationLevel ?? "", educationLevel: row.educationLevel ?? "-",
educationLevelId: guidCheck(row.educationLevelId) ?? "", educationLevelId: guidCheck(row.educationLevelId) ?? "-",
institute: row.institute ?? "", institute: row.institute ?? "-",
degree: row.degree ?? "", degree: row.degree ?? "-",
field: row.field ?? "", field: row.field ?? "-",
gpa: row.gpa ?? "", gpa: row.gpa ?? "-",
country: row.country ?? "", country: row.country ?? "-",
duration: row.duration ?? "", duration: row.duration ?? "-",
other: row.other ?? "", other: row.other ?? "-",
fundName: row.fundName ?? "", fundName: row.fundName ?? "-",
durationYear: row.durationYear ?? 0, durationYear: row.durationYear ?? 0,
finishDate: row.finishDate ?? new Date(), finishDate: row.finishDate ?? new Date(),
isDate: row.isDate ? "true" : "false", isDate: row.isDate ? "true" : "false",
startDate: row.startDate ? new Date(row.startDate) : new Date(), startDate: row.startDate ? new Date(row.startDate) : "",
endDate: row.endDate ? new Date(row.endDate) : new Date(), endDate: row.endDate ? new Date(row.endDate) : "",
positionPath: row.positionPath ?? "", positionPath: row.positionPath ?? "-",
isEducation: row.isEducation ? true : false, isEducation: row.isEducation ? true : false,
}); });
}); });

View file

@ -544,10 +544,10 @@ onMounted(() => {
v-if="col.name == 'issueDate' || col.name == 'expireDate'" v-if="col.name == 'issueDate' || col.name == 'expireDate'"
class="table_ellipsis" class="table_ellipsis"
> >
{{ date2Thai(col.value) }} {{ col.value ? date2Thai(col.value) : "-" }}
</div> </div>
<div v-else class="table_ellipsis"> <div v-else class="table_ellipsis">
{{ col.value }} {{ col.value ? col.value : "-" }}
</div> </div>
</q-td> </q-td>
</q-tr> </q-tr>

View file

@ -696,7 +696,9 @@ watch(visibleColumns, (count: String[], prevCount: String[]) => {
onMounted(async () => { onMounted(async () => {
await fetchLevel(); await fetchLevel();
await fetchPositionPath(); await fetchPositionPath();
rows.value = props.data; rows.value = props.data;
rowsData.value = props.data;
}); });
</script> </script>
<template> <template>
@ -729,15 +731,19 @@ onMounted(async () => {
> >
{{ {{
props.row.isDate == "true" props.row.isDate == "true"
? date2Thai(col.value) ? col.value
: new Date(col.value).getFullYear() + 543 ? date2Thai(col.value)
: "-"
: col.value
? new Date(col.value).getFullYear() + 543
: "-"
}} }}
</div> </div>
<div v-else-if="col.name == 'finishDate'" class="table_ellipsis"> <div v-else-if="col.name == 'finishDate'" class="table_ellipsis">
{{ date2Thai(col.value) }} {{ col.value ? date2Thai(col.value) : "-" }}
</div> </div>
<div v-else class="table_ellipsis"> <div v-else class="table_ellipsis">
{{ col.value }} {{ col.value ?? "-" }}
</div> </div>
</q-td> </q-td>
<!-- <q-td auto-width> <!-- <q-td auto-width>

View file

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, watch } from "vue"; import { ref, watch, computed } from "vue";
import { useQuasar } from "quasar"; import { useQuasar } from "quasar";
import avatar from "@/assets/avatar_user.jpg"; import avatar from "@/assets/avatar_user.jpg";
@ -21,7 +21,7 @@ const mixin = useCounterMixin();
const route = useRoute(); const route = useRoute();
const DataStore = usePlacementDataStore(); const DataStore = usePlacementDataStore();
const storeCommand = useCommandMainStore(); const storeCommand = useCommandMainStore();
const { dialogConfirm, dateText,onSearchDataTable } = mixin; const { dialogConfirm, dateText, onSearchDataTable } = mixin;
const modal = defineModel<boolean>("modal", { required: true }); const modal = defineModel<boolean>("modal", { required: true });
/** props */ /** props */
@ -144,6 +144,22 @@ const columns = ref<QTableProps["columns"]>([
}, },
]); ]);
const dataMapToSend = computed(() => {
return selected.value.map((i: any) => ({
id: i.id,
profileId: i.profileId,
prefix: i.prefix,
firstName: i.firstName,
lastName: i.lastName,
citizenId: i.citizenId,
rootId: i.rootId,
remarkVertical: i.reason,
position: i.positionCandidate,
posType: i.posTypeCandidateName,
posLevel: i.posLevelCandidateName,
}));
});
/** /**
* ลเตอร คำส * ลเตอร คำส
* @param val าจาก Input * @param val าจาก Input
@ -172,11 +188,19 @@ function saveOrder() {
} }
/** ฟังก์ชั่นสำหรับ filter รายการข้อมูลคนตามประเภทคำสั่งที่เลือก */ /** ฟังก์ชั่นสำหรับ filter รายการข้อมูลคนตามประเภทคำสั่งที่เลือก */
function filterSelectOrder() { function filterSelectOrder(val: string) {
const data = props.rows ? props.rows : []; const data = props.rows ? props.rows : [];
selected.value = []; selected.value = [];
rows.value = data;
rowsData.value = data; if (val === "C-PM-01" || val === "C-PM-02") {
rows.value = rowsData.value = data;
} else {
rows.value = rowsData.value = data.filter(
(e: any) => e?.bmaOfficerCheck === "OFFICER"
);
}
onSearch();
} }
/** ปิด Modal และล้างค่าที่เลือก */ /** ปิด Modal และล้างค่าที่เลือก */
@ -185,7 +209,6 @@ function closeModal() {
commandType.value = ""; commandType.value = "";
} }
function onSearch() { function onSearch() {
rows.value = onSearchDataTable( rows.value = onSearchDataTable(
filter.value, filter.value,
@ -233,7 +256,7 @@ watch(
<template> <template>
<q-dialog v-model="modal" persistent> <q-dialog v-model="modal" persistent>
<q-card style="width: 1200px; max-width: 80vw"> <q-card style="min-width: 80%">
<DialogHeader :tittle="'ส่งไปออกคำสั่ง'" :close="closeModal" /> <DialogHeader :tittle="'ส่งไปออกคำสั่ง'" :close="closeModal" />
<q-separator /> <q-separator />
<q-card-section> <q-card-section>
@ -460,6 +483,6 @@ watch(
<DialogCreateCommand <DialogCreateCommand
v-model:modal="modalCommand" v-model:modal="modalCommand"
:command-type-code="commandType" :command-type-code="commandType"
:persons="selected" :persons="dataMapToSend"
/> />
</template> </template>

View file

@ -23,6 +23,7 @@ import DialogFooter from "@/modules/05_placement/components/PersonalList/DialogF
import DialogHeader from "@/components/DialogHeader.vue"; import DialogHeader from "@/components/DialogHeader.vue";
import DialogOrders from "@/modules/05_placement/components/PersonalList/DialogOrders.vue"; // import DialogOrders from "@/modules/05_placement/components/PersonalList/DialogOrders.vue"; //
import PopupPersonal from "@/components/Dialogs/PopupPersonalNew.vue"; import PopupPersonal from "@/components/Dialogs/PopupPersonalNew.vue";
import DialogPreviewCommand from "@/modules/18_command/components/DialogPreviewCommand.vue";
const $q = useQuasar(); // show dialog const $q = useQuasar(); // show dialog
const DataStore = usePlacementDataStore(); const DataStore = usePlacementDataStore();
@ -48,6 +49,10 @@ const props = defineProps({
}, },
}); });
const modalCommand = ref<boolean>(false);
const command = ref<string>("");
const commandId = ref<string>("");
let roleAdmin = ref<boolean>(false); let roleAdmin = ref<boolean>(false);
const edit = ref<boolean>(true); const edit = ref<boolean>(true);
const modalPersonal = ref<boolean>(false); const modalPersonal = ref<boolean>(false);
@ -116,6 +121,7 @@ const visibleColumns = ref<any[]>([
"statusName", "statusName",
"draft", "draft",
"positionCandidate", "positionCandidate",
"refCommandNo",
]); ]);
/** /**
@ -227,6 +233,17 @@ const columns = ref<QTableProps["columns"]>([
sort: (a: string, b: string) => sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }), a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
}, },
{
name: "refCommandNo",
align: "left",
label: "คำสั่งบรรจุ",
sortable: true,
field: "refCommandNo",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
]); ]);
/** /**
@ -370,6 +387,8 @@ async function getTable() {
citizenId: data.citizenId, citizenId: data.citizenId,
id: data.id, id: data.id,
profileId: data.profileId, profileId: data.profileId,
refCommandNo: data.refCommandNo,
commandId: data.commandId,
}; };
rowsAll.value.push(rowData); rowsAll.value.push(rowData);
}); });
@ -735,7 +754,6 @@ function onSubmitDate() {
*/ */
function openModalOrder(val: boolean) { function openModalOrder(val: boolean) {
// object #e.draft == "" && // object #e.draft == "" &&
rowsOrder.value = rows.value.filter( rowsOrder.value = rows.value.filter(
(e: any) => (e: any) =>
(DataStore.isStaff && (DataStore.isStaff &&
@ -845,6 +863,13 @@ function onSearchAdd() {
); );
} }
function onRefCommand(data: any) {
modalCommand.value = true;
command.value = data.refCommandNo;
commandId.value = data.commandId;
// commandId.value = 'bdf9da91-ba45-497a-a2b7-cc49e2446d97'; //
}
onMounted(async () => { onMounted(async () => {
await getWorkFlow(); await getWorkFlow();
await getTable(); await getTable();
@ -1283,6 +1308,23 @@ onMounted(async () => {
{{ props.row.statusName }} {{ props.row.statusName }}
</div> </div>
</template> </template>
<template v-else-if="col.name === 'refCommandNo'">
<div
class="text-weight-medium"
:class="
props.row.refCommandNo && props.row.commandId
? 'table_ellipsis text-blue cursor-pointer'
: 'table_ellipsis '
"
@click="
props.row.refCommandNo && props.row.commandId
? onRefCommand(props.row)
: null
"
>
{{ props.row.refCommandNo ? props.row.refCommandNo : "-" }}
</div>
</template>
</q-td> </q-td>
</q-tr> </q-tr>
</template> </template>
@ -1677,6 +1719,12 @@ onMounted(async () => {
:id="personalId" :id="personalId"
@update:modal="updatemodalPersonal" @update:modal="updatemodalPersonal"
/> />
<DialogPreviewCommand
v-model:modal="modalCommand"
v-model:command="command"
v-model:commandId="commandId"
/>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>

View file

@ -26,6 +26,9 @@ const dataMapToSend = computed(() => {
citizenId: i.citizenId, citizenId: i.citizenId,
rootId: i.rootId, rootId: i.rootId,
remarkVertical: i.reason, remarkVertical: i.reason,
position: i.position,
posType: i.posTypeName,
posLevel: i.posLevelName,
})); }));
}); });
const mixin = useCounterMixin(); const mixin = useCounterMixin();

View file

@ -43,6 +43,9 @@ const dataMapToSend = computed(() => {
lastName: i.lastName, lastName: i.lastName,
citizenId: i.citizenId, citizenId: i.citizenId,
remarkVertical: i.reason, remarkVertical: i.reason,
position: i.positionOld,
posType: i.posTypeNameOld,
posLevel: i.posLevelNameOld,
})); }));
}); });
const columns2 = ref<QTableProps["columns"]>([ const columns2 = ref<QTableProps["columns"]>([

View file

@ -14,7 +14,7 @@ import DialogCreateCommand from "@/modules/18_command/components/DialogCreateCom
const $q = useQuasar(); const $q = useQuasar();
const mixin = useCounterMixin(); const mixin = useCounterMixin();
const { statusText } = useTransferDataStore(); const { statusText } = useTransferDataStore();
const { dialogConfirm, date2Thai,onSearchDataTable } = mixin; const { dialogConfirm, date2Thai, onSearchDataTable } = mixin;
const modal = defineModel<boolean>("modal", { required: true }); const modal = defineModel<boolean>("modal", { required: true });
/** props */ /** props */
@ -23,8 +23,8 @@ const props = defineProps({
fetchData: Function, fetchData: Function,
}); });
const rows = defineModel<any[]>('rows',{required:true}) const rows = defineModel<any[]>("rows", { required: true });
const rowsData = defineModel<any[]>('rowsData',{required:true}) const rowsData = defineModel<any[]>("rowsData", { required: true });
const modalCommand = ref<boolean>(false); //- modal const modalCommand = ref<boolean>(false); //- modal
//Table //Table
const selected = ref<ResponseData[]>([]); // const selected = ref<ResponseData[]>([]); //
@ -37,6 +37,9 @@ const dataMapToSend = computed(() => {
lastName: i.lastName, lastName: i.lastName,
citizenId: i.citizenId, citizenId: i.citizenId,
remarkVertical: i.reason, remarkVertical: i.reason,
position: i.positionOld,
posType: i.positionTypeOld,
posLevel: i.positionLevelOld,
})); }));
}); });

View file

@ -61,6 +61,9 @@ const dataMapToSend = computed(() => {
firstName: i.firstName, firstName: i.firstName,
lastName: i.lastName, lastName: i.lastName,
citizenId: i.idcard, citizenId: i.idcard,
position: i.positionOld,
posType: i.positionTypeOld,
posLevel: i.positionLevelOld,
})); }));
}); });

View file

@ -27,6 +27,9 @@ const dataMapToSend = computed(() => {
lastName: i.lastName, lastName: i.lastName,
citizenId: i.citizenId, citizenId: i.citizenId,
rootId: i.rootId, rootId: i.rootId,
position: i.positionOld,
posType: i.positionTypeOld,
posLevel: i.positionLevelOld,
})) }))
: []; : [];
}); });

View file

@ -258,6 +258,7 @@ function close() {
modal.value = false; modal.value = false;
member.value = ""; member.value = "";
selected.value = []; selected.value = [];
rowsDirector.value = [];
} }
function updatePagination(newPagination: any) { function updatePagination(newPagination: any) {
@ -324,13 +325,13 @@ async function getPerson() {
); );
totalList.value = Math.ceil(dataTotal / pagination.value.rowsPerPage); totalList.value = Math.ceil(dataTotal / pagination.value.rowsPerPage);
total.value = dataTotal; total.value = dataTotal;
hideLoader();
}) })
.catch((e) => { .catch((e) => {
messageError($q, e); messageError($q, e);
hideLoader();
}) })
.finally(() => {}); .finally(() => {
hideLoader();
});
} }
function onDelete(id: string) { function onDelete(id: string) {

View file

@ -5,6 +5,7 @@ import { useQuasar } from "quasar";
import http from "@/plugins/http"; import http from "@/plugins/http";
import config from "@/app.config"; import config from "@/app.config";
import genReport from "@/plugins/genreport";
import { useProbationDataStore } from "@/modules/05_placement/storeProbation"; import { useProbationDataStore } from "@/modules/05_placement/storeProbation";
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
@ -13,7 +14,7 @@ import type {
AppointTopicMain, AppointTopicMain,
} from "@/modules/05_placement/interface/index/Main"; } from "@/modules/05_placement/interface/index/Main";
import genReport from "@/plugins/genreport"; import FormUploadFile from "@/modules/05_placement/components/probation/FormEvaluation/FormUploadFile.vue";
const $q = useQuasar(); const $q = useQuasar();
const isEdit = ref<boolean>(false); const isEdit = ref<boolean>(false);
@ -86,6 +87,7 @@ const activityCount = ref<number>(2);
const activity_desc = ref<string[]>(Array(activityCount.value).fill("")); const activity_desc = ref<string[]>(Array(activityCount.value).fill(""));
const goal_desc = ref<string[]>(Array(activityCount.value).fill("")); const goal_desc = ref<string[]>(Array(activityCount.value).fill(""));
const checkRule = ref<CheckboxItem[]>([]); const checkRule = ref<CheckboxItem[]>([]);
const isCheckFile = ref<boolean>(false);
const isDatePicker2Readonly = computed(() => { const isDatePicker2Readonly = computed(() => {
return date_start.value === undefined; return date_start.value === undefined;
@ -167,13 +169,12 @@ interface CheckboxItem {
status_select: number; status_select: number;
checked: number; checked: number;
} }
/** /**
* update edit * update edit
* @param id personal id * @param id personal id
*/ */
async function dataEdit(id: string) { async function dataEdit(id: string) {
// await myForm.value.validate().then((result: boolean) => {
// if (result) {
showLoader(); showLoader();
const data = putDataEdit(id); const data = putDataEdit(id);
http http
@ -185,10 +186,6 @@ async function dataEdit(id: string) {
getAssign(); getAssign();
hideLoader(); hideLoader();
}); });
// } else {
// dialogMessageNotify($q, "");
// }
// });
} }
/** /**
@ -773,11 +770,11 @@ async function getAssign() {
)?.directors; )?.directors;
const dataPerson = dataMap?.map((dataPerson: AppointTopic) => ({ const dataPerson = dataMap?.map((dataPerson: AppointTopic) => ({
...dataPerson, ...dataPerson,
name: `${dataPerson.name} (${dataPerson.position}${ name: `${dataPerson.name} ${
dataPerson.positionLevel && dataPerson.positionType dataPerson.position
? ", " + dataPerson.positionType + " : " + dataPerson.positionLevel ? `(${dataPerson.position}${dataPerson.positionLevel})`
: "" : ""
})`, }`,
})); }));
reportPersonIdOp.value = dataPerson ?? []; reportPersonIdOp.value = dataPerson ?? [];
if (reportPersonIdOp.value.length !== 0) { if (reportPersonIdOp.value.length !== 0) {
@ -906,6 +903,7 @@ function filterFnCaretaker(val: string, update: any) {
const dataFilter = filtermantor(OPcaretakerNew.value, [ const dataFilter = filtermantor(OPcaretakerNew.value, [
caretaker2.value, caretaker2.value,
]).filter((i: any) => i.id !== chairman.value.id); ]).filter((i: any) => i.id !== chairman.value.id);
if (val == "") { if (val == "") {
update(() => { update(() => {
optionCaretaker.value = dataFilter; optionCaretaker.value = dataFilter;
@ -1007,11 +1005,11 @@ function updateAppointMent() {
const data = appointTopic.value.directors; const data = appointTopic.value.directors;
const dataPerson = data.map((dataPerson: AppointTopic) => ({ const dataPerson = data.map((dataPerson: AppointTopic) => ({
...dataPerson, ...dataPerson,
name: `${dataPerson.name} (${dataPerson.position}${ name: `${dataPerson.name} ${
dataPerson.positionLevel && dataPerson.positionType dataPerson.position
? ", " + dataPerson.positionType + " : " + dataPerson.positionLevel ? `(${dataPerson.position}${dataPerson.positionLevel})`
: "" : ""
})`, }`,
})); }));
reportPersonIdOp.value = dataPerson; reportPersonIdOp.value = dataPerson;
@ -1032,11 +1030,10 @@ function updateAppointMent() {
const createChairmanObject = (dataPerson: AppointTopic) => ({ const createChairmanObject = (dataPerson: AppointTopic) => ({
id: dataPerson.profileId, id: dataPerson.profileId,
name: dataPerson.name, name: dataPerson.name,
label: dataPerson.position label: dataPerson.position
? `${dataPerson.name} (${dataPerson.position}${ ? `${dataPerson.name} (${dataPerson.position}${
dataPerson.positionLevel && dataPerson.positionType dataPerson.positionLevel ? dataPerson.positionLevel : ""
? ", " + dataPerson.positionType + " : " + dataPerson.positionLevel
: ""
})` })`
: dataPerson.name, : dataPerson.name,
posLevel: dataPerson.positionLevel, posLevel: dataPerson.positionLevel,
@ -1152,7 +1149,8 @@ onMounted(async () => {
<q-btn <q-btn
v-if=" v-if="
!checkRoutePermisson && !checkRoutePermisson &&
probationStore.dataPermissions?.tab1.isEdit probationStore.dataPermissions?.tab1.isEdit &&
!isCheckFile
" "
dense dense
flat flat
@ -2878,8 +2876,20 @@ onMounted(async () => {
</q-select> </q-select>
</div> </div>
</div> </div>
<FormUploadFile
:group="'มอบหมายงาน'"
v-model:is-check-file="isCheckFile"
:check-route-permisson="checkRoutePermisson"
:data-permissions="
probationStore.dataPermissions?.tab1.isEdit
? probationStore.dataPermissions?.tab1.isEdit
: false
"
/>
</div> </div>
</div> </div>
<q-separator v-show="routeName == 'probationWorkAdd'" /> <q-separator v-show="routeName == 'probationWorkAdd'" />
<div <div
v-show="routeName == 'probationWorkAdd'" v-show="routeName == 'probationWorkAdd'"

View file

@ -0,0 +1,292 @@
<script setup lang="ts">
import { ref, watch } from "vue";
import { useQuasar } from "quasar";
import { useRoute } from "vue-router";
import { useCounterMixin } from "@/stores/mixin";
import http from "@/plugins/http";
import config from "@/app.config";
import type { QTableProps } from "quasar";
import DialogHeader from "@/components/DialogHeader.vue";
const $q = useQuasar();
const route = useRoute();
const { showLoader, hideLoader, messageError } = useCounterMixin();
const modal = defineModel<boolean>("modal", { required: true }); //popup /
const emit = defineEmits(["update-authority"]);
const personalId = ref<string>(route.params.personalId.toString());
const selected = ref<any[]>([]);
const isAct = ref<boolean>(false);
const search = ref<string>("");
const rows = ref<any[]>([]); ///
const page = ref<number>(1);
const pageSize = ref<number>(10);
const maxPaeg = ref<number>(1);
const total = ref<number>(0);
const columns = ref<QTableProps["columns"]>([
{
name: "citizenId",
align: "left",
label: "เลขประจำตัวประชาชน",
sortable: true,
field: "citizenId",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "posNo",
align: "left",
label: "เลขที่ตำแหน่ง",
sortable: true,
field: "posNo",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "fullName",
align: "left",
label: "ชื่อ-นามสกุล",
sortable: true,
field: "fullName",
format(val, row) {
return `${row.prefix}${row.firstName} ${row.lastName}`;
},
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "position",
align: "left",
label: "ตำแหน่ง",
sortable: true,
field: "position",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "posType",
align: "left",
label: "ประเภทตำแหน่ง",
sortable: true,
field: "posType",
format(val, row) {
return `${row.posType} ${row.posLevel ? `(${row.posLevel})` : ""} `;
},
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "actFullName",
align: "left",
label: "รักษาการแทน",
sortable: true,
field: "actFullName",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
]);
function onCloseDialog() {
modal.value = false;
isAct.value = false;
rows.value = [];
selected.value = [];
search.value = "";
page.value = 1;
pageSize.value = 10;
maxPaeg.value = 1;
total.value = 0;
}
function fetchList() {
showLoader();
http
.post(config.API.probationCommanderDirector, {
isDirector: true, // fix true
isAct: isAct.value,
keyword: search.value.trim(),
page: page.value,
pageSize: pageSize.value,
profileId: personalId.value,
})
.then((res) => {
const data = res.data.result;
rows.value = data.data;
maxPaeg.value = Math.ceil(data.total / pageSize.value);
total.value = data.total;
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
function onAct() {
onSearchData();
}
function onSearchData() {
page.value = 1;
fetchList();
}
function updatePagination(newPagination: any) {
pageSize.value = newPagination.rowsPerPage;
}
function onSelectAuthority() {
emit("update-authority", selected.value[0]);
onCloseDialog();
}
watch(modal, (val) => {
if (val) {
fetchList();
}
});
</script>
<template>
<!-- อำนาจออกคำส -->
<q-dialog v-model="modal" persistent>
<q-card style="min-width: 70%">
<DialogHeader
:tittle="'เลือกผู้มีอำนาจออกคำสั่ง'"
:close="onCloseDialog"
/>
<q-separator />
<q-card-section>
<div class="col-12 q-col-gutter-sm">
<div class="col-12 row q-col-gutter-md items-start">
<div class="col-12 col-sm-4 col-md-4">
<q-input
v-model="search"
outlined
hide-bottom-space
dense
label="คำค้น"
/>
</div>
<q-checkbox
keep-color
v-model="isAct"
label="แสดงเฉพาะรักษาการแทน"
color="primary"
@update:model-value="onAct"
>
<q-tooltip>แสดงเฉพาะรกษาการแทน </q-tooltip>
</q-checkbox>
<q-space />
<div class="col-12 col-sm-6 col-md-3">
<q-btn
color="primary"
icon="search"
label="ค้นหา"
class="full-width q-pa-sm"
outline
@click.prevent="onSearchData"
>
</q-btn>
</div>
</div>
<div class="col-12">
<d-table
flat
:columns="columns"
:rows="rows"
row-key="key"
dense
selection="single"
v-model:selected="selected"
:rows-per-page-options="[10, 25, 50, 100]"
@update:pagination="updatePagination"
>
<template v-slot:header-selection="scope">
<q-checkbox
keep-color
color="primary"
dense
v-model="scope.checkBox"
/>
</template>
<template v-slot:header="props">
<q-tr :props="props">
<q-th class="text-center"> </q-th>
<q-th
v-for="col in props.cols"
:key="col.name"
:props="props"
>
<span class="text-weight-medium">{{ col.label }}</span>
</q-th>
</q-tr>
</template>
<template v-slot:body="props">
<q-tr :props="props">
<q-td class="text-center">
<q-checkbox
keep-color
color="primary"
dense
v-model="props.selected"
/>
</q-td>
<q-td
v-for="col in props.cols"
:key="col.name"
:props="props"
>
<div>
{{ col.value ?? "-" }}
</div>
</q-td>
</q-tr>
</template>
<template v-slot:pagination="scope">
งหมด {{ total }} รายการ
<q-pagination
v-model="page"
active-color="primary"
color="dark"
:max="Number(maxPaeg)"
size="sm"
boundary-links
direction-links
:max-pages="5"
@update:model-value="fetchList"
></q-pagination>
</template>
</d-table>
</div>
</div>
</q-card-section>
<q-separator />
<q-card-actions align="right">
<q-btn
:disable="selected.length === 0"
label="เลือกผู้มีอำนาจออกคำสั่ง"
color="public"
@click="onSelectAuthority"
/>
</q-card-actions>
</q-card>
</q-dialog>
</template>
<style scoped></style>

View file

@ -9,6 +9,8 @@ import config from "@/app.config";
import criterion from "@/modules/05_placement/components/probation/Criterion.vue"; import criterion from "@/modules/05_placement/components/probation/Criterion.vue";
import type { ListDataText } from "@/modules/05_placement/interface/index/Main"; import type { ListDataText } from "@/modules/05_placement/interface/index/Main";
import FormUploadFile from "@/modules/05_placement/components/probation/FormEvaluation/FormUploadFile.vue";
const router = useRouter(); const router = useRouter();
const routeName = router.currentRoute.value.name; const routeName = router.currentRoute.value.name;
@ -68,6 +70,7 @@ const start_date = ref<Date>(new Date());
const date_finish = ref<Date>(new Date()); const date_finish = ref<Date>(new Date());
const status = ref<boolean>(true); const status = ref<boolean>(true);
const dataArr = ref<any>(); const dataArr = ref<any>();
const isCheckFile = ref<boolean>(false);
const behavio_strengthRules = [ const behavio_strengthRules = [
(val: any) => (val && val.length > 0) || "กรุณากรอกข้อมูลจุดเด่น", (val: any) => (val && val.length > 0) || "กรุณากรอกข้อมูลจุดเด่น",
@ -298,10 +301,10 @@ onMounted(async () => {
<div class="toptitle text-dark col-12 row items-center q-gutter-md"> <div class="toptitle text-dark col-12 row items-center q-gutter-md">
<div>แบบประเมนผล (งคบบญชา)</div> <div>แบบประเมนผล (งคบบญชา)</div>
<div v-if="status == false"> <div v-if="!status">
<q-btn <q-btn
v-if=" v-if="
!checkRoutePermisson && probationStore.dataPermissions?.tab4.isEdit !checkRoutePermisson && probationStore.dataPermissions?.tab4.isEdit && !isCheckFile
" "
dense dense
flat flat
@ -1081,6 +1084,17 @@ onMounted(async () => {
</div> </div>
</div> </div>
<FormUploadFile
:group="`ประเมินผลผู้บังคับบัญชาครั้งที่ ${props.tab?.charAt(4)}`"
v-model:is-check-file="isCheckFile"
:check-route-permisson="checkRoutePermisson"
:data-permissions="
probationStore.dataPermissions?.tab4.isEdit
? probationStore.dataPermissions?.tab4.isEdit
: false
"
/>
<!-- <Footer /> --> <!-- <Footer /> -->
<q-toolbar class="text-primary" v-if="routeName == 'FormEvaluateAdd'"> <q-toolbar class="text-primary" v-if="routeName == 'FormEvaluateAdd'">
<q-space /> <q-space />

View file

@ -9,6 +9,7 @@ import config from "@/app.config";
import criterion from "@/modules/05_placement/components/probation/Criterion.vue"; import criterion from "@/modules/05_placement/components/probation/Criterion.vue";
import type { ListDataText } from "@/modules/05_placement/interface/index/Main"; import type { ListDataText } from "@/modules/05_placement/interface/index/Main";
import FormUploadFile from "@/modules/05_placement/components/probation/FormEvaluation/FormUploadFile.vue";
const optionText = ref<ListDataText[]>([ const optionText = ref<ListDataText[]>([
{ value: "1", label: "ต่ำกว่าความคาดหวังมาก (1)" }, { value: "1", label: "ต่ำกว่าความคาดหวังมาก (1)" },
@ -94,6 +95,8 @@ const develop_result_option = ref<any>([
{ name: "ไม่ผ่าน (ต่ำกว่าร้อยละ 60)", value: 0 }, { name: "ไม่ผ่าน (ต่ำกว่าร้อยละ 60)", value: 0 },
]); ]);
const isCheckFile = ref<boolean>(false);
// score // score
const score1 = computed(() => { const score1 = computed(() => {
if ( if (
@ -126,6 +129,29 @@ const achievement_result: any = computed(() => {
} }
return 0; return 0;
}); });
const score1Per60 = computed(() => {
if (
etc.value === true &&
achievement_other.value.text !== undefined &&
achievement_other.value.level !== undefined
) {
return (
((learn_level.value +
apply_level.value +
success_level.value +
achievement_other.value.level) /
achievement_score_total.value) *
60
);
}
return (
((learn_level.value + apply_level.value + success_level.value) /
achievement_score_total.value) *
60
);
});
const score2 = computed(() => { const score2 = computed(() => {
let sum_conduct = conduct_level.value.reduce( let sum_conduct = conduct_level.value.reduce(
(sum: number, level: number) => sum + level, (sum: number, level: number) => sum + level,
@ -186,19 +212,24 @@ const percent_sum: any = computed(() => {
}); });
const score4 = computed(() => { const score4 = computed(() => {
return ( return (
Number(orientation.value) + (Number(orientation.value) +
Number(self_learning.value) + Number(self_learning.value) +
Number(training_seminar.value) + Number(training_seminar.value) +
Number(other_training.value) Number(other_training.value)) /
4
); );
}); });
const score5 = computed(() => { const score5 = computed(() => {
return ( const total =
Number(orientation_percent.value) + (Number(orientation_percent.value) +
Number(self_learning_percent.value) + Number(self_learning_percent.value) +
Number(training_seminar_percent.value) + Number(training_seminar_percent.value) +
Number(other_training_percent.value) Number(other_training_percent.value)) /
); 4;
develop_result.value = total > 60 ? 1 : 0;
return total;
}); });
/**set true */ /**set true */
@ -360,7 +391,7 @@ function putformData() {
develop_self_learning_percent: Number(self_learning_percent.value), develop_self_learning_percent: Number(self_learning_percent.value),
develop_training_seminar_percent: Number(training_seminar_percent.value), develop_training_seminar_percent: Number(training_seminar_percent.value),
develop_other_training_percent: Number(other_training_percent.value), develop_other_training_percent: Number(other_training_percent.value),
achievement_score: Number(score1.value), achievement_score: Number(score1Per60.value),
achievement_percent: Number(percent_score1.value), achievement_percent: Number(percent_score1.value),
achievement_score_total: Number(achievement_score_total.value), achievement_score_total: Number(achievement_score_total.value),
achievement_result: Number(achievement_result.value), achievement_result: Number(achievement_result.value),
@ -368,7 +399,7 @@ function putformData() {
behavior_percent: Number(percent_score2.value), behavior_percent: Number(percent_score2.value),
behavior_score_total: Number(behavior_score_total.value), behavior_score_total: Number(behavior_score_total.value),
behavior_result: Number(behavior_result.value), behavior_result: Number(behavior_result.value),
sum_score: Number(score1.value) + Number(score2.value), sum_score: (Number(score1Per60.value) + Number(score2.value)) / 2,
sum_percent: percent_sum.value, sum_percent: percent_sum.value,
chairman_dated: dateToISO(dateAutherise.value), chairman_dated: dateToISO(dateAutherise.value),
develop_result: Number(develop_result.value), develop_result: Number(develop_result.value),
@ -423,11 +454,12 @@ onMounted(async () => {
<div class="row col-12 no-margin q-pa-sm"> <div class="row col-12 no-margin q-pa-sm">
<div class="toptitle text-dark col-12 row items-center q-gutter-md"> <div class="toptitle text-dark col-12 row items-center q-gutter-md">
<div>แบบประเมนผล (คณะกรรมการ)</div> <div>แบบประเมนผล (คณะกรรมการ)</div>
<div v-if="status == false"> <div v-if="!status">
<q-btn <q-btn
v-if=" v-if="
!checkRoutePermisson && !checkRoutePermisson &&
probationStore.dataPermissions?.tab5.isEdit probationStore.dataPermissions?.tab5.isEdit &&
!isCheckFile
" "
dense dense
flat flat
@ -921,7 +953,7 @@ onMounted(async () => {
</q-item-label> </q-item-label>
<q-item-label caption style="color: #464444"> <q-item-label caption style="color: #464444">
<div class="row text-weight-bold"> <div class="row text-weight-bold">
<div class="col">{{ score1 }}</div> <div class="col">{{ score1Per60 }}</div>
<div class="col">{{ percent_score1 }}</div> <div class="col">{{ percent_score1 }}</div>
</div> </div>
</q-item-label> </q-item-label>
@ -984,7 +1016,7 @@ onMounted(async () => {
</q-item-label> </q-item-label>
<q-item-label caption style="color: #464444"> <q-item-label caption style="color: #464444">
<div class="row text-weight-bold"> <div class="row text-weight-bold">
<div class="col">{{ score1 + score2 }}</div> <div class="col">{{ (score1Per60 + score2) / 2 }}</div>
<div class="col">{{ percent_sum }}</div> <div class="col">{{ percent_sum }}</div>
</div> </div>
</q-item-label> </q-item-label>
@ -1030,6 +1062,8 @@ onMounted(async () => {
type="number" type="number"
:readonly="!status" :readonly="!status"
v-model="orientation" v-model="orientation"
:rules="[(val:number) => val <= 100 || 'คะแนนต้องไม่เกิน 100 คะแนน']"
hide-bottom-space
/> />
</div> </div>
<div class="col"> <div class="col">
@ -1039,6 +1073,8 @@ onMounted(async () => {
type="number" type="number"
:readonly="!status" :readonly="!status"
v-model="orientation_percent" v-model="orientation_percent"
:rules="[(val:number) => val <= 100 || 'ร้อยละต้องไม่เกิน 100']"
hide-bottom-space
/> />
</div> </div>
</div> </div>
@ -1052,6 +1088,8 @@ onMounted(async () => {
type="number" type="number"
:readonly="!status" :readonly="!status"
v-model="self_learning" v-model="self_learning"
:rules="[(val:number) => val <= 100 || 'คะแนนต้องไม่เกิน 100 คะแนน']"
hide-bottom-space
/> />
</div> </div>
<div class="col"> <div class="col">
@ -1061,6 +1099,8 @@ onMounted(async () => {
type="number" type="number"
:readonly="!status" :readonly="!status"
v-model="self_learning_percent" v-model="self_learning_percent"
:rules="[(val:number) => val <= 100 || 'ร้อยละต้องไม่เกิน 100']"
hide-bottom-space
/> />
</div> </div>
</div> </div>
@ -1074,6 +1114,8 @@ onMounted(async () => {
type="number" type="number"
:readonly="!status" :readonly="!status"
v-model="training_seminar" v-model="training_seminar"
:rules="[(val:number) => val <= 100 || 'คะแนนต้องไม่เกิน 100 คะแนน']"
hide-bottom-space
/> />
</div> </div>
<div class="col"> <div class="col">
@ -1083,6 +1125,8 @@ onMounted(async () => {
type="number" type="number"
:readonly="!status" :readonly="!status"
v-model="training_seminar_percent" v-model="training_seminar_percent"
:rules="[(val:number) => val <= 100 || 'ร้อยละต้องไม่เกิน 100']"
hide-bottom-space
/> />
</div> </div>
</div> </div>
@ -1098,6 +1142,8 @@ onMounted(async () => {
type="number" type="number"
:readonly="!status" :readonly="!status"
v-model="other_training" v-model="other_training"
:rules="[(val:number) => val <= 100 || 'คะแนนต้องไม่เกิน 100 คะแนน']"
hide-bottom-space
/> />
</div> </div>
<div class="col"> <div class="col">
@ -1107,6 +1153,8 @@ onMounted(async () => {
type="number" type="number"
:readonly="!status" :readonly="!status"
v-model="other_training_percent" v-model="other_training_percent"
:rules="[(val:number) => val <= 100 || 'ร้อยละต้องไม่เกิน 100']"
hide-bottom-space
/> />
</div> </div>
</div> </div>
@ -1356,6 +1404,17 @@ onMounted(async () => {
</div> </div>
</div> </div>
<FormUploadFile
:group="`ประเมินผลคณะกรรมการครั้งที่ ${props.tab?.charAt(4)}`"
:check-route-permisson="checkRoutePermisson"
:data-permissions="
probationStore.dataPermissions?.tab5.isEdit
? probationStore.dataPermissions?.tab5.isEdit
: false
"
v-model:is-check-file="isCheckFile"
/>
<q-toolbar <q-toolbar
class="text-primary" class="text-primary"
v-if="routeName == 'probationFormAddevaluascore'" v-if="routeName == 'probationFormAddevaluascore'"

View file

@ -155,6 +155,29 @@ const achievement_result: any = computed(() => {
} }
return 0; return 0;
}); });
const score1Per60 = computed(() => {
if (
etc.value === true &&
achievement_other.value.text !== undefined &&
achievement_other.value.level !== undefined
) {
return (
((learn_level.value +
apply_level.value +
success_level.value +
achievement_other.value.level) /
achievement_score_total.value) *
60
);
}
return (
((learn_level.value + apply_level.value + success_level.value) /
achievement_score_total.value) *
60
);
});
const score2 = computed(() => { const score2 = computed(() => {
let sum_conduct = conduct_level.value.reduce( let sum_conduct = conduct_level.value.reduce(
(sum: number, level: number) => sum + level, (sum: number, level: number) => sum + level,
@ -216,18 +239,21 @@ const percent_sum: any = computed(() => {
}); });
const score4 = computed(() => { const score4 = computed(() => {
return ( return (
Number(orientation.value) + (Number(orientation.value) +
Number(self_learning.value) + Number(self_learning.value) +
Number(training_seminar.value) + Number(training_seminar.value) +
Number(other_training.value) Number(other_training.value)) /
4
); );
}); });
const score5 = computed(() => { const score5 = computed(() => {
const total = const total =
Number(orientation_percent.value) + (Number(orientation_percent.value) +
Number(self_learning_percent.value) + Number(self_learning_percent.value) +
Number(training_seminar_percent.value) + Number(training_seminar_percent.value) +
Number(other_training_percent.value); Number(other_training_percent.value)) /
4;
develop_result.value = total > 60 ? 1 : 0; develop_result.value = total > 60 ? 1 : 0;
return total; return total;
@ -337,7 +363,7 @@ const putformData = () => {
develop_self_learning_percent: Number(self_learning_percent.value), develop_self_learning_percent: Number(self_learning_percent.value),
develop_training_seminar_percent: Number(training_seminar_percent.value), develop_training_seminar_percent: Number(training_seminar_percent.value),
develop_other_training_percent: Number(other_training_percent.value), develop_other_training_percent: Number(other_training_percent.value),
achievement_score: Number(score1.value), achievement_score: Number(score1Per60.value),
achievement_percent: Number(percent_score1.value), achievement_percent: Number(percent_score1.value),
achievement_score_total: Number(achievement_score_total.value), achievement_score_total: Number(achievement_score_total.value),
achievement_result: Number(achievement_result.value), achievement_result: Number(achievement_result.value),
@ -345,7 +371,7 @@ const putformData = () => {
behavior_percent: Number(percent_score2.value), behavior_percent: Number(percent_score2.value),
behavior_score_total: Number(behavior_score_total.value), behavior_score_total: Number(behavior_score_total.value),
behavior_result: Number(behavior_result.value), behavior_result: Number(behavior_result.value),
sum_score: Number(score1.value) + Number(score2.value), sum_score: (Number(score1Per60.value) + Number(score2.value)) / 2,
sum_percent: percent_sum.value, sum_percent: percent_sum.value,
develop_result: Number(develop_result.value), develop_result: Number(develop_result.value),
chairman_dated: dateToISO(dateAutherise.value), chairman_dated: dateToISO(dateAutherise.value),
@ -1007,7 +1033,7 @@ watch(lengthdiscipline_level, (newLength) => {
</q-item-label> </q-item-label>
<q-item-label caption style="color: #464444"> <q-item-label caption style="color: #464444">
<div class="row text-weight-bold"> <div class="row text-weight-bold">
<div class="col">{{ score1 }}</div> <div class="col">{{ score1Per60 }}</div>
<div class="col">{{ percent_score1 }}</div> <div class="col">{{ percent_score1 }}</div>
</div> </div>
</q-item-label> </q-item-label>
@ -1077,7 +1103,9 @@ watch(lengthdiscipline_level, (newLength) => {
</q-item-label> </q-item-label>
<q-item-label caption style="color: #464444"> <q-item-label caption style="color: #464444">
<div class="row text-weight-bold"> <div class="row text-weight-bold">
<div class="col">{{ score1 + score2 }}</div> <div class="col">
{{ (score1Per60 + score2) / 2 }}
</div>
<div class="col">{{ percent_sum }}</div> <div class="col">{{ percent_sum }}</div>
</div> </div>
</q-item-label> </q-item-label>
@ -1122,6 +1150,8 @@ watch(lengthdiscipline_level, (newLength) => {
dense dense
type="number" type="number"
v-model="orientation" v-model="orientation"
:rules="[(val:number) => val <= 100 || 'คะแนนต้องไม่เกิน 100 คะแนน']"
hide-bottom-space
/> />
</div> </div>
<div class="col"> <div class="col">
@ -1130,6 +1160,8 @@ watch(lengthdiscipline_level, (newLength) => {
dense dense
type="number" type="number"
v-model="orientation_percent" v-model="orientation_percent"
:rules="[(val:number) => val <= 100 || 'ร้อยละต้องไม่เกิน 100']"
hide-bottom-space
/> />
</div> </div>
</div> </div>
@ -1142,6 +1174,8 @@ watch(lengthdiscipline_level, (newLength) => {
dense dense
type="number" type="number"
v-model="self_learning" v-model="self_learning"
:rules="[(val:number) => val <= 100 || 'คะแนนต้องไม่เกิน 100 คะแนน']"
hide-bottom-space
/> />
</div> </div>
<div class="col"> <div class="col">
@ -1150,6 +1184,8 @@ watch(lengthdiscipline_level, (newLength) => {
dense dense
type="number" type="number"
v-model="self_learning_percent" v-model="self_learning_percent"
:rules="[(val:number) => val <= 100 || 'ร้อยละต้องไม่เกิน 100']"
hide-bottom-space
/> />
</div> </div>
</div> </div>
@ -1162,6 +1198,8 @@ watch(lengthdiscipline_level, (newLength) => {
dense dense
type="number" type="number"
v-model="training_seminar" v-model="training_seminar"
:rules="[(val:number) => val <= 100 || 'คะแนนต้องไม่เกิน 100 คะแนน']"
hide-bottom-space
/> />
</div> </div>
<div class="col"> <div class="col">
@ -1170,6 +1208,8 @@ watch(lengthdiscipline_level, (newLength) => {
dense dense
type="number" type="number"
v-model="training_seminar_percent" v-model="training_seminar_percent"
:rules="[(val:number) => val <= 100 || 'ร้อยละต้องไม่เกิน 100']"
hide-bottom-space
/> />
</div> </div>
</div> </div>
@ -1184,6 +1224,8 @@ watch(lengthdiscipline_level, (newLength) => {
dense dense
type="number" type="number"
v-model="other_training" v-model="other_training"
:rules="[(val:number) => val <= 100 || 'คะแนนต้องไม่เกิน 100 คะแนน']"
hide-bottom-space
/> />
</div> </div>
<div class="col"> <div class="col">
@ -1192,6 +1234,8 @@ watch(lengthdiscipline_level, (newLength) => {
dense dense
type="number" type="number"
v-model="other_training_percent" v-model="other_training_percent"
:rules="[(val:number) => val <= 100 || 'ร้อยละต้องไม่เกิน 100']"
hide-bottom-space
/> />
</div> </div>
</div> </div>

View file

@ -8,6 +8,9 @@ import config from "@/app.config";
import { useProbationDataStore } from "@/modules/05_placement/storeProbation"; import { useProbationDataStore } from "@/modules/05_placement/storeProbation";
import genReport from "@/plugins/genreport"; import genReport from "@/plugins/genreport";
import FormUploadFile from "@/modules/05_placement/components/probation/FormEvaluation/FormUploadFile.vue";
import DialogSelectAuthority from "@/modules/05_placement/components/probation/FormEvaluation/DialogSelectAuthority.vue";
const probationStore = useProbationDataStore(); const probationStore = useProbationDataStore();
const $q = useQuasar(); const $q = useQuasar();
@ -32,7 +35,7 @@ const assign = ref<any>([]);
const mentors = ref<any>([]); const mentors = ref<any>([]);
const commander = ref<any>([]); const commander = ref<any>([]);
const status = ref<boolean>(true); const status = ref<boolean>(true);
const ID = ref<string>(""); const evaluateId = ref<string>("");
const date_start = ref<Date>(new Date()); const date_start = ref<Date>(new Date());
const date_finish = ref<Date>(); const date_finish = ref<Date>();
const develop = ref<number>(); const develop = ref<number>();
@ -55,182 +58,191 @@ const options = ref<any>([
{ value: 2, label: "พัฒนาไม่ครบ 3 ส่วน" }, { value: 2, label: "พัฒนาไม่ครบ 3 ส่วน" },
]); ]);
const optionsResult = ref<any>([ const optionsResult = ref<any>([
{ value: 1, label: "ไม่ต่ำกว่ามาตรฐานที่กำหนด เห็นควรให้รับราชการต่อ" }, {
{ value: 2, label: "ต่ำกว่ามาตรฐานที่กำหนด เห็นควรให้ออกจากราชการ" }, value: 4,
label: "ไม่ต่ำกว่ามาตรฐานที่กำหนดเห็นควรให้ทดลองปฏิบัติหน้าที่ราชการต่อไป",
type: "save1",
},
{
value: 2,
label: "ต่ำกว่ามาตรฐานที่กำหนดเห็นควรให้ออกจากราชการ",
type: "save1",
},
{
value: 1,
label: "ไม่ต่ำกว่ามาตรฐานที่กำหนดเห็นควรให้ทดลองปฏิบัติหน้าที่ราชการต่อไป",
type: "save2",
},
{
value: 2,
label: "ต่ำกว่ามาตรฐานที่กำหนดเห็นควรให้ออกจากราชการ",
type: "save2",
},
{ {
value: 3, value: 3,
label: "เห็นควรให้ขยายระยะเวลาทดลองปฏิบัติหน้าที่ราชการต่อไปอีก", label: "เห็นควรให้ขยายระยะเวลาทดลองปฏิบัติหน้าที่ราชการต่อไปอีก",
type: "save2",
}, },
]); ]);
const props = defineProps({
tab: { type: String, require: true },
data: { type: Object, require: true },
fetchData: { type: Function, require: true },
});
const isCheckFile = ref<boolean>(false);
/** get /** get
* @param id personal id * @param id personal id
*/ */
async function fecthAssign(id: string) { async function fecthAssign() {
showLoader(); const data = props.data;
await http
.get(config.API.evaluateReportcreate(id))
.then((res) => {
assign.value = res.data.result.assign;
person.value = res.data.result.person;
mentors.value = res.data.result.mentors;
date_start.value = res.data.result.assign.date_start;
date_finish.value = res.data.result.assign.date_finish;
if ( const foundData = props?.data?.result.find(
res.data.result.result.develop_complete != null && (e: any) =>
res.data.result.result.evaluate_result != null (e.evaluate_no === 1 && props?.tab === "save1") ||
) { (e.evaluate_no === 2 && props?.tab === "save2")
develop.value = res.data.result.result.develop_complete; );
result.value = res.data.result.result.evaluate_result;
changeReson52(Number(res.data.result.result.evaluate_result));
}
director_id.value = res.data.result.chairman; console.log(foundData);
director_id2.value = res.data.result.commander;
if (mentors.value.length != 0) { if (foundData) {
director_id3.value = mentors.value[0]; date_start.value = foundData.start_date;
} date_finish.value = foundData.end_date;
commander.value = res.data.result.commander; }
optionDirector.value = mentors.value;
}) assign.value = data?.assign;
.catch((e) => { person.value = data?.person;
// messageError($q, e); mentors.value = data?.mentors;
}) if (
.finally(() => { data?.result.develop_complete != null &&
hideLoader(); data?.result.evaluate_result != null
}); ) {
develop.value = data.result.develop_complete;
result.value = data.result.evaluate_result;
changeReson52(Number(data.result.evaluate_result));
}
director_id.value = data?.chairman;
director_id2.value = data?.commander;
if (mentors.value.length != 0) {
director_id3.value = mentors.value[0];
}
commander.value = data?.commander;
optionDirector.value = mentors.value;
} }
/** get /** get
* @param id personal id * @param id personal id
*/ */
const fecthResult = async (id: string) => { const fecthResult = async (id: string) => {
showLoader();
const noNumber = props?.tab ? Number(props?.tab.charAt(4)) : "";
await http await http
.get(config.API.createformReport(id)) .get(config.API.createformReport(id) + `&evaluate_no=${noNumber}`)
.then(async (res: any) => { .then(async (res: any) => {
if (res.data.result != null) { if (res.data.result != null) {
const data = await res.data.result.evaluate; const data = await res.data.result.evaluate;
ID.value = data.id; evaluateId.value = data.id;
date_start.value = data.date_start; date_start.value = data.date_start;
date_finish.value = data.date_finish; date_finish.value = data.date_finish;
develop.value = await Number(data.develop_complete); develop.value = Number(data.develop_complete);
result.value = await Number(data.pass_result); result.value = Number(data.pass_result);
reson.value = await data.reson; reson.value = data.reson;
chairman_dated.value = await data.chairman_dated; chairman_dated.value = data.chairman_dated;
director1_dated.value = await data.director1_dated; director1_dated.value = data.director1_dated;
director2_dated.value = await data.director2_dated; director2_dated.value = data.director2_dated;
status.value = false; status.value = false;
action.value = "edit"; action.value = "edit";
expand_month.value = data.expand_month; expand_month.value = data.expand_month;
authority_name.value = data.authority_name;
authority_pos.value = data.authority_pos;
authority_type.value = data.authority_type;
authority_level.value = data.authority_level;
authority_dated.value = data.authority_dated;
changeReson52(Number(data.pass_result)); changeReson52(Number(data.pass_result));
} }
}) })
.catch((e) => {}); .catch((e) => {})
.finally(() => {
hideLoader();
});
}; };
/** เช็คก่อน save */ /** เช็คก่อน save */
async function savaForm() { async function savaForm() {
await myForm.value.validate().then((result: boolean) => { await myForm.value.validate().then((result: boolean) => {
if (result) { if (result) {
dialogConfirm($q, async () => await postData("post")); if (authority_name.value === "") {
} else { dialogMessageNotify($q, "กรุณาเลือกผู้มีอำนาจ");
dialogMessageNotify($q, "กรุณากรอกข้อมูลให้ครบ"); } else {
dialogConfirm($q, async () => await postData("post"));
}
} }
}); });
} }
/** แปลงรหัสไฟล์ */
function downloadFile(response: any, filename: string) {
const link = document.createElement("a");
var fileName = filename;
link.href = window.URL.createObjectURL(new Blob([response.data]));
link.setAttribute("download", fileName);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
/**
* ดาวโหลดไฟล
* @param type docx/pdf
*/
async function clickdownloadFile(type: string) {
showLoader();
await http
.get(config.API.reportEvaluateResult(type, assignId.value))
.then(async (res) => {
const data = res.data.result;
await genReport(
data,
`แบบรายงานการประเมินฯ_${person.value.name}.${type}`,
type
);
hideLoader();
})
.catch(async (e) => {
messageError($q, JSON.parse(await e.response.data.text()));
hideLoader();
})
.finally(() => {});
}
/** post/put data /** post/put data
* @param action post put * @param action post put
*/ */
async function postData(action: string) { async function postData(action: string) {
const data = await { const data = {
start_date: date_start.value, start_date: date_start.value,
date_finish: date_finish.value, date_finish: date_finish.value,
develop_complete: develop.value, develop_complete: props.tab === "save1" ? 0 : develop.value,
pass_result: result.value, pass_result: result.value,
reson: reson.value, reson: reson.value,
chairman_dated: chairman_dated.value, chairman_dated: chairman_dated.value,
director1_dated: director1_dated.value, // director1_dated: director1_dated.value ? director1_dated.value : new Date(),
director2_dated: director2_dated.value, // director2_dated: director2_dated.value ? director2_dated.value : new Date(),
expand_month: expand_month.value, expand_month: expand_month.value ? expand_month.value : undefined,
evaluate_no: props?.tab ? Number(props?.tab.charAt(4)) : undefined,
authority_name: authority_name.value,
authority_pos: authority_pos.value,
authority_type: authority_type.value,
authority_level: authority_level.value,
authority_dated: authority_dated.value,
}; };
if (action === "post") { if (action === "post") {
showLoader(); showLoader();
await http await http
.post(config.API.createformReport(assignId.value), data) .post(config.API.createformReport(assignId.value), data)
.then(() => { .then(async () => {
await props.fetchData?.(assignId.value);
// await fecthResult(assignId.value);
success($q, "บันทึกสำเร็จ"); success($q, "บันทึกสำเร็จ");
fecthResult(assignId.value);
router.push(`/probation/detail/${personalId.value}/${assignId.value}`); router.push(`/probation/detail/${personalId.value}/${assignId.value}`);
status.value = false;
}) })
.catch((e: any) => { .catch((e: any) => {
messageError($q, e); messageError($q, e);
}) })
.finally(() => { .finally(() => {
status.value = false;
hideLoader();
});
} else if (action === "put") {
showLoader();
await http
.put(config.API.createformReport(assignId.value), data)
.then(() => {
success($q, "บันทึกสำเร็จ");
fecthResult(assignId.value);
router.push(`/probation/detail/${personalId.value}/${assignId.value}`);
})
.catch((e: any) => {
messageError($q, e);
})
.finally(() => {
status.value = false;
hideLoader(); hideLoader();
}); });
} }
// else if (action === "put") {
// showLoader();
// await http
// .put(config.API.createformReport(assignId.value), data)
// .then(() => {
// success($q, "");
// fecthResult(assignId.value);
// status.value = false;
// router.push(`/probation/detail/${personalId.value}/${assignId.value}`);
// })
// .catch((e: any) => {
// messageError($q, e);
// })
// .finally(() => {
// hideLoader();
// });
// }
} }
/** ผลการประเมินการทดลองปฏิบัติหน้าที่ราชการ */ /** ผลการประเมินการทดลองปฏิบัติหน้าที่ราชการ */
function selectResult() { function selectResult() {
if (result.value !== 3) { expand_month.value = "";
expand_month.value = "";
}
changeReson52(Number(result.value)); changeReson52(Number(result.value));
} }
@ -238,25 +250,55 @@ function selectResult() {
* @param val วเลข * @param val วเลข
*/ */
function changeReson52(val: number) { function changeReson52(val: number) {
switch (val) { if (props.tab === "save1") {
case 1: switch (val) {
reson52.value = "เห็นควรให้รับราชการต่อไป"; case 4:
break; reson52.value = "เห็นควรให้ทดลองปฏิบัติหน้าที่ราชการต่อไป";
case 2: break;
reson52.value = "เห็นควรให้ออกจากราชการ"; case 2:
break; reson52.value = "เห็นควรให้ออกจากราชการ";
case 3: break;
reson52.value = `เห็นควรให้ขยายเวลาทดลองปฏิบัตหิน้าท่ีราชการต่อไปอีก ${expand_month.value} เดือน`;
break;
default: default:
break; break;
}
} else if (props.tab === "save2") {
switch (val) {
case 1:
reson52.value = "เห็นควรให้รับราชการต่อไป";
break;
case 2:
reson52.value = "เห็นควรให้ออกจากราชการ";
break;
case 3:
reson52.value = `เห็นควรให้ขยายเวลาทดลองปฏิบัติหน้าที่ราชการต่อไปอีก ${
expand_month.value ? expand_month.value : ""
} เดอน`;
break;
default:
break;
}
} }
} }
onMounted(() => { const modal = ref<boolean>(false);
fecthAssign(assignId.value); const authority_dated = ref<Date | null>(null);
fecthResult(assignId.value); const authority_name = ref<string>("");
const authority_pos = ref<string>("");
const authority_type = ref<string>("");
const authority_level = ref<string>("");
function updateAuthority(data: any) {
authority_name.value = `${data.prefix}${data.firstName} ${data.lastName}`;
authority_pos.value = `${data.position}`;
authority_type.value = `${data.posType}`;
authority_level.value = `${data.posLevel}`;
}
onMounted(async () => {
await fecthAssign();
await fecthResult(assignId.value);
}); });
</script> </script>
@ -264,32 +306,6 @@ onMounted(() => {
<div class="row col-12"> <div class="row col-12">
<div class="toptitle text-dark col-12 row items-center q-gutter-md"> <div class="toptitle text-dark col-12 row items-center q-gutter-md">
<div>แบบรายงานการประเมนฯ</div> <div>แบบรายงานการประเมนฯ</div>
<q-btn
v-if="!status"
size="12px"
flat
dense
icon="mdi-download"
color="primary"
>
<q-tooltip>ดาวนโหลด</q-tooltip>
<q-menu>
<q-list style="min-width: 150px">
<q-item clickable v-close-popup @click="clickdownloadFile('pdf')">
<q-item-section avatar
><q-icon color="red" name="mdi-file-pdf"
/></q-item-section>
<q-item-section>ไฟล .pdf</q-item-section>
</q-item>
<q-item clickable v-close-popup @click="clickdownloadFile('docx')">
<q-item-section avatar
><q-icon color="blue" name="mdi-file-word"
/></q-item-section>
<q-item-section>ไฟล .docx</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>
</div> </div>
<div class="col-12 row"> <div class="col-12 row">
@ -317,7 +333,9 @@ onMounted(() => {
<div class="col-12 text-top0 row items-center"> <div class="col-12 text-top0 row items-center">
<q-icon name="mdi-label" color="grey-4" class="q-pr-sm" /> <q-icon name="mdi-label" color="grey-4" class="q-pr-sm" />
ประเมนผล ประเมนผล
<span class="text-primary q-pr-sm"> ครงท 1 </span> <span class="text-primary q-pr-sm">
ครงท {{ props?.tab ? props?.tab.charAt(4) : "" }}</span
>
</div> </div>
<div class="col-12 text-top0 row items-center"> <div class="col-12 text-top0 row items-center">
@ -326,7 +344,7 @@ onMounted(() => {
</div> </div>
</div> </div>
<q-form ref="myForm"> <q-form ref="myForm" class="col-12">
<div class="row col-12"> <div class="row col-12">
<div class="col-12 row q-col-gutter-md"> <div class="col-12 row q-col-gutter-md">
<div class="col-xs-12 col-sm-6"> <div class="col-xs-12 col-sm-6">
@ -343,6 +361,7 @@ onMounted(() => {
" "
:enableTimePicker="false" :enableTimePicker="false"
week-start="0" week-start="0"
:max-date="date_finish"
> >
<template #year="{ year }"> <template #year="{ year }">
{{ year + 543 }} {{ year + 543 }}
@ -382,17 +401,18 @@ onMounted(() => {
<div class="col-xs-12 col-sm-6"> <div class="col-xs-12 col-sm-6">
<datepicker <datepicker
menu-class-name="modalfix" menu-class-name="modalfix"
v-model="date_finish"
:locale="'th'"
autoApply
:readonly=" :readonly="
!status || !status ||
checkRoutePermisson || checkRoutePermisson ||
probationStore.dataPermissions?.tab6.isEdit == false probationStore.dataPermissions?.tab6.isEdit == false
" "
v-model="date_finish"
:locale="'th'"
autoApply
borderless borderless
:enableTimePicker="false" :enableTimePicker="false"
week-start="0" week-start="0"
:min-date="date_start"
> >
<template #year="{ year }"> <template #year="{ year }">
{{ year + 543 }} {{ year + 543 }}
@ -429,7 +449,7 @@ onMounted(() => {
<div class="col-12 row q-mt-xs"> <div class="col-12 row q-mt-xs">
<div class="col-12 row q-col-gutter-md"> <div class="col-12 row q-col-gutter-md">
<div class="col-xs-12 col-sm-6"> <div class="col-xs-12 col-sm-6" v-if="props?.tab === 'save2'">
<q-select <q-select
:rules="[ :rules="[
(val:string) => (val:string) =>
@ -463,6 +483,7 @@ onMounted(() => {
</template> </template>
</q-select> </q-select>
</div> </div>
<div class="col-xs-12 col-sm-6"> <div class="col-xs-12 col-sm-6">
<div class="row"> <div class="row">
<q-select <q-select
@ -473,7 +494,7 @@ onMounted(() => {
'กรุณาเลือกผลการประเมินการทดลองปฏิบัติหน้าที่ราชการ', 'กรุณาเลือกผลการประเมินการทดลองปฏิบัติหน้าที่ราชการ',
]" ]"
hide-bottom-space hide-bottom-space
:options="optionsResult" :options="optionsResult.filter((e:any)=> e.type === props?.tab)"
:readonly=" :readonly="
!status || !status ||
checkRoutePermisson || checkRoutePermisson ||
@ -502,11 +523,17 @@ onMounted(() => {
<div class="row q-mt-xs" v-if="result === 3"> <div class="row q-mt-xs" v-if="result === 3">
<q-input <q-input
outlined outlined
@change="changeReson52(3)"
dense dense
v-model="expand_month" v-model="expand_month"
label="จำนวนเดือน" label="จำนวนเดือน"
:rules="[(val:string) => !!val || 'กรุณากรอกจำนวนเดือน']" :rules="[(val:string) => !!val || 'กรุณากรอกจำนวนเดือน']"
type="number" type="number"
:readonly="
!status ||
checkRoutePermisson ||
probationStore.dataPermissions?.tab6.isEdit == false
"
/> />
</div> </div>
</div> </div>
@ -559,8 +586,7 @@ onMounted(() => {
<div class="row col-12 q-gutter-lg q-mt-none"> <div class="row col-12 q-gutter-lg q-mt-none">
<div class="col-12 row"> <div class="col-12 row">
<div class="col-12 text-top2 row items-center"> <div class="col-12 text-top2 row items-center">
ประธานคณะกรรมการประเมนผลการปฏหนาทราชการ/านาจสงบรรจตามมาตรา ประธานคณะกรรมการประเมนผลการปฏหนาทราชการ
52
</div> </div>
<div class="col-12 row q-col-gutter-md"> <div class="col-12 row q-col-gutter-md">
<q-select <q-select
@ -622,10 +648,86 @@ onMounted(() => {
</div> </div>
<div class="col-12 row q-mt-xs"> <div class="col-12 row q-mt-xs">
<div class="col-12 text-top2 row items-center"> <div class="col-12 text-top2 row items-center q-gutter-sm">
คณะกรรมการ <span> านาจสงบรรจตามมาตรา 52 </span>
<!-- ความเหนของผอำนาจสงบรรจตามมาตรา 52 --> <div
v-if="
action == 'add' &&
!checkRoutePermisson &&
probationStore.dataPermissions?.tab6.isEdit
"
>
<q-btn
color="primary"
label="เลือกผู้มีอํานาจ"
@click="modal = true"
/>
</div>
</div> </div>
<div class="col-12 row q-col-gutter-md">
<q-input
class="col-xs-12 col-sm-8"
dense
outlined
label="ชื่อ-นามสกุล"
readonly
option-label="label"
:model-value="`${authority_name ? authority_name : ''} ${
authority_pos ? `(${authority_pos}${authority_level})` : ''
}`"
/>
<div class="col-xs-12 col-sm-4">
<datepicker
menu-class-name="modalfix"
v-model="authority_dated"
:locale="'th'"
autoApply
borderless
:readonly="
!status ||
checkRoutePermisson ||
probationStore.dataPermissions?.tab6.isEdit == false
"
: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="!status || checkRoutePermisson"
class="full-width datepicker col-3"
:model-value="
authority_dated != null
? date2Thai(authority_dated)
: null
"
: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>
</div>
<!-- <div class="col-12 row q-mt-xs">
<div class="col-12 text-top2 row items-center">คณะกรรมการ</div>
<div class="col-12 row q-col-gutter-md"> <div class="col-12 row q-col-gutter-md">
<q-select <q-select
class="col-xs-12 col-sm-8" class="col-xs-12 col-sm-8"
@ -685,12 +787,11 @@ onMounted(() => {
</datepicker> </datepicker>
</div> </div>
</div> </div>
</div> </div> -->
<div class="col-12 row q-mt-xs"> <!-- <div class="col-12 row q-mt-xs">
<div class="col-12 text-top2 row items-center"> <div class="col-12 text-top2 row items-center">
คณะกรรมการ คณะกรรมการ
<!-- อำนาจสงบรรจตามมาตรา 52 -->
</div> </div>
<div class="col-12 row q-col-gutter-md"> <div class="col-12 row q-col-gutter-md">
@ -753,7 +854,7 @@ onMounted(() => {
</datepicker> </datepicker>
</div> </div>
</div> </div>
</div> </div> -->
</div> </div>
</q-form> </q-form>
@ -768,7 +869,26 @@ onMounted(() => {
<q-space /> <q-space />
<q-btn label="บันทึก" color="secondary" @click="savaForm" /> <q-btn label="บันทึก" color="secondary" @click="savaForm" />
</q-toolbar> </q-toolbar>
<FormUploadFile
v-else
:group="`รายงานผลครั้งที่ ${props.tab?.charAt(4)}`"
v-model:is-check-file="isCheckFile"
:check-route-permisson="checkRoutePermisson"
:data-permissions="
probationStore.dataPermissions?.tab6.isEdit
? probationStore.dataPermissions?.tab6.isEdit
: false
"
:round="props.tab?.charAt(4)"
:pass-result="result"
/>
</div> </div>
<DialogSelectAuthority
v-model:modal="modal"
@update-authority="updateAuthority"
/>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>

View file

@ -8,9 +8,11 @@ import { useRouter, useRoute } from "vue-router";
import http from "@/plugins/http"; import http from "@/plugins/http";
import config from "@/app.config"; import config from "@/app.config";
import criterion from "@/modules/05_placement/components/probation/Criterion.vue";
import type { ListDataText } from "@/modules/05_placement/interface/index/Main"; import type { ListDataText } from "@/modules/05_placement/interface/index/Main";
import criterion from "@/modules/05_placement/components/probation/Criterion.vue";
import FormUploadFile from "@/modules/05_placement/components/probation/FormEvaluation/FormUploadFile.vue";
const router = useRouter(); const router = useRouter();
const routeName = router.currentRoute.value.name; const routeName = router.currentRoute.value.name;
@ -42,6 +44,8 @@ const evaluate_id = ref<string>("");
const evaluate_no = ref<number>(1); const evaluate_no = ref<number>(1);
const dataArr = ref<any>(); const dataArr = ref<any>();
const isCheckFile = ref<boolean>(false);
const checkArray = ref<number>(0); const checkArray = ref<number>(0);
const list1_1 = ref<any[]>([]); const list1_1 = ref<any[]>([]);
const option = ref<any>([]); const option = ref<any>([]);
@ -373,10 +377,10 @@ onMounted(async () => {
<div class="row col-12 no-margin q-pa-sm"> <div class="row col-12 no-margin q-pa-sm">
<div class="toptitle text-dark col-12 row items-center q-gutter-md"> <div class="toptitle text-dark col-12 row items-center q-gutter-md">
<div>แบบบนทกผล (เเล)</div> <div>แบบบนทกผล (เเล)</div>
<div v-if="status == false"> <div v-if="!status">
<q-btn <q-btn
v-if=" v-if="
!checkRoutePermisson && probationStore.dataPermissions?.tab2.isEdit !checkRoutePermisson && probationStore.dataPermissions?.tab2.isEdit && !isCheckFile
" "
dense dense
flat flat
@ -1255,6 +1259,18 @@ onMounted(async () => {
</div> </div>
</div> </div>
</div> </div>
<FormUploadFile
:group="`บันทึกผลผู้ดูแลครั้งที่ ${props.tab?.charAt(4)}`"
v-model:is-check-file="isCheckFile"
:check-route-permisson="checkRoutePermisson"
:data-permissions="
probationStore.dataPermissions?.tab2.isEdit
? probationStore.dataPermissions?.tab2.isEdit
: false
"
/>
<q-toolbar <q-toolbar
class="text-primary" class="text-primary"
v-if="routeName == 'probationFormAddresult'" v-if="routeName == 'probationFormAddresult'"

View file

@ -10,6 +10,7 @@ import http from "@/plugins/http";
import config from "@/app.config"; import config from "@/app.config";
import criterion from "@/modules/05_placement/components/probation/Criterion.vue"; import criterion from "@/modules/05_placement/components/probation/Criterion.vue";
import FormUploadFile from "@/modules/05_placement/components/probation/FormEvaluation/FormUploadFile.vue";
import type { ListDataText } from "@/modules/05_placement/interface/index/Main"; import type { ListDataText } from "@/modules/05_placement/interface/index/Main";
@ -35,6 +36,7 @@ const {
const assignId = ref<string>(route.params.form.toString()); const assignId = ref<string>(route.params.form.toString());
const personalId = ref<string>(route.params.personalId.toString()); const personalId = ref<string>(route.params.personalId.toString());
const isCheckFile = ref<boolean>(false);
const start_date = ref<Date>(new Date()); const start_date = ref<Date>(new Date());
const date_finish = ref<Date>(new Date()); const date_finish = ref<Date>(new Date());
@ -382,7 +384,9 @@ onMounted(async () => {
<div v-if="status == false"> <div v-if="status == false">
<q-btn <q-btn
v-if=" v-if="
!checkRoutePermisson && probationStore.dataPermissions?.tab3.isEdit !checkRoutePermisson &&
probationStore.dataPermissions?.tab3.isEdit &&
!isCheckFile
" "
dense dense
flat flat
@ -1268,6 +1272,17 @@ onMounted(async () => {
</div> </div>
</div> </div>
<FormUploadFile
:group="`บันทึกผลผู้บังคับบัญชาครั้งที่ ${props.tab?.charAt(4)}`"
v-model:is-check-file="isCheckFile"
:check-route-permisson="checkRoutePermisson"
:data-permissions="
probationStore.dataPermissions?.tab3.isEdit
? probationStore.dataPermissions?.tab3.isEdit
: false
"
/>
<q-toolbar <q-toolbar
class="text-primary" class="text-primary"
v-if="routeName == 'probationFormAddresult'" v-if="routeName == 'probationFormAddresult'"

View file

@ -0,0 +1,192 @@
<script setup lang="ts">
import { onMounted, ref } from "vue";
import { useQuasar } from "quasar";
import axios from "axios";
import { useRoute } from "vue-router";
import { useCounterMixin } from "@/stores/mixin";
import http from "@/plugins/http";
import config from "@/app.config";
const $q = useQuasar();
const route = useRoute();
const mixin = useCounterMixin();
const {
messageError,
date2Thai,
showLoader,
hideLoader,
success,
dialogConfirm,
dialogRemove,
} = mixin;
const group = defineModel<string>("group", { required: true });
const isCheckFile = defineModel<boolean>("isCheckFile", { required: true });
const round = defineModel<string>("round", { default: "" });
const passResult = defineModel<number>("passResult", { default: 0 });
const checkRoutePermisson = defineModel<boolean>("checkRoutePermisson", {
required: true,
});
const dataPermissions = defineModel<boolean>("dataPermissions", {
required: true,
});
const assignId = ref<string>(route.params.form as string);
const file = ref<any>();
const dataDownload = ref<any>();
function onUploadFiles() {
showLoader();
http
.post(config.API.file("ทดลองงาน", group.value, assignId.value), {
replace: true,
fileList: [
{
fileName: file.value.name,
},
],
})
.then(async (res) => {
const foundKey: string | undefined = Object.keys(res.data).find(
(key) =>
res.data[key]?.fileName !== undefined &&
res.data[key]?.fileName !== ""
);
foundKey && (await uploadFileURL(res.data[foundKey]?.uploadUrl));
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
async function uploadFileURL(uploadUrl: string) {
const Data = new FormData();
Data.append("file", file.value);
showLoader();
await axios
.put(uploadUrl, file.value, {
headers: {
"Content-Type": file.value.type,
},
})
.then(async () => {
if (round.value === "2") {
await onUpdateStatusAssign();
} else if (passResult.value === 2) {
await onUpdateStatusAssign();
}
file.value = null;
await success($q, "อัปโหลดไฟล์สำเร็จ");
await fetchCheckfile();
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
/** function เช็คไฟล์*/
async function fetchCheckfile() {
isCheckFile.value = false;
http
.get(config.API.file("ทดลองงาน", group.value, assignId.value))
.then(async (res) => {
if (res.data.length >= 1) {
isCheckFile.value = true;
dataDownload.value = res.data[0];
}
})
.catch((e) => {
messageError($q, e);
});
}
async function onDownloadFile() {
showLoader();
http
.get(config.API.filefullPath(`${dataDownload.value.pathname}`))
.then(async (res) => {
const data = res.data.downloadUrl;
window.open(data, "_blank");
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
}
async function onUpdateStatusAssign() {
await http
.patch(
config.API.createformReport(assignId.value) +
`&evaluate_no=${round.value}`
)
.catch((err) => {
messageError($q, err);
});
}
onMounted(() => {
fetchCheckfile();
});
</script>
<template>
<div
class="col-12"
v-if="!checkRoutePermisson && dataPermissions && !isCheckFile"
>
<div class="col-12">
<q-separator size="3px" color="grey-2" />
</div>
<div class="col-12 q-mt-md">
<div class="col-12 row">
<q-file
class="col-12"
outlined
dense
v-model="file"
label="อัปโหลดเอกสาร"
hide-bottom-space
>
<template v-slot:prepend>
<q-icon name="attach_file" color="primary" />
</template>
<template v-slot:after>
<q-btn
v-if="file"
size="14px"
flat
round
dense
color="primary"
icon="mdi-upload"
@click="onUploadFiles"
><q-tooltip>ปโหลดเอกสาร</q-tooltip></q-btn
>
</template>
</q-file>
</div>
</div>
</div>
<div class="col-12" v-if="isCheckFile">
<q-btn
color="primary"
icon="mdi-download"
label="ดาวน์โหลดไฟล์"
@click="onDownloadFile"
/>
</div>
</template>
<style scoped></style>

View file

@ -2,6 +2,10 @@
import { ref, watch } from "vue"; import { ref, watch } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { useProbationDataStore } from "@/modules/05_placement/storeProbation";
const DataStore = useProbationDataStore();
const tabHead = ref<string>("save1"); const tabHead = ref<string>("save1");
const route = useRoute(); const route = useRoute();
const checkRoutePermisson = ref<boolean>(route.name == "probationFormDetail"); const checkRoutePermisson = ref<boolean>(route.name == "probationFormDetail");
@ -17,6 +21,13 @@ const props = defineProps({
loop: { loop: {
type: Number, type: Number,
}, },
isMax: {
required: false,
type: Boolean,
default() {
return false;
},
},
addData: { addData: {
type: Function, type: Function,
default() { default() {
@ -69,8 +80,20 @@ function nextPage() {
> >
<q-tab v-for="(i, j) in loop" :name="`save${i}`" :key="j"> <q-tab v-for="(i, j) in loop" :name="`save${i}`" :key="j">
<div class="row col-12 items-center"> <div class="row col-12 items-center">
<div class="q-mr-sm">ครงท{{ i }}</div> <div class="q-mr-sm">ครงท {{ i }}</div>
<q-btn <q-btn
v-if="
(DataStore.mainTab === 'tab5' &&
i === 1 &&
DataStore.isCheckFormReport1) ||
(DataStore.mainTab === 'tab5' &&
i === 2 &&
DataStore.isCheckFormReport2) ||
DataStore.mainTab === 'tab2' ||
DataStore.mainTab === 'tab3' ||
DataStore.mainTab === 'tab4' ||
DataStore.mainTab === 'tab8'
"
size="12px" size="12px"
flat flat
dense dense
@ -109,7 +132,7 @@ function nextPage() {
</q-tabs> </q-tabs>
<div> <div>
<q-btn <q-btn
v-if="!checkRoutePermisson && props.checkPermission" v-if="!checkRoutePermisson && props.checkPermission && !isMax"
color="blue" color="blue"
flat flat
dense dense

View file

@ -130,6 +130,7 @@ onMounted(async () => {
:loop="probationStore.tabs.length" :loop="probationStore.tabs.length"
:FileDownload="FileDownload" :FileDownload="FileDownload"
:checkPermission="probationStore?.dataPermissions?.tab2?.isEdit as boolean" :checkPermission="probationStore?.dataPermissions?.tab2?.isEdit as boolean"
:is-max="probationStore.tabs.length === 3"
/> />
<q-tab-panels <q-tab-panels
v-model="tab" v-model="tab"

View file

@ -53,7 +53,7 @@ async function fecthAssign(id: string) {
// messageError($q, e); // messageError($q, e);
}) })
.finally(() => { .finally(() => {
probationStore.checkLoad && hideLoader(); hideLoader();
}); });
} }
@ -146,6 +146,7 @@ onMounted(async () => {
:loop="probationStore.tabs.length" :loop="probationStore.tabs.length"
:FileDownload="FileDownload" :FileDownload="FileDownload"
:checkPermission="probationStore?.dataPermissions?.tab3?.isEdit as boolean" :checkPermission="probationStore?.dataPermissions?.tab3?.isEdit as boolean"
:is-max="probationStore.tabs.length === 3"
/> />
<q-tab-panels <q-tab-panels
v-model="tab" v-model="tab"

View file

@ -114,6 +114,7 @@ onMounted(() => {
:add-data="addData" :add-data="addData"
:FileDownload="FileDownload" :FileDownload="FileDownload"
:checkPermission="probationStore?.dataPermissions?.tab4?.isEdit as boolean" :checkPermission="probationStore?.dataPermissions?.tab4?.isEdit as boolean"
:is-max="tabs.length === 2"
/> />
<q-tab-panels <q-tab-panels

View file

@ -103,6 +103,7 @@ const changeTab = (tabVal: string) => {
:add-data="addData" :add-data="addData"
:FileDownload="FileDownload" :FileDownload="FileDownload"
:checkPermission="probationStore?.dataPermissions?.tab5?.isEdit as boolean" :checkPermission="probationStore?.dataPermissions?.tab5?.isEdit as boolean"
:is-max="tabs.length === 2"
/> />
<q-tab-panels <q-tab-panels

View file

@ -1,16 +1,152 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, defineAsyncComponent } from "vue"; import { ref, defineAsyncComponent, onMounted } from "vue";
import { useQuasar } from "quasar";
import { useRoute, useRouter } from "vue-router";
import { useCounterMixin } from "@/stores/mixin";
import { useProbationDataStore } from "@/modules/05_placement/storeProbation";
import http from "@/plugins/http";
import config from "@/app.config";
import genReport from "@/plugins/genreport";
const DataStore = useProbationDataStore();
const Header = defineAsyncComponent(
() =>
import(
"@/modules/05_placement/components/probation/FormEvaluation/Header.vue"
)
);
const FormReport = defineAsyncComponent( const FormReport = defineAsyncComponent(
() => () =>
import( import(
"@/modules/05_placement/components/probation/FormEvaluation/FormReport.vue" "@/modules/05_placement/components/probation/FormEvaluation/FormReport.vue"
) )
); );
const $q = useQuasar();
const route = useRoute();
const { messageError, showLoader, hideLoader } = useCounterMixin();
const tab = ref<string>("save1");
const tabs = ref<any[]>([]);
const dataArrayNumber = ref<number>(1);
const assignId = ref<string>(route.params.form.toString());
const isLoad = ref<boolean>(false);
const fullName = ref<string>("");
const dataResult = ref<any>();
/**
* @param id assignId
*/
async function fecthAssign(id: string) {
isLoad.value = false;
showLoader();
await http
.get(config.API.evaluateReportcreate(id))
.then((res) => {
dataResult.value = res.data.result;
fullName.value = res.data.result.person.name;
tabs.value = res.data.result.result.map((e: any, index: number) => {
return { no: index + 1, ...e };
});
const report1 = tabs.value.find((e) => e.evaluate_no === 1);
const report2 = tabs.value.find((e) => e.evaluate_no === 2);
DataStore.isCheckFormReport1 = report1?.isResult ?? false;
DataStore.isCheckFormReport2 = report2?.isResult ?? false;
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
isLoad.value = true;
});
}
/**
* download file
* @param type type
*/
async function onDownloadFile(type: string) {
const noNumber = tab.value ? Number(tab.value.charAt(4)) : "";
showLoader();
await http
.get(config.API.reportEvaluateResult(type, assignId.value) + `/${noNumber}`)
.then(async (res) => {
const data = res.data.result;
await genReport(
data,
`แบบรายงานการประเมินฯ${fullName.value}.${type}`,
type
);
})
.catch(async (e) => {
messageError($q, JSON.parse(await e.response.data.text()));
})
.finally(() => {
hideLoader();
});
}
const changeTab = (tabVal: string) => {
tab.value = tabVal;
dataArrayNumber.value = Number(tabVal.charAt(4));
};
/** ไปหน้า page add */
function addData() {
tabs.value.push({ no: 2 });
}
onMounted(() => {
fecthAssign(assignId.value);
});
</script> </script>
<template> <template>
<div class="col-12 q-ma-sm"> <Header
<FormReport /> v-if="tabs.length > 0"
:change-tab="changeTab"
:add-data="addData"
:loop="tabs.length"
:FileDownload="onDownloadFile"
:checkPermission="false"
/>
<q-tab-panels
v-model="tab"
animated
swipeable
vertical
transition-prev="jump-up"
transition-next="jump-up"
v-if="tabs.length > 0"
class="mt"
>
<q-tab-panel v-for="item in tabs" :name="`save${item.no}`" :key="item.no">
<FormReport
:tab="tab"
:data="dataResult"
:fetch-data="fecthAssign"
action="edit"
v-if="isLoad"
/>
</q-tab-panel>
</q-tab-panels>
<div class="q-gutter-md" v-else>
<div class="flex justify-center items-center q-my-md q-gutter-md">
งไมไดดำเนนการแบบประเมนผล
</div>
</div> </div>
</template> </template>
<style lang="scss" scoped>
.mt {
margin-top: 25px;
}
</style>

Some files were not shown because too many files have changed in this diff Show more