รายการคำสั่ง ==> API

This commit is contained in:
DESKTOP-1R2VSQH\Lenovo ThinkPad E490 2024-09-12 17:11:00 +07:00
parent 71be6d095f
commit 15b33b147a
14 changed files with 568 additions and 145 deletions

View file

@ -1,7 +1,11 @@
import env from "../index"; import env from "../index";
const command = `${env.API_URI}/order`; const command = `${env.API_URI}/org/command`;
export default { export default {
commandType: `${command}/order-type`, commandType: `${command}Type/list`, //ประเภทคำสั่ง
commandList: `${command}/list`, //list รายการ
command, //สร้างคำสั่ง
commandAction: (commandId: string, type: string) =>
`${command}/${type}/${commandId}`,
}; };

View file

@ -6,7 +6,8 @@ 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";
import type { DataListCommand } from "@/modules/18_command/interface/response/Main"; import type { FormCommand } from "@/modules/18_command/interface/request/Main";
import type { DataCommandType } from "@/modules/18_command/interface/response/Main";
import DialogHeader from "@/components/DialogHeader.vue"; import DialogHeader from "@/components/DialogHeader.vue";
@ -14,18 +15,19 @@ import { useCounterMixin } from "@/stores/mixin";
const $q = useQuasar(); const $q = useQuasar();
const router = useRouter(); const router = useRouter();
const { dialogConfirm, showLoader, hideLoader, messageError } = const { dialogConfirm, showLoader, hideLoader, messageError, success } =
useCounterMixin(); useCounterMixin();
const modal = defineModel<boolean>("modal", { required: true }); const modal = defineModel<boolean>("modal", { required: true });
const isCopy = defineModel<boolean>("isCopy", { required: true }); const isCopy = defineModel<boolean>("isCopy", { required: true });
const commandId = defineModel<string>("commandId", { default: "" });
const commandType = ref<string>(""); const commandType = ref<string>("");
const commandNo = ref<string>(""); const commandNo = ref<string>("");
const commandYear = ref<string>(""); const commandYear = ref<number>(new Date().getFullYear());
const listCommand = ref<DataListCommand[]>([]); const listCommand = ref<DataCommandType[]>([]);
const commandOp = ref<DataListCommand[]>([]); const commandOp = ref<DataCommandType[]>([]);
async function fetchCommandType() { async function fetchCommandType() {
showLoader(); showLoader();
@ -46,10 +48,29 @@ async function fetchCommandType() {
function onSubmit() { function onSubmit() {
dialogConfirm($q, () => { dialogConfirm($q, () => {
!isCopy.value && router.push(`/command/edit/1234`); showLoader();
console.log(commandNo.value); const body: FormCommand = {
console.log(commandYear.value); commandYear: commandYear.value,
onClose(); commandNo: commandNo.value,
commandTypeId: !isCopy.value ? commandType.value : undefined,
};
const path = !isCopy.value
? config.API.command
: config.API.commandAction(commandId.value, "copy");
http[!isCopy.value ? "post" : "put"](path, body)
.then(async (res) => {
const id = await res.data.result;
router.push(`/command/edit/${id}`);
success($q, "บันทึกข้อมูลสำเร็จ");
onClose();
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}); });
} }
@ -72,7 +93,7 @@ function filterSelector(val: string, update: Function, refData: string) {
function onClose() { function onClose() {
modal.value = false; modal.value = false;
commandNo.value = ""; commandNo.value = "";
commandYear.value = ""; commandYear.value = new Date().getFullYear();
} }
watch(modal, () => { watch(modal, () => {
@ -130,7 +151,6 @@ watch(modal, () => {
v-model="commandNo" v-model="commandNo"
hide-bottom-space hide-bottom-space
:label="`${'คำสั่งเลขที่'}`" :label="`${'คำสั่งเลขที่'}`"
:rules="[(val) => !!val || `${'กรุณากรอกคำสั่งเลขที่'}`]"
lazy-rules lazy-rules
/> />
</div> </div>
@ -138,17 +158,41 @@ watch(modal, () => {
>/</label >/</label
> >
<div class="col-5"> <div class="col-5">
<q-input <datepicker
class="inputgreen" menu-class-name="modalfix"
outlined
dense
v-model="commandYear" v-model="commandYear"
hide-bottom-space :locale="'th'"
:label="`${'พ.ศ.'}`" autoApply
mask="####" year-picker
:rules="[(val) => !!val || `${'กรุณากรอก พ.ศ.'}`]" :enableTimePicker="false"
lazy-rules class="inputgreen"
/> >
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
dense
outlined
hide-bottom-space
:model-value="
commandYear == null ? null : commandYear + 543
"
:label="`${'พ.ศ.'}`"
:rules="[(val) => !!val || `${'กรุณากรอก พ.ศ.'}`]"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
style="color: var(--q-primary)"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div> </div>
</div> </div>
</q-card-section> </q-card-section>

View file

@ -1,81 +1,113 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from "vue"; import { onMounted, ref, watch } from "vue";
import { useQuasar } from "quasar"; import { useQuasar } from "quasar";
import http from "@/plugins/http";
import config from "@/app.config";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
import { useCommandListStore } from "@/modules/18_command/store/ListStore"; import { useCommandListStore } from "@/modules/18_command/store/ListStore";
import DialogFormCommand from "@/modules/18_command/components/Main/DialogFormCommand.vue";
import type { QTableProps } from "quasar"; import type { QTableProps } from "quasar";
import type { Pagination } from "@/modules/18_command/interface/index/Main";
import DialogFormCommand from "@/modules/18_command/components/Main/DialogFormCommand.vue";
const $q = useQuasar(); const $q = useQuasar();
const router = useRouter(); const router = useRouter();
const store = useCommandListStore(); const store = useCommandListStore();
const { date2Thai, dialogRemove, dialogConfirm } = useCounterMixin(); const {
showLoader,
hideLoader,
success,
messageError,
date2Thai,
dialogRemove,
dialogConfirm,
} = useCounterMixin();
const page = defineModel<number>("page", { required: true });
const pageSize = defineModel<number>("pageSize", { required: true });
const props = defineProps({
fetchList: { type: Function, required: true },
});
const columns = ref<QTableProps["columns"]>([ const columns = ref<QTableProps["columns"]>([
{ {
name: "orderNo", name: "commandNo",
align: "left", align: "left",
label: "เลขที่คำสั่ง", label: "เลขที่คำสั่ง",
sortable: false, sortable: false,
field: "orderNo", field: "commandNo",
format(val, row) {
return val ? `${val} / ${row.commandYear + 543}` : "-";
},
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
style: "font-size: 14px", style: "font-size: 14px",
}, },
{ {
name: "orderName", name: "issue",
align: "center", align: "left",
label: "ชื่อคำสั่ง", label: "ชื่อคำสั่ง",
sortable: true, sortable: true,
field: "orderName", field: "issue",
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
style: "font-size: 14px", style: "font-size: 14px",
}, },
{ {
name: "signatoryDate", name: "commandExcecuteDate",
align: "center", align: "left",
label: "วันที่ลงนาม", label: "วันที่ลงนาม",
sortable: false, sortable: false,
field: (v) => date2Thai(v), field: "commandExcecuteDate",
format(val) {
return val ? date2Thai(val) : "-";
},
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
style: "font-size: 14px", style: "font-size: 14px",
}, },
{ {
name: "orderDate", name: "commandAffectDate",
align: "center", align: "left",
label: "วันที่คำสั่งมีผล", label: "วันที่คำสั่งมีผล",
sortable: false, sortable: false,
field: (v) => date2Thai(v), field: "commandAffectDate",
format(val) {
return val ? date2Thai(val) : "-";
},
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
style: "font-size: 14px", style: "font-size: 14px",
}, },
{ {
name: "orderBy", name: "createdFullName",
align: "center", align: "left",
label: "ผู้สร้าง", label: "ผู้สร้าง",
sortable: false, sortable: false,
field: "orderBy", field: "createdFullName",
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
style: "font-size: 14px", style: "font-size: 14px",
}, },
{ {
name: "signatoryBy", name: "assignFullName",
align: "center", align: "left",
label: "ผู้ลงนาม", label: "ผู้ลงนาม",
sortable: false, sortable: false,
field: "signatoryBy", field: "assignFullName",
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
style: "font-size: 14px", style: "font-size: 14px",
}, },
]); ]);
const modalCopy = ref<boolean>(false); const modalCopy = ref<boolean>(false);
const isCheckPageSize = ref<boolean>(false);
const commandId = ref<string>(""); const commandId = ref<string>("");
async function fetchListCommand() {
await props.fetchList?.();
}
function onRedirectToDetail(type: string, id: string) { function onRedirectToDetail(type: string, id: string) {
router.push(`/command/${type}/${id}`); router.push(`/command/${type}/${id}`);
} }
@ -88,7 +120,21 @@ function onCopy(id: string) {
function onCancel(id: string) { function onCancel(id: string) {
dialogRemove( dialogRemove(
$q, $q,
() => {}, async () => {
showLoader();
await http
.put(config.API.commandAction(id, "cancel"))
.then(async () => {
await fetchListCommand();
success($q, "ยกเลิกรายการสำเร็จ");
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
},
"ยืนยันการยกเลิกการออกคำสั่ง", "ยืนยันการยกเลิกการออกคำสั่ง",
"ต้องการยืนยันการยกเลิกการออกคำสั่งนี้ใช่หรือไม่ ?" "ต้องการยืนยันการยกเลิกการออกคำสั่งนี้ใช่หรือไม่ ?"
); );
@ -102,6 +148,46 @@ function onReCommand(id: string) {
"ต้องการยืนยืนยันการดึงไปทำคำสั่งใหม่ใช่หรือไม่ ?" "ต้องการยืนยืนยันการดึงไปทำคำสั่งใหม่ใช่หรือไม่ ?"
); );
} }
function onDeleteCommand(id: string) {
dialogRemove(
$q,
async () => {
showLoader();
await http
.delete(config.API.command + `/${id}`)
.then(async () => {
await fetchListCommand();
success($q, "ลบรายการสำเร็จ");
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
},
"ยืนยันการลบคำสั่ง",
"ต้องการยืนยืนยันการลบคำสั่งนี้ใช่หรือไม่ ?"
);
}
/**
* function updatePagination
* @param newPagination อม Pagination ใหม
*/
function updatePagination(newPagination: Pagination) {
page.value = 1;
pageSize.value = newPagination.rowsPerPage;
}
watch(pageSize, () => {
isCheckPageSize.value = true;
fetchListCommand();
});
onMounted(() => {
!isCheckPageSize.value && fetchListCommand();
});
</script> </script>
<template> <template>
@ -114,6 +200,8 @@ function onReCommand(id: string) {
dense dense
bordered bordered
:paging="true" :paging="true"
:rows-per-page-options="[10, 25, 50, 100]"
@update:pagination="updatePagination"
> >
<template v-slot:header="props"> <template v-slot:header="props">
<q-tr :props="props"> <q-tr :props="props">
@ -139,7 +227,7 @@ function onReCommand(id: string) {
<q-item <q-item
clickable clickable
v-close-popup v-close-popup
v-if="store.tabsMain !== 'list_cancel'" v-if="store.tabsMain !== 'CANCEL'"
@click.pervent="onRedirectToDetail('edit', props.row.id)" @click.pervent="onRedirectToDetail('edit', props.row.id)"
> >
<q-item-section> <q-item-section>
@ -196,7 +284,7 @@ function onReCommand(id: string) {
<q-item <q-item
clickable clickable
v-close-popup v-close-popup
v-if="store.tabsMain !== 'list_cancel'" v-if="store.tabsMain !== 'CANCEL'"
@click.pervent="onCancel(props.row.id)" @click.pervent="onCancel(props.row.id)"
> >
<q-item-section> <q-item-section>
@ -216,7 +304,7 @@ function onReCommand(id: string) {
<q-item <q-item
clickable clickable
v-close-popup v-close-popup
v-if="store.tabsMain === 'list_cancel'" v-if="store.tabsMain === 'CANCEL'"
@click.pervent="onReCommand(props.row.id)" @click.pervent="onReCommand(props.row.id)"
> >
<q-item-section> <q-item-section>
@ -226,6 +314,20 @@ function onReCommand(id: string) {
</div> </div>
</q-item-section> </q-item-section>
</q-item> </q-item>
<q-item
clickable
v-close-popup
v-if="store.tabsMain === 'CANCEL'"
@click.pervent="onDeleteCommand(props.row.id)"
>
<q-item-section>
<div class="row items-center">
<q-icon color="red" size="xs" name="mdi-delete" />
<div class="q-pl-md">ลบคำส</div>
</div>
</q-item-section>
</q-item>
</q-list> </q-list>
</q-menu> </q-menu>
</q-btn> </q-btn>
@ -237,9 +339,27 @@ function onReCommand(id: string) {
</q-td> </q-td>
</q-tr> </q-tr>
</template> </template>
<template v-slot:pagination="scope">
งหมด {{ store.total }} รายการ
<q-pagination
v-model="page"
active-color="primary"
color="dark"
:max="Number(store.maxPage)"
size="sm"
boundary-links
direction-links
:max-pages="5"
@update:model-value="fetchListCommand"
></q-pagination>
</template>
</d-table> </d-table>
<DialogFormCommand v-model:modal="modalCopy" :is-copy="true" /> <DialogFormCommand
v-model:modal="modalCopy"
:is-copy="true"
:command-id="commandId"
/>
</template> </template>
<style scoped></style> <style scoped></style>

View file

@ -1,27 +1,101 @@
<script setup lang="ts"> <script setup lang="ts">
import { reactive, ref } from "vue"; import { onMounted, reactive, ref, watch } from "vue";
import { useQuasar } from "quasar";
import { useRoute } from "vue-router";
import http from "@/plugins/http";
import config from "@/app.config";
import { useCounterMixin } from "@/stores/mixin";
import { useCommandDetail } from "@/modules/18_command/store/DetailStore"; import { useCommandDetail } from "@/modules/18_command/store/DetailStore";
import type { FormDataDetail } from "@/modules/18_command/interface/request/Main";
import DialogPerview from "@/modules/18_command/components/Step/Dialog1_Perview.vue"; import DialogPerview from "@/modules/18_command/components/Step/Dialog1_Perview.vue";
const $q = useQuasar();
const route = useRoute();
const store = useCommandDetail(); const store = useCommandDetail();
const { showLoader, hideLoader, success, messageError } = useCounterMixin();
const formData = reactive({ const isChangeData = defineModel<boolean>("isChangeData", { required: true });
commandNo: "", const props = defineProps({
commandYear: "", onCheckChangeData: { type: Function, required: true },
commandName: "",
commandHeader: "",
commandCenter: "",
commandFooter: "",
}); });
const commandId = ref<string>(route.params.id.toString());
const formData = reactive<FormDataDetail>({
commandNo: "",
commandYear: null,
// commandName: "",
detailHeader: "",
detailBody: "",
detailFooter: "",
issue: null,
});
const modalPreview = ref<boolean>(false); const modalPreview = ref<boolean>(false);
async function fetchData() {
showLoader();
await http
.get(config.API.commandAction(commandId.value, "tab1"))
.then(async (res) => {
const data = await res.data.result;
formData.commandNo = data.commandNo;
formData.commandYear = data.commandYear;
formData.detailHeader = data.detailHeader;
formData.detailBody = data.detailBody;
formData.detailFooter = data.detailFooter;
formData.issue = data.issue;
isChangeData.value = false;
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
async function onSubmit() {
showLoader();
await http
.put(config.API.commandAction(commandId.value, "tab1"), formData)
.then(async () => {
// await fetchData();
// success($q, "");
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
onMounted(() => {
fetchData();
});
/**
* เรยก function ไปใชหนาหล
*/
defineExpose({
onSubmit,
});
</script> </script>
<template> <template>
<q-card-section> <q-card-section>
<div class="row q-col-gutter-sm"> <div class="row q-col-gutter-sm">
<div class="col-12 row justify-end">
<q-btn
label="แสดงตัวอย่าง"
color="info"
icon="mdi-eye"
@click.prevent="modalPreview = true"
/>
</div>
<!-- คำสงเลขท --> <!-- คำสงเลขท -->
<div class="col-4 row"> <div class="col-4 row">
<div class="col-6"> <div class="col-6">
@ -33,22 +107,53 @@ const modalPreview = ref<boolean>(false);
v-model="formData.commandNo" v-model="formData.commandNo"
hide-bottom-space hide-bottom-space
:label="`${'คำสั่งเลขที่'}`" :label="`${'คำสั่งเลขที่'}`"
@update:model-value="props.onCheckChangeData()"
/> />
</div> </div>
<label class="col-1 flex justify-center items-center text-bold"> <label class="col-1 flex justify-center items-center text-bold">
/ /
</label> </label>
<div class="col-5"> <div class="col-5">
<q-input <datepicker
menu-class-name="modalfix"
v-model="formData.commandYear"
:locale="'th'"
autoApply
year-picker
:enableTimePicker="false"
:class="store.classInput(!store.readonly)" :class="store.classInput(!store.readonly)"
:readonly="store.readonly" :readonly="store.readonly"
outlined @update:model-value="props.onCheckChangeData()"
dense >
v-model="formData.commandYear" <template #year="{ year }">{{ year + 543 }}</template>
hide-bottom-space <template #year-overlay-value="{ value }">{{
:label="`${'พ.ศ.'}`" parseInt(value + 543)
mask="####" }}</template>
/> <template #trigger>
<q-input
dense
outlined
hide-bottom-space
:class="store.classInput(!store.readonly)"
:readonly="store.readonly"
:model-value="
formData.commandYear == null
? null
: formData.commandYear + 543
"
:label="`${'พ.ศ.'}`"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
style="color: var(--q-primary)"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div> </div>
</div> </div>
@ -59,9 +164,10 @@ const modalPreview = ref<boolean>(false);
:readonly="store.readonly" :readonly="store.readonly"
outlined outlined
dense dense
v-model="formData.commandName" v-model="formData.issue"
hide-bottom-space hide-bottom-space
:label="`${'คำสั่งเรื่อง'}`" :label="`${'คำสั่งเรื่อง'}`"
@update:model-value="props.onCheckChangeData()"
/> />
</div> </div>
@ -76,15 +182,16 @@ const modalPreview = ref<boolean>(false);
<q-field <q-field
class="q_field_p_none" class="q_field_p_none"
ref="fieldRef" ref="fieldRef"
v-model="formData.commandHeader" v-model="formData.detailHeader"
borderless borderless
hide-bottom-space hide-bottom-space
> >
<template #control> <template #control>
<q-editor <q-editor
@update:model-value="props.onCheckChangeData()"
:readonly="store.readonly" :readonly="store.readonly"
class="full-width" class="full-width"
v-model="formData.commandHeader" v-model="formData.detailHeader"
min-height="5rem" min-height="5rem"
:toolbar="[ :toolbar="[
['left', 'center', 'right', 'justify'], ['left', 'center', 'right', 'justify'],
@ -116,15 +223,16 @@ const modalPreview = ref<boolean>(false);
<q-field <q-field
class="q_field_p_none" class="q_field_p_none"
ref="fieldRef" ref="fieldRef"
v-model="formData.commandCenter" v-model="formData.detailBody"
borderless borderless
hide-bottom-space hide-bottom-space
> >
<template #control> <template #control>
<q-editor <q-editor
@update:model-value="props.onCheckChangeData()"
:readonly="store.readonly" :readonly="store.readonly"
class="full-width" class="full-width"
v-model="formData.commandCenter" v-model="formData.detailBody"
min-height="5rem" min-height="5rem"
:toolbar="[ :toolbar="[
['left', 'center', 'right', 'justify'], ['left', 'center', 'right', 'justify'],
@ -156,15 +264,16 @@ const modalPreview = ref<boolean>(false);
<q-field <q-field
class="q_field_p_none" class="q_field_p_none"
ref="fieldRef" ref="fieldRef"
v-model="formData.commandFooter" v-model="formData.detailFooter"
borderless borderless
hide-bottom-space hide-bottom-space
> >
<template #control> <template #control>
<q-editor <q-editor
@update:model-value="props.onCheckChangeData()"
:readonly="store.readonly" :readonly="store.readonly"
class="full-width" class="full-width"
v-model="formData.commandFooter" v-model="formData.detailFooter"
min-height="5rem" min-height="5rem"
:toolbar="[ :toolbar="[
['left', 'center', 'right', 'justify'], ['left', 'center', 'right', 'justify'],
@ -184,22 +293,13 @@ const modalPreview = ref<boolean>(false);
</q-card-section> </q-card-section>
</q-card> </q-card>
</div> </div>
<div class="col-12 row justify-end">
<q-btn
label="แสดงตัวอย่าง"
color="info"
icon="mdi-eye"
@click.prevent="modalPreview = true"
/>
</div>
</div> </div>
</q-card-section> </q-card-section>
<q-separator /> <q-separator />
<q-card-actions align="right" v-if="!store.readonly"> <q-card-actions align="right" v-if="!store.readonly">
<q-btn label="บันทึก" color="public" /> <q-btn label="บันทึก" color="public" @click="onSubmit" />
</q-card-actions> </q-card-actions>
<DialogPerview v-model:modal="modalPreview" /> <DialogPerview v-model:modal="modalPreview" />

View file

@ -24,6 +24,11 @@ const {
success, success,
} = useCounterMixin(); } = useCounterMixin();
const isChangeData = defineModel<boolean>("isChangeData", { required: true });
const props = defineProps({
onCheckChangeData: { type: Function, required: true },
});
const posNoOptions = ref<DataOption[]>(storePosSalary.optionPos); const posNoOptions = ref<DataOption[]>(storePosSalary.optionPos);
const templatePos = ref<string>(""); const templatePos = ref<string>("");
const position = ref<string>(""); const position = ref<string>("");
@ -116,6 +121,11 @@ function filterSelector(val: string, update: Function, filtername: string) {
break; break;
} }
} }
function onSubmit() {}
defineExpose({
onSubmit,
});
</script> </script>
<template> <template>

View file

@ -21,6 +21,11 @@ const {
success, success,
} = useCounterMixin(); } = useCounterMixin();
const isChangeData = defineModel<boolean>("isChangeData", { required: true });
const props = defineProps({
onCheckChangeData: { type: Function, required: true },
});
const filter = ref<string>(""); const filter = ref<string>("");
const rows = ref<any[]>([ const rows = ref<any[]>([
{ {
@ -109,6 +114,11 @@ function onDelete(id: string) {
} }
function onSubmitPerson() {} function onSubmitPerson() {}
function onSubmit() {}
defineExpose({
onSubmit,
});
</script> </script>
<template> <template>

View file

@ -1,4 +1,14 @@
<script setup lang="ts"></script> <script setup lang="ts">
const isChangeData = defineModel<boolean>("isChangeData", { required: true });
const props = defineProps({
onCheckChangeData: { type: Function, required: true },
});
function onSubmit() {}
defineExpose({
onSubmit,
});
</script>
<template> <template>
<div>คำสงและบญชแนบทาย</div> <div>คำสงและบญชแนบทาย</div>

View file

@ -7,4 +7,9 @@ interface DataOption {
name: string; name: string;
} }
export type { Pagination, DataOption }; interface ItemTabs {
label: string;
name: string;
}
export type { Pagination, DataOption, ItemTabs };

View file

@ -1 +1,24 @@
export type {}; interface FormQuery {
page: number;
pageSize: number;
year: number;
keyword: string;
}
interface FormCommand {
commandYear: number;
commandNo: string;
commandTypeId?: string;
}
interface FormDataDetail {
commandNo: string;
commandYear: number | null;
// commandName: string;
detailHeader: string;
detailBody: string;
detailFooter: string;
issue: string | null;
}
export type { FormQuery, FormCommand, FormDataDetail };

View file

@ -1,4 +1,25 @@
interface ResListCommand {
data: {
result: {
data: DataListCommand[];
total: number;
};
};
}
interface DataListCommand { interface DataListCommand {
assignFullName: string;
commandAffectDate: null | Date | string;
commandExcecuteDate: null | Date | string;
commandNo: string;
commandYear: number;
createdFullName: string;
id: string;
status: string;
issue?: string;
}
interface DataCommandType {
category: string; category: string;
commandCode: string; commandCode: string;
createdAt: string | Date; createdAt: string | Date;
@ -11,4 +32,4 @@ interface DataListCommand {
name: string; name: string;
} }
export type { DataListCommand }; export type { ResListCommand, DataListCommand, DataCommandType };

View file

@ -3,6 +3,7 @@ import { defineStore } from "pinia";
export const useCommandDetail = defineStore("commandDetailStore", () => { export const useCommandDetail = defineStore("commandDetailStore", () => {
const readonly = ref<boolean>(false); const readonly = ref<boolean>(false);
const isChangeData = ref<boolean>(false);
const classInput = (val: boolean) => { const classInput = (val: boolean) => {
return { return {
@ -14,5 +15,6 @@ export const useCommandDetail = defineStore("commandDetailStore", () => {
return { return {
classInput, classInput,
readonly, readonly,
}; };
}); });

View file

@ -1,12 +1,18 @@
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { ref } from "vue"; import { ref } from "vue";
import type { DataListCommand } from "@/modules/18_command/interface/response/Main";
export const useCommandListStore = defineStore("commandListStore", () => { export const useCommandListStore = defineStore("commandListStore", () => {
const tabsMain = ref<string>("list_draft"); const tabsMain = ref<string>("DRAFT");
const rows = ref<any[]>([]); const rows = ref<DataListCommand[]>([]);
const total = ref<number>(0);
const maxPage = ref<number>(0);
return { return {
tabsMain, tabsMain,
rows, rows,
total,
maxPage,
}; };
}); });

View file

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, ref } from "vue"; import { onMounted, ref, watch } from "vue";
import { useRouter, useRoute } from "vue-router"; import { useRouter, useRoute } from "vue-router";
import { useCommandDetail } from "@/modules/18_command/store/DetailStore"; import { useCommandDetail } from "@/modules/18_command/store/DetailStore";
@ -13,25 +13,51 @@ const router = useRouter();
const route = useRoute(); const route = useRoute();
const store = useCommandDetail(); const store = useCommandDetail();
const componentMap: any = { const childDetailRef = ref<InstanceType<typeof Detail> | null>(null);
Detail, const childListPersonsRef = ref<InstanceType<typeof ListPersons> | null>(null);
ListPersons, const childReceivedCopyRef = ref<InstanceType<typeof ReceivedCopy> | null>(
ReceivedCopy, null
Attached, );
}; const childAttachedRef = ref<InstanceType<typeof Attached> | null>(null);
const readonly = ref<boolean>(route.name === "commandViewDetailPage"); const readonly = ref<boolean>(route.name === "commandViewDetailPage");
const isChangeData = ref<boolean>(false);
const tabs = ref<string>("Detail"); const tabs = ref<string>("Detail");
const tabsManu = ref([ const tabsManu = ref([
{ label: "รายละเอียดคำสั่ง", name: "Detail" }, { label: "รายละเอียดคำสั่ง", name: "Detail" },
{ label: "รายชื่อผู้ออกคำสั่ง", name: "ListPersons" }, {
{ label: "รายชื่อผู้ได้รับสำเนาคำสั่ง", name: "ReceivedCopy" }, label: "รายชื่อผู้ออกคำสั่ง",
name: "ListPersons",
},
{
label: "รายชื่อผู้ได้รับสำเนาคำสั่ง",
name: "ReceivedCopy",
},
{ label: "คำสั่งและบัญชีแนบท้าบ", name: "Attached" }, { label: "คำสั่งและบัญชีแนบท้าบ", name: "Attached" },
]); ]);
/**
* function เชคการแกไขอม
*/
function onCheckChangeData() {
isChangeData.value = true;
}
onMounted(() => { onMounted(() => {
store.readonly = readonly.value; store.readonly = readonly.value;
}); });
watch(tabs, (newValue, oldValue) => {
console.log(`Count changed from ${oldValue} to ${newValue}`);
if (isChangeData.value) {
// component
if (oldValue === "Detail") {
console.log(childDetailRef.value);
childDetailRef.value?.onSubmit();
}
}
});
</script> </script>
<template> <template>
@ -73,14 +99,43 @@ onMounted(() => {
<q-separator /> <q-separator />
<q-tab-panels v-model="tabs" animated> <q-tab-panels v-model="tabs" animated>
<q-tab-panel <q-tab-panel style="padding: 0px" name="Detail">
style="padding: 0px"
v-for="(panel, index) in tabsManu"
:key="index"
:name="panel.name"
>
<q-card> <q-card>
<component :is="componentMap[panel.name]" /> <Detail
ref="childDetailRef"
v-model:is-change-data="isChangeData"
:on-check-change-data="onCheckChangeData"
/>
</q-card>
</q-tab-panel>
<q-tab-panel style="padding: 0px" name="ListPersons">
<q-card>
<ListPersons
ref="childListPersonsRef"
v-model:is-change-data="isChangeData"
:on-check-change-data="onCheckChangeData"
/>
</q-card>
</q-tab-panel>
<q-tab-panel style="padding: 0px" name="ReceivedCopy">
<q-card>
<ReceivedCopy
ref="childReceivedCopyRef"
v-model:is-change-data="isChangeData"
:on-check-change-data="onCheckChangeData"
/>
</q-card>
</q-tab-panel>
<q-tab-panel style="padding: 0px" name="Attached">
<q-card>
<Attached
ref="childAttachedRef"
v-model:is-change-data="isChangeData"
:on-check-change-data="onCheckChangeData"
/>
</q-card> </q-card>
</q-tab-panel> </q-tab-panel>
</q-tab-panels> </q-tab-panels>

View file

@ -1,53 +1,59 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, ref } from "vue"; import { reactive, ref } from "vue";
import { useQuasar } from "quasar";
import http from "@/plugins/http";
import config from "@/app.config";
import { useCounterMixin } from "@/stores/mixin";
import { useCommandListStore } from "@/modules/18_command/store/ListStore"; import { useCommandListStore } from "@/modules/18_command/store/ListStore";
import type { ItemTabs } from "@/modules/18_command/interface/index/Main";
import type { FormQuery } from "@/modules/18_command/interface/request/Main";
import type { ResListCommand } from "@/modules/18_command/interface/response/Main";
import DialogFormCommand from "@/modules/18_command/components/Main/DialogFormCommand.vue"; import DialogFormCommand from "@/modules/18_command/components/Main/DialogFormCommand.vue";
import TableList from "@/modules/18_command/components/Main/TableMain.vue"; import TableList from "@/modules/18_command/components/Main/TableMain.vue";
const $q = useQuasar();
const store = useCommandListStore(); const store = useCommandListStore();
const { showLoader, hideLoader, messageError } = useCounterMixin();
const yearly = ref<number>(new Date().getFullYear());
const searchKeyword = ref<string>("");
const modalAdd = ref<boolean>(false); const modalAdd = ref<boolean>(false);
const tabsManu = ref([ const tabsManu = ref<ItemTabs[]>([
{ label: "แบบร่าง", name: "list_draft" }, { label: "แบบร่าง", name: "DRAFT" },
{ label: "รอผู้มีอำนาจ", name: "list_authority" }, { label: "รอผู้มีอำนาจ", name: "PENDING" },
{ label: "รอออกคำสั่ง", name: "list_orders" }, { label: "รอออกคำสั่ง", name: "WAITING" },
{ label: "ออกคำสั่งเสร็จสิ้น", name: "list_completed" }, { label: "ออกคำสั่งเสร็จสิ้น", name: "REPORTED" },
{ label: "ยกเลิก", name: "list_cancel" }, { label: "ยกเลิก", name: "CANCEL" },
]); ]);
onMounted(() => { const queryParams = reactive<FormQuery>({
store.rows = [ page: 1,
{ pageSize: 10,
id: "1", year: new Date().getFullYear(),
caseFault: null, keyword: "",
faultLevel: null,
fiscalYear: "2024",
fullName: "นายพิชัยยุทธ แสงศรี",
orderBy: "สำนักงานเขตพระนคร",
orderById: "32c99b86-c390-45d2-b1aa-7af5ba2de788",
orderByOrganization: "สำนักงานเขตพระนคร",
orderDate: "2024-08-23T03:09:00",
orderId: "08dcc321-17f7-43a8-80ef-40f7822a6e46",
orderName: "คำสั่งแต่งตั้ง",
orderNo: "23",
orderStatusName: "ออกคำสั่งแล้ว",
orderStatusValue: "e0d7c384-642d-4a01-a2e9-b06180ab466d",
orderTypeName: "คำสั่งแต่งตั้ง",
orderTypeValue: "3b3c8fcf-7940-4963-ab48-b8e803ed534d",
refRaw: null,
result: null,
signatoryBy: "นายวิษณุ สุวรรณรัตน์",
signatoryDate: "2024-08-23T03:09:00",
signatoryPosition: "ผู้อำนวยการ",
},
];
console.log("mounted");
}); });
async function fetchListCommand() {
showLoader();
await http
.get(config.API.commandList, {
params: { ...queryParams, status: store.tabsMain },
})
.then(async (res: ResListCommand) => {
const data = await res.data.result;
store.rows = data.data;
store.total = data.total;
store.maxPage = Math.ceil(data.total / queryParams.pageSize);
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
</script> </script>
<template> <template>
@ -58,11 +64,12 @@ onMounted(() => {
<q-toolbar class="q-pa-sm"> <q-toolbar class="q-pa-sm">
<datepicker <datepicker
menu-class-name="modalfix" menu-class-name="modalfix"
v-model="yearly" v-model="queryParams.year"
:locale="'th'" :locale="'th'"
autoApply autoApply
year-picker year-picker
:enableTimePicker="false" :enableTimePicker="false"
@update:model-value="fetchListCommand"
> >
<template #year="{ year }">{{ year + 543 }}</template> <template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{ <template #year-overlay-value="{ value }">{{
@ -73,7 +80,9 @@ onMounted(() => {
dense dense
outlined outlined
hide-bottom-space hide-bottom-space
:model-value="yearly == null ? null : yearly + 543" :model-value="
queryParams.year == null ? null : queryParams.year + 543
"
:label="`${'ปีงบประมาณ'}`" :label="`${'ปีงบประมาณ'}`"
> >
<template v-slot:prepend> <template v-slot:prepend>
@ -101,12 +110,12 @@ onMounted(() => {
<q-input <q-input
dense dense
outlined outlined
v-model="searchKeyword" v-model="queryParams.keyword"
label="ค้นหา" label="ค้นหา"
clearable clearable
style="width: 300px" style="width: 300px"
> >
<template v-slot:append v-if="!searchKeyword"> <template v-slot:append v-if="!queryParams.keyword">
<q-icon name="search" /> </template <q-icon name="search" /> </template
></q-input> ></q-input>
</q-toolbar> </q-toolbar>
@ -138,7 +147,11 @@ onMounted(() => {
:key="index" :key="index"
:name="panel.name" :name="panel.name"
> >
<TableList /> <TableList
:fetch-list="fetchListCommand"
v-model:page="queryParams.page"
v-model:pageSize="queryParams.pageSize"
/>
</q-tab-panel> </q-tab-panel>
</q-tab-panels> </q-tab-panels>
</q-card-section> </q-card-section>