chore: install prettier

This commit is contained in:
Viet An
2026-05-04 15:22:27 +07:00
parent 93d29ca7d8
commit bd58e2b847
267 changed files with 22950 additions and 13581 deletions

View File

@@ -1,34 +1,34 @@
<script setup>
import InventoryHighlightCard from '@/components/inventory/InventoryHighlightCard.vue';
import InventoryTable from '@/components/inventory/InventoryTable.vue';
import InventoryHighlightCard from "@/components/inventory/InventoryHighlightCard.vue";
import InventoryTable from "@/components/inventory/InventoryTable.vue";
const { $store } = useNuxtApp();
const inventoryHighlights = [
{
name: 'Tổng số SKU',
name: "Tổng số SKU",
value: 12,
icon: 'material-symbols:deployed-code-outline',
color: 'blue',
icon: "material-symbols:deployed-code-outline",
color: "blue",
},
{
name: 'Tổng tồn kho',
value: '1,120',
icon: 'material-symbols:box-outline-rounded',
color: 'green',
unit: 'đơn vị'
name: "Tổng tồn kho",
value: "1,120",
icon: "material-symbols:box-outline-rounded",
color: "green",
unit: "đơn vị",
},
{
name: 'Giá trị tồn kho',
value: '294.5M',
icon: 'material-symbols:attach-money-rounded',
color: 'purple',
name: "Giá trị tồn kho",
value: "294.5M",
icon: "material-symbols:attach-money-rounded",
color: "purple",
},
{
name: 'Sắp hết hàng',
name: "Sắp hết hàng",
value: 3,
icon: 'material-symbols:warning-outline-rounded',
color: 'red',
unit: 'sản phẩm'
icon: "material-symbols:warning-outline-rounded",
color: "red",
unit: "sản phẩm",
},
];
</script>
@@ -42,25 +42,37 @@ const inventoryHighlights = [
<div class="content buttons is-justify-content-flex-end">
<button class="button fs-14">
<span class="icon">
<Icon :size="18" name="material-symbols:download-rounded" />
<Icon
:size="18"
name="material-symbols:download-rounded"
/>
</span>
<span>Export</span>
</button>
<button class="button fs-14">
<span class="icon">
<Icon :size="18" name="material-symbols:upload-rounded" />
<Icon
:size="18"
name="material-symbols:upload-rounded"
/>
</span>
<span>Import</span>
</button>
<button class="button fs-14">
<span class="icon">
<Icon :size="18" name="material-symbols:sync" />
<Icon
:size="18"
name="material-symbols:sync"
/>
</span>
<span>Chuyển kho</span>
</button>
<button class="button fs-14 is-primary">
<span class="icon">
<Icon :size="18" name="material-symbols:add-2-rounded" />
<Icon
:size="18"
name="material-symbols:add-2-rounded"
/>
</span>
<span>Điều chỉnh</span>
</button>
@@ -77,4 +89,4 @@ const inventoryHighlights = [
</div>
<InventoryTable />
</div>
</template>
</template>

View File

@@ -4,8 +4,8 @@ const props = defineProps({
value: String,
unit: String,
icon: String,
color: String
})
color: String,
});
</script>
<template>
<div class="cell">
@@ -15,7 +15,12 @@ const props = defineProps({
<p class="fs-14 has-text-grey">{{ name }}</p>
<p class="fs-22 font-bold">{{ value }}</p>
</div>
<div :class="['p-3 rounded-lg is-flex is-justify-content-center is-align-items-center', `has-background-${color}-soft`]">
<div
:class="[
'p-3 rounded-lg is-flex is-justify-content-center is-align-items-center',
`has-background-${color}-soft`,
]"
>
<Icon
:name="icon"
:class="`has-text-${color}-40`"

View File

@@ -4,7 +4,7 @@ const props = defineProps({
selected: Boolean,
});
const emit = defineEmits(['selectInvItem', 'unselect']);
const emit = defineEmits(["selectInvItem", "unselect"]);
const { $dayjs } = useNuxtApp();
</script>
@@ -24,15 +24,22 @@ const { $dayjs } = useNuxtApp();
<td class="is-family-monospace fs-12">{{ invItem.storage__position }}</td>
<td class="has-text-right">{{ invItem.stock }}</td>
<td class="has-text-right">{{ invItem.preorder }}</td>
<td
:class="['has-text-right', invItem.status === 'OK' ? 'has-text-success-30' : 'has-text-warning-30']"
>{{ invItem.available }}</td>
<td :class="['has-text-right', invItem.status === 'OK' ? 'has-text-success-30' : 'has-text-warning-30']">
{{ invItem.available }}
</td>
<td class="is-family-monospace fs-12">{{ invItem.batch }}</td>
<td>{{ $dayjs(invItem.expired).format('L') }}</td>
<td>{{ $dayjs(invItem.expired).format("L") }}</td>
<td>
<span
:class="['tag is-rounded', invItem.status === 'OK' ? 'has-background-success-soft has-text-success-bold' : 'has-background-warning-soft has-text-warning-bold']"
>{{ invItem.status }}</span></td>
<span
:class="[
'tag is-rounded',
invItem.status === 'OK'
? 'has-background-success-soft has-text-success-bold'
: 'has-background-warning-soft has-text-warning-bold',
]"
>{{ invItem.status }}</span
>
</td>
</tr>
</template>
<style scoped>
@@ -44,4 +51,4 @@ td {
vertical-align: middle;
--bulma-table-cell-padding: 0.75em;
}
</style>
</style>

