added fund

This commit is contained in:
2026-08-01 17:30:37 +03:30
parent 6a9e5aee47
commit 9a975e1cba
10 changed files with 348 additions and 104 deletions
+23
View File
@@ -9,6 +9,29 @@ export const getReferralsTable = async (params: TableInput,customer_id: number)
//funds
export const getFundsTable = async (params: TableInput,customer_id: number) => await useAxios.post<Array<Funds>>(`/admin/customers/${customer_id}/funds`, params)
export const getPiggyFundsTable = async (params: TableInput, customer_id: number) =>
await useAxios.post(`/admin/customers/${customer_id}/piggy-funds`, params)
export const getAssetPiggyFundsTable = async (
params: TableInput,
customer_id: number,
product_id: number
) => await useAxios.post(`/admin/customers/${customer_id}/assets/${product_id}/piggy-funds`, params)
export const getAssetTransactionsTable = async (
params: TableInput,
customer_id: number,
product_id: number
) =>
await useAxios.post(`/admin/customers/${customer_id}/assets/${product_id}/transactions`, params)
export const getPiggyFundTransactionsTable = async (
params: TableInput,
customer_id: number,
fund_id: number
) =>
await useAxios.post(`/admin/customers/${customer_id}/piggy-funds/${fund_id}/transactions`, params)
export const getReferrals = async (val: Referrals) => await useAxios.post<Funds>(`/admin/customers/4/referrals`, val)
//me
export const getMyInformation = async () => await useAxios.get<User>('/admin/me')
+6 -1
View File
@@ -174,7 +174,7 @@ import SettingValueField from './SettingValueField.vue'
import SettingCard from './SettingCard.vue'
import { refreshAppModeMenu } from '@/router'
import { useUserStore } from '@/store/userStore'
import { applyBannerEnabledFromRows, applyTrackingSystemsEnabledFromRows, applyConditionalOrderEnabledFromRows, applyPriceTriggerEnabledFromRows, applyAppNotificationEnabledFromRows, applyPriceProviderFromRows, applySupportChatMenuEnabledFromRows, setBannerEnabledFromSettings, setConditionalOrderEnabledFromSettings, setPriceTriggerEnabledFromSettings, setAppNotificationEnabledFromSettings, setPriceProviderFromSettings, setStoreModeFromSettings, setTrackingSystemsEnabledFromSettings } from '@/utils/config'
import { applyBannerEnabledFromRows, applyTrackingSystemsEnabledFromRows, applyConditionalOrderEnabledFromRows, applyProductFundsEnabledFromRows, applyPriceTriggerEnabledFromRows, applyAppNotificationEnabledFromRows, applyPriceProviderFromRows, applySupportChatMenuEnabledFromRows, setBannerEnabledFromSettings, setConditionalOrderEnabledFromSettings, setProductFundsEnabledFromSettings, setPriceTriggerEnabledFromSettings, setAppNotificationEnabledFromSettings, setPriceProviderFromSettings, setStoreModeFromSettings, setTrackingSystemsEnabledFromSettings } from '@/utils/config'
import {
EDITABLE_SETTING_GROUPS,
SYSTEM_SETTING_GROUPS,
@@ -423,6 +423,7 @@ async function initConfig() {
applyBannerEnabledFromRows(baseData.value)
applyTrackingSystemsEnabledFromRows(baseData.value)
applyConditionalOrderEnabledFromRows(baseData.value)
applyProductFundsEnabledFromRows(baseData.value)
applyPriceTriggerEnabledFromRows(baseData.value)
applyAppNotificationEnabledFromRows(baseData.value)
applyPriceProviderFromRows(baseData.value)
@@ -483,6 +484,10 @@ function syncMenuFlagsFromSetting(key: string | undefined, value: string) {
setConditionalOrderEnabledFromSettings(isSwitchOn(value))
return
}
if (key === 'enable_product_funds') {
setProductFundsEnabledFromSettings(isSwitchOn(value))
return
}
if (key === 'has_page_price_trigger') {
setPriceTriggerEnabledFromSettings(isSwitchOn(value))
return
@@ -134,7 +134,7 @@ export const SYSTEM_SETTING_GROUPS: SettingGroupDef[] = [
title: 'دسترسی مشتری به قابلیت‌ها',
icon: 'vuesax-linear:people',
match: (k) =>
/^(enable_conditional_order|has_page_price_trigger|has_page_notification|banner_enabled|jibit_enabled|customer_direct_sms|has_page_earn_money|group_sms|tracking_systems_enabled|permision__enabled|show_to_users_chat)$/.test(
/^(enable_conditional_order|enable_product_funds|has_page_price_trigger|has_page_notification|banner_enabled|jibit_enabled|customer_direct_sms|has_page_earn_money|group_sms|tracking_systems_enabled|permision__enabled|show_to_users_chat)$/.test(
k
)
},
@@ -245,6 +245,7 @@ const KEY_TYPE_FALLBACK: Record<string, SettingFieldType> = {
fee_free: 'number',
fee_conditional_order: 'price',
enable_conditional_order: 'switch',
enable_product_funds: 'switch',
has_page_price_trigger: 'switch',
has_page_notification: 'switch',
min_withdraw: 'price',
@@ -627,6 +628,8 @@ const KEY_HELP_FALLBACK: Record<string, string> = {
'مبلغ ریالی که با هر بار ثبت تریگر سفارش شرطی از کیف پول ریالی مشتری کم می‌شود. صفر = رایگان.',
enable_conditional_order:
'روشن: قابلیت سفارش شرطی سراسری فعال است. خاموش: منو و ارزیابی اجرا نمی‌شود. فقط از صفحه دیپلوی قابل تغییر است.',
enable_product_funds:
'روشن: ساخت و مدیریت قلک per-product در اپ مشتری فعال است (یک محصول در هر قلک؛ انتقال بدون سند حسابداری). خاموش: منو و API ساخت قلک جدید در دسترس نیست. فقط از دیپلوی قابل تغییر است.',
has_page_price_trigger:
'روشن: منوی هشدار قیمت در اپ مشتری نمایش داده می‌شود. خاموش: منو و صفحه مخفی است. فقط از صفحه دیپلوی قابل تغییر است.',
has_page_notification:
@@ -910,6 +913,7 @@ export const KEY_LABEL_FALLBACK: Record<string, string> = {
fee_free: 'معافیت کارمزد سفارش اول',
fee_conditional_order: 'کارمزد سفارش شرطی',
enable_conditional_order: 'سفارش شرطی',
enable_product_funds: 'قلک محصول',
has_page_price_trigger: 'هشدار قیمت',
has_page_notification: 'اعلان داخل اپ',
jibit_enabled: 'احراز هویت جیبیت',
@@ -1021,6 +1025,7 @@ export const SETTING_LOCKED_KEYS = new Set([
'group_sms',
'customer_direct_sms',
'enable_conditional_order',
'enable_product_funds',
'has_page_price_trigger',
'has_page_notification',
'jibit_enabled',
@@ -1,103 +1,140 @@
<template>
<div>
<BasicShowContext title="لیست قلک ها">
<BasicShowContext title="لیست دارایی ها">
<BaseTable v-bind="tblProps" @register="submit" ref="tbl">
<template #action="{ record }">
<div class="flex items-center justify-center gap-2">
<a-tooltip placement="bottom">
<template #title><span>قلک‌های این دارایی</span></template>
<Icon
class="cursor-pointer"
icon="vuesax-linear:safe-home"
color="#7C3AED"
@click="openAssetFunds(record)"
/>
</a-tooltip>
<a-tooltip placement="bottom">
<template #title><span>تراکنش‌های این دارایی</span></template>
<Icon
class="cursor-pointer"
icon="vuesax-linear:receipt-2"
color="#4572E9"
@click="openAssetTx(record)"
/>
</a-tooltip>
</div>
</template>
</BaseTable>
</BasicShowContext>
<BasicActionSheet
v-model:visible="assetFundsVisible"
:title="assetSheetTitle"
@close="assetFundsVisible = false"
>
<BaseTable v-if="assetFundsVisible" v-bind="assetFundsTblProps" @register="assetFundsSubmit" />
</BasicActionSheet>
<BasicActionSheet
v-model:visible="assetTxVisible"
:title="assetTxSheetTitle"
@close="assetTxVisible = false"
>
<BaseTable v-if="assetTxVisible" v-bind="assetTxTblProps" @register="assetTxSubmit" />
</BasicActionSheet>
</div>
</template>
<script lang="tsx" setup>
import type {TableInput} from '@core/type/baseTable'
import type { TableInput } from '@core/type/baseTable'
import useBaseTable from '@core/components/BaseTable/hooks/useBaseTable'
import Icon from '@core/components/BaseIcon/src/Icon.vue'
import { cols } from '@/pages/menuPages/customers/base/hooks/fundsColumns'
import { piggyFundsCols } from '@/pages/menuPages/customers/base/hooks/piggyFundsColumns'
import { onMounted, ref, computed } from 'vue'
import {
changeCustomerActivation,
changeCustomerArchive,
changeCustomerOrderActivation,
confirmUser,
getCustomerTable
} from '@/api/customer'
import {cols} from '@/pages/menuPages/customers/base/hooks/fundsColumns'
import {useUserStore} from '@/store/userStore'
import {usePrefix} from '@core/composable/usePrefix'
import {message} from 'ant-design-vue'
import {inputRules} from '@/utils/inputRules'
import type {User} from '@/model/user'
import {toJalaliNoTime} from '@core/utils/useDataTime'
import type {Customer} from '@/model/customer'
import {onMounted} from 'vue'
import {getFundsTable} from "@/api/user";
getFundsTable,
getAssetPiggyFundsTable,
getAssetTransactionsTable
} from '@/api/user'
import BasicActionSheet from '@/components/BasicActionSheet.vue'
import BasicShowContext from '@/components/BasicShowContext.vue'
const [submit, reload] = useBaseTable()
const [assetFundsSubmit] = useBaseTable()
const [assetTxSubmit] = useBaseTable()
interface Prop {
customerId?: number
}
const emits = defineEmits(['delete', 'edit', 'add', 'info', 'chargeMoney', 'chargeGold'])
const props = defineProps<Prop>()
const {prefixCls} = usePrefix('pophoverstatus')
//permission
function checkPermission(temp: string) {
const store = useUserStore()
return store.canAccess(temp)
}
//define table
const table = ref(null)
const confirmVisible = ref<boolean>(false)
const confirmInfo = ref<Customer>()
const tblProps = ref<any>({
columns: cols,
api: (params: TableInput) => {
return getFundsTable(params, props.customerId)
}
//bordered: true
api: (params: TableInput) => getFundsTable(params, props.customerId!)
})
const refPop = ref()
const loading = ref<boolean>(false)
const assetFundsVisible = ref(false)
const assetTxVisible = ref(false)
const selectedProductId = ref<number>(0)
const selectedProductTitle = ref('')
const fetch = () => {
// console.log('sss')
reload()
const assetSheetTitle = computed(
() => `قلک‌های دارایی «${selectedProductTitle.value || '—'}»`
)
const assetTxSheetTitle = computed(
() => `تراکنش‌های دارایی «${selectedProductTitle.value || '—'}»`
)
const assetFundsTblProps = computed(() => ({
columns: piggyFundsCols.filter((c) => c.key !== 'action'),
api: (params: TableInput) =>
getAssetPiggyFundsTable(params, props.customerId!, selectedProductId.value)
}))
const assetTxCols = [
{
title: 'ردیف',
dataIndex: 'id',
key: 'row',
filterable: false,
sortable: false,
customRender: (record: any) => record.index + 1
},
{ title: 'کد', dataIndex: 'id', key: 'id', type: 'Number' },
{ title: 'نوع', dataIndex: 'type_str', key: 'type_str', type: 'Text' },
{ title: 'طلا', dataIndex: 'gold', key: 'gold', type: 'Number' },
{ title: 'ریال', dataIndex: 'cash', key: 'cash', type: 'Number' },
{ title: 'تاریخ', dataIndex: 'created_at', key: 'created_at', type: 'Text' }
]
const assetTxTblProps = computed(() => ({
columns: assetTxCols,
api: (params: TableInput) =>
getAssetTransactionsTable(params, props.customerId!, selectedProductId.value)
}))
function productTitleOf(record: any) {
return record?.product_title || record?.product?.title || `#${record?.product_id ?? ''}`
}
// const spinTable = (val: boolean) => {
// // console.log('sss')
// table?.value?.loading.value = val
// }
defineExpose({
fetch
// spinTable
})
function openAssetFunds(record: any) {
selectedProductId.value = Number(record?.product_id ?? 0)
selectedProductTitle.value = productTitleOf(record)
if (!selectedProductId.value || !props.customerId) return
assetFundsVisible.value = true
}
function openAssetTx(record: any) {
selectedProductId.value = Number(record?.product_id ?? 0)
selectedProductTitle.value = productTitleOf(record)
if (!selectedProductId.value || !props.customerId) return
assetTxVisible.value = true
}
const fetch = () => reload()
defineExpose({ fetch })
onMounted(() => {})
</script>
<style lang="less">
@prefix: ~'@{prefixCls}-pophoverstatus';
.ant-popover,
.ant-tooltip {
z-index: 1001 !important;
}
.@{prefix} {
.ant-menu-rtl.ant-menu-inline,
.ant-menu-rtl.ant-menu-vertical {
border-left: none;
}
.ant-menu-item-only-child {
border-radius: @border-radius-base;
}
//bor
/* .ant-input-group-addon:first-child {
!* border: #d9d9d9 1px solid;
border-radius: 0 6px 6px 0;*!
}*/
}
</style>
@@ -0,0 +1,101 @@
<template>
<div>
<BasicShowContext title="لیست قلک ها">
<BaseTable v-bind="tblProps" @register="submit" ref="tbl">
<template #action="{ record }">
<div class="flex items-center justify-center gap-2">
<a-tooltip placement="bottom">
<template #title><span>مشخصات / تراکنش‌ها</span></template>
<Icon
class="cursor-pointer"
icon="vuesax-linear:info-circle"
color="#4572E9"
@click="openDetails(record)"
/>
</a-tooltip>
</div>
</template>
</BaseTable>
</BasicShowContext>
<BasicActionSheet
v-model:visible="detailsVisible"
:title="detailsTitle"
@close="detailsVisible = false"
>
<div class="mb-3 flex flex-wrap gap-3 text-sm">
<span>کد قلک: {{ selectedFund?.id ?? '—' }}</span>
<span>عنوان: {{ selectedFund?.title || '—' }}</span>
<span>محصول: {{ productTitleOf(selectedFund) }}</span>
<span>موجودی: {{ selectedFund?.gold ?? 0 }}</span>
</div>
<BaseTable v-if="detailsVisible" v-bind="txTblProps" @register="txSubmit" />
</BasicActionSheet>
</div>
</template>
<script lang="tsx" setup>
import type { TableInput } from '@core/type/baseTable'
import useBaseTable from '@core/components/BaseTable/hooks/useBaseTable'
import Icon from '@core/components/BaseIcon/src/Icon.vue'
import { piggyFundsCols } from '@/pages/menuPages/customers/base/hooks/piggyFundsColumns'
import { computed, ref } from 'vue'
import { getPiggyFundsTable, getPiggyFundTransactionsTable } from '@/api/user'
import BasicActionSheet from '@/components/BasicActionSheet.vue'
import BasicShowContext from '@/components/BasicShowContext.vue'
const [submit, reload] = useBaseTable()
const [txSubmit] = useBaseTable()
interface Prop {
customerId?: number
}
const props = defineProps<Prop>()
const tblProps = ref<any>({
columns: piggyFundsCols,
api: (params: TableInput) => getPiggyFundsTable(params, props.customerId!)
})
const detailsVisible = ref(false)
const selectedFund = ref<any>(null)
const detailsTitle = computed(
() => `مشخصات قلک «${selectedFund.value?.title || selectedFund.value?.id || '—'}»`
)
const txCols = [
{
title: 'ردیف',
dataIndex: 'id',
key: 'row',
filterable: false,
sortable: false,
customRender: (record: any) => record.index + 1
},
{ title: 'کد', dataIndex: 'id', key: 'id', type: 'Number' },
{ title: 'نوع', dataIndex: 'type_str', key: 'type_str', type: 'Text' },
{ title: 'طلا', dataIndex: 'gold', key: 'gold', type: 'Number' },
{ title: 'ریال', dataIndex: 'cash', key: 'cash', type: 'Number' },
{ title: 'تاریخ', dataIndex: 'created_at', key: 'created_at', type: 'Text' }
]
const txTblProps = computed(() => ({
columns: txCols,
api: (params: TableInput) =>
getPiggyFundTransactionsTable(params, props.customerId!, Number(selectedFund.value?.id ?? 0))
}))
function productTitleOf(record: any) {
return record?.product_title || record?.product?.title || '—'
}
function openDetails(record: any) {
selectedFund.value = record
detailsVisible.value = true
}
const fetch = () => reload()
defineExpose({ fetch })
</script>
@@ -1,26 +1,6 @@
import type { BaseTableColumn } from '@core/type/baseTable'
import { toJalaliNoTime, toTime } from '@core/utils/useDataTime'
import CustomTag from '@/components/CustomTag.vue'
import { usePrice } from '@core/utils/usePrice'
/*import BudgetSelect from '@/components/BudgetSelect.vue'
import { useStaticApiListsStore } from '@/store/staticApisStore'
import type { FilterSelect } from '@/model/filterSelect'
import type { DocItem } from '@/model/docType'*/
//define store
//const store = useStaticApiListsStore()
//document types
/*let docTypes: DocItem[]*/
/*onMounted(async () => {
docTypes = await store.readyDocTypeList()
})
const filteredDocTypes: FilterSelect = docTypes?.map((x: DocItem) => {
return {
label: x.title,
value: x.id
}
})*/
/** ستون‌های تب دارایی‌ها (جمع آزاد + قلک) */
export const cols: BaseTableColumn[] = [
{
title: 'ردیف',
@@ -33,11 +13,10 @@ export const cols: BaseTableColumn[] = [
}
},
{
title: 'کد قلک',
title: 'کد دارایی',
dataIndex: 'id',
key: 'id',
key: 'wallet_id',
type: 'Number'
// className: 'column-money'
},
{
title: 'نام محصول',
@@ -48,9 +27,31 @@ export const cols: BaseTableColumn[] = [
record.record?.product_title || record.record?.product?.title || '-'
},
{
title: 'موجودی',
title: 'موجودی کل',
dataIndex: 'gold',
key: 'gold',
type: 'Number'
},
{
title: 'آزاد',
dataIndex: 'free_gold',
key: 'free_gold',
type: 'Number',
customRender: (record: any) => record.record?.free_gold ?? record.record?.gold ?? '-'
},
{
title: 'در قلک',
dataIndex: 'fund_gold',
key: 'fund_gold',
type: 'Number',
customRender: (record: any) => record.record?.fund_gold ?? 0
},
{
title: 'عملیات',
dataIndex: 'action',
key: 'action',
slot: 'action',
filterable: false,
sortable: false
}
]
@@ -0,0 +1,47 @@
import type { BaseTableColumn } from '@core/type/baseTable'
/** ستون‌های تب قلک‌ها (مدل Fund) */
export const piggyFundsCols: BaseTableColumn[] = [
{
title: 'ردیف',
dataIndex: 'id',
key: 'row',
filterable: false,
sortable: false,
customRender: (record: any) => record.index + 1
},
{
title: 'کد قلک',
dataIndex: 'id',
key: 'id',
type: 'Number'
},
{
title: 'عنوان قلک',
dataIndex: 'title',
key: 'title',
type: 'Text'
},
{
title: 'نام محصول',
dataIndex: 'product_title',
key: 'product_title',
type: 'Text',
customRender: (record: any) =>
record.record?.product_title || record.record?.product?.title || '-'
},
{
title: 'موجودی',
dataIndex: 'gold',
key: 'gold',
type: 'Number'
},
{
title: 'عملیات',
dataIndex: 'action',
key: 'action',
slot: 'action',
filterable: false,
sortable: false
}
]
+12 -2
View File
@@ -240,9 +240,12 @@
<a-tab-pane key="معرفی کرده ها" tab="معرفی کرده ها">
<ReferralsTable ref="referralTable" :customerId="userInfo?.id" />
</a-tab-pane>
<a-tab-pane key="قلک ها" tab="قلک ها">
<a-tab-pane key="دارایی ها" tab="دارایی ها">
<FundsTable ref="fundTable" :customerId="userInfo?.id" />
</a-tab-pane>
<a-tab-pane key="قلک ها" tab="قلک ها">
<PiggyFundsTable ref="piggyFundTable" :customerId="userInfo?.id" />
</a-tab-pane>
<a-tab-pane v-if="pargarWalletSyncVisible" key="لاگ پرگار" tab="لاگ پرگار">
<CustomerPargarLogsTable ref="pargarLogsTable" :customer-id="userInfo?.id" />
</a-tab-pane>
@@ -304,6 +307,7 @@ import ordersTbl from '@/pages/menuPages/orders/components/table.vue'
import transactionsTbl from '@/pages/menuPages/transactions/components/table.vue'
import smsTbl from '@/pages/menuPages/sms/components/table.vue'
import FundsTable from '@/pages/menuPages/customers/base/components/fundsTable.vue'
import PiggyFundsTable from '@/pages/menuPages/customers/base/components/piggyFundsTable.vue'
import ReferralsTable from '@/pages/menuPages/customers/base/components/referralsTable.vue'
import CustomerPargarLogsTable from '@/pages/menuPages/customers/base/components/CustomerPargarLogsTable.vue'
import CustomerConditionalOrderTab from '@/pages/menuPages/customers/base/components/CustomerConditionalOrderTab.vue'
@@ -378,6 +382,7 @@ const transactionTable = ref(null)
const smsTable = ref(null)
const referralTable = ref(null)
const fundTable = ref(null)
const piggyFundTable = ref(null)
const pargarLogsTable = ref<{ fetch?: () => void } | null>(null)
const refreshTable = () => table?.value?.fetch()
const refreshOrderTable = () => orderTable?.value?.fetch()
@@ -385,6 +390,7 @@ const refreshTransactionTable = () => transactionTable?.value?.fetch()
const refreshSMSTable = () => smsTable?.value?.fetch()
const refreshReferralTable = () => referralTable?.value?.fetch()
const refreshFundTable = () => fundTable?.value?.fetch()
const refreshPiggyFundTable = () => piggyFundTable?.value?.fetch()
const refreshPargarLogsTable = () => pargarLogsTable.value?.fetch?.()
let updateKey = ref<number>(0)
@@ -542,10 +548,14 @@ async function refreshInfoTab(key: string) {
await nextTick()
refreshReferralTable()
break
case 'قلک ها':
case 'دارایی ها':
await nextTick()
refreshFundTable()
break
case 'قلک ها':
await nextTick()
refreshPiggyFundTable()
break
case 'لاگ پرگار':
await nextTick()
refreshPargarLogsTable()
+15
View File
@@ -46,6 +46,9 @@ export const customerDirectSmsEnabledSetting = ref(false)
/** reactive — منو و UI سفارش شرطی (ادمین + کنترل‌های مشتری) */
export const conditionalOrderEnabledSetting = ref(false)
/** reactive — قلک per-product در اپ مشتری */
export const productFundsEnabledSetting = ref(false)
/** reactive — منو و UI هشدار قیمت */
export const priceTriggerEnabledSetting = ref(false)
@@ -144,6 +147,10 @@ export function setConditionalOrderEnabledFromSettings(value: boolean): void {
conditionalOrderEnabledSetting.value = value
}
export function setProductFundsEnabledFromSettings(value: boolean): void {
productFundsEnabledSetting.value = value
}
export function setPriceTriggerEnabledFromSettings(value: boolean): void {
priceTriggerEnabledSetting.value = value
}
@@ -236,6 +243,13 @@ export function applyConditionalOrderEnabledFromRows(
if (row) setConditionalOrderEnabledFromSettings(isSwitchOn(row.value))
}
export function applyProductFundsEnabledFromRows(
rows: Array<{ key?: string; value?: string | null }>
) {
const row = rows.find((item) => item.key === 'enable_product_funds')
if (row) setProductFundsEnabledFromSettings(isSwitchOn(row.value))
}
export function applyPriceTriggerEnabledFromRows(
rows: Array<{ key?: string; value?: string | null }>
) {
@@ -276,6 +290,7 @@ async function bootstrapSettingsFromApi(): Promise<void> {
applyTrackingSystemsEnabledFromRows(list)
applyCustomerDirectSmsFromRows(list)
applyConditionalOrderEnabledFromRows(list)
applyProductFundsEnabledFromRows(list)
applyPriceTriggerEnabledFromRows(list)
applyAppNotificationEnabledFromRows(list)
applySupportChatMenuEnabledFromRows(list)