ui(admin-panel): responsive users, offers, reports, finance, sms, config, notify and branch menus

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
s.esmaeili
2026-10-13 10:30:25 +03:30
co-authored by Cursor
parent c1b3e90b9b
commit 5a30024548
35 changed files with 260 additions and 81 deletions
@@ -166,17 +166,29 @@ body #app .ant-menu-item-selected {
margin: 0; margin: 0;
} }
} }
// date-range filter rows on report pages: the two dates side by side, the
// action buttons on their own row without the blank spacer label
.filter-grid {
grid-template-columns: 1fr 1fr;
.ant-form-item:last-child {
grid-column: 1 / -1;
.ant-form-item-label {
display: none;
}
}
}
// a nested section card inside the page card: drop the double frame // a nested section card inside the page card: drop the double frame
.page-card .ant-card .ant-card, .page-card .ant-card .ant-card,
.page-card > .ant-card-body .ant-card { .page-card > .ant-card-body .ant-card {
box-shadow: none; box-shadow: none;
} }
// a horizontally scrollable plain <a-table> inside a page card // a horizontally scrollable plain <a-table> (class="table-scroll" on it or
.page-card .table-scroll .ant-table-content, // on any ancestor)
.table-scroll .ant-table-content,
.detail-modal .ant-table-content { .detail-modal .ant-table-content {
overflow-x: auto; overflow-x: auto;
} }
.page-card .table-scroll .ant-table-content > table, .table-scroll .ant-table-content > table,
.detail-modal .ant-table-content > table { .detail-modal .ant-table-content > table {
min-width: max-content; min-width: max-content;
} }
@@ -77,7 +77,7 @@
<!-- route-based fallback for direct links to /category/add/:id? --> <!-- route-based fallback for direct links to /category/add/:id? -->
<a-spin v-else :spinning="loading"> <a-spin v-else :spinning="loading">
<a-form layout="vertical" @submit.prevent="handleSubmit"> <a-form layout="vertical" @submit.prevent="handleSubmit">
<a-card :title="`دسته بندی ${typeSuffix}`" class="mb-base"> <a-card :title="`دسته بندی ${typeSuffix}`" class="mb-base page-card">
<a-form-item <a-form-item
label="نوع نمایش" label="نوع نمایش"
:validate-status="err.type ? 'error' : ''" :validate-status="err.type ? 'error' : ''"
@@ -129,7 +129,7 @@
<a-textarea v-model:value="form.body_html" :auto-size="{ minRows: 3, maxRows: 8 }" /> <a-textarea v-model:value="form.body_html" :auto-size="{ minRows: 3, maxRows: 8 }" />
</a-form-item> </a-form-item>
<a-button type="primary" @click="handleSubmit">ثبت اطلاعات</a-button> <a-button type="primary" class="form-submit" @click="handleSubmit">ثبت اطلاعات</a-button>
</a-card> </a-card>
</a-form> </a-form>
</a-spin> </a-spin>
@@ -5,8 +5,8 @@
slot in legacy stays absent. slot in legacy stays absent.
--> -->
<div id="page-user-list"> <div id="page-user-list">
<a-card title="لیست دسته بندی ها"> <a-card title="لیست دسته بندی ها" class="page-card">
<XTable ref="tbl" :model="model"> <XTable ref="tbl" :model="model" mobile-cards>
<template #add> <template #add>
<ListPageHeader rid="collection.create" add-label="افزودن دسته" @add="openAdd" /> <ListPageHeader rid="collection.create" add-label="افزودن دسته" @add="openAdd" />
</template> </template>
@@ -3,7 +3,7 @@
Ported from legacy henza_admin/src/views/branch/addCustomer.vue — a 19-line Ported from legacy henza_admin/src/views/branch/addCustomer.vue — a 19-line
wrapper whose entire template is <singleCustomer />. Kept as a wrapper. wrapper whose entire template is <singleCustomer />. Kept as a wrapper.
--> -->
<div> <div class="page-card">
<SingleCustomerForm /> <SingleCustomerForm />
</div> </div>
</template> </template>
@@ -7,8 +7,8 @@
only their own without the view having to filter. only their own without the view having to filter.
--> -->
<div id="page-user-list"> <div id="page-user-list">
<a-card title="فاکتور خرید"> <a-card title="فاکتور خرید" class="page-card">
<XTable ref="tbl" :model="model"> <XTable ref="tbl" :model="model" mobile-cards>
<template #opt="{ record }"> <template #opt="{ record }">
<a-tooltip title="مشاهده"> <a-tooltip title="مشاهده">
<EyeOutlined class="cursor-pointer mx-1 text-primary" @click="view(record)" /> <EyeOutlined class="cursor-pointer mx-1 text-primary" @click="view(record)" />
@@ -16,9 +16,9 @@
</template> </template>
</XTable> </XTable>
<a-modal v-model:open="visible" title="مشاهده فاکتور" width="70%"> <a-modal v-model:open="visible" title="مشاهده فاکتور" width="70%" wrap-class-name="detail-modal">
<div v-if="tempRow"> <div v-if="tempRow">
<a-descriptions bordered size="small" :column="2"> <a-descriptions bordered size="small" :column="{ xxl: 2, xl: 2, lg: 2, md: 2, sm: 2, xs: 1 }">
<a-descriptions-item label="شعبه">{{ tempRow.name }}</a-descriptions-item> <a-descriptions-item label="شعبه">{{ tempRow.name }}</a-descriptions-item>
<a-descriptions-item label="ثبت کننده"> <a-descriptions-item label="ثبت کننده">
{{ tempRow.allocator_user?.name ?? '-' }} {{ tempRow.allocator_user?.name ?? '-' }}
@@ -9,7 +9,7 @@
endpoints here, because a dashboard showing placeholder rows is worse than endpoints here, because a dashboard showing placeholder rows is worse than
one showing nothing. Recorded in docs/ADMIN-PORT-PLAN.md. one showing nothing. Recorded in docs/ADMIN-PORT-PLAN.md.
--> -->
<a-spin :spinning="loading"> <a-spin :spinning="loading" class="page-card table-scroll">
<a-card title="سفارشات هفته جاری"> <a-card title="سفارشات هفته جاری">
<a-table <a-table
size="small" size="small"
@@ -89,4 +89,10 @@ onMounted(async () => {
.mt-4 { .mt-4 {
margin-top: 1rem; margin-top: 1rem;
} }
@media (max-width: 575px) {
.mt-4 {
margin-top: 12px;
}
}
</style> </style>
@@ -11,7 +11,7 @@
branch mode gates the whole route instead. Preserved. branch mode gates the whole route instead. Preserved.
--> -->
<a-spin :spinning="loading"> <a-spin :spinning="loading">
<a-card title="ثبت سفارش"> <a-card title="ثبت سفارش" class="page-card">
<span>جهت ثبت سفارش مشتری را انتخاب نمایید</span> <span>جهت ثبت سفارش مشتری را انتخاب نمایید</span>
<a-form layout="vertical" class="mt-4" @submit.prevent="submitOrder"> <a-form layout="vertical" class="mt-4" @submit.prevent="submitOrder">
@@ -37,7 +37,7 @@
<div v-if="form.customer_id != null"> <div v-if="form.customer_id != null">
<h6>تعداد {{ items.length }} محصول انتخاب شده است.</h6> <h6>تعداد {{ items.length }} محصول انتخاب شده است.</h6>
<XTable ref="tblProducts" :model="cols"> <XTable ref="tblProducts" :model="cols" mobile-cards>
<template #image="{ record }"> <template #image="{ record }">
<img <img
width="90px" width="90px"
@@ -64,7 +64,7 @@
</template> </template>
</XTable> </XTable>
<a-card v-if="items.length > 0" title="سبد سفارش" class="mt-4"> <a-card v-if="items.length > 0" title="سبد سفارش" class="mt-4 table-scroll">
<a-table <a-table
:columns="columns" :columns="columns"
:data-source="items" :data-source="items"
@@ -107,7 +107,7 @@
<a-textarea v-model:value="form.note" :auto-size="{ minRows: 2, maxRows: 4 }" /> <a-textarea v-model:value="form.note" :auto-size="{ minRows: 2, maxRows: 4 }" />
</a-form-item> </a-form-item>
<a-button type="primary" :disabled="items.length < 1" @click="submitOrder"> <a-button type="primary" class="form-submit" :disabled="items.length < 1" @click="submitOrder">
ثبت سفارش ثبت سفارش
</a-button> </a-button>
</a-card> </a-card>
@@ -249,4 +249,20 @@ onMounted(async () => {
.totals { .totals {
margin: 1rem 0; margin: 1rem 0;
} }
@media (max-width: 575px) {
.customer-field {
max-width: none;
}
.mt-4 {
margin-top: 12px;
}
.totals {
margin: 12px 0;
}
h6 {
font-size: 12px;
margin-bottom: 8px;
}
}
</style> </style>
+2 -2
View File
@@ -6,8 +6,8 @@
city has none — so saving silently copied the parent's onto the child. city has none — so saving silently copied the parent's onto the child.
--> -->
<div id="page-user-list"> <div id="page-user-list">
<a-card title="لیست شهر ها"> <a-card title="لیست شهر ها" class="page-card">
<XTable ref="citiesTable" :model="model"> <XTable ref="citiesTable" :model="model" mobile-cards>
<template #add> <template #add>
<ListPageHeader rid="cities.create" add-label="افزودن شهر" @add="addOpen = true" /> <ListPageHeader rid="cities.create" add-label="افزودن شهر" @add="addOpen = true" />
</template> </template>
@@ -37,7 +37,7 @@
<!-- route-based fallback for direct links to /city/create --> <!-- route-based fallback for direct links to /city/create -->
<a-spin v-else :spinning="loading"> <a-spin v-else :spinning="loading">
<a-form layout="vertical" @submit.prevent="handleSubmit"> <a-form layout="vertical" @submit.prevent="handleSubmit">
<a-card title="افزودن شهر"> <a-card title="افزودن شهر" class="page-card">
<div class="grid-2"> <div class="grid-2">
<a-form-item label="نام شهر" :validate-status="err.title ? 'error' : ''" :help="err.title"> <a-form-item label="نام شهر" :validate-status="err.title ? 'error' : ''" :help="err.title">
<a-input v-model:value="form.title" /> <a-input v-model:value="form.title" />
@@ -52,7 +52,7 @@
<a-input-number v-model:value="form.percent_aux" class="w-full" :min="0" :max="100" :step="0.1" /> <a-input-number v-model:value="form.percent_aux" class="w-full" :min="0" :max="100" :step="0.1" />
</a-form-item> </a-form-item>
</div> </div>
<a-button type="primary" @click="handleSubmit">ثبت اطلاعات</a-button> <a-button type="primary" class="form-submit" @click="handleSubmit">ثبت اطلاعات</a-button>
</a-card> </a-card>
</a-form> </a-form>
</a-spin> </a-spin>
@@ -7,8 +7,8 @@
longer exists) becomes the bundled logo. longer exists) becomes the bundled logo.
--> -->
<div id="page-user-list"> <div id="page-user-list">
<a-card title="لیست دیدگاه ها"> <a-card title="لیست دیدگاه ها" class="page-card">
<XTable ref="tbl" :model="model"> <XTable ref="tbl" :model="model" mobile-cards>
<template #customer="{ text }"> <template #customer="{ text }">
{{ text && text.fname && text.lname ? `${text.fname} ${text.lname}` : 'بدون نام' }} {{ text && text.fname && text.lname ? `${text.fname} ${text.lname}` : 'بدون نام' }}
</template> </template>
@@ -92,7 +92,7 @@
</XTable> </XTable>
<!-- مشاهده دیدگاه --> <!-- مشاهده دیدگاه -->
<a-modal v-model:open="visibleComment" title="مشاهده دیدگاه" width="80%"> <a-modal v-model:open="visibleComment" title="مشاهده دیدگاه" width="80%" wrap-class-name="detail-modal">
<div v-if="tempRow" class="comments-list"> <div v-if="tempRow" class="comments-list">
<ul> <ul>
<li class="comment-item"> <li class="comment-item">
@@ -270,4 +270,20 @@ async function submitChanges(row: Record<string, any>) {
border: 1px solid grey; border: 1px solid grey;
border-radius: 50%; border-radius: 50%;
} }
@media (max-width: 575px) {
.comment-item {
gap: 10px;
flex-wrap: nowrap;
margin-bottom: 12px;
}
.comment-item .img {
width: 40px;
height: 40px;
flex-shrink: 0;
}
.comment-body {
min-width: 0;
}
}
</style> </style>
@@ -121,7 +121,7 @@
<!-- route-based fallback for direct links to /add/findoc and /edit/findoc/:id --> <!-- route-based fallback for direct links to /add/findoc and /edit/findoc/:id -->
<a-spin v-else :spinning="loading"> <a-spin v-else :spinning="loading">
<a-form layout="vertical" @submit.prevent="handleSubmit"> <a-form layout="vertical" @submit.prevent="handleSubmit">
<a-card title="ثبت سند مالی" class="mb-base"> <a-card title="ثبت سند مالی" class="mb-base page-card">
<div class="grid-3"> <div class="grid-3">
<a-form-item label="نوع سند"> <a-form-item label="نوع سند">
<a-select v-model:value="form.type"> <a-select v-model:value="form.type">
@@ -213,7 +213,7 @@
<a-textarea v-model:value="form.note" :auto-size="{ minRows: 3, maxRows: 5 }" /> <a-textarea v-model:value="form.note" :auto-size="{ minRows: 3, maxRows: 5 }" />
</a-form-item> </a-form-item>
<a-button type="primary" @click="handleSubmit">ثبت اطلاعات</a-button> <a-button type="primary" class="form-submit" @click="handleSubmit">ثبت اطلاعات</a-button>
</a-card> </a-card>
</a-form> </a-form>
</a-spin> </a-spin>
+2 -2
View File
@@ -7,8 +7,8 @@
--> -->
<div id="page-user-list"> <div id="page-user-list">
<a-spin :spinning="loading"> <a-spin :spinning="loading">
<a-card title="لیست اسناد مالی"> <a-card title="لیست اسناد مالی" class="page-card">
<XTable ref="tbl" :model="model"> <XTable ref="tbl" :model="model" mobile-cards>
<template #add> <template #add>
<ListPageHeader rid="document.create" add-label="ثبت سند مالی" @add="openAdd" /> <ListPageHeader rid="document.create" add-label="ثبت سند مالی" @add="openAdd" />
</template> </template>
@@ -26,7 +26,7 @@
@submit="handleSubmit" @submit="handleSubmit"
> >
<a-card title="لیست محصولات"> <a-card title="لیست محصولات">
<XTable ref="tblProducts" :model="productCols"> <XTable ref="tblProducts" :model="productCols" mobile-cards>
<template #image="{ record }"> <template #image="{ record }">
<img <img
width="90px" width="90px"
@@ -42,7 +42,7 @@
</XTable> </XTable>
</a-card> </a-card>
<a-card v-if="items.length > 0" title="ثبت سفارش" class="mt-5"> <a-card v-if="items.length > 0" title="ثبت سفارش" class="mt-5 table-scroll">
<a-table :columns="columns" :data-source="items" bordered :pagination="false" row-key="pid"> <a-table :columns="columns" :data-source="items" bordered :pagination="false" row-key="pid">
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'delete'"> <template v-if="column.dataIndex === 'delete'">
@@ -87,8 +87,8 @@
<!-- route-based fallback for direct links to /invoice/add and /invoice/edit/:id --> <!-- route-based fallback for direct links to /invoice/add and /invoice/edit/:id -->
<a-spin v-else :spinning="loading"> <a-spin v-else :spinning="loading">
<a-card title="لیست محصولات"> <a-card title="لیست محصولات" class="page-card">
<XTable ref="tblProducts" :model="productCols"> <XTable ref="tblProducts" :model="productCols" mobile-cards>
<template #image="{ record }"> <template #image="{ record }">
<img <img
width="90px" width="90px"
@@ -103,7 +103,7 @@
</template> </template>
</XTable> </XTable>
<a-card v-if="items.length > 0" title="ثبت سفارش" class="mt-5"> <a-card v-if="items.length > 0" title="ثبت سفارش" class="mt-5 table-scroll">
<a-table <a-table
:columns="columns" :columns="columns"
:data-source="items" :data-source="items"
@@ -151,7 +151,7 @@
</a-form-item> </a-form-item>
</div> </div>
<a-button type="primary" :disabled="items.length < 1" @click="handleSubmit"> <a-button type="primary" class="form-submit" :disabled="items.length < 1" @click="handleSubmit">
ثبت تغییرات ثبت تغییرات
</a-button> </a-button>
</a-form> </a-form>
@@ -4,8 +4,8 @@
branch-allocation grid. branch-allocation grid.
--> -->
<div id="page-user-list"> <div id="page-user-list">
<a-card title="لیست فاکتورها"> <a-card title="لیست فاکتورها" class="page-card">
<XTable ref="tbl" :model="model"> <XTable ref="tbl" :model="model" mobile-cards>
<template #add> <template #add>
<ListPageHeader rid="invoice.create" add-label="افزودن فاکتور" @add="openAdd" /> <ListPageHeader rid="invoice.create" add-label="افزودن فاکتور" @add="openAdd" />
</template> </template>
@@ -39,9 +39,9 @@
</template> </template>
</XTable> </XTable>
<a-modal v-model:open="visible" title="مشاهده فاکتور" width="70%"> <a-modal v-model:open="visible" title="مشاهده فاکتور" width="70%" wrap-class-name="detail-modal">
<div v-if="tempRow"> <div v-if="tempRow">
<a-descriptions bordered size="small" :column="2"> <a-descriptions bordered size="small" :column="{ xxl: 2, xl: 2, lg: 2, md: 2, sm: 2, xs: 1 }">
<a-descriptions-item label="شعبه">{{ tempRow.name }}</a-descriptions-item> <a-descriptions-item label="شعبه">{{ tempRow.name }}</a-descriptions-item>
<a-descriptions-item label="ثبت کننده"> <a-descriptions-item label="ثبت کننده">
{{ tempRow.allocator_user?.name ?? '-' }} {{ tempRow.allocator_user?.name ?? '-' }}
+18 -1
View File
@@ -12,7 +12,7 @@
one here too — each slide uses the shared ImageUploadInput, which posts to the one here too — each slide uses the shared ImageUploadInput, which posts to the
ported `file/create` endpoint and stores the returned URL. ported `file/create` endpoint and stores the returned URL.
--> -->
<a-card v-if="hasPermission('config.statics')" title="مدیریت ثابت ها"> <a-card v-if="hasPermission('config.statics')" title="مدیریت ثابت ها" class="page-card table-scroll">
<a-spin :spinning="loading"> <a-spin :spinning="loading">
<a-tabs> <a-tabs>
<!-- برندها --> <!-- برندها -->
@@ -380,4 +380,21 @@ onMounted(async () => {
.mt-4 { .mt-4 {
margin-top: 1rem; margin-top: 1rem;
} }
@media (max-width: 575px) {
/* the add-row input fills what the button leaves instead of a fixed 260px */
.row > .ant-input {
flex: 1 1 140px;
max-width: none !important;
}
.slide {
padding: 10px;
}
.slide .row > * {
flex: 1 1 100%;
}
.mt-4 {
margin-top: 12px;
}
}
</style> </style>
@@ -7,7 +7,7 @@
the server only ever says whether one is set, never what it is. the server only ever says whether one is set, never what it is.
--> -->
<div> <div>
<a-card v-if="hasPermission('config.accounting')" title="اتصال به نرم‌افزار حسابداری"> <a-card v-if="hasPermission('config.accounting')" title="اتصال به نرم‌افزار حسابداری" class="page-card table-scroll">
<template #extra> <template #extra>
<a-space> <a-space>
<a-tag v-if="overview?.busy" color="processing">همگام‌سازی در حال اجرا</a-tag> <a-tag v-if="overview?.busy" color="processing">همگام‌سازی در حال اجرا</a-tag>
@@ -766,4 +766,32 @@ pre {
white-space: pre-wrap; white-space: pre-wrap;
word-break: break-all; word-break: break-all;
} }
@media (max-width: 575px) {
.mb-4 {
margin-bottom: 12px;
}
.mt-4 {
margin-top: 12px;
}
/* toolbars above the log/links/movement tables: wrap instead of overflowing */
:deep(.ant-space) {
flex-wrap: wrap;
}
:deep(.ant-tabs-tabpane > .ant-space .ant-select),
:deep(.ant-tabs-tabpane > .ant-space .ant-input-search),
:deep(.ant-tabs-tabpane > .ant-space .ant-input) {
width: 100% !important;
}
:deep(.ant-tabs-tabpane > .ant-space > .ant-space-item) {
flex: 1 1 140px;
}
:deep(.ant-alert) {
padding: 10px 12px;
}
:deep(.ant-alert-with-description .ant-alert-icon) {
font-size: 18px;
margin-inline-end: 8px;
}
}
</style> </style>
+13 -1
View File
@@ -3,7 +3,7 @@
Ported from legacy henza_admin/src/views/manage/report.vue — a shortcut board Ported from legacy henza_admin/src/views/manage/report.vue — a shortcut board
of report links, read from the `dashboard.links` setting. of report links, read from the `dashboard.links` setting.
--> -->
<a-card title="مدیریت گزارشات"> <a-card title="مدیریت گزارشات" class="page-card">
<a-empty v-if="links.length === 0" description="هنوز لینکی تعریف نشده است" /> <a-empty v-if="links.length === 0" description="هنوز لینکی تعریف نشده است" />
<div v-else class="links"> <div v-else class="links">
<a v-for="(l, i) in links" :key="i" :href="l.url" target="_blank" class="link-card"> <a v-for="(l, i) in links" :key="i" :href="l.url" target="_blank" class="link-card">
@@ -39,4 +39,16 @@ onMounted(async () => {
color: #1c2d56; color: #1c2d56;
} }
.link-card:hover { border-color: #1c2d56; } .link-card:hover { border-color: #1c2d56; }
@media (max-width: 575px) {
.links {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
}
.link-card {
padding: 12px;
text-align: center;
}
}
</style> </style>
+15 -1
View File
@@ -9,7 +9,7 @@
draft side by side → the admin confirms the sample is right → «تأیید و draft side by side → the admin confirms the sample is right → «تأیید و
ثبت». The approved sample is kept with the formula as its reference. ثبت». The approved sample is kept with the formula as its reference.
--> -->
<div v-if="hasPermission('config.wage')" class="wage"> <div v-if="hasPermission('config.wage')" class="wage page-card">
<a-spin :spinning="loading"> <a-spin :spinning="loading">
<!-- ── status ─────────────────────────────────────────── --> <!-- ── status ─────────────────────────────────────────── -->
<a-card class="mb-4" :bordered="false"> <a-card class="mb-4" :bordered="false">
@@ -498,4 +498,18 @@ onMounted(async () => {
.hist { padding: 8px 0; border-bottom: 1px solid #f5f5f5; } .hist { padding: 8px 0; border-bottom: 1px solid #f5f5f5; }
.hist__meta { font-size: 12px; color: #888; } .hist__meta { font-size: 12px; color: #888; }
@media (max-width: 575px) {
.mb-4 { margin-bottom: 12px; }
.mt-4 { margin-top: 12px; }
.wage :deep(.ant-row) { row-gap: 12px !important; }
.status__title { font-size: 14px; }
.formula { padding: 10px 12px; font-size: 13px; line-height: 2; }
.chip { padding: 0 8px; line-height: 24px; }
.num { width: 100%; flex: 1 1 140px; }
.limit .num { width: auto; flex: 1 1 140px; }
.sample { grid-template-columns: 1fr 1fr; gap: 10px; }
.cmp { font-size: 12px; }
.cmp th, .cmp td { padding: 6px; }
}
</style> </style>
+3 -3
View File
@@ -8,7 +8,7 @@
active tab — so the visually-second tab opens first. active tab — so the visually-second tab opens first.
--> -->
<div> <div>
<a-card v-if="hasPermission('config.wallet')" title="مدیریت کیف پول"> <a-card v-if="hasPermission('config.wallet')" title="مدیریت کیف پول" class="page-card">
<a-tabs default-active-key="1"> <a-tabs default-active-key="1">
<a-tab-pane key="2" tab="تاریخ تولد" force-render> <a-tab-pane key="2" tab="تاریخ تولد" force-render>
<a-spin :spinning="loading" tip="لطفا کمی تامل کنید"> <a-spin :spinning="loading" tip="لطفا کمی تامل کنید">
@@ -29,7 +29,7 @@
<a-input-number v-model:value="form2.birthday_credit" class="w-full" :min="0" /> <a-input-number v-model:value="form2.birthday_credit" class="w-full" :min="0" />
</a-form-item> </a-form-item>
</div> </div>
<a-button type="primary" class="mb-4 mt-4 mr-4" @click="setWallet2">ارسال</a-button> <a-button type="primary" class="mb-4 mt-4 mr-4 form-submit" @click="setWallet2">ارسال</a-button>
</a-form> </a-form>
</a-spin> </a-spin>
</a-tab-pane> </a-tab-pane>
@@ -60,7 +60,7 @@
/> />
</a-form-item> </a-form-item>
</div> </div>
<a-button type="primary" class="mb-4 mt-4 mr-4" @click="setWallet1">ارسال</a-button> <a-button type="primary" class="mb-4 mt-4 mr-4 form-submit" @click="setWallet1">ارسال</a-button>
</a-form> </a-form>
</a-spin> </a-spin>
</a-tab-pane> </a-tab-pane>
@@ -3,8 +3,8 @@
Ported from legacy henza_admin/src/views/newsletters/newsletters.vue. Ported from legacy henza_admin/src/views/newsletters/newsletters.vue.
The delete action is COMMENTED OUT in legacy and stays absent. The delete action is COMMENTED OUT in legacy and stays absent.
--> -->
<a-card title="لیست خبرنامه"> <a-card title="لیست خبرنامه" class="page-card">
<XTable ref="newsletter" :model="model"> <XTable ref="newsletter" :model="model" mobile-cards>
<template #actions="{ record }"> <template #actions="{ record }">
<span class="muted">{{ record.email ?? '-' }}</span> <span class="muted">{{ record.email ?? '-' }}</span>
</template> </template>
+2 -2
View File
@@ -1,7 +1,7 @@
<template> <template>
<!-- Ported from legacy henza_admin/src/views/notify/create.vue. --> <!-- Ported from legacy henza_admin/src/views/notify/create.vue. -->
<a-spin :spinning="loading"> <a-spin :spinning="loading">
<a-card title="ارسال نوتیفیکیشن"> <a-card title="ارسال نوتیفیکیشن" class="page-card">
<a-form layout="vertical" @submit.prevent="handleSubmit"> <a-form layout="vertical" @submit.prevent="handleSubmit">
<div class="grid-2"> <div class="grid-2">
<a-form-item label="عنوان" :validate-status="err.title ? 'error' : ''" :help="err.title"> <a-form-item label="عنوان" :validate-status="err.title ? 'error' : ''" :help="err.title">
@@ -21,7 +21,7 @@
<a-textarea v-model:value="form.text" :auto-size="{ minRows: 4, maxRows: 8 }" /> <a-textarea v-model:value="form.text" :auto-size="{ minRows: 4, maxRows: 8 }" />
</a-form-item> </a-form-item>
<a-button type="primary" @click="handleSubmit">ارسال</a-button> <a-button type="primary" class="form-submit" @click="handleSubmit">ارسال</a-button>
</a-form> </a-form>
</a-card> </a-card>
</a-spin> </a-spin>
+3 -3
View File
@@ -3,8 +3,8 @@
Ported from legacy henza_admin/src/views/notify/user.vue — the received Ported from legacy henza_admin/src/views/notify/user.vue — the received
notifications list, with a read-state modal. notifications list, with a read-state modal.
--> -->
<a-card title="لیست نوتیفیکیشن های دریافتی"> <a-card title="لیست نوتیفیکیشن های دریافتی" class="page-card">
<XTable ref="tbl" :model="model"> <XTable ref="tbl" :model="model" mobile-cards>
<template #opt="{ record }"> <template #opt="{ record }">
<a-tooltip title="مشاهده"> <a-tooltip title="مشاهده">
<EyeOutlined class="cursor-pointer mx-1 text-primary" @click="view(record)" /> <EyeOutlined class="cursor-pointer mx-1 text-primary" @click="view(record)" />
@@ -12,7 +12,7 @@
</template> </template>
</XTable> </XTable>
<a-modal v-model:open="visible" title="مشاهده نوتیفیکیشن" width="60%"> <a-modal v-model:open="visible" title="مشاهده نوتیفیکیشن" width="60%" wrap-class-name="detail-modal">
<div v-if="tempRow"> <div v-if="tempRow">
<a-descriptions bordered size="small" :column="1"> <a-descriptions bordered size="small" :column="1">
<a-descriptions-item label="عنوان">{{ tempRow.title }}</a-descriptions-item> <a-descriptions-item label="عنوان">{{ tempRow.title }}</a-descriptions-item>
@@ -10,7 +10,7 @@
The card title in legacy is "تعریف تخفیف" (the same string the promotion form The card title in legacy is "تعریف تخفیف" (the same string the promotion form
uses) even though this screen defines EXCLUSIONS — preserved, not corrected. uses) even though this screen defines EXCLUSIONS — preserved, not corrected.
--> -->
<div id="page-user-view"> <div id="page-user-view" class="page-card">
<div id="user-data"> <div id="user-data">
<a-spin :spinning="loading"> <a-spin :spinning="loading">
<a-form layout="vertical"> <a-form layout="vertical">
@@ -27,7 +27,7 @@
<template v-if="type === 1"> <template v-if="type === 1">
<h6>تعداد {{ selectedRow.length }} محصول انتخاب شده است</h6> <h6>تعداد {{ selectedRow.length }} محصول انتخاب شده است</h6>
<XTable ref="tblProducts" v-model="selectedRow" :model="productCols" :has-selection="true"> <XTable ref="tblProducts" v-model="selectedRow" :model="productCols" :has-selection="true" mobile-cards>
<template #image="{ record }"> <template #image="{ record }">
<img <img
width="90px" width="90px"
@@ -42,24 +42,24 @@
<template v-if="type === 2"> <template v-if="type === 2">
<h6>تعداد {{ selectedRow.length }} دسته بندی انتخاب شده است</h6> <h6>تعداد {{ selectedRow.length }} دسته بندی انتخاب شده است</h6>
<XTable ref="tblCategory" v-model="selectedRow" :model="categoryCols" :has-selection="true" /> <XTable ref="tblCategory" v-model="selectedRow" :model="categoryCols" :has-selection="true" mobile-cards />
<h6>تعداد {{ selectedRow.length }} دسته بندی انتخاب شده است</h6> <h6>تعداد {{ selectedRow.length }} دسته بندی انتخاب شده است</h6>
</template> </template>
<template v-if="type === 3"> <template v-if="type === 3">
<h6>تعداد {{ selectedRow.length }} مشتری انتخاب شده است</h6> <h6>تعداد {{ selectedRow.length }} مشتری انتخاب شده است</h6>
<XTable ref="tblCustomer" v-model="selectedRow" :model="customerCols" :has-selection="true" /> <XTable ref="tblCustomer" v-model="selectedRow" :model="customerCols" :has-selection="true" mobile-cards />
<h6>تعداد {{ selectedRow.length }} مشتری انتخاب شده است</h6> <h6>تعداد {{ selectedRow.length }} مشتری انتخاب شده است</h6>
</template> </template>
<template v-if="type === 4"> <template v-if="type === 4">
<h6>تعداد {{ selectedRow.length }} برند انتخاب شده است</h6> <h6>تعداد {{ selectedRow.length }} برند انتخاب شده است</h6>
<XTable ref="tblBrand" v-model="selectedRow" :model="brandCols" :has-selection="true" /> <XTable ref="tblBrand" v-model="selectedRow" :model="brandCols" :has-selection="true" mobile-cards />
<h6>تعداد {{ selectedRow.length }} برند انتخاب شده است</h6> <h6>تعداد {{ selectedRow.length }} برند انتخاب شده است</h6>
</template> </template>
<div class="mt-5"> <div class="mt-5">
<a-button type="primary" class="mr-4" @click="handleSubmit">ثبت</a-button> <a-button type="primary" class="mr-4 form-submit" @click="handleSubmit">ثبت</a-button>
</div> </div>
</a-card> </a-card>
</a-form> </a-form>
@@ -221,4 +221,17 @@ onMounted(getData);
.mt-5 { .mt-5 {
margin-top: 1.25rem; margin-top: 1.25rem;
} }
@media (max-width: 575px) {
.mb-10 {
margin-bottom: 12px;
}
.mt-5 {
margin-top: 12px;
}
h6 {
font-size: 12px;
margin-bottom: 8px;
}
}
</style> </style>
@@ -128,7 +128,7 @@
<!-- route-based fallback for direct links to /major/promotion/(tak/)add and .../edit/:id --> <!-- route-based fallback for direct links to /major/promotion/(tak/)add and .../edit/:id -->
<a-spin v-else :spinning="loading"> <a-spin v-else :spinning="loading">
<a-form layout="vertical" @submit.prevent="handleSubmit"> <a-form layout="vertical" @submit.prevent="handleSubmit">
<a-card :title="title" class="mb-base"> <a-card :title="title" class="mb-base page-card">
<div class="grid-4 grid-4--tight"> <div class="grid-4 grid-4--tight">
<a-form-item label="نوع تخفیف"> <a-form-item label="نوع تخفیف">
<!-- legacy disables the type selector while editing --> <!-- legacy disables the type selector while editing -->
@@ -242,7 +242,7 @@
<a-textarea v-model:value="form.description" :auto-size="{ minRows: 3, maxRows: 6 }" /> <a-textarea v-model:value="form.description" :auto-size="{ minRows: 3, maxRows: 6 }" />
</a-form-item> </a-form-item>
<a-button type="primary" @click="handleSubmit">ثبت اطلاعات</a-button> <a-button type="primary" class="form-submit" @click="handleSubmit">ثبت اطلاعات</a-button>
</a-card> </a-card>
</a-form> </a-form>
</a-spin> </a-spin>
@@ -3,7 +3,7 @@
Ported from legacy henza_admin/src/views/promotion/autopromotion.vue — Ported from legacy henza_admin/src/views/promotion/autopromotion.vue —
the one-shot welcome discount for new customers. State toggle + percentage. the one-shot welcome discount for new customers. State toggle + percentage.
--> -->
<a-form layout="vertical" @submit.prevent="handleSubmit"> <a-form layout="vertical" class="page-card" @submit.prevent="handleSubmit">
<a-spin :spinning="loading"> <a-spin :spinning="loading">
<a-card title="تخفیف اتوماتیک یکبار مصرف ویژه مشتریان جدید" class="mb-base"> <a-card title="تخفیف اتوماتیک یکبار مصرف ویژه مشتریان جدید" class="mb-base">
<div class="grid-3"> <div class="grid-3">
@@ -30,7 +30,7 @@
</a-card> </a-card>
</a-spin> </a-spin>
<a-button type="primary" class="mr-4" @click="handleSubmit">ثبت اطلاعات</a-button> <a-button type="primary" class="mr-4 form-submit" @click="handleSubmit">ثبت اطلاعات</a-button>
</a-form> </a-form>
</template> </template>
@@ -7,8 +7,8 @@
commented-out `sts` and `confirmed` slots which stay absent. commented-out `sts` and `confirmed` slots which stay absent.
--> -->
<div id="page-user-list"> <div id="page-user-list">
<a-card title="لیست تخفیف ها"> <a-card title="لیست تخفیف ها" class="page-card">
<XTable ref="tbl" :model="model"> <XTable ref="tbl" :model="model" mobile-cards>
<template #add> <template #add>
<div class="list-page-header-row"> <div class="list-page-header-row">
<ListPageHeader rid="offers.create" add-label="افزودن تخفیف عمده" @add="openAdd('omde')" /> <ListPageHeader rid="offers.create" add-label="افزودن تخفیف عمده" @add="openAdd('omde')" />
@@ -140,5 +140,12 @@ async function deletePromotion(record: Record<string, any>) {
display: flex; display: flex;
gap: 0.5rem; gap: 0.5rem;
} }
@media (max-width: 575px) {
.list-page-header-row {
flex-wrap: wrap;
justify-content: flex-end;
}
}
</style> </style>
@@ -8,9 +8,9 @@
--> -->
<div id="page-user-list"> <div id="page-user-list">
<a-spin :spinning="loading"> <a-spin :spinning="loading">
<a-card title="گزارش تجمیعی سفارشات و اسناد مالی"> <a-card title="گزارش تجمیعی سفارشات و اسناد مالی" class="page-card table-scroll">
<a-form layout="vertical"> <a-form layout="vertical">
<div class="grid-4"> <div class="grid-4 filter-grid">
<DateInput v-model="filters.start_date" label="از تاریخ" /> <DateInput v-model="filters.start_date" label="از تاریخ" />
<DateInput v-model="filters.end_date" label="تا تاریخ" /> <DateInput v-model="filters.end_date" label="تا تاریخ" />
<a-form-item label=" "> <a-form-item label=" ">
@@ -122,4 +122,15 @@ onMounted(load);
.mt-4 { .mt-4 {
margin-top: 1rem; margin-top: 1rem;
} }
@media (max-width: 575px) {
.summary {
flex-wrap: wrap;
row-gap: 6px;
margin-top: 0;
}
.mt-4 {
margin-top: 12px;
}
}
</style> </style>
+13 -2
View File
@@ -5,9 +5,9 @@
--> -->
<div id="page-user-list"> <div id="page-user-list">
<a-spin :spinning="loading"> <a-spin :spinning="loading">
<a-card title="گزارش محصولات"> <a-card title="گزارش محصولات" class="page-card table-scroll">
<a-form layout="vertical"> <a-form layout="vertical">
<div class="grid-4"> <div class="grid-4 filter-grid">
<DateInput v-model="filters.start_date" label="از تاریخ" /> <DateInput v-model="filters.start_date" label="از تاریخ" />
<DateInput v-model="filters.end_date" label="تا تاریخ" /> <DateInput v-model="filters.end_date" label="تا تاریخ" />
<a-form-item label=" "> <a-form-item label=" ">
@@ -80,4 +80,15 @@ onMounted(load);
.mt-4 { .mt-4 {
margin-top: 1rem; margin-top: 1rem;
} }
@media (max-width: 575px) {
.summary {
flex-wrap: wrap;
row-gap: 6px;
margin-top: 0;
}
.mt-4 {
margin-top: 12px;
}
}
</style> </style>
+7 -3
View File
@@ -7,7 +7,7 @@
NOTE the "تک فروشی" audience has a rid (sms.create.tak) but NO option in the NOTE the "تک فروشی" audience has a rid (sms.create.tak) but NO option in the
legacy markup, so it is unreachable. Preserved as absent. legacy markup, so it is unreachable. Preserved as absent.
--> -->
<a-spin :spinning="loading"> <a-spin :spinning="loading" class="page-card">
<a-card title="ارسال پیامک"> <a-card title="ارسال پیامک">
<a-form layout="vertical" @submit.prevent="handleSubmit"> <a-form layout="vertical" @submit.prevent="handleSubmit">
<div class="grid-2"> <div class="grid-2">
@@ -51,12 +51,12 @@
<a-textarea v-model:value="text" :auto-size="{ minRows: 4, maxRows: 8 }" /> <a-textarea v-model:value="text" :auto-size="{ minRows: 4, maxRows: 8 }" />
</a-form-item> </a-form-item>
<a-button type="primary" @click="handleSubmit">ارسال</a-button> <a-button type="primary" class="form-submit" @click="handleSubmit">ارسال</a-button>
</a-form> </a-form>
</a-card> </a-card>
<a-card v-if="hasPermission('sms.list')" title="لیست پیامک ها" class="mt-4"> <a-card v-if="hasPermission('sms.list')" title="لیست پیامک ها" class="mt-4">
<XTable ref="tbl" :model="model" /> <XTable ref="tbl" :model="model" mobile-cards />
</a-card> </a-card>
</a-spin> </a-spin>
</template> </template>
@@ -111,4 +111,8 @@ async function handleSubmit() {
<style scoped> <style scoped>
/* .grid-2 now comes from the global utilities.less (dedup) */ /* .grid-2 now comes from the global utilities.less (dedup) */
.mt-4 { margin-top: 1rem; } .mt-4 { margin-top: 1rem; }
@media (max-width: 575px) {
.mt-4 { margin-top: 12px; }
}
</style> </style>
+1 -1
View File
@@ -4,7 +4,7 @@
activity log ("آمار"). Pick a customer, see their recent actions. activity log ("آمار"). Pick a customer, see their recent actions.
--> -->
<a-spin :spinning="loading"> <a-spin :spinning="loading">
<a-card title="آمار"> <a-card title="آمار" class="page-card table-scroll">
<a-form layout="vertical"> <a-form layout="vertical">
<div class="grid-2"> <div class="grid-2">
<a-form-item label="مشتری"> <a-form-item label="مشتری">
+2 -2
View File
@@ -5,8 +5,8 @@
user-type list, as legacy did. user-type list, as legacy did.
--> -->
<div id="page-user-list"> <div id="page-user-list">
<a-card title="لیست مدیران"> <a-card title="لیست مدیران" class="page-card">
<XTable ref="tbl" :model="model"> <XTable ref="tbl" :model="model" mobile-cards>
<!-- legacy ListUser.vue:4 — the add-user button, gated on the same rid. --> <!-- legacy ListUser.vue:4 — the add-user button, gated on the same rid. -->
<template #add> <template #add>
<ListPageHeader rid="user.list.create" add-label="افزودن کاربر" @add="openAdd" /> <ListPageHeader rid="user.list.create" add-label="افزودن کاربر" @add="openAdd" />
+13 -1
View File
@@ -13,7 +13,7 @@
is drawn with a rotated border that lands wrong under [dir=rtl]. is drawn with a rotated border that lands wrong under [dir=rtl].
--> -->
<a-form layout="vertical" @submit.prevent="handleSubmit"> <a-form layout="vertical" @submit.prevent="handleSubmit">
<a-card id="rid" title="دسترسی ها"> <a-card id="rid" title="دسترسی ها" class="page-card">
<div class="grid-2"> <div class="grid-2">
<a-form-item <a-form-item
label="سطح کاربر" label="سطح کاربر"
@@ -52,6 +52,7 @@
<a-button <a-button
v-if="!newUT && hasPermission('user.permission.edit')" v-if="!newUT && hasPermission('user.permission.edit')"
type="primary" type="primary"
class="form-submit"
html-type="submit" html-type="submit"
> >
ثبت تغییرات ثبت تغییرات
@@ -60,6 +61,7 @@
<a-button <a-button
v-if="newUT && hasPermission('user.permission.create')" v-if="newUT && hasPermission('user.permission.create')"
type="primary" type="primary"
class="form-submit"
html-type="submit" html-type="submit"
> >
افزودن افزودن
@@ -211,4 +213,14 @@ onMounted(async () => {
.tree-item { .tree-item {
grid-column: 1 / -1; grid-column: 1 / -1;
} }
@media (max-width: 575px) {
/* the permission tree nests deep; a smaller indent keeps titles readable */
.tree-item :deep(.ant-tree-indent-unit) {
width: 14px;
}
.tree-item :deep(.ant-tree-node-content-wrapper) {
white-space: normal;
}
}
</style> </style>
@@ -82,7 +82,7 @@
<!-- route-based fallback for direct links to /user/create and /user/edit/:id --> <!-- route-based fallback for direct links to /user/create and /user/edit/:id -->
<a-spin v-else :spinning="loading"> <a-spin v-else :spinning="loading">
<a-form layout="vertical" @submit.prevent="handleSubmit"> <a-form layout="vertical" @submit.prevent="handleSubmit">
<a-card :title="id ? 'ویرایش مدیر' : 'افزودن مدیر'" class="mb-base"> <a-card :title="id ? 'ویرایش مدیر' : 'افزودن مدیر'" class="mb-base page-card">
<div class="grid-3"> <div class="grid-3">
<a-form-item label="نام" :validate-status="err.fname ? 'error' : ''" :help="err.fname"> <a-form-item label="نام" :validate-status="err.fname ? 'error' : ''" :help="err.fname">
<a-input v-model:value="form.fname" /> <a-input v-model:value="form.fname" />
@@ -139,7 +139,7 @@
<p v-if="id" class="hint">برای تغییر ندادن رمز عبور، هر دو فیلد رمز را خالی بگذارید.</p> <p v-if="id" class="hint">برای تغییر ندادن رمز عبور، هر دو فیلد رمز را خالی بگذارید.</p>
<a-button type="primary" @click="handleSubmit">ثبت اطلاعات</a-button> <a-button type="primary" class="form-submit" @click="handleSubmit">ثبت اطلاعات</a-button>
</a-card> </a-card>
</a-form> </a-form>
</a-spin> </a-spin>
+2 -2
View File
@@ -9,8 +9,8 @@
real title is shown when present, with the same fallback — the fallback is real title is shown when present, with the same fallback — the fallback is
what legacy actually displayed. what legacy actually displayed.
--> -->
<a-card title="اطلاعات کاربری"> <a-card title="اطلاعات کاربری" class="page-card">
<a-descriptions> <a-descriptions :column="{ xxl: 3, xl: 3, lg: 3, md: 2, sm: 2, xs: 1 }">
<a-descriptions-item label="نام">{{ user?.fname || '-' }}</a-descriptions-item> <a-descriptions-item label="نام">{{ user?.fname || '-' }}</a-descriptions-item>
<a-descriptions-item label="نام خانوادگی">{{ user?.lname || '-' }}</a-descriptions-item> <a-descriptions-item label="نام خانوادگی">{{ user?.lname || '-' }}</a-descriptions-item>
<a-descriptions-item label="شماره تلفن">{{ user?.mobile || '-' }}</a-descriptions-item> <a-descriptions-item label="شماره تلفن">{{ user?.mobile || '-' }}</a-descriptions-item>
+2 -2
View File
@@ -7,8 +7,8 @@
mismatch, preserved. mismatch, preserved.
--> -->
<div> <div>
<a-card v-if="hasPermission('wallet.percent')" title="لیست کیف پول های شارژ شده"> <a-card v-if="hasPermission('wallet.percent')" title="لیست کیف پول های شارژ شده" class="page-card">
<XTable ref="tbl" :model="model"> <XTable ref="tbl" :model="model" mobile-cards>
<template #time="{ text }"> <template #time="{ text }">
{{ text ? jdateTime(text) : '' }} {{ text ? jdateTime(text) : '' }}
</template> </template>