รายการคำสั่ง ==> 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

@ -6,7 +6,8 @@ import { useRouter } from "vue-router";
import http from "@/plugins/http";
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";
@ -14,18 +15,19 @@ import { useCounterMixin } from "@/stores/mixin";
const $q = useQuasar();
const router = useRouter();
const { dialogConfirm, showLoader, hideLoader, messageError } =
const { dialogConfirm, showLoader, hideLoader, messageError, success } =
useCounterMixin();
const modal = defineModel<boolean>("modal", { required: true });
const isCopy = defineModel<boolean>("isCopy", { required: true });
const commandId = defineModel<string>("commandId", { default: "" });
const commandType = ref<string>("");
const commandNo = ref<string>("");
const commandYear = ref<string>("");
const commandYear = ref<number>(new Date().getFullYear());
const listCommand = ref<DataListCommand[]>([]);
const commandOp = ref<DataListCommand[]>([]);
const listCommand = ref<DataCommandType[]>([]);
const commandOp = ref<DataCommandType[]>([]);
async function fetchCommandType() {
showLoader();
@ -46,10 +48,29 @@ async function fetchCommandType() {
function onSubmit() {
dialogConfirm($q, () => {
!isCopy.value && router.push(`/command/edit/1234`);
console.log(commandNo.value);
console.log(commandYear.value);
onClose();
showLoader();
const body: FormCommand = {
commandYear: commandYear.value,
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() {
modal.value = false;
commandNo.value = "";
commandYear.value = "";
commandYear.value = new Date().getFullYear();
}
watch(modal, () => {
@ -130,7 +151,6 @@ watch(modal, () => {
v-model="commandNo"
hide-bottom-space
:label="`${'คำสั่งเลขที่'}`"
:rules="[(val) => !!val || `${'กรุณากรอกคำสั่งเลขที่'}`]"
lazy-rules
/>
</div>
@ -138,17 +158,41 @@ watch(modal, () => {
>/</label
>
<div class="col-5">
<q-input
class="inputgreen"
outlined
dense
<datepicker
menu-class-name="modalfix"
v-model="commandYear"
hide-bottom-space
:label="`${'พ.ศ.'}`"
mask="####"
:rules="[(val) => !!val || `${'กรุณากรอก พ.ศ.'}`]"
lazy-rules
/>
:locale="'th'"
autoApply
year-picker
:enableTimePicker="false"
class="inputgreen"
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
dense
outlined
hide-bottom-space
:model-value="
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>
</q-card-section>

View file

@ -1,81 +1,113 @@
<script setup lang="ts">
import { ref } from "vue";
import { onMounted, ref, watch } from "vue";
import { useQuasar } from "quasar";
import http from "@/plugins/http";
import config from "@/app.config";
import { useRouter } from "vue-router";
import { useCounterMixin } from "@/stores/mixin";
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 { Pagination } from "@/modules/18_command/interface/index/Main";
import DialogFormCommand from "@/modules/18_command/components/Main/DialogFormCommand.vue";
const $q = useQuasar();
const router = useRouter();
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"]>([
{
name: "orderNo",
name: "commandNo",
align: "left",
label: "เลขที่คำสั่ง",
sortable: false,
field: "orderNo",
field: "commandNo",
format(val, row) {
return val ? `${val} / ${row.commandYear + 543}` : "-";
},
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "orderName",
align: "center",
name: "issue",
align: "left",
label: "ชื่อคำสั่ง",
sortable: true,
field: "orderName",
field: "issue",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "signatoryDate",
align: "center",
name: "commandExcecuteDate",
align: "left",
label: "วันที่ลงนาม",
sortable: false,
field: (v) => date2Thai(v),
field: "commandExcecuteDate",
format(val) {
return val ? date2Thai(val) : "-";
},
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "orderDate",
align: "center",
name: "commandAffectDate",
align: "left",
label: "วันที่คำสั่งมีผล",
sortable: false,
field: (v) => date2Thai(v),
field: "commandAffectDate",
format(val) {
return val ? date2Thai(val) : "-";
},
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "orderBy",
align: "center",
name: "createdFullName",
align: "left",
label: "ผู้สร้าง",
sortable: false,
field: "orderBy",
field: "createdFullName",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "signatoryBy",
align: "center",
name: "assignFullName",
align: "left",
label: "ผู้ลงนาม",
sortable: false,
field: "signatoryBy",
field: "assignFullName",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
]);
const modalCopy = ref<boolean>(false);
const isCheckPageSize = ref<boolean>(false);
const commandId = ref<string>("");
async function fetchListCommand() {
await props.fetchList?.();
}
function onRedirectToDetail(type: string, id: string) {
router.push(`/command/${type}/${id}`);
}
@ -88,7 +120,21 @@ function onCopy(id: string) {
function onCancel(id: string) {
dialogRemove(
$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>
<template>
@ -114,6 +200,8 @@ function onReCommand(id: string) {
dense
bordered
:paging="true"
:rows-per-page-options="[10, 25, 50, 100]"
@update:pagination="updatePagination"
>
<template v-slot:header="props">
<q-tr :props="props">
@ -139,7 +227,7 @@ function onReCommand(id: string) {
<q-item
clickable
v-close-popup
v-if="store.tabsMain !== 'list_cancel'"
v-if="store.tabsMain !== 'CANCEL'"
@click.pervent="onRedirectToDetail('edit', props.row.id)"
>
<q-item-section>
@ -196,7 +284,7 @@ function onReCommand(id: string) {
<q-item
clickable
v-close-popup
v-if="store.tabsMain !== 'list_cancel'"
v-if="store.tabsMain !== 'CANCEL'"
@click.pervent="onCancel(props.row.id)"
>
<q-item-section>
@ -216,7 +304,7 @@ function onReCommand(id: string) {
<q-item
clickable
v-close-popup
v-if="store.tabsMain === 'list_cancel'"
v-if="store.tabsMain === 'CANCEL'"
@click.pervent="onReCommand(props.row.id)"
>
<q-item-section>
@ -226,6 +314,20 @@ function onReCommand(id: string) {
</div>
</q-item-section>
</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-menu>
</q-btn>
@ -237,9 +339,27 @@ function onReCommand(id: string) {
</q-td>
</q-tr>
</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>
<DialogFormCommand v-model:modal="modalCopy" :is-copy="true" />
<DialogFormCommand
v-model:modal="modalCopy"
:is-copy="true"
:command-id="commandId"
/>
</template>
<style scoped></style>

View file

@ -1,27 +1,101 @@
<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 type { FormDataDetail } from "@/modules/18_command/interface/request/Main";
import DialogPerview from "@/modules/18_command/components/Step/Dialog1_Perview.vue";
const $q = useQuasar();
const route = useRoute();
const store = useCommandDetail();
const { showLoader, hideLoader, success, messageError } = useCounterMixin();
const formData = reactive({
commandNo: "",
commandYear: "",
commandName: "",
commandHeader: "",
commandCenter: "",
commandFooter: "",
const isChangeData = defineModel<boolean>("isChangeData", { required: true });
const props = defineProps({
onCheckChangeData: { type: Function, required: true },
});
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);
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>
<template>
<q-card-section>
<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-6">
@ -33,22 +107,53 @@ const modalPreview = ref<boolean>(false);
v-model="formData.commandNo"
hide-bottom-space
:label="`${'คำสั่งเลขที่'}`"
@update:model-value="props.onCheckChangeData()"
/>
</div>
<label class="col-1 flex justify-center items-center text-bold">
/
</label>
<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)"
:readonly="store.readonly"
outlined
dense
v-model="formData.commandYear"
hide-bottom-space
:label="`${'พ.ศ.'}`"
mask="####"
/>
@update:model-value="props.onCheckChangeData()"
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</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>
@ -59,9 +164,10 @@ const modalPreview = ref<boolean>(false);
:readonly="store.readonly"
outlined
dense
v-model="formData.commandName"
v-model="formData.issue"
hide-bottom-space
:label="`${'คำสั่งเรื่อง'}`"
@update:model-value="props.onCheckChangeData()"
/>
</div>
@ -76,15 +182,16 @@ const modalPreview = ref<boolean>(false);
<q-field
class="q_field_p_none"
ref="fieldRef"
v-model="formData.commandHeader"
v-model="formData.detailHeader"
borderless
hide-bottom-space
>
<template #control>
<q-editor
@update:model-value="props.onCheckChangeData()"
:readonly="store.readonly"
class="full-width"
v-model="formData.commandHeader"
v-model="formData.detailHeader"
min-height="5rem"
:toolbar="[
['left', 'center', 'right', 'justify'],
@ -116,15 +223,16 @@ const modalPreview = ref<boolean>(false);
<q-field
class="q_field_p_none"
ref="fieldRef"
v-model="formData.commandCenter"
v-model="formData.detailBody"
borderless
hide-bottom-space
>
<template #control>
<q-editor
@update:model-value="props.onCheckChangeData()"
:readonly="store.readonly"
class="full-width"
v-model="formData.commandCenter"
v-model="formData.detailBody"
min-height="5rem"
:toolbar="[
['left', 'center', 'right', 'justify'],
@ -156,15 +264,16 @@ const modalPreview = ref<boolean>(false);
<q-field
class="q_field_p_none"
ref="fieldRef"
v-model="formData.commandFooter"
v-model="formData.detailFooter"
borderless
hide-bottom-space
>
<template #control>
<q-editor
@update:model-value="props.onCheckChangeData()"
:readonly="store.readonly"
class="full-width"
v-model="formData.commandFooter"
v-model="formData.detailFooter"
min-height="5rem"
:toolbar="[
['left', 'center', 'right', 'justify'],
@ -184,22 +293,13 @@ const modalPreview = ref<boolean>(false);
</q-card-section>
</q-card>
</div>
<div class="col-12 row justify-end">
<q-btn
label="แสดงตัวอย่าง"
color="info"
icon="mdi-eye"
@click.prevent="modalPreview = true"
/>
</div>
</div>
</q-card-section>
<q-separator />
<q-card-actions align="right" v-if="!store.readonly">
<q-btn label="บันทึก" color="public" />
<q-btn label="บันทึก" color="public" @click="onSubmit" />
</q-card-actions>
<DialogPerview v-model:modal="modalPreview" />

View file

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

View file

@ -21,6 +21,11 @@ const {
success,
} = useCounterMixin();
const isChangeData = defineModel<boolean>("isChangeData", { required: true });
const props = defineProps({
onCheckChangeData: { type: Function, required: true },
});
const filter = ref<string>("");
const rows = ref<any[]>([
{
@ -109,6 +114,11 @@ function onDelete(id: string) {
}
function onSubmitPerson() {}
function onSubmit() {}
defineExpose({
onSubmit,
});
</script>
<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>
<div>คำสงและบญชแนบทาย</div>