feat: build UI
This commit is contained in:
+5
-259
@@ -1,11 +1,13 @@
|
||||
@use "sass:color";
|
||||
@use "bulma/sass/utilities/initial-variables.scss" as *;
|
||||
@use "bulma/sass/utilities/derived-variables.scss" as *;
|
||||
@use "bulma/sass/utilities/mixins.scss" as *;
|
||||
|
||||
@import url('https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900');
|
||||
@use "bulma/sass/components/card.scss" as *;
|
||||
@use "utils.scss";
|
||||
@use "overrides-components.scss";
|
||||
|
||||
:root {
|
||||
--bulma-family-primary: 'Inter', 'SF Pro', 'Helvetica', 'Arial', sans-serif;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
@@ -124,81 +126,15 @@ $size: (
|
||||
// 4. CUSTOM CLASSES
|
||||
// ==========================================
|
||||
|
||||
.fullheight { height: 100vh; }
|
||||
|
||||
.textsize {
|
||||
@include mobile { font-size: 18px; }
|
||||
}
|
||||
|
||||
.header-logo {
|
||||
background: url('/logo_dev.png') no-repeat center center;
|
||||
background-size: 40px;
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.border-bottom { border-bottom: 1px solid color.change($black-pure, $alpha: 0.15) }
|
||||
|
||||
.carousel-height {
|
||||
width: 100%;
|
||||
height: 80vh;
|
||||
@include mobile { height: 110vh; }
|
||||
}
|
||||
|
||||
// Mobile Spacing Utilities
|
||||
.mobile-mt20 { @include mobile { margin-top: 20px; } }
|
||||
.mobile-px10 { @include mobile { padding-left: 10px; padding-right: 10px; } }
|
||||
.mobile-pt10 { @include mobile { padding-top: 10px; } }
|
||||
.mobile-pt80 { padding-top: 120px; @include mobile { padding-top: 80px; } }
|
||||
|
||||
.fullhd-pt30 {
|
||||
padding-top: 30px;
|
||||
@include until($fullhd) { padding-top: 0px; }
|
||||
}
|
||||
|
||||
.media-width {
|
||||
width: 120px !important;
|
||||
@include mobile { width: 112px !important; }
|
||||
}
|
||||
|
||||
.hideon-mobile { @include mobile { display: none; } }
|
||||
|
||||
// Typography Classes
|
||||
.maintext {
|
||||
margin-top: 20px;
|
||||
font-size: 40px;
|
||||
line-height: 3rem;
|
||||
font-weight: 600;
|
||||
color: $blue-dianne;
|
||||
@include mobile { font-size: 34px; }
|
||||
}
|
||||
|
||||
.subtext {
|
||||
margin-top: 30px;
|
||||
font-size: 1.2rem;
|
||||
line-height: 2rem;
|
||||
color: $cutty-sark;
|
||||
@include mobile { line-height: 1.8rem; }
|
||||
}
|
||||
|
||||
.dotslide {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.activetab {
|
||||
border-radius: 8px;
|
||||
color: $white-pure;
|
||||
background-color: $blue-dianne;
|
||||
}
|
||||
|
||||
// Block Layout
|
||||
.blockdiv {
|
||||
max-width: 1900px !important;
|
||||
background-color: $white-pure;
|
||||
padding: 60px 15px 40px 15px;
|
||||
|
||||
@include until($desktop) { padding: 65px 20px 30px 20px; }
|
||||
@@ -213,31 +149,6 @@ $size: (
|
||||
}
|
||||
}
|
||||
|
||||
.padding-text {
|
||||
padding-left: 15%; padding-right: 5%;
|
||||
@include until($desktop) { padding-left: 0; padding-right: 0; }
|
||||
@include until($fullhd) { padding-left: 0; padding-right: 0; }
|
||||
}
|
||||
|
||||
.padding-image {
|
||||
padding-left: 5%; padding-right: 15%;
|
||||
@include until($fullhd) { padding-left: 0; padding-right: 0; }
|
||||
@include until($desktop) { padding-left: 15%; padding-right: 15%; }
|
||||
@include mobile { padding-left: 0; padding-right: 0; }
|
||||
}
|
||||
|
||||
.imgcontainer {
|
||||
position: relative;
|
||||
width: 100% !important;
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
.centered {
|
||||
position: absolute;
|
||||
top: 80%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
// Tooltip Styles
|
||||
.tooltip {
|
||||
position: relative;
|
||||
@@ -262,8 +173,6 @@ $size: (
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.to-left { right: 30px; }
|
||||
|
||||
@mixin tooltipshow() {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
@@ -277,166 +186,3 @@ $size: (
|
||||
|
||||
.tooltip:hover .tooltiptext { @include tooltipshow() }
|
||||
.tooltip:hover .tooltiptext .to-left { @include tooltipshow() }
|
||||
|
||||
// Dot Indicators
|
||||
@mixin dot($background) {
|
||||
height: 22px;
|
||||
width: 22px;
|
||||
text-align: center;
|
||||
color: $white-pure;
|
||||
font-weight: bold;
|
||||
background-color: $background;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
font-size: 15px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
@each $name, $hex in $color {
|
||||
.dot-#{$name} {
|
||||
@include dot($hex);
|
||||
}
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 5. HELPER CLASSES GENERATOR
|
||||
// ==========================================
|
||||
@each $name, $hex in $color {
|
||||
.bg-#{$name} { background-color: $hex !important; }
|
||||
.text-#{$name} { color: $hex !important; }
|
||||
.border-#{$name} { border-color: $hex !important; }
|
||||
.icon-#{$name} { color: $hex !important; }
|
||||
|
||||
.icon-bg-#{$name} {
|
||||
background-color: $hex !important;
|
||||
color: if(color.channel($hex, "lightness", $space: hsl) > 70, $blue-dianne, $white-pure) !important;
|
||||
padding: 0.5rem;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 6. BULMA OVERRIDES
|
||||
// ==========================================
|
||||
|
||||
// Backgrounds
|
||||
.has-background-primary { background-color: $primary-color !important; }
|
||||
.has-background-secondary { background-color: $secondary-color !important; }
|
||||
.has-background-info { background-color: $info-color !important; }
|
||||
.has-background-success { background-color: $success-color !important; }
|
||||
.has-background-warning { background-color: $warning-color !important; }
|
||||
.has-background-danger { background-color: $danger-color !important; }
|
||||
.has-background-light { background-color: $light-color !important; }
|
||||
.has-background-dark { background-color: $dark-color !important; }
|
||||
.has-background-white { background-color: $white-pure !important; }
|
||||
|
||||
// Text Colors
|
||||
.has-text-primary { color: #086e71 !important; }
|
||||
.has-text-secondary { color: $secondary-color !important; }
|
||||
.has-text-info { color: $info-color !important; }
|
||||
.has-text-success { color: $success-color !important; }
|
||||
.has-text-warning { color: $warning-color !important; }
|
||||
.has-text-danger { color: $danger-color !important; }
|
||||
.has-text-light { color: $accent-color !important; }
|
||||
.has-text-dark { color: $dark-color !important; }
|
||||
|
||||
// Button/Element States (is-*)
|
||||
.is-primary {
|
||||
background-color: $primary-color !important;
|
||||
border-color: transparent !important;
|
||||
color: $white-pure !important;
|
||||
}
|
||||
|
||||
.is-secondary {
|
||||
background-color: $secondary-color !important;
|
||||
border-color: transparent !important;
|
||||
color: $white-pure !important;
|
||||
}
|
||||
|
||||
.is-link {
|
||||
background-color: $link-color !important;
|
||||
border-color: transparent !important;
|
||||
color: $white-pure !important;
|
||||
}
|
||||
|
||||
.is-info {
|
||||
background-color: $info-color !important;
|
||||
border-color: transparent !important;
|
||||
color: $white-pure !important;
|
||||
}
|
||||
|
||||
.is-success {
|
||||
background-color: $success-color !important;
|
||||
border-color: transparent !important;
|
||||
color: $white-pure !important;
|
||||
}
|
||||
|
||||
.is-warning {
|
||||
background-color: $warning-color !important;
|
||||
border-color: transparent !important;
|
||||
color: $white-pure !important;
|
||||
}
|
||||
|
||||
.is-danger {
|
||||
background-color: $danger-color !important;
|
||||
border-color: transparent !important;
|
||||
color: $white-pure !important;
|
||||
}
|
||||
|
||||
.is-light {
|
||||
background-color: $light-color !important;
|
||||
border-color: transparent !important;
|
||||
color: $blue-dianne !important;
|
||||
}
|
||||
|
||||
.is-dark {
|
||||
background-color: $dark-color !important;
|
||||
border-color: transparent !important;
|
||||
color: $white-pure !important;
|
||||
}
|
||||
|
||||
// Outlined Variants
|
||||
.is-primary.is-outlined {
|
||||
background-color: transparent !important;
|
||||
border-color: $primary-color !important;
|
||||
color: $primary-color !important;
|
||||
}
|
||||
|
||||
.is-link.is-outlined {
|
||||
background-color: transparent !important;
|
||||
border-color: $link-color !important;
|
||||
color: $link-color !important;
|
||||
}
|
||||
|
||||
.is-info.is-outlined {
|
||||
background-color: transparent !important;
|
||||
border-color: $info-color !important;
|
||||
color: $info-color !important;
|
||||
}
|
||||
|
||||
.is-success.is-outlined {
|
||||
background-color: transparent !important;
|
||||
border-color: $success-color !important;
|
||||
color: $success-color !important;
|
||||
}
|
||||
|
||||
.is-warning.is-outlined {
|
||||
background-color: transparent !important;
|
||||
border-color: $warning-color !important;
|
||||
color: $warning-color !important;
|
||||
}
|
||||
|
||||
.is-primary.is-light {
|
||||
background-color: rgba($primary-color, 0.1) !important;
|
||||
color: $primary-color !important;
|
||||
}
|
||||
|
||||
.is-info.is-light {
|
||||
background-color: rgba($info-color, 0.2) !important;
|
||||
color: color.adjust($info-color, $lightness: -10%) !important;
|
||||
}
|
||||
|
||||
.is-success.is-light {
|
||||
background-color: rgba($success-color, 0.1) !important;
|
||||
color: $success-color !important;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
@use "bulma/sass/utilities/initial-variables.scss" as *;
|
||||
|
||||
.card {
|
||||
--bulma-card-shadow: none;
|
||||
border: 1px solid $grey-lighter;
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
@use "sass:list";
|
||||
|
||||
.font-thin {
|
||||
font-weight: 100;
|
||||
}
|
||||
.font-extralight {
|
||||
font-weight: 200;
|
||||
}
|
||||
.font-light {
|
||||
font-weight: 300;
|
||||
}
|
||||
.font-normal {
|
||||
font-weight: 400;
|
||||
}
|
||||
.font-medium {
|
||||
font-weight: 500;
|
||||
}
|
||||
.font-semibold {
|
||||
font-weight: 600;
|
||||
}
|
||||
.font-bold {
|
||||
font-weight: 700;
|
||||
}
|
||||
.font-extrabold {
|
||||
font-weight: 800;
|
||||
}
|
||||
.font-black {
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.rounded-xs {
|
||||
border-radius: 0.125rem;
|
||||
}
|
||||
.rounded-sm {
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
.rounded-md {
|
||||
border-radius: 0.375rem;
|
||||
}
|
||||
.rounded-lg {
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
.rounded-xl {
|
||||
border-radius: 0.75rem;
|
||||
}
|
||||
.rounded-2xl {
|
||||
border-radius: 1rem;
|
||||
}
|
||||
.rounded-3xl {
|
||||
border-radius: 1.5rem;
|
||||
}
|
||||
.rounded-4xl {
|
||||
border-radius: 2rem;
|
||||
}
|
||||
.rounded-none {
|
||||
border-radius: 0;
|
||||
}
|
||||
.rounded-full {
|
||||
border-radius: calc(infinity * 1px);
|
||||
}
|
||||
|
||||
$base: 0.25rem;
|
||||
|
||||
@function spacing($step) {
|
||||
@return $step * $base;
|
||||
}
|
||||
|
||||
$spacing-types: (
|
||||
"p": "padding",
|
||||
"m": "margin",
|
||||
);
|
||||
|
||||
$spacing-variants: (
|
||||
"": (""),
|
||||
"x": ("-left", "-right"),
|
||||
"y": ("-top", "-bottom"),
|
||||
"t": ("-top"),
|
||||
"b": ("-bottom"),
|
||||
"l": ("-left"),
|
||||
"r": ("-right"),
|
||||
);
|
||||
|
||||
@each $type-prefix, $type in $spacing-types {
|
||||
@each $dir-suffix, $sides in $spacing-variants {
|
||||
@for $i from 0 through 48 {
|
||||
// Whole step: p-0, p-1, p-2 ...
|
||||
.#{$type-prefix}#{$dir-suffix}-#{$i} {
|
||||
@each $side in $sides {
|
||||
#{$type}#{$side}: spacing($i);
|
||||
}
|
||||
}
|
||||
|
||||
// Half step: p-0\.5, p-1\.5, p-2\.5 ...
|
||||
// Stop at 47.5 — 48.5 would exceed the scale
|
||||
@if $i < 48 {
|
||||
.#{$type-prefix}#{$dir-suffix}-#{$i}\.5 {
|
||||
@each $side in $sides {
|
||||
#{$type}#{$side}: spacing($i + 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ─── CSS custom properties ─────────────────────────────────────────────────
|
||||
:root {
|
||||
--spacing: 0.25rem;
|
||||
--container-3xs: 16rem;
|
||||
--container-2xs: 18rem;
|
||||
--container-xs: 20rem;
|
||||
--container-sm: 24rem;
|
||||
--container-md: 28rem;
|
||||
--container-lg: 32rem;
|
||||
--container-xl: 36rem;
|
||||
--container-2xl: 42rem;
|
||||
--container-3xl: 48rem;
|
||||
--container-4xl: 56rem;
|
||||
--container-5xl: 64rem;
|
||||
--container-6xl: 72rem;
|
||||
--container-7xl: 80rem;
|
||||
}
|
||||
|
||||
// ─── Shared mixin ──────────────────────────────────────────────────────────
|
||||
@mixin set-props($props, $value) {
|
||||
@each $prop in $props {
|
||||
#{$prop}: $value;
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Class types ───────────────────────────────────────────────────────────
|
||||
$class-types: (
|
||||
"w": (width),
|
||||
"h": (height),
|
||||
"size": (width, height),
|
||||
);
|
||||
|
||||
// ─── Numeric: w-0 → w-48, h-0 → h-48, size-0 → size-48 ───────────────────
|
||||
@each $prefix, $props in $class-types {
|
||||
@for $i from 0 through 48 {
|
||||
.#{$prefix}-#{$i} {
|
||||
@include set-props($props, calc(var(--spacing) * #{$i}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Fractions ─────────────────────────────────────────────────────────────
|
||||
$fractions: (
|
||||
"1\\/2": (1, 2),
|
||||
"1\\/3": (1, 3),
|
||||
"2\\/3": (2, 3),
|
||||
"1\\/4": (1, 4),
|
||||
"2\\/4": (2, 4),
|
||||
"3\\/4": (3, 4),
|
||||
"1\\/5": (1, 5),
|
||||
"2\\/5": (2, 5),
|
||||
"3\\/5": (3, 5),
|
||||
"4\\/5": (4, 5),
|
||||
"1\\/6": (1, 6),
|
||||
"2\\/6": (2, 6),
|
||||
"3\\/6": (3, 6),
|
||||
"4\\/6": (4, 6),
|
||||
"5\\/6": (5, 6),
|
||||
"1\\/12": (1, 12),
|
||||
"2\\/12": (2, 12),
|
||||
"3\\/12": (3, 12),
|
||||
"4\\/12": (4, 12),
|
||||
"5\\/12": (5, 12),
|
||||
"6\\/12": (6, 12),
|
||||
"7\\/12": (7, 12),
|
||||
"8\\/12": (8, 12),
|
||||
"9\\/12": (9, 12),
|
||||
"10\\/12": (10, 12),
|
||||
"11\\/12": (11, 12),
|
||||
);
|
||||
|
||||
@each $prefix, $props in $class-types {
|
||||
@each $name, $pair in $fractions {
|
||||
$num: list.nth($pair, 1);
|
||||
$den: list.nth($pair, 2);
|
||||
.#{$prefix}-#{$name} {
|
||||
@include set-props($props, calc(#{$num} / #{$den} * 100%));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Container sizes (w- only) ─────────────────────────────────────────────
|
||||
$containers: (
|
||||
"3xs", "2xs", "xs", "sm", "md", "lg", "xl",
|
||||
"2xl", "3xl", "4xl", "5xl", "6xl", "7xl"
|
||||
);
|
||||
|
||||
@each $name in $containers {
|
||||
.w-#{$name} { width: var(--container-#{$name}); }
|
||||
}
|
||||
|
||||
// ─── Shared keywords (auto, px, full, min, max, fit) ───────────────────────
|
||||
// These are identical in value across w-, h-, and size-
|
||||
$shared-keywords: (
|
||||
"auto": auto,
|
||||
"px": 1px,
|
||||
"full": 100%,
|
||||
"min": min-content,
|
||||
"max": max-content,
|
||||
"fit": fit-content,
|
||||
);
|
||||
|
||||
@each $prefix, $props in $class-types {
|
||||
@each $name, $value in $shared-keywords {
|
||||
.#{$prefix}-#{$name} {
|
||||
@include set-props($props, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Viewport keywords ─────────────────────────────────────────────────────
|
||||
// dvw/dvh/lvw/lvh/svw/svh apply equally to w-, h-, and size-
|
||||
$viewport-keywords: (
|
||||
"dvw": 100dvw,
|
||||
"dvh": 100dvh,
|
||||
"lvw": 100lvw,
|
||||
"lvh": 100lvh,
|
||||
"svw": 100svw,
|
||||
"svh": 100svh,
|
||||
);
|
||||
|
||||
@each $prefix, $props in $class-types {
|
||||
@each $name, $value in $viewport-keywords {
|
||||
.#{$prefix}-#{$name} {
|
||||
@include set-props($props, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.w-screen { width: 100vw; }
|
||||
.h-screen { height: 100vh; }
|
||||
+25
-16
@@ -1,11 +1,20 @@
|
||||
<template>
|
||||
<nav class="navbar is-fixed-top has-shadow px-3" role="navigation">
|
||||
<div class="navbar-brand mr-5">
|
||||
<span class="navbar-item">
|
||||
<SvgIcon v-bind="{ name: 'dot.svg', size: 18, type: 'primary' }"</SvgIcon>
|
||||
<span class="fsb-20 has-text-primary">{{$dayjs().format('DD/MM')}}</span>
|
||||
<span class="navbar-item is-gap-1">
|
||||
<div style="width: 16px; height: 16px" class="has-background-primary rounded-full"></div>
|
||||
<span class="fs-17 font-semibold has-text-primary">{{$dayjs().format('DD/MM')}}</span>
|
||||
</span>
|
||||
<a class="navbar-item header-logo" @click="changeTab(leftmenu[0])"></a>
|
||||
<a
|
||||
class="navbar-item p-0 has-text-primary"
|
||||
@click="changeTab(leftmenu[0])"
|
||||
>
|
||||
<svg
|
||||
style="max-height: none; width: 44px"
|
||||
width="80" height="80" viewBox="0 0 80 80" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="currentColor" d="M40 8C57.6731 8 72 22.3269 72 40C72 57.6731 57.6731 72 40 72C22.3269 72 8 57.6731 8 40C8 22.3269 22.3269 8 40 8ZM15.7285 31.5762V49.2266H21.9854C23.778 49.2266 25.3185 48.8727 26.6055 48.166C27.898 47.4593 28.8887 46.4453 29.5781 45.124C30.2733 43.8025 30.6211 42.2224 30.6211 40.3838C30.6211 38.5511 30.2733 36.9768 29.5781 35.6611C28.8887 34.3455 27.9033 33.3367 26.6221 32.6357C25.3409 31.9292 23.8123 31.5762 22.0371 31.5762H15.7285ZM33.3857 49.2266H45.3135V46.1494H37.1172V41.9355H44.667V38.8584H37.1172V34.6533H45.2793V31.5762H33.3857V49.2266ZM53.3818 49.2266H58.1914L64.2754 31.5762H60.1387L55.8643 44.9863H55.7002L51.4346 31.5762H47.2891L53.3818 49.2266ZM21.8389 34.7734C22.942 34.7734 23.8704 34.9687 24.623 35.3594C25.3756 35.75 25.9411 36.3593 26.3203 37.1865C26.7052 38.0138 26.8984 39.0797 26.8984 40.3838C26.8984 41.6995 26.7053 42.7743 26.3203 43.6074C25.9411 44.4346 25.3726 45.047 24.6143 45.4434C23.8617 45.8339 22.9339 46.0292 21.8311 46.0293H19.4609V34.7734H21.8389Z" />
|
||||
</svg>
|
||||
</a>
|
||||
<a
|
||||
role="button"
|
||||
class="navbar-burger"
|
||||
@@ -22,23 +31,23 @@
|
||||
</a>
|
||||
</div>
|
||||
<div class="navbar-menu" id="navMenu">
|
||||
<div class="navbar-start" style="min-width: 650px;">
|
||||
<div class="navbar-start is-gap-1 is-align-items-center" style="min-width: 650px;">
|
||||
<template v-for="(v, i) in leftmenu" :key="i" :id="v.code">
|
||||
<a class="navbar-item px-2" v-if="!v.submenu" @click="changeTab(v)">
|
||||
<span
|
||||
:class="`fsb-17 ${currentTab.code === v.code ? 'activetab' : ''}`"
|
||||
style="padding: 3px 4px"
|
||||
>
|
||||
<a class="navbar-item rounded-lg is-clipped p-0" v-if="!v.submenu" @click="changeTab(v)">
|
||||
<span :class="[
|
||||
'px-3 py-1.5 fs-14 font-medium',
|
||||
currentTab.code === v.code ? 'has-text-primary-50 has-background-primary-95' : 'has-text-grey-30'
|
||||
]">
|
||||
{{ v[lang] }}
|
||||
</span>
|
||||
</a>
|
||||
<div class="navbar-item has-dropdown is-hoverable" v-else>
|
||||
<a class="navbar-item px-2" @click="changeTab(v)">
|
||||
<span
|
||||
:class="`icon-text ${currentTab.code === v.code ? 'activetab' : ''}`"
|
||||
style="padding: 3px 4px"
|
||||
>
|
||||
<span class="fsb-16">{{ v[lang] }}</span>
|
||||
<span :class="[
|
||||
'px-3 py-1 font-medium',
|
||||
currentTab.code === v.code ? 'has-text-primary-bold has-background-primary-soft' : 'has-text-grey-30'
|
||||
]">
|
||||
<span>{{ v[lang] }}</span>
|
||||
<SvgIcon
|
||||
style="padding-top: 5px"
|
||||
v-bind="{ name: 'down2.svg', type: currentTab.code === v.code ? 'white' : 'dark', size: 15 }"
|
||||
@@ -48,7 +57,7 @@
|
||||
</a>
|
||||
<div class="navbar-dropdown has-background-light">
|
||||
<a
|
||||
class="navbar-item has-background-light fs-15 has-text-black py-1 border-bottom"
|
||||
class="navbar-item has-background-light py-1 border-bottom"
|
||||
v-for="x in v.submenu"
|
||||
@click="changeTab(v, x)"
|
||||
>
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<template>
|
||||
<div
|
||||
class="fs-13 font-semibold mx-0 px-0 is-flex is-justify-content-center is-align-items-center is-flex-shrink-0 rounded-full size-10"
|
||||
style="border: 1px solid var(--bulma-grey-80)"
|
||||
:style="image && 'border: none'">
|
||||
<div>
|
||||
<span>{{text}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: ['text', 'image', 'type', 'size']
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.cbox {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: var(--grey-100);
|
||||
border: 1px solid hsl(0, 0%, 85%);
|
||||
border-radius: 50%;
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +1,90 @@
|
||||
<script setup>
|
||||
import DashboardHighlightCard from '@/components/dashboard/DashboardHighlightCard.vue';
|
||||
import Delivery from '@/components/dashboard/Delivery.vue';
|
||||
import OrderStatus from '@/components/dashboard/OrderStatus.vue';
|
||||
import RevenueChart from '@/components/dashboard/RevenueChart.vue';
|
||||
import TopCustomers from '@/components/dashboard/TopCustomers.vue';
|
||||
import TopProducts from '@/components/dashboard/TopProducts.vue';
|
||||
import Warnings from '@/components/dashboard/Warnings.vue';
|
||||
|
||||
const highlights = [
|
||||
{
|
||||
name: 'Doanh thu hôm nay',
|
||||
value: '72.5M',
|
||||
color: 'blue',
|
||||
icon: 'material-symbols:attach-money-rounded',
|
||||
subheader: {
|
||||
value: '+12.5%',
|
||||
fluctuation: 'up',
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Số đơn hàng',
|
||||
value: '73',
|
||||
color: 'purple',
|
||||
icon: 'material-symbols:shopping-cart-outline-rounded',
|
||||
subheader: {
|
||||
value: '+8 đơn',
|
||||
fluctuation: 'up',
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Đơn đang giao',
|
||||
value: '8',
|
||||
color: 'orange',
|
||||
icon: 'material-symbols:delivery-truck-speed-outline-rounded',
|
||||
},
|
||||
{
|
||||
name: 'Đơn hoàn thành',
|
||||
value: '38',
|
||||
color: 'green',
|
||||
icon: 'material-symbols:check-circle-outline-rounded',
|
||||
},
|
||||
{
|
||||
name: 'Công nợ phải thu',
|
||||
value: '245M',
|
||||
color: 'red',
|
||||
icon: 'material-symbols:universal-currency-alt-outline-rounded',
|
||||
subheader: {
|
||||
value: '+15M',
|
||||
fluctuation: 'down',
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Tồn kho',
|
||||
value: '1,250',
|
||||
color: 'cyan',
|
||||
icon: 'material-symbols:box-outline-rounded',
|
||||
subheader: {
|
||||
value: '-45 SP',
|
||||
fluctuation: 'down',
|
||||
}
|
||||
},
|
||||
]
|
||||
</script>
|
||||
<template>
|
||||
Dashboard
|
||||
<div>
|
||||
<div class="fixed-grid has-2-cols has-3-cols-tablet has-6-cols-desktop">
|
||||
<div class="grid">
|
||||
<DashboardHighlightCard
|
||||
v-for="highlight in highlights"
|
||||
v-bind="highlight"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fixed-grid has-3-cols">
|
||||
<div class="grid">
|
||||
<div class="cell is-col-span-2">
|
||||
<RevenueChart />
|
||||
</div>
|
||||
<div class="cell">
|
||||
<TopCustomers />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<TopProducts />
|
||||
<OrderStatus />
|
||||
<Delivery />
|
||||
<Warnings />
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,41 @@
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
name: String,
|
||||
value: String,
|
||||
color: String,
|
||||
icon: String,
|
||||
subheader: Object
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<div class="cell">
|
||||
<div class="card h-full">
|
||||
<div class="card-content is-flex is-gap-0.5 is-justify-content-space-between">
|
||||
<div>
|
||||
<p class="fs-14 has-text-grey mb-1">{{ name }}</p>
|
||||
<p class="fsb-26 mb-1 has-text-black">{{ value }}</p>
|
||||
<div v-if="subheader"
|
||||
:class="[
|
||||
'is-flex is-gap-0.5 is-align-items-center',
|
||||
subheader.fluctuation === 'up' ? 'has-text-green-40' : 'has-text-red-40'
|
||||
]"
|
||||
>
|
||||
<Icon
|
||||
:name="subheader.fluctuation === 'up' ? 'material-symbols:arrow-upward-rounded' :'material-symbols:arrow-downward-rounded'"
|
||||
color="inherit"
|
||||
/>
|
||||
<p class="fs-14">{{ subheader.value }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
:class="[
|
||||
'rounded-lg size-12 is-flex-shrink-0 is-flex is-justify-content-center is-align-items-center',
|
||||
`has-background-${color}-soft has-text-${color}-40`
|
||||
]"
|
||||
">
|
||||
<Icon :name="icon" :size="28" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,53 @@
|
||||
<script setup>
|
||||
import Driver from '@/components/dashboard/Driver.vue';
|
||||
|
||||
const drivers = [
|
||||
{
|
||||
name: 'Nguyễn Văn A',
|
||||
status: 'Đang giao',
|
||||
deliveries: 3,
|
||||
deliveries_completed: 2,
|
||||
},
|
||||
{
|
||||
name: 'Trần Văn B',
|
||||
status: 'Đang giao',
|
||||
deliveries: 2,
|
||||
deliveries_completed: 1,
|
||||
},
|
||||
{
|
||||
name: 'Lê Thị C',
|
||||
status: 'Hoàn thành',
|
||||
deliveries: 4,
|
||||
deliveries_completed: 4,
|
||||
},
|
||||
{
|
||||
name: 'Phạm Văn D',
|
||||
status: 'Đang giao',
|
||||
deliveries: 1,
|
||||
deliveries_completed: 0,
|
||||
},
|
||||
]
|
||||
</script>
|
||||
<template>
|
||||
<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="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>
|
||||
</div>
|
||||
<div class="cell is-flex is-flex-direction-column is-gap-2">
|
||||
<Driver
|
||||
v-for="driver in drivers"
|
||||
:key="driver.name"
|
||||
v-bind="driver"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,35 @@
|
||||
<script setup>
|
||||
import AvatarBox from '@/components/dashboard/AvatarBox.vue';
|
||||
|
||||
const props = defineProps({
|
||||
name: String,
|
||||
status: String,
|
||||
deliveries: Number,
|
||||
deliveries_completed: Number,
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<div
|
||||
class="is-flex is-gap-2 fs-14 p-3 rounded-lg"
|
||||
:style="{
|
||||
border: '1px solid var(--bulma-grey-80)',
|
||||
}"
|
||||
>
|
||||
<AvatarBox :text="name.slice(0, 2)" />
|
||||
<div class="is-flex-grow-1">
|
||||
<div class="is-flex is-gap-1 is-align-items-center">
|
||||
<p>{{ name }}</p>
|
||||
<span :class="['tag', status === 'Đang giao' ? 'is-warning' : 'is-success']">{{ status }}</span>
|
||||
</div>
|
||||
<p class="fs-13 has-text-grey">Đơn: {{ deliveries_completed }}/{{ deliveries }}</p>
|
||||
<progress
|
||||
v-if="deliveries !== deliveries_completed"
|
||||
class="progress is-small is-primary mt-2"
|
||||
style="--bulma-size-small: 0.4rem;"
|
||||
:value="deliveries_completed"
|
||||
:max="deliveries"
|
||||
>
|
||||
</progress>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,54 @@
|
||||
<script setup>
|
||||
import OrderStatusCard from '@/components/dashboard/OrderStatusCard.vue';
|
||||
|
||||
const statuses = [
|
||||
{
|
||||
id: 1,
|
||||
code: 'pending',
|
||||
name: 'Chờ xử lý',
|
||||
value: 12,
|
||||
color: 'orange',
|
||||
icon: 'material-symbols:clock-loader-40'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
code: 'delivering',
|
||||
name: 'Đang giao',
|
||||
value: 8,
|
||||
color: 'blue',
|
||||
icon: 'material-symbols:delivery-truck-speed-outline-rounded'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
code: 'delivered',
|
||||
name: 'Đã giao',
|
||||
value: 15,
|
||||
color: 'purple',
|
||||
icon: 'material-symbols:bucket-check-outline-rounded'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
code: 'completed',
|
||||
name: 'Hoàn thành',
|
||||
value: 38,
|
||||
color: 'green',
|
||||
icon: 'material-symbols:check-circle-outline-rounded'
|
||||
},
|
||||
]
|
||||
</script>
|
||||
<template>
|
||||
<div class="card h-full">
|
||||
<div class="card-content">
|
||||
<p class="fs-17 font-semibold mb-4">Trạng thái đơn hàng</p>
|
||||
<div class="fixed-grid has-2-cols-mobile has-4-cols">
|
||||
<div class="grid">
|
||||
<OrderStatusCard
|
||||
v-for="status in statuses"
|
||||
:key="status.name"
|
||||
v-bind="status"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,33 @@
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
id: Number,
|
||||
code: String,
|
||||
name: String,
|
||||
value: Number,
|
||||
icon: String,
|
||||
color: String,
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<div class="cell">
|
||||
<div class="card" :style="{ border: `1px solid var(--bulma-${color}-70)` }">
|
||||
<div class="card-content is-flex is-flex-direction-column is-align-items-center is-gap-1">
|
||||
<div
|
||||
:class="[
|
||||
'p-3 is-flex rounded-full',
|
||||
`has-background-${color}-90`,
|
||||
`has-text-${color}-40`,
|
||||
]" >
|
||||
<Icon
|
||||
:name="icon"
|
||||
:size="24"
|
||||
/>
|
||||
</div>
|
||||
<div class="is-flex is-flex-direction-column is-align-items-center">
|
||||
<p class="fs-24 font-bold">{{ value }}</p>
|
||||
<p class="has-text-grey">{{ name }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,61 @@
|
||||
<script setup>
|
||||
const { $shortenCurrency } = useNuxtApp();
|
||||
const revenueChartOptions = {
|
||||
chart: {
|
||||
type: 'spline'
|
||||
},
|
||||
credits: {
|
||||
enabled: false,
|
||||
},
|
||||
title: {
|
||||
text: null,
|
||||
},
|
||||
xAxis: {
|
||||
categories: [
|
||||
'10/4', '11/4', '12/4', '13/4', '14/4', '15/4', '16/4', '17/4', '18/4'
|
||||
],
|
||||
accessibility: {
|
||||
description: 'Dates'
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
title: {
|
||||
text: 'Doanh thu'
|
||||
},
|
||||
labels: {
|
||||
format: '{value}'
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
crosshairs: true,
|
||||
shared: true,
|
||||
valueSuffix: ' VNĐ',
|
||||
},
|
||||
plotOptions: {
|
||||
spline: {
|
||||
marker: {
|
||||
enabled: false
|
||||
}
|
||||
}
|
||||
},
|
||||
series: [{
|
||||
name: 'Doanh thu',
|
||||
data: [45000000, 52000000, 48000000, 51000000, 58000000, 61000000, 67500000, 72000000, 69000000],
|
||||
showInLegend: false,
|
||||
}]
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<div class="is-flex is-justify-content-space-between mb-2">
|
||||
<p style="font-weight: 600; font-size: 18px">Doanh thu theo ngày</p>
|
||||
<div class="buttons">
|
||||
<button class="button is-primary fs-14">7 ngày</button>
|
||||
<button class="button is-white fs-14">30 ngày</button>
|
||||
</div>
|
||||
</div>
|
||||
<highcharts :options="revenueChartOptions" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,23 @@
|
||||
<script setup>
|
||||
import AvatarBox from '@/components/dashboard/AvatarBox.vue';
|
||||
|
||||
const props = defineProps({
|
||||
name: String,
|
||||
order_count: Number,
|
||||
paid: Number,
|
||||
})
|
||||
|
||||
const { $shortenCurrency } = useNuxtApp();
|
||||
</script>
|
||||
<template>
|
||||
<div class="is-flex is-gap-1 is-justify-content-space-between">
|
||||
<div class="is-flex is-gap-1">
|
||||
<AvatarBox :text="name.slice(0, 2)" />
|
||||
<div>
|
||||
<p>{{ name }}</p>
|
||||
<p class="fs-13 has-text-grey">{{ order_count }} đơn hàng</p>
|
||||
</div>
|
||||
</div>
|
||||
<p class="font-semibold">{{ $shortenCurrency(paid) }}</p>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,47 @@
|
||||
<script setup>
|
||||
import TopCustomer from '@/components/dashboard/TopCustomer.vue';
|
||||
|
||||
|
||||
const customers = [
|
||||
{
|
||||
name: 'Công ty TNHH ABC',
|
||||
order_count: 45,
|
||||
paid: 125000000,
|
||||
},
|
||||
{
|
||||
name: 'Siêu thị XYZ',
|
||||
order_count: 38,
|
||||
paid: 98000000,
|
||||
},
|
||||
{
|
||||
name: 'Nhà hàng Đông Dương',
|
||||
order_count: 32,
|
||||
paid: 87000000,
|
||||
},
|
||||
{
|
||||
name: 'Khách sạn Mường Thanh',
|
||||
order_count: 28,
|
||||
paid: 76000000,
|
||||
},
|
||||
{
|
||||
name: 'Cửa hàng Bách Hoá',
|
||||
order_count: 24,
|
||||
paid: 64000000,
|
||||
},
|
||||
|
||||
]
|
||||
</script>
|
||||
<template>
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="fs-17 font-semibold mb-4">Top khách hàng</p>
|
||||
<div class="is-flex is-flex-direction-column is-gap-1.5">
|
||||
<TopCustomer
|
||||
v-for="cus in customers"
|
||||
:key="cus.name"
|
||||
v-bind="cus"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,29 @@
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
name: String,
|
||||
sold_count: Number,
|
||||
revenue: Number,
|
||||
topRevenue: Number,
|
||||
});
|
||||
|
||||
const { $shortenCurrency } = useNuxtApp();
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<div class="is-flex is-gap-1 is-justify-content-space-between mb-2">
|
||||
<div>
|
||||
<p>{{ name }}</p>
|
||||
<p class="fs-13 has-text-grey-60">Đã bán {{ sold_count }} sản phẩm</p>
|
||||
</div>
|
||||
<p class="font-semibold">{{ $shortenCurrency(revenue) }}</p>
|
||||
</div>
|
||||
<progress class="progress is-small is-primary" :value="revenue" :max="topRevenue">
|
||||
15%
|
||||
</progress>
|
||||
</div>
|
||||
</template>
|
||||
<style scoped>
|
||||
.progress {
|
||||
--bulma-size-small: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,48 @@
|
||||
<script setup>
|
||||
import TopProduct from '@/components/dashboard/TopProduct.vue';
|
||||
|
||||
const products = [
|
||||
{
|
||||
name: 'Gạo ST25 - Bao 5kg',
|
||||
sold_count: 1250,
|
||||
revenue: 156000000
|
||||
},
|
||||
{
|
||||
name: 'Nước mắm Phú Quốc - Chai 500ml',
|
||||
sold_count: 980,
|
||||
revenue: 132000000
|
||||
},
|
||||
{
|
||||
name: 'Đường tinh luyện - Bao 1kg',
|
||||
sold_count: 856,
|
||||
revenue: 98000000
|
||||
},
|
||||
{
|
||||
name: 'Dầu ăn Neptune - Chai 1L',
|
||||
sold_count: 742,
|
||||
revenue: 87000000
|
||||
},
|
||||
{
|
||||
name: 'Bột mì đa dụng - Bao 1kg',
|
||||
sold_count: 623,
|
||||
revenue: 72000000
|
||||
},
|
||||
]
|
||||
</script>
|
||||
<template>
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="fs-17 font-semibold mb-4">Top sản phẩm</p>
|
||||
<div class="is-flex is-flex-direction-column is-gap-2">
|
||||
<TopProduct
|
||||
v-for="product in products"
|
||||
:key="product.name"
|
||||
v-bind="{
|
||||
...product,
|
||||
topRevenue: products[0].revenue
|
||||
}"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,36 @@
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
name: String,
|
||||
details: String,
|
||||
level: Number,
|
||||
type: String
|
||||
})
|
||||
|
||||
const color = computed(() => {
|
||||
if (props.level === 1) return 'yellow';
|
||||
if (props.level === 2) return 'orange';
|
||||
if (props.level === 3) return 'red';
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
<template>
|
||||
<div
|
||||
:class="['card m-0', `has-background-${color}-95`]"
|
||||
:style="{
|
||||
borderColor: `var(--bulma-${color}-70)`,
|
||||
}"
|
||||
>
|
||||
<div class="card-content p-4 is-flex is-align-items-center is-gap-2">
|
||||
<Icon
|
||||
:name="type === 'time' ? 'material-symbols:clock-loader-40' : 'material-symbols:box-outline-rounded'"
|
||||
:size="20"
|
||||
:class="`has-text-${color}-45`"
|
||||
/>
|
||||
<div>
|
||||
<p :class="`has-text-${color}-40`">{{ name }}</p>
|
||||
<p class="fs-13 has-text-grey">{{ details }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,38 @@
|
||||
<script setup>
|
||||
import Warning from '@/components/dashboard/Warning.vue';
|
||||
|
||||
const warnings = [
|
||||
{
|
||||
name: 'Công nợ sắp đến hạn',
|
||||
details: 'Công ty TNHH ABC - 35.000.000đ - Hạn: 25/03/2026',
|
||||
level: 1,
|
||||
type: 'time',
|
||||
},
|
||||
{
|
||||
name: 'Đơn giao trễ',
|
||||
details: 'Đơn hàng #DH-2156 - Đã trễ 2 giờ - Khách: Siêu thị XYZ',
|
||||
level: 3,
|
||||
type: 'time',
|
||||
},
|
||||
{
|
||||
name: 'Tồn kho thấp',
|
||||
details: 'Gạo ST25 - Chỉ còn 45 bao - Cần nhập thêm',
|
||||
level: 2,
|
||||
type: 'inventory'
|
||||
},
|
||||
]
|
||||
</script>
|
||||
<template>
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="fs-17 font-semibold mb-4">Cảnh báo và thông báo</p>
|
||||
<div class="is-flex is-flex-direction-column is-gap-1">
|
||||
<Warning
|
||||
v-for="warning in warnings"
|
||||
:key="warning.details"
|
||||
v-bind="warning"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,5 +1,43 @@
|
||||
<script setup>
|
||||
import InventoryHighlightCard from '@/components/inventory/InventoryHighlightCard.vue';
|
||||
|
||||
const inventoryHighlights = [
|
||||
{
|
||||
name: 'Tổng số SKU',
|
||||
value: 12,
|
||||
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: 'Giá trị tồn kho',
|
||||
value: '294.5M',
|
||||
icon: 'material-symbols:attach-money-rounded',
|
||||
color: 'purple',
|
||||
},
|
||||
{
|
||||
name: 'Sắp hết hàng',
|
||||
value: 3,
|
||||
icon: 'material-symbols:warning-outline-rounded',
|
||||
color: 'red',
|
||||
unit: 'sản phẩm'
|
||||
},
|
||||
];
|
||||
</script>
|
||||
<template>
|
||||
Inventory
|
||||
<div class="fixed-grid has-2-cols-mobile has-4-cols">
|
||||
<div class="grid">
|
||||
<InventoryHighlightCard
|
||||
v-for="highlight in inventoryHighlights"
|
||||
:key="highlight.name"
|
||||
v-bind="highlight"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,28 @@
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
name: String,
|
||||
value: String,
|
||||
unit: String,
|
||||
icon: String,
|
||||
color: String
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<div class="cell">
|
||||
<div class="card h-full">
|
||||
<div class="card-content is-flex is-justify-content-space-between is-align-items-start is-gap-1">
|
||||
<div>
|
||||
<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`]">
|
||||
<Icon
|
||||
:name="icon"
|
||||
:class="`has-text-${color}-40`"
|
||||
:size="24"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,34 @@
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
name: String,
|
||||
value: Number,
|
||||
icon: String,
|
||||
color: String,
|
||||
unit: String
|
||||
})
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<div class="cell">
|
||||
<div class="card h-full">
|
||||
<div class="card-content is-flex is-gap-1 is-justify-content-space-between is-align-items-center">
|
||||
<div>
|
||||
<p class="has-text-grey">{{ name }}</p>
|
||||
<div class="is-flex is-gap-1 is-align-items-center">
|
||||
<p class="fs-26 font-bold">{{ value }}</p>
|
||||
<span class="fs-13 has-text-grey">{{ unit }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
:class="['p-3 is-flex', `has-background-${color}-soft`]" style="border-radius: 8px"
|
||||
>
|
||||
<Icon
|
||||
:name="icon"
|
||||
:size="26"
|
||||
:class="`has-text-${color}-40`"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,53 @@
|
||||
<script setup>
|
||||
import PipelinePhase from '@/components/orders/PipelinePhase.vue';
|
||||
|
||||
const phases = [
|
||||
{
|
||||
name: 'Nháp',
|
||||
value: 2,
|
||||
icon: 'material-symbols:assignment-outline-rounded',
|
||||
color: 'yellow',
|
||||
index: 1,
|
||||
},
|
||||
{
|
||||
name: 'Đã xác nhận',
|
||||
value: 3,
|
||||
icon: 'material-symbols:check-circle-outline-rounded',
|
||||
color: 'blue',
|
||||
index: 2,
|
||||
},
|
||||
{
|
||||
name: 'Đang giao',
|
||||
value: 2,
|
||||
icon: 'material-symbols:delivery-truck-speed-outline-rounded',
|
||||
color: 'orange',
|
||||
index: 3,
|
||||
},
|
||||
{
|
||||
name: 'Hoàn thành',
|
||||
value: 1,
|
||||
icon: 'material-symbols:box-outline-rounded',
|
||||
color: 'green',
|
||||
index: 4,
|
||||
},
|
||||
]
|
||||
</script>
|
||||
<template>
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="fs-17 font-semibold mb-4">Pipeline đơn hàng</p>
|
||||
<div class="is-flex is-justify-content-space-evenly">
|
||||
<PipelinePhase
|
||||
v-for="phase in phases"
|
||||
:key="phases.name"
|
||||
v-bind="phase"
|
||||
/>
|
||||
</div>
|
||||
<hr class="has-background-grey-lighter" />
|
||||
<div class="is-flex is-justify-content-space-between">
|
||||
<p>Tổng đơn hàng</p>
|
||||
<p class="fs-18 font-semibold">{{ phases.reduce((prev, curr) => prev + curr.value, 0) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,85 @@
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
id: Number,
|
||||
code: String,
|
||||
employee: Number,
|
||||
employee__name: String,
|
||||
customer: Number,
|
||||
customer__name: String,
|
||||
customer__phone: String,
|
||||
total: String,
|
||||
status: Number,
|
||||
status__name: String,
|
||||
status__color: String,
|
||||
payment_status: Number,
|
||||
payment_status__name: String,
|
||||
payment_status__color: String,
|
||||
delivery_status: Number,
|
||||
delivery_status__name: String,
|
||||
delivery_status__color: String,
|
||||
order__products: Array,
|
||||
create_time: String
|
||||
});
|
||||
|
||||
const { $dayjs, $shortenCurrency } = useNuxtApp();
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<tr>
|
||||
<td>
|
||||
<div>
|
||||
<p class="fs-15 font-semibold">{{ code }}</p>
|
||||
<p class="fs-13 has-text-grey">{{ employee__name }}</p>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<p>{{ customer__name }}</p>
|
||||
<div class="is-flex is-gap-0.5 is-align-items-center mt-1 fs-13 has-text-grey">
|
||||
<Icon name="material-symbols:call-outline-rounded"
|
||||
:size="15"
|
||||
/>
|
||||
<span class="fs-12">{{ customer__phone }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="has-text-right">
|
||||
<div>
|
||||
<p class="font-semibold">{{ $shortenCurrency(total) }}</p>
|
||||
<p class="fs-13 has-text-grey">{{ order__products.length }} SP</p>
|
||||
</div>
|
||||
</td>
|
||||
<td class="has-text-centered">
|
||||
<span :class="[
|
||||
'tag rounded-full',
|
||||
`has-background-${status__color}-80 has-text-${status__color}-25`
|
||||
]">
|
||||
{{ status__name }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<p :class="`has-text-${payment_status__color}-40`">{{ payment_status__name }}</p>
|
||||
</td>
|
||||
<td>
|
||||
<p :class="`has-text-${delivery_status__color}-40`">{{ delivery_status__name }}</p>
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<div class="is-flex is-gap-0.5">
|
||||
<Icon :size="18" name="material-symbols:calendar-month-outline-rounded" />
|
||||
<span class="fs-13">{{ $dayjs(create_time).format('L') }}</span>
|
||||
</div>
|
||||
<p class="has-text-grey fs-12">{{ $dayjs(create_time).format('HH:mm') }}</p>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<button class="button is-dark fs-13 rounded-full">Xác nhận</button>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
<style scoped>
|
||||
td {
|
||||
vertical-align: middle;
|
||||
--bulma-table-cell-padding: 0.75em;
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +1,54 @@
|
||||
<script setup>
|
||||
import OrderHighlightCard from '@/components/orders/OrderHighlightCard.vue';
|
||||
import OrderPipeline from '@/components/orders/OrderPipeline.vue';
|
||||
import OrdersTable from '@/components/orders/OrdersTable.vue';
|
||||
|
||||
const highlights = [
|
||||
{
|
||||
name: 'Nháp',
|
||||
value: 2,
|
||||
icon: 'material-symbols:assignment-outline-rounded',
|
||||
color: 'yellow',
|
||||
},
|
||||
{
|
||||
name: 'Đã xác nhận',
|
||||
value: 3,
|
||||
icon: 'material-symbols:check-circle-outline-rounded',
|
||||
color: 'blue',
|
||||
},
|
||||
{
|
||||
name: 'Đang giao',
|
||||
value: 2,
|
||||
icon: 'material-symbols:delivery-truck-speed-outline-rounded',
|
||||
color: 'orange',
|
||||
},
|
||||
{
|
||||
name: 'Hoàn thành',
|
||||
value: 1,
|
||||
icon: 'material-symbols:box-outline-rounded',
|
||||
color: 'green',
|
||||
},
|
||||
{
|
||||
name: 'Doanh thu',
|
||||
value: '6.8M',
|
||||
icon: 'material-symbols:attach-money-rounded',
|
||||
color: 'purple',
|
||||
unit: 'VNĐ'
|
||||
},
|
||||
]
|
||||
</script>
|
||||
<template>
|
||||
Orders
|
||||
</template>
|
||||
<div>
|
||||
<div class="fixed-grid has-2-cols-mobile has-5-cols">
|
||||
<div class="grid">
|
||||
<OrderHighlightCard
|
||||
v-for="highlight in highlights"
|
||||
:key="highlight.name"
|
||||
v-bind="highlight"
|
||||
/>
|
||||
</div>
|
||||
<OrderPipeline />
|
||||
<OrdersTable />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
<script setup>
|
||||
import OrderRow from '@/components/orders/OrderRow.vue';
|
||||
|
||||
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: 'orange',
|
||||
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'
|
||||
},
|
||||
]
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<div class="card">
|
||||
<div class="card-content"></div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<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:list-alt-outline-rounded" :size="22" />
|
||||
<span>Danh sách đơn hàng ({{ orders.length }})</span>
|
||||
</p>
|
||||
<table class="table is-fullwidth is-hoverable fs-14">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Đơn hàng</th>
|
||||
<th>Khách hàng</th>
|
||||
<th class="has-text-right">Tổng tiền</th>
|
||||
<th class="has-text-centered">Trạng thái</th>
|
||||
<th>Thanh toán</th>
|
||||
<th>Giao hàng</th>
|
||||
<th>Ngày tạo</th>
|
||||
<th>Thao tác</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<OrderRow
|
||||
v-for="order in orders"
|
||||
:key="order.id"
|
||||
v-bind="order"
|
||||
/>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<style scoped>
|
||||
th {
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,44 @@
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
name: String,
|
||||
value: Number,
|
||||
icon: String,
|
||||
color: String,
|
||||
index: Number,
|
||||
});
|
||||
|
||||
const progressUnfilled = computed(() => `var(--bulma-${props.color}-85)`);
|
||||
</script>
|
||||
<template>
|
||||
<div class="is-flex-grow-1">
|
||||
<div class="is-flex is-justify-content-space-between">
|
||||
<p :class="`has-text-${color}-40`">{{ name }}</p>
|
||||
<p :class="['fs-18 font-bold', `has-text-${color}-30`]">{{ value }}</p>
|
||||
</div>
|
||||
<progress
|
||||
:class="['progress is-small mt-2', `is-${color}`]"
|
||||
value="20"
|
||||
max="100"
|
||||
>
|
||||
</progress>
|
||||
</div>
|
||||
<div
|
||||
v-if="index < 4"
|
||||
class="is-flex is-justify-content-center is-align-items-center"
|
||||
style="width: 60px; height: 48px"
|
||||
>
|
||||
<Icon
|
||||
name="material-symbols:arrow-forward-rounded"
|
||||
:size="24"
|
||||
class="has-text-grey-70"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<style lang="scss" scoped>
|
||||
$progress-value-background-color: 'red';
|
||||
|
||||
.progress {
|
||||
--bulma-size-small: 0.5rem;
|
||||
background-color: v-bind(progressUnfilled);
|
||||
}
|
||||
</style>
|
||||
@@ -1,7 +1,6 @@
|
||||
<template>
|
||||
<div
|
||||
style="min-height: 100vh"
|
||||
class="has-background-white"
|
||||
style="min-height: 100vh; background-color: #f9fafb;"
|
||||
data-theme="light"
|
||||
lang="vi"
|
||||
>
|
||||
@@ -48,7 +47,7 @@ async function checkRedirect() {
|
||||
$store.commit("login", row);
|
||||
}
|
||||
} else if (!$store.login) return /* $requestLogin(); */
|
||||
await checkLogin();
|
||||
// await checkLogin();
|
||||
}
|
||||
async function checkLogin() {
|
||||
if ($store.login ? $store.login.token : false) {
|
||||
|
||||
+6
-6
@@ -3,17 +3,17 @@
|
||||
<TopMenu @changetab="changeTab" />
|
||||
</ClientOnly>
|
||||
<ClientOnly>
|
||||
<div class="container blockdiv" style="padding-bottom: 0">
|
||||
<div class="fsb-18 mb-2 has-text-black" v-if="tab">
|
||||
<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">
|
||||
<span>{{ tab[$store.lang] }}</span>
|
||||
<SvgIcon class="mx-2" v-bind="{ name: 'right.svg', size: 17, type: 'has-text-black' }"></SvgIcon>
|
||||
<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>
|
||||
<a class="ml-3" @click="refresh()">
|
||||
<SvgIcon v-bind="{name: 'refresh.svg', type: 'primary', size: 20}"></SvgIcon>
|
||||
</a>
|
||||
<button class="button is-primary is-light rounded-full p-1" @click="refresh()">
|
||||
<Icon name="material-symbols:refresh-rounded" :size="24" />
|
||||
</button>
|
||||
</div>
|
||||
<KeepAlive>
|
||||
<component :is="componentMap[vbind.component]" v-bind="vbind" :key="componentKey" v-if="componentKey" />
|
||||
|
||||
@@ -5,11 +5,12 @@ import dayjs from 'dayjs';
|
||||
import weekday from 'dayjs/plugin/weekday';
|
||||
import weekOfYear from 'dayjs/plugin/weekOfYear';
|
||||
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||
import localizedFormat from 'dayjs/plugin/localizedFormat'
|
||||
import 'dayjs/locale/vi';
|
||||
dayjs.extend(weekday);
|
||||
dayjs.extend(weekOfYear);
|
||||
dayjs.extend(relativeTime);
|
||||
|
||||
dayjs.extend(localizedFormat);
|
||||
dayjs.locale('vi');
|
||||
|
||||
export default defineNuxtPlugin(() => {
|
||||
@@ -608,6 +609,12 @@ export default defineNuxtPlugin(() => {
|
||||
return `https://img.vietqr.io/image/${bankInfo.bank.code}-${bankInfo.account.number}-print.png?${params.toString()}`;
|
||||
};
|
||||
|
||||
function shortenCurrency(amount) {
|
||||
return new Intl.NumberFormat('en', { notation: 'compact' }).format(
|
||||
Number(amount),
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
provide: {
|
||||
dialog,
|
||||
@@ -636,6 +643,7 @@ export default defineNuxtPlugin(() => {
|
||||
formatDateVN,
|
||||
getFirstAndLastName,
|
||||
paymentQR,
|
||||
shortenCurrency
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
+9571
-722
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
+28
-49
@@ -1,53 +1,32 @@
|
||||
$blue-dianne: #204853;
|
||||
$parchment: #fefefe;
|
||||
$sirocco: #758385;
|
||||
$delta: #b0afaa;
|
||||
$cutty-sark: #566c72;
|
||||
$silver-rust: #ccc5bc;
|
||||
$fiord: #3c5b63;
|
||||
$pewter: #959b99;
|
||||
$pearl-bush: #ffffff;
|
||||
$red: #ff2e4e;
|
||||
$orange: #fd8206;
|
||||
$yellow: #eec704;
|
||||
$green: #16d164;
|
||||
$cyan: #03c2c2;
|
||||
$blue: #1678ff;
|
||||
$purple: #833bff;
|
||||
$pink: #ff2bdd;
|
||||
$grey: #767676;
|
||||
|
||||
// Set your brand colors
|
||||
$primary: $blue-dianne;
|
||||
$secondary: $fiord;
|
||||
$accent: $parchment;
|
||||
$findata: $sirocco;
|
||||
$danger: #f14668;
|
||||
$dark: $cutty-sark;
|
||||
$light: $pearl-bush;
|
||||
$twitter: $pewter;
|
||||
$warning: $cutty-sark;
|
||||
$info: $sirocco;
|
||||
$success: $fiord;
|
||||
|
||||
// Path to Bulma's sass folder
|
||||
@use "bulma/sass" with (
|
||||
$family-primary: 'Arial, sans-serif',
|
||||
$primary: $primary,
|
||||
$info: $info,
|
||||
$success: $success,
|
||||
$warning: $warning,
|
||||
$danger: $danger,
|
||||
$body-color: $sitecolor,
|
||||
$text: $sitecolor,
|
||||
$link: $blue-dianne,
|
||||
$link-hover: $fiord
|
||||
$family-primary: "'Inter', 'SF Pro', 'Helvetica', 'Arial', sans-serif",
|
||||
$primary: $blue,
|
||||
$link: $blue,
|
||||
$info: $cyan,
|
||||
$success: $green,
|
||||
$warning: $yellow,
|
||||
$danger: $red,
|
||||
$custom-colors: (
|
||||
"red": $red,
|
||||
"orange": $orange,
|
||||
"yellow": $yellow,
|
||||
"green": $green,
|
||||
"cyan": $cyan,
|
||||
"blue": $blue,
|
||||
"purple": $purple,
|
||||
"pink": $pink,
|
||||
"grey": $grey
|
||||
)
|
||||
);
|
||||
|
||||
a {
|
||||
color: inherit !important;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: $primary !important;
|
||||
}
|
||||
|
||||
strong, label {
|
||||
color: $sitecolor !important;
|
||||
}
|
||||
|
||||
.hyperlink:hover {
|
||||
cursor: pointer;
|
||||
color: $primary !important;
|
||||
}
|
||||
@import url('https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900');
|
||||
+1
-2
@@ -10,8 +10,7 @@ export default defineNuxtConfig({
|
||||
script: [{ src: "/js/html2pdf.bundle.min.js" }, { src: "/js/html2canvas.min.js" }],
|
||||
},
|
||||
},
|
||||
modules: ["@pinia/nuxt", "pinia-plugin-persistedstate/nuxt", "@nuxt/image","nuxt-qrcode"],
|
||||
|
||||
modules: ["@pinia/nuxt", "pinia-plugin-persistedstate/nuxt", "@nuxt/image","nuxt-qrcode", "@nuxt/icon"],
|
||||
compatibilityDate: "2025-10-01",
|
||||
devtools: { enabled: true },
|
||||
});
|
||||
|
||||
Generated
+236
-59
@@ -18,7 +18,7 @@
|
||||
"@vueup/vue-quill": "^1.2.0",
|
||||
"axios": "^1.9.0",
|
||||
"bowser": "^2.11.0",
|
||||
"bulma": "^1.0.2",
|
||||
"bulma": "^1.0.4",
|
||||
"crypto-js": "^4.2.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"docx-preview": "^0.3.6",
|
||||
@@ -44,10 +44,24 @@
|
||||
"vue3-quill": "^0.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/icon": "^2.2.1",
|
||||
"nuxt": "^4.2.0",
|
||||
"typescript": "^5.9.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@antfu/install-pkg": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-1.1.0.tgz",
|
||||
"integrity": "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"package-manager-detector": "^1.3.0",
|
||||
"tinyexec": "^1.0.1"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
}
|
||||
},
|
||||
"node_modules/@aps_sdk/authentication": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@aps_sdk/authentication/-/authentication-1.0.0.tgz",
|
||||
@@ -1113,6 +1127,47 @@
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@iconify/collections": {
|
||||
"version": "1.0.670",
|
||||
"resolved": "https://registry.npmjs.org/@iconify/collections/-/collections-1.0.670.tgz",
|
||||
"integrity": "sha512-32kW4oJ+QV1HCndcjwAprDyJJ0+T9ahP4y2lmLfekdGWNMwG1pVZah4biqT+HrZdEiBm8InJrbCvaitIusTE3g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@iconify/types": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@iconify/types": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz",
|
||||
"integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@iconify/utils": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-3.1.0.tgz",
|
||||
"integrity": "sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@antfu/install-pkg": "^1.1.0",
|
||||
"@iconify/types": "^2.0.0",
|
||||
"mlly": "^1.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@iconify/vue": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@iconify/vue/-/vue-5.0.0.tgz",
|
||||
"integrity": "sha512-C+KuEWIF5nSBrobFJhT//JS87OZ++QDORB6f2q2Wm6fl2mueSTpFBeBsveK0KW9hWiZ4mNiPjsh6Zs4jjdROSg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@iconify/types": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/cyberalien"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": ">=3"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/colour": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz",
|
||||
@@ -2208,6 +2263,94 @@
|
||||
"node": "^18.17.0 || >=20.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@nuxt/icon": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@nuxt/icon/-/icon-2.2.1.tgz",
|
||||
"integrity": "sha512-GI840yYGuvHI0BGDQ63d6rAxGzG96jQcWrnaWIQKlyQo/7sx9PjXkSHckXUXyX1MCr9zY6U25Td6OatfY6Hklw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@iconify/collections": "^1.0.641",
|
||||
"@iconify/types": "^2.0.0",
|
||||
"@iconify/utils": "^3.1.0",
|
||||
"@iconify/vue": "^5.0.0",
|
||||
"@nuxt/devtools-kit": "^3.1.1",
|
||||
"@nuxt/kit": "^4.2.2",
|
||||
"consola": "^3.4.2",
|
||||
"local-pkg": "^1.1.2",
|
||||
"mlly": "^1.8.0",
|
||||
"ohash": "^2.0.11",
|
||||
"pathe": "^2.0.3",
|
||||
"picomatch": "^4.0.3",
|
||||
"std-env": "^3.10.0",
|
||||
"tinyglobby": "^0.2.15"
|
||||
}
|
||||
},
|
||||
"node_modules/@nuxt/icon/node_modules/@nuxt/devtools-kit": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@nuxt/devtools-kit/-/devtools-kit-3.2.4.tgz",
|
||||
"integrity": "sha512-Yxy2Xgmq5hf3dQy983V0xh0OJV2mYwRZz9eVIGc3EaribdFGPDNGMMbYqX9qCty3Pbxn/bCF3J0UyPaNlHVayQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@nuxt/kit": "^4.4.2",
|
||||
"execa": "^8.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vite": ">=6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@nuxt/icon/node_modules/@nuxt/kit": {
|
||||
"version": "4.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-4.4.2.tgz",
|
||||
"integrity": "sha512-5+IPRNX2CjkBhuWUwz0hBuLqiaJPRoKzQ+SvcdrQDbAyE+VDeFt74VpSFr5/R0ujrK4b+XnSHUJWdS72w6hsog==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"c12": "^3.3.3",
|
||||
"consola": "^3.4.2",
|
||||
"defu": "^6.1.4",
|
||||
"destr": "^2.0.5",
|
||||
"errx": "^0.1.0",
|
||||
"exsolve": "^1.0.8",
|
||||
"ignore": "^7.0.5",
|
||||
"jiti": "^2.6.1",
|
||||
"klona": "^2.0.6",
|
||||
"mlly": "^1.8.1",
|
||||
"ohash": "^2.0.11",
|
||||
"pathe": "^2.0.3",
|
||||
"pkg-types": "^2.3.0",
|
||||
"rc9": "^3.0.0",
|
||||
"scule": "^1.3.0",
|
||||
"semver": "^7.7.4",
|
||||
"tinyglobby": "^0.2.15",
|
||||
"ufo": "^1.6.3",
|
||||
"unctx": "^2.5.0",
|
||||
"untyped": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@nuxt/icon/node_modules/picomatch": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
|
||||
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/@nuxt/icon/node_modules/rc9": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/rc9/-/rc9-3.0.1.tgz",
|
||||
"integrity": "sha512-gMDyleLWVE+i6Sgtc0QbbY6pEKqYs97NGi6isHQPqYlLemPoO8dxQ3uGi0f4NiP98c+jMW6cG1Kx9dDwfvqARQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"defu": "^6.1.6",
|
||||
"destr": "^2.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@nuxt/image": {
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@nuxt/image/-/image-1.11.0.tgz",
|
||||
@@ -5715,10 +5858,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.15.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"license": "MIT",
|
||||
"version": "8.16.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
|
||||
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@@ -6877,8 +7019,7 @@
|
||||
"node_modules/bulma": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/bulma/-/bulma-1.0.4.tgz",
|
||||
"integrity": "sha512-Ffb6YGXDiZYX3cqvSbHWqQ8+LkX6tVoTcZuVB3lm93sbAVXlO0D6QlOTMnV6g18gILpAXqkG2z9hf9z4hCjz2g==",
|
||||
"license": "MIT"
|
||||
"integrity": "sha512-Ffb6YGXDiZYX3cqvSbHWqQ8+LkX6tVoTcZuVB3lm93sbAVXlO0D6QlOTMnV6g18gILpAXqkG2z9hf9z4hCjz2g=="
|
||||
},
|
||||
"node_modules/bundle-name": {
|
||||
"version": "4.1.0",
|
||||
@@ -6897,23 +7038,22 @@
|
||||
}
|
||||
},
|
||||
"node_modules/c12": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/c12/-/c12-3.3.2.tgz",
|
||||
"integrity": "sha512-QkikB2X5voO1okL3QsES0N690Sn/K9WokXqUsDQsWy5SnYb+psYQFGA10iy1bZHj3fjISKsI67Q90gruvWWM3A==",
|
||||
"license": "MIT",
|
||||
"version": "3.3.4",
|
||||
"resolved": "https://registry.npmjs.org/c12/-/c12-3.3.4.tgz",
|
||||
"integrity": "sha512-cM0ApFQSBXuourJejzwv/AuPRvAxordTyParRVcHjjtXirtkzM0uK2L9TTn9s0cXZbG7E55jCivRQzoxYmRAlA==",
|
||||
"dependencies": {
|
||||
"chokidar": "^4.0.3",
|
||||
"confbox": "^0.2.2",
|
||||
"defu": "^6.1.4",
|
||||
"dotenv": "^17.2.3",
|
||||
"chokidar": "^5.0.0",
|
||||
"confbox": "^0.2.4",
|
||||
"defu": "^6.1.6",
|
||||
"dotenv": "^17.3.1",
|
||||
"exsolve": "^1.0.8",
|
||||
"giget": "^2.0.0",
|
||||
"giget": "^3.2.0",
|
||||
"jiti": "^2.6.1",
|
||||
"ohash": "^2.0.11",
|
||||
"pathe": "^2.0.3",
|
||||
"perfect-debounce": "^2.0.0",
|
||||
"perfect-debounce": "^2.1.0",
|
||||
"pkg-types": "^2.3.0",
|
||||
"rc9": "^2.1.2"
|
||||
"rc9": "^3.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"magicast": "*"
|
||||
@@ -6924,6 +7064,49 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/c12/node_modules/chokidar": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz",
|
||||
"integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==",
|
||||
"dependencies": {
|
||||
"readdirp": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 20.19.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/c12/node_modules/giget": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/giget/-/giget-3.2.0.tgz",
|
||||
"integrity": "sha512-GvHTWcykIR/fP8cj8dMpuMMkvaeJfPvYnhq0oW+chSeIr+ldX21ifU2Ms6KBoyKZQZmVaUAAhQ2EZ68KJF8a7A==",
|
||||
"bin": {
|
||||
"giget": "dist/cli.mjs"
|
||||
}
|
||||
},
|
||||
"node_modules/c12/node_modules/rc9": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/rc9/-/rc9-3.0.1.tgz",
|
||||
"integrity": "sha512-gMDyleLWVE+i6Sgtc0QbbY6pEKqYs97NGi6isHQPqYlLemPoO8dxQ3uGi0f4NiP98c+jMW6cG1Kx9dDwfvqARQ==",
|
||||
"dependencies": {
|
||||
"defu": "^6.1.6",
|
||||
"destr": "^2.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/c12/node_modules/readdirp": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz",
|
||||
"integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==",
|
||||
"engines": {
|
||||
"node": ">= 20.19.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/cac": {
|
||||
"version": "6.7.14",
|
||||
"resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
|
||||
@@ -7914,10 +8097,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/confbox": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz",
|
||||
"integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==",
|
||||
"license": "MIT"
|
||||
"version": "0.2.4",
|
||||
"resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz",
|
||||
"integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ=="
|
||||
},
|
||||
"node_modules/config-chain": {
|
||||
"version": "1.1.13",
|
||||
@@ -8679,10 +8861,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/defu": {
|
||||
"version": "6.1.4",
|
||||
"resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz",
|
||||
"integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==",
|
||||
"license": "MIT"
|
||||
"version": "6.1.7",
|
||||
"resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz",
|
||||
"integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ=="
|
||||
},
|
||||
"node_modules/delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
@@ -8905,10 +9086,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "17.2.3",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz",
|
||||
"integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==",
|
||||
"license": "BSD-2-Clause",
|
||||
"version": "17.4.1",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.1.tgz",
|
||||
"integrity": "sha512-k8DaKGP6r1G30Lx8V4+pCsLzKr8vLmV2paqEj1Y55GdAgJuIqpRp5FfajGF8KtwMxCz9qJc6wUIJnm053d/WCw==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -10076,6 +10256,7 @@
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz",
|
||||
"integrity": "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"citty": "^0.1.6",
|
||||
@@ -12554,15 +12735,14 @@
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/mlly": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz",
|
||||
"integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==",
|
||||
"license": "MIT",
|
||||
"version": "1.8.2",
|
||||
"resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.2.tgz",
|
||||
"integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==",
|
||||
"dependencies": {
|
||||
"acorn": "^8.15.0",
|
||||
"acorn": "^8.16.0",
|
||||
"pathe": "^2.0.3",
|
||||
"pkg-types": "^1.3.1",
|
||||
"ufo": "^1.6.1"
|
||||
"ufo": "^1.6.3"
|
||||
}
|
||||
},
|
||||
"node_modules/mlly/node_modules/confbox": {
|
||||
@@ -13318,6 +13498,7 @@
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.2.tgz",
|
||||
"integrity": "sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"citty": "^0.1.6",
|
||||
@@ -14042,10 +14223,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/perfect-debounce": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.0.0.tgz",
|
||||
"integrity": "sha512-fkEH/OBiKrqqI/yIgjR92lMfs2K8105zt/VT6+7eTjNwisrsh47CeIED9z58zI7DfKdH3uHAn25ziRZn3kgAow==",
|
||||
"license": "MIT"
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.1.0.tgz",
|
||||
"integrity": "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g=="
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.1.1",
|
||||
@@ -15786,10 +15966,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.7.3",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
|
||||
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
|
||||
"license": "ISC",
|
||||
"version": "7.7.4",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
|
||||
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
@@ -17197,6 +17376,7 @@
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz",
|
||||
"integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
@@ -17538,10 +17718,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ufo": {
|
||||
"version": "1.6.1",
|
||||
"resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz",
|
||||
"integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==",
|
||||
"license": "MIT"
|
||||
"version": "1.6.3",
|
||||
"resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz",
|
||||
"integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q=="
|
||||
},
|
||||
"node_modules/ultrahtml": {
|
||||
"version": "1.6.0",
|
||||
@@ -17557,15 +17736,14 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/unctx": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/unctx/-/unctx-2.4.1.tgz",
|
||||
"integrity": "sha512-AbaYw0Nm4mK4qjhns67C+kgxR2YWiwlDBPzxrN8h8C6VtAdCgditAY5Dezu3IJy4XVqAnbrXt9oQJvsn3fyozg==",
|
||||
"license": "MIT",
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/unctx/-/unctx-2.5.0.tgz",
|
||||
"integrity": "sha512-p+Rz9x0R7X+CYDkT+Xg8/GhpcShTlU8n+cf9OtOEf7zEQsNcCZO1dPKNRDqvUTaq+P32PMMkxWHwfrxkqfqAYg==",
|
||||
"dependencies": {
|
||||
"acorn": "^8.14.0",
|
||||
"acorn": "^8.15.0",
|
||||
"estree-walker": "^3.0.3",
|
||||
"magic-string": "^0.30.17",
|
||||
"unplugin": "^2.1.0"
|
||||
"magic-string": "^0.30.21",
|
||||
"unplugin": "^2.3.11"
|
||||
}
|
||||
},
|
||||
"node_modules/unctx/node_modules/estree-walker": {
|
||||
@@ -17796,10 +17974,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/unplugin": {
|
||||
"version": "2.3.10",
|
||||
"resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.10.tgz",
|
||||
"integrity": "sha512-6NCPkv1ClwH+/BGE9QeoTIl09nuiAt0gS28nn1PvYXsGKRwM2TCbFA2QiilmehPDTXIe684k4rZI1yl3A1PCUw==",
|
||||
"license": "MIT",
|
||||
"version": "2.3.11",
|
||||
"resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.11.tgz",
|
||||
"integrity": "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==",
|
||||
"dependencies": {
|
||||
"@jridgewell/remapping": "^2.3.5",
|
||||
"acorn": "^8.15.0",
|
||||
|
||||
+2
-1
@@ -22,7 +22,7 @@
|
||||
"@vueup/vue-quill": "^1.2.0",
|
||||
"axios": "^1.9.0",
|
||||
"bowser": "^2.11.0",
|
||||
"bulma": "^1.0.2",
|
||||
"bulma": "^1.0.4",
|
||||
"crypto-js": "^4.2.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"docx-preview": "^0.3.6",
|
||||
@@ -51,6 +51,7 @@
|
||||
"vue": "latest"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/icon": "^2.2.1",
|
||||
"nuxt": "^4.2.0",
|
||||
"typescript": "^5.9.3"
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 176 KiB |
Reference in New Issue
Block a user