This commit is contained in:
Viet An
2026-06-18 08:41:33 +07:00
parent a8aa9a3dce
commit b7c82e944d
17 changed files with 531 additions and 775 deletions

View File

@@ -0,0 +1,118 @@
<script setup>
const props = defineProps({
invoice: Object,
});
const { $dayjs, $shortenCurrency } = useNuxtApp();
const showModal = ref();
function openModal() {
showModal.value = {
component: "orders/SelectedOrder",
title: "Chi tiết đơn hàng",
width: "75%",
height: "500px",
vbind: {
invoice: props.invoice,
},
};
}
</script>
<template>
<tr
class="is-clickable"
@click="openModal"
>
<td>
<div>
<p class="fs-15 font-semibold">{{ invoice.code }}</p>
<p class="has-text-grey">{{ invoice.staff__fullname }}</p>
</div>
</td>
<td>
<div>
<p>{{ invoice.customer_name }}</p>
<div class="is-flex is-gap-0.5 is-align-items-center mt-1 has-text-grey">
<Icon
name="material-symbols:call-outline-rounded"
:size="15"
/>
<span class="fs-12">{{ invoice.customer_phone }}</span>
</div>
</div>
</td>
<td class="has-text-right">
<div>
<p class="fs-14 font-semibold">{{ $shortenCurrency(invoice.total_amount) }}</p>
<p class="has-text-grey">{{ invoice.product_amount }} SP</p>
</div>
</td>
<td class="has-text-centered">
<span
:class="['tag rounded-full', `has-background-${invoice.status__color}-80 has-text-${invoice.status__color}-25`]"
>
{{ invoice.status }}
</span>
</td>
<td>
<p :class="`has-text-${invoice.payment_status__color}-40`">
{{ invoice.payment_status__name }}
</p>
</td>
<td>
<p :class="`has-text-${invoice.delivery_status__color}-40`">
{{ invoice.delivery__status }}
</p>
</td>
<td>
<div>
<div class="is-flex is-gap-0.5">
<Icon
:size="18"
name="material-symbols:calendar-today-outline-rounded"
/>
<span>{{ $dayjs(invoice.create_time).format("L") }}</span>
</div>
<p class="has-text-grey fs-12">
{{ $dayjs(invoice.create_time).format("HH:mm") }}
</p>
</div>
</td>
<td>
<button
v-if="invoice.status__name !== 'Hoàn thành'"
:class="[
'button fs-12 has-text-white rounded-lg',
invoice.status__name === 'Nháp'
? 'is-primary'
: invoice.status__name === 'Đã xác nhận'
? 'is-orange'
: 'is-success',
]"
>
{{
invoice.status__name === "Nháp"
? "Xác nhận"
: invoice.status__name === "Đã xác nhận"
? "Giao hàng"
: "Hoàn thành"
}}
</button>
</td>
<Modal
v-if="showModal"
v-bind="showModal"
@close="showModal = null"
/>
</tr>
</template>
<style scoped>
tr.is-selected {
--bulma-table-row-active-background-color: var(--bulma-primary-95);
color: unset;
}
td {
vertical-align: middle;
--bulma-table-cell-padding: 0.75em;
}
</style>

View File

