Add support panel UI, search filters, and money thousand separators.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-08 11:20:26 +03:30
co-authored by Cursor
parent ab4d9ef133
commit d0d621502f
13 changed files with 1169 additions and 132 deletions
+29 -4
View File
@@ -2,7 +2,7 @@
import { computed, onMounted, ref } from 'vue'
import { useRouter } from 'vue-router'
import { message } from 'ant-design-vue'
import { ArrowRightOutlined, AppstoreAddOutlined } from '@ant-design/icons-vue'
import { ArrowRightOutlined, AppstoreAddOutlined, SearchOutlined } from '@ant-design/icons-vue'
import api from '@/api/http'
type ExpiryLevel = 'healthy' | 'warning' | 'critical' | 'unknown' | 'none'
@@ -12,6 +12,7 @@ type TenantRow = {
product: 'hamkar' | 'khanegi'
nameFa: string
domain: string
slug?: string
pluginCount: number
summary: {
expiryLevel: ExpiryLevel
@@ -22,10 +23,22 @@ type TenantRow = {
const router = useRouter()
const loadingList = ref(false)
const tenants = ref<TenantRow[]>([])
const q = ref('')
const filteredTenants = computed(() => {
const term = q.value.trim().toLowerCase()
if (!term) return tenants.value
return tenants.value.filter((t) => {
const blob = [t.nameFa, t.domain, t.slug || '', t.summary?.expiryLabel || '']
.join(' ')
.toLowerCase()
return blob.includes(term)
})
})
const groupedTenants = computed(() => ({
hamkar: tenants.value.filter((t) => t.product === 'hamkar'),
khanegi: tenants.value.filter((t) => t.product === 'khanegi'),
hamkar: filteredTenants.value.filter((t) => t.product === 'hamkar'),
khanegi: filteredTenants.value.filter((t) => t.product === 'khanegi'),
}))
function toneClass(level?: ExpiryLevel) {
@@ -60,11 +73,23 @@ onMounted(loadTenants)
<div style="flex: 1">
<h1 class="page-title">پنل افزونه</h1>
<p class="page-sub">
اشتراک افزونه‌های نسخه‌ها — هر نسخه می‌تواند چند افزونه داشته باشد یا هیچ‌کدام
اشتراک افزونه‌های نسخه‌ها — هر نسخه می‌تواند چند افزونه داشته باشد یا هیچ‌کدام ·
{{ filteredTenants.length }} مورد
</p>
</div>
</div>
<div class="toolbar">
<a-input
v-model:value="q"
allow-clear
placeholder="جستجو نام، دامنه یا slug"
style="flex: 1; min-width: 180px"
>
<template #prefix><SearchOutlined /></template>
</a-input>
</div>
<div class="legend">
<span class="chip healthy">اعتبار کافی</span>
<span class="chip warning">نزدیک هشدار</span>