feat(customers): add Digipay installment admin section

Wire routes, settings groups, page access, and customer UI for installment management.
This commit is contained in:
2026-10-21 03:38:59 -04:00
parent e5b3d0c931
commit 88271dba2a
7 changed files with 129 additions and 1 deletions
@@ -15,6 +15,12 @@ export type SettingGroupDef = {
/** گروه‌های صفحه تنظیمات عادی (فقط can_edit=1) */ /** گروه‌های صفحه تنظیمات عادی (فقط can_edit=1) */
export const EDITABLE_SETTING_GROUPS: SettingGroupDef[] = [ export const EDITABLE_SETTING_GROUPS: SettingGroupDef[] = [
{
id: 'digipay_installment',
title: 'خرید اقساطی دیجی‌پی',
icon: 'vuesax-linear:calendar',
match: (k) => k === 'enable_digipay_installment' || k.startsWith('digipay_')
},
{ {
id: 'general', id: 'general',
title: 'عمومی و برند', title: 'عمومی و برند',
@@ -0,0 +1,84 @@
<template>
<BasicShowContext title="خرید اقساطی" :help="digipayInstallmentPageIntro">
<div class="flex flex-col gap-2 p-2.5">
<div class="text-sm font-bold">ثبت اعتبار بعد از دیجی‌پی</div>
<p class="text-xs opacity-70">
کاربر اول با لینک تنظیمات به دیجی‌پی می‌رود. بعد از احراز، مانده اعتبارش را اینجا بنویسید تا در اپ بتواند مس بخرد.
</p>
<a-form layout="vertical" class="sm:grid sm:grid-cols-2 sm:gap-2" @finish="save">
<a-form-item label="موبایل مشتری" name="mobile" :rules="[{ required: true, message: 'موبایل را وارد کنید' }]">
<a-input v-model:value="form.mobile" placeholder="09..." />
</a-form-item>
<a-form-item label="مانده ۴ قسط (تومان)" name="plan4">
<a-input-number v-model:value="form.plan4_toman" class="w-full" :min="0" />
</a-form-item>
<a-form-item label="مانده ۱۲ قسط (تومان)" name="plan12">
<a-input-number v-model:value="form.plan12_toman" class="w-full" :min="0" />
</a-form-item>
<a-form-item label=" " class="flex items-end">
<a-button type="primary" html-type="submit" :loading="saving">ثبت اعتبار</a-button>
</a-form-item>
</a-form>
<div class="mt-2 text-sm font-bold">خریدهای اخیر</div>
<a-table
size="small"
row-key="id"
:loading="loading"
:data-source="rows"
:pagination="false"
:columns="columns"
/>
</div>
</BasicShowContext>
</template>
<script setup lang="ts">
import { onMounted, reactive, ref } from 'vue'
import { message } from 'ant-design-vue'
import useAxios from '@core/utils/useAxios'
import { digipayInstallmentPageIntro } from '@/utils/adminHelpCopy'
const form = reactive({ mobile: '', plan4_toman: 0, plan12_toman: 0 })
const saving = ref(false)
const loading = ref(false)
const rows = ref<Record<string, unknown>[]>([])
const columns = [
{ title: 'مشتری', dataIndex: 'name' },
{ title: 'موبایل', dataIndex: 'mobile' },
{ title: 'طرح', dataIndex: 'plan' },
{ title: 'مبلغ مس (تومان)', dataIndex: 'amount_toman' },
{ title: 'کارمزد (تومان)', dataIndex: 'fee_toman' },
{ title: 'مقدار', dataIndex: 'grams' }
]
async function load() {
loading.value = true
try {
const res = await useAxios.post('/admin/digipay_installment/orders')
rows.value = res?.data?.data || res?.data || []
} finally {
loading.value = false
}
}
async function save() {
saving.value = true
try {
await useAxios.post('/admin/digipay_installment/credit', {
mobile: form.mobile,
plan4_toman: form.plan4_toman || 0,
plan12_toman: form.plan12_toman || 0
})
message.success('اعتبار ثبت شد')
await load()
} catch (e: any) {
message.error(e?.response?.data?.message || 'ثبت اعتبار انجام نشد')
} finally {
saving.value = false
}
}
onMounted(load)
</script>
+2 -1
View File
@@ -21,7 +21,7 @@ import { computed } from 'vue'
import BasicMenu from '@/components/BasicMenu/index.vue' import BasicMenu from '@/components/BasicMenu/index.vue'
import { useRouterStore } from '@core/stores/router' import { useRouterStore } from '@core/stores/router'
import { get } from 'lodash' import { get } from 'lodash'
import { customerSpecialPricingEnabledSetting, goldCreditEnabledSetting, initWalletSettingsFromApi } from '@/utils/config' import { customerSpecialPricingEnabledSetting, digipayInstallmentEnabledSetting, goldCreditEnabledSetting, initWalletSettingsFromApi } from '@/utils/config'
initWalletSettingsFromApi() initWalletSettingsFromApi()
@@ -36,6 +36,7 @@ const menu = computed(() => {
.filter((child) => { .filter((child) => {
if (child.name === 'customerMain_specialPrice') return customerSpecialPricingEnabledSetting.value if (child.name === 'customerMain_specialPrice') return customerSpecialPricingEnabledSetting.value
if (child.name === 'customerMain_goldCredit') return goldCreditEnabledSetting.value if (child.name === 'customerMain_goldCredit') return goldCreditEnabledSetting.value
if (child.name === 'customerMain_digipayInstallment') return digipayInstallmentEnabledSetting.value
return true return true
}) })
.sort((a, b) => (a.meta?.order ?? 99) - (b.meta?.order ?? 99)) .sort((a, b) => (a.meta?.order ?? 99) - (b.meta?.order ?? 99))
+10
View File
@@ -81,6 +81,16 @@ const Customers: RouteRecordRaw = {
order: 4 order: 4
} }
}, },
{
name: 'customerMain_digipayInstallment',
path: 'digipay-installment',
component: () => import('@/pages/menuPages/customers/digipayInstallment/index.vue'),
meta: {
icon: 'vuesax-linear:calendar',
title: 'خرید اقساطی',
order: 6
}
},
{ {
name: 'customerMain_goldCredit', name: 'customerMain_goldCredit',
path: 'gold-credit', path: 'gold-credit',
+3
View File
@@ -183,6 +183,9 @@ export const customersArchivePageIntro =
export const customersOnlinePageIntro = export const customersOnlinePageIntro =
'مشتریانی که الان اپ را باز دارند. با بستن اپ از لیست حذف می‌شوند. برای جزئیات روی کارت بزنید.' 'مشتریانی که الان اپ را باز دارند. با بستن اپ از لیست حذف می‌شوند. برای جزئیات روی کارت بزنید.'
export const digipayInstallmentPageIntro =
'بعد از احراز کاربر در دیجی‌پی، مانده اعتبار ۴ قسط و ۱۲ قسط را با موبایل مشتری اینجا بنویسید. خرید از اپ همان مانده را کم می‌کند و مس را به کیف می‌نشاند.'
export const goldCreditPageIntro = export const goldCreditPageIntro =
'اعتبار طلایی مشتریان: درخواست‌های جدید و اعتبارهای فعال. از تب‌ها بین درخواست و فعال جابه‌جا شوید.' 'اعتبار طلایی مشتریان: درخواست‌های جدید و اعتبارهای فعال. از تب‌ها بین درخواست و فعال جابه‌جا شوید.'
+8
View File
@@ -7,6 +7,7 @@ import {
customerSpecialPricingEnabledSetting, customerSpecialPricingEnabledSetting,
getConfigApp, getConfigApp,
giftCardEnabledSetting, giftCardEnabledSetting,
digipayInstallmentEnabledSetting,
goldCreditEnabledSetting, goldCreditEnabledSetting,
hasLandingSetting, hasLandingSetting,
isStoreApp, isStoreApp,
@@ -64,6 +65,12 @@ export const ADMIN_PAGE_TREE: AccessNode[] = [
title: 'اعتبار', title: 'اعتبار',
route: 'customerMain_goldCredit', route: 'customerMain_goldCredit',
enabled: () => goldCreditEnabledSetting.value enabled: () => goldCreditEnabledSetting.value
},
{
key: 'customerMain_digipayInstallment',
title: 'خرید اقساطی',
route: 'customerMain_digipayInstallment',
enabled: () => digipayInstallmentEnabledSetting.value
} }
] ]
}, },
@@ -240,6 +247,7 @@ export const PAGE_TABLE_ACTIONS: Record<string, PageTableAction[]> = {
{ key: 'toggle', label: 'فعال/غیرفعال' }, { key: 'toggle', label: 'فعال/غیرفعال' },
{ key: 'delete', label: 'حذف' } { key: 'delete', label: 'حذف' }
], ],
customerMain_digipayInstallment: [{ key: 'edit', label: 'ثبت اعتبار' }],
customerMain_goldCredit: [ customerMain_goldCredit: [
{ key: 'detail', label: 'جزئیات' }, { key: 'detail', label: 'جزئیات' },
{ key: 'edit', label: 'ویرایش' }, { key: 'edit', label: 'ویرایش' },
+16
View File
@@ -80,6 +80,9 @@ export const customerSpecialPricingEnabledSetting = ref(false)
/** reactive — زیرمنوی اعتبار طلایی در مشتریان */ /** reactive — زیرمنوی اعتبار طلایی در مشتریان */
export const goldCreditEnabledSetting = ref(false) export const goldCreditEnabledSetting = ref(false)
/** reactive — زیرمنوی خرید اقساطی دیجی‌پی */
export const digipayInstallmentEnabledSetting = ref(false)
/** reactive — منو و زنگوله اعلان داخل اپ */ /** reactive — منو و زنگوله اعلان داخل اپ */
export const appNotificationEnabledSetting = ref(true) export const appNotificationEnabledSetting = ref(true)
@@ -185,6 +188,10 @@ export function setCustomerSpecialPricingEnabledFromSettings(value: boolean): vo
customerSpecialPricingEnabledSetting.value = value customerSpecialPricingEnabledSetting.value = value
} }
export function setDigipayInstallmentEnabledFromSettings(value: boolean): void {
digipayInstallmentEnabledSetting.value = value
}
export function setGoldCreditEnabledFromSettings(value: boolean): void { export function setGoldCreditEnabledFromSettings(value: boolean): void {
goldCreditEnabledSetting.value = value goldCreditEnabledSetting.value = value
} }
@@ -314,6 +321,13 @@ export function applyCustomerSpecialPricingFromRows(
if (row) setCustomerSpecialPricingEnabledFromSettings(isSwitchOn(row.value)) if (row) setCustomerSpecialPricingEnabledFromSettings(isSwitchOn(row.value))
} }
export function applyDigipayInstallmentEnabledFromRows(
rows: Array<{ key?: string; value?: string | null }>
) {
const row = rows.find((item) => item.key === 'enable_digipay_installment')
if (row) setDigipayInstallmentEnabledFromSettings(isSwitchOn(row.value))
}
export function applyGoldCreditEnabledFromRows( export function applyGoldCreditEnabledFromRows(
rows: Array<{ key?: string; value?: string | null }> rows: Array<{ key?: string; value?: string | null }>
) { ) {
@@ -340,6 +354,7 @@ export function applySuperAdminAccessFlagsFromItems(
applyGroupSmsFromRows(rows) applyGroupSmsFromRows(rows)
applyCustomerSpecialPricingFromRows(rows) applyCustomerSpecialPricingFromRows(rows)
applyGoldCreditEnabledFromRows(rows) applyGoldCreditEnabledFromRows(rows)
applyDigipayInstallmentEnabledFromRows(rows)
applyConditionalOrderEnabledFromRows(rows) applyConditionalOrderEnabledFromRows(rows)
applyAutomationEnabledFromRows(rows) applyAutomationEnabledFromRows(rows)
applyProductFundsEnabledFromRows(rows) applyProductFundsEnabledFromRows(rows)
@@ -442,6 +457,7 @@ async function bootstrapSettingsFromApi(): Promise<void> {
applyGroupSmsFromRows(list) applyGroupSmsFromRows(list)
applyCustomerSpecialPricingFromRows(list) applyCustomerSpecialPricingFromRows(list)
applyGoldCreditEnabledFromRows(list) applyGoldCreditEnabledFromRows(list)
applyDigipayInstallmentEnabledFromRows(list)
applyConditionalOrderEnabledFromRows(list) applyConditionalOrderEnabledFromRows(list)
applyAutomationEnabledFromRows(list) applyAutomationEnabledFromRows(list)
applyProductFundsEnabledFromRows(list) applyProductFundsEnabledFromRows(list)