Merge branch 'NiceDev'

This commit is contained in:
DESKTOP-1R2VSQH\Lenovo ThinkPad E490 2025-09-08 11:33:29 +07:00
commit 87c999ddd0
190 changed files with 18478 additions and 11310 deletions

View file

@ -2,4 +2,5 @@ VITE_API_URI_CONFIG=VITE_API_URI_CONFIG
VITE_API_PUBLISH_URL=VITE_API_PUBLISH_URL VITE_API_PUBLISH_URL=VITE_API_PUBLISH_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_URL_LANDING=VITE_URL_LANDING
VITE_API_REPORT_URL=VITE_API_REPORT_URL VITE_API_REPORT_URL=VITE_API_REPORT_URL

View file

@ -0,0 +1,50 @@
# /.forgejo/workflows/build.yml
name: Build
on:
push:
tags:
- "v[0-9]+.[0-9]+.[0-9]+"
- "v[0-9]+.[0-9]+.[0-9]+*"
workflow_dispatch:
env:
REGISTRY: ${{ vars.CONTAINER_REGISTRY }}
REGISTRY_USERNAME: ${{ vars.CONTAINER_REGISTRY_USERNAME }}
REGISTRY_PASSWORD: ${{ secrets.CONTAINER_REGISTRY_PASSWORD }}
CONTAINER_IMAGE_NAME: ${{ vars.CONTAINER_REGISTRY }}/${{ vars.CONTAINER_IMAGE_OWNER }}/${{ vars.CONTAINER_IMAGE_NAME }}
IMAGE_VERSION: build
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
with:
config-inline: |
[registry."${{ env.REGISTRY }}"]
ca=["/etc/ssl/certs/ca-certificates.crt"]
- name: Tag Version
run: |
if [[ "${{ github.event_name }}" == "push" ]]; then
echo "IMAGE_VERSION=${{ github.ref_name }}" | sed 's/v//g' >> $GITHUB_ENV
else
echo "IMAGE_VERSION=${{ env.IMAGE_VERSION }}-${{ github.run_number }}" >> $GITHUB_ENV
fi
- name: Login in to registry
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ env.REGISTRY_USERNAME }}
password: ${{ env.REGISTRY_PASSWORD }}
- name: Build and push docker image
uses: docker/build-push-action@v3
with:
platforms: linux/amd64
context: .
file: ./docker/Dockerfile
tags: ${{ env.CONTAINER_IMAGE_NAME }}:latest,${{ env.CONTAINER_IMAGE_NAME }}:${{ env.IMAGE_VERSION }}
push: true

View file

@ -0,0 +1,29 @@
name: Build
on:
workflow_dispatch:
inputs:
version:
description: "Version to deploy"
type: string
required: false
default: "latest"
env:
IMAGE_VERSION: build
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Remote Deploy
uses: appleboy/ssh-action@v1.2.1
with:
host: ${{ vars.SSH_DEPLOY_HOST }}
port: ${{ vars.SSH_DEPLOY_PORT }}
username: ${{ secrets.SSH_DEPLOY_USER }}
password: ${{ secrets.SSH_DEPLOY_PASSWORD }}
script: |
cd ~/repo
./replace-env.sh APP_USER "${{ inputs.version }}"
./deploy.sh hrms-user

View file

@ -12,6 +12,7 @@ do
sed -i 's|VITE_API_PUBLISH_URL|'${VITE_API_PUBLISH_URL}'|g' $file sed -i 's|VITE_API_PUBLISH_URL|'${VITE_API_PUBLISH_URL}'|g' $file
sed -i 's|VITE_MANUAL_URL|'${VITE_MANUAL_URL}'|g' $file sed -i 's|VITE_MANUAL_URL|'${VITE_MANUAL_URL}'|g' $file
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_URL_LANDING|'${VITE_URL_LANDING}'|g' $file
sed -i 's|VITE_API_REPORT_URL|'${VITE_API_REPORT_URL}'|g' $file sed -i 's|VITE_API_REPORT_URL|'${VITE_API_REPORT_URL}'|g' $file

50
package-lock.json generated
View file

@ -19,8 +19,10 @@
"@tato30/vue-pdf": "^1.5.1", "@tato30/vue-pdf": "^1.5.1",
"@vuepic/vue-datepicker": "^3.6.3", "@vuepic/vue-datepicker": "^3.6.3",
"bma-org-chart": "^0.0.7", "bma-org-chart": "^0.0.7",
"dom-to-image-more": "^3.6.0",
"keycloak-js": "^20.0.2", "keycloak-js": "^20.0.2",
"moment": "^2.29.4", "moment": "^2.29.4",
"pdf-lib": "^1.17.1",
"pinia": "^2.0.29", "pinia": "^2.0.29",
"quasar": "^2.11.1", "quasar": "^2.11.1",
"socket.io-client": "^4.7.4", "socket.io-client": "^4.7.4",
@ -1143,6 +1145,24 @@
"node": ">= 8" "node": ">= 8"
} }
}, },
"node_modules/@pdf-lib/standard-fonts": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@pdf-lib/standard-fonts/-/standard-fonts-1.0.0.tgz",
"integrity": "sha512-hU30BK9IUN/su0Mn9VdlVKsWBS6GyhVfqjwl1FjZN4TxP6cCw0jP2w7V3Hf5uX7M0AZJ16vey9yE0ny7Sa59ZA==",
"license": "MIT",
"dependencies": {
"pako": "^1.0.6"
}
},
"node_modules/@pdf-lib/upng": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@pdf-lib/upng/-/upng-1.0.1.tgz",
"integrity": "sha512-dQK2FUMQtowVP00mtIksrlZhdFXQZPC+taih1q4CvPZ5vqdxR/LKBaFg0oAfzd1GlHZXXSPdQfzQnt+ViGvEIQ==",
"license": "MIT",
"dependencies": {
"pako": "^1.0.10"
}
},
"node_modules/@quasar/extras": { "node_modules/@quasar/extras": {
"version": "1.15.8", "version": "1.15.8",
"license": "MIT", "license": "MIT",
@ -3006,6 +3026,12 @@
"node": ">=6.0.0" "node": ">=6.0.0"
} }
}, },
"node_modules/dom-to-image-more": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/dom-to-image-more/-/dom-to-image-more-3.6.0.tgz",
"integrity": "sha512-0BB0M9gRRP7znKBNLRAvNyWnkDIzSgMSDcS7WdPDzPnWhW2YJqxUR/dCHiJ2HdCV3K2rVky5Vba8UF31mvrCuQ==",
"license": "MIT"
},
"node_modules/domexception": { "node_modules/domexception": {
"version": "4.0.0", "version": "4.0.0",
"dev": true, "dev": true,
@ -5871,6 +5897,12 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/pako": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
"license": "(MIT AND Zlib)"
},
"node_modules/panzoom": { "node_modules/panzoom": {
"version": "9.4.3", "version": "9.4.3",
"resolved": "https://registry.npmjs.org/panzoom/-/panzoom-9.4.3.tgz", "resolved": "https://registry.npmjs.org/panzoom/-/panzoom-9.4.3.tgz",
@ -5980,6 +6012,24 @@
"through": "~2.3" "through": "~2.3"
} }
}, },
"node_modules/pdf-lib": {
"version": "1.17.1",
"resolved": "https://registry.npmjs.org/pdf-lib/-/pdf-lib-1.17.1.tgz",
"integrity": "sha512-V/mpyJAoTsN4cnP31vc0wfNA1+p20evqqnap0KLoRUN0Yk/p3wN52DOEsL4oBFcLdb76hlpKPtzJIgo67j/XLw==",
"license": "MIT",
"dependencies": {
"@pdf-lib/standard-fonts": "^1.0.0",
"@pdf-lib/upng": "^1.0.1",
"pako": "^1.0.11",
"tslib": "^1.11.1"
}
},
"node_modules/pdf-lib/node_modules/tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"license": "0BSD"
},
"node_modules/pdfjs-dist": { "node_modules/pdfjs-dist": {
"version": "3.7.107", "version": "3.7.107",
"resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-3.7.107.tgz", "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-3.7.107.tgz",

View file

@ -26,8 +26,10 @@
"@tato30/vue-pdf": "^1.5.1", "@tato30/vue-pdf": "^1.5.1",
"@vuepic/vue-datepicker": "^3.6.3", "@vuepic/vue-datepicker": "^3.6.3",
"bma-org-chart": "^0.0.7", "bma-org-chart": "^0.0.7",
"dom-to-image-more": "^3.6.0",
"keycloak-js": "^20.0.2", "keycloak-js": "^20.0.2",
"moment": "^2.29.4", "moment": "^2.29.4",
"pdf-lib": "^1.17.1",
"pinia": "^2.0.29", "pinia": "^2.0.29",
"quasar": "^2.11.1", "quasar": "^2.11.1",
"socket.io-client": "^4.7.4", "socket.io-client": "^4.7.4",

View file

@ -73,6 +73,8 @@ export default {
developmentReQuestIDP: (id: string) => `${developmentOrg}/profile/development/registry/USER/${id}`, developmentReQuestIDP: (id: string) => `${developmentOrg}/profile/development/registry/USER/${id}`,
developmentIDP: (id: string) => `${development}/main/registry/USER/${id}`, developmentIDP: (id: string) => `${development}/main/registry/USER/${id}`,
kpiReject:(id:string)=>`${kpiEvaluation}/reject-agreement/${id}` kpiReject:(id:string)=>`${kpiEvaluation}/reject-agreement/${id}`,
kpiReportList:(id:string)=>`${Kpi}/report/list/${id}`
}; };

View file

@ -5,17 +5,9 @@ const profile = `${env.API_URI}/profile/keycloak`;
export default { export default {
profileBykeycloak: () => `${profile}`, profileBykeycloak: () => `${profile}`,
positionBykeycloak: () => `${env.API_URI}/org/profile/keycloak/position`, // positionBykeycloak: () => `${env.API_URI}/org/profile/keycloak/position`,
appealMainList: ( appealMainList: () => `${appeal}/user`,
status: string,
type: string,
year: number,
page: number,
pageSize: number,
keyword: string
) =>
`${appeal}/user?status=${status}&type=${type}&year=${year}&page=${page}&pageSize=${pageSize}&keyword=${keyword}`,
appealAdd: () => `${appeal}`, appealAdd: () => `${appeal}`,
appealByID: (id: string) => `${appeal}/${id}`, appealByID: (id: string) => `${appeal}/${id}`,

View file

@ -6,16 +6,18 @@ const holiday = `${env.API_URI}/metadata/holiday/`;
export default { export default {
listUser: () => `${retirementResign}/resign/user`, listUser: () => `${retirementResign}/resign/user`,
listUserByType:(type:string) => `${retirementResign}/resign${type}/user`, listUserByType: (type: string) => `${retirementResign}/resign${type}/user`,
listResign: () => `${retirementResign}/resign`, listResign: () => `${retirementResign}/resign`,
listResignByType: (type:string) => `${retirementResign}/resign${type}`, listResignByType: (type: string) => `${retirementResign}/resign${type}`,
resingByid: (id: string) => `${retirementResign}/resign/${id}`, resingByid: (id: string) => `${retirementResign}/resign/${id}`,
resingByidType: (type:string,id: string) => `${retirementResign}/resign${type}/${id}`, resingByidType: (type: string, id: string) =>
`${retirementResign}/resign${type}/user/${id}`,
questionnaireByid: (id: string) => questionnaireByid: (id: string) =>
`${retirementResign}/resign/questionnaire/${id}`, `${retirementResign}/resign/questionnaire/${id}`,
listquestionnaire: () => `${retirementResign}/resign/questionnaire`, listquestionnaire: () => `${retirementResign}/resign/questionnaire`,
cancelResign: (id: string) => `${retirementResign}/resign/cancel/${id}`, cancelResign: (id: string) => `${retirementResign}/resign/cancel/${id}`,
cancelResignByType: (type:string,id: string) => `${retirementResign}/resign${type}/cancel/${id}`, cancelResignByType: (type: string, id: string) =>
`${retirementResign}/resign${type}/cancel/${id}`,
// คำถาม // คำถาม
questionList: () => `${retirementResign}/resign/questionnaire/question`, questionList: () => `${retirementResign}/resign/questionnaire/question`,

View file

@ -6,6 +6,8 @@ const profileOrg = `${env.API_URI}/org/profile`;
const report = `${env.API_URI}/org`; const report = `${env.API_URI}/org`;
const workflow = `${env.API_URI}/org/workflow`; const workflow = `${env.API_URI}/org/workflow`;
export default { export default {
orgCommandCode: `${metadata}commandCode`,
profilePosition: () => `${org}/profile/keycloak/position`, profilePosition: () => `${org}/profile/keycloak/position`,
searchCommander: `${org}/profile/search/commander`, searchCommander: `${org}/profile/search/commander`,
@ -38,12 +40,23 @@ export default {
dataUserDuty: `${profileOrg}/duty/user`, dataUserDuty: `${profileOrg}/duty/user`,
dataUserDutyByType: (type: string) => `${org}/profile${type}/duty/user`, dataUserDutyByType: (type: string) => `${org}/profile${type}/duty/user`,
dataUserActpositionByType: (type: string) => `${org}/profile${type}/actposition/user`, dataUserActpositionByType: (type: string) =>
dataUserAssistanceByType: (type: string) => `${org}/profile${type}/assistance/user`, `${org}/profile${type}/actposition/user`,
dataUserAssistanceByType: (type: string) =>
`${org}/profile${type}/assistance/user`,
//ตำแหน่ง
dataUserPosition: (type: string) =>
`${org}/profile${type}/salary/position/user`,
dataUserPositionHistory: (emType: string, id: string) =>
`${org}/profile${emType}/salary/position/history/${id}`,
dataUserSalary: `${profileOrg}/salary/user`, dataUserSalary: `${profileOrg}/salary/user`,
dataUserSalaryPosition: `${profileOrg}/salary/position/user`,
dataUserSalaryByType: (type: string) => `${org}/profile${type}/salary/user`, dataUserSalaryByType: (type: string) => `${org}/profile${type}/salary/user`,
dataUserAssessments: `${profileOrg}/assessments/user`, dataUserAssessments: `${profileOrg}/assessments/user`,
dataUserPortfolio: `${env.API_URI}/development/portfolio/user`,
dataUserPerformance: `${env.API_URI}/evaluation/performance/user`,
dataUserNopaid: `${profileOrg}/nopaid/user`, dataUserNopaid: `${profileOrg}/nopaid/user`,
dataUserNopaidByType: (type: string) => `${org}/profile${type}/nopaid/user`, dataUserNopaidByType: (type: string) => `${org}/profile${type}/nopaid/user`,
@ -51,6 +64,8 @@ export default {
dataUserCertificateByType: (emType: string, type: string) => dataUserCertificateByType: (emType: string, type: string) =>
`${org}/profile${emType}/${type}/user`, `${org}/profile${emType}/${type}/user`,
dataUserEvaByType: (type: string) => `${org}/profile/${type}/user`,
dataUserOther: `${profileOrg}/other/user`, dataUserOther: `${profileOrg}/other/user`,
dataUserOtherByType: (type: string) => `${org}/profile${type}/other/user`, dataUserOtherByType: (type: string) => `${org}/profile${type}/other/user`,
@ -103,6 +118,9 @@ export default {
dataUserSalaryNopaidHistoryByType: (emType: string, id: string) => dataUserSalaryNopaidHistoryByType: (emType: string, id: string) =>
`${org}/profile${emType}/nopaid/history/${id}`, `${org}/profile${emType}/nopaid/history/${id}`,
salaryTenurePosition: (emType: string) =>
`${org}/profile${emType}/salary/tenure/user`,
dataUserCertificateHistory: (type: string, id: string) => dataUserCertificateHistory: (type: string, id: string) =>
`${profileOrg}/${type}/history/${id}`, `${profileOrg}/${type}/history/${id}`,
dataUserCertificateHistoryByType: ( dataUserCertificateHistoryByType: (
@ -151,6 +169,10 @@ export default {
* workflow * workflow
*/ */
workflow: `${workflow}/`, workflow: `${workflow}/`,
commanderPosexe: (type:string)=>`${workflow}/commander-posexe/${type}`,
commanderOperate: `${workflow}/commander/operate`,
keycloakLogSSO: `${org}/keycloak/log/sso`, keycloakLogSSO: `${org}/keycloak/log/sso`,
orgAssistance:(id:string)=>`${profileOrg}/assistance/${id}`
}; };

View file

@ -34,7 +34,7 @@ const API = {
...reports, ...reports,
}; };
const path = import.meta.env.VITE_MANUAL_URL ?? "e"; const path = import.meta.env.VITE_MANUAL_URL ?? "";
/** /**
* *
@ -46,14 +46,14 @@ const generatePopupPath = (routeName: any, type: string) => {
if (routeName.includes("organizationChart")) { if (routeName.includes("organizationChart")) {
return `${path}/chapter-1-user${type}-organization-chart`; return `${path}/chapter-1-user${type}-organization-chart`;
} }
if (routeName.includes("registry")) { if (routeName.includes("registry") || routeName.includes("request-edit")) {
return `${path}/chapter-2-user${type}-registry`; return `${path}/chapter-2-user${type}-registry`;
} }
if (routeName.includes("evaluate")) { if (routeName.includes("evaluate")) {
return `${path}/chapter-3-user-evaluate`; return `${path}/chapter-3-user-evaluate`;
} }
if (routeName.includes("leave")) { if (routeName.includes("leave") || routeName.includes("addAbsence")) {
return `${path}/chapter-${type ? "3" : "4"}-user${type}-leave`; return `${path}/chapter-${type ? "3" : "4"}-user${type}-leave`;
} }
@ -79,7 +79,7 @@ const generatePopupPath = (routeName: any, type: string) => {
return `${path}/chapter-14-user-service-testing`; return `${path}/chapter-14-user-service-testing`;
} }
if (routeName.includes("Retire")) { if (routeName.includes("Retire")) {
return `${path}/chapter-${type ? "5" : "11"}-user${type}-retire`; return `${path}/chapter-${type ? "6" : "12"}-user${type}-retire`;
} else { } else {
return manualConfig[routeName as keyof typeof manualConfig]; return manualConfig[routeName as keyof typeof manualConfig];
} }
@ -93,6 +93,8 @@ const manualConfig = {
addPortfolio: `${path}/chapter-5-user-portfolio`, addPortfolio: `${path}/chapter-5-user-portfolio`,
addTransfer: `${path}/chapter-6-user-transfer`, addTransfer: `${path}/chapter-6-user-transfer`,
KPIMain: `${path}/chapter-8-user-KPI`, KPIMain: `${path}/chapter-8-user-KPI`,
KPIAdd: `${path}/chapter-8-user-KPI`,
KPIEdit: `${path}/chapter-8-user-KPI`,
KPIMainEvaluator: `${path}/chapter-9-user-KPI-evaluator`, KPIMainEvaluator: `${path}/chapter-9-user-KPI-evaluator`,
}; };

View file

@ -1,8 +1,18 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, watch } from "vue"; import { ref, reactive, watch } from "vue";
import { useQuasar } from "quasar";
import http from "@/plugins/http";
import genReport from "@/plugins/genreport";
import { useCounterMixin } from "@/stores/mixin";
import PopupReplyInbox from "@/components/PopupReplyInbox.vue"; import PopupReplyInbox from "@/components/PopupReplyInbox.vue";
import type { Attachments } from "@/modules/01_dashboard/interface/Main";
const $q = useQuasar();
const { showLoader, hideLoader, messageError } = useCounterMixin();
const props = defineProps({ const props = defineProps({
modal: { modal: {
type: Boolean, type: Boolean,
@ -60,9 +70,29 @@ watch(
const modalReply = ref<boolean>(false); const modalReply = ref<boolean>(false);
function fileOpen(url: string) { const fileOpen = async (attachmentsData: Attachments) => {
window.open(url, "_blank"); if (attachmentsData.isReport) {
} showLoader();
await http
.get(attachmentsData.url)
.then(async (res) => {
const result = res.data;
if (attachmentsData.isTemplate) {
await genReport(result.result, attachmentsData.name, "pdf");
} else {
window.open(result.downloadUrl, "_blank");
}
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
} else {
window.open(attachmentsData.url, "_blank");
}
};
</script> </script>
<template> <template>
<q-dialog v-model="modal"> <q-dialog v-model="modal">
@ -116,7 +146,7 @@ function fileOpen(url: string) {
v-for="(item, index) in detail.payload.attachments" v-for="(item, index) in detail.payload.attachments"
:key="index" :key="index"
> >
<q-item clickable v-close-popup @click.stop="fileOpen(item.url)"> <q-item clickable v-close-popup @click.stop="fileOpen(item)">
<q-item-section>{{ item.name }}</q-item-section> <q-item-section>{{ item.name }}</q-item-section>
</q-item> </q-item>
<q-separator /> <q-separator />

View file

@ -0,0 +1,62 @@
<script setup lang="ts">
import { ref } from "vue";
/** importType*/
import type { QTableProps } from "quasar";
const columns = defineModel<QTableProps["columns"]>("columns", {
required: true,
});
const rows = ref<Array<{ id: string; name: string }>>([
{
id: "",
name: "",
},
]);
/** ตัวอย่างการใช้งาน */
/// <SkeletonTable v-if="isLoading" :columns="columns" />
</script>
<template>
<d-table
flat
bordered
:columns="columns"
:rows="rows"
row-key="id"
hide-pagination
>
<template v-slot:body="props">
<q-tr :props="props" class="cursor-pointer">
<q-td v-for="col in props.cols" :key="col.name" :props="props">
<div>
<q-skeleton type="text" width="80px" />
</div>
</q-td>
</q-tr>
</template>
<template v-slot:item="props">
<div class="q-mb-xs col-xs-12 col-sm-6 col-md-4 col-lg-3">
<q-card bordered flat>
<q-list dense class="q-mt-lg relative-position">
<q-item v-for="col in props.cols" :key="col.name">
<q-item-section>
<q-item-label class="text-grey-6 text-weight-medium">{{
col.label
}}</q-item-label>
</q-item-section>
<q-item-section>
<q-item-label class="text-dark text-weight-medium">
<q-skeleton type="text" />
</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-card>
</div>
</template>
</d-table>
</template>

View file

@ -10,13 +10,16 @@
dense dense
:pagination-label="paginationLabel" :pagination-label="paginationLabel"
v-model:pagination="pagination" v-model:pagination="pagination"
@request="onRequest"
:grid="!$q.screen.gt.xs" :grid="!$q.screen.gt.xs"
:rows-per-page-options="[10, 25, 50, 100]" :rows-per-page-options="[10, 25, 50, 100]"
:loading="loading"
> >
<template v-slot:pagination="scope"> <template v-slot:pagination="scope">
งหมด {{ attrs.rows.length }} รายการ งหมด {{ pagination.rowsNumber || attrs.rows.length }} รายการ
<q-pagination <q-pagination
v-model="pagination.page" v-model="pagination.page"
@update:model-value="handlePageChange"
active-color="primary" active-color="primary"
color="dark" color="dark"
:max="scope.pagesNumber" :max="scope.pagesNumber"
@ -27,9 +30,25 @@
></q-pagination> ></q-pagination>
</template> </template>
<template v-for="(_, slot) in slots" v-slot:[slot]="scope"> <template v-for="(_, slot) in slots" v-slot:[slot]="scope" :key="slot">
<slot :name="slot" v-bind="scope || {}" /> <slot :name="slot" v-bind="scope || {}" />
</template> </template>
<template v-slot:loading>
<q-inner-loading showing class="q-mt-lg">
<q-spinner-dots color="primary" size="40px" />
</q-inner-loading>
</template>
<template v-slot:no-data>
<div
v-if="!loading && attrs.rows.length === 0"
class="full-width row flex-center q-pa-sm rounded-borders text-weight-medium"
>
<span> ไมพบขอม </span>
</div>
</template>
<!-- <template #item="props"> <!-- <template #item="props">
<div class="q-pa-xs col-xs-12 col-sm-6 col-md-4 col-lg-3"> <div class="q-pa-xs col-xs-12 col-sm-6 col-md-4 col-lg-3">
<q-card bordered flat> <q-card bordered flat>
@ -55,22 +74,45 @@
</q-table> </q-table>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, useAttrs, useSlots } from "vue"; import { ref, useAttrs, useSlots, computed, watch } from "vue";
const attrs = ref<any>(useAttrs()); const attrs = ref<any>(useAttrs());
const slots = ref<any>(useSlots()); const slots = ref<any>(useSlots());
const emit = defineEmits(["update:pagination", "request"]);
const props = defineProps({ const props = defineProps({
paging: { paging: {
type: Boolean, type: Boolean,
defualt: false, default: false,
},
loading: {
type: Boolean,
default: false,
},
pagination: {
type: Object,
default: () => ({
sortBy: "desc",
descending: false,
page: 1,
rowsPerPage: 10,
// rowsNumber: 0,
}),
}, },
}); });
const pagination = ref({ // Internal pagination state
sortBy: "desc", const internalPagination = ref({
descending: false, ...props.pagination,
page: 1, });
rowsPerPage: 10,
// computed sync props internal state
const pagination = computed({
get: () => internalPagination.value,
set: (value) => {
internalPagination.value = { ...value };
emit("update:pagination", value);
},
}); });
const paginationLabel = (start: string, end: string, total: string) => { const paginationLabel = (start: string, end: string, total: string) => {
@ -78,6 +120,57 @@ const paginationLabel = (start: string, end: string, total: string) => {
return " " + start + " ถึง " + end + " จากจำนวน " + total + " รายการ"; return " " + start + " ถึง " + end + " จากจำนวน " + total + " รายการ";
else return start + "-" + end + " ใน " + total; else return start + "-" + end + " ใน " + total;
}; };
function onRequest(requestProp: any) {
if (!requestProp || !requestProp.pagination) {
return;
}
const { pagination: newPagination } = requestProp;
// (page rowsPerPage ) request
const isPageChange =
internalPagination.value.page !== newPagination.page ||
internalPagination.value.rowsPerPage !== newPagination.rowsPerPage;
internalPagination.value = {
...internalPagination.value,
...newPagination,
};
// if (isPageChange) {
emit("request", requestProp);
// }
}
function handlePageChange(newPage: number) {
if (!newPage || newPage < 1) {
return;
}
internalPagination.value = {
...internalPagination.value,
page: newPage,
};
// request object onRequest
const requestProp = {
pagination: internalPagination.value,
filter: null,
getCellValue: () => {},
};
emit("request", requestProp);
}
// Watch props internal state parent
watch(
() => props.pagination,
(newPagination) => {
internalPagination.value = { ...newPagination };
},
{ deep: true, immediate: true }
);
</script> </script>
<style lang="scss"> <style lang="scss">
@ -113,5 +206,33 @@ const paginationLabel = (start: string, end: string, total: string) => {
margin-bottom: 0 !important; margin-bottom: 0 !important;
min-height: 0px !important; min-height: 0px !important;
} }
// Loading styles
.loading-overlay {
width: 100%;
}
.loading-row {
background: white;
}
.loading-cell {
text-align: center;
padding: 60px 20px;
border: none;
}
.loading-content {
display: flex;
flex-direction: column;
align-items: center;
gap: 16px;
}
.loading-text {
color: #666;
font-size: 14px;
font-weight: 500;
}
} }
</style> </style>

View file

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from "vue"; import { ref, computed } from "vue";
import { useQuasar } from "quasar"; import { useQuasar } from "quasar";
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
@ -10,6 +10,9 @@ const $q = useQuasar();
const { dialogConfirm } = useCounterMixin(); const { dialogConfirm } = useCounterMixin();
const modal = defineModel<boolean>("modal", { required: true }); const modal = defineModel<boolean>("modal", { required: true });
const props = defineProps({
sysName: { type: String, require: true },
});
const isAcknowledge = ref<boolean>(false); const isAcknowledge = ref<boolean>(false);
const isConsider = ref<boolean>(true); const isConsider = ref<boolean>(true);
@ -19,6 +22,12 @@ const acknowledge = ref<boolean>(false);
const consider = ref<string>(""); const consider = ref<string>("");
const comment = ref<string>(""); const comment = ref<string>("");
const rejectName = computed(() =>
props.sysName && ["SYS_RESIGN", "SYS_RESIGN_EMP"].includes(props.sysName)
? "ยับยั้ง"
: "ไม่อนุมัติ"
);
function onSubmit() { function onSubmit() {
dialogConfirm($q, () => {}); dialogConfirm($q, () => {});
} }
@ -52,8 +61,10 @@ function onCloseModal() {
label="รับทราบ" label="รับทราบ"
/> />
</div> </div>
<div v-if="!isAcknowledge && isConsider"> <div v-if="isConsider">
<div class="text-weight-bold">จารณา (อน/ไมอน)</div> <div class="text-weight-bold">
{{ `พิจารณา (อนุมัติ/${rejectName})` }}
</div>
<div class="q-pa-sm q-gutter-sm"> <div class="q-pa-sm q-gutter-sm">
<q-radio <q-radio
dense dense
@ -68,13 +79,13 @@ function onCloseModal() {
keep-color keep-color
color="primary" color="primary"
v-model="consider" v-model="consider"
label="ไม่อนุมัติ" :label="`${rejectName}`"
val="reject" val="reject"
/> />
</div> </div>
</div> </div>
<div v-if="!isAcknowledge && isComment"> <div v-if="isComment">
<div class="text-weight-bold">แสดงความเหนในเอกสาร</div> <div class="text-weight-bold">แสดงความเหนในเอกสาร</div>
<div class="q-pa-sm q-gutter-sm"> <div class="q-pa-sm q-gutter-sm">
<div class="col-12"> <div class="col-12">

View file

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { reactive, ref, watch } from "vue"; import { reactive, ref, watch, computed } from "vue";
import { useQuasar } from "quasar"; import { useQuasar } from "quasar";
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
@ -7,9 +7,9 @@ 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 { Pagination } from "@/components/Workflow/interface/index/Main";
import type { DataQuery } from "@/components/Workflow/interface/request/Main"; import type { DataQuery } from "@/components/Workflow/interface/request/Main";
import type { DataCommander } from "@/components/Workflow/interface/response/Main"; import type { DataCommander } from "@/components/Workflow/interface/response/Main";
import type { PropsTable } from "@/interface/PropsTable";
import DialogHeader from "@/components/DialogHeader.vue"; import DialogHeader from "@/components/DialogHeader.vue";
@ -20,14 +20,31 @@ const { dialogConfirm, showLoader, hideLoader, messageError } =
const modal = defineModel<boolean>("modal", { required: true }); const modal = defineModel<boolean>("modal", { required: true });
const props = defineProps({ const props = defineProps({
stateId: { type: String, require: true }, stateId: { type: String, require: true },
keycloakId: { type: String, require: true },
sysName: { type: String, require: true },
fetchData: { type: Function, require: true }, fetchData: { type: Function, require: true },
type: { type: String, require: true }, type: { type: String, require: true },
}); });
const rejectName = computed(() =>
props.sysName && ["SYS_RESIGN", "SYS_RESIGN_EMP"].includes(props.sysName)
? "ยับยั้ง"
: "ไม่อนุมัติ"
);
/** table*/ /** table*/
const selected = ref<DataCommander[]>([]); const selected = ref<DataCommander[]>([]);
const rows = ref<DataCommander[]>([]); const rows = ref<DataCommander[]>([]);
const columns = ref<QTableProps["columns"]>([ const columns = ref<QTableProps["columns"]>([
{
name: "posNo",
align: "left",
label: "เลขที่ตำแหน่ง",
sortable: true,
field: "posNo",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{ {
name: "fullName", name: "fullName",
align: "left", align: "left",
@ -59,17 +76,19 @@ const columns = ref<QTableProps["columns"]>([
style: "font-size: 14px", style: "font-size: 14px",
}, },
]); ]);
const pagination = ref<PropsTable.Pagination>({
const total = ref<number>(0); sortBy: "",
const totalList = ref<number>(1); descending: true,
page: 1,
rowsPerPage: 10,
rowsNumber: 0,
});
const isAcceptSetting = ref<boolean>(false); const isAcceptSetting = ref<boolean>(false);
const isApproveSetting = ref<boolean>(false); const isApproveSetting = ref<boolean>(false);
const isReasonSetting = ref<boolean>(false); const isReasonSetting = ref<boolean>(false);
const formDataQuery = reactive<DataQuery>({ const formDataQuery = reactive<DataQuery>({
page: 1,
pageSize: 10,
isAct: false, isAct: false,
keyword: "", keyword: "",
}); });
@ -77,12 +96,14 @@ const formDataQuery = reactive<DataQuery>({
async function fetchLists() { async function fetchLists() {
showLoader(); showLoader();
await http await http
.put(config.API.workflow + `commander/${props.type}`, formDataQuery) .put(config.API.workflow + `commander/${props.type}`, {
...formDataQuery,
keycloakId: props.keycloakId,
page: pagination.value.page,
pageSize: pagination.value.rowsPerPage,
})
.then(async (res) => { .then(async (res) => {
totalList.value = Math.ceil( pagination.value.rowsNumber = res.data.result.total;
res.data.result.total / formDataQuery.pageSize
);
total.value = res.data.result.total;
rows.value = res.data.result.data; rows.value = res.data.result.data;
}) })
.catch((err) => { .catch((err) => {
@ -119,7 +140,7 @@ function onSubmit() {
} }
function onSearchData() { function onSearchData() {
formDataQuery.page = 1; pagination.value.page = 1;
fetchLists(); fetchLists();
} }
@ -130,32 +151,25 @@ function onCloseModal() {
isAcceptSetting.value = false; isAcceptSetting.value = false;
isApproveSetting.value = false; isApproveSetting.value = false;
isReasonSetting.value = false; isReasonSetting.value = false;
formDataQuery.page = 1;
formDataQuery.pageSize = 10;
formDataQuery.isAct = false; formDataQuery.isAct = false;
formDataQuery.keyword = ""; formDataQuery.keyword = "";
} }
/**
* งกนร request จากตาราง เมอมการเปลยน pagination
* @param requestProps อมลการรองขอจากตาราง
*/
function onTableRequest(requestProps: PropsTable.RequestProps) {
const newPagination = requestProps?.pagination || requestProps;
if (!newPagination?.page || !newPagination?.rowsPerPage) return;
pagination.value = { ...newPagination };
}
watch(modal, (val) => { watch(modal, (val) => {
if (val) { if (val) {
fetchLists(); fetchLists();
} }
}); });
watch(
() => [formDataQuery.isAct, formDataQuery.pageSize],
() => {
onSearchData();
}
);
/**
* function updatePagination
* @param newPagination อม Pagination ใหม
*/
function updatePagination(newPagination: Pagination) {
formDataQuery.pageSize = newPagination.rowsPerPage;
}
</script> </script>
<template> <template>
@ -211,7 +225,8 @@ function updatePagination(newPagination: Pagination) {
:rows-per-page-options="[10, 25, 50, 100]" :rows-per-page-options="[10, 25, 50, 100]"
selection="single" selection="single"
v-model:selected="selected" v-model:selected="selected"
@update:pagination="updatePagination" v-model:pagination="pagination"
@request="onTableRequest"
> >
<template v-slot:header-selection="scope"> <template v-slot:header-selection="scope">
<q-checkbox <q-checkbox
@ -246,21 +261,6 @@ function updatePagination(newPagination: Pagination) {
</q-td> </q-td>
</q-tr> </q-tr>
</template> </template>
<template v-slot:pagination="scope">
งหมด {{ total }} รายการ
<q-pagination
v-model="formDataQuery.page"
active-color="primary"
color="dark"
:max="Number(totalList)"
size="sm"
boundary-links
direction-links
:max-pages="5"
@update:model-value="fetchLists()"
></q-pagination>
</template>
</d-table> </d-table>
<div class="q-gutter-xs q-pt-sm"> <div class="q-gutter-xs q-pt-sm">
<div> <div>
@ -281,10 +281,10 @@ function updatePagination(newPagination: Pagination) {
keep-color keep-color
color="primary" color="primary"
v-model="isApproveSetting" v-model="isApproveSetting"
label="ให้เลือกพิจารณา (อนุมัติ/ไม่อนุมัติ)" :label="`ให้เลือกพิจารณา (อนุมัติ/${rejectName})`"
/> />
</div> </div>
<div v-if="!isAcceptSetting"> <div>
<q-checkbox <q-checkbox
dense dense
keep-color keep-color

View file

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, ref } from "vue"; import { onMounted, ref, computed } from "vue";
import { useQuasar } from "quasar"; import { useQuasar } from "quasar";
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
@ -20,9 +20,17 @@ const { id, sysName } = defineProps({
sysName: { type: String, require: true }, sysName: { type: String, require: true },
}); });
const rejectName = computed(() =>
sysName && ["SYS_RESIGN", "SYS_RESIGN_EMP"].includes(sysName)
? "ยับยั้ง"
: "ไม่อนุมัติ"
);
const stateId = ref<string>(""); //id state const stateId = ref<string>(""); //id state
const state = ref<number>(1); //state const state = ref<number>(1); //state
const isPermission = ref<boolean>(true); // Workflow const isPermission = ref<boolean>(true); // Workflow
const KeycloakId = ref<string>("");
const isLoading = ref<boolean>(false); //
const permission = ref<Permission>({ const permission = ref<Permission>({
isChangeState: false, /// isChangeState: false, ///
@ -40,6 +48,7 @@ const itemState = ref<DataListState[]>([]);
/** ฟังก์ชันเรียกข้อมูล Workflow ที่อยู่ปัจุบัน*/ /** ฟังก์ชันเรียกข้อมูล Workflow ที่อยู่ปัจุบัน*/
async function fetchCheckState() { async function fetchCheckState() {
isLoading.value = true;
await http await http
.post(config.API.workflow + `check-user-now`, { .post(config.API.workflow + `check-user-now`, {
refId: id, refId: id,
@ -62,9 +71,13 @@ async function fetchCheckState() {
isCancel: data.can_cancel, isCancel: data.can_cancel,
isSing: data.can_sing, isSing: data.can_sing,
}; };
KeycloakId.value = data.keycloakId;
}) })
.catch(() => { .catch(() => {
isPermission.value = false; isPermission.value = false;
})
.finally(() => {
isLoading.value = false;
}); });
} }
@ -120,7 +133,22 @@ defineExpose({
<div class="q-pl-sm text-weight-bold text-dark">สถานะการดำเนนเรอง</div> <div class="q-pl-sm text-weight-bold text-dark">สถานะการดำเนนเรอง</div>
</div> </div>
<div class="col-12"><q-separator /></div> <div class="col-12"><q-separator /></div>
<q-card-section> <q-card-section class="col-12 q-px-lg q-py-md" v-if="isLoading">
<q-timeline color="primary">
<q-timeline-entry
v-for="(step, index) in 4"
:key="index"
:icon="`mdi-numeric-${index + 1}`"
color="grey-4"
>
<template #title>
<q-skeleton type="rect" width="150px" height="20px" />
</template>
</q-timeline-entry>
</q-timeline>
</q-card-section>
<q-card-section v-else>
<div class="q-px-lg q-py-md"> <div class="q-px-lg q-py-md">
<q-timeline color="primary"> <q-timeline color="primary">
<q-timeline-entry <q-timeline-entry
@ -187,7 +215,7 @@ defineExpose({
? item.isApprove === true ? item.isApprove === true
? "อนุมัติ" ? "อนุมัติ"
: item.isApprove === false : item.isApprove === false
? "ไม่อนุมัติ" ? `${rejectName}`
: "" : ""
: "" : ""
}} }}
@ -236,5 +264,7 @@ defineExpose({
:state-id="stateId" :state-id="stateId"
:fetch-data="fetchCheckState" :fetch-data="fetchCheckState"
:type="typeSelectPerson" :type="typeSelectPerson"
:sys-name="sysName"
:keycloak-id="KeycloakId"
/> />
</template> </template>

View file

@ -1,6 +1,4 @@
interface DataQuery { interface DataQuery {
page: number;
pageSize: number;
isAct: boolean; isAct: boolean;
keyword: string; keyword: string;
} }

View file

@ -9,6 +9,13 @@ interface ProfileData {
posLevelName: string; posLevelName: string;
posNo: string; posNo: string;
profileId: string; profileId: string;
citizenId?: string;
salary?: number | null;
birthDate?: string;
keycloakId?: string;
org?: string;
dateStart?: string;
dateRetireLaw?: string;
} }
interface InformationData { interface InformationData {
@ -28,4 +35,64 @@ interface InformationData {
email: string; email: string;
} }
export type { ProfileData, InformationData }; interface DataProfile {
amountSpecial: number;
avatar: string;
avatarName: string;
birthDate: string;
child1: string;
child1DnaId: string;
child1Id: string;
child1ShortName: string;
child2: string;
child2DnaId: string;
child2Id: string;
child2ShortName: string;
child3: string;
child3DnaId: string;
child3Id: string;
child3ShortName: string;
child4: string | null;
child4DnaId: string | null;
child4Id: string | null;
child4ShortName: string | null;
citizenId: string;
dateRetireLaw: string;
dateStart: string;
firstName: string;
isDirector: boolean;
isProbation: boolean;
keycloak: string;
lastName: string;
leaveDate: string | null;
node: number;
nodeDnaId: string;
nodeId: string;
nodeShortName: string;
posExecutiveId: string | null;
posExecutiveName: string | null;
posExecutivePriority: number | null;
posLevelId: string;
posLevelName: string;
posLevelRank: number;
posMaster: number;
posMasterNo: number;
posNo: string;
posTypeId: string;
posTypeName: string;
posTypeRank: number;
position: string;
positionArea: string | null;
positionExecutiveField: string | null;
prefix: string;
profileId: string;
profileType: string;
rank: string | null;
root: string;
rootDnaId: string;
rootId: string;
rootShortName: string;
salary: number;
}
export type { ProfileData, InformationData, DataProfile };

View file

@ -0,0 +1,36 @@
/** Namespace สำหรับ Table-related types */
export namespace PropsTable {
/** Interface สำหรับ pagination object */
export interface Pagination {
/** หน้าปัจจุบัน (เริ่มจาก 1) */
page: number;
/** จำนวนแถวต่อหน้า */
rowsPerPage: number;
/** จำนวนแถวทั้งหมด */
rowsNumber?: number;
/** คอลัมน์ที่ใช้ sort */
sortBy?: string;
/** เรียงจากมากไปน้อย */
descending?: boolean;
rowsTotal?: number;
}
/** Interface สำหรับ request props จาก d-table */
export interface RequestProps {
/** ข้อมูล pagination */
pagination: Pagination;
/** ตัวกรองข้อมูล */
filter?: any;
/** function สำหรับดึงค่าจาก cell */
getCellValue?: (col: any, row: any) => any;
}
/** Union type สำหรับ handleRequest function */
export type HandleRequestProps = RequestProps;
}
// Export แบบเดิมเพื่อ backward compatibility
export type TablePagination = PropsTable.Pagination;
export type TableRequestProps = PropsTable.RequestProps;
export type HandleRequestProps = PropsTable.HandleRequestProps;

View file

@ -17,7 +17,6 @@ import { getToken, tokenParsed } from "@/plugins/auth";
export const useSupportStore = defineStore("supportServiceStore", () => { export const useSupportStore = defineStore("supportServiceStore", () => {
const { showLoader, hideLoader, messageError } = useCounterMixin(); const { showLoader, hideLoader, messageError } = useCounterMixin();
const $q = useQuasar();
const openChat = ref<boolean>(false); const openChat = ref<boolean>(false);
const icon = ref<string>("mdi-account-check"); const icon = ref<string>("mdi-account-check");
@ -114,7 +113,7 @@ export const useSupportStore = defineStore("supportServiceStore", () => {
const res = await http const res = await http
.get(config.API.supportMessageStatus(issueId)) .get(config.API.supportMessageStatus(issueId))
.catch((err) => { .catch((err) => {
messageError($q, err); console.log(err);
}) })
.finally(() => { .finally(() => {
hideLoader(); hideLoader();
@ -129,7 +128,7 @@ export const useSupportStore = defineStore("supportServiceStore", () => {
const res = await http const res = await http
.get(config.API.supportMessage(issueId)) .get(config.API.supportMessage(issueId))
.catch((err) => { .catch((err) => {
messageError($q, err); console.log(err);
}) })
.finally(() => { .finally(() => {
hideLoader(); hideLoader();
@ -149,7 +148,7 @@ export const useSupportStore = defineStore("supportServiceStore", () => {
const res = await http const res = await http
.get(config.API.supportIssueUserId(userId.value)) .get(config.API.supportIssueUserId(userId.value))
.catch((err) => { .catch((err) => {
messageError($q, err); console.log(err);
}) })
.finally(() => { .finally(() => {
hideLoader(); hideLoader();
@ -166,7 +165,7 @@ export const useSupportStore = defineStore("supportServiceStore", () => {
const res = await http const res = await http
.get(config.API.supportIssueCategory) .get(config.API.supportIssueCategory)
.catch((err) => { .catch((err) => {
messageError($q, err); console.log(err);
}) })
.finally(() => { .finally(() => {
hideLoader(); hideLoader();
@ -188,7 +187,7 @@ export const useSupportStore = defineStore("supportServiceStore", () => {
const res = await http const res = await http
.post(config.API.supportNewIssue, requestBody) .post(config.API.supportNewIssue, requestBody)
.catch((err) => { .catch((err) => {
messageError($q, err); console.log(err);
}) })
.finally(() => { .finally(() => {
hideLoader(); hideLoader();
@ -203,7 +202,7 @@ export const useSupportStore = defineStore("supportServiceStore", () => {
const res = await http const res = await http
.get(config.API.supportSearchIssue(searchData)) .get(config.API.supportSearchIssue(searchData))
.catch((err) => { .catch((err) => {
messageError($q, err); console.log(err);
}); });
if (res && res.data) { if (res && res.data) {
issue.value = res.data; issue.value = res.data;

View file

@ -31,4 +31,11 @@ interface MenuMainList {
active: boolean; active: boolean;
} }
export type { InboxList, InboxDetail, MenuMainList }; interface Attachments {
name: string;
url: string;
isReport: boolean;
isTemplate: boolean;
}
export type { InboxList, InboxDetail, MenuMainList, Attachments };

View file

@ -26,27 +26,25 @@ const { showLoader, hideLoader, date2Thai, messageError } = mixin;
const fullname = ref<string>(""); // const fullname = ref<string>(""); //
const inboxList = ref<InboxDetail[]>([]); // const inboxList = ref<InboxDetail[]>([]); //
const idInboxActive = ref<string>(); // Id const idInboxActive = ref<string>(); // Id
// const isLoadingInbox = ref<boolean>(true); //
//
const filteredItems = computed(() => { const filteredItems = computed(() => {
const isOfficer = dataStore.officerType === "OFFICER"; const isOfficer = dataStore.officerType === "OFFICER";
const conditions: Record<string, boolean> = { const conditions: Record<string, boolean> = {
"ทดลองปฏิบัติหน้าที่ราชการ": dataStore.isProbation, ทดลองปฏหนาทราชการ: dataStore.isProbation,
"ประเมินบุคคล": isOfficer, ประเมนบคคล: isOfficer,
"ผลงาน": isOfficer, ผลงาน: isOfficer,
"ขอโอน": isOfficer, ขอโอน: isOfficer,
"ผู้ขอรับการประเมิน (KPI)": isOfficer, "ผู้ขอรับการประเมิน (KPI)": isOfficer,
"ผู้ประเมิน (KPI)": isOfficer, "ผู้ประเมิน (KPI)": isOfficer,
"ทุนการศึกษา/ฝึกอบรม": isOfficer, "ทุนการศึกษา/ฝึกอบรม": isOfficer,
"การพัฒนารายบุคคล": isOfficer, การพฒนารายบคคล: isOfficer,
}; };
return items.value.filter( return items.value.filter((item) => conditions[item.title] ?? true);
(item) => conditions[item.title] ?? true
);
}); });
const items = ref<MenuMainList[]>([ const items = ref<MenuMainList[]>([
{ {
icon: "mdi-account-group-outline", icon: "mdi-account-group-outline",
@ -98,7 +96,7 @@ const items = ref<MenuMainList[]>([
}, },
{ {
icon: "mdi-scale-balance", icon: "mdi-scale-balance",
title: "อุทธรณ์ร้องทุกข์", title: "อุทธรณ์/ร้องทุกข์",
sub: "ทำเรื่องขออุทธรณ์ หรือร้องทุกข์", sub: "ทำเรื่องขออุทธรณ์ หรือร้องทุกข์",
color: "green-3", color: "green-3",
path: "/appeal-complain", path: "/appeal-complain",
@ -151,7 +149,10 @@ const items = ref<MenuMainList[]>([
* @param index หนาทโหลดขอม * @param index หนาทโหลดขอม
*/ */
const fetchlistInbox = async (index: number) => { const fetchlistInbox = async (index: number) => {
index === 1 && showLoader(); if (index === 1) {
isLoadingInbox.value = true; //
}
index != 0 && index != 0 &&
(await http (await http
.get(config.API.msgInbox + `?page=${index}&pageSize=${10}`) .get(config.API.msgInbox + `?page=${index}&pageSize=${10}`)
@ -176,7 +177,7 @@ const fetchlistInbox = async (index: number) => {
} }
}) })
.finally(() => { .finally(() => {
hideLoader(); isLoadingInbox.value = false;
})); }));
}; };
@ -252,11 +253,17 @@ const totalInbox = ref<number>(0); // จำนวนข้อความทั
*/ */
async function onLoad(index: number, done: Function) { async function onLoad(index: number, done: Function) {
const num = index === 1 ? 0 : index++; const num = index === 1 ? 0 : index++;
if (inboxList.value.length < totalInbox.value) { try {
setTimeout(() => { // infinite scroll
fetchlistInbox(num); if (inboxList.value.length >= totalInbox.value) {
done(); done(true);
}, 3000); return;
}
await fetchlistInbox(num);
done();
} catch (error) {
done(true);
} }
} }
@ -287,7 +294,16 @@ onMounted(async () => {
v-for="(item, j) in filteredItems" v-for="(item, j) in filteredItems"
:key="j" :key="j"
> >
<q-card bordered @click="goToPage(item.path)" class="noactive col-12"> <q-card v-if="dataStore.isLoadingMenu" bordered class="col-12">
<q-skeleton width="100%" height="180px" />
</q-card>
<q-card
v-else
bordered
@click="goToPage(item.path)"
class="noactive col-12"
>
<div class="col-12"> <div class="col-12">
<q-avatar <q-avatar
:color="item.color" :color="item.color"
@ -326,12 +342,28 @@ onMounted(async () => {
กลองขอความ กลองขอความ
</div> </div>
<q-space /> <q-space />
<div class="text-grey-5" style="font-size: 12px"> <div v-if="isLoadingInbox">
<q-skeleton type="text" width="80px" />
</div>
<div v-else class="text-grey-5" style="font-size: 12px">
งหมด {{ totalInbox }} อความ งหมด {{ totalInbox }} อความ
</div> </div>
</div> </div>
<div <div
v-if="totalInbox != 0" class="q-pa-sm"
v-if="isLoadingInbox"
style="height: calc(100% - 60px)"
>
<div v-for="(item, index) in 3">
<q-skeleton type="text" width="10%" class="text-subtitle1" />
<q-skeleton type="text" width="50%" class="text-subtitle1" />
<q-skeleton type="text" class="text-caption" />
</div>
</div>
<div
v-if="totalInbox != 0 && !isLoadingInbox"
ref="scrollTargetRef" ref="scrollTargetRef"
style="max-height: 90%; overflow: auto" style="max-height: 90%; overflow: auto"
> >
@ -403,7 +435,11 @@ onMounted(async () => {
</q-infinite-scroll> </q-infinite-scroll>
</div> </div>
<q-banner rounded class="bg-amber-1 text-center q-mx-sm" v-else> <q-banner
rounded
class="bg-amber-1 text-center q-mx-sm"
v-else-if="totalInbox === 0 && !isLoadingInbox"
>
<div class="text-yellow-10"> <div class="text-yellow-10">
<q-icon <q-icon
name="mdi-alert-box" name="mdi-alert-box"

View file

@ -13,9 +13,10 @@ export const useTransferDataStore = defineStore("transfer", () => {
return "ไม่อนุมัติ"; return "ไม่อนุมัติ";
case "REPORT": case "REPORT":
return "ส่งรายชื่อไปออกคำสั่ง"; return "ส่งรายชื่อไปออกคำสั่ง";
case "WAITING":
return "รอออกคำสั่ง";
case "DONE": case "DONE":
return "ออกคำสั่งเสร็จแล้ว"; return "ออกคำสั่งเสร็จแล้ว";
default: default:
return "-"; return "-";
} }

View file

@ -1,60 +1,65 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted } from "vue" import { ref, onMounted } from "vue";
import { useQuasar } from "quasar" import { useQuasar } from "quasar";
import { useRouter, useRoute } from "vue-router" 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 { useCounterMixin } from "@/stores/mixin" import { useCounterMixin } from "@/stores/mixin";
import type { QForm } from "quasar" import type { QForm } from "quasar";
import Workflow from "@/components/Workflow/Main.vue" import Workflow from "@/components/Workflow/Main.vue";
const $q = useQuasar() const $q = useQuasar();
const route = useRoute() const route = useRoute();
const router = useRouter() const router = useRouter();
const mixin = useCounterMixin() const mixin = useCounterMixin();
const { success, messageError, showLoader, hideLoader, dialogConfirm } = mixin const { success, messageError, dialogConfirm ,showLoader,hideLoader} = mixin;
const id = ref<string>(router.currentRoute.value.name === "addTransfer" ? "" : route.params.id.toString()) //id path const id = ref<string>(
router.currentRoute.value.name === "addTransfer"
? ""
: route.params.id.toString()
); //id path
const files = ref<any>() // const isLoading = ref<boolean>(false);
const tranferOrg = ref<string>("") // const files = ref<any>(); //
const noteReason = ref<string>("") // const tranferOrg = ref<string>(""); //
const routeName = router.currentRoute.value.name // path const noteReason = ref<string>(""); //
const routeName = router.currentRoute.value.name; // path
/** Dialog Save */ /** Dialog Save */
async function saveData() { async function saveData() {
dialogConfirm( dialogConfirm(
$q, $q,
() => { () => {
createTransfer() createTransfer();
}, },
"ยืนยันการยื่นข้อมูลการโอน", "ยืนยันการยื่นข้อมูลการโอน",
"ต้องการยื่นข้อมูลการโอนนี้ใช่หรือไม่" "ต้องการยื่นข้อมูลการโอนนี้ใช่หรือไม่"
) );
} }
/** ฟังก์ชั่นสร้างขอโอน */ /** ฟังก์ชั่นสร้างขอโอน */
async function createTransfer() { async function createTransfer() {
showLoader() showLoader()
const formData = new FormData() const formData = new FormData();
formData.append("Organization", tranferOrg.value) formData.append("Organization", tranferOrg.value);
formData.append("Reason", noteReason.value) formData.append("Reason", noteReason.value);
formData.append("file", files.value) formData.append("file", files.value ? files.value : null);
await http await http
.post(config.API.listtransfer(), formData) .post(config.API.listtransfer(), formData)
.then(res => { .then((res) => {
router.push(`/transfer/` + res.data.result) router.push(`/transfer/` + res.data.result);
success($q, "บันทึกข้อมูลสำเร็จ") hideLoader()
}) success($q, "บันทึกข้อมูลสำเร็จ");
.catch(e => { })
messageError($q, e) .catch((e) => {
}) messageError($q, e);
.finally(() => { hideLoader()
hideLoader() })
}) .finally(() => {});
} }
/** /**
@ -62,21 +67,21 @@ async function createTransfer() {
* @param id ไอดของขอม * @param id ไอดของขอม
*/ */
async function fecthDataTransfer(id: string) { async function fecthDataTransfer(id: string) {
showLoader() isLoading.value = true;
await http await http
.get(config.API.transferByid(id)) .get(config.API.transferByid(id))
.then((res: any) => { .then((res: any) => {
let data = res.data.result let data = res.data.result;
tranferOrg.value = data.organization tranferOrg.value = data.organization;
noteReason.value = data.reason noteReason.value = data.reason;
files.value = data.docs files.value = data.docs;
}) isLoading.value = false;
.catch((e: any) => { })
messageError($q, e) .catch((e: any) => {
}) messageError($q, e);
.finally(() => { isLoading.value = false;
hideLoader() })
}) .finally(() => {});
} }
/** /**
@ -84,104 +89,141 @@ async function fecthDataTransfer(id: string) {
* @param url URL File * @param url URL File
*/ */
function fileOpen(url: string) { function fileOpen(url: string) {
window.open(url, "_blank") window.open(url, "_blank");
} }
/** /**
* เรยกฟงกนทงหมดตอนเรยกใชไฟล * เรยกฟงกนทงหมดตอนเรยกใชไฟล
*/ */
onMounted(() => { onMounted(() => {
if (route.params.id !== undefined) { if (route.params.id !== undefined) {
fecthDataTransfer(id.value) fecthDataTransfer(id.value);
} }
}) });
</script> </script>
<template> <template>
<div class="col-12 row justify-center"> <div class="col-12 row justify-center">
<div class="col-xs-12 col-sm-12 col-md-11"> <div class="col-xs-12 col-sm-12 col-md-11">
<div class="toptitle text-white col-12 row items-center"> <div class="toptitle text-white col-12 row items-center">
<q-btn icon="mdi-arrow-left" unelevated round dense flat color="primary" class="q-mr-sm" @click="router.go(-1)" /> <q-btn
<div v-if="routeName == 'addTransfer'">เพิ่มเรื่องขอโอน</div> icon="mdi-arrow-left"
<div v-else>รายละเอียดเรื่องขอโอน</div> unelevated
</div> round
<q-form class="col-12" greedy @submit.prevent @validation-success="saveData"> dense
<q-card bordered> flat
<q-card-section> color="primary"
<div class="row"> class="q-mr-sm"
<div class="col-12 row q-col-gutter-sm"> @click="router.push('/transfer')"
<q-input />
:class="routeName != 'addTransfer' ? 'col-12' : 'col-12 inputgreen'" <div v-if="routeName == 'addTransfer'">เพิ่มเรื่องขอโอน</div>
dense <div v-else>รายละเอียดเรื่องขอโอน</div>
outlined </div>
v-model="tranferOrg" <q-form
hide-bottom-space class="col-12"
label="หน่วยงานที่ขอโอนไป" greedy
:readonly="routeName != 'addTransfer'" @submit.prevent
:rules="[(val:string) => !!val || `${'กรุณากรอกหน่วยงานที่ขอโอนไป'}`]" @validation-success="saveData"
/> >
<q-card bordered>
<q-card-section>
<div class="row">
<div class="col-12 row q-col-gutter-sm">
<q-input
v-if="!isLoading"
:class="
routeName != 'addTransfer' ? 'col-12' : 'col-12 inputgreen'
"
dense
outlined
v-model="tranferOrg"
hide-bottom-space
label="หน่วยงานที่ขอโอนไป"
:readonly="routeName != 'addTransfer'"
:rules="[(val:string) => !!val || `${'กรุณากรอกหน่วยงานที่ขอโอนไป'}`]"
/>
<div class="col-12" v-else>
<q-skeleton type="QInput" height="40px" />
</div>
<q-input
v-if="!isLoading"
:class="
routeName != 'addTransfer' ? 'col-12' : 'col-12 inputgreen'
"
dense
outlined
v-model="noteReason"
label="เหตุผล"
hide-bottom-space
type="textarea"
:readonly="routeName != 'addTransfer'"
:rules="[(val:string) => !!val || `${'กรุณากรอกเหตุผล'}`]"
/>
<div class="col-12" v-else>
<q-skeleton type="QInput" height="120px" />
</div>
<div class="col-12 row" v-if="routeName == 'addTransfer'">
<q-file
v-model="files"
class="col-xs-12 col-sm-12 inputgreen"
outlined
dense
accept=".pdf"
label="เอกสารเพิ่มเติม"
>
<template v-slot:prepend>
<q-icon name="attach_file" /> </template
></q-file>
</div>
<q-input <div
:class="routeName != 'addTransfer' ? 'col-12' : 'col-12 inputgreen'" class="col-12 row"
dense v-if="routeName != 'addTransfer' && files && files.length > 0"
outlined >
v-model="noteReason" <q-card bordered flat class="full-width">
label="เหตุผล" <div
hide-bottom-space class="bg-grey-1 q-pa-sm col-12 row items-center text-primary"
type="textarea" >
:readonly="routeName != 'addTransfer'" <div class="q-pl-sm text-weight-bold text-dark">
:rules="[(val:string) => !!val || `${'กรุณากรอกเหตุผล'}`]" เอกสารเพมเต
/> </div>
</div>
<q-separator />
<q-list separator>
<q-item v-for="file in files" :key="file.key">
<q-item-section>
{{ file.fileName }}
</q-item-section>
<q-item-section avatar>
<q-btn
color="blue"
round
flat
icon="mdi-download"
@click="fileOpen(file.pathName)"
>
<q-tooltip> ดาวนโหลดไฟล </q-tooltip>
</q-btn>
</q-item-section>
</q-item>
</q-list>
</q-card>
</div>
<div class="col-12 row" v-if="routeName == 'addTransfer'"> <!-- Workflow -->
<q-file <div class="col-12" v-if="routeName != 'addTransfer'">
v-model="files" <Workflow :id="id" :sys-name="`SYS_TRANSFER_REQ`" />
class="col-xs-12 col-sm-12 inputgreen" </div>
outlined </div>
dense </div>
lazy-rules </q-card-section>
hide-bottom-space
accept=".pdf"
:rules="[(val: string) => !!val || 'กรุณาเลือกไฟล์เอกสารเพิ่มเติม']"
label="เอกสารเพิ่มเติม"
>
<template v-slot:prepend> <q-icon name="attach_file" /> </template
></q-file>
</div>
<div class="col-12 row" v-if="routeName != 'addTransfer'"> <q-separator v-if="routeName == 'addTransfer'" />
<q-card bordered flat class="full-width"> <q-card-actions align="right" v-if="routeName == 'addTransfer'">
<div class="bg-grey-1 q-pa-sm col-12 row items-center text-primary"> <q-btn color="primary" label="ยื่นเรื่องขอโอน" type="onsubmit" />
<div class="q-pl-sm text-weight-bold text-dark">เอกสารเพมเต</div> </q-card-actions>
</div> </q-card>
<q-separator /> </q-form>
<q-list separator> </div>
<q-item v-for="file in files" :key="file.key"> </div>
<q-item-section>
{{ file.fileName }}
</q-item-section>
<q-item-section avatar>
<q-btn color="teal-5" round flat icon="mdi-download" @click="fileOpen(file.pathName)"></q-btn>
</q-item-section>
</q-item>
</q-list>
</q-card>
</div>
<!-- Workflow -->
<div class="col-12" v-if="routeName != 'addTransfer'">
<Workflow :id="id" :sys-name="`SYS_TRANSFER_REQ`" />
</div>
</div>
</div>
</q-card-section>
<q-separator v-if="routeName == 'addTransfer'" />
<q-card-actions align="right" v-if="routeName == 'addTransfer'">
<q-btn color="primary" label="ยื่นเรื่องขอโอน" type="onsubmit" />
</q-card-actions>
</q-card>
</q-form>
</div>
</div>
</template> </template>

View file

@ -20,8 +20,7 @@ const mixin = useCounterMixin();
const transferData = useTransferDataStore(); const transferData = useTransferDataStore();
const { statusText } = transferData; const { statusText } = transferData;
const { date2Thai, messageError, showLoader, hideLoader, onSearchDataTable } = const { date2Thai, messageError, onSearchDataTable } = mixin;
mixin;
const pagination = ref({ const pagination = ref({
sortBy: "desc", sortBy: "desc",
@ -30,6 +29,7 @@ const pagination = ref({
rowsPerPage: 10, rowsPerPage: 10,
}); });
const isLoading = ref<boolean>(false);
const rows = ref<TransferMain[]>([]); const rows = ref<TransferMain[]>([]);
const rowsData = ref<TransferMain[]>([]); const rowsData = ref<TransferMain[]>([]);
const filter = ref<string>(""); const filter = ref<string>("");
@ -120,7 +120,7 @@ const columns = ref<QTableProps["columns"]>([
// //
async function fecthListTransfer() { async function fecthListTransfer() {
showLoader(); isLoading.value = true;
await http await http
.get(config.API.listUserTransfer()) .get(config.API.listUserTransfer())
.then((res) => { .then((res) => {
@ -139,12 +139,11 @@ async function fecthListTransfer() {
})); }));
rows.value = listData; rows.value = listData;
rowsData.value = listData; rowsData.value = listData;
isLoading.value = false;
}) })
.catch((e: any) => { .catch((e: any) => {
messageError($q, e); messageError($q, e);
}) isLoading.value = false;
.finally(() => {
hideLoader();
}); });
} }
@ -219,7 +218,7 @@ onMounted(async () => {
debounce="300" debounce="300"
placeholder="ค้นหา" placeholder="ค้นหา"
style="max-width: 200px" style="max-width: 200px"
@keydown.enter="onSearch" @keydown.enter.prevent="onSearch"
> >
<template v-slot:append> <template v-slot:append>
<q-icon name="search" /> <q-icon name="search" />
@ -251,27 +250,13 @@ onMounted(async () => {
dense dense
:paging="true" :paging="true"
row-key="id" row-key="id"
class="custom-table2"
style="max-height: 80vh"
:rows="rows" :rows="rows"
:columns="columns" :columns="columns"
:visible-columns="visibleColumns" :visible-columns="visibleColumns"
:rows-per-page-options="[10, 25, 50, 100]" :rows-per-page-options="[10, 25, 50, 100]"
v-model:pagination="pagination" :pagination="pagination"
:loading="isLoading"
> >
<template v-slot:pagination="scope">
งหมด {{ rows.length }} รายการ
<q-pagination
v-model="pagination.page"
active-color="primary"
color="dark"
:max="scope.pagesNumber"
:max-pages="5"
size="sm"
boundary-links
direction-links
></q-pagination>
</template>
<template v-slot:header="props"> <template v-slot:header="props">
<q-tr :props="props"> <q-tr :props="props">
<q-th <q-th
@ -295,13 +280,7 @@ onMounted(async () => {
<div v-if="col.name == 'no'"> <div v-if="col.name == 'no'">
{{ props.rowIndex + 1 }} {{ props.rowIndex + 1 }}
</div> </div>
<div v-else-if="col.name == 'noPos'">
{{
props.row.rootShortNameOld && props.row.noPos
? `${props.row.rootShortNameOld}${props.row.noPos}`
: "-"
}}
</div>
<div v-else-if="col.name == 'salary'"> <div v-else-if="col.name == 'salary'">
{{ {{
props.row.salary props.row.salary
@ -351,4 +330,5 @@ onMounted(async () => {
</div> </div>
</div> </div>
</template> </template>
<style scoped lang="scss"></style> <style scoped lang="scss"></style>

View file

@ -54,15 +54,37 @@ interface MainListResponse {
isActive: boolean; isActive: boolean;
} }
interface DataOptions{ interface DataOptions {
id:string id: string;
name:string name: string;
} }
interface RowsType {
commanders: SeqTypeRow[];
approvers: SeqTypeRow[];
cancelCommanders: SeqTypeRow[] | null;
cancelApprovers: SeqTypeRow[] | null;
}
interface SeqTypeRow {
seq: number;
prefix: string;
firstName: string;
lastName: string;
positionName: string;
profileId: string;
keycloakId: string;
approveStatus: string;
comment: string;
rejectDate: Date | null;
}
export type { export type {
QuestionDescription, QuestionDescription,
OptionQuestions, OptionQuestions,
OptionQuestions2, OptionQuestions2,
MainList, MainList,
MainListResponse, MainListResponse,
DataOptions DataOptions,
RowsType,
SeqTypeRow,
}; };

View file

@ -4,29 +4,45 @@ export const useRestDataStore = defineStore("Rest", () => {
const statusText = (val: string) => { const statusText = (val: string) => {
switch (val) { switch (val) {
case "WAITTING": case "WAITTING":
return "รอดำเนินการ"; return "ใหม่";
case "PENDING": case "PENDING":
return "เลือกตำแหน่งแล้ว"; return "รอดำเนินการ";
case "APPROVE": case "APPROVE":
return "อนุมัติ"; return "อนุมัติ";
case "REJECT": case "REJECT":
return "ไม่อนุมัติ"; return "ไม่อนุมัติ";
case "REPORT": case "REPORT":
return "ส่งรายชื่อไปออกคำสั่ง"; return "ส่งรายชื่อไปออกคำสั่ง";
case "WAITING":
return "รอออกคำสั่ง";
case "DONE": case "DONE":
return "ออกคำสั่งเสร็จแล้ว"; return "ออกคำสั่งเสร็จสิ้น";
case "DONECANCEL": case "DONECANCEL":
return "ยกเลิกการลาออก"; return "ยกเลิกการลาออกสำเร็จ";
case "CANCEL": case "CANCEL":
return "ยกเลิกการลาออก"; return "ยกเลิกการลาออกสำเร็จ";
case "DONEREJECT": case "DONEREJECT":
return "ออกคำสั่งยกเลิกลาออกเสร็จแล้ว"; return "ออกคำสั่งยกเลิกลาออกเสร็จแล้ว";
case "CANCELING":
return "กำลังดำเนินการยกเลิก";
default: default:
return "-"; return "-";
} }
}; };
function convertStatusText(val: string) {
switch (val) {
case "PENDING":
return "รอดำเนินการ";
case "APPROVE":
return "อนุญาต";
case "REJECT":
return "ยับยั้ง";
}
}
return { return {
statusText, statusText,
convertStatusText,
}; };
}); });

View file

@ -45,8 +45,8 @@ function onSubmit() {
.put(config.API.cancelResignByType(link.value, id.value), { .put(config.API.cancelResignByType(link.value, id.value), {
reason: reason.value, reason: reason.value,
}) })
.then(() => { .then(async () => {
props.fectData?.(id.value); await props.fectData?.(id.value);
success($q, "ยกเลิกการลาออกสำเร็จ"); success($q, "ยกเลิกการลาออกสำเร็จ");
}) })
.catch((err) => { .catch((err) => {

View file

@ -1,23 +1,32 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted } from "vue"; import { ref, onMounted } from "vue";
import { useQuasar } from "quasar"; import { is, useQuasar } from "quasar";
import type { QForm } from "quasar"; import type { QForm, QTableProps } from "quasar";
import { useRouter, useRoute } from "vue-router"; 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 { useRestDataStore } from "@/modules/03_retire/store";
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
import { useDataStore } from "@/stores/data"; import { useDataStore } from "@/stores/data";
import type { DataOptions } from "@/modules/03_retire/interface/Main"; import type {
DataOptions,
RowsType,
SeqTypeRow,
} from "@/modules/03_retire/interface/Main";
import Dialog from "@/modules/03_retire/views/DialogRetire.vue"; import Dialog from "@/modules/03_retire/views/DialogRetire.vue";
import Header from "@/components/DialogHeader.vue"; import Header from "@/components/DialogHeader.vue";
import Workflow from "@/components/Workflow/Main.vue"; import Workflow from "@/components/Workflow/Main.vue";
const $q = useQuasar(); const $q = useQuasar();
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
const store = useRestDataStore();
const { convertStatusText } = store;
const link = ref<string>(""); const link = ref<string>("");
const dataStore = useDataStore(); const dataStore = useDataStore();
const routeName = router.currentRoute.value.name; const routeName = router.currentRoute.value.name;
@ -37,6 +46,8 @@ const id = ref<string>(
? route.params.id.toString() ? route.params.id.toString()
: "" : ""
); // id path ); // id path
const isLoad = ref<boolean>(false);
const rowsApprover = ref<RowsType>();
const myform = ref<QForm | null>(null); //form const myform = ref<QForm | null>(null); //form
const tranferOrg = ref(""); // const tranferOrg = ref(""); //
const dateCommand = ref<Date>(new Date()); // const dateCommand = ref<Date>(new Date()); //
@ -73,18 +84,68 @@ const dataDetail = ref<any>({});
const modalWorkflow = ref<boolean>(false); const modalWorkflow = ref<boolean>(false);
/** const columnsCommanders = ref<QTableProps["columns"]>([
* งกนเปลยนเป string ของ status {
* @param val value ของ status true/false name: "no",
*/ align: "left",
function statusOrder(val: boolean) { label: "ลำดับ",
switch (val) { sortable: true,
case true: field: "no",
return "ยับยั้ง"; headerStyle: "font-size: 14px",
case false: style: "font-size: 14px",
return "อนุญาต"; },
} {
} 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: "positionName",
align: "left",
label: "ตำแหน่ง",
sortable: true,
field: "positionName",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "approveStatus",
align: "left",
label: "สถานะ",
sortable: true,
field: "approveStatus",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "comment",
align: "left",
label: "ความคิดเห็นและเหตุผล",
field: "comment",
sortable: true,
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "rejectDate",
align: "left",
label: "วันสุดท้ายที่ยับยั้ง",
field: "rejectDate",
sortable: true,
headerStyle: "font-size: 14px",
style: "font-size: 14px",
format(val, row) {
return `${row.rejectDate ? date2Thai(row.rejectDate) : "-"}`;
},
},
]);
/** /**
* นทกขอมลการลาออก * นทกขอมลการลาออก
@ -103,7 +164,7 @@ async function onSubmit() {
dateLeave.value !== null ? dateToISO(dateLeave.value) : "" dateLeave.value !== null ? dateToISO(dateLeave.value) : ""
); );
formData.append("Reason", noteReason.value); formData.append("Reason", noteReason.value);
formData.append("file", files.value); formData.append("file", files.value ? files.value : null);
if (noteReason.value == "OTHER") { if (noteReason.value == "OTHER") {
formData.append("remark", remark.value); formData.append("remark", remark.value);
} }
@ -143,7 +204,7 @@ function cancelResing() {
* @param id ไอดของขอม * @param id ไอดของขอม
*/ */
async function fectDataresign(id: string) { async function fectDataresign(id: string) {
showLoader(); isLoad.value = true;
await http await http
.get(config.API.resingByidType(link.value, id)) .get(config.API.resingByidType(link.value, id))
.then((res) => { .then((res) => {
@ -159,15 +220,20 @@ async function fectDataresign(id: string) {
noteReason.value = data.reason; noteReason.value = data.reason;
remark.value = data.remark; remark.value = data.remark;
rowsApprover.value = {
commanders: data.commanders,
approvers: data.approvers,
cancelCommanders: data.cancelCommanders ?? null,
cancelApprovers: data.cancelApprovers ?? null,
};
files.value = data.docs; files.value = data.docs;
dataDetail.value = data; dataDetail.value = data;
isLoad.value = false;
}) })
.catch((e) => { .catch((e) => {
messageError($q, e); messageError($q, e);
}) })
.finally(() => { .finally(() => {});
hideLoader();
});
} }
/** /**
@ -228,6 +294,8 @@ onMounted(async () => {
v-if=" v-if="
dataDetail.statusMain !== 'CANCEL' && dataDetail.statusMain !== 'CANCEL' &&
dataDetail.statusMain !== 'DONECANCEL' && dataDetail.statusMain !== 'DONECANCEL' &&
dataDetail.statusMain !== 'CANCELING' &&
dataDetail.statusCancel === null &&
checkCancleLeave checkCancleLeave
" "
unelevated unelevated
@ -237,7 +305,7 @@ onMounted(async () => {
:disable="tranferOrg == '' && noteReason == ''" :disable="tranferOrg == '' && noteReason == ''"
/> />
<q-btn <!-- <q-btn
v-else-if=" v-else-if="
(dataDetail.statusMain === 'CANCEL' || (dataDetail.statusMain === 'CANCEL' ||
dataDetail.statusMain === 'DONECANCEL') && dataDetail.statusMain === 'DONECANCEL') &&
@ -247,11 +315,12 @@ onMounted(async () => {
color="red" color="red"
label="ติดตามสถานะยกเลิกการขอลาออก" label="ติดตามสถานะยกเลิกการขอลาออก"
@click="modalWorkflow = true" @click="modalWorkflow = true"
/> /> -->
</q-card-actions> </q-card-actions>
<div class="col-12 row q-col-gutter-sm q-pa-md"> <div class="col-12 row q-col-gutter-sm q-pa-md">
<q-input <q-input
v-if="!isLoad"
:class=" :class="
routeName !== 'AddRetire' routeName !== 'AddRetire'
? 'col-md-9 col-xs-12' ? 'col-md-9 col-xs-12'
@ -266,7 +335,9 @@ onMounted(async () => {
:readonly="routeName != 'AddRetire'" :readonly="routeName != 'AddRetire'"
:rules="[(val:string) => !!val || `${'กรุณากรอกสถานที่ยื่นขอลาออกจากราชการ'}`]" :rules="[(val:string) => !!val || `${'กรุณากรอกสถานที่ยื่นขอลาออกจากราชการ'}`]"
/> />
<div class="col-md-9 col-xs-12 inputgreen" v-else>
<q-skeleton type="QInput" height="40px" />
</div>
<!-- <datepicker <!-- <datepicker
:class=" :class="
routeName !== 'AddRetire' routeName !== 'AddRetire'
@ -317,6 +388,7 @@ onMounted(async () => {
</datepicker> --> </datepicker> -->
<datepicker <datepicker
v-if="!isLoad"
:class=" :class="
routeName !== 'AddRetire' routeName !== 'AddRetire'
? 'col-md-3 col-xs-12' ? 'col-md-3 col-xs-12'
@ -362,7 +434,11 @@ onMounted(async () => {
</q-input> </q-input>
</template> </template>
</datepicker> </datepicker>
<div v-else class="col-md-3 col-xs-12">
<q-skeleton type="QInput" height="40px" />
</div>
<q-select <q-select
v-if="!isLoad"
v-model="noteReason" v-model="noteReason"
:class=" :class="
routeName !== 'AddRetire' ? 'col-12' : 'col-12 inputgreen' routeName !== 'AddRetire' ? 'col-12' : 'col-12 inputgreen'
@ -382,6 +458,9 @@ onMounted(async () => {
]" ]"
> >
</q-select> </q-select>
<div v-else class="col-12">
<q-skeleton type="QInput" height="40px" />
</div>
<q-input <q-input
:class=" :class="
routeName !== 'AddRetire' ? 'col-12' : 'col-12 inputgreen' routeName !== 'AddRetire' ? 'col-12' : 'col-12 inputgreen'
@ -404,10 +483,7 @@ onMounted(async () => {
class="col-xs-12 col-sm-12 inputgreen" class="col-xs-12 col-sm-12 inputgreen"
outlined outlined
dense dense
lazy-rules
hide-bottom-space
accept=".pdf" accept=".pdf"
:rules="[(val: string) => !!val || 'กรุณาเลือกเอกสารเพิ่มเติม']"
label="เอกสารเพิ่มเติม" label="เอกสารเพิ่มเติม"
> >
<template v-slot:prepend> <template v-slot:prepend>
@ -415,7 +491,10 @@ onMounted(async () => {
></q-file> ></q-file>
</div> </div>
<div class="col-12 row" v-if="routeName != 'AddRetire'"> <div
class="col-12 row"
v-if="routeName != 'AddRetire' && files && files.length > 0"
>
<q-card bordered flat class="row col-12 text-dark q-mt-sm"> <q-card bordered flat class="row col-12 text-dark q-mt-sm">
<div <div
class="bg-grey-1 q-pa-sm col-12 row items-center text-primary" class="bg-grey-1 q-pa-sm col-12 row items-center text-primary"
@ -510,126 +589,314 @@ onMounted(async () => {
</q-card> </q-card>
</div> --> </div> -->
<!-- ผลการพจารณาของผงคบบญชา --> <div class="row col-12" v-if="routeName != 'AddRetire'">
<div class="col-12 row" v-if="routeName != 'AddRetire'"> <div class="col-12 q-mt-sm text-weight-bold text-primary">
<q-card bordered class="row col-12 text-dark q-mt-sm"> ผลการพจารณาการขอลาออก
<div </div>
class="bg-grey-1 q-pa-sm col-12 row items-center text-primary"
> <div class="col-12 q-mt-md">
<div class="q-pl-sm text-weight-bold text-dark"> <!-- ผลการพจารณาของผงคบบญชา -->
ผลการพจารณาของผงคบบญชา <div class="col-12 row" v-if="routeName != 'AddRetire'">
</div> <q-card bordered class="row col-12 text-dark">
</div> <div
<q-separator /> class="bg-grey-1 q-pa-sm col-12 row items-center text-primary"
<div class="row col-12 q-pa-md"> >
<div class="col-12 row bg-white q-col-gutter-md"> <div class="q-pl-sm text-weight-bold text-dark">
<div class="col-xs-6 row items-start"> ผลการพจารณาของผงคบบญชา
<div class="col-12 text-top">สถานะ</div>
<div class="col-12 text-detail">
{{
dataDetail.commanderReject !== null
? statusOrder(dataDetail.commanderReject)
: "-"
}}
</div> </div>
</div> </div>
<div class="col-xs-6 row items-start"> <q-separator />
<div class="col-12 text-top">นสดทายทบย</div> <div class="col-12 q-pa-sm">
<div class="col-12 text-detail"> <d-table
{{ ref="table"
dataDetail.commanderRejectDate !== null :columns="columnsCommanders"
? date2Thai(dataDetail.commanderRejectDate) :rows="rowsApprover?.commanders ?? []"
: "-" row-key="key"
}} flat
</div> bordered
</div> :paging="true"
<div class="col-xs-12 row items-start"> dense
<div class="col-12 text-top">ความคดเหนและเหตผล</div> :rows-per-page-options="[1, 25, 50, 100]"
<div :pagination="{ page: 1, rowsPerPage: 10 }"
class="col-12 text-detail" :loading="isLoad"
v-if="dataDetail.commanderReject === false"
> >
{{ <template v-slot:header="props">
dataDetail.commanderApproveReason !== null <q-tr :props="props">
? dataDetail.commanderApproveReason <q-th
: "-" v-for="col in props.cols"
}} :key="col.name"
</div> :props="props"
<div >
class="col-12 text-detail" <span class="text-weight-medium">{{
v-if="dataDetail.commanderReject === true" col.label
> }}</span>
{{ </q-th>
dataDetail.commanderRejectReason !== null </q-tr>
? dataDetail.commanderRejectReason </template>
: "-" <template v-slot:body="props">
}} <q-tr :props="props" class="cursor-pointer">
<q-td
v-for="col in props.cols"
:key="col.name"
:props="props"
>
<div v-if="col.name == 'no'">
{{ props.rowIndex + 1 }}
</div>
<div v-else-if="col.name == 'approveStatus'">
{{
props.row.approveStatus
? convertStatusText(props.row.approveStatus)
: "-"
}}
</div>
<div v-else>
{{ col.value ? col.value : "-" }}
</div>
</q-td>
</q-tr>
</template>
</d-table>
</div>
</q-card>
</div>
<div class="col-12 row" v-if="routeName != 'AddRetire'">
<q-card bordered class="row col-12 text-dark q-mt-sm">
<div
class="bg-grey-1 q-pa-sm col-12 row items-center text-primary"
>
<div class="q-pl-sm text-weight-bold text-dark">
ผลการพจารณาของผอำนาจ
</div> </div>
</div> </div>
</div> <q-separator />
<div class="row col-12 q-pa-md">
<div class="col-12 row bg-white q-col-gutter-md">
<div class="col-xs-6 row items-start">
<div class="col-12 text-top"> - นามสก</div>
<div class="col-12 text-detail" v-if="!isLoad">
{{
rowsApprover &&
rowsApprover.approvers &&
rowsApprover.approvers[0]?.firstName
? `${rowsApprover?.approvers[0].prefix}${rowsApprover?.approvers[0].firstName} ${rowsApprover?.approvers[0].lastName}`
: "-"
}}
</div>
<q-skeleton v-else type="text" width="150px" />
</div>
<div class="col-xs-6 row items-start">
<div class="col-12 text-top">สถานะ</div>
<div v-if="!isLoad" class="col-12 text-detail">
{{
rowsApprover &&
rowsApprover.approvers &&
rowsApprover.approvers[0]?.approveStatus
? convertStatusText(
rowsApprover?.approvers[0].approveStatus
)
: "-"
}}
</div>
<q-skeleton v-else type="text" width="150px" />
</div>
<div class="col-xs-6 row items-start">
<div class="col-12 text-top">
นสดทายทบย
</div>
<div v-if="!isLoad" class="col-12 text-detail">
{{
rowsApprover &&
rowsApprover.approvers &&
rowsApprover.approvers[0]?.rejectDate
? date2Thai(
rowsApprover?.approvers[0].rejectDate
)
: "-"
}}
</div>
<q-skeleton v-else type="text" width="150px" />
</div>
<div class="col-xs-12 row items-start">
<div class="col-12 text-top">
ความคดเหนและเหตผล
</div>
<div v-if="!isLoad" class="col-12 text-detail">
{{
rowsApprover &&
rowsApprover.approvers &&
rowsApprover.approvers[0]?.comment
? rowsApprover?.approvers[0].comment
: "-"
}}
</div>
<q-skeleton v-else type="text" width="150px" />
</div>
</div>
</div>
</q-card>
</div> </div>
</q-card> </div>
</div> </div>
<!-- ผลการพจารณาของผอำนาจ --> <!-- ยกเลกการลาออก -->
<div class="col-12 row" v-if="routeName != 'AddRetire'"> <div
<q-card bordered class="row col-12 text-dark q-mt-sm"> class="row col-12"
<div v-if="
class="bg-grey-1 q-pa-sm col-12 row items-center text-primary" routeName != 'AddRetire' &&
> rowsApprover &&
<div class="q-pl-sm text-weight-bold text-dark"> rowsApprover?.cancelCommanders &&
ผลการพจารณาของผอำนาจ rowsApprover?.cancelCommanders?.length > 0
</div> "
</div> >
<q-separator /> <div class="col-12 q-mt-sm text-weight-bold text-red">
<div class="row col-12 q-pa-md"> ผลการพจารณาการขอยกเลกลาออก
<div class="col-12 row bg-white q-col-gutter-md"> </div>
<div class="col-xs-6 row items-start">
<div class="col-12 text-top">สถานะ</div> <div class="col-12 q-pa-sm">
<div class="col-12 text-detail"> <!-- ผลการพจารณาของผงคบบญชา -->
{{ <div class="col-12 row" v-if="routeName != 'AddRetire'">
dataDetail.oligarchReject !== null <q-card bordered class="row col-12 text-dark q-mt-sm">
? statusOrder(dataDetail.oligarchReject) <div
: "-" class="bg-grey-1 q-pa-sm col-12 row items-center text-primary"
}} >
<div class="q-pl-sm text-weight-bold text-dark">
ผลการพจารณาของผงคบบญชา
</div> </div>
</div> </div>
<div class="col-xs-6 row items-start"> <q-separator />
<div class="col-12 text-top">นสดทายทบย</div> <div class="col-12 q-pa-sm">
<div class="col-12 text-detail"> <d-table
{{ ref="table"
dataDetail.oligarchRejectDate !== null :columns="columnsCommanders"
? date2Thai(dataDetail.oligarchRejectDate) :rows="rowsApprover?.cancelCommanders ?? []"
: "-" row-key="key"
}} flat
</div> bordered
</div> :paging="true"
<div class="col-xs-12 row items-start"> dense
<div class="col-12 text-top">ความคดเหนและเหตผล</div> :rows-per-page-options="[1, 25, 50, 100]"
<div :pagination="{ page: 1, rowsPerPage: 10 }"
class="col-12 text-detail" :loading="isLoad"
v-if="dataDetail.oligarchReject == false"
> >
{{ <template v-slot:header="props">
dataDetail.oligarchApproveReason !== null <q-tr :props="props">
? dataDetail.oligarchApproveReason <q-th
: "-" v-for="col in props.cols"
}} :key="col.name"
</div> :props="props"
<div >
class="col-12 text-detail" <span class="text-weight-medium">{{
v-else-if="dataDetail.oligarchReject == true" col.label
> }}</span>
{{ </q-th>
dataDetail.oligarchRejectReason !== null </q-tr>
? dataDetail.oligarchRejectReason </template>
: "-" <template v-slot:body="props">
}} <q-tr :props="props" class="cursor-pointer">
<q-td
v-for="col in props.cols"
:key="col.name"
:props="props"
>
<div v-if="col.name == 'no'">
{{ props.rowIndex + 1 }}
</div>
<div v-else-if="col.name == 'approveStatus'">
{{
props.row.approveStatus
? convertStatusText(props.row.approveStatus)
: "-"
}}
</div>
<div v-else>
{{ col.value ? col.value : "-" }}
</div>
</q-td>
</q-tr>
</template>
</d-table>
</div>
</q-card>
</div>
<div class="col-12 row" v-if="routeName != 'AddRetire'">
<q-card bordered class="row col-12 text-dark q-mt-sm">
<div
class="bg-grey-1 q-pa-sm col-12 row items-center text-primary"
>
<div class="q-pl-sm text-weight-bold text-dark">
ผลการพจารณาของผอำนาจ
</div> </div>
</div> </div>
</div> <q-separator />
<div class="row col-12 q-pa-md">
<div class="col-12 row bg-white q-col-gutter-md">
<div class="col-xs-6 row items-start">
<div class="col-12 text-top"> - นามสก</div>
<div class="col-12 text-detail">
{{
rowsApprover &&
rowsApprover.cancelApprovers &&
rowsApprover.cancelApprovers[0]?.firstName
? `${rowsApprover?.cancelApprovers[0].prefix}${rowsApprover?.cancelApprovers[0].firstName} ${rowsApprover?.cancelApprovers[0].lastName}`
: "-"
}}
</div>
</div>
<div class="col-xs-6 row items-start">
<div class="col-12 text-top">สถานะ</div>
<div class="col-12 text-detail">
{{
rowsApprover &&
rowsApprover.cancelApprovers &&
rowsApprover.cancelApprovers[0]?.approveStatus
? convertStatusText(
rowsApprover?.cancelApprovers[0]
.approveStatus
)
: "-"
}}
</div>
</div>
<div class="col-xs-6 row items-start">
<div class="col-12 text-top">
นสดทายทบย
</div>
<div class="col-12 text-detail">
{{
rowsApprover &&
rowsApprover.cancelApprovers &&
rowsApprover.cancelApprovers[0]?.rejectDate
? date2Thai(
rowsApprover?.cancelApprovers[0].rejectDate
)
: "-"
}}
</div>
</div>
<div class="col-xs-12 row items-start">
<div class="col-12 text-top">
ความคดเหนและเหตผล
</div>
<div class="col-12 text-detail">
{{
rowsApprover &&
rowsApprover.cancelApprovers &&
rowsApprover.cancelApprovers[0]?.comment
? rowsApprover?.cancelApprovers[0].comment
: "-"
}}
</div>
</div>
</div>
</div>
</q-card>
</div> </div>
</q-card> </div>
</div> </div>
</div> </div>
@ -662,7 +929,7 @@ onMounted(async () => {
dataStore.officerType == 'OFFICER' dataStore.officerType == 'OFFICER'
" "
> >
<Workflow :id="id" sys-name="SYS_RESIGN" /> <!-- <Workflow :id="id" sys-name="SYS_RESIGN" /> -->
</div> </div>
</div> </div>
</div> </div>
@ -691,3 +958,13 @@ onMounted(async () => {
</q-card> </q-card>
</q-dialog> </q-dialog>
</template> </template>
<style scoped>
.text-top {
color: gray;
font-weight: 400;
padding-bottom: 3px;
}
.text-detail {
font-weight: 500;
}
</style>

View file

@ -20,11 +20,13 @@ const router = useRouter();
const link = ref<string>(""); const link = ref<string>("");
const dataStore = useDataStore(); const dataStore = useDataStore();
const mixin = useCounterMixin(); const mixin = useCounterMixin();
const { date2Thai, messageError, showLoader, hideLoader } = mixin; const { date2Thai, messageError, onSearchDataTable } = mixin;
const RestData = useRestDataStore(); const RestData = useRestDataStore();
const { statusText } = RestData; //Func status to text const { statusText } = RestData; //Func status to text
const isLoad = ref<boolean>(false);
const rows = ref<MainList[]>([]); const rows = ref<MainList[]>([]);
const rowsData = ref<MainList[]>([]);
const filter = ref<string>(""); const filter = ref<string>("");
const pagination = ref({ const pagination = ref({
sortBy: "desc", sortBy: "desc",
@ -91,11 +93,12 @@ const columns = ref<QTableProps["columns"]>([
/** ดึงข้อมูล */ /** ดึงข้อมูล */
async function fectListleave() { async function fectListleave() {
isLoad.value = true;
await http await http
.get(config.API.listUserByType(link.value)) .get(config.API.listUserByType(link.value))
.then(async (res) => { .then(async (res) => {
let data = await res.data.result; let data = await res.data.result;
rows.value = data.map((e: MainListResponse) => ({ const list = data.map((e: MainListResponse) => ({
id: e.id, id: e.id,
placeLeave: e.location, placeLeave: e.location,
dateStartLeave: date2Thai(e.sendDate), dateStartLeave: date2Thai(e.sendDate),
@ -103,9 +106,13 @@ async function fectListleave() {
status: e.status, status: e.status,
statustext: statusText(e.status), statustext: statusText(e.status),
})); }));
rowsData.value = list;
rows.value = list;
isLoad.value = false;
}) })
.catch((e: any) => { .catch((e: any) => {
messageError($q, e); messageError($q, e);
isLoad.value = false;
}) })
.finally(() => {}); .finally(() => {});
} }
@ -117,10 +124,13 @@ async function clickAdd() {
router.push(`/retire/add`); router.push(`/retire/add`);
} }
/** ทำก่อน mounted */ function onSearch() {
onBeforeMount(() => { rows.value = onSearchDataTable(
showLoader(); filter.value,
}); rowsData.value,
columns.value ? columns.value : []
);
}
/** /**
* เรยกฟงกนทงหมดตอนเรยกใชไฟล * เรยกฟงกนทงหมดตอนเรยกใชไฟล
@ -128,7 +138,6 @@ onBeforeMount(() => {
onMounted(async () => { onMounted(async () => {
link.value = await dataStore.getProFileType(); link.value = await dataStore.getProFileType();
await fectListleave(); await fectListleave();
hideLoader();
}); });
</script> </script>
<template> <template>
@ -161,15 +170,10 @@ onMounted(async () => {
debounce="300" debounce="300"
placeholder="ค้นหา" placeholder="ค้นหา"
style="max-width: 200px" style="max-width: 200px"
@keydown.enter.prevent="onSearch"
> >
<template v-slot:append> <template v-slot:append>
<q-icon v-if="filter == ''" name="search" /> <q-icon name="search" />
<q-icon
v-if="filter !== ''"
name="clear"
class="cursor-pointer"
@click="filter = ''"
/>
</template> </template>
</q-input> </q-input>
<!-- แสดงคอลมนใน table --> <!-- แสดงคอลมนใน table -->
@ -193,7 +197,7 @@ onMounted(async () => {
</div> </div>
<div> <div>
<d-table <d-table
flat fla
bordered bordered
dense dense
row-key="id" row-key="id"
@ -202,20 +206,8 @@ onMounted(async () => {
:visible-columns="visibleColumns" :visible-columns="visibleColumns"
:rows-per-page-options="[10, 25, 50, 100]" :rows-per-page-options="[10, 25, 50, 100]"
v-model:pagination="pagination" v-model:pagination="pagination"
:loading="isLoad"
> >
<template v-slot:pagination="scope">
งหมด {{ rows.length }} รายการ
<q-pagination
v-model="pagination.page"
active-color="primary"
color="dark"
:max="scope.pagesNumber"
:max-pages="5"
size="sm"
boundary-links
direction-links
></q-pagination>
</template>
<template v-slot:header="props"> <template v-slot:header="props">
<q-tr :props="props"> <q-tr :props="props">
<q-th <q-th

View file

@ -176,8 +176,7 @@ function saveForm() {
suggestFriendsReason.value == "")) || suggestFriendsReason.value == "")) ||
futureWork.value.length === 0 || futureWork.value.length === 0 ||
(futureWork.value === 1 && (futureWork.value === 1 &&
(futureWorkReason.value == null || futureWorkReason.value == "")) || (futureWorkReason.value == null || futureWorkReason.value == ""))
suggestion.value.length < 1
) { ) {
hasError = true; hasError = true;
} else { } else {

View file

@ -6,6 +6,7 @@ import http from "@/plugins/http";
import config from "@/app.config"; import config from "@/app.config";
import { tokenParsed } from "@/plugins/auth"; import { tokenParsed } from "@/plugins/auth";
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
import { useLeaveStore } from "@/modules/05_leave/store";
import FullCalendar from "@fullcalendar/vue3"; import FullCalendar from "@fullcalendar/vue3";
import dayGridPlugin from "@fullcalendar/daygrid"; import dayGridPlugin from "@fullcalendar/daygrid";
@ -23,8 +24,9 @@ import type {
import DialogDetail from "@/modules/05_leave/components/DialogDetail.vue"; import DialogDetail from "@/modules/05_leave/components/DialogDetail.vue";
const $q = useQuasar(); const $q = useQuasar();
const store = useLeaveStore();
const mixin = useCounterMixin(); const mixin = useCounterMixin();
const { showLoader, hideLoader, messageError, monthYear2Thai } = mixin; const { messageError, monthYear2Thai } = mixin;
const emit = defineEmits(["update:dateYear"]); const emit = defineEmits(["update:dateYear"]);
const mainData = ref<DataCalendar[]>([]); const mainData = ref<DataCalendar[]>([]);
@ -35,10 +37,10 @@ const leaveId = ref<string>("");
/** filter calendar left */ /** filter calendar left */
const filterLists = ref<any>([]); const filterLists = ref<any>([]);
const filterVal = ref<any>([keycloakId.value]); const filterVal = ref<any>([keycloakId.value]);
const isLoading = ref<boolean>(false);
const isLoadingHoliday = ref<boolean>(false);
/** /** Option ของปฏิทิน */
* Option ของปฏ
*/
const fullCalendar = ref<any>(); //ref calendar const fullCalendar = ref<any>(); //ref calendar
const calendarOptions = ref<any>({ const calendarOptions = ref<any>({
plugins: [ plugins: [
@ -74,7 +76,7 @@ const dateMonth = ref<DataDateMonthObject>({
/** function เรียกข้อมูล calendar*/ /** function เรียกข้อมูล calendar*/
async function fetchDataCalendar() { async function fetchDataCalendar() {
showLoader(); isLoading.value = true;
await http await http
.post(config.API.leaveCalendar(), { .post(config.API.leaveCalendar(), {
year: dateMonth.value.year, year: dateMonth.value.year,
@ -120,7 +122,7 @@ async function fetchDataCalendar() {
messageError($q, err); messageError($q, err);
}) })
.finally(() => { .finally(() => {
hideLoader(); isLoading.value = false;
}); });
} }
@ -128,7 +130,7 @@ async function fetchDataCalendar() {
* fetch นหยดในปฏ * fetch นหยดในปฏ
*/ */
async function fetchData() { async function fetchData() {
showLoader(); isLoadingHoliday.value = true;
await http await http
.get( .get(
config.API.listHolidayHistoryYearMonth( config.API.listHolidayHistoryYearMonth(
@ -138,7 +140,6 @@ async function fetchData() {
) )
.then((res) => { .then((res) => {
const dataNormal = res.data.result.normal; const dataNormal = res.data.result.normal;
const dataSixDays = res.data.result.sixDays;
const data = dataNormal; const data = dataNormal;
const event = data.map((e: any) => ({ const event = data.map((e: any) => ({
id: e.id, id: e.id,
@ -155,23 +156,12 @@ async function fetchData() {
...calendarOptions.value.events, ...calendarOptions.value.events,
...event, ...event,
]; ];
// const dataSix = dataSixDays
// const eventSix = dataSix.map((e: any) => ({
// id: e.id,
// title: `${e.name} `,
// start: e.holidayDate,
// end: new Date(new Date(e.holidayDate).setHours(23, 59, 59)).toISOString(),
// allDay: e.holidayDate === e.holidayDate ? true : false,
// color: "#FFE5CC",
// textColor: "#FF8000",
// }))
// calendarOptions.value.events = [...calendarOptions.value.events, ...eventSix]
}) })
.catch((e) => { .catch((e) => {
messageError($q, e); messageError($q, e);
}) })
.finally(async () => { .finally(() => {
hideLoader(); isLoadingHoliday.value = false;
}); });
} }
@ -184,14 +174,11 @@ function convertKeycloakId(id: any) {
/** function เรียกประเภทการลา */ /** function เรียกประเภทการลา */
const leaveType = ref<LeaveType[]>([]); const leaveType = ref<LeaveType[]>([]);
async function fectOptionType() { async function fectOptionType() {
await http const data = await store.fetchLeaveTypeData();
.get(config.API.leaveType()) if (!data) {
.then(async (res) => { return;
leaveType.value = res.data.result; }
}) leaveType.value = data;
.catch((err) => {
messageError($q, err);
});
} }
/** /**
@ -205,11 +192,16 @@ function monthYearThai(val: DataDateMonthObject) {
/** function อัปเดท Calendar */ /** function อัปเดท Calendar */
async function updateMonth() { async function updateMonth() {
await fetchDataCalendar(); try {
await fetchData(); await fetchDataCalendar();
const calen = fullCalendar.value.getApi(); await fetchData();
const date = new Date(dateMonth.value.year, dateMonth.value.month); const calen = fullCalendar.value.getApi();
calen.gotoDate(date); const date = new Date(dateMonth.value.year, dateMonth.value.month);
calen.gotoDate(date);
} catch (error) {
messageError($q, error);
} finally {
}
} }
/** /**
@ -226,7 +218,7 @@ async function onClickClose() {
modal.value = false; modal.value = false;
} }
/**** ตรวจสอบว่ามีการส่งข้อมูลเข้ามาที่Calendar */ /** ตรวจสอบว่ามีการส่งข้อมูลเข้ามาที่Calendar */
watch( watch(
() => filterVal.value, () => filterVal.value,
async () => { async () => {
@ -255,20 +247,39 @@ watch(
/**Hook */ /**Hook */
onMounted(async () => { onMounted(async () => {
const user = await tokenParsed(); try {
keycloakId.value = await (user ? user.sub : ""); isLoading.value = true;
filterVal.value.push(keycloakId.value); // keycloakId
await fetchDataCalendar(); const user = await tokenParsed();
await fetchData(); keycloakId.value = await (user ? user.sub : "");
await fectOptionType(); filterVal.value.push(keycloakId.value);
await Promise.all([fetchDataCalendar(), fectOptionType()]);
await fetchData();
} catch (error) {
messageError($q, error);
} finally {
isLoading.value = false;
}
}); });
</script> </script>
<template> <template>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-3 q-mt-sm q-pr-sm row"> <div class="col-xs-12 col-md-3 q-mt-sm q-pr-sm row">
<q-card class="col-12" flat bordered > <q-card class="col-12" flat bordered>
<q-scroll-area style="height: 38vw"> <q-card-section v-if="isLoading">
<q-item>
<q-item-section avatar>
<q-skeleton type="QToggle" height="20px" width="25px" />
</q-item-section>
<q-item-section>
<q-skeleton type="text" class="text-subtitle1" />
</q-item-section>
</q-item>
</q-card-section>
<q-scroll-area style="height: 38vw" v-else>
<div class="q-gutter-sm col-12"> <div class="q-gutter-sm col-12">
<q-list class="rounded-borders q-pt-sm" dense> <q-list class="rounded-borders q-pt-sm" dense>
<q-item <q-item
@ -339,7 +350,13 @@ onMounted(async () => {
</q-card> </q-card>
<div class="main-content"> <div class="main-content">
<q-skeleton
height="100%"
square
v-if="isLoading || isLoadingHoliday"
/>
<FullCalendar <FullCalendar
v-else
ref="fullCalendar" ref="fullCalendar"
class="demo-app-calendar" class="demo-app-calendar"
:options="calendarOptions" :options="calendarOptions"

View file

@ -140,6 +140,8 @@ const formData = reactive<FremDetail>({
approveStep: "", approveStep: "",
dear: "", dear: "",
leaveRange: "", leaveRange: "",
leaveRangeEnd: "",
leaveSubTypeName: "",
}); });
/** Form รายละเอียดข้อมูล*/ /** Form รายละเอียดข้อมูล*/
@ -154,10 +156,15 @@ const formDataCancle = reactive<FromCancelDetail>({
leaveAddress: "", leaveAddress: "",
leaveNumber: "", leaveNumber: "",
leaveDetail: "", leaveDetail: "",
leaveSubTypeName: "",
leaveTotal: 0, leaveTotal: 0,
leaveStartDate: new Date(), leaveDateStart: new Date(),
leaveEndDate: new Date(), leaveDateEnd: new Date(),
leaveRange: "",
leaveRangeEnd: "",
leaveDirectorComment: "",
}); });
const isLoading = ref<boolean>(false);
/** form ขอยกเลิก*/ /** form ขอยกเลิก*/
const formDelete = reactive<FormDelete>({ const formDelete = reactive<FormDelete>({
@ -181,7 +188,7 @@ const formDeleteRef: FormDeleteRef = {
* @param id การลา * @param id การลา
*/ */
async function fetchDataDetail(id: string) { async function fetchDataDetail(id: string) {
showLoader(); isLoading.value = true;
await http await http
.get(config.API.leaveUserId(id), {}) .get(config.API.leaveUserId(id), {})
.then((res) => { .then((res) => {
@ -205,9 +212,11 @@ async function fetchDataDetail(id: string) {
formData.leaveAddress = data.leaveAddress ?? "-"; formData.leaveAddress = data.leaveAddress ?? "-";
formData.leaveNumber = data.leaveNumber ?? "-"; formData.leaveNumber = data.leaveNumber ?? "-";
formData.leaveDetail = data.leaveDetail ?? "-"; formData.leaveDetail = data.leaveDetail ?? "-";
formData.leaveSubTypeName = data.leaveSubTypeName ?? null;
formData.leaveDocument = data.leaveDocument; formData.leaveDocument = data.leaveDocument;
formData.leaveDraftDocument = data.leaveDraftDocument; formData.leaveDraftDocument = data.leaveDraftDocument;
formData.leaveRange = data.leaveRange; formData.leaveRange = data.leaveRange;
formData.leaveRangeEnd = data.leaveRangeEnd;
formData.leaveLastStart = formData.leaveLastStart =
data.leaveLastStart && date2Thai(data.leaveLastStart); data.leaveLastStart && date2Thai(data.leaveLastStart);
formData.leaveLastEnd = formData.leaveLastEnd =
@ -226,7 +235,7 @@ async function fetchDataDetail(id: string) {
data.wifeDayDateBorn && date2Thai(data.wifeDayDateBorn); data.wifeDayDateBorn && date2Thai(data.wifeDayDateBorn);
formData.restDayOldTotal = data.restDayOldTotal ?? "-"; formData.restDayOldTotal = data.restDayOldTotal ?? "-";
formData.restDayCurrentTotal = data.restDayCurrentTotal ?? "-"; formData.restDayCurrentTotal = data.restDayCurrentTotal ?? "-";
formData.ordainDayStatus = data.ordainDayStatus ? "เคย" : "ไม่เคยบวช"; formData.ordainDayStatus = data.ordainDayStatus;
formData.ordainDayLocationName = data.ordainDayLocationName ?? "-"; formData.ordainDayLocationName = data.ordainDayLocationName ?? "-";
formData.ordainDayLocationAddress = data.ordainDayLocationAddress ?? "-"; formData.ordainDayLocationAddress = data.ordainDayLocationAddress ?? "-";
formData.ordainDayLocationNumber = data.ordainDayLocationNumber ?? "-"; formData.ordainDayLocationNumber = data.ordainDayLocationNumber ?? "-";
@ -236,9 +245,7 @@ async function fetchDataDetail(id: string) {
data.ordainDayBuddhistLentName ?? "-"; data.ordainDayBuddhistLentName ?? "-";
formData.ordainDayBuddhistLentAddress = formData.ordainDayBuddhistLentAddress =
data.ordainDayBuddhistLentAddress ?? "-"; data.ordainDayBuddhistLentAddress ?? "-";
formData.hajjDayStatus = data.hajjDayStatus formData.hajjDayStatus = data.hajjDayStatus;
? "เคย"
: "ไม่เคยไปประกอบพิธีฮัจญ์";
formData.absentDaySummon = data.absentDaySummon ?? "-"; formData.absentDaySummon = data.absentDaySummon ?? "-";
formData.absentDayLocation = data.absentDayLocation ?? "-"; formData.absentDayLocation = data.absentDayLocation ?? "-";
formData.absentDayRegistorDate = formData.absentDayRegistorDate =
@ -267,18 +274,14 @@ async function fetchDataDetail(id: string) {
formData.coupleDaySumTotalHistory = data.coupleDaySumTotalHistory ?? "-"; formData.coupleDaySumTotalHistory = data.coupleDaySumTotalHistory ?? "-";
formData.approveStep = data.approveStep ?? "-"; formData.approveStep = data.approveStep ?? "-";
formData.dear = data.dear ?? "-"; formData.dear = data.dear ?? "-";
checkLeaveType( checkLeaveType(formData.leaveTypeId);
formData.leaveTypeId,
formData.ordainDayLocationName,
formData.studyDayTrainingSubject
);
}) })
.catch((err) => { .catch((err) => {
props.onClickClose?.(); props.onClickClose?.();
messageError($q, err); messageError($q, err);
}) })
.finally(() => { .finally(() => {
hideLoader(); isLoading.value = false;
}); });
} }
@ -287,11 +290,7 @@ async function fetchDataDetail(id: string) {
* @param leaveTypeId ประเภทการลา * @param leaveTypeId ประเภทการลา
* @param leaveTypeName ประเภทการลา * @param leaveTypeName ประเภทการลา
*/ */
function checkLeaveType( function checkLeaveType(leaveTypeId: string) {
leaveTypeId: string,
ordainDayLocationName: string,
studyDayTrainingSubject: string
) {
if (props.leaveType) { if (props.leaveType) {
const filtertype = props.leaveType.find((e: any) => e.id === leaveTypeId); const filtertype = props.leaveType.find((e: any) => e.id === leaveTypeId);
const type = filtertype.code; const type = filtertype.code;
@ -301,15 +300,22 @@ function checkLeaveType(
checkForm.value = "FormChildbirth"; checkForm.value = "FormChildbirth";
} else if (type === "LV-005") { } else if (type === "LV-005") {
checkForm.value = "FormHoliday"; checkForm.value = "FormHoliday";
} else if (type === "LV-006" && ordainDayLocationName === "") { } else if (type === "LV-006" && formData.leaveSubTypeName === "ลาอุปสมบท") {
checkForm.value = "FormHajj";
} else if (type === "LV-006") {
checkForm.value = "FormUpasom"; checkForm.value = "FormUpasom";
} else if (
type === "LV-006" &&
formData.leaveSubTypeName === "ลาประกอบพิธีฮัจญ์"
) {
checkForm.value = "FormHajj";
} else if (type === "LV-007") { } else if (type === "LV-007") {
checkForm.value = "FormCheckSelect"; checkForm.value = "FormCheckSelect";
} else if (type === "LV-008" && studyDayTrainingSubject === "") { } else if (type === "LV-008" && formData.leaveSubTypeName === "ศึกษาต่อ") {
checkForm.value = "FormStudy"; checkForm.value = "FormStudy";
} else if (type === "LV-008") { } else if (
(type === "LV-008" && formData.leaveSubTypeName === "ฝึกอบรม") ||
(type === "LV-008" && formData.leaveSubTypeName === "ปฎิบัติการวิจัย") ||
(type === "LV-008" && formData.leaveSubTypeName === "ดูงาน")
) {
checkForm.value = "FormLeaveToTraining"; checkForm.value = "FormLeaveToTraining";
} else if (type === "LV-009") { } else if (type === "LV-009") {
checkForm.value = "FormLeaveToWorkInternational"; checkForm.value = "FormLeaveToWorkInternational";
@ -326,7 +332,7 @@ function checkLeaveType(
* @param id ยกเลกการลา * @param id ยกเลกการลา
*/ */
async function fetchDataCancelDetail(id: string) { async function fetchDataCancelDetail(id: string) {
showLoader(); isLoading.value = true;
await http await http
.get(config.API.leaveCancelById(id)) .get(config.API.leaveCancelById(id))
.then((res) => { .then((res) => {
@ -335,22 +341,26 @@ async function fetchDataCancelDetail(id: string) {
formDataCancle.leaveWrote = data.leaveWrote ?? "-"; formDataCancle.leaveWrote = data.leaveWrote ?? "-";
formDataCancle.fullname = data.fullName ?? "-"; formDataCancle.fullname = data.fullName ?? "-";
formDataCancle.status = convertStatud(data.status) ?? "-"; formDataCancle.status = convertStatud(data.status) ?? "-";
formDataCancle.leaveStartDate = formDataCancle.leaveDateStart =
data.leaveStartDate && date2Thai(data.leaveStartDate); data.leaveStartDate && date2Thai(data.leaveStartDate);
formDataCancle.leaveEndDate = formDataCancle.leaveDateEnd =
data.leaveEndDate && date2Thai(data.leaveEndDate); data.leaveEndDate && date2Thai(data.leaveEndDate);
formDataCancle.leaveTotal = data.leaveTotal ?? "-"; formDataCancle.leaveTotal = data.leaveTotal ?? "-";
formDataCancle.leaveAddress = data.leaveAddress ?? "-"; formDataCancle.leaveAddress = data.leaveAddress ?? "-";
formDataCancle.leaveNumber = data.leaveNumber ?? "-"; formDataCancle.leaveNumber = data.leaveNumber ?? "-";
formDataCancle.leaveResonDelete = data.leaveReasonDelete ?? "-"; formDataCancle.leaveResonDelete = data.leaveReasonDelete ?? "-";
formDataCancle.leaveDetail = data.leaveDetail ?? "-"; formDataCancle.leaveDetail = data.leaveDetail ?? "-";
formDataCancle.leaveSubTypeName = data.leaveSubTypeName ?? null;
formDataCancle.leaveDocDelete = data.leaveDocDelete ?? null; formDataCancle.leaveDocDelete = data.leaveDocDelete ?? null;
formDataCancle.leaveRange = data.leaveRange;
formDataCancle.leaveRangeEnd = data.leaveRangeEnd;
formDataCancle.leaveDirectorComment = data.leaveDirectorComment;
}) })
.catch((err) => { .catch((err) => {
messageError($q, err); messageError($q, err);
}) })
.finally(() => { .finally(() => {
hideLoader(); isLoading.value = false;
}); });
} }
@ -389,7 +399,8 @@ async function onSubmit() {
formData.append("doc", formDelete.doc); formData.append("doc", formDelete.doc);
await http await http
.post(config.API.leaveCancelById(id), formData) .post(config.API.leaveCancelById(id), formData)
.then(() => { .then(async () => {
await props.fetchDataTable?.();
success($q, "บันทึกข้อมูลสำเร็จ"); success($q, "บันทึกข้อมูลสำเร็จ");
props.onClickClose?.(); props.onClickClose?.();
}) })
@ -397,7 +408,6 @@ async function onSubmit() {
messageError($q, err); messageError($q, err);
}) })
.finally(() => { .finally(() => {
props.fetchDataTable?.();
hideLoader(); hideLoader();
}); });
} }
@ -431,8 +441,13 @@ watch(
/> />
<q-separator /> <q-separator />
<q-card-section v-if="isLoading">
<div v-for="i in 10" :key="i">
<q-skeleton type="text" class="text-subtitle1" />
</div>
</q-card-section>
<q-card-section> <q-card-section v-else class="scroll" style="max-height: 60vh">
<div class="row"> <div class="row">
<div <div
flat flat
@ -498,7 +513,7 @@ watch(
/> />
<!-- าราชการแสดงเฉพาะทนใบลาไปแลวเทาน กจางไม workflow --> <!-- าราชการแสดงเฉพาะทนใบลาไปแลวเทาน กจางไม workflow -->
<Workflow <!-- <Workflow
v-if="leaveStatus != 'DRAFT'" v-if="leaveStatus != 'DRAFT'"
:id="props.leaveId" :id="props.leaveId"
:sys-name=" :sys-name="
@ -506,7 +521,7 @@ watch(
? 'SYS_LEAVE_LIST' ? 'SYS_LEAVE_LIST'
: 'SYS_LEAVE_LIST_EMP' : 'SYS_LEAVE_LIST_EMP'
" "
/> /> -->
</div> </div>
<div <div
@ -559,23 +574,25 @@ watch(
label="ยืนยัน" label="ยืนยัน"
unelevated unelevated
color="secondary" color="secondary"
:loading="isLoading"
@click="onClickSave" @click="onClickSave"
/> />
</q-card-section> </q-card-section>
</q-card> </q-card>
<q-card <q-card v-if="props.leaveStatus === 'DELETE'" style="min-width: 40vw">
q-card
v-if="props.leaveStatus === 'DELETE'"
style="min-width: 40vw"
>
<DialogHeader <DialogHeader
:tittle="`${titleMainCancle} ${titleName}`" :tittle="`${titleMainCancle} ${titleName}`"
:close="props.onClickClose" :close="props.onClickClose"
/> />
<q-separator /> <q-separator />
<q-card-section class="q-p-md row q-gutter-y-md"> <q-card-section v-if="isLoading">
<div v-for="i in 10" :key="i">
<q-skeleton type="text" class="text-subtitle1" />
</div>
</q-card-section>
<q-card-section class="q-p-md row q-gutter-y-md" v-else>
<div flat class="col-12"> <div flat class="col-12">
<div class="col-12 q-col-gutter-sm row items-center"></div> <div class="col-12 q-col-gutter-sm row items-center"></div>
<FormCancel :data="formDataCancle" /> <FormCancel :data="formDataCancle" />

View file

@ -15,7 +15,7 @@ const typeForm = defineModel<string>("type", { required: true });
const $q = useQuasar(); const $q = useQuasar();
const dataStore = useLeaveStore(); const dataStore = useLeaveStore();
const mixin = useCounterMixin(); const mixin = useCounterMixin();
const { date2Thai, dateToISO, messageError } = mixin; const { date2Thai, messageError, convertDateToAPI } = mixin;
const edit = ref<boolean>(true); const edit = ref<boolean>(true);
const leaveDocumentRef = ref<any>(null); const leaveDocumentRef = ref<any>(null);
@ -46,10 +46,9 @@ const formDataSick = reactive<any>({
leaveStartDate: null, leaveStartDate: null,
leaveEndDate: null, leaveEndDate: null,
leaveRange: "ALL", leaveRange: "ALL",
leaveRangeEnd: "ALL",
leaveTotal: "", leaveTotal: "",
leaveLast: null, leaveLast: null,
leaveNumber: "",
leaveAddress: "",
leaveDetail: "", leaveDetail: "",
leaveDocument: [], leaveDocument: [],
}); });
@ -66,6 +65,8 @@ const leaveNumberRef = ref<object | null>(null);
const leaveAddressRef = ref<object | null>(null); const leaveAddressRef = ref<object | null>(null);
const leaveDetailRef = ref<object | null>(null); const leaveDetailRef = ref<object | null>(null);
const isLoadLeaveDate = ref<boolean>(false);
/** maping ref เข้าตัวแปรเพื่อเตรียมตรวจสอบ */ /** maping ref เข้าตัวแปรเพื่อเตรียมตรวจสอบ */
const FormRef: FormRef = { const FormRef: FormRef = {
leaveWrote: leaveWroteRef, leaveWrote: leaveWroteRef,
@ -87,19 +88,6 @@ async function fileUploadDoc(files: any) {
}); });
} }
/**
* function เซทค leaveStartDate เเละ leaveEndDate
*/
function resetDate() {
if (
formDataSick.leaveRange === "MORNING" ||
formDataSick.leaveRange === "AFTERNOON"
) {
formDataSick.leaveStartDate = null;
formDataSick.leaveEndDate = null;
}
}
/** ฟังก์ชั่นตรวจสอบความถูกต้องของข้อมูลในฟอร์ม */ /** ฟังก์ชั่นตรวจสอบความถูกต้องของข้อมูลในฟอร์ม */
function onValidate() { function onValidate() {
const hasError = []; const hasError = [];
@ -123,17 +111,18 @@ function onValidate() {
formData.append("type", formDataSick.type); formData.append("type", formDataSick.type);
formData.append("leaveRange", formDataSick.leaveRange); formData.append("leaveRange", formDataSick.leaveRange);
formData.append("leaveRangeEnd", formDataSick.leaveRangeEnd);
formData.append( formData.append(
"leaveStartDate", "leaveStartDate",
dateToISO(new Date(formDataSick.leaveStartDate)) convertDateToAPI(formDataSick.leaveStartDate) ?? ""
); );
formData.append( formData.append(
"leaveEndDate", "leaveEndDate",
dateToISO(new Date(formDataSick.leaveEndDate)) convertDateToAPI(formDataSick.leaveEndDate) ?? ""
); );
formData.append("leaveWrote", formDataSick.leaveWrote); formData.append("leaveWrote", formDataSick.leaveWrote);
formData.append("leaveAddress", formDataSick.leaveAddress); formData.append("leaveAddress", dataStore.currentAddress);
formData.append("leaveNumber", formDataSick.leaveNumber); formData.append("leaveNumber", dataStore.telephoneNumber);
formData.append("leaveDetail", formDataSick.leaveDetail); formData.append("leaveDetail", formDataSick.leaveDetail);
formData.append("leaveTotal", formDataSick.leaveTotal); formData.append("leaveTotal", formDataSick.leaveTotal);
props.onSubmit(formData, isLeave.value); props.onSubmit(formData, isLeave.value);
@ -146,55 +135,55 @@ function onValidate() {
*/ */
const isLeave = ref<boolean>(true); const isLeave = ref<boolean>(true);
const reasonLeave = ref<string>(""); const reasonLeave = ref<string>("");
async function fetchCheck() {
await http
.post(config.API.leaveCheck(), {
type: dataStore.typeId ?? null,
StartLeaveDate: formDataSick.leaveStartDate ?? null,
EndLeaveDate: formDataSick.leaveEndDate ?? null,
})
.then((res: any) => {
const data = res.data.result;
formDataSick.leaveTotal =
data.totalDate - data.sumDateWork - data.sumDateHoliday;
isLeave.value = data.isLeave;
reasonLeave.value = data.message
? data.message
: "จำนวนวันลาเกินที่กำหนด";
})
.catch((e: any) => {
messageError($q, e);
})
.finally(() => {
leaveDocumentRef.value.resetValidation();
});
}
/** const checkDate = computed(() => {
* งกนแปลงครงว/งว if (
*/ convertDateToAPI(formDataSick.leaveStartDate) ==
const isReadOnly = computed(() => { convertDateToAPI(formDataSick.leaveEndDate)
const conditionleaveRange = ) {
formDataSick.leaveRange === "MORNING" || return true;
formDataSick.leaveRange === "AFTERNOON";
if (conditionleaveRange) {
formDataSick.leaveEndDate = formDataSick.leaveStartDate; // Set formDataSick.leaveEndDate to null
formDataSick.leaveTotal = 0.5;
} else { } else {
formDataSick.leaveTotal = null; return false;
} }
return conditionleaveRange;
}); });
/** // const totalCheck = ref<number | null>(null);
* แกไขClassเม status เป edit async function fetchCheck() {
* @param val status edit true/false if (formDataSick.leaveStartDate && formDataSick.leaveEndDate) {
*/ isLoadLeaveDate.value = true;
function inputEdit(val: boolean) { await http
return { .post(config.API.leaveCheck(), {
"full-width cursor-pointer ": val, type: dataStore.typeId ?? null,
"full-width cursor-pointer inputgreen": !val, StartLeaveDate: convertDateToAPI(formDataSick.leaveStartDate) ?? null,
}; EndLeaveDate: convertDateToAPI(formDataSick.leaveEndDate) ?? null,
leaveRange: formDataSick.leaveRange,
leaveRangeEnd: checkDate.value
? formDataSick.leaveRange
: formDataSick.leaveRangeEnd,
})
.then((res: any) => {
const data = res.data.result;
formDataSick.leaveTotal =
data.totalDate - data.sumDateWork - data.sumDateHoliday;
// totalCheck.value =
// data.totalDate - data.sumDateWork - data.sumDateHoliday;
reasonLeave.value =
data.message != ""
? data.message
: formDataSick.leaveTotal > 0
? "จำนวนวันลาเกินที่กำหนด"
: "ช่วงวันลาที่ระบุไม่ถูกต้อง";
isLeave.value = formDataSick.leaveTotal > 0 ? data.isLeave : false;
})
.catch((e: any) => {
messageError($q, e);
// totalCheck.value = null;
})
.finally(() => {
leaveDocumentRef.value.resetValidation();
isLoadLeaveDate.value = false;
});
}
} }
/** แจ้งเมื่อวันลาไม่ถูกต้อง */ /** แจ้งเมื่อวันลาไม่ถูกต้อง */
@ -205,36 +194,39 @@ const dateEndInputStyle = computed(() => {
const leaveId = ref<any>(""); const leaveId = ref<any>("");
/** ตรวจสอบว่ามีการส่งข้อมูลเข้ามาที่ฟอร์มไหม เมื่อมีการส่งจะ map ข้อมูลเข้า v-model ของฟอร์ม */ /** ตรวจสอบว่ามีการส่งข้อมูลเข้ามาที่ฟอร์มไหม เมื่อมีการส่งจะ map ข้อมูลเข้า v-model ของฟอร์ม */
const statusCheck = ref<any>(""); const statusCheck = ref<any>("");
watch(props.data, () => { watch(
if (props.data) { () => props.data,
formDataSick.leaveWrote = props.data.leaveWrote; () => {
formDataSick.leaveStartDate = new Date(props.data.leaveStartDate); if (props.data) {
formDataSick.leaveEndDate = new Date(props.data.leaveEndDate); // totalCheck.value = null;
formDataSick.contractTel = props.data.contractTel; formDataSick.leaveWrote = props.data.leaveWrote;
formDataSick.leaveTotal = props.data.leaveTotal; formDataSick.leaveStartDate = new Date(props.data.leaveStartDate);
formDataSick.leaveNumber = props.data.leaveNumber; formDataSick.leaveEndDate = new Date(props.data.leaveEndDate);
formDataSick.leaveDetail = props.data.leaveDetail; formDataSick.contractTel = props.data.contractTel;
formDataSick.leaveRange = props.data.leaveRange; formDataSick.leaveTotal = props.data.leaveTotal;
leaveDocumentList.value = props.data.leaveDocument; formDataSick.leaveDetail = props.data.leaveDetail;
formDataSick.leaveAddress = props.data.leaveAddress; formDataSick.leaveRange = props.data.leaveRange;
statusCheck.value = props.data.status; formDataSick.leaveRangeEnd = props.data.leaveRangeEnd;
formDataSick.leaveDocument = []; leaveDocumentList.value = props.data.leaveDocument;
statusCheck.value = props.data.status;
formDataSick.leaveDocument = [];
}
} }
}); );
/** Hook */ /** Hook */
onMounted(() => { onMounted(() => {
if (props.data) { if (props.data) {
// totalCheck.value = null;
formDataSick.leaveWrote = props.data.leaveWrote; formDataSick.leaveWrote = props.data.leaveWrote;
formDataSick.leaveStartDate = new Date(props.data.leaveStartDate); formDataSick.leaveStartDate = new Date(props.data.leaveStartDate);
formDataSick.leaveEndDate = new Date(props.data.leaveEndDate); formDataSick.leaveEndDate = new Date(props.data.leaveEndDate);
formDataSick.contractTel = props.data.contractTel; formDataSick.contractTel = props.data.contractTel;
formDataSick.leaveTotal = props.data.leaveTotal; formDataSick.leaveTotal = props.data.leaveTotal;
formDataSick.leaveNumber = props.data.leaveNumber;
formDataSick.leaveDetail = props.data.leaveDetail; formDataSick.leaveDetail = props.data.leaveDetail;
formDataSick.leaveRange = props.data.leaveRange; formDataSick.leaveRange = props.data.leaveRange;
formDataSick.leaveRangeEnd = props.data.leaveRangeEnd;
leaveDocumentList.value = props.data.leaveDocument; leaveDocumentList.value = props.data.leaveDocument;
formDataSick.leaveAddress = props.data.leaveAddress;
statusCheck.value = props.data.status; statusCheck.value = props.data.status;
leaveId.value = props.data.id; leaveId.value = props.data.id;
} }
@ -249,253 +241,296 @@ onMounted(() => {
</div> </div>
<q-form greedy @submit.prevent @validation-success="onValidate"> <q-form greedy @submit.prevent @validation-success="onValidate">
<q-card bordered class="q-pa-md bg-grey-1"> <q-card bordered class="q-pa-md bg-grey-1">
<div class="col-12 row q-pa-sm q-col-gutter-sm"> <div class="row q-col-gutter-sm">
<q-input <div class="col-12 col-sm-12 inputgreen">
class="col-12 col-sm-12 cursor-pointer inputgreen" <q-input
ref="leaveWroteRef" ref="leaveWroteRef"
for="leaveWroteRef" for="leaveWroteRef"
dense dense
hide-bottom-space hide-bottom-space
bg-color="white" bg-color="white"
outlined outlined
v-model="formDataSick.leaveWrote" v-model="formDataSick.leaveWrote"
label="เขียนที่" label="เขียนที่"
:readonly="!edit || statusCheck === 'NEW'" :readonly="!edit || statusCheck === 'NEW'"
:rules="[(val:string) => !!val || `${'เขียนที่'}`]" :rules="[(val:string) => !!val || `${'เขียนที่'}`]"
/>
<div class="col-12 col-md-4 col-sm-12">
<q-radio
v-model="formDataSick.leaveRange"
:disable="!edit || statusCheck === 'NEW'"
val="ALL"
label="ลาทั้งวัน"
checked-icon="task_alt"
/>
<q-radio
v-model="formDataSick.leaveRange"
:disable="!edit || statusCheck === 'NEW'"
val="MORNING"
label="ลาครึ่งวันเช้า"
checked-icon="task_alt"
@update:model-value="resetDate"
/>
<q-radio
v-model="formDataSick.leaveRange"
:disable="!edit || statusCheck === 'NEW'"
val="AFTERNOON"
label="ลาครึ่งวันบ่าย"
checked-icon="task_alt"
@update:model-value="resetDate"
/> />
</div> </div>
<div class="full-width">
<div class="q-col-gutter-sm row">
<datepicker
class="col-12 col-md-3 col-sm-6"
menu-class-name="modalfix"
v-model="formDataSick.leaveStartDate"
:locale="'th'"
autoApply
borderless
:enableTimePicker="false"
week-start="0"
:readonly="!edit || statusCheck === 'NEW'"
@update:model-value="formDataSick.leaveEndDate = null"
>
<template #year="{ year }">
{{ year + 543 }}
</template>
<template #year-overlay-value="{ value }">
{{ parseInt(value + 543) }}
</template>
<template #trigger>
<q-input
outlined
dense
ref="leaveStartDateRef"
for="leaveStartDateRef"
hide-bottom-space
:readonly="!edit || statusCheck === 'NEW'"
bg-color="white"
class="full-width cursor-pointer inputgreen"
:model-value="
formDataSick.leaveStartDate != null
? date2Thai(formDataSick.leaveStartDate)
: null
"
:label="`${'ลาตั้งแต่วันที่'}`"
:rules="[(val:string) => !!val || `${'กรุณาเลือกลาตั้งแต่วันที่'}`]"
style="color: var(--q-primary)"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
style="color: var(--q-primary)"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
<datepicker <div class="col-12">
class="col-12 col-md-3 col-sm-6" <div class="row q-col-gutter-sm">
menu-class-name="modalfix" <div class="col-12 col-md-3 col-sm-6 inputgreen">
v-model="formDataSick.leaveEndDate" <datepicker
:locale="'th'" v-model="formDataSick.leaveStartDate"
autoApply :locale="'th'"
borderless autoApply
:enableTimePicker="false" hide-bottom-space
week-start="0" borderless
:readonly="isReadOnly" :enableTimePicker="false"
@update:model-value="fetchCheck()" week-start="0"
:min-date="formDataSick.leaveStartDate" :readonly="!edit || statusCheck === 'NEW'"
> @update:model-value="
<template #year="{ year }"> (formDataSick.leaveEndDate = null), fetchCheck()
{{ year + 543 }} "
</template> >
<template #year-overlay-value="{ value }"> <template #year="{ year }">
{{ parseInt(value + 543) }} {{ year + 543 }}
</template> </template>
<template #trigger> <template #year-overlay-value="{ value }">
<q-input {{ parseInt(value + 543) }}
outlined </template>
dense <template #trigger>
ref="leaveEndDateRef" <q-input
for="leaveEndDateRef" outlined
hide-bottom-space dense
bg-color="white" ref="leaveStartDateRef"
:readonly="isReadOnly" for="leaveStartDateRef"
:class="inputEdit(isReadOnly)" hide-bottom-space
:model-value=" bg-color="white"
formDataSick.leaveEndDate != null :readonly="!edit || statusCheck === 'NEW'"
? date2Thai(formDataSick.leaveEndDate) class="full-width datepicker"
: null :model-value="
" formDataSick.leaveStartDate != null
:label="`${'ลาถึงวันที่'}`" ? date2Thai(formDataSick.leaveStartDate)
> : null
<template v-slot:prepend> "
<q-icon :label="`${'วันที่เริ่มต้น'}`"
name="event" :rules="[(val:string) => !!val || `${'กรุณาเลือกวันที่เริ่มต้น'}`]"
class="cursor-pointer" >
style="color: var(--q-primary)" <template v-slot:prepend>
> <q-icon
</q-icon> name="event"
</template> class="cursor-pointer"
</q-input> style="color: var(--q-primary)"
</template> >
</datepicker> </q-icon>
<q-input </template>
:bottom-slots="!isLeave ? true : false" </q-input>
:color="!isLeave ? 'red' : 'black'" </template>
:bg-color="!isLeave ? 'red-2' : 'white'" </datepicker>
:border-color="!isLeave ? 'red' : 'gray'" </div>
:input-class="!isLeave ? dateEndInputStyle : ''"
class="col-12 col-md-3 col-sm-6"
dense
outlined
ref="leaveTotalRef"
for="leaveTotalRef"
v-model="formDataSick.leaveTotal"
label="จำนวนวันที่ลา"
readonly
>
<template v-slot:hint>
<span style="color: red">
{{ !isLeave ? reasonLeave : "" }}
</span>
</template>
</q-input>
<q-input <div class="col-12 col-md-3 col-sm-6 inputgreen">
class="col-12 col-md-3 col-sm-6" <q-select
dense outlined
outlined dense
ref="leaveLastRef" bg-color="white"
for="leaveLastRef" v-model="formDataSick.leaveRange"
v-model="dataStore.leaveLast" :options="dataStore.rangeOptions"
label="ลาครั้งสุดท้ายเมื่อวันที่" emit-value
readonly map-options
hide-bottom-space option-value="id"
bg-color="white" option-label="name"
/> @update:model-value="fetchCheck()"
>
<template v-slot:prepend>
<q-icon
name="mdi-clock-outline"
style="color: var(--q-primary)"
/>
</template>
</q-select>
</div>
</div> </div>
</div> </div>
<div class="col-12">
<div class="row q-col-gutter-sm">
<div class="col-12 col-md-3 col-sm-6 inputgreen">
<datepicker
v-model="formDataSick.leaveEndDate"
:locale="'th'"
autoApply
hide-bottom-space
@update:model-value="fetchCheck()"
borderless
:enableTimePicker="false"
week-start="0"
:min-date="formDataSick.leaveStartDate"
>
<template #year="{ year }">
{{ year + 543 }}
</template>
<template #year-overlay-value="{ value }">
{{ parseInt(value + 543) }}
</template>
<template #trigger>
<q-input
outlined
dense
ref="leaveEndDateRef"
for="leaveEndDateRef"
hide-bottom-space
bg-color="white"
class="full-width datepicker"
:model-value="
formDataSick.leaveEndDate != null
? date2Thai(formDataSick.leaveEndDate)
: 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 class="col-12 col-md-3 col-sm-6 inputgreen">
<q-select
v-if="!checkDate"
outlined
dense
bg-color="white"
v-model="formDataSick.leaveRangeEnd"
:options="dataStore.rangeOptions.filter((items:any)=> items.id !== 'AFTERNOON')"
emit-value
map-options
option-value="id"
option-label="name"
@update:model-value="fetchCheck()"
>
<template v-slot:prepend>
<q-icon
name="mdi-clock-outline"
style="color: var(--q-primary)"
/>
</template>
</q-select>
</div>
</div>
</div>
<div class="col-12">
<div class="row q-col-gutter-sm">
<div class="col-12 col-md-3 col-sm-6">
<q-input
:bottom-slots="!isLeave ? true : false"
:color="!isLeave ? 'red' : 'black'"
:bg-color="!isLeave ? 'red-2' : 'white'"
:border-color="!isLeave ? 'red' : 'gray'"
:input-class="!isLeave ? dateEndInputStyle : ''"
dense
outlined
ref="leaveTotalRef"
for="leaveTotalRef"
v-model="formDataSick.leaveTotal"
label="จำนวนวันที่ลา (วัน)"
readonly
:loading="isLoadLeaveDate"
>
<template v-slot:hint>
<span style="color: red">
{{ !isLeave ? reasonLeave : "" }}
</span>
</template>
</q-input>
</div>
<div class="col-12 col-md-3 col-sm-6">
<q-input
dense
outlined
ref="leaveLastRef"
for="leaveLastRef"
v-model="dataStore.leaveLast"
label="ลาครั้งสุดท้ายเมื่อวันที่"
readonly
hide-bottom-space
bg-color="white"
/>
</div>
</div>
</div>
<div class="full-width"> <div class="full-width">
<div class="q-col-gutter-sm row"> <div class="q-col-gutter-sm row">
<q-input <div class="col-12 col-md-3 col-sm-12 inputgreen">
class="col-12 col-md-3 col-sm-6 cursor-pointer inputgreen" <q-input
dense dense
outlined outlined
ref="leaveNumberRef" ref="leaveNumberRef"
for="leaveNumberRef" for="leaveNumberRef"
v-model="formDataSick.leaveNumber" v-model="dataStore.telephoneNumber"
mask="(###)-###-####" mask="(###)-###-####"
hide-bottom-space hide-bottom-space
bg-color="white" bg-color="white"
unmasked-value lazy-rules
label="หมายเลขโทรศัพท์ที่ติดต่อได้" unmasked-value
:readonly="!edit || statusCheck === 'NEW'" label="หมายเลขโทรศัพท์ที่ติดต่อได้"
:rules="[ :readonly="!edit || statusCheck === 'NEW'"
:rules="[
(val:string) => !!val || `${'กรุณากรอกหมายเลขโทรศัพท์ที่ติดต่อได้'}`, (val:string) => !!val || `${'กรุณากรอกหมายเลขโทรศัพท์ที่ติดต่อได้'}`,
]" ]"
/> />
</div>
<q-input <div class="col-12 col-md-9 col-sm-12 inputgreen">
class="col-12 col-md-9 col-sm-6 cursor-pointer inputgreen" <q-input
dense dense
outlined outlined
ref="leaveAddressRef" ref="leaveAddressRef"
for="leaveAddressRef" for="leaveAddressRef"
v-model="formDataSick.leaveAddress" v-model="dataStore.currentAddress"
label="ที่อยู่ที่ติดต่อได้ระหว่างลา" label="ที่อยู่ที่ติดต่อได้ระหว่างลา"
:readonly="!edit || statusCheck === 'NEW'" :readonly="!edit || statusCheck === 'NEW'"
:rules="[ :rules="[
(val:string) => !!val || `${'กรุณากรอกที่อยู่ที่ติดต่อได้ระหว่างลา'}`, (val:string) => !!val || `${'กรุณากรอกที่อยู่ที่ติดต่อได้ระหว่างลา'}`,
]" ]"
hide-bottom-space hide-bottom-space
bg-color="white" bg-color="white"
/> />
</div>
</div> </div>
</div> </div>
<q-input
type="textarea" <div class="col-12 inputgreen">
class="col-12 col-md-12 col-sm-12 cursor-pointer inputgreen" <q-input
dense type="textarea"
outlined dense
ref="leaveDetailRef" outlined
for="leaveDetailRef" ref="leaveDetailRef"
v-model="formDataSick.leaveDetail" for="leaveDetailRef"
label="รายละเอียด" v-model="formDataSick.leaveDetail"
:readonly="!edit || statusCheck === 'NEW'" label="สาเหตุการลา"
bg-color="white" :readonly="!edit || statusCheck === 'NEW'"
/> bg-color="white"
/>
</div>
<div class="full-width" v-if="statusCheck != 'NEW'"> <div class="full-width" v-if="statusCheck != 'NEW'">
<div class="q-col-gutter-sm row"> <div class="q-col-gutter-sm row">
<!-- multiple --> <!-- multiple -->
<q-file <div class="col-12 q-pl-sm col-12">
ref="leaveDocumentRef" <q-file
for="leaveDocumentRef" ref="leaveDocumentRef"
v-model="formDataSick.leaveDocument" for="leaveDocumentRef"
dense v-model="formDataSick.leaveDocument"
label="เอกสารประกอบ" dense
outlined label="เอกสารประกอบ"
use-chips outlined
lazy-rules use-chips
multiple lazy-rules
hide-bottom-space multiple
bg-color="white" hide-bottom-space
class="col-12 q-pl-sm col-12" bg-color="white"
:rules="typeForm == 'LV-001' && formDataSick.leaveTotal >= 30 ?[ :rules="typeForm == 'LV-001' && formDataSick.leaveTotal >= 30 ?[
(val:string) => !!val && val.length >= 30 || `${'กรุณาแนบเอกสารประกอบ หรือ ใบรับรองแพทย์ กรณีลาป่วยตั้งเเต่ 30 วันขึ้นไป'}`, (val:string) => !!val && val.length >= 30 || `${'กรุณาแนบเอกสารประกอบ หรือ ใบรับรองแพทย์ กรณีลาป่วยตั้งเเต่ 30 วันขึ้นไป'}`,
]:[]" ]:[]"
> >
<template v-slot:prepend> <template v-slot:prepend>
<q-icon name="attach_file" color="primary" /> <q-icon name="attach_file" color="primary" />
</template> </template>
</q-file> </q-file>
</div>
</div> </div>
</div> </div>
<div class="col-12" v-if="data"> <div class="col-12" v-if="data">
@ -581,15 +616,21 @@ onMounted(() => {
<q-separator class="q-mt-sm" /> <q-separator class="q-mt-sm" />
<q-card-actions align="right" class="bg-white text-teal q-pa-none q-pt-sm"> <q-card-actions align="right" class="bg-white text-teal q-pa-none q-pt-sm">
<!-- <div v-if="totalCheck == 0" class="text-red q-mr-sm">
**จำนวนวนลาของทานไมกตอง หรอวนทนลาของทานตรงกบวนหย
</div> -->
<q-btn <q-btn
v-if="!props.data || props.data.status == 'DRAFT'" v-if="!props.data || props.data.status == 'DRAFT'"
id="onSubmit" id="onSubmit"
type="submit" type="submit"
unelevated unelevated
:disable="!isLeave"
class="q-px-md items-center btnBlue" class="q-px-md items-center btnBlue"
label="บันทึก" label="บันทึก"
><q-tooltip>นทกแบบราง</q-tooltip></q-btn :loading="isLoadLeaveDate"
> >
<q-tooltip>นทกแบบราง</q-tooltip>
</q-btn>
<q-btn <q-btn
v-if="data && statusCheck != 'NEW'" v-if="data && statusCheck != 'NEW'"
id="onSubmit" id="onSubmit"
@ -599,8 +640,10 @@ onMounted(() => {
color="primary" color="primary"
label="ยื่นใบลา" label="ยื่นใบลา"
@click="onConfirm()" @click="onConfirm()"
><q-tooltip>นใบลา</q-tooltip></q-btn :loading="isLoadLeaveDate"
> >
<q-tooltip>นใบลา</q-tooltip>
</q-btn>
</q-card-actions> </q-card-actions>
</q-form> </q-form>
</template> </template>

View file

@ -13,7 +13,7 @@ import type { FormRef } from "@/modules/05_leave/interface/request/BirthForm";
const $q = useQuasar(); const $q = useQuasar();
const dataStore = useLeaveStore(); const dataStore = useLeaveStore();
const mixin = useCounterMixin(); const mixin = useCounterMixin();
const { date2Thai, dateToISO, messageError } = mixin; const { date2Thai, messageError, convertDateToAPI } = mixin;
const edit = ref<boolean>(true); const edit = ref<boolean>(true);
const leaveId = ref<string>(""); const leaveId = ref<string>("");
@ -38,6 +38,8 @@ const props = defineProps({
}, },
}); });
const isLoadCheck = ref<boolean>(false);
/** ข้อมูล v-model ของฟอร์ม */ /** ข้อมูล v-model ของฟอร์ม */
const formDataBirth = reactive<any>({ const formDataBirth = reactive<any>({
type: dataStore.typeId, type: dataStore.typeId,
@ -46,8 +48,8 @@ const formDataBirth = reactive<any>({
leaveEndDate: null, leaveEndDate: null,
leaveTotal: "", leaveTotal: "",
leaveLast: "", leaveLast: "",
leaveNumber: "", leaveRange: "ALL",
leaveAddress: "", leaveRangeEnd: "ALL",
leaveDetail: "", leaveDetail: "",
leaveDocument: [], leaveDocument: [],
}); });
@ -106,17 +108,19 @@ function onValidate() {
formData.append("type", formDataBirth.type); formData.append("type", formDataBirth.type);
formData.append( formData.append(
"leaveStartDate", "leaveStartDate",
dateToISO(new Date(formDataBirth.leaveStartDate)) convertDateToAPI(formDataBirth.leaveStartDate) ?? ""
); );
formData.append( formData.append(
"leaveEndDate", "leaveEndDate",
dateToISO(new Date(formDataBirth.leaveEndDate)) convertDateToAPI(formDataBirth.leaveEndDate) ?? ""
); );
formData.append("leaveWrote", formDataBirth.leaveWrote); formData.append("leaveWrote", formDataBirth.leaveWrote);
formData.append("leaveAddress", formDataBirth.leaveAddress); formData.append("leaveAddress", dataStore.currentAddress);
formData.append("leaveNumber", formDataBirth.leaveNumber); formData.append("leaveNumber", dataStore.telephoneNumber);
formData.append("leaveDetail", formDataBirth.leaveDetail); formData.append("leaveDetail", formDataBirth.leaveDetail);
formData.append("leaveTotal", formDataBirth.leaveTotal); formData.append("leaveTotal", formDataBirth.leaveTotal);
formData.append("leaveRange", formDataBirth.leaveRange);
formData.append("leaveRangeEnd", formDataBirth.leaveRangeEnd);
props.onSubmit(formData, isLeave.value); props.onSubmit(formData, isLeave.value);
} }
@ -124,28 +128,61 @@ function onValidate() {
const isLeave = ref<boolean>(true); const isLeave = ref<boolean>(true);
const reasonLeave = ref<string>(""); const reasonLeave = ref<string>("");
/**
* check าลาไดไหม จาก api const checkDate = computed(() => {
* @param formData if (
*/ convertDateToAPI(formDataBirth.leaveEndDate) ==
convertDateToAPI(formDataBirth.leaveStartDate)
) {
return true;
} else {
return false;
}
});
/** ตรวจสอบวันลา */
async function fetchCheck() { async function fetchCheck() {
await http if (formDataBirth.leaveStartDate && formDataBirth.leaveEndDate) {
.post(config.API.leaveCheck(), { isLoadCheck.value = true;
type: dataStore.typeId ?? null, const checkDate = computed(() => {
StartLeaveDate: formDataBirth.leaveStartDate ?? null, if (
EndLeaveDate: formDataBirth.leaveEndDate ?? null, convertDateToAPI(formDataBirth.leaveEndDate) ==
}) convertDateToAPI(formDataBirth.leaveStartDate)
.then((res: any) => { ) {
const data = res.data.result; return true;
isLeave.value = data.isLeave; } else {
formDataBirth.leaveTotal = data.totalDate; return false;
reasonLeave.value = data.message }
? data.message
: "จำนวนวันลาเกินที่กำหนด";
})
.catch((e: any) => {
messageError($q, e);
}); });
await http
.post(config.API.leaveCheck(), {
type: dataStore.typeId ?? null,
StartLeaveDate: convertDateToAPI(formDataBirth.leaveStartDate) ?? null,
EndLeaveDate: convertDateToAPI(formDataBirth.leaveEndDate) ?? null,
leaveRange: formDataBirth.leaveRange,
leaveRangeEnd: checkDate.value
? formDataBirth.leaveRange
: formDataBirth.leaveRangeEnd,
})
.then((res) => {
const data = res.data.result;
formDataBirth.leaveTotal = data.totalDate;
reasonLeave.value =
data.message != ""
? data.message
: formDataBirth.leaveTotal > 0
? "จำนวนวันลาเกินที่กำหนด"
: "ช่วงวันลาที่ระบุไม่ถูกต้อง";
isLeave.value = formDataBirth.leaveTotal > 0 ? data.isLeave : false;
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
isLoadCheck.value = false;
});
}
} }
/** แจ้งเมื่อวันลาไม่ถูกต้อง */ /** แจ้งเมื่อวันลาไม่ถูกต้อง */
@ -156,32 +193,36 @@ const dateEndInputStyle = computed(() => {
/** ตรวจสอบว่ามีการส่งข้อมูลเข้ามาที่ฟอร์มไหม เมื่อมีการส่งจะ map ข้อมูลเข้า v-model ของฟอร์ม */ /** ตรวจสอบว่ามีการส่งข้อมูลเข้ามาที่ฟอร์มไหม เมื่อมีการส่งจะ map ข้อมูลเข้า v-model ของฟอร์ม */
const leaveDocumentList = ref<any>(); const leaveDocumentList = ref<any>();
const statusCheck = ref<any>(""); const statusCheck = ref<any>("");
watch(props.data, () => { watch(
if (props.data) { () => props.data,
formDataBirth.leaveWrote = props.data.leaveWrote; () => {
formDataBirth.leaveStartDate = props.data.leaveStartDate; if (props.data) {
formDataBirth.leaveEndDate = props.data.leaveEndDate; // totalCheck.value = null;
formDataBirth.leaveTotal = props.data.leaveTotal; formDataBirth.leaveWrote = props.data.leaveWrote;
formDataBirth.leaveNumber = props.data.leaveNumber; formDataBirth.leaveStartDate = props.data.leaveStartDate;
formDataBirth.leaveAddress = props.data.leaveAddress; formDataBirth.leaveEndDate = props.data.leaveEndDate;
formDataBirth.leaveDetail = props.data.leaveDetail; formDataBirth.leaveTotal = props.data.leaveTotal;
leaveDocumentList.value = props.data.leaveDocument; formDataBirth.leaveDetail = props.data.leaveDetail;
statusCheck.value = props.data.status; formDataBirth.leaveRangeEnd = props.data.leaveRangeEnd;
formDataBirth.leaveDocument = []; leaveDocumentList.value = props.data.leaveDocument;
statusCheck.value = props.data.status;
formDataBirth.leaveDocument = [];
}
} }
}); );
/** Hook */ /** Hook */
onMounted(() => { onMounted(() => {
if (props.data) { if (props.data) {
// totalCheck.value = null;
formDataBirth.leaveWrote = props.data.leaveWrote; formDataBirth.leaveWrote = props.data.leaveWrote;
formDataBirth.leaveStartDate = props.data.leaveStartDate; formDataBirth.leaveStartDate = props.data.leaveStartDate;
formDataBirth.leaveEndDate = props.data.leaveEndDate; formDataBirth.leaveEndDate = props.data.leaveEndDate;
formDataBirth.leaveTotal = props.data.leaveTotal; formDataBirth.leaveTotal = props.data.leaveTotal;
formDataBirth.leaveNumber = props.data.leaveNumber;
formDataBirth.leaveAddress = props.data.leaveAddress;
formDataBirth.leaveDetail = props.data.leaveDetail; formDataBirth.leaveDetail = props.data.leaveDetail;
leaveDocumentList.value = props.data.leaveDocument; leaveDocumentList.value = props.data.leaveDocument;
formDataBirth.leaveRange = props.data.leaveRange;
formDataBirth.leaveRangeEnd = props.data.leaveRangeEnd;
statusCheck.value = props.data.status; statusCheck.value = props.data.status;
leaveId.value = props.data.id; leaveId.value = props.data.id;
} }
@ -196,220 +237,292 @@ onMounted(() => {
</div> </div>
<form @submit.prevent.stop="onValidate"> <form @submit.prevent.stop="onValidate">
<q-card bordered class="q-pa-md bg-grey-1"> <q-card bordered class="q-pa-md bg-grey-1">
<div class="col-12 row q-pa-sm q-col-gutter-sm"> <div class="col-12 row q-col-gutter-sm">
<q-input <div class="col-12 inputgreen">
class="col-12 col-sm-12 cursor-pointer inputgreen" <q-input
ref="leaveWroteRef" ref="leaveWroteRef"
for="leaveWroteRef" for="leaveWroteRef"
dense dense
outlined outlined
v-model="formDataBirth.leaveWrote" v-model="formDataBirth.leaveWrote"
label="เขียนที่" label="เขียนที่"
hide-bottom-space hide-bottom-space
bg-color="white" bg-color="white"
:readonly="!edit || statusCheck === 'NEW'" :readonly="!edit || statusCheck === 'NEW'"
:rules="[(val:string) => !!val || `${'เขียนที่'}`]" :rules="[(val:string) => !!val || `${'เขียนที่'}`]"
/> />
</div>
<datepicker <div class="col-12">
class="col-12 col-md-3 col-sm-12 cursor-pointer inputgreen" <div class="row q-col-gutter-sm">
menu-class-name="modalfix" <div class="col-12 col-md-3 col-sm-6 inputgreen">
v-model="formDataBirth.leaveStartDate" <datepicker
:locale="'th'" v-model="formDataBirth.leaveStartDate"
autoApply :locale="'th'"
hide-bottom-space autoApply
borderless hide-bottom-space
:enableTimePicker="false" borderless
week-start="0" :enableTimePicker="false"
:readonly="!edit || statusCheck === 'NEW'" week-start="0"
@update:model-value="formDataBirth.leaveEndDate = null" :readonly="!edit || statusCheck === 'NEW'"
> @update:model-value="
<template #year="{ year }"> (formDataBirth.leaveEndDate = null), fetchCheck()
{{ year + 543 }} "
</template> >
<template #year-overlay-value="{ value }"> <template #year="{ year }">
{{ parseInt(value + 543) }} {{ year + 543 }}
</template> </template>
<template #trigger> <template #year-overlay-value="{ value }">
<q-input {{ parseInt(value + 543) }}
outlined </template>
dense <template #trigger>
ref="leaveStartDateRef" <q-input
for="leaveStartDateRef" outlined
hide-bottom-space dense
bg-color="white" ref="leaveStartDateRef"
:readonly="!edit || statusCheck === 'NEW'" for="leaveStartDateRef"
class="full-width datepicker" hide-bottom-space
:model-value=" bg-color="white"
formDataBirth.leaveStartDate != null :readonly="!edit || statusCheck === 'NEW'"
? date2Thai(formDataBirth.leaveStartDate) class="full-width datepicker"
: null :model-value="
" formDataBirth.leaveStartDate != null
:label="`${'ลาตั้งแต่วันที่'}`" ? date2Thai(formDataBirth.leaveStartDate)
:rules="[(val:string) => !!val || `${'กรุณาเลือกลาตั้งแต่วันที่'}`]" : null
> "
<template v-slot:prepend> :label="`${'วันที่เริ่มต้น'}`"
<q-icon :rules="[(val:string) => !!val || `${'กรุณาเลือกวันที่เริ่มต้น'}`]"
name="event" >
class="cursor-pointer" <template v-slot:prepend>
style="color: var(--q-primary)" <q-icon
> name="event"
</q-icon> class="cursor-pointer"
</template> style="color: var(--q-primary)"
</q-input> >
</template> </q-icon>
</datepicker> </template>
</q-input>
</template>
</datepicker>
</div>
<datepicker <div class="col-12 col-md-3 col-sm-6 inputgreen">
class="col-12 col-md-3 col-sm-12 cursor-pointer inputgreen" <q-select
menu-class-name="modalfix" outlined
v-model="formDataBirth.leaveEndDate" dense
:locale="'th'" bg-color="white"
autoApply v-model="formDataBirth.leaveRange"
@update:model-value="fetchCheck()" :options="dataStore.rangeOptions"
borderless emit-value
hide-bottom-space map-options
:enableTimePicker="false" option-value="id"
week-start="0" option-label="name"
:readonly="!formDataBirth.leaveStartDate" @update:model-value="fetchCheck()"
:min-date="formDataBirth.leaveStartDate" >
> <template v-slot:prepend>
<template #year="{ year }"> <q-icon
{{ year + 543 }} name="mdi-clock-outline"
</template> style="color: var(--q-primary)"
<template #year-overlay-value="{ value }"> />
{{ parseInt(value + 543) }} </template>
</template> </q-select>
<template #trigger> </div>
<q-input
outlined
dense
ref="leaveEndDateRef"
for="leaveEndDateRef"
hide-bottom-space
:readonly="!formDataBirth.leaveStartDate"
class="full-width datepicker"
bg-color="white"
:model-value="
formDataBirth.leaveEndDate != null
? date2Thai(formDataBirth.leaveEndDate)
: null
"
:label="`${'ลาถึงวันที่'}`"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
style="color: var(--q-primary)"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
<q-input
class="col-12 col-md-3 col-sm-6"
dense
outlined
ref="leaveTotalRef"
for="leaveTotalRef"
v-model="formDataBirth.leaveTotal"
label="จำนวนวันที่ลา"
readonly
:bottom-slots="!isLeave ? true : false"
:color="!isLeave ? 'red' : 'black'"
:bg-color="!isLeave ? 'red-2' : 'white'"
:border-color="!isLeave ? 'red' : 'gray'"
:input-class="!isLeave ? dateEndInputStyle : ''"
>
<template v-slot:hint>
<span style="color: red">
{{ !isLeave ? reasonLeave : "" }}
</span>
</template>
</q-input>
<q-input
class="col-12 col-md-3 col-sm-6"
dense
outlined
ref="leaveLastRef"
for="leaveLastRef"
v-model="dataStore.leaveLast"
label="ลาครั้งสุดท้ายเมื่อวันที่"
readonly
hide-bottom-space
bg-color="white"
/>
<div class="full-width">
<div class="q-col-gutter-sm row">
<q-input
class="col-12 col-md-3 col-sm-12 cursor-pointer inputgreen"
dense
outlined
hide-bottom-space
bg-color="white"
ref="leaveNumberRef"
for="leaveNumberRef"
v-model="formDataBirth.leaveNumber"
mask="(###)-###-####"
unmasked-value
label="หมายเลขโทรศัพท์ที่ติดต่อได้"
:readonly="!edit || statusCheck === 'NEW'"
:rules="[
(val:string) => !!val || `${'กรุณากรอกหมายเลขโทรศัพท์ที่ติดต่อได้'}`,
]"
/>
<q-input
class="col-12 col-md-9 col-sm-12 cursor-pointer inputgreen"
dense
outlined
hide-bottom-space
bg-color="white"
ref="leaveAddressRef"
for="leaveAddressRef"
v-model="formDataBirth.leaveAddress"
label="ที่อยู่ที่ติดต่อได้ระหว่างลา"
:readonly="!edit || statusCheck === 'NEW'"
:rules="[
(val:string) => !!val || `${'กรุณากรอกที่อยู่ที่ติดต่อได้ระหว่างลา'}`,
]"
/>
</div> </div>
</div> </div>
<q-input
type="textarea" <div class="col-12">
class="col-12 col-md-12 col-sm-12 cursor-pointer inputgreen" <div class="row q-col-gutter-sm">
dense <div class="col-12 col-md-3 col-sm-6 inputgreen">
outlined <datepicker
bg-color="white" v-model="formDataBirth.leaveEndDate"
ref="leaveDetailRef" :locale="'th'"
for="leaveDetailRef" autoApply
v-model="formDataBirth.leaveDetail" hide-bottom-space
label="รายละเอียด" @update:model-value="fetchCheck()"
:readonly="!edit || statusCheck === 'NEW'" borderless
/> :enableTimePicker="false"
week-start="0"
:min-date="formDataBirth.leaveStartDate"
>
<template #year="{ year }">
{{ year + 543 }}
</template>
<template #year-overlay-value="{ value }">
{{ parseInt(value + 543) }}
</template>
<template #trigger>
<q-input
outlined
dense
ref="leaveEndDateRef"
for="leaveEndDateRef"
hide-bottom-space
bg-color="white"
class="full-width datepicker"
:model-value="
formDataBirth.leaveEndDate != null
? date2Thai(formDataBirth.leaveEndDate)
: 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 class="col-12 col-md-3 col-sm-6 inputgreen">
<q-select
v-if="!checkDate"
outlined
dense
bg-color="white"
v-model="formDataBirth.leaveRangeEnd"
:options="dataStore.rangeOptions.filter((items:any)=> items.id !== 'AFTERNOON')"
emit-value
map-options
option-value="id"
option-label="name"
@update:model-value="fetchCheck()"
>
<template v-slot:prepend>
<q-icon
name="mdi-clock-outline"
style="color: var(--q-primary)"
/>
</template>
</q-select>
</div>
</div>
</div>
<div class="col-12">
<div class="row q-col-gutter-sm">
<div class="col-12 col-md-3 col-sm-6">
<q-input
:bottom-slots="!isLeave ? true : false"
:color="!isLeave ? 'red' : 'black'"
:bg-color="!isLeave ? 'red-2' : 'white'"
:border-color="!isLeave ? 'red' : 'gray'"
:input-class="!isLeave ? dateEndInputStyle : ''"
dense
outlined
ref="leaveTotalRef"
for="leaveTotalRef"
v-model="formDataBirth.leaveTotal"
label="จำนวนวันที่ลา (วัน)"
readonly
:loading="isLoadCheck"
>
<template v-slot:hint>
<span style="color: red">
{{ !isLeave ? reasonLeave : "" }}
</span>
</template>
</q-input>
</div>
<div class="col-12 col-md-3 col-sm-6">
<q-input
dense
outlined
ref="leaveLastRef"
for="leaveLastRef"
v-model="dataStore.leaveLast"
label="ลาครั้งสุดท้ายเมื่อวันที่"
readonly
hide-bottom-space
bg-color="white"
/>
</div>
</div>
</div>
<div class="full-width">
<div class="q-col-gutter-sm row">
<div class="col-12 col-md-3 col-sm-12 inputgreen">
<q-input
dense
outlined
hide-bottom-space
bg-color="white"
ref="leaveNumberRef"
for="leaveNumberRef"
v-model="dataStore.telephoneNumber"
mask="(###)-###-####"
unmasked-value
lazy-rules
label="หมายเลขโทรศัพท์ที่ติดต่อได้"
:readonly="!edit || statusCheck === 'NEW'"
:rules="[
(val:string) => !!val || `${'กรุณากรอกหมายเลขโทรศัพท์ที่ติดต่อได้'}`,
]"
/>
</div>
<div class="col-12 col-md-9 col-sm-12 inputgreen">
<q-input
dense
outlined
hide-bottom-space
bg-color="white"
ref="leaveAddressRef"
for="leaveAddressRef"
v-model="dataStore.currentAddress"
label="ที่อยู่ที่ติดต่อได้ระหว่างลา"
:readonly="!edit || statusCheck === 'NEW'"
:rules="[
(val:string) => !!val || `${'กรุณากรอกที่อยู่ที่ติดต่อได้ระหว่างลา'}`,
]"
/>
</div>
</div>
</div>
<div class="col-12 inputgreen">
<q-input
type="textarea"
dense
outlined
bg-color="white"
ref="leaveDetailRef"
for="leaveDetailRef"
v-model="formDataBirth.leaveDetail"
label="สาเหตุการลา"
:readonly="!edit || statusCheck === 'NEW'"
/>
</div>
<div class="full-width" v-if="statusCheck != 'NEW'"> <div class="full-width" v-if="statusCheck != 'NEW'">
<div class="q-col-gutter-sm row"> <div class="q-col-gutter-sm row">
<!-- multiple --> <!-- multiple -->
<q-file <div class="q-pl-sm col-12">
for="leaveDocumentRef" <q-file
hide-bottom-space for="leaveDocumentRef"
v-model="formDataBirth.leaveDocument" hide-bottom-space
@added="fileUploadDoc" v-model="formDataBirth.leaveDocument"
dense @added="fileUploadDoc"
bg-color="white" dense
label="เอกสารประกอบ" bg-color="white"
outlined label="เอกสารประกอบ"
multiple outlined
use-chips multiple
class="q-pl-sm col-12" use-chips
> >
<template v-slot:prepend> <template v-slot:prepend>
<q-icon name="attach_file" color="primary" /> <q-icon name="attach_file" color="primary" />
</template> </template>
</q-file> </q-file>
</div>
</div> </div>
</div> </div>
<div class="col-12 row" v-if="data"> <div class="col-12 row" v-if="data">
@ -477,23 +590,26 @@ onMounted(() => {
id="onSubmit" id="onSubmit"
type="submit" type="submit"
unelevated unelevated
dense :disable="!isLeave"
class="q-px-md items-center btnBlue" class="q-px-md items-center btnBlue"
label="บันทึก" label="บันทึก"
><q-tooltip>นทกแบบราง</q-tooltip></q-btn :loading="isLoadCheck"
> >
<q-tooltip>นทกแบบราง</q-tooltip>
</q-btn>
<q-btn <q-btn
v-if="data && statusCheck != 'NEW'" v-if="data && statusCheck != 'NEW'"
id="onSubmit" id="onSubmit"
type="button" type="button"
unelevated unelevated
dense
class="q-px-md items-center q-ml-sm" class="q-px-md items-center q-ml-sm"
color="primary" color="primary"
label="ยื่นใบลา" label="ยื่นใบลา"
@click="onConfirm()" @click="onConfirm()"
><q-tooltip>นใบลา</q-tooltip></q-btn :loading="isLoadCheck"
> >
<q-tooltip>นใบลา</q-tooltip>
</q-btn>
</div> </div>
</form> </form>
</template> </template>

View file

@ -1,7 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, onMounted, computed, watch } from "vue"; import { ref, reactive, onMounted, computed, watch } from "vue";
import { useQuasar } from "quasar"; import { useQuasar } from "quasar";
import { useRouter } from "vue-router";
import http from "@/plugins/http"; import http from "@/plugins/http";
import config from "@/app.config"; import config from "@/app.config";
@ -14,7 +13,7 @@ import type { FormRef } from "@/modules/05_leave/interface/request/HelpWifeForm"
const $q = useQuasar(); const $q = useQuasar();
const dataStore = useLeaveStore(); const dataStore = useLeaveStore();
const mixin = useCounterMixin(); const mixin = useCounterMixin();
const { date2Thai, calculateDurationYmd, dateToISO, messageError } = mixin; const { date2Thai, messageError, convertDateToAPI } = mixin;
const edit = ref<boolean>(true); const edit = ref<boolean>(true);
const leaveId = ref<string>(""); const leaveId = ref<string>("");
@ -48,9 +47,9 @@ const formDataHelpWife = reactive<any>({
leaveStartDate: null, leaveStartDate: null,
leaveEndDate: null, leaveEndDate: null,
leaveTotal: "", leaveTotal: "",
leaveNumber: "",
leaveAddress: "",
leaveDetail: "", leaveDetail: "",
leaveRange: "ALL",
leaveRangeEnd: "ALL",
leaveDocument: [], leaveDocument: [],
}); });
@ -117,20 +116,22 @@ function onValidate() {
formData.append("type", formDataHelpWife.type); formData.append("type", formDataHelpWife.type);
formData.append( formData.append(
"leaveStartDate", "leaveStartDate",
dateToISO(new Date(formDataHelpWife.leaveStartDate)) convertDateToAPI(formDataHelpWife.leaveStartDate) ?? ""
); );
formData.append( formData.append(
"leaveEndDate", "leaveEndDate",
dateToISO(new Date(formDataHelpWife.leaveEndDate)) convertDateToAPI(formDataHelpWife.leaveEndDate) ?? ""
); );
formData.append("leaveWrote", formDataHelpWife.leaveWrote); formData.append("leaveWrote", formDataHelpWife.leaveWrote);
formData.append("leaveAddress", formDataHelpWife.leaveAddress); formData.append("leaveAddress", dataStore.currentAddress);
formData.append("leaveNumber", formDataHelpWife.leaveNumber); formData.append("leaveNumber", dataStore.telephoneNumber);
formData.append("leaveDetail", formDataHelpWife.leaveDetail); formData.append("leaveDetail", formDataHelpWife.leaveDetail);
formData.append("wifeDayName", formDataHelpWife.wifeDayName); formData.append("wifeDayName", formDataHelpWife.wifeDayName);
formData.append("leaveRange", formDataHelpWife.leaveRange);
formData.append("leaveRangeEnd", formDataHelpWife.leaveRangeEnd);
formData.append( formData.append(
"wifeDayDateBorn", "wifeDayDateBorn",
dateToISO(new Date(formDataHelpWife.wifeDayDateBorn)) convertDateToAPI(formDataHelpWife.wifeDayDateBorn) ?? ""
); );
formData.append("leaveTotal", formDataHelpWife.leaveTotal); formData.append("leaveTotal", formDataHelpWife.leaveTotal);
@ -138,66 +139,79 @@ function onValidate() {
} }
} }
/**
* function พเดทค LeaveTotal
*/
function updateLeaveTotal() {
const newLeaveTotal = calculateDurationYmd(
formDataHelpWife.leaveStartDate,
formDataHelpWife.leaveEndDate
);
formDataHelpWife.leaveTotal = newLeaveTotal;
}
const reasonLeave = ref<string>(""); const reasonLeave = ref<string>("");
const checkDate = computed(() => {
/** if (
* check าลาไดไหม จาก api convertDateToAPI(formDataHelpWife.leaveEndDate) ==
* @param formData convertDateToAPI(formDataHelpWife.leaveStartDate)
*/ ) {
async function fetchCheck() { return true;
await http } else {
.post(config.API.leaveCheck(), { return false;
type: dataStore.typeId ?? null,
StartLeaveDate: formDataHelpWife.leaveStartDate ?? null,
EndLeaveDate: formDataHelpWife.leaveEndDate ?? null,
})
.then((res: any) => {
const data = res.data.result;
isLeave.value = data.isLeave;
formDataHelpWife.leaveTotal =
data.totalDate - data.sumDateWork - data.sumDateHoliday;
reasonLeave.value = data.message
? data.message
: "จำนวนวันลาเกินที่กำหนด";
})
.catch((e: any) => {
messageError($q, e);
});
}
/** ตรวจสอบว่ามีการส่งข้อมูลเข้ามาที่ฟอร์มไหม เมื่อมีการส่งจะ map ข้อมูลเข้า v-model ของฟอร์ม */
watch(props.data, () => {
if (props.data) {
formDataHelpWife.leaveWrote = props.data.leaveWrote;
formDataHelpWife.wifeDayName = props.data.wifeDayName;
formDataHelpWife.wifeDayDateBorn = props.data.wifeDayDateBorn;
formDataHelpWife.leaveStartDate = props.data.leaveStartDate;
formDataHelpWife.leaveEndDate = props.data.leaveEndDate;
formDataHelpWife.leaveTotal = props.data.leaveTotal;
formDataHelpWife.leaveNumber = props.data.leaveNumber;
formDataHelpWife.leaveAddress = props.data.leaveAddress;
formDataHelpWife.leaveDetail = props.data.leaveDetail;
formDataHelpWife.leaveDocument = [];
leaveDocumentList.value = props.data.leaveDocument;
statusCheck.value = props.data.status;
} }
}); });
const isLoadCheck = ref<boolean>(false);
/** fetchCheck ว่าลาได้ไหม จาก api */
async function fetchCheck() {
if (formDataHelpWife.leaveStartDate && formDataHelpWife.leaveEndDate) {
isLoadCheck.value = true;
await http
.post(config.API.leaveCheck(), {
type: dataStore.typeId ?? null,
StartLeaveDate:
convertDateToAPI(formDataHelpWife.leaveStartDate) ?? null,
EndLeaveDate: convertDateToAPI(formDataHelpWife.leaveEndDate) ?? null,
leaveRange: formDataHelpWife.leaveRange,
leaveRangeEnd: checkDate.value
? formDataHelpWife.leaveRange
: formDataHelpWife.leaveRangeEnd,
})
.then((res: any) => {
const data = res.data.result;
formDataHelpWife.leaveTotal =
data.totalDate - data.sumDateWork - data.sumDateHoliday;
reasonLeave.value =
data.message != ""
? data.message
: formDataHelpWife.leaveTotal > 0
? "จำนวนวันลาเกินที่กำหนด"
: "ช่วงวันลาที่ระบุไม่ถูกต้อง";
isLeave.value = formDataHelpWife.leaveTotal > 0 ? data.isLeave : false;
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
isLoadCheck.value = false;
});
}
}
/** ตรวจสอบว่ามีการส่งข้อมูลเข้ามาที่ฟอร์มไหม เมื่อมีการส่งจะ map ข้อมูลเข้า v-model ของฟอร์ม */
watch(
() => props.data,
async () => {
if (props.data) {
formDataHelpWife.leaveWrote = props.data.leaveWrote;
formDataHelpWife.wifeDayName = props.data.wifeDayName;
formDataHelpWife.wifeDayDateBorn = props.data.wifeDayDateBorn;
formDataHelpWife.leaveStartDate = props.data.leaveStartDate;
formDataHelpWife.leaveEndDate = props.data.leaveEndDate;
formDataHelpWife.leaveTotal = props.data.leaveTotal;
formDataHelpWife.leaveRangeEnd = props.data.leaveRangeEnd;
formDataHelpWife.leaveRange = props.data.leaveRange;
formDataHelpWife.leaveDetail = props.data.leaveDetail;
formDataHelpWife.leaveDocument = [];
leaveDocumentList.value = props.data.leaveDocument;
statusCheck.value = props.data.status;
}
}
);
/**Hook */ /**Hook */
onMounted(() => { onMounted(async () => {
if (props.data) { if (props.data) {
formDataHelpWife.leaveWrote = props.data.leaveWrote; formDataHelpWife.leaveWrote = props.data.leaveWrote;
formDataHelpWife.wifeDayName = props.data.wifeDayName; formDataHelpWife.wifeDayName = props.data.wifeDayName;
@ -205,10 +219,10 @@ onMounted(() => {
formDataHelpWife.leaveStartDate = props.data.leaveStartDate; formDataHelpWife.leaveStartDate = props.data.leaveStartDate;
formDataHelpWife.leaveEndDate = props.data.leaveEndDate; formDataHelpWife.leaveEndDate = props.data.leaveEndDate;
formDataHelpWife.leaveTotal = props.data.leaveTotal; formDataHelpWife.leaveTotal = props.data.leaveTotal;
formDataHelpWife.leaveNumber = props.data.leaveNumber;
formDataHelpWife.leaveAddress = props.data.leaveAddress;
formDataHelpWife.leaveDetail = props.data.leaveDetail; formDataHelpWife.leaveDetail = props.data.leaveDetail;
leaveDocumentList.value = props.data.leaveDocument; leaveDocumentList.value = props.data.leaveDocument;
formDataHelpWife.leaveRange = props.data.leaveRange;
formDataHelpWife.leaveRangeEnd = props.data.leaveRangeEnd;
statusCheck.value = props.data.status; statusCheck.value = props.data.status;
leaveId.value = props.data.id; leaveId.value = props.data.id;
} }
@ -223,138 +237,203 @@ onMounted(() => {
<form @submit.prevent.stop="onValidate"> <form @submit.prevent.stop="onValidate">
<q-card bordered class="q-pa-md bg-grey-1"> <q-card bordered class="q-pa-md bg-grey-1">
<div class="col-12 row q-pa-sm q-col-gutter-sm"> <div class="col-12 row q-pa-sm q-col-gutter-sm">
<q-input <div class="col-12 inputgreen">
class="col-12 col-12 col-sm-12 cursor-pointer inputgreen" <q-input
ref="leaveWroteRef" ref="leaveWroteRef"
for="leaveWroteRef" for="leaveWroteRef"
dense dense
outlined outlined
hide-bottom-space hide-bottom-space
bg-color="white" bg-color="white"
v-model="formDataHelpWife.leaveWrote" v-model="formDataHelpWife.leaveWrote"
label="เขียนที่" label="เขียนที่"
:readonly="!edit || statusCheck === 'NEW'" :readonly="!edit || statusCheck === 'NEW'"
:rules="[(val:string) => !!val || `${'เขียนที่'}`]" :rules="[(val:string) => !!val || `${'เขียนที่'}`]"
/> />
<datepicker </div>
class="col-12 col-md-4 col-sm-12 cursor-pointer inputgreen"
menu-class-name="modalfix"
v-model="formDataHelpWife.leaveStartDate"
:locale="'th'"
autoApply
hide-bottom-space
borderless
:enableTimePicker="false"
week-start="0"
:readonly="!edit || statusCheck === 'NEW'"
@update:model-value="formDataHelpWife.leaveEndDate = null"
>
<template #year="{ year }">
{{ year + 543 }}
</template>
<template #year-overlay-value="{ value }">
{{ parseInt(value + 543) }}
</template>
<template #trigger>
<q-input
outlined
dense
ref="leaveStartDateRef"
for="leaveStartDateRef"
hide-bottom-space
bg-color="white"
:readonly="!edit || statusCheck === 'NEW'"
class="full-width datepicker"
:model-value="
formDataHelpWife.leaveStartDate != null
? date2Thai(formDataHelpWife.leaveStartDate)
: 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>
<datepicker <div class="col-12">
class="col-12 col-md-4 col-sm-12 cursor-pointer inputgreen" <div class="row q-col-gutter-sm">
menu-class-name="modalfix" <div class="col-12 col-md-3 col-sm-6 inputgreen">
v-model="formDataHelpWife.leaveEndDate" <datepicker
:locale="'th'" v-model="formDataHelpWife.leaveStartDate"
autoApply :locale="'th'"
borderless autoApply
hide-bottom-space hide-bottom-space
:enableTimePicker="false" borderless
@update:model-value="updateLeaveTotal, fetchCheck()" :enableTimePicker="false"
week-start="0" week-start="0"
:readonly="!formDataHelpWife.leaveStartDate" :readonly="!edit || statusCheck === 'NEW'"
:min-date="formDataHelpWife.leaveStartDate" @update:model-value="
> (formDataHelpWife.leaveEndDate = null), fetchCheck()
<template #year="{ year }"> "
{{ year + 543 }} >
</template> <template #year="{ year }">
<template #year-overlay-value="{ value }"> {{ year + 543 }}
{{ parseInt(value + 543) }} </template>
</template> <template #year-overlay-value="{ value }">
<template #trigger> {{ parseInt(value + 543) }}
<q-input </template>
outlined <template #trigger>
dense <q-input
ref="leaveEndDateRef" outlined
for="leaveEndDateRef" dense
hide-bottom-space ref="leaveStartDateRef"
bg-color="white" for="leaveStartDateRef"
:readonly="!formDataHelpWife.leaveStartDate" hide-bottom-space
class="full-width datepicker" bg-color="white"
:model-value=" :readonly="!edit || statusCheck === 'NEW'"
formDataHelpWife.leaveEndDate != null class="full-width datepicker"
? date2Thai(formDataHelpWife.leaveEndDate) :model-value="
: null formDataHelpWife.leaveStartDate != null
" ? date2Thai(formDataHelpWife.leaveStartDate)
:label="`${'ลาถึงวันที่'}`" : null
> "
<template v-slot:prepend> :label="`${'วันที่เริ่มต้น'}`"
<q-icon :rules="[(val:string) => !!val || `${'กรุณาเลือกวันที่เริ่มต้น'}`]"
name="event" >
class="cursor-pointer" <template v-slot:prepend>
style="color: var(--q-primary)" <q-icon
> name="event"
</q-icon> class="cursor-pointer"
</template> style="color: var(--q-primary)"
</q-input> >
</template> </q-icon>
</datepicker> </template>
<q-input </q-input>
class="col-12 col-md-2 col-sm-6" </template>
dense </datepicker>
outlined </div>
ref="leaveTotalRef"
for="leaveTotalRef" <div class="col-12 col-md-3 col-sm-6 inputgreen">
v-model="formDataHelpWife.leaveTotal" <q-select
label="จำนวนวันที่ลา" outlined
readonly dense
:bottom-slots="!isLeave ? true : false" bg-color="white"
:color="!isLeave ? 'red' : 'black'" v-model="formDataHelpWife.leaveRange"
:bg-color="!isLeave ? 'red-2' : 'white'" :options="dataStore.rangeOptions"
:border-color="!isLeave ? 'red' : 'gray'" emit-value
:input-class="!isLeave ? dateEndInputStyle : ''" map-options
> option-value="id"
<template v-slot:hint> option-label="name"
<span style="color: red"> @update:model-value="fetchCheck()"
{{ !isLeave ? reasonLeave : "" }} >
</span> <template v-slot:prepend>
</template> <q-icon
</q-input> name="mdi-clock-outline"
<div class="col-12 col-md-4 col-sm-12 cursor-pointer inputgreen"> style="color: var(--q-primary)"
/>
</template>
</q-select>
</div>
</div>
</div>
<div class="col-12">
<div class="row q-col-gutter-sm">
<div class="col-12 col-md-3 col-sm-6 inputgreen">
<datepicker
v-model="formDataHelpWife.leaveEndDate"
:locale="'th'"
autoApply
hide-bottom-space
@update:model-value="fetchCheck()"
borderless
:enableTimePicker="false"
week-start="0"
:min-date="formDataHelpWife.leaveStartDate"
>
<template #year="{ year }">
{{ year + 543 }}
</template>
<template #year-overlay-value="{ value }">
{{ parseInt(value + 543) }}
</template>
<template #trigger>
<q-input
outlined
dense
ref="leaveEndDateRef"
for="leaveEndDateRef"
hide-bottom-space
bg-color="white"
class="full-width datepicker"
:model-value="
formDataHelpWife.leaveEndDate != null
? date2Thai(formDataHelpWife.leaveEndDate)
: 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 class="col-12 col-md-3 col-sm-6 inputgreen">
<q-select
v-if="!checkDate"
outlined
dense
bg-color="white"
v-model="formDataHelpWife.leaveRangeEnd"
:options="dataStore.rangeOptions.filter((items:any)=> items.id !== 'AFTERNOON')"
emit-value
map-options
option-value="id"
option-label="name"
@update:model-value="fetchCheck()"
>
<template v-slot:prepend>
<q-icon
name="mdi-clock-outline"
style="color: var(--q-primary)"
/>
</template>
</q-select>
</div>
</div>
</div>
<div class="col-12">
<div class="row q-col-gutter-sm">
<div class="col-12 col-md-3 col-sm-6 inputgreen">
<q-input
:bottom-slots="!isLeave ? true : false"
:color="!isLeave ? 'red' : 'black'"
:bg-color="!isLeave ? 'red-2' : 'white'"
:border-color="!isLeave ? 'red' : 'gray'"
:input-class="!isLeave ? dateEndInputStyle : ''"
class="col-12 col-md-3 col-sm-6"
dense
outlined
ref="leaveTotalRef"
for="leaveTotalRef"
v-model="formDataHelpWife.leaveTotal"
label="จำนวนวันที่ลา (วัน)"
readonly
:loading="isLoadCheck"
>
<template v-slot:hint>
<span style="color: red">
{{ !isLeave ? reasonLeave : "" }}
</span>
</template>
</q-input>
</div>
</div>
</div>
<div class="col-12 col-md-8 col-sm-12 inputgreen">
<q-input <q-input
class="col-12 col-sm-12" class="col-12 col-sm-12"
ref="wifeDayNameRef" ref="wifeDayNameRef"
@ -370,121 +449,129 @@ onMounted(() => {
/> />
</div> </div>
<datepicker <div class="col-12 col-md-4 col-sm-12 inputgreen">
class="col-12 col-md-4 col-sm-12 cursor-pointer inputgreen" <datepicker
menu-class-name="modalfix" v-model="formDataHelpWife.wifeDayDateBorn"
v-model="formDataHelpWife.wifeDayDateBorn" :locale="'th'"
:locale="'th'" autoApply
autoApply borderless
borderless hide-bottom-space
hide-bottom-space :enableTimePicker="false"
:enableTimePicker="false" week-start="0"
week-start="0" :readonly="!edit || statusCheck === 'NEW'"
:readonly="!edit || statusCheck === 'NEW'" >
> <template #year="{ year }">
<template #year="{ year }"> {{ year + 543 }}
{{ year + 543 }} </template>
</template> <template #year-overlay-value="{ value }">
<template #year-overlay-value="{ value }"> {{ parseInt(value + 543) }}
{{ parseInt(value + 543) }} </template>
</template> <template #trigger>
<template #trigger> <q-input
<q-input outlined
outlined dense
dense ref="wifeDayDateBornRef"
ref="wifeDayDateBornRef" for="wifeDayDateBornRef"
for="wifeDayDateBornRef" hide-bottom-space
hide-bottom-space bg-color="white"
bg-color="white" :readonly="!edit || statusCheck === 'NEW'"
:readonly="!edit || statusCheck === 'NEW'" class="full-width datepicker"
class="full-width datepicker" :model-value="
:model-value=" formDataHelpWife.wifeDayDateBorn != null
formDataHelpWife.wifeDayDateBorn != null ? date2Thai(formDataHelpWife.wifeDayDateBorn)
? date2Thai(formDataHelpWife.wifeDayDateBorn) : null
: null "
" :label="`${'วันที่คลอด'}`"
:label="`${'วันที่คลอด'}`" :rules="[(val:string) => !!val || `${'กรุณาเลือกวันที่คลอด'}`]"
:rules="[(val:string) => !!val || `${'กรุณาเลือกวันที่คลอด'}`]" >
> <template v-slot:prepend>
<template v-slot:prepend> <q-icon
<q-icon name="event"
name="event" class="cursor-pointer"
class="cursor-pointer" style="color: var(--q-primary)"
style="color: var(--q-primary)" >
> </q-icon>
</q-icon> </template>
</template> </q-input>
</q-input> </template>
</template> </datepicker>
</datepicker> </div>
<div class="full-width"> <div class="full-width">
<div class="q-col-gutter-sm row"> <div class="q-col-gutter-sm row">
<q-input <div class="col-12 col-md-3 col-sm-12 inputgreen">
class="col-12 col-md-3 col-sm-12 cursor-pointer inputgreen" <q-input
dense dense
outlined outlined
ref="leaveNumberRef" ref="leaveNumberRef"
for="leaveNumberRef" for="leaveNumberRef"
v-model="formDataHelpWife.leaveNumber" v-model="dataStore.telephoneNumber"
mask="(###)-###-####" mask="(###)-###-####"
unmasked-value unmasked-value
hide-bottom-space hide-bottom-space
bg-color="white" lazy-rules
label="หมายเลขโทรศัพท์ที่ติดต่อได้" bg-color="white"
:readonly="!edit || statusCheck === 'NEW'" label="หมายเลขโทรศัพท์ที่ติดต่อได้"
:rules="[ :readonly="!edit || statusCheck === 'NEW'"
:rules="[
(val:string) => !!val || `${'กรุณากรอกหมายเลขโทรศัพท์ที่ติดต่อได้'}`, (val:string) => !!val || `${'กรุณากรอกหมายเลขโทรศัพท์ที่ติดต่อได้'}`,
]" ]"
/> />
</div>
<q-input <div class="col-12 col-md-9 col-sm-12 inputgreen">
class="col-12 col-md-9 col-sm-12 cursor-pointer inputgreen" <q-input
dense dense
outlined outlined
hide-bottom-space hide-bottom-space
bg-color="white" bg-color="white"
ref="leaveAddressRef" ref="leaveAddressRef"
for="leaveAddressRef" for="leaveAddressRef"
v-model="formDataHelpWife.leaveAddress" v-model="dataStore.currentAddress"
label="ที่อยู่ที่ติดต่อได้ระหว่างลา" label="ที่อยู่ที่ติดต่อได้ระหว่างลา"
:readonly="!edit || statusCheck === 'NEW'" :readonly="!edit || statusCheck === 'NEW'"
:rules="[ :rules="[
(val:string) => !!val || `${'กรุณากรอกที่อยู่ที่ติดต่อได้ระหว่างลา'}`, (val:string) => !!val || `${'กรุณากรอกที่อยู่ที่ติดต่อได้ระหว่างลา'}`,
]" ]"
/> />
</div>
</div> </div>
</div> </div>
<q-input
hide-bottom-space <div class="col-12 inputgreen">
bg-color="white" <q-input
type="textarea" hide-bottom-space
class="col-12 col-md-12 col-sm-12 cursor-pointer inputgreen" bg-color="white"
dense type="textarea"
outlined dense
ref="leaveDetailRef" outlined
for="leaveDetailRef" ref="leaveDetailRef"
v-model="formDataHelpWife.leaveDetail" for="leaveDetailRef"
label="รายละเอียด" v-model="formDataHelpWife.leaveDetail"
:readonly="!edit || statusCheck === 'NEW'" label="สาเหตุการลา"
/> :readonly="!edit || statusCheck === 'NEW'"
/>
</div>
<div class="full-width" v-if="statusCheck != 'NEW'"> <div class="full-width" v-if="statusCheck != 'NEW'">
<div class="q-col-gutter-sm row"> <div class="q-col-gutter-sm row">
<q-file <div class="q-pl-sm col-12">
bg-color="white" <q-file
ref="leaveDocumentRef" bg-color="white"
v-model="formDataHelpWife.leaveDocument" ref="leaveDocumentRef"
@added="fileUploadDoc" v-model="formDataHelpWife.leaveDocument"
dense @added="fileUploadDoc"
label="เอกสารประกอบ" dense
outlined label="เอกสารประกอบ"
use-chips outlined
class="q-pl-sm col-12" use-chips
multiple multiple
> >
<template v-slot:prepend> <template v-slot:prepend>
<q-icon name="attach_file" color="primary" /> <q-icon name="attach_file" color="primary" />
</template> </template>
</q-file> </q-file>
</div>
</div> </div>
</div> </div>
<div class="col-12" v-if="data"> <div class="col-12" v-if="data">
@ -547,28 +634,32 @@ onMounted(() => {
<div class="row col-12 q-pt-md"> <div class="row col-12 q-pt-md">
<q-space /> <q-space />
<!-- <div v-if="totalCheck == 0" class="text-red q-mr-sm">**จำนวนวันลาของท่านไม่ถูกต้อง หรือวันที่ยื่นลาของท่านตรงกับวันหยุด</div> -->
<q-btn <q-btn
v-if="!props.data || props.data.status == 'DRAFT'" v-if="!props.data || props.data.status == 'DRAFT'"
id="onSubmit" id="onSubmit"
type="submit" type="submit"
unelevated unelevated
dense :disable="!isLeave"
class="q-px-md items-center btnBlue" class="q-px-md items-center btnBlue"
label="บันทึก" label="บันทึก"
><q-tooltip>นทกแบบราง</q-tooltip></q-btn :loading="isLoadCheck"
> >
<q-tooltip>นทกแบบราง</q-tooltip>
</q-btn>
<q-btn <q-btn
v-if="data && statusCheck != 'NEW'" v-if="data && statusCheck != 'NEW'"
id="onSubmit" id="onSubmit"
type="button" type="button"
unelevated unelevated
dense
class="q-px-md items-center q-ml-sm" class="q-px-md items-center q-ml-sm"
color="primary" color="primary"
label="ยื่นใบลา" label="ยื่นใบลา"
@click="onConfirm()" @click="onConfirm()"
><q-tooltip>นใบลา</q-tooltip></q-btn :loading="isLoadCheck"
> >
<q-tooltip>นใบลา</q-tooltip>
</q-btn>
</div> </div>
</form> </form>
</template> </template>

View file

@ -1,7 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, onMounted, computed, watch } from "vue"; import { ref, reactive, onMounted, computed, watch } from "vue";
import { useQuasar } from "quasar"; import { useQuasar } from "quasar";
import { useRouter } from "vue-router";
import http from "@/plugins/http"; import http from "@/plugins/http";
import config from "@/app.config"; import config from "@/app.config";
@ -9,12 +8,13 @@ import { useCounterMixin } from "@/stores/mixin";
import { useLeaveStore } from "@/modules/05_leave/store"; import { useLeaveStore } from "@/modules/05_leave/store";
import type { FormRef } from "@/modules/05_leave/interface/request/VacationForm"; import type { FormRef } from "@/modules/05_leave/interface/request/VacationForm";
import type { DataOption } from "@/modules/14_IDP/interface/Main";
/** Use */ /** Use */
const $q = useQuasar(); const $q = useQuasar();
const dataStore = useLeaveStore(); const dataStore = useLeaveStore();
const mixin = useCounterMixin(); const mixin = useCounterMixin();
const { date2Thai, dateToISO, messageError } = mixin; const { date2Thai, messageError, convertDateToAPI } = mixin;
const edit = ref<boolean>(true); const edit = ref<boolean>(true);
const leaveId = ref<string>(""); const leaveId = ref<string>("");
@ -49,9 +49,8 @@ const formDataVacation = reactive<any>({
leaveStartDate: null, leaveStartDate: null,
leaveEndDate: null, leaveEndDate: null,
leaveTotal: "", leaveTotal: "",
leaveNumber: "",
leaveAddress: "",
leaveDetail: "", leaveDetail: "",
leaveRangeEnd: "ALL",
leaveDocument: [], leaveDocument: [],
}); });
@ -95,20 +94,6 @@ const fileUploadDoc = async (files: any) => {
const leaveDocumentList = ref<any>(); const leaveDocumentList = ref<any>();
const statusCheck = ref<string>(""); const statusCheck = ref<string>("");
/** ฟังก์ชั่นแปลงค่า ครึ่งวัน/ทั้งวัน */
const isReadOnly = computed(() => {
const conditionleaveRange =
formDataVacation.leaveRange === "MORNING" ||
formDataVacation.leaveRange === "AFTERNOON";
if (conditionleaveRange) {
formDataVacation.leaveEndDate = formDataVacation.leaveStartDate; // Set formDataVacation.leaveEndDate to null
formDataVacation.leaveTotal = 0.5;
} else {
formDataVacation.leaveTotal = null;
}
return conditionleaveRange;
});
/** แจ้งเมื่อวันลาไม่ถูกต้อง */ /** แจ้งเมื่อวันลาไม่ถูกต้อง */
const dateEndInputStyle = computed(() => { const dateEndInputStyle = computed(() => {
return !isLeave.value ? "input-alert" : ""; return !isLeave.value ? "input-alert" : "";
@ -136,17 +121,18 @@ function onValidate() {
// formData.append("leaveDocument", formDataVacation.leaveDocument); // formData.append("leaveDocument", formDataVacation.leaveDocument);
formData.append("type", formDataVacation.type); formData.append("type", formDataVacation.type);
formData.append("leaveRange", formDataVacation.leaveRange); formData.append("leaveRange", formDataVacation.leaveRange);
formData.append("leaveRangeEnd", formDataVacation.leaveRangeEnd);
formData.append( formData.append(
"leaveStartDate", "leaveStartDate",
dateToISO(new Date(formDataVacation.leaveStartDate)) convertDateToAPI(formDataVacation.leaveStartDate) ?? ""
); );
formData.append( formData.append(
"leaveEndDate", "leaveEndDate",
dateToISO(new Date(formDataVacation.leaveEndDate)) convertDateToAPI(formDataVacation.leaveEndDate) ?? ""
); );
formData.append("leaveWrote", formDataVacation.leaveWrote); formData.append("leaveWrote", formDataVacation.leaveWrote);
formData.append("leaveAddress", formDataVacation.leaveAddress); formData.append("leaveAddress", dataStore.currentAddress);
formData.append("leaveNumber", formDataVacation.leaveNumber); formData.append("leaveNumber", dataStore.telephoneNumber);
formData.append("leaveDetail", formDataVacation.leaveDetail); formData.append("leaveDetail", formDataVacation.leaveDetail);
formData.append("leaveTotal", formDataVacation.leaveTotal); formData.append("leaveTotal", formDataVacation.leaveTotal);
props.onSubmit(formData, isLeave.value); props.onSubmit(formData, isLeave.value);
@ -160,74 +146,92 @@ function onValidate() {
const isLeave = ref<boolean>(true); const isLeave = ref<boolean>(true);
const reasonLeave = ref<string>(""); const reasonLeave = ref<string>("");
async function fetchCheck() { const checkDate = computed(() => {
await http
.post(config.API.leaveCheck(), {
type: dataStore.typeId ?? null,
StartLeaveDate: formDataVacation.leaveStartDate ?? null,
EndLeaveDate: formDataVacation.leaveEndDate ?? null,
})
.then((res: any) => {
const data = res.data.result;
isLeave.value = data.isLeave;
formDataVacation.leaveTotal =
data.totalDate - data.sumDateWork - data.sumDateHoliday;
reasonLeave.value = data.message
? data.message
: "จำนวนวันลาเกินที่กำหนด";
})
.catch((e: any) => {
messageError($q, e);
});
}
/**
* function เซทค leaveStartDate เเละ leaveEndDate
*/
function resetDate() {
if ( if (
formDataVacation.leaveRange === "MORNING" || convertDateToAPI(formDataVacation.leaveEndDate) ==
formDataVacation.leaveRange === "AFTERNOON" convertDateToAPI(formDataVacation.leaveStartDate)
) { ) {
formDataVacation.leaveStartDate = null; return true;
formDataVacation.leaveEndDate = null; } else {
} return false;
}
watch(props.data, () => {
if (props.data) {
formDataVacation.leaveWrote = props.data.leaveWrote;
formDataVacation.restDayOldTotal = props.data.restDayOldTotal;
formDataVacation.restDayCurrentTotal = props.data.restDayCurrentTotal;
formDataVacation.leaveStartDate = props.data.leaveStartDate;
formDataVacation.leaveEndDate = props.data.leaveEndDate;
formDataVacation.leaveTotal = props.data.leaveTotal;
formDataVacation.leaveNumber = props.data.leaveNumber;
formDataVacation.leaveAddress = props.data.leaveAddress;
formDataVacation.leaveDetail = props.data.leaveDetail;
leaveDocumentList.value = props.data.leaveDocument;
statusCheck.value = props.data.status;
formDataVacation.leaveRange = props.data.leaveRange;
formDataVacation.leaveDocument = [];
} }
}); });
const isLoadCheck = ref<boolean>(false);
async function fetchCheck() {
if (formDataVacation.leaveStartDate && formDataVacation.leaveEndDate) {
isLoadCheck.value = true;
await http
.post(config.API.leaveCheck(), {
type: dataStore.typeId ?? null,
StartLeaveDate:
convertDateToAPI(formDataVacation.leaveStartDate) ?? null,
EndLeaveDate: convertDateToAPI(formDataVacation.leaveEndDate) ?? null,
leaveRange: formDataVacation.leaveRange,
leaveRangeEnd: checkDate.value
? formDataVacation.leaveRange
: formDataVacation.leaveRangeEnd,
})
.then((res: any) => {
const data = res.data.result;
formDataVacation.leaveTotal =
data.totalDate - data.sumDateWork - data.sumDateHoliday;
reasonLeave.value =
data.message != ""
? data.message
: formDataVacation.leaveTotal > 0
? "จำนวนวันลาเกินที่กำหนด"
: "ช่วงวันลาที่ระบุไม่ถูกต้อง";
isLeave.value = formDataVacation.leaveTotal > 0 ? data.isLeave : false;
})
.catch((e: any) => {
messageError($q, e);
})
.finally(() => {
isLoadCheck.value = false;
});
}
}
watch(
() => props.data,
() => {
if (props.data) {
formDataVacation.leaveWrote = props.data.leaveWrote;
formDataVacation.restDayOldTotal = props.data.restDayOldTotal;
formDataVacation.restDayCurrentTotal = props.data.restDayCurrentTotal;
formDataVacation.leaveStartDate = props.data.leaveStartDate;
formDataVacation.leaveEndDate = props.data.leaveEndDate;
formDataVacation.leaveTotal = props.data.leaveTotal;
formDataVacation.leaveDetail = props.data.leaveDetail;
formDataVacation.leaveRangeEnd = props.data.leaveRangeEnd;
leaveDocumentList.value = props.data.leaveDocument;
statusCheck.value = props.data.status;
formDataVacation.leaveRange = props.data.leaveRange;
formDataVacation.leaveDocument = [];
}
}
);
/**Hook */ /**Hook */
onMounted(() => { onMounted(() => {
if (props.data) { if (props.data) {
// totalCheck.value = null;
formDataVacation.leaveWrote = props.data.leaveWrote; formDataVacation.leaveWrote = props.data.leaveWrote;
formDataVacation.restDayOldTotal = props.data.restDayOldTotal; formDataVacation.restDayOldTotal = props.data.restDayOldTotal;
formDataVacation.restDayCurrentTotal = props.data.restDayCurrentTotal; formDataVacation.restDayCurrentTotal = props.data.restDayCurrentTotal;
formDataVacation.leaveStartDate = props.data.leaveStartDate; formDataVacation.leaveStartDate = props.data.leaveStartDate;
formDataVacation.leaveEndDate = props.data.leaveEndDate; formDataVacation.leaveEndDate = props.data.leaveEndDate;
formDataVacation.leaveTotal = props.data.leaveTotal; formDataVacation.leaveTotal = props.data.leaveTotal;
formDataVacation.leaveNumber = props.data.leaveNumber;
formDataVacation.leaveAddress = props.data.leaveAddress;
formDataVacation.leaveDetail = props.data.leaveDetail; formDataVacation.leaveDetail = props.data.leaveDetail;
leaveDocumentList.value = props.data.leaveDocument; leaveDocumentList.value = props.data.leaveDocument;
statusCheck.value = props.data.status; statusCheck.value = props.data.status;
formDataVacation.leaveRange = props.data.leaveRange; formDataVacation.leaveRange = props.data.leaveRange;
formDataVacation.leaveRangeEnd = props.data.leaveRangeEnd;
leaveId.value = props.data.id; leaveId.value = props.data.id;
} }
}); });
@ -241,20 +245,173 @@ onMounted(() => {
<form @submit.prevent.stop="onValidate"> <form @submit.prevent.stop="onValidate">
<q-card bordered class="q-pa-md bg-grey-1"> <q-card bordered class="q-pa-md bg-grey-1">
<div class="row q-pa-sm q-col-gutter-sm"> <div class="row q-pa-sm q-col-gutter-sm">
<q-input <div class="col-12 inputgreen">
class="col-12 col-sm-12 cursor-pointer inputgreen" <q-input
ref="leaveWroteRef" ref="leaveWroteRef"
for="leaveWroteRef" for="leaveWroteRef"
dense dense
hide-bottom-space hide-bottom-space
bg-color="white" bg-color="white"
outlined outlined
v-model="formDataVacation.leaveWrote" v-model="formDataVacation.leaveWrote"
label="เขียนที่" label="เขียนที่"
:readonly="!edit || statusCheck === 'NEW'" :readonly="!edit || statusCheck === 'NEW'"
:rules="[(val:string) => !!val || `${'เขียนที่'}`]" :rules="[(val:string) => !!val || `${'กรุณากรอกเขียนที่'}`]"
/> />
<div class="col-12 col-md-4 col-sm-6"> </div>
<div class="col-12">
<div class="row q-col-gutter-sm">
<div class="col-12 col-md-3 col-sm-6 inputgreen">
<datepicker
v-model="formDataVacation.leaveStartDate"
:locale="'th'"
autoApply
hide-bottom-space
borderless
:enableTimePicker="false"
week-start="0"
:readonly="!edit || statusCheck === 'NEW'"
@update:model-value="
(formDataVacation.leaveEndDate = null), fetchCheck()
"
>
<template #year="{ year }">
{{ year + 543 }}
</template>
<template #year-overlay-value="{ value }">
{{ parseInt(value + 543) }}
</template>
<template #trigger>
<q-input
outlined
dense
ref="leaveStartDateRef"
for="leaveStartDateRef"
hide-bottom-space
bg-color="white"
:readonly="!edit || statusCheck === 'NEW'"
class="full-width datepicker"
:model-value="
formDataVacation.leaveStartDate != null
? date2Thai(formDataVacation.leaveStartDate)
: 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 class="col-12 col-md-3 col-sm-6 inputgreen">
<q-select
outlined
dense
bg-color="white"
v-model="formDataVacation.leaveRange"
:options="dataStore.rangeOptions"
emit-value
map-options
option-value="id"
option-label="name"
@update:model-value="fetchCheck()"
>
<template v-slot:prepend>
<q-icon
name="mdi-clock-outline"
style="color: var(--q-primary)"
/>
</template>
</q-select>
</div>
</div>
</div>
<div class="col-12">
<div class="row q-col-gutter-sm">
<div class="col-12 col-md-3 col-sm-6 inputgreen">
<datepicker
v-model="formDataVacation.leaveEndDate"
:locale="'th'"
autoApply
hide-bottom-space
@update:model-value="fetchCheck()"
borderless
:enableTimePicker="false"
week-start="0"
:min-date="formDataVacation.leaveStartDate"
>
<template #year="{ year }">
{{ year + 543 }}
</template>
<template #year-overlay-value="{ value }">
{{ parseInt(value + 543) }}
</template>
<template #trigger>
<q-input
outlined
dense
ref="leaveEndDateRef"
for="leaveEndDateRef"
hide-bottom-space
bg-color="white"
class="full-width datepicker"
:model-value="
formDataVacation.leaveEndDate != null
? date2Thai(formDataVacation.leaveEndDate)
: 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 class="col-12 col-md-3 col-sm-6 inputgreen">
<q-select
v-if="!checkDate"
outlined
dense
bg-color="white"
v-model="formDataVacation.leaveRangeEnd"
:options="dataStore.rangeOptions.filter((items:DataOption)=> items.id !== 'AFTERNOON')"
emit-value
map-options
option-value="id"
option-label="name"
@update:model-value="fetchCheck()"
>
<template v-slot:prepend>
<q-icon
name="mdi-clock-outline"
style="color: var(--q-primary)"
/>
</template>
</q-select>
</div>
</div>
</div>
<!-- <div class="col-12 col-md-4 col-sm-6">
<q-radio <q-radio
v-model="formDataVacation.leaveRange" v-model="formDataVacation.leaveRange"
val="ALL" val="ALL"
@ -275,220 +432,135 @@ onMounted(() => {
checked-icon="task_alt" checked-icon="task_alt"
@update:model-value="resetDate" @update:model-value="resetDate"
/> />
</div> -->
<div class="col-12 col-md-3 col-sm-6">
<q-input
:bottom-slots="!isLeave ? true : false"
:color="!isLeave ? 'red' : 'black'"
:bg-color="!isLeave ? 'red-2' : 'white'"
:border-color="!isLeave ? 'red' : 'gray'"
:input-class="!isLeave ? dateEndInputStyle : ''"
dense
outlined
ref="leaveTotalRef"
for="leaveTotalRef"
v-model="formDataVacation.leaveTotal"
label="จำนวนวันที่ลา (วัน)"
readonly
:loading="isLoadCheck"
>
<template v-slot:hint>
<span style="color: red">
{{ !isLeave ? reasonLeave : "" }}
</span>
</template>
</q-input>
</div> </div>
<q-input
class="col-12 col-md-4 col-sm-6"
ref="restDayOldTotalRef"
for="restDayOldTotalRef"
dense
hide-bottom-space
bg-color="white"
readonly
outlined
v-model="dataStore.restDayTotalOld"
label="จำนวนวันลาพักผ่อนสะสม จากปีที่ผ่านมา"
/>
<q-input <div class="col-12 col-md-3 col-sm-6">
class="col-12 col-md-4 col-sm-6" <q-input
ref="restDayCurrentTotalRef" ref="restDayOldTotalRef"
for="restDayCurrentTotalRef" for="restDayOldTotalRef"
dense dense
readonly hide-bottom-space
hide-bottom-space bg-color="white"
bg-color="white" readonly
outlined outlined
v-model="dataStore.restDayCurrentTotal" v-model="dataStore.restDayTotalOld"
label="จำนวนวันลาพักผ่อนประจำปีปัจจุบัน" label="จำนวนวันลาพักผ่อนสะสม จากปีที่ผ่านมา"
/> />
</div>
<datepicker <div class="col-12 col-md-3 col-sm-6">
class="col-12 col-md-3 col-sm-6 cursor-pointer inputgreen" <q-input
menu-class-name="modalfix" ref="restDayCurrentTotalRef"
v-model="formDataVacation.leaveStartDate" for="restDayCurrentTotalRef"
:locale="'th'" dense
autoApply readonly
hide-bottom-space hide-bottom-space
borderless bg-color="white"
:enableTimePicker="false" outlined
week-start="0" v-model="dataStore.restDayCurrentTotal"
:readonly="!edit || statusCheck === 'NEW'" label="จำนวนวันลาพักผ่อนประจำปีปัจจุบัน"
@update:model-value="formDataVacation.leaveEndDate = null" />
> </div>
<template #year="{ year }">
{{ year + 543 }}
</template>
<template #year-overlay-value="{ value }">
{{ parseInt(value + 543) }}
</template>
<template #trigger>
<q-input
outlined
dense
ref="leaveStartDateRef"
for="leaveStartDateRef"
hide-bottom-space
bg-color="white"
:readonly="!edit || statusCheck === 'NEW'"
class="full-width datepicker"
:model-value="
formDataVacation.leaveStartDate != null
? date2Thai(formDataVacation.leaveStartDate)
: 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>
<datepicker
class="col-12 col-md-3 col-sm-6 cursor-pointer inputgreen"
menu-class-name="modalfix"
v-model="formDataVacation.leaveEndDate"
:locale="'th'"
autoApply
hide-bottom-space
@update:model-value="fetchCheck()"
borderless
:enableTimePicker="false"
week-start="0"
:readonly="isReadOnly"
:min-date="formDataVacation.leaveStartDate"
>
<template #year="{ year }">
{{ year + 543 }}
</template>
<template #year-overlay-value="{ value }">
{{ parseInt(value + 543) }}
</template>
<template #trigger>
<q-input
outlined
dense
ref="leaveEndDateRef"
for="leaveEndDateRef"
hide-bottom-space
bg-color="white"
class="full-width datepicker"
:readonly="isReadOnly"
:model-value="
formDataVacation.leaveEndDate != null
? date2Thai(formDataVacation.leaveEndDate)
: null
"
:label="`${'ลาถึงวันที่'}`"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
style="color: var(--q-primary)"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
<q-input
:bottom-slots="!isLeave ? true : false"
:color="!isLeave ? 'red' : 'black'"
:bg-color="!isLeave ? 'red-2' : 'white'"
:border-color="!isLeave ? 'red' : 'gray'"
:input-class="!isLeave ? dateEndInputStyle : ''"
class="col-12 col-md-2 col-sm-6"
dense
outlined
ref="leaveTotalRef"
for="leaveTotalRef"
v-model="formDataVacation.leaveTotal"
label="จำนวนวันที่ลา"
readonly
>
<template v-slot:hint>
<span style="color: red">
{{ !isLeave ? reasonLeave : "" }}
</span>
</template>
</q-input>
<div class="full-width"> <div class="full-width">
<div class="q-col-gutter-sm row"> <div class="q-col-gutter-sm row">
<q-input <div class="col-12 col-md-3 col-sm-12 inputgreen">
class="col-12 col-md-3 col-sm-12 cursor-pointer inputgreen" <q-input
dense dense
outlined outlined
hide-bottom-space hide-bottom-space
bg-color="white" bg-color="white"
ref="leaveNumberRef" ref="leaveNumberRef"
for="leaveNumberRef" for="leaveNumberRef"
v-model="formDataVacation.leaveNumber" v-model="dataStore.telephoneNumber"
mask="(###)-###-####" mask="(###)-###-####"
unmasked-value lazy-rules
label="หมายเลขโทรศัพท์ที่ติดต่อได้" unmasked-value
:readonly="!edit || statusCheck === 'NEW'" label="หมายเลขโทรศัพท์ที่ติดต่อได้"
:rules="[ :readonly="!edit || statusCheck === 'NEW'"
:rules="[
(val:string) => !!val || `${'กรุณากรอกหมายเลขโทรศัพท์ที่ติดต่อได้'}`, (val:string) => !!val || `${'กรุณากรอกหมายเลขโทรศัพท์ที่ติดต่อได้'}`,
]" ]"
/> />
</div>
<q-input <div class="col-12 col-md-9 col-sm-12 inputgreen">
class="col-12 col-md-9 col-sm-6 cursor-pointer inputgreen" <q-input
dense dense
outlined outlined
hide-bottom-space hide-bottom-space
bg-color="white" bg-color="white"
ref="leaveAddressRef" ref="leaveAddressRef"
for="leaveAddressRef" for="leaveAddressRef"
v-model="formDataVacation.leaveAddress" v-model="dataStore.currentAddress"
label="ที่อยู่ที่ติดต่อได้ระหว่างลา" label="ที่อยู่ที่ติดต่อได้ระหว่างลา"
:readonly="!edit || statusCheck === 'NEW'" :readonly="!edit || statusCheck === 'NEW'"
:rules="[ :rules="[
(val:string) => !!val || `${'กรุณากรอกที่อยู่ที่ติดต่อได้ระหว่างลา'}`, (val:string) => !!val || `${'กรุณากรอกที่อยู่ที่ติดต่อได้ระหว่างลา'}`,
]" ]"
/> />
</div>
</div> </div>
</div> </div>
<q-input
type="textarea" <div class="col-12 inputgreen">
hide-bottom-space <q-input
bg-color="white" type="textarea"
class="col-12 col-md-12 col-sm-12 cursor-pointer inputgreen" hide-bottom-space
dense bg-color="white"
outlined dense
ref="leaveDetailRef" outlined
for="leaveDetailRef" ref="leaveDetailRef"
v-model="formDataVacation.leaveDetail" for="leaveDetailRef"
label="รายละเอียด" v-model="formDataVacation.leaveDetail"
:readonly="!edit || statusCheck === 'NEW'" label="สาเหตุการลา"
/> :readonly="!edit || statusCheck === 'NEW'"
/>
</div>
<div class="full-width" v-if="statusCheck != 'NEW'"> <div class="full-width" v-if="statusCheck != 'NEW'">
<div class="q-col-gutter-sm row"> <div class="q-col-gutter-sm row">
<!-- multiple --> <!-- multiple -->
<q-file <div class="q-pl-sm col-12">
ref="leaveDocumentRef" <q-file
bg-color="white" ref="leaveDocumentRef"
v-model="formDataVacation.leaveDocument" bg-color="white"
@added="fileUploadDoc" v-model="formDataVacation.leaveDocument"
dense @added="fileUploadDoc"
label="เอกสารประกอบ" dense
multiple label="เอกสารประกอบ"
outlined multiple
use-chips outlined
class="q-pl-sm col-12" use-chips
> >
<template v-slot:prepend> <template v-slot:prepend>
<q-icon name="attach_file" color="primary" /> <q-icon name="attach_file" color="primary" />
</template> </template>
</q-file> </q-file>
</div>
</div> </div>
</div> </div>
<div class="col-12" v-if="data"> <div class="col-12" v-if="data">
@ -548,30 +620,33 @@ onMounted(() => {
</q-card> </q-card>
<q-separator class="q-mt-sm" /> <q-separator class="q-mt-sm" />
<div class="row col-12 q-pt-md"> <div class="row col-12 q-pt-md items-center">
<q-space /> <q-space />
<q-btn <q-btn
v-if="!props.data || props.data.status == 'DRAFT'" v-if="!props.data || props.data.status == 'DRAFT'"
id="onSubmit" id="onSubmit"
type="submit" type="submit"
unelevated unelevated
dense :disable="!isLeave"
class="q-px-md items-center btnBlue" class="q-px-md items-center btnBlue"
label="บันทึก" label="บันทึก"
><q-tooltip>นทกแบบราง</q-tooltip></q-btn :loading="isLoadCheck"
> >
<q-tooltip>นทกแบบราง</q-tooltip>
</q-btn>
<q-btn <q-btn
v-if="data && statusCheck != 'NEW'" v-if="data && statusCheck != 'NEW'"
id="onSubmit" id="onSubmit"
type="button" type="button"
unelevated unelevated
dense
class="q-px-md items-center q-ml-sm" class="q-px-md items-center q-ml-sm"
color="primary" color="primary"
label="ยื่นใบลา" label="ยื่นใบลา"
@click="onConfirm()" @click="onConfirm()"
><q-tooltip>นใบลา</q-tooltip></q-btn :loading="isLoadCheck"
> >
<q-tooltip>นใบลา</q-tooltip>
</q-btn>
</div> </div>
</form> </form>
</template> </template>

View file

@ -13,10 +13,17 @@ import type { HajiForm } from "@/modules/05_leave/interface/request/AddAbsence";
const dataStore = useLeaveStore(); const dataStore = useLeaveStore();
const $q = useQuasar(); const $q = useQuasar();
const mixin = useCounterMixin(); const mixin = useCounterMixin();
const { date2Thai, calculateDurationYmd, messageError, dateToISO } = mixin; const {
date2Thai,
calculateDurationYmd,
messageError,
convertDateToAPI,
} = mixin;
const edit = ref<boolean>(true); const edit = ref<boolean>(true);
const leaveId = ref<any>(""); const leaveId = ref<any>("");
const leaveText = ref<string>("");
/** ตัวแปร ref สำหรับแสดง validate */ /** ตัวแปร ref สำหรับแสดง validate */
const leaveWroteRef = ref<object | null>(null); const leaveWroteRef = ref<object | null>(null);
@ -52,10 +59,12 @@ const formDataHaji = reactive<any>({
leavegovernmentDate: null, leavegovernmentDate: null,
leaveStartDate: null, leaveStartDate: null,
leaveEndDate: null, leaveEndDate: null,
totalLeave: 0, leaveTotal: 0,
hajjDayStatus: "true", hajjDayStatus: true,
leaveDocument: [], leaveDocument: [],
leaveDetail: "", leaveDetail: "",
leaveRange: "ALL",
leaveRangeEnd: "ALL",
}); });
/** maping ref เข้าตัวแปรเพื่อเตรียมตรวจสอบ */ /** maping ref เข้าตัวแปรเพื่อเตรียมตรวจสอบ */
@ -68,7 +77,6 @@ const formRef: HajiForm = {
}; };
/** ส่วนของการประกาศและเลือกไฟล์เอกสารประกอบ */ /** ส่วนของการประกาศและเลือกไฟล์เอกสารประกอบ */
const nameFile = ref<string>("");
const fileDocDataUpload = ref<File[]>([]); const fileDocDataUpload = ref<File[]>([]);
const fileUploadDoc = async (files: any) => { const fileUploadDoc = async (files: any) => {
files.forEach((file: any) => { files.forEach((file: any) => {
@ -99,16 +107,19 @@ function onValidate() {
formData.append("type", formDataHaji.type); formData.append("type", formDataHaji.type);
formData.append( formData.append(
"leaveStartDate", "leaveStartDate",
dateToISO(new Date(formDataHaji.leaveStartDate)) convertDateToAPI(formDataHaji.leaveStartDate) ?? ""
); );
formData.append( formData.append(
"leaveEndDate", "leaveEndDate",
dateToISO(new Date(formDataHaji.leaveEndDate)) convertDateToAPI(formDataHaji.leaveEndDate) ?? ""
); );
formData.append("hajjDayStatus", formDataHaji.hajjDayStatus); formData.append("hajjDayStatus", formDataHaji.hajjDayStatus);
formData.append("leaveWrote", formDataHaji.leaveWrote); formData.append("leaveWrote", formDataHaji.leaveWrote);
formData.append("leaveDetail", formDataHaji.leaveDetail); formData.append("leaveDetail", formDataHaji.leaveDetail);
formData.append("leaveTotal", formDataHaji.leaveTotal); formData.append("leaveTotal", formDataHaji.leaveTotal);
formData.append("leaveRange", formDataHaji.leaveRange);
formData.append("leaveRangeEnd", formDataHaji.leaveRangeEnd);
formData.append("hajj", "true");
props.onSubmit(formData, isLeave.value); props.onSubmit(formData, isLeave.value);
} }
} }
@ -119,36 +130,54 @@ function onValidate() {
*/ */
const isLeave = ref<boolean>(true); const isLeave = ref<boolean>(true);
const reasonLeave = ref<string>(""); const reasonLeave = ref<string>("");
const checkDate = computed(() => {
if (
convertDateToAPI(formDataHaji.leaveEndDate) ==
convertDateToAPI(formDataHaji.leaveStartDate)
) {
return true;
} else {
return false;
}
});
const isLoadCheck = ref<boolean>(false);
async function fetchCheck() { async function fetchCheck() {
await http if (formDataHaji.leaveStartDate && formDataHaji.leaveEndDate) {
.post(config.API.leaveCheck(), { isLoadCheck.value = true;
type: dataStore.typeId ?? null, await http
StartLeaveDate: formDataHaji.leaveStartDate ?? null, .post(config.API.leaveCheck(), {
EndLeaveDate: formDataHaji.leaveEndDate ?? null, type: dataStore.typeId ?? null,
}) StartLeaveDate: convertDateToAPI(formDataHaji.leaveStartDate) ?? null,
.then((res: any) => { EndLeaveDate: convertDateToAPI(formDataHaji.leaveEndDate) ?? null,
const data = res.data.result; leaveRange: formDataHaji.leaveRange,
isLeave.value = data.isLeave; leaveRangeEnd: checkDate.value
formDataHaji.leaveTotal = data.totalDate; ? formDataHaji.leaveRange
: formDataHaji.leaveRangeEnd,
reasonLeave.value = data.message })
? data.message .then((res: any) => {
: "จำนวนวันลาเกินที่กำหนด"; const data = res.data.result;
}) formDataHaji.leaveTotal = data.totalDate;
.catch((e: any) => { leaveText.value = calculateDurationYmd(
messageError($q, e); convertDateToAPI(formDataHaji.leaveStartDate),
}); convertDateToAPI(formDataHaji.leaveEndDate)
} );
reasonLeave.value =
/** data.message != ""
* function พเดทค LeaveTotal ? data.message
*/ : formDataHaji.leaveTotal > 0
function updateLeaveTotal() { ? "จำนวนวันลาเกินที่กำหนด"
const newLeaveTotal = calculateDurationYmd( : "ช่วงวันลาที่ระบุไม่ถูกต้อง";
formDataHaji.leaveStartDate, isLeave.value = formDataHaji.leaveTotal > 0 ? data.isLeave : false;
formDataHaji.leaveEndDate })
); .catch((e: any) => {
formDataHaji.leaveTotal = newLeaveTotal; messageError($q, e);
})
.finally(() => {
isLoadCheck.value = false;
});
}
} }
/** แจ้งเมื่อวันลาไม่ถูกต้อง */ /** แจ้งเมื่อวันลาไม่ถูกต้อง */
@ -159,32 +188,39 @@ const dateEndInputStyle = computed(() => {
/** ตรวจสอบว่ามีการส่งข้อมูลเข้ามาที่ฟอร์มไหม เมื่อมีการส่งจะ map ข้อมูลเข้า v-model ของฟอร์ม */ /** ตรวจสอบว่ามีการส่งข้อมูลเข้ามาที่ฟอร์มไหม เมื่อมีการส่งจะ map ข้อมูลเข้า v-model ของฟอร์ม */
const leaveDocumentList = ref<any>(); const leaveDocumentList = ref<any>();
const statusCheck = ref<any>(""); const statusCheck = ref<any>("");
watch(props.data, () => { watch(
if (props.data) { () => props.data,
formDataHaji.leaveWrote = props.data.leaveWrote; async () => {
formDataHaji.leaveTotal = props.data.leaveTotal; if (props.data) {
formDataHaji.leaveStartDate = props.data.leaveStartDate; // totalCheck.value = null;
formDataHaji.leaveEndDate = props.data.leaveEndDate; formDataHaji.leaveWrote = props.data.leaveWrote;
formDataHaji.totalLeave = props.data.totalLeave; formDataHaji.leaveTotal = props.data.leaveTotal;
formDataHaji.hajjDayStatus = props.data.hajjDayStatus; formDataHaji.leaveStartDate = props.data.leaveStartDate;
formDataHaji.leaveDetail = props.data.leaveDetail; formDataHaji.leaveEndDate = props.data.leaveEndDate;
leaveDocumentList.value = props.data.leaveDocument; formDataHaji.hajjDayStatus = props.data.hajjDayStatus;
statusCheck.value = props.data.status; formDataHaji.leaveDetail = props.data.leaveDetail;
formDataHaji.leaveDocument = []; formDataHaji.leaveRangeEnd = props.data.leaveRangeEnd;
formDataHaji.leaveRange = props.data.leaveRange;
leaveDocumentList.value = props.data.leaveDocument;
statusCheck.value = props.data.status;
formDataHaji.leaveDocument = [];
}
} }
}); );
/**Hook */ /**Hook */
onMounted(() => { onMounted(async () => {
if (props.data) { if (props.data) {
// totalCheck.value = null;
formDataHaji.leaveWrote = props.data.leaveWrote; formDataHaji.leaveWrote = props.data.leaveWrote;
formDataHaji.leaveTotal = props.data.leaveTotal; formDataHaji.leaveTotal = props.data.leaveTotal;
formDataHaji.leaveStartDate = props.data.leaveStartDate; formDataHaji.leaveStartDate = props.data.leaveStartDate;
formDataHaji.leaveEndDate = props.data.leaveEndDate; formDataHaji.leaveEndDate = props.data.leaveEndDate;
formDataHaji.totalLeave = props.data.totalLeave;
formDataHaji.hajjDayStatus = props.data.hajjDayStatus; formDataHaji.hajjDayStatus = props.data.hajjDayStatus;
formDataHaji.leaveDetail = props.data.leaveDetail; formDataHaji.leaveDetail = props.data.leaveDetail;
leaveDocumentList.value = props.data.leaveDocument; leaveDocumentList.value = props.data.leaveDocument;
formDataHaji.leaveRange = props.data.leaveRange;
formDataHaji.leaveRangeEnd = props.data.leaveRangeEnd;
statusCheck.value = props.data.status; statusCheck.value = props.data.status;
// formDataHaji.leaveDocument = props.data.leaveDocument; // formDataHaji.leaveDocument = props.data.leaveDocument;
leaveId.value = props.data.id; leaveId.value = props.data.id;
@ -203,7 +239,7 @@ onMounted(() => {
<q-input <q-input
v-model="formDataHaji.leaveWrote" v-model="formDataHaji.leaveWrote"
ref="leaveWroteRef" ref="leaveWroteRef"
class="col-12 col-sm-12 cursor-pointer inputgreen" class="col-12 col-sm-12 inputgreen"
bg-color="white" bg-color="white"
dense dense
outlined outlined
@ -213,19 +249,21 @@ onMounted(() => {
:rules="[(val:string) => !!val || `${'เขียนที่'}`]" :rules="[(val:string) => !!val || `${'เขียนที่'}`]"
/> />
<div class="full-width"> <div class="col-12">
<div class="q-col-gutter-sm row"> <div class="row q-col-gutter-sm">
<datepicker <datepicker
class="col-12 col-md-3 col-sm-6 inputgreen"
v-model="formDataHaji.leaveStartDate" v-model="formDataHaji.leaveStartDate"
class="col-12 col-md-4 col-sm-6 cursor-pointer inputgreen"
menu-class-name="modalfix"
autoApply
borderless
week-start="0"
:enableTimePicker="false"
:locale="'th'" :locale="'th'"
autoApply
hide-bottom-space
borderless
:enableTimePicker="false"
week-start="0"
:readonly="!edit || statusCheck === 'NEW'" :readonly="!edit || statusCheck === 'NEW'"
@update:model-value="formDataHaji.leaveEndDate = null" @update:model-value="
(formDataHaji.leaveEndDate = null), fetchCheck()
"
> >
<template #year="{ year }"> <template #year="{ year }">
{{ year + 543 }} {{ year + 543 }}
@ -235,20 +273,21 @@ onMounted(() => {
</template> </template>
<template #trigger> <template #trigger>
<q-input <q-input
ref="leaveStartDateRef"
bg-color="white"
class="full-width datepicker"
outlined outlined
dense dense
ref="leaveStartDateRef"
for="leaveStartDateRef"
hide-bottom-space hide-bottom-space
:label="`${'ลาตั้งแต่วันที่'}`" bg-color="white"
:readonly="!edit || statusCheck === 'NEW'" :readonly="!edit || statusCheck === 'NEW'"
:rules="[(val:string) => !!val || `${'กรุณาเลือกลาตั้งแต่วันที่'}`]" class="full-width datepicker"
:model-value=" :model-value="
formDataHaji.leaveStartDate != null formDataHaji.leaveStartDate != null
? date2Thai(formDataHaji.leaveStartDate) ? date2Thai(formDataHaji.leaveStartDate)
: null : null
" "
:label="`${'วันที่เริ่มต้น'}`"
:rules="[(val:string) => !!val || `${'กรุณาเลือกวันที่เริ่มต้น'}`]"
> >
<template v-slot:prepend> <template v-slot:prepend>
<q-icon <q-icon
@ -261,18 +300,40 @@ onMounted(() => {
</q-input> </q-input>
</template> </template>
</datepicker> </datepicker>
<q-select
outlined
dense
class="col-12 col-md-3 col-sm-6 inputgreen"
bg-color="white"
v-model="formDataHaji.leaveRange"
:options="dataStore.rangeOptions"
emit-value
map-options
option-value="id"
option-label="name"
@update:model-value="fetchCheck()"
>
<template v-slot:prepend>
<q-icon
name="mdi-clock-outline"
style="color: var(--q-primary)"
/>
</template>
</q-select>
</div>
</div>
<div class="col-12">
<div class="row q-col-gutter-sm">
<datepicker <datepicker
class="col-12 col-md-3 col-sm-6 inputgreen"
v-model="formDataHaji.leaveEndDate" v-model="formDataHaji.leaveEndDate"
class="col-12 col-md-4 col-sm-6 cursor-pointer inputgreen"
menu-class-name="modalfix"
autoApply
borderless
week-start="0"
:enableTimePicker="false"
:locale="'th'" :locale="'th'"
@update:model-value="updateLeaveTotal(), fetchCheck()" autoApply
:readonly="!formDataHaji.leaveStartDate || statusCheck === 'NEW'" hide-bottom-space
@update:model-value="fetchCheck()"
borderless
:enableTimePicker="false"
week-start="0"
:min-date="formDataHaji.leaveStartDate" :min-date="formDataHaji.leaveStartDate"
> >
<template #year="{ year }"> <template #year="{ year }">
@ -283,22 +344,20 @@ onMounted(() => {
</template> </template>
<template #trigger> <template #trigger>
<q-input <q-input
ref="leaveEndDateRef"
class="full-width datepicker"
bg-color="white"
outlined outlined
dense dense
:readonly=" ref="leaveEndDateRef"
!formDataHaji.leaveStartDate || statusCheck === 'NEW' for="leaveEndDateRef"
"
hide-bottom-space hide-bottom-space
:label="`${'ลาถึงวันที่'}`" bg-color="white"
class="full-width datepicker"
:model-value=" :model-value="
formDataHaji.leaveEndDate != null formDataHaji.leaveEndDate != null
? date2Thai(formDataHaji.leaveEndDate) ? date2Thai(formDataHaji.leaveEndDate)
: null : null
" "
@update:model-value="fetchCheck()" :label="`${'วันที่สิ้นสุด'}`"
:rules="[(val:string) => !!val || `${'กรุณาเลือกวันที่สิ้นสุด'}`]"
> >
<template v-slot:prepend> <template v-slot:prepend>
<q-icon <q-icon
@ -311,32 +370,58 @@ onMounted(() => {
</q-input> </q-input>
</template> </template>
</datepicker> </datepicker>
<q-select
<q-input v-if="!checkDate"
:bottom-slots="!isLeave ? true : false"
:color="!isLeave ? 'red' : 'black'"
:bg-color="!isLeave ? 'red-2' : 'white'"
:border-color="!isLeave ? 'red' : 'gray'"
:input-class="!isLeave ? dateEndInputStyle : ''"
class="col-12 col-md-2 col-sm-6"
dense
outlined outlined
ref="leaveTotalRef" dense
for="leaveTotalRef" class="col-12 col-md-3 col-sm-6 inputgreen"
v-model="formDataHaji.leaveTotal" bg-color="white"
label="จำนวนวันที่ลา" v-model="formDataHaji.leaveRangeEnd"
readonly :options="dataStore.rangeOptions.filter((items:any)=> items.id !== 'AFTERNOON')"
emit-value
map-options
option-value="id"
option-label="name"
@update:model-value="fetchCheck()"
> >
<template v-slot:hint> <template v-slot:prepend>
<span style="color: red"> <q-icon
{{ !isLeave ? reasonLeave : "" }} name="mdi-clock-outline"
</span> style="color: var(--q-primary)"
/>
</template> </template>
</q-input> </q-select>
</div>
</div>
<div class="full-width">
<div class="q-col-gutter-sm row">
<div class="col-12 col-md-3 col-sm-6">
<q-input
:bottom-slots="!isLeave ? true : false"
:color="!isLeave ? 'red' : 'black'"
:bg-color="!isLeave ? 'red-2' : 'white'"
:border-color="!isLeave ? 'red' : 'gray'"
:input-class="!isLeave ? dateEndInputStyle : ''"
dense
outlined
ref="leaveTotalRef"
for="leaveTotalRef"
v-model="formDataHaji.leaveTotal"
label="จำนวนวันที่ลา (วัน)"
readonly
:loading="isLoadCheck"
>
<template v-slot:hint>
<span style="color: red">
{{ !isLeave ? reasonLeave : "" }}
</span>
</template>
</q-input>
</div>
<datepicker <datepicker
class="col-12 col-md-4 col-sm-6" class="col-12 col-md-3 col-sm-6"
menu-class-name="modalfix"
autoApply autoApply
borderless borderless
readonly readonly
@ -390,29 +475,31 @@ onMounted(() => {
<q-radio <q-radio
v-model="formDataHaji.hajjDayStatus" v-model="formDataHaji.hajjDayStatus"
:disable="statusCheck === 'NEW'" :disable="statusCheck === 'NEW'"
:val="'true'" :val="true"
checked-icon="task_alt" checked-icon="task_alt"
label="เคย" label="เคย"
/> />
<q-radio <q-radio
v-model="formDataHaji.hajjDayStatus" v-model="formDataHaji.hajjDayStatus"
:disable="statusCheck === 'NEW'" :disable="statusCheck === 'NEW'"
:val="'false'" :val="false"
checked-icon="task_alt" checked-icon="task_alt"
label="ไม่เคยไปประกอบพิธีฮัจญ์" label="ไม่เคยไปประกอบพิธีฮัจญ์"
/> />
</div> </div>
<q-input <div class="col-12 inputgreen">
v-model="formDataHaji.leaveDetail" <q-input
class="col-12 q-mt-sm cursor-pointer inputgreen" v-model="formDataHaji.leaveDetail"
bg-color="white" :readonly="!edit || statusCheck === 'NEW'"
dense bg-color="white"
outlined dense
type="textarea" outlined
label="รายละเอียด" type="textarea"
:readonly="!edit || statusCheck === 'NEW'" label="สาเหตุการลา"
/> />
</div>
<div class="full-width" v-if="statusCheck != 'NEW'"> <div class="full-width" v-if="statusCheck != 'NEW'">
<div class="q-col-gutter-sm row"> <div class="q-col-gutter-sm row">
<!-- multiple --> <!-- multiple -->
@ -492,28 +579,32 @@ onMounted(() => {
<q-separator class="q-mt-sm" /> <q-separator class="q-mt-sm" />
<div class="row col-12 q-pt-md"> <div class="row col-12 q-pt-md">
<q-space /> <q-space />
<!-- <div v-if="totalCheck == 0" class="text-red q-mr-sm">**จำนวนวันลาของท่านไม่ถูกต้อง หรือวันที่ยื่นลาของท่านตรงกับวันหยุด</div> -->
<q-btn <q-btn
v-if="!props.data || props.data.status == 'DRAFT'" v-if="!props.data || props.data.status == 'DRAFT'"
id="onSubmit" id="onSubmit"
type="submit" type="submit"
unelevated unelevated
dense
class="q-px-md items-center btnBlue" class="q-px-md items-center btnBlue"
label="บันทึก" label="บันทึก"
><q-tooltip>นทกแบบราง</q-tooltip></q-btn :disable="!isLeave"
:loading="isLoadCheck"
> >
<q-tooltip>นทกแบบราง</q-tooltip>
</q-btn>
<q-btn <q-btn
v-if="data && statusCheck != 'NEW'" v-if="data && statusCheck != 'NEW'"
id="onSubmit" id="onSubmit"
type="button" type="button"
unelevated unelevated
dense
class="q-px-md items-center q-ml-sm" class="q-px-md items-center q-ml-sm"
color="primary" color="primary"
label="ยื่นใบลา" label="ยื่นใบลา"
@click="onConfirm()" @click="onConfirm()"
><q-tooltip>นใบลา</q-tooltip></q-btn :loading="isLoadCheck"
> >
<q-tooltip>นใบลา</q-tooltip>
</q-btn>
</div> </div>
</form> </form>
</template> </template>

View file

@ -13,10 +13,11 @@ import type { MilitaryForm } from "@/modules/05_leave/interface/request/AddAbsen
const dataStore = useLeaveStore(); const dataStore = useLeaveStore();
const $q = useQuasar(); const $q = useQuasar();
const mixin = useCounterMixin(); const mixin = useCounterMixin();
const { date2Thai, calculateDurationYmd, dateToISO, messageError } = mixin; const { date2Thai, calculateDurationYmd, messageError, convertDateToAPI } =
mixin;
const edit = ref<boolean>(true); const edit = ref<boolean>(true);
const leaveId = ref<string>(""); const leaveId = ref<string>("");
const leaveText = ref<string>("");
/** ตัวแปร ref สำหรับแสดง validate */ /** ตัวแปร ref สำหรับแสดง validate */
const leaveStartDateRef = ref<object | null>(null); const leaveStartDateRef = ref<object | null>(null);
const leaveEndDateRef = ref<object | null>(null); const leaveEndDateRef = ref<object | null>(null);
@ -60,6 +61,8 @@ const formDataMilitary = reactive<any>({
absentDayLocation: "", absentDayLocation: "",
absentDayRegistorDate: null, absentDayRegistorDate: null,
absentDayGetIn: "", absentDayGetIn: "",
leaveRange: "ALL",
leaveRangeEnd: "ALL",
absentDayAt: "", absentDayAt: "",
leaveDetail: "", leaveDetail: "",
}); });
@ -117,84 +120,112 @@ function onValidate() {
formData.append("type", formDataMilitary.type); formData.append("type", formDataMilitary.type);
formData.append( formData.append(
"leaveStartDate", "leaveStartDate",
dateToISO(new Date(formDataMilitary.leaveStartDate)) convertDateToAPI(formDataMilitary.leaveStartDate) ?? ""
); );
formData.append( formData.append(
"leaveEndDate", "leaveEndDate",
dateToISO(new Date(formDataMilitary.leaveEndDate)) convertDateToAPI(formDataMilitary.leaveEndDate) ?? ""
); );
formData.append("absentDaySummon", formDataMilitary.absentDaySummon); formData.append("absentDaySummon", formDataMilitary.absentDaySummon);
formData.append("absentDayLocation", formDataMilitary.absentDayLocation); formData.append("absentDayLocation", formDataMilitary.absentDayLocation);
formData.append( formData.append(
"absentDayRegistorDate", "absentDayRegistorDate",
dateToISO(new Date(formDataMilitary.absentDayRegistorDate)) convertDateToAPI(formDataMilitary.absentDayRegistorDate) ?? ""
); );
formData.append("absentDayGetIn", formDataMilitary.absentDayGetIn); formData.append("absentDayGetIn", formDataMilitary.absentDayGetIn);
formData.append("absentDayAt", formDataMilitary.absentDayAt); formData.append("absentDayAt", formDataMilitary.absentDayAt);
formData.append("leaveWrote", formDataMilitary.leaveWrote); formData.append("leaveWrote", formDataMilitary.leaveWrote);
formData.append("leaveDetail", formDataMilitary.leaveDetail); formData.append("leaveDetail", formDataMilitary.leaveDetail);
formData.append("leaveTotal", formDataMilitary.leaveTotal); formData.append("leaveTotal", formDataMilitary.leaveTotal);
formData.append("leaveRange", formDataMilitary.leaveRange);
formData.append("leaveRangeEnd", formDataMilitary.leaveRangeEnd);
props.onSubmit(formData, isLeave.value); props.onSubmit(formData, isLeave.value);
} }
} }
const reasonLeave = ref<string>(""); const reasonLeave = ref<string>("");
/** const checkDate = computed(() => {
* check าลาไดไหม จาก api if (
* @param formData convertDateToAPI(formDataMilitary.leaveEndDate) ==
*/ convertDateToAPI(formDataMilitary.leaveStartDate)
async function fetchCheck() { ) {
await http return true;
.post(config.API.leaveCheck(), { } else {
type: dataStore.typeId ?? null, return false;
StartLeaveDate: formDataMilitary.leaveStartDate ?? null,
EndLeaveDate: formDataMilitary.leaveEndDate ?? null,
})
.then((res: any) => {
const data = res.data.result;
isLeave.value = data.isLeave;
formDataMilitary.leaveTotal = data.totalDate;
reasonLeave.value = data.message
? data.message
: "จำนวนวันลาเกินที่กำหนด";
})
.catch((e: any) => {
messageError($q, e);
});
}
/**
* function พเดทค LeaveTotal
*/
function updateLeaveTotal() {
const newLeaveTotal = calculateDurationYmd(
formDataMilitary.leaveStartDate,
formDataMilitary.leaveEndDate
);
formDataMilitary.leaveTotal = newLeaveTotal;
}
watch(props.data, () => {
if (props.data) {
formDataMilitary.leaveWrote = props.data.leaveWrote;
formDataMilitary.leaveStartDate = props.data.leaveStartDate;
formDataMilitary.leaveEndDate = props.data.leaveEndDate;
formDataMilitary.leaveTotal = props.data.leaveTotal;
formDataMilitary.absentDaySummon = props.data.absentDaySummon;
formDataMilitary.absentDayLocation = props.data.absentDayLocation;
formDataMilitary.absentDayRegistorDate = props.data.absentDayRegistorDate;
formDataMilitary.absentDayGetIn = props.data.absentDayGetIn;
formDataMilitary.absentDayAt = props.data.absentDayAt;
formDataMilitary.leaveDetail = props.data.leaveDetail;
leaveDocumentList.value = props.data.leaveDocument;
statusCheck.value = props.data.status;
formDataMilitary.leaveDocument = [];
} }
}); });
const isLoadCheck = ref<boolean>(false);
/** check ว่าลาได้ไหม จาก api*/
async function fetchCheck() {
if (formDataMilitary.leaveStartDate && formDataMilitary.leaveEndDate) {
isLoadCheck.value = true;
await http
.post(config.API.leaveCheck(), {
type: dataStore.typeId ?? null,
StartLeaveDate:
convertDateToAPI(formDataMilitary.leaveStartDate) ?? null,
EndLeaveDate: convertDateToAPI(formDataMilitary.leaveEndDate) ?? null,
leaveRange: formDataMilitary.leaveRange,
leaveRangeEnd: checkDate.value
? formDataMilitary.leaveRange
: formDataMilitary.leaveRangeEnd,
})
.then((res: any) => {
const data = res.data.result;
isLeave.value = data.isLeave;
formDataMilitary.leaveTotal = data.totalDate;
leaveText.value = calculateDurationYmd(
convertDateToAPI(formDataMilitary.leaveStartDate),
convertDateToAPI(formDataMilitary.leaveEndDate)
);
reasonLeave.value =
data.message != "" ? data.message : "จำนวนวันลาเกินที่กำหนด";
})
.catch((e: any) => {
messageError($q, e);
})
.finally(() => {
isLoadCheck.value = false;
});
}
}
watch(
() => props.data,
async () => {
if (props.data) {
// totalCheck.value = null;
formDataMilitary.leaveWrote = props.data.leaveWrote;
formDataMilitary.leaveStartDate = props.data.leaveStartDate;
formDataMilitary.leaveEndDate = props.data.leaveEndDate;
formDataMilitary.leaveTotal = props.data.leaveTotal;
formDataMilitary.absentDaySummon = props.data.absentDaySummon;
formDataMilitary.absentDayLocation = props.data.absentDayLocation;
formDataMilitary.absentDayRegistorDate = props.data.absentDayRegistorDate;
formDataMilitary.absentDayGetIn = props.data.absentDayGetIn;
formDataMilitary.absentDayAt = props.data.absentDayAt;
formDataMilitary.leaveRange = props.data.leaveRange;
formDataMilitary.leaveRangeEnd = props.data.leaveRangeEnd;
const leaveTotal = await calculateDurationYmd(
props.data.leaveStartDate,
props.data.leaveEndDate
);
leaveText.value = leaveTotal;
formDataMilitary.leaveDetail = props.data.leaveDetail;
leaveDocumentList.value = props.data.leaveDocument;
statusCheck.value = props.data.status;
formDataMilitary.leaveDocument = [];
}
}
);
/**Hook */ /**Hook */
onMounted(() => { onMounted(async () => {
if (props.data) { if (props.data) {
// totalCheck.value = null;
formDataMilitary.leaveWrote = props.data.leaveWrote; formDataMilitary.leaveWrote = props.data.leaveWrote;
formDataMilitary.leaveStartDate = props.data.leaveStartDate; formDataMilitary.leaveStartDate = props.data.leaveStartDate;
formDataMilitary.leaveEndDate = props.data.leaveEndDate; formDataMilitary.leaveEndDate = props.data.leaveEndDate;
@ -205,6 +236,14 @@ onMounted(() => {
formDataMilitary.absentDayGetIn = props.data.absentDayGetIn; formDataMilitary.absentDayGetIn = props.data.absentDayGetIn;
formDataMilitary.absentDayAt = props.data.absentDayAt; formDataMilitary.absentDayAt = props.data.absentDayAt;
formDataMilitary.leaveDetail = props.data.leaveDetail; formDataMilitary.leaveDetail = props.data.leaveDetail;
formDataMilitary.leaveRange = props.data.leaveRange;
formDataMilitary.leaveRangeEnd = props.data.leaveRangeEnd;
const leaveTotal = await calculateDurationYmd(
props.data.leaveStartDate,
props.data.leaveEndDate
);
leaveText.value = leaveTotal;
leaveDocumentList.value = props.data.leaveDocument; leaveDocumentList.value = props.data.leaveDocument;
statusCheck.value = props.data.status; statusCheck.value = props.data.status;
leaveId.value = props.data.id; leaveId.value = props.data.id;
@ -220,172 +259,236 @@ onMounted(() => {
<form @submit.prevent="onValidate"> <form @submit.prevent="onValidate">
<q-card bordered class="q-pa-md bg-grey-1"> <q-card bordered class="q-pa-md bg-grey-1">
<div class="row q-pa-sm q-col-gutter-sm"> <div class="row q-pa-sm q-col-gutter-sm">
<q-input <div class="col-12 inputgreen">
ref="leaveWroteRef" <q-input
class="col-12 col-sm-12 cursor-pointer inputgreen" ref="leaveWroteRef"
dense dense
outlined outlined
bg-color="white" bg-color="white"
hide-bottom-space hide-bottom-space
v-model="formDataMilitary.leaveWrote" v-model="formDataMilitary.leaveWrote"
label="เขียนที่" label="เขียนที่"
:readonly="!edit || statusCheck === 'NEW'" :readonly="!edit || statusCheck === 'NEW'"
:rules="[(val:string) => !!val || `${'เขียนที่'}`]" :rules="[(val:string) => !!val || `${'เขียนที่'}`]"
/> />
</div>
<datepicker <div class="col-12">
class="col-12 col-md-4 col-sm-6 cursor-pointer inputgreen" <div class="row q-col-gutter-sm">
menu-class-name="modalfix" <div class="col-12 col-md-3 col-sm-6 inputgreen">
v-model="formDataMilitary.leaveStartDate" <datepicker
:locale="'th'" v-model="formDataMilitary.leaveStartDate"
autoApply :locale="'th'"
borderless autoApply
:enableTimePicker="false" hide-bottom-space
week-start="0" borderless
:readonly="!edit || statusCheck === 'NEW'" :enableTimePicker="false"
@update:model-value="formDataMilitary.leaveEndDate = null" week-start="0"
> :readonly="!edit || statusCheck === 'NEW'"
<template #year="{ year }"> @update:model-value="
{{ year + 543 }} (formDataMilitary.leaveEndDate = null), fetchCheck()
</template> "
<template #year-overlay-value="{ value }"> >
{{ parseInt(value + 543) }} <template #year="{ year }">
</template> {{ year + 543 }}
<template #trigger> </template>
<q-input <template #year-overlay-value="{ value }">
outlined {{ parseInt(value + 543) }}
bg-color="white" </template>
dense <template #trigger>
ref="leaveStartDateRef" <q-input
hide-bottom-space outlined
:readonly="!edit || statusCheck === 'NEW'" dense
class="full-width datepicker" ref="leaveStartDateRef"
:model-value=" for="leaveStartDateRef"
formDataMilitary.leaveStartDate != null hide-bottom-space
? date2Thai(formDataMilitary.leaveStartDate) bg-color="white"
: null :readonly="!edit || statusCheck === 'NEW'"
" class="full-width datepicker"
:label="`${'ลาตั้งแต่วันที่'}`" :model-value="
:rules="[(val:string) => !!val || `${'กรุณาเลือกลาตั้งแต่วันที่'}`]" formDataMilitary.leaveStartDate != null
> ? date2Thai(formDataMilitary.leaveStartDate)
<template v-slot:prepend> : null
<q-icon "
name="event" :label="`${'วันที่เริ่มต้น'}`"
class="cursor-pointer" :rules="[(val:string) => !!val || `${'กรุณาเลือกวันที่เริ่มต้น'}`]"
style="color: var(--q-primary)" >
> <template v-slot:prepend>
</q-icon> <q-icon
</template> name="event"
</q-input> class="cursor-pointer"
</template> style="color: var(--q-primary)"
</datepicker> >
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<datepicker <!-- <div class="col-12 col-sm-3 inputgreen">
class="col-12 col-md-4 col-sm-6 cursor-pointer inputgreen" <q-select
menu-class-name="modalfix" outlined
v-model="formDataMilitary.leaveEndDate" dense
:locale="'th'" bg-color="white"
autoApply v-model="formDataMilitary.leaveRange"
borderless :options="dataStore.rangeOptions"
:enableTimePicker="false" emit-value
week-start="0" map-options
@update:model-value="updateLeaveTotal, fetchCheck()" option-value="id"
:readonly="!formDataMilitary.leaveStartDate || statusCheck === 'NEW'" option-label="name"
:min-date="formDataMilitary.leaveStartDate" @update:model-value="fetchCheck()"
> >
<template #year="{ year }"> <template v-slot:prepend>
{{ year + 543 }} <q-icon
</template> name="mdi-clock-outline"
<template #year-overlay-value="{ value }"> style="color: var(--q-primary)"
{{ parseInt(value + 543) }} />
</template> </template>
<template #trigger> </q-select>
<q-input </div> -->
outlined <!-- </div>
dense </div>
ref="leaveEndDateRef"
bg-color="white"
hide-bottom-space
:readonly="
!formDataMilitary.leaveStartDate || statusCheck === 'NEW'
"
class="full-width datepicker"
:model-value="
formDataMilitary.leaveEndDate != null
? date2Thai(formDataMilitary.leaveEndDate)
: null
"
:label="`${'ลาถึงวันที่'}`"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
style="color: var(--q-primary)"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
<q-input <div class="col-12">
:bottom-slots="!isLeave ? true : false" <div class="row q-col-gutter-sm"> -->
:color="!isLeave ? 'red' : 'black'" <div class="col-12 col-md-3 col-sm-6 inputgreen">
:bg-color="!isLeave ? 'red-2' : 'white'" <datepicker
:border-color="!isLeave ? 'red' : 'gray'" v-model="formDataMilitary.leaveEndDate"
:input-class="!isLeave ? dateEndInputStyle : ''" :locale="'th'"
class="col-12 col-md-2 col-sm-6" autoApply
dense hide-bottom-space
outlined @update:model-value="fetchCheck()"
ref="leaveTotalRef" borderless
for="leaveTotalRef" :enableTimePicker="false"
v-model="formDataMilitary.leaveTotal" week-start="0"
label="จำนวนวันที่ลา" :min-date="formDataMilitary.leaveStartDate"
readonly >
> <template #year="{ year }">
<template v-slot:hint> {{ year + 543 }}
<span style="color: red"> </template>
{{ !isLeave ? reasonLeave : "" }} <template #year-overlay-value="{ value }">
</span> {{ parseInt(value + 543) }}
</template> </template>
</q-input> <template #trigger>
<q-input
outlined
dense
ref="leaveEndDateRef"
for="leaveEndDateRef"
hide-bottom-space
bg-color="white"
class="full-width datepicker"
:model-value="
formDataMilitary.leaveEndDate != null
? date2Thai(formDataMilitary.leaveEndDate)
: 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 class="col-12 col-sm-3 inputgreen">
<q-select
v-if="!checkDate"
outlined
dense
bg-color="white"
v-model="formDataMilitary.leaveRangeEnd"
:options="dataStore.rangeOptions.filter((items:any)=> items.id !== 'AFTERNOON')"
emit-value
map-options
option-value="id"
option-label="name"
@update:model-value="fetchCheck()"
>
<template v-slot:prepend>
<q-icon
name="mdi-clock-outline"
style="color: var(--q-primary)"
/>
</template>
</q-select>
</div> -->
<!-- </div>
</div>
<div class="full-width"> <div class="full-width">
<div class="q-col-gutter-sm row"> <div class="q-col-gutter-sm row"> -->
<q-input <div class="col-12 col-md-3 col-sm-6">
ref="absentDaySummonRef" <q-input
class="col-12 col-sm-6 col-md-4 cursor-pointer inputgreen" :bottom-slots="!isLeave ? true : false"
dense :color="!isLeave ? 'red' : 'black'"
bg-color="white" :bg-color="!isLeave ? 'red-2' : 'white'"
outlined :border-color="!isLeave ? 'red' : 'gray'"
v-model="formDataMilitary.absentDaySummon" :input-class="!isLeave ? dateEndInputStyle : ''"
label="ได้รับหมายเรียกของ" dense
hide-bottom-space outlined
:readonly="!edit || statusCheck === 'NEW'" ref="leaveTotalRef"
:rules="[(val:string) => !!val || `${'กรุณากรอกได้รับหมายเรียกของ'}`]" for="leaveTotalRef"
/> v-model="leaveText"
label="จำนวนวันที่ลา"
readonly
:loading="isLoadCheck"
>
<template v-slot:hint>
<span style="color: red">
{{ !isLeave ? reasonLeave : "" }}
</span>
</template>
</q-input>
</div>
</div>
</div>
<q-input <div class="col-12">
ref="atRef" <div class="row q-col-gutter-sm">
class="col-12 col-sm-6 col-md-4 cursor-pointer inputgreen" <div class="col-12 col-md-8 col-sm-6 inputgreen">
dense <q-input
bg-color="white" ref="absentDaySummonRef"
outlined dense
v-model="formDataMilitary.absentDayLocation" bg-color="white"
label="ที่" outlined
hide-bottom-space v-model="formDataMilitary.absentDaySummon"
:readonly="!edit || statusCheck === 'NEW'" label="ได้รับหมายเรียกของ"
:rules="[(val:string) => !!val || `${'กรุณากรอกที่'}`]" hide-bottom-space
/> :readonly="!edit || statusCheck === 'NEW'"
:rules="[(val:string) => !!val || `${'กรุณากรอกได้รับหมายเรียกของ'}`]"
/>
</div>
<div class="col-12 col-md-4 col-sm-6 inputgreen">
<q-input
ref="atRef"
dense
bg-color="white"
outlined
v-model="formDataMilitary.absentDayLocation"
label="ที่"
hide-bottom-space
:readonly="!edit || statusCheck === 'NEW'"
:rules="[(val:string) => !!val || `${'กรุณากรอกที่'}`]"
/>
</div>
</div> </div>
</div> </div>
<div class="full-width"> <div class="full-width">
<div class="q-col-gutter-sm row"> <div class="q-col-gutter-sm row">
<datepicker <datepicker
class="col-12 col-md-4 col-sm-6 cursor-pointer inputgreen" class="col-12 col-md-4 col-sm-6 inputgreen"
menu-class-name="modalfix"
v-model="formDataMilitary.absentDayRegistorDate" v-model="formDataMilitary.absentDayRegistorDate"
:locale="'th'" :locale="'th'"
autoApply autoApply
@ -430,7 +533,7 @@ onMounted(() => {
</datepicker> </datepicker>
<q-input <q-input
class="col-12 col-sm-6 col-md-4 cursor-pointer inputgreen" class="col-12 col-md-4 col-sm-6 inputgreen"
dense dense
bg-color="white" bg-color="white"
ref="absentDayGetInRef" ref="absentDayGetInRef"
@ -443,7 +546,7 @@ onMounted(() => {
/> />
<q-input <q-input
class="col-12 col-sm-6 col-md-4 cursor-pointer inputgreen" class="col-12 col-md-4 col-sm-12 inputgreen"
dense dense
bg-color="white" bg-color="white"
outlined outlined
@ -457,16 +560,17 @@ onMounted(() => {
</div> </div>
</div> </div>
<q-input <div class="col-12 inputgreen">
class="col-12 col-md-12 col-sm-12 cursor-pointer inputgreen" <q-input
dense v-model="formDataMilitary.leaveDetail"
:readonly="!edit || statusCheck === 'NEW'" :readonly="!edit || statusCheck === 'NEW'"
bg-color="white" bg-color="white"
outlined dense
v-model="formDataMilitary.leaveDetail" outlined
type="textarea" type="textarea"
label="รายละเอียด" label="สาเหตุการลา"
/> />
</div>
<div class="col-12" v-if="statusCheck != 'NEW'"> <div class="col-12" v-if="statusCheck != 'NEW'">
<!-- multiple --> <!-- multiple -->
@ -544,28 +648,32 @@ onMounted(() => {
<q-separator class="q-mt-sm" /> <q-separator class="q-mt-sm" />
<div class="row col-12 q-pt-md"> <div class="row col-12 q-pt-md">
<q-space /> <q-space />
<!-- <div v-if="totalCheck == 0" class="text-red q-mr-sm">**จำนวนวันลาของท่านไม่ถูกต้อง หรือวันที่ยื่นลาของท่านตรงกับวันหยุด</div> -->
<q-btn <q-btn
v-if="!props.data || props.data.status == 'DRAFT'" v-if="!props.data || props.data.status == 'DRAFT'"
id="onSubmit" id="onSubmit"
type="submit" type="submit"
unelevated unelevated
dense
class="q-px-md items-center btnBlue" class="q-px-md items-center btnBlue"
label="บันทึก" label="บันทึก"
><q-tooltip>นทกแบบราง</q-tooltip></q-btn :disable="!isLeave"
:loading="isLoadCheck"
> >
<q-tooltip>นทกแบบราง</q-tooltip>
</q-btn>
<q-btn <q-btn
v-if="data && statusCheck != 'NEW'" v-if="data && statusCheck != 'NEW'"
id="onSubmit" id="onSubmit"
type="button" type="button"
unelevated unelevated
dense
class="q-px-md items-center q-ml-sm" class="q-px-md items-center q-ml-sm"
color="primary" color="primary"
label="ยื่นใบลา" label="ยื่นใบลา"
@click="onConfirm()" @click="onConfirm()"
><q-tooltip>นใบลา</q-tooltip></q-btn :loading="isLoadCheck"
> >
<q-tooltip>นใบลา</q-tooltip>
</q-btn>
</div> </div>
</form> </form>
</template> </template>

File diff suppressed because it is too large Load diff

View file

@ -17,10 +17,11 @@ const {
date2Thai, date2Thai,
arabicNumberToText, arabicNumberToText,
calculateDurationYmd, calculateDurationYmd,
dateToISO,
messageError, messageError,
convertDateToAPI,
} = mixin; } = mixin;
const leaveText = ref<string>("");
const edit = ref<boolean>(true); const edit = ref<boolean>(true);
const leaveId = ref<any>(""); const leaveId = ref<any>("");
@ -54,11 +55,11 @@ const formDataTrain = reactive<any>({
leavegovernmentDate: new Date(), leavegovernmentDate: new Date(),
leaveSalary: 10000, leaveSalary: 10000,
leaveSalaryText: arabicNumberToText(10000), leaveSalaryText: arabicNumberToText(10000),
leaveNumber: "",
leaveAddress: "",
studyDayScholarship: "", studyDayScholarship: "",
studyDayCountry: "", studyDayCountry: "",
studyDayTrainingSubject: "", studyDayTrainingSubject: "",
leaveRange: "ALL",
leaveRangeEnd: "ALL",
studyDayTrainingName: "", studyDayTrainingName: "",
leaveDocument: [], leaveDocument: [],
leaveDetail: "", leaveDetail: "",
@ -124,11 +125,11 @@ function onValidate() {
formData.append("type", formDataTrain.type); // formData.append("type", formDataTrain.type); //
formData.append( formData.append(
"leaveStartDate", "leaveStartDate",
dateToISO(new Date(formDataTrain.leaveStartDate)) convertDateToAPI(formDataTrain.leaveStartDate) ?? ""
); // ); //
formData.append( formData.append(
"leaveEndDate", "leaveEndDate",
dateToISO(new Date(formDataTrain.leaveEndDate)) convertDateToAPI(formDataTrain.leaveEndDate) ?? ""
); // ); //
formData.append("studyDayCountry", formDataTrain.studyDayCountry); formData.append("studyDayCountry", formDataTrain.studyDayCountry);
formData.append("studyDayTrainingName", formDataTrain.studyDayTrainingName); formData.append("studyDayTrainingName", formDataTrain.studyDayTrainingName);
@ -139,80 +140,104 @@ function onValidate() {
formData.append("leaveWrote", formDataTrain.leaveWrote); // formData.append("leaveWrote", formDataTrain.leaveWrote); //
formData.append("leaveDetail", formDataTrain.leaveDetail); // formData.append("leaveDetail", formDataTrain.leaveDetail); //
formData.append("studyDayScholarship", formDataTrain.studyDayScholarship); formData.append("studyDayScholarship", formDataTrain.studyDayScholarship);
formData.append("leaveAddress", formDataTrain.leaveAddress); // formData.append("leaveAddress", dataStore.currentAddress); //
formData.append("leaveNumber", formDataTrain.leaveNumber); // formData.append("leaveNumber", dataStore.telephoneNumber); //
formData.append("leaveSalaryText", formDataTrain.leaveSalaryText); // formData.append("leaveSalaryText", formDataTrain.leaveSalaryText); //
formData.append("leaveSalary", formDataTrain.leaveSalary); // formData.append("leaveSalary", formDataTrain.leaveSalary); //
formData.append("leaveTotal", formDataTrain.leaveTotalDay); // formData.append("leaveTotal", formDataTrain.leaveTotal); //
formData.append("leaveRange", formDataTrain.leaveRange);
formData.append("leaveRangeEnd", formDataTrain.leaveRangeEnd);
props.onSubmit(formData, isLeave.value); props.onSubmit(formData, isLeave.value);
} }
} }
const reasonLeave = ref<string>(""); const reasonLeave = ref<string>("");
async function fetchCheck() { const checkDate = computed(() => {
await http if (
.post(config.API.leaveCheck(), { convertDateToAPI(formDataTrain.leaveEndDate) ==
type: dataStore.typeId ?? null, convertDateToAPI(formDataTrain.leaveStartDate)
StartLeaveDate: formDataTrain.leaveStartDate ?? null, ) {
EndLeaveDate: formDataTrain.leaveEndDate ?? null, return true;
}) } else {
.then((res: any) => { return false;
const data = res.data.result;
isLeave.value = data.isLeave;
formDataTrain.leaveTotalDay = data.totalDate;
reasonLeave.value = data.message
? data.message
: "จำนวนวันลาเกินที่กำหนด";
})
.catch((e: any) => {
messageError($q, e);
});
}
/**
* function พเดทค LeaveTotal
*/
function updateLeaveTotal() {
const newLeaveTotal = calculateDurationYmd(
formDataTrain.leaveStartDate,
formDataTrain.leaveEndDate
);
formDataTrain.leaveTotal = newLeaveTotal;
}
watch(props.data, async () => {
if (props.data) {
formDataTrain.leaveWrote = props.data.leaveWrote;
formDataTrain.leaveStartDate = props.data.leaveStartDate;
formDataTrain.leaveEndDate = props.data.leaveEndDate;
formDataTrain.leaveTotal = props.data.leaveTotal;
formDataTrain.leavebirthDate = props.data.leavebirthDate;
formDataTrain.leavegovernmentDate = props.data.leavegovernmentDate;
formDataTrain.leaveSalary = props.data.leaveSalary;
formDataTrain.leaveSalaryText = props.data.leaveSalaryText;
formDataTrain.leaveNumber = props.data.leaveNumber;
formDataTrain.leaveAddress = props.data.leaveAddress;
formDataTrain.studyDayScholarship = props.data.studyDayScholarship;
formDataTrain.studyDayCountry = props.data.studyDayCountry;
formDataTrain.studyDayTrainingSubject = props.data.studyDayTrainingSubject;
formDataTrain.studyDayTrainingName = props.data.studyDayTrainingName;
formDataTrain.leaveDetail = props.data.leaveDetail;
formDataTrain.leaveDocument = [];
const leaveTotal = await calculateDurationYmd(
props.data.leaveStartDate,
props.data.leaveEndDate
);
formDataTrain.leaveTotal = leaveTotal;
leaveDocumentList.value = props.data.leaveDocument;
statusCheck.value = props.data.status;
} }
}); });
const isLoadCheck = ref<boolean>(false);
async function fetchCheck() {
if (formDataTrain.leaveStartDate && formDataTrain.leaveEndDate) {
isLoadCheck.value = true;
await http
.post(config.API.leaveCheck(), {
type: dataStore.typeId ?? null,
StartLeaveDate: convertDateToAPI(formDataTrain.leaveStartDate) ?? null,
EndLeaveDate: convertDateToAPI(formDataTrain.leaveEndDate) ?? null,
leaveRange: formDataTrain.leaveRange,
leaveRangeEnd: checkDate.value
? formDataTrain.leaveRange
: formDataTrain.leaveRangeEnd,
})
.then((res: any) => {
const data = res.data.result;
isLeave.value = data.isLeave;
formDataTrain.leaveTotal = data.totalDate;
leaveText.value = calculateDurationYmd(
convertDateToAPI(formDataTrain.leaveStartDate),
convertDateToAPI(formDataTrain.leaveEndDate)
);
reasonLeave.value = data.message
? data.message
: "จำนวนวันลาเกินที่กำหนด";
})
.catch((e: any) => {
messageError($q, e);
})
.finally(() => {
isLoadCheck.value = false;
});
}
}
watch(
() => props.data,
async () => {
if (props.data) {
formDataTrain.leaveWrote = props.data.leaveWrote;
formDataTrain.leaveStartDate = props.data.leaveStartDate;
formDataTrain.leaveEndDate = props.data.leaveEndDate;
formDataTrain.leaveTotal = props.data.leaveTotal;
formDataTrain.leavebirthDate = props.data.leavebirthDate;
formDataTrain.leavegovernmentDate = props.data.leavegovernmentDate;
formDataTrain.leaveSalary = props.data.leaveSalary;
formDataTrain.leaveSalaryText = props.data.leaveSalaryText;
formDataTrain.studyDayScholarship = props.data.studyDayScholarship;
formDataTrain.studyDayCountry = props.data.studyDayCountry;
formDataTrain.studyDayTrainingSubject =
props.data.studyDayTrainingSubject;
formDataTrain.studyDayTrainingName = props.data.studyDayTrainingName;
formDataTrain.leaveDetail = props.data.leaveDetail;
formDataTrain.leaveRange = props.data.leaveRange;
formDataTrain.leaveRangeEnd = props.data.leaveRangeEnd;
formDataTrain.leaveDocument = [];
const leaveTotal = await calculateDurationYmd(
props.data.leaveStartDate,
props.data.leaveEndDate
);
leaveText.value = leaveTotal;
leaveDocumentList.value = props.data.leaveDocument;
statusCheck.value = props.data.status;
}
}
);
/**Hook */ /**Hook */
onMounted(async () => { onMounted(async () => {
if (props.data) { if (props.data) {
// totalCheck.value = null;
formDataTrain.leaveWrote = props.data.leaveWrote; formDataTrain.leaveWrote = props.data.leaveWrote;
formDataTrain.leaveStartDate = props.data.leaveStartDate; formDataTrain.leaveStartDate = props.data.leaveStartDate;
formDataTrain.leaveEndDate = props.data.leaveEndDate; formDataTrain.leaveEndDate = props.data.leaveEndDate;
@ -221,11 +246,13 @@ onMounted(async () => {
formDataTrain.leavegovernmentDate = props.data.leavegovernmentDate; formDataTrain.leavegovernmentDate = props.data.leavegovernmentDate;
formDataTrain.leaveSalary = props.data.leaveSalary; formDataTrain.leaveSalary = props.data.leaveSalary;
formDataTrain.leaveSalaryText = props.data.leaveSalaryText; formDataTrain.leaveSalaryText = props.data.leaveSalaryText;
formDataTrain.leaveNumber = props.data.leaveNumber;
formDataTrain.leaveAddress = props.data.leaveAddress;
formDataTrain.studyDayScholarship = props.data.studyDayScholarship; formDataTrain.studyDayScholarship = props.data.studyDayScholarship;
formDataTrain.studyDayCountry = props.data.studyDayCountry; formDataTrain.studyDayCountry = props.data.studyDayCountry;
formDataTrain.studyDayTrainingSubject = props.data.studyDayTrainingSubject; formDataTrain.studyDayTrainingSubject = props.data.studyDayTrainingSubject;
formDataTrain.leaveRange = props.data.leaveRange;
formDataTrain.leaveRangeEnd = props.data.leaveRangeEnd;
formDataTrain.studyDayTrainingName = props.data.studyDayTrainingName; formDataTrain.studyDayTrainingName = props.data.studyDayTrainingName;
formDataTrain.leaveDetail = props.data.leaveDetail; formDataTrain.leaveDetail = props.data.leaveDetail;
// formDataTrain.leaveDocument = props.data.leaveDocument; // formDataTrain.leaveDocument = props.data.leaveDocument;
@ -233,7 +260,7 @@ onMounted(async () => {
props.data.leaveStartDate, props.data.leaveStartDate,
props.data.leaveEndDate props.data.leaveEndDate
); );
formDataTrain.leaveTotal = leaveTotal; leaveText.value = leaveTotal;
leaveDocumentList.value = props.data.leaveDocument; leaveDocumentList.value = props.data.leaveDocument;
statusCheck.value = props.data.status; statusCheck.value = props.data.status;
leaveId.value = props.data.id; leaveId.value = props.data.id;
@ -249,312 +276,383 @@ onMounted(async () => {
<form @submit.prevent="onValidate"> <form @submit.prevent="onValidate">
<q-card bordered class="q-pa-md bg-grey-1"> <q-card bordered class="q-pa-md bg-grey-1">
<div class="row q-pa-sm q-col-gutter-sm"> <div class="row q-pa-sm q-col-gutter-sm">
<q-input <div class="col-12 inputgreen">
v-model="formDataTrain.leaveWrote" <q-input
ref="leaveWroteRef" v-model="formDataTrain.leaveWrote"
class="col-12 col-sm-12 cursor-pointer inputgreen" ref="leaveWroteRef"
bg-color="white" bg-color="white"
dense dense
outlined outlined
label="เขียนที่" label="เขียนที่"
:readonly="!edit || statusCheck === 'NEW'" :readonly="!edit || statusCheck === 'NEW'"
hide-bottom-space hide-bottom-space
:rules="[(val:string) => !!val || `${'เขียนที่'}`]" :rules="[(val:string) => !!val || `${'เขียนที่'}`]"
/> />
</div>
<datepicker <div class="col-12">
v-model="formDataTrain.leaveStartDate" <div class="row q-col-gutter-sm">
class="col-12 col-md-4 col-sm-6 cursor-pointer inputgreen" <div class="col-12 col-md-3 col-sm-6 inputgreen">
menu-class-name="modalfix" <datepicker
autoApply v-model="formDataTrain.leaveStartDate"
borderless :locale="'th'"
week-start="0" autoApply
:enableTimePicker="false" hide-bottom-space
:locale="'th'" borderless
:readonly="!edit || statusCheck === 'NEW'" :enableTimePicker="false"
@update:model-value="formDataTrain.leaveEndDate = null" week-start="0"
> :readonly="!edit || statusCheck === 'NEW'"
<template #year="{ year }"> @update:model-value="
{{ year + 543 }} (formDataTrain.leaveEndDate = null), fetchCheck()
</template> "
<template #year-overlay-value="{ value }"> >
{{ parseInt(value + 543) }} <template #year="{ year }">
</template> {{ year + 543 }}
<template #trigger> </template>
<q-input <template #year-overlay-value="{ value }">
ref="leaveStartDateRef" {{ parseInt(value + 543) }}
class="full-width datepicker" </template>
bg-color="white" <template #trigger>
outlined <q-input
dense outlined
lazy-rules dense
hide-bottom-space ref="leaveStartDateRef"
:readonly="!edit || statusCheck === 'NEW'" for="leaveStartDateRef"
:label="`${'ลาตั้งแต่วันที่'}`" hide-bottom-space
:model-value=" bg-color="white"
formDataTrain.leaveStartDate != null :readonly="!edit || statusCheck === 'NEW'"
? date2Thai(formDataTrain.leaveStartDate) class="full-width datepicker"
: null :model-value="
" formDataTrain.leaveStartDate != null
:rules="[(val:string) => !!val || `${'กรุณาเลือกลาตั้งแต่วันที่'}`]" ? date2Thai(formDataTrain.leaveStartDate)
> : null
<template v-slot:prepend> "
<q-icon :label="`${'วันที่เริ่มต้น'}`"
name="event" :rules="[(val:string) => !!val || `${'กรุณาเลือกวันที่เริ่มต้น'}`]"
class="cursor-pointer" >
style="color: var(--q-primary)" <template v-slot:prepend>
> <q-icon
</q-icon> name="event"
</template> class="cursor-pointer"
</q-input> style="color: var(--q-primary)"
</template> >
</datepicker> </q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<datepicker <!-- <div class="col-12 col-sm-3 inputgreen">
v-model="formDataTrain.leaveEndDate" <q-select
class="col-12 col-md-4 col-sm-6 cursor-pointer inputgreen" outlined
menu-class-name="modalfix" dense
autoApply bg-color="white"
borderless v-model="formDataTrain.leaveRange"
@update:model-value="updateLeaveTotal(), fetchCheck()" :options="dataStore.rangeOptions"
week-start="0" emit-value
:readonly="!formDataTrain.leaveStartDate || statusCheck === 'NEW'" map-options
:locale="'th'" option-value="id"
:enableTimePicker="false" option-label="name"
:min-date="formDataTrain.leaveStartDate" @update:model-value="fetchCheck()"
> >
<template #year="{ year }"> <template v-slot:prepend>
{{ year + 543 }} <q-icon
</template> name="mdi-clock-outline"
<template #year-overlay-value="{ value }"> style="color: var(--q-primary)"
{{ parseInt(value + 543) }} />
</template> </template>
<template #trigger> </q-select>
<q-input </div> -->
ref="leaveEndDateRef" <!-- </div>
class="full-width datepicker" </div>
outlined <div class="col-12">
dense <div class="row q-col-gutter-sm"> -->
lazy-rules <div class="col-12 col-md-3 col-sm-6 inputgreen">
bg-color="white" <datepicker
hide-bottom-space v-model="formDataTrain.leaveEndDate"
:label="`${'ลาถึงวันที่'}`" :locale="'th'"
:readonly="!formDataTrain.leaveStartDate || statusCheck === 'NEW'" autoApply
:model-value=" hide-bottom-space
formDataTrain.leaveEndDate != null @update:model-value="fetchCheck()"
? date2Thai(formDataTrain.leaveEndDate) borderless
: null :enableTimePicker="false"
" week-start="0"
> :min-date="formDataTrain.leaveStartDate"
<template v-slot:prepend> >
<q-icon <template #year="{ year }">
name="event" {{ year + 543 }}
class="cursor-pointer" </template>
style="color: var(--q-primary)" <template #year-overlay-value="{ value }">
> {{ parseInt(value + 543) }}
</q-icon> </template>
</template> <template #trigger>
</q-input> <q-input
</template> outlined
</datepicker> dense
ref="leaveEndDateRef"
for="leaveEndDateRef"
hide-bottom-space
bg-color="white"
class="full-width datepicker"
:model-value="
formDataTrain.leaveEndDate != null
? date2Thai(formDataTrain.leaveEndDate)
: 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>
<q-input <!-- <div class="col-12 col-sm-3 inputgreen">
class="col-12 col-md-2 col-sm-6" <q-select
dense v-if="!checkDate"
outlined outlined
ref="leaveTotalRef" dense
for="leaveTotalRef" bg-color="white"
v-model="formDataTrain.leaveTotal" v-model="formDataTrain.leaveRangeEnd"
label="มีกำหนด" :options="dataStore.rangeOptions.filter((items:any)=> items.id !== 'AFTERNOON')"
readonly emit-value
:bottom-slots="!isLeave ? true : false" map-options
:color="!isLeave ? 'red' : 'black'" option-value="id"
:bg-color="!isLeave ? 'red-2' : 'white'" option-label="name"
:border-color="!isLeave ? 'red' : 'gray'" @update:model-value="fetchCheck()"
:input-class="!isLeave ? dateEndInputStyle : ''" >
> <template v-slot:prepend>
<template v-slot:hint> <q-icon
<span style="color: red"> name="mdi-clock-outline"
{{ !isLeave ? reasonLeave : "" }} style="color: var(--q-primary)"
</span> />
</template> </template>
</q-input> </q-select>
</div> -->
<!-- </div>
</div>
<div class="full-width">
<div class="q-col-gutter-sm row"> -->
<div class="col-12 col-md-3 col-sm-6">
<q-input
:bottom-slots="!isLeave ? true : false"
:color="!isLeave ? 'red' : 'black'"
:bg-color="!isLeave ? 'red-2' : 'white'"
:border-color="!isLeave ? 'red' : 'gray'"
:input-class="!isLeave ? dateEndInputStyle : ''"
dense
outlined
ref="leaveTotalRef"
for="leaveTotalRef"
v-model="leaveText"
label="มีกำหนด"
readonly
:loading="isLoadCheck"
>
<template v-slot:hint>
<span style="color: red">
{{ !isLeave ? reasonLeave : "" }}
</span>
</template>
</q-input>
</div>
</div>
</div>
<div class="full-width"> <div class="full-width">
<div class="q-col-gutter-sm row"> <div class="q-col-gutter-sm row">
<datepicker <div class="col-12 col-sm-3">
v-model="formDataTrain.leavegovernmentDate" <datepicker
class="col-12 col-md-3 col-sm-6" v-model="formDataTrain.leavegovernmentDate"
menu-class-name="modalfix" autoApply
autoApply borderless
borderless week-start="0"
week-start="0" readonly
readonly :enableTimePicker="false"
:enableTimePicker="false" :locale="'th'"
:locale="'th'" >
> <template #year="{ year }">
<template #year="{ year }"> {{ year + 543 }}
{{ year + 543 }} </template>
</template> <template #year-overlay-value="{ value }">
<template #year-overlay-value="{ value }"> {{ parseInt(value + 543) }}
{{ parseInt(value + 543) }} </template>
</template> <template #trigger>
<template #trigger> <q-input
<q-input ref="leavegovernmentDateRef"
ref="leavegovernmentDateRef" class="full-width"
class="full-width" outlined
outlined readonly
readonly bg-color="white"
bg-color="white" dense
dense hide-bottom-space
hide-bottom-space :label="`${'วันที่เข้ารับราชการ'}`"
:label="`${'วันที่เข้ารับราชการ'}`" :model-value="
:model-value=" dataStore.dateAppoint != null
dataStore.dateAppoint != null ? date2Thai(dataStore.dateAppoint)
? date2Thai(dataStore.dateAppoint) : null
: null "
" :rules="[
:rules="[
(val:string) => !!val || `${'กรุณาเลือกวันที่เข้ารับราชการ'}`, (val:string) => !!val || `${'กรุณาเลือกวันที่เข้ารับราชการ'}`,
]" ]"
> >
<template v-slot:prepend> <template v-slot:prepend>
<q-icon <q-icon
name="event" name="event"
class="cursor-pointer" class="cursor-pointer"
style="color: var(--black)" style="color: var(--black)"
> >
</q-icon> </q-icon>
</template> </template>
</q-input> </q-input>
</template> </template>
</datepicker> </datepicker>
</div>
<datepicker <div class="col-12 col-sm-3">
v-model="formDataTrain.leavebirthDate" <datepicker
class="col-12 col-md-3 col-sm-6" v-model="formDataTrain.leavebirthDate"
menu-class-name="modalfix" autoApply
autoApply borderless
borderless readonly
readonly week-start="0"
week-start="0" :enableTimePicker="false"
:enableTimePicker="false" :locale="'th'"
:locale="'th'" >
> <template #year="{ year }">
<template #year="{ year }"> {{ year + 543 }}
{{ year + 543 }} </template>
</template> <template #year-overlay-value="{ value }">
<template #year-overlay-value="{ value }"> {{ parseInt(value + 543) }}
{{ parseInt(value + 543) }} </template>
</template> <template #trigger>
<template #trigger> <q-input
<q-input ref="leavebirthDateRef"
ref="leavebirthDateRef" class="full-width"
class="full-width" bg-color="white"
bg-color="white" outlined
outlined dense
dense readonly
readonly hide-bottom-space
hide-bottom-space :label="`${'วันเดือนปีเกิด'}`"
:label="`${'วันเดือนปีเกิด'}`" :model-value="
:model-value=" dataStore.birthDate != null
dataStore.birthDate != null ? date2Thai(dataStore.birthDate)
? date2Thai(dataStore.birthDate) : null
: null "
" >
:rules="[(val:string) => !!val || `${'กรุณาเลือกลาถึงวันที่'}`]" <template v-slot:prepend>
> <q-icon
<template v-slot:prepend> name="event"
<q-icon class="cursor-pointer"
name="event" style="color: var(---black)"
class="cursor-pointer" >
style="color: var(---black)" </q-icon>
> </template>
</q-icon> </q-input>
</template> </template>
</q-input> </datepicker>
</template> </div>
</datepicker>
<q-input <div class="col-12 col-sm-3">
v-model="dataStore.salary" <q-input
class="col-12 col-sm-6 col-md-3" v-model="dataStore.salary"
bg-color="white" bg-color="white"
dense dense
outlined outlined
readonly readonly
label="เงินเดือนปัจจุบัน" label="เงินเดือนปัจจุบัน"
/> />
</div>
<q-input <div class="col-12 col-sm-3">
v-model="dataStore.salaryText" <q-input
class="col-12 col-sm-6 col-md-3" v-model="dataStore.salaryText"
dense dense
readonly readonly
outlined outlined
bg-color="white" bg-color="white"
label="เงินเดือนปัจจุบัน (ตัวอักษร)" label="เงินเดือนปัจจุบัน (ตัวอักษร)"
/> />
</div>
</div>
</div>
<div class="full-width">
<div class="q-col-gutter-sm row">
<div class="col-12 col-sm-8 inputgreen">
<q-input
v-model="formDataTrain.studyDayTrainingSubject"
ref="studyDayTrainingSubjectRef"
bg-color="white"
dense
outlined
label="ด้าน/หลักสูตร"
hide-bottom-space
:readonly="!edit || statusCheck === 'NEW'"
:rules="[(val:string) => !!val || `${'กรุณากรอกด้าน/หลักสูตร'}`]"
/>
</div>
<div class="col-12 col-sm-4 inputgreen">
<q-input
v-model="formDataTrain.studyDayTrainingName"
ref="studyDayTrainingNameRef"
bg-color="white"
dense
outlined
label="ณ สถานที่"
hide-bottom-space
:readonly="!edit || statusCheck === 'NEW'"
:rules="[(val:string) => !!val || `${'กรุณากรอก ณ สถานที่'}`]"
/>
</div>
<div class="col-12 col-sm-4 inputgreen">
<q-input
v-model="formDataTrain.studyDayCountry"
ref="studyDayCountryRef"
dense
bg-color="white"
outlined
label="ประเทศ"
hide-bottom-space
:readonly="!edit || statusCheck === 'NEW'"
:rules="[(val:string) => !!val || `${'กรุณากรอกประเทศ'}`]"
/>
</div>
<div class="col-12 col-sm-8 inputgreen">
<q-input
v-model="formDataTrain.studyDayScholarship"
ref="studyDayScholarshipRef"
bg-color="white"
dense
outlined
label="ด้วยทุน"
hide-bottom-space
:readonly="!edit || statusCheck === 'NEW'"
:rules="[(val:string) => !!val || `${'กรุณากรอกด้วยทุน'}`]"
/>
</div>
</div> </div>
</div> </div>
<div class="full-width"> <div class="full-width">
<div class="q-col-gutter-sm row"> <div class="q-col-gutter-sm row">
<q-input <q-input
v-model="formDataTrain.studyDayTrainingSubject" v-model="dataStore.telephoneNumber"
class="col-12 col-sm-6 col-md-4 cursor-pointer inputgreen" class="col-12 col-sm-4 inputgreen"
ref="studyDayTrainingSubjectRef"
bg-color="white"
dense
outlined
label="ด้าน/หลักสูตร"
hide-bottom-space
:readonly="!edit || statusCheck === 'NEW'"
:rules="[(val:string) => !!val || `${'กรุณากรอกด้าน/หลักสูตร'}`]"
/>
<q-input
v-model="formDataTrain.studyDayTrainingName"
ref="studyDayTrainingNameRef"
class="col-12 col-sm-6 col-md-4 cursor-pointer inputgreen"
bg-color="white"
dense
outlined
label="ณ สถานที่"
hide-bottom-space
:readonly="!edit || statusCheck === 'NEW'"
:rules="[(val:string) => !!val || `${'กรุณากรอก ณ สถานที่'}`]"
/>
<q-input
v-model="formDataTrain.studyDayCountry"
ref="studyDayCountryRef"
class="col-12 col-sm-6 col-md-4 cursor-pointer inputgreen"
dense
bg-color="white"
outlined
label="ประเทศ"
hide-bottom-space
:readonly="!edit || statusCheck === 'NEW'"
:rules="[(val:string) => !!val || `${'กรุณากรอกประเทศ'}`]"
/>
<q-input
v-model="formDataTrain.studyDayScholarship"
ref="studyDayScholarshipRef"
class="col-12 col-sm-6 col-md-4 cursor-pointer inputgreen"
bg-color="white"
dense
outlined
label="ด้วยทุน"
hide-bottom-space
:readonly="!edit || statusCheck === 'NEW'"
:rules="[(val:string) => !!val || `${'กรุณากรอกด้วยทุน'}`]"
/>
<q-input
v-model="formDataTrain.leaveNumber"
class="col-12 col-sm-6 col-md-4 cursor-pointer inputgreen"
ref="leaveNumberRef" ref="leaveNumberRef"
dense dense
outlined outlined
@ -570,9 +668,9 @@ onMounted(async () => {
/> />
<q-input <q-input
v-model="formDataTrain.leaveAddress" v-model="dataStore.currentAddress"
ref="leaveAddressRef" ref="leaveAddressRef"
class="col-12 cursor-pointer inputgreen" class="col-12 col-sm-8 inputgreen"
bg-color="white" bg-color="white"
dense dense
outlined outlined
@ -586,16 +684,17 @@ onMounted(async () => {
</div> </div>
</div> </div>
<q-input <div class="col-12 inputgreen">
v-model="formDataTrain.leaveDetail" <q-input
class="col-12 col-md-12 col-sm-12 cursor-pointer inputgreen" v-model="formDataTrain.leaveDetail"
:readonly="!edit || statusCheck === 'NEW'" :readonly="!edit || statusCheck === 'NEW'"
bg-color="white" bg-color="white"
dense dense
outlined outlined
type="textarea" type="textarea"
label="รายละเอียด" label="สาเหตุการลา"
/> />
</div>
<div class="col-12" v-if="statusCheck != 'NEW'"> <div class="col-12" v-if="statusCheck != 'NEW'">
<q-file <q-file
@ -672,28 +771,32 @@ onMounted(async () => {
<div class="row col-12 q-pt-md"> <div class="row col-12 q-pt-md">
<q-space /> <q-space />
<!-- <div v-if="totalCheck == 0" class="text-red q-mr-sm">**จำนวนวันลาของท่านไม่ถูกต้อง หรือวันที่ยื่นลาของท่านตรงกับวันหยุด</div> -->
<q-btn <q-btn
v-if="!props.data || props.data.status == 'DRAFT'" v-if="!props.data || props.data.status == 'DRAFT'"
id="onSubmit" id="onSubmit"
type="submit" type="submit"
unelevated unelevated
dense
class="q-px-md items-center btnBlue" class="q-px-md items-center btnBlue"
label="บันทึก" label="บันทึก"
><q-tooltip>นทกแบบราง</q-tooltip></q-btn :disable="!isLeave"
:loading="isLoadCheck"
> >
<q-tooltip>นทกแบบราง</q-tooltip>
</q-btn>
<q-btn <q-btn
v-if="data && statusCheck != 'NEW'" v-if="data && statusCheck != 'NEW'"
id="onSubmit" id="onSubmit"
type="button" type="button"
unelevated unelevated
dense
class="q-px-md items-center q-ml-sm" class="q-px-md items-center q-ml-sm"
color="primary" color="primary"
label="ยื่นใบลา" label="ยื่นใบลา"
@click="onConfirm()" @click="onConfirm()"
><q-tooltip>นใบลา</q-tooltip></q-btn :loading="isLoadCheck"
> >
<q-tooltip>นใบลา</q-tooltip>
</q-btn>
</div> </div>
</form> </form>
</template> </template>

View file

@ -1,6 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, watch, onMounted, computed } from "vue"; import { ref, reactive, watch, onMounted, computed } from "vue";
import { useRouter } from "vue-router";
import { useQuasar } from "quasar"; import { useQuasar } from "quasar";
import http from "@/plugins/http"; import http from "@/plugins/http";
@ -15,11 +14,19 @@ import type { FormRef } from "@/modules/05_leave/interface/request/WorkInternati
const $q = useQuasar(); const $q = useQuasar();
const dataStore = useLeaveStore(); const dataStore = useLeaveStore();
const mixin = useCounterMixin(); const mixin = useCounterMixin();
const { date2Thai, dateToISO, messageError, showLoader, hideLoader } = mixin; const {
date2Thai,
calculateDurationYmd,
messageError,
showLoader,
hideLoader,
convertDateToAPI,
} = mixin;
const edit = ref<boolean>(true); const edit = ref<boolean>(true);
const isSave = ref<boolean>(false); const isSave = ref<boolean>(false);
const leaveId = ref<string>(""); const leaveId = ref<string>("");
const leaveText = ref<string>("");
/** รับ props มาจากหน้าหลัก */ /** รับ props มาจากหน้าหลัก */
const props = defineProps({ const props = defineProps({
@ -48,6 +55,8 @@ const formDataWorkInternational = reactive<any>({
leaveStartDate: null, leaveStartDate: null,
leaveEndDate: null, leaveEndDate: null,
leaveDetail: "", leaveDetail: "",
leaveRange: "ALL",
leaveRangeEnd: "ALL",
leaveDocument: [], leaveDocument: [],
leaveDraftDocument: null, leaveDraftDocument: null,
}); });
@ -69,8 +78,6 @@ const FormRef: FormRef = {
}; };
/** ส่วนของการประกาศและเลือกไฟล์เอกสารประกอบ */ /** ส่วนของการประกาศและเลือกไฟล์เอกสารประกอบ */
const nameFile = ref<string>("");
const nameFileDraft = ref<string>("");
const fileDocDataUpload = ref<File[]>([]); const fileDocDataUpload = ref<File[]>([]);
const fileUploadDoc = async (files: any) => { const fileUploadDoc = async (files: any) => {
files.forEach((file: any) => { files.forEach((file: any) => {
@ -109,15 +116,19 @@ async function onValidate() {
formData.append("type", formDataWorkInternational.type); // formData.append("type", formDataWorkInternational.type); //
formData.append( formData.append(
"leaveStartDate", "leaveStartDate",
dateToISO(formDataWorkInternational.leaveStartDate) convertDateToAPI(formDataWorkInternational.leaveStartDate) ?? ""
); // ); //
formData.append( formData.append(
"leaveEndDate", "leaveEndDate",
dateToISO(formDataWorkInternational.leaveEndDate) convertDateToAPI(formDataWorkInternational.leaveEndDate) ?? ""
); // ); //
formData.append("leaveWrote", formDataWorkInternational.leaveWrote); // formData.append("leaveWrote", formDataWorkInternational.leaveWrote); //
formData.append("leaveDetail", formDataWorkInternational.leaveDetail); formData.append("leaveDetail", formDataWorkInternational.leaveDetail);
formData.append("leaveTotal", formDataWorkInternational.leaveTotal); // formData.append("leaveTotal", formDataWorkInternational.leaveTotal); //
formData.append("leaveRange", formDataWorkInternational.leaveRange);
formData.append("leaveRangeEnd", formDataWorkInternational.leaveRangeEnd);
await props.onSubmit(formData, isLeave.value); await props.onSubmit(formData, isLeave.value);
} }
} }
@ -141,30 +152,60 @@ async function onClickDownloadFile(id: string, fileName: string) {
const reasonLeave = ref<string>(""); const reasonLeave = ref<string>("");
const checkDate = computed(() => {
if (
convertDateToAPI(formDataWorkInternational.leaveEndDate) ==
convertDateToAPI(formDataWorkInternational.leaveStartDate)
) {
return true;
} else {
return false;
}
});
/** /**
* check าลาไดไหม จาก api * check าลาไดไหม จาก api
* @param formData * @param formData
*/ */
const isLeave = ref<boolean>(true); const isLeave = ref<boolean>(true);
const isLoadCheck = ref<boolean>(false);
async function fetchCheck() { async function fetchCheck() {
await http if (
.post(config.API.leaveCheck(), { formDataWorkInternational.leaveStartDate &&
type: dataStore.typeId ?? null, formDataWorkInternational.leaveEndDate
StartLeaveDate: formDataWorkInternational.leaveStartDate ?? null, ) {
EndLeaveDate: formDataWorkInternational.leaveEndDate ?? null, isLoadCheck.value = true;
}) await http
.then((res: any) => { .post(config.API.leaveCheck(), {
const data = res.data.result; type: dataStore.typeId ?? null,
isLeave.value = data.isLeave; StartLeaveDate:
formDataWorkInternational.leaveTotal = data.totalDate; convertDateToAPI(formDataWorkInternational.leaveStartDate) ?? null,
EndLeaveDate:
reasonLeave.value = data.message convertDateToAPI(formDataWorkInternational.leaveEndDate) ?? null,
? data.message leaveRange: formDataWorkInternational.leaveRange,
: "จำนวนวันลาเกินที่กำหนด"; leaveRangeEnd: checkDate.value
}) ? formDataWorkInternational.leaveRange
.catch((e: any) => { : formDataWorkInternational.leaveRangeEnd,
messageError($q, e); })
}); .then((res: any) => {
const data = res.data.result;
isLeave.value = data.isLeave;
formDataWorkInternational.leaveTotal = data.totalDate;
leaveText.value = calculateDurationYmd(
convertDateToAPI(formDataWorkInternational.leaveStartDate),
convertDateToAPI(formDataWorkInternational.leaveEndDate)
);
reasonLeave.value = data.message
? data.message
: "จำนวนวันลาเกินที่กำหนด";
})
.catch((e: any) => {
messageError($q, e);
})
.finally(() => {
isLoadCheck.value = false;
});
}
} }
/** แจ้งเมื่อวันลาไม่ถูกต้อง */ /** แจ้งเมื่อวันลาไม่ถูกต้อง */
@ -177,38 +218,58 @@ const leaveDocumentList = ref<any>();
const leaveDraftDocument = ref<string>(); const leaveDraftDocument = ref<string>();
const statusCheck = ref<string>(""); const statusCheck = ref<string>("");
watch(props, () => {
if (props.data) {
formDataWorkInternational.leaveWrote = props.data.leaveWrote;
formDataWorkInternational.leaveStartDate = new Date(
props.data.leaveStartDate
);
formDataWorkInternational.leaveEndDate = new Date(props.data.leaveEndDate);
formDataWorkInternational.leaveDetail = props.data.leaveDetail;
leaveDraftDocument.value = props.data.leaveDraftDocument;
leaveDocumentList.value = props.data.leaveDocument;
statusCheck.value = props.data.status;
formDataWorkInternational.leaveDraftDocument = null;
formDataWorkInternational.leaveDocument = [];
}
});
watch( watch(
() => formDataWorkInternational.leaveEndDate, () => props,
() => { async () => {
if ( if (props.data) {
formDataWorkInternational.leaveStartDate !== null && // totalCheck.value = null;
formDataWorkInternational.leaveEndDate !== null formDataWorkInternational.leaveWrote = props.data.leaveWrote;
) { formDataWorkInternational.leaveStartDate = new Date(
fetchCheck(); props.data.leaveStartDate
);
formDataWorkInternational.leaveEndDate = new Date(
props.data.leaveEndDate
);
formDataWorkInternational.leaveDetail = props.data.leaveDetail;
leaveDraftDocument.value = props.data.leaveDraftDocument;
formDataWorkInternational.leaveRange = props.data.leaveRange;
formDataWorkInternational.leaveRangeEnd = props.data.leaveRangeEnd;
formDataWorkInternational.leaveTotal = props.data.leaveTotal;
leaveDocumentList.value = props.data.leaveDocument;
statusCheck.value = props.data.status;
formDataWorkInternational.leaveDraftDocument = null;
formDataWorkInternational.leaveDocument = [];
const leaveTotal = await calculateDurationYmd(
props.data.leaveStartDate,
props.data.leaveEndDate
);
leaveText.value = leaveTotal;
} }
} }
); );
// watch(
// () => formDataWorkInternational.leaveEndDate,
// () => {
// if (
// formDataWorkInternational.leaveStartDate !== null &&
// formDataWorkInternational.leaveEndDate !== null
// ) {
// fetchCheck();
// }
// }
// );
/**Hook */ /**Hook */
onMounted(() => { onMounted(async () => {
if (props.data) { if (props.data) {
// totalCheck.value = null;
formDataWorkInternational.leaveWrote = props.data.leaveWrote; formDataWorkInternational.leaveWrote = props.data.leaveWrote;
formDataWorkInternational.leaveRange = props.data.leaveRange;
formDataWorkInternational.leaveRangeEnd = props.data.leaveRangeEnd;
formDataWorkInternational.leaveTotal = props.data.leaveTotal;
formDataWorkInternational.leaveStartDate = new Date( formDataWorkInternational.leaveStartDate = new Date(
props.data.leaveStartDate props.data.leaveStartDate
); );
@ -218,6 +279,11 @@ onMounted(() => {
leaveDocumentList.value = props.data.leaveDocument; leaveDocumentList.value = props.data.leaveDocument;
statusCheck.value = props.data.status; statusCheck.value = props.data.status;
leaveId.value = props.data.id; leaveId.value = props.data.id;
const leaveTotal = await calculateDurationYmd(
props.data.leaveStartDate,
props.data.leaveEndDate
);
leaveText.value = leaveTotal;
} }
}); });
</script> </script>
@ -230,140 +296,211 @@ onMounted(() => {
<form @submit.prevent.stop="onValidate"> <form @submit.prevent.stop="onValidate">
<q-card bordered class="q-pa-md bg-grey-1"> <q-card bordered class="q-pa-md bg-grey-1">
<div class="col-12 row q-pa-sm q-col-gutter-sm"> <div class="col-12 row q-pa-sm q-col-gutter-sm">
<q-input <div class="col-12 inputgreen">
class="col-12 col-sm-12 cursor-pointer inputgreen" <q-input
ref="leaveWroteRef" ref="leaveWroteRef"
hide-bottom-space hide-bottom-space
bg-color="white" bg-color="white"
for="leaveWroteRef" for="leaveWroteRef"
dense dense
outlined outlined
v-model="formDataWorkInternational.leaveWrote" v-model="formDataWorkInternational.leaveWrote"
label="เขียนที่" label="เขียนที่"
:readonly="!edit || statusCheck === 'NEW'" :readonly="!edit || statusCheck === 'NEW'"
:rules="[(val:string) => !!val || `${'เขียนที่'}`]" :rules="[(val:string) => !!val || `${'เขียนที่'}`]"
/> />
</div>
<datepicker <div class="col-12">
class="col-12 col-md-6 col-sm-6 cursor-pointer inputgreen" <div class="row q-col-gutter-sm">
menu-class-name="modalfix" <div class="col-12 col-md-3 col-sm-6 inputgreen">
v-model="formDataWorkInternational.leaveStartDate" <datepicker
:locale="'th'" v-model="formDataWorkInternational.leaveStartDate"
hide-bottom-space :locale="'th'"
autoApply autoApply
borderless hide-bottom-space
:enableTimePicker="false" borderless
week-start="0" :enableTimePicker="false"
:readonly="!edit || statusCheck === 'NEW'" week-start="0"
@update:model-value="formDataWorkInternational.leaveEndDate = null" :readonly="!edit || statusCheck === 'NEW'"
> @update:model-value="
<template #year="{ year }"> (formDataWorkInternational.leaveEndDate = null), fetchCheck()
{{ year + 543 }} "
</template> >
<template #year-overlay-value="{ value }"> <template #year="{ year }">
{{ parseInt(value + 543) }} {{ year + 543 }}
</template> </template>
<template #trigger> <template #year-overlay-value="{ value }">
<q-input {{ parseInt(value + 543) }}
outlined </template>
dense <template #trigger>
ref="leaveStartDateRef" <q-input
for="leaveStartDateRef" outlined
hide-bottom-space dense
bg-color="white" ref="leaveStartDateRef"
:readonly="!edit || statusCheck === 'NEW'" for="leaveStartDateRef"
class="full-width datepicker" hide-bottom-space
:model-value=" bg-color="white"
formDataWorkInternational.leaveStartDate != null :readonly="!edit || statusCheck === 'NEW'"
? date2Thai(formDataWorkInternational.leaveStartDate) class="full-width datepicker"
: null :model-value="
" formDataWorkInternational.leaveStartDate != null
:label="`${'ลาตั้งแต่วันที่'}`" ? date2Thai(formDataWorkInternational.leaveStartDate)
:rules="[(val:string) => !!val || `${'กรุณาเลือกลาตั้งแต่วันที่'}`]" : null
> "
<template v-slot:prepend> :label="`${'วันที่เริ่มต้น'}`"
<q-icon :rules="[(val:string) => !!val || `${'กรุณาเลือกวันที่เริ่มต้น'}`]"
name="event" >
class="cursor-pointer" <template v-slot:prepend>
style="color: var(--q-primary)" <q-icon
> name="event"
</q-icon> class="cursor-pointer"
</template> style="color: var(--q-primary)"
</q-input> >
</template> </q-icon>
</datepicker> </template>
</q-input>
</template>
</datepicker>
</div>
<datepicker <!-- <div class="col-12 col-md-3 col-sm-6 inputgreen">
:class="!isLeave ? dateEndInputStyle : ''" <q-select
class="col-12 col-md-6 col-sm-6 cursor-pointer" outlined
menu-class-name="modalfix" dense
v-model="formDataWorkInternational.leaveEndDate" bg-color="white"
:locale="'th'" v-model="formDataWorkInternational.leaveRange"
autoApply :options="dataStore.rangeOptions"
hide-bottom-space emit-value
borderless map-options
:enableTimePicker="false" option-value="id"
week-start="0" option-label="name"
:readonly=" @update:model-value="fetchCheck()"
!formDataWorkInternational.leaveStartDate || statusCheck === 'NEW' >
" <template v-slot:prepend>
:min-date="formDataWorkInternational.leaveStartDate" <q-icon
> name="mdi-clock-outline"
<template #year="{ year }"> style="color: var(--q-primary)"
{{ year + 543 }} />
</template> </template>
<template #year-overlay-value="{ value }"> </q-select>
{{ parseInt(value + 543) }} </div> -->
</template> <!-- </div>
<template #trigger> </div>
<q-input <div class="col-12">
outlined <div class="row q-col-gutter-sm"> -->
dense <div class="col-12 col-md-3 col-sm-6 inputgreen">
ref="leaveEndDateRef" <datepicker
for="leaveEndDateRef" v-model="formDataWorkInternational.leaveEndDate"
:readonly=" :locale="'th'"
!formDataWorkInternational.leaveStartDate || autoApply
statusCheck === 'NEW' hide-bottom-space
" @update:model-value="fetchCheck()"
class="full-width datepicker" borderless
:model-value=" :enableTimePicker="false"
formDataWorkInternational.leaveEndDate != null week-start="0"
? date2Thai(formDataWorkInternational.leaveEndDate) :min-date="formDataWorkInternational.leaveStartDate"
: null >
" <template #year="{ year }">
:label="`${'ลาถึงวันที่'}`" {{ year + 543 }}
:bottom-slots="!isLeave ? true : false" </template>
:color="!isLeave ? 'red' : 'black'" <template #year-overlay-value="{ value }">
:bg-color="!isLeave ? 'red-2' : 'white'" {{ parseInt(value + 543) }}
:border-color="!isLeave ? 'red' : 'gray'" </template>
:input-class="!isLeave ? dateEndInputStyle : ''" <template #trigger>
> <q-input
<template v-slot:prepend> outlined
<q-icon name="event" class="cursor-pointer" color="primary"> dense
</q-icon> ref="leaveEndDateRef"
</template> for="leaveEndDateRef"
hide-bottom-space
bg-color="white"
class="full-width datepicker"
:model-value="
formDataWorkInternational.leaveEndDate != null
? date2Thai(formDataWorkInternational.leaveEndDate)
: 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 class="col-12 col-md-3 col-sm-6 inputgreen">
<q-select
outlined
dense
v-if="!checkDate"
bg-color="white"
v-model="formDataWorkInternational.leaveRangeEnd"
:options="dataStore.rangeOptions.filter((items:any)=> items.id !== 'AFTERNOON')"
emit-value
map-options
option-value="id"
option-label="name"
@update:model-value="fetchCheck()"
>
<template v-slot:prepend>
<q-icon
name="mdi-clock-outline"
style="color: var(--q-primary)"
/>
</template>
</q-select>
</div> -->
<div class="col-12 col-md-3 col-sm-6">
<q-input
:bottom-slots="!isLeave ? true : false"
:color="!isLeave ? 'red' : 'black'"
:bg-color="!isLeave ? 'red-2' : 'white'"
:border-color="!isLeave ? 'red' : 'gray'"
:input-class="!isLeave ? dateEndInputStyle : ''"
dense
outlined
ref="leaveTotalRef"
for="leaveTotalRef"
v-model="leaveText"
label="มีกำหนด"
readonly
:loading="isLoadCheck"
>
<template v-slot:hint>
<span style="color: red">
{{ !isLeave ? reasonLeave : "" }}
</span>
</template>
</q-input>
</div>
</div>
</div>
<div class="col-12 inputgreen">
<q-input
hide-bottom-space
type="textarea"
dense
bg-color="white"
outlined
ref="leaveDetailRef"
for="leaveDetailRef"
v-model="formDataWorkInternational.leaveDetail"
label="สาเหตุการลา"
:readonly="!edit || statusCheck === 'NEW'"
/>
</div>
<template v-slot:hint>
<span style="color: red">
{{ !isLeave ? reasonLeave : "" }}
</span>
</template>
</q-input>
</template>
</datepicker>
<q-input
hide-bottom-space
type="textarea"
class="col-12 col-md-12 col-sm-12 cursor-pointer inputgreen"
dense
bg-color="white"
outlined
ref="leaveDetailRef"
for="leaveDetailRef"
v-model="formDataWorkInternational.leaveDetail"
label="รายละเอียด"
:readonly="!edit || statusCheck === 'NEW'"
/>
<div class="full-width" v-if="statusCheck != 'NEW'"> <div class="full-width" v-if="statusCheck != 'NEW'">
<div class="q-col-gutter-sm row"> <div class="q-col-gutter-sm row">
<q-file <q-file
@ -501,28 +638,32 @@ onMounted(() => {
<q-separator class="q-mt-sm" /> <q-separator class="q-mt-sm" />
<div class="row col-12 q-pt-md"> <div class="row col-12 q-pt-md">
<q-space /> <q-space />
<!-- <div v-if="totalCheck == 0" class="text-red q-mr-sm">**จำนวนวันลาของท่านไม่ถูกต้อง หรือวันที่ยื่นลาของท่านตรงกับวันหยุด</div> -->
<q-btn <q-btn
v-if="!props.data || props.data.status == 'DRAFT'" v-if="!props.data || props.data.status == 'DRAFT'"
id="onSubmit" id="onSubmit"
type="submit" type="submit"
unelevated unelevated
dense
class="q-px-md items-center btnBlue" class="q-px-md items-center btnBlue"
label="บันทึก" label="บันทึก"
><q-tooltip>นทกแบบราง</q-tooltip></q-btn :disable="!isLeave"
:loading="isLoadCheck"
> >
<q-tooltip>นทกแบบราง</q-tooltip>
</q-btn>
<q-btn <q-btn
v-if="data && statusCheck != 'NEW'" v-if="data && statusCheck != 'NEW'"
id="onSubmit" id="onSubmit"
type="button" type="button"
unelevated unelevated
dense
class="q-px-md items-center q-ml-sm" class="q-px-md items-center q-ml-sm"
color="primary" color="primary"
label="ยื่นใบลา" label="ยื่นใบลา"
@click="onConfirm()" @click="onConfirm()"
><q-tooltip>นใบลา</q-tooltip></q-btn :loading="isLoadCheck"
> >
<q-tooltip>นใบลา</q-tooltip>
</q-btn>
</div> </div>
</div> </div>
</form> </form>

View file

@ -4,7 +4,6 @@ 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 { useRouter } from "vue-router";
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
import { useLeaveStore } from "@/modules/05_leave/store"; import { useLeaveStore } from "@/modules/05_leave/store";
@ -15,9 +14,22 @@ const dataStore = useLeaveStore();
const $q = useQuasar(); const $q = useQuasar();
const mixin = useCounterMixin(); const mixin = useCounterMixin();
const { date2Thai, calculateDurationYmd, dateToISO, messageError } = mixin; const { date2Thai, calculateDurationYmd, messageError, convertDateToAPI } =
mixin;
const leaveText = ref<string>("");
const edit = ref<boolean>(true); const edit = ref<boolean>(true);
const leaveId = ref<string>(""); const leaveId = ref<string>("");
const checkDate = computed(() => {
if (
convertDateToAPI(formDataFollowSpouse.leaveEndDate) ==
convertDateToAPI(formDataFollowSpouse.leaveStartDate)
) {
return true;
} else {
return false;
}
});
/** รับ props มาจากหน้าหลัก */ /** รับ props มาจากหน้าหลัก */
const props = defineProps({ const props = defineProps({
@ -48,6 +60,8 @@ const formDataFollowSpouse = reactive<any>({
leaveTotal: "", // leaveTotal: "", //
leaveTotalDay: "", // leaveTotalDay: "", //
leaveSalaryText: "", leaveSalaryText: "",
leaveRange: "ALL",
leaveRangeEnd: "ALL",
leaveSalary: 0, // leaveSalary: 0, //
coupleDayName: "", // coupleDayName: "", //
coupleDayPosition: "", // coupleDayPosition: "", //
@ -55,6 +69,7 @@ const formDataFollowSpouse = reactive<any>({
coupleDayLevelCountry: "", // coupleDayLevelCountry: "", //
coupleDayCountryHistory: "", // coupleDayCountryHistory: "", //
coupleDayTotalHistory: null, coupleDayTotalHistory: null,
coupleDaySumTotalHistory: null,
coupleDayStartDateHistory: null, coupleDayStartDateHistory: null,
coupleDayEndDateHistory: null, coupleDayEndDateHistory: null,
leaveDetail: leaveDetail:
@ -131,23 +146,19 @@ function onValidate() {
formData.append("type", formDataFollowSpouse.type); // formData.append("type", formDataFollowSpouse.type); //
formData.append( formData.append(
"leaveStartDate", "leaveStartDate",
dateToISO(new Date(formDataFollowSpouse.leaveStartDate)) convertDateToAPI(formDataFollowSpouse.leaveStartDate) ?? ""
); // ); //
formData.append( formData.append(
"leaveEndDate", "leaveEndDate",
dateToISO(new Date(formDataFollowSpouse.leaveEndDate)) convertDateToAPI(formDataFollowSpouse.leaveEndDate) ?? ""
); // ); //
formData.append( formData.append(
"coupleDayStartDateHistory", "coupleDayStartDateHistory",
formDataFollowSpouse.coupleDayStartDateHistory convertDateToAPI(formDataFollowSpouse.coupleDayStartDateHistory) ?? ""
? dateToISO(new Date(formDataFollowSpouse.coupleDayStartDateHistory))
: ""
); // ); //
formData.append( formData.append(
"coupleDayEndDateHistory", "coupleDayEndDateHistory",
formDataFollowSpouse.coupleDayEndDateHistory convertDateToAPI(formDataFollowSpouse.coupleDayEndDateHistory) ?? ""
? dateToISO(new Date(formDataFollowSpouse.coupleDayEndDateHistory))
: ""
); // ); //
formData.append("leaveWrote", formDataFollowSpouse.leaveWrote); // formData.append("leaveWrote", formDataFollowSpouse.leaveWrote); //
formData.append("leaveDetail", formDataFollowSpouse.leaveDetail); // formData.append("leaveDetail", formDataFollowSpouse.leaveDetail); //
@ -157,6 +168,10 @@ function onValidate() {
"coupleDayTotalHistory", "coupleDayTotalHistory",
formDataFollowSpouse.coupleDayTotalHistory formDataFollowSpouse.coupleDayTotalHistory
); // ); //
formData.append(
"coupleDaySumTotalHistory",
formDataFollowSpouse.coupleDaySumTotalHistory
); //
formData.append( formData.append(
"coupleDayCountryHistory", "coupleDayCountryHistory",
formDataFollowSpouse.coupleDayCountryHistory formDataFollowSpouse.coupleDayCountryHistory
@ -171,7 +186,10 @@ function onValidate() {
formDataFollowSpouse.coupleDayPosition formDataFollowSpouse.coupleDayPosition
); // ); //
formData.append("coupleDayName", formDataFollowSpouse.coupleDayName); // formData.append("coupleDayName", formDataFollowSpouse.coupleDayName); //
formData.append("leaveTotal", formDataFollowSpouse.leaveTotalDay); // formData.append("leaveTotal", formDataFollowSpouse.leaveTotal); //
formData.append("leaveRange", formDataFollowSpouse.leaveRange);
formData.append("leaveRangeEnd", formDataFollowSpouse.leaveRangeEnd);
props.onSubmit(formData, isLeave.value); props.onSubmit(formData, isLeave.value);
} }
} }
@ -183,37 +201,46 @@ const reasonLeave = ref<string>("");
* @param formData * @param formData
*/ */
const isLeave = ref<boolean>(true); const isLeave = ref<boolean>(true);
const isLoadCheck = ref<boolean>(false);
async function fetchCheck() { async function fetchCheck() {
await http if (
.post(config.API.leaveCheck(), { formDataFollowSpouse.leaveStartDate &&
type: dataStore.typeId ?? null,
StartLeaveDate: formDataFollowSpouse.leaveStartDate ?? null,
EndLeaveDate: formDataFollowSpouse.leaveEndDate ?? null,
})
.then((res: any) => {
const data = res.data.result;
isLeave.value = data.isLeave;
formDataFollowSpouse.leaveTotalDay = data.totalDate;
reasonLeave.value = data.message
? data.message
: "จำนวนวันลาเกินที่กำหนด";
})
.catch((e: any) => {
messageError($q, e);
});
}
/**
* function พเดทค LeaveTotal
*/
function updateLeaveTotal() {
fetchCheck();
const newLeaveTotal = calculateDurationYmd(
formDataFollowSpouse.leaveStartDate,
formDataFollowSpouse.leaveEndDate formDataFollowSpouse.leaveEndDate
); ) {
formDataFollowSpouse.leaveTotal = newLeaveTotal; isLoadCheck.value = true;
await http
.post(config.API.leaveCheck(), {
type: dataStore.typeId ?? null,
StartLeaveDate:
convertDateToAPI(formDataFollowSpouse.leaveStartDate) ?? null,
EndLeaveDate:
convertDateToAPI(formDataFollowSpouse.leaveEndDate) ?? null,
leaveRange: formDataFollowSpouse.leaveRange,
leaveRangeEnd: checkDate.value
? formDataFollowSpouse.leaveRange
: formDataFollowSpouse.leaveRangeEnd,
})
.then((res: any) => {
const data = res.data.result;
isLeave.value = data.isLeave;
formDataFollowSpouse.leaveTotal = data.totalDate;
// totalCheck.value = data.totalDate;
leaveText.value = calculateDurationYmd(
convertDateToAPI(formDataFollowSpouse.leaveStartDate),
convertDateToAPI(formDataFollowSpouse.leaveEndDate)
);
reasonLeave.value = data.message
? data.message
: "จำนวนวันลาเกินที่กำหนด";
checkTotalHistory();
})
.catch((e: any) => {
messageError($q, e);
})
.finally(() => {
isLoadCheck.value = false;
});
}
} }
/** /**
@ -225,8 +252,23 @@ function updateLeaveHistoryTotal() {
formDataFollowSpouse.coupleDayEndDateHistory formDataFollowSpouse.coupleDayEndDateHistory
); );
formDataFollowSpouse.coupleDayTotalHistory = newLeaveTotal; formDataFollowSpouse.coupleDayTotalHistory = newLeaveTotal;
checkTotalHistory();
} }
function checkTotalHistory() {
if (
formDataFollowSpouse.coupleDayStartDateHistory &&
formDataFollowSpouse.coupleDayEndDateHistory
) {
const start = new Date(formDataFollowSpouse.coupleDayStartDateHistory);
const end = new Date(formDataFollowSpouse.coupleDayEndDateHistory);
const msInDay = 1000 * 60 * 60 * 24;
const diffTime = end.getTime() - start.getTime();
const diffDays = Math.abs(Math.ceil(diffTime / msInDay)) + 1;
formDataFollowSpouse.coupleDaySumTotalHistory =
diffDays + formDataFollowSpouse.leaveTotal;
}
}
/** แจ้งเมื่อวันลาไม่ถูกต้อง */ /** แจ้งเมื่อวันลาไม่ถูกต้อง */
const dateEndInputStyle = computed(() => { const dateEndInputStyle = computed(() => {
return !isLeave.value ? "input-alert" : ""; return !isLeave.value ? "input-alert" : "";
@ -235,55 +277,70 @@ const dateEndInputStyle = computed(() => {
/** ตรวจสอบว่ามีการส่งข้อมูลเข้ามาที่ฟอร์มไหม เมื่อมีการส่งจะ map ข้อมูลเข้า v-model ของฟอร์ม */ /** ตรวจสอบว่ามีการส่งข้อมูลเข้ามาที่ฟอร์มไหม เมื่อมีการส่งจะ map ข้อมูลเข้า v-model ของฟอร์ม */
const leaveDocumentList = ref<any>(); const leaveDocumentList = ref<any>();
const statusCheck = ref<any>(""); const statusCheck = ref<any>("");
watch(props.data, async () => { watch(
if (props.data) { () => props.data,
formDataFollowSpouse.leaveWrote = props.data.leaveWrote; async () => {
formDataFollowSpouse.leaveStartDate = new Date(props.data.leaveStartDate); if (props.data) {
formDataFollowSpouse.leaveEndDate = new Date(props.data.leaveEndDate); // totalCheck.value = null;
formDataFollowSpouse.leaveDetail = props.data.leaveDetail; formDataFollowSpouse.leaveWrote = props.data.leaveWrote;
formDataFollowSpouse.leaveTotal = props.data.leaveTotal; formDataFollowSpouse.leaveStartDate = new Date(props.data.leaveStartDate);
formDataFollowSpouse.leaveSalaryText = props.data.leaveSalaryText; formDataFollowSpouse.leaveEndDate = new Date(props.data.leaveEndDate);
formDataFollowSpouse.leaveSalary = props.data.leaveSalary; formDataFollowSpouse.leaveDetail = props.data.leaveDetail;
formDataFollowSpouse.coupleDayName = props.data.coupleDayName; formDataFollowSpouse.leaveTotal = props.data.leaveTotal;
formDataFollowSpouse.coupleDayPosition = props.data.coupleDayPosition; formDataFollowSpouse.leaveSalaryText = props.data.leaveSalaryText;
formDataFollowSpouse.coupleDayLevel = props.data.coupleDayLevel; formDataFollowSpouse.leaveSalary = props.data.leaveSalary;
formDataFollowSpouse.coupleDayLevelCountry = formDataFollowSpouse.coupleDayName = props.data.coupleDayName;
props.data.coupleDayLevelCountry; formDataFollowSpouse.coupleDayPosition = props.data.coupleDayPosition;
formDataFollowSpouse.coupleDayCountryHistory = formDataFollowSpouse.coupleDayLevel = props.data.coupleDayLevel;
props.data.coupleDayCountryHistory; formDataFollowSpouse.leaveRange = props.data.leaveRange;
formDataFollowSpouse.coupleDayTotalHistory = formDataFollowSpouse.leaveRangeEnd = props.data.leaveRangeEnd;
props.data.coupleDayTotalHistory; formDataFollowSpouse.coupleDaySumTotalHistory =
formDataFollowSpouse.coupleDayStartDateHistory = props.data.coupleDaySumTotalHistory;
props.data.coupleDayStartDateHistory; formDataFollowSpouse.coupleDayLevelCountry =
formDataFollowSpouse.coupleDayEndDateHistory = props.data.coupleDayLevelCountry;
props.data.coupleDayEndDateHistory; formDataFollowSpouse.coupleDayCountryHistory =
leaveDocumentList.value = props.data.leaveDocument; props.data.coupleDayCountryHistory;
formDataFollowSpouse.coupleDayTotalHistory =
props.data.coupleDayTotalHistory;
formDataFollowSpouse.coupleDayStartDateHistory =
props.data.coupleDayStartDateHistory;
formDataFollowSpouse.coupleDayEndDateHistory =
props.data.coupleDayEndDateHistory;
leaveDocumentList.value = props.data.leaveDocument;
checkTotalHistory();
const leaveTotal = await calculateDurationYmd(
props.data.leaveStartDate,
props.data.leaveEndDate
);
leaveText.value = leaveTotal;
const leaveTotal = await calculateDurationYmd( const coupleDayTotalHistory = await calculateDurationYmd(
props.data.leaveStartDate, props.data.coupleDayStartDateHistory,
props.data.leaveEndDate props.data.coupleDayEndDateHistory
); );
formDataFollowSpouse.leaveTotal = leaveTotal; formDataFollowSpouse.coupleDayTotalHistory = coupleDayTotalHistory;
const coupleDayTotalHistory = await calculateDurationYmd( statusCheck.value = props.data.status;
props.data.coupleDayStartDateHistory, formDataFollowSpouse.leaveDocument = [];
props.data.coupleDayEndDateHistory }
);
formDataFollowSpouse.coupleDayTotalHistory = coupleDayTotalHistory;
statusCheck.value = props.data.status;
formDataFollowSpouse.leaveDocument = [];
} }
}); );
/**Hook */ /**Hook */
onMounted(async () => { onMounted(async () => {
if (props.data) { if (props.data) {
// totalCheck.value = null;
formDataFollowSpouse.leaveWrote = props.data.leaveWrote; formDataFollowSpouse.leaveWrote = props.data.leaveWrote;
formDataFollowSpouse.leaveStartDate = new Date(props.data.leaveStartDate); formDataFollowSpouse.leaveStartDate = new Date(props.data.leaveStartDate);
formDataFollowSpouse.leaveEndDate = new Date(props.data.leaveEndDate); formDataFollowSpouse.leaveEndDate = new Date(props.data.leaveEndDate);
formDataFollowSpouse.leaveDetail = props.data.leaveDetail; formDataFollowSpouse.leaveDetail = props.data.leaveDetail;
formDataFollowSpouse.leaveTotal = props.data.leaveTotal; formDataFollowSpouse.leaveTotal = props.data.leaveTotal;
formDataFollowSpouse.leaveRange = props.data.leaveRange;
formDataFollowSpouse.leaveRangeEnd = props.data.leaveRangeEnd;
formDataFollowSpouse.leaveSalaryText = props.data.leaveSalaryText; formDataFollowSpouse.leaveSalaryText = props.data.leaveSalaryText;
formDataFollowSpouse.leaveSalary = props.data.leaveSalary; formDataFollowSpouse.leaveSalary = props.data.leaveSalary;
formDataFollowSpouse.coupleDaySumTotalHistory =
props.data.coupleDaySumTotalHistory;
formDataFollowSpouse.coupleDayName = props.data.coupleDayName; formDataFollowSpouse.coupleDayName = props.data.coupleDayName;
formDataFollowSpouse.coupleDayPosition = props.data.coupleDayPosition; formDataFollowSpouse.coupleDayPosition = props.data.coupleDayPosition;
formDataFollowSpouse.coupleDayLevel = props.data.coupleDayLevel; formDataFollowSpouse.coupleDayLevel = props.data.coupleDayLevel;
@ -298,12 +355,13 @@ onMounted(async () => {
formDataFollowSpouse.coupleDayEndDateHistory = formDataFollowSpouse.coupleDayEndDateHistory =
props.data.coupleDayEndDateHistory; props.data.coupleDayEndDateHistory;
leaveDocumentList.value = props.data.leaveDocument; leaveDocumentList.value = props.data.leaveDocument;
checkTotalHistory();
const leaveTotal = await calculateDurationYmd( const leaveTotal = await calculateDurationYmd(
props.data.leaveStartDate, props.data.leaveStartDate,
props.data.leaveEndDate props.data.leaveEndDate
); );
formDataFollowSpouse.leaveTotal = leaveTotal; leaveText.value = leaveTotal;
const coupleDayTotalHistory = await calculateDurationYmd( const coupleDayTotalHistory = await calculateDurationYmd(
props.data.coupleDayStartDateHistory, props.data.coupleDayStartDateHistory,
props.data.coupleDayEndDateHistory props.data.coupleDayEndDateHistory
@ -323,143 +381,198 @@ onMounted(async () => {
<form @submit.prevent.stop="onValidate"> <form @submit.prevent.stop="onValidate">
<q-card bordered class="q-pa-md bg-grey-1"> <q-card bordered class="q-pa-md bg-grey-1">
<div class="col-12 row q-pa-sm q-col-gutter-sm"> <div class="col-12 row q-pa-sm q-col-gutter-sm">
<q-input <div class="col-12 col-sm-12 inputgreen">
class="col-12 col-sm-12 cursor-pointer inputgreen" <q-input
ref="leaveWroteRef" ref="leaveWroteRef"
for="leaveWroteRef" for="leaveWroteRef"
dense dense
hide-bottom-space hide-bottom-space
bg-color="white" bg-color="white"
outlined outlined
v-model="formDataFollowSpouse.leaveWrote" v-model="formDataFollowSpouse.leaveWrote"
label="เขียนที่" label="เขียนที่"
:readonly="!edit || statusCheck === 'NEW'" :readonly="!edit || statusCheck === 'NEW'"
:rules="[(val:string) => !!val || `${'เขียนที่'}`]" :rules="[(val:string) => !!val || `${'เขียนที่'}`]"
/> />
<datepicker </div>
class="col-12 col-md-4 col-sm-12 cursor-pointer inputgreen"
menu-class-name="modalfix"
v-model="formDataFollowSpouse.leaveStartDate"
:locale="'th'"
autoApply
hide-bottom-space
borderless
:enableTimePicker="false"
week-start="0"
:readonly="!edit || statusCheck === 'NEW'"
@update:model-value="formDataFollowSpouse.leaveEndDate = null"
>
<template #year="{ year }">
{{ year + 543 }}
</template>
<template #year-overlay-value="{ value }">
{{ parseInt(value + 543) }}
</template>
<template #trigger>
<q-input
outlined
dense
ref="leaveStartDateRef"
for="leaveStartDateRef"
hide-bottom-space
bg-color="white"
:readonly="!edit || statusCheck === 'NEW'"
class="full-width datepicker"
:model-value="
formDataFollowSpouse.leaveStartDate != null
? date2Thai(formDataFollowSpouse.leaveStartDate)
: 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>
<datepicker <div class="col-12">
class="col-12 col-md-4 col-sm-12 cursor-pointer inputgreen" <div class="row q-col-gutter-sm">
menu-class-name="modalfix" <div class="col-12 col-md-3 col-sm-6 inputgreen">
v-model="formDataFollowSpouse.leaveEndDate" <datepicker
:locale="'th'" v-model="formDataFollowSpouse.leaveStartDate"
autoApply :locale="'th'"
borderless autoApply
hide-bottom-space hide-bottom-space
:enableTimePicker="false" borderless
week-start="0" :enableTimePicker="false"
@update:model-value="updateLeaveTotal(), fetchCheck()" week-start="0"
:readonly=" :readonly="!edit || statusCheck === 'NEW'"
!formDataFollowSpouse.leaveStartDate || statusCheck === 'NEW' @update:model-value="
" (formDataFollowSpouse.leaveEndDate = null), fetchCheck()
:min-date="formDataFollowSpouse.leaveStartDate" "
> >
<template #year="{ year }"> <template #year="{ year }">
{{ year + 543 }} {{ year + 543 }}
</template> </template>
<template #year-overlay-value="{ value }"> <template #year-overlay-value="{ value }">
{{ parseInt(value + 543) }} {{ parseInt(value + 543) }}
</template> </template>
<template #trigger> <template #trigger>
<q-input <q-input
outlined outlined
dense dense
ref="leaveEndDateRef" ref="leaveStartDateRef"
for="leaveEndDateRef" for="leaveStartDateRef"
hide-bottom-space hide-bottom-space
bg-color="white" bg-color="white"
:readonly=" :readonly="!edit || statusCheck === 'NEW'"
!formDataFollowSpouse.leaveStartDate || statusCheck === 'NEW' class="full-width datepicker"
" :model-value="
class="full-width datepicker" formDataFollowSpouse.leaveStartDate != null
:model-value=" ? date2Thai(formDataFollowSpouse.leaveStartDate)
formDataFollowSpouse.leaveEndDate != null : null
? date2Thai(formDataFollowSpouse.leaveEndDate) "
: null :label="`${'วันที่เริ่มต้น'}`"
" :rules="[(val:string) => !!val || `${'กรุณาเลือกวันที่เริ่มต้น'}`]"
:label="`${'ลาถึงวันที่'}`" >
> <template v-slot:prepend>
<template v-slot:prepend> <q-icon
<q-icon name="event"
name="event" class="cursor-pointer"
class="cursor-pointer" style="color: var(--q-primary)"
style="color: var(--q-primary)" >
> </q-icon>
</q-icon> </template>
</template> </q-input>
</q-input> </template>
</template> </datepicker>
</datepicker> </div>
<q-input
:bottom-slots="!isLeave ? true : false"
:color="!isLeave ? 'red' : 'black'"
:bg-color="!isLeave ? 'red-2' : 'white'"
:border-color="!isLeave ? 'red' : 'gray'"
:input-class="!isLeave ? dateEndInputStyle : ''"
class="col-12 col-md-2 col-sm-6"
dense
outlined
ref="leaveTotalRef"
for="leaveTotalRef"
v-model="formDataFollowSpouse.leaveTotal"
label="เป็นเวลา"
readonly
>
<template v-slot:hint>
<span style="color: red">
{{ !isLeave ? reasonLeave : "" }}
</span>
</template>
</q-input>
<div class="col-12 col-md-6 col-sm-12"> <!-- <div class="col-12 col-md-3 col-sm-6 inputgreen">
<q-select
outlined
dense
bg-color="white"
v-model="formDataFollowSpouse.leaveRange"
:options="dataStore.rangeOptions"
emit-value
map-options
option-value="id"
option-label="name"
@update:model-value="fetchCheck()"
>
<template v-slot:prepend>
<q-icon
name="mdi-clock-outline"
style="color: var(--q-primary)"
/>
</template>
</q-select>
</div> -->
<!-- </div>
</div>
<div class="col-12">
<div class="row q-col-gutter-sm"> -->
<div class="col-12 col-md-3 col-sm-6 inputgreen">
<datepicker
v-model="formDataFollowSpouse.leaveEndDate"
:locale="'th'"
autoApply
hide-bottom-space
@update:model-value="fetchCheck()"
borderless
:enableTimePicker="false"
week-start="0"
:min-date="formDataFollowSpouse.leaveStartDate"
>
<template #year="{ year }">
{{ year + 543 }}
</template>
<template #year-overlay-value="{ value }">
{{ parseInt(value + 543) }}
</template>
<template #trigger>
<q-input
outlined
dense
ref="leaveEndDateRef"
for="leaveEndDateRef"
hide-bottom-space
bg-color="white"
class="full-width datepicker"
:model-value="
formDataFollowSpouse.leaveEndDate != null
? date2Thai(formDataFollowSpouse.leaveEndDate)
: 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 class="col-12 col-md-3 col-sm-6 inputgreen">
<q-select
v-if="!checkDate"
outlined
dense
bg-color="white"
v-model="formDataFollowSpouse.leaveRangeEnd"
:options="dataStore.rangeOptions.filter((items:any)=> items.id !== 'AFTERNOON')"
emit-value
map-options
option-value="id"
option-label="name"
@update:model-value="fetchCheck()"
>
<template v-slot:prepend>
<q-icon
name="mdi-clock-outline"
style="color: var(--q-primary)"
/>
</template>
</q-select>
</div> -->
<div class="col-12 col-md-3 col-sm-6">
<q-input
:bottom-slots="!isLeave ? true : false"
:color="!isLeave ? 'red' : 'black'"
:bg-color="!isLeave ? 'red-2' : 'white'"
:border-color="!isLeave ? 'red' : 'gray'"
:input-class="!isLeave ? dateEndInputStyle : ''"
dense
outlined
ref="leaveTotalRef"
for="leaveTotalRef"
v-model="leaveText"
label="เป็นเวลา"
readonly
:loading="isLoadCheck"
>
<template v-slot:hint>
<span style="color: red">
{{ !isLeave ? reasonLeave : "" }}
</span>
</template>
</q-input>
</div>
</div>
</div>
<div class="col-12 col-md-3 col-sm-12">
<q-input <q-input
hide-bottom-space hide-bottom-space
bg-color="white" bg-color="white"
@ -473,7 +586,7 @@ onMounted(async () => {
readonly readonly
/> />
</div> </div>
<div class="col-12 col-md-6 col-sm-12"> <div class="col-12 col-md-9 col-sm-12">
<q-input <q-input
hide-bottom-space hide-bottom-space
bg-color="white" bg-color="white"
@ -490,7 +603,7 @@ onMounted(async () => {
<div class="col-md-3 col-sm-12"> <div class="col-md-3 col-sm-12">
<q-input <q-input
class="col-12 col-sm-12 cursor-pointer inputgreen" class="col-12 col-sm-12 inputgreen"
hide-bottom-space hide-bottom-space
ref="coupleDayNameRef" ref="coupleDayNameRef"
for="coupleDayNameRef" for="coupleDayNameRef"
@ -505,7 +618,7 @@ onMounted(async () => {
</div> </div>
<div class="col-md-3 col-sm-12"> <div class="col-md-3 col-sm-12">
<q-input <q-input
class="col-12 col-sm-12 cursor-pointer inputgreen" class="col-12 col-sm-12 inputgreen"
hide-bottom-space hide-bottom-space
ref="coupleDayPositionRef" ref="coupleDayPositionRef"
for="coupleDayPositionRef" for="coupleDayPositionRef"
@ -520,7 +633,7 @@ onMounted(async () => {
</div> </div>
<div class="col-md-3 col-sm-12"> <div class="col-md-3 col-sm-12">
<q-input <q-input
class="col-12 col-sm-12 cursor-pointer inputgreen" class="col-12 col-sm-12 inputgreen"
ref="coupleDayLevelRef" ref="coupleDayLevelRef"
for="coupleDayLevelRef" for="coupleDayLevelRef"
dense dense
@ -535,7 +648,7 @@ onMounted(async () => {
</div> </div>
<div class="col-md-3 col-sm-12"> <div class="col-md-3 col-sm-12">
<q-input <q-input
class="col-12 col-sm-12 cursor-pointer inputgreen" class="col-12 col-sm-12 inputgreen"
ref="coupleDayLevelCountryRef" ref="coupleDayLevelCountryRef"
for="coupleDayLevelCountryRef" for="coupleDayLevelCountryRef"
hide-bottom-space hide-bottom-space
@ -551,9 +664,9 @@ onMounted(async () => {
<div class="text-weight-bold text-dark col-12"> <div class="text-weight-bold text-dark col-12">
ประวการลาตดตามคสมรสครงสดทาย ประวการลาตดตามคสมรสครงสดทาย
</div> </div>
<datepicker <datepicker
class="col-12 col-md-3 col-sm-12 inputgreen" class="col-12 col-md-3 col-sm-12 inputgreen"
menu-class-name="modalfix"
v-model="formDataFollowSpouse.coupleDayStartDateHistory" v-model="formDataFollowSpouse.coupleDayStartDateHistory"
:locale="'th'" :locale="'th'"
autoApply autoApply
@ -600,7 +713,6 @@ onMounted(async () => {
</datepicker> </datepicker>
<datepicker <datepicker
class="col-12 col-md-3 col-sm-12 inputgreen" class="col-12 col-md-3 col-sm-12 inputgreen"
menu-class-name="modalfix"
v-model="formDataFollowSpouse.coupleDayEndDateHistory" v-model="formDataFollowSpouse.coupleDayEndDateHistory"
:locale="'th'" :locale="'th'"
autoApply autoApply
@ -608,6 +720,7 @@ onMounted(async () => {
borderless borderless
:enableTimePicker="false" :enableTimePicker="false"
:readonly="!edit || statusCheck === 'NEW'" :readonly="!edit || statusCheck === 'NEW'"
:min-date="formDataFollowSpouse.coupleDayStartDateHistory"
week-start="0" week-start="0"
@update:model-value="updateLeaveHistoryTotal()" @update:model-value="updateLeaveHistoryTotal()"
> >
@ -677,14 +790,14 @@ onMounted(async () => {
<q-input <q-input
hide-bottom-space hide-bottom-space
type="textarea" type="textarea"
class="col-12 col-md-12 col-sm-12 cursor-pointer inputgreen" class="col-12 col-md-12 col-sm-12 inputgreen"
dense dense
bg-color="white" bg-color="white"
outlined outlined
ref="leaveDetailRef" ref="leaveDetailRef"
for="leaveDetailRef" for="leaveDetailRef"
v-model="formDataFollowSpouse.leaveDetail" v-model="formDataFollowSpouse.leaveDetail"
label="รายละเอียด" label="สาเหตุการลา"
:readonly="!edit || statusCheck === 'NEW'" :readonly="!edit || statusCheck === 'NEW'"
/> />
<div class="full-width" v-if="statusCheck != 'NEW'"> <div class="full-width" v-if="statusCheck != 'NEW'">
@ -791,28 +904,32 @@ onMounted(async () => {
<q-separator class="q-mt-sm" /> <q-separator class="q-mt-sm" />
<div class="row col-12 q-pt-md"> <div class="row col-12 q-pt-md">
<q-space /> <q-space />
<!-- <div v-if="totalCheck == 0" class="text-red q-mr-sm">**จำนวนวันลาของท่านไม่ถูกต้อง หรือวันที่ยื่นลาของท่านตรงกับวันหยุด</div> -->
<q-btn <q-btn
v-if="!props.data || props.data.status == 'DRAFT'" v-if="!props.data || props.data.status == 'DRAFT'"
id="onSubmit" id="onSubmit"
type="submit" type="submit"
unelevated unelevated
dense
class="q-px-md items-center btnBlue" class="q-px-md items-center btnBlue"
label="บันทึก" label="บันทึก"
><q-tooltip>นทกแบบราง</q-tooltip></q-btn :disable="!isLeave"
:loading="isLoadCheck"
> >
<q-tooltip>นทกแบบราง</q-tooltip>
</q-btn>
<q-btn <q-btn
v-if="data && statusCheck != 'NEW'" v-if="data && statusCheck != 'NEW'"
id="onSubmit" id="onSubmit"
type="button" type="button"
unelevated unelevated
dense
class="q-px-md items-center q-ml-sm" class="q-px-md items-center q-ml-sm"
color="primary" color="primary"
label="ยื่นใบลา" label="ยื่นใบลา"
@click="onConfirm()" @click="onConfirm()"
><q-tooltip>นใบลา</q-tooltip></q-btn :loading="isLoadCheck"
> >
<q-tooltip>นใบลา</q-tooltip>
</q-btn>
</div> </div>
</form> </form>
</template> </template>

View file

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { reactive, ref, onMounted, computed, watch } from "vue"; import { reactive, ref, onMounted, computed, watch } from "vue";
import { useQuasar } from "quasar"; import { is, useQuasar } from "quasar";
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
import type { RehabilitationForm } from "@/modules/05_leave/interface/request/AddAbsence"; import type { RehabilitationForm } from "@/modules/05_leave/interface/request/AddAbsence";
@ -8,11 +8,19 @@ import { useLeaveStore } from "@/modules/05_leave/store";
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 genReport from "@/plugins/genreport";
import { load } from "@/router/loader";
const $q = useQuasar(); const $q = useQuasar();
const dataStore = useLeaveStore(); const dataStore = useLeaveStore();
const mixin = useCounterMixin(); const mixin = useCounterMixin();
const { date2Thai, dateToISO, messageError, showLoader, hideLoader } = mixin; const {
date2Thai,
calculateDurationYmd,
messageError,
showLoader,
hideLoader,
convertDateToAPI,
} = mixin;
const edit = ref<boolean>(true); const edit = ref<boolean>(true);
const isSave = ref<boolean>(false); const isSave = ref<boolean>(false);
@ -20,6 +28,7 @@ const leaveId = ref<any>("");
const leaveStartDateRef = ref<object | null>(null); const leaveStartDateRef = ref<object | null>(null);
const leaveEndDateRef = ref<object | null>(null); const leaveEndDateRef = ref<object | null>(null);
const leaveWroteRef = ref<object | null>(null); const leaveWroteRef = ref<object | null>(null);
const leaveText = ref<string>("");
/** รับ props มาจากหน้าหลัก */ /** รับ props มาจากหน้าหลัก */
const props = defineProps({ const props = defineProps({
@ -49,6 +58,8 @@ const formDataRehabilitation = reactive<any>({
leaveEndDate: null, leaveEndDate: null,
leaveDocument: [], leaveDocument: [],
leaveDetail: "", leaveDetail: "",
leaveRange: "ALL",
leaveRangeEnd: "ALL",
leaveDraftDocument: null, leaveDraftDocument: null,
}); });
@ -78,15 +89,18 @@ async function onValidate() {
formData.append("type", formDataRehabilitation.type); // formData.append("type", formDataRehabilitation.type); //
formData.append( formData.append(
"leaveStartDate", "leaveStartDate",
dateToISO(new Date(formDataRehabilitation.leaveStartDate)) convertDateToAPI(formDataRehabilitation.leaveStartDate) ?? ""
); );
formData.append( formData.append(
"leaveEndDate", "leaveEndDate",
dateToISO(new Date(formDataRehabilitation.leaveEndDate)) convertDateToAPI(formDataRehabilitation.leaveEndDate) ?? ""
); );
formData.append("leaveWrote", formDataRehabilitation.leaveWrote); // formData.append("leaveWrote", formDataRehabilitation.leaveWrote); //
formData.append("leaveDetail", formDataRehabilitation.leaveDetail); // formData.append("leaveDetail", formDataRehabilitation.leaveDetail); //
formData.append("leaveTotal", formDataRehabilitation.leaveTotal); // formData.append("leaveTotal", formDataRehabilitation.leaveTotal); //
formData.append("leaveRange", formDataRehabilitation.leaveRange);
formData.append("leaveRangeEnd", formDataRehabilitation.leaveRangeEnd);
props.onSubmit(formData, isLeave.value); props.onSubmit(formData, isLeave.value);
} }
@ -101,33 +115,59 @@ const fileUploadDoc = async (files: any) => {
const reasonLeave = ref<string>(""); const reasonLeave = ref<string>("");
const isLeave = ref<boolean>(true); const isLeave = ref<boolean>(true);
/** const checkDate = computed(() => {
* check าลาไดไหม จาก api if (
* @param formData convertDateToAPI(formDataRehabilitation.leaveEndDate) ==
*/ convertDateToAPI(formDataRehabilitation.leaveStartDate)
async function FetchCheck() { ) {
showLoader(); return true;
await http } else {
.post(config.API.leaveCheck(), { return false;
type: dataStore.typeId ?? null, }
StartLeaveDate: formDataRehabilitation.leaveStartDate ?? null, });
EndLeaveDate: formDataRehabilitation.leaveEndDate ?? null,
})
.then((res: any) => {
const data = res.data.result;
isLeave.value = data.isLeave;
formDataRehabilitation.leaveTotal = data.totalDate;
reasonLeave.value = data.message const isLoadCheck = ref<boolean>(false);
? data.message /** check ว่าลาได้ไหม จาก api */
: "จำนวนวันลาเกินที่กำหนด"; async function fetchCheck() {
}) if (
.catch((e: any) => { formDataRehabilitation.leaveStartDate &&
messageError($q, e); formDataRehabilitation.leaveEndDate
}) ) {
.finally(() => { isLoadCheck.value = true;
hideLoader(); await http
}); .post(config.API.leaveCheck(), {
type: dataStore.typeId ?? null,
StartLeaveDate:
convertDateToAPI(formDataRehabilitation.leaveStartDate) ?? null,
EndLeaveDate:
convertDateToAPI(formDataRehabilitation.leaveEndDate) ?? null,
leaveRange: formDataRehabilitation.leaveRange,
leaveRangeEnd: checkDate.value
? formDataRehabilitation.leaveRange
: formDataRehabilitation.leaveRangeEnd,
})
.then((res: any) => {
const data = res.data.result;
isLeave.value = data.isLeave;
formDataRehabilitation.leaveTotal = data.totalDate;
// totalCheck.value = data.totalDate;
leaveText.value = calculateDurationYmd(
convertDateToAPI(formDataRehabilitation.leaveStartDate),
convertDateToAPI(formDataRehabilitation.leaveEndDate)
);
reasonLeave.value = data.message
? data.message
: "จำนวนวันลาเกินที่กำหนด";
})
.catch((e: any) => {
messageError($q, e);
// totalCheck.value = null
})
.finally(() => {
isLoadCheck.value = false;
});
}
} }
//download function //download function
@ -156,32 +196,56 @@ const dateEndInputStyle = computed(() => {
const leaveDocumentList = ref<any>(); const leaveDocumentList = ref<any>();
const leaveDraftDocument = ref<string>(); const leaveDraftDocument = ref<string>();
const statusCheck = ref<string>(""); const statusCheck = ref<string>("");
watch(props.data, () => { watch(
if (props.data) { () => props.data,
formDataRehabilitation.leaveWrote = props.data.leaveWrote; async () => {
formDataRehabilitation.leaveStartDate = new Date(props.data.leaveStartDate); if (props.data) {
formDataRehabilitation.leaveEndDate = new Date(props.data.leaveEndDate); // totalCheck.value = null;
formDataRehabilitation.leaveDetail = props.data.leaveDetail; formDataRehabilitation.leaveWrote = props.data.leaveWrote;
leaveDraftDocument.value = props.data.leaveDraftDocument; formDataRehabilitation.leaveStartDate = new Date(
leaveDocumentList.value = props.data.leaveDocument; props.data.leaveStartDate
formDataRehabilitation.leaveDraftDocument = null; );
formDataRehabilitation.leaveDocument = []; formDataRehabilitation.leaveEndDate = new Date(props.data.leaveEndDate);
statusCheck.value = props.data.status; formDataRehabilitation.leaveDetail = props.data.leaveDetail;
leaveDraftDocument.value = props.data.leaveDraftDocument;
leaveDocumentList.value = props.data.leaveDocument;
formDataRehabilitation.leaveRange = props.data.leaveRange;
formDataRehabilitation.leaveRangeEnd = props.data.leaveRangeEnd;
formDataRehabilitation.leaveDraftDocument = null;
formDataRehabilitation.leaveDocument = [];
statusCheck.value = props.data.status;
const leaveTotal = await calculateDurationYmd(
props.data.leaveStartDate,
props.data.leaveEndDate
);
leaveText.value = leaveTotal;
}
} }
}); );
/**Hook */ /**Hook */
onMounted(() => { onMounted(async () => {
if (props.data) { if (props.data) {
// totalCheck.value = null;
formDataRehabilitation.leaveWrote = props.data.leaveWrote; formDataRehabilitation.leaveWrote = props.data.leaveWrote;
formDataRehabilitation.leaveStartDate = new Date(props.data.leaveStartDate); formDataRehabilitation.leaveStartDate = new Date(props.data.leaveStartDate);
formDataRehabilitation.leaveEndDate = new Date(props.data.leaveEndDate); formDataRehabilitation.leaveEndDate = new Date(props.data.leaveEndDate);
formDataRehabilitation.leaveDetail = props.data.leaveDetail; formDataRehabilitation.leaveDetail = props.data.leaveDetail;
formDataRehabilitation.leaveRange = props.data.leaveRange;
formDataRehabilitation.leaveRangeEnd = props.data.leaveRangeEnd;
leaveDraftDocument.value = props.data.leaveDraftDocument; leaveDraftDocument.value = props.data.leaveDraftDocument;
leaveDocumentList.value = props.data.leaveDocument; leaveDocumentList.value = props.data.leaveDocument;
statusCheck.value = props.data.status; statusCheck.value = props.data.status;
leaveId.value = props.data.id; leaveId.value = props.data.id;
FetchCheck(); const leaveTotal = await calculateDurationYmd(
props.data.leaveStartDate,
props.data.leaveEndDate
);
leaveText.value = leaveTotal;
fetchCheck();
} }
}); });
</script> </script>
@ -195,153 +259,206 @@ onMounted(() => {
<q-form greedy @submit.prevent @validation-success="onValidate"> <q-form greedy @submit.prevent @validation-success="onValidate">
<q-card bordered class="q-pa-md bg-grey-1"> <q-card bordered class="q-pa-md bg-grey-1">
<div class="row q-pa-sm q-col-gutter-sm"> <div class="row q-pa-sm q-col-gutter-sm">
<q-input <div class="col-12 col-sm-12 inputgreen">
v-model="formDataRehabilitation.leaveWrote" <q-input
class="col-12 col-sm-12 cursor-pointer inputgreen" v-model="formDataRehabilitation.leaveWrote"
ref="leaveWroteRef" ref="leaveWroteRef"
dense dense
outlined outlined
bg-color="white" bg-color="white"
label="เขียนที่" label="เขียนที่"
hide-bottom-space hide-bottom-space
:readonly="!edit || statusCheck === 'NEW'" :readonly="!edit || statusCheck === 'NEW'"
:rules="[(val:string) => !!val || `${'เขียนที่'}`]" :rules="[(val:string) => !!val || `${'เขียนที่'}`]"
/> />
</div>
<datepicker <div class="col-12">
v-model="formDataRehabilitation.leaveStartDate" <div class="row q-col-gutter-sm">
class="col-12 col-md-4 col-sm-6 cursor-pointer inputgreen" <div class="col-12 col-md-3 col-sm-6 inputgreen">
menu-class-name="modalfix" <datepicker
autoApply v-model="formDataRehabilitation.leaveStartDate"
borderless :locale="'th'"
week-start="0" autoApply
:enableTimePicker="false" hide-bottom-space
:locale="'th'" borderless
:readonly="!edit || statusCheck === 'NEW'" :enableTimePicker="false"
@update:model-value="formDataRehabilitation.leaveEndDate = null" week-start="0"
> :readonly="!edit || statusCheck === 'NEW'"
<template #year="{ year }"> @update:model-value="
{{ year + 543 }} (formDataRehabilitation.leaveEndDate = null), fetchCheck()
</template> "
<template #year-overlay-value="{ value }"> >
{{ parseInt(value + 543) }} <template #year="{ year }">
</template> {{ year + 543 }}
<template #trigger> </template>
<q-input <template #year-overlay-value="{ value }">
ref="leaveStartDateRef" {{ parseInt(value + 543) }}
class="full-width datepicker" </template>
bg-color="white" <template #trigger>
outlined <q-input
dense outlined
lazy-rules dense
hide-bottom-space ref="leaveStartDateRef"
:readonly="!edit || statusCheck === 'NEW'" for="leaveStartDateRef"
:model-value=" hide-bottom-space
formDataRehabilitation.leaveStartDate != null bg-color="white"
? date2Thai(formDataRehabilitation.leaveStartDate) :readonly="!edit || statusCheck === 'NEW'"
: null class="full-width datepicker"
" :model-value="
:label="`${'ลาตั้งแต่วันที่'}`" formDataRehabilitation.leaveStartDate != null
:rules="[(val:string) => !!val || `${'กรุณาเลือกลาตั้งแต่วันที่'}`]" ? date2Thai(formDataRehabilitation.leaveStartDate)
> : null
<template v-slot:prepend> "
<q-icon :label="`${'วันที่เริ่มต้น'}`"
name="event" :rules="[(val:string) => !!val || `${'กรุณาเลือกวันที่เริ่มต้น'}`]"
class="cursor-pointer" >
style="color: var(--q-primary)" <template v-slot:prepend>
> <q-icon
</q-icon> name="event"
</template> class="cursor-pointer"
</q-input> style="color: var(--q-primary)"
</template> >
</datepicker> </q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<datepicker <!-- <div class="col-12 col-md-3 col-sm-6 inputgreen">
:class="!isLeave ? dateEndInputStyle : ''" <q-select
v-model="formDataRehabilitation.leaveEndDate" outlined
class="col-12 col-md-4 col-sm-6 cursor-pointer inputgreen" dense
menu-class-name="modalfix" bg-color="white"
autoApply v-model="formDataRehabilitation.leaveRange"
borderless :options="dataStore.rangeOptions"
week-start="0" emit-value
:locale="'th'" map-options
@update:model-value="FetchCheck()" option-value="id"
:readonly=" option-label="name"
!formDataRehabilitation.leaveStartDate || statusCheck === 'NEW' @update:model-value="fetchCheck()"
" >
:enableTimePicker="false" <template v-slot:prepend>
:min-date="formDataRehabilitation.leaveStartDate" <q-icon
> name="mdi-clock-outline"
<template #year="{ year }"> style="color: var(--q-primary)"
{{ year + 543 }} />
</template> </template>
<template #year-overlay-value="{ value }"> </q-select>
{{ parseInt(value + 543) }} </div> -->
</template> <!-- </div>
<template #trigger> </div>
<q-input <div class="col-12">
ref="leaveEndDateRef" <div class="row q-col-gutter-sm"> -->
class="full-width datepicker" <div class="col-12 col-md-3 col-sm-6 inputgreen">
outlined <datepicker
dense v-model="formDataRehabilitation.leaveEndDate"
lazy-rules :locale="'th'"
hide-bottom-space autoApply
:readonly=" hide-bottom-space
!formDataRehabilitation.leaveStartDate || statusCheck === 'NEW' @update:model-value="fetchCheck()"
" borderless
:model-value=" :enableTimePicker="false"
formDataRehabilitation.leaveEndDate != null week-start="0"
? date2Thai(formDataRehabilitation.leaveEndDate) :min-date="formDataRehabilitation.leaveStartDate"
: null >
" <template #year="{ year }">
:label="`${'ลาถึงวันที่'}`" {{ year + 543 }}
:bottom-slots="!isLeave ? true : false" </template>
:color="!isLeave ? 'red' : 'black'" <template #year-overlay-value="{ value }">
:bg-color="!isLeave ? 'red-2' : 'white'" {{ parseInt(value + 543) }}
:border-color="!isLeave ? 'red' : 'gray'" </template>
:input-class="!isLeave ? dateEndInputStyle : ''" <template #trigger>
> <q-input
<template v-slot:prepend> outlined
<q-icon dense
name="event" ref="leaveEndDateRef"
class="cursor-pointer" for="leaveEndDateRef"
style="color: var(--q-primary)" hide-bottom-space
> bg-color="white"
</q-icon> class="full-width datepicker"
</template> :model-value="
formDataRehabilitation.leaveEndDate != null
? date2Thai(formDataRehabilitation.leaveEndDate)
: 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>
<template v-slot:hint> <!-- <div class="col-12 col-md-3 col-sm-6 inputgreen">
<span style="color: red"> <q-select
{{ !isLeave ? reasonLeave : "" }} v-if="!checkDate"
</span> outlined
</template> dense
</q-input> bg-color="white"
</template> v-model="formDataRehabilitation.leaveRangeEnd"
</datepicker> :options="dataStore.rangeOptions.filter((items:any)=> items.id !== 'AFTERNOON')"
emit-value
map-options
option-value="id"
option-label="name"
@update:model-value="fetchCheck()"
>
<template v-slot:prepend>
<q-icon
name="mdi-clock-outline"
style="color: var(--q-primary)"
/>
</template>
</q-select>
</div> -->
<q-input <div class="col-12 col-md-3 col-sm-6">
class="col-12 col-md-4 col-sm-12" <q-input
dense :bottom-slots="!isLeave ? true : false"
outlined :color="!isLeave ? 'red' : 'black'"
readonly :bg-color="!isLeave ? 'red-2' : 'white'"
hide-bottom-space :border-color="!isLeave ? 'red' : 'gray'"
bg-color="white" :input-class="!isLeave ? dateEndInputStyle : ''"
ref="coupleDayTotalHistoryRef" dense
for="coupleDayTotalHistoryRef" outlined
v-model="formDataRehabilitation.leaveTotal" ref="leaveTotalRef"
label="เป็นเวลา" for="leaveTotalRef"
/> v-model="leaveText"
label="เป็นเวลา"
readonly
:loading="isLoadCheck"
>
<template v-slot:hint>
<span style="color: red">
{{ !isLeave ? reasonLeave : "" }}
</span>
</template>
</q-input>
</div>
</div>
</div>
<q-input <div class="col-12 col-md-12 col-sm-12 inputgreen">
v-model="formDataRehabilitation.leaveDetail" <q-input
:readonly="!edit || statusCheck === 'NEW'" v-model="formDataRehabilitation.leaveDetail"
class="col-12 col-md-12 col-sm-12 cursor-pointer inputgreen" :readonly="!edit || statusCheck === 'NEW'"
bg-color="white" bg-color="white"
dense dense
outlined outlined
type="textarea" type="textarea"
label="รายละเอียด" label="สาเหตุการลา"
/> />
</div>
<div class="col-12" v-if="statusCheck != 'NEW'"> <div class="col-12" v-if="statusCheck != 'NEW'">
<q-file <q-file
@ -476,28 +593,32 @@ onMounted(() => {
<q-separator class="q-mt-sm" /> <q-separator class="q-mt-sm" />
<div class="row col-12 q-pt-md"> <div class="row col-12 q-pt-md">
<q-space /> <q-space />
<!-- <div v-if="totalCheck == 0" class="text-red q-mr-sm">**จำนวนวันลาของท่านไม่ถูกต้อง หรือวันที่ยื่นลาของท่านตรงกับวันหยุด</div> -->
<q-btn <q-btn
v-if="!props.data || props.data.status == 'DRAFT'" v-if="!props.data || props.data.status == 'DRAFT'"
id="onSubmit" id="onSubmit"
type="submit" type="submit"
unelevated unelevated
dense
class="q-px-md items-center btnBlue" class="q-px-md items-center btnBlue"
label="บันทึก" label="บันทึก"
><q-tooltip>นทกแบบราง</q-tooltip></q-btn :disable="!isLeave"
:loading="isLoadCheck"
> >
<q-tooltip>นทกแบบราง</q-tooltip>
</q-btn>
<q-btn <q-btn
v-if="data && statusCheck != 'NEW'" v-if="data && statusCheck != 'NEW'"
id="onSubmit" id="onSubmit"
type="button" type="button"
unelevated unelevated
dense
class="q-px-md items-center q-ml-sm" class="q-px-md items-center q-ml-sm"
color="primary" color="primary"
label="ยื่นใบลา" label="ยื่นใบลา"
@click="onConfirm()" @click="onConfirm()"
><q-tooltip>นใบลา</q-tooltip></q-btn :loading="isLoadCheck"
> >
<q-tooltip>นใบลา</q-tooltip>
</q-btn>
</div> </div>
</div> </div>
</q-form> </q-form>

View file

@ -1,12 +1,22 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted } from "vue"; import { ref } from "vue";
import { useQuasar, type QTableProps } from "quasar";
import http from "@/plugins/http";
import config from "@/app.config";
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
import { useLeaveStore } from "@/modules/05_leave/store"; import { useLeaveStore } from "@/modules/05_leave/store";
import { useDataStore } from "@/stores/data";
const mixin = useCounterMixin(); import type { PropsTable } from "@/interface/PropsTable";
import type { DataCommander } from "@/modules/05_leave/interface/response/main";
import DialogHeader from "@/components/DialogHeader.vue";
const $q = useQuasar();
const dataStore = useLeaveStore(); const dataStore = useLeaveStore();
const { date2Thai } = mixin; const storeData = useDataStore();
const { date2Thai, messageError } = useCounterMixin();
/** รับ props มาจากหน้าหลัก */ /** รับ props มาจากหน้าหลัก */
const props = defineProps({ const props = defineProps({
@ -16,18 +26,166 @@ const props = defineProps({
}, },
}); });
/**Hook */ const modal = ref<boolean>(false);
onMounted(() => {
dataStore.typeLeave = ""; const isAct = ref<boolean>(false);
const selected = ref<DataCommander[]>([]);
const search = ref<string>("");
const isLoading = ref<boolean>(false);
const rows = ref<DataCommander[]>([]);
const columns = ref<QTableProps["columns"]>([
{
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: "posExecutiveName",
align: "left",
label: "ตำแหน่งทางการบริหาร",
sortable: true,
field: "posExecutiveName",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
]);
const pagination = ref<PropsTable.Pagination>({
sortBy: "createdAt",
descending: true,
page: 1,
rowsPerPage: 10,
rowsNumber: 0,
}); });
/** ฟังก์ชันสำหรับดึงข้อมูลผู้บังคับบัญชา */
async function getCommander() {
isLoading.value = true;
await http
.put(config.API.commanderOperate, {
isAct: isAct.value,
keyword: search.value.trim(),
page: pagination.value.page,
pageSize: pagination.value.rowsPerPage,
keycloakId: storeData.formData.keycloakId,
type:
storeData.officerType.toLocaleUpperCase() == "OFFICER"
? "officer"
: "employee",
})
.then((res) => {
const result = res.data.result;
rows.value = result.data;
pagination.value = {
...pagination.value,
rowsNumber: result.total,
};
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
isLoading.value = false;
});
}
/*** ฟังก์ชันสำหรับเปิด Modal และดึงข้อมูลผู้บังคับบัญชา */
function onPerson() {
modal.value = true;
getCommander();
}
/*** ฟังก์ชันสำหรับปิด Modal และล้างข้อมูล */
function closeDialog() {
modal.value = false;
search.value = "";
rows.value = [];
selected.value = [];
pagination.value = {
sortBy: "createdAt",
descending: true,
page: 1,
rowsPerPage: 10,
rowsNumber: 0,
};
}
/** ฟังก์ชันสำหรับยืนยันการเลือกผู้บังคับบัญชา */
function onSubmit() {
modal.value = false;
dataStore.dear = selected.value[0].firstName
? `${selected.value[0].prefix}${selected.value[0].firstName} ${selected.value[0].lastName}`
: "";
dataStore.commanderPosition = selected.value[0].posExecutiveName;
}
/**
* งกนร request จากตาราง เมอมการเปลยน pagination
* @param requestProps อมลการรองขอจากตาราง
*/
function onTableRequest(requestProps: PropsTable.RequestProps) {
const newPagination = requestProps?.pagination || requestProps;
if (!newPagination?.page || !newPagination?.rowsPerPage) return;
pagination.value = { ...newPagination };
getCommander();
}
/** ฟังก์ชันสำหรับค้นหาข้อมูล*/
function getSearch() {
pagination.value.page = 1;
getCommander();
}
</script> </script>
<template> <template>
<q-card bordered class="q-pa-md bg-grey-1"> <q-card bordered class="q-pa-md bg-grey-1">
<div class="col-12 row q-pa-sm q-col-gutter-sm items-center">
<q-input
v-model="dataStore.dear"
dense
outlined
bg-color="white"
label="เรียน (ชื่อ - นามสกุล)"
class="col-4"
></q-input>
<q-input
v-model="dataStore.commanderPosition"
dense
outlined
bg-color="white"
label="เรียน (ตำแหน่ง)"
class="col-4"
></q-input>
<div class="col-4">
<q-btn
class="bg-secondary text-white"
icon="add"
unelevated
@click="onPerson"
><q-tooltip>เพมรายช</q-tooltip></q-btn
>
</div>
</div>
<div class="col-12"><q-separator /></div>
<div class="col-12 row q-pa-sm q-col-gutter-sm"> <div class="col-12 row q-pa-sm q-col-gutter-sm">
<datepicker <datepicker
class="col-12 col-sm-4" class="col-12 col-sm-6"
menu-class-name="modalfix"
v-model="dataStore.dateSendLeave" v-model="dataStore.dateSendLeave"
:locale="'th'" :locale="'th'"
autoApply autoApply
@ -70,7 +228,7 @@ onMounted(() => {
</template> </template>
</datepicker> </datepicker>
<q-input <q-input
class="col-12 col-sm-4" class="col-12 col-sm-6"
dense dense
bg-color="white" bg-color="white"
outlined outlined
@ -78,26 +236,18 @@ onMounted(() => {
v-model="dataStore.typeLeave" v-model="dataStore.typeLeave"
label="เรื่อง" label="เรื่อง"
/> />
<q-input <q-input
class="col-12 col-sm-4" class="col-12 col-sm-4"
dense dense
outlined outlined
readonly readonly
bg-color="white" bg-color="white"
v-model="dataStore.dear"
label="เรียน"
/>
<q-input
class="col-12 col-sm-3"
dense
outlined
readonly
bg-color="white"
v-model="dataStore.fullName" v-model="dataStore.fullName"
label="ชื่อผู้ยื่นขอ" label="ชื่อผู้ยื่นขอ"
/> />
<q-input <q-input
class="col-12 col-sm-3" class="col-12 col-sm-4"
dense dense
outlined outlined
readonly readonly
@ -106,7 +256,7 @@ onMounted(() => {
label="ตำแหน่งผู้ยื่นขอ" label="ตำแหน่งผู้ยื่นขอ"
/> />
<q-input <q-input
class="col-12 col-sm-3" class="col-12 col-sm-4"
dense dense
outlined outlined
readonly readonly
@ -115,7 +265,7 @@ onMounted(() => {
label="ระดับผู้ยื่นขอ" label="ระดับผู้ยื่นขอ"
/> />
<q-input <q-input
class="col-12 col-sm-3" class="col-12 text-html"
dense dense
outlined outlined
readonly readonly
@ -154,4 +304,131 @@ onMounted(() => {
/> />
</div> </div>
</q-card> </q-card>
<q-dialog v-model="modal" persistent>
<q-card class="col-12" style="width: 80%">
<q-form greedy @submit.prevent @validation-success="onSubmit">
<DialogHeader :tittle="`เลือกผู้บังคับบัญชา`" :close="closeDialog" />
<q-separator />
<q-card-section>
<div class="row q-col-gutter-sm">
<div class="col-12">
<div class="row q-col-gutter-md items-start">
<div class="col-12 col-sm-6 col-md-4">
<q-input
v-model="search"
outlined
hide-bottom-space
dense
label="คำค้น"
@keydown.enter.prevent="getSearch()"
/>
</div>
<div class="col-12 col-sm-6 col-md-4">
<q-checkbox
keep-color
v-model="isAct"
label="แสดงเฉพาะรักษาการแทน"
color="primary"
@update:model-value="getSearch()"
>
<q-tooltip>แสดงเฉพาะรกษาการแทน </q-tooltip>
</q-checkbox>
</div>
<q-space v-if="$q.screen.gt.sm" />
<div class="col-12 col-md-3">
<q-btn
color="primary"
icon="search"
label="ค้นหา"
class="full-width q-pa-sm"
outline
@click.prevent="getSearch()"
>
</q-btn>
</div>
</div>
</div>
<div class="col-12">
<d-table
ref="table"
:columns="columns"
:rows="rows"
row-key="key"
flat
bordered
:paging="true"
dense
:rows-per-page-options="[10, 25, 50, 100]"
selection="single"
v-model:pagination="pagination"
v-model:selected="selected"
:loading="isLoading"
@request="onTableRequest"
>
<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 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-tr>
</template>
<template v-slot:body="props">
<q-tr :props="props" class="cursor-pointer">
<q-td>
<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 v-if="col.name == 'no'">
{{ props.rowIndex + 1 }}
</div>
<div v-else>
{{ col.value ? col.value : "-" }}
</div>
</q-td>
</q-tr>
</template>
</d-table>
</div>
</div>
</q-card-section>
<q-separator />
<q-card-actions align="right">
<q-btn
label="บันทึก"
color="secondary"
type="submit"
:disable="selected.length === 0"
>
<q-tooltip>นทกขอม</q-tooltip>
</q-btn>
</q-card-actions>
</q-form>
</q-card>
</q-dialog>
</template> </template>

View file

@ -30,19 +30,20 @@ const year = ref<number>(new Date().getFullYear());
const type = ref<string>("00000000-0000-0000-0000-000000000000"); const type = ref<string>("00000000-0000-0000-0000-000000000000");
const status = ref<string>("ALL"); const status = ref<string>("ALL");
const filter = ref<string>(""); const filter = ref<string>("");
const isLoading = ref<boolean>(false);
/** pagination*/ /** pagination*/
const maxPage = ref<number>(1); const maxPage = ref<number>(1);
const page = ref<number>(1); const page = ref<number>(1);
const pageSize = ref<number>(10); const pageSize = ref<number>(10);
const total = ref<number>(0);
/** function เรียกข้อมูลการลา*/ /** function เรียกข้อมูลการลา*/
async function fetchDataTable() { async function fetchDataTable() {
showLoader(); isLoading.value = true;
const body = { const body = {
year: year.value, //*( .) year: year.value, //*( .)
type: type.value, //*Id type: LeaveData.type, //*Id
status: status.value, //* status: LeaveData.status, //*
page: page.value.toString(), //* page: page.value.toString(), //*
pageSize: pageSize.value.toString(), //* pageSize: pageSize.value.toString(), //*
keyword: filter.value, //keyword keyword: filter.value, //keyword
@ -53,26 +54,24 @@ async function fetchDataTable() {
const data = res.data.result.data; const data = res.data.result.data;
LeaveData.fetchListLeave(data); LeaveData.fetchListLeave(data);
maxPage.value = Math.ceil(res.data.result.total / pageSize.value); maxPage.value = Math.ceil(res.data.result.total / pageSize.value);
total.value = res.data.result.total;
}) })
.catch((err) => { .catch((err) => {
messageError($q, err); messageError($q, err);
}) })
.finally(() => { .finally(() => {
hideLoader(); isLoading.value = false;
}); });
} }
/** function เรียกประเภทการลา */ /** function เรียกประเภทการลา */
async function fectOptionType() { async function fectOptionType() {
await http const data = await LeaveData.fetchLeaveTypeData();
.get(config.API.leaveType()) if (!data) {
.then(async (res) => { return;
leaveType.value = res.data.result; }
LeaveData.fetchLeaveType(res.data.result); leaveType.value = data;
}) LeaveData.fetchLeaveType(data);
.catch((err) => {
messageError($q, err);
});
} }
/** /**
@ -94,25 +93,26 @@ async function onClickEdit(id: string) {
router.push(`/leave/edit/${id}`); router.push(`/leave/edit/${id}`);
} }
//
function clickDelete(id: string) {
dialogRemove($q, () => onClickDelete(id));
}
/** /**
* function ลบรายการ * งกนลบขอมลการลา
* @param id * @param id รายการลาทองการลบ
*/ */
async function onClickDelete(id: string) { function clickDelete(id: string) {
await http dialogRemove($q, async () => {
.delete(config.API.leaveUserId(id)) showLoader();
.then(async (res) => { await http
success($q, "ลบข้อมูลสำเร็จ"); .delete(config.API.leaveUserId(id))
fetchDataTable(); .then(async () => {
}) await fetchDataTable();
.catch((err) => { success($q, "ลบข้อมูลสำเร็จ");
messageError($q, err); })
}); .catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
});
} }
/** function closePopup*/ /** function closePopup*/
@ -129,10 +129,10 @@ async function onClickClose() {
*/ */
async function updateFilterTable(y: number, t: string, s: string, k: string) { async function updateFilterTable(y: number, t: string, s: string, k: string) {
if (t && s) { if (t && s) {
year.value = await y; year.value = y;
type.value = await t; type.value = t;
status.value = await s; status.value = s;
filter.value = await k; filter.value = k;
await fetchDataTable(); await fetchDataTable();
} }
} }
@ -143,7 +143,7 @@ async function updateFilterTable(y: number, t: string, s: string, k: string) {
* @param ps แถวตอหน * @param ps แถวตอหน
*/ */
async function updatePagination(p: number, ps: number) { async function updatePagination(p: number, ps: number) {
(page.value = await p), (pageSize.value = await ps); (page.value = p), (pageSize.value = ps);
await fetchDataTable(); await fetchDataTable();
} }
@ -154,9 +154,11 @@ function convert(val: any) {
); );
const type = filtertype?.code; const type = filtertype?.code;
if (type == "LV-006" && val.hajjDayStatus == false) { if (type == "LV-006" && val.hajjDayStatus == false) {
return "ลาอุปสมบท"; return "ลาอุปสมบทหรือการลาประกอบพิธีฮัจญ์ฯ";
// return ""; API
} else if (type == "LV-006" && val.hajjDayStatus == true) { } else if (type == "LV-006" && val.hajjDayStatus == true) {
return "ลาประกอบพิธีฮัจญ์"; return "ลาอุปสมบทหรือการลาประกอบพิธีฮัจญ์ฯ";
// return ""; API
} else { } else {
return val.leaveTypeName; return val.leaveTypeName;
} }
@ -185,6 +187,8 @@ onMounted(async () => {
:maxPage="maxPage" :maxPage="maxPage"
:pageSize="pageSize" :pageSize="pageSize"
:leaveType="leaveType" :leaveType="leaveType"
:total="total"
:isloadingData="isLoading"
> >
<template #columns="props"> <template #columns="props">
<q-tr :props="props" class="cursor-pointer"> <q-tr :props="props" class="cursor-pointer">
@ -193,14 +197,22 @@ onMounted(async () => {
:props="props" :props="props"
@click="onClickView(props.row.id, props.row.status)" @click="onClickView(props.row.id, props.row.status)"
> >
{{ (page - 1) * pageSize + props.rowIndex + 1 }} {{ props.rowIndex + 1 }}
</q-td> </q-td>
<q-td <q-td
key="leaveTypeName" key="leaveTypeName"
:props="props" :props="props"
@click="onClickView(props.row.id, props.row.status)" @click="onClickView(props.row.id, props.row.status)"
> >
{{ convert(props.row) }} {{
props.row.leaveTypeName
? `${props.row.leaveTypeName} ${
props.row.leaveSubTypeName
? `(${props.row.leaveSubTypeName})`
: ""
}`
: "-"
}}
</q-td> </q-td>
<q-td <q-td
key="dateLeave" key="dateLeave"
@ -256,7 +268,9 @@ onMounted(async () => {
class="q-mr-sm" class="q-mr-sm"
/> />
<q-icon <q-icon
v-if="props.row.status == 'DELETE'" v-if="
props.row.status == 'DELETING' || props.row.status == 'DELETE'
"
size="10px" size="10px"
color="grey-10" color="grey-10"
name="mdi-circle" name="mdi-circle"
@ -271,7 +285,8 @@ onMounted(async () => {
v-if=" v-if="
props.row.status != 'DELETE' && props.row.status != 'DELETE' &&
props.row.status != 'REJECT' && props.row.status != 'REJECT' &&
props.row.status != 'CANCEL' props.row.status != 'CANCEL' &&
props.row.status != 'DELETING'
" "
flat flat
icon="mdi-dots-vertical" icon="mdi-dots-vertical"
@ -284,6 +299,7 @@ onMounted(async () => {
<q-menu> <q-menu>
<q-list> <q-list>
<q-item <q-item
v-if="props.row.status != 'DRAFT'"
clickable clickable
v-close-popup v-close-popup
@click="onClickView(props.row.id, 'CANCEL')" @click="onClickView(props.row.id, 'CANCEL')"
@ -424,7 +440,10 @@ onMounted(async () => {
class="q-mr-sm" class="q-mr-sm"
/> />
<q-icon <q-icon
v-if="props.row.status == 'DELETE'" v-if="
props.row.status == 'DELETING' ||
props.row.status == 'DELETE'
"
size="10px" size="10px"
color="grey-10" color="grey-10"
name="mdi-circle" name="mdi-circle"

View file

@ -2,6 +2,7 @@
import { ref, useAttrs, watch } from "vue"; import { ref, useAttrs, watch } from "vue";
import { useQuasar } from "quasar"; import { useQuasar } from "quasar";
import type { PropsTable } from "@/interface/PropsTable";
import { useLeaveStore } from "@/modules/05_leave/store"; import { useLeaveStore } from "@/modules/05_leave/store";
const $q = useQuasar(); const $q = useQuasar();
@ -14,7 +15,7 @@ const props = defineProps({
count: Number, count: Number,
pass: Number, pass: Number,
notpass: Number, notpass: Number,
total: Number,
name: String, name: String,
icon: String, icon: String,
inputvisible: Array, inputvisible: Array,
@ -33,6 +34,10 @@ const props = defineProps({
type: Object, type: Object,
require: true, require: true,
}, },
isloadingData: {
type: Boolean,
default: false,
},
}); });
/** /**
@ -47,17 +52,28 @@ const emit = defineEmits([
const table = ref<any>(null); const table = ref<any>(null);
/** /** ตั้งค่า pagination*/
* งค pagination
*/
const currentPage = ref<number>(1); const currentPage = ref<number>(1);
const pagination = ref({
sortBy: "desc", const pagination = ref<PropsTable.Pagination>({
descending: false, sortBy: "dateSendLeave",
descending: true,
page: 1, page: 1,
rowsPerPage: Number(props.pageSize), rowsPerPage: Number(props.pageSize),
rowsNumber: Number(props.total),
}); });
// Watch props pagination ( props)
watch(
() => [props.pageSize, props.total],
([newPageSize, newTotal]) => {
pagination.value.rowsPerPage = Number(newPageSize);
pagination.value.rowsNumber = Number(newTotal);
},
{ immediate: true }
);
/** filter */ /** filter */
const year = ref<number>(new Date().getFullYear()); const year = ref<number>(new Date().getFullYear());
const filter = ref<string>(""); const filter = ref<string>("");
@ -83,15 +99,17 @@ function updatePagination(p: number, ps: number) {
emit("update:Pagination", p, ps); emit("update:Pagination", p, ps);
} }
/** function updatePageSize*/ /**
function updatePageSize(newPageSize: any) { * งกนร request จากตาราง เมอมการเปลยน pagination
currentPage.value = 1; * @param requestProps อมลการรองขอจากตาราง
pagination.value.rowsPerPage = newPageSize.rowsPerPage; */
function onTableRequest(requestProps: PropsTable.RequestProps) {
const newPagination = requestProps?.pagination || requestProps;
if (!newPagination?.page || !newPagination?.rowsPerPage) return;
currentPage.value = newPagination.page;
pagination.value = { ...newPagination };
updatePagination(newPagination.page, newPagination.rowsPerPage);
} }
watch([() => currentPage.value, () => pagination.value.rowsPerPage], () => {
updatePagination(currentPage.value, pagination.value.rowsPerPage);
});
</script> </script>
<template> <template>
@ -100,7 +118,6 @@ watch([() => currentPage.value, () => pagination.value.rowsPerPage], () => {
<div class="items-center col-12 row q-col-gutter-sm"> <div class="items-center col-12 row q-col-gutter-sm">
<datepicker <datepicker
v-if="leaveStore.tabValue === 'list'" v-if="leaveStore.tabValue === 'list'"
menu-class-name="modalfix"
v-model="year" v-model="year"
class="col-xs-12 col-sm-auto" class="col-xs-12 col-sm-auto"
:locale="'th'" :locale="'th'"
@ -134,6 +151,8 @@ watch([() => currentPage.value, () => pagination.value.rowsPerPage], () => {
</datepicker> </datepicker>
<!-- นหาขอความใน table --> <!-- นหาขอความใน table -->
<q-select <q-select
fill-input
hide-selected
outlined outlined
dense dense
v-model="leaveStore.type" v-model="leaveStore.type"
@ -173,6 +192,8 @@ watch([() => currentPage.value, () => pagination.value.rowsPerPage], () => {
/> </template /> </template
></q-select> ></q-select>
<q-select <q-select
fill-input
hide-selected
outlined outlined
dense dense
v-model="leaveStore.status" v-model="leaveStore.status"
@ -240,9 +261,10 @@ watch([() => currentPage.value, () => pagination.value.rowsPerPage], () => {
:virtual-scroll-sticky-size-start="48" :virtual-scroll-sticky-size-start="48"
dense dense
:rows-per-page-options="[10, 25, 50, 100]" :rows-per-page-options="[10, 25, 50, 100]"
:pagination="pagination" v-model:pagination="pagination"
@update:pagination="updatePageSize" @request="onTableRequest"
:grid="$q.screen.gt.xs ? false : true" :grid="$q.screen.gt.xs ? false : true"
:loading="isloadingData"
> >
<template v-slot:header="props"> <template v-slot:header="props">
<q-tr :props="props"> <q-tr :props="props">
@ -251,17 +273,6 @@ watch([() => currentPage.value, () => pagination.value.rowsPerPage], () => {
</q-th> </q-th>
</q-tr> </q-tr>
</template> </template>
<template v-slot:pagination="scope">
<q-pagination
v-model="currentPage"
active-color="primary"
color="dark"
:max="Number(props.maxPage)"
size="sm"
boundary-links
direction-links
></q-pagination>
</template>
<template #body="props"> <template #body="props">
<slot v-bind="props" name="columns"></slot> <slot v-bind="props" name="columns"></slot>
</template> </template>

View file

@ -1,4 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { useLeaveStore } from "@/modules/05_leave/store";
const store = useLeaveStore();
const { converstType } = store;
/** /**
* prop จาก component * prop จาก component
*/ */
@ -26,22 +30,16 @@ const props = defineProps({
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveDateStart }}</div> <div class="col-xs-12 col-md-6">{{ props.data.leaveDateStart }} {{ `${props.data.leaveRange && props.data.leaveRange !== 'ALL' ? `(${converstType(props.data.leaveRange)})`:''}` }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveDateEnd }}</div> <div class="col-xs-12 col-md-6">{{ props.data.leaveDateEnd }} {{ `${props.data.leaveDateStart !== props.data.leaveDateEnd ? `${props.data.leaveRangeEnd && props.data.leaveRangeEnd !== 'ALL' ? `(${converstType(props.data.leaveRangeEnd)})`:''}` :''}` }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div> <div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div>
<div class="col-xs-12 col-md-6"> <div class="col-xs-12 col-md-6">
{{ {{ props.data.leaveTotal ? props.data.leaveTotal + " วัน" : "-" }}
props.data.leaveRange == "ALL"
? props.data.leaveTotal + " วัน"
: props.data.leaveRange == "MORNING"
? "ลาครึ่งวันเช้า (0.5)"
: "ลาครึ่งวันบ่าย (0.5)"
}}
</div> </div>
</div> </div>
<div class="row"> <div class="row">
@ -67,7 +65,7 @@ const props = defineProps({
<div class="col-xs-12 col-md-6">{{ props.data.leaveAddress }}</div> <div class="col-xs-12 col-md-6">{{ props.data.leaveAddress }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">รายละเอยด</div> <div class="col-xs-12 col-md-6 text-grey-8">สาเหตการลา</div>
<div class="col-xs-12 col-md-6"> <div class="col-xs-12 col-md-6">
{{ props.data.leaveDetail ? props.data.leaveDetail : "-" }} {{ props.data.leaveDetail ? props.data.leaveDetail : "-" }}
</div> </div>

View file

@ -1,4 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { useLeaveStore } from '@/modules/05_leave/store'
const store = useLeaveStore()
const { converstType } = store
/** /**
* prop จาก component * prop จาก component
*/ */
@ -25,11 +29,11 @@ const props = defineProps({
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveDateStart }}</div> <div class="col-xs-12 col-md-6">{{ props.data.leaveDateStart }} {{ `${props.data.leaveRange && props.data.leaveRange !== 'ALL' ? `(${converstType(props.data.leaveRange)})`:''}` }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveDateEnd }}</div> <div class="col-xs-12 col-md-6">{{ props.data.leaveDateEnd }} {{ `${props.data.leaveDateStart !== props.data.leaveDateEnd ? `${props.data.leaveRangeEnd && props.data.leaveRangeEnd !== 'ALL' ? `(${converstType(props.data.leaveRangeEnd)})`:''}` :''}` }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div> <div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div>
@ -56,7 +60,7 @@ const props = defineProps({
<div class="col-xs-12 col-md-6">{{ props.data.leaveAddress }}</div> <div class="col-xs-12 col-md-6">{{ props.data.leaveAddress }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">รายละเอยด</div> <div class="col-xs-12 col-md-6 text-grey-8">สาเหตการลา</div>
<div class="col-xs-12 col-md-6"> <div class="col-xs-12 col-md-6">
{{ props.data.leaveDetail ? props.data.leaveDetail : "-" }} {{ props.data.leaveDetail ? props.data.leaveDetail : "-" }}
</div> </div>

View file

@ -1,4 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { useLeaveStore } from "@/modules/05_leave/store";
const store = useLeaveStore();
const { converstType } = store;
/** /**
* prop จาก component * prop จาก component
*/ */
@ -38,22 +42,16 @@ const props = defineProps({
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveDateStart }}</div> <div class="col-xs-12 col-md-6">{{ props.data.leaveDateStart }} {{ `${props.data.leaveRange && props.data.leaveRange !== 'ALL' ? `(${converstType(props.data.leaveRange)})`:''}` }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveDateEnd }}</div> <div class="col-xs-12 col-md-6">{{ props.data.leaveDateEnd }} {{ `${props.data.leaveDateStart !== props.data.leaveDateEnd ? `${props.data.leaveRangeEnd && props.data.leaveRangeEnd !== 'ALL' ? `(${converstType(props.data.leaveRangeEnd)})`:''}` :''}` }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div> <div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div>
<div class="col-xs-12 col-md-6"> <div class="col-xs-12 col-md-6">
{{ {{ props.data.leaveTotal ? props.data.leaveTotal + " วัน" : "-" }}
props.data.leaveRange == "ALL"
? props.data.leaveTotal + " วัน"
: props.data.leaveRange == "MORNING"
? "ลาครึ่งวันเช้า (0.5)"
: "ลาครึ่งวันบ่าย (0.5)"
}}
</div> </div>
</div> </div>
<div class="row"> <div class="row">
@ -71,7 +69,7 @@ const props = defineProps({
<div class="col-xs-12 col-md-6">{{ props.data.leaveAddress }}</div> <div class="col-xs-12 col-md-6">{{ props.data.leaveAddress }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">รายละเอยด</div> <div class="col-xs-12 col-md-6 text-grey-8">สาเหตการลา</div>
<div class="col-xs-12 col-md-6"> <div class="col-xs-12 col-md-6">
{{ props.data.leaveDetail ? props.data.leaveDetail : "-" }} {{ props.data.leaveDetail ? props.data.leaveDetail : "-" }}
</div> </div>

View file

@ -1,4 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { useLeaveStore } from '@/modules/05_leave/store'
const store = useLeaveStore()
const { converstType } = store
/** /**
* prop จาก component * prop จาก component
*/ */
@ -26,11 +30,11 @@ const props = defineProps({
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveDateStart }}</div> <div class="col-xs-12 col-md-6">{{ props.data.leaveDateStart }} {{ `${props.data.leaveRange && props.data.leaveRange !== 'ALL' ? `(${converstType(props.data.leaveRange)})`:''}` }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveDateEnd }}</div> <div class="col-xs-12 col-md-6">{{ props.data.leaveDateEnd }} {{ `${props.data.leaveDateStart !== props.data.leaveDateEnd ? `${props.data.leaveRangeEnd && props.data.leaveRangeEnd !== 'ALL' ? `(${converstType(props.data.leaveRangeEnd)})`:''}` :''}` }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div> <div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div>
@ -72,7 +76,7 @@ const props = defineProps({
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">รายละเอยด</div> <div class="col-xs-12 col-md-6 text-grey-8">สาเหตการลา</div>
<div class="col-xs-12 col-md-6"> <div class="col-xs-12 col-md-6">
{{ props.data.leaveDetail ? props.data.leaveDetail : "-" }} {{ props.data.leaveDetail ? props.data.leaveDetail : "-" }}
</div> </div>

View file

@ -1,4 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { useLeaveStore } from '@/modules/05_leave/store'
const store = useLeaveStore()
const { converstType } = store
/** /**
* prop จาก component * prop จาก component
*/ */
@ -26,11 +30,11 @@ const props = defineProps({
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveDateStart }}</div> <div class="col-xs-12 col-md-6">{{ props.data.leaveDateStart }} {{ `${props.data.leaveRange && props.data.leaveRange !== 'ALL' ? `(${converstType(props.data.leaveRange)})`:''}` }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveDateEnd }}</div> <div class="col-xs-12 col-md-6">{{ props.data.leaveDateEnd }} {{ `${props.data.leaveDateStart !== props.data.leaveDateEnd ? `${props.data.leaveRangeEnd && props.data.leaveRangeEnd !== 'ALL' ? `(${converstType(props.data.leaveRangeEnd)})`:''}` :''}` }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div> <div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div>
@ -51,7 +55,7 @@ const props = defineProps({
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">รายละเอยด</div> <div class="col-xs-12 col-md-6 text-grey-8">สาเหตการลา</div>
<div class="col-xs-12 col-md-6"> <div class="col-xs-12 col-md-6">
{{ props.data.leaveDetail ? props.data.leaveDetail : "-" }} {{ props.data.leaveDetail ? props.data.leaveDetail : "-" }}
</div> </div>

View file

@ -1,4 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { useLeaveStore } from '@/modules/05_leave/store'
const store = useLeaveStore()
const { converstType } = store
/** /**
* prop จาก component * prop จาก component
*/ */
@ -26,11 +30,11 @@ const props = defineProps({
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveDateStart }}</div> <div class="col-xs-12 col-md-6">{{ props.data.leaveDateStart }} {{ `${props.data.leaveRange && props.data.leaveRange !== 'ALL' ? `(${converstType(props.data.leaveRange)})`:''}` }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveDateEnd }}</div> <div class="col-xs-12 col-md-6">{{ props.data.leaveDateEnd }} {{ `${props.data.leaveDateStart !== props.data.leaveDateEnd ? `${props.data.leaveRangeEnd && props.data.leaveRangeEnd !== 'ALL' ? `(${converstType(props.data.leaveRangeEnd)})`:''}` :''}` }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div> <div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div>
@ -61,7 +65,7 @@ const props = defineProps({
<div class="col-xs-12 col-md-6">{{ props.data.absentDayAt }}</div> <div class="col-xs-12 col-md-6">{{ props.data.absentDayAt }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">รายละเอยด</div> <div class="col-xs-12 col-md-6 text-grey-8">สาเหตการลา</div>
<div class="col-xs-12 col-md-6"> <div class="col-xs-12 col-md-6">
{{ props.data.leaveDetail ? props.data.leaveDetail : "-" }} {{ props.data.leaveDetail ? props.data.leaveDetail : "-" }}
</div> </div>

View file

@ -1,4 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { useLeaveStore } from '@/modules/05_leave/store'
const store = useLeaveStore()
const { converstType } = store
/** /**
* prop จาก component * prop จาก component
*/ */
@ -18,7 +22,7 @@ const props = defineProps({
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">เรอง</div> <div class="col-xs-12 col-md-6 text-grey-8">เรอง</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveTypeName }}</div> <div class="col-xs-12 col-md-6">กษาต</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">เขยนท</div> <div class="col-xs-12 col-md-6 text-grey-8">เขยนท</div>
@ -26,11 +30,11 @@ const props = defineProps({
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveDateStart }}</div> <div class="col-xs-12 col-md-6">{{ props.data.leaveDateStart }} {{ `${props.data.leaveRange && props.data.leaveRange !== 'ALL' ? `(${converstType(props.data.leaveRange)})`:''}` }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveDateEnd }}</div> <div class="col-xs-12 col-md-6">{{ props.data.leaveDateEnd }} {{ `${props.data.leaveDateStart !== props.data.leaveDateEnd ? `${props.data.leaveRangeEnd && props.data.leaveRangeEnd !== 'ALL' ? `(${converstType(props.data.leaveRangeEnd)})`:''}` :''}` }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div> <div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div>
@ -85,7 +89,7 @@ const props = defineProps({
<div class="col-xs-12 col-md-6">{{ props.data.leaveAddress }}</div> <div class="col-xs-12 col-md-6">{{ props.data.leaveAddress }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">รายละเอยด</div> <div class="col-xs-12 col-md-6 text-grey-8">สาเหตการลา</div>
<div class="col-xs-12 col-md-6"> <div class="col-xs-12 col-md-6">
{{ props.data.leaveDetail ? props.data.leaveDetail : "-" }} {{ props.data.leaveDetail ? props.data.leaveDetail : "-" }}
</div> </div>

View file

@ -1,4 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { useLeaveStore } from "@/modules/05_leave/store";
const store = useLeaveStore();
const { converstType } = store;
/** /**
* prop จาก component * prop จาก component
*/ */
@ -17,7 +21,7 @@ const props = defineProps({
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">เรอง</div> <div class="col-xs-12 col-md-6 text-grey-8">เรอง</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveTypeName }}</div> <div class="col-xs-12 col-md-6">{{ props.data.leaveSubTypeName }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">เขยนท</div> <div class="col-xs-12 col-md-6 text-grey-8">เขยนท</div>
@ -25,11 +29,33 @@ const props = defineProps({
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveDateStart }}</div> <div class="col-xs-12 col-md-6">
{{ props.data.leaveDateStart }}
{{
`${
props.data.leaveRange && props.data.leaveRange !== "ALL"
? `(${converstType(props.data.leaveRange)})`
: ""
}`
}}
</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveDateEnd }}</div> <div class="col-xs-12 col-md-6">
{{ props.data.leaveDateEnd }}
{{
`${
props.data.leaveDateStart !== props.data.leaveDateEnd
? `${
props.data.leaveRangeEnd && props.data.leaveRangeEnd !== "ALL"
? `(${converstType(props.data.leaveRangeEnd)})`
: ""
}`
: ""
}`
}}
</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div> <div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div>
@ -84,7 +110,7 @@ const props = defineProps({
<div class="col-xs-12 col-md-6">{{ props.data.leaveAddress }}</div> <div class="col-xs-12 col-md-6">{{ props.data.leaveAddress }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">รายละเอยด</div> <div class="col-xs-12 col-md-6 text-grey-8">สาเหตการลา</div>
<div class="col-xs-12 col-md-6"> <div class="col-xs-12 col-md-6">
{{ props.data.leaveDetail ? props.data.leaveDetail : "-" }} {{ props.data.leaveDetail ? props.data.leaveDetail : "-" }}
</div> </div>

View file

@ -1,4 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { useLeaveStore } from '@/modules/05_leave/store'
const store = useLeaveStore()
const { converstType } = store
/** /**
* prop จาก component * prop จาก component
*/ */
@ -25,11 +29,11 @@ const props = defineProps({
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveDateStart }}</div> <div class="col-xs-12 col-md-6">{{ props.data.leaveDateStart }} {{ `${props.data.leaveRange && props.data.leaveRange !== 'ALL' ? `(${converstType(props.data.leaveRange)})`:''}` }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveDateEnd }}</div> <div class="col-xs-12 col-md-6">{{ props.data.leaveDateEnd }} {{ `${props.data.leaveDateStart !== props.data.leaveDateEnd ? `${props.data.leaveRangeEnd && props.data.leaveRangeEnd !== 'ALL' ? `(${converstType(props.data.leaveRangeEnd)})`:''}` :''}` }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div> <div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div>
@ -38,7 +42,7 @@ const props = defineProps({
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">รายละเอยด</div> <div class="col-xs-12 col-md-6 text-grey-8">รายละสาเหตการลาเอยด</div>
<div class="col-xs-12 col-md-6"> <div class="col-xs-12 col-md-6">
{{ props.data.leaveDetail ? props.data.leaveDetail : "-" }} {{ props.data.leaveDetail ? props.data.leaveDetail : "-" }}
</div> </div>

View file

@ -1,4 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { useLeaveStore } from '@/modules/05_leave/store'
const store = useLeaveStore()
const { converstType } = store
/** /**
* prop จาก component * prop จาก component
*/ */
@ -25,11 +29,11 @@ const props = defineProps({
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveDateStart }}</div> <div class="col-xs-12 col-md-6">{{ props.data.leaveDateStart }} {{ `${props.data.leaveRange && props.data.leaveRange !== 'ALL' ? `(${converstType(props.data.leaveRange)})`:''}` }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveDateEnd }}</div> <div class="col-xs-12 col-md-6">{{ props.data.leaveDateEnd }} {{ `${props.data.leaveDateStart !== props.data.leaveDateEnd ? `${props.data.leaveRangeEnd && props.data.leaveRangeEnd !== 'ALL' ? `(${converstType(props.data.leaveRangeEnd)})`:''}` :''}` }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div> <div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div>
@ -119,7 +123,7 @@ const props = defineProps({
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">รายละเอยด</div> <div class="col-xs-12 col-md-6 text-grey-8">สาเหตการลา</div>
<div class="col-xs-12 col-md-6"> <div class="col-xs-12 col-md-6">
{{ props.data.leaveDetail ? props.data.leaveDetail : "-" }} {{ props.data.leaveDetail ? props.data.leaveDetail : "-" }}
</div> </div>

View file

@ -1,4 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { useLeaveStore } from '@/modules/05_leave/store'
const store = useLeaveStore()
const { converstType } = store
/** /**
* prop จาก component * prop จาก component
*/ */
@ -25,11 +29,11 @@ const props = defineProps({
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveDateStart }}</div> <div class="col-xs-12 col-md-6">{{ props.data.leaveDateStart }} {{ `${props.data.leaveRange && props.data.leaveRange !== 'ALL' ? `(${converstType(props.data.leaveRange)})`:''}` }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveDateEnd }}</div> <div class="col-xs-12 col-md-6">{{ props.data.leaveDateEnd }} {{ `${props.data.leaveDateStart !== props.data.leaveDateEnd ? `${props.data.leaveRangeEnd && props.data.leaveRangeEnd !== 'ALL' ? `(${converstType(props.data.leaveRangeEnd)})`:''}` :''}` }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div> <div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div>
@ -38,7 +42,7 @@ const props = defineProps({
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">รายละเอยด</div> <div class="col-xs-12 col-md-6 text-grey-8">สาเหตการลา</div>
<div class="col-xs-12 col-md-6"> <div class="col-xs-12 col-md-6">
{{ props.data.leaveDetail ? props.data.leaveDetail : "-" }} {{ props.data.leaveDetail ? props.data.leaveDetail : "-" }}
</div> </div>
@ -47,7 +51,7 @@ const props = defineProps({
<div class="col-xs-12 col-md-6 text-grey-8">เอกสารประกอบ</div> <div class="col-xs-12 col-md-6 text-grey-8">เอกสารประกอบ</div>
<div class="col-xs-12 col-md-6" v-if="props.data.leaveDocument"> <div class="col-xs-12 col-md-6" v-if="props.data.leaveDocument">
<q-btn <q-btn
:href="props.data.leaveDocument" :href="props.data.leaveDraftDocument"
target="_blank" target="_blank"
outline outline
color="blue" color="blue"

View file

@ -1,4 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { useLeaveStore } from "@/modules/05_leave/store";
const store = useLeaveStore();
const { converstType } = store;
/** /**
* prop จาก component * prop จาก component
*/ */
@ -20,7 +24,13 @@ const props = defineProps({
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ประเภทการลา</div> <div class="col-xs-12 col-md-6 text-grey-8">ประเภทการลา</div>
<div class="col-xs-12 col-md-6"> <div class="col-xs-12 col-md-6">
{{ props.data.leaveTypeName ? props.data.leaveTypeName : "-" }} {{
props.data.leaveSubTypeName
? props.data.leaveSubTypeName
: props.data.leaveTypeName
? props.data.leaveTypeName
: "-"
}}
</div> </div>
</div> </div>
<div class="row"> <div class="row">
@ -29,28 +39,40 @@ const props = defineProps({
{{ props.data.fullname ? props.data.fullname : "-" }} {{ props.data.fullname ? props.data.fullname : "-" }}
</div> </div>
</div> </div>
<div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">สถานะการขอลา</div>
<div class="col-xs-12 col-md-6">
{{ props.data.status ? props.data.status : "-" }}
</div>
</div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div>
<div class="col-xs-12 col-md-6"> <div class="col-xs-12 col-md-6">
{{ props.data.leaveStartDate ? props.data.leaveStartDate : "-" }} {{ props.data.leaveDateStart }}
{{
`${
props.data.leaveRange && props.data.leaveRange !== "ALL"
? `(${converstType(props.data.leaveRange)})`
: ""
}`
}}
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div>
<div class="col-xs-12 col-md-6"> <div class="col-xs-12 col-md-6">
{{ props.data.leaveEndDate ? props.data.leaveEndDate : "-" }} {{ props.data.leaveDateEnd }}
{{
`${
props.data.leaveDateStart !== props.data.leaveDateEnd
? `${
props.data.leaveRangeEnd && props.data.leaveRangeEnd !== "ALL"
? `(${converstType(props.data.leaveRangeEnd)})`
: ""
}`
: ""
}`
}}
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div> <div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div>
<div class="col-xs-12 col-md-6"> <div class="col-xs-12 col-md-6">
{{ props.data.leaveTotal ? props.data.leaveTotal : "-" }} {{ props.data.leaveTotal ? props.data.leaveTotal + ` วัน` : "-" }}
</div> </div>
</div> </div>
<div class="row"> <div class="row">
@ -65,6 +87,12 @@ const props = defineProps({
{{ props.data.leaveNumber ? props.data.leaveNumber : "-" }} {{ props.data.leaveNumber ? props.data.leaveNumber : "-" }}
</div> </div>
</div> </div>
<div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">รายละเอยดการลา</div>
<div class="col-xs-12 col-md-6">
{{ props.data.leaveDetail ? props.data.leaveDetail : "-" }}
</div>
</div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">เหตผลการยกเลกการลา</div> <div class="col-xs-12 col-md-6 text-grey-8">เหตผลการยกเลกการลา</div>
<div class="col-xs-12 col-md-6"> <div class="col-xs-12 col-md-6">
@ -72,9 +100,19 @@ const props = defineProps({
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">รายละเอยดการลา</div> <div class="col-xs-12 col-md-6 text-grey-8">สถานะการขอยกเล</div>
<div class="col-xs-12 col-md-6"> <div class="col-xs-12 col-md-6">
{{ props.data.leaveDetail ? props.data.leaveDetail : "-" }} {{ props.data.status != "ใหม่" ? props.data.status : "-" }}
</div>
</div>
<div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ความคดเหนของผอำนาจ</div>
<div class="col-xs-12 col-md-6">
{{
props.data.leaveDirectorComment && props.data.status != "ใหม่"
? props.data.leaveDirectorComment
: "-"
}}
</div> </div>
</div> </div>
<div class="row"> <div class="row">

View file

@ -122,7 +122,9 @@ interface FormData {
coupleDaySumTotalHistory: string; coupleDaySumTotalHistory: string;
approveStep: string; approveStep: string;
dear: string; dear: string;
leaveRangeEnd: string;
leaveLast: string; leaveLast: string;
leaveSubTypeName: string;
leaveRange: string; leaveRange: string;
} }

View file

@ -16,7 +16,7 @@ interface OrdinationForm {
leavebirthDate: object | null; leavebirthDate: object | null;
leaveStartDate: object | null; leaveStartDate: object | null;
leaveEndDate: object | null; leaveEndDate: object | null;
totalLeave: object | null; leaveTotal: object | null;
ordainDayOrdination: object | null; ordainDayOrdination: object | null;
ordainDayLocationName: object | null; ordainDayLocationName: object | null;
ordainDayLocationNumber: object | null; ordainDayLocationNumber: object | null;

View file

@ -7,6 +7,9 @@ interface ListLeave {
fullName: string; //คำนำหน้า ชื่อ นามสกุล คนขอลา fullName: string; //คำนำหน้า ชื่อ นามสกุล คนขอลา
dateSendLeave: Date | null; //วันที่ยื่นใบลา dateSendLeave: Date | null; //วันที่ยื่นใบลา
status: string; //สถานะการของลา status: string; //สถานะการของลา
leaveSubTypeName: string;
leaveRange: string;
leaveRangeEnd: string;
isDelete: boolean; //ขอยกเลิกคำขอลา ถ้าเคยขอแล้วจะเป็น true ไม่เคยเป็น false isDelete: boolean; //ขอยกเลิกคำขอลา ถ้าเคยขอแล้วจะเป็น true ไม่เคยเป็น false
hajjDayStatus: boolean; hajjDayStatus: boolean;
} }
@ -18,6 +21,9 @@ interface ListLeaveTable {
fullName: string; fullName: string;
dateSendLeave: string | null; dateSendLeave: string | null;
status: string; status: string;
leaveSubTypeName: string;
leaveRange: string;
leaveRangeEnd: string;
isDelete: boolean; isDelete: boolean;
hajjDayStatus: boolean; hajjDayStatus: boolean;
} }
@ -82,6 +88,8 @@ interface FremDetail {
approveStep: string; approveStep: string;
dear: string; dear: string;
leaveRange: string; leaveRange: string;
leaveRangeEnd: string;
leaveSubTypeName: string;
} }
interface FromCancelDetail { interface FromCancelDetail {
@ -90,14 +98,20 @@ interface FromCancelDetail {
fullname: String; //คำนำหน้า ชื่อ นามสกุล คนขอลา fullname: String; //คำนำหน้า ชื่อ นามสกุล คนขอลา
status: String; //สถานะการของลา status: String; //สถานะการของลา
leaveDocDelete: string; //เอกสารการยกเลิกการลา leaveDocDelete: string; //เอกสารการยกเลิกการลา
leaveSubTypeName: string;
leaveResonDelete: String; //เหตุผลการยกเลิกการลา leaveResonDelete: String; //เหตุผลการยกเลิกการลา
leaveWrote: String; //เขียนที่ leaveWrote: String; //เขียนที่
leaveAddress: String; //สถานที่ติดต่อขณะลา leaveAddress: String; //สถานที่ติดต่อขณะลา
leaveNumber: String; //หมายเลขที่ติดต่อขณะลา leaveNumber: String; //หมายเลขที่ติดต่อขณะลา
leaveDetail: String; //รายละเอียดการลา leaveDetail: String; //รายละเอียดการลา
leaveTotal: number; //จำนวนวันที่ลา leaveTotal: number; //จำนวนวันที่ลา
leaveStartDate: Date; //วัน เดือน ปีเริ่มต้นลา leaveStartDate?: Date; //วัน เดือน ปีเริ่มต้นลา
leaveEndDate: Date; //วัน เดือน ปีสิ้นสุดลา leaveEndDate?: Date; //วัน เดือน ปีสิ้นสุดลา
leaveDateStart?: Date;
leaveDateEnd?: Date; //วัน เดือน ปีสิ้นสุดลา
leaveRange?: string; //ช่วงการลา
leaveRangeEnd?: string; //ช่วงการลา
leaveDirectorComment?: string; //ความคิดเห็นของผู้บังคับบัญชา
} }
interface FormDelete { interface FormDelete {

View file

@ -0,0 +1,34 @@
interface DataCommander {
actFullName: string;
actFullNameId: string;
actFullNameKeycloakId: string;
citizenId: string;
firstName: string;
id: string;
isDeputy: number;
isDirector: number;
isOfficer: boolean;
key: string;
keycloakId: string;
lastName: string;
orgChild1: string;
orgChild1Id: string;
orgChild2: string;
orgChild2Id: string;
orgChild3: string;
orgChild3Id: string;
orgChild4: string;
orgChild4Id: string;
orgRevisionId: string;
orgRoot: string;
orgRootId: string;
posExecutiveName: string;
posExecutiveNameOrg: string;
posLevel: string;
posNo: string;
posType: string;
position: string;
prefix: string;
}
export type { DataCommander };

View file

@ -1,6 +1,5 @@
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { ref } from "vue"; import { ref } from "vue";
import { useQuasar } from "quasar";
import http from "@/plugins/http"; import http from "@/plugins/http";
import config from "@/app.config"; import config from "@/app.config";
@ -15,10 +14,10 @@ import type {
ListLeave, ListLeave,
ListLeaveTable, ListLeaveTable,
} from "@/modules/05_leave/interface/response/leave"; } from "@/modules/05_leave/interface/response/leave";
import type { DataOption } from "../14_IDP/interface/Main";
const mixin = useCounterMixin(); const mixin = useCounterMixin();
const { date2Thai, messageError, showLoader, hideLoader } = mixin; const { date2Thai, showLoader, hideLoader } = mixin;
const $q = useQuasar();
const type = ref<string>("00000000-0000-0000-0000-000000000000"); const type = ref<string>("00000000-0000-0000-0000-000000000000");
const status = ref<string>("ALL"); const status = ref<string>("ALL");
export const useLeaveStore = defineStore("Leave", () => { export const useLeaveStore = defineStore("Leave", () => {
@ -28,6 +27,8 @@ export const useLeaveStore = defineStore("Leave", () => {
const LeaveStatus = ref<string | null>("0"); const LeaveStatus = ref<string | null>("0");
const fiscalYearyear = ref<Number | null>(new Date().getFullYear()); const fiscalYearyear = ref<Number | null>(new Date().getFullYear());
const rows = ref<ListLeaveTable[]>([]); const rows = ref<ListLeaveTable[]>([]);
const leaveTypeData = ref<TypeLeave[]>([]);
const isLoadingProfile = ref<boolean>(false); // สถานะการโหลดข้อมูลโปรไฟล์
/** /**
* function Table * function Table
@ -39,11 +40,24 @@ export const useLeaveStore = defineStore("Leave", () => {
leaveTypeName: e.leaveTypeName, leaveTypeName: e.leaveTypeName,
leaveTypeId: e.leaveTypeId, leaveTypeId: e.leaveTypeId,
fullName: e.fullName, fullName: e.fullName,
dateSendLeave: e.dateSendLeave && date2Thai(e.dateSendLeave), dateSendLeave: e.dateSendLeave && date2Thai(e.dateSendLeave, false, true),
dateLeave: dateLeave:
date2Thai(e.leaveStartDate) + " - " + date2Thai(e.leaveEndDate), e.leaveStartDate && e.leaveEndDate
? e.leaveStartDate === e.leaveEndDate
? date2Thai(e.leaveEndDate)
: `${date2Thai(e.leaveStartDate)}${
e.leaveRange !== "ALL" ? ` (${converstType(e.leaveRange)})` : ""
} - ${date2Thai(e.leaveEndDate)}${
e.leaveRangeEnd !== "ALL"
? ` (${converstType(e.leaveRangeEnd)})`
: ""
}`
: "-",
status: e.status, status: e.status,
hajjDayStatus: e.hajjDayStatus, hajjDayStatus: e.hajjDayStatus,
leaveRange: e.leaveRange,
leaveRangeEnd: e.leaveRangeEnd,
leaveSubTypeName: e.leaveSubTypeName,
statusConvert: convertStatud(e.status), statusConvert: convertStatud(e.status),
isDelete: e.isDelete, isDelete: e.isDelete,
})); }));
@ -63,8 +77,10 @@ export const useLeaveStore = defineStore("Leave", () => {
return "อนุมัติ"; return "อนุมัติ";
case "REJECT": case "REJECT":
return "ไม่อนุมัติ"; return "ไม่อนุมัติ";
case "DELETING":
return "กำลังดำเนินการยกเลิก";
case "DELETE": case "DELETE":
return "ยกเลิก"; return "ยกเลิกสำเร็จ";
} }
} }
@ -108,9 +124,10 @@ export const useLeaveStore = defineStore("Leave", () => {
{ id: "DRAFT", name: "แบบร่าง" }, { id: "DRAFT", name: "แบบร่าง" },
{ id: "NEW", name: "ใหม่" }, { id: "NEW", name: "ใหม่" },
{ id: "PENDING", name: "กำลังดำเนินการ" }, { id: "PENDING", name: "กำลังดำเนินการ" },
{ id: "APPROVE", name: "อนุมัติ " }, { id: "APPROVE", name: "อนุญาต " },
{ id: "REJECT", name: "ไม่อนุมัติ" }, { id: "REJECT", name: "ไม่อนุญาต" },
{ id: "DELETE", name: "ยกเลิก" }, { id: "DELETING", name: "กำลังดำเนินการยกเลิก" },
{ id: "DELETE", name: "ยกเลิกสำเร็จ" },
]); ]);
const statusOptions = ref<any[]>(statusOptionsMain.value); const statusOptions = ref<any[]>(statusOptionsMain.value);
@ -120,10 +137,9 @@ export const useLeaveStore = defineStore("Leave", () => {
* @param update * @param update
* @param refData * @param refData
*/ */
function filterOption(val: any, update: Function, refData: string) { function filterOption(val: string, update: Function, refData: string) {
switch (refData) { switch (refData) {
case "LeaveTypeOption": case "LeaveTypeOption":
type.value = "";
update(() => { update(() => {
typeOptions.value = typeOptionsMain.value.filter( typeOptions.value = typeOptionsMain.value.filter(
(v: any) => v.name.indexOf(val) > -1 (v: any) => v.name.indexOf(val) > -1
@ -131,7 +147,6 @@ export const useLeaveStore = defineStore("Leave", () => {
}); });
break; break;
case "LeaveStatusOption": case "LeaveStatusOption":
status.value = "";
update(() => { update(() => {
statusOptions.value = statusOptionsMain.value.filter( statusOptions.value = statusOptionsMain.value.filter(
(v: any) => v.name.indexOf(val) > -1 (v: any) => v.name.indexOf(val) > -1
@ -143,17 +158,41 @@ export const useLeaveStore = defineStore("Leave", () => {
} }
} }
const rangeOptions = ref<DataOption[]>([
{
id: "ALL",
name: "เต็มวัน",
},
{
id: "MORNING",
name: "ครึ่งวันเช้า",
},
{
id: "AFTERNOON",
name: "ครึ่งวันบ่าย",
},
]);
function converstType(val: string) {
switch (val) {
case "ALL":
return "";
case "MORNING":
return "ครึ่งวันเช้า";
case "AFTERNOON":
return "ครึ่งวันบ่าย";
}
}
/** รายการประเภทการลาของ ลาไปศึกษา ฝึกอบรม ปฎิบัติการวิจัย หรือดูงาน*/ /** รายการประเภทการลาของ ลาไปศึกษา ฝึกอบรม ปฎิบัติการวิจัย หรือดูงาน*/
const optionsSpecific = ref<OptionData[]>([ const optionsSpecific = ref<string[]>([
{ id: "s1", name: "ลาไปศึกษาต่อ", code: "s1" }, "ศึกษาต่อ",
{ id: "s2", name: "ลาฝึกอบรม/ปฎิบัติการวิจัย/ดูงาน", code: "s2" }, "ฝึกอบรม",
"ปฎิบัติการวิจัย",
"ดูงาน",
]); ]);
/** รายการประเภทการลาของ ลาอุปสมบทหรือลาประกอบพิธีฮัจญ์*/ /** รายการประเภทการลาของ ลาอุปสมบทหรือลาประกอบพิธีฮัจญ์*/
const optionsOrdination = ref<OptionData[]>([ const optionsOrdination = ref<string[]>(["ลาอุปสมบท", "ลาประกอบพิธีฮัจญ์"]);
{ id: "b1", name: "ลาอุปสมบท", code: "b1" },
{ id: "b2", name: "ลาประกอบพิธีฮัจญ์", code: "b2" },
]);
/** data table filter & column ของรายการลา */ /** data table filter & column ของรายการลา */
const visibleColumns = ref<string[]>([ const visibleColumns = ref<string[]>([
@ -233,24 +272,6 @@ export const useLeaveStore = defineStore("Leave", () => {
return options.value.find((x) => x.code == val)?.name; return options.value.find((x) => x.code == val)?.name;
} }
/**
* /
* @param val string
* @returns
*/
function convertSubtitleInfo(val: string) {
return optionsOrdination.value.find((x) => x.id == val)?.name;
}
/**
*
* @param val string
* @returns
*/
function convertSubtitleInfo2(val: string) {
return optionsSpecific.value.find((x) => x.id == val)?.name;
}
/** /**
* id api * id api
* @param val string * @param val string
@ -266,6 +287,7 @@ export const useLeaveStore = defineStore("Leave", () => {
const dateSendLeave = ref<Date>(); //วันที่ยื่นใบลา const dateSendLeave = ref<Date>(); //วันที่ยื่นใบลา
const leaveTypeName = ref<string>(""); //Name ประเภทการลา const leaveTypeName = ref<string>(""); //Name ประเภทการลา
const dear = ref<string>(""); //เรียน const dear = ref<string>(""); //เรียน
const commanderPosition = ref<string>(""); //ตำแหน่งผู้บังคับบัญชา
const fullName = ref<string>(""); //คำนำหน้า ชื่อ นามสกุล ผู้ยื่นขอ const fullName = ref<string>(""); //คำนำหน้า ชื่อ นามสกุล ผู้ยื่นขอ
const positionName = ref<string>(""); //ตำแหน่งผู้ยื่นขอ const positionName = ref<string>(""); //ตำแหน่งผู้ยื่นขอ
const positionLevelName = ref<string>(""); //ระดับผู้ยื่นขอ const positionLevelName = ref<string>(""); //ระดับผู้ยื่นขอ
@ -281,16 +303,20 @@ export const useLeaveStore = defineStore("Leave", () => {
const leaveLast = ref<any>(); const leaveLast = ref<any>();
const restDayCurrentTotal = ref<number>(0); const restDayCurrentTotal = ref<number>(0);
const telephoneNumber = ref<string>("");
const currentAddress = ref<string>("");
//ดึงข้อมูล profile จาก API //ดึงข้อมูล profile จาก API
async function fetchProfile() { async function fetchProfile() {
showLoader(); // showLoader();
isLoadingProfile.value = true;
await http await http
.post(config.API.leaveProfile(), { type: typeId.value }) .post(config.API.leaveProfile(), { type: typeId.value })
.then((res: any) => { .then((res: any) => {
const data = res.data.result; const data = res.data.result;
dateSendLeave.value = data.dateSendLeave; dateSendLeave.value = data.dateSendLeave;
leaveTypeName.value = data.leaveTypeName; leaveTypeName.value = data.leaveTypeName;
dear.value = data.dear; typeLeave.value = data.leaveTypeName;
fullName.value = data.fullName; fullName.value = data.fullName;
positionName.value = data.positionName; positionName.value = data.positionName;
positionLevelName.value = data.positionLevelName; positionLevelName.value = data.positionLevelName;
@ -301,6 +327,14 @@ export const useLeaveStore = defineStore("Leave", () => {
restDayTotalOld.value = data.restDayTotalOld; restDayTotalOld.value = data.restDayTotalOld;
birthDate.value = data.birthDate; birthDate.value = data.birthDate;
dateAppoint.value = data.dateAppoint; dateAppoint.value = data.dateAppoint;
telephoneNumber.value =
data.telephoneNumber && data.telephoneNumber !== "-"
? data.telephoneNumber
: null;
currentAddress.value = data.currentSubDistrict
? `${data.currentAddress} ${data.currentSubDistrict} ${data.currentDistrict} ${data.currentProvince} ${data.currentZipCode}`
: "";
salary.value = data.salary ? data.salary.toLocaleString("th-TH") : ""; salary.value = data.salary ? data.salary.toLocaleString("th-TH") : "";
salaryText.value = data.salaryText; salaryText.value = data.salaryText;
leaveLast.value = leaveLast.value =
@ -311,10 +345,11 @@ export const useLeaveStore = defineStore("Leave", () => {
Number(data.leaveLimit) - Number(data.restDayTotalOld); Number(data.leaveLimit) - Number(data.restDayTotalOld);
}) })
.catch((e: any) => { .catch((e: any) => {
messageError($q, e); console.log(e);
}) })
.finally(() => { .finally(() => {
hideLoader(); // hideLoader();
isLoadingProfile.value = false;
}); });
} }
@ -335,12 +370,13 @@ export const useLeaveStore = defineStore("Leave", () => {
Number(data.leaveLimit) - Number(data.restDayTotalOld); Number(data.leaveLimit) - Number(data.restDayTotalOld);
}) })
.catch((e: any) => { .catch((e: any) => {
messageError($q, e); console.log(e);
}); });
dateSendLeave.value = data.dateSendLeave; dateSendLeave.value = data.dateSendLeave;
typeLeave.value = data.leaveTypeName; typeLeave.value = data.leaveTypeName;
dear.value = data.dear; dear.value = data.dear;
commanderPosition.value = data.commanderPosition;
fullName.value = data.fullName; fullName.value = data.fullName;
positionName.value = data.positionName; positionName.value = data.positionName;
positionLevelName.value = data.positionLevelName; positionLevelName.value = data.positionLevelName;
@ -354,6 +390,7 @@ export const useLeaveStore = defineStore("Leave", () => {
dateSendLeave.value = undefined; dateSendLeave.value = undefined;
leaveTypeName.value = ""; leaveTypeName.value = "";
dear.value = ""; dear.value = "";
commanderPosition.value = "";
fullName.value = ""; fullName.value = "";
positionName.value = ""; positionName.value = "";
positionLevelName.value = ""; positionLevelName.value = "";
@ -370,6 +407,21 @@ export const useLeaveStore = defineStore("Leave", () => {
restDayCurrentTotal.value = 0; restDayCurrentTotal.value = 0;
} }
/** ฟังก์ชันเรียกข้อมูลประเภทการลา */
async function fetchLeaveTypeData() {
if (leaveTypeData.value.length > 0) {
return leaveTypeData.value;
} else {
try {
const res = await http.get(config.API.leaveType());
leaveTypeData.value = res.data.result;
return leaveTypeData.value;
} catch (error) {
console.error("Fetch leave type error:", error);
}
}
}
return { return {
tabValue, tabValue,
typeOptions, typeOptions,
@ -398,6 +450,7 @@ export const useLeaveStore = defineStore("Leave", () => {
dateSendLeave, dateSendLeave,
leaveTypeName, leaveTypeName,
dear, dear,
commanderPosition,
fullName, fullName,
positionName, positionName,
positionLevelName, positionLevelName,
@ -419,5 +472,12 @@ export const useLeaveStore = defineStore("Leave", () => {
typeOptionsMain, typeOptionsMain,
status, status,
statusOptionsMain, statusOptionsMain,
telephoneNumber,
currentAddress,
rangeOptions,
converstType,
fetchLeaveTypeData,
isLoadingProfile,
}; };
}); });

View file

@ -29,7 +29,15 @@ const myform = ref<QForm | null>(null);
const dataStore = useLeaveStore(); const dataStore = useLeaveStore();
const mixin = useCounterMixin(); const mixin = useCounterMixin();
const { fetchLeaveType } = dataStore; const { fetchLeaveType } = dataStore;
const { dialogConfirm, success, messageError, showLoader, hideLoader } = mixin; const {
dialogConfirm,
success,
messageError,
showLoader,
hideLoader,
convertDateToAPI,
dialogMessageNotify,
} = mixin;
const model = ref<string>(""); const model = ref<string>("");
const modelSpecific = ref<string>(""); const modelSpecific = ref<string>("");
@ -51,21 +59,34 @@ async function fectOptionType() {
function onSubmit(postData: FormData, isLeave: boolean = true) { function onSubmit(postData: FormData, isLeave: boolean = true) {
if (isLeave) { if (isLeave) {
dialogConfirm($q, async () => { if (dataStore.commanderPosition !== "" && dataStore.dear !== "") {
showLoader(); dialogConfirm($q, async () => {
await http showLoader();
.post(config.API.leaveUser(), postData) if (model.value === "LV-006" || model.value === "LV-008") {
.then((res) => { postData.append("leaveSubTypeName", modelSpecific.value);
router.push(`/leave/edit/${res.data.result.id}`); }
success($q, "บันทึกสำเร็จ"); if (postData.get("leaveEndDate") === postData.get("leaveStartDate")) {
}) postData.set("leaveRangeEnd", postData.get("leaveRange") as string);
.catch((e: any) => { }
messageError($q, e); postData.append("commanderPosition", dataStore.commanderPosition);
}) postData.append("dear", dataStore.dear);
.finally(() => { await http
hideLoader(); .post(config.API.leaveUser(), postData)
});
}); .then((res) => {
router.push(`/leave/edit/${res.data.result.id}`);
success($q, "บันทึกสำเร็จ");
})
.catch((e: any) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
});
} else {
dialogMessageNotify($q, "กรุณาเพิ่มรายชื่อ ผู้บังคับบัญชา");
}
} else { } else {
messageError($q, "", "ไม่มีสิทธิ์ลา"); messageError($q, "", "ไม่มีสิทธิ์ลา");
} }
@ -85,6 +106,8 @@ function filterOptionFn(val: string, update: Function) {
} }
onMounted(async () => { onMounted(async () => {
dataStore.typeLeave = "";
if (dataStore.options.length == 0) { if (dataStore.options.length == 0) {
await fectOptionType(); await fectOptionType();
} }
@ -126,7 +149,7 @@ onMounted(async () => {
<div class="row"> <div class="row">
<q-select <q-select
dense dense
class="col-12 col-sm-6 col-md-4 inputgreen" class="col-12 col-sm-9 col-md-6 inputgreen"
outlined outlined
v-model="model" v-model="model"
:options="option" :options="option"
@ -155,7 +178,7 @@ onMounted(async () => {
<div class="row q-mt-sm"> <div class="row q-mt-sm">
<div <div
class="col-12 col-sm-6 col-md-3" class="col-12 col-sm-6 col-md-4"
v-if="model === 'LV-006' || model === 'LV-008'" v-if="model === 'LV-006' || model === 'LV-008'"
> >
<q-select <q-select
@ -167,14 +190,11 @@ onMounted(async () => {
? dataStore.optionsOrdination ? dataStore.optionsOrdination
: dataStore.optionsSpecific : dataStore.optionsSpecific
" "
option-value="code" option-value="id"
option-label="name" option-label="name"
emit-value emit-value
map-options map-options
prefix="ประเภทการลา :" prefix="ประเภทการลา :"
@update:model-value="
dataStore.typeConvert(model, modelSpecific)
"
/> />
</div> </div>
</div> </div>
@ -191,11 +211,92 @@ onMounted(async () => {
อมลการลา อมลการลา
</div> </div>
</div> </div>
<FormPart2 :model="model" /> <q-card
bordered
class="q-pa-md bg-grey-1"
v-if="dataStore.isLoadingProfile"
>
<div class="row q-col-gutter-sm">
<div class="col-12">
<div class="row q-col-gutter-sm">
<div class="col-md-4 col-xs-12">
<q-skeleton height="40px" />
</div>
<div class="col-md-4 col-xs-12">
<q-skeleton height="40px" />
</div>
</div>
</div>
<div class="col-md-6 col-xs-12">
<q-skeleton height="40px" />
</div>
<div class="col-md-6 col-xs-12">
<q-skeleton height="40px" />
</div>
<div class="col-md-4 col-xs-12">
<q-skeleton height="40px" />
</div>
<div class="col-md-4 col-xs-12">
<q-skeleton height="40px" />
</div>
<div class="col-md-4 col-xs-12">
<q-skeleton height="40px" />
</div>
<div class="col-md-4 col-xs-12">
<q-skeleton height="40px" />
</div>
</div>
</q-card>
<FormPart2 v-else :model="model" />
</div> </div>
</div> </div>
<div class="col-12"> <div class="col-12" v-if="dataStore.isLoadingProfile">
<div style="display: flex; align-items: center">
<q-icon
name="mdi-numeric-3-circle"
size="20px"
color="primary"
/>
<div class="q-pl-sm text-weight-bold text-dark">กรอกขอม</div>
</div>
<q-card bordered class="q-pa-md bg-grey-1">
<div class="row q-col-gutter-sm">
<div class="col-12">
<q-skeleton height="40px" />
</div>
<div class="col-12">
<div class="row q-col-gutter-sm">
<div class="col-md-3 col-xs-6">
<q-skeleton height="40px" />
</div>
<div class="col-md-3 col-xs-6">
<q-skeleton height="40px" />
</div>
</div>
</div>
<div class="col-12">
<div class="row q-col-gutter-sm">
<div class="col-md-3 col-xs-12">
<q-skeleton height="40px" />
</div>
</div>
</div>
<div class="col-12">
<q-skeleton height="40px" />
</div>
<div class="col-12">
<q-skeleton height="120px" />
</div>
<div class="col-12">
<q-skeleton height="40px" />
</div>
</div>
</q-card>
</div>
<div class="col-12" v-else>
<SickForm <SickForm
v-if="model === 'LV-001' || model === 'LV-002'" v-if="model === 'LV-001' || model === 'LV-002'"
v-model:type="model" v-model:type="model"
@ -208,11 +309,13 @@ onMounted(async () => {
/> />
<VacationForm v-if="model === 'LV-005'" :on-submit="onSubmit" /> <VacationForm v-if="model === 'LV-005'" :on-submit="onSubmit" />
<OrdinationForm <OrdinationForm
v-if="model === 'LV-006' && modelSpecific == 'b1'" v-if="model === 'LV-006' && modelSpecific == 'ลาอุปสมบท'"
:on-submit="onSubmit" :on-submit="onSubmit"
/> />
<HajjForm <HajjForm
v-if="model === 'LV-006' && modelSpecific == 'b2'" v-if="
model === 'LV-006' && modelSpecific == 'ลาประกอบพิธีฮัจญ์'
"
:on-submit="onSubmit" :on-submit="onSubmit"
/> />
<MilitaryForm <MilitaryForm
@ -221,15 +324,15 @@ onMounted(async () => {
:on-submit="onSubmit" :on-submit="onSubmit"
/> />
<StudyForm <StudyForm
v-if="model === 'LV-008' && modelSpecific === 's1'" v-if="model === 'LV-008' && modelSpecific === 'ศึกษาต่อ'"
style="width: 100%" style="width: 100%"
:on-submit="onSubmit" :on-submit="onSubmit"
/> />
<TrainForm <TrainForm
v-if=" v-if="
model === 'LV-008' && (model === 'LV-008' && modelSpecific == 'ฝึกอบรม') ||
modelSpecific != 's1' && (model === 'LV-008' && modelSpecific == 'ปฎิบัติการวิจัย') ||
modelSpecific != '' (model === 'LV-008' && modelSpecific == 'ดูงาน')
" "
:on-submit="onSubmit" :on-submit="onSubmit"
/> />

View file

@ -38,6 +38,7 @@ const {
success, success,
date2Thai, date2Thai,
dialogRemove, dialogRemove,
dialogMessageNotify,
} = mixin; } = mixin;
const titleName = ref<string>(""); const titleName = ref<string>("");
@ -99,9 +100,11 @@ const formData = reactive<FormData>({
coupleDayEndDateHistory: null, // () coupleDayEndDateHistory: null, // ()
coupleDaySumTotalHistory: "", // () coupleDaySumTotalHistory: "", // ()
approveStep: "", approveStep: "",
leaveRangeEnd: "",
dear: "", dear: "",
leaveLast: "", leaveLast: "",
leaveRange: "", leaveRange: "",
leaveSubTypeName: "",
}); });
const model = computed(() => { const model = computed(() => {
@ -109,23 +112,7 @@ const model = computed(() => {
dataStore.options.find((x) => x.id == formData.leaveTypeId)?.code ?? "" dataStore.options.find((x) => x.id == formData.leaveTypeId)?.code ?? ""
); );
}); });
const modelSpecific = computed(() => { const modelSpecific = ref<string>("");
const code = dataStore.options.find(
(x) => x.id == formData.leaveTypeId
)?.code;
if (code == "LV-006" && formData.ordainDayLocationName != "") {
return "b1";
} else if (code == "LV-006" && formData.ordainDayLocationName == "") {
return "b2";
} else if (code == "LV-008" && formData.studyDayTrainingSubject == "") {
return "s1";
} else if (code == "LV-008" && formData.studyDayTrainingSubject != "") {
return "s2";
} else {
return "";
}
});
/** /**
* function เรยกขอมลการลา * function เรยกขอมลการลา
@ -208,6 +195,16 @@ async function fetchDataDetail(id: string) {
formData.dear = data.dear ?? "-"; formData.dear = data.dear ?? "-";
formData.leaveLast = data.leaveLast ?? "-"; formData.leaveLast = data.leaveLast ?? "-";
formData.leaveRange = data.leaveRange; formData.leaveRange = data.leaveRange;
formData.leaveRangeEnd =
data.leaveRangeEnd == "AFTERNOON" ? "ALL" : data.leaveRangeEnd;
formData.ordainDayLocationNumber = data.ordainDayLocationNumber;
formData.ordainDayStatus = data.ordainDayStatus;
modelSpecific.value = data.leaveSubTypeName;
dataStore.telephoneNumber =
data.leaveNumber && data.leaveNumber !== "-" ? data.leaveNumber : null;
dataStore.currentAddress = data.leaveAddress ? data.leaveAddress : "";
await dataStore.fetchProfileOld(data); await dataStore.fetchProfileOld(data);
}) })
.catch((err) => { .catch((err) => {
@ -223,23 +220,35 @@ async function fetchDataDetail(id: string) {
* @param formData อมลใน formdata * @param formData อมลใน formdata
* @param isLeave วแปรเชควาใชหน edit หรอไม * @param isLeave วแปรเชควาใชหน edit หรอไม
*/ */
function onSubmit(formData: FormData, isLeave: boolean = true) { function onSubmit(formData: any, isLeave: boolean = true) {
if (isLeave) { if (isLeave) {
dialogConfirm($q, async () => { if (dataStore.commanderPosition !== "" && dataStore.dear !== "") {
showLoader(); dialogConfirm($q, async () => {
await http showLoader();
.put(config.API.leaveUserId(personalId.value), formData) if (model.value === "LV-006" || model.value === "LV-008") {
.then(async () => { formData.append("leaveSubTypeName", modelSpecific.value);
await fetchDataDetail(personalId.value); }
success($q, "บันทึกสำเร็จ"); if (formData.get("leaveEndDate") === formData.get("leaveStartDate")) {
}) formData.set("leaveRangeEnd", formData.get("leaveRange") as string);
.catch((e: any) => { }
messageError($q, e); formData.append("commanderPosition", dataStore.commanderPosition);
}) formData.append("dear", dataStore.dear);
.finally(() => { await http
hideLoader(); .put(config.API.leaveUserId(personalId.value), formData)
}); .then(async () => {
}); await fetchDataDetail(personalId.value);
success($q, "บันทึกสำเร็จ");
})
.catch((e: any) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
});
} else {
dialogMessageNotify($q, "กรุณาเพิ่มรายชื่อ ผู้บังคับบัญชา");
}
} else { } else {
messageError($q, "", "ไม่มีสิทธิ์ลา"); messageError($q, "", "ไม่มีสิทธิ์ลา");
} }
@ -295,10 +304,27 @@ async function onClickDelete(id: string, docId: string) {
}); });
} }
/** function เรียกประเภทการลา */
async function fectOptionType() {
await http
.get(config.API.leaveType())
.then(async (res) => {
dataStore.fetchLeaveType(res.data.result);
})
.catch((err) => {
messageError($q, err);
});
}
/** /**
* เรยกใชงาน fetchData เพอดงขอม * เรยกใชงาน fetchData เพอดงขอม
*/ */
onMounted(async () => { onMounted(async () => {
dataStore.typeLeave = "";
if (dataStore.options.length == 0) {
fectOptionType();
}
await fetchDataDetail(personalId.value); await fetchDataDetail(personalId.value);
}); });
</script> </script>
@ -341,7 +367,7 @@ onMounted(async () => {
<q-select <q-select
readonly readonly
dense dense
class="col-12 col-sm-6 col-md-4" class="col-12 col-sm-9 col-md-6"
outlined outlined
v-model="formData.leaveTypeName" v-model="formData.leaveTypeName"
option-value="code" option-value="code"
@ -353,7 +379,7 @@ onMounted(async () => {
</div> </div>
<div class="row q-mt-sm"> <div class="row q-mt-sm">
<div <div
class="col-12 col-sm-6 col-md-3" class="col-12 col-sm-6 col-md-4"
v-if="model === 'LV-006' || model === 'LV-008'" v-if="model === 'LV-006' || model === 'LV-008'"
> >
<q-select <q-select
@ -366,14 +392,11 @@ onMounted(async () => {
? dataStore.optionsOrdination ? dataStore.optionsOrdination
: dataStore.optionsSpecific : dataStore.optionsSpecific
" "
option-value="code" option-value="id"
option-label="name" option-label="name"
emit-value emit-value
map-options map-options
prefix="ประเภทการลา :" prefix="ประเภทการลา :"
@update:model-value="
dataStore.typeConvert(model, modelSpecific)
"
/> />
</div> </div>
</div> </div>
@ -427,14 +450,16 @@ onMounted(async () => {
:click-delete="clickDelete" :click-delete="clickDelete"
/> />
<OrdinationForm <OrdinationForm
v-if="model === 'LV-006' && modelSpecific === 'b1'" v-if="model === 'LV-006' && modelSpecific === 'ลาอุปสมบท'"
:data="formData" :data="formData"
:on-submit="onSubmit" :on-submit="onSubmit"
:on-confirm="onConfirm" :on-confirm="onConfirm"
:click-delete="clickDelete" :click-delete="clickDelete"
/> />
<HajjForm <HajjForm
v-if="model === 'LV-006' && modelSpecific === 'b2'" v-if="
model === 'LV-006' && modelSpecific === 'ลาประกอบพิธีฮัจญ์'
"
:data="formData" :data="formData"
:on-submit="onSubmit" :on-submit="onSubmit"
:on-confirm="onConfirm" :on-confirm="onConfirm"
@ -449,7 +474,7 @@ onMounted(async () => {
:click-delete="clickDelete" :click-delete="clickDelete"
/> />
<StudyForm <StudyForm
v-if="model === 'LV-008' && modelSpecific === 's1'" v-if="model === 'LV-008' && modelSpecific === 'ศึกษาต่อ'"
style="width: 100%" style="width: 100%"
:data="formData" :data="formData"
:on-submit="onSubmit" :on-submit="onSubmit"
@ -458,9 +483,9 @@ onMounted(async () => {
/> />
<TrainForm <TrainForm
v-if=" v-if="
model === 'LV-008' && (model === 'LV-008' && modelSpecific == 'ฝึกอบรม') ||
modelSpecific != 's1' && (model === 'LV-008' && modelSpecific == 'ปฎิบัติการวิจัย') ||
modelSpecific != '' (model === 'LV-008' && modelSpecific == 'ดูงาน')
" "
:data="formData" :data="formData"
:on-submit="onSubmit" :on-submit="onSubmit"

View file

@ -118,8 +118,11 @@ const columns = ref<QTableProps["columns"]>([
}, },
]); ]);
const isloadingSummary = ref<boolean>(false);
/** function เรียกข้อมูลตารางสถิติการลา*/ /** function เรียกข้อมูลตารางสถิติการลา*/
async function fetchStatsTable() { async function fetchStatsTable() {
isloadingSummary.value = true;
await http await http
.get(config.API.leaveStats()) .get(config.API.leaveStats())
.then((res) => { .then((res) => {
@ -135,8 +138,13 @@ async function fetchStatsTable() {
: el.leaveTypeName === "ลากิจส่วนตัว" : el.leaveTypeName === "ลากิจส่วนตัว"
? "text-deep-purple" ? "text-deep-purple"
: "text-indigo", : "text-indigo",
value: el.leavePercent, value:
all: el.leaveLimit, el.leaveLimit > 0
? Math.round(
(Number(el.leaveCountApprove) / Number(el.leaveLimit)) * 100
)
: 0,
all: Number(el.leaveLimit),
use: el.leaveCountApprove, use: el.leaveCountApprove,
remain: Number(el.leaveLimit) - Number(el.leaveCountApprove), remain: Number(el.leaveLimit) - Number(el.leaveCountApprove),
})); }));
@ -166,6 +174,9 @@ async function fetchStatsTable() {
}) })
.catch((err) => { .catch((err) => {
messageError($q, err); messageError($q, err);
})
.finally(() => {
isloadingSummary.value = false;
}); });
} }
@ -205,7 +216,7 @@ onMounted(async () => {
<div class="col-xs-12 col-sm-12 col-md-11 row"> <div class="col-xs-12 col-sm-12 col-md-11 row">
<!-- สถการลา --> <!-- สถการลา -->
<div class="col-12 row q-pb-sm"> <div class="col-12 row q-pb-sm">
<q-card bordered class="col-12 row"> <q-card bordered class="col-12 row" v-if="!isloadingSummary">
<div class="row col-12 items-center q-px-md q-py-sm"> <div class="row col-12 items-center q-px-md q-py-sm">
<div class="text-weight-bold">สถการลา</div> <div class="text-weight-bold">สถการลา</div>
<q-space /> <q-space />
@ -225,12 +236,7 @@ onMounted(async () => {
:key="item.text" :key="item.text"
> >
<div class="col-xs-12 col-sm-12"> <div class="col-xs-12 col-sm-12">
<q-card <q-card bordered flat class="col-12 row shadow-0 no-wrap">
bordered
flat
class="col-12 row shadow-0 no-wrap"
v-if="item.text === 'ลาพักผ่อน'"
>
<div class="col-xs-12 col-sm-8 row justify-center q-py-md"> <div class="col-xs-12 col-sm-8 row justify-center q-py-md">
<div class="col-12 row items-center justify-center q-pb-sm"> <div class="col-12 row items-center justify-center q-pb-sm">
<q-knob <q-knob
@ -243,7 +249,7 @@ onMounted(async () => {
class="text-indigo" class="text-indigo"
> >
<span class="text-subtitle2 text-weight-bold">{{ <span class="text-subtitle2 text-weight-bold">{{
item.value item.remain
}}</span> }}</span>
</q-knob> </q-knob>
</div> </div>
@ -273,6 +279,7 @@ onMounted(async () => {
</q-card> </q-card>
</div> </div>
</div> </div>
<div class="col-6 row"> <div class="col-6 row">
<div <div
bordered bordered
@ -322,6 +329,91 @@ onMounted(async () => {
</div> </div>
</div> </div>
</q-card> </q-card>
<q-card bordered class="col-12 row q-px-md q-py-sm" v-else>
<div class="row col-12 items-center q-px-md q-py-sm">
<div class="text-weight-bold">สถการลา</div>
<q-space />
<q-skeleton type="QBtn" size="20px" style="width: 100px" />
</div>
<div
bordered
class="col-6 row justify-center q-px-md q-pb-md q-col-gutter-sm"
>
<div class="col-xs-12 col-sm-12">
<q-card bordered flat class="col-12 row shadow-0 no-wrap">
<div class="col-xs-12 col-sm-8 row justify-center q-py-md">
<div class="col-12 row items-center justify-center q-pb-sm">
<q-skeleton type="circle" size="60px" />
<div class="col-12 row items-center justify-center">
<q-skeleton type="text" size="20px" style="width: 50px" />
</div>
</div>
</div>
<div class="row gt-xs"><q-separator vertical /></div>
<div class="col-xs-12 col-sm-4 gt-xs row">
<div class="col-12 row text-dark text-body2 items-center">
<div class="col-12 row q-pa-xs q-px-md row">
<span class="text-grey-7 col-6">ได</span>
<q-skeleton type="text" style="width: 50px" />
</div>
<div class="col-12"><q-separator /></div>
<div class="col-12 row q-pa-xs q-px-md">
<span class="text-grey-7 col-6">ใชไป</span>
<q-skeleton type="text" style="width: 50px" />
</div>
<div class="col-12"><q-separator /></div>
<div class="col-12 row q-pa-xs q-px-md">
<span class="text-grey-7 col-6">คงเหล</span>
<q-skeleton type="text" style="width: 50px" />
</div>
</div>
</div>
</q-card>
</div>
</div>
<div class="col-6 row">
<div bordered class="col-12 row justify-center q-px-md q-pb-md">
<div class="col-xs-12 col-sm-12 row">
<div class="col-12 row">
<q-card
bordered
flat
class="shadow-0 col-12 fit row items-center q-px-lg"
>
<div class="text-subtitle2 col-4">
<q-skeleton type="text" style="width: 50px" />
</div>
<div class="text-subtitle2 col-8 row">
<span class="text-grey-7 q-pr-md">ใชไป</span>
<q-skeleton type="text" style="width: 50px" />
</div>
</q-card>
</div>
</div>
</div>
<div bordered class="col-12 row justify-center q-px-md q-pb-md">
<div class="col-xs-12 col-sm-12 row">
<div class="col-12 row">
<q-card
bordered
flat
class="shadow-0 col-12 fit row items-center q-px-lg"
>
<div class="text-subtitle2 col-4">
<q-skeleton type="text" style="width: 50px" />
</div>
<div class="text-subtitle2 col-8 row">
<span class="text-grey-7 q-pr-md">ใชไป</span>
<q-skeleton type="text" style="width: 50px" />
</div>
</q-card>
</div>
</div>
</div>
</div>
</q-card>
</div> </div>
<div class="row col-12"> <div class="row col-12">

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, nextTick } from "vue";
import { useRouter, useRoute } from "vue-router"; import { useRouter, useRoute } from "vue-router";
import { useQuasar } from "quasar"; import { useQuasar } from "quasar";
@ -71,7 +71,7 @@ async function onCilckNextStep() {
store.step === 1 store.step === 1
? checkSelectForm() ? checkSelectForm()
: store.step === 2 || store.step === 6 : store.step === 2 || store.step === 6
? validateForm() ? onSubmitFormData()
: store.step == 3 || store.step == 7 : store.step == 3 || store.step == 7
? dialogConfirm( ? dialogConfirm(
$q, $q,
@ -85,35 +85,42 @@ async function onCilckNextStep() {
} }
/** function validateForm Step 2,4*/ /** function validateForm Step 2,4*/
async function validateForm() { async function onSubmitFormData() {
store.checkFileupload = !store.checkFileupload; store.checkFileupload = !store.checkFileupload;
const emptyValues = downloadFileRef.value.filter((e: string) => e === ""); if (store.step === 2) {
const hasError = []; if (!store.statusUpload) {
for (const key in formCommandRef) { saveStep2();
if (Object.prototype.hasOwnProperty.call(formCommandRef, key)) { } else {
const property = formCommandRef[key]; if (!downloadFile.value.some((e: string) => e === "")) {
if (property.value && typeof property.value.validate === "function") {
const isValid = property.value.validate();
hasError.push(isValid);
}
}
}
if (hasError.every((result) => result === true)) {
if (emptyValues.length > 0 && store.statusUpload === true) {
} else if (store.step === 2) {
if (store.statusUpload === false) {
saveStep2();
} else {
nextTostep3(); nextTostep3();
} }
}
} else {
if (!store.statusUpload6) {
saveStep6();
} else { } else {
if (store.statusUpload6 === false) { if (!downloadFile.value.some((e: string) => e === "")) {
saveStep6();
} else {
nextTostep7(); nextTostep7();
} }
} }
} }
// const emptyValues = downloadFileRef.value.filter((e: string) => e === "");
// const hasError = [];
// for (const key in formCommandRef) {
// if (Object.prototype.hasOwnProperty.call(formCommandRef, key)) {
// const property = formCommandRef[key];
// if (property.value && typeof property.value.validate === "function") {
// const isValid = property.value.validate();
// hasError.push(isValid);
// }
// }
// }
// if (hasError.every((result) => result === true)) {
// if (emptyValues.length > 0 && store.statusUpload === true) {
// }
// }
} }
const pdfSrc = ref<any>(); const pdfSrc = ref<any>();
@ -191,7 +198,7 @@ const formDataStep1 = ref<PersonInformation>();
* @param id id ประเม * @param id id ประเม
*/ */
async function fetchDataStep1(id: string) { async function fetchDataStep1(id: string) {
showLoader(); // showLoader();
showLoadStatus.value = false; showLoadStatus.value = false;
await http await http
.get(config.API.evaluationCheckspecByid(id)) .get(config.API.evaluationCheckspecByid(id))
@ -204,9 +211,6 @@ async function fetchDataStep1(id: string) {
}) })
.finally(() => { .finally(() => {
showLoadStatus.value = true; showLoadStatus.value = true;
setTimeout(() => {
hideLoader();
}, 3000);
}); });
} }
@ -251,17 +255,40 @@ function checkSelectForm() {
async function saveStep1() { async function saveStep1() {
showLoader(); showLoader();
const salaries = formDetail.value.salaries.map((e: any) => ({ const salaries = formDetail.value.salaries.map((e: any) => ({
amount: e.amount, profileId: e.profileId,
date: e.date, commandCode: e.commandCode,
mouthSalaryAmount: e.mouthSalaryAmount ? e.mouthSalaryAmount : 0, commandNo: e.commandNo,
commandYear: e.commandYear ? Number(e.commandYear) : 0,
commandDateAffect: e.commandDateAffect,
commandDateSign: e.commandDateSign,
posNoAbb: e.posNoAbb,
posNo: e.posNo, posNo: e.posNo,
position: e.position, positionName: e.positionName,
positionSalaryAmount: e.positionSalaryAmount ? e.positionSalaryAmount : 0, positionType: e.positionType,
refCommandDate: e.refCommandDate, positionLevel: e.positionLevel,
refCommandNo: e.refCommandNo ? e.refCommandNo : "", positionLine: e.positionLine,
salaryClass: e.salaryClass ? e.salaryClass : "", positionPathSide: e.positionPathSide,
salaryRef: e.salaryRef ? e.salaryRef : "", positionExecutive: e.positionExecutive,
salaryStatus: e.salaryStatus ? e.salariesStatus : "", amount: e.amount ? e.amount.toString() : "0",
amountSpecial: e.amountSpecial ? e.amountSpecial.toString() : "0",
positionSalaryAmount: e.positionSalaryAmount
? e.positionSalaryAmount.toString()
: "0",
mouthSalaryAmount: e.mouthSalaryAmount
? e.mouthSalaryAmount.toString()
: "0",
orgRoot: e.orgRoot,
orgChild1: e.orgChild1,
orgChild2: e.orgChild2,
orgChild3: e.orgChild3,
orgChild4: e.orgChild4,
remark: e.remark,
commandId: e.commandId,
isGovernment: e.isGovernment,
positionCee: e.positionCee,
commandName: e.commandName,
posNumCodeSit: e.posNumCodeSit,
posNumCodeSitAbb: e.posNumCodeSitAbb,
})); }));
const educations = formDetail.value.educations.map((e: any) => ({ const educations = formDetail.value.educations.map((e: any) => ({
@ -282,16 +309,32 @@ async function saveStep1() {
startDate: e.startDate, startDate: e.startDate,
})); }));
const assessments = formDetail.value.assessments.map((e: any) => ({ const certificates = formDetail.value.certificates.map((e: any) => ({
date: e.date, ...e,
point1: e.point1,
point1Total: e.point1Total,
point2: e.point2,
point2Total: e.point2Total,
pointSum: e.pointSum,
pointSumTotal: e.pointSumTotal,
})); }));
const trainings = formDetail.value.trainings.map((e: any) => ({
...e,
}));
const performances = formDetail.value.assessments.map(
({ id, isAdd, ...rest }: any) => ({
...rest,
})
);
const portfolios = formDetail.value.experience.map(
({
id,
lastUpdatedAt,
lastUpdateFullName,
createdFullName,
createdAt,
...rest
}: any) => ({
...rest,
})
);
const evaluateType = route.params.type.toString(); const evaluateType = route.params.type.toString();
const form = { const form = {
root: formDetail.value.root, root: formDetail.value.root,
@ -316,12 +359,15 @@ async function saveStep1() {
isHaveSpecificQft: formSpec.isHaveSpecificQft, isHaveSpecificQft: formSpec.isHaveSpecificQft,
isHaveProLicense: formSpec.isHaveProLicense, isHaveProLicense: formSpec.isHaveProLicense,
isHaveMinPeriodOrHoldPos: formSpec.isHaveMinPeriodOrHoldPos, isHaveMinPeriodOrHoldPos: formSpec.isHaveMinPeriodOrHoldPos,
posExecutive: formDetail.value.posExecutive ?? "",
positionArea: formDetail.value.positionArea ?? "",
reason: "", reason: "",
educations: [...educations], educations: [...educations],
certificates: [...formDetail.value.certificates], certificates: [...certificates],
salaries: [...salaries], salaries: [...salaries],
trainings: [...formDetail.value.trainings], trainings: [...trainings],
assessments: [...assessments], performances: [...performances],
portfolios: [...portfolios],
}; };
await http await http
@ -343,41 +389,20 @@ const statusUpload = ref<boolean>(false);
const formCommand = reactive<FormCommand>({ const formCommand = reactive<FormCommand>({
commanderFullname: "", commanderFullname: "",
commanderPosition: "", commanderPosition: "",
commanderPositionOld: "",
commanderOrg: "",
commanderOrgOld: "",
commanderAboveFullname: "", commanderAboveFullname: "",
commanderAbovePosition: "", commanderAbovePosition: "",
commanderAbovePositionOld: "",
commanderAboveOrgOld: "",
commanderAboveOrg: "",
author: "", author: "",
subject: "", subject: [],
assignedPosition: "", assignedPosition: "",
}); });
const commanderFullnameRef = ref<object | null>(null); const downloadFile = ref<string[]>([]);
const commanderPositionRef = ref<object | null>(null);
const commanderAboveFullnameRef = ref<object | null>(null);
const commanderAbovePositionRef = ref<object | null>(null);
const fileEvaluation1Ref = ref<object | null>(null);
const fileEvaluation2Ref = ref<object | null>(null);
const fileEvaluation3Ref = ref<object | null>(null);
const fileEvaluation4Ref = ref<object | null>(null);
const fileEvaluation5Ref = ref<object | null>(null);
const fileEvaluation6Ref = ref<object | null>(null);
const performanceRef = ref<object | null>(null);
const performanceOwnerRef = ref<object | null>(null);
const assignedPositionRef = ref<object | null>(null);
const formCommandRef: FormCommandRef = {
commanderFullname: commanderFullnameRef,
commanderPosition: commanderPositionRef,
commanderAboveFullname: commanderAboveFullnameRef,
commanderAbovePosition: commanderAbovePositionRef,
fileEvaluation1: fileEvaluation1Ref,
fileEvaluation2: fileEvaluation2Ref,
fileEvaluation3: fileEvaluation3Ref,
fileEvaluation4: fileEvaluation4Ref,
fileEvaluation5: fileEvaluation5Ref,
fileEvaluation6: fileEvaluation6Ref,
performance: performanceRef,
performanceOwner: performanceOwnerRef,
assignedPosition: assignedPositionRef,
};
const downloadFileRef = ref<any>();
/** /**
* function ปเดท ผลงาน,เซนเอกสาร, Ref * function ปเดท ผลงาน,เซนเอกสาร, Ref
* @param val เซนเอกสาร * @param val เซนเอกสาร
@ -386,38 +411,22 @@ const downloadFileRef = ref<any>();
function updateformCommand(val: any, ref: any) { function updateformCommand(val: any, ref: any) {
formCommand.commanderFullname = val.commanderFullname; formCommand.commanderFullname = val.commanderFullname;
formCommand.commanderPosition = val.commanderPosition; formCommand.commanderPosition = val.commanderPosition;
formCommand.commanderPositionOld = val.commanderPositionOld;
formCommand.commanderOrg = val.commanderOrg;
formCommand.commanderOrgOld = val.commanderOrgOld;
formCommand.commanderAboveFullname = val.commanderAboveFullname; formCommand.commanderAboveFullname = val.commanderAboveFullname;
formCommand.commanderAbovePosition = val.commanderAbovePosition; formCommand.commanderAbovePosition = val.commanderAbovePosition;
formCommand.commanderAbovePositionOld = val.commanderAbovePositionOld;
formCommand.commanderAboveOrgOld = val.commanderAboveOrgOld;
formCommand.commanderAboveOrg = val.commanderAboveOrg;
formCommand.author = val.author; formCommand.author = val.author;
formCommand.subject = val.subject; formCommand.subject = val.subject;
formCommand.assignedPosition = val.assignedPosition; formCommand.assignedPosition = val.assignedPosition;
commanderFullnameRef.value = ref.commanderFullnameRef; downloadFile.value = ref.downloadFile;
commanderPositionRef.value = ref.commanderPositionRef;
commanderAboveFullnameRef.value = ref.commanderAboveFullnameRef;
commanderAbovePositionRef.value = ref.commanderAbovePositionRef;
fileEvaluation1Ref.value = ref.fileEvaluation1Ref;
fileEvaluation2Ref.value = ref.fileEvaluation2Ref;
fileEvaluation3Ref.value = ref.fileEvaluation3Ref;
fileEvaluation4Ref.value = ref.fileEvaluation4Ref;
fileEvaluation5Ref.value = ref.fileEvaluation5Ref;
fileEvaluation6Ref.value = ref.fileEvaluation6Ref;
downloadFileRef.value = ref.downloadFile;
performanceRef.value = ref.performance;
performanceOwnerRef.value = ref.performanceOwner;
assignedPositionRef.value = ref.assignedPosition;
statusUpload.value = ref.statusUpload; statusUpload.value = ref.statusUpload;
} }
/** function บันทึกข้อมูล ผลงานม,ผู้เซ็นเอกสาร*/ /** function บันทึกข้อมูล ผลงานม,ผู้เซ็นเอกสาร*/
async function saveStep2() { async function saveStep2() {
const body = {
commanderFullname: formCommand.commanderFullname,
commanderPosition: formCommand.commanderPosition,
commanderAboveFullname: formCommand.commanderAboveFullname,
commanderAbovePosition: formCommand.commanderAbovePosition,
author: formCommand.author,
subject: formCommand.subject,
};
dialogConfirm( dialogConfirm(
$q, $q,
async () => { async () => {
@ -430,10 +439,10 @@ async function saveStep2() {
route.params.id.toString(), route.params.id.toString(),
"director" "director"
), ),
body { ...formCommand, assignedPosition: undefined }
) )
.then(() => { .then(async () => {
route.params.id && fetchCheckStep(route.params.id.toString()); route.params.id && (await fetchCheckStep(route.params.id.toString()));
}) })
.catch((err) => { .catch((err) => {
messageError($q, err); messageError($q, err);
@ -495,8 +504,14 @@ async function saveStep6() {
const body = { const body = {
commanderAboveFullnameDoc2: formCommand.commanderAboveFullname, commanderAboveFullnameDoc2: formCommand.commanderAboveFullname,
commanderAbovePositionDoc2: formCommand.commanderAbovePosition, commanderAbovePositionDoc2: formCommand.commanderAbovePosition,
commanderAbovePositionOldDoc2: formCommand.commanderAbovePositionOld,
commanderAboveOrgOldDoc2: formCommand.commanderAboveOrgOld,
commanderAboveOrgDoc2: formCommand.commanderAboveOrg,
commanderFullnameDoc2: formCommand.commanderFullname, commanderFullnameDoc2: formCommand.commanderFullname,
commanderPositionDoc2: formCommand.commanderPosition, commanderPositionDoc2: formCommand.commanderPosition,
commanderPositionOldDoc2: formCommand.commanderPositionOld,
commanderOrgDoc2: formCommand.commanderOrg,
commanderOrgOldDoc2: formCommand.commanderOrgOld,
authorDoc2: formCommand.author, authorDoc2: formCommand.author,
subjectDoc2: formCommand.subject, subjectDoc2: formCommand.subject,
assignedPosition: formCommand.assignedPosition, assignedPosition: formCommand.assignedPosition,
@ -516,8 +531,8 @@ async function saveStep6() {
), ),
body body
) )
.then(() => { .then(async () => {
route.params.id && fetchCheckStep(route.params.id.toString()); route.params.id && (await fetchCheckStep(route.params.id.toString()));
}) })
.catch((err) => { .catch((err) => {
messageError($q, err); messageError($q, err);
@ -563,7 +578,9 @@ async function saveStep7() {
.then(() => { .then(() => {
route.params.id && fetchCheckStep(route.params.id.toString()); route.params.id && fetchCheckStep(route.params.id.toString());
}) })
.catch(() => {}) .catch((err) => {
messageError($q, err);
})
.finally(() => { .finally(() => {
hideLoader(); hideLoader();
}); });
@ -644,163 +661,172 @@ onMounted(async () => {
</div> </div>
</div> </div>
</div> </div>
<q-form
<div class="col-xs-12 col-sm-9 q-pa-md" v-if="showLoadStatus"> class="col-xs-12 col-sm-9"
<div class="col-12 row items-center"> greedy
<div class="toptitle2"> @submit.prevent
{{ store.step }}.{{ store.title[store.step - 1] }} @validation-success="onCilckNextStep"
>
<div class="col-xs-12 col-sm-9 q-pa-md" v-if="showLoadStatus">
<div class="col-12 row items-center">
<div class="toptitle2">
{{ store.step }}.{{ store.title[store.step - 1] }}
</div>
<q-space />
<div>
<q-btn
v-if="store.step === 1"
:href="externalLink"
target="_blank"
outline
color="blue"
dense
class="q-px-md"
no-caps
>
ตรวจสอบคณสมบ ..
</q-btn>
</div>
</div> </div>
<q-space /> <div class="col-12 q-pt-sm">
<div> <div class="q-col-gutter-md col-12 row">
<q-btn <div
v-if="store.step === 1" :class="
:href="externalLink" store.step === 2 ||
target="_blank" store.step === 4 ||
outline store.step === 5 ||
color="blue" store.step === 6 ||
dense store.step === 8 ||
class="q-px-md" store.step === 9
no-caps ? 'col-12 row'
> : 'col-xs-12 col-sm-5 row'
ตรวจสอบคณสมบ ..
</q-btn>
</div>
</div>
<div class="col-12 q-pt-sm">
<div class="q-col-gutter-md col-12 row">
<div
:class="
store.step === 2 ||
store.step === 4 ||
store.step === 5 ||
store.step === 6 ||
store.step === 8 ||
store.step === 9
? 'col-12 row'
: 'col-xs-12 col-sm-5 row'
"
>
<q-card
flat
bordered
class="col-12 shadow-0"
:style="
$q.screen.lt.sm
? ''
: 'max-height: 60vh; overflow: scroll;'
" "
> >
<Step1 <q-card
v-if="store.step === 1" flat
@update:spec="updateCheckSpec" bordered
:data="formDataStep1" class="col-12 shadow-0"
:educations="formDetail?.educations" :style="
/> $q.screen.lt.sm
<Step2 ? ''
v-if="store.step === 2" : 'max-height: 60vh; overflow: scroll;'
@update:form="updateformCommand" "
/> >
<Step3 <Step1
v-if="store.step === 3" v-if="store.step === 1"
@update:file="updateFilePDF" @update:spec="updateCheckSpec"
/> :data="formDataStep1"
<Step4 v-if="store.step === 4" /> :educations="formDetail?.educations"
<Step5 v-if="store.step === 5" /> />
<Step6 <Step2
v-if="store.step === 6" v-if="store.step === 2"
@update:form="updateformCommand" @update:form="updateformCommand"
/> />
<Step7 <Step3
v-if="store.step === 7" v-if="store.step === 3"
@update:file="updateFilePDF" @update:file="updateFilePDF"
/> />
<Step8 v-if="store.step === 8" /> <Step4 v-if="store.step === 4" />
<Step9 v-if="store.step === 9" /> <Step5 v-if="store.step === 5" />
</q-card> <Step6
</div> v-if="store.step === 6"
<div @update:form="updateformCommand"
class="col-xs-12 col-sm-7" />
v-if=" <Step7
store.step === 1 || store.step === 3 || store.step === 7 v-if="store.step === 7"
" @update:file="updateFilePDF"
> />
<div class="col-12"> <Step8 v-if="store.step === 8" />
<ViewStep1 <Step9 v-if="store.step === 9" />
v-if="store.step === 1" </q-card>
@update:formDeital="updateFormDetail" </div>
:data="formDataStep1" <div
/> class="col-xs-12 col-sm-7"
<ViewStep3 v-if="
v-if="store.step === 3 && pdfSrc" store.step === 1 || store.step === 3 || store.step === 7
:pdfSrc="pdfSrc" "
:urlDownloadFile="urlDownloadFile" >
/> <div class="col-12">
<ViewStep7 <ViewStep1
v-if="store.step === 7 && pdfSrc" v-if="store.step === 1"
:pdfSrc="pdfSrc" @update:formDeital="updateFormDetail"
:urlDownloadFile="urlDownloadFile" :data="formDataStep1"
/> />
<ViewStep3
v-if="store.step === 3 && pdfSrc"
:pdfSrc="pdfSrc"
:urlDownloadFile="urlDownloadFile"
/>
<ViewStep7
v-if="store.step === 7 && pdfSrc"
:pdfSrc="pdfSrc"
:urlDownloadFile="urlDownloadFile"
/>
</div>
</div> </div>
</div> </div>
</div> </div>
<q-card-actions
class="q-pt-sm q-pa-none q-gutter-sm"
align="right"
>
<q-btn
v-if="
store.step >= store.currentStep &&
store.statusUpload === false &&
store.step !== 3 &&
store.step !== 4 &&
store.step !== 5 &&
store.step !== 7 &&
store.step !== 8 &&
store.step !== 9
"
unelevated
:label="
store.step === 2 || store.step === 6
? 'บันทึกข้อมูล'
: 'ดำเนินการต่อ'
"
color="public"
type="submit"
/>
<q-btn
v-else-if="
store.step >= store.currentStep &&
(store.step == 3 || store.step == 7)
"
unelevated
label="ยื่นเอกสาร"
color="public"
type="submit"
/>
<q-btn
v-if="
store.step >= store.currentStep &&
store.step == 2 &&
store.statusUpload
"
unelevated
label="ดำเนินการต่อ"
color="public"
type="submit"
/>
<q-btn
v-if="
store.step >= store.currentStep &&
store.step == 6 &&
store.statusUpload
"
unelevated
label="ดำเนินการต่อ"
color="public"
type="submit"
/>
</q-card-actions>
</div> </div>
<q-card-actions class="q-pt-sm q-pa-none q-gutter-sm" align="right"> </q-form>
<q-btn
v-if="
store.step >= store.currentStep &&
store.statusUpload === false &&
store.step !== 3 &&
store.step !== 4 &&
store.step !== 5 &&
store.step !== 7 &&
store.step !== 8 &&
store.step !== 9
"
unelevated
:label="
store.step === 2 || store.step === 6
? 'บันทึกข้อมูล'
: 'ดำเนินการต่อ'
"
color="public"
@click="onCilckNextStep()"
/>
<q-btn
v-else-if="
store.step >= store.currentStep &&
(store.step == 3 || store.step == 7)
"
unelevated
label="ยื่นเอกสาร"
color="public"
@click="onCilckNextStep()"
/>
<q-btn
v-if="
store.step >= store.currentStep &&
store.step == 2 &&
store.statusUpload
"
unelevated
label="ดำเนินการต่อ"
color="public"
@click="onCilckNextStep()"
/>
<q-btn
v-if="
store.step >= store.currentStep &&
store.step == 6 &&
store.statusUpload
"
unelevated
label="ดำเนินการต่อ"
color="public"
@click="onCilckNextStep()"
/>
</q-card-actions>
</div>
</q-card> </q-card>
</div> </div>
</div> </div>

View file

@ -1,16 +1,18 @@
<script setup lang="ts"> <script setup lang="ts">
import { reactive, onMounted } from "vue"; import { reactive, ref, onMounted } from "vue";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import { useQuasar } from "quasar"; 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 { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
import { useDataStore } from "@/stores/data";
import type { FormCommandSe } from "@/modules/06_evaluate/interface/evalute"; import type { FormCommandSe } from "@/modules/06_evaluate/interface/evalute";
const $q = useQuasar(); const $q = useQuasar();
const router = useRouter(); const router = useRouter();
const dataPerson = useDataStore();
const mixin = useCounterMixin(); const mixin = useCounterMixin();
const { dialogConfirm, messageError, showLoader, hideLoader } = mixin; const { dialogConfirm, messageError, showLoader, hideLoader } = mixin;
@ -23,14 +25,24 @@ const formData = reactive<FormCommandSe>({
commanderAbovePosition: "", commanderAbovePosition: "",
}); });
/** const isLoading = ref(false);
* นยนการบนทกขอม
*/ /** ยืนยันการบันทึกข้อมูล */
function onSubmit() { function onSubmit() {
dialogConfirm($q, () => { dialogConfirm($q, async () => {
showLoader(); showLoader();
http const body = {
.post(config.API.evaluationExpertise, formData) ...formData,
citizenId: dataPerson.formData.citizenId,
prefix: dataPerson.formData.prefix,
fullName: `${dataPerson.formData.prefix}${dataPerson.formData.firstName} ${dataPerson.formData.lastName}`,
position: dataPerson.formData.position,
salary: dataPerson.formData.salary?.toString(),
posNo: dataPerson.formData.posNo,
birthDate: dataPerson.formData.birthDate,
};
await http
.post(config.API.evaluationExpertise, body)
.then((res) => { .then((res) => {
router.push(`/evaluate/detail/expertise/${res.data.result.id}`); router.push(`/evaluate/detail/expertise/${res.data.result.id}`);
}) })
@ -43,12 +55,10 @@ function onSubmit() {
}); });
} }
/** /** ฟังก์ชันดึงข้อมูลรายชื่อ ผู้บังคับบัญชาชั้นต้น */
* fetch รายช งคบบญชาชนต, async function getData() {
*/ isLoading.value = true;
function getData() { await http
showLoader();
http
.get(config.API.orgSearchCommander()) .get(config.API.orgSearchCommander())
.then(async (res) => { .then(async (res) => {
const data = await res.data.result; const data = await res.data.result;
@ -62,12 +72,12 @@ function getData() {
messageError($q, e); messageError($q, e);
}) })
.finally(() => { .finally(() => {
hideLoader(); isLoading.value = false;
}); });
} }
onMounted(() => { onMounted(async () => {
getData(); await getData();
}); });
</script> </script>
@ -84,15 +94,21 @@ onMounted(() => {
flat flat
color="primary" color="primary"
class="q-mr-sm" class="q-mr-sm"
@click="router.go(-1)" @click="router.push('/evaluate')"
/> />
<div>ประเมนเชยวชาญ</div> <div>ประเมนเชยวชาญ</div>
</div> </div>
</div> </div>
<div class="col-xs-12 col-sm-12 col-md-11 row q-col-gutter-md"> <div class="col-xs-12 col-sm-12 col-md-11 row q-col-gutter-md">
<div class="col-12"> <div class="col-12">
<q-card bordered> <q-skeleton
v-if="isLoading"
height="230px"
square
style="border-radius: 8px"
/>
<q-card bordered v-else>
<div class="col-12 row q-pa-md q-col-gutter-y-md"> <div class="col-12 row q-pa-md q-col-gutter-y-md">
<div class="col-12"> <div class="col-12">
<q-card bordered class="col-12"> <q-card bordered class="col-12">

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,128 @@
<script setup lang="ts">
import { useQuasar } from "quasar";
import { ref, watch } from "vue";
import http from "@/plugins/http";
import config from "@/app.config";
import { useCounterMixin } from "@/stores/mixin";
import type { CardDataPos } from "@/modules/10_registry/interface/index/Main";
import DialogHeader from "@/components/DialogHeader.vue";
const $q = useQuasar();
const { showLoader, hideLoader, messageError, formatDatePosition } =
useCounterMixin();
const modal = defineModel<boolean>("modal", { required: true });
const isLoading = ref<boolean>(false);
const cardData = ref<CardDataPos[]>([
{
label: "ระยะเวลาดำรงตำแหน่งในสายงาน",
data: [],
},
{
label: "ระยะเวลาดำรงตำแหน่งตามระดับ",
data: [],
},
{
label: "ระยะเวลาดำรงตำแหน่งทางการบริหาร",
data: [],
},
]);
function onClosePopup() {
modal.value = false;
}
async function fetchDataPosition() {
isLoading.value = true;
await http
.get(config.API.salaryTenurePosition(""))
.then((res) => {
const data = res.data.result;
if (data) {
// map
const formatData = (list: any) =>
list.map((e: any) => ({
name: e.name ?? "",
time: formatDatePosition(e.year, e.month, e.day),
}));
// data
const position = data.position ? formatData(data.position) : []; //
const posLevel = data.posLevel ? formatData(data.posLevel) : []; //
const posExecutive = data.posExecutive
? formatData(data.posExecutive)
: []; //
// cardData
if (cardData.value[0]) {
cardData.value[0].data = position;
}
if (cardData.value[1]) {
cardData.value[1].data = posLevel;
}
if (cardData.value[2]) {
cardData.value[2].data = posExecutive;
}
// cardData
if (posExecutive.length === 0 && cardData.value.length > 2) {
cardData.value.splice(2, 1);
}
}
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
isLoading.value = false;
});
}
watch(modal, (v) => {
if (v) {
fetchDataPosition();
} else {
cardData.value.forEach((item) => {
item.data = [];
});
}
});
</script>
<template>
<q-dialog v-model="modal" persistent>
<q-card style="min-width: 40%">
<DialogHeader :tittle="`ประวัติการรับราชการ`" :close="onClosePopup" />
<q-separator />
<q-card-section>
<div class="row q-col-gutter-sm q-pb-sm">
<q-skeleton v-if="isLoading" width="100%" height="240px" />
<div
v-else
class="col"
v-for="(item, index) in cardData"
:key="index"
>
<q-card bordered class="col-12" style="border: 1px solid #d6dee1">
<div class="col-12 text-weight-medium bg-grey-1 q-py-xs q-px-md">
{{ item.label }}
</div>
<div class="col-12"><q-separator /></div>
<q-card-section class="q-pt-none" style="min-height: 200px">
<li v-for="data in item.data">
{{ data.name }} {{ data.time }}
</li>
</q-card-section>
</q-card>
</div>
</div>
</q-card-section>
</q-card>
</q-dialog>
</template>
<style scoped></style>

View file

@ -1,7 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, watch } from "vue"; import { ref, onMounted } from "vue";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import { useQuasar } from "quasar"; import { useQuasar } from "quasar";
import type { PropsTable } from "@/interface/PropsTable";
import type { QTableProps } from "quasar"; import type { QTableProps } from "quasar";
import config from "@/app.config"; import config from "@/app.config";
@ -14,25 +16,16 @@ const $q = useQuasar();
const store = useEvaluateStore(); const store = useEvaluateStore();
const mixin = useCounterMixin(); const mixin = useCounterMixin();
const router = useRouter(); const router = useRouter();
const total = defineModel<number>("total", { required: true });
const totalList = defineModel<number>("totalList", { required: true });
const pagination = defineModel<any>("pagination", { required: true });
const { dialogRemove, showLoader, hideLoader, success, messageError } = mixin; const { dialogRemove, showLoader, hideLoader, success, messageError } = mixin;
const isLoading = defineModel<boolean>("isLoading", {
default: false,
});
const pagination = defineModel<PropsTable.Pagination>("pagination", {
required: true,
});
const props = defineProps({ const props = defineProps({
page: {
type: Number,
require: true,
},
pageSize: {
type: Number,
require: true,
},
maxPage: {
type: Number,
require: true,
},
fetchData: { fetchData: {
type: Function, type: Function,
require: true, require: true,
@ -82,25 +75,11 @@ const columns = ref<QTableProps["columns"]>([
}, },
]); ]);
/**
* function งขอมลไป Update Paging
* @param newPagination อม Paging ใหม
* @param page หน
*/
function updateProp(newPagination: any, page: number) {
emit("update:pagination", newPagination, page);
}
function updatePagination(newPagination: any) {
pagination.value.page = 1;
pagination.value.rowsPerPage = newPagination.rowsPerPage;
}
/** /**
* function ลบรายการประเม * function ลบรายการประเม
* @param id รายการประเม * @param id รายการประเม
*/ */
async function onCkilckDelete(id: string) { async function onClickDelete(id: string) {
dialogRemove($q, async () => { dialogRemove($q, async () => {
showLoader(); showLoader();
await http await http
@ -127,6 +106,17 @@ function redirectToDetail(data: any) {
router.push(`/evaluate/detail/${data.typeparam.toLowerCase()}/${data.id}`); router.push(`/evaluate/detail/${data.typeparam.toLowerCase()}/${data.id}`);
} }
/**
* งกนร request จากตาราง เมอมการเปลยน pagination
* @param requestProps อมลการรองขอจากตาราง
*/
function onTableRequest(requestProps: PropsTable.RequestProps) {
const newPagination = requestProps?.pagination || requestProps;
if (!newPagination?.page || !newPagination?.rowsPerPage) return;
pagination.value = { ...newPagination };
props.fetchData?.();
}
/** Hook lifecycle*/ /** Hook lifecycle*/
onMounted(() => { onMounted(() => {
store.columns = columns.value; store.columns = columns.value;
@ -139,13 +129,15 @@ onMounted(() => {
ref="table" ref="table"
flat flat
bordered bordered
class="custom-header-table"
:columns="columns" :columns="columns"
:rows="store.row" :rows="store.row"
dense dense
:visible-columns="store.visibleColumns" :visible-columns="store.visibleColumns"
:rows-per-page-options="[10, 25, 50, 100]" :rows-per-page-options="[10, 25, 50, 100]"
@update:pagination="updatePagination" @request="onTableRequest"
v-model:pagination="pagination"
:loading="isLoading"
row-key="id"
> >
<template v-slot:header="props"> <template v-slot:header="props">
<q-tr :props="props"> <q-tr :props="props">
@ -182,7 +174,7 @@ onMounted(() => {
round round
color="red" color="red"
icon="delete" icon="delete"
@click.stop="onCkilckDelete(props.row.id)" @click.stop="onClickDelete(props.row.id)"
> >
<q-tooltip>ลบ</q-tooltip> <q-tooltip>ลบ</q-tooltip>
</q-btn> </q-btn>
@ -227,7 +219,7 @@ onMounted(() => {
round round
color="red" color="red"
icon="delete" icon="delete"
@click.stop="onCkilckDelete(props.row.id)" @click.stop="onClickDelete(props.row.id)"
> >
<q-tooltip>ลบ</q-tooltip> <q-tooltip>ลบ</q-tooltip>
</q-btn> </q-btn>
@ -235,48 +227,7 @@ onMounted(() => {
</q-card> </q-card>
</div> </div>
</template> </template>
<template v-slot:pagination="scope">
งหมด {{ total }} รายการ
<q-pagination
v-model="pagination.page"
active-color="primary"
color="dark"
:max="Number(totalList)"
size="sm"
boundary-links
direction-links
:max-pages="5"
@update:model-value="props.fetchData?.()"
></q-pagination>
</template>
</d-table> </d-table>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped></style>
.custom-header-table {
height: auto;
.q-table tr:nth-child(odd) td {
background: white;
}
.q-table tr:nth-child(even) td {
background: #f8f8f8;
}
.q-table thead tr {
background: #ecebeb;
}
.q-table thead tr th {
position: sticky;
z-index: 1;
}
/* this will be the loading indicator */
.q-table thead tr:last-child th {
/* height of all previous header rows */
top: 48px;
}
.q-table thead tr:first-child th {
top: 0;
}
}
</style>

View file

@ -9,6 +9,7 @@ import type {
} from "@/modules/06_evaluate/interface/evalute"; } from "@/modules/06_evaluate/interface/evalute";
import PopupCheckFeatures from "@/modules/06_evaluate/components/PopupCheckFeatures.vue"; import PopupCheckFeatures from "@/modules/06_evaluate/components/PopupCheckFeatures.vue";
import PopupPosition from "@/modules/06_evaluate/components/PopupPosition.vue";
/** use*/ /** use*/
const store = useEvaluateStore(); const store = useEvaluateStore();
@ -24,6 +25,7 @@ const education = ref<any>();
const emit = defineEmits(["update:spec"]); const emit = defineEmits(["update:spec"]);
const modal = ref<boolean>(false); const modal = ref<boolean>(false);
const modalPosition = ref<boolean>(false);
const show = ref<boolean>(false); const show = ref<boolean>(false);
const formData = reactive<FormSpec>({ const formData = reactive<FormSpec>({
@ -35,6 +37,7 @@ const formData = reactive<FormSpec>({
isHaveProLicense: false, // isHaveProLicense: false, //
isHaveMinPeriodOrHoldPos: false, // ] isHaveMinPeriodOrHoldPos: false, // ]
}); });
const isLoading = ref<boolean>(false);
/** function อัปเดทตรวจสอบคุณสมบัติ*/ /** function อัปเดทตรวจสอบคุณสมบัติ*/
async function updateValue() { async function updateValue() {
@ -46,6 +49,7 @@ async function updateValue() {
* @param data ตรวจสอบคณสมบ * @param data ตรวจสอบคณสมบ
*/ */
async function fetchCheckSpec(data: PersonInformation) { async function fetchCheckSpec(data: PersonInformation) {
isLoading.value = true;
formData.isEducationalQft = data.isEducationalQft; formData.isEducationalQft = data.isEducationalQft;
formData.isGovermantServiceHtr = data.isGovermantServiceHtr; formData.isGovermantServiceHtr = data.isGovermantServiceHtr;
formData.isOperatingExp = data.isOperatingExp; formData.isOperatingExp = data.isOperatingExp;
@ -53,6 +57,7 @@ async function fetchCheckSpec(data: PersonInformation) {
formData.isHaveSpecificQft = data.isHaveSpecificQft; formData.isHaveSpecificQft = data.isHaveSpecificQft;
formData.isHaveProLicense = data.isHaveProLicense; formData.isHaveProLicense = data.isHaveProLicense;
formData.isHaveMinPeriodOrHoldPos = data.isHaveMinPeriodOrHoldPos; formData.isHaveMinPeriodOrHoldPos = data.isHaveMinPeriodOrHoldPos;
isLoading.value = false;
} }
/** /**
@ -69,6 +74,10 @@ function closeModal() {
modal.value = false; modal.value = false;
} }
function onViewDataPosition() {
modalPosition.value = true;
}
/**hook lifecycle*/ /**hook lifecycle*/
onMounted(() => { onMounted(() => {
props.data && fetchCheckSpec(props.data); props.data && fetchCheckSpec(props.data);
@ -81,7 +90,8 @@ onMounted(() => {
</script> </script>
<template> <template>
<div class="q-pa-sm"> <q-skeleton v-if="isLoading" class="q-mb-md" width="100%" height="100%" />
<div class="q-pa-sm" v-else>
<q-list dense> <q-list dense>
<q-item v-ripple class="listItem"> <q-item v-ripple class="listItem">
<q-item-section avatar> <q-item-section avatar>
@ -120,7 +130,19 @@ onMounted(() => {
/> />
</q-item-section> </q-item-section>
<q-item-section> <q-item-section>
<q-item-label>ประวการรบราชการ </q-item-label> <q-item-label
>ประวการรบราชการ
<q-btn
flat
round
dense
color="info"
icon="info"
@click="onViewDataPosition()"
>
<q-tooltip>อมลประวการรบราชการ</q-tooltip>
</q-btn>
</q-item-label>
</q-item-section> </q-item-section>
</q-item> </q-item>
<q-item v-ripple class="listItem"> <q-item v-ripple class="listItem">
@ -223,6 +245,8 @@ onMounted(() => {
:close-modal="closeModal" :close-modal="closeModal"
:educations="educations" :educations="educations"
/> />
<PopupPosition v-model:modal="modalPosition" />
</template> </template>
<style> <style>

File diff suppressed because it is too large Load diff

View file

@ -13,7 +13,7 @@ const $q = useQuasar();
const store = useEvaluateStore(); const store = useEvaluateStore();
const mixin = useCounterMixin(); const mixin = useCounterMixin();
const route = useRoute(); const route = useRoute();
const { showLoader, hideLoader, messageError } = mixin; const { messageError } = mixin;
/** id ประเมิน*/ /** id ประเมิน*/
const evaluateId = ref<string>(route.params.id.toString()); const evaluateId = ref<string>(route.params.id.toString());
@ -21,14 +21,25 @@ const evaluateId = ref<string>(route.params.id.toString());
/** emit*/ /** emit*/
const emit = defineEmits(["update:file"]); const emit = defineEmits(["update:file"]);
const isLoading = ref(false);
const selectedItem = ref(1); const selectedItem = ref(1);
const fileName = ref([ const formTemplates = ref([
"1-แบบพิจารณาคุณสมบัติบุคคล", {
"2-แบบแสดงรายละเอียดการเสนอผลงาน", title: "แบบพิจารณาคุณสมบัติบุคคล",
"3-แบบตรวจสอบความถูกต้องครบถ้วนของข้อมูลเพื่อประกอบการคัดเลือกบุคคล (เอกสารแบบ ก)", fileName: "1-แบบพิจารณาคุณสมบัติบุคคล",
"4-แบบประเมินคุณลักษณะบุคคล", },
"5-แบบสรุปข้อมูลของผู้ขอรับการคัดเลือก (เอกสารหมายเลข 9)", {
"6-ผลงานที่จะส่งประเมิน (เอกสารหมายเลข 11)", title: "แบบแสดงรายละเอียดการเสนอผลงาน",
fileName: "2-แบบแสดงรายละเอียดการเสนอผลงาน",
},
{
title: "แบบประเมินคุณลักษณะบุคคล",
fileName: "4-แบบประเมินคุณลักษณะบุคคล",
},
{
title: "ผลงานที่จะส่งประเมิน (เอกสารหมายเลข 11)",
fileName: "6-ผลงานที่จะส่งประเมิน (เอกสารหมายเลข 11)",
},
]); ]);
/** /**
@ -38,26 +49,28 @@ const fileName = ref([
function handleItemClick(itemNumber: number) { function handleItemClick(itemNumber: number) {
store.tabPanels = itemNumber.toString(); store.tabPanels = itemNumber.toString();
selectedItem.value = itemNumber; selectedItem.value = itemNumber;
fetchDocument(fileName.value[itemNumber - 1]); fetchDocument(formTemplates.value[itemNumber - 1].fileName);
} }
/** /**
* function เรกยเอกสาร * function เรกยเอกสาร
* @param fileName อเอกสาร * @param fileName อเอกสาร
*/ */
async function fetchDocument(fileName: string) { async function fetchDocument(fileName: string, forceDownload = false) {
showLoader(); if (forceDownload) {
isLoading.value = true;
}
evaluateId.value && evaluateId.value &&
(await http (await http
.get(config.API.loadFileDocument("เล่ม 1", evaluateId.value, fileName)) .get(config.API.loadFileDocument("เล่ม 1", evaluateId.value, fileName))
.then((res) => { .then(async (res) => {
downloadFile(res.data.downloadUrl); await downloadFile(res.data.downloadUrl);
}) })
.catch((err) => { .catch((err) => {
messageError($q, err); messageError($q, err);
}) })
.finally(() => { .finally(() => {
showLoader(); isLoading.value = false;
})); }));
} }
@ -66,7 +79,6 @@ async function fetchDocument(fileName: string) {
* @param url งกดาวนโหลดไฟล * @param url งกดาวนโหลดไฟล
*/ */
async function downloadFile(url: string) { async function downloadFile(url: string) {
showLoader();
await axios await axios
.get(url, { .get(url, {
responseType: "blob", responseType: "blob",
@ -81,84 +93,32 @@ async function downloadFile(url: string) {
}) })
.catch((err) => { .catch((err) => {
messageError($q, err); messageError($q, err);
})
.finally(() => {
hideLoader();
}); });
} }
/** HooK lifecycle*/ /** HooK lifecycle*/
onMounted(async () => { onMounted(async () => {
await fetchDocument(fileName.value[selectedItem.value - 1]); await fetchDocument(
formTemplates.value[selectedItem.value - 1].fileName,
true
);
}); });
</script> </script>
<template> <template>
<q-list separator> <q-list separator>
<q-item <q-item
v-for="(item, index) in formTemplates"
:key="index"
clickable clickable
v-ripple v-ripple
:active="selectedItem === 1 ? true : false" :active="selectedItem === index + 1 ? true : false"
active-class="text-primary" active-class="text-primary"
@click="handleItemClick(1)" @click="handleItemClick(index + 1)"
class="cursor-pointer" class="cursor-pointer"
> >
<q-item-section>แบบพจารณาคณสมบคคล</q-item-section> <q-skeleton v-if="isLoading" type="text" width="100%" />
</q-item> <q-item-section v-else>{{ item.title }}</q-item-section>
<q-item
clickable
v-ripple
:active="selectedItem === 2 ? true : false"
active-class="text-primary"
@click="handleItemClick(2)"
class="cursor-pointer"
>
<q-item-section>แบบแสดงรายละเอยดการเสนอผลงาน</q-item-section>
</q-item>
<q-item
clickable
v-ripple
:active="selectedItem === 3 ? true : false"
active-class="text-primary"
@click="handleItemClick(3)"
class="cursor-pointer"
>
<q-item-section
>แบบตรวจสอบความถกตองครบถวนของขอมลเพอประกอบการคดเลอกบคคล
(เอกสารแบบ )</q-item-section
>
</q-item>
<q-item
clickable
v-ripple
:active="selectedItem === 4 ? true : false"
active-class="text-primary"
@click="handleItemClick(4)"
class="cursor-pointer"
>
<q-item-section> แบบประเมนคณลกษณะบคคล </q-item-section>
</q-item>
<q-item
clickable
v-ripple
:active="selectedItem === 5 ? true : false"
active-class="text-primary"
@click="handleItemClick(5)"
class="cursor-pointer"
>
<q-item-section>
แบบสรปขอมลของผขอรบการคดเลอก (เอกสารหมายเลข 9)
</q-item-section>
</q-item>
<q-item
clickable
v-ripple
:active="selectedItem === 6 ? true : false"
active-class="text-primary"
@click="handleItemClick(6)"
class="cursor-pointer"
>
<q-item-section> ผลงานทจะสงประเม (เอกสารหมายเลข 11) </q-item-section>
</q-item> </q-item>
</q-list> </q-list>
</template> </template>

View file

@ -1,7 +1,223 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from "vue"; import { ref, onMounted } from "vue";
import { is, useQuasar } from "quasar";
import axios from "axios";
import http from "@/plugins/http";
import config from "@/app.config";
import genReport from "@/plugins/genreport";
import { useRoute } from "vue-router";
import { useCounterMixin } from "@/stores/mixin";
import { useEvaluateStore } from "@/modules/06_evaluate/store";
const $q = useQuasar();
const route = useRoute();
const store = useEvaluateStore();
const { showLoader, hideLoader, messageError, success } = useCounterMixin();
const formTemplates = ref<any[]>([
{
code: "EV1_005",
templateName: "template-1",
title: "แบบพิจารณาคุณสมบัติบุคคล (ฉบับแก้ไข)",
fileName: "1-แบบพิจารณาคุณสมบัติบุคคล (ฉบับแก้ไข)",
downloadFile: "",
file: null,
isLoading: false,
},
{
code: "EV1_006",
templateName: "template-2",
title: "แบบแสดงรายละเอียดการเสนอผลงาน (ฉบับแก้ไข)",
fileName: "2-แบบแสดงรายละเอียดการเสนอผลงาน (ฉบับแก้ไข)",
downloadFile: "",
file: null,
isLoading: false,
},
{
code: "EV1_008",
templateName: "template-4",
title: "แบบประเมินคุณลักษณะบุคคล (ฉบับแก้ไข)",
fileName: "4-แบบประเมินคุณลักษณะบุคคล (ฉบับแก้ไข)",
downloadFile: "",
file: null,
isLoading: false,
},
{
code: "EV1_010",
templateName: "template-6",
title: "ผลงานที่จะส่งประเมิน (เอกสารหมายเลข 11) (ฉบับแก้ไข)",
fileName: "6-ผลงานที่จะส่งประเมิน (เอกสารหมายเลข 11) (ฉบับแก้ไข)",
downloadFile: "",
file: null,
isLoading: false,
},
]);
const evaluateId = ref<string>(route.params.id.toString());
const status = ref<string>("WAIT_CHECK_DOC_V1"); const status = ref<string>("WAIT_CHECK_DOC_V1");
const profile = ref<any>();
const author = ref<string>("");
const subject = ref<string>("");
/**
* function
* @param id evaluate ID
*/
async function fetchCheckSpec(id: string) {
await http
.get(config.API.evaluationReportCheckspecByid(id))
.then((res) => {
const data = res.data.result;
profile.value = data;
})
.catch((err) => {
messageError($q, err);
});
}
/**
* function fecth รายชอผเซนเอกสาร
* @param id evaluate ID
*/
function fetcheSigner(id: string) {
http
.get(config.API.evaluationSignerDoc1(id))
.then((res) => {
const data = res.data.result;
author.value = data.author;
subject.value = data.subject;
})
.catch((err) => {
messageError($q, err);
});
}
/**
* funcion ดาวนโหลดไฟล
* @param tp templatname
* @param templateName
* @param fileName ไฟล
*/
async function onClickDowloadFile(
tp: string,
templateName: string,
fileName: string
) {
showLoader();
const body = {
template: tp,
reportName: templateName,
data: profile.value,
};
await genReport(body, fileName); //
hideLoader();
}
/**
* function fetch งกปโหลดไฟล
* @param volume เล
* @param id evaluate ID
* @param type ประเภทไฟล
* @param file ไฟล
*/
async function fetchPathUpload(
volume: string,
id: string | undefined,
type: string,
file: any
) {
const body = {
fileList: {
fileName: type,
metadata: {
subject: subject.value,
author: author.value,
},
},
};
if (id && file) {
showLoader();
await http
.post(config.API.loadPathDocument(volume, id), body)
.then(async (res) => {
const foundKey: string | undefined = Object.keys(res.data).find(
(key) =>
res.data[key]?.fileName !== undefined &&
res.data[key]?.fileName !== ""
);
foundKey && (await uploadfile(res.data[foundKey]?.uploadUrl, file));
await downloadFile(type);
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
}
/**
* functoin ปโหลดไฟล
* @param uploadUrl link ปโหลด
* @param file ไฟล
*/
async function uploadfile(uploadUrl: string, file: any) {
await axios
.put(uploadUrl, file, {
headers: {
"Content-Type": file.type,
},
})
.then(() => {
success($q, "อัปโหลไฟล์สำเร็จ");
})
.catch((err) => {
messageError($q, err);
});
}
/**
* function ดาวนโหลดไฟล
* @param fileName อไฟล
*/
async function downloadFile(fileName: string) {
const loadingKey = formTemplates.value.findIndex(
(item) => item.fileName === fileName
);
formTemplates.value[loadingKey].isLoading = true;
await http
.get(config.API.loadFileDocument("เล่ม 1", evaluateId.value, fileName))
.then((res) => {
const index = formTemplates.value.findIndex(
(item) => item.fileName === fileName
);
if (index !== -1) {
formTemplates.value[index].downloadFile = res.data.downloadUrl;
}
})
.finally(() => {
formTemplates.value[loadingKey].isLoading = false;
});
}
/**lifecycle Hooks*/
onMounted(async () => {
try {
await Promise.all([
fetcheSigner(evaluateId.value),
fetchCheckSpec(evaluateId.value),
formTemplates.value.forEach((e) => {
downloadFile(e.fileName);
}),
]);
} catch (error) {
console.log(error);
}
});
</script> </script>
<template> <template>
@ -15,6 +231,104 @@ const status = ref<string>("WAIT_CHECK_DOC_V1");
style="font-size: 16px" style="font-size: 16px"
/> />
</div> </div>
<div class="row q-col-gutter-sm q-pa-sm">
<div class="col-6" v-for="(item, index) in formTemplates" :key="index">
<q-skeleton
:height="store.currentStep !== 4 ? '50px' : '100px'"
v-if="item.isLoading"
/>
<q-card
v-else
bordered
class="cardSp1"
v-if="
(store.currentStep !== 4 &&
formTemplates.some((e) => e.downloadFile !== '')) ||
store.currentStep == 4
"
>
<div
class="text-weight-medium bg-grey-1 q-py-sm q-pl-md q-pr-sm col-12 row items-center"
>
<div>{{ item.title }}</div>
<q-space />
<!-- <div>
<q-btn
flat
dense
icon="download"
color="indigo"
@click="
onClickDowloadFile(item.code, item.templateName, item.title)
"
>
<q-tooltip> ดาวนโหลดตนแบบ </q-tooltip></q-btn
>
</div> -->
<div>
<q-btn
v-if="item.downloadFile != ''"
:href="item.downloadFile"
target="_blank"
class="q-ml-sm"
color="blue"
flat
dense
icon="visibility"
>
<q-tooltip> ไฟลเอกสาร </q-tooltip></q-btn
>
</div>
</div>
<div class="col-12"><q-separator /></div>
<div class="row" v-if="store.currentStep === 4">
<div class="col-12 q-pa-sm">
<div class="row q-col-gutter-md col-12">
<q-file
v-model="item.file"
class="col-xs-12 col-sm-12"
label="อัปโหลดไฟล์"
outlined
dense
lazy-rules
hide-bottom-space
accept=".pdf"
:rules="
item.downloadFile === ''
? [(val:any) => !!val || 'กรุณาเลือกไฟล์']
: []
"
>
<template v-slot:prepend>
<q-icon name="attach_file" />
</template>
<template v-slot:after>
<q-btn
:disable="!item.file"
flat
round
dense
color="primary"
icon="mdi-upload"
@click="
fetchPathUpload(
'เล่ม 1',
evaluateId,
item.fileName,
item.file
)
"
><q-tooltip>ปโหลดไฟล</q-tooltip></q-btn
>
</template>
</q-file>
</div>
</div>
</div>
</q-card>
</div>
</div>
</template> </template>
<style scoped></style> <style scoped></style>

View file

@ -12,7 +12,7 @@ import type { FileObject } from "@/modules/06_evaluate/interface/main";
const $q = useQuasar(); const $q = useQuasar();
const mixins = useCounterMixin(); const mixins = useCounterMixin();
const route = useRoute(); const route = useRoute();
const { date2Thai, success, showLoader, hideLoader } = mixins; const { date2Thai, success, showLoader, hideLoader, messageError } = mixins;
/** id ประเมิน*/ /** id ประเมิน*/
const evaluateId = ref<string>(route.params.id.toString()); const evaluateId = ref<string>(route.params.id.toString());
@ -20,6 +20,7 @@ const evaluateId = ref<string>(route.params.id.toString());
const dateStartAnnounce = ref<string | null>(date2Thai(new Date())); const dateStartAnnounce = ref<string | null>(date2Thai(new Date()));
const dateEndAnnounce = ref<string | null>(date2Thai(new Date())); const dateEndAnnounce = ref<string | null>(date2Thai(new Date()));
const statusFile = ref<boolean>(false); const statusFile = ref<boolean>(false);
const isLoading = ref<boolean>(false);
/** เอกสารประกาศผลการคัดเลือกบุคคล*/ /** เอกสารประกาศผลการคัดเลือกบุคคล*/
const items = ref<FileObject[]>([ const items = ref<FileObject[]>([
@ -44,22 +45,16 @@ const items = ref<FileObject[]>([
]); ]);
/** fuinction เรียกข้อมูลลิงก์ดาวนฺโหลด*/ /** fuinction เรียกข้อมูลลิงก์ดาวนฺโหลด*/
function onClickfetchDocument(fileName: string, type: string) { async function onClickfetchDocument(fileName: string, type: string) {
if (evaluateId.value) { if (evaluateId.value) {
showLoader(); await http
http
.get(config.API.loadFileDocument("เล่ม 1", evaluateId.value, fileName)) .get(config.API.loadFileDocument("เล่ม 1", evaluateId.value, fileName))
.then((res) => { .then((res) => {
const downloadUrl = res.data.downloadUrl; const downloadUrl = res.data.downloadUrl;
type === "COPPY" && coppyLink(downloadUrl); type === "COPPY" && coppyLink(downloadUrl);
type === "CHECK" && (statusFile.value = true); type === "CHECK" && (statusFile.value = true);
}) })
.catch(() => {}) .catch(() => {});
.finally(() => {
setTimeout(() => {
hideLoader();
}, 1500);
});
} }
} }
@ -71,9 +66,10 @@ async function coppyLink(link: string) {
} }
/** function เรียกข้อมูลวันที่ประกาศ*/ /** function เรียกข้อมูลวันที่ประกาศ*/
function fetchCheckDate() { async function fetchCheckDate() {
isLoading.value = true;
evaluateId.value && evaluateId.value &&
http (await http
.get(config.API.evaluationCheckDate(evaluateId.value)) .get(config.API.evaluationCheckDate(evaluateId.value))
.then((res) => { .then((res) => {
const data = res.data.result; const data = res.data.result;
@ -82,7 +78,12 @@ function fetchCheckDate() {
endDate.setDate(endDate.getDate() + 30); endDate.setDate(endDate.getDate() + 30);
dateEndAnnounce.value = date2Thai(endDate); dateEndAnnounce.value = date2Thai(endDate);
}) })
.catch(() => {}); .catch((err) => {
messageError($q, err);
})
.finally(() => {
isLoading.value = false;
}));
} }
/** Hook lifecycle*/ /** Hook lifecycle*/
@ -91,10 +92,12 @@ onMounted(async () => {
await onClickfetchDocument("บันทึกแจ้งผลการประกาศคัดเลือก", "CHECK"); await onClickfetchDocument("บันทึกแจ้งผลการประกาศคัดเลือก", "CHECK");
}); });
</script> </script>
`
<template> <template>
<div class="row col-12 q-pa-sm"> <div class="row col-12 q-pa-sm">
<div class="row col-12 q-col-gutter-sm"> <q-skeleton v-if="isLoading" style="width: 100%; height: 300px" />
<div v-else class="row col-12 q-col-gutter-sm">
<div class="col-12 text-center"> <div class="col-12 text-center">
<q-banner rounded class="text-weight-bold text-red-14 bg-red-1"> <q-banner rounded class="text-weight-bold text-red-14 bg-red-1">
<div class="text-weight-bold"> <div class="text-weight-bold">

View file

@ -29,41 +29,35 @@ const evaluateId = ref<string>(route.params.id.toString());
const emit = defineEmits(["update:form"]); const emit = defineEmits(["update:form"]);
const fileEvaluation1 = ref<any>(); const fileEvaluation1 = ref<any>();
const assignedPosLevel = ref<string>(""); //
/** form จัดเตรียมเอกสารเล่ม 2*/ /** form จัดเตรียมเอกสารเล่ม 2*/
const formCommand = reactive<FormCommand>({ const formCommand = reactive<FormCommand>({
commanderFullname: "", commanderFullname: "",
commanderPosition: "", commanderPosition: "",
commanderPositionOld: "",
commanderOrg: "",
commanderOrgOld: "",
commanderAboveFullname: "", commanderAboveFullname: "",
commanderAbovePosition: "", commanderAbovePosition: "",
commanderAbovePositionOld: "",
commanderAboveOrgOld: "",
commanderAboveOrg: "",
author: "", author: "",
subject: "", subject: [""],
assignedPosition: "", assignedPosition: "",
}); });
/** ref input*/
const commanderFullnameRef = ref<object | null>(null);
const commanderPositionRef = ref<object | null>(null);
const commanderAboveFullnameRef = ref<object | null>(null);
const commanderAbovePositionRef = ref<object | null>(null);
const fileEvaluation1Ref = ref<object | null>(null);
const performanceRef = ref<object | null>(null);
const performanceOwnerRef = ref<object | null>(null);
const assignedPositionRef = ref<object | null>(null);
const modalView = ref<boolean>(false); const modalView = ref<boolean>(false);
const isLoading = ref<boolean>(false); //
const isLoadingFile = ref<boolean>(false);
const isLoadingDate = ref<boolean>(false);
/** function อัปเดท ผลงาน,ผู้เซ็นเอกสาร*/ /** function อัปเดท ผลงาน,ผู้เซ็นเอกสาร*/
function updateInput(value: any) { function updateInput(value: any) {
const ref = { const ref = {
commanderFullnameRef: commanderFullnameRef.value,
commanderPositionRef: commanderPositionRef.value,
commanderAboveFullnameRef: commanderAboveFullnameRef.value,
commanderAbovePositionRef: commanderAbovePositionRef.value,
fileEvaluation1Ref: fileEvaluation1Ref.value,
downloadFile: [downloadUrl.value], downloadFile: [downloadUrl.value],
performance: performanceRef.value,
performanceOwner: performanceOwnerRef.value,
assignedPosition: assignedPositionRef.value,
}; };
emit("update:form", value, ref); emit("update:form", value, ref);
} }
@ -95,16 +89,18 @@ async function fetchPathUpload(
showLoader(); showLoader();
await http await http
.post(config.API.loadPathDocument(volume, id), body) .post(config.API.loadPathDocument(volume, id), body)
.then((res) => { .then(async (res) => {
const foundKey: string | undefined = Object.keys(res.data).find( const foundKey: string | undefined = Object.keys(res.data).find(
(key) => (key) =>
res.data[key]?.fileName !== undefined && res.data[key]?.fileName !== undefined &&
res.data[key]?.fileName !== "" res.data[key]?.fileName !== ""
); );
foundKey && uploadfile(res.data[foundKey]?.uploadUrl, file); foundKey && (await uploadfile(res.data[foundKey]?.uploadUrl, file));
}) })
.catch((err) => { .catch((err) => {
messageError($q, err); messageError($q, err);
})
.finally(() => {
hideLoader(); hideLoader();
}); });
} }
@ -139,90 +135,85 @@ async function uploadfile(uploadUrl: string, file: any) {
* @param id ประเม * @param id ประเม
*/ */
async function fetcheSigner(id: string) { async function fetcheSigner(id: string) {
showLoader(); isLoading.value = true;
await http await http
.get(config.API.evaluationSignerDoc2(id)) .get(config.API.evaluationSignerDoc2(id))
.then((res) => { .then((res) => {
const data = res.data.result; const data = res.data.result;
formCommand.commanderFullname = data.commanderFullnameDoc2; formCommand.commanderFullname = data.commanderFullnameDoc2;
formCommand.commanderPosition = data.commanderPositionDoc2; formCommand.commanderPosition = data.commanderPositionDoc2;
formCommand.commanderPositionOld = data.commanderPositionOldDoc2;
formCommand.commanderOrg = data.commanderOrgDoc2;
formCommand.commanderOrgOld = data.commanderOrgOldDoc2;
formCommand.commanderAboveFullname = data.commanderAboveFullnameDoc2; formCommand.commanderAboveFullname = data.commanderAboveFullnameDoc2;
formCommand.commanderAbovePosition = data.commanderAbovePositionDoc2; formCommand.commanderAbovePosition = data.commanderAbovePositionDoc2;
formCommand.commanderAbovePositionOld =
data.commanderAbovePositionOldDoc2;
formCommand.commanderAboveOrgOld = data.commanderAboveOrgOldDoc2;
formCommand.commanderAboveOrg = data.commanderAboveOrgDoc2;
formCommand.author = data.authorDoc2; formCommand.author = data.authorDoc2;
formCommand.subject = data.subjectDoc2; formCommand.subject = data.subjectDoc2;
formCommand.assignedPosition = data.assignedPosition; formCommand.assignedPosition = data.assignedPosition;
assignedPosLevel.value = data.assignedPosLevel;
store.statusUpload6 = data.commanderFullnameDoc2 === null ? false : true; store.statusUpload6 = data.isUpdated;
}) })
.catch(() => { .catch((err) => {
store.statusUpload6 = false; messageError($q, err);
getCommander();
}) })
.finally(() => { .finally(() => {
hideLoader(); isLoading.value = false;
}); });
} }
const dateEndPrepareDoc2 = ref<string | null>(date2Thai(new Date())); const dateEndPrepareDoc2 = ref<string | null>(date2Thai(new Date()));
/** functoin เรียกข้อมูลวันสุดท้ายของการส่งผลงาน*/ /** functoin เรียกข้อมูลวันสุดท้ายของการส่งผลงาน*/
async function fetchCheckDate() { async function fetchCheckDate() {
evaluateId.value && if (!evaluateId.value) return;
(await http isLoadingDate.value = true;
.get(config.API.evaluationCheckDate(evaluateId.value)) await http
.then((res) => { .get(config.API.evaluationCheckDate(evaluateId.value))
const data = res.data.result; .then((res) => {
const data = res.data.result;
const endDate = new Date(data.dateEndAnnounce); const endDate = new Date(data.dateEndAnnounce);
endDate.setDate(endDate.getDate() + 180); endDate.setDate(endDate.getDate() + 180);
dateEndPrepareDoc2.value = date2Thai(endDate); dateEndPrepareDoc2.value = date2Thai(endDate);
}) })
.catch((err) => {})); .catch((err) => {
messageError($q, err);
})
.finally(() => {
isLoadingDate.value = false;
});
} }
const downloadUrl = ref<string>(""); const downloadUrl = ref<string>("");
/** function เช็คไฟล์อัปโหลด*/ /** function เช็คไฟล์อัปโหลด*/
function checkDoc() { async function checkDoc() {
// showLoader(); isLoadingFile.value = true;
http await http
.get( .get(
config.API.loadFileDocument("เล่ม 2", evaluateId.value, "1-เอกสารเล่ม 2") config.API.loadFileDocument("เล่ม 2", evaluateId.value, "1-เอกสารเล่ม 2")
) )
.then((res: any) => { .then((res: any) => {
downloadUrl.value = res.data.downloadUrl; downloadUrl.value = res.data.downloadUrl;
}) })
.catch(() => {})
.finally(() => { .finally(() => {
// hideLoader();
const ref = { const ref = {
commanderFullnameRef: commanderFullnameRef.value,
commanderPositionRef: commanderPositionRef.value,
commanderAboveFullnameRef: commanderAboveFullnameRef.value,
commanderAbovePositionRef: commanderAbovePositionRef.value,
fileEvaluation1Ref: fileEvaluation1Ref.value,
downloadFile: [downloadUrl.value], downloadFile: [downloadUrl.value],
performance: performanceRef.value,
performanceOwner: performanceOwnerRef.value,
assignedPosition: assignedPositionRef.value,
}; };
emit("update:form", formCommand, ref); emit("update:form", formCommand, ref);
isLoadingFile.value = false;
}); });
} }
function getCommander() { function onAddSubject() {
http formCommand.subject.push("");
.get(config.API.searchCommander) }
.then((res) => {
const data = res.data.result; function onDeleteSubject(index: number) {
formCommand.commanderFullname = data.commanderFullname; formCommand.subject.splice(index, 1);
formCommand.commanderPosition = data.commanderPosition;
formCommand.commanderAboveFullname = data.commanderAboveFullname;
formCommand.commanderAbovePosition = data.commanderAbovePosition;
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {});
} }
watch( watch(
@ -258,9 +249,10 @@ onMounted(async () => {
<template> <template>
<div class="row col-12 q-pa-sm"> <div class="row col-12 q-pa-sm">
<div class="row q-col-gutter-sm"> <div class="row col-12 q-col-gutter-sm">
<div class="col-12 text-center"> <div class="col-12 text-center">
<q-banner rounded class="text-weight-bold text-red-14 bg-red-1"> <q-skeleton v-if="isLoadingDate" height="50px" />
<q-banner v-else rounded class="text-weight-bold text-red-14 bg-red-1">
<div class="text-weight-bold"> <div class="text-weight-bold">
<q-icon name="info_outline" color="red-14" size="24px" /> <q-icon name="info_outline" color="red-14" size="24px" />
นสดทายของการสงผลงานคอวนท {{ dateEndPrepareDoc2 }} นสดทายของการสงผลงานคอวนท {{ dateEndPrepareDoc2 }}
@ -270,30 +262,22 @@ onMounted(async () => {
<!-- ผลงาน --> <!-- ผลงาน -->
<div class="col-12"> <div class="col-12">
<q-card bordered class="shadow-0" style="border: 1px solid #d6dee1"> <q-skeleton v-if="isLoading" height="200px" width="100%" />
<q-card
v-else
bordered
class="shadow-0"
style="border: 1px solid #d6dee1"
>
<div class="text-weight-medium bg-grey-1 q-py-sm q-px-md">ผลงาน</div> <div class="text-weight-medium bg-grey-1 q-py-sm q-px-md">ผลงาน</div>
<div class="col-12"><q-separator /></div> <div class="col-12"><q-separator /></div>
<div class="col-12"> <div class="col-12 q-pa-sm">
<div class="row q-col-gutter-sm col-12"> <div class="row q-col-gutter-sm">
<div class="col-xs-12 col-sm-12 row"> <div class="col-12 row q-col-gutter-sm">
<div class="row col-12 q-col-gutter-sm q-pa-sm"> <div class="col-6">
<q-input <q-input
:readonly="store.currentStep != 6" :readonly="store.currentStep != 6 || store.statusUpload6"
ref="performanceRef"
dense
class="col-xs-12 col-sm-6"
outlined
label="ชื่อผลงาน"
v-model="formCommand.subject"
@update:model-value="updateInput(formCommand)"
:rules="[(val:string) => !!val || `${'กรุณากรอกชื่อผลงาน'}`]"
hide-bottom-space
lazy-rules
/>
<q-input
:readonly="store.currentStep != 6"
ref="performanceOwnerRef"
class="col-xs-12 col-sm-6"
dense dense
outlined outlined
v-model="formCommand.author" v-model="formCommand.author"
@ -303,9 +287,10 @@ onMounted(async () => {
:rules="[(val:string) => !!val || `${'กรุณากรอกเจ้าของผลงาน'}`]" :rules="[(val:string) => !!val || `${'กรุณากรอกเจ้าของผลงาน'}`]"
lazy-rules lazy-rules
/> />
</div>
<div class="col-3">
<q-input <q-input
:readonly="store.currentStep != 6" :readonly="store.currentStep != 6 || store.statusUpload6"
ref="assignedPositionRef"
class="col-xs-12 col-sm-6" class="col-xs-12 col-sm-6"
dense dense
outlined outlined
@ -314,11 +299,72 @@ onMounted(async () => {
label="ตำแหน่งที่ได้รับ" label="ตำแหน่งที่ได้รับ"
hide-bottom-space hide-bottom-space
:rules="[ :rules="[
(val:string) => !!val || `${'กรุณากรอกตำแหน่งที่ได้รับ'}`, (val:string) => !!val || `${'กรุณากรอกตำแหน่งที่ได้รับ'}`,
]" ]"
lazy-rules lazy-rules
/> />
</div> </div>
<div class="col-3">
<q-input
readonly
class="col-xs-12 col-sm-6"
dense
outlined
v-model="assignedPosLevel"
label="ระดับตำแหน่งที่ได้รับ"
hide-bottom-space
/>
</div>
</div>
<div
class="col-12"
v-if="store.currentStep === 6 && !store.statusUpload6"
>
<q-btn
flat
round
color="primary"
icon="add"
@click="onAddSubject"
>
<q-tooltip>เพมชอผลงาน</q-tooltip>
</q-btn>
</div>
<div
class="row col-12 q-col-gutter-sm"
v-for="(item, index) in formCommand.subject"
:key="index"
>
<div class="col-11">
<q-input
:readonly="store.currentStep != 6 || store.statusUpload6"
dense
outlined
label="ชื่อผลงาน"
v-model="formCommand.subject[index]"
@update:model-value="updateInput(formCommand)"
:rules="[(val:string) => !!val || `${'กรุณากรอกชื่อผลงาน'}`]"
hide-bottom-space
lazy-rules
/>
</div>
<div
class="row col-1 items-centet justify-center"
v-if="index !== 0"
>
<q-btn
v-if="store.currentStep === 6 && !store.statusUpload6"
flat
round
color="red"
icon="delete"
@click="onDeleteSubject(index)"
>
<q-tooltip>ลบ</q-tooltip>
</q-btn>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -327,7 +373,13 @@ onMounted(async () => {
<!-- เลอกผเซนเอกสาร --> <!-- เลอกผเซนเอกสาร -->
<div class="col-12"> <div class="col-12">
<q-card bordered class="shadow-0" style="border: 1px solid #d6dee1"> <q-skeleton v-if="isLoading" height="200px" width="100%" />
<q-card
v-else
bordered
class="shadow-0"
style="border: 1px solid #d6dee1"
>
<div class="text-weight-medium bg-grey-1 q-py-sm q-px-md"> <div class="text-weight-medium bg-grey-1 q-py-sm q-px-md">
เลอกผเซนเอกสาร เลอกผเซนเอกสาร
</div> </div>
@ -340,8 +392,7 @@ onMounted(async () => {
</div> </div>
<div class="row col-12 q-col-gutter-sm q-pa-sm"> <div class="row col-12 q-col-gutter-sm q-pa-sm">
<q-input <q-input
:readonly="store.currentStep != 6" :readonly="store.currentStep != 6 || store.statusUpload6"
ref="commanderFullnameRef"
dense dense
class="col-xs-12 col-sm-6" class="col-xs-12 col-sm-6"
outlined outlined
@ -352,19 +403,63 @@ onMounted(async () => {
lazy-rules lazy-rules
hide-bottom-space hide-bottom-space
/> />
<q-input <div class="col-12">
:readonly="store.currentStep != 6" <div class="row col-12 q-col-gutter-sm">
ref="commanderPositionRef" <q-input
class="col-xs-12 col-sm-6" :readonly="
dense store.currentStep != 6 || store.statusUpload6
outlined "
v-model="formCommand.commanderPosition" class="col-xs-6 col-sm-6"
@update:model-value="updateInput(formCommand)" dense
label="ตำแหน่ง" outlined
:rules="[(val:string) => !!val || `${'กรุณากรอกตำแหน่ง'}`]" v-model="formCommand.commanderPosition"
lazy-rules @update:model-value="updateInput(formCommand)"
hide-bottom-space label="ตำแหน่ง"
/> :rules="[(val:string) => !!val || `${'กรุณากรอกตำแหน่ง'}`]"
lazy-rules
hide-bottom-space
/>
<q-input
:readonly="
store.currentStep != 6 || store.statusUpload6
"
class="col-xs-6 col-sm-6"
dense
outlined
v-model="formCommand.commanderOrg"
@update:model-value="updateInput(formCommand)"
label="สังกัด"
:rules="[(val:string) => !!val || `${'กรุณากรอกสังกัด'}`]"
lazy-rules
hide-bottom-space
/>
<q-input
:readonly="
store.currentStep != 6 || store.statusUpload6
"
class="col-xs-6 col-sm-6"
dense
outlined
v-model="formCommand.commanderPositionOld"
@update:model-value="updateInput(formCommand)"
label="ตำแหน่งเดิม"
hide-bottom-space
/>
<q-input
:readonly="
store.currentStep != 6 || store.statusUpload6
"
class="col-xs-6 col-sm-6"
dense
outlined
v-model="formCommand.commanderOrgOld"
@update:model-value="updateInput(formCommand)"
label="สังกัดเดิม"
hide-bottom-space
/>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -376,8 +471,7 @@ onMounted(async () => {
</div> </div>
<div class="row col-12 q-col-gutter-sm q-pa-sm"> <div class="row col-12 q-col-gutter-sm q-pa-sm">
<q-input <q-input
:readonly="store.currentStep != 6" :readonly="store.currentStep != 6 || store.statusUpload6"
ref="commanderAboveFullnameRef"
dense dense
class="col-xs-12 col-sm-6" class="col-xs-12 col-sm-6"
outlined outlined
@ -388,19 +482,63 @@ onMounted(async () => {
@update:model-value="updateInput(formCommand)" @update:model-value="updateInput(formCommand)"
hide-bottom-space hide-bottom-space
/> />
<q-input
:readonly="store.currentStep != 6" <div class="col-12">
ref="commanderAbovePositionRef" <div class="row col-12 q-col-gutter-sm">
class="col-xs-12 col-sm-6" <q-input
dense :readonly="
outlined store.currentStep != 6 || store.statusUpload6
v-model="formCommand.commanderAbovePosition" "
label="ตำแหน่ง" class="col-xs-6 col-sm-6"
:rules="[(val:string) => !!val || `${'กรุณากรอกตำแหน่ง'}`]" dense
lazy-rules outlined
@update:model-value="updateInput(formCommand)" v-model="formCommand.commanderAbovePosition"
hide-bottom-space label="ตำแหน่ง"
/> :rules="[(val:string) => !!val || `${'กรุณากรอกตำแหน่ง'}`]"
lazy-rules
@update:model-value="updateInput(formCommand)"
hide-bottom-space
/>
<q-input
:readonly="
store.currentStep != 6 || store.statusUpload6
"
class="col-xs-6 col-sm-6"
dense
outlined
v-model="formCommand.commanderAboveOrg"
label="สังกัด"
:rules="[(val:string) => !!val || `${'กรุณากรอกสังกัด'}`]"
lazy-rules
hide-bottom-space
@update:model-value="updateInput(formCommand)"
/>
<q-input
:readonly="
store.currentStep != 6 || store.statusUpload6
"
class="col-xs-6 col-sm-6"
dense
outlined
v-model="formCommand.commanderAbovePositionOld"
label="ตำแหน่งเดิม"
hide-bottom-space
@update:model-value="updateInput(formCommand)"
/>
<q-input
:readonly="
store.currentStep != 6 || store.statusUpload6
"
class="col-xs-6 col-sm-6"
dense
outlined
v-model="formCommand.commanderAboveOrgOld"
label="สังกัดเดิม"
hide-bottom-space
@update:model-value="updateInput(formCommand)"
/>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -410,7 +548,13 @@ onMounted(async () => {
<!-- ปไฟล --> <!-- ปไฟล -->
<div class="col-12" v-if="store.currentStep === 6"> <div class="col-12" v-if="store.currentStep === 6">
<q-card bordered class="shadow-0" style="border: 1px solid #d6dee1"> <q-skeleton height="100px" v-if="isLoadingFile" />
<q-card
v-else
bordered
class="shadow-0"
style="border: 1px solid #d6dee1"
>
<div class="col-12 row bg-grey-1"> <div class="col-12 row bg-grey-1">
<div class="text-weight-medium q-py-sm q-px-md">เอกสารเล 2</div> <div class="text-weight-medium q-py-sm q-px-md">เอกสารเล 2</div>
<q-space /> <q-space />
@ -434,7 +578,6 @@ onMounted(async () => {
<div class="col-12"> <div class="col-12">
<q-file <q-file
:disable="!store.statusUpload6" :disable="!store.statusUpload6"
ref="fileEvaluation1Ref"
v-model="fileEvaluation1" v-model="fileEvaluation1"
class="col-12" class="col-12"
outlined outlined

View file

@ -13,7 +13,7 @@ import { useCounterMixin } from "@/stores/mixin";
const $q = useQuasar(); const $q = useQuasar();
const mixin = useCounterMixin(); const mixin = useCounterMixin();
const route = useRoute(); const route = useRoute();
const { showLoader, hideLoader, messageError } = mixin; const { messageError } = mixin;
/** emit*/ /** emit*/
const emit = defineEmits(["update:file"]); const emit = defineEmits(["update:file"]);
@ -22,25 +22,25 @@ const emit = defineEmits(["update:file"]);
const evaluateId = ref<string>(route.params.id.toString()); const evaluateId = ref<string>(route.params.id.toString());
const selectedItem = ref(1); const selectedItem = ref(1);
const isLoading = ref(false);
/** function เรีกยเอกสาร*/ /** function เรีกยเอกสาร*/
async function fetchDocument() { async function fetchDocument() {
showLoader(); if (!evaluateId.value) return;
evaluateId.value && isLoading.value = true;
(await http await http
.get( .get(
config.API.loadFileDocument( config.API.loadFileDocument("เล่ม 2", evaluateId.value, "1-เอกสารเล่ม 2")
"เล่ม 2", )
evaluateId.value, .then(async (res) => {
"1-เอกสารเล่ม 2" await downloadFile(res.data.downloadUrl);
) })
) .catch((err) => {
.then((res) => { messageError($q, err);
downloadFile(res.data.downloadUrl); })
}) .finally(() => {
.catch((err) => { isLoading.value = false;
messageError($q, err); });
}));
} }
/** /**
@ -63,9 +63,6 @@ async function downloadFile(url: string) {
}) })
.catch((err) => { .catch((err) => {
messageError($q, err); messageError($q, err);
})
.finally(() => {
hideLoader();
}); });
} }
@ -84,7 +81,9 @@ onMounted(async () => {
active-class="text-primary" active-class="text-primary"
class="cursor-pointer" class="cursor-pointer"
> >
<q-item-section>เอกสารเล 2</q-item-section> <q-skeleton v-if="isLoading" type="text" width="100%" />
<q-item-section v-else>เอกสารเล่ม 2</q-item-section>
</q-item> </q-item>
</q-list> </q-list>
</template> </template>

View file

@ -69,20 +69,20 @@ async function fetchPathUpload(
showLoader(); showLoader();
await http await http
.post(config.API.loadPathDocument(volume, id), body) .post(config.API.loadPathDocument(volume, id), body)
.then((res) => { .then(async (res) => {
const foundKey: string | undefined = Object.keys(res.data).find( const foundKey: string | undefined = Object.keys(res.data).find(
(key) => (key) =>
res.data[key]?.fileName !== undefined && res.data[key]?.fileName !== undefined &&
res.data[key]?.fileName !== "" res.data[key]?.fileName !== ""
); );
foundKey && uploadfile(res.data[foundKey]?.uploadUrl, file); foundKey && (await uploadfile(res.data[foundKey]?.uploadUrl, file));
}) })
.catch((err) => { .catch((err) => {
messageError($q, err); messageError($q, err);
})
.finally(() => {
hideLoader(); hideLoader();
}); });
// .finally(() => {
// });
} }
} }
@ -103,17 +103,15 @@ async function uploadfile(uploadUrl: string, file: any) {
}) })
.catch((err) => { .catch((err) => {
messageError($q, err); messageError($q, err);
})
.finally(() => {
hideLoader();
}); });
} }
const downloadUrl = ref<string>(""); const downloadUrl = ref<string>("");
const isLoadingFile = ref<boolean>(false);
/** function เช็คไฟล์อัปโหลด*/ /** function เช็คไฟล์อัปโหลด*/
function checkDoc() { async function checkDoc() {
showLoader(); isLoadingFile.value = true;
http await http
.get( .get(
config.API.loadFileDocument( config.API.loadFileDocument(
"เล่ม 2", "เล่ม 2",
@ -124,11 +122,8 @@ function checkDoc() {
.then((res: any) => { .then((res: any) => {
downloadUrl.value = res.data.downloadUrl; downloadUrl.value = res.data.downloadUrl;
}) })
.catch((e) => {
// messageError($q, e);
})
.finally(() => { .finally(() => {
hideLoader(); isLoadingFile.value = false;
}); });
} }
@ -141,7 +136,6 @@ const assignedPosition = ref<string>("");
* @param id ประเม * @param id ประเม
*/ */
async function fetcheSigner(id: string) { async function fetcheSigner(id: string) {
showLoader();
await http await http
.get(config.API.evaluationSignerDoc2(id)) .get(config.API.evaluationSignerDoc2(id))
.then((res) => { .then((res) => {
@ -151,16 +145,18 @@ async function fetcheSigner(id: string) {
assignedPosition.value = data.assignedPosition; assignedPosition.value = data.assignedPosition;
evaluationResult.value = data.evaluationResult; evaluationResult.value = data.evaluationResult;
}) })
.catch(() => {}) .catch((err) => {
.finally(() => { messageError($q, err);
hideLoader();
}); });
} }
/** lifecycleHook*/ /** lifecycleHook*/
onMounted(async () => { onMounted(async () => {
await checkDoc(); try {
await fetcheSigner(evaluateId.value); await Promise.all([checkDoc(), fetcheSigner(evaluateId.value)]);
} catch (error) {
console.log(error);
}
}); });
</script> </script>
@ -178,8 +174,17 @@ onMounted(async () => {
/> />
</div> </div>
<div class="col-12"> <div
<q-card class="shadow-0" bordered> class="col-12"
v-if="
(store.currentStep !== 8 && downloadUrl) || store.currentStep == 8
"
>
<q-skeleton
:height="store.currentStep !== 8 ? '50px' : '100px'"
v-if="isLoadingFile"
/>
<q-card v-else class="shadow-0" bordered>
<div class="row col-12 bg-grey-1 q-px-sm q-py-xs items-center"> <div class="row col-12 bg-grey-1 q-px-sm q-py-xs items-center">
<div class="text-weight-medium">เอกสารเล 2 (ฉบบแกไข)</div> <div class="text-weight-medium">เอกสารเล 2 (ฉบบแกไข)</div>
<q-space /> <q-space />

View file

@ -13,7 +13,9 @@ import HeaderDialog from "@/components/DialogHeader.vue";
const $q = useQuasar(); const $q = useQuasar();
const route = useRoute(); const route = useRoute();
const mixins = useCounterMixin(); const mixins = useCounterMixin();
const { showLoader, hideLoader, date2Thai, messageError } = mixins; const { date2Thai, messageError } = mixins;
const isLoading = ref<boolean>(false);
const evaluateId = computed(() => { const evaluateId = computed(() => {
const id = route.params.id ? route.params.id.toString() : ""; const id = route.params.id ? route.params.id.toString() : "";
@ -73,7 +75,7 @@ const columns = ref<QTableProps["columns"]>([
style: "font-size: 14px", style: "font-size: 14px",
}, },
]); ]);
const row = ref<any>(); const row = ref<any[]>([]);
/** /**
* function เรยกขอมลประวการประเม * function เรยกขอมลประวการประเม
@ -85,7 +87,7 @@ async function fetchListHistory(id: string) {
minute: "2-digit", minute: "2-digit",
second: "2-digit", second: "2-digit",
}; };
showLoader(); isLoading.value = true;
await http await http
.get(config.API.evaluationHistory(id)) .get(config.API.evaluationHistory(id))
.then((res) => { .then((res) => {
@ -104,7 +106,7 @@ async function fetchListHistory(id: string) {
messageError($q, err); messageError($q, err);
}) })
.finally(() => { .finally(() => {
hideLoader(); isLoading.value = false;
}); });
} }
@ -124,7 +126,7 @@ watch(
<q-card-section> <q-card-section>
<div class="col-xs-12 col-sm-12 col-md-12 row q-col-gutter-md"> <div class="col-xs-12 col-sm-12 col-md-12 row q-col-gutter-md">
<div class="col-12"> <div class="col-12">
<q-table <d-table
ref="table" ref="table"
flat flat
bordered bordered
@ -133,6 +135,8 @@ watch(
:rows="row" :rows="row"
dense dense
:rows-per-page-options="[10, 25, 50, 100]" :rows-per-page-options="[10, 25, 50, 100]"
:pagination="{ page: 1, rowsPerPage: 10 }"
:loading="isLoading"
> >
<template v-slot:header="props"> <template v-slot:header="props">
<q-tr :props="props"> <q-tr :props="props">
@ -161,7 +165,7 @@ watch(
</q-td> </q-td>
</q-tr> </q-tr>
</template> </template>
</q-table> </d-table>
</div> </div>
</div> </div>
</q-card-section> </q-card-section>
@ -169,31 +173,4 @@ watch(
</q-dialog> </q-dialog>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped></style>
.custom-header-table {
height: auto;
.q-table tr:nth-child(odd) td {
background: white;
}
.q-table tr:nth-child(even) td {
background: #f8f8f8;
}
.q-table thead tr {
background: #ecebeb;
}
.q-table thead tr th {
position: sticky;
z-index: 1;
}
/* this will be the loading indicator */
.q-table thead tr:last-child th {
/* height of all previous header rows */
top: 48px;
}
.q-table thead tr:first-child th {
top: 0;
}
}
</style>

View file

@ -8,6 +8,10 @@ const props = defineProps({
type: Array as () => any[], type: Array as () => any[],
require: true, require: true,
}, },
isLoading: {
type: Boolean,
default: false,
},
}); });
</script> </script>
@ -24,6 +28,9 @@ const props = defineProps({
virtual-scroll virtual-scroll
class="row col-12" class="row col-12"
:style="$q.screen.lt.sm ? 'width: 80vw' : 'width: 50vw;'" :style="$q.screen.lt.sm ? 'width: 80vw' : 'width: 50vw;'"
:pagination="{ page: 1, rowsPerPage: 10 }"
:loading="isLoading"
row-key="id"
> >
<template v-slot:header="props"> <template v-slot:header="props">
<q-tr :props="props" class="bg-grey-2"> <q-tr :props="props" class="bg-grey-2">
@ -46,30 +53,4 @@ const props = defineProps({
</div> </div>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped></style>
.custom-header-table {
height: auto;
.q-table tr:nth-child(odd) td {
background: white;
}
.q-table tr:nth-child(even) td {
background: #f8f8f8;
}
.q-table thead tr {
background: #ecebeb;
}
.q-table thead tr th {
position: sticky;
}
/* this will be the loading indicator */
.q-table thead tr:last-child th {
/* height of all previous header rows */
top: 48px;
}
.q-table thead tr:first-child th {
top: 0;
}
}
</style>

View file

@ -1,5 +1,6 @@
div
<script setup lang="ts"> <script setup lang="ts">
import { reactive, onMounted } from "vue"; import { reactive, onMounted, ref } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { useQuasar } from "quasar"; import { useQuasar } from "quasar";
@ -7,8 +8,11 @@ import http from "@/plugins/http";
import config from "@/app.config"; import config from "@/app.config";
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
import { useEvaluateDetailStore } from "@/modules/06_evaluate/stores/evaluteDetail"; import { useEvaluateDetailStore } from "@/modules/06_evaluate/stores/evaluteDetail";
import { useEvaluateStore } from "@/modules/06_evaluate/store";
import { useDataStore } from "@/stores/data";
/** importType*/ /** importType*/
import type { DataProfile } from "@/interface/Main";
import type { import type {
EducationForm, EducationForm,
CertificatesForm, CertificatesForm,
@ -16,18 +20,21 @@ import type {
/** importComponents*/ /** importComponents*/
import TableData from "@/modules/06_evaluate/components/viewstep/tableStep1.vue"; import TableData from "@/modules/06_evaluate/components/viewstep/tableStep1.vue";
import HeaderDialog from "@/components/DialogHeader.vue";
/** use*/ /** use*/
const mixin = useCounterMixin(); const mixin = useCounterMixin();
const store = useEvaluateDetailStore(); const store = useEvaluateDetailStore();
const storeEva = useEvaluateStore();
const storeData = useDataStore();
const $q = useQuasar(); const $q = useQuasar();
const route = useRoute(); const route = useRoute();
const { showLoader, hideLoader, messageError, date2Thai } = mixin; const { messageError, date2Thai, findOrgNameHtml } = mixin;
const { const {
columnsCertificates, columnsCertificates,
columnSalaries, columnSalaries,
columnTraining, columnTraining,
columnProjectsProposed, columnExperience,
columnAssessments, columnAssessments,
} = store; } = store;
@ -57,97 +64,169 @@ const formDetail = reactive<any>({
month: 0, month: 0,
day: 0, day: 0,
}, },
posExecutive: "",
positionArea: "",
educations: [] as EducationForm[], educations: [] as EducationForm[],
certificates: [], certificates: [],
salaries: [], salaries: [],
trainings: [], trainings: [],
assessments: [], assessments: [],
experience: [],
honor: [], honor: [],
}); });
const isLoading = reactive({
loadDetail: false,
loadEducation: false,
loadCertificate: false,
loadSalary: false,
loadTraining: false,
loadAssessment: false,
loadExperience: false,
});
/** function เรียกข้อมูลตรวจสอบคุณสมบัติ*/ /** function เรียกข้อมูลตรวจสอบคุณสมบัติ*/
async function fetchDetail() { async function fetchDetail() {
showLoader(); isLoading.loadDetail = true;
await http try {
.get(config.API.positionBykeycloak()) if (!storeData.dataprofilePosition) {
const res = await http.get(config.API.profilePosition());
await updateFormDetail(res.data.result);
} else {
await updateFormDetail(storeData.dataprofilePosition);
}
} catch (error) {
messageError($q, error);
} finally {
isLoading.loadDetail = false;
}
}
async function updateFormDetail(data: DataProfile) {
formDetail.root = data.root;
formDetail.rootId = data.rootId;
formDetail.userId = data.profileId;
formDetail.citizenId = data.citizenId;
formDetail.prefix = data.prefix;
formDetail.fullName = `${data.firstName} ${data.lastName}`;
formDetail.firstName = data.firstName;
formDetail.lastName = data.lastName;
formDetail.position = data.position;
formDetail.oc = data.rootShortName;
formDetail.positionLevel = data.posLevelName;
formDetail.posNo = data.posNo ?? "";
formDetail.birthDate = data.birthDate;
// formDetail.govAge = data.govAge; //
formDetail.salary = data.salary;
formDetail.posExecutive = data.posExecutiveName;
formDetail.positionArea = data.positionArea;
await fetchDataAllDetail();
emit("update:formDeital", formDetail);
}
async function fetchDataAllDetail() {
//
isLoading.loadEducation = true;
http
.get(config.API.dataUserEducations)
.then((res) => { .then((res) => {
const data = res.data.result; formDetail.educations = res.data.result;
formDetail.root = data.root;
formDetail.rootId = data.rootId;
formDetail.userId = data.id;
formDetail.citizenId = data.citizenId;
formDetail.prefix = data.prefix;
formDetail.fullName = `${data.firstName} ${data.lastName}`;
formDetail.firstName = data.firstName;
formDetail.lastName = data.lastName;
formDetail.position = data.position;
formDetail.oc = data.rootShortName;
formDetail.positionLevel = data.posLevelName;
formDetail.posNo = data.posNo ?? "";
formDetail.birthDate = data.birthDate;
formDetail.govAge = data.govAge; //
formDetail.salary = data.salary;
http.get(config.API.dataUserEducations).then((res) => {
formDetail.educations = res.data.result;
});
http.get(config.API.dataUserCertificate("certificate")).then((res) => {
formDetail.certificates = res.data.result.map(
(e: CertificatesForm) => ({
certificateNo: e.certificateNo,
certificateType: e.certificateType,
expireDate: e.expireDate,
issueDate: e.issueDate,
issuer: e.issuer,
})
);
});
http.get(config.API.dataUserSalary).then((res) => {
formDetail.salaries = res.data.result;
// formDetail.salary = formDetail.salaries
// ? formattedNumber(
// formDetail.salaries[formDetail.salaries.length - 1].amount
// )
// : "";
});
http.get(config.API.dataUserCertificate("training")).then((res) => {
formDetail.trainings = res.data.result.map((e: any) => ({
dateOrder: e.dateOrder,
department: e.department,
duration: e.duration,
endDate: e.endDate,
name: e.name,
numberOrder: e.numberOrder,
place: e.place,
startDate: e.startDate,
topic: e.topic,
yearly: e.yearly,
}));
});
http.get(config.API.dataUserAssessments).then((res) => {
// formDetail.honor = res.data.result
// res.data.result.map((e: any) => ({
// receivedDate: e.createdAt,
// authority: e.issuer,
// detail: e.detail,
// orderNumber: e.refCommandNo,
// doce: e.refCommandDate,
formDetail.assessments = res.data.result;
});
// }));
emit("update:formDeital", formDetail);
}) })
.catch((err) => { .catch((e) => {
messageError($q, err); messageError($q, e);
})
.then(() => {
isLoading.loadEducation = false;
});
//
isLoading.loadCertificate = true;
http
.get(config.API.dataUserCertificate("certificate"))
.then((res) => {
formDetail.certificates = res.data.result.map((e: CertificatesForm) => ({
certificateNo: e.certificateNo,
certificateType: e.certificateType,
expireDate: e.expireDate,
issueDate: e.issueDate,
issuer: e.issuer,
}));
})
.catch((e) => {
messageError($q, e);
}) })
.finally(() => { .finally(() => {
setTimeout(() => { isLoading.loadCertificate = false;
hideLoader(); });
}, 2500);
//
isLoading.loadSalary = true;
http
.get(config.API.dataUserSalaryPosition)
.then((res) => {
formDetail.salaries = res.data.result;
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
isLoading.loadSalary = false;
});
//
isLoading.loadTraining = true;
http
.get(config.API.dataUserCertificate("training"))
.then((res) => {
formDetail.trainings = res.data.result.map((e: any) => ({
dateOrder: e.dateOrder,
department: e.department,
duration: e.duration,
endDate: e.endDate,
name: e.name,
numberOrder: e.numberOrder,
place: e.place,
startDate: e.startDate,
topic: e.topic,
yearly: e.yearly,
}));
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
isLoading.loadTraining = false;
});
//
isLoading.loadExperience = true;
http
.get(config.API.dataUserPerformance)
.then((res) => {
formDetail.assessments = res.data.result.map((e: any) => ({
...e,
isAdd: false,
}));
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
isLoading.loadExperience = false;
});
//
isLoading.loadExperience = true;
http
.get(config.API.dataUserPortfolio)
.then((res) => {
formDetail.experience = res.data.result;
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
isLoading.loadExperience = false;
}); });
} }
@ -156,60 +235,52 @@ async function fetchDetail() {
* @param id ประเม * @param id ประเม
*/ */
async function fetchCheckSpec(data: any) { async function fetchCheckSpec(data: any) {
formDetail.userId = data.id; isLoading.loadEducation = true;
formDetail.citizenId = data.citizenId; isLoading.loadCertificate = true;
formDetail.prefix = data.prefix; isLoading.loadSalary = true;
formDetail.fullName = data.fullName; isLoading.loadTraining = true;
formDetail.position = data.position; isLoading.loadExperience = true;
formDetail.oc = data.oc; try {
formDetail.salary = data.salary ? formattedNumber(data.salary) : ""; formDetail.userId = data.id;
formDetail.positionLevel = data.positionLevel; formDetail.citizenId = data.citizenId;
formDetail.posNo = data.posNo; formDetail.prefix = data.prefix;
formDetail.birthDate = data.birthDate; formDetail.fullName = data.fullName;
formDetail.educations = data.educations; formDetail.position = data.position;
formDetail.oc = data.oc;
formDetail.certificates = data.certificates.map((e: CertificatesForm) => ({ formDetail.salary = data.salary ? formattedNumber(data.salary) : "";
certificateNo: e.certificateNo, formDetail.positionLevel = data.positionLevel;
certificateType: e.certificateType, formDetail.posNo = data.posNo;
expireDate: date2Thai(e.expireDate), formDetail.birthDate = data.birthDate;
issueDate: date2Thai(e.issueDate), formDetail.educations = data.educations;
issuer: e.issuer, formDetail.certificates = data.certificates.map((e: CertificatesForm) => ({
})); certificateNo: e.certificateNo,
formDetail.salaries = data.salaries.map((e: any) => ({ certificateType: e.certificateType,
amount: e.amount, expireDate: date2Thai(e.expireDate),
date: e.date, issueDate: date2Thai(e.issueDate),
mouthSalaryAmount: e.mouthSalaryAmount ? e.mouthSalaryAmount : 0, issuer: e.issuer,
posNo: e.posNo, }));
position: e.position, formDetail.salaries = data.salaries;
positionSalaryAmount: e.positionSalaryAmount ? e.positionSalaryAmount : 0, formDetail.trainings = data.trainings.map((e: any) => ({
refCommandDate: e.refCommandDate ? e.refCommandDate : "", dateOrder: date2Thai(e.dateOrder),
department: e.department,
refCommandNo: e.refCommandNo ? e.refCommandNo : "", duration: e.duration,
salaryClass: e.salaryClass ? e.salaryClass : "", endDate: date2Thai(e.endDate),
salaryRef: e.salaryRef ? e.salaryRef : "", name: e.name,
salaryStatus: e.salaryStatus ? e.salariesStatus : "", numberOrder: e.numberOrder,
// place: e.place,
oc: "-", startDate: date2Thai(e.startDate),
lineWork: "-", topic: e.topic,
side: "-", yearly: e.yearly,
positionType: "-", }));
level: "-", formDetail.assessments = data.performances;
positionsAdministrative: "-", formDetail.experience = data.portfolios;
aspectAdministrative: "-", } finally {
})); isLoading.loadEducation = false;
formDetail.trainings = data.trainings.map((e: any) => ({ isLoading.loadCertificate = false;
dateOrder: date2Thai(e.dateOrder), isLoading.loadSalary = false;
department: e.department, isLoading.loadTraining = false;
duration: e.duration, isLoading.loadExperience = false;
endDate: date2Thai(e.endDate), }
name: e.name,
numberOrder: e.numberOrder,
place: e.place,
startDate: date2Thai(e.startDate),
topic: e.topic,
yearly: e.yearly,
}));
formDetail.assessments = data.assessments;
} }
/** /**
@ -226,40 +297,107 @@ function formattedNumber(x: number) {
/** get data */ /** get data */
function getData() { function getData() {
showLoader(); isLoading.loadDetail = true;
http http
.get(config.API.dataUserGovernment) .get(config.API.dataUserGovernment)
.then((res) => { .then(async (res) => {
const data = res.data.result; const data = await res.data.result;
formDetail.org = data.org; formDetail.org = data.org;
formDetail.govAge = data.govAge formDetail.govAge = data.govAge
? `${data.govAge.year} วัน ${data.govAge.month} เดือน ${data.govAge.year} ปี` ? `${data.govAge.year} ปี ${data.govAge.month} เดือน ${data.govAge.day} วัน`
: ""; : "";
}) })
.catch((e) => { .catch((e) => {
messageError($q, e); messageError($q, e);
}) })
.finally(() => { .finally(() => {
setTimeout(() => { isLoading.loadDetail = false;
hideLoader();
}, 2500);
}); });
} }
/** ผลงานที่เคยเสนอขอ*/
const modalPerformance = ref<boolean>(false);
const isEdit = ref<boolean>(false);
const isIndex = ref<number>();
const formPerformance = reactive<any>({
year: null,
type: "",
subject: "",
evaluationResult: "",
});
const typeOptions = ref<string[]>([
"ประเมินชำนาญการ",
"ประเมินชำนาญการพิเศษ",
"ประเมินเชี่ยวชาญ",
]);
const resultOptions = ref<any[]>([
{ label: "ผ่าน", value: "ผ่าน" },
{ label: "ไม่ผ่าน", value: "ไม่ผ่าน" },
]);
function onOpenDialogPerformance(
stetusEdit: boolean = false,
index: number | null = null
) {
if (stetusEdit && index !== null) {
isIndex.value = index;
const data = formDetail.assessments[index];
formPerformance.year = data.year ? Number(data.year) - 543 : null;
formPerformance.type = data.type;
formPerformance.subject = data.subject;
formPerformance.evaluationResult = data.evaluationResult;
}
isEdit.value = stetusEdit;
modalPerformance.value = true;
}
function onCloseDialogPerformance() {
modalPerformance.value = false;
formPerformance.year = null;
formPerformance.type = "";
formPerformance.subject = "";
formPerformance.evaluationResult = "";
}
function onSubmitPerformance() {
const body = {
...formPerformance,
year: formPerformance.year ? Number(formPerformance.year) + 543 : null,
isAdd: true,
};
if (isEdit.value && isIndex.value !== null && isIndex.value !== undefined) {
formDetail.assessments[isIndex.value] = body;
} else {
formDetail.assessments.push(body);
}
onCloseDialogPerformance();
}
function onDeletePerformance(index: number) {
formDetail.assessments.splice(index, 1);
}
onMounted(async () => { onMounted(async () => {
const promises = []; try {
const promises = [];
if (route.name === "evaluate-add") { if (route.name === "evaluate-add") {
promises.push(fetchDetail()); promises.push(fetchDetail());
}
if (props.data) {
promises.push(fetchCheckSpec(props.data));
}
promises.push(getData());
await Promise.all(promises);
} catch (error) {
console.log(error);
} finally {
} }
if (props.data) {
promises.push(fetchCheckSpec(props.data));
}
promises.push(getData());
await Promise.all(promises);
}); });
</script> </script>
@ -270,7 +408,10 @@ onMounted(async () => {
:style="$q.screen.lt.sm ? '' : 'height: 60vh; overflow: scroll;'" :style="$q.screen.lt.sm ? '' : 'height: 60vh; overflow: scroll;'"
> >
<div class="row col-12"> <div class="row col-12">
<q-card class="col-12 cardSp1" bordered> <div class="col-12" v-if="isLoading.loadDetail">
<q-skeleton height="200px" class="q-mb-md" />
</div>
<q-card v-else class="col-12 cardSp1" bordered>
<div class="text-weight-bold row items-center bg-grey-2 col-12"> <div class="text-weight-bold row items-center bg-grey-2 col-12">
<span class="q-ml-lg q-my-sm">อมลสวนต</span> <span class="q-ml-lg q-my-sm">อมลสวนต</span>
</div> </div>
@ -318,7 +459,7 @@ onMounted(async () => {
borderless borderless
readonly readonly
:model-value="`${formDetail.posNo ? formDetail.posNo : '-'}`" :model-value="`${formDetail.posNo ? formDetail.posNo : '-'}`"
label="ตำแหน่งเลขที่" label="เลขที่ตำแหน่ง"
/> />
</div> </div>
<div class="col-xs-6 col-sm-4 col-md-3"> <div class="col-xs-6 col-sm-4 col-md-3">
@ -360,7 +501,7 @@ onMounted(async () => {
label="อายุราชการ" label="อายุราชการ"
/> />
</div> </div>
<div class="col-xs-12 col-sm-9"> <div class="col-xs-12 col-sm-9 text-html">
<q-input <q-input
borderless borderless
readonly readonly
@ -373,7 +514,10 @@ onMounted(async () => {
</div> </div>
</q-card> </q-card>
<q-card class="col-12 cardSp1" bordered> <div class="col-12" v-if="isLoading.loadEducation">
<q-skeleton height="200px" class="q-mb-md" />
</div>
<q-card v-else class="col-12 cardSp1" bordered>
<div class="text-weight-bold row items-center bg-grey-2 col-12"> <div class="text-weight-bold row items-center bg-grey-2 col-12">
<span class="q-ml-lg q-my-sm">ประวการศกษา </span> <span class="q-ml-lg q-my-sm">ประวการศกษา </span>
</div> </div>
@ -514,6 +658,7 @@ onMounted(async () => {
class="col-12" class="col-12"
:columns="columnsCertificates" :columns="columnsCertificates"
:row="formDetail.certificates" :row="formDetail.certificates"
:is-loading="isLoading.loadCertificate"
/> />
</q-card> </q-card>
@ -522,7 +667,7 @@ onMounted(async () => {
<span class="q-ml-lg q-my-sm">ประวการรบราชการ</span> <span class="q-ml-lg q-my-sm">ประวการรบราชการ</span>
</div> </div>
<div class="col-12"><q-separator /></div> <div class="col-12"><q-separator /></div>
<div class="col-10"> <div class="col-10 q-pa-sm">
<d-table <d-table
ref="table" ref="table"
row-key="id" row-key="id"
@ -533,6 +678,8 @@ onMounted(async () => {
:rows="formDetail.salaries" :rows="formDetail.salaries"
:paging="true" :paging="true"
:rows-per-page-options="[20, 50, 100]" :rows-per-page-options="[20, 50, 100]"
:pagination="{ page: 1, rowsPerPage: 20 }"
:loading="isLoading.loadSalary"
> >
<template v-slot:header="props"> <template v-slot:header="props">
<q-tr :props="props"> <q-tr :props="props">
@ -548,14 +695,26 @@ onMounted(async () => {
:key="col.id" :key="col.id"
class="vertical-top" class="vertical-top"
> >
<div class="table_ellipsis"> <div v-if="col.name == 'organization'" class="text-html">
{{
props.row
? findOrgNameHtml({
root: props.row.orgRoot,
child1: props.row.orgChild1,
child2: props.row.orgChild2,
child3: props.row.orgChild3,
child4: props.row.orgChild4,
})
: "-"
}}
</div>
<div v-else class="table_ellipsis">
{{ col.value ? col.value : "-" }} {{ col.value ? col.value : "-" }}
</div> </div>
</q-td> </q-td>
</q-tr> </q-tr>
</template> </template>
</d-table> </d-table>
<!-- <TableData :columns="columnSalaries" :row="formDetail.salaries" /> -->
</div> </div>
</q-card> </q-card>
@ -568,6 +727,7 @@ onMounted(async () => {
class="col-12" class="col-12"
:columns="columnTraining" :columns="columnTraining"
:row="formDetail.trainings" :row="formDetail.trainings"
:is-loading="isLoading.loadTraining"
/> />
</q-card> </q-card>
@ -576,23 +736,190 @@ onMounted(async () => {
<span class="q-ml-lg q-my-sm">ประสบการณในการปฏงาน </span> <span class="q-ml-lg q-my-sm">ประสบการณในการปฏงาน </span>
</div> </div>
<div class="col-12"><q-separator /></div> <div class="col-12"><q-separator /></div>
<div class="col-12 q-pa-sm">-</div> <TableData
class="col-12"
:columns="columnExperience"
:row="formDetail.experience"
:is-loading="isLoading.loadExperience"
/>
</q-card> </q-card>
<q-card class="col-12 cardSp1" bordered> <q-card class="col-12 cardSp1" bordered>
<div class="text-weight-bold row items-center bg-grey-2 col-12"> <div class="text-weight-bold row items-center bg-grey-2 col-12">
<span class="q-ml-lg q-my-sm">ผลงานทเคยเสนอขอประเม (าม)</span> <span class="q-ml-lg q-my-sm">ผลงานทเคยเสนอขอประเม (าม) </span>
<q-btn
v-if="storeEva.currentStep === 1"
class="q-ml-sm"
flat
round
dense
color="primary"
icon="add"
@click.stop="onOpenDialogPerformance(false)"
>
<q-tooltip>เพมขอม </q-tooltip>
</q-btn>
</div> </div>
<div class="col-12"><q-separator /></div> <div class="col-12"><q-separator /></div>
<div class="col-10"> <div class="col-10">
<TableData <div class="q-pa-sm row col-12">
:columns="columnAssessments" <d-table
:row="formDetail.assessments" flat
/> bordered
:columns="columnAssessments"
:rows="formDetail.assessments"
dense
:rows-per-page-options="[10, 25, 50, 100]"
virtual-scroll
class="row col-12"
:style="$q.screen.lt.sm ? 'width: 80vw' : 'width: 50vw;'"
:pagination="{ page: 1, rowsPerPage: 20 }"
:loading="isLoading.loadExperience"
>
<template v-slot:header="props">
<q-tr :props="props" class="bg-grey-2">
<q-th auto-widt v-if="storeEva.currentStep === 1" />
<q-th
v-for="col in props.cols"
:key="col.name"
:props="props"
>
<span class="text-body2 text-black">{{ col.label }}</span>
</q-th>
</q-tr>
</template>
<template v-slot:body="props">
<q-tr :props="props">
<q-td auto-widt v-if="storeEva.currentStep === 1">
<q-btn
v-if="props.row.isAdd"
flat
dense
round
color="edit"
icon="edit"
@Click.stop.prevent="
onOpenDialogPerformance(true, props.rowIndex)
"
>
<q-tooltip>แกไข</q-tooltip>
</q-btn>
<q-btn
v-if="props.row.isAdd"
flat
dense
round
color="red"
icon="delete"
@click.stop.pervent="onDeletePerformance(props.rowIndex)"
>
<q-tooltip>ลบ</q-tooltip>
</q-btn>
</q-td>
<q-td
v-for="col in props.cols"
:key="col.name"
:props="props"
>
<div>
{{ !col.value ? "-" : col.value }}
</div>
</q-td>
</q-tr>
</template>
</d-table>
</div>
</div> </div>
</q-card> </q-card>
</div> </div>
</q-card> </q-card>
<q-dialog v-model="modalPerformance" persistent>
<q-card style="min-width: 35%">
<q-form greedy @submit.prevent @validation-success="onSubmitPerformance">
<HeaderDialog
:tittle="'ผลงานที่เคยเสนอขอประเมิน (ถ้ามี)'"
:close="onCloseDialogPerformance"
/>
<q-separator />
<q-card-section>
<div class="row q-col-gutter-sm">
<div class="col-12">
<datepicker
menu-class-name="modalfix"
v-model="formPerformance.year"
:locale="'th'"
autoApply
year-picker
:enableTimePicker="false"
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
dense
outlined
:model-value="
!formPerformance.year
? null
: Number(formPerformance.year) + 543
"
:label="`${'ปี พ.ศ.'}`"
:rules="[(val:string) => !!val || 'กรุณาเลือกปี พ.ศ.']"
hide-bottom-space
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
style="color: var(--q-primary)"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<div class="col-12">
<q-select
dense
outlined
label="ระดับตอนที่ยืนขอ"
hide-bottom-space
v-model="formPerformance.type"
:options="typeOptions"
/>
</div>
<div class="col-12">
<q-input
v-model="formPerformance.subject"
label="เรื่อง/ชื่อเรื่อง"
outlined
dense
hide-bottom-space
/>
</div>
<div class="col-12">
<q-option-group
:options="resultOptions"
type="radio"
v-model="formPerformance.evaluationResult"
inline
/>
</div>
</div>
</q-card-section>
<q-separator />
<q-card-actions align="right">
<q-btn label="บันทึก" color="public" type="submit" />
</q-card-actions>
</q-form>
</q-card>
</q-dialog>
</template> </template>
<style> <style>

View file

@ -38,10 +38,16 @@ interface FormSpec {
interface FormCommand { interface FormCommand {
commanderFullname: string; commanderFullname: string;
commanderPosition: string; commanderPosition: string;
commanderPositionOld: string;
commanderOrgOld: string;
commanderOrg: string;
commanderAboveFullname: string; commanderAboveFullname: string;
commanderAbovePosition: string; commanderAbovePosition: string;
commanderAbovePositionOld: string;
commanderAboveOrgOld: string;
commanderAboveOrg: string;
author: string; author: string;
subject: string; subject: string[];
assignedPosition: string; assignedPosition: string;
} }
@ -134,5 +140,5 @@ export type {
ListMenu, ListMenu,
FormRef, FormRef,
FormData, FormData,
FormCommandSe FormCommandSe,
}; };

View file

@ -1,15 +1,13 @@
import http from "@/plugins/http"; import http from "@/plugins/http";
import config from "@/app.config"; import config from "@/app.config";
import { useQuasar } from "quasar";
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
import { useEvaluateStore } from "@/modules/06_evaluate/store"; import { useEvaluateStore } from "@/modules/06_evaluate/store";
const store = useEvaluateStore(); const store = useEvaluateStore();
const mixin = useCounterMixin(); const mixin = useCounterMixin();
const $q = useQuasar();
const { showLoader, hideLoader, messageError } = mixin; const { showLoader, hideLoader } = mixin;
/** function เช็คการยื่นข้อประเมิน*/ /** function เช็คการยื่นข้อประเมิน*/
async function fetchCheckStatus() { async function fetchCheckStatus() {
@ -26,7 +24,7 @@ async function fetchCheckStatus() {
fetchCheckStep(store?.evaluateId); fetchCheckStep(store?.evaluateId);
}) })
.catch((err) => { .catch((err) => {
messageError($q, err); console.log(err);
}) })
.finally(() => { .finally(() => {
hideLoader(); hideLoader();
@ -65,7 +63,7 @@ async function fetchCheckStep(id: string) {
store.step = step; store.step = step;
}) })
.catch((err) => { .catch((err) => {
messageError($q, err); console.log(err);
}) })
.finally(() => { .finally(() => {
store.showLoadStatus = true; store.showLoadStatus = true;
@ -143,7 +141,7 @@ async function saveEvaluation(formSpec: any, detail: any) {
fetchCheckStatus(); fetchCheckStatus();
}) })
.catch((err) => { .catch((err) => {
messageError($q, err); console.log(err);
}) })
.finally(() => { .finally(() => {
fetchCheckStep(store?.evaluateId); fetchCheckStep(store?.evaluateId);
@ -155,10 +153,9 @@ async function nextPrapare(type: string, body: any) {
showLoader(); showLoader();
await http await http
.put(config.API.evaluationPreparedoc(store.evaluateId, type), body) .put(config.API.evaluationPreparedoc(store.evaluateId, type), body)
.then((res) => { .then((res) => {})
})
.catch((err) => { .catch((err) => {
messageError($q, err); console.log(err);
}) })
.finally(() => { .finally(() => {
hideLoader(); hideLoader();
@ -170,10 +167,9 @@ async function nextCheckDoc(type: string) {
showLoader(); showLoader();
await http await http
.put(config.API.evaluationCheckdoc(store.evaluateId, type)) .put(config.API.evaluationCheckdoc(store.evaluateId, type))
.then((res) => { .then((res) => {})
})
.catch((err) => { .catch((err) => {
messageError($q, err); console.log(err);
}) })
.finally(() => { .finally(() => {
hideLoader(); hideLoader();

View file

@ -7,8 +7,9 @@ import { useCounterMixin } from "@/stores/mixin";
export const useEvaluateDetailStore = defineStore("evaluateDetailStore", () => { export const useEvaluateDetailStore = defineStore("evaluateDetailStore", () => {
/** columns TableViewStep1*/ /** columns TableViewStep1*/
const mixin = useCounterMixin(); const mixin = useCounterMixin();
const { date2Thai } = mixin; const { date2Thai, findOrgNameHtml, findOrgName } = mixin;
//ใบอนุญาตประกอบวิชาชีพ
const columnsCertificates = ref<QTableProps["columns"]>([ const columnsCertificates = ref<QTableProps["columns"]>([
{ {
name: "certificateType", name: "certificateType",
@ -57,62 +58,81 @@ export const useEvaluateDetailStore = defineStore("evaluateDetailStore", () => {
}, },
]); ]);
//ประวัติการรับราชการ
const columnSalaries = ref<QTableProps["columns"]>([ const columnSalaries = ref<QTableProps["columns"]>([
{ {
name: "date", name: "commandDateAffect",
align: "left", align: "left",
label: "วัน เดือน ปี", label: "วันที่คำสั่งมีผล",
sortable: true, sortable: true,
field: "date", field: "commandDateAffect",
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
style: "font-size: 14px", style: "font-size: 14px",
format: (v) => date2Thai(v), format: (v) => date2Thai(v),
}, },
{ {
name: "amount", name: "commandDateSign",
align: "left", align: "left",
label: "เงินเดือน", label: "วันที่ลงนาม",
sortable: true, sortable: true,
field: "amount", field: "commandDateSign",
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
style: "font-size: 14px", style: "font-size: 14px",
format: (v) => Number(v).toLocaleString(), format: (v) => date2Thai(v),
}, },
{ {
name: "positionSalaryAmount", name: "posNumCodeSit",
align: "left", align: "left",
label: "เงินประจำตำแหน่ง", label: "หน่วยงานที่ออกคำสั่ง",
sortable: true, sortable: false,
field: "positionSalaryAmount", field: "posNumCodeSit",
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
style: "font-size: 14px", style: "font-size: 14px",
format: (v) => Number(v).toLocaleString(), format(val, row) {
return row.posNumCodeSitAbb && row.posNumCodeSit
? `${row.posNumCodeSit} (${row.posNumCodeSitAbb})`
: row.posNumCodeSit
? row.posNumCodeSit
: "-";
},
}, },
{
name: "mouthSalaryAmount",
align: "left",
label: "เงินค่าตอบแทนรายเดือน",
sortable: true,
field: "mouthSalaryAmount",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
format: (v) => Number(v).toLocaleString(),
},
{ {
name: "posNo", name: "posNo",
align: "left", align: "left",
label: "ตำแหน่งเลขที่", label: "เลขที่ตำแหน่ง",
sortable: true, sortable: true,
field: "posNo", field: "posNo",
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
style: "font-size: 14px", style: "font-size: 14px",
format(val, row) {
return row.posNoAbb && row.posNo
? `${row.posNoAbb} ${row.posNo}`
: row.posNo
? row.posNo
: "-";
},
sort: (a: string, b: string) =>
a
.toString()
.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "positionName",
align: "left",
label: "ตำแหน่งในสายงาน",
sortable: true,
field: "positionName",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a
.toString()
.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
}, },
{ {
name: "positionType", name: "positionType",
align: "left", align: "left",
label: "ประเภทตำแหน่ง", label: "ตำแหน่งประเภท",
sortable: true, sortable: true,
field: "positionType", field: "positionType",
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
@ -124,30 +144,102 @@ export const useEvaluateDetailStore = defineStore("evaluateDetailStore", () => {
label: "ระดับ", label: "ระดับ",
sortable: true, sortable: true,
field: "positionLevel", field: "positionLevel",
format(val, row) {
return `${
row.positionLevel
? row.positionLevel
: row.positionCee
? row.positionCee
: "-"
}`;
},
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
style: "font-size: 14px", style: "font-size: 14px",
}, },
{ {
name: "templateDoc", name: "positionExecutive",
align: "left", align: "left",
label: "เอกสารอ้างอิง", label: "ตำแหน่งทางการบริหาร",
sortable: true, sortable: true,
field: "templateDoc", field: "positionExecutive",
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
style: "font-size: 14px", style: "font-size: 14px",
}, },
{ {
name: "refCommandNo", name: "commandNo",
align: "left", align: "left",
label: "เลขที่คำสั่ง", label: "เลขที่คำสั่ง",
sortable: true, sortable: true,
field: "refCommandNo", field: "commandNo",
format(val, row) {
return row.commandNo && row.commandYear
? `${row.commandNo}/${Number(row.commandYear) + 543}`
: "";
},
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "commandCode",
align: "left",
label: "ประเภทคำสั่ง",
sortable: true,
field: "commandCode",
format(val, row) {
return row.commandName;
},
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "organization",
align: "left",
label: "สังกัด",
sortable: true,
field: "organization",
headerStyle: "font-size: 14px;min-width:280px",
style: "font-size: 14px",
format(val, row) {
return findOrgName({
root: row.orgRoot,
child1: row.orgChild1,
child2: row.orgChild2,
child3: row.orgChild3,
child4: row.orgChild4,
});
},
},
{
name: "amount",
align: "left",
label: "เงินเดือน",
sortable: true,
field: "amount",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
format(v, row) {
return row.amount
? `${row.amount.toLocaleString()}${
row.amountSpecial !== 0 && row.amountSpecial
? ` (${row.amountSpecial.toLocaleString()})`
: ""
}`
: "-";
},
},
{
name: "remark",
align: "left",
label: "หมายเหตุ",
sortable: true,
field: "remark",
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
style: "font-size: 14px", style: "font-size: 14px",
}, },
]); ]);
//ประวัติการฝึกอบรมดูงาน
const columnTraining = ref<QTableProps["columns"]>([ const columnTraining = ref<QTableProps["columns"]>([
{ {
name: "name", name: "name",
@ -265,97 +357,65 @@ export const useEvaluateDetailStore = defineStore("evaluateDetailStore", () => {
}, },
]); ]);
/** ผลงานที่เคยเสนอขอประเมิน (ถ้ามี)*/ //ผลงานที่เคยเสนอขอประเมิน (ถ้ามี)
const columnAssessments = ref<QTableProps["columns"]>([ const columnAssessments = ref<QTableProps["columns"]>([
{ {
name: "date", name: "year",
align: "left", align: "left",
label: "วันที่ได้รับ", label: "ปี พ.ศ.",
sortable: true, sortable: true,
field: "date", field: "year",
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
style: "font-size: 14px", style: "font-size: 14px",
format: (v) => date2Thai(v),
}, },
{ {
name: "point1Total", name: "type",
align: "left", align: "left",
label: "ส่วนที่1 (น้ำหนัก)", label: "ระดับตอนที่ยื่นขอ",
sortable: true, sortable: true,
field: "point1Total", field: "type",
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
style: "font-size: 14px", style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
}, },
{ {
name: "point1", name: "subject",
align: "left", align: "left",
label: "ผลประเมินส่วนที่1 (คะแนน)", label: "เรื่อง/ชื่อเรื่อง",
sortable: true, sortable: true,
field: "point1", field: "subject",
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
style: "font-size: 14px", style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
}, },
{ {
name: "point2Total", name: "evaluationResult",
align: "left", align: "left",
label: "ส่วนที่2 (น้ำหนัก)", label: "ผลการประเมิน (ผ่าน/ไม่ผ่าน)",
sortable: true, sortable: true,
field: "point2Total", field: "evaluationResult",
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
style: "font-size: 14px", style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "point2",
align: "left",
label: "ผลประเมินส่วนที่2 (คะแนน)",
sortable: true,
field: "point2",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "pointSumTotal",
align: "left",
label: "ผลรวม (น้ำหนัก)",
sortable: true,
field: "pointSumTotal",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "pointSum",
align: "left",
label: "ผลประเมินรวม (คะแนน)",
sortable: true,
field: "pointSum",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
}, },
]);
//ประสบการณ์ในการปฏิบัติงาน
const columnExperience = ref<QTableProps["columns"]>([
{ {
name: "name", name: "name",
align: "left", align: "left",
label: "ผลประเมิน", label: "ชื่อผลงาน",
sortable: true, sortable: true,
field: "name", field: "name",
format(val, row) {
return `${textPoint(row.pointSum)} ${textRangePoint(row.pointSum)}`;
},
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
style: "font-size: 14px", style: "font-size: 14px",
sort: (a: string, b: string) => },
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }), {
name: "detail",
align: "left",
label: "รายละเอียดผลงาน",
sortable: true,
field: "detail",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
}, },
]); ]);
@ -384,6 +444,7 @@ export const useEvaluateDetailStore = defineStore("evaluateDetailStore", () => {
columnSalaries, columnSalaries,
columnTraining, columnTraining,
columnProjectsProposed, columnProjectsProposed,
columnExperience,
columnAssessments, columnAssessments,
}; };
}); });

View file

@ -7,12 +7,14 @@ import http from "@/plugins/http";
import config from "@/app.config"; import config from "@/app.config";
import { useEvaluateStore } from "@/modules/06_evaluate/store"; import { useEvaluateStore } from "@/modules/06_evaluate/store";
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
import { useDataStore } from "@/stores/data";
/** import Components*/ /** import Components*/
import TableListEvaluate from "@/modules/06_evaluate/components/TableListEvaluate.vue"; // import TableListEvaluate from "@/modules/06_evaluate/components/TableListEvaluate.vue"; //
import DialogMain from "@/modules/06_evaluate/components/DialogMain.vue"; // popup import DialogMain from "@/modules/06_evaluate/components/DialogMain.vue"; // popup
/** import Type*/ /** import Type*/
import type { PropsTable } from "@/interface/PropsTable";
import type { ListMenu } from "@/modules/06_evaluate/interface/evalute"; import type { ListMenu } from "@/modules/06_evaluate/interface/evalute";
import type { OptionStatus } from "@/modules/06_evaluate/interface/main"; import type { OptionStatus } from "@/modules/06_evaluate/interface/main";
@ -20,10 +22,12 @@ import type { OptionStatus } from "@/modules/06_evaluate/interface/main";
const $q = useQuasar(); const $q = useQuasar();
const mixin = useCounterMixin(); const mixin = useCounterMixin();
const store = useEvaluateStore(); const store = useEvaluateStore();
const dataStore = useDataStore();
const router = useRouter(); const router = useRouter();
const { showLoader, hideLoader, messageError } = mixin; const { messageError } = mixin;
/** ตัวแปร*/ /** ตัวแปร*/
const isLoading = ref<boolean>(false);
const modal = ref<boolean>(false); const modal = ref<boolean>(false);
const menu = ref<ListMenu>(); const menu = ref<ListMenu>();
const listMenu = ref<ListMenu[]>([ const listMenu = ref<ListMenu[]>([
@ -47,13 +51,12 @@ const listMenu = ref<ListMenu[]>([
}, },
]); ]);
const total = ref<number>(0); const pagination = ref<PropsTable.Pagination>({
const totalList = ref<number>(1); sortBy: "",
const pagination = ref({
sortBy: "createdAt",
descending: true, descending: true,
page: 1, page: 1,
rowsPerPage: 10, rowsPerPage: 10,
rowsNumber: 0,
}); });
/** /**
@ -71,52 +74,64 @@ function openExpert() {
/** function เรียกรายการประเมิน*/ /** function เรียกรายการประเมิน*/
async function fetchEvaluteList() { async function fetchEvaluteList() {
showLoader(); isLoading.value = true;
const body = { const body = {
page: pagination.value.page, page: pagination.value.page,
pageSize: pagination.value.rowsPerPage, pageSize: pagination.value.rowsPerPage,
keyword: store.filterKeyword, keyword: store.filterKeyword,
status: selectedStatus.value, status: selectedStatus.value,
...(pagination.value.sortBy && {
sortBy: pagination.value.sortBy,
descending: pagination.value.descending,
}),
}; };
await http await http
.put(config.API.evaluationList(), body) .put(config.API.evaluationList(), body)
.then(async (res) => { .then(async (res) => {
totalList.value = Math.ceil( const result = res.data.result;
res.data.result.total / pagination.value.rowsPerPage pagination.value.rowsNumber = result.total;
); store.fetchEvaluateList(result.data);
total.value = res.data.result.total;
store.fetchEvaluateList(res.data.result.data);
await getProfileCheck();
}) })
.catch((err) => { .catch((err) => {
messageError($q, err); messageError($q, err);
}) })
.finally(() => { .finally(() => {
hideLoader(); isLoading.value = false;
}); });
} }
/** function เรียกรายการประเมิน*/ /** function เรียกรายการประเมิน*/
const statusSubmit = ref<boolean>(true); const statusSubmit = ref<boolean>(true);
async function getProfileCheck() { async function getProfileCheck() {
await http if (!dataStore.dataprofilePosition) {
.get(config.API.profilePosition()) await http
.then(async (res: any) => { .get(config.API.profilePosition())
const data = res.data.result; .then(async (res: any) => {
if ( const data = res.data.result;
data.posTypeRank != 2 || checkProfilePosition(data);
(data.posTypeRank == 2 && data.posLevelRank >= 4) })
) { .catch((err) => {
statusSubmit.value = false; messageError($q, err);
} else { });
listMenu.value = await listMenu.value.filter( } else {
(x: ListMenu) => x.level > data.posLevelRank const data = dataStore.dataprofilePosition;
); checkProfilePosition(data);
} }
}) }
.catch((err) => {
messageError($q, err); function checkProfilePosition(data: any) {
}); if (
data.posTypeRank != 2 ||
(data.posTypeRank == 2 && data.posLevelRank >= 4)
) {
statusSubmit.value = false;
} else {
listMenu.value = listMenu.value.filter(
(x: ListMenu) => x.level > data.posLevelRank
);
}
} }
const selectedStatus = ref<string[]>([ const selectedStatus = ref<string[]>([
@ -181,16 +196,10 @@ function getSearch() {
fetchEvaluteList(); fetchEvaluteList();
} }
watch(
() => pagination.value.rowsPerPage,
async () => {
getSearch();
}
);
/** hook lifecycle*/ /** hook lifecycle*/
onMounted(async () => { onMounted(async () => {
await fetchEvaluteList(); await fetchEvaluteList();
await getProfileCheck();
}); });
</script> </script>
@ -206,12 +215,14 @@ onMounted(async () => {
flat flat
color="primary" color="primary"
class="q-mr-sm" class="q-mr-sm"
@click="router.go(-1)" @click="router.push('/')"
/> />
<div>ประเมนบคคล</div> <div>ประเมนบคคล</div>
</div> </div>
</div> </div>
<div class="col-xs-12 col-sm-12 col-md-11 row q-col-gutter-md"> <div class="col-xs-12 col-sm-12 col-md-11 row q-col-gutter-md">
<div class="col-12 row"> <div class="col-12 row">
<q-card bordered class="col-12 row caedNone q-pa-md"> <q-card bordered class="col-12 row caedNone q-pa-md">
@ -312,9 +323,8 @@ onMounted(async () => {
<div class="col-12"> <div class="col-12">
<TableListEvaluate <TableListEvaluate
:fetchData="fetchEvaluteList" :fetchData="fetchEvaluteList"
v-model:total="total"
v-model:total-list="totalList"
v-model:pagination="pagination" v-model:pagination="pagination"
v-model:isLoading="isLoading"
/> />
</div> </div>
</q-card> </q-card>

View file

@ -6,16 +6,22 @@ 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 { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
import { useDataStore } from "@/stores/data";
import Form from "@/modules/07_appealComplain/views/Form.vue"; import Form from "@/modules/07_appealComplain/views/Form.vue";
import type { DataProfile } from "@/interface/Main";
import type { import type {
FormProfile, FormProfile,
FormDataType, FormDataType,
} from "@/modules/07_appealComplain/interface/response/mainType"; } from "@/modules/07_appealComplain/interface/response/mainType";
const router = useRouter(); const router = useRouter();
const $q = useQuasar(); const $q = useQuasar();
const mixin = useCounterMixin(); const mixin = useCounterMixin();
const storeData = useDataStore();
const isLoad = ref<boolean>(false)
const { findOrgName, success, messageError, showLoader, hideLoader } = mixin; const { findOrgName, success, messageError, showLoader, hideLoader } = mixin;
const formProfile = reactive<FormProfile>({ const formProfile = reactive<FormProfile>({
@ -27,24 +33,31 @@ const formProfile = reactive<FormProfile>({
}); });
/** ดึงข้อมูลจาก keycloak*/ /** ดึงข้อมูลจาก keycloak*/
function getProFile() { async function getProFile() {
showLoader(); try {
http isLoad.value = true
.get(config.API.positionBykeycloak()) if (!storeData.dataprofilePosition) {
.then((res) => { const res = await http.get(config.API.profilePosition());
const data = res.data.result; await updateFormProfile(res.data.result);
formProfile.profileId = data.profileId; isLoad.value = false
formProfile.fullname = `${data.prefix}${data.firstName} ${data.lastName}`; } else {
formProfile.citizenId = data.citizenId; await updateFormProfile(storeData.dataprofilePosition);
formProfile.oc = findOrgName(data); isLoad.value = false
formProfile.position = data.position; }
}) } catch (error) {
.catch((e) => { messageError($q, error);
messageError($q, e); isLoad.value = false
}) } finally {
.finally(() => { hideLoader();
hideLoader(); }
}); }
async function updateFormProfile(data: DataProfile) {
formProfile.profileId = data.profileId;
formProfile.fullname = `${data.prefix}${data.firstName} ${data.lastName}`;
formProfile.citizenId = data.citizenId;
formProfile.oc = findOrgName(data);
formProfile.position = data.position;
} }
/** /**
@ -100,11 +113,11 @@ onMounted(() => {
flat flat
color="primary" color="primary"
class="q-mr-sm" class="q-mr-sm"
@click="router.go(-1)" @click="router.push('/appeal-complain')"
/> />
เพมอทธรณ/องทกข เพมอทธรณ/องทกข
</div> </div>
<Form :on-submit="onSubmit" :form-profile="formProfile" /> <Form :on-submit="onSubmit" :form-profile="formProfile" v-model:isLoad="isLoad"/>
</div> </div>
</div> </div>
</template> </template>

View file

@ -22,6 +22,7 @@ const route = useRoute();
const mixin = useCounterMixin(); const mixin = useCounterMixin();
const { messageError, showLoader, hideLoader } = mixin; const { messageError, showLoader, hideLoader } = mixin;
const isLoad = ref<boolean>(false);
const id = ref<string>(route.params.id as string); const id = ref<string>(route.params.id as string);
const historyStatusOb = reactive<HistoryStatusType>({ const historyStatusOb = reactive<HistoryStatusType>({
status: "", status: "",
@ -53,7 +54,7 @@ const data = reactive<EditDataList>({
/** ดึงข้อมูล */ /** ดึงข้อมูล */
function getData() { function getData() {
showLoader(); isLoad.value = true;
http http
.get(config.API.appealByID(id.value)) .get(config.API.appealByID(id.value))
.then((res) => { .then((res) => {
@ -73,13 +74,13 @@ function getData() {
data.disciplineComplaint_Appeal_Docs = data.disciplineComplaint_Appeal_Docs =
dataList.disciplineComplaint_Appeal_Docs; dataList.disciplineComplaint_Appeal_Docs;
data.historyStatus = dataList.historyStatus; data.historyStatus = dataList.historyStatus;
isLoad.value = false;
}) })
.catch((e) => { .catch((e) => {
messageError($q, e); messageError($q, e);
isLoad.value = false;
}) })
.finally(() => { .finally(() => {});
hideLoader();
});
} }
/** / /** /
@ -122,7 +123,7 @@ onMounted(() => {
/> />
แกไขอทธรณ/องทกข แกไขอทธรณ/องทกข
</div> </div>
<Form :data="data" :get-report="getReport" /> <Form :data="data" :get-report="getReport" v-model:is-load="isLoad"/>
</div> </div>
</div> </div>
</template> </template>

View file

@ -17,6 +17,7 @@ const mixin = useCounterMixin();
const { dialogConfirm } = mixin; const { dialogConfirm } = mixin;
const dataStore = useAppealComplainStore(); const dataStore = useAppealComplainStore();
const isLoad = defineModel<boolean>("isLoad", { required: true });
const printForm = ref<string>(""); const printForm = ref<string>("");
const isReadOnly = ref<boolean>(false); const isReadOnly = ref<boolean>(false);
const historyStatusOb = reactive<HistoryStatusType>({ const historyStatusOb = reactive<HistoryStatusType>({
@ -148,35 +149,46 @@ function onSubmit(data: FormDataType) {
); );
} }
watch(props.formProfile, () => { watch(
if (props.formProfile !== null) { () => props.formProfile,
formData.fullname = props.formProfile.fullname; (newValue) => {
formData.profileId = props.formProfile.profileId; if (newValue !== null) {
formData.citizenId = props.formProfile.citizenId; formData.fullname = newValue.fullname;
formData.oc = props.formProfile.oc; formData.profileId = newValue.profileId;
formData.position = props.formProfile.position; formData.citizenId = newValue.citizenId;
} formData.oc = newValue.oc;
}); formData.position = newValue.position;
}
},
{ deep: true }
);
watch(props.data, () => { watch(
isReadOnly.value = true; () => props.data,
formData.id = props.data.id; (newValue) => {
formData.title = props.data.title; if (newValue !== null) {
formData.description = props.data.description; isReadOnly.value = true;
formData.status = props.data.status; formData.id = props.data.id;
formData.type = props.data.type; formData.title = props.data.title;
formData.year = props.data.year; formData.description = props.data.description;
formData.caseType = props.data.caseType; formData.status = props.data.status;
formData.caseNumber = props.data.caseNumber; formData.type = props.data.type;
formData.fullname = props.data.fullname; formData.year = props.data.year;
formData.citizenId = props.data.citizenId; formData.caseType = props.data.caseType;
formData.profileId = props.data.profileId; formData.caseNumber = props.data.caseNumber;
formData.lastUpdatedAt = props.data.lastUpdatedAt; formData.fullname = props.data.fullname;
formData.disciplineComplaint_Appeal_Docs = formData.citizenId = props.data.citizenId;
props.data.disciplineComplaint_Appeal_Docs; formData.profileId = props.data.profileId;
formData.historyStatus = props.data.historyStatus; formData.lastUpdatedAt = props.data.lastUpdatedAt;
}); formData.disciplineComplaint_Appeal_Docs =
props.data.disciplineComplaint_Appeal_Docs;
formData.historyStatus = props.data.historyStatus;
}
},
{ deep: true }
);
</script> </script>
<template> <template>
<div class="row"> <div class="row">
<div class="col-sm-12 col-md-12 col-xs-12"> <div class="col-sm-12 col-md-12 col-xs-12">
@ -226,6 +238,7 @@ watch(props.data, () => {
<div class="row q-col-gutter-sm"> <div class="row q-col-gutter-sm">
<div class="col-xs-12 col-md-3"> <div class="col-xs-12 col-md-3">
<q-select <q-select
v-if="!isLoad"
:class="inputEdit(isReadOnly)" :class="inputEdit(isReadOnly)"
:readonly="isReadOnly" :readonly="isReadOnly"
ref="typeRef" ref="typeRef"
@ -242,9 +255,11 @@ watch(props.data, () => {
lazy-rules lazy-rules
hide-bottom-space hide-bottom-space
/> />
<q-skeleton v-else type="QSelect" height="40px" />
</div> </div>
<div class="col-xs-12 col-md-3"> <div class="col-xs-12 col-md-3">
<q-input <q-input
v-if="!isLoad"
:class="inputEdit(isReadOnly)" :class="inputEdit(isReadOnly)"
:readonly="isReadOnly" :readonly="isReadOnly"
ref="titleRef" ref="titleRef"
@ -257,11 +272,13 @@ watch(props.data, () => {
label="เรื่องอุทธรณ์/ร้องทุกข์" label="เรื่องอุทธรณ์/ร้องทุกข์"
hide-bottom-space hide-bottom-space
/> />
<q-skeleton v-else type="QInput" height="40px" />
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<q-input <q-input
v-if="!isLoad"
:class="inputEdit(isReadOnly)" :class="inputEdit(isReadOnly)"
:readonly="isReadOnly" :readonly="isReadOnly"
ref="descriptionRef" ref="descriptionRef"
@ -276,11 +293,13 @@ watch(props.data, () => {
rows="5" rows="5"
hide-bottom-space hide-bottom-space
/> />
<q-skeleton v-else type="QInput" height="120px" />
</div> </div>
</div> </div>
<div class="row" v-if="!isReadOnly"> <div class="row" v-if="!isReadOnly">
<div class="col-12"> <div class="col-12">
<q-file <q-file
v-if="!isLoad"
ref="fileRef" ref="fileRef"
v-model="formData.files" v-model="formData.files"
label="อัปโหลดเอกสารหลักฐาน" label="อัปโหลดเอกสารหลักฐาน"
@ -290,6 +309,7 @@ watch(props.data, () => {
hide-bottom-space hide-bottom-space
bg-color="white" bg-color="white"
/> />
<q-skeleton v-else type="QInput" height="40px" />
</div> </div>
</div> </div>
<q-card bordered class="col-12 row" v-if="isReadOnly"> <q-card bordered class="col-12 row" v-if="isReadOnly">
@ -324,7 +344,7 @@ watch(props.data, () => {
flat flat
icon="mdi-download" icon="mdi-download"
outline outline
color="primary" color="blue"
@click="downLoadFile(file.pathName)" @click="downLoadFile(file.pathName)"
> >
<q-tooltip>ดาวหโหลดเอกสาร</q-tooltip> <q-tooltip>ดาวหโหลดเอกสาร</q-tooltip>
@ -339,11 +359,11 @@ watch(props.data, () => {
</q-card> </q-card>
</div> </div>
</div> </div>
<q-separator v-if="!isReadOnly" /> <q-separator v-if="!isReadOnly && !isLoad" />
<q-card-actions <q-card-actions
align="right" align="right"
class="bg-white text-teal" class="bg-white text-teal"
v-if="!isReadOnly" v-if="!isReadOnly && !isLoad"
> >
<q-btn id="onSubmit" type="submit" label="บันทึก" color="secondary" <q-btn id="onSubmit" type="submit" label="บันทึก" color="secondary"
><q-tooltip>นท</q-tooltip></q-btn ><q-tooltip>นท</q-tooltip></q-btn

View file

@ -1,7 +1,7 @@
useA useA
<script setup lang="ts"> <script setup lang="ts">
import type { QTableProps } from "quasar"; import type { QTableProps } from "quasar";
import { ref, onMounted, reactive, watch } from "vue"; import { ref, onMounted, reactive } from "vue";
import { useQuasar } from "quasar"; import { useQuasar } from "quasar";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
@ -10,6 +10,7 @@ import config from "@/app.config";
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
import { useAppealComplainStore } from "@/modules/07_appealComplain/store"; import { useAppealComplainStore } from "@/modules/07_appealComplain/store";
import type { PropsTable } from "@/interface/PropsTable";
import type { FormType } from "@/modules/07_appealComplain/interface/response/mainType"; import type { FormType } from "@/modules/07_appealComplain/interface/response/mainType";
import type { DataOption } from "@/modules/07_appealComplain/interface/index/main"; import type { DataOption } from "@/modules/07_appealComplain/interface/index/main";
@ -17,7 +18,7 @@ const $q = useQuasar();
const router = useRouter(); const router = useRouter();
const mixin = useCounterMixin(); const mixin = useCounterMixin();
const dataStore = useAppealComplainStore(); const dataStore = useAppealComplainStore();
const { messageError, showLoader, hideLoader } = mixin; const { messageError } = mixin;
const filterKeyword = ref<string>(""); const filterKeyword = ref<string>("");
const type = ref<DataOption[]>([ const type = ref<DataOption[]>([
@ -25,25 +26,19 @@ const type = ref<DataOption[]>([
...dataStore.typeOptions, ...dataStore.typeOptions,
]); ]);
const total = ref<number>(0); const isload = ref<boolean>(false);
const totalList = ref<number>(1); const pagination = ref<PropsTable.Pagination>({
const pagination = ref({ sortBy: "",
sortBy: "createdAt",
descending: true, descending: true,
page: 1, page: 1,
rowsPerPage: 10, rowsPerPage: 10,
rowsNumber: 0,
}); });
/**
* เพมหวขอตาราง
*/
const formData = reactive<FormType>({ const formData = reactive<FormType>({
type: "ALL", type: "ALL",
status: "ALL", status: "ALL",
year: new Date().getFullYear(), year: new Date().getFullYear(),
}); });
const visibleColumns = ref<string[]>([ const visibleColumns = ref<string[]>([
"no", "no",
"title", "title",
@ -56,7 +51,6 @@ const visibleColumns = ref<string[]>([
"lastUpdatedAt", "lastUpdatedAt",
"status", "status",
]); ]);
const columns = ref<QTableProps["columns"]>([ const columns = ref<QTableProps["columns"]>([
{ {
name: "no", name: "no",
@ -154,31 +148,33 @@ const columns = ref<QTableProps["columns"]>([
// //
async function getData() { async function getData() {
showLoader(); isload.value = true;
const params = new URLSearchParams({
status: formData.status,
type: formData.type,
year: String(formData.year),
page: String(pagination.value.page),
pageSize: String(pagination.value.rowsPerPage),
keyword: filterKeyword.value,
});
if (pagination.value.sortBy) {
params.append("sortBy", pagination.value.sortBy);
params.append("descending", String(pagination.value.descending));
}
await http await http
.get( .get(config.API.appealMainList() + `?${params.toString()}`)
config.API.appealMainList( .then(async (res) => {
formData.status, const result = res.data.result;
formData.type, pagination.value.rowsNumber = result.total;
formData.year, dataStore.fetchAppealComplain(result.data);
pagination.value.page,
pagination.value.rowsPerPage,
filterKeyword.value
)
)
.then((res) => {
totalList.value = Math.ceil(
res.data.result.total / pagination.value.rowsPerPage
);
total.value = res.data.result.total;
let data = res.data.result.data;
dataStore.fetchAppealComplain(data);
}) })
.catch((e: any) => { .catch((e) => {
messageError($q, e); messageError($q, e);
}) })
.finally(() => { .finally(() => {
hideLoader(); isload.value = false;
}); });
} }
@ -211,22 +207,21 @@ function redirectToPageadd() {
router.push(`/appeal-complain/add`); router.push(`/appeal-complain/add`);
} }
function updatePagination(newPagination: any) {
pagination.value.page = 1;
pagination.value.rowsPerPage = newPagination.rowsPerPage;
}
function getSearch() { function getSearch() {
pagination.value.page = 1; pagination.value.page = 1;
getData(); getData();
} }
watch( /**
() => pagination.value.rowsPerPage, * งกนร request จากตาราง เมอมการเปลยน pagination
async () => { * @param requestProps อมลการรองขอจากตาราง
getSearch(); */
} function onTableRequest(requestProps: PropsTable.RequestProps) {
); const newPagination = requestProps?.pagination || requestProps;
if (!newPagination?.page || !newPagination?.rowsPerPage) return;
pagination.value = { ...newPagination };
getData();
}
/** /**
* เรยกฟงกนทงหมดตอนเรยกใชไฟล * เรยกฟงกนทงหมดตอนเรยกใชไฟล
@ -238,6 +233,7 @@ onMounted(async () => {
await getData(); await getData();
}); });
</script> </script>
<template> <template>
<div class="col-12 row justify-center"> <div class="col-12 row justify-center">
<div class="col-xs-12 col-sm-12 col-md-11"> <div class="col-xs-12 col-sm-12 col-md-11">
@ -252,7 +248,7 @@ onMounted(async () => {
class="q-mr-sm" class="q-mr-sm"
@click="clickBack" @click="clickBack"
/> />
ทธรณองทกข ทธรณ/องทกข
</div> </div>
<div class="col-12"> <div class="col-12">
<q-card bordered class="q-pa-md"> <q-card bordered class="q-pa-md">
@ -264,13 +260,13 @@ onMounted(async () => {
color="primary" color="primary"
icon="mdi-plus" icon="mdi-plus"
@click="redirectToPageadd()" @click="redirectToPageadd()"
><q-tooltip>เพมการอทธรณ/องทกข</q-tooltip></q-btn
> >
<q-tooltip>เพมการอทธรณ/องทกข</q-tooltip>
</q-btn>
<div class="row col-12 q-col-gutter-sm q-mb-sm"> <div class="row col-12 q-col-gutter-sm q-mb-sm">
<div class="col-xs-12 col-md-2"> <div class="col-xs-12 col-md-2">
<datepicker <datepicker
menu-class-name="modalfix"
v-model="formData.year" v-model="formData.year"
class="col-2" class="col-2"
:locale="'th'" :locale="'th'"
@ -378,29 +374,14 @@ onMounted(async () => {
flat flat
bordered bordered
dense dense
class="custom-table2"
style="max-height: 80vh"
:rows="dataStore.rows" :rows="dataStore.rows"
:columns="dataStore.columns" :columns="dataStore.columns"
:visible-columns="dataStore.visibleColumns" :visible-columns="dataStore.visibleColumns"
:rows-per-page-options="[10, 25, 50, 100]" :rows-per-page-options="[10, 25, 50, 100]"
@update:pagination="updatePagination" @request="onTableRequest"
v-model:pagination="pagination"
:loading="isload"
> >
<template v-slot:pagination="scope">
งหมด {{ total }} รายการ
<q-pagination
v-model="pagination.page"
active-color="primary"
color="dark"
:max="Number(totalList)"
size="sm"
boundary-links
direction-links
:max-pages="5"
@update:model-value="getData()"
></q-pagination>
</template>
<template v-slot:header="props"> <template v-slot:header="props">
<q-tr :props="props"> <q-tr :props="props">
<q-th <q-th
@ -419,14 +400,10 @@ onMounted(async () => {
v-for="col in props.cols" v-for="col in props.cols"
:key="col.name" :key="col.name"
:props="props" :props="props"
@click="editPage(props.row.id)" @click.stop.prevent="editPage(props.row.id)"
> >
<div v-if="col.name == 'no'"> <div v-if="col.name == 'no'">
{{ {{ props.rowIndex + 1 }}
(pagination.page - 1) * pagination.rowsPerPage +
props.rowIndex +
1
}}
</div> </div>
<div v-else> <div v-else>
@ -439,7 +416,7 @@ onMounted(async () => {
<template #item="props"> <template #item="props">
<div class="q-pa-xs col-xs-12 col-sm-6 col-md-4 col-lg-3"> <div class="q-pa-xs col-xs-12 col-sm-6 col-md-4 col-lg-3">
<q-card bordered flat> <q-card bordered flat>
<q-list @click="editPage(props.row.id)"> <q-list @click.stop.prevent="editPage(props.row.id)">
<q-item v-for="col in props.cols" :key="col.name"> <q-item v-for="col in props.cols" :key="col.name">
<q-item-section> <q-item-section>
<q-item-label caption>{{ col.label }}</q-item-label> <q-item-label caption>{{ col.label }}</q-item-label>
@ -463,49 +440,5 @@ onMounted(async () => {
</div> </div>
</div> </div>
</template> </template>
<style lang="scss">
.icon-color {
color: #4154b3;
}
.custom-table2 { <style lang="scss"></style>
max-height: 64vh;
.q-table tr:nth-child(odd) td {
background: white;
}
.q-table tr:nth-child(even) td {
background: #f8f8f8;
}
.q-table thead tr {
background: #ecebeb;
}
.q-table thead tr th {
position: sticky;
}
.q-table td:nth-of-type(2) {
z-index: 3 !important;
}
.q-table th:nth-of-type(2),
.q-table td:nth-of-type(2) {
position: sticky;
left: 0;
z-index: 1;
}
/* this will be the loading indicator */
.q-table thead tr:last-child th {
/* height of all previous header rows */
top: 48px;
}
.q-table thead tr:first-child th {
top: 0;
}
}
</style>

View file

@ -1,15 +1,17 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from "vue"; import { ref, watch } from "vue";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import type { QTableProps } from "quasar"; import type { QTableProps } from "quasar";
import { useKpiDataStore } from "@/modules/08_KPI/store"; import { useKpiDataStore } from "@/modules/08_KPI/store";
import type { PropsTable } from "@/interface/PropsTable";
import type { ResEvaluatorAssessor } from "@/modules/08_KPI/interface/response/index"; import type { ResEvaluatorAssessor } from "@/modules/08_KPI/interface/response/index";
import type { FormQuery } from "@/modules/08_KPI/interface/request/index"; import type { FormQuery } from "@/modules/08_KPI/interface/request/index";
const store = useKpiDataStore(); const store = useKpiDataStore();
const router = useRouter(); const router = useRouter();
const isLoad = defineModel<boolean>("isLoad", { required: true });
const visibleColumns = defineModel<string[]>("visibleColumns", { const visibleColumns = defineModel<string[]>("visibleColumns", {
required: true, required: true,
}); });
@ -19,24 +21,48 @@ const columns = defineModel<QTableProps["columns"]>("columns", {
const rows = defineModel<ResEvaluatorAssessor[]>("rows", { required: true }); const rows = defineModel<ResEvaluatorAssessor[]>("rows", { required: true });
const formQuery = defineModel<FormQuery>("formQuery", { required: true }); const formQuery = defineModel<FormQuery>("formQuery", { required: true });
const total = defineModel<number>("total", { required: true }); const total = defineModel<number>("total", { required: true });
const maxPage = defineModel<number>("maxPage", { required: true });
const props = defineProps({ const props = defineProps({
updatePagination: { type: Function },
fetchList: { type: Function }, fetchList: { type: Function },
}); });
const pagination = ref({ const pagination = ref<PropsTable.Pagination>({
sortBy: "desc", sortBy: "desc",
descending: false, descending: false,
page: 1, page: formQuery.value.page,
rowsPerPage: 10, rowsPerPage: formQuery.value.pageSize,
rowsNumber: total.value,
}); });
async function redirectViewDetail(id: string) { async function redirectViewDetail(id: string) {
store.tabMain = await ""; store.tabMain = "";
router.push(`/KPI-evaluator/${id}`); router.push(`/KPI-evaluator/${id}`);
} }
/**
* งกนร request จากตาราง เมอมการเปลยน pagination
* @param requestProps อมลการรองขอจากตาราง
*/
function onTableRequest(requestProps: PropsTable.RequestProps) {
const newPagination = requestProps?.pagination || requestProps;
if (!newPagination?.page || !newPagination?.rowsPerPage) return;
formQuery.value.page = newPagination.page;
formQuery.value.pageSize = newPagination.rowsPerPage;
props?.fetchList?.();
}
watch(
[
() => formQuery.value.page,
() => formQuery.value.pageSize,
() => total.value,
],
([page, pageSize, total]) => {
pagination.value.page = page;
pagination.value.rowsPerPage = pageSize;
pagination.value.rowsNumber = total;
}
);
</script> </script>
<template> <template>
@ -50,11 +76,11 @@ async function redirectViewDetail(id: string) {
bordered bordered
:paging="true" :paging="true"
dense dense
class="custom-table2" :rows-per-page-options="[1, 10, 25, 50, 100]"
:rows-per-page-options="[10, 25, 50, 100]"
:visible-columns="visibleColumns" :visible-columns="visibleColumns"
v-model:pagination="pagination" v-model:pagination="pagination"
@update:pagination="props.updatePagination" @request="onTableRequest"
:loading="isLoad"
> >
<template v-slot:header="props"> <template v-slot:header="props">
<q-tr :props="props"> <q-tr :props="props">
@ -105,20 +131,6 @@ async function redirectViewDetail(id: string) {
</q-card> </q-card>
</div> </div>
</template> </template>
<template v-slot:pagination="scope">
งหมด {{ total }} รายการ
<q-pagination
v-model="formQuery.page"
active-color="primary"
color="dark"
:max="Number(maxPage)"
size="sm"
boundary-links
direction-links
:max-pages="5"
@update:model-value="props.fetchList?.()"
></q-pagination>
</template>
</d-table> </d-table>
</div> </div>
</template> </template>

View file

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from "vue"; import { ref, watch } from "vue";
import { useQuasar } from "quasar"; import { Loading, useQuasar } from "quasar";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import type { QTableProps } from "quasar"; import type { QTableProps } from "quasar";
@ -9,6 +9,7 @@ import http from "@/plugins/http";
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
import { useKpiDataStore } from "@/modules/08_KPI/store"; import { useKpiDataStore } from "@/modules/08_KPI/store";
import type { PropsTable } from "@/interface/PropsTable";
import type { FormQuery } from "@/modules/08_KPI/interface/request/index"; import type { FormQuery } from "@/modules/08_KPI/interface/request/index";
import type { ResEvaluatorAssessor } from "@/modules/08_KPI/interface/response/index"; import type { ResEvaluatorAssessor } from "@/modules/08_KPI/interface/response/index";
@ -33,24 +34,24 @@ const columns = defineModel<QTableProps["columns"]>("columns", {
const rows = defineModel<ResEvaluatorAssessor[]>("rows", { required: true }); const rows = defineModel<ResEvaluatorAssessor[]>("rows", { required: true });
const formQuery = defineModel<FormQuery>("formQuery", { required: true }); const formQuery = defineModel<FormQuery>("formQuery", { required: true });
const total = defineModel<number>("total", { required: true }); const total = defineModel<number>("total", { required: true });
const maxPage = defineModel<number>("maxPage", { required: true }); const isLoad = defineModel<boolean>("isLoad", { required: true });
const props = defineProps({ const props = defineProps({
updatePagination: { type: Function },
fetchList: { type: Function }, fetchList: { type: Function },
}); });
const pagination = ref<PropsTable.Pagination>({
sortBy: "desc",
descending: false,
page: formQuery.value.page,
rowsPerPage: formQuery.value.pageSize,
rowsNumber: total.value,
});
function redirectViewDetail(id: string) { function redirectViewDetail(id: string) {
router.push(`/KPI-evaluator/${id}`); router.push(`/KPI-evaluator/${id}`);
} }
const pagination = ref({
sortBy: "desc",
descending: false,
page: 1,
rowsPerPage: 10,
});
async function onClickApprove(type: string = "") { async function onClickApprove(type: string = "") {
if (store.selected.length !== 0) { if (store.selected.length !== 0) {
const userIds = await store.selected.map( const userIds = await store.selected.map(
@ -104,6 +105,31 @@ async function onClickApprove(type: string = "") {
dialogMessageNotify($q, "เลือกอย่างน้อย 1 รายการ"); dialogMessageNotify($q, "เลือกอย่างน้อย 1 รายการ");
} }
} }
/**
* งกนร request จากตาราง เมอมการเปลยน pagination
* @param requestProps อมลการรองขอจากตาราง
*/
function onTableRequest(requestProps: PropsTable.RequestProps) {
const newPagination = requestProps?.pagination || requestProps;
if (!newPagination?.page || !newPagination?.rowsPerPage) return;
formQuery.value.page = newPagination.page;
formQuery.value.pageSize = newPagination.rowsPerPage;
props?.fetchList?.();
}
watch(
[
() => formQuery.value.page,
() => formQuery.value.pageSize,
() => total.value,
],
([page, pageSize, total]) => {
pagination.value.page = page;
pagination.value.rowsPerPage = pageSize;
pagination.value.rowsNumber = total;
}
);
</script> </script>
<template> <template>
@ -120,13 +146,14 @@ async function onClickApprove(type: string = "") {
:rows-per-page-options="[10, 25, 50, 100]" :rows-per-page-options="[10, 25, 50, 100]"
:visible-columns="visibleColumns" :visible-columns="visibleColumns"
v-model:pagination="pagination" v-model:pagination="pagination"
@update:pagination="props.updatePagination"
:selection=" :selection="
store.tabMainevaluator === '5' || store.tabMainevaluator === '6' store.tabMainevaluator === '5' || store.tabMainevaluator === '6'
? 'none' ? 'none'
: 'multiple' : 'multiple'
" "
v-model:selected="store.selected" v-model:selected="store.selected"
@request="onTableRequest"
:loading="isLoad"
> >
<template v-slot:header-selection="scope"> <template v-slot:header-selection="scope">
<q-checkbox keep-color color="primary" dense v-model="scope.selected" /> <q-checkbox keep-color color="primary" dense v-model="scope.selected" />
@ -187,10 +214,7 @@ async function onClickApprove(type: string = "") {
</q-card-section> </q-card-section>
<q-separator /> <q-separator />
<q-list @click="redirectViewDetail(props.row.id)"> <q-list @click="redirectViewDetail(props.row.id)">
<q-item <q-item v-for="col in props.cols" :key="col.name">
v-for="col in props.cols"
:key="col.name"
>
<q-item-section> <q-item-section>
<q-item-label caption>{{ col.label }}</q-item-label> <q-item-label caption>{{ col.label }}</q-item-label>
@ -210,20 +234,6 @@ async function onClickApprove(type: string = "") {
</q-card> </q-card>
</div> </div>
</template> </template>
<template v-slot:pagination="scope">
งหมด {{ total }} รายการ
<q-pagination
v-model="formQuery.page"
active-color="primary"
color="dark"
:max="Number(maxPage)"
size="sm"
boundary-links
direction-links
:max-pages="5"
@update:model-value="props.fetchList?.()"
></q-pagination>
</template>
</d-table> </d-table>
</div> </div>

View file

@ -37,6 +37,10 @@ const store = useKpiDataStore();
const evaluationId = ref<string>(route.params.id.toString()); const evaluationId = ref<string>(route.params.id.toString());
const isLoad01 = ref<boolean>(false);
const isLoad02 = ref<boolean>(false);
const isLoad03 = ref<boolean>(false);
const rows_01 = ref<EvaluationIndicatorType[]>(); const rows_01 = ref<EvaluationIndicatorType[]>();
const rows_02 = ref<EvaluationIndicatorType[]>(); const rows_02 = ref<EvaluationIndicatorType[]>();
const rows_03 = ref<EvaluationIndicatorType[]>(); const rows_03 = ref<EvaluationIndicatorType[]>();
@ -53,6 +57,7 @@ const resultRole = ref<number>(0);
const resultAssigned = ref<number>(0); const resultAssigned = ref<number>(0);
function fetchListPlanned() { function fetchListPlanned() {
isLoad01.value = true;
http http
.get(config.API.kpiAchievement("planned") + `?id=${evaluationId.value}`) .get(config.API.kpiAchievement("planned") + `?id=${evaluationId.value}`)
.then((res) => { .then((res) => {
@ -62,6 +67,7 @@ function fetchListPlanned() {
evaluationResults: (e.point / 5) * e.weight, evaluationResults: (e.point / 5) * e.weight,
})); }));
rows_01.value = newRow; rows_01.value = newRow;
isLoad01.value = false;
if (newRow.length > 0) { if (newRow.length > 0) {
resultPlanned.value = newRow.reduce( resultPlanned.value = newRow.reduce(
@ -89,6 +95,7 @@ function fetchListPlanned() {
} }
function fetchListRole() { function fetchListRole() {
isLoad02.value = true;
http http
.get(config.API.kpiAchievement("role") + `?id=${evaluationId.value}`) .get(config.API.kpiAchievement("role") + `?id=${evaluationId.value}`)
.then((res) => { .then((res) => {
@ -98,7 +105,7 @@ function fetchListRole() {
evaluationResults: (e.point / 5) * e.weight, evaluationResults: (e.point / 5) * e.weight,
})); }));
rows_02.value = newRow; rows_02.value = newRow;
isLoad02.value = false;
if (newRow.length > 0) { if (newRow.length > 0) {
resultRole.value = newRow.reduce( resultRole.value = newRow.reduce(
(sum: number, e: any) => sum + e.evaluationResults, (sum: number, e: any) => sum + e.evaluationResults,
@ -119,6 +126,7 @@ function fetchListRole() {
} }
function fetchAssigned() { function fetchAssigned() {
isLoad03.value = true;
http http
.get(config.API.kpiAchievement("special") + `?id=${evaluationId.value}`) .get(config.API.kpiAchievement("special") + `?id=${evaluationId.value}`)
.then((res) => { .then((res) => {
@ -129,7 +137,7 @@ function fetchAssigned() {
})); }));
rows_03.value = newRow; rows_03.value = newRow;
isLoad03.value = false;
if (newRow.length > 0) { if (newRow.length > 0) {
resultAssigned.value = newRow.reduce( resultAssigned.value = newRow.reduce(
(sum: number, e: any) => sum + e.evaluationResults, (sum: number, e: any) => sum + e.evaluationResults,
@ -195,8 +203,10 @@ watch(
store.indicatorScoreVal = store.indicatorScoreVal =
store.indicatorPercentVal * store.indicatorPercentVal *
((store.dataProfile.isProbation ((store.dataEvaluation.isProbation
? store.indicatorProbationScore ? store.indicatorProbationScore
: groupNo.value == 2
? store.excusiveIndicatorScore
: store.indicatorScore) / : store.indicatorScore) /
100); 100);
} }
@ -228,7 +238,39 @@ async function onSubmitReject() {
}); });
} }
// check group of form
const groupNo = computed(() => {
if (
store.dataEvaluation.posExecutiveName == "ปลัดกรุงเทพมหานคร" ||
store.dataEvaluation.posExecutiveName == "รองปลัดกรุงเทพมหานคร" ||
store.dataEvaluation.posExecutiveName == "ผู้อำนวยการสำนัก" ||
store.dataEvaluation.posExecutiveName == "หัวหน้าสำนักงานก.ก." ||
store.dataEvaluation.posExecutiveName == "หัวหน้าสำนักงาน ก.ก." ||
store.dataEvaluation.posExecutiveName ==
"หัวหน้าสำนักงานเลขานุการผู้ว่าราชการกรุงเทพมหานคร" ||
store.dataEvaluation.posExecutiveName == "เลขานุการสภากรุงเทพมหานคร" ||
store.dataEvaluation.posExecutiveName == "ผู้อำนวยการเขต" ||
store.dataEvaluation.posExecutiveName ==
"หัวหน้าส่วนราชการในสังกัดสำนักปลัดกรุงเทพมหานคร"
) {
return 1;
} else if (
store.dataEvaluation.posTypeName == "อำนวยการ" ||
store.dataEvaluation.posTypeName == "บริหาร" ||
(store.dataEvaluation.posTypeName == "วิชาการ" &&
store.dataEvaluation.posExecutiveName != null) ||
(store.dataEvaluation.posTypeName == "ทั่วไป" &&
store.dataEvaluation.posLevelName == "อาวุโส" &&
store.dataEvaluation.posExecutiveName != null)
) {
return 2;
} else {
return 3;
}
});
onMounted(() => { onMounted(() => {
store.indicatorWeightTotal = 0
getCriteria(); getCriteria();
fetchListPlanned(); fetchListPlanned();
fetchListRole(); fetchListRole();
@ -309,14 +351,10 @@ onMounted(() => {
</div> </div>
<div class="q-gutter-md q-mt-sm"> <div class="q-gutter-md q-mt-sm">
<!-- องคประกอบท 1 --> <!-- องคประกอบท 1 -->
<div <div v-if="groupNo == 1">
v-if="
store.dataEvaluation.posTypeName == 'อำนวยการ' ||
store.dataEvaluation.posTypeName == 'บริหาร'
"
>
<Work <Work
v-model:data="rows_01" v-model:data="rows_01"
v-model:isLoad="isLoad01"
:title="`มิติที่ 1 ภารกิจตามนโยบายและยุทธศาสตร์ของกรุงเทพมหานคร`" :title="`มิติที่ 1 ภารกิจตามนโยบายและยุทธศาสตร์ของกรุงเทพมหานคร`"
:page="1" :page="1"
:fetchList="fetchListPlanned" :fetchList="fetchListPlanned"
@ -363,6 +401,7 @@ onMounted(() => {
<Work <Work
v-model:data="rows_03" v-model:data="rows_03"
v-model:isLoad="isLoad03"
:title="`มิติที่ 2 วาระเร่งด่วนที่ได้รับมอบหมายพิเศษ (ถ้ามี)`" :title="`มิติที่ 2 วาระเร่งด่วนที่ได้รับมอบหมายพิเศษ (ถ้ามี)`"
:page="3" :page="3"
:fetchList="fetchAssigned" :fetchList="fetchAssigned"
@ -409,12 +448,16 @@ onMounted(() => {
คะแนน)</span คะแนน)</span
> >
<div class="text-primary q-pl-md"> <div class="text-primary q-pl-md">
{{ <div v-if="!isLoad01">
( {{
store.excusiveIndicator1ScoreVal + (
store.excusiveIndicator2ScoreVal store.excusiveIndicator1ScoreVal +
).toFixed(2) store.excusiveIndicator2ScoreVal
}} ).toFixed(2)
}}
</div>
<q-skeleton v-else type="text" />
</div> </div>
</div> </div>
</div> </div>
@ -424,6 +467,7 @@ onMounted(() => {
<div v-else> <div v-else>
<Work <Work
v-model:data="rows_01" v-model:data="rows_01"
v-model:isLoad="isLoad01"
:title="`1. งานตามแผนปฏิบัติราชการประจำปี`" :title="`1. งานตามแผนปฏิบัติราชการประจำปี`"
:page="1" :page="1"
:fetchList="fetchListPlanned" :fetchList="fetchListPlanned"
@ -431,6 +475,7 @@ onMounted(() => {
/> />
<Work <Work
v-model:data="rows_02" v-model:data="rows_02"
v-model:isLoad="isLoad02"
:title="`2. งานตามหน้าที่ความรับผิดชอบหลัก`" :title="`2. งานตามหน้าที่ความรับผิดชอบหลัก`"
:page="2" :page="2"
:fetchList="fetchListRole" :fetchList="fetchListRole"
@ -438,6 +483,7 @@ onMounted(() => {
/> />
<Work <Work
v-model:data="rows_03" v-model:data="rows_03"
v-model:isLoad="isLoad03"
:title="`3. งานอื่น ๆ ที่ได้รับมอบหมาย`" :title="`3. งานอื่น ๆ ที่ได้รับมอบหมาย`"
:page="3" :page="3"
:fetchList="fetchAssigned" :fetchList="fetchAssigned"
@ -480,14 +526,19 @@ onMounted(() => {
<span <span
>สรปผลการประเมนผลสมฤทธของงาน (คะแนนเต >สรปผลการประเมนผลสมฤทธของงาน (คะแนนเต
{{ {{
store.dataProfile.isProbation store.dataEvaluation.isProbation
? store.indicatorProbationScore ? store.indicatorProbationScore
: groupNo == 2
? store.excusiveIndicatorScore
: store.indicatorScore : store.indicatorScore
}} }}
คะแนน)</span คะแนน)</span
> >
<div class="text-primary q-pl-md"> <div class="text-primary q-pl-md">
{{ store.indicatorScoreVal.toFixed(2) }} <div v-if="!isLoad01">
{{ store.indicatorScoreVal.toFixed(2) }}
</div>
<q-skeleton v-else type="text" />
</div> </div>
</div> </div>
</div> </div>
@ -512,9 +563,8 @@ onMounted(() => {
:rows="[ :rows="[
{ {
name: `สรุปผลการประเมินสมรรถนะ (คะแนนเต็ม ${ name: `สรุปผลการประเมินสมรรถนะ (คะแนนเต็ม ${
store.dataEvaluation.posTypeName != 'อำนวยการ' && groupNo == 3
store.dataEvaluation.posTypeName != 'บริหาร' ? store.dataEvaluation.isProbation
? store.dataProfile.isProbation
? store.competencyProbationScore ? store.competencyProbationScore
: store.competencyScore : store.competencyScore
: store.excusiveCompetencyScore : store.excusiveCompetencyScore
@ -542,12 +592,7 @@ onMounted(() => {
class="q-mt-xs q-mb-md" class="q-mt-xs q-mb-md"
/> />
<div <div v-if="groupNo == 3">
v-if="
store.dataEvaluation.posTypeName != 'อำนวยการ' &&
store.dataEvaluation.posTypeName != 'บริหาร'
"
>
<Develop /> <Develop />
<div v-if="isShowScore"> <div v-if="isShowScore">
@ -558,7 +603,7 @@ onMounted(() => {
:rows="[ :rows="[
{ {
name: `ผลการประเมินการพัฒนาตนเอง (คะแนนเต็ม ${ name: `ผลการประเมินการพัฒนาตนเอง (คะแนนเต็ม ${
store.dataProfile.isProbation store.dataEvaluation.isProbation
? store.devProbationScore ? store.devProbationScore
: store.devScore : store.devScore
} คะแนน)`, } คะแนน)`,
@ -588,19 +633,13 @@ onMounted(() => {
</div> </div>
<div v-if="isShowScore"> <div v-if="isShowScore">
<div <div v-if="groupNo == 3" class="row text-body2 text-weight-bold">
v-if="
store.dataEvaluation.posTypeName != 'อำนวยการ' &&
store.dataEvaluation.posTypeName != 'บริหาร'
"
class="row text-body2 text-weight-bold"
>
<div class="col-12 text-center row justify-center"> <div class="col-12 text-center row justify-center">
<span> <span>
สรปผลการประเมนพฤตกรรมการปฏราชการ (สมรรถนะ+การพฒนาตนเอง) สรปผลการประเมนพฤตกรรมการปฏราชการ (สมรรถนะ+การพฒนาตนเอง)
(คะแนนเต (คะแนนเต
{{ {{
store.dataProfile.isProbation store.dataEvaluation.isProbation
? store.competencyDevProbationScore ? store.competencyDevProbationScore
: store.competencyDevScore : store.competencyDevScore
}} }}

View file

@ -175,7 +175,7 @@ onMounted(() => {
debounce="300" debounce="300"
v-model="filterKeyword" v-model="filterKeyword"
placeholder="ค้นหา" placeholder="ค้นหา"
@keydown.enter="onSearch" @keydown.enter.prevent="onSearch"
> >
<template v-slot:append> <template v-slot:append>
<q-icon name="search" /> <q-icon name="search" />

View file

@ -192,7 +192,9 @@ function userOpen() {
}); });
} }
const isLoad = ref<boolean>(false);
function getData() { function getData() {
isLoad.value = true;
http http
.get(config.API.kpiSendToGet(id.value)) .get(config.API.kpiSendToGet(id.value))
.then((res) => { .then((res) => {
@ -220,9 +222,11 @@ function getData() {
sumWeight.value = data.weightPoint1 + data.weightPoint2; sumWeight.value = data.weightPoint1 + data.weightPoint2;
sumResult.value = data.summaryPoint; sumResult.value = data.summaryPoint;
result.value = data.evaluationResults; result.value = data.evaluationResults;
isLoad.value = false;
}) })
.catch((e) => { .catch((e) => {
messageError($q, e); messageError($q, e);
isLoad.value = false;
}) })
.finally(() => {}); .finally(() => {});
} }
@ -306,22 +310,47 @@ onMounted(() => {
<tbody> <tbody>
<tr> <tr>
<td class="text-left">องคประกอบท 1 ผลสมฤทธของงาน</td> <td class="text-left">องคประกอบท 1 ผลสมฤทธของงาน</td>
<td class="text-left">{{ weight1 }}</td> <td class="text-left">
<td class="text-left">{{ result1 }}</td> <div v-if="!isLoad">
{{ weight1 }}
</div>
<q-skeleton v-else type="text" />
</td>
<td class="text-left">
<div v-if="!isLoad">{{ result1 }}</div>
<q-skeleton v-else type="text" />
</td>
</tr> </tr>
<tr> <tr>
<td class="text-left"> <td class="text-left">
องคประกอบท 2 พฤตกรรมการปฎราชการ (สมรรถนะ) องคประกอบท 2 พฤตกรรมการปฎราชการ (สมรรถนะ)
</td> </td>
<td class="text-left">{{ weight2 }}</td> <td class="text-left">
<td class="text-left">{{ result2 }}</td> <div v-if="!isLoad">{{ weight2 }}</div>
<q-skeleton v-else type="text" />
</td>
<td class="text-left">
<div v-if="!isLoad">{{ result2 }}</div>
<q-skeleton v-else type="text" />
</td>
</tr> </tr>
<tr> <tr>
<td class="text-right text-bold" style="font-size: 16px"> <td class="text-right text-bold" style="font-size: 16px">
รวม รวม
</td> </td>
<td class="text-left">{{ sumWeight }}</td> <td class="text-left">
<td class="text-left">{{ sumResult }}</td> <div v-if="!isLoad">{{ sumWeight }}</div>
<q-skeleton v-else type="text" />
</td>
<td class="text-left">
<div v-if="!isLoad">{{ sumResult }}</div>
<q-skeleton v-else type="text" />
</td>
</tr> </tr>
</tbody> </tbody>
</q-markup-table> </q-markup-table>
@ -332,7 +361,7 @@ onMounted(() => {
</div> </div>
</div> </div>
<div class="col-12 no-pointer"> <div class="col-12 no-pointer">
<div class="column"> <div class="column" v-if="!isLoad">
<q-radio <q-radio
v-model="result" v-model="result"
checked-icon="task_alt" checked-icon="task_alt"
@ -369,6 +398,12 @@ onMounted(() => {
label="ต้องปรับปรุง (คะแนนต่ำกว่าร้อยละ 60.00)" label="ต้องปรับปรุง (คะแนนต่ำกว่าร้อยละ 60.00)"
/> />
</div> </div>
<q-item v-else dense v-for="item in 5" style="max-width: 300px;">
<q-item-section class="q-pa-none">
<q-skeleton type="text" />
</q-item-section>
</q-item>
</div> </div>
<div class="col-12"> <div class="col-12">
<div class="text-weight-bold text-body2"> <div class="text-weight-bold text-body2">
@ -378,6 +413,7 @@ onMounted(() => {
<div class="col-12"> <div class="col-12">
<q-input <q-input
v-if="!isLoad"
v-model="title" v-model="title"
outlined outlined
lazy-rules lazy-rules
@ -390,9 +426,11 @@ onMounted(() => {
" "
:rules="[(val:string) => !!val || `${'กรุณากรอกชื่อเรื่อง/เนื้อหา/หัวข้อการพัฒนา'}`,]" :rules="[(val:string) => !!val || `${'กรุณากรอกชื่อเรื่อง/เนื้อหา/หัวข้อการพัฒนา'}`,]"
/> />
<q-skeleton v-else type="QInput" height="150px" />
</div> </div>
<div class="col-12"> <div class="col-12">
<q-input <q-input
v-if="!isLoad"
v-model="developmentMethod" v-model="developmentMethod"
outlined outlined
lazy-rules lazy-rules
@ -405,9 +443,11 @@ onMounted(() => {
" "
:rules="[(val:string) => !!val || `${'กรุณากรอกวิธีการพัฒนา'}`,]" :rules="[(val:string) => !!val || `${'กรุณากรอกวิธีการพัฒนา'}`,]"
/> />
<q-skeleton v-else type="QInput" height="150px" />
</div> </div>
<div class="col-12"> <div class="col-12">
<q-input <q-input
v-if="!isLoad"
v-model="developmentPeriod" v-model="developmentPeriod"
outlined outlined
hide-bottom-space hide-bottom-space
@ -420,6 +460,7 @@ onMounted(() => {
" "
:rules="[(val:string) => !!val || `${'กรุณากรอกช่วงเวลาการพัฒนา'}`,]" :rules="[(val:string) => !!val || `${'กรุณากรอกช่วงเวลาการพัฒนา'}`,]"
/> />
<q-skeleton v-else type="QInput" height="150px" />
</div> </div>
<div class="col-12"> <div class="col-12">
<div class="text-weight-bold text-body2"> <div class="text-weight-bold text-body2">
@ -428,6 +469,7 @@ onMounted(() => {
</div> </div>
<div class="col-12"> <div class="col-12">
<q-input <q-input
v-if="!isLoad"
v-model="evaluatorComment" v-model="evaluatorComment"
outlined outlined
lazy-rules lazy-rules
@ -440,6 +482,7 @@ onMounted(() => {
" "
:rules="[(val:string) => !!val || `${'กรุณากรอกความเห็นของ'}`,]" :rules="[(val:string) => !!val || `${'กรุณากรอกความเห็นของ'}`,]"
/> />
<q-skeleton v-else type="QInput" height="150px" />
</div> </div>
</div> </div>
</q-card-section> </q-card-section>
@ -519,6 +562,7 @@ onMounted(() => {
<div class="col-12"> <div class="col-12">
<q-input <q-input
v-if="!isLoad"
lazy-rules lazy-rules
v-model="superiorComment" v-model="superiorComment"
outlined outlined
@ -538,6 +582,7 @@ onMounted(() => {
ref="superiorCommentRef" ref="superiorCommentRef"
:rules="[(val:string) => superiorCommentCheck !== 'false'||!!val || `${'กรุณากรอกความเห็น'}`,]" :rules="[(val:string) => superiorCommentCheck !== 'false'||!!val || `${'กรุณากรอกความเห็น'}`,]"
/> />
<q-skeleton v-else type="QInput" height="150px" />
</div> </div>
</div> </div>
</q-card-section> </q-card-section>
@ -621,6 +666,7 @@ onMounted(() => {
</div> </div>
<div class="col-12"> <div class="col-12">
<q-input <q-input
v-if="!isLoad"
lazy-rules lazy-rules
ref="additionalSuperiorCommentRef" ref="additionalSuperiorCommentRef"
v-model="additionalSuperiorComment" v-model="additionalSuperiorComment"
@ -641,6 +687,7 @@ onMounted(() => {
" "
:rules="[(val:string) => additionalSuperiorCheck !== 'false'||!!val || `${'กรุณากรอกความเห็น'}`,]" :rules="[(val:string) => additionalSuperiorCheck !== 'false'||!!val || `${'กรุณากรอกความเห็น'}`,]"
/> />
<q-skeleton v-else type="QInput" height="150px" />
</div> </div>
</div> </div>
</q-card-section> </q-card-section>

View file

@ -32,18 +32,20 @@ const isReadonly = ref<boolean>(
const documentFile = ref<any>(null); const documentFile = ref<any>(null);
const fileList = ref<ArrayFileList[]>([]); const fileList = ref<ArrayFileList[]>([]);
const isLoad = ref<boolean>(false);
async function getData() { async function getData() {
showLoader(); isLoad.value = true;
await http await http
.get(config.API.file("ไฟล์เอกสาร", "KPI", id.value)) .get(config.API.file("ไฟล์เอกสาร", "KPI", id.value))
.then((res) => { .then((res) => {
fileList.value = res.data; fileList.value = res.data;
isLoad.value = false;
}) })
.catch((e) => { .catch((e) => {
messageError($q, e); messageError($q, e);
}) })
.finally(() => { .finally(() => {
hideLoader(); isLoad.value = false;
}); });
} }
@ -190,7 +192,11 @@ onMounted(() => {
<!-- <div class="col-1 self-center" v-if="formData.documentFile"></div> --> <!-- <div class="col-1 self-center" v-if="formData.documentFile"></div> -->
</div> </div>
<div v-if="fileList.length > 0" class="col-xs-12 row"> <div v-if="isLoad" class="col-12">
<q-skeleton />
</div>
<div v-else-if="fileList.length > 0" class="col-xs-12 row">
<q-list class="full-width rounded-borders" bordered separator> <q-list class="full-width rounded-borders" bordered separator>
<q-item <q-item
clickable clickable

View file

@ -36,6 +36,8 @@ const search = ref<string>("");
const listCheckID = ref<string | null>(null); const listCheckID = ref<string | null>(null);
const listTarget = ref<any>([]); const listTarget = ref<any>([]);
const isLoad = ref<boolean>(false);
const isLoadList = ref<boolean>(false);
const formFilter = reactive<any>({ const formFilter = reactive<any>({
isAll: false, isAll: false,
keyword: "", keyword: "",
@ -86,23 +88,25 @@ const roundOp = ref<DataOptions[]>([
]); ]);
function fetchListPlan() { function fetchListPlan() {
formFilter.nodeId = store.dataProfile.nodeDnaId; formFilter.nodeId = formFilter.isAll
formFilter.node = store.dataProfile.node; ? store.dataProfile.rootDnaId
: store.dataProfile.nodeDnaId;
formFilter.node = formFilter.isAll ? 0 : store.dataProfile.node;
formFilter.year = formFilter?.year ? formFilter.year.toString() : ""; formFilter.year = formFilter?.year ? formFilter.year.toString() : "";
isLoadList.value = true;
showLoader();
http http
.post(config.API.kpiPlan + `/search`, formFilter) .post(config.API.kpiPlan + `/search`, formFilter)
.then((res) => { .then((res) => {
listTarget.value = res.data.result.data; listTarget.value = res.data.result.data;
maxPage.value = Math.ceil(res.data.result.total / formFilter.pageSize); maxPage.value = Math.ceil(res.data.result.total / formFilter.pageSize);
totalList.value = res.data.result.total; totalList.value = res.data.result.total;
isLoadList.value = false;
}) })
.catch((err) => { .catch((err) => {
messageError($q, err); messageError($q, err);
}) })
.finally(() => { .finally(() => {
hideLoader(); isLoadList.value = false;
}); });
} }
@ -111,7 +115,7 @@ function fetchListPlan() {
* @param id id * @param id id
*/ */
function fetchListPlanByid(id: string) { function fetchListPlanByid(id: string) {
showLoader(); isLoad.value = true;
http http
.get(config.API.kpiAchievement("planned") + `/${id}`) .get(config.API.kpiAchievement("planned") + `/${id}`)
.then((res) => { .then((res) => {
@ -136,38 +140,42 @@ function fetchListPlanByid(id: string) {
formDetail.endDate = data.endDate; formDetail.endDate = data.endDate;
listCheckID.value = data.kpiPlanId; listCheckID.value = data.kpiPlanId;
isLoad.value = false;
}) })
.catch((err) => { .catch((err) => {
messageError($q, err); messageError($q, err);
}) })
.finally(() => { .finally(() => {
hideLoader(); isLoad.value = false;
}); });
} }
function fetchListRole() { function fetchListRole() {
formFilter.nodeId = store.dataProfile.nodeDnaId; formFilter.nodeId = formFilter.isAll
formFilter.node = store.dataProfile.node; ? store.dataProfile.rootDnaId
: store.dataProfile.nodeDnaId;
formFilter.node = formFilter.isAll ? 0 : store.dataProfile.node;
formFilter.year = formFilter?.year ? formFilter.year.toString() : ""; formFilter.year = formFilter?.year ? formFilter.year.toString() : "";
formFilter.position = store.dataProfile.position; formFilter.position = store.dataProfile.position;
isLoadList.value = true;
http http
.post(config.API.kpiRole + `/search`, formFilter) .post(config.API.kpiRole + `/search`, formFilter)
.then((res) => { .then((res) => {
listTarget.value = res.data.result.data; listTarget.value = res.data.result.data;
maxPage.value = Math.ceil(res.data.result.total / formFilter.pageSize); maxPage.value = Math.ceil(res.data.result.total / formFilter.pageSize);
totalList.value = res.data.result.total; totalList.value = res.data.result.total;
isLoadList.value = false;
}) })
.catch((err) => { .catch((err) => {
messageError($q, err); messageError($q, err);
}) })
.finally(() => { .finally(() => {
hideLoader(); isLoadList.value = false;
}); });
} }
function fetchRoleByid(id: string) { function fetchRoleByid(id: string) {
showLoader(); isLoad.value = true;
http http
.get(config.API.kpiAchievement("role") + `/${id}`) .get(config.API.kpiAchievement("role") + `/${id}`)
.then((res) => { .then((res) => {
@ -189,18 +197,17 @@ function fetchRoleByid(id: string) {
formDetail.includingName = data.includingName; formDetail.includingName = data.includingName;
formDetail.including = data.including; formDetail.including = data.including;
listCheckID.value = data.kpiRoleId; listCheckID.value = data.kpiRoleId;
isLoad.value = false;
}) })
.catch((err) => { .catch((err) => {
messageError($q, err); messageError($q, err);
}) })
.finally(() => { .finally(() => {
hideLoader(); isLoad.value = false;
}); });
} }
function fetchListSpecial() { function fetchListSpecial() {
// formFilter.nodeId = store.dataProfile.nodeDnaId;
// formFilter.node = store.dataProfile.node;
formFilter.year = formFilter?.year ? formFilter.year.toString() : ""; formFilter.year = formFilter?.year ? formFilter.year.toString() : "";
const body = { const body = {
@ -210,25 +217,25 @@ function fetchListSpecial() {
pageSize: formFilter.pageSize, pageSize: formFilter.pageSize,
page: formFilter.page, page: formFilter.page,
}; };
isLoadList.value = true;
showLoader();
http http
.post(config.API.kpiSpecial + `/search`, body) .post(config.API.kpiSpecial + `/search`, body)
.then((res) => { .then((res) => {
listTarget.value = res.data.result.data; listTarget.value = res.data.result.data;
maxPage.value = Math.ceil(res.data.result.total / formFilter.pageSize); maxPage.value = Math.ceil(res.data.result.total / formFilter.pageSize);
totalList.value = res.data.result.total; totalList.value = res.data.result.total;
isLoadList.value = false;
}) })
.catch((err) => { .catch((err) => {
messageError($q, err); messageError($q, err);
}) })
.finally(() => { .finally(() => {
hideLoader(); isLoadList.value = false;
}); });
} }
function fetchspecialByid(id: string) { function fetchspecialByid(id: string) {
showLoader(); isLoad.value = true;
http http
.get(config.API.kpiAchievement("special") + `/${id}`) .get(config.API.kpiAchievement("special") + `/${id}`)
.then((res) => { .then((res) => {
@ -250,18 +257,19 @@ function fetchspecialByid(id: string) {
formDetail.endDate = data.endDate; formDetail.endDate = data.endDate;
listCheckID.value = data.kpiSpecialId; listCheckID.value = data.kpiSpecialId;
isLoad.value = false;
}) })
.catch((err) => { .catch((err) => {
messageError($q, err); messageError($q, err);
}) })
.finally(() => { .finally(() => {
hideLoader(); isLoad.value = false;
}); });
} }
function clickList(id: string, isData: boolean = false) { function clickList(id: string, isData: boolean = false) {
if (!checkDetail.value) { if (!checkDetail.value) {
showLoader(); isLoad.value=true
const url = const url =
numpage.value === 1 numpage.value === 1
? config.API.kpiPlan ? config.API.kpiPlan
@ -299,12 +307,13 @@ function clickList(id: string, isData: boolean = false) {
formDetail.strategyId = data.strategyId; formDetail.strategyId = data.strategyId;
formDetail.strategyName = data.strategyName; formDetail.strategyName = data.strategyName;
formDetail.documentInfoEvidence = data.documentInfoEvidence; formDetail.documentInfoEvidence = data.documentInfoEvidence;
isLoad.value=false
}) })
.catch((err) => { .catch((err) => {
messageError($q, err); messageError($q, err);
}) })
.finally(() => { .finally(() => {
hideLoader(); isLoad.value=false
}); });
} }
} }
@ -593,7 +602,7 @@ const title = computed(() => {
<q-separator /> <q-separator />
<q-card-section class="q-pa-none"> <q-card-section class="q-pa-none">
<q-list separator> <q-list separator v-if="!isLoadList">
<q-item <q-item
dense dense
v-for="(item, index) in listTarget" v-for="(item, index) in listTarget"
@ -620,6 +629,25 @@ const title = computed(() => {
</q-item-section> </q-item-section>
</q-item> </q-item>
</q-list> </q-list>
<q-list v-else separator>
<q-item dense v-for="item in 2">
<q-item-section class="q-pa-none">
<div
class="row items-center"
style="min-height: 50px"
>
<div class="col-5">
<q-skeleton type="text" width="50px" />
</div>
<div class="col-7">
<q-skeleton type="text" />
</div>
</div>
</q-item-section>
</q-item>
</q-list>
<q-separator /> <q-separator />
<div <div
class="q-pa-lg flex justify-end" class="q-pa-lg flex justify-end"
@ -660,18 +688,33 @@ const title = computed(() => {
<div class="q-pa-sm q-col-gutter-lg"> <div class="q-pa-sm q-col-gutter-lg">
<div class="col-12 row" v-if="numpage !== 3"> <div class="col-12 row" v-if="numpage !== 3">
<div class="col-4 text-grey-6">หนวยงาน/วนราชการ</div> <div class="col-4 text-grey-6">หนวยงาน/วนราชการ</div>
<div class="col-8">{{ formDetail.nodeName }}</div> <div v-if="!isLoad" class="col-8">
{{ formDetail.nodeName }}
</div>
<div class="col-8" v-else>
<q-skeleton type="text" />
</div>
</div> </div>
<div class="col-12 row" v-if="numpage === 1"> <div class="col-12 row" v-if="numpage === 1">
<div class="col-4 text-grey-6">ทธศาสตร / แผน</div> <div class="col-4 text-grey-6">ทธศาสตร / แผน</div>
<div class="col-8">{{ formDetail.strategyName }}</div> <div v-if="!isLoad" class="col-8">
{{ formDetail.strategyName }}
</div>
<div class="col-8" v-else>
<q-skeleton type="text" />
</div>
</div> </div>
<div class="col-12 row"> <div class="col-12 row">
<div class="col-4 text-grey-6">ลำด/รหสตวช</div> <div class="col-4 text-grey-6">ลำด/รหสตวช</div>
<div class="col-8"> <div class="col-8">
<q-skeleton
v-if="isLoad"
type="QInput"
height="40px"
/>
<q-input <q-input
v-if="numpage === 3" v-else-if="numpage === 3"
outlined outlined
:readonly="checkDetail" :readonly="checkDetail"
v-model="formDetail.including" v-model="formDetail.including"
@ -692,8 +735,13 @@ const title = computed(() => {
<div class="col-12 row"> <div class="col-12 row">
<div class="col-4 text-grey-6">อตวช</div> <div class="col-4 text-grey-6">อตวช</div>
<div class="col-8"> <div class="col-8">
<q-skeleton
v-if="isLoad"
type="QInput"
height="40px"
/>
<q-input <q-input
v-if="numpage === 3" v-else-if="numpage === 3"
outlined outlined
:readonly="checkDetail" :readonly="checkDetail"
v-model="formDetail.includingName" v-model="formDetail.includingName"
@ -713,6 +761,7 @@ const title = computed(() => {
<div class="col-4 text-grey-6">าเปาหมาย</div> <div class="col-4 text-grey-6">าเปาหมาย</div>
<div class="col-8"> <div class="col-8">
<q-input <q-input
v-if="!isLoad"
outlined outlined
v-model="formDetail.target" v-model="formDetail.target"
bg-color="white" bg-color="white"
@ -725,12 +774,14 @@ const title = computed(() => {
hide-bottom-space hide-bottom-space
lazy-rules lazy-rules
/> />
<q-skeleton v-else type="QInput" height="40px" />
</div> </div>
</div> </div>
<div class="col-12 row"> <div class="col-12 row">
<div class="col-4 text-grey-6">หนวยน</div> <div class="col-4 text-grey-6">หนวยน</div>
<div class="col-8"> <div class="col-8">
<q-input <q-input
v-if="!isLoad"
outlined outlined
v-model="formDetail.unit" v-model="formDetail.unit"
bg-color="white" bg-color="white"
@ -744,12 +795,14 @@ const title = computed(() => {
hide-bottom-space hide-bottom-space
reverse-fill-mask reverse-fill-mask
/> />
<q-skeleton v-else type="QInput" height="40px" />
</div> </div>
</div> </div>
<div class="col-12 row"> <div class="col-12 row">
<div class="col-4 text-grey-6">ำหน (อยละ)</div> <div class="col-4 text-grey-6">ำหน (อยละ)</div>
<div class="col-8"> <div class="col-8">
<q-input <q-input
v-if="!isLoad"
outlined outlined
v-model="formDetail.weight" v-model="formDetail.weight"
bg-color="white" bg-color="white"
@ -764,6 +817,7 @@ const title = computed(() => {
lazy-rules lazy-rules
mask="###" mask="###"
/> />
<q-skeleton v-else type="QInput" height="40px" />
</div> </div>
</div> </div>
</div> </div>
@ -782,6 +836,7 @@ const title = computed(() => {
<div class="col-6 text-center text-body2">5</div> <div class="col-6 text-center text-body2">5</div>
<div class="col-6"> <div class="col-6">
<q-input <q-input
v-if="!isLoad"
v-model="formDetail.achievement5" v-model="formDetail.achievement5"
outlined outlined
dense dense
@ -791,6 +846,7 @@ const title = computed(() => {
class="inputgreen" class="inputgreen"
lazy-rules lazy-rules
/> />
<q-skeleton v-else type="QInput" height="40px" />
</div> </div>
</div> </div>
<q-separator /> <q-separator />
@ -798,6 +854,7 @@ const title = computed(() => {
<div class="col-6 text-center text-body2">4</div> <div class="col-6 text-center text-body2">4</div>
<div class="col-6 text-center text-primary"> <div class="col-6 text-center text-primary">
<q-input <q-input
v-if="!isLoad"
v-model="formDetail.achievement4" v-model="formDetail.achievement4"
outlined outlined
:readonly="checkDetail" :readonly="checkDetail"
@ -807,6 +864,7 @@ const title = computed(() => {
class="inputgreen" class="inputgreen"
lazy-rules lazy-rules
/> />
<q-skeleton v-else type="QInput" height="40px" />
</div> </div>
</div> </div>
<q-separator /> <q-separator />
@ -814,6 +872,7 @@ const title = computed(() => {
<div class="col-6 text-center text-body2">3</div> <div class="col-6 text-center text-body2">3</div>
<div class="col-6 text-center text-primary"> <div class="col-6 text-center text-primary">
<q-input <q-input
v-if="!isLoad"
v-model="formDetail.achievement3" v-model="formDetail.achievement3"
outlined outlined
:readonly="checkDetail" :readonly="checkDetail"
@ -823,6 +882,7 @@ const title = computed(() => {
class="inputgreen" class="inputgreen"
lazy-rules lazy-rules
/> />
<q-skeleton v-else type="QInput" height="40px" />
</div> </div>
</div> </div>
<q-separator /> <q-separator />
@ -830,6 +890,7 @@ const title = computed(() => {
<div class="col-6 text-center text-body2">2</div> <div class="col-6 text-center text-body2">2</div>
<div class="col-6 text-center text-primary"> <div class="col-6 text-center text-primary">
<q-input <q-input
v-if="!isLoad"
v-model="formDetail.achievement2" v-model="formDetail.achievement2"
outlined outlined
:readonly="checkDetail" :readonly="checkDetail"
@ -839,6 +900,7 @@ const title = computed(() => {
class="inputgreen" class="inputgreen"
lazy-rules lazy-rules
/> />
<q-skeleton v-else type="QInput" height="40px" />
</div> </div>
</div> </div>
<q-separator /> <q-separator />
@ -846,6 +908,7 @@ const title = computed(() => {
<div class="col-6 text-center text-body2">1</div> <div class="col-6 text-center text-body2">1</div>
<div class="col-6 text-center text-primary"> <div class="col-6 text-center text-primary">
<q-input <q-input
v-if="!isLoad"
v-model="formDetail.achievement1" v-model="formDetail.achievement1"
outlined outlined
:readonly="checkDetail" :readonly="checkDetail"
@ -855,12 +918,14 @@ const title = computed(() => {
class="inputgreen" class="inputgreen"
lazy-rules lazy-rules
/> />
<q-skeleton v-else type="QInput" height="40px" />
</div> </div>
</div> </div>
</q-card> </q-card>
</div> </div>
<div class="col-12"> <div class="col-12">
<q-input <q-input
v-if="!isLoad"
v-model="formDetail.meaning" v-model="formDetail.meaning"
label="นิยามหรือความหมายของตัวชี้วัด" label="นิยามหรือความหมายของตัวชี้วัด"
type="textarea" type="textarea"
@ -872,10 +937,12 @@ const title = computed(() => {
class="inputgreen" class="inputgreen"
lazy-rules lazy-rules
/> />
<q-skeleton v-else type="QInput" height="150px" />
</div> </div>
<div class="col-12"> <div class="col-12">
<q-input <q-input
v-if="!isLoad"
v-model="formDetail.formula" v-model="formDetail.formula"
label="สูตรคำนวณ" label="สูตรคำนวณ"
:readonly="checkDetail" :readonly="checkDetail"
@ -887,10 +954,12 @@ const title = computed(() => {
class="inputgreen" class="inputgreen"
lazy-rules lazy-rules
/> />
<q-skeleton v-else type="QInput" height="150px" />
</div> </div>
<div class="col-12"> <div class="col-12">
<q-input <q-input
v-if="!isLoad"
v-model="formDetail.documentInfoEvidence" v-model="formDetail.documentInfoEvidence"
label="ข้อมูลเอกสารหลักฐาน" label="ข้อมูลเอกสารหลักฐาน"
type="textarea" type="textarea"
@ -902,9 +971,11 @@ const title = computed(() => {
class="inputgreen" class="inputgreen"
lazy-rules lazy-rules
/> />
<q-skeleton v-else type="QInput" height="150px" />
</div> </div>
<div class="col-3"> <div class="col-3">
<datepicker <datepicker
v-if="!isLoad"
v-model="formDetail.startDate" v-model="formDetail.startDate"
:locale="'th'" :locale="'th'"
:readonly="checkDetail" :readonly="checkDetail"
@ -950,9 +1021,11 @@ const title = computed(() => {
</q-input> </q-input>
</template> </template>
</datepicker> </datepicker>
<q-skeleton v-else type="QInput" height="40px" />
</div> </div>
<div class="col-3"> <div class="col-3">
<datepicker <datepicker
v-if="!isLoad"
v-model="formDetail.endDate" v-model="formDetail.endDate"
:locale="'th'" :locale="'th'"
:readonly="checkDetail" :readonly="checkDetail"
@ -998,6 +1071,7 @@ const title = computed(() => {
</q-input> </q-input>
</template> </template>
</datepicker> </datepicker>
<q-skeleton v-else type="QInput" height="40px" />
</div> </div>
</div> </div>
</div> </div>

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