added some feature for plugin

This commit is contained in:
2026-09-09 17:13:40 +03:30
parent c2f2b23afe
commit ba09c1d442
+68 -16
View File
@@ -8,6 +8,7 @@ import MoneyInput from '@/components/MoneyInput.vue'
import { useAuthStore } from '@/stores/auth'
import { SUPERADMIN_SYSTEM_SETTING_KEYS } from '@/config/superAdminSettingKeys'
import { rewriteLegacyUploadUrl } from '@/utils/rewriteLegacyUploadUrl'
import { formatNumber, rialToToman } from '@/utils/money'
import {
resolveSettingDescription,
resolveSettingTitle,
@@ -250,13 +251,19 @@ async function save(item: CatalogItem) {
return
}
}
const prices = item.prices.map((price) => ({
durationDays: price.durationDays,
enabled: price.enabled,
originalPriceRials:
price.enabled && price.hasDiscount ? price.originalPriceRials : price.finalPriceRials,
finalPriceRials: price.finalPriceRials,
}))
const prices = item.prices.map((price) => {
const finalPriceRials = Math.max(0, Math.trunc(Number(price.finalPriceRials) || 0))
const originalPriceRials =
price.enabled && price.hasDiscount
? Math.max(0, Math.trunc(Number(price.originalPriceRials) || 0))
: finalPriceRials
return {
durationDays: price.durationDays,
enabled: Boolean(price.enabled),
originalPriceRials,
finalPriceRials,
}
})
savingId.value = item.settingKey
try {
const id = await ensureCatalogId(item)
@@ -268,6 +275,7 @@ async function save(item: CatalogItem) {
prices,
})
message.success('ذخیره شد')
closeDetail()
await load()
} catch (e: any) {
const msg = e?.response?.data?.message
@@ -339,6 +347,17 @@ function slotUploader(item: CatalogItem) {
}) => uploadSlot(item, options)
}
function priceSummary(item: CatalogItem): string[] {
return item.prices
.filter((row) => row.enabled)
.map((row) => {
const toman = rialToToman(row.finalPriceRials)
const label = durationLabel[row.durationDays]
if (toman <= 0) return `${label} رایگان`
return `${label} ${formatNumber(toman)} تومان`
})
}
onMounted(load)
</script>
@@ -398,6 +417,10 @@ onMounted(load)
>
<strong>{{ item.titleFa || 'بدون عنوان' }}</strong>
<span class="catalog-key" dir="ltr">{{ item.settingKey }}</span>
<span v-if="priceSummary(item).length" class="catalog-prices">
{{ priceSummary(item).join(' · ') }}
</span>
<span v-else class="catalog-prices muted">قیمتی روشن نیست</span>
</button>
<div v-if="!filteredItems.length" class="empty-hint">
{{ items.length ? 'نتیجه‌ای برای این جستجو نیست' : 'کلید دسترسی‌ای در قالب نیست' }}
@@ -408,12 +431,13 @@ onMounted(load)
<a-modal
v-model:open="showDetail"
:title="selectedItem?.titleFa || 'جزئیات افزونه'"
width="40rem"
wrap-class-name="sa-modal-wrap"
width="64rem"
wrap-class-name="sa-modal-wrap catalog-detail-modal"
:footer="null"
@cancel="closeDetail"
>
<div v-if="selectedItem" class="catalog-detail">
<div class="catalog-detail-grid">
<a-form layout="vertical" class="catalog-form">
<a-form-item label="عنوان" required>
<a-input v-model:value="selectedItem.titleFa" :disabled="!canWrite" placeholder="مثلاً ماژول جدید" />
@@ -422,7 +446,7 @@ onMounted(load)
<a-input :value="selectedItem.settingKey" disabled dir="ltr" />
</a-form-item>
<a-form-item label="توضیح">
<a-textarea v-model:value="selectedItem.description" :rows="4" :maxlength="4000" :disabled="!canWrite" />
<a-textarea v-model:value="selectedItem.description" :rows="2" :maxlength="4000" :disabled="!canWrite" />
</a-form-item>
<a-form-item label="عکس‌ها">
<p class="img-hint">حداکثر سه عکس. در ادمین ماژول عکس اول روی کارت است.</p>
@@ -493,7 +517,7 @@ onMounted(load)
<span>اصلی</span>
<MoneyInput
v-model:value="price.originalPriceRials"
size="middle"
size="small"
addon-after="تومان"
:disabled="!canWrite || !price.enabled"
/>
@@ -502,7 +526,7 @@ onMounted(load)
<span>{{ price.hasDiscount ? 'نهایی' : 'قیمت' }}</span>
<MoneyInput
v-model:value="price.finalPriceRials"
size="middle"
size="small"
addon-after="تومان"
:disabled="!canWrite || !price.enabled"
/>
@@ -511,6 +535,7 @@ onMounted(load)
</article>
</div>
</section>
</div>
<a-button
v-if="canWrite"
type="primary"
@@ -633,9 +658,31 @@ onMounted(load)
direction: ltr;
unicode-bidi: isolate;
}
.catalog-prices {
font-size: 0.75rem;
color: #17324d;
font-weight: 700;
line-height: 1.45;
}
.catalog-prices.muted {
font-weight: 500;
color: #94a3b8;
}
.catalog-detail {
min-width: 0;
}
.catalog-detail-grid {
display: grid;
gap: 12px;
min-width: 0;
}
@media (min-width: 900px) {
.catalog-detail-grid {
grid-template-columns: minmax(16rem, 0.9fr) minmax(20rem, 1.2fr);
align-items: start;
gap: 14px;
}
}
.catalog-detail > .ant-btn {
margin-top: 12px;
}
@@ -679,6 +726,11 @@ onMounted(load)
display: grid;
gap: 8px;
}
@media (min-width: 640px) {
.price-list {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
.price-item {
border: 1px solid #e8eef5;
border-radius: 12px;
@@ -738,8 +790,9 @@ onMounted(load)
}
.img-slots {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
grid-template-columns: repeat(3, 4.75rem);
gap: 6px;
justify-content: start;
}
.img-slot {
position: relative;
@@ -768,9 +821,8 @@ onMounted(load)
font-size: 0.75rem;
}
.img-slots :deep(.ant-upload.ant-upload-select-picture-card) {
width: 100%;
height: auto;
aspect-ratio: 1;
width: 4.75rem;
height: 4.75rem;
margin: 0;
}
</style>