489 lines
14 KiB
Vue
489 lines
14 KiB
Vue
<template>
|
|
<template v-if="isMobile">
|
|
<button
|
|
type="button"
|
|
class="dashboard-operations-trigger"
|
|
:class="{ 'is-open': menuOpen }"
|
|
@click="menuOpen = true"
|
|
>
|
|
<BaseIcon icon="vuesax-linear:setting-2" :size="18" />
|
|
<span>عملیات</span>
|
|
<BaseIcon
|
|
icon="vuesax-linear:arrow-down"
|
|
:size="14"
|
|
class="dashboard-operations-trigger__chevron"
|
|
/>
|
|
</button>
|
|
|
|
<BasicActionSheet
|
|
v-model:visible="menuOpen"
|
|
title="عملیات سریع"
|
|
compact
|
|
drawer-height="auto"
|
|
:show-button="false"
|
|
>
|
|
<div class="dash-quick-sheet">
|
|
<header class="dash-quick-sheet__header">
|
|
<h3 class="dash-quick-sheet__title">عملیات سریع</h3>
|
|
<p class="dash-quick-sheet__subtitle">دسترسی سریع به ابزارهای میز کار</p>
|
|
</header>
|
|
|
|
<button
|
|
type="button"
|
|
class="dash-quick-sheet__featured"
|
|
@click="runAction('wallet')"
|
|
>
|
|
<span class="dash-quick-sheet__featured-icon">
|
|
<BaseIcon icon="vuesax-linear:empty-wallet" :size="22" />
|
|
</span>
|
|
<span class="dash-quick-sheet__featured-text">
|
|
<span class="dash-quick-sheet__featured-label">شارژ / دشارژ کیف پول</span>
|
|
<span class="dash-quick-sheet__featured-hint">{{ metalLabel.manageGoldCash() }}</span>
|
|
</span>
|
|
<BaseIcon icon="vuesax-linear:arrow-left-2" :size="16" class="dash-quick-sheet__featured-arrow" />
|
|
</button>
|
|
|
|
<section v-for="group in mobileMenuGroups" :key="group.title" class="dash-quick-sheet__section">
|
|
<p class="dash-quick-sheet__section-title">{{ group.title }}</p>
|
|
<div class="dash-quick-sheet__list">
|
|
<button
|
|
v-for="item in group.items"
|
|
:key="item.key"
|
|
type="button"
|
|
class="dash-quick-sheet__item"
|
|
:class="[
|
|
item.tone ? `dash-quick-sheet__item--${item.tone}` : '',
|
|
{ 'dash-quick-sheet__item--nav': item.nav },
|
|
]"
|
|
:disabled="item.disabled"
|
|
@click="runAction(item.key)"
|
|
>
|
|
<span class="dash-quick-sheet__badge" :class="`dash-quick-sheet__badge--${item.tone ?? 'slate'}`">
|
|
<BaseIcon :icon="item.icon" :size="18" />
|
|
</span>
|
|
<span class="dash-quick-sheet__item-body">
|
|
<span class="dash-quick-sheet__item-label">{{ item.label }}</span>
|
|
<span v-if="item.hint" class="dash-quick-sheet__item-hint">{{ item.hint }}</span>
|
|
</span>
|
|
<span v-if="item.badge" class="dash-quick-sheet__count">{{ item.badge }}</span>
|
|
<BaseIcon
|
|
v-if="item.nav"
|
|
icon="vuesax-linear:arrow-left-2"
|
|
:size="15"
|
|
class="dash-quick-sheet__item-arrow"
|
|
/>
|
|
</button>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</BasicActionSheet>
|
|
</template>
|
|
|
|
<div v-else class="dashboard-quick-actions-bar">
|
|
<DashboardQuickActionBtn
|
|
v-for="item in actionItems"
|
|
:key="item.key"
|
|
:icon="item.icon"
|
|
:label="item.shortLabel"
|
|
:variant="item.variant"
|
|
:loading="item.loading"
|
|
:disabled="item.disabled"
|
|
:to="item.to"
|
|
@click="item.onClick?.()"
|
|
>
|
|
<template v-if="item.key === 'restore'">
|
|
{{ item.shortLabel }}
|
|
<span v-if="productSnapshotCount" class="mr-0.5 opacity-80">({{ productSnapshotCount }})</span>
|
|
</template>
|
|
</DashboardQuickActionBtn>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed, ref } from 'vue'
|
|
import { useRouter } from 'vue-router'
|
|
import type { RouteLocationRaw } from 'vue-router'
|
|
import BasicActionSheet from '@/components/BasicActionSheet.vue'
|
|
import DashboardQuickActionBtn from '@/pages/dashboard/components/DashboardQuickActionBtn.vue'
|
|
import { isMobile } from '@core/utils/is'
|
|
import { metalLabel } from '@/utils/adminMetalLabels'
|
|
|
|
type ActionVariant = 'default' | 'accent' | 'danger' | 'primary'
|
|
type ItemTone = 'slate' | 'emerald' | 'rose' | 'amber' | 'sky' | 'violet'
|
|
|
|
type ActionItem = {
|
|
key: string
|
|
label: string
|
|
shortLabel: string
|
|
icon: string
|
|
variant?: ActionVariant
|
|
danger?: boolean
|
|
disabled?: boolean
|
|
loading?: boolean
|
|
to?: RouteLocationRaw
|
|
onClick?: () => void
|
|
}
|
|
|
|
type MobileMenuItem = {
|
|
key: string
|
|
label: string
|
|
hint?: string
|
|
badge?: string
|
|
icon: string
|
|
tone?: ItemTone
|
|
disabled?: boolean
|
|
nav?: boolean
|
|
}
|
|
|
|
type MobileMenuGroup = {
|
|
title: string
|
|
items: MobileMenuItem[]
|
|
}
|
|
|
|
const props = defineProps<{
|
|
quickActionLoading: boolean
|
|
hasProductSnapshot: boolean
|
|
productSnapshotCount: number
|
|
}>()
|
|
|
|
const emit = defineEmits<{
|
|
wallet: []
|
|
deactivateAll: []
|
|
restoreProducts: []
|
|
closeAllBuy: []
|
|
closeAllSell: []
|
|
syncPrices: []
|
|
syncShow: []
|
|
}>()
|
|
|
|
const router = useRouter()
|
|
const menuOpen = ref(false)
|
|
|
|
const actionItems = computed<ActionItem[]>(() => [
|
|
{
|
|
key: 'wallet',
|
|
label: 'شارژ / دشارژ کیف پول',
|
|
shortLabel: 'کیف پول',
|
|
icon: 'vuesax-linear:empty-wallet',
|
|
variant: 'accent',
|
|
onClick: () => emit('wallet'),
|
|
},
|
|
{
|
|
key: 'deactivate-all',
|
|
label: 'بستن همه محصولات',
|
|
shortLabel: 'بستن همه محصولات',
|
|
icon: 'vuesax-linear:close-circle',
|
|
variant: 'danger',
|
|
danger: true,
|
|
loading: props.quickActionLoading,
|
|
onClick: () => emit('deactivateAll'),
|
|
},
|
|
{
|
|
key: 'restore',
|
|
label: 'بازگردانی محصولات قبلی',
|
|
shortLabel: 'بازگردانی محصولات',
|
|
icon: 'vuesax-linear:refresh-circle',
|
|
disabled: !props.hasProductSnapshot,
|
|
loading: props.quickActionLoading,
|
|
onClick: () => emit('restoreProducts'),
|
|
},
|
|
{
|
|
key: 'close-buy',
|
|
label: 'بستن خرید همه محصولات',
|
|
shortLabel: 'بستن خرید',
|
|
icon: 'vuesax-linear:money-receive',
|
|
loading: props.quickActionLoading,
|
|
onClick: () => emit('closeAllBuy'),
|
|
},
|
|
{
|
|
key: 'close-sell',
|
|
label: 'بستن فروش همه محصولات',
|
|
shortLabel: 'بستن فروش',
|
|
icon: 'vuesax-linear:money-send',
|
|
loading: props.quickActionLoading,
|
|
onClick: () => emit('closeAllSell'),
|
|
},
|
|
{
|
|
key: 'sync-prices',
|
|
label: 'همگامسازی قیمت محصولات',
|
|
shortLabel: 'همگامسازی قیمت',
|
|
icon: 'vuesax-linear:coin',
|
|
loading: props.quickActionLoading,
|
|
onClick: () => emit('syncPrices'),
|
|
},
|
|
{
|
|
key: 'sync-show',
|
|
label: 'بروزرسانی نمایش محصولات',
|
|
shortLabel: 'بروز نمایش',
|
|
icon: 'vuesax-linear:eye',
|
|
loading: props.quickActionLoading,
|
|
onClick: () => emit('syncShow'),
|
|
},
|
|
{
|
|
key: 'products',
|
|
label: 'مدیریت محصولات',
|
|
shortLabel: 'محصولات',
|
|
icon: 'vuesax-linear:box',
|
|
to: { name: 'productsMain_limitedOrder' },
|
|
},
|
|
{
|
|
key: 'orders',
|
|
label: 'لیست سفارشات',
|
|
shortLabel: 'سفارشات',
|
|
icon: 'vuesax-linear:receipt-2',
|
|
variant: 'primary',
|
|
to: { name: 'ordersMain' },
|
|
},
|
|
])
|
|
|
|
const mobileMenuGroups = computed<MobileMenuGroup[]>(() => [
|
|
{
|
|
title: 'محصولات',
|
|
items: [
|
|
{
|
|
key: 'deactivate-all',
|
|
label: 'بستن همه محصولات',
|
|
icon: 'vuesax-linear:close-circle',
|
|
tone: 'rose',
|
|
disabled: props.quickActionLoading,
|
|
},
|
|
{
|
|
key: 'restore',
|
|
label: 'بازگردانی محصولات',
|
|
hint: props.hasProductSnapshot ? 'بازگشت به وضعیت قبلی' : 'ابتدا محصولات را ببندید',
|
|
icon: 'vuesax-linear:refresh-circle',
|
|
tone: 'sky',
|
|
badge: props.productSnapshotCount ? String(props.productSnapshotCount) : undefined,
|
|
disabled: !props.hasProductSnapshot || props.quickActionLoading,
|
|
},
|
|
{
|
|
key: 'close-buy',
|
|
label: 'بستن خرید همه',
|
|
icon: 'vuesax-linear:money-receive',
|
|
tone: 'slate',
|
|
disabled: props.quickActionLoading,
|
|
},
|
|
{
|
|
key: 'close-sell',
|
|
label: 'بستن فروش همه',
|
|
icon: 'vuesax-linear:money-send',
|
|
tone: 'slate',
|
|
disabled: props.quickActionLoading,
|
|
},
|
|
{
|
|
key: 'sync-prices',
|
|
label: 'همگامسازی قیمت',
|
|
icon: 'vuesax-linear:coin',
|
|
tone: 'amber',
|
|
disabled: props.quickActionLoading,
|
|
},
|
|
{
|
|
key: 'sync-show',
|
|
label: 'بروزرسانی نمایش',
|
|
icon: 'vuesax-linear:eye',
|
|
tone: 'violet',
|
|
disabled: props.quickActionLoading,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
title: 'صفحات',
|
|
items: [
|
|
{
|
|
key: 'products',
|
|
label: 'مدیریت محصولات',
|
|
icon: 'vuesax-linear:box',
|
|
tone: 'slate',
|
|
nav: true,
|
|
},
|
|
{
|
|
key: 'orders',
|
|
label: 'لیست سفارشات',
|
|
icon: 'vuesax-linear:receipt-2',
|
|
tone: 'amber',
|
|
nav: true,
|
|
},
|
|
],
|
|
},
|
|
])
|
|
|
|
const mobileActions: Record<string, () => void> = {
|
|
wallet: () => emit('wallet'),
|
|
'deactivate-all': () => emit('deactivateAll'),
|
|
restore: () => emit('restoreProducts'),
|
|
'close-buy': () => emit('closeAllBuy'),
|
|
'close-sell': () => emit('closeAllSell'),
|
|
'sync-prices': () => emit('syncPrices'),
|
|
'sync-show': () => emit('syncShow'),
|
|
products: () => void router.push({ name: 'productsMain_limitedOrder' }),
|
|
orders: () => void router.push({ name: 'ordersMain' }),
|
|
}
|
|
|
|
function runAction(key: string) {
|
|
menuOpen.value = false
|
|
mobileActions[key]?.()
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.dashboard-operations-trigger {
|
|
@apply inline-flex h-9 w-full items-center justify-center gap-2 rounded-lg border border-white/30 bg-white px-3.5 text-sm font-semibold text-slate-800 shadow-md transition-all;
|
|
appearance: none;
|
|
}
|
|
|
|
.dashboard-operations-trigger:hover {
|
|
@apply bg-slate-50;
|
|
}
|
|
|
|
.dashboard-operations-trigger.is-open {
|
|
@apply border-amber-300 bg-amber-50 text-slate-900;
|
|
}
|
|
|
|
.dashboard-operations-trigger__chevron {
|
|
@apply opacity-60 transition-transform duration-200;
|
|
}
|
|
|
|
.dashboard-operations-trigger.is-open .dashboard-operations-trigger__chevron {
|
|
@apply rotate-180 opacity-80;
|
|
}
|
|
|
|
.dashboard-quick-actions-bar {
|
|
display: flex;
|
|
max-width: 100%;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
justify-content: flex-start;
|
|
gap: 0.375rem;
|
|
}
|
|
|
|
@media (min-width: 768px) and (max-width: 1279px) {
|
|
.dashboard-quick-actions-bar {
|
|
width: 100%;
|
|
justify-content: flex-start;
|
|
}
|
|
}
|
|
|
|
.dash-quick-sheet {
|
|
@apply pb-2;
|
|
}
|
|
|
|
.dash-quick-sheet__header {
|
|
@apply mb-4 px-1 text-center;
|
|
}
|
|
|
|
.dash-quick-sheet__title {
|
|
@apply text-base font-bold text-slate-800 dark:text-slate-100;
|
|
}
|
|
|
|
.dash-quick-sheet__subtitle {
|
|
@apply mt-0.5 text-xs text-slate-500;
|
|
}
|
|
|
|
.dash-quick-sheet__featured {
|
|
@apply mb-5 flex w-full items-center gap-3 rounded-2xl bg-gradient-to-l from-emerald-600 to-teal-600 p-3.5 text-right text-white shadow-lg shadow-emerald-900/15 transition-transform active:scale-[0.98];
|
|
appearance: none;
|
|
border: 0;
|
|
}
|
|
|
|
.dash-quick-sheet__featured-icon {
|
|
@apply flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-white/20 backdrop-blur-sm;
|
|
}
|
|
|
|
.dash-quick-sheet__featured-text {
|
|
@apply flex min-w-0 flex-1 flex-col gap-0.5;
|
|
}
|
|
|
|
.dash-quick-sheet__featured-label {
|
|
@apply text-sm font-bold leading-tight;
|
|
}
|
|
|
|
.dash-quick-sheet__featured-hint {
|
|
@apply text-[11px] leading-tight text-white/75;
|
|
}
|
|
|
|
.dash-quick-sheet__featured-arrow {
|
|
@apply shrink-0 opacity-70;
|
|
}
|
|
|
|
.dash-quick-sheet__section + .dash-quick-sheet__section {
|
|
@apply mt-4;
|
|
}
|
|
|
|
.dash-quick-sheet__section-title {
|
|
@apply mb-2 px-1 text-[11px] font-semibold tracking-wide text-slate-400;
|
|
}
|
|
|
|
.dash-quick-sheet__list {
|
|
@apply overflow-hidden rounded-2xl border border-slate-100 bg-slate-50/80 dark:border-slate-700/60 dark:bg-slate-800/40;
|
|
}
|
|
|
|
.dash-quick-sheet__item {
|
|
@apply flex w-full items-center gap-3 border-0 bg-transparent px-3 py-3 text-right transition-colors;
|
|
appearance: none;
|
|
}
|
|
|
|
.dash-quick-sheet__item + .dash-quick-sheet__item {
|
|
@apply border-t border-slate-100 dark:border-slate-700/60;
|
|
}
|
|
|
|
.dash-quick-sheet__item:active:not(:disabled) {
|
|
@apply bg-white dark:bg-slate-700/50;
|
|
}
|
|
|
|
.dash-quick-sheet__item:disabled {
|
|
@apply cursor-not-allowed opacity-45;
|
|
}
|
|
|
|
.dash-quick-sheet__badge {
|
|
@apply flex h-9 w-9 shrink-0 items-center justify-center rounded-xl;
|
|
}
|
|
|
|
.dash-quick-sheet__badge--slate {
|
|
@apply bg-slate-200/80 text-slate-600 dark:bg-slate-700 dark:text-slate-300;
|
|
}
|
|
|
|
.dash-quick-sheet__badge--emerald {
|
|
@apply bg-emerald-100 text-emerald-600 dark:bg-emerald-900/40 dark:text-emerald-300;
|
|
}
|
|
|
|
.dash-quick-sheet__badge--rose {
|
|
@apply bg-rose-100 text-rose-600 dark:bg-rose-900/40 dark:text-rose-300;
|
|
}
|
|
|
|
.dash-quick-sheet__badge--amber {
|
|
@apply bg-amber-100 text-amber-700 dark:bg-amber-900/40 dark:text-amber-300;
|
|
}
|
|
|
|
.dash-quick-sheet__badge--sky {
|
|
@apply bg-sky-100 text-sky-600 dark:bg-sky-900/40 dark:text-sky-300;
|
|
}
|
|
|
|
.dash-quick-sheet__badge--violet {
|
|
@apply bg-violet-100 text-violet-600 dark:bg-violet-900/40 dark:text-violet-300;
|
|
}
|
|
|
|
.dash-quick-sheet__item-body {
|
|
@apply flex min-w-0 flex-1 flex-col gap-0.5;
|
|
}
|
|
|
|
.dash-quick-sheet__item-label {
|
|
@apply text-[13px] font-semibold leading-tight text-slate-800 dark:text-slate-100;
|
|
}
|
|
|
|
.dash-quick-sheet__item-hint {
|
|
@apply text-[11px] leading-tight text-slate-400;
|
|
}
|
|
|
|
.dash-quick-sheet__item--rose .dash-quick-sheet__item-label {
|
|
@apply text-rose-700 dark:text-rose-300;
|
|
}
|
|
|
|
.dash-quick-sheet__count {
|
|
@apply rounded-full bg-slate-200/90 px-2 py-0.5 text-[10px] font-bold text-slate-600 dark:bg-slate-600 dark:text-slate-200;
|
|
}
|
|
|
|
.dash-quick-sheet__item-arrow {
|
|
@apply shrink-0 text-slate-300 dark:text-slate-500;
|
|
}
|
|
</style>
|