Files
boursecu_admin/src/pages/menuPages/customers/base/components/goldCreditSettingsModal.vue
T
mohmdsdgandCursor 084b449177 Add customers gold credit menu with request and active tabs.
Gate the submenu on enable_gold_credit and wire settings UI for SuperAdmin and tenant credit options.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-30 00:17:03 +03:30

165 lines
5.1 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<BasicModal
v-model:visible="modalVisible"
title="تنظیمات اعتبار طلایی"
width="48rem"
ok-text="بستن"
@ok="modalVisible = false"
>
<a-spin :spinning="loading">
<div class="space-y-4">
<div class="text-sm text-gray-500 mb-2">
این تنظیمات در اپ کاربر اعمال می‌شوند. روش‌های پرداخت غیرفعال در اپ نمایش داده نمی‌شوند؛
ادمین همچنان می‌تواند از همه روش‌ها استفاده کند.
</div>
<div
v-for="row in rows"
:key="row.id ?? row.key"
class="rounded-xl border border-slate-100 bg-slate-50/60 p-3"
>
<div class="font-medium text-sm text-gray-800 mb-1">{{ row.title_fa || row.key }}</div>
<div v-if="row.description" class="text-xs text-gray-500 mb-2 whitespace-pre-wrap">
{{ displayDescription(row) }}
</div>
<SettingValueField
:model-value="drafts[row.id!] ?? ''"
:setting-key="row.key"
:setting-type="row.type"
:description="row.description"
:rows="row.key === 'gold_credit_tiers' ? 6 : 4"
:disabled="savingIds.has(row.id!)"
@update:value="onDraftChange(row, $event)"
/>
<div v-if="savedFlashIds.has(row.id!)" class="text-xs text-green-600 mt-1">ذخیره شد</div>
</div>
</div>
</a-spin>
</BasicModal>
</template>
<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import { message } from 'ant-design-vue'
import { getConfiguration, setConfiguration } from '@/api/configuration'
import type { Const } from '@/model/configuration'
import SettingValueField from '@/pages/menuPages/configuration/SettingValueField.vue'
import { formatValueForSave, resolveSettingFieldType } from '@/pages/menuPages/configuration/settingTypes'
const GOLD_CREDIT_KEYS = [
'gold_credit_pay_gold_enabled',
'gold_credit_pay_rial_enabled',
'gold_credit_pay_mixed_enabled',
'gold_credit_min_balance_gram',
'gold_credit_default_months',
'gold_credit_info_text',
'gold_credit_request_success_text',
'gold_credit_tiers',
'gold_credit_penalty_type',
'gold_credit_penalty_amount',
'gold_credit_grace_hours',
]
const props = defineProps<{ visible?: boolean }>()
const emit = defineEmits<{ (e: 'update:visible', value: boolean): void }>()
const modalVisible = computed({
get: () => props.visible ?? false,
set: (v: boolean) => emit('update:visible', v),
})
const loading = ref(false)
const rows = ref<Const[]>([])
const drafts = ref<Record<number, string>>({})
const savingIds = ref(new Set<number>())
const savedFlashIds = ref(new Set<number>())
const saveTimers = new Map<number, ReturnType<typeof setTimeout>>()
const debounceTimers = new Map<number, ReturnType<typeof setTimeout>>()
function displayDescription(row: Const) {
if (row.type === 'select' && row.description?.includes('|')) {
return row.description.split('|')[0]
}
return row.description
}
watch(
() => props.visible,
async (open) => {
if (!open) return
loading.value = true
try {
const all = (await getConfiguration()) ?? []
rows.value = all
.filter((r) => r.key && GOLD_CREDIT_KEYS.includes(r.key))
.sort(
(a, b) =>
GOLD_CREDIT_KEYS.indexOf(a.key!) - GOLD_CREDIT_KEYS.indexOf(b.key!)
)
const next: Record<number, string> = {}
for (const row of rows.value) {
if (row.id != null) next[row.id] = String(row.value ?? '')
}
drafts.value = next
} finally {
loading.value = false
}
}
)
function onDraftChange(row: Const, value: string) {
if (row.id == null) return
drafts.value[row.id] = value
scheduleSave(row)
}
function scheduleSave(row: Const) {
if (row.id == null) return
if (debounceTimers.has(row.id)) clearTimeout(debounceTimers.get(row.id))
debounceTimers.set(
row.id,
setTimeout(() => {
void saveRow(row)
}, 600)
)
}
async function saveRow(row: Const) {
if (row.id == null) return
const type = resolveSettingFieldType(row)
const raw = drafts.value[row.id] ?? row.value ?? ''
const value = formatValueForSave(raw, type)
if (value === (row.value ?? '')) return
savingIds.value.add(row.id)
savedFlashIds.value.delete(row.id)
try {
await setConfiguration({
id: row.id,
key: row.key,
value,
description: row.description ?? '',
is_active: row.is_active,
title_fa: row.title_fa ?? '',
type,
})
row.value = value
savedFlashIds.value.add(row.id)
if (saveTimers.has(row.id)) clearTimeout(saveTimers.get(row.id))
saveTimers.set(
row.id,
setTimeout(() => {
savedFlashIds.value.delete(row.id!)
savedFlashIds.value = new Set(savedFlashIds.value)
}, 2000)
)
} catch {
drafts.value[row.id] = String(row.value ?? '')
message.error(`ذخیره «${row.title_fa || row.key}» ناموفق بود`)
} finally {
savingIds.value.delete(row.id)
savingIds.value = new Set(savingIds.value)
}
}
</script>