View File

@@ -1,434 +1,420 @@
<script setup>
import InventoryRow from '@/components/inventory/InventoryRow.vue';
import SelectedInvItem from '@/components/inventory/SelectedInvItem.vue';
import InventoryRow from "@/components/inventory/InventoryRow.vue";
import SelectedInvItem from "@/components/inventory/SelectedInvItem.vue";
const invItems = [
{
id: 1,
name: 'Dầu gội thảo mộc 500ml',
category: 'Chăm sóc tóc',
sku: 'DG-012',
storage: 'Kho TP.HCM',
storage__position: 'WH-HCM/C-01',
name: "Dầu gội thảo mộc 500ml",
category: "Chăm sóc tóc",
sku: "DG-012",
storage: "Kho TP.HCM",
storage__position: "WH-HCM/C-01",
stock: 200,
preorder: 50,
available: 150,
unit_price: '120000.00',
total: '24000000.00',
batch: 'BATCH-2024-012',
expired: '2026-08-20',
status: 'OK',
unit_price: "120000.00",
total: "24000000.00",
batch: "BATCH-2024-012",
expired: "2026-08-20",
status: "OK",
moveHistory: [
{
id: 1,
type: 1,
type__name: 'Nhập',
date: '2026-04-03',
code: 'PO-009',
to__code: 'WH-HCM/C-01',
type__name: "Nhập",
date: "2026-04-03",
code: "PO-009",
to__code: "WH-HCM/C-01",
delta: 300,
},
{
id: 2,
type: 2,
type__name: 'Xuất',
date: '2026-04-04',
code: 'SO-034',
from__code: 'WH-HCM/C-01',
delta: -100
type__name: "Xuất",
date: "2026-04-04",
code: "SO-034",
from__code: "WH-HCM/C-01",
delta: -100,
},
]
],
},
{
id: 2,
name: 'Gel rửa mặt làm sạch sâu',
category: 'Mỹ phẩm',
sku: 'GRM-006',
storage: 'Kho Hà Nội',
storage__position: 'WH-HN/A-03',
name: "Gel rửa mặt làm sạch sâu",
category: "Mỹ phẩm",
sku: "GRM-006",
storage: "Kho Hà Nội",
storage__position: "WH-HN/A-03",
stock: 12,
preorder: 5,
available: 7,
unit_price: '140000.00',
total: '1700000.00',
batch: 'BATCH-2024-006',
expired: '2025-11-20',
status: 'Thấp',
unit_price: "140000.00",
total: "1700000.00",
batch: "BATCH-2024-006",
expired: "2025-11-20",
status: "Thấp",
moveHistory: [
{
id: 3,
type: 2,
type__name: 'Xuất',
date: '2026-03-28',
code: 'SO-028',
to__code: 'WH-HN/A-03',
type__name: "Xuất",
date: "2026-03-28",
code: "SO-028",
to__code: "WH-HN/A-03",
delta: -50,
},
]
],
},
{
id: 3,
name: 'Kem chống nắng SPF 50+',
category: 'Mỹ phẩm',
sku: 'KCN-001',
storage: 'Kho Hà Nội',
storage__position: 'WH-HN/A-01',
name: "Kem chống nắng SPF 50+",
category: "Mỹ phẩm",
sku: "KCN-001",
storage: "Kho Hà Nội",
storage__position: "WH-HN/A-01",
stock: 150,
preorder: 20,
available: 130,
unit_price: '280000.00',
total: '42000000.00',
batch: 'BATCH-2024-001',
expired: '2025-10-15',
status: 'OK',
unit_price: "280000.00",
total: "42000000.00",
batch: "BATCH-2024-001",
expired: "2025-10-15",
status: "OK",
moveHistory: [
{
id: 4,
type: 1,
type__name: 'Nhập',
date: '2026-04-05',
code: 'PO-001',
from__code: 'WH-HN/A-01',
type__name: "Nhập",
date: "2026-04-05",
code: "PO-001",
from__code: "WH-HN/A-01",
delta: 200,
},
{
id: 5,
type: 2,
type__name: 'Xuất',
date: '2026-04-06',
code: 'SO-023',
from__code: 'WH-HN/A-01',
type__name: "Xuất",
date: "2026-04-06",
code: "SO-023",
from__code: "WH-HN/A-01",
delta: -50,
},
]
],
},
{
id: 4,
name: 'Kem dưỡng ẩm ban đêm',
category: 'Dưỡng da',
sku: 'KD-007',
storage: 'Kho Đà Nẵng',
storage__position: 'WH-DN/A-01',
name: "Kem dưỡng ẩm ban đêm",
category: "Dưỡng da",
sku: "KD-007",
storage: "Kho Đà Nẵng",
storage__position: "WH-DN/A-01",
stock: 8,
preorder: 3,
available: 5,
unit_price: '380000.00',
total: '30040000.00',
batch: 'BATCH-2024-007',
expired: '2025-09-10',
status: 'Thấp',
unit_price: "380000.00",
total: "30040000.00",
batch: "BATCH-2024-007",
expired: "2025-09-10",
status: "Thấp",
moveHistory: [
{
id: 6,
type: 2,
type__name: 'Xuất',
date: '2026-03-25',
code: 'SO-029',
from__code: 'WH-DN/A-01',
type__name: "Xuất",
date: "2026-03-25",
code: "SO-029",
from__code: "WH-DN/A-01",
delta: -40,
},
]
],
},
{
id: 5,
name: 'Kem mắt chống lão hóa',
category: 'Dưỡng da',
sku: 'KM-011',
storage: 'Kho Hà Nội',
storage__position: 'WH-HN/B-02',
name: "Kem mắt chống lão hóa",
category: "Dưỡng da",
sku: "KM-011",
storage: "Kho Hà Nội",
storage__position: "WH-HN/B-02",
stock: 30,
preorder: 28,
available: 2,
unit_price: '550000.00',
total: '16500000.00',
batch: 'BATCH-2024-011',
expired: '2025-10-05',
status: 'Thấp',
unit_price: "550000.00",
total: "16500000.00",
batch: "BATCH-2024-011",
expired: "2025-10-05",
status: "Thấp",
moveHistory: [
{
id: 7,
type: 2,
type__name: 'Xuất',
date: '2026-03-27',
code: 'SO-033',
from__code: 'WH-HN/B-02',
type__name: "Xuất",
date: "2026-03-27",
code: "SO-033",
from__code: "WH-HN/B-02",
delta: -25,
},
]
],
},
{
id: 6,
name: 'Mặt nạ collagen 10 miếng',
category: 'Mặt nạ',
sku: 'MN-004',
storage: 'Kho TP.HCM',
storage__position: 'WH-HCM/A-01',
name: "Mặt nạ collagen 10 miếng",
category: "Mặt nạ",
sku: "MN-004",
storage: "Kho TP.HCM",
storage__position: "WH-HCM/A-01",
stock: 45,
preorder: 15,
available: 30,
unit_price: '320000.00',
total: '14400000.00',
batch: 'BATCH-2024-004',
expired: '2025-08-15',
status: 'OK',
unit_price: "320000.00",
total: "14400000.00",
batch: "BATCH-2024-004",
expired: "2025-08-15",
status: "OK",
moveHistory: [
{
id: 8,
type: 1,
type__name: 'Nhập',
date: '2026-03-30',
code: 'PO-004',
to__code: 'WH-HCM/A-01',
type__name: "Nhập",
date: "2026-03-30",
code: "PO-004",
to__code: "WH-HCM/A-01",
delta: 60,
},
{
id: 9,
type: 2,
type__name: 'Xuất',
date: '2026-04-01',
code: 'SO-026',
from__code: 'WH-HCM/A-01',
type__name: "Xuất",
date: "2026-04-01",
code: "SO-026",
from__code: "WH-HCM/A-01",
delta: -15,
},
]
],
},
{
id: 7,
name: 'Nước tẩy trang 3 trong 1',
category: 'Tẩy trang',
sku: 'NTT-010',
storage: 'Kho Đà Nẵng',
storage__position: 'WH-DN/A-02',
name: "Nước tẩy trang 3 trong 1",
category: "Tẩy trang",
sku: "NTT-010",
storage: "Kho Đà Nẵng",
storage__position: "WH-DN/A-02",
stock: 140,
preorder: 35,
available: 105,
unit_price: '195000.00',
total: '27300000.00',
batch: 'BATCH-2024-010',
expired: '2026-04-30',
status: 'OK',
unit_price: "195000.00",
total: "27300000.00",
batch: "BATCH-2024-010",
expired: "2026-04-30",
status: "OK",
moveHistory: [
{
id: 10,
type: 1,
type__name: 'Nhập',
date: '2026-03-29',
code: 'PO-008',
to__code: 'WH-DN/A-02',
type__name: "Nhập",
date: "2026-03-29",
code: "PO-008",
to__code: "WH-DN/A-02",
delta: 200,
},
{
id: 11,
type: 2,
type__name: 'Xuất',
date: '2026-04-01',
code: 'SO-032',
from__code: 'WH-DN/A-02',
type__name: "Xuất",
date: "2026-04-01",
code: "SO-032",
from__code: "WH-DN/A-02",
delta: -60,
},
]
],
},
{
id: 8,
name: 'Phấn nền BB cream',
category: 'Trang điểm',
sku: 'PN-009',
storage: 'Kho TP.HCM',
storage__position: 'WH-HCM/B-01',
name: "Phấn nền BB cream",
category: "Trang điểm",
sku: "PN-009",
storage: "Kho TP.HCM",
storage__position: "WH-HCM/B-01",
stock: 65,
preorder: 20,
available: 45,
unit_price: '220000.00',
total: '14300000.00',
batch: 'BATCH-2024-009',
expired: '2025-07-15',
status: 'OK',
unit_price: "220000.00",
total: "14300000.00",
batch: "BATCH-2024-009",
expired: "2025-07-15",
status: "OK",
moveHistory: [
{
id: 12,
type: 1,
type__name: 'Nhập',
date: '2026-04-01',
code: 'PO-007',
to__code: 'WH-HCM/B-01',
type__name: "Nhập",
date: "2026-04-01",
code: "PO-007",
to__code: "WH-HCM/B-01",
delta: 100,
},
{
id: 13,
type: 2,
type__name: 'Xuất',
date: '2026-04-02',
code: 'SO-031',
from__code: 'WH-HCM/B-01',
type__name: "Xuất",
date: "2026-04-02",
code: "SO-031",
from__code: "WH-HCM/B-01",
delta: -35,
},
]
],
},
{
id: 9,
name: 'Serum Vitamin C 30ml',
category: 'Dưỡng da',
sku: 'SER-003',
storage: 'Kho Hà Nội',
storage__position: 'WH-HN/B-01',
name: "Serum Vitamin C 30ml",
category: "Dưỡng da",
sku: "SER-003",
storage: "Kho Hà Nội",
storage__position: "WH-HN/B-01",
stock: 220,
preorder: 40,
available: 180,
unit_price: '450000.00',
total: '99000000.00',
batch: 'BATCH-2024-003',
expired: '2025-12-31',
status: 'OK',
unit_price: "450000.00",
total: "99000000.00",
batch: "BATCH-2024-003",
expired: "2025-12-31",
status: "OK",
moveHistory: [
{
id: 14,
type: 1,
type__name: 'Nhập',
date: '2026-04-01',
code: 'PO-003',
to__code: 'WH-HN/B-01',
type__name: "Nhập",
date: "2026-04-01",
code: "PO-003",
to__code: "WH-HN/B-01",
delta: 300,
},
{
id: 15,
type: 2,
type__name: 'Xuất',
date: '2026-04-02',
code: 'SO-025',
from__code: 'WH-HN/B-01',
type__name: "Xuất",
date: "2026-04-02",
code: "SO-025",
from__code: "WH-HN/B-01",
delta: -80,
},
]
],
},
{
id: 10,
name: 'Son dưỡng môi vitamin E',
category: 'Trang điểm',
sku: 'SD-008',
storage: 'Kho Hà Nội',
storage__position: 'WH-HN/C-01',
name: "Son dưỡng môi vitamin E",
category: "Trang điểm",
sku: "SD-008",
storage: "Kho Hà Nội",
storage__position: "WH-HN/C-01",
stock: 95,
preorder: 45,
available: 50,
unit_price: '75000.00',
total: '7100000.00',
batch: 'BATCH-2024-008',
expired: '2026-02-28',
status: 'OK',
unit_price: "75000.00",
total: "7100000.00",
batch: "BATCH-2024-008",
expired: "2026-02-28",
status: "OK",
moveHistory: [
{
id: 16,
type: 1,
type__name: 'Nhập',
date: '2026-04-04',
code: 'PO-006',
to__code: 'WH-HN/C-01',
type__name: "Nhập",
date: "2026-04-04",
code: "PO-006",
to__code: "WH-HN/C-01",
delta: 150,
},
{
id: 17,
type: 2,
type__name: 'Xuất',
date: '2026-04-02',
code: 'SO-030',
from__code: 'WH-HN/C-01',
type__name: "Xuất",
date: "2026-04-02",
code: "SO-030",
from__code: "WH-HN/C-01",
delta: -55,
},
]
],
},
{
id: 11,
name: 'Sữa rửa mặt trà xanh 150ml',
category: 'Mỹ phẩm',
sku: 'SRM-002',
storage: 'Kho Hà Nội',
storage__position: 'WH-HN/A-02',
name: "Sữa rửa mặt trà xanh 150ml",
category: "Mỹ phẩm",
sku: "SRM-002",
storage: "Kho Hà Nội",
storage__position: "WH-HN/A-02",
stock: 85,
preorder: 30,
available: 55,
unit_price: '150000.00',
total: '12800000.00',
batch: 'BATCH-2024-002',
expired: '2026-03-20',
status: 'OK',
unit_price: "150000.00",
total: "12800000.00",
batch: "BATCH-2024-002",
expired: "2026-03-20",
status: "OK",
moveHistory: [
{
id: 18,
type: 1,
type__name: 'Nhập',
date: '2026-04-03',
code: 'PO-002',
to__code: 'WH-HN/A-02',
type__name: "Nhập",
date: "2026-04-03",
code: "PO-002",
to__code: "WH-HN/A-02",
delta: 100,
},
{
id: 19,
type: 2,
type__name: 'Xuất',
date: '2026-04-04',
code: 'SO-025',
from__code: 'WH-HN/A-02',
type__name: "Xuất",
date: "2026-04-04",
code: "SO-025",
from__code: "WH-HN/A-02",
delta: -15,
},
]
],
},
{
id: 12,
name: 'Toner cân bằng da 200ml',
category: 'Dưỡng da',
sku: 'TN-005',
storage: 'Kho TP.HCM',
storage__position: 'WH-HCM/A-02',
name: "Toner cân bằng da 200ml",
category: "Dưỡng da",
sku: "TN-005",
storage: "Kho TP.HCM",
storage__position: "WH-HCM/A-02",
stock: 180,
preorder: 25,
available: 155,
unit_price: '180000.00',
total: '32400000.00',
batch: 'BATCH-2024-005',
expired: '2026-06-30',
status: 'OK',
unit_price: "180000.00",
total: "32400000.00",
batch: "BATCH-2024-005",
expired: "2026-06-30",
status: "OK",
moveHistory: [
{
id: 20,
type: 1,
type__name: 'Nhập',
date: '2026-04-02',
code: 'PO-005',
to__code: 'WH-HCM/A-02',
type__name: "Nhập",
date: "2026-04-02",
code: "PO-005",
to__code: "WH-HCM/A-02",
delta: 200,
},
{
id: 21,
type: 2,
type__name: 'Xuất',
date: '2026-04-04',
code: 'SO-025',
from__code: 'WH-HCM/A-02',
type__name: "Xuất",
date: "2026-04-04",
code: "SO-025",
from__code: "WH-HCM/A-02",
delta: -15,
},
]
],
},
];
const storages = [
'Kho Hà Nội',
'Kho TP.HCM',
'Kho Đà Nẵng',
];
const storages = ["Kho Hà Nội", "Kho TP.HCM", "Kho Đà Nẵng"];
const categories = [
'Chăm sóc tóc',
'Dưỡng da',
'Mỹ phẩm',
'Mặt nạ',
'Trang điểm',
'Tẩy trang',
];
const categories = ["Chăm sóc tóc", "Dưỡng da", "Mỹ phẩm", "Mặt nạ", "Trang điểm", "Tẩy trang"];
const statuses = [
'OK',
'Thấp',
];
const statuses = ["OK", "Thấp"];
const input = ref();
const selectedStorage = ref();
@@ -436,30 +422,30 @@ const selectedCategory = ref();
const selectedStatus = ref();
const filteredInvItems = computed(() => {
const filteredByInput = invItems.filter(invItem => {
const filteredByInput = invItems.filter((invItem) => {
if (!input.value) return true;
const values = Object.values(invItem);
const strValues = values.filter(v => typeof v === 'string');
return strValues.some(str => str.toLowerCase().includes(input.value.toLowerCase()));
const strValues = values.filter((v) => typeof v === "string");
return strValues.some((str) => str.toLowerCase().includes(input.value.toLowerCase()));
});
const filteredByStorage = filteredByInput.filter(invItem => {
const filteredByStorage = filteredByInput.filter((invItem) => {
if (!selectedStorage.value) return true;
return invItem.storage === selectedStorage.value;
});
const filteredByCategory = filteredByStorage.filter(invItem => {
const filteredByCategory = filteredByStorage.filter((invItem) => {
if (!selectedCategory.value) return true;
return invItem.category === selectedCategory.value;
});
const filteredByStatus = filteredByCategory.filter(invItem => {
const filteredByStatus = filteredByCategory.filter((invItem) => {
if (!selectedStatus.value) return true;
return invItem.status === selectedStatus.value;
});
return filteredByStatus;
})
});
const selectedInvItem = ref(null);
</script>
@@ -470,9 +456,17 @@ const selectedInvItem = ref(null);
<div class="is-flex is-gap-2 is-align-items-center">
<div class="field is-flex-grow-1 mb-0">
<p class="control has-icons-left">
<input v-model="input" class="input" type="text" placeholder="Tìm kiếm theo tên, SKU, barcode..." />
<input
v-model="input"
class="input"
type="text"
placeholder="Tìm kiếm theo tên, SKU, barcode..."
/>
<span class="icon is-small is-left">
<Icon name="material-symbols:search-rounded" :size="20" />
<Icon
name="material-symbols:search-rounded"
:size="20"
/>
</span>
</p>
</div>
@@ -484,7 +478,7 @@ const selectedInvItem = ref(null);
:key="storage"
:value="storage"
>
{{ storage }}
{{ storage }}
</option>
</select>
</div>
@@ -496,7 +490,7 @@ const selectedInvItem = ref(null);
:key="category"
:value="category"
>
{{ category }}
{{ category }}
</option>
</select>
</div>
@@ -508,7 +502,7 @@ const selectedInvItem = ref(null);
:key="status"
:value="status"
>
{{ status }}
{{ status }}
</option>
</select>
</div>
@@ -517,13 +511,14 @@ const selectedInvItem = ref(null);
</div>
<div class="fixed-grid has-3-cols">
<div class="grid">
<div
:class="['cell', selectedInvItem ? 'is-col-span-2' : 'is-col-span-3']"
>
<div :class="['cell', selectedInvItem ? 'is-col-span-2' : 'is-col-span-3']">
<div class="card is-clipped">
<div class="card-content p-0">
<p class="p-5 fs-17 font-semibold is-flex is-align-items-center is-gap-1">
<Icon name="material-symbols:deployed-code-outline" :size="22" />
<Icon
name="material-symbols:deployed-code-outline"
:size="22"
/>
<span>Danh sách tồn kho ({{ filteredInvItems.length }})</span>
</p>
<table class="table is-fullwidth is-hoverable fs-13">
@@ -547,11 +542,13 @@ const selectedInvItem = ref(null);
:key="invItem.id"
:invItem="invItem"
:selected="invItem.id === selectedInvItem?.id"
@selectInvItem="(id) => {
selectedInvItem = filteredInvItems.find(item => item.id === id);
}"
@selectInvItem="
(id) => {
selectedInvItem = filteredInvItems.find((item) => item.id === id);
}
"
@unselect="selectedInvItem = null"
/>
/>
</tbody>
</table>
</div>
@@ -560,7 +557,7 @@ const selectedInvItem = ref(null);
<SelectedInvItem
:invItem="selectedInvItem"
@unselect="selectedInvItem = null"
/>
/>
</div>
</div>
</template>

View File

@@ -1,39 +1,47 @@
<script setup>
const props = defineProps({
invItem: Object
invItem: Object,
});
const { $dayjs, $numtoString } = useNuxtApp();
const emit = defineEmits('unselect');
const emit = defineEmits("unselect");
</script>
<template>
<div v-if="invItem" class="cell relative fs-14">
<div
v-if="invItem"
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="z-index: 1; right: 0.5rem; top: 0.5rem;"
style="z-index: 1; right: 0.5rem; top: 0.5rem"
>
<span class="icon">
<Icon name="material-symbols:close-rounded" :size="22" />
<Icon
name="material-symbols:close-rounded"
:size="22"
/>
</span>
</button>
<div class="card-content is-clipped">
<div class="py-3 sticky top-0">
<p class="fs-17 font-semibold">Chi tiết sản phẩm</p>
<p class="fs-17 font-semibold">Chi tiết sản phẩm</p>
</div>
<hr class="m-0" />
<div style="max-height: 600px; overflow-y: scroll">
<div>
<div class="is-flex is-gap-2 is-align-items-center">
<div class="is-flex is-gap-2">
<div class="has-background-purple size-12 rounded-md is-flex is-justify-content-center is-align-items-center">
<div
class="has-background-purple size-12 rounded-md is-flex is-justify-content-center is-align-items-center"
>
<Icon
name="material-symbols:deployed-code-outline"
:size="24"
class="has-text-white"
/>
/>
</div>
<div>
<p class="font-semibold mb-1">{{ invItem.name }}</p>
@@ -45,11 +53,15 @@ const emit = defineEmits('unselect');
<div class="is-flex is-gap-1 mt-4">
<div class="px-4 py-3 is-flex-grow-1 rounded-md has-background-blue-95 has-text-blue-40">
<p class="fs-13">Giá đơn vị</p>
<p class="fs-16 font-semibold">{{ $numtoString(invItem.unit_price, { hasUnit: true }) }}</p>
<p class="fs-16 font-semibold">
{{ $numtoString(invItem.unit_price, { hasUnit: true }) }}
</p>
</div>
<div class="px-4 py-3 is-flex-grow-1 rounded-md has-background-purple-90 has-text-purple-40">
<p class="fs-13">Tổng giá trị</p>
<p class="fs-16 font-semibold">{{ $numtoString(invItem.total, { hasUnit: true }) }}</p>
<p class="fs-16 font-semibold">
{{ $numtoString(invItem.total, { hasUnit: true }) }}
</p>
</div>
</div>
<div class="mt-6">
@@ -62,12 +74,16 @@ const emit = defineEmits('unselect');
<hr class="my-1 has-background-grey-95" />
<div class="py-2 is-flex is-justify-content-space-between">
<p class="has-text-grey-40">Đặt trước</p>
<p class="fs-14 font-semibold has-text-orange">{{ invItem.preorder }}</p>
<p class="fs-14 font-semibold has-text-orange">
{{ invItem.preorder }}
</p>
</div>
<hr class="my-1 has-background-grey-95" />
<div class="py-2 is-flex is-justify-content-space-between">
<p class="has-text-grey-40">Khả dụng</p>
<p class="fs-14 font-semibold has-text-green">{{ invItem.available }}</p>
<p class="fs-14 font-semibold has-text-green">
{{ invItem.available }}
</p>
</div>
</div>
</div>
@@ -75,10 +91,15 @@ const emit = defineEmits('unselect');
<p class="fs-15 font-semibold mb-4">Vị trí lưu kho</p>
<div class="p-4 rounded-md has-background-grey-95">
<div class="is-flex is-gap-1">
<Icon name="material-symbols:location-on-outline-rounded" :size="20" />
<Icon
name="material-symbols:location-on-outline-rounded"
:size="20"
/>
<div>
<p>{{ invItem.storage }}</p>
<p class="mt-1 fs-13 is-family-monospace">{{ invItem.storage__position }}</p>
<p class="mt-1 fs-13 is-family-monospace">
{{ invItem.storage__position }}
</p>
</div>
</div>
</div>
@@ -91,12 +112,14 @@ const emit = defineEmits('unselect');
</div>
<div class="p-4 mt-4 rounded-md has-background-grey-95">
<div class="is-flex is-gap-1 is-align-items-center">
<Icon name="material-symbols:calendar-today-outline-rounded" :size="18"
<Icon
name="material-symbols:calendar-today-outline-rounded"
:size="18"
class="has-text-grey-50"
/>
/>
<p class="fs-13 has-text-grey">Hạn sử dụng</p>
</div>
<p class="mt-1">{{ $dayjs(invItem.expired).format('LL') }}</p>
<p class="mt-1">{{ $dayjs(invItem.expired).format("LL") }}</p>
</div>
</div>
<div class="mt-6">
@@ -108,29 +131,37 @@ const emit = defineEmits('unselect');
>
<div class="is-flex is-justify-content-space-between mb-1">
<div class="is-flex is-gap-1 is-align-items-center">
<div :class="[
'p-1 rounded-sm is-flex is-align-items-center',
`has-background-${move.delta > 0 ? 'success' : 'danger'}-soft`
]">
<div
:class="[
'p-1 rounded-sm is-flex is-align-items-center',
`has-background-${move.delta > 0 ? 'success' : 'danger'}-soft`,
]"
>
<Icon
:name="move.delta > 0 ? 'ph:chart-line-up' : 'ph:chart-line-down'"
:size="18"
:class="`has-text-${move.delta > 0 ? 'success' : 'danger'}-40`"
/>
</div>
<p :class="`has-text-${move.delta > 0 ? 'success' : 'danger'}-40`">{{ move.type__name }}</p>
<p :class="`has-text-${move.delta > 0 ? 'success' : 'danger'}-40`">
{{ move.type__name }}
</p>
</div>
<p
:class="['fs-14 font-semibold', `has-text-${move.delta > 0 ? 'success' : 'danger'}-40`]"
>{{ new Intl.NumberFormat('en-US', { signDisplay: 'exceptZero' }).format(move.delta) }}</p>
<p :class="['fs-14 font-semibold', `has-text-${move.delta > 0 ? 'success' : 'danger'}-40`]">
{{
new Intl.NumberFormat("en-US", {
signDisplay: "exceptZero",
}).format(move.delta)
}}
</p>
</div>
<p class="is-flex is-gap-0.5 is-align-items-center">
<span>{{ $dayjs(move.date).format('L') }}</span>
<span>{{ $dayjs(move.date).format("L") }}</span>
<span></span>
<span class="is-family-monospace">{{ move.code }}</span>
</p>
<p>
<span>{{ move.from__code ? 'Từ' : 'Đến' }}</span>
<span>{{ move.from__code ? "Từ" : "Đến" }}</span>
<span>: </span>
<span>{{ move.from__code || move.to__code }}</span>
</p>
@@ -152,7 +183,7 @@ const emit = defineEmits('unselect');
</div>
</div>
</div>
</div>
</div>
</template>
<style scoped>
.card-content {
@@ -162,4 +193,4 @@ const emit = defineEmits('unselect');
padding: var(--bulma-card-content-padding);
}
}
</style>
</style>