diff --git a/app/components/Modal.vue b/app/components/Modal.vue index a27b579..74868d5 100644 --- a/app/components/Modal.vue +++ b/app/components/Modal.vue @@ -16,6 +16,7 @@ :style="{ width: $store.viewport <= 1 ? 'calc(100% - 2rem)' : width, height, + // maxHeight: 'calc(100vh - var(--bulma-modal-card-spacing))', }" >
diff --git a/app/components/datatable/ContextMenu.vue b/app/components/datatable/ContextMenu.vue index c9eddff..a37a2e0 100644 --- a/app/components/datatable/ContextMenu.vue +++ b/app/components/datatable/ContextMenu.vue @@ -552,7 +552,6 @@ function tableOption() { vbind: { pagename: props.pagename }, title: "Tùy chọn bảng", width: "50%", - height: "400px", }; } const getFields = function () { diff --git a/app/components/datatable/TableSetting.vue b/app/components/datatable/TableSetting.vue index c3ac55f..87e4e20 100644 --- a/app/components/datatable/TableSetting.vue +++ b/app/components/datatable/TableSetting.vue @@ -237,8 +237,8 @@ input[type="color"]::-webkit-color-swatch { .box { box-shadow: none; - border: 1px solid var(--bulma-grey-85); - background-color: var(--bulma-grey-95); + border: 1px solid var(--bulma-grey-90); + background-color: var(--bulma-grey-100); height: 100%; } diff --git a/app/components/imports/EditProductButton.vue b/app/components/imports/EditProductButton.vue index 8d3a3e8..0472a8b 100644 --- a/app/components/imports/EditProductButton.vue +++ b/app/components/imports/EditProductButton.vue @@ -9,7 +9,6 @@ function displayModal() { showModal.value = { title: "Cập nhật sản phẩm", width: "90%", - height: "400px", component: "imports/EditProduct", vbind: { variant: props.variant }, }; diff --git a/app/components/imports/Products.vue b/app/components/imports/Products.vue index 93f1e56..12e26b7 100644 --- a/app/components/imports/Products.vue +++ b/app/components/imports/Products.vue @@ -18,7 +18,7 @@ import DataView from "~/components/datatable/DataView.vue"; component: 'imports/AddProduct', title: 'Tạo sản phẩm', width: '90%', - height: '450px', + height: '600px', }, }" /> diff --git a/app/components/orders/InvoiceRow.vue b/app/components/orders/InvoiceRow.vue index afa1a82..c21ab1d 100644 --- a/app/components/orders/InvoiceRow.vue +++ b/app/components/orders/InvoiceRow.vue @@ -3,14 +3,25 @@ const props = defineProps({ invoice: Object, }); -const { $dayjs, $shortenCurrency } = useNuxtApp(); +const { $getdata, $dayjs, $shortenCurrency } = useNuxtApp(); +const paymentRecords = ref([]); +onMounted(async () => { + paymentRecords.value = await $getdata("Payment_Record", { + filter: { invoice: props.invoice.id }, + }); +}); + +/* + + */ +/* invoice.total_amount */ const showModal = ref(); function openModal() { showModal.value = { component: "orders/SelectedOrder", title: "Chi tiết đơn hàng", - width: "75%", + width: "min(700px, 75%)", vbind: { invoice: props.invoice, }, diff --git a/app/components/orders/OrderDeliveryTab.vue b/app/components/orders/OrderDeliveryTab.vue index 62eddf6..74c732b 100644 --- a/app/components/orders/OrderDeliveryTab.vue +++ b/app/components/orders/OrderDeliveryTab.vue @@ -16,7 +16,7 @@ const props = defineProps({

{{ invoice.delivery__tracking_code }}

-

+

{{ capitalize(invoice.delivery__status) }}

diff --git a/app/components/orders/OrderPaymentTab.vue b/app/components/orders/OrderPaymentTab.vue index 9229f7b..556d85d 100644 --- a/app/components/orders/OrderPaymentTab.vue +++ b/app/components/orders/OrderPaymentTab.vue @@ -8,15 +8,15 @@ const { $formatNum } = useNuxtApp(); diff --git a/app/components/orders/OrdersTable.vue b/app/components/orders/OrdersTable.vue index 8317b5c..2485aa0 100644 --- a/app/components/orders/OrdersTable.vue +++ b/app/components/orders/OrdersTable.vue @@ -7,7 +7,7 @@ const props = defineProps({ viewMode: String, }); -const { $dayjs } = useNuxtApp(); +const { $getdata, $dayjs } = useNuxtApp(); const { invoices } = inject("orders"); const statuses = [ @@ -51,16 +51,11 @@ const paymentStatuses = [ }, ]; -const employees = [ - { - id: 1, - name: "Trần Thị B", - }, - { - id: 5, - name: "Hoàng Văn E", - }, -]; +const employees = ref([]); + +onMounted(async () => { + employees.value = await $getdata("Staff"); +}); const input = ref(); const dateRange = ref({ @@ -99,7 +94,7 @@ const filteredInvoices = computed(() => { const filteredByDates = filteredByEmployees.filter((order) => { if (!dateRange.value) return true; const from = $dayjs(dateRange.value.from || 0); - const to = $dayjs(dateRange.value.to || undefined); + const to = $dayjs(dateRange.value.to || undefined).endOf("day"); const createTime = $dayjs(order.create_time); return createTime.isSameOrAfter(from) && createTime.isSameOrBefore(to); }); @@ -123,10 +118,7 @@ function toggleStatus(id) { diff --git a/app/components/pos/EditAddress.vue b/app/components/pos/AddressForm.vue similarity index 86% rename from app/components/pos/EditAddress.vue rename to app/components/pos/AddressForm.vue index b35f369..5a51a07 100644 --- a/app/components/pos/EditAddress.vue +++ b/app/components/pos/AddressForm.vue @@ -7,25 +7,22 @@ const props = defineProps({ const emit = defineEmits(["modalevent"]); -const { $patchapi } = useNuxtApp(); +const { $insertapi, $patchapi } = useNuxtApp(); const addressRef = ref({ ...props.address }); const isLoading = ref(false); -async function updateAddress() { + +async function submitAddress() { isLoading.value = true; - const updated = await $patchapi("Customer_Address", addressRef.value); + const res = props.address + ? await $patchapi("Customer_Address", addressRef.value) + : await $insertapi("Customer_Address", addressRef.value); isLoading.value = false; - emit("modalevent", { name: "update" }); + emit("modalevent", { name: "submit" }); } const isDirty = computed(() => { - if (props.address) { - // edit - return !isEqual(props.address, addressRef); - } else { - return true; - // create - // true if - } + if (props.address) return !isEqual(props.address, addressRef.value); + return true; }); const isValid = computed(() => { if (!addressRef.value.city) return false; @@ -112,9 +109,6 @@ const isValid = computed(() => { -
address: {{ address }}
-
addressRef: {{ addressRef }}
-
isDirty: {{ isDirty.toString() }}
+
-
+
{ return result; }; - const numberToVietnameseCurrency = (amount) => { - if (amount === null || amount === undefined || amount === "") return ""; - - amount = Number(amount); - if (isNaN(amount)) return ""; - - const units = ["", "một", "hai", "ba", "bốn", "năm", "sáu", "bảy", "tám", "chín"]; - const scales = ["", "nghìn", "triệu", "tỷ"]; - - function readThreeDigits(num) { - let result = ""; - const hundred = Math.floor(num / 100); - const ten = Math.floor((num % 100) / 10); - const unit = num % 10; - - if (hundred > 0) { - result += units[hundred] + " trăm"; - if (ten === 0 && unit > 0) result += " lẻ"; - } - - if (ten > 1) { - result += " " + units[ten] + " mươi"; - if (unit === 1) result += " mốt"; - else if (unit === 5) result += " lăm"; - else if (unit > 0) result += " " + units[unit]; - } else if (ten === 1) { - result += " mười"; - if (unit === 5) result += " lăm"; - else if (unit > 0) result += " " + units[unit]; - } else if (ten === 0 && unit > 0 && hundred === 0) { - result += units[unit]; - } - - return result.trim(); - } - - let text = ""; - let scaleIndex = 0; - - while (amount > 0) { - const chunk = amount % 1000; - if (chunk > 0) { - text = `${readThreeDigits(chunk)} ${scales[scaleIndex]} ${text}`; - } - amount = Math.floor(amount / 1000); - scaleIndex++; - } - - text = text.trim(); - text = text.charAt(0).toUpperCase() + text.slice(1); - - return text; - }; - - const getFirstAndLastName = (fullName, showDots) => { - if (!fullName) return ""; - - var parts = fullName.trim().replace(/\s+/g, " ").split(" "); - - if (parts.length === 1) return parts[0]; - - var first = parts[0]; - var last = parts[parts.length - 1]; - - return showDots ? first + "..." + last : first + " " + last; - }; - - const paymentQR = (content = "", bankCode = "MB", amount = 0) => { - const listBanks = [ - { - bank: { - code: "MB", - name: "MB Bank", - }, - account: { - number: "146768686868", - name: "CONG TY CO PHAN BAT DONG SAN UTOPIA", - }, - content: "Thanh toán hóa đơn", - }, - ]; - - let bankInfo = listBanks.find( - (item) => item.bank.code && bankCode && item.bank.code.toLowerCase() === bankCode.toLowerCase(), - ); - - if (!bankInfo) return; - - const params = new URLSearchParams({ - addInfo: content || bankInfo.content, - accountName: bankInfo.account.name || "", - amount: amount || 0, - }); - return `https://img.vietqr.io/image/${bankInfo.bank.code}-${bankInfo.account.number}-print.png?${params.toString()}`; - }; - function shortenCurrency(amount) { return new Intl.NumberFormat("en", { notation: "compact" }).format(Number(amount)); } @@ -654,10 +558,7 @@ export default defineNuxtPlugin((nuxtApp) => { lang, formatFileSize, numberToVietnamese, - numberToVietnameseCurrency, formatDateVN, - getFirstAndLastName, - paymentQR, shortenCurrency, }, }; diff --git a/app/plugins/04-components.js b/app/plugins/04-components.js index d74ab8d..d805fa7 100644 --- a/app/plugins/04-components.js +++ b/app/plugins/04-components.js @@ -36,7 +36,7 @@ import Inventory from "~/components/inventory/Inventory.vue"; import Rights from "~/components/rights/Rights.vue"; import POS from "~/components/pos/POS.vue"; import ChooseIMEIButton from "~/components/pos/ChooseIMEIButton.vue"; -import EditAddress from "~/components/pos/EditAddress.vue"; +import AddressForm from "~/components/pos/AddressForm.vue"; import CreateReceipts from "~/components/receipts/CreateReceipts.vue"; import Return from "~/components/receipts/Return.vue"; import Imports from "~/components/imports/Imports.vue"; @@ -111,7 +111,7 @@ const components = { Rights, POS, ChooseIMEIButton, - EditAddress, + AddressForm, CreateReceipts, Return, Imports, diff --git a/app/utils/apis.js b/app/utils/apis.js index 9b101b3..13c2ed6 100644 --- a/app/utils/apis.js +++ b/app/utils/apis.js @@ -497,7 +497,7 @@ export default /** @type {const} */ ([ url_detail: "data-detail/Invoice_Detail/", params: { values: - "id,code,invoice,variant,variant__code,variant__product,variant__product__name,variant__color,variant__price,variant__image__code,imei_sold,price,status,note,deleted,create_time,update_time", + "id,code,invoice,variant,variant__code,variant__product,variant__product__name,variant__color,variant__color__name,variant__ram__code,variant__ram__capacity,variant__internal_storage__code,variant__internal_storage__capacity,variant__price,variant__image__code,imei_sold,price,status,note,deleted,create_time,update_time", }, }, { @@ -648,6 +648,12 @@ export default /** @type {const} */ ([ url_detail: "data-detail/Payment_Method/", params: {}, }, + { + name: "Payment_Record", + url: "data/Payment_Record/", + url_detail: "data-detail/Payment_Record/", + params: {}, + }, { name: "Customer_Address", url: "data/Customer_Address/", @@ -685,6 +691,12 @@ export default /** @type {const} */ ([ "id,code,cart,imei,quantity,status,total_price,deleted,create_time,update_time,imei__code,imei__imei,imei__variant,imei__variant,imei__variant__code,imei__variant__product,imei__variant__product__code,imei__variant__product__name,imei__variant__product__manufacturer,imei__variant__product__os,imei__variant__product__battery,imei__variant__product__screen,imei__variant__product__cpu,imei__variant__product__gpu,imei__variant__product__camera_system,imei__variant__product__sim,imei__variant__product__network_technology,imei__variant__product__charging_technology,imei__variant__product__external_storage,imei__variant__product__ip_rating,imei__variant__product__design,imei__variant__product__creator,imei__variant__product__updater,imei__variant__product__deleted,imei__variant__color,imei__variant__color__code,imei__variant__color__name,imei__variant__color__hex_code,imei__variant__color__deleted,imei__variant__ram,imei__variant__ram__code,imei__variant__ram__capacity,imei__variant__ram__deleted,imei__variant__internal_storage,imei__variant__internal_storage__code,imei__variant__internal_storage__capacity,imei__variant__internal_storage__deleted,imei__variant__image,imei__variant__image__code,imei__variant__image__name,imei__variant__image__path,imei__variant__image__is_active,imei__variant__image__deleted,imei__variant__image__create_time,imei__variant__price,imei__variant__note,imei__variant__creator,imei__variant__updater,imei__variant__deleted,imei__variant__create_time,imei__variant__update_time,imei__deleted,imei__create_time,imei__update_time", }, }, + { + name: "Staff", + url: "data/Staff/", + url_detail: "data-detail/Staff/", + params: {}, + }, ]); /** diff --git a/nuxt.config.ts b/nuxt.config.ts index 9a27914..8e884a2 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -11,9 +11,12 @@ export default defineNuxtConfig({ script: [{ src: "/js/html2pdf.bundle.min.js" }, { src: "/js/html2canvas.min.js" }], htmlAttrs: { lang: "vi", - class: "theme-light has-background-blue-100 min-h-dvh", + class: "theme-light has-background-blue-100", }, }, + rootAttrs: { + class: 'min-h-dvh is-flex is-flex-direction-column' + } }, modules: ["@pinia/nuxt", "pinia-plugin-persistedstate/nuxt", "@nuxt/image", "nuxt-qrcode", "@nuxt/icon"], compatibilityDate: "2026-06-01",