From 8645fc4c450a7f8bfe5db9914566ec03d1e802e1 Mon Sep 17 00:00:00 2001 From: Thanaphon Frappet Date: Tue, 4 Mar 2025 11:02:26 +0700 Subject: [PATCH 01/11] feat: add apex charts --- package.json | 2 ++ pnpm-lock.yaml | 78 ++++++++++++++++++++++++++++++++++++++++++ src/boot/components.ts | 2 ++ 3 files changed, 82 insertions(+) diff --git a/package.json b/package.json index bd2467ca..bdc29566 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "@quasar/extras": "^1.16.12", "@tato30/vue-pdf": "^1.11.0", "@vuepic/vue-datepicker": "^8.8.1", + "apexcharts": "^4.5.0", "axios": "^1.7.4", "cropperjs": "^1.6.2", "keycloak-js": "^25.0.4", @@ -34,6 +35,7 @@ "udsv": "^0.6.0", "uuid": "^10.0.0", "vue": "^3.4.38", + "vue3-apexcharts": "^1.7.0", "vue-dragscroll": "^4.0.6", "vue-i18n": "^9.14.0", "vue-pdf": "^4.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4cba44ed..9543f9bc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,6 +17,9 @@ importers: '@vuepic/vue-datepicker': specifier: ^8.8.1 version: 8.8.1(vue@3.4.38(typescript@5.5.4)) + apexcharts: + specifier: ^4.5.0 + version: 4.5.0 axios: specifier: ^1.7.4 version: 1.7.4 @@ -77,6 +80,9 @@ importers: vue-router: specifier: ^4.4.3 version: 4.4.3(vue@3.4.38(typescript@5.5.4)) + vue3-apexcharts: + specifier: ^1.7.0 + version: 1.8.0(apexcharts@4.5.0)(vue@3.4.38(typescript@5.5.4)) devDependencies: '@faker-js/faker': specifier: ^9.3.0 @@ -725,6 +731,31 @@ packages: '@socket.io/component-emitter@3.1.1': resolution: {integrity: sha512-dzJtaDAAoXx4GCOJpbB2eG/Qj8VDpdwkLsWGzGm+0L7E8/434RyMbAHmk9ubXWVAb9nXmc44jUf8GKqVDiKezg==} + '@svgdotjs/svg.draggable.js@3.0.6': + resolution: {integrity: sha512-7iJFm9lL3C40HQcqzEfezK2l+dW2CpoVY3b77KQGqc8GXWa6LhhmX5Ckv7alQfUXBuZbjpICZ+Dvq1czlGx7gA==} + peerDependencies: + '@svgdotjs/svg.js': ^3.2.4 + + '@svgdotjs/svg.filter.js@3.0.9': + resolution: {integrity: sha512-/69XMRCDoam2HgC4ldHIaDgeQf1ViHIsa0Ld4uWgiXtZ+E24DWHe/9Ib6kbNiZ7WRIdlVokUDR1Fg0kjIpkfbw==} + engines: {node: '>= 0.8.0'} + + '@svgdotjs/svg.js@3.2.4': + resolution: {integrity: sha512-BjJ/7vWNowlX3Z8O4ywT58DqbNRyYlkk6Yz/D13aB7hGmfQTvGX4Tkgtm/ApYlu9M7lCQi15xUEidqMUmdMYwg==} + + '@svgdotjs/svg.resize.js@2.0.5': + resolution: {integrity: sha512-4heRW4B1QrJeENfi7326lUPYBCevj78FJs8kfeDxn5st0IYPIRXoTtOSYvTzFWgaWWXd3YCDE6ao4fmv91RthA==} + engines: {node: '>= 14.18'} + peerDependencies: + '@svgdotjs/svg.js': ^3.2.4 + '@svgdotjs/svg.select.js': ^4.0.1 + + '@svgdotjs/svg.select.js@4.0.2': + resolution: {integrity: sha512-5gWdrvoQX3keo03SCmgaBbD+kFftq0F/f2bzCbNnpkkvW6tk4rl4MakORzFuNjvXPWwB4az9GwuvVxQVnjaK2g==} + engines: {node: '>= 14.18'} + peerDependencies: + '@svgdotjs/svg.js': ^3.2.4 + '@tato30/vue-pdf@1.11.0': resolution: {integrity: sha512-GQNfVqq8if6/tezgcW1E0iU7kO5VfzMihdU6sfRnw0ewDYcP43JFt3r2fmDggyAY5lu7ArEwCFvlWi7WbvleCw==} peerDependencies: @@ -979,6 +1010,9 @@ packages: '@xtuc/long@4.2.2': resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + '@yr/monotone-cubic-spline@1.0.3': + resolution: {integrity: sha512-FQXkOta0XBSUPHndIKON2Y9JeQz5ZeMqLYZVVK93FliNBFm7LNMIZmY6FrMEB9XPcDbE2bekMbZD6kzDkxwYjA==} + abbrev@1.1.1: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} @@ -1052,6 +1086,9 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} + apexcharts@4.5.0: + resolution: {integrity: sha512-E7ZkrVqPNBUWy/Rmg8DEIqHNBmElzICE/oxOX5Ekvs2ICQUOK/VkEkMH09JGJu+O/EA0NL31hxlmF+wrwrSLaQ==} + aproba@1.2.0: resolution: {integrity: sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==} @@ -3569,6 +3606,12 @@ packages: peerDependencies: vue: ^3.2.0 + vue3-apexcharts@1.8.0: + resolution: {integrity: sha512-5tSD4mXTBbIJ9ir+58qHE6oNtIe0RNgqIRYMKpcsIaxkKtwUww4JhvPkpUFlmiW4OJbbdklgjleXq1lfcM4gdA==} + peerDependencies: + apexcharts: '>=4.0.0' + vue: '>=3.0.0' + vue@3.4.38: resolution: {integrity: sha512-f0ZgN+mZ5KFgVv9wz0f4OgVKukoXtS3nwET4c2vLBGQR50aI8G0cqbFtLlX9Yiyg3LFGBitruPHt2PxwTduJEw==} peerDependencies: @@ -4186,6 +4229,25 @@ snapshots: '@socket.io/component-emitter@3.1.1': {} + '@svgdotjs/svg.draggable.js@3.0.6(@svgdotjs/svg.js@3.2.4)': + dependencies: + '@svgdotjs/svg.js': 3.2.4 + + '@svgdotjs/svg.filter.js@3.0.9': + dependencies: + '@svgdotjs/svg.js': 3.2.4 + + '@svgdotjs/svg.js@3.2.4': {} + + '@svgdotjs/svg.resize.js@2.0.5(@svgdotjs/svg.js@3.2.4)(@svgdotjs/svg.select.js@4.0.2(@svgdotjs/svg.js@3.2.4))': + dependencies: + '@svgdotjs/svg.js': 3.2.4 + '@svgdotjs/svg.select.js': 4.0.2(@svgdotjs/svg.js@3.2.4) + + '@svgdotjs/svg.select.js@4.0.2(@svgdotjs/svg.js@3.2.4)': + dependencies: + '@svgdotjs/svg.js': 3.2.4 + '@tato30/vue-pdf@1.11.0(vue@3.4.38(typescript@5.5.4))': dependencies: pdfjs-dist: 4.5.136 @@ -4549,6 +4611,8 @@ snapshots: '@xtuc/long@4.2.2': {} + '@yr/monotone-cubic-spline@1.0.3': {} + abbrev@1.1.1: optional: true @@ -4625,6 +4689,15 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 + apexcharts@4.5.0: + dependencies: + '@svgdotjs/svg.draggable.js': 3.0.6(@svgdotjs/svg.js@3.2.4) + '@svgdotjs/svg.filter.js': 3.0.9 + '@svgdotjs/svg.js': 3.2.4 + '@svgdotjs/svg.resize.js': 2.0.5(@svgdotjs/svg.js@3.2.4)(@svgdotjs/svg.select.js@4.0.2(@svgdotjs/svg.js@3.2.4)) + '@svgdotjs/svg.select.js': 4.0.2(@svgdotjs/svg.js@3.2.4) + '@yr/monotone-cubic-spline': 1.0.3 + aproba@1.2.0: {} aproba@2.0.0: @@ -7513,6 +7586,11 @@ snapshots: '@vue/devtools-api': 6.6.3 vue: 3.4.38(typescript@5.5.4) + vue3-apexcharts@1.8.0(apexcharts@4.5.0)(vue@3.4.38(typescript@5.5.4)): + dependencies: + apexcharts: 4.5.0 + vue: 3.4.38(typescript@5.5.4) + vue@3.4.38(typescript@5.5.4): dependencies: '@vue/compiler-dom': 3.4.38 diff --git a/src/boot/components.ts b/src/boot/components.ts index 0987be70..9983cfed 100644 --- a/src/boot/components.ts +++ b/src/boot/components.ts @@ -4,10 +4,12 @@ import '@vuepic/vue-datepicker/dist/main.css'; import GlobalDialog from 'components/GlobalDialog.vue'; import GlobalLoading from 'components/GlobalLoading.vue'; import VueDragscroll from 'vue-dragscroll'; +import VueApexCharts from 'vue3-apexcharts'; export default boot(({ app }) => { app.component('global-dialog', GlobalDialog); app.component('global-loading', GlobalLoading); app.component('VueDatePicker', VueDatePicker); + app.component('VueApexCharts', VueApexCharts); app.use(VueDragscroll); }); From 6f256cc2543229701f1dfcf50de103edd1180b5b Mon Sep 17 00:00:00 2001 From: Thanaphon Frappet Date: Tue, 4 Mar 2025 11:06:00 +0700 Subject: [PATCH 02/11] refactor: show menu dash board --- src/layouts/DrawerComponent.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/src/layouts/DrawerComponent.vue b/src/layouts/DrawerComponent.vue index dde0f1ed..4a3928f0 100644 --- a/src/layouts/DrawerComponent.vue +++ b/src/layouts/DrawerComponent.vue @@ -171,7 +171,6 @@ onMounted(async () => { { label: 'menu.overall', icon: 'mdi-monitor-dashboard', - disabled: true, children: [ { label: 'report', route: '' }, { label: 'dashboard', route: '' }, From 4be37ad2688f22ae20ecd402fd24218324bf8196 Mon Sep 17 00:00:00 2001 From: Thanaphon Frappet Date: Tue, 4 Mar 2025 11:22:31 +0700 Subject: [PATCH 03/11] feat: add route report and dashboard --- src/layouts/DrawerComponent.vue | 4 ++-- src/router/routes.ts | 32 +++++++++++++++++++++----------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/layouts/DrawerComponent.vue b/src/layouts/DrawerComponent.vue index 4a3928f0..5e07ca3a 100644 --- a/src/layouts/DrawerComponent.vue +++ b/src/layouts/DrawerComponent.vue @@ -172,8 +172,8 @@ onMounted(async () => { label: 'menu.overall', icon: 'mdi-monitor-dashboard', children: [ - { label: 'report', route: '' }, - { label: 'dashboard', route: '' }, + { label: 'report', route: '/report' }, + { label: 'dashboard', route: '/dash-board' }, ], }, ]; diff --git a/src/router/routes.ts b/src/router/routes.ts index 785f6601..6d752495 100644 --- a/src/router/routes.ts +++ b/src/router/routes.ts @@ -75,16 +75,16 @@ const routes: RouteRecordRaw[] = [ name: 'productAndService', component: () => import('pages/04_product-service/MainPage.vue'), }, - { - path: '/quotation', - name: 'Quotation', - component: () => import('pages/05_quotation/MainPage.vue'), - }, { path: '/workflow', name: 'Workflow', component: () => import('pages/04_flow-managment/MainPage.vue'), }, + { + path: '/quotation', + name: 'Quotation', + component: () => import('pages/05_quotation/MainPage.vue'), + }, { path: '/document-management', name: 'document-management', @@ -105,15 +105,20 @@ const routes: RouteRecordRaw[] = [ name: 'TaskOrder', component: () => import('pages/09_task-order/MainPage.vue'), }, + { + path: '/invoice', + name: '/Invoice', + component: () => import('pages/10_invoice/MainPage.vue'), + }, { path: '/credit-note', name: 'CreditNote', component: () => import('pages/11_credit-note/MainPage.vue'), }, { - path: '/invoice', - name: '/Invoice', - component: () => import('pages/10_invoice/MainPage.vue'), + path: '/debit-note', + name: 'debitNote', + component: () => import('pages/12_debit-note/MainPage.vue'), }, { path: '/receipt', @@ -121,9 +126,14 @@ const routes: RouteRecordRaw[] = [ component: () => import('pages/13_receipt/MainPage.vue'), }, { - path: '/debit-note', - name: 'debitNote', - component: () => import('pages/12_debit-note/MainPage.vue'), + path: '/report', + name: 'report', + component: () => import('pages/14_report/MainPage.vue'), + }, + { + path: '/dash-board', + name: 'dashBoard', + component: () => import('pages/15_dash-board/MainPage.vue'), }, ], }, From 780a2629798afacbf59fda2654ed5596b806c33e Mon Sep 17 00:00:00 2001 From: Thanaphon Frappet Date: Tue, 4 Mar 2025 11:25:13 +0700 Subject: [PATCH 04/11] feat: add directory report and dashboard --- src/pages/14_report/MainPage.vue | 11 +++++++++++ src/pages/15_dash-board/MainPage.vue | 11 +++++++++++ 2 files changed, 22 insertions(+) create mode 100644 src/pages/14_report/MainPage.vue create mode 100644 src/pages/15_dash-board/MainPage.vue diff --git a/src/pages/14_report/MainPage.vue b/src/pages/14_report/MainPage.vue new file mode 100644 index 00000000..081ecf2e --- /dev/null +++ b/src/pages/14_report/MainPage.vue @@ -0,0 +1,11 @@ + + + diff --git a/src/pages/15_dash-board/MainPage.vue b/src/pages/15_dash-board/MainPage.vue new file mode 100644 index 00000000..081ecf2e --- /dev/null +++ b/src/pages/15_dash-board/MainPage.vue @@ -0,0 +1,11 @@ + + + From b892924a18c4be9c2f4b4b7be6de0d7c0eed8816 Mon Sep 17 00:00:00 2001 From: Thanaphon Frappet Date: Tue, 4 Mar 2025 13:31:35 +0700 Subject: [PATCH 05/11] feat: add title --- src/pages/14_report/MainPage.vue | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/pages/14_report/MainPage.vue b/src/pages/14_report/MainPage.vue index 081ecf2e..7f3a32b7 100644 --- a/src/pages/14_report/MainPage.vue +++ b/src/pages/14_report/MainPage.vue @@ -1,11 +1,24 @@ - + + From 9aef3592912dea7e8e06fa6979f4d851f1cefe0b Mon Sep 17 00:00:00 2001 From: Thanaphon Frappet Date: Wed, 5 Mar 2025 16:07:37 +0700 Subject: [PATCH 06/11] feat: add stores of report --- src/stores/report/index.ts | 71 ++++++++++++++++++++++++++++++++++++++ src/stores/report/types.ts | 41 ++++++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 src/stores/report/index.ts create mode 100644 src/stores/report/types.ts diff --git a/src/stores/report/index.ts b/src/stores/report/index.ts new file mode 100644 index 00000000..0f0ab14f --- /dev/null +++ b/src/stores/report/index.ts @@ -0,0 +1,71 @@ +import { ref } from 'vue'; +import { defineStore } from 'pinia'; +import { Pagination, Status } from '../types'; +import { api } from 'src/boot/axios'; +import { Report, ReportProduct, ReportQuotation, ReportSale } from './types'; + +const ENDPOINT = 'report'; + +export async function getReportQuotation() { + const res = await api.get(`/${ENDPOINT}/quotation`); + if (res.status < 400) { + res.data; + return res.data; + } + return null; +} + +export async function getReportInvoice() { + const res = await api.get(`/${ENDPOINT}/invoice`); + if (res.status < 400) { + return res.data; + } + return null; +} + +export async function getReportReceipt() { + const res = await api.get(`/${ENDPOINT}/receipt`); + if (res.status < 400) { + return res.data; + } + return null; +} + +export async function getReportSale() { + const res = await api.get(`/${ENDPOINT}/sale`); + + if (res.status < 400) { + return res.data; + } + return null; +} + +export async function getReportProduct() { + const res = await api.get(`/${ENDPOINT}/Product`); + if (res.status < 400) { + return res.data; + } + return null; +} + +export const useReportStore = defineStore('report-store', () => { + const dataReportQuotation = ref([]); + const dataReportInvoice = ref([]); + const dataReportReceipt = ref([]); + const dataReportSale = ref(); + const dataReportProduct = ref([]); + + return { + dataReportQuotation, + dataReportInvoice, + dataReportReceipt, + dataReportSale, + dataReportProduct, + + getReportQuotation, + getReportInvoice, + getReportReceipt, + getReportSale, + getReportProduct, + }; +}); diff --git a/src/stores/report/types.ts b/src/stores/report/types.ts new file mode 100644 index 00000000..92215ae3 --- /dev/null +++ b/src/stores/report/types.ts @@ -0,0 +1,41 @@ +import { QuotationStatus } from 'src/stores/quotations/types'; +import { ProductGroup } from '../product-service/types'; +import { User } from '../user'; +import { CustomerBranch } from '../customer'; + +export type ReportQuotation = { + updatedAt: Date | null; + createdAt: Date | null; + status: QuotationStatus; + code: string; +}; + +export enum Status { + PaymentInProcess = 'PaymentInProcess', + PaymentSuccess = 'PaymentSuccess', + PaymentWait = 'PaymentWait', + PaymentRetry = 'PaymentRetry', +} + +// use with Invoice and Receipt +export type Report = { + createdAt: Date | null; + status: Status; + code: string; +}; + +export type ReportProduct = { + updatedAt: Date | null; + createdAt: Date | null; + order: number; + did: number; + sale: number; + name: string; + code: string; +}; + +export type ReportSale = { + byCustomer: (Omit & { _count: number })[]; + bySale: (User & { _count: number })[]; + byProductGroup: (Omit & { _count: number })[]; +}; From 2e32ad28d79ab5543e1f43d9a26b3c89e56cecbf Mon Sep 17 00:00:00 2001 From: Thanaphon Frappet Date: Wed, 5 Mar 2025 16:36:54 +0700 Subject: [PATCH 07/11] feat: add i18n --- src/i18n/eng.ts | 40 ++++++++++++++++++++++++++++++++++++++++ src/i18n/tha.ts | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/src/i18n/eng.ts b/src/i18n/eng.ts index c822240c..3b7d494a 100644 --- a/src/i18n/eng.ts +++ b/src/i18n/eng.ts @@ -1336,4 +1336,44 @@ export default { Succeed: 'Completed', }, }, + + report: { + report: { + title: 'Report', + view: { + Document: 'Document Status Report', + Invoice: 'Payment Report', + Product: 'Product and Service Report', + admin: { + Product: 'Product Movement Report', + Sale: 'Sales Summary Report', + }, + }, + document: { + code: 'Code', + status: 'Quotation Status', + createAt: 'Created Date', + updateAt: 'Updated Date', + }, + table: { + code: 'Code', + status: 'Status', + createAt: 'Created Date', + }, + product: { + did: 'Processed Quantity', + sale: 'Sold Quantity', + name: 'Product Name', + code: 'Product Code', + }, + sale: { + byCustomer: 'Sales by Branch', + byProductGroup: 'Sales by Product Category', + bySale: 'Sales by Salesperson', + code: 'Code', + name: 'Name', + count: 'Sold Quantity', + }, + }, + }, }; diff --git a/src/i18n/tha.ts b/src/i18n/tha.ts index c3205cbc..8657680f 100644 --- a/src/i18n/tha.ts +++ b/src/i18n/tha.ts @@ -1315,4 +1315,43 @@ export default { Succeed: 'เสร็จสิ้น', }, }, + + report: { + title: 'รายงาน', + view: { + Document: 'รายงานสถานะเอกสาร', + Invoice: 'รายงานการชำระเงิน', + Product: 'รายงานสินค้าและบริการ', + admin: { + Product: 'รายงานการเคลื่อนไหวของสินค้า', + Sale: 'รายงานสรุปยอดขาย', + }, + }, + document: { + code: 'รหัส', + status: 'สถานะใบเสนอราคา', + createAt: 'วันที่สร้าง', + updateAt: 'วันที่แก้ไข', + }, + table: { + code: 'รหัส', + status: 'สถานะ', + createAt: 'วันที่สร้าง', + }, + product: { + did: 'จำนวนที่ออกไปดำเนินการ', + sale: 'จำนวนที่ขายออกไป', + name: 'ชื่อสินค้า', + code: 'รหัสสินค้า', + }, + + sale: { + byCustomer: 'ยอดขายตามสาขา', + byProductGroup: 'ยอดขายตามประเภทสินค้า', + bySale: 'ยอดขายตามพนักงานขาย', + code: 'รหัส', + name: 'ชื่อ', + count: 'จำนวนที่ขาย', + }, + }, }; From ba10fc960932860f594ebc9969654b462443c657 Mon Sep 17 00:00:00 2001 From: Thanaphon Frappet Date: Wed, 5 Mar 2025 16:37:53 +0700 Subject: [PATCH 08/11] feat: set constant variable --- src/pages/14_report/constants.ts | 153 +++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 src/pages/14_report/constants.ts diff --git a/src/pages/14_report/constants.ts b/src/pages/14_report/constants.ts new file mode 100644 index 00000000..fc2b9883 --- /dev/null +++ b/src/pages/14_report/constants.ts @@ -0,0 +1,153 @@ +import { QTableProps } from 'quasar'; +import { Invoice, Receipt } from 'src/stores/payment/types'; +import { + Report, + ReportProduct, + ReportQuotation, +} from 'src/stores/report/types'; +import { formatNumberDecimal } from 'src/stores/utils'; +import { dateFormatJS } from 'src/utils/datetime'; + +export enum ViewMode { + Document = 'document', + Invoice = 'invoice', + Receipt = 'receipt', + Product = 'product', + Sale = 'sale', +} + +type ColumnsSale = { + code: string; + name: string; + _count: number; +}; + +type ColumnsBySale = ColumnsSale & { + url?: string; + id?: string; + gender?: string; +}; + +export const colReportQuotation = [ + { + name: 'code', + align: 'center', + label: 'report.document.code', + field: (data: ReportQuotation) => data.code, + }, + { + name: '#status', + align: 'center', + label: 'report.document.status', + field: '', + }, + { + name: 'createAt', + align: 'center', + label: 'report.document.createAt', + field: (data: ReportQuotation) => dateFormatJS({ date: data.createdAt }), + }, + { + name: 'updateAt', + align: 'center', + label: 'report.document.updateAt', + field: (data: ReportQuotation) => dateFormatJS({ date: data.updatedAt }), + }, +] as const satisfies QTableProps['columns']; + +export const colReport = [ + { + name: 'code', + align: 'center', + label: 'report.table.code', + field: (data: Report) => data.code, + }, + { + name: '#status', + align: 'center', + label: 'report.table.status', + field: '', + }, + { + name: 'createAt', + align: 'center', + label: 'report.table.createAt', + field: (data: Report) => dateFormatJS({ date: data.createdAt }), + }, +] as const satisfies QTableProps['columns']; + +export const colReportProduct = [ + { + name: 'code', + align: 'center', + label: 'report.product.code', + field: (data: ReportProduct) => data.code, + }, + { + name: 'name', + align: 'center', + label: 'report.product.name', + field: (data: ReportProduct) => data.name, + }, + { + name: 'sale', + align: 'center', + label: 'report.product.sale', + field: (data: ReportProduct) => data.sale, + }, + { + name: 'did', + align: 'center', + label: 'report.product.did', + field: (data: ReportProduct) => data.did, + }, +] as const satisfies QTableProps['columns']; + +export const colReportSale = [ + { + name: 'code', + align: 'left', + label: 'report.sale.code', + field: (data: ColumnsSale) => data.code, + }, + { + name: '#name', + align: 'left', + label: 'report.sale.name', + field: '', + }, + { + name: 'count', + align: 'center', + label: 'report.sale.count', + field: (data: ColumnsSale) => data._count, + }, +] as const satisfies QTableProps['columns']; + +export const colReportBySale = [ + { + name: 'code', + align: 'left', + label: 'report.sale.code', + field: (data: ColumnsBySale) => data.code, + }, + { + name: '#name', + align: 'left', + label: 'report.sale.name', + field: '', + }, + { + name: 'count', + align: 'center', + label: 'report.sale.count', + field: (data: ColumnsBySale) => data._count, + }, +] as const satisfies QTableProps['columns']; + +export const pageTabs = [ + { label: 'Document', value: ViewMode.Document, by: ['user'] }, + { label: 'Invoice', value: ViewMode.Invoice, by: ['user'] }, + { label: 'Product', value: ViewMode.Product, by: ['user', 'admin'] }, + { label: 'Sale', value: ViewMode.Sale, by: ['admin'] }, +]; From 7f14e6be46316f726324fd75643b8ea6c2288b19 Mon Sep 17 00:00:00 2001 From: Thanaphon Frappet Date: Wed, 5 Mar 2025 16:39:20 +0700 Subject: [PATCH 09/11] feat: new Table and expansion --- src/components/14_report/Expansion.vue | 29 ++++++++++ src/pages/14_report/Table/TableReport.vue | 64 +++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 src/components/14_report/Expansion.vue create mode 100644 src/pages/14_report/Table/TableReport.vue diff --git a/src/components/14_report/Expansion.vue b/src/components/14_report/Expansion.vue new file mode 100644 index 00000000..581c677b --- /dev/null +++ b/src/components/14_report/Expansion.vue @@ -0,0 +1,29 @@ + + + + + diff --git a/src/pages/14_report/Table/TableReport.vue b/src/pages/14_report/Table/TableReport.vue new file mode 100644 index 00000000..29214126 --- /dev/null +++ b/src/pages/14_report/Table/TableReport.vue @@ -0,0 +1,64 @@ + + From 724f71ae4f2a5ab6fb1f4314a030210e8081b1fa Mon Sep 17 00:00:00 2001 From: Thanaphon Frappet Date: Wed, 5 Mar 2025 16:40:47 +0700 Subject: [PATCH 10/11] refactor: import and bind value --- src/pages/14_report/MainPage.vue | 346 ++++++++++++++++++++++++++++++- 1 file changed, 342 insertions(+), 4 deletions(-) diff --git a/src/pages/14_report/MainPage.vue b/src/pages/14_report/MainPage.vue index 7f3a32b7..b8464197 100644 --- a/src/pages/14_report/MainPage.vue +++ b/src/pages/14_report/MainPage.vue @@ -1,24 +1,362 @@ From 49d860a10816b180fd276a3c7037fec33e3e2b20 Mon Sep 17 00:00:00 2001 From: Thanaphon Frappet Date: Wed, 5 Mar 2025 16:52:36 +0700 Subject: [PATCH 11/11] refactor: handle roles executive --- src/i18n/eng.ts | 5 +---- src/i18n/tha.ts | 5 +---- src/pages/14_report/MainPage.vue | 17 ++++++++--------- src/pages/14_report/constants.ts | 2 +- 4 files changed, 11 insertions(+), 18 deletions(-) diff --git a/src/i18n/eng.ts b/src/i18n/eng.ts index 3b7d494a..51e53bf9 100644 --- a/src/i18n/eng.ts +++ b/src/i18n/eng.ts @@ -1344,10 +1344,7 @@ export default { Document: 'Document Status Report', Invoice: 'Payment Report', Product: 'Product and Service Report', - admin: { - Product: 'Product Movement Report', - Sale: 'Sales Summary Report', - }, + Sale: 'Sales Summary Report', }, document: { code: 'Code', diff --git a/src/i18n/tha.ts b/src/i18n/tha.ts index 8657680f..7d7b561f 100644 --- a/src/i18n/tha.ts +++ b/src/i18n/tha.ts @@ -1322,10 +1322,7 @@ export default { Document: 'รายงานสถานะเอกสาร', Invoice: 'รายงานการชำระเงิน', Product: 'รายงานสินค้าและบริการ', - admin: { - Product: 'รายงานการเคลื่อนไหวของสินค้า', - Sale: 'รายงานสรุปยอดขาย', - }, + Sale: 'รายงานสรุปยอดขาย', }, document: { code: 'รหัส', diff --git a/src/pages/14_report/MainPage.vue b/src/pages/14_report/MainPage.vue index b8464197..9c72fdee 100644 --- a/src/pages/14_report/MainPage.vue +++ b/src/pages/14_report/MainPage.vue @@ -62,24 +62,23 @@ onMounted(async () => { navigatorStore.current.path = [{ text: '' }]; }); -const isAdmin = computed(() => { +const isExecutive = computed(() => { const roles = userRoles.value; - - return roles.includes('head_of_admin') || roles.includes('head_of_account'); + return roles.includes('executive'); }); const filteredTabs = computed(() => { return pageTabs.filter((tab) => { - if (isAdmin.value) { - return !(tab.by.length === 1 && tab.by.includes('user')); - } else { - return !(tab.by.length === 1 && tab.by.includes('admin')); + if (!isExecutive.value) { + return !tab.by.includes('admin'); } + + return true; }); }); const pageState = reactive({ - currentTab: isAdmin.value ? ViewMode.Product : ViewMode.Document, + currentTab: isExecutive.value ? ViewMode.Product : ViewMode.Document, }); async function fetchReportTab() { @@ -152,7 +151,7 @@ watch([() => pageState.currentTab], async () => { : 'app-text-muted' " > - {{ $t(`report.view${isAdmin ? '.admin' : ''}.${tab.label}`) }} + {{ $t(`report.view.${tab.label}`) }} diff --git a/src/pages/14_report/constants.ts b/src/pages/14_report/constants.ts index fc2b9883..dd4af0e7 100644 --- a/src/pages/14_report/constants.ts +++ b/src/pages/14_report/constants.ts @@ -148,6 +148,6 @@ export const colReportBySale = [ export const pageTabs = [ { label: 'Document', value: ViewMode.Document, by: ['user'] }, { label: 'Invoice', value: ViewMode.Invoice, by: ['user'] }, - { label: 'Product', value: ViewMode.Product, by: ['user', 'admin'] }, + { label: 'Product', value: ViewMode.Product, by: ['user'] }, { label: 'Sale', value: ViewMode.Sale, by: ['admin'] }, ];