changes
This commit is contained in:
@@ -129,18 +129,12 @@ $size: (
|
||||
// Block Layout
|
||||
.blockdiv {
|
||||
max-width: 1900px !important;
|
||||
padding: 60px 15px 40px 15px;
|
||||
|
||||
@include until($desktop) { padding: 65px 20px 30px 20px; }
|
||||
@include mobile { padding: 65px 16px 30px 16px; }
|
||||
padding: 1rem 2rem 2rem;
|
||||
@include mobile { padding: 1rem; }
|
||||
|
||||
.columns .column {
|
||||
@include mobile { padding-left: 0; padding-right: 0; }
|
||||
}
|
||||
|
||||
.padding-desktop {
|
||||
@media screen and (min-width: $desktop) { padding-left: 20px; padding-right: 20px; }
|
||||
}
|
||||
}
|
||||
|
||||
// Tooltip Styles
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<nav class="navbar is-fixed-top has-shadow px-3" role="navigation">
|
||||
<nav class="navbar has-shadow sticky px-3" style="top: 0" role="navigation">
|
||||
<div class="navbar-brand mr-5">
|
||||
<span class="navbar-item is-gap-1">
|
||||
<div style="width: 16px; height: 16px" class="has-background-primary rounded-full"></div>
|
||||
@@ -31,7 +31,7 @@
|
||||
</a>
|
||||
</div>
|
||||
<div class="navbar-menu" id="navMenu">
|
||||
<div class="navbar-start is-gap-1 is-align-items-center" style="min-width: 650px;">
|
||||
<div class="navbar-start is-gap-1 is-align-items-center" >
|
||||
<template v-for="(v, i) in leftmenu" :key="i" :id="v.code">
|
||||
<a class="navbar-item rounded-lg is-clipped p-0" v-if="!v.submenu" @click="changeTab(v)">
|
||||
<span :class="[
|
||||
@@ -67,7 +67,7 @@
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="navbar-end">
|
||||
<div v-if="false" class="navbar-end">
|
||||
<a class="navbar-item" @click="changeTab(tabConfig)" v-if="tabConfig">
|
||||
<SvgIcon v-bind="{ name: 'configuration.svg', type: 'findata', size: 24 }"></SvgIcon>
|
||||
</a>
|
||||
@@ -127,9 +127,9 @@ const menu = [
|
||||
index: 0,
|
||||
},
|
||||
]
|
||||
if($store.rights.length>0) {
|
||||
menu = menu.filter(v=>$findIndex($store.rights, {setting: v.id})>=0)
|
||||
}
|
||||
// if($store.rights.length>0) {
|
||||
// menu = menu.filter(v=>$findIndex($store.rights, {setting: v.id})>=0)
|
||||
// }
|
||||
if(menu.length===0) {
|
||||
$snackbar($store.lang==='vi'? 'Bạn không có quyền truy cập' : 'You do not have permission to access.')
|
||||
}
|
||||
|
||||
@@ -68,11 +68,12 @@ const highlights = [
|
||||
<div class="grid">
|
||||
<DashboardHighlightCard
|
||||
v-for="highlight in highlights"
|
||||
:key="highlight.name"
|
||||
v-bind="highlight"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fixed-grid has-3-cols">
|
||||
<div class="fixed-grid has-1-cols-mobile has-3-cols">
|
||||
<div class="grid">
|
||||
<div class="cell is-col-span-2">
|
||||
<RevenueChart />
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script setup>
|
||||
import DeliveryInteractive from '@/components/dashboard/DeliveryInteractive.vue';
|
||||
import Driver from '@/components/dashboard/Driver.vue';
|
||||
|
||||
const drivers = [
|
||||
@@ -32,11 +33,11 @@ const drivers = [
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="fs-17 font-semibold mb-4">Giao nhận & Tài xế</p>
|
||||
<div class="fixed-grid has-3-cols">
|
||||
<div class="fixed-grid has-1-cols-mobile has-3-cols">
|
||||
<div class="grid">
|
||||
<div class="cell is-col-span-2">
|
||||
<div style="border-radius: 0.5rem; overflow: hidden">
|
||||
<NuxtImg src="/map-demo.png" class="w-full" />
|
||||
<div>
|
||||
<DeliveryInteractive />
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell is-flex is-flex-direction-column is-gap-2">
|
||||
|
||||
477
app/components/dashboard/DeliveryInteractive.vue
Normal file
477
app/components/dashboard/DeliveryInteractive.vue
Normal file
@@ -0,0 +1,477 @@
|
||||
<template>
|
||||
<div
|
||||
class="relative w-full has-background-blue-95 rounded-lg is-clipped"
|
||||
style="height: 360px"
|
||||
>
|
||||
<div class="absolute inset-0 w-full h-full opacity-20"><div class="absolute w-full border-t border-gray-300" style="top: 20%;"></div><div class="absolute w-full border-t border-gray-300" style="top: 40%;"></div><div class="absolute w-full border-t border-gray-300" style="top: 60%;"></div><div class="absolute w-full border-t border-gray-300" style="top: 80%;"></div><div class="absolute w-full border-t border-gray-300" style="top: 100%;"></div><div class="absolute h-full border-l border-gray-300" style="left: 20%;"></div><div class="absolute h-full border-l border-gray-300" style="left: 40%;"></div><div class="absolute h-full border-l border-gray-300" style="left: 60%;"></div><div class="absolute h-full border-l border-gray-300" style="left: 80%;"></div><div class="absolute h-full border-l border-gray-300" style="left: 100%;"></div>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="absolute transform -translate-x-1/2 -translate-y-full"
|
||||
style="left: 33.3333%; top: 40%"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="lucide lucide-map-pin w-6 h-6 has-text-orange-50"
|
||||
>
|
||||
<path
|
||||
d="M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0"
|
||||
></path>
|
||||
<circle cx="12" cy="10" r="3"></circle>
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="absolute transform -translate-x-1/2 -translate-y-full"
|
||||
style="left: 56.6667%; top: 60%"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="lucide lucide-map-pin w-6 h-6 has-text-green-50"
|
||||
>
|
||||
<path
|
||||
d="M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0"
|
||||
></path>
|
||||
<circle cx="12" cy="10" r="3"></circle>
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="absolute transform -translate-x-1/2 -translate-y-full"
|
||||
style="left: 10%; top: 28%"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="lucide lucide-map-pin w-6 h-6 has-text-orange-50"
|
||||
>
|
||||
<path
|
||||
d="M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0"
|
||||
></path>
|
||||
<circle cx="12" cy="10" r="3"></circle>
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="absolute transform -translate-x-1/2 -translate-y-full"
|
||||
style="left: 83.3333%; top: 80%"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="lucide lucide-map-pin w-6 h-6 has-text-green-50"
|
||||
>
|
||||
<path
|
||||
d="M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0"
|
||||
></path>
|
||||
<circle cx="12" cy="10" r="3"></circle>
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="absolute transform -translate-x-1/2 -translate-y-full"
|
||||
style="left: 40%; top: 52%"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="lucide lucide-map-pin w-6 h-6 has-text-blue-50"
|
||||
>
|
||||
<path
|
||||
d="M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0"
|
||||
></path>
|
||||
<circle cx="12" cy="10" r="3"></circle>
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="absolute transform -translate-x-1/2 -translate-y-1/2 transition-all duration-3000 ease-linear animate-move-random-1"
|
||||
style="left: 39.3933%; top: 56.171%"
|
||||
>
|
||||
<div class="relative">
|
||||
<div
|
||||
class="w-10 h-10 rounded-full has-background-blue-50 border-2 border-white is-flex is-justify-content-center is-align-items-center"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="white"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="lucide lucide-navigation w-5 h-5 text-white"
|
||||
>
|
||||
<polygon points="3 11 22 2 13 21 11 13 3 11"></polygon>
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="absolute -inset-1 rounded-full has-background-blue-60 animate-ping opacity-40"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="absolute transform -translate-x-1/2 -translate-y-1/2 transition-all duration-3000 ease-linear animate-move-random-2"
|
||||
style="left: 22.8854%; top: 33.4304%"
|
||||
>
|
||||
<div class="relative">
|
||||
<div
|
||||
class="w-10 h-10 rounded-full has-background-blue-50 border-2 border-white is-flex is-justify-content-center is-align-items-center"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="white"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="lucide lucide-navigation w-5 h-5 text-white"
|
||||
>
|
||||
<polygon points="3 11 22 2 13 21 11 13 3 11"></polygon>
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="absolute -inset-1 rounded-full has-background-blue-60 animate-ping opacity-40"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="absolute transform -translate-x-1/2 -translate-y-1/2 transition-all duration-3000 ease-linear"
|
||||
style="left: 73.3333%; top: 72%"
|
||||
>
|
||||
<div class="relative">
|
||||
<div
|
||||
class="w-10 h-10 rounded-full bg-gray-400 border-2 border-white is-flex is-justify-content-center is-align-items-center"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="white"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="lucide lucide-navigation w-5 h-5 text-white"
|
||||
>
|
||||
<polygon points="3 11 22 2 13 21 11 13 3 11"></polygon>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="absolute transform -translate-x-1/2 -translate-y-1/2 transition-all duration-3000 ease-linear animate-move-random-3"
|
||||
style="left: 37.052%; top: 75.6278%"
|
||||
>
|
||||
<div class="relative">
|
||||
<div
|
||||
class="w-10 h-10 rounded-full has-background-blue-50 border-2 border-white is-flex is-justify-content-center is-align-items-center"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="white"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="lucide lucide-navigation w-5 h-5 text-white"
|
||||
>
|
||||
<polygon points="3 11 22 2 13 21 11 13 3 11"></polygon>
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="absolute -inset-1 rounded-full has-background-blue-60 animate-ping opacity-40"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="absolute bottom-3 right-3 backdrop-blur px-3 py-1.5 rounded-lg text-xs font-medium has-text-gray-60"
|
||||
style="background-color: hsla(0, 100%, 100%, 0.9)"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="lucide lucide-map-pin w-4 h-4 inline mr-1"
|
||||
>
|
||||
<path
|
||||
d="M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0"
|
||||
></path>
|
||||
<circle cx="12" cy="10" r="3"></circle></svg>Hà Nội
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<style scoped>
|
||||
.absolute {
|
||||
position: absolute;
|
||||
}
|
||||
.relative {
|
||||
position: relative;
|
||||
}
|
||||
.-inset-1 {
|
||||
inset: calc(var(--spacing) * -1);
|
||||
}
|
||||
.right-3 {
|
||||
right: calc(var(--spacing) * 3);
|
||||
}
|
||||
.bottom-3 {
|
||||
bottom: calc(var(--spacing) * 3);
|
||||
}
|
||||
.mr-1 {
|
||||
margin-right: calc(var(--spacing) * 1);
|
||||
}
|
||||
.inline {
|
||||
display: inline;
|
||||
}
|
||||
.h-3 {
|
||||
height: calc(var(--spacing) * 3);
|
||||
}
|
||||
.h-5 {
|
||||
height: calc(var(--spacing) * 5);
|
||||
}
|
||||
.h-6 {
|
||||
height: calc(var(--spacing) * 6);
|
||||
}
|
||||
.h-10 {
|
||||
height: calc(var(--spacing) * 10);
|
||||
}
|
||||
.w-3 {
|
||||
width: calc(var(--spacing) * 3);
|
||||
}
|
||||
.w-5 {
|
||||
width: calc(var(--spacing) * 5);
|
||||
}
|
||||
.w-6 {
|
||||
width: calc(var(--spacing) * 6);
|
||||
}
|
||||
.w-10 {
|
||||
width: calc(var(--spacing) * 10);
|
||||
}
|
||||
.w-full {
|
||||
width: 100%;
|
||||
}
|
||||
.-translate-x-1\/2 {
|
||||
--tw-translate-x: calc(calc(1 / 2 * 100%) * -1);
|
||||
translate: var(--tw-translate-x) var(--tw-translate-y);
|
||||
}
|
||||
.-translate-y-1\/2 {
|
||||
--tw-translate-y: calc(calc(1 / 2 * 100%) * -1);
|
||||
translate: var(--tw-translate-x) var(--tw-translate-y);
|
||||
}
|
||||
.-translate-y-full {
|
||||
--tw-translate-y: -100%;
|
||||
translate: var(--tw-translate-x) var(--tw-translate-y);
|
||||
}
|
||||
.transform {
|
||||
transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,);
|
||||
}
|
||||
.animate-ping {
|
||||
animation: ping 1s cubic-bezier(0,0,0.2,1) infinite;
|
||||
}
|
||||
@keyframes ping {
|
||||
0% {
|
||||
opacity: 0.4;
|
||||
transform: scale(0.5);
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: scale(1.5);
|
||||
}
|
||||
}
|
||||
.animate-move-random-1 {
|
||||
animation: move-random-1 30s ease-in-out infinite;
|
||||
}
|
||||
.animate-move-random-2 {
|
||||
animation: move-random-2 60s ease-in-out infinite;
|
||||
}
|
||||
.animate-move-random-3 {
|
||||
animation: move-random-3 50s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes move-random-1 {
|
||||
0% {
|
||||
transform: translateX(0) translateY(0)
|
||||
}
|
||||
|
||||
33% {
|
||||
transform: translateX(30px) translateY(24px)
|
||||
}
|
||||
|
||||
66% {
|
||||
transform: translateX(60px) translateY(12px)
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateX(0) translateY(0)
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes move-random-2 {
|
||||
0% {
|
||||
transform: translateX(0) translateY(0)
|
||||
}
|
||||
|
||||
23% {
|
||||
transform: translateX(-20px) translateY(-36px)
|
||||
}
|
||||
|
||||
46% {
|
||||
transform: translateX(0) translateY(22px)
|
||||
}
|
||||
|
||||
75% {
|
||||
transform: translateX(30px) translateY(-12px)
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateX(0) translateY(0)
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes move-random-3 {
|
||||
0% {
|
||||
transform: translateX(0) translateY(0)
|
||||
}
|
||||
|
||||
10% {
|
||||
transform: translateX(-30px) translateY(-15px)
|
||||
}
|
||||
|
||||
30% {
|
||||
transform: translateX(-10px) translateY(26px)
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: translateX(48px) translateY(-28px)
|
||||
}
|
||||
|
||||
80% {
|
||||
transform: translateX(17px) translateY(10px)
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateX(0) translateY(0)
|
||||
}
|
||||
}
|
||||
.border-2 {
|
||||
border-style: var(--tw-border-style);
|
||||
border-width: 2px;
|
||||
}
|
||||
.border-white {
|
||||
border-color: var(--color-white);
|
||||
}
|
||||
.bg-gray-400 {
|
||||
background-color: var(--color-gray-400);
|
||||
}
|
||||
.bg-white\/90 {
|
||||
background-color: color-mix(in srgb, #fff 90%, transparent);
|
||||
@supports (color: color-mix(in lab, red, red)) {
|
||||
background-color: color-mix(in oklab, var(--color-white) 90%, transparent);
|
||||
}
|
||||
}
|
||||
.px-3 {
|
||||
padding-inline: calc(var(--spacing) * 3);
|
||||
}
|
||||
.py-1\.5 {
|
||||
padding-block: calc(var(--spacing) * 1.5);
|
||||
}
|
||||
.text-xs {
|
||||
font-size: var(--text-xs);
|
||||
line-height: var(--tw-leading, var(--text-xs--line-height));
|
||||
}
|
||||
.font-medium {
|
||||
--tw-font-weight: var(--font-weight-medium);
|
||||
font-weight: var(--font-weight-medium);
|
||||
}
|
||||
.text-gray-600 {
|
||||
color: var(--color-gray-600);
|
||||
}
|
||||
.text-white {
|
||||
color: var(--color-white);
|
||||
}
|
||||
.opacity-40 {
|
||||
opacity: 40%;
|
||||
}
|
||||
.shadow {
|
||||
--tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||
}
|
||||
.backdrop-blur {
|
||||
--tw-backdrop-blur: blur(8px);
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);
|
||||
backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);
|
||||
}
|
||||
.transition-all {
|
||||
transition-property: all;
|
||||
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
|
||||
transition-duration: var(--tw-duration, var(--default-transition-duration));
|
||||
}
|
||||
.duration-3000 {
|
||||
--tw-duration: 3000ms;
|
||||
transition-duration: 3000ms;
|
||||
}
|
||||
.ease-linear {
|
||||
--tw-ease: linear;
|
||||
transition-timing-function: linear;
|
||||
}
|
||||
.border-t {
|
||||
border-top-style: solid;
|
||||
border-top-width: 1px;
|
||||
}
|
||||
.border-l {
|
||||
border-left-style: solid;
|
||||
border-left-width: 1px;
|
||||
}
|
||||
.border-gray-300 {
|
||||
border-color: var(--bulma-grey-85);
|
||||
}
|
||||
</style>
|
||||
@@ -117,7 +117,6 @@
|
||||
weeks.value.map(v=>{
|
||||
v.dates = dates.filter(x=>x.week===v.week)
|
||||
})
|
||||
console.log('weeks.value', weeks.value)
|
||||
}
|
||||
function nextMonth() {
|
||||
month = month + 1
|
||||
|
||||
@@ -33,6 +33,32 @@ const inventoryHighlights = [
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<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" />
|
||||
</span>
|
||||
<span>Export</span>
|
||||
</button>
|
||||
<button class="button fs-14">
|
||||
<span class="icon">
|
||||
<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" />
|
||||
</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" />
|
||||
</span>
|
||||
<span>Điều chỉnh</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="fixed-grid has-2-cols-mobile has-4-cols">
|
||||
<div class="grid">
|
||||
<InventoryHighlightCard
|
||||
|
||||
@@ -13,7 +13,7 @@ const emit = defineEmits('unselect');
|
||||
<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;"
|
||||
style="z-index: 1; right: 0.5rem; top: 0.5rem;"
|
||||
>
|
||||
<span class="icon">
|
||||
<Icon name="material-symbols:close-rounded" :size="22" />
|
||||
|
||||
19
app/components/orders/OrderDeliveryTab.vue
Normal file
19
app/components/orders/OrderDeliveryTab.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
order: Object
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="is-flex is-flex-direction-column is-gap-2">
|
||||
<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 }}</p>
|
||||
</div>
|
||||
<div class="p-4 rounded-md has-background-grey-95">
|
||||
<p class="has-text-grey">Địa chỉ giao hàng</p>
|
||||
<p class="mt-1 has-text-grey-10">{{ order.customer__name }}</p>
|
||||
<p class="has-text-grey-10">{{ order.customer__phone }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
83
app/components/orders/OrderHistoryTab.vue
Normal file
83
app/components/orders/OrderHistoryTab.vue
Normal file
@@ -0,0 +1,83 @@
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
order: Object
|
||||
});
|
||||
|
||||
const { $dayjs } = useNuxtApp();
|
||||
|
||||
const historyItems = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Tạo đơn hàng',
|
||||
details: 'Đơn hàng được tạo',
|
||||
icon: 'material-symbols:info-outline-rounded',
|
||||
color: 'blue',
|
||||
time: '2026-02-11T08:51:04.587660+07:00'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Xác nhận',
|
||||
details: 'Đơn hàng được xác nhận',
|
||||
icon: 'material-symbols:check-circle-outline-rounded',
|
||||
color: 'green',
|
||||
time: '2026-02-11T10:30:04.587660+07:00'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Xuất kho',
|
||||
details: 'Hàng đã xuất kho',
|
||||
icon: 'material-symbols:check-circle-outline-rounded',
|
||||
color: 'green',
|
||||
time: '2026-02-11T11:02:04.587660+07:00'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'Đang giao',
|
||||
details: 'Tài xế đang giao hàng',
|
||||
icon: 'material-symbols:info-outline-rounded',
|
||||
color: 'blue',
|
||||
time: '2026-02-11T14:20:04.587660+07:00'
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'Giao hàng',
|
||||
details: 'Đã giao thành công',
|
||||
icon: 'material-symbols:check-circle-outline-rounded',
|
||||
color: 'green',
|
||||
time: '2026-02-11T17:38:04.587660+07:00'
|
||||
},
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="is-flex is-flex-direction-column is-gap-2">
|
||||
<div
|
||||
v-for="item in historyItems"
|
||||
:key="item.id"
|
||||
class="is-flex is-gap-2"
|
||||
>
|
||||
<div class="is-flex is-flex-direction-column is-align-items-center is-gap-0.5">
|
||||
<Icon
|
||||
:name="item.icon"
|
||||
:size="22"
|
||||
:class="`has-text-${item.color}-40`"
|
||||
/>
|
||||
<div class="is-flex-grow-1 has-background-grey-lighter rounded-full"
|
||||
style="width: 3px"
|
||||
></div>
|
||||
</div>
|
||||
<div class="is-flex-grow-1">
|
||||
<div class="is-flex is-gap-1 is-justify-content-space-between">
|
||||
<div>
|
||||
<p class="fs-15">{{ item.name }}</p>
|
||||
<p class="fs-13 has-text-grey">{{ item.details }}</p>
|
||||
</div>
|
||||
<p class="is-family-monospace fs-12 has-text-grey">{{ $dayjs(item.time).format('HH:mm') }}</p>
|
||||
</div>
|
||||
<hr class="mt-4 mb-0 has-background-grey-95" style="height: 2px" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
66
app/components/orders/OrderKanbanCard.vue
Normal file
66
app/components/orders/OrderKanbanCard.vue
Normal file
@@ -0,0 +1,66 @@
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
order: Object
|
||||
});
|
||||
|
||||
const { $dayjs, $shortenCurrency } = useNuxtApp();
|
||||
const emit = defineEmits(['selectOrder', 'unselect']);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
:class="[
|
||||
'card fs-14 is-clickable',
|
||||
`has-background-${order.status__color}-95`
|
||||
]"
|
||||
:style="{ border: `1px solid var(--bulma-${order.status__color}-60)` }"
|
||||
@click="selected ? emit('unselect') : emit('selectOrder', order.id)"
|
||||
>
|
||||
<div class="card-content p-4">
|
||||
<div class="mb-4 is-flex is-justify-content-space-between is-gap-1">
|
||||
<p class="fs-15 font-bold">{{ order.code }}</p>
|
||||
<span
|
||||
:class="['fs-13', `has-text-${order.payment_status__color}-40`]"
|
||||
>
|
||||
{{ order.payment_status__name }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="is-flex is-flex-direction-column is-gap-2">
|
||||
<!-- customer info -->
|
||||
<div>
|
||||
<p class="has-text-grey-10">{{ order.customer__name }}</p>
|
||||
<div class="has-text-grey fs-13 mt-1 is-flex is-gap-1 is-align-items-center">
|
||||
<Icon name="material-symbols:call-outline-rounded" />
|
||||
<p>{{ order.customer__phone }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- product info -->
|
||||
<div>
|
||||
<p class="fs-24 has-text-grey-10 font-bold">{{ $shortenCurrency(order.total) }}</p>
|
||||
<p class="fs-13 has-text-grey">{{ order.order__products.length }} sản phẩm</p>
|
||||
</div>
|
||||
<hr class="m-0" />
|
||||
<div class="is-flex is-flex-direction-column is-gap-0.5 fs-13 has-text-grey">
|
||||
<p class=" is-flex is-align-items-center is-gap-0.5">
|
||||
<Icon name="material-symbols:calendar-today-outline-rounded" :size="16" />
|
||||
<span>{{ $dayjs(order.create_time).format('L') }}</span>
|
||||
<span>•</span>
|
||||
<span>{{ $dayjs(order.create_time).format('HH:mm') }}</span>
|
||||
</p>
|
||||
<p>
|
||||
NV: <span>{{ order.employee__name }}</span>
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
v-if="order.status__name !== 'Hoàn thành'"
|
||||
:class="[
|
||||
'button fs-14 has-text-white',
|
||||
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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
25
app/components/orders/OrderPaymentTab.vue
Normal file
25
app/components/orders/OrderPaymentTab.vue
Normal file
@@ -0,0 +1,25 @@
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
order: Object
|
||||
});
|
||||
const { $numtoString } = useNuxtApp();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="is-flex is-gap-2">
|
||||
<div class="is-flex-grow-1 p-3 rounded-md has-background-grey-95">
|
||||
<p class="fs-13 has-text-grey">Tổng tiền</p>
|
||||
<p class="font-bold">{{ $numtoString(order.total, { hasUnit: true }) }}</p>
|
||||
</div>
|
||||
<div class="is-flex-grow-1 p-3 rounded-md has-background-success-95">
|
||||
<p class="fs-13 has-text-success-40">Đã thanh toán</p>
|
||||
<p class="font-bold has-text-success-30">0 đ</p>
|
||||
</div>
|
||||
</div>
|
||||
<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 }) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
34
app/components/orders/OrderProductTab.vue
Normal file
34
app/components/orders/OrderProductTab.vue
Normal file
@@ -0,0 +1,34 @@
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
order: Object
|
||||
});
|
||||
|
||||
const { $numtoString } = useNuxtApp();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="is-flex is-flex-direction-column is-gap-2">
|
||||
<div
|
||||
v-for="product in order.order__products"
|
||||
:key="product.id"
|
||||
class="p-3 has-background-grey-95 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>
|
||||
</div>
|
||||
<div class="is-flex is-gap-8 fs-13 has-text-grey-50 mt-1">
|
||||
<p>SL: {{ product.quantity }}</p>
|
||||
<p>Đơn giá: {{ $numtoString(product.unit_price, { hasUnit: true }) }}</p>
|
||||
<p>Giảm: {{ new Intl.NumberFormat("vi-VN", { style: "percent" }).format(product.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>
|
||||
</div>
|
||||
</template>
|
||||
17
app/components/orders/OrderReceiptTab.vue
Normal file
17
app/components/orders/OrderReceiptTab.vue
Normal file
@@ -0,0 +1,17 @@
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
order: Object
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="is-flex is-flex-direction-column is-gap-2 is-align-items-center">
|
||||
<Icon
|
||||
name="material-symbols:receipt-long-outline-rounded"
|
||||
:size="50"
|
||||
class="has-text-grey-70"
|
||||
/>
|
||||
<p>Chưa có hoá đơn</p>
|
||||
<button class="button is-primary has-background-purple">Tạo hoá đơn</button>
|
||||
</div>
|
||||
</template>
|
||||
@@ -59,7 +59,15 @@ const emit = defineEmits(['selectOrder', 'unselect'])
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<button class="button is-dark fs-13 rounded-full">Xác nhận</button>
|
||||
<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>
|
||||
|
||||
@@ -35,10 +35,40 @@ const highlights = [
|
||||
color: 'purple',
|
||||
unit: 'VNĐ'
|
||||
},
|
||||
]
|
||||
];
|
||||
|
||||
const viewModes = [
|
||||
{ name: 'list', icon: 'material-symbols:format-list-bulleted-rounded' },
|
||||
{ name: 'grid', icon: 'material-symbols:grid-view-outline-rounded' }
|
||||
];
|
||||
const viewMode = ref('list');
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<div class="content is-flex is-gap-2 is-justify-content-flex-end is-align-items-center">
|
||||
<div class="tabs is-toggle m-0">
|
||||
<ul class="is-flex-grow-0 ml-auto">
|
||||
<li
|
||||
v-for="mode in viewModes"
|
||||
:key="mode.name"
|
||||
:class="[mode.name === viewMode && 'is-active']"
|
||||
@click="viewMode = mode.name"
|
||||
>
|
||||
<a class="px-3 py-1">
|
||||
<span class="icon m-0">
|
||||
<Icon :name="mode.icon" :size="18" />
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<button class="button fs-14 is-primary">
|
||||
<span class="icon">
|
||||
<Icon :size="18" name="material-symbols:add-2-rounded" />
|
||||
</span>
|
||||
<span>Tạo đơn hàng</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="fixed-grid has-2-cols-mobile has-5-cols">
|
||||
<div class="grid">
|
||||
<OrderHighlightCard
|
||||
@@ -49,6 +79,13 @@ const highlights = [
|
||||
</div>
|
||||
</div>
|
||||
<OrderPipeline />
|
||||
<OrdersTable />
|
||||
<OrdersTable :viewMode="viewMode" />
|
||||
</div>
|
||||
</template>
|
||||
<style scoped>
|
||||
.tabs {
|
||||
--bulma-tabs-toggle-link-active-background-color: var(--bulma-link-90);
|
||||
--bulma-tabs-toggle-link-active-border-color: var(--bulma-link-90);
|
||||
--bulma-tabs-toggle-link-active-color: var(--bulma-link-40);
|
||||
}
|
||||
</style>
|
||||
|
||||
48
app/components/orders/OrdersKanban.vue
Normal file
48
app/components/orders/OrdersKanban.vue
Normal file
@@ -0,0 +1,48 @@
|
||||
<script setup>
|
||||
import OrderKanbanCard from '@/components/orders/OrderKanbanCard.vue';
|
||||
|
||||
const props = defineProps({
|
||||
orders: Array,
|
||||
statuses: Array,
|
||||
});
|
||||
|
||||
const emit = defineEmits(['selectOrder', 'unselect']);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="p-5 fixed-grid has-4-cols">
|
||||
<div class="grid">
|
||||
<div
|
||||
v-for="status in statuses"
|
||||
:key="status.id"
|
||||
class="card"
|
||||
style="border: none"
|
||||
>
|
||||
<div class="card-content p-0 is-clipped">
|
||||
<div :class="['p-4 is-flex is-justify-content-space-between is-align-items-center', `has-background-${status.color}-90`]">
|
||||
<p class="font-semibold has-text-grey-10">{{ status.name }}</p>
|
||||
<p class="px-2 py-1 font-semibold rounded-lg has-background-white"
|
||||
:style="{ border: `1px solid var(--bulma-${status.color}-60)`}"
|
||||
>
|
||||
{{ orders.filter(o => o.status === status.id).length }}
|
||||
</p>
|
||||
</div>
|
||||
<hr class="m-0 has-background-grey-80" />
|
||||
<div class="has-background-grey-95 p-4">
|
||||
<OrderKanbanCard
|
||||
v-if="orders.filter(o => o.status === status.id).length > 0"
|
||||
v-for="order in orders.filter(o => o.status === status.id)"
|
||||
:key="order.id"
|
||||
:order="order"
|
||||
@selectOrder="emit('selectOrder', order.id)"
|
||||
@unselect="emit('unselect')"
|
||||
/>
|
||||
<p v-else class="fs-13 has-text-centered has-text-grey">
|
||||
Không có đơn hàng
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -3,6 +3,10 @@ import OrderRow from '@/components/orders/OrderRow.vue';
|
||||
import SelectedOrder from '@/components/orders/SelectedOrder.vue';
|
||||
import { pull } from 'es-toolkit';
|
||||
|
||||
const props = defineProps({
|
||||
viewMode: String
|
||||
});
|
||||
|
||||
const { $dayjs } = useNuxtApp();
|
||||
|
||||
const orders = [
|
||||
@@ -480,7 +484,7 @@ function toggleStatus(id) {
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<div class="card">
|
||||
<div class="card is-clipped">
|
||||
<div class="card-content">
|
||||
<div class="is-flex is-gap-2 is-align-items-center">
|
||||
<div class="field is-flex-grow-1 m-0">
|
||||
@@ -556,8 +560,9 @@ function toggleStatus(id) {
|
||||
<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">
|
||||
<div class="card is-clipped">
|
||||
<div class="card-content p-0">
|
||||
<template v-if="viewMode === 'list'">
|
||||
<p class="p-5 fs-17 font-semibold is-flex is-align-items-center is-gap-1">
|
||||
<Icon name="material-symbols:list-alt-outline-rounded" :size="22" />
|
||||
<span>Danh sách đơn hàng ({{ filteredOrders.length }})</span>
|
||||
@@ -587,6 +592,16 @@ function toggleStatus(id) {
|
||||
/>
|
||||
</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>
|
||||
|
||||
@@ -1,10 +1,46 @@
|
||||
<script setup>
|
||||
import OrderDeliveryTab from '@/components/orders/OrderDeliveryTab.vue';
|
||||
import OrderHistoryTab from '@/components/orders/OrderHistoryTab.vue';
|
||||
import OrderPaymentTab from '@/components/orders/OrderPaymentTab.vue';
|
||||
import OrderProductTab from '@/components/orders/OrderProductTab.vue';
|
||||
import OrderReceiptTab from '@/components/orders/OrderReceiptTab.vue';
|
||||
|
||||
const props = defineProps({
|
||||
order: Object
|
||||
});
|
||||
|
||||
const { $dayjs, $numtoString } = useNuxtApp();
|
||||
const emit = defineEmits(['unselect']);
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
name: 'Chi tiết đơn',
|
||||
heading: 'Chi tiết sản phẩm',
|
||||
icon: 'material-symbols:deployed-code-outline'
|
||||
},
|
||||
{
|
||||
name: 'Giao hàng',
|
||||
heading: 'Thông tin giao hàng',
|
||||
icon: 'material-symbols:delivery-truck-speed-outline-rounded'
|
||||
},
|
||||
{
|
||||
name: 'Hoá đơn',
|
||||
heading: 'Hoá đơn',
|
||||
icon: 'material-symbols:receipt-long-outline-rounded'
|
||||
},
|
||||
{
|
||||
name: 'Thanh toán',
|
||||
heading: 'Thanh toán',
|
||||
icon: 'material-symbols:credit-card-outline'
|
||||
},
|
||||
{
|
||||
name: 'Lịch sử',
|
||||
heading: 'Lịch sử đơn hàng',
|
||||
icon: 'material-symbols:history-rounded'
|
||||
},
|
||||
];
|
||||
|
||||
const activeTab = ref(tabs[0]);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -55,35 +91,32 @@ const emit = defineEmits(['unselect']);
|
||||
<button class="button fs-14 is-flex-grow-1">Ghi thanh toán</button>
|
||||
</div>
|
||||
<hr class="m-0" />
|
||||
<div class="tabs is-toggle fs-13">
|
||||
<div class="tabs is-toggle m-0 fs-13">
|
||||
<ul>
|
||||
<li class="is-active">
|
||||
<a>
|
||||
<span>Chi tiết đơn</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a>
|
||||
<span>Giao hàng</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a>
|
||||
<span>Hoá đơn</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a>
|
||||
<span>Thanh toán</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a>
|
||||
<span>Lịch sử</span>
|
||||
</a>
|
||||
<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">
|
||||
<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'" :order="order" />
|
||||
<OrderDeliveryTab v-else-if="activeTab.name === 'Giao hàng'" :order="order" />
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
<template>
|
||||
<ClientOnly>
|
||||
<TopMenu @changetab="changeTab" />
|
||||
</ClientOnly>
|
||||
<ClientOnly>
|
||||
<div class="container blockdiv has-text-text-20">
|
||||
<div class="fs-17 font-semibold mb-2 is-flex is-align-items-center is-gap-1" v-if="tab">
|
||||
<template v-if="subtab">
|
||||
@@ -10,11 +8,16 @@
|
||||
<SvgIcon class="mx-2" v-bind="{ name: 'right.svg', size: 17, type: 'has-text-black' }"></SvgIcon>
|
||||
<span>{{ subtab[$store.lang] }}</span>
|
||||
</template>
|
||||
<span v-else>{{ tab[$store.lang] }}</span>
|
||||
<div v-else>
|
||||
<div class="is-flex is-gap-1 is-align-items-center mb-1">
|
||||
<p>{{ tab[$store.lang] }}</p>
|
||||
<button class="button is-primary is-light rounded-full p-1" @click="refresh()">
|
||||
<Icon name="material-symbols:refresh-rounded" :size="24" />
|
||||
<Icon name="material-symbols:refresh-rounded" :size="20" />
|
||||
</button>
|
||||
</div>
|
||||
<p class="has-text-grey fs-13 font-normal">Cập nhật: 16:25:54</p>
|
||||
</div>
|
||||
</div>
|
||||
<KeepAlive>
|
||||
<component :is="componentMap[vbind.component]" v-bind="vbind" :key="componentKey" v-if="componentKey" />
|
||||
</KeepAlive>
|
||||
|
||||
@@ -11635,7 +11635,7 @@ a.navbar-item.is-active, a.navbar-item.is-selected,
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1023px) {
|
||||
@media screen and (max-width: 767px) {
|
||||
.navbar > .container {
|
||||
display: block;
|
||||
}
|
||||
@@ -11684,7 +11684,7 @@ a.navbar-item.is-active, a.navbar-item.is-selected,
|
||||
padding-bottom: var(--bulma-navbar-height);
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 1024px) {
|
||||
@media screen and (min-width: 768px) {
|
||||
.navbar,
|
||||
.navbar-menu,
|
||||
.navbar-start,
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -13,6 +13,7 @@ $grey: #767676;
|
||||
@use "bulma/sass" with (
|
||||
$family-primary: string.unquote("'Inter', 'SF Pro', 'Helvetica', 'Arial', sans-serif"),
|
||||
$family-monospace: string.unquote("'Roboto Mono', monospace"),
|
||||
$navbar-breakpoint: 768px,
|
||||
$primary: $blue,
|
||||
$link: $blue,
|
||||
$info: $cyan,
|
||||
|
||||
Reference in New Issue
Block a user