Merge remote-tracking branch 'origin/modular' into modular

This commit is contained in:
2026-07-21 16:59:50 +03:30
2 changed files with 158 additions and 75 deletions
@@ -79,7 +79,7 @@
</BasicActionSheet>
</template>
<div v-else class="flex max-w-full flex-wrap items-center justify-end gap-1.5 sm:justify-start">
<div v-else class="dashboard-quick-actions-bar">
<DashboardQuickActionBtn
v-for="item in actionItems"
:key="item.key"
@@ -347,6 +347,22 @@ function runAction(key: string) {
@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;
}
+141 -74
View File
@@ -5,9 +5,9 @@
<section
class="dashboard-hero rounded-xl bg-gradient-to-l from-[#0f766e] via-[#1e3a5f] to-[#0f172a] px-3 py-2.5 text-white shadow-md"
>
<div class="flex flex-col gap-2.5 md:flex-row md:items-center md:justify-between md:gap-3">
<div class="order-2 min-w-0 md:order-1">
<div class="flex min-w-0 flex-wrap items-center gap-x-2 gap-y-0.5">
<div class="dashboard-hero__row">
<div class="dashboard-hero__price min-w-0">
<div class="flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1">
<DashboardLabelWithHelp
label="مظنه"
:help="copy.hero"
@@ -16,17 +16,17 @@
label-class="text-white/80"
/>
<span class="text-[11px] text-white/80">/گرم</span>
<span class="text-lg font-bold leading-none">{{ usePrice(master?.price ?? 0, true, 'ریال') }}</span>
<span class="text-lg font-bold leading-none sm:text-xl">{{ usePrice(master?.price ?? 0, true, 'ریال') }}</span>
<span class="text-white/35">·</span>
<span class="text-[11px] text-white/80">مثقال</span>
<span class="text-sm font-semibold leading-none">{{ usePrice(master?.pricem ?? 0, true, 'ریال') }}</span>
<span class="text-sm font-semibold leading-none sm:text-base">{{ usePrice(master?.pricem ?? 0, true, 'ریال') }}</span>
</div>
<p v-if="master?.update_date" class="mt-1 text-[10px] leading-none text-white/55">
<p v-if="master?.update_date" class="mt-1.5 text-[10px] leading-none text-white/55">
{{ toJalali(master.update_date) }}
</p>
</div>
<div class="order-1 w-full shrink-0 md:order-2 md:w-auto">
<div class="dashboard-hero__actions min-w-0">
<DashboardQuickActionsBar
:quick-action-loading="quickActionLoading"
:has-product-snapshot="hasProductSnapshot"
@@ -226,9 +226,9 @@
</div>
</section>
<!-- Orders + side charts -->
<section class="mt-2 grid grid-cols-1 gap-2 xl:grid-cols-3">
<div class="flex flex-col gap-2 xl:col-span-1">
<!-- Orders + side charts — ارتفاع سفارشات = مجموع دو پنل کناری -->
<section class="dashboard-orders-row mt-2 grid grid-cols-1 gap-2 lg:grid-cols-3 lg:items-stretch">
<div class="dashboard-orders-side flex flex-col gap-2 lg:col-span-1">
<div class="dashboard-panel">
<div class="mb-2 flex items-start justify-between gap-2">
<DashboardSectionHeader
@@ -320,70 +320,72 @@
</div>
</div>
<div class="dashboard-panel xl:col-span-2">
<div class="mb-2 flex items-start justify-between gap-2">
<DashboardSectionHeader
class="!mb-0 min-w-0 flex-1"
title="آخرین سفارشات"
:help="copy.orders.recent"
/>
<router-link :to="{ name: 'ordersMain' }">
<a-button type="link" class="!px-0">همه سفارشات</a-button>
</router-link>
</div>
<div class="overflow-x-auto">
<table class="dashboard-table w-full min-w-[52rem] text-sm">
<thead>
<tr class="border-b text-xs">
<th class="px-2 py-2 text-right">کد</th>
<th class="px-2 py-2 text-right">نوع</th>
<th class="px-2 py-2 text-right">مشتری</th>
<th class="px-2 py-2 text-right">مقدار</th>
<th class="px-2 py-2 text-right">مظنه/گرم</th>
<th class="px-2 py-2 text-right">قیمت مشتری</th>
<th class="px-2 py-2 text-right">سود اختلاف قیمت/گرم</th>
<th class="px-2 py-2 text-right">سود کل اختلاف قیمت</th>
<th class="px-2 py-2 text-right">کارمزد (ریال)</th>
<th class="px-2 py-2 text-right">وضعیت</th>
<th class="px-2 py-2 text-right">تاریخ</th>
</tr>
</thead>
<tbody>
<tr
v-for="order in recentOrders"
:key="order.id"
class="border-b hover:bg-[var(--admin-bg-hover)]"
>
<td class="px-2 py-2.5 font-medium">#{{ order.id }}</td>
<td class="px-2 py-2.5">
<span class="rounded-md px-2 py-0.5 text-xs" :class="directionClass(order.direction)">
{{ directionLabel(order.direction) }}
</span>
</td>
<td class="max-w-[8rem] truncate px-2 py-2.5">{{ order.customer?.name ?? '—' }}</td>
<td class="px-2 py-2.5">{{ formatGram(order.amount) }}</td>
<td class="px-2 py-2.5">{{ usePrice(order.price_original ?? 0, true, 'ریال') }}</td>
<td class="px-2 py-2.5">{{ usePrice(order.price ?? 0, true, 'ریال') }}</td>
<td class="dashboard-profit px-2 py-2.5">
{{ usePrice(order.fee ?? 0, true, 'ریال') }}
</td>
<td class="dashboard-profit px-2 py-2.5 font-semibold">
{{ usePrice(order.total_fee ?? 0, true, 'ریال') }}
</td>
<td class="px-2 py-2.5">
{{ usePrice(order.service_charge_price ?? 0, true, 'ریال') }}
</td>
<td class="px-2 py-2.5">
<span class="rounded-md px-2 py-0.5 text-xs" :class="stsClass(order.sts)">
{{ stsLabel(order) }}
</span>
</td>
<td class="dashboard-text-muted whitespace-nowrap px-2 py-2.5 text-xs">
{{ order.created_at ? toJalali(order.created_at) : '—' }}
</td>
</tr>
</tbody>
</table>
<div class="dashboard-orders-main relative min-h-[22rem] lg:col-span-2 lg:min-h-0">
<div class="dashboard-panel dashboard-orders-panel flex h-full min-h-0 flex-col overflow-hidden lg:absolute lg:inset-0">
<div class="mb-2 flex shrink-0 items-start justify-between gap-2">
<DashboardSectionHeader
class="!mb-0 min-w-0 flex-1"
title="آخرین سفارشات"
:help="copy.orders.recent"
/>
<router-link :to="{ name: 'ordersMain' }">
<a-button type="link" class="!px-0">همه سفارشات</a-button>
</router-link>
</div>
<div class="min-h-0 flex-1 overflow-auto">
<table class="dashboard-table w-full min-w-[52rem] text-sm">
<thead>
<tr class="border-b text-xs">
<th class="px-2 py-2 text-right">کد</th>
<th class="px-2 py-2 text-right">نوع</th>
<th class="px-2 py-2 text-right">مشتری</th>
<th class="px-2 py-2 text-right">مقدار</th>
<th class="px-2 py-2 text-right">مظنه/گرم</th>
<th class="px-2 py-2 text-right">قیمت مشتری</th>
<th class="px-2 py-2 text-right">سود اختلاف قیمت/گرم</th>
<th class="px-2 py-2 text-right">سود کل اختلاف قیمت</th>
<th class="px-2 py-2 text-right">کارمزد (ریال)</th>
<th class="px-2 py-2 text-right">وضعیت</th>
<th class="px-2 py-2 text-right">تاریخ</th>
</tr>
</thead>
<tbody>
<tr
v-for="order in recentOrders"
:key="order.id"
class="border-b hover:bg-[var(--admin-bg-hover)]"
>
<td class="px-2 py-2.5 font-medium">#{{ order.id }}</td>
<td class="px-2 py-2.5">
<span class="rounded-md px-2 py-0.5 text-xs" :class="directionClass(order.direction)">
{{ directionLabel(order.direction) }}
</span>
</td>
<td class="max-w-[8rem] truncate px-2 py-2.5">{{ order.customer?.name ?? '—' }}</td>
<td class="px-2 py-2.5">{{ formatGram(order.amount) }}</td>
<td class="px-2 py-2.5">{{ usePrice(order.price_original ?? 0, true, 'ریال') }}</td>
<td class="px-2 py-2.5">{{ usePrice(order.price ?? 0, true, 'ریال') }}</td>
<td class="dashboard-profit px-2 py-2.5">
{{ usePrice(order.fee ?? 0, true, 'ریال') }}
</td>
<td class="dashboard-profit px-2 py-2.5 font-semibold">
{{ usePrice(order.total_fee ?? 0, true, 'ریال') }}
</td>
<td class="px-2 py-2.5">
{{ usePrice(order.service_charge_price ?? 0, true, 'ریال') }}
</td>
<td class="px-2 py-2.5">
<span class="rounded-md px-2 py-0.5 text-xs" :class="stsClass(order.sts)">
{{ stsLabel(order) }}
</span>
</td>
<td class="dashboard-text-muted whitespace-nowrap px-2 py-2.5 text-xs">
{{ order.created_at ? toJalali(order.created_at) : '—' }}
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</section>
@@ -625,6 +627,71 @@ const walletMetricItems = computed(() => [
padding: 1rem;
}
.dashboard-hero__row {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.dashboard-hero__actions {
width: 100%;
}
@media (min-width: 1280px) {
.dashboard-hero__row {
flex-direction: row;
align-items: center;
justify-content: space-between;
gap: 1rem;
}
.dashboard-hero__price {
order: 1;
min-width: 0;
}
.dashboard-hero__actions {
order: 2;
width: auto;
max-width: min(100%, 42rem);
flex-shrink: 0;
}
}
@media (min-width: 768px) and (max-width: 1279px) {
/* دسکتاپ باریک: مظنه بالا، دکمه‌ها زیرش در ردیف مرتب — نه قاطی کنار هم */
.dashboard-hero__row {
flex-direction: column;
align-items: stretch;
gap: 0.875rem;
}
.dashboard-hero__price {
order: 1;
}
.dashboard-hero__actions {
order: 2;
width: 100%;
}
}
/* ارتفاع «آخرین سفارشات» = ارتفاع ستون دو نمودار؛ جدول داخل اسکرول می‌شود */
@media (min-width: 1024px) {
.dashboard-orders-row {
align-items: stretch;
}
.dashboard-orders-main {
/* ارتفاع ردیف را ستون کناری تعیین می‌کند */
min-height: 0;
}
.dashboard-orders-panel {
max-height: 100%;
}
}
.dashboard-metrics-row {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));