Split desktop and mobile layouts with shared page data so APIs fetch once per context.
Add layout shells, desktop views, module-level page caches, and UI fixes for auth, home, wallet, transactions, address, and related pages. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
<template>
|
||||
<div class="wallet-add-card-form pb-4 mt-2">
|
||||
<a-form :model="cardForm" layout="vertical">
|
||||
<a-form-item
|
||||
:rules="cardNumberValidation()"
|
||||
class="w-full"
|
||||
label="شماره کارت"
|
||||
name="cart_number"
|
||||
>
|
||||
<BasicInput v-model:value="cardForm.cart_number" type="number" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
v-if="walletStore.walletInfo"
|
||||
class="w-full"
|
||||
label="تاریخ تولد"
|
||||
name="birth_date"
|
||||
>
|
||||
<BaseDatePicker v-model:value="cardForm.birth_date" class="w-full" inputReadOnly />
|
||||
</a-form-item>
|
||||
<BasicButton
|
||||
v-if="showActions"
|
||||
:disabled="loading"
|
||||
class="w-full mt-5"
|
||||
type="primary"
|
||||
@click="addCard"
|
||||
>
|
||||
<a-spin v-if="loading" size="small" />
|
||||
<div v-else>ثبت</div>
|
||||
</BasicButton>
|
||||
<BasicButton v-if="showActions" class="w-full mt-2" @click="showAddCard = false">بازگشت</BasicButton>
|
||||
</a-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
|
||||
import BasicInput from '@/components/BasicPacks/BasicInput.vue'
|
||||
import BaseDatePicker from '@/components/BasicPacks/BaseDatePicker'
|
||||
import { cardNumberValidation } from '@/utils/inputRules'
|
||||
import { useWalletPageContext } from '../composables/useWalletPage'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
/** Inline ثبت/بازگشت — mobile action sheet only; desktop uses modal footer */
|
||||
showActions?: boolean
|
||||
}>(),
|
||||
{ showActions: true }
|
||||
)
|
||||
|
||||
const {
|
||||
cardForm,
|
||||
walletStore,
|
||||
loading,
|
||||
showAddCard,
|
||||
addCard,
|
||||
} = useWalletPageContext()
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.wallet-add-card-form {
|
||||
@media screen and (max-width: 767.98px) {
|
||||
padding-bottom: 5rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,291 @@
|
||||
import { computed, inject, onMounted, provide, ref, type InjectionKey, type Ref } from 'vue'
|
||||
import OtpInput from 'vue3-otp-input'
|
||||
import { formatCashWalletBalanceText } from '@/utils/productDealMethod'
|
||||
import { usePriceWithoutType } from '@/utils/usePrice'
|
||||
import { loading, loadingMore } from '@/utils'
|
||||
import router from '@/router'
|
||||
import { useWalletStore } from '@/store/walletStore'
|
||||
import type { Transaction } from '@/models/transaction'
|
||||
import { createCard, withdraw, confirmCode } from '@/api/wallet'
|
||||
import { useInfiniteScroll } from '@vueuse/core'
|
||||
import { message } from 'ant-design-vue'
|
||||
import type { Card } from '@/models/wallet'
|
||||
import { useUserStore } from '@/store/userStore'
|
||||
import { useConfigStore } from '@/store/configStore'
|
||||
import { isBazretalaProject } from '@/utils/config'
|
||||
import { useDesktopBreakpoint } from '@/layouts/composables/useAppLayout'
|
||||
import {
|
||||
buildSupportMessengerUrl,
|
||||
DEFAULT_SUPPORT_MESSENGER_TEXT,
|
||||
supportMessengerSettings,
|
||||
} from '@/utils/supportMessenger'
|
||||
import {
|
||||
initWalletPageData,
|
||||
loadMoreWalletDeposits,
|
||||
loadMoreWalletWithdrawals,
|
||||
refreshWalletCards,
|
||||
walletCardItems,
|
||||
walletDepositItems,
|
||||
walletWithdrawItems,
|
||||
} from './useWalletPageData'
|
||||
|
||||
export interface WalletPageContext {
|
||||
isDeposit: Ref<boolean>
|
||||
walletStore: ReturnType<typeof useWalletStore>
|
||||
config: ReturnType<typeof useConfigStore>
|
||||
showAddCard: Ref<boolean>
|
||||
chargeAccountModal: Ref<boolean>
|
||||
showConfirmCode: Ref<boolean>
|
||||
withdrawInfModal: Ref<boolean>
|
||||
infoVisible: Ref<boolean>
|
||||
refOtpInput: Ref<InstanceType<typeof OtpInput> | null>
|
||||
form: Ref<Transaction>
|
||||
cardForm: Ref<Card>
|
||||
disableButton: ReturnType<typeof computed<boolean>>
|
||||
cardItems: typeof walletCardItems
|
||||
depositItems: typeof walletDepositItems
|
||||
withdrawItems: typeof walletWithdrawItems
|
||||
loading: typeof loading
|
||||
loadingMore: typeof loadingMore
|
||||
mobileDepositScrollEl: Ref<HTMLElement | null>
|
||||
desktopDepositScrollEl: Ref<HTMLElement | null>
|
||||
supportMessengerText: ReturnType<typeof computed<string>>
|
||||
supportMessengerLink: ReturnType<typeof computed<string | undefined>>
|
||||
isBazretalaProject: typeof isBazretalaProject
|
||||
usePriceWithoutType: typeof usePriceWithoutType
|
||||
formatCashWalletBalanceText: typeof formatCashWalletBalanceText
|
||||
setIsDeposit: (val: boolean) => void
|
||||
useStyle: () => string
|
||||
formatter: (value: number) => string
|
||||
percentChange: (val: number) => void
|
||||
ok: () => Promise<void>
|
||||
addCard: () => Promise<void>
|
||||
getCards: () => Promise<void>
|
||||
handleOnComplete: (value: string) => Promise<void>
|
||||
}
|
||||
|
||||
export const WALLET_PAGE_CONTEXT_KEY: InjectionKey<WalletPageContext> = Symbol('walletPageContext')
|
||||
|
||||
export function useWalletPage() {
|
||||
const isDeposit = ref(true)
|
||||
const walletStore = useWalletStore()
|
||||
const userStore = useUserStore()
|
||||
const config = useConfigStore()
|
||||
const isDesktop = useDesktopBreakpoint()
|
||||
const showAddCard = ref(false)
|
||||
const chargeAccountModal = ref(false)
|
||||
const showConfirmCode = ref(false)
|
||||
const withdrawInfModal = ref(false)
|
||||
const infoVisible = ref(false)
|
||||
const refOtpInput = ref<InstanceType<typeof OtpInput> | null>(null)
|
||||
const mobileDepositScrollEl = ref<HTMLElement | null>(null)
|
||||
const desktopDepositScrollEl = ref<HTMLElement | null>(null)
|
||||
|
||||
const activeDepositScrollEl = computed(() =>
|
||||
isDesktop.value ? desktopDepositScrollEl.value : mobileDepositScrollEl.value,
|
||||
)
|
||||
|
||||
const supportMessengerText = computed(
|
||||
() => supportMessengerSettings.value.messengerText || DEFAULT_SUPPORT_MESSENGER_TEXT,
|
||||
)
|
||||
|
||||
const supportMessengerLink = computed(() =>
|
||||
buildSupportMessengerUrl(
|
||||
supportMessengerSettings.value.messenger,
|
||||
supportMessengerSettings.value.messengerId,
|
||||
),
|
||||
)
|
||||
|
||||
const form = ref<Transaction>({
|
||||
value: undefined,
|
||||
percentWallet: 0,
|
||||
card_id: undefined,
|
||||
})
|
||||
|
||||
const cardForm = ref<Card>({
|
||||
birth_date: 0,
|
||||
account_number: '',
|
||||
bank_name: '',
|
||||
cart_number: '',
|
||||
shaba_number: '',
|
||||
})
|
||||
|
||||
const disableButton = computed(() => {
|
||||
if (!loading.value) {
|
||||
if (walletStore?.walletInfo?.cash && !isDeposit.value) {
|
||||
if (walletCardItems.value.length > 0) {
|
||||
return (
|
||||
walletStore?.walletInfo?.cash <= 0
|
||||
|| walletStore?.walletInfo?.cash < parseInt(form.value?.value)
|
||||
|| isNaN(parseInt(form.value?.value))
|
||||
|| parseInt(form.value?.value) < 1000000
|
||||
)
|
||||
}
|
||||
return true
|
||||
}
|
||||
if (isDeposit.value) {
|
||||
return isNaN(parseInt(form.value?.value)) || parseInt(form.value?.value) < 1000000
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
const unitCalculator = computed(() => (walletStore?.walletInfo?.cash ?? 0) / 100)
|
||||
|
||||
function resetData() {
|
||||
form.value.value = undefined
|
||||
form.value.percentWallet = 0
|
||||
}
|
||||
|
||||
async function addCard() {
|
||||
try {
|
||||
loading.value = true
|
||||
await createCard(cardForm.value)
|
||||
await getCards()
|
||||
showAddCard.value = false
|
||||
cardForm.value = {
|
||||
birth_date: 0,
|
||||
account_number: '',
|
||||
bank_name: '',
|
||||
cart_number: '',
|
||||
shaba_number: '',
|
||||
}
|
||||
message.success('کارت وارد شده با موفقیت افزوده شد و پس از تایید نمایش داده خواهد شد.')
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function getCards() {
|
||||
await refreshWalletCards()
|
||||
form.value.card_id = walletCardItems.value.length ? walletCardItems.value[0].id : undefined
|
||||
}
|
||||
|
||||
function setIsDeposit(val: boolean) {
|
||||
isDeposit.value = val
|
||||
form.value.value = undefined
|
||||
form.value.percentWallet = 0
|
||||
}
|
||||
|
||||
function useStyle() {
|
||||
if (isDeposit.value) return 'right: 2%;'
|
||||
return ' right: 98%; transform: translate(100%, 0);'
|
||||
}
|
||||
|
||||
const formatter = (value: number) => `${value}%`
|
||||
|
||||
function percentChange(val: number) {
|
||||
if (val !== 0) form.value.value = parseInt((unitCalculator.value * val).toFixed())
|
||||
else form.value.value = undefined
|
||||
}
|
||||
|
||||
async function ok() {
|
||||
try {
|
||||
if (form.value.value !== undefined) {
|
||||
loading.value = true
|
||||
if (!isDeposit.value) {
|
||||
await confirmCode({ value: form.value.value })
|
||||
showConfirmCode.value = true
|
||||
}
|
||||
if (isDeposit.value) {
|
||||
chargeAccountModal.value = true
|
||||
}
|
||||
} else {
|
||||
message.error('ابتدا مبلغ را وارد کنید')
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function handleOnComplete(value: string) {
|
||||
try {
|
||||
infoVisible.value = true
|
||||
showConfirmCode.value = false
|
||||
await withdraw({ ...form.value, otp: value })
|
||||
await walletStore.getMyWallet()
|
||||
await message.success('عملیات با موفقیت انجام شد')
|
||||
withdrawInfModal.value = true
|
||||
resetData()
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
} finally {
|
||||
infoVisible.value = false
|
||||
refOtpInput.value?.clearInput()
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
if (router.currentRoute.value.query.state === 'deposit') {
|
||||
isDeposit.value = true
|
||||
}
|
||||
cardForm.value.birth_date = userStore.userInfo?.birth_date
|
||||
await initWalletPageData()
|
||||
form.value.card_id = walletCardItems.value.length ? walletCardItems.value[0].id : undefined
|
||||
})
|
||||
|
||||
if (!userStore.isSingle) {
|
||||
useInfiniteScroll(
|
||||
activeDepositScrollEl,
|
||||
async () => {
|
||||
if (isDeposit.value) {
|
||||
await loadMoreWalletDeposits()
|
||||
} else {
|
||||
await loadMoreWalletWithdrawals()
|
||||
}
|
||||
},
|
||||
{ distance: 12 },
|
||||
)
|
||||
}
|
||||
|
||||
const context: WalletPageContext = {
|
||||
isDeposit,
|
||||
walletStore,
|
||||
config,
|
||||
showAddCard,
|
||||
chargeAccountModal,
|
||||
showConfirmCode,
|
||||
withdrawInfModal,
|
||||
infoVisible,
|
||||
refOtpInput,
|
||||
form,
|
||||
cardForm,
|
||||
disableButton,
|
||||
cardItems: walletCardItems,
|
||||
depositItems: walletDepositItems,
|
||||
withdrawItems: walletWithdrawItems,
|
||||
loading,
|
||||
loadingMore,
|
||||
mobileDepositScrollEl,
|
||||
desktopDepositScrollEl,
|
||||
supportMessengerText,
|
||||
supportMessengerLink,
|
||||
isBazretalaProject,
|
||||
usePriceWithoutType,
|
||||
formatCashWalletBalanceText,
|
||||
setIsDeposit,
|
||||
useStyle,
|
||||
formatter,
|
||||
percentChange,
|
||||
ok,
|
||||
addCard,
|
||||
getCards,
|
||||
handleOnComplete,
|
||||
}
|
||||
|
||||
provide(WALLET_PAGE_CONTEXT_KEY, context)
|
||||
return context
|
||||
}
|
||||
|
||||
export function useWalletPageContext() {
|
||||
const context = inject(WALLET_PAGE_CONTEXT_KEY)
|
||||
if (!context) {
|
||||
throw new Error('useWalletPageContext must be used within a page that calls useWalletPage()')
|
||||
}
|
||||
return context
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
import { ref } from 'vue'
|
||||
import { loading, loadingMore } from '@/utils'
|
||||
import type { Transaction } from '@/models/transaction'
|
||||
import { getActivatedCards } from '@/api/wallet'
|
||||
import { getTransactionTable, getTransactionTable2 } from '@/api/transaction'
|
||||
import type { TableEngineInput, TableOutput } from '@/models/table'
|
||||
import type { Card } from '@/models/wallet'
|
||||
import { useWalletStore } from '@/store/walletStore'
|
||||
import { runOnceAsync, resetOnceAsyncByPrefix } from '@/composables/useOnceAsync'
|
||||
import { loadSupportMessengerFromSettings } from '@/utils/supportMessenger'
|
||||
|
||||
/**
|
||||
* Shared wallet page datasets — mobile and desktop views read this module state only.
|
||||
* Resize / breakpoint changes must not trigger new requests.
|
||||
*/
|
||||
let initPromise: Promise<void> | null = null
|
||||
const initialized = ref(false)
|
||||
|
||||
export const walletCardItems = ref<Card[]>([])
|
||||
export const walletDepositItems = ref<Transaction[]>([])
|
||||
export const walletWithdrawItems = ref<Transaction[]>([])
|
||||
export const walletDepositTableOutput = ref<TableOutput<Transaction> | null>(null)
|
||||
export const walletWithdrawTableOutput = ref<TableOutput<Transaction> | null>(null)
|
||||
|
||||
export const walletDepositPagination = ref<TableEngineInput>({
|
||||
filters: [],
|
||||
limit: 6,
|
||||
page: 0,
|
||||
})
|
||||
|
||||
export const walletWithdrawPagination = ref<TableEngineInput>({
|
||||
filters: [
|
||||
{
|
||||
field: 'type',
|
||||
cr: 'and',
|
||||
type: 'number',
|
||||
op: 'eq',
|
||||
value: 4,
|
||||
},
|
||||
],
|
||||
limit: 6,
|
||||
page: 0,
|
||||
})
|
||||
|
||||
export function isWalletPageDataInitialized() {
|
||||
return initialized.value
|
||||
}
|
||||
|
||||
async function fetchDepositPage(append: boolean) {
|
||||
const isFirstPage = walletDepositPagination.value.page === 0 && !append
|
||||
|
||||
if (isFirstPage) {
|
||||
loading.value = true
|
||||
} else {
|
||||
loadingMore.value = true
|
||||
}
|
||||
|
||||
try {
|
||||
walletDepositTableOutput.value = await getTransactionTable2(walletDepositPagination.value)
|
||||
const rows = walletDepositTableOutput.value.rows
|
||||
|
||||
if (isFirstPage) {
|
||||
walletDepositItems.value = [...rows]
|
||||
} else {
|
||||
walletDepositItems.value.push(...rows)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Wallet deposit table error:', error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
loadingMore.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchWithdrawPage(append: boolean) {
|
||||
const isFirstPage = walletWithdrawPagination.value.page === 0 && !append
|
||||
|
||||
if (isFirstPage) {
|
||||
loading.value = true
|
||||
} else {
|
||||
loadingMore.value = true
|
||||
}
|
||||
|
||||
try {
|
||||
walletWithdrawTableOutput.value = await getTransactionTable(walletWithdrawPagination.value)
|
||||
const rows = walletWithdrawTableOutput.value.rows
|
||||
|
||||
if (isFirstPage) {
|
||||
walletWithdrawItems.value = [...rows]
|
||||
} else {
|
||||
walletWithdrawItems.value.push(...rows)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Wallet withdraw table error:', error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
loadingMore.value = false
|
||||
}
|
||||
}
|
||||
|
||||
export async function refreshWalletCards() {
|
||||
try {
|
||||
walletCardItems.value = (await getActivatedCards()) ?? []
|
||||
} catch (error) {
|
||||
console.error('Wallet cards refresh error:', error)
|
||||
}
|
||||
}
|
||||
|
||||
export async function loadMoreWalletDeposits() {
|
||||
if (
|
||||
!walletDepositTableOutput.value
|
||||
|| (walletDepositPagination.value.page + 1) * walletDepositPagination.value.limit
|
||||
>= walletDepositTableOutput.value.query.total
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
walletDepositPagination.value.page++
|
||||
await fetchDepositPage(true)
|
||||
}
|
||||
|
||||
export async function loadMoreWalletWithdrawals() {
|
||||
if (
|
||||
!walletWithdrawTableOutput.value
|
||||
|| (walletWithdrawPagination.value.page + 1) * walletWithdrawPagination.value.limit
|
||||
>= walletWithdrawTableOutput.value.query.total
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
walletWithdrawPagination.value.page++
|
||||
await fetchWithdrawPage(true)
|
||||
}
|
||||
|
||||
export async function initWalletPageData(force = false) {
|
||||
if (!force && initialized.value) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!force && initPromise) {
|
||||
return initPromise
|
||||
}
|
||||
|
||||
initPromise = (async () => {
|
||||
try {
|
||||
if (force) {
|
||||
resetWalletPageData()
|
||||
}
|
||||
|
||||
loading.value = true
|
||||
const walletStore = useWalletStore()
|
||||
|
||||
walletDepositPagination.value.page = 0
|
||||
walletWithdrawPagination.value.page = 0
|
||||
|
||||
await Promise.all([
|
||||
runOnceAsync('wallet:getMyWallet', () => walletStore.getMyWallet(), force),
|
||||
runOnceAsync('wallet:cards', () => refreshWalletCards(), force),
|
||||
runOnceAsync('wallet:deposit:init', () => fetchDepositPage(false), force),
|
||||
runOnceAsync('wallet:withdraw:init', () => fetchWithdrawPage(false), force),
|
||||
])
|
||||
|
||||
loadSupportMessengerFromSettings()
|
||||
initialized.value = true
|
||||
} catch (error) {
|
||||
console.error('Wallet page initialization error:', error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
initPromise = null
|
||||
}
|
||||
})()
|
||||
|
||||
return initPromise
|
||||
}
|
||||
|
||||
export function resetWalletPageData() {
|
||||
initialized.value = false
|
||||
initPromise = null
|
||||
resetOnceAsyncByPrefix('wallet:')
|
||||
walletCardItems.value = []
|
||||
walletDepositItems.value = []
|
||||
walletWithdrawItems.value = []
|
||||
walletDepositTableOutput.value = null
|
||||
walletWithdrawTableOutput.value = null
|
||||
walletDepositPagination.value.page = 0
|
||||
walletWithdrawPagination.value.page = 0
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
<template>
|
||||
<div class="dwallet">
|
||||
<div class="dwallet__container">
|
||||
<header class="dwallet-topbar">
|
||||
<p class="dwallet-topbar__eyebrow">مالی</p>
|
||||
<h1 class="dwallet-topbar__title">کیف پول</h1>
|
||||
<p class="dwallet-topbar__subtitle">واریز و برداشت وجه از کیف پول خود</p>
|
||||
</header>
|
||||
|
||||
<div class="dwallet-toolbar">
|
||||
<div class="dwallet-toggle">
|
||||
<button
|
||||
type="button"
|
||||
class="dwallet-toggle__btn"
|
||||
:class="{ 'dwallet-toggle__btn--active': isDeposit }"
|
||||
@click="setIsDeposit(true)"
|
||||
>
|
||||
واریز
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="dwallet-toggle__btn"
|
||||
:class="{ 'dwallet-toggle__btn--active': !isDeposit }"
|
||||
@click="setIsDeposit(false)"
|
||||
>
|
||||
برداشت
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="dwallet-balance-pill">
|
||||
<span class="dwallet-balance-pill__label">موجودی کیف پول</span>
|
||||
<span class="dwallet-balance-pill__value number-ltr">
|
||||
{{ usePriceWithoutType(walletStore?.walletInfo?.cash ?? 0) }}
|
||||
<span>ریال</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dwallet-grid">
|
||||
<section class="dwallet-surface dwallet-form">
|
||||
<h2 class="dwallet-form__title">{{ isDeposit ? 'واریز به کیف پول' : 'برداشت از کیف پول' }}</h2>
|
||||
|
||||
<a-form :model="form" name="wallet-desktop" @finish="ok()">
|
||||
<a-form-item :rules="[required()]">
|
||||
<BasicInput
|
||||
v-model:value="form.value"
|
||||
addon-before="ریال"
|
||||
:addon-bg-color="useConfigStore().config.color"
|
||||
addon-text-color="white"
|
||||
place-holder="مبلغ"
|
||||
size="large"
|
||||
type="price"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<Transition mode="out-in" name="fade">
|
||||
<div v-if="!isDeposit" key="withdraw" class="dwallet-form__extras">
|
||||
<p class="dwallet-form__hint dwallet-form__hint--warn">
|
||||
حداقل مبلغ برداشتی 100 هزار تومان می باشد.
|
||||
</p>
|
||||
<p class="dwallet-form__balance-text">
|
||||
{{ formatCashWalletBalanceText(usePriceWithoutType(walletStore?.walletInfo?.cash ?? 0)) }}
|
||||
</p>
|
||||
<a-form-item v-if="walletStore?.walletInfo" class="!mt-3">
|
||||
<a-slider
|
||||
v-model:value="form.percentWallet"
|
||||
:disabled="walletStore?.walletInfo?.cash <= 0"
|
||||
:max="100"
|
||||
:min="0"
|
||||
:step="10"
|
||||
:tip-formatter="formatter"
|
||||
@change="percentChange"
|
||||
/>
|
||||
</a-form-item>
|
||||
</div>
|
||||
<div v-else key="deposit" class="dwallet-form__extras">
|
||||
<p v-if="!isBazretalaProject()" class="dwallet-form__hint dwallet-form__hint--warn">
|
||||
حداقل مبلغ واریزی 100 هزار تومان می باشد.
|
||||
</p>
|
||||
<div class="dwallet-quick-amounts">
|
||||
<button type="button" class="dwallet-quick-amounts__btn" @click="form.value = 10000000">
|
||||
{{ usePriceWithoutType(10000000) }}
|
||||
</button>
|
||||
<button type="button" class="dwallet-quick-amounts__btn" @click="form.value = 50000000">
|
||||
{{ usePriceWithoutType(50000000) }}
|
||||
</button>
|
||||
<button type="button" class="dwallet-quick-amounts__btn" @click="form.value = 100000000">
|
||||
{{ usePriceWithoutType(100000000) }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
|
||||
<BasicButton
|
||||
:disabled="disableButton"
|
||||
class="dwallet-form__submit"
|
||||
html-type="submit"
|
||||
type="primary"
|
||||
>
|
||||
<a-spin v-if="loading" size="small" />
|
||||
<span v-else>{{ isDeposit ? 'واریز' : 'برداشت' }}</span>
|
||||
</BasicButton>
|
||||
</a-form>
|
||||
</section>
|
||||
|
||||
<section class="dwallet-surface dwallet-side">
|
||||
<template v-if="isDeposit">
|
||||
<div class="dwallet-side__header">
|
||||
<h3 class="dwallet-side__title">تاریخچه واریز</h3>
|
||||
</div>
|
||||
<div
|
||||
:ref="(node) => { desktopDepositScrollEl = (node as HTMLElement | null) }"
|
||||
class="dwallet-side__scroll"
|
||||
>
|
||||
<list-anim v-if="!loading" :numberItemsAnim="4">
|
||||
<Item v-for="item in depositItems" :key="item.id" :item="item" />
|
||||
<TransactionSkeleton v-if="loadingMore" class="mt-1 mb-4" />
|
||||
</list-anim>
|
||||
<div v-else class="dwallet-side__skeletons">
|
||||
<TransactionSkeleton v-for="i in 6" :key="i" class="mt-1" />
|
||||
</div>
|
||||
<p v-if="!loading && !depositItems.length" class="dwallet-side__empty">
|
||||
تراکنش واریزی ثبت نشده است.
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<div class="dwallet-side__header">
|
||||
<h3 class="dwallet-side__title">کارتهای بانکی</h3>
|
||||
<button type="button" class="dwallet-side__add-btn" @click="showAddCard = true">
|
||||
<BasicIcon icon="vuesax-linear:add" size="16" />
|
||||
<span>افزودن کارت</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-if="!loading && cardItems.length === 0" class="dwallet-side__empty dwallet-side__empty--cards">
|
||||
<BasicIcon icon="vuesax-linear:card" size="32" />
|
||||
<p>هیچ کارتی یافت نشد</p>
|
||||
<button type="button" class="dwallet-side__add-btn dwallet-side__add-btn--primary" @click="showAddCard = true">
|
||||
افزودن کارت جدید
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-else-if="cardItems.length > 0" class="dwallet-cards">
|
||||
<CardSlider
|
||||
v-model:id="form.card_id"
|
||||
:items="cardItems"
|
||||
class="dwallet-cards__slider"
|
||||
@cardDeleted="getCards"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import BasicInput from '@/components/BasicPacks/BasicInput.vue'
|
||||
import ListAnim from '@/components/ListAnim.vue'
|
||||
import TransactionSkeleton from '@/components/TransactionSkeleton.vue'
|
||||
import { useConfigStore } from '@/store/configStore'
|
||||
import { required } from '@/utils/inputRules'
|
||||
import CardSlider from '../components/UISlider/index.vue'
|
||||
import Item from '../components/Item.vue'
|
||||
import { useWalletPageContext } from '../composables/useWalletPage'
|
||||
|
||||
const {
|
||||
isDeposit,
|
||||
walletStore,
|
||||
showAddCard,
|
||||
form,
|
||||
disableButton,
|
||||
cardItems,
|
||||
depositItems,
|
||||
loading,
|
||||
loadingMore,
|
||||
desktopDepositScrollEl,
|
||||
isBazretalaProject,
|
||||
usePriceWithoutType,
|
||||
formatCashWalletBalanceText,
|
||||
setIsDeposit,
|
||||
formatter,
|
||||
percentChange,
|
||||
ok,
|
||||
getCards,
|
||||
} = useWalletPageContext()
|
||||
</script>
|
||||
@@ -0,0 +1,296 @@
|
||||
/* Premium desktop wallet page */
|
||||
|
||||
.dwallet {
|
||||
min-height: 100%;
|
||||
background: #f6f7f9;
|
||||
color: #111827;
|
||||
}
|
||||
|
||||
.dwallet__container {
|
||||
max-width: 1180px;
|
||||
margin: 0 auto;
|
||||
padding: 28px 36px 40px;
|
||||
}
|
||||
|
||||
.dwallet-topbar {
|
||||
margin-bottom: 24px;
|
||||
padding-bottom: 24px;
|
||||
border-bottom: 1px solid rgba(15, 23, 42, 0.06);
|
||||
|
||||
&__eyebrow {
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: #9ca3af;
|
||||
margin: 0 0 4px;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 26px;
|
||||
font-weight: 600;
|
||||
letter-spacing: -0.03em;
|
||||
color: #111827;
|
||||
margin: 0 0 6px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
&__subtitle {
|
||||
font-size: 14px;
|
||||
color: #6b7280;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.dwallet-toolbar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.dwallet-toggle {
|
||||
display: inline-flex;
|
||||
gap: 4px;
|
||||
padding: 4px;
|
||||
background: #f3f4f6;
|
||||
border-radius: 12px;
|
||||
|
||||
&__btn {
|
||||
min-width: 96px;
|
||||
padding: 10px 18px;
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
background: transparent;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #6b7280;
|
||||
font-family: inherit;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
color: #374151;
|
||||
}
|
||||
|
||||
&--active {
|
||||
background: #fff;
|
||||
color: @App-primary-color;
|
||||
box-shadow: 0 1px 3px rgba(15, 23, 42, 0.08);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dwallet-balance-pill {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
gap: 2px;
|
||||
padding: 10px 16px;
|
||||
background: #fff;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 12px;
|
||||
|
||||
&__label {
|
||||
font-size: 12px;
|
||||
color: #9ca3af;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
&__value {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #111827;
|
||||
gap: 4px;
|
||||
|
||||
span {
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: #6b7280;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dwallet-grid {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
|
||||
gap: 20px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.dwallet-surface {
|
||||
background: #fff;
|
||||
border: 1px solid rgba(15, 23, 42, 0.06);
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
|
||||
}
|
||||
|
||||
.dwallet-form {
|
||||
padding: 24px;
|
||||
|
||||
&__title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #111827;
|
||||
margin: 0 0 20px;
|
||||
}
|
||||
|
||||
&__extras {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
&__hint {
|
||||
font-size: 12px;
|
||||
margin: 0 0 10px;
|
||||
line-height: 1.5;
|
||||
|
||||
&--warn {
|
||||
color: #dc2626;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
&__balance-text {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #374151;
|
||||
margin: 0 0 8px;
|
||||
}
|
||||
|
||||
&__submit {
|
||||
width: 100%;
|
||||
margin-top: 16px;
|
||||
min-height: 44px;
|
||||
}
|
||||
}
|
||||
|
||||
.dwallet-quick-amounts {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 8px;
|
||||
|
||||
&__btn {
|
||||
padding: 10px 8px;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 10px;
|
||||
background: #f9fafb;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: #374151;
|
||||
font-family: inherit;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.15s ease, background 0.15s ease, color 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
border-color: @App-primary-color;
|
||||
color: @App-primary-color;
|
||||
background: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dwallet-side {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 420px;
|
||||
overflow: hidden;
|
||||
|
||||
&__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
padding: 20px 24px 0;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #111827;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
&__scroll {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 16px 24px 24px;
|
||||
max-height: 520px;
|
||||
}
|
||||
|
||||
&__skeletons {
|
||||
padding: 16px 24px 24px;
|
||||
}
|
||||
|
||||
&__empty {
|
||||
text-align: center;
|
||||
color: #9ca3af;
|
||||
font-size: 14px;
|
||||
padding: 32px 24px;
|
||||
|
||||
&--cards {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 12px;
|
||||
flex: 1;
|
||||
min-height: 280px;
|
||||
color: #6b7280;
|
||||
}
|
||||
}
|
||||
|
||||
&__add-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 10px;
|
||||
background: #fff;
|
||||
color: #374151;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
font-family: inherit;
|
||||
padding: 8px 12px;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.15s ease, color 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
border-color: @App-primary-color;
|
||||
color: @App-primary-color;
|
||||
}
|
||||
|
||||
&--primary {
|
||||
background: @App-primary-color;
|
||||
border-color: @App-primary-color;
|
||||
color: #fff;
|
||||
padding: 10px 16px;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.92;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dwallet-cards {
|
||||
padding: 8px 24px 24px;
|
||||
|
||||
&__slider {
|
||||
height: 240px !important;
|
||||
|
||||
:deep(.h-\[28vh\]) {
|
||||
height: 240px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1023.98px) {
|
||||
.dwallet-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.dwallet-side {
|
||||
min-height: 320px;
|
||||
}
|
||||
}
|
||||
+68
-658
@@ -1,217 +1,42 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="absolute inset-0 bg-cover bg-center opacity-60" :style="{ backgroundImage: `url(${img})` }"></div>
|
||||
<div class="bg-white py-3 px-3 text-primary font-bold drop-shadow z-[1999] wrap-fix">کیف پول</div>
|
||||
<div
|
||||
class="bg-white wrap-fix py-3 top-11 px-3 text-primary font-bold flex justify-evenly z-[1999]"
|
||||
>
|
||||
<div class="flex justify-evenly w-full px-2 h-11 items-center bg-gray-50 relative rounded">
|
||||
<div
|
||||
:class="isDeposit ? 'text-primary' : 'text-gray-400'"
|
||||
class="w-full text-center z-2"
|
||||
@click="setIsDeposit(true)"
|
||||
>
|
||||
واریز
|
||||
</div>
|
||||
<div
|
||||
:class="!isDeposit ? 'text-primary' : 'text-gray-400'"
|
||||
class="w-full text-center z-2"
|
||||
@click="setIsDeposit(false)"
|
||||
>
|
||||
برداشت
|
||||
</div>
|
||||
<!-- <div ref="bganim" class="absolute bg-white h-8 w-1/2 rounded-lg " :style="`transform: translateX(${isDeposit? '0':'-100%'}); left: ${isDeposit? '0':'100%'}`"></div>-->
|
||||
<div
|
||||
ref="bganim"
|
||||
:style="useStyle()"
|
||||
class="absolute bg-white h-8 w-1/2 rounded-lg animate right"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="px-5 pt-26" :class="isDeposit ? 'pb-2' : 'pb-[calc(var(--app-bottom-chrome-height)+var(--app-add-card-height)+1rem)]'">
|
||||
<a-form :model="form" class="!mt-5" name="basic" @finish="ok()">
|
||||
<div class="border-gray-200 border-1 rounded-xl p-5 trans h-40 relative">
|
||||
<bg_main />
|
||||
<div class="z-100 relative">
|
||||
<a-form-item :rules="[required()]">
|
||||
<BasicInput
|
||||
v-model:value="form.value"
|
||||
addon-before="ریال"
|
||||
:addon-bg-color="useConfigStore().config.color"
|
||||
addon-text-color="white"
|
||||
place-holder="مبلغ"
|
||||
size="large"
|
||||
type="price"
|
||||
/>
|
||||
</a-form-item>
|
||||
<Transition mode="out-in" name="fade">
|
||||
<div v-if="!isDeposit">
|
||||
<div class="text-red text-xs font-bold mb-2">حداقل مبلغ برداشتی 100 هزار تومان می باشد.</div>
|
||||
<div class="font-bold text-xs">
|
||||
{{ formatCashWalletBalanceText(usePriceWithoutType(walletStore?.walletInfo?.cash ?? 0)) }}
|
||||
</div>
|
||||
<a-form-item v-if="walletStore?.walletInfo" class="!mt-3">
|
||||
<a-slider
|
||||
v-model:value="form.percentWallet"
|
||||
:disabled="walletStore?.walletInfo?.cash <= 0"
|
||||
:max="100"
|
||||
:min="0"
|
||||
:step="10"
|
||||
:tip-formatter="formatter"
|
||||
@change="percentChange"
|
||||
/>
|
||||
</a-form-item>
|
||||
</div>
|
||||
<div v-else class=" mt-3">
|
||||
<div v-if="!isBazretalaProject()" class="text-red text-xs font-bold mb-2">حداقل مبلغ واریزی 100 هزار تومان می باشد.</div>
|
||||
<div class="flex gap-2">
|
||||
<BasicButton class="w-full font-bold !px-1" @click="form.value = 10000000">
|
||||
{{ usePriceWithoutType(10000000) }}
|
||||
</BasicButton>
|
||||
<BasicButton class="w-full font-bold !px-1" @click="form.value = 50000000">
|
||||
{{ usePriceWithoutType(50000000) }}
|
||||
</BasicButton>
|
||||
<BasicButton class="w-full font-bold !px-1" @click="form.value = 100000000">
|
||||
{{ usePriceWithoutType(100000000) }}
|
||||
</BasicButton>
|
||||
</div>
|
||||
<div class="wallet-page-root">
|
||||
<ResponsiveViewPair>
|
||||
<template #mobile>
|
||||
<MobileWalletView />
|
||||
</template>
|
||||
<template #desktop>
|
||||
<DesktopWalletView />
|
||||
</template>
|
||||
</ResponsiveViewPair>
|
||||
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
</div>
|
||||
<a-form-item>
|
||||
<BasicButton
|
||||
:disabled="disableButton"
|
||||
class="w-full py-2 mt-5"
|
||||
html-type="submit"
|
||||
type="primary"
|
||||
>
|
||||
<div>
|
||||
<a-spin v-if="loading" size="small" />
|
||||
<div v-else>{{ isDeposit ? 'واریز' : 'برداشت' }}</div>
|
||||
</div>
|
||||
</BasicButton>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<div
|
||||
v-if="isDeposit"
|
||||
ref="el"
|
||||
:class="loading ? 'h-screen' : ''"
|
||||
class="px-3 overflow-y-scroll w-full h-[49vh] pb-16"
|
||||
style="max-height: calc(100vh - 50px)"
|
||||
>
|
||||
<list-anim v-if="!loading" :numberItemsAnim="4">
|
||||
<Item
|
||||
v-for="item in isDeposit ? depositItems : withdrawItems"
|
||||
:key="item.id"
|
||||
:item="item"
|
||||
/>
|
||||
<TransactionSkeleton v-if="loadingMore" class="mt-1 mb-8" />
|
||||
</list-anim>
|
||||
<TransactionSkeleton v-for="i in 13" v-else :key="i" class="mt-1" />
|
||||
</div>
|
||||
<!-- <Slider/>-->
|
||||
<Transition mode="out-in" name="fade">
|
||||
<template v-if="!isDeposit">
|
||||
<div
|
||||
v-if="!loading && cardItems.length === 0"
|
||||
class="h-30 flex items-center justify-center"
|
||||
>
|
||||
هیچ کارتی یافت نشد
|
||||
</div>
|
||||
</template>
|
||||
</Transition>
|
||||
</div>
|
||||
|
||||
<Teleport to="body">
|
||||
<CardSlider
|
||||
v-if="!isDeposit && cardItems.length > 0 && !showAddCard"
|
||||
v-model:id="form.card_id"
|
||||
:items="cardItems"
|
||||
class="card-slider-wrap wallet-card-slider"
|
||||
@cardDeleted="getCards"
|
||||
/>
|
||||
</Teleport>
|
||||
|
||||
<Teleport to="body">
|
||||
<div
|
||||
v-if="!isDeposit && !showAddCard"
|
||||
class="add-card app-dock-add-bar"
|
||||
@click="showAddCard = true"
|
||||
>
|
||||
<div>افزودن کارت جدید</div>
|
||||
<BasicIcon icon="vuesax-linear:add" />
|
||||
</div>
|
||||
</Teleport>
|
||||
|
||||
<BasicActionSheet v-model:show="showAddCard" class="!max-h-[95vh]">
|
||||
<div class="font-bold text-lg">افزودن کارت</div>
|
||||
<div class="mt-4 text-red-600 font-bold">توجه : حتما شماره کارت صاحب حساب نرم افزار وارد شود.</div>
|
||||
<div class="pb-20 mt-5">
|
||||
<a-form :model="cardForm">
|
||||
<!-- <a-form-item
|
||||
:rules="required()"
|
||||
class="w-full gap-2 !flex-col"
|
||||
label="نام بانک"
|
||||
name="bank_name"
|
||||
>
|
||||
<BasicInput v-model:value="cardForm.bank_name" />
|
||||
</a-form-item>-->
|
||||
<a-form-item
|
||||
:rules="cardNumberValidation()"
|
||||
class="w-full gap-2 !flex-col"
|
||||
label="شماره کارت"
|
||||
name="cart_number"
|
||||
>
|
||||
<BasicInput v-model:value="cardForm.cart_number" type="number" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
v-if="walletStore.walletInfo"
|
||||
class="w-full gap-2 !flex-col"
|
||||
label="تاریخ تولد"
|
||||
name="cart_number"
|
||||
>
|
||||
<BaseDatePicker v-model:value="cardForm.birth_date" class="w-full" inputReadOnly/>
|
||||
</a-form-item>
|
||||
<!-- <a-form-item
|
||||
:rules="required()"
|
||||
class="w-full gap-2 !flex-col"
|
||||
label="شماره حساب"
|
||||
name="account_number"
|
||||
>
|
||||
<BasicInput v-model:value="cardForm.account_number" type="number" />
|
||||
</a-form-item>-->
|
||||
<!-- <a-form-item
|
||||
:rules="required()"
|
||||
class="w-full gap-2 !flex-col"
|
||||
label="شماره شبا"
|
||||
name="shaba_number"
|
||||
>
|
||||
<BasicInput v-model:value="cardForm.shaba_number"/>
|
||||
</a-form-item>-->
|
||||
<BasicButton
|
||||
:disabled="loading"
|
||||
class="w-full mt-5 md:mt-10"
|
||||
type="primary"
|
||||
@click="addCard"
|
||||
>
|
||||
<a-spin v-if="loading" size="small" />
|
||||
<div v-else>ثبت</div>
|
||||
</BasicButton>
|
||||
<BasicButton class="w-full mt-2 mb-8" @click="showAddCard = false">بازگشت</BasicButton>
|
||||
</a-form>
|
||||
</div>
|
||||
<BasicActionSheet v-if="!isDesktop" v-model:show="showAddCard" class="!max-h-[95vh]">
|
||||
<div class="font-bold text-lg">افزودن کارت</div>
|
||||
<div class="mt-4 text-red-600 font-bold">توجه : حتما شماره کارت صاحب حساب نرم افزار وارد شود.</div>
|
||||
<WalletAddCardForm />
|
||||
</BasicActionSheet>
|
||||
|
||||
<BasicModal
|
||||
v-else
|
||||
v-model:visible="showAddCard"
|
||||
title="افزودن کارت"
|
||||
width="480px"
|
||||
destroy-on-close
|
||||
:loading="loading"
|
||||
@ok="addCard"
|
||||
>
|
||||
<div class="text-red-600 font-bold mb-4">توجه : حتما شماره کارت صاحب حساب نرم افزار وارد شود.</div>
|
||||
<WalletAddCardForm :show-actions="false" />
|
||||
</BasicModal>
|
||||
|
||||
<DialogVant v-model:show="showConfirmCode" :closeOnClickOverlay="true" :timeOut="-1">
|
||||
<template v-slot:title>
|
||||
<template #title>
|
||||
<div>
|
||||
<div class="flex justify-end">
|
||||
<BasicIcon
|
||||
@click="showConfirmCode = false"
|
||||
icon="vuesax-linear:close-circle"
|
||||
size="30"
|
||||
class="text-red"
|
||||
@click="showConfirmCode = false"
|
||||
/>
|
||||
</div>
|
||||
<div class="p-5 text-sm">لطفا کد ارسالی را وارد کنید.</div>
|
||||
@@ -232,85 +57,30 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot:button>
|
||||
<template #button>
|
||||
<div></div>
|
||||
<div class="flex justify-end">
|
||||
<BasicButton @click="showConfirmCode = false" class="py-2" type="primary">
|
||||
<BasicButton class="py-2" type="primary" @click="showConfirmCode = false">
|
||||
بستن
|
||||
</BasicButton>
|
||||
</div>
|
||||
</template>
|
||||
</DialogVant>
|
||||
|
||||
<SkeletonLoading v-model:show="infoVisible" />
|
||||
|
||||
<!--
|
||||
<transaction mode="out-in" name="fade">
|
||||
<div v-if="isDeposit"
|
||||
class="bg-white fixed right-0 left-0 bottom-0 top-20 z-100 op-90 flex justify-center items-center">
|
||||
<div class="flex flex-col justify-center mt-[-20vh] items-center px-5">
|
||||
<DotLottieVue class="w-80vw " autoplay loop
|
||||
src="https://lottie.host/203d9dc9-a102-43a6-864a-2d3eef2daf4d/xNBrLOheY7.json" />
|
||||
<div class="flex justify-center items-center text-justify text-primary font-bold">
|
||||
با توجه به اختلال پیش آمده در سامانه پیپینگ
|
||||
برای شارژ کیف پول خود از طریق لینک زیر اقدام نمایید:
|
||||
</div>
|
||||
<a class="mt-2 w-full " href="https://www.payping.ir/d/Hzy0">
|
||||
<BasicButton class="w-full">https://www.payping.ir/d/Hzy0</BasicButton>
|
||||
</a>
|
||||
<div class="w-full">
|
||||
<div class="text-justify mt-2 text-primary font-bold">
|
||||
و یا مبلغ مورد نظر خود را به شماره حساب:
|
||||
</div>
|
||||
</div>
|
||||
<BasicButton icon="vuesax-linear:copy" class="flex-1 w-full mt-1" icon-size="18" @click.stop="copyCode('838-40-89997745-1')">
|
||||
838-40-89997745-1
|
||||
</BasicButton>
|
||||
<div class="w-full">
|
||||
<div class="text-justify mt-2 text-primary font-bold">
|
||||
با شماره شبا:
|
||||
</div>
|
||||
<BasicButton icon="vuesax-linear:copy" class="flex-1 w-full mt-1" icon-size="18" @click.stop="copyCode('IR550560083804089997745001')">
|
||||
IR550560083804089997745001
|
||||
</BasicButton>
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<div class="text-justify mt-2 text-primary font-bold flex">
|
||||
به نام
|
||||
<div class="mx-1 font-extrabold text-blue-600">پديده طلاي شقايق</div>
|
||||
بانک سامان واریز نمایید.
|
||||
</div>
|
||||
<div class="text-justify mt-2 text-primary font-bold">
|
||||
توجه داشته باشید بعد از پرداخت موفق، رسید خود را به شماره 09190909884 در واتس اپ ارسال نمایید.
|
||||
</div>
|
||||
</div>
|
||||
<a class="mt-1 w-full " href="https://wa.me/09190909884">
|
||||
<BasicButton class="w-full !text-green-600" icon="vuesax-linear:whatsapp">شماره واتساپ</BasicButton>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</transaction>
|
||||
-->
|
||||
<BasicModal
|
||||
v-model:visible="chargeAccountModal"
|
||||
custom-footer
|
||||
:closable="false"
|
||||
>
|
||||
<BasicModal v-model:visible="chargeAccountModal" custom-footer :closable="false">
|
||||
<div v-if="config.config.name === 'garoosi'" class="text-center">
|
||||
<div class=" font-bold text-red-600">مشتریان گرامی</div>
|
||||
<div class="font-bold text-red-600">مشتریان گرامی</div>
|
||||
<div class="mt-2">
|
||||
<span>جهت شارژ حساب کاربری خود، مبلغ موردنظر را به شماره کارت زیر واریز نموده و از طریق لینک زیر به پشتیبان اطلاع دهید.</span>
|
||||
</div>
|
||||
|
||||
<div class="mt-1 text-red-600">در صورت عدم همخوانی کارت ملی و فیش واریزی کیف پول شارژ نمیشود!</div>
|
||||
<div class="mt-4">(سیده زهرا موسوی)</div>
|
||||
<div class="mt-1">شماره کارت:6037701900311389</div>
|
||||
<!-- <div>شماره حساب: 0233273609006</div>-->
|
||||
<div>شماره شبا: IR 080160000000001143804581</div>
|
||||
<BasicButton class="mt-4">
|
||||
<a class="w-full" href="https://ble.ir/garoosigallery">
|
||||
پیام به پشتیبانی
|
||||
</a>
|
||||
<a class="w-full" href="https://ble.ir/garoosigallery">پیام به پشتیبانی</a>
|
||||
</BasicButton>
|
||||
</div>
|
||||
<div v-else-if="isBazretalaProject()" class="text-center">
|
||||
@@ -325,11 +95,10 @@
|
||||
<div>شماره شبا: IR 110170000000372468150002</div>
|
||||
</div>
|
||||
<div v-else class="text-center">
|
||||
<div class=" font-bold text-red-600">مشتریان گرامی</div>
|
||||
<div class="font-bold text-red-600">مشتریان گرامی</div>
|
||||
<div class="mt-2">
|
||||
<span>{{ supportMessengerText }}</span>
|
||||
</div>
|
||||
|
||||
<BasicButton v-if="supportMessengerLink">
|
||||
<a
|
||||
class="w-full"
|
||||
@@ -341,25 +110,20 @@
|
||||
</a>
|
||||
</BasicButton>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<a-button type="primary" class="w-full" @click="chargeAccountModal = false">
|
||||
متوجه شدم
|
||||
</a-button>
|
||||
</template>
|
||||
</BasicModal>
|
||||
<BasicModal
|
||||
v-model:visible="withdrawInfModal"
|
||||
custom-footer
|
||||
:closable="false"
|
||||
>
|
||||
|
||||
<BasicModal v-model:visible="withdrawInfModal" custom-footer :closable="false">
|
||||
<div class="text-center">
|
||||
<div class=" font-bold text-red-600">مشتری گرامی</div>
|
||||
<div class="font-bold text-red-600">مشتری گرامی</div>
|
||||
<div class="mt-2">
|
||||
<div>واریز مبلغ مورد نظر، نهایتاً ظرف مدت ۲۴ ساعت آینده انجام میپذیرد.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<a-button type="primary" class="w-full" @click="withdrawInfModal = false">
|
||||
متوجه شدم
|
||||
@@ -370,396 +134,42 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { formatCashWalletBalanceText } from '@/utils/productDealMethod'
|
||||
import { usePriceWithoutType } from '@/utils/usePrice'
|
||||
import { loading, loadingMore } from '@/utils'
|
||||
import BasicActionSheet from '@/components/BasicPacks/BasicActionSheet.vue'
|
||||
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import router from '@/router'
|
||||
import { useWalletStore } from '@/store/walletStore'
|
||||
import Bg_main from '@/components/bg_main.vue'
|
||||
import type { Transaction } from '@/models/transaction'
|
||||
import { createCard, deposit, getActivatedCards, withdraw, confirmCode } from '@/api/wallet'
|
||||
import { useInfiniteScroll } from '@vueuse/core'
|
||||
import { message } from 'ant-design-vue'
|
||||
import ListAnim from '@/components/ListAnim.vue'
|
||||
import TransactionSkeleton from '@/components/TransactionSkeleton.vue'
|
||||
import Item from './components/Item.vue'
|
||||
import type { TableEngineInput, TableOutput } from '@/models/table'
|
||||
import { getTransactionTable, getTransactionTable2 } from '@/api/transaction'
|
||||
import BasicInput from '@/components/BasicPacks/BasicInput.vue'
|
||||
import CardSlider from './components/UISlider/index.vue'
|
||||
import BasicActionSheet from '@/components/BasicPacks/BasicActionSheet.vue'
|
||||
import type { Card } from '@/models/wallet'
|
||||
import { cardNumberValidation, required } from '@/utils/inputRules'
|
||||
import { useUserStore } from '@/store/userStore'
|
||||
import { DotLottieVue } from '@lottiefiles/dotlottie-vue'
|
||||
import OtpInput from 'vue3-otp-input'
|
||||
import DialogVant from '@/components/DialogVant.vue'
|
||||
import SkeletonLoading from './components/SkeletonLoading.vue'
|
||||
import BaseDatePicker from '@/components/BasicPacks/BaseDatePicker'
|
||||
import img from '@/assets/img/user_ly1.svg'
|
||||
import BasicModal from '@/components/BasicPacks/BasicModal.vue'
|
||||
import { useConfigStore } from '@/store/configStore'
|
||||
import { isBazretalaProject } from '@/utils/config'
|
||||
import {
|
||||
buildSupportMessengerUrl,
|
||||
DEFAULT_SUPPORT_MESSENGER_TEXT,
|
||||
loadSupportMessengerFromSettings,
|
||||
supportMessengerSettings,
|
||||
} from '@/utils/supportMessenger'
|
||||
import DialogVant from '@/components/DialogVant.vue'
|
||||
import OtpInput from 'vue3-otp-input'
|
||||
import { useDesktopBreakpoint } from '@/layouts/composables/useAppLayout'
|
||||
import ResponsiveViewPair from '@/layouts/components/ResponsiveViewPair.vue'
|
||||
import { useWalletPage } from './composables/useWalletPage'
|
||||
import DesktopWalletView from './desktop/DesktopWalletView.vue'
|
||||
import MobileWalletView from './mobile/MobileWalletView.vue'
|
||||
import SkeletonLoading from './components/SkeletonLoading.vue'
|
||||
import WalletAddCardForm from './components/WalletAddCardForm.vue'
|
||||
|
||||
const isDeposit = ref<boolean>(true)
|
||||
const walletStore = useWalletStore()
|
||||
const userStore = useUserStore()
|
||||
const showAddCard = ref<boolean>(false)
|
||||
const chargeAccountModal = ref<boolean>(false)
|
||||
const showConfirmCode = ref<boolean>(false)
|
||||
const refOtpInput = ref<InstanceType<typeof VOtpInput> | null>(null)
|
||||
const withdrawInfModal = ref<boolean>(false)
|
||||
const isDesktop = useDesktopBreakpoint()
|
||||
|
||||
const config = useConfigStore()
|
||||
|
||||
const supportMessengerText = computed(() =>
|
||||
supportMessengerSettings.value.messengerText || DEFAULT_SUPPORT_MESSENGER_TEXT
|
||||
)
|
||||
|
||||
const supportMessengerLink = computed(() =>
|
||||
buildSupportMessengerUrl(
|
||||
supportMessengerSettings.value.messenger,
|
||||
supportMessengerSettings.value.messengerId
|
||||
)
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
if (router.currentRoute.value.query.state === 'deposit') {
|
||||
isDeposit.value = true
|
||||
}
|
||||
walletStore.getMyWallet()
|
||||
isDeposit.value = true
|
||||
loadSupportMessengerFromSettings()
|
||||
})
|
||||
|
||||
const form = ref<Transaction>({
|
||||
value: undefined,
|
||||
percentWallet: 0,
|
||||
card_id: undefined
|
||||
})
|
||||
|
||||
const infoVisible = ref<boolean>(false)
|
||||
const cardForm = ref<Card>({
|
||||
birth_date: 0,
|
||||
account_number: '',
|
||||
bank_name: '',
|
||||
cart_number: '',
|
||||
shaba_number: ''
|
||||
})
|
||||
|
||||
const disableButton = computed(() => {
|
||||
if (!loading.value) {
|
||||
if (walletStore?.walletInfo?.cash && !isDeposit.value) {
|
||||
if (cardItems.value.length > 0) {
|
||||
return (
|
||||
walletStore?.walletInfo?.cash <= 0 ||
|
||||
walletStore?.walletInfo?.cash < parseInt(form.value?.value) ||
|
||||
isNaN(parseInt(form.value?.value)) ||
|
||||
parseInt(form.value?.value) < 1000000
|
||||
)
|
||||
} else return true
|
||||
} else if (isDeposit.value) {
|
||||
return isNaN(parseInt(form.value?.value)) || parseInt(form.value?.value) < 1000000
|
||||
} else return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
})
|
||||
const bganim = ref(null)
|
||||
|
||||
const unitCalculator = computed(() => {
|
||||
return (walletStore?.walletInfo?.cash ?? 0) / 100
|
||||
})
|
||||
|
||||
function copyCode(val: string) {
|
||||
// nextTick(() => {
|
||||
navigator.clipboard.writeText(val)
|
||||
message.info('کد رونوشت شد')
|
||||
// })
|
||||
}
|
||||
|
||||
const cardItems = ref<Card[]>([])
|
||||
|
||||
const cardTableOutput = ref<TableOutput<Card> | null>(null)
|
||||
|
||||
const resetData = () => {
|
||||
form.value.value = undefined
|
||||
form.value.percentWallet = 0
|
||||
}
|
||||
|
||||
async function addCard() {
|
||||
try {
|
||||
loading.value = true
|
||||
await createCard(cardForm.value)
|
||||
await getCards()
|
||||
showAddCard.value = false
|
||||
cardForm.value = {
|
||||
birth_date: 0,
|
||||
account_number: '',
|
||||
bank_name: '',
|
||||
cart_number: '',
|
||||
shaba_number: ''
|
||||
}
|
||||
message.success('کارت وارد شده با موفقیت افزوده شد و پس از تایید نمایش داده خواهد شد.')
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function getCards() {
|
||||
try {
|
||||
/* cardTableOutput.value = await getCardsTable()
|
||||
cardItems.value.push(...cardTableOutput.value.rows)*/
|
||||
cardItems.value = (await getActivatedCards()) ?? []
|
||||
form.value.card_id = (await cardItems.value.length) ? cardItems.value[0].id : undefined
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
|
||||
function setIsDeposit(val: boolean) {
|
||||
isDeposit.value = val
|
||||
form.value.value = undefined
|
||||
form.value.percentWallet = 0
|
||||
// console.log(bganim.value.classList)
|
||||
// bganim?.value?.classList.add(val?'right':'left')
|
||||
// bganim?.value?.style.transform = `translateX(${val ? '0' : '-100'});`
|
||||
// bganim?.value?.style.animationDirection = val? 'normal':'reverse'
|
||||
// val? bganim?.value?.classList?.add("move") : bganim?.value?.classList?.remove("move")
|
||||
// const el = bganim.value?.
|
||||
// el.
|
||||
}
|
||||
|
||||
function useStyle() {
|
||||
if (isDeposit.value) return 'right: 2%;'
|
||||
// if (isDeposit.value) return 'animation-direction: normal'
|
||||
// else return 'animation-direction: reverse'
|
||||
else return ' right: 98%; transform: translate(100%, 0);'
|
||||
}
|
||||
|
||||
const formatter = (value: number) => {
|
||||
return `${value}%`
|
||||
}
|
||||
|
||||
function percentChange(val: number) {
|
||||
if (val !== 0) form.value.value = parseInt((unitCalculator.value * val).toFixed())
|
||||
else form.value.value = undefined
|
||||
}
|
||||
|
||||
async function ok() {
|
||||
try {
|
||||
if (form.value.value !== undefined) {
|
||||
loading.value = true
|
||||
if (!isDeposit.value) {
|
||||
await confirmCode({ value: form.value.value })
|
||||
showConfirmCode.value = await true
|
||||
}
|
||||
if (isDeposit.value) {
|
||||
chargeAccountModal.value = true
|
||||
/*const data = await deposit(form.value)
|
||||
window.location.href = data
|
||||
await walletStore.getMyWallet()
|
||||
resetData()
|
||||
message.success('عملیات با موفقیت انجام شد')*/
|
||||
}
|
||||
} else {
|
||||
message.error('ابتدا مبلغ را وارد کنید')
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
//table
|
||||
const items = ref<Transaction[]>([])
|
||||
const depositItems = ref<Transaction[]>([])
|
||||
const withdrawItems = ref<Transaction[]>([])
|
||||
const depositTableOutput = ref<TableOutput<Transaction> | null>(null)
|
||||
const withdrawTableOutput = ref<TableOutput<Transaction> | null>(null)
|
||||
const depositPagination = ref<TableEngineInput>({
|
||||
filters: [
|
||||
/*{
|
||||
field: 'type',
|
||||
cr: 'and',
|
||||
type: 'number',
|
||||
op: 'eq',
|
||||
value: 3
|
||||
}*/
|
||||
],
|
||||
limit: 6,
|
||||
page: 0
|
||||
})
|
||||
const withdrawPagination = ref<TableEngineInput>({
|
||||
filters: [
|
||||
{
|
||||
field: 'type',
|
||||
cr: 'and',
|
||||
type: 'number',
|
||||
op: 'eq',
|
||||
value: 4
|
||||
}
|
||||
],
|
||||
limit: 6,
|
||||
page: 0
|
||||
})
|
||||
const el = ref()
|
||||
// const {y} = useScroll(el)
|
||||
|
||||
onMounted(async () => {
|
||||
cardForm.value.birth_date = userStore.userInfo?.birth_date
|
||||
await initWithdrawTable()
|
||||
await initDepositTable()
|
||||
await getCards()
|
||||
})
|
||||
|
||||
if (!userStore.isSingle) {
|
||||
useInfiniteScroll(
|
||||
el,
|
||||
async () => {
|
||||
// load more
|
||||
// if (!userStore.isSingle) {
|
||||
if (isDeposit.value) {
|
||||
if (
|
||||
depositTableOutput.value &&
|
||||
(depositPagination.value.page + 1) * depositPagination.value.limit <
|
||||
depositTableOutput.value.query.total
|
||||
) {
|
||||
depositPagination.value.page++
|
||||
console.log('Updated Page:', depositPagination.value.page)
|
||||
await initDepositTable()
|
||||
}
|
||||
} else {
|
||||
if (
|
||||
withdrawTableOutput.value &&
|
||||
(withdrawPagination.value.page + 1) * withdrawPagination.value.limit <
|
||||
withdrawTableOutput.value.query.total
|
||||
) {
|
||||
// console.log('gfgf')
|
||||
withdrawPagination.value.page++
|
||||
await initWithdrawTable()
|
||||
}
|
||||
}
|
||||
// }
|
||||
},
|
||||
{ distance: 12 }
|
||||
)
|
||||
}
|
||||
|
||||
async function initDepositTable() {
|
||||
try {
|
||||
depositPagination.value.page === 0 ? (loading.value = true) : (loadingMore.value = true)
|
||||
depositTableOutput.value = await getTransactionTable2(depositPagination.value)
|
||||
depositItems.value.push(...depositTableOutput.value.rows)
|
||||
// console.log(tableOutput.value)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
loadingMore.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function initWithdrawTable() {
|
||||
try {
|
||||
withdrawPagination.value.page === 0 ? (loading.value = true) : (loadingMore.value = true)
|
||||
withdrawTableOutput.value = await getTransactionTable(withdrawPagination.value)
|
||||
withdrawItems.value.push(...withdrawTableOutput.value.rows)
|
||||
// console.log(tableOutput.value)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
loadingMore.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function handleOnComplete(value: string) {
|
||||
try {
|
||||
infoVisible.value = true
|
||||
showConfirmCode.value = false
|
||||
await withdraw({ ...form.value, otp: value })
|
||||
await walletStore.getMyWallet()
|
||||
await message.success('عملیات با موفقیت انجام شد')
|
||||
withdrawInfModal.value = true
|
||||
resetData()
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
infoVisible.value = false
|
||||
refOtpInput.value?.clearInput()
|
||||
}
|
||||
const {
|
||||
config,
|
||||
showAddCard,
|
||||
chargeAccountModal,
|
||||
showConfirmCode,
|
||||
withdrawInfModal,
|
||||
infoVisible,
|
||||
refOtpInput,
|
||||
supportMessengerText,
|
||||
supportMessengerLink,
|
||||
isBazretalaProject,
|
||||
handleOnComplete,
|
||||
loading,
|
||||
addCard,
|
||||
} = useWalletPage()
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/*.right {
|
||||
left: 100%;
|
||||
transform: translateX(-100%);
|
||||
}*/
|
||||
|
||||
.left {
|
||||
transform: translateX(0);
|
||||
left: 0;
|
||||
}
|
||||
|
||||
/*.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}*/
|
||||
/*.trans{
|
||||
transition: height 1s;
|
||||
}*/
|
||||
.toggle-transe-parent {
|
||||
animation: ease-in-out infinite alternate swingParent;
|
||||
}
|
||||
|
||||
@keyframes swingParent {
|
||||
from {
|
||||
transform: translateX(0);
|
||||
left: 0;
|
||||
}
|
||||
to {
|
||||
left: 100%;
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
}
|
||||
|
||||
.animate.right {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.animate.right.move {
|
||||
right: 100%;
|
||||
transform: translate(100%, 0);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 426px) {
|
||||
:deep(.ant-form-item .ant-form-item-label) {
|
||||
margin-top: 30px !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 426px) {
|
||||
.card-slider-wrap {
|
||||
width: 426px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.wallet-page-root {
|
||||
min-height: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="absolute inset-0 bg-cover bg-center opacity-60" :style="{ backgroundImage: `url(${img})` }"></div>
|
||||
<div class="bg-white py-3 px-3 text-primary font-bold drop-shadow z-[1999] wrap-fix">کیف پول</div>
|
||||
<div class="bg-white wrap-fix py-3 top-11 px-3 text-primary font-bold flex justify-evenly z-[1999]">
|
||||
<div class="flex justify-evenly w-full px-2 h-11 items-center bg-gray-50 relative rounded">
|
||||
<div
|
||||
:class="isDeposit ? 'text-primary' : 'text-gray-400'"
|
||||
class="w-full text-center z-2"
|
||||
@click="setIsDeposit(true)"
|
||||
>
|
||||
واریز
|
||||
</div>
|
||||
<div
|
||||
:class="!isDeposit ? 'text-primary' : 'text-gray-400'"
|
||||
class="w-full text-center z-2"
|
||||
@click="setIsDeposit(false)"
|
||||
>
|
||||
برداشت
|
||||
</div>
|
||||
<div
|
||||
:style="useStyle()"
|
||||
class="absolute bg-white h-8 w-1/2 rounded-lg animate right"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="px-5 pt-26"
|
||||
:class="isDeposit ? 'pb-2' : 'pb-[calc(var(--app-bottom-chrome-height)+var(--app-add-card-height)+1rem)]'"
|
||||
>
|
||||
<a-form :model="form" class="!mt-5" name="basic" @finish="ok()">
|
||||
<div class="border-gray-200 border-1 rounded-xl p-5 trans h-40 relative">
|
||||
<bg_main />
|
||||
<div class="z-100 relative">
|
||||
<a-form-item :rules="[required()]">
|
||||
<BasicInput
|
||||
v-model:value="form.value"
|
||||
addon-before="ریال"
|
||||
:addon-bg-color="useConfigStore().config.color"
|
||||
addon-text-color="white"
|
||||
place-holder="مبلغ"
|
||||
size="large"
|
||||
type="price"
|
||||
/>
|
||||
</a-form-item>
|
||||
<Transition mode="out-in" name="fade">
|
||||
<div v-if="!isDeposit">
|
||||
<div class="text-red text-xs font-bold mb-2">حداقل مبلغ برداشتی 100 هزار تومان می باشد.</div>
|
||||
<div class="font-bold text-xs">
|
||||
{{ formatCashWalletBalanceText(usePriceWithoutType(walletStore?.walletInfo?.cash ?? 0)) }}
|
||||
</div>
|
||||
<a-form-item v-if="walletStore?.walletInfo" class="!mt-3">
|
||||
<a-slider
|
||||
v-model:value="form.percentWallet"
|
||||
:disabled="walletStore?.walletInfo?.cash <= 0"
|
||||
:max="100"
|
||||
:min="0"
|
||||
:step="10"
|
||||
:tip-formatter="formatter"
|
||||
@change="percentChange"
|
||||
/>
|
||||
</a-form-item>
|
||||
</div>
|
||||
<div v-else class="mt-3">
|
||||
<div v-if="!isBazretalaProject()" class="text-red text-xs font-bold mb-2">
|
||||
حداقل مبلغ واریزی 100 هزار تومان می باشد.
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<BasicButton class="w-full font-bold !px-1" @click="form.value = 10000000">
|
||||
{{ usePriceWithoutType(10000000) }}
|
||||
</BasicButton>
|
||||
<BasicButton class="w-full font-bold !px-1" @click="form.value = 50000000">
|
||||
{{ usePriceWithoutType(50000000) }}
|
||||
</BasicButton>
|
||||
<BasicButton class="w-full font-bold !px-1" @click="form.value = 100000000">
|
||||
{{ usePriceWithoutType(100000000) }}
|
||||
</BasicButton>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
</div>
|
||||
<a-form-item>
|
||||
<BasicButton
|
||||
:disabled="disableButton"
|
||||
class="w-full py-2 mt-5"
|
||||
html-type="submit"
|
||||
type="primary"
|
||||
>
|
||||
<div>
|
||||
<a-spin v-if="loading" size="small" />
|
||||
<div v-else>{{ isDeposit ? 'واریز' : 'برداشت' }}</div>
|
||||
</div>
|
||||
</BasicButton>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<div
|
||||
v-if="isDeposit"
|
||||
:ref="(node) => { mobileDepositScrollEl = (node as HTMLElement | null) }"
|
||||
:class="loading ? 'h-screen' : ''"
|
||||
class="px-3 overflow-y-scroll w-full h-[49vh] pb-16"
|
||||
style="max-height: calc(100vh - 50px)"
|
||||
>
|
||||
<list-anim v-if="!loading" :numberItemsAnim="4">
|
||||
<Item v-for="item in depositItems" :key="item.id" :item="item" />
|
||||
<TransactionSkeleton v-if="loadingMore" class="mt-1 mb-8" />
|
||||
</list-anim>
|
||||
<TransactionSkeleton v-for="i in 13" v-else :key="i" class="mt-1" />
|
||||
</div>
|
||||
<Transition mode="out-in" name="fade">
|
||||
<template v-if="!isDeposit">
|
||||
<div
|
||||
v-if="!loading && cardItems.length === 0"
|
||||
class="h-30 flex items-center justify-center"
|
||||
>
|
||||
هیچ کارتی یافت نشد
|
||||
</div>
|
||||
</template>
|
||||
</Transition>
|
||||
</div>
|
||||
|
||||
<Teleport to="body">
|
||||
<CardSlider
|
||||
v-if="!isDeposit && cardItems.length > 0 && !showAddCard"
|
||||
v-model:id="form.card_id"
|
||||
:items="cardItems"
|
||||
class="card-slider-wrap wallet-card-slider"
|
||||
@cardDeleted="getCards"
|
||||
/>
|
||||
</Teleport>
|
||||
|
||||
<Teleport to="body">
|
||||
<div
|
||||
v-if="!isDeposit && !showAddCard"
|
||||
class="add-card app-dock-add-bar"
|
||||
@click="showAddCard = true"
|
||||
>
|
||||
<div>افزودن کارت جدید</div>
|
||||
<BasicIcon icon="vuesax-linear:add" />
|
||||
</div>
|
||||
</Teleport>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import BasicInput from '@/components/BasicPacks/BasicInput.vue'
|
||||
import Bg_main from '@/components/bg_main.vue'
|
||||
import ListAnim from '@/components/ListAnim.vue'
|
||||
import TransactionSkeleton from '@/components/TransactionSkeleton.vue'
|
||||
import { useConfigStore } from '@/store/configStore'
|
||||
import { required } from '@/utils/inputRules'
|
||||
import img from '@/assets/img/user_ly1.svg'
|
||||
import CardSlider from '../components/UISlider/index.vue'
|
||||
import Item from '../components/Item.vue'
|
||||
import { useWalletPageContext } from '../composables/useWalletPage'
|
||||
|
||||
const {
|
||||
isDeposit,
|
||||
walletStore,
|
||||
showAddCard,
|
||||
form,
|
||||
disableButton,
|
||||
cardItems,
|
||||
depositItems,
|
||||
loading,
|
||||
loadingMore,
|
||||
mobileDepositScrollEl,
|
||||
isBazretalaProject,
|
||||
usePriceWithoutType,
|
||||
formatCashWalletBalanceText,
|
||||
setIsDeposit,
|
||||
useStyle,
|
||||
formatter,
|
||||
percentChange,
|
||||
ok,
|
||||
getCards,
|
||||
} = useWalletPageContext()
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.animate.right {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 426px) {
|
||||
.card-slider-wrap {
|
||||
width: 426px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user