@@ -1,6 +1,6 @@
<script setup>
const props = defineProps({
order: Object,
invoice: Object,
});
</script>
@@ -9,13 +9,13 @@ const props = defineProps({
<div class="p-4 rounded-md has-background-primary-95">
<p class="has-text-grey">Trạng thái</p>
<p class="fs-17 mt-1 font-semibold has-text-primary-50">
{{ order.delivery_status__name }}
{{ invoice.delivery_status__name }}
</p>
</div>
<div class="p-4 rounded-md has-background-white-bis">
<p class="has-text-grey">Địa chỉ giao hàng</p>
<p class="mt-1 has-text-grey-darker">{{ order.customer__name }}</p>
<p class="has-text-grey-darker">{{ order.customer__phone }}</p>
<p class="mt-1 has-text-grey-darker">{{ invoice.customer__name }}</p>
<p class="has-text-grey-darker">{{ invoice.customer__phone }}</p>
</div>
</div>
</template>

View File

@@ -1,6 +1,6 @@
<script setup>
const props = defineProps({
order: Object,
invoice: Object,
});
const { $dayjs } = useNuxtApp();

View File

@@ -5,6 +5,19 @@ const props = defineProps({
const { $dayjs, $shortenCurrency } = useNuxtApp();
const emit = defineEmits(["selectOrder", "unselect"]);
const showModal = ref();
function openModal() {
showModal.value = {
component: "orders/SelectedOrder",
title: "SelectedOrder",
width: "75%",
height: "500px",
vbind: {
order: props.order,
},
};
}
</script>
<template>
@@ -72,5 +85,10 @@ const emit = defineEmits(["selectOrder", "unselect"]);
</button>
</div>
</div>
<Modal
v-if="showModal"
v-bind="showModal"
@close="showModal = null"
/>
</div>
</template>

View File

@@ -1,6 +1,6 @@
<script setup>
const props = defineProps({
order: Object,
invoice: Object,
});
const { $numtoString } = useNuxtApp();
</script>
@@ -11,7 +11,7 @@ const { $numtoString } = useNuxtApp();
<div class="is-flex-grow-1 p-3 rounded-md has-background-white-bis">
<p class="fs-13 has-text-grey">Tổng tiền</p>
<p class="font-bold">
{{ $numtoString(order.total, { hasUnit: true }) }}
{{ $numtoString(invoice.total, { hasUnit: true }) }}
</p>
</div>
<div class="is-flex-grow-1 p-3 rounded-md has-background-success-95">
@@ -22,7 +22,7 @@ const { $numtoString } = useNuxtApp();
<div class="p-4 mt-4 rounded-md has-background-danger-95">
<p class="fs-13 has-text-danger-50">Còn lại</p>
<p class="fs-20 font-bold has-text-danger-40">
{{ $numtoString(order.total, { hasUnit: true }) }}
{{ $numtoString(invoice.total, { hasUnit: true }) }}
</p>
</div>
</div>

View File

@@ -1,39 +1,66 @@
<script setup>
const props = defineProps({
order: Object,
invoice: Object,
});
const { $numtoString } = useNuxtApp();
const { $getdata, $numtoString } = useNuxtApp();
const invoiceDetails = ref([]);
onMounted(async () => {
invoiceDetails.value = await $getdata("Invoice_Detail", { filter: { invoice: props.invoice.id } });
});
</script>
<template>
<div>
<pre class="fs-12 max-h-40 mb-2">{{ invoiceDetails }}</pre>
<div class="is-flex is-flex-direction-column is-gap-2">
<div
v-for="product in order.order__products"
:key="product.id"
v-for="invoiceDetail in invoiceDetails"
:key="invoiceDetail.id"
class="p-3 has-background-white-ter rounded-md"
>
<div class="fs-15 is-flex is-justify-content-space-between">
<p class="">{{ product.name }}</p>
<p class="font-bold">
{{ $numtoString(product.total, { hasUnit: true }) }}
<p>{{ invoiceDetail.variant__product__name }}</p>
<p class="font-semibold">
{{ $numtoString(invoiceDetail.price, { hasUnit: true }) }}
</p>
</div>
<div class="is-flex is-gap-8 fs-13 has-text-grey-dark mt-1">
<p>SL: {{ product.quantity }}</p>
<p>Đơn giá: {{ $numtoString(product.unit_price, { hasUnit: true }) }}</p>
<p>SL: {{ invoiceDetail.quantity }}</p>
<p>Đơn giá: {{ $numtoString(invoiceDetail.price, { hasUnit: true }) }}</p>
<p>
Giảm:
{{ new Intl.NumberFormat("vi-VN", { style: "percent" }).format(product.discount) }}
{{ new Intl.NumberFormat("vi-VN", { style: "percent" }).format(invoiceDetail.discount) }}
</p>
</div>
</div>
</div>
<hr />
<div class="font-bold is-flex is-gap-2 is-justify-content-space-between is-align-items-center">
<p class="fs-15">Tổng cộng</p>
<p class="fs-18">{{ $numtoString(order.total, { hasUnit: true }) }}</p>
</div>
<table class="table is-fullwidth is-bordered fs-14 mb-8">
<tbody class="has-text-right">
<tr>
<td class="has-text-grey-dark">Tổng tiền hàng</td>
<td>{{ $numtoString(invoice.total_amount, { hasUnit: true }) }}</td>
</tr>
<tr>
<td class="has-text-grey-dark">Phí vận chuyển</td>
<td>{{ $numtoString(invoice.shipping_fee, { hasUnit: true }) }}</td>
</tr>
<tr>
<td class="has-text-grey-dark">Giảm giá</td>
<td>{{ $numtoString(invoice.discount_amount, { hasUnit: true }) }}</td>
</tr>
<tr class="font-bold">
<td>Tổng cộng</td>
<td class="fs-17">{{ $numtoString(invoice.final_amount, { hasUnit: true }) }}</td>
</tr>
</tbody>
</table>
</div>
</template>
<style scoped>
table td {
vertical-align: middle;
}
</style>

View File

@@ -1,6 +1,6 @@
<script setup>
const props = defineProps({
order: Object,
invoice: Object,
});
</script>

View File

@@ -1,98 +0,0 @@
<script setup>
const props = defineProps({
order: Object,
selected: Boolean,
});
const { $dayjs, $shortenCurrency } = useNuxtApp();
const emit = defineEmits(["selectOrder", "unselect"]);
</script>
<template>
<tr
:class="['is-clickable', selected && 'is-selected']"
@click="selected ? emit('unselect') : emit('selectOrder', order.id)"
>
<td>
<div>
<p class="fs-15 font-semibold">{{ order.code }}</p>
<p class="has-text-grey">{{ order.employee__name }}</p>
</div>
</td>
<td>
<div>
<p>{{ order.customer__name }}</p>
<div class="is-flex is-gap-0.5 is-align-items-center mt-1 has-text-grey">
<Icon
name="material-symbols:call-outline-rounded"
:size="15"
/>
<span class="fs-12">{{ order.customer__phone }}</span>
</div>
</div>
</td>
<td class="has-text-right">
<div>
<p class="fs-14 font-semibold">{{ $shortenCurrency(order.total) }}</p>
<p class="has-text-grey">{{ order.order__products.length }} SP</p>
</div>
</td>
<td class="has-text-centered">
<span
:class="['tag rounded-full', `has-background-${order.status__color}-80 has-text-${order.status__color}-25`]"
>
{{ order.status__name }}
</span>
</td>
<td>
<p :class="`has-text-${order.payment_status__color}-40`">
{{ order.payment_status__name }}
</p>
</td>
<td>
<p :class="`has-text-${order.delivery_status__color}-40`">
{{ order.delivery_status__name }}
</p>
</td>
<td>
<div>
<div class="is-flex is-gap-0.5">
<Icon
:size="18"
name="material-symbols:calendar-today-outline-rounded"
/>
<span>{{ $dayjs(order.create_time).format("L") }}</span>
</div>
<p class="has-text-grey fs-12">
{{ $dayjs(order.create_time).format("HH:mm") }}
</p>
</div>
</td>
<td>
<button
v-if="order.status__name !== 'Hoàn thành'"
:class="[
'button fs-12 has-text-white rounded-lg',
order.status__name === 'Nháp'
? 'is-primary'
: order.status__name === 'Đã xác nhận'
? 'is-orange'
: 'is-success',
]"
>
{{
order.status__name === "Nháp" ? "Xác nhận" : order.status__name === "Đã xác nhận" ? "Giao hàng" : "Hoàn thành"
}}
</button>
</td>
</tr>
</template>
<style scoped>
tr.is-selected {
--bulma-table-row-active-background-color: var(--bulma-primary-95);
color: unset;
}
td {
vertical-align: middle;
--bulma-table-cell-padding: 0.75em;
}
</style>

View File

@@ -3,7 +3,7 @@ import OrderHighlightCard from "~/components/orders/OrderHighlightCard.vue";
import OrderPipeline from "~/components/orders/OrderPipeline.vue";
import OrdersTable from "~/components/orders/OrdersTable.vue";
const { $store } = useNuxtApp();
const { $getdata, $store } = useNuxtApp();
const highlights = [
{
name: "Nháp",
@@ -43,6 +43,14 @@ const viewModes = [
{ name: "grid", icon: "material-symbols:grid-view-outline-rounded" },
];
const viewMode = ref("list");
const invoices = ref();
onMounted(async () => {
invoices.value = await $getdata("Invoice");
});
provide("orders", {
invoices,
});
</script>
<template>
<div>
@@ -82,7 +90,7 @@ const viewMode = ref("list");
</button>
</div>
</Teleport>
<div class="fixed-grid has-2-cols-mobile has-5-cols">
<!-- <div class="fixed-grid has-2-cols-mobile has-5-cols">
<div class="grid">
<OrderHighlightCard
v-for="highlight in highlights"
@@ -91,7 +99,7 @@ const viewMode = ref("list");
/>
</div>
</div>
<OrderPipeline />
<OrderPipeline /> -->
<OrdersTable :viewMode="viewMode" />
</div>
</template>

View File

@@ -1,376 +1,14 @@
<script setup>
import OrderRow from "~/components/orders/OrderRow.vue";
import SelectedOrder from "~/components/orders/SelectedOrder.vue";
import { pull } from "es-toolkit";
import InvoiceRow from "~/components/orders/InvoiceRow.vue";
import OrdersKanban from "~/components/orders/OrdersKanban.vue";
const props = defineProps({
viewMode: String,
});
const { $dayjs } = useNuxtApp();
const orders = [
{
id: 1,
code: "SO001",
employee: 1,
employee__name: "Trần Thị B",
customer: 1,
customer__name: "Nguyễn Văn A",
customer__phone: "0901234567",
total: "5200000.00",
status: 1,
status__name: "Nháp",
status__color: "yellow",
payment_status: 1,
payment_status__name: "Chưa thanh toán",
payment_status__color: "red",
delivery_status: 1,
delivery_status__name: "Chờ xử lý",
delivery_status__color: "grey",
order__products: [
{
id: 1,
name: "Kem chống nắng SPF 50+",
unit_price: "280000.00",
quantity: 10,
discount: null,
total: "2800000.00",
},
{
id: 2,
name: "Serum Vitamin C 30ml",
unit_price: "450000.00",
quantity: 5,
discount: 0.1,
total: "2025000.00",
},
{
id: 3,
name: "Son dưỡng môi vitamin E",
unit_price: "75000.00",
quantity: 5,
discount: null,
total: "375000.00",
},
],
create_time: "2026-02-11T08:51:04.587660+07:00",
},
{
id: 2,
code: "SO002",
employee: 1,
employee__name: "Trần Thị B",
customer: 3,
customer__name: "Lê Thị C",
customer__phone: "0912345678",
total: "8500000.00",
status: 2,
status__name: "Đã xác nhận",
status__color: "blue",
payment_status: 2,
payment_status__name: "Một phần",
payment_status__color: "yellow",
delivery_status: 2,
delivery_status__name: "Sẵn sàng",
delivery_status__color: "blue",
order__products: [
{
id: 3,
name: "Mặt nạ collagen 10 miếng",
unit_price: "320000.00",
quantity: 15,
discount: 0.05,
total: "4560000.00",
},
{
id: 4,
name: "Toner cân bằng da 200ml",
unit_price: "180000.00",
quantity: 20,
discount: 0.1,
total: "3240000.00",
},
{
id: 5,
name: "Gel rửa mặt làm sạch sâu",
unit_price: "140000.00",
quantity: 5,
discount: null,
total: "700000.00",
},
],
create_time: "2026-04-06T09:10:09.587660+07:00",
},
{
id: 3,
code: "SO003",
employee: 5,
employee__name: "Hoàng Văn E",
customer: 4,
customer__name: "Phạm Văn D",
customer__phone: "0923456703",
total: "12300000.00",
status: 3,
status__name: "Đang giao",
status__color: "orange",
payment_status: 3,
payment_status__name: "Đã thanh toán",
payment_status__color: "green",
delivery_status: 3,
delivery_status__name: "Hoàn thành",
delivery_status__color: "green",
order__products: [
{
id: 6,
name: "Kem dưỡng ẩm ban đêm",
unit_price: "380000.00",
quantity: 20,
discount: 0.05,
total: "7220000.00",
},
{
id: 7,
name: "Phấn nền BB cream",
unit_price: "220000.00",
quantity: 15,
discount: null,
total: "3300000.00",
},
{
id: 8,
name: "Nước tẩy trang 3 trong 1",
unit_price: "195000.00",
quantity: 10,
discount: 0.1,
total: "1755000.00",
},
],
create_time: "2026-04-05T02:33:24.587660+07:00",
},
{
id: 4,
code: "SO004",
employee: 1,
employee__name: "Trần Thị B",
customer: 6,
customer__name: "Vũ Thị F",
customer__phone: "0934835222",
total: "6800000.00",
status: 4,
status__name: "Hoàn thành",
status__color: "green",
payment_status: 3,
payment_status__name: "Đã thanh toán",
payment_status__color: "green",
delivery_status: 3,
delivery_status__name: "Hoàn thành",
delivery_status__color: "green",
order__products: [
{
id: 9,
name: "Dầu gội thảo mộc 500ml",
unit_price: "120000.00",
quantity: 30,
discount: 0.1,
total: "3240000.00",
},
{
id: 10,
name: "Sữa rửa mặt trà xanh 150ml",
unit_price: "150000.00",
quantity: 20,
discount: 0.05,
total: "2850000.00",
},
{
id: 11,
name: "Son dưỡng môi vitamin E",
unit_price: "75000.00",
quantity: 10,
discount: 0.05,
total: "712500.00",
},
],
create_time: "2026-04-04T23:21:11.587660+07:00",
},
{
id: 5,
code: "SO005",
employee: 5,
employee__name: "Hoàng Văn E",
customer: 7,
customer__name: "Đỗ Văn G",
customer__phone: "0945781113",
total: "9400000.00",
status: 2,
status__name: "Đã xác nhận",
status__color: "blue",
payment_status: 1,
payment_status__name: "Chưa thanh toán",
payment_status__color: "red",
delivery_status: 1,
delivery_status__name: "Chờ xử lý",
delivery_status__color: "grey",
order__products: [
{
id: 12,
name: "Kem mắt chống lão hóa",
unit_price: "550000.00",
quantity: 10,
discount: null,
total: "5500000.00",
},
{
id: 13,
name: "Serum Vitamin C 30ml",
unit_price: "450000.00",
quantity: 8,
discount: 0.05,
total: "3420000.00",
},
{
id: 14,
name: "Gel rửa mặt làm sạch sâu",
unit_price: "140000.00",
quantity: 5,
discount: 0.15,
total: "595000.00",
},
],
create_time: "2026-04-07T11:21:46.587660+07:00",
},
{
id: 6,
code: "SO006",
employee: 1,
employee__name: "Trần Thị B",
customer: 8,
customer__name: "Bùi Thị H",
customer__phone: "0933184392",
total: "4200000.00",
status: 1,
status__name: "Nháp",
status__color: "yellow",
payment_status: 1,
payment_status__name: "Chưa thanh toán",
payment_status__color: "red",
delivery_status: 1,
delivery_status__name: "Chờ xử lý",
delivery_status__color: "grey",
order__products: [
{
id: 15,
name: "Toner cân bằng da 200ml",
unit_price: "180000.00",
quantity: 15,
discount: null,
total: "2700000.00",
},
{
id: 16,
name: "Mặt nạ collagen 10 miếng",
unit_price: "320000.00",
quantity: 5,
discount: 0.05,
total: "1520000.00",
},
],
create_time: "2026-04-07T13:17:36.587660+07:00",
},
{
id: 7,
code: "SO007",
employee: 5,
employee__name: "Hoàng Văn E",
customer: 9,
customer__name: "Ngô Văn I",
customer__phone: "0978335172",
total: "15600000.00",
status: 3,
status__name: "Đang giao",
status__color: "orange",
payment_status: 3,
payment_status__name: "Đã thanh toán",
payment_status__color: "green",
delivery_status: 2,
delivery_status__name: "Hoàn thành",
delivery_status__color: "green",
order__products: [
{
id: 17,
name: "Kem chống nắng SPF 50+",
unit_price: "280000.00",
quantity: 30,
discount: 0.1,
total: "7560000.00",
},
{
id: 18,
name: "Phấn nền BB cream",
unit_price: "220000.00",
quantity: 25,
discount: 0.05,
total: "5225000.00",
},
{
id: 19,
name: "Kem dưỡng ẩm ban đêm",
unit_price: "380000.00",
quantity: 8,
discount: 0.05,
total: "2880000.00",
},
],
create_time: "2026-06-04T09:30:12.587660+07:00",
},
{
id: 8,
code: "SO008",
employee: 1,
employee__name: "Trần Thị B",
customer: 11,
customer__name: "Đinh Thị K",
customer__phone: "0922104853",
total: "7900000.00",
status: 2,
status__name: "Đã xác nhận",
status__color: "blue",
payment_status: 2,
payment_status__name: "Một phần",
payment_status__color: "yellow",
delivery_status: 2,
delivery_status__name: "Sẵn sàng",
delivery_status__color: "blue",
order__products: [
{
id: 20,
name: "Nước tẩy trang 3 trong 1",
unit_price: "195000.00",
quantity: 20,
discount: 0.05,
total: "3705000.00",
},
{
id: 21,
name: "Sữa rửa mặt trà xanh 150ml",
unit_price: "150000.00",
quantity: 18,
discount: null,
total: "2700000.00",
},
{
id: 22,
name: "Dầu gội thảo mộc 500ml",
unit_price: "120000.00",
quantity: 13,
discount: 0.05,
total: "1482000.00",
},
],
create_time: "2026-04-06T16:01:22.587660+07:00",
},
];
const { invoices } = inject("orders");
const statuses = [
{
@@ -434,8 +72,9 @@ const selectedStatuses = ref([]);
const selectedPaymentStatus = ref();
const selectedEmployee = ref();
const filteredOrders = computed(() => {
const filteredByInput = orders.filter((order) => {
const filteredInvoices = computed(() => {
if (!invoices.value) return [];
const filteredByInput = invoices.value.filter((order) => {
if (!input.value) return true;
const values = Object.values(order);
const strValues = values.filter((v) => typeof v === "string");
@@ -470,7 +109,7 @@ const filteredOrders = computed(() => {
const selectedOrder = ref(null);
watch(filteredOrders, () => {
watch(filteredInvoices, () => {
selectedOrder.value = null;
});
@@ -484,7 +123,10 @@ function toggleStatus(id) {
</script>
<template>
<div>
<div class="card">
<div
v-if="true"
class="card"
>
<div class="card-content">
<div class="is-flex is-gap-2 is-align-items-center">
<div class="field is-flex-grow-1 m-0">
@@ -569,69 +211,45 @@ function toggleStatus(id) {
</div>
</div>
</div>
<div class="fixed-grid has-3-cols">
<div class="grid">
<div :class="['cell', selectedOrder ? 'is-col-span-2' : 'is-col-span-3']">
<div class="card is-clipped">
<div class="card-content p-0">
<template v-if="viewMode === 'list'">
<p class="p-5 icon-text fs-16 font-semibold w-full">
<span class="icon">
<Icon
name="material-symbols:list-alt-outline-rounded"
:size="22"
/>
</span>
<span>Danh sách đơn hàng ({{ filteredOrders.length }})</span>
</p>
<table class="table is-fullwidth is-hoverable fs-13">
<thead>
<tr>
<th class="font-semibold">Đơn hàng</th>
<th class="font-semibold">Khách hàng</th>
<th class="font-semibold has-text-right">Tng tiền</th>
<th class="font-semibold has-text-centered">Trạng thái</th>
<th class="font-semibold">Thanh toán</th>
<th class="font-semibold">Giao hàng</th>
<th class="font-semibold">Ngày tạo</th>
<th class="font-semibold">Thao tác</th>
</tr>
</thead>
<tbody>
<OrderRow
v-for="order in filteredOrders"
:key="order.id"
v-bind="{
order,
selected: order.id === selectedOrder?.id,
}"
@selectOrder="
(id) => {
selectedOrder = filteredOrders.find((order) => order.id === id);
}
"
@unselect="selectedOrder = null"
/>
</tbody>
</table>
</template>
<OrdersKanban
v-else
:orders="filteredOrders"
:statuses="statuses"
@selectOrder="
(id) => {
selectedOrder = filteredOrders.find((order) => order.id === id);
}
"
@unselect="selectedOrder = null"
/>
</div>
</div>
</div>
<SelectedOrder
:order="selectedOrder"
@unselect="selectedOrder = null"
<div class="card is-clipped">
<div class="card-content p-0">
<p class="p-5 icon-text fs-16 font-semibold w-full">
<span class="icon">
<Icon
name="material-symbols:list-alt-outline-rounded"
:size="22"
/>
</span>
<span>Danh sách đơn hàng ({{ filteredInvoices.length }})</span>
</p>
<table
v-if="viewMode === 'list'"
class="table is-fullwidth is-hoverable fs-13"
>
<thead>
<tr>
<th class="font-semibold">Đơn hàng</th>
<th class="font-semibold">Khách hàng</th>
<th class="font-semibold has-text-right">Tổng tiền</th>
<th class="font-semibold has-text-centered">Trạng thái</th>
<th class="font-semibold">Thanh toán</th>
<th class="font-semibold">Giao hàng</th>
<th class="font-semibold">Ngày tạo</th>
<th class="font-semibold">Thao tác</th>
</tr>
</thead>
<tbody>
<InvoiceRow
v-for="invoice in filteredInvoices"
:key="invoice.id"
:invoice="invoice"
/>
</tbody>
</table>
<OrdersKanban
v-else
:orders="filteredInvoices"
:statuses="statuses"
/>
</div>
</div>

View File

@@ -6,7 +6,7 @@ import OrderProductTab from "~/components/orders/OrderProductTab.vue";
import OrderReceiptTab from "~/components/orders/OrderReceiptTab.vue";
const props = defineProps({
order: Object,
invoice: Object,
});
const { $dayjs, $numtoString } = useNuxtApp();
@@ -44,131 +44,112 @@ const activeTab = ref(tabs[0]);
</script>
<template>
<div
v-if="order"
class="cell relative fs-14"
>
<div class="card">
<button
@click="emit('unselect')"
class="button is-white rounded-full has-text-grey absolute size-8 is-flex is-justify-content-center is-align-items-center"
style="right: 0.5rem; top: 0.5rem"
>
<span class="icon">
<Icon
name="material-symbols:close-rounded"
:size="22"
/>
<div v-if="invoice">
<div>
<div class="is-flex is-gap-1.5 is-align-items-center">
<span class="fs-17 font-bold">{{ invoice.code }}</span>
<span
:class="[
'tag rounded-full',
`has-background-${invoice.status__color}-80 has-text-${invoice.status__color}-25`,
]"
>
{{ invoice.status }}
</span>
</button>
<div class="card-content">
<div>
<div class="is-flex is-gap-2 is-align-items-center">
<span class="fs-17 font-bold">{{ order.code }}</span>
<span
:class="[
'tag rounded-full',
`has-background-${order.status__color}-80 has-text-${order.status__color}-25`,
]"
>
{{ order.status__name }}
</span>
</div>
<div class="is-flex is-gap-0.5 is-flex-direction-column mt-2">
<div class="is-flex is-gap-1 is-align-items-center">
<Icon
name="material-symbols:person-outline-rounded"
:size="18"
/>
<p>{{ order.customer__name }}</p>
</div>
<div class="is-flex is-gap-1 is-align-items-center">
<Icon
name="material-symbols:call-outline-rounded"
:size="18"
/>
<p>{{ order.customer__phone }}</p>
</div>
<div class="is-flex is-gap-1 is-align-items-center">
<Icon
name="material-symbols:calendar-today-outline-rounded"
:size="18"
/>
<p>{{ $dayjs(order.create_time).format("LL") }}</p>
</div>
</div>
<div class="p-4 has-background-primary-95 rounded-lg mt-6">
<p>Tổng giá trị đơn hàng</p>
<p class="font-bold fs-28">
{{ $numtoString(order.total, { hasUnit: true }) }}
</p>
</div>
</div>
<hr class="m-0" />
<div class="buttons m-0">
<button class="button fs-14 is-flex-grow-1 is-primary">Xác nhận đơn</button>
<button class="button fs-14 is-flex-grow-1">Ghi thanh toán</button>
</div>
<hr class="m-0" />
<div class="tabs is-toggle m-0 fs-13">
<ul>
<li
v-for="tab in tabs"
:key="tab.name"
:class="activeTab.name === tab.name && 'is-active'"
@click="activeTab = tab"
>
<a>{{ tab.name }}</a>
</li>
</ul>
</div>
<hr class="m-0" />
<div id="tab-content">
<div class="is-flex is-gap-1 mb-4">
</div>
<div class="is-flex is-gap-0.5 is-flex-direction-column mt-4">
<p class="icon-text">
<span class="icon">
<Icon
:name="activeTab.icon"
:size="21"
name="material-symbols:person-outline-rounded"
:size="18"
/>
<span class="fs-15 font-semibold">{{ activeTab.heading }}</span>
</div>
<div>
<OrderProductTab
v-if="activeTab.name === 'Chi tiết đơn'"
:order="order"
</span>
<span>{{ invoice.customer_name }}</span>
</p>
<p class="icon-text">
<span class="icon">
<Icon
name="material-symbols:call-outline-rounded"
:size="18"
/>
<OrderDeliveryTab
v-else-if="activeTab.name === 'Giao hàng'"
:order="order"
</span>
<span>{{ invoice.customer_phone }}</span>
</p>
<p class="icon-text">
<span class="icon">
<Icon
name="material-symbols:calendar-today-outline-rounded"
:size="18"
/>
<OrderReceiptTab
v-else-if="activeTab.name === 'Hoá đơn'"
:order="order"
/>
<OrderPaymentTab
v-else-if="activeTab.name === 'Thanh toán'"
:order="order"
/>
<OrderHistoryTab
v-else-if="activeTab.name === 'Lịch sử'"
:order="order"
/>
</div>
</div>
</span>
<span>{{ $dayjs(invoice.create_time).format("LL") }}</span>
</p>
</div>
<div class="px-6 py-4 has-background-primary-95 rounded-lg mt-6">
<p>Tổng giá trị đơn hàng</p>
<p class="font-bold fs-25">
{{ $numtoString(invoice.total_amount, { hasUnit: true }) }}
</p>
</div>
</div>
<hr />
<div class="buttons m-0">
<button class="button fs-14 is-flex-grow-1 is-primary">Xác nhận đơn</button>
<button class="button fs-14 is-flex-grow-1">Ghi thanh toán</button>
</div>
<hr />
<div class="tabs is-toggle m-0 fs-13">
<ul>
<li
v-for="tab in tabs"
:key="tab.name"
:class="activeTab.name === tab.name && 'is-active'"
@click="activeTab = tab"
>
<a>{{ tab.name }}</a>
</li>
</ul>
</div>
<div
id="tab-content"
class="mt-4"
>
<div class="is-flex is-gap-1 mb-4">
<Icon
:name="activeTab.icon"
:size="21"
/>
<span class="fs-15 font-semibold">{{ activeTab.heading }}</span>
</div>
<div>
<OrderProductTab
v-if="activeTab.name === 'Chi tiết đơn'"
:invoice="invoice"
/>
<OrderDeliveryTab
v-else-if="activeTab.name === 'Giao hàng'"
:invoice="invoice"
/>
<OrderReceiptTab
v-else-if="activeTab.name === 'Hoá đơn'"
:invoice="invoice"
/>
<OrderPaymentTab
v-else-if="activeTab.name === 'Thanh toán'"
:invoice="invoice"
/>
<OrderHistoryTab
v-else-if="activeTab.name === 'Lịch sử'"
:invoice="invoice"
/>
</div>
</div>
</div>
</template>
<style scoped>
.card-content {
padding: 0; /* 1.5rem */
> div {
padding: var(--bulma-card-content-padding);
}
}
.tabs {
--bulma-tabs-toggle-link-active-background-color: var(--bulma-link-90);
--bulma-tabs-toggle-link-active-background-color: var(--bulma-link-95);
--bulma-tabs-toggle-link-active-border-color: var(--bulma-link-90);
--bulma-tabs-toggle-link-active-color: var(--bulma-link-40);
}