From eba12e451a8ff3d1b791b2a1c3030e63c13d9a8c Mon Sep 17 00:00:00 2001 From: puriphatt Date: Mon, 10 Mar 2025 10:23:01 +0700 Subject: [PATCH 01/48] fix: revert number formatting in DataDisplay and restore original value in ChartReceipt --- src/components/08_request-list/DataDisplay.vue | 3 +-- src/pages/15_dash-board/chart/ChartReceipt.vue | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/components/08_request-list/DataDisplay.vue b/src/components/08_request-list/DataDisplay.vue index b344a5bb..30a8e52b 100644 --- a/src/components/08_request-list/DataDisplay.vue +++ b/src/components/08_request-list/DataDisplay.vue @@ -1,6 +1,5 @@ + + diff --git a/src/pages/04_property-managment/PropertyDialog.vue b/src/pages/04_property-managment/PropertyDialog.vue new file mode 100644 index 00000000..aab4caa5 --- /dev/null +++ b/src/pages/04_property-managment/PropertyDialog.vue @@ -0,0 +1,3 @@ + + + diff --git a/src/router/routes.ts b/src/router/routes.ts index 2f7405d1..c4573313 100644 --- a/src/router/routes.ts +++ b/src/router/routes.ts @@ -80,6 +80,11 @@ const routes: RouteRecordRaw[] = [ name: 'Workflow', component: () => import('pages/04_flow-managment/MainPage.vue'), }, + { + path: '/property', + name: 'Property', + component: () => import('pages/04_property-managment/MainPage.vue'), + }, { path: '/quotation', name: 'Quotation', From 841f1157b1871f5d395b06bdbd401020c960d5c6 Mon Sep 17 00:00:00 2001 From: Thanaphon Frappet Date: Mon, 10 Mar 2025 15:47:24 +0700 Subject: [PATCH 13/48] feat: up code test --- src/i18n/tha.ts | 6 + src/layouts/DrawerComponent.vue | 1 + src/pages/04_property-managment/MainPage.vue | 511 ++++++++++++++++++- src/stores/property/index.ts | 71 +++ src/stores/property/types.ts | 5 + 5 files changed, 592 insertions(+), 2 deletions(-) create mode 100644 src/stores/property/index.ts create mode 100644 src/stores/property/types.ts diff --git a/src/i18n/tha.ts b/src/i18n/tha.ts index 06a21d9c..ea4066d6 100644 --- a/src/i18n/tha.ts +++ b/src/i18n/tha.ts @@ -194,6 +194,7 @@ export default { personnel: 'บุคลากร', productService: 'สินค้าและบริการ', workflow: 'ขั้นตอนการทำงาน', + property: 'คุณสมบัติ', customer: 'ลูกค้า', mainData: 'ข้อมูลหลัก', agencies: 'หน่วยงาน', @@ -1431,4 +1432,9 @@ export default { 11: 'พฤศจิกายน', 12: 'ธันวาคม', }, + + property: { + title: 'คุณสมบัติ', + caption: 'จัดการคุณสมบัติ', + }, }; diff --git a/src/layouts/DrawerComponent.vue b/src/layouts/DrawerComponent.vue index 5e07ca3a..6d9f0e06 100644 --- a/src/layouts/DrawerComponent.vue +++ b/src/layouts/DrawerComponent.vue @@ -120,6 +120,7 @@ onMounted(async () => { ), }, { label: 'workflow', route: '/workflow' }, + { label: 'property', route: '/property' }, { label: 'productService', route: '/product-service' }, { label: 'customer', route: '/customer-management' }, { label: 'agencies', route: '/agencies-management' }, diff --git a/src/pages/04_property-managment/MainPage.vue b/src/pages/04_property-managment/MainPage.vue index aab4caa5..60c0c329 100644 --- a/src/pages/04_property-managment/MainPage.vue +++ b/src/pages/04_property-managment/MainPage.vue @@ -1,3 +1,510 @@ - - + + diff --git a/src/stores/property/index.ts b/src/stores/property/index.ts new file mode 100644 index 00000000..93109146 --- /dev/null +++ b/src/stores/property/index.ts @@ -0,0 +1,71 @@ +import { ref } from 'vue'; +import { defineStore } from 'pinia'; +import { api } from 'src/boot/axios'; +import { PaginationResult } from 'src/types'; +import { Status } from '../types'; +import { Property } from './types'; + +export const useProperty = defineStore('property-store', () => { + const data = ref([]); + const page = ref(1); + const pageMax = ref(1); + const pageSize = ref(30); + + async function getProperty(id: string) { + const res = await api.get(`/property/${id}`); + + if (res.status >= 400) return null; + + return res.data; + } + + async function getPropertyList(params?: { + page?: number; + pageSize?: number; + query?: string; + status?: Status; + activeOnly?: boolean; + }) { + const res = await api.get>('/property', { + params, + }); + + if (res.status >= 400) return null; + + return res.data; + } + + async function creatProperty(data: Property) { + const res = await api.post('/property', data); + if (res.status >= 400) return null; + return res; + } + + async function editProperty(data: Property & { id: string }) { + const res = await api.put(`/property/${data.id}`, { + ...data, + id: undefined, + }); + if (res.status >= 400) return null; + return res; + } + + async function deleteProperty(id: string) { + const res = await api.delete(`/property/${id}`); + if (res.status >= 400) return null; + return res; + } + + return { + data, + page, + pageSize, + pageMax, + + getProperty, + getPropertyList, + creatProperty, + editProperty, + deleteProperty, + }; +}); diff --git a/src/stores/property/types.ts b/src/stores/property/types.ts new file mode 100644 index 00000000..778b6504 --- /dev/null +++ b/src/stores/property/types.ts @@ -0,0 +1,5 @@ +export type Property = { + name: string; + nameEn: string; + type: Record; +}; From da5cec3638b8897f9469d3d912f1c077b98ba1ef Mon Sep 17 00:00:00 2001 From: Thanaphon Frappet Date: Mon, 10 Mar 2025 15:51:19 +0700 Subject: [PATCH 14/48] fix: code error --- src/pages/04_property-managment/MainPage.vue | 27 +++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/pages/04_property-managment/MainPage.vue b/src/pages/04_property-managment/MainPage.vue index 60c0c329..7bc13852 100644 --- a/src/pages/04_property-managment/MainPage.vue +++ b/src/pages/04_property-managment/MainPage.vue @@ -1,7 +1,7 @@ @@ -428,7 +443,12 @@ watch([() => pastYears.value], async () => { style="margin-left: auto" :icon="'material-symbols:download'" :label="$t('general.download')" - @click.stop="reportStore.downloadReportInvoice()" + @click.stop=" + reportStore.downloadReportInvoice({ + startDate: state.date[0], + endDate: state.date[1], + }) + " /> @@ -469,7 +489,12 @@ watch([() => pastYears.value], async () => { style="margin-left: auto" :icon="'material-symbols:download'" :label="$t('general.download')" - @click.stop="reportStore.downloadReportInvoice()" + @click.stop=" + reportStore.downloadReportInvoice({ + startDate: state.date[0], + endDate: state.date[1], + }) + " /> @@ -492,7 +517,10 @@ watch([() => pastYears.value], async () => { :icon="'material-symbols:download'" :label="$t('general.download')" @click.stop=" - reportStore.downloadReportSale('by-customer') + reportStore.downloadReportSale('by-customer', { + startDate: state.date[0], + endDate: state.date[1], + }) " /> @@ -533,7 +561,10 @@ watch([() => pastYears.value], async () => { :icon="'material-symbols:download'" :label="$t('general.download')" @click.stop=" - reportStore.downloadReportSale('by-product-group') + reportStore.downloadReportSale('by-product-group', { + startDate: state.date[0], + endDate: state.date[1], + }) " /> @@ -565,7 +596,12 @@ watch([() => pastYears.value], async () => { style="margin-left: auto" :icon="'material-symbols:download'" :label="$t('general.download')" - @click.stop="reportStore.downloadReportSale('by-sale')" + @click.stop=" + reportStore.downloadReportSale('by-sale', { + startDate: state.date[0], + endDate: state.date[1], + }) + " /> diff --git a/src/stores/report/index.ts b/src/stores/report/index.ts index 0fa216cd..8e259dbe 100644 --- a/src/stores/report/index.ts +++ b/src/stores/report/index.ts @@ -15,7 +15,28 @@ import { getToken } from 'src/services/keycloak'; const ENDPOINT = 'report'; -async function _download(url: string, filename?: string) { +async function _download( + url: string, + filename?: string, + params?: { + startDate: string | Date; + endDate: string | Date; + }, +) { + if (params) { + const queryParams = new URLSearchParams({ + startDate: + params.startDate instanceof Date + ? params.startDate.toISOString() + : params.startDate, + endDate: + params.endDate instanceof Date + ? params.endDate.toISOString() + : params.endDate, + }).toString(); + url += '?' + queryParams; + } + const res = await fetch(url, { headers: { ['Authorization']: 'Bearer ' + (await getToken()) }, }); @@ -30,10 +51,14 @@ async function _download(url: string, filename?: string) { } } -export async function downloadReportQuotation() { +export async function downloadReportQuotation(params?: { + startDate: string | Date; + endDate: string | Date; +}) { await _download( baseUrl + '/' + ENDPOINT + '/quotation/download', 'quotation-report', + params, ); } @@ -51,10 +76,14 @@ export async function getReportQuotation(params?: { return null; } -export async function downloadReportInvoice() { +export async function downloadReportInvoice(params?: { + startDate: string | Date; + endDate: string | Date; +}) { await _download( baseUrl + '/' + ENDPOINT + '/invoice/download', 'invoice-report', + params, ); } @@ -69,10 +98,14 @@ export async function getReportInvoice(params?: { return null; } -export async function downloadReportReceipt() { +export async function downloadReportReceipt(params?: { + startDate: string | Date; + endDate: string | Date; +}) { await _download( baseUrl + '/' + ENDPOINT + '/receipt/download', 'receipt-report', + params, ); } @@ -89,10 +122,15 @@ export async function getReportReceipt(params?: { export async function downloadReportSale( category: 'by-product-group' | 'by-sale' | 'by-customer', + params?: { + startDate: string | Date; + endDate: string | Date; + }, ) { await _download( baseUrl + '/' + ENDPOINT + '/sale/' + category + '/download', 'sale-' + category + '-report', + params, ); } @@ -108,10 +146,14 @@ export async function getReportSale(params?: { return null; } -export async function downloadReportProduct() { +export async function downloadReportProduct(params?: { + startDate: string | Date; + endDate: string | Date; +}) { await _download( baseUrl + '/' + ENDPOINT + '/receipt/download', 'product-report', + params, ); } From e2abeca79aea7c9f4e5b71b4f47c3fe517d6c746 Mon Sep 17 00:00:00 2001 From: Thanaphon Frappet Date: Wed, 12 Mar 2025 15:46:46 +0700 Subject: [PATCH 38/48] fix: v-mode open missing --- src/pages/08_request-list/RequestAction.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/08_request-list/RequestAction.vue b/src/pages/08_request-list/RequestAction.vue index b9fbf082..26f9c71e 100644 --- a/src/pages/08_request-list/RequestAction.vue +++ b/src/pages/08_request-list/RequestAction.vue @@ -33,7 +33,7 @@ enum Step { Configure = 2, } -const open = defineModel('selected', { default: false }); +const open = defineModel({ default: false }); const step = ref(Step.Product); const selected = ref<{ _work: RequestWork }[]>([]); const form = reactive({ From 4975ecb3349d1f516c32842aa316a9421f5560ae Mon Sep 17 00:00:00 2001 From: puriphatt Date: Thu, 13 Mar 2025 09:46:35 +0700 Subject: [PATCH 39/48] feat: i18n add rejection messages for cancellation requests in English and Thai translations --- src/i18n/eng.ts | 3 +++ src/i18n/tha.ts | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/i18n/eng.ts b/src/i18n/eng.ts index e135b4e7..5987b5d8 100644 --- a/src/i18n/eng.ts +++ b/src/i18n/eng.ts @@ -941,6 +941,7 @@ export default { Ended: 'Ended', Completed: 'Completed', Canceled: 'Canceled', + RejectCancel: 'Reject cancellation request', }, Pending: 'Pending', @@ -949,6 +950,8 @@ export default { Completed: 'Completed', Canceled: 'Canceled', CancelRequested: 'Cancel Requested', + RejectCancel: 'Rejection of cancellation request', + RejectedCancel: 'Cancellation request rejected', AwaitOrder: 'Awaiting Order', ReadyOrder: 'Ready for Order', diff --git a/src/i18n/tha.ts b/src/i18n/tha.ts index fdda03b5..86aee090 100644 --- a/src/i18n/tha.ts +++ b/src/i18n/tha.ts @@ -931,6 +931,7 @@ export default { Ended: 'จบงาน', Completed: 'เสร็จสิ้น', Canceled: 'ยกเลิก', + RejectCancel: 'ปฏิเสธคําขอยกเลิก', }, Pending: 'รอดำเนินการ', Ready: 'พร้อมดำเนินการ', @@ -938,6 +939,8 @@ export default { Completed: 'เสร็จสิ้น', Canceled: 'ยกเลิก', CancelRequested: 'ต้องการยกเลิก', + RejectCancel: 'การปฏิเสธคําขอยกเลิก', + RejectedCancel: 'ปฏิเสธคําขอยกเลิกแล้ว', AwaitOrder: 'รอสั่งงาน', ReadyOrder: 'พร้อมสั่งงาน', From 644c2a000858292054a3cb1927ad3db955b631c5 Mon Sep 17 00:00:00 2001 From: puriphatt Date: Thu, 13 Mar 2025 09:46:49 +0700 Subject: [PATCH 40/48] feat: add request rejection functionality and update types for cancel requests --- src/stores/request-list/index.ts | 30 ++++++++++++++++++++++++++++++ src/stores/request-list/types.ts | 3 +++ 2 files changed, 33 insertions(+) diff --git a/src/stores/request-list/index.ts b/src/stores/request-list/index.ts index cabff09c..24b625e1 100644 --- a/src/stores/request-list/index.ts +++ b/src/stores/request-list/index.ts @@ -294,6 +294,33 @@ export const useRequestList = defineStore('request-list', () => { return null; } + async function rejectRequest(requestDataId: string) { + const res = await api.post( + `/request-data/${requestDataId}/reject-request-cancel`, + ); + + if (res.status < 400) return true; + + return false; + } + + async function rejectRequestWork( + requestDataId: string, + requestWorkId: string, + body: { + reason: string; + }, + ) { + const res = await api.post( + `/request-data/{requestDataId}/request-work/${requestWorkId}/reject-request-cancel`, + body, + ); + + if (res.status < 400) return true; + + return false; + } + return { data, page, @@ -316,6 +343,9 @@ export const useRequestList = defineStore('request-list', () => { cancelRequest, actionRequestWork, + + rejectRequest, + rejectRequestWork, }; }); diff --git a/src/stores/request-list/types.ts b/src/stores/request-list/types.ts index c17e0ebf..37d5171b 100644 --- a/src/stores/request-list/types.ts +++ b/src/stores/request-list/types.ts @@ -43,6 +43,7 @@ export enum RequestWorkStatus { Ended = 'Ended', Completed = 'Completed', Canceled = 'Canceled', + RejectCancel = 'RejectCancel', } export enum DocStatus { @@ -65,6 +66,8 @@ export type RequestWork = { processByUserId?: string; customerRequestCancel?: boolean; customerRequestCancelReason?: string; + rejectRequestCancel?: boolean; + rejectRequestCancelReason?: string; }; export type RowDocument = { From e1d1ee7d8ba92f042345ce46f63ec4c0a9da014e Mon Sep 17 00:00:00 2001 From: puriphatt Date: Thu, 13 Mar 2025 09:47:03 +0700 Subject: [PATCH 41/48] feat: add cancellation reason input component to request list --- src/pages/08_request-list/FormCancel.vue | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/pages/08_request-list/FormCancel.vue diff --git a/src/pages/08_request-list/FormCancel.vue b/src/pages/08_request-list/FormCancel.vue new file mode 100644 index 00000000..4490418d --- /dev/null +++ b/src/pages/08_request-list/FormCancel.vue @@ -0,0 +1,21 @@ + + + + From c1adc9dee383ca106f7faaf6e289803edce38c84 Mon Sep 17 00:00:00 2001 From: puriphatt Date: Thu, 13 Mar 2025 09:47:12 +0700 Subject: [PATCH 42/48] feat: add reject request cancellation functionality and UI components --- .../08_request-list/ProductExpansion.vue | 34 +++++--- src/pages/08_request-list/RequestListView.vue | 79 +++++++++++++++++-- 2 files changed, 99 insertions(+), 14 deletions(-) diff --git a/src/pages/08_request-list/ProductExpansion.vue b/src/pages/08_request-list/ProductExpansion.vue index 788f4d0c..93f617eb 100644 --- a/src/pages/08_request-list/ProductExpansion.vue +++ b/src/pages/08_request-list/ProductExpansion.vue @@ -20,6 +20,8 @@ const props = defineProps<{ imgUrl?: string; requestCancel?: boolean; requestCancelReason?: string; + rejectRequestCancel?: boolean; + rejectRequestCancelReason?: string; installmentInfo?: { total: number; paid?: number; @@ -37,7 +39,9 @@ function changeableStatus(currentStatus?: RequestWorkStatus) { case RequestWorkStatus.Ready: case RequestWorkStatus.Waiting: case RequestWorkStatus.InProgress: - return [RequestWorkStatus.Canceled]; + return props.requestCancel && !props.rejectRequestCancel + ? [RequestWorkStatus.Canceled, RequestWorkStatus.RejectCancel] + : [RequestWorkStatus.Canceled]; case RequestWorkStatus.Validate: case RequestWorkStatus.Ended: case RequestWorkStatus.Completed: @@ -45,12 +49,15 @@ function changeableStatus(currentStatus?: RequestWorkStatus) { return []; default: if (props.readonly) return []; + const statuses = [ + RequestWorkStatus.Ready, + RequestWorkStatus.Ended, + RequestWorkStatus.Canceled, + ]; if (props.orderAble) { - return [ - RequestWorkStatus.Ready, - RequestWorkStatus.Ended, - RequestWorkStatus.Canceled, - ]; + return props.requestCancel && !props.rejectRequestCancel + ? [...statuses, RequestWorkStatus.RejectCancel] + : statuses; } else { return [RequestWorkStatus.Ended, RequestWorkStatus.Canceled]; } @@ -103,11 +110,19 @@ function changeableStatus(currentStatus?: RequestWorkStatus) { v-if="requestCancel && !cancel" :hsla-color="'--red-5-hsl'" class="q-ml-sm" - :title="$t(`requestList.status.CancelRequested`) || '-'" + :title=" + rejectRequestCancel + ? $t('requestList.status.RejectedCancel') || '-' + : $t(`requestList.status.CancelRequested`) || '-' + " > @@ -171,10 +186,11 @@ function changeableStatus(currentStatus?: RequestWorkStatus) { clickable v-close-popup class="row items-center" + :class="{ 'bordered-t': value === 'RejectCancel' }" @click=" $emit('changeStatus', { step: status, - requestWorkStatus: value, + requestWorkStatus: value as RequestWorkStatus, }) " > diff --git a/src/pages/08_request-list/RequestListView.vue b/src/pages/08_request-list/RequestListView.vue index eae2002a..47423b7c 100644 --- a/src/pages/08_request-list/RequestListView.vue +++ b/src/pages/08_request-list/RequestListView.vue @@ -11,10 +11,13 @@ import PropertiesExpansion from './PropertiesExpansion.vue'; import FormGroupHead from './FormGroupHead.vue'; import AvatarGroup from 'src/components/shared/AvatarGroup.vue'; import { StateButton } from 'components/button'; -import { CancelButton, MainButton } from 'components/button'; +import { CancelButton, MainButton, SaveButton } from 'components/button'; import DutyExpansion from './DutyExpansion.vue'; import MessengerExpansion from './MessengerExpansion.vue'; import RequestAction from './RequestAction.vue'; +import DialogFormContainer from 'src/components/dialog/DialogFormContainer.vue'; +import DialogHeader from 'src/components/dialog/DialogHeader.vue'; +import FormCancel from './FormCancel.vue'; // NOTE: Store import { @@ -104,6 +107,9 @@ const pageState = reactive({ hideMetaData: false, currentStep: 1, requestActionDialog: false, + rejectCancelDialog: false, + rejectCancelReason: '', + requestWorkId: '', }); // NOTE: Function @@ -173,6 +179,13 @@ async function triggerChangeStatusWork(step: Step, responsibleUserId?: string) { }); return; } + + if (step.workStatus === 'RejectCancel') { + pageState.rejectCancelDialog = true; + pageState.requestWorkId = step.requestWorkId; + return; + } + const res = await requestListStore.editStatusRequestWork(step); if (res) { const indexWork = workList.value?.findIndex( @@ -400,6 +413,30 @@ async function submitRequestAction(data: { pageState.requestActionDialog = false; } } + +async function submitRejectCancel() { + const current = route.params['requestListId']; + if (typeof current !== 'string') return; + + const res = await requestListStore.rejectRequestWork( + current, + pageState.requestWorkId, + { + reason: pageState.rejectCancelReason, + }, + ); + + if (res) { + const indexWork = workList.value?.findIndex( + (v) => v.id === pageState.requestWorkId, + ); + + workList.value[indexWork].rejectRequestCancel = true; + workList.value[indexWork].rejectRequestCancelReason = + pageState.rejectCancelReason; + pageState.rejectCancelDialog = false; + } +} From ab51d7a8db6400a1a5b60337799b721423646da9 Mon Sep 17 00:00:00 2001 From: puriphatt Date: Thu, 13 Mar 2025 09:53:07 +0700 Subject: [PATCH 43/48] fix: update color logic for cancellation badge and correct API endpoint for reject request cancel --- src/pages/08_request-list/ProductExpansion.vue | 2 +- src/stores/request-list/index.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/08_request-list/ProductExpansion.vue b/src/pages/08_request-list/ProductExpansion.vue index 93f617eb..4d110dc3 100644 --- a/src/pages/08_request-list/ProductExpansion.vue +++ b/src/pages/08_request-list/ProductExpansion.vue @@ -108,7 +108,7 @@ function changeableStatus(currentStatus?: RequestWorkStatus) { +
+
-