Add support panel UI, search filters, and money thousand separators.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -6,7 +6,9 @@ import { ArrowRightOutlined } from '@ant-design/icons-vue'
|
||||
import type { TableColumnsType } from 'ant-design-vue'
|
||||
import api from '@/api/http'
|
||||
import JalaliDatePicker from '@/components/JalaliDatePicker.vue'
|
||||
import MoneyInput from '@/components/MoneyInput.vue'
|
||||
import { formatIranDateTime, todayIranDateInput } from '@/utils/datetime'
|
||||
import { formatMoney, formatNumber } from '@/utils/money'
|
||||
|
||||
type BalanceLevel = 'healthy' | 'warning' | 'critical' | 'unknown'
|
||||
|
||||
@@ -96,42 +98,6 @@ const pageSize = 20
|
||||
|
||||
const tenantId = computed(() => String(route.params.tenantId || ''))
|
||||
|
||||
function toGroupedDisplay(value: number | null | undefined) {
|
||||
if (value == null || Number.isNaN(Number(value))) return ''
|
||||
const n = Math.trunc(Number(value))
|
||||
const neg = n < 0
|
||||
const digits = String(Math.abs(n))
|
||||
const grouped = digits.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
||||
return neg ? `-${grouped}` : grouped
|
||||
}
|
||||
|
||||
function fromGroupedInput(raw: string, allowNegative = false) {
|
||||
const text = String(raw ?? '')
|
||||
const neg = allowNegative && text.trim().startsWith('-')
|
||||
const digits = text.replace(/[^\d]/g, '')
|
||||
if (!digits) return 0
|
||||
const n = Number(digits)
|
||||
return neg ? -n : n
|
||||
}
|
||||
|
||||
function onGroupedMoneyInput(
|
||||
apply: (n: number) => void,
|
||||
value: string | number,
|
||||
allowNegative = false,
|
||||
) {
|
||||
apply(fromGroupedInput(String(value ?? ''), allowNegative))
|
||||
}
|
||||
|
||||
function formatNumber(value: number | null | undefined) {
|
||||
if (value == null) return '—'
|
||||
return new Intl.NumberFormat('fa-IR').format(value)
|
||||
}
|
||||
|
||||
function formatMoney(value: number | null | undefined) {
|
||||
if (value == null) return '—'
|
||||
return `${formatNumber(value)} ریال`
|
||||
}
|
||||
|
||||
function toneClass(level?: BalanceLevel) {
|
||||
return level || 'unknown'
|
||||
}
|
||||
@@ -478,13 +444,7 @@ onMounted(async () => {
|
||||
<div class="subcard sky">
|
||||
<h3>تعرفه پیامک</h3>
|
||||
<div class="inline-actions">
|
||||
<a-input
|
||||
size="large"
|
||||
dir="ltr"
|
||||
class="money-input"
|
||||
:value="toGroupedDisplay(form.pricePerPartRials)"
|
||||
@update:value="(v: string | number) => onGroupedMoneyInput((n) => (form.pricePerPartRials = n), v)"
|
||||
/>
|
||||
<MoneyInput v-model:value="form.pricePerPartRials" placeholder="قیمت هر پارت" />
|
||||
<a-button type="primary" size="large" :loading="saving" @click="savePrice">ذخیره قیمت</a-button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -492,13 +452,10 @@ onMounted(async () => {
|
||||
<div class="subcard emerald">
|
||||
<h3>شارژ کیف پول</h3>
|
||||
<div class="charge-grid">
|
||||
<a-input
|
||||
size="large"
|
||||
dir="ltr"
|
||||
class="money-input"
|
||||
<MoneyInput
|
||||
v-model:value="chargeForm.amountRials"
|
||||
allow-negative
|
||||
placeholder="مبلغ (ریال)"
|
||||
:value="toGroupedDisplay(chargeForm.amountRials)"
|
||||
@update:value="(v: string | number) => onGroupedMoneyInput((n) => (chargeForm.amountRials = n), v, true)"
|
||||
/>
|
||||
<a-input v-model:value="chargeForm.note" size="large" placeholder="توضیح (اختیاری)" />
|
||||
<a-button type="primary" size="large" :loading="charging" @click="openChargeConfirm">
|
||||
@@ -542,23 +499,11 @@ onMounted(async () => {
|
||||
<div class="threshold-grid">
|
||||
<label>
|
||||
<span class="tone-label"><i class="dot critical" /> آستانه قرمز</span>
|
||||
<a-input
|
||||
size="large"
|
||||
dir="ltr"
|
||||
class="money-input"
|
||||
:value="toGroupedDisplay(form.alertCriticalRials)"
|
||||
@update:value="(v: string | number) => onGroupedMoneyInput((n) => (form.alertCriticalRials = n), v)"
|
||||
/>
|
||||
<MoneyInput v-model:value="form.alertCriticalRials" />
|
||||
</label>
|
||||
<label>
|
||||
<span class="tone-label"><i class="dot warning" /> آستانه زرد</span>
|
||||
<a-input
|
||||
size="large"
|
||||
dir="ltr"
|
||||
class="money-input"
|
||||
:value="toGroupedDisplay(form.alertWarningRials)"
|
||||
@update:value="(v: string | number) => onGroupedMoneyInput((n) => (form.alertWarningRials = n), v)"
|
||||
/>
|
||||
<MoneyInput v-model:value="form.alertWarningRials" />
|
||||
</label>
|
||||
<a-button type="primary" size="large" :loading="saving" @click="saveThresholds">ذخیره آستانهها</a-button>
|
||||
</div>
|
||||
@@ -1007,10 +952,6 @@ onMounted(async () => {
|
||||
font-size: 0.78rem;
|
||||
}
|
||||
|
||||
.money-input :deep(input) {
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.money-input,
|
||||
.filter-row :deep(.jalali-date-field),
|
||||
.filter-row :deep(.ant-input),
|
||||
|
||||
Reference in New Issue
Block a user