Merge branch 'boursecu' of https://get.feep.ir/khaneghi_abshodeh/khanegi_boursecu into boursecu
This commit is contained in:
@@ -1,4 +1,12 @@
|
||||
import useAxios from '@/utils/useAxios'
|
||||
import type {Physicalreceive} from "@/models/physicalreceive";
|
||||
export const physicalReceiveApi = async (obj:Object) => await useAxios.post(`/customer/wallet/withdraw_physical`, obj)
|
||||
export const getPhysicalReceiveList = async (obj?:Object) => await useAxios.post<Physicalreceive>(`/customer/wallet/withdraw_physical/table`, obj)
|
||||
import type { Physicalreceive } from '@/models/physicalreceive'
|
||||
import type { TableEngineInput, TableEngineOutput } from '@/models/table'
|
||||
|
||||
export const physicalReceiveApi = async (obj: Object) =>
|
||||
await useAxios.post(`/customer/wallet/withdraw_physical`, obj)
|
||||
|
||||
export const getPhysicalReceiveList = async (obj?: TableEngineInput) =>
|
||||
await useAxios.post<TableEngineOutput<Physicalreceive>>(
|
||||
`/customer/wallet/withdraw_physical/table`,
|
||||
obj,
|
||||
)
|
||||
|
||||
@@ -30,13 +30,14 @@
|
||||
<div
|
||||
class="flex items-center gap-1"
|
||||
:class="variant === 'desktop' ? 'dpr-cart-row__input' : 'pr-cart-row__input'"
|
||||
@focusin="selectCountInput"
|
||||
>
|
||||
<BasicInput
|
||||
v-model:value="item.count"
|
||||
:addon-before="quantityUnit"
|
||||
:addon-bg-color="config.config?.color"
|
||||
addon-text-color="white"
|
||||
type="text"
|
||||
type="number"
|
||||
:inputmode="isCountBased ? 'numeric' : 'decimal'"
|
||||
@update:value="onCountInput"
|
||||
/>
|
||||
@@ -91,6 +92,13 @@ const displayGold = computed(() => {
|
||||
|
||||
const config = useConfigStore()
|
||||
|
||||
function selectCountInput(e: FocusEvent) {
|
||||
const el = e.target as HTMLInputElement | null
|
||||
if (!el || el.tagName !== 'INPUT' || typeof el.select !== 'function') return
|
||||
// تا کاربر با تایپ عدد جدید، مقدار قبلی را جایگزین کند
|
||||
requestAnimationFrame(() => el.select())
|
||||
}
|
||||
|
||||
function onCountInput(raw: string | number) {
|
||||
countError.value = ''
|
||||
const normalized = persianToEnglishDigits(String(raw ?? '').trim())
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<template>
|
||||
<MobileRequestListView v-show="!isDesktop" />
|
||||
<DesktopRequestListView v-show="isDesktop" />
|
||||
<div class="physical-receive-list-root">
|
||||
<MobileRequestListView v-show="!isDesktop" />
|
||||
<DesktopRequestListView v-show="isDesktop" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -12,3 +14,20 @@ import MobileRequestListView from '../mobile/MobileRequestListView.vue'
|
||||
const { isDesktop } = usePhysicalReceiveShellContext()
|
||||
usePhysicalReceiveList()
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.physical-receive-list-root {
|
||||
flex: 1 1 0;
|
||||
min-height: 0;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.physical-receive-list-root > * {
|
||||
flex: 1 1 0;
|
||||
min-height: 0;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -44,6 +44,12 @@ const { isDesktop } = usePhysicalReceiveShell()
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.physical-receive-page-root__content > :deep(.physical-receive-list-root),
|
||||
.physical-receive-page-root__content > :deep(.physical-new-request) {
|
||||
flex: 1 1 0;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.physical-receive-page-root--desktop {
|
||||
height: auto;
|
||||
min-height: 0;
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
class="flex flex-col gap-4 mpage-content px-2 pb-[calc(var(--app-bottom-chrome-height)+var(--app-add-card-height)+1rem)]"
|
||||
>
|
||||
<RequestItem v-for="item in requestItems" :key="item.id" :item="item" />
|
||||
<div class="physical-receive-list">
|
||||
<div class="physical-receive-list__scroll mpage-content px-2">
|
||||
<div
|
||||
class="flex flex-col gap-4 pb-[calc(var(--app-add-card-height,88px)+1.25rem)]"
|
||||
>
|
||||
<RequestItem v-for="item in requestItems" :key="item.id" :item="item" />
|
||||
</div>
|
||||
</div>
|
||||
<Teleport to="body">
|
||||
<div class="add-request app-dock-add-bar" @click="openAdd()">
|
||||
@@ -21,3 +23,21 @@ import { usePhysicalReceiveListContext } from '../composables/usePhysicalReceive
|
||||
|
||||
const { requestItems, openAdd } = usePhysicalReceiveListContext()
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.physical-receive-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.physical-receive-list__scroll {
|
||||
flex: 1 1 0;
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
overscroll-behavior-y: contain;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -44,7 +44,16 @@
|
||||
|
||||
<div ref="listRef" :class="loading ? 'min-h-[50vh]' : ''" class="mt-5">
|
||||
<list-anim v-if="!loading">
|
||||
<Item v-for="item in items" :key="item.id" :item="item" />
|
||||
<template v-if="activeTab.fetchMode === 'physical'">
|
||||
<RequestItem
|
||||
v-for="item in physicalItems"
|
||||
:key="item.id"
|
||||
:item="item"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<Item v-for="item in items" :key="item.id" :item="item" />
|
||||
</template>
|
||||
<div :ref="bindMobileObserver" class="w-full opacity-0 relative">
|
||||
در حال بارگذاری
|
||||
</div>
|
||||
@@ -55,7 +64,7 @@
|
||||
<TransactionSkeleton v-for="i in 8" :key="i" class="mt-1" />
|
||||
</template>
|
||||
|
||||
<div v-if="!loading && items.length === 0" class="dtxn-empty">
|
||||
<div v-if="!loading && listEmpty" class="dtxn-empty">
|
||||
<img :src="emptyImage" alt="" class="dtxn-empty__image" />
|
||||
<p class="dtxn-empty__text">{{ emptyText }}</p>
|
||||
</div>
|
||||
@@ -72,6 +81,7 @@ import ListAnim from '@/components/ListAnim.vue'
|
||||
import TransactionSkeleton from '@/components/TransactionSkeleton.vue'
|
||||
import emptyImage from '@/assets/img/cash_empty.svg'
|
||||
import Item from './components/Item.vue'
|
||||
import RequestItem from '@/views/base/physicalReceive/components/RequestItem.vue'
|
||||
import BoursecuTransactionFilters from './components/BoursecuTransactionFilters.vue'
|
||||
import { BOURSECU_TRANSACTION_TABS } from './config/boursecuTabs'
|
||||
import { useTransactionsPageContext } from './composables/useTransactionsPage'
|
||||
@@ -80,10 +90,12 @@ const listRef = ref<HTMLElement | null>(null)
|
||||
|
||||
const {
|
||||
items,
|
||||
physicalItems,
|
||||
activeTabId,
|
||||
tradeSide,
|
||||
activeTab,
|
||||
emptyText,
|
||||
listEmpty,
|
||||
setActiveTab,
|
||||
setTradeSide,
|
||||
bindMobileObserver,
|
||||
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
transactionDateFromFilter,
|
||||
transactionDateToFilter,
|
||||
transactionItems,
|
||||
physicalReceiveItems,
|
||||
transactionPagination,
|
||||
transactionStatusFilter,
|
||||
transactionProductFilter,
|
||||
@@ -37,6 +38,7 @@ import {
|
||||
export interface TransactionsPageContext {
|
||||
pagination: typeof transactionPagination
|
||||
items: typeof transactionItems
|
||||
physicalItems: typeof physicalReceiveItems
|
||||
tableOutput: typeof transactionTableOutput
|
||||
showFilter: ReturnType<typeof ref<boolean>>
|
||||
dateFilter: typeof transactionDateFilter
|
||||
@@ -53,6 +55,7 @@ export interface TransactionsPageContext {
|
||||
activeTab: ReturnType<typeof computed<BoursecuTransactionTab>>
|
||||
statusOptions: ReturnType<typeof computed<ReturnType<typeof getBoursecuStatusOptionsForTab>>>
|
||||
emptyText: ReturnType<typeof computed<string>>
|
||||
listEmpty: ReturnType<typeof computed<boolean>>
|
||||
resetPagination: typeof resetTransactionsPagination
|
||||
initTable: () => Promise<void>
|
||||
reloadTable: typeof reloadTransactionsTable
|
||||
@@ -111,6 +114,13 @@ export function useTransactionsPageProvider() {
|
||||
return activeTab.value.emptyText
|
||||
})
|
||||
|
||||
const listEmpty = computed(() => {
|
||||
if (activeTab.value.fetchMode === 'physical') {
|
||||
return physicalReceiveItems.value.length === 0
|
||||
}
|
||||
return transactionItems.value.length === 0
|
||||
})
|
||||
|
||||
async function initTable() {
|
||||
await reloadTransactionsTable()
|
||||
}
|
||||
@@ -207,6 +217,7 @@ export function useTransactionsPageProvider() {
|
||||
const context: TransactionsPageContext = {
|
||||
pagination: transactionPagination,
|
||||
items: transactionItems,
|
||||
physicalItems: physicalReceiveItems,
|
||||
tableOutput: transactionTableOutput,
|
||||
showFilter,
|
||||
dateFilter: transactionDateFilter,
|
||||
@@ -223,6 +234,7 @@ export function useTransactionsPageProvider() {
|
||||
activeTab,
|
||||
statusOptions,
|
||||
emptyText,
|
||||
listEmpty,
|
||||
resetPagination: resetTransactionsPagination,
|
||||
initTable,
|
||||
reloadTable: reloadTransactionsTable,
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { ref } from 'vue'
|
||||
import { getTransactionTable, getTransactionTable2 } from '@/api/transaction'
|
||||
import { getPhysicalReceiveList } from '@/api/physicalreceive'
|
||||
import type { TableEngineInput, TableEngineOutput } from '@/models/table'
|
||||
import type { Transaction } from '@/models/transaction'
|
||||
import type { Physicalreceive } from '@/models/physicalreceive'
|
||||
import { loading, loadingMore } from '@/utils'
|
||||
import {
|
||||
BOURSECU_TRANSACTION_TABS,
|
||||
@@ -17,7 +19,10 @@ let activeFetchId = 0
|
||||
export const transactionsBoursecuMode = ref(true)
|
||||
export const transactionPagination = ref<TableEngineInput>({ filters: [], limit: 7, page: 0 })
|
||||
export const transactionItems = ref<Transaction[]>([])
|
||||
export const transactionTableOutput = ref<TableEngineOutput<Transaction> | null>(null)
|
||||
export const physicalReceiveItems = ref<Physicalreceive[]>([])
|
||||
export const transactionTableOutput = ref<TableEngineOutput<Transaction | Physicalreceive> | null>(
|
||||
null,
|
||||
)
|
||||
export const transactionDateFilter = ref<string>()
|
||||
export const transactionDateFromFilter = ref<string>()
|
||||
export const transactionDateToFilter = ref<string>()
|
||||
@@ -46,12 +51,19 @@ export function resetTransactionsPagination() {
|
||||
|
||||
function resolveTransactionFetcher() {
|
||||
const activeTab = getActiveBoursecuTab()
|
||||
return activeTab.fetchMode === 'deposit' ? getTransactionTable2 : getTransactionTable
|
||||
if (activeTab.fetchMode === 'deposit') {
|
||||
return getTransactionTable2
|
||||
}
|
||||
if (activeTab.fetchMode === 'physical') {
|
||||
return getPhysicalReceiveList
|
||||
}
|
||||
return getTransactionTable
|
||||
}
|
||||
|
||||
async function fetchTransactionsPage(append: boolean): Promise<boolean> {
|
||||
const fetchId = ++activeFetchId
|
||||
const isFirstPage = transactionPagination.value.page === 0 && !append
|
||||
const isPhysical = getActiveBoursecuTab().fetchMode === 'physical'
|
||||
|
||||
if (isFirstPage) {
|
||||
loading.value = true
|
||||
@@ -69,10 +81,22 @@ async function fetchTransactionsPage(append: boolean): Promise<boolean> {
|
||||
transactionTableOutput.value = output
|
||||
const rows = output.rows ?? []
|
||||
|
||||
if (isFirstPage) {
|
||||
transactionItems.value = [...rows]
|
||||
if (isPhysical) {
|
||||
const physicalRows = rows as Physicalreceive[]
|
||||
if (isFirstPage) {
|
||||
physicalReceiveItems.value = [...physicalRows]
|
||||
transactionItems.value = []
|
||||
} else {
|
||||
physicalReceiveItems.value.push(...physicalRows)
|
||||
}
|
||||
} else {
|
||||
transactionItems.value.push(...rows)
|
||||
const txRows = rows as Transaction[]
|
||||
if (isFirstPage) {
|
||||
transactionItems.value = [...txRows]
|
||||
physicalReceiveItems.value = []
|
||||
} else {
|
||||
transactionItems.value.push(...txRows)
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
@@ -93,6 +117,7 @@ async function fetchTransactionsPage(append: boolean): Promise<boolean> {
|
||||
export async function reloadTransactionsTable() {
|
||||
transactionPagination.value.page = 0
|
||||
transactionItems.value = []
|
||||
physicalReceiveItems.value = []
|
||||
transactionTableOutput.value = null
|
||||
resetTransactionsPagination()
|
||||
await fetchTransactionsPage(false)
|
||||
@@ -128,6 +153,7 @@ export function resetTransactionsPageData() {
|
||||
transactionsBoursecuMode.value = true
|
||||
transactionPagination.value = { filters: [], limit: 7, page: 0 }
|
||||
transactionItems.value = []
|
||||
physicalReceiveItems.value = []
|
||||
transactionTableOutput.value = null
|
||||
transactionDateFilter.value = undefined
|
||||
transactionDateFromFilter.value = undefined
|
||||
|
||||
@@ -8,7 +8,7 @@ export type BoursecuTransactionTabId =
|
||||
|
||||
export type BoursecuTradeSide = 'buy' | 'sell'
|
||||
|
||||
export type BoursecuTransactionFetchMode = 'transaction' | 'deposit'
|
||||
export type BoursecuTransactionFetchMode = 'transaction' | 'deposit' | 'physical'
|
||||
|
||||
export type BoursecuTradeStatusFilter = 'completed' | 'pending' | 'cancelled'
|
||||
export type BoursecuFulfillmentStatusFilter = 'delivered' | 'registered' | 'cancelled'
|
||||
@@ -38,10 +38,11 @@ export const BOURSECU_TRADE_STATUS_OPTIONS: BoursecuTransactionStatusOption[] =
|
||||
{ value: 'cancelled', label: 'لغو شده', sts: 3 },
|
||||
]
|
||||
|
||||
/** وضعیتهای سند برداشت فیزیکی (Withdraw::$STS) */
|
||||
export const BOURSECU_FULFILLMENT_STATUS_OPTIONS: BoursecuTransactionStatusOption[] = [
|
||||
{ value: 'delivered', label: 'تحویل شده', sts: 2 },
|
||||
{ value: 'registered', label: 'ثبت درخواست', sts: 1 },
|
||||
{ value: 'cancelled', label: 'لغو شده', sts: 3 },
|
||||
{ value: 'registered', label: 'در انتظار ارسال', sts: 50 },
|
||||
{ value: 'delivered', label: 'ارسال شده', sts: 51 },
|
||||
{ value: 'cancelled', label: 'لغو شده', sts: 52 },
|
||||
]
|
||||
|
||||
/** @deprecated Use getBoursecuStatusOptionsForTab instead */
|
||||
@@ -74,8 +75,8 @@ export const BOURSECU_TRANSACTION_TABS: BoursecuTransactionTab[] = [
|
||||
id: 'physical',
|
||||
label: 'تحویل فیزیکی',
|
||||
emptyText: 'درخواست تحویل فیزیکی برای شما ثبت نشده است',
|
||||
fetchMode: 'physical',
|
||||
showAdvancedFilters: true,
|
||||
typeFilters: [9],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -97,11 +98,12 @@ export function getBoursecuStatusOptionsForTab(
|
||||
}
|
||||
|
||||
export function boursecuTabSupportsProductFilter(tab: BoursecuTransactionTab): boolean {
|
||||
return tab.id === 'trades' || tab.id === 'physical'
|
||||
// فیلتر محصول روی جدول سند برداشت فیزیکی (hasMany Transaction) قابلاعتماد نیست
|
||||
return tab.id === 'trades'
|
||||
}
|
||||
|
||||
function getBoursecuStatusFilterField(tab: BoursecuTransactionTab): string {
|
||||
if (tab.fetchMode === 'deposit') {
|
||||
if (tab.fetchMode === 'deposit' || tab.fetchMode === 'physical') {
|
||||
return 'sts'
|
||||
}
|
||||
|
||||
@@ -129,7 +131,7 @@ export function buildBoursecuTransactionPagination(
|
||||
): TableEngineInput {
|
||||
const filters: TableEngineInput['filters'] = []
|
||||
|
||||
if (tab.fetchMode !== 'deposit' && tab.typeFilters?.length) {
|
||||
if (tab.fetchMode !== 'deposit' && tab.fetchMode !== 'physical' && tab.typeFilters?.length) {
|
||||
const typeValue =
|
||||
tab.showTradeToggle && tab.typeFilters.includes(TRADE_TYPE_BY_SIDE[tradeSide])
|
||||
? TRADE_TYPE_BY_SIDE[tradeSide]
|
||||
|
||||
@@ -42,12 +42,22 @@
|
||||
<div ref="listRef" :class="loading ? 'min-h-[40vh]' : ''" class="mt-5">
|
||||
<div v-if="!loading" class="dtxn-list">
|
||||
<list-anim>
|
||||
<Item
|
||||
v-for="item in items"
|
||||
:key="item.id"
|
||||
:item="item"
|
||||
variant="desktop"
|
||||
/>
|
||||
<template v-if="activeTab.fetchMode === 'physical'">
|
||||
<RequestItem
|
||||
v-for="item in physicalItems"
|
||||
:key="item.id"
|
||||
:item="item"
|
||||
variant="desktop"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<Item
|
||||
v-for="item in items"
|
||||
:key="item.id"
|
||||
:item="item"
|
||||
variant="desktop"
|
||||
/>
|
||||
</template>
|
||||
</list-anim>
|
||||
<div :ref="bindDesktopObserver" class="w-full opacity-0 relative">
|
||||
در حال بارگذاری
|
||||
@@ -59,7 +69,7 @@
|
||||
<TransactionSkeleton v-for="i in 8" :key="i" class="mt-1" />
|
||||
</template>
|
||||
|
||||
<div v-if="!loading && items.length === 0" class="dtxn-empty">
|
||||
<div v-if="!loading && listEmpty" class="dtxn-empty">
|
||||
<img :src="emptyImage" alt="" class="dtxn-empty__image" />
|
||||
<p class="dtxn-empty__text">{{ emptyText }}</p>
|
||||
</div>
|
||||
@@ -76,6 +86,7 @@ import ListAnim from '@/components/ListAnim.vue'
|
||||
import TransactionSkeleton from '@/components/TransactionSkeleton.vue'
|
||||
import emptyImage from '@/assets/img/cash_empty.svg'
|
||||
import Item from '../components/Item.vue'
|
||||
import RequestItem from '@/views/base/physicalReceive/components/RequestItem.vue'
|
||||
import BoursecuTransactionFilters from '../components/BoursecuTransactionFilters.vue'
|
||||
import { BOURSECU_TRANSACTION_TABS } from '../config/boursecuTabs'
|
||||
import { useTransactionsPageContext } from '../composables/useTransactionsPage'
|
||||
@@ -84,10 +95,12 @@ const listRef = ref<HTMLElement | null>(null)
|
||||
|
||||
const {
|
||||
items,
|
||||
physicalItems,
|
||||
activeTabId,
|
||||
tradeSide,
|
||||
activeTab,
|
||||
emptyText,
|
||||
listEmpty,
|
||||
setActiveTab,
|
||||
setTradeSide,
|
||||
bindDesktopObserver,
|
||||
|
||||
Reference in New Issue
Block a user