API workflow

This commit is contained in:
DESKTOP-1R2VSQH\Lenovo ThinkPad E490 2024-10-16 18:11:38 +07:00
parent 95cfcee530
commit a6c7981fd8
5 changed files with 228 additions and 97 deletions

View file

@ -6,6 +6,7 @@ const orgProfile = `${env.API_URI}/org/profile`;
const orgEmployeePos = `${env.API_URI}/org/employee/pos`; const orgEmployeePos = `${env.API_URI}/org/employee/pos`;
const orgAct = `${env.API_URI}/org/act`; const orgAct = `${env.API_URI}/org/act`;
const orgPosAct = `${env.API_URI}/org/pos/act`; const orgPosAct = `${env.API_URI}/org/pos/act`;
const workflow = `${env.API_URI}/org/workflow`;
export default { export default {
keycloakPosition: () => `${organization}/profile/keycloak/position`, keycloakPosition: () => `${organization}/profile/keycloak/position`,
@ -134,4 +135,9 @@ export default {
orgPermissionsSys: `${organization}/permission`, orgPermissionsSys: `${organization}/permission`,
checkIsOfficer: (id: string) => `${organization}/check/child1/${id}`, checkIsOfficer: (id: string) => `${organization}/check/child1/${id}`,
/**
* workflow
*/
workflow: `${workflow}/`,
}; };

View file

@ -1,34 +1,90 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from "vue"; import { ref, watch } from "vue";
import { useQuasar } from "quasar"; import { useQuasar } from "quasar";
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
import http from "@/plugins/http";
import config from "@/app.config";
import DialogHeader from "@/components/DialogHeader.vue"; import DialogHeader from "@/components/DialogHeader.vue";
const $q = useQuasar(); const $q = useQuasar();
const { dialogConfirm } = useCounterMixin(); const { dialogConfirm, showLoader, hideLoader, messageError } =
useCounterMixin();
const modal = defineModel<boolean>("modal", { required: true }); const modal = defineModel<boolean>("modal", { required: true });
const { stateId } = defineProps({
stateId: { type: String, require: true },
});
const isAcknowledge = ref<boolean>(false); const isAcceptSetting = ref<boolean>(false);
const isConsider = ref<boolean>(true); const isApproveSetting = ref<boolean>(false);
const isComment = ref<boolean>(true); const isReasonSetting = ref<boolean>(false);
const acknowledge = ref<boolean>(false); const isAccept = ref<boolean>(false);
const consider = ref<string>(""); const isApprove = ref<string>("");
const comment = ref<string>(""); const reason = ref<string>("");
async function fetchData() {
showLoader();
await http
.post(config.API.workflow + `comment-state-user`, { stateId: stateId })
.then(async (res) => {
const data = res.data.result;
isAcceptSetting.value = data.isAcceptSetting;
isApproveSetting.value = data.isApproveSetting;
isReasonSetting.value = data.isReasonSetting;
isAccept.value = data.isAccept;
isApprove.value = data.isApprove ? "approve" : "";
reason.value = data.reason;
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
function onSubmit() { function onSubmit() {
dialogConfirm($q, () => {}); dialogConfirm($q, async () => {
showLoader();
await http
.post(config.API.workflow + `comment`, {
stateId: stateId,
isAccept: isAcceptSetting.value ? isAccept.value : undefined,
isApprove: isApproveSetting.value
? isApprove.value === "approve"
? true
: false
: undefined,
reason: isReasonSetting.value ? reason.value : undefined,
})
.then(async () => {
onCloseModal();
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
});
} }
function onCloseModal() { function onCloseModal() {
modal.value = false; modal.value = false;
acknowledge.value = false; isAccept.value = false;
consider.value = ""; isApprove.value = "";
comment.value = ""; reason.value = "";
} }
watch(modal, (val) => {
if (val) {
fetchData();
}
});
</script> </script>
<template> <template>
@ -43,23 +99,23 @@ function onCloseModal() {
<q-card-section> <q-card-section>
<div class="q-gutter-xs"> <div class="q-gutter-xs">
<div v-if="isAcknowledge"> <div v-if="isAcceptSetting">
<q-checkbox <q-checkbox
keep-color keep-color
color="primary" color="primary"
dense dense
v-model="acknowledge" v-model="isAccept"
label="รับทราบ" label="รับทราบ"
/> />
</div> </div>
<div v-if="!isAcknowledge && isConsider"> <div v-if="!isAcceptSetting && isApproveSetting">
<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">
<q-radio <q-radio
dense dense
keep-color keep-color
color="primary" color="primary"
v-model="consider" v-model="isApprove"
label="อนุมัติ" label="อนุมัติ"
val="approve" val="approve"
/> />
@ -67,14 +123,14 @@ function onCloseModal() {
dense dense
keep-color keep-color
color="primary" color="primary"
v-model="consider" v-model="isApprove"
label="ไม่อนุมัติ" label="ไม่อนุมัติ"
val="reject" val="reject"
/> />
</div> </div>
</div> </div>
<div v-if="!isAcknowledge && isComment"> <div v-if="!isAcceptSetting && isReasonSetting">
<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">
@ -82,7 +138,7 @@ function onCloseModal() {
dense dense
outlined outlined
label="ความเห็น" label="ความเห็น"
v-model="comment" v-model="reason"
type="textarea" type="textarea"
lazy-rules lazy-rules
:rules="[ :rules="[
@ -103,7 +159,7 @@ function onCloseModal() {
label="บันทึก" label="บันทึก"
color="public" color="public"
type="submit" type="submit"
:disable="!isAcknowledge && !isConsider && !isComment" :disable="!isAcceptSetting && !isApproveSetting && !isReasonSetting"
> >
</q-btn> </q-btn>
</q-card-actions> </q-card-actions>

View file

@ -3,15 +3,22 @@ import { ref, watch } from "vue";
import { useQuasar } from "quasar"; import { useQuasar } from "quasar";
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
import http from "@/plugins/http";
import config from "@/app.config";
import type { QTableProps } from "quasar"; import type { QTableProps } from "quasar";
import DialogHeader from "@/components/DialogHeader.vue"; import DialogHeader from "@/components/DialogHeader.vue";
const $q = useQuasar(); const $q = useQuasar();
const { dialogConfirm } = useCounterMixin(); const { dialogConfirm, showLoader, hideLoader, messageError } =
useCounterMixin();
const modal = defineModel<boolean>("modal", { required: true }); const modal = defineModel<boolean>("modal", { required: true });
const { stateId, fetchData } = defineProps({
stateId: { type: String, require: true },
fetchData: { type: Function, require: true },
});
/** table*/ /** table*/
const selected = ref<any[]>([]); const selected = ref<any[]>([]);
@ -62,14 +69,34 @@ const columns = ref<QTableProps["columns"]>([
}, },
]); ]);
const isAcknowledge = ref<boolean>(false); const isAcceptSetting = ref<boolean>(false);
const isConsider = ref<boolean>(false); const isApproveSetting = ref<boolean>(false);
const isComment = ref<boolean>(false); const isReasonSetting = ref<boolean>(false);
function fetchLists() {} function fetchLists() {}
function onSubmit() { function onSubmit() {
dialogConfirm($q, () => {}); dialogConfirm($q, async () => {
showLoader();
await http
.post(config.API.workflow + `add-step`, {
stateId: stateId,
profileId: selected.value[0].id,
isAcceptSetting: isAcceptSetting.value,
isApproveSetting: isApproveSetting.value,
isReasonSetting: isReasonSetting.value,
})
.then(async () => {
await fetchData?.();
onCloseModal();
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
});
} }
function onCloseModal() { function onCloseModal() {
@ -146,26 +173,28 @@ watch(modal, (val) => {
keep-color keep-color
color="primary" color="primary"
dense dense
v-model="isAcknowledge" v-model="isAcceptSetting"
label="ให้เลือกรับทราบ" label="ให้เลือกรับทราบ"
@update:model-value="(isConsider = false), (isComment = false)" @update:model-value="
(isApproveSetting = false), (isReasonSetting = false)
"
/> />
</div> </div>
<div v-if="!isAcknowledge"> <div v-if="!isAcceptSetting">
<q-checkbox <q-checkbox
dense dense
keep-color keep-color
color="primary" color="primary"
v-model="isConsider" v-model="isApproveSetting"
label="ให้เลือกพิจารณา (อนุมัติ/ไม่อนุมัติ)" label="ให้เลือกพิจารณา (อนุมัติ/ไม่อนุมัติ)"
/> />
</div> </div>
<div v-if="!isAcknowledge"> <div v-if="!isAcceptSetting">
<q-checkbox <q-checkbox
dense dense
keep-color keep-color
color="primary" color="primary"
v-model="isComment" v-model="isReasonSetting"
label="ให้แสดงความเห็นในเอกสาร" label="ให้แสดงความเห็นในเอกสาร"
/> />
</div> </div>
@ -181,7 +210,7 @@ watch(modal, (val) => {
type="submit" type="submit"
:disable=" :disable="
selected.length === 0 || selected.length === 0 ||
(!isAcknowledge && !isConsider && !isComment) (!isAcceptSetting && !isApproveSetting && !isReasonSetting)
" "
> >
</q-btn> </q-btn>

View file

@ -3,74 +3,100 @@ import { onMounted, ref } from "vue";
import { useQuasar } from "quasar"; import { useQuasar } from "quasar";
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
import http from "@/plugins/http";
import config from "@/app.config";
import DialogSelectPerson from "@/components/Workflow/DialogSelectPerson.vue"; import DialogSelectPerson from "@/components/Workflow/DialogSelectPerson.vue";
import DialogApprove from "@/components/Workflow/DialogApprove.vue"; import DialogApprove from "@/components/Workflow/DialogApprove.vue";
const $q = useQuasar(); const $q = useQuasar();
const { dialogConfirm } = useCounterMixin(); const { dialogConfirm, showLoader, hideLoader, messageError } =
useCounterMixin();
const { id, sysName } = defineProps({ const { id, sysName } = defineProps({
id: { type: String, require: true }, id: { type: String, require: true },
sysName: { type: String, require: true }, sysName: { type: String, require: true },
}); });
const state = ref<number>(1); const stateId = ref<string>(""); //id state
const isChangeState = ref<boolean>(false); const state = ref<number>(2); //state
const isOperate = ref<boolean>(false);
const isChangeState = ref<boolean>(false); ///
const isOperate = ref<boolean>(true); // (state)
const isView = ref<boolean>(true); //
const isUpdate = ref<boolean>(true); //
const isDelete = ref<boolean>(true); // ()
const isCancel = ref<boolean>(true); // ()
const rowsOperate = ref<any[]>([
{
fullName: "ชื่อนาม - สกุล",
comment: "ความเห็น",
position: " บริหาร - ต้น ",
status: "อนุมัติ",
},
]);
const modalSelectPerson = ref<boolean>(false); const modalSelectPerson = ref<boolean>(false);
const modalApprove = ref<boolean>(false); const modalApprove = ref<boolean>(false);
const itemState = ref<any[]>([ const itemState = ref<any[]>([]);
{
stateNo: 1,
stateName: "Darft",
},
{
stateNo: 2,
stateName: "Operate",
},
{
stateNo: 3,
stateName: "Finish",
},
]);
function fetchData() { async function fetchData() {
console.log(id, sysName); console.log(id, sysName);
const data = { await http
stateNo: 1, .post(config.API.workflow + `check-state-all`, {
step: 1, refId: id,
can_view: true, system: sysName,
can_update: true, })
can_operate: true, .then(async (res) => {
can_change_state: true, const data = await res.data.result;
can_delete: false, itemState.value = data;
can_cancel: false, })
}; .catch((err) => {
messageError($q, err);
state.value = data.stateNo; });
isChangeState.value = data.can_change_state;
isOperate.value = data.can_operate;
} }
function onConfirmDraft() { async function fetchCheckState() {
dialogConfirm($q, () => { await http
state.value++; .post(config.API.workflow + `check-user-now`, {
refId: id,
system: sysName,
})
.then(async (res) => {
const data = await res.data.result;
stateId.value = data.stateId;
state.value = data.stateNo;
isChangeState.value = data.can_change_state;
isOperate.value = data.can_operate;
isView.value = data.can_view;
isUpdate.value = data.can_update;
isDelete.value = data.can_delete;
isCancel.value = data.can_cancel;
})
.catch((err) => {
messageError($q, err);
});
}
function onChangeState() {
dialogConfirm($q, async () => {
showLoader();
await http
.post(config.API.workflow + `state-next`, {
refId: id,
system: sysName,
})
.then(async () => {
await Promise.all([fetchData(), fetchCheckState()]);
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}); });
} }
onMounted(() => { async function fetchAllFunction() {
fetchData(); await Promise.all([fetchData(), fetchCheckState()]);
}
onMounted(async () => {
await fetchAllFunction();
}); });
</script> </script>
@ -103,14 +129,11 @@ onMounted(() => {
:color="state < index + 1 ? 'grey-4' : ''" :color="state < index + 1 ? 'grey-4' : ''"
> >
<!-- Darft --> <!-- Darft -->
<div <div class="row q-col-gutter-sm" v-if="state === 1">
class="row q-col-gutter-sm"
v-if="step.stateName === 'Darft' && state === 1"
>
<div> <div>
<q-btn <q-btn
v-if="isChangeState" v-if="isChangeState"
@click.prevent="onConfirmDraft" @click.prevent="onChangeState"
label="Next Step" label="Next Step"
color="primary" color="primary"
/> />
@ -120,31 +143,44 @@ onMounted(() => {
<!-- Operate --> <!-- Operate -->
<div <div
class="q-col-gutter-sm" class="q-col-gutter-sm"
v-if="step.stateName === 'Operate' && state > 1" v-if="index > 0 && index < itemState.length - 1 && state > index"
> >
<div> <div v-if="step.stateUserComments.length !== 0">
<q-list bordered separator style="min-width: 20vw"> <q-list bordered separator style="min-width: 20vw">
<q-item v-for="(item, index) in rowsOperate" :key="index"> <q-item
v-for="(item, index) in step.stateUserComments"
:key="index"
>
<q-item-section> <q-item-section>
<q-item-label <q-item-label
>{{ item.fullName }} >{{ item.createdFullName }}
{{ `(${item.position})` }}</q-item-label <!-- {{ `(${item.position})` }} -->
> </q-item-label>
<q-item-label caption lines="2">{{ <q-item-label caption lines="2">{{
item.comment item.isReasonSetting ? item.reason : ""
}}</q-item-label> }}</q-item-label>
</q-item-section> </q-item-section>
<q-item-section side top> <q-item-section side top>
<q-item-label class="text-green"> <q-item-label class="text-green">
{{ item.status }}</q-item-label {{
item.isAcceptSetting
? item.isAccept
? "รับทราบ"
: ""
: item.isApproveSetting
? item.isApprove
? "อนุมันติ"
: ""
: ""
}}</q-item-label
> >
</q-item-section> </q-item-section>
</q-item> </q-item>
</q-list> </q-list>
</div> </div>
<div v-if="isOperate && state === 2"> <div v-if="isOperate">
<q-btn <q-btn
@click.prevent="modalSelectPerson = true" @click.prevent="modalSelectPerson = true"
label="ส่งไปผู้บังคับบัญชา/ผู้มีอำนาจ" label="ส่งไปผู้บังคับบัญชา/ผู้มีอำนาจ"
@ -152,9 +188,9 @@ onMounted(() => {
/> />
</div> </div>
<div v-if="isChangeState && state === 2"> <div v-if="isChangeState">
<q-btn <q-btn
@click.prevent="onConfirmDraft" @click.prevent="onChangeState"
label="Next Step" label="Next Step"
color="primary" color="primary"
/> />
@ -166,7 +202,11 @@ onMounted(() => {
</q-card-section> </q-card-section>
</q-card> </q-card>
<DialogSelectPerson v-model:modal="modalSelectPerson" /> <DialogSelectPerson
v-model:modal="modalSelectPerson"
:state-id="stateId"
:fetch-data="fetchAllFunction"
/>
<DialogApprove v-model:modal="modalApprove" /> <DialogApprove v-model:modal="modalApprove" :state-id="stateId" />
</template> </template>

View file

@ -686,7 +686,7 @@ onMounted(async () => {
</q-card> </q-card>
<!-- Workflow --> <!-- Workflow -->
<WorkFlow :id="transferId" :sys-name="'transfer'" /> <WorkFlow :id="transferId" :sys-name="'PLACEMENT_TRANSFER'" />
</div> </div>
</template> </template>