Merge feature/responsive-layout-refactor into modular for desktop layouts.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
<template>
|
||||
<div v-if="item" class="bg-white flex flex-col items-center p-3 rounded-xl">
|
||||
<div
|
||||
v-if="item"
|
||||
class="bg-white flex flex-col items-center p-3 rounded-xl"
|
||||
:class="{ 'dfund-card': variant === 'desktop' }"
|
||||
>
|
||||
<img :src="displayImage" class="w-[87px] h-[87px] object-contain" alt="" @error="onImageError">
|
||||
<div class="mt-3">{{ item.title ?? '-' }}</div>
|
||||
<div class="mt-1 flex flex-col items-center gap-0.5 text-center">
|
||||
@@ -21,9 +25,12 @@ import { getProductDisplayImage } from '@/utils/productAssets'
|
||||
|
||||
interface Prop {
|
||||
item: WalletInventoryCard
|
||||
variant?: 'mobile' | 'desktop'
|
||||
}
|
||||
|
||||
const props = defineProps<Prop>()
|
||||
const props = withDefaults(defineProps<Prop>(), {
|
||||
variant: 'mobile',
|
||||
})
|
||||
const imageSrc = ref('')
|
||||
|
||||
const displayImage = computed(() => imageSrc.value || resolveImage())
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
import { computed, inject, onMounted, provide, type InjectionKey, type Ref } from 'vue'
|
||||
import router from '@/router'
|
||||
import { loading } from '@/utils'
|
||||
import { usePriceWithoutType } from '@/utils/usePrice'
|
||||
import { useConfigStore } from '@/store/configStore'
|
||||
import { useWalletAssets } from '@/composables/useWalletAssets'
|
||||
import type { WalletMetalTotal } from '@/models/walletAssets'
|
||||
import { resolveSummaryMetalWeight, fundPageInventoryCards } from '@/utils/productAssets'
|
||||
import { useWalletStore } from '@/store/walletStore'
|
||||
import { getLastPrices } from '@/utils/price'
|
||||
import {
|
||||
getProjectFundEmptyImage,
|
||||
getProjectFundEmptyText,
|
||||
getProjectFundHeaderBackground,
|
||||
isBazretalaProject,
|
||||
} from '@/utils/config'
|
||||
import img from '@/assets/img/user_ly1.svg'
|
||||
import empty from '@/assets/img/cash_empty.svg'
|
||||
|
||||
export interface FundPageContext {
|
||||
isDesktop: Ref<boolean>
|
||||
nameProject: string
|
||||
meta: ReturnType<typeof computed>
|
||||
inventoryCards: ReturnType<typeof computed>
|
||||
metalTotals: ReturnType<typeof computed>
|
||||
primaryMetalTotal: ReturnType<typeof computed>
|
||||
cashWallet: ReturnType<typeof computed>
|
||||
totalRialValue: ReturnType<typeof computed>
|
||||
countBasedInventory: ReturnType<typeof computed>
|
||||
fundHeaderBackground: string
|
||||
fundEmptyImage: string
|
||||
fundEmptyText: string
|
||||
isBazretalaProject: typeof isBazretalaProject
|
||||
formatMetalTotal: (metal: WalletMetalTotal) => string
|
||||
openFundInfo: (productId: number) => void
|
||||
goBack: () => void
|
||||
}
|
||||
|
||||
export const FUND_PAGE_KEY: InjectionKey<FundPageContext> = Symbol('fundPage')
|
||||
|
||||
export function useFundPage(isDesktop: Ref<boolean>) {
|
||||
const nameProject = useConfigStore().config.name
|
||||
const { assetsSummary, loadWalletAssets } = useWalletAssets()
|
||||
const walletStore = useWalletStore()
|
||||
const fundHeaderBackground = getProjectFundHeaderBackground(img)
|
||||
const fundEmptyImage = getProjectFundEmptyImage(empty)
|
||||
const fundEmptyText = getProjectFundEmptyText()
|
||||
|
||||
const meta = computed(() => assetsSummary.value?.meta)
|
||||
const inventoryCards = computed(() =>
|
||||
fundPageInventoryCards(assetsSummary.value?.inventory_cards ?? [])
|
||||
)
|
||||
const metalTotals = computed(() => assetsSummary.value?.metal_totals ?? [])
|
||||
const primaryMetalTotal = computed(() => metalTotals.value[0])
|
||||
const cashWallet = computed(() => assetsSummary.value?.cash_wallet ?? 0)
|
||||
const totalRialValue = computed(() => assetsSummary.value?.total_rial_value ?? 0)
|
||||
const countBasedInventory = computed(() =>
|
||||
(assetsSummary.value?.count_products ?? []).reduce(
|
||||
(sum, item) => sum + Number(item.quantity ?? 0),
|
||||
0
|
||||
)
|
||||
)
|
||||
|
||||
function formatMetalTotal(metal: WalletMetalTotal) {
|
||||
return `${resolveSummaryMetalWeight(metal, inventoryCards.value)}${metal.unit}`
|
||||
}
|
||||
|
||||
function openFundInfo(productId: number) {
|
||||
router.push({ name: 'fund_info', params: { id: productId } })
|
||||
}
|
||||
|
||||
function goBack() {
|
||||
router.back()
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
loading.value = true
|
||||
const tasks = [loadWalletAssets(true), getLastPrices()]
|
||||
if (isBazretalaProject()) {
|
||||
tasks.push(walletStore.getMyWallet())
|
||||
}
|
||||
await Promise.all(tasks)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
})
|
||||
|
||||
const context: FundPageContext = {
|
||||
isDesktop,
|
||||
nameProject,
|
||||
meta,
|
||||
inventoryCards,
|
||||
metalTotals,
|
||||
primaryMetalTotal,
|
||||
cashWallet,
|
||||
totalRialValue,
|
||||
countBasedInventory,
|
||||
fundHeaderBackground,
|
||||
fundEmptyImage,
|
||||
fundEmptyText,
|
||||
isBazretalaProject,
|
||||
formatMetalTotal,
|
||||
openFundInfo,
|
||||
goBack,
|
||||
}
|
||||
|
||||
provide(FUND_PAGE_KEY, context)
|
||||
return context
|
||||
}
|
||||
|
||||
export function useFundPageContext() {
|
||||
const context = inject(FUND_PAGE_KEY)
|
||||
if (!context) {
|
||||
throw new Error('useFundPageContext must be used within useFundPage')
|
||||
}
|
||||
return context
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
<template>
|
||||
<div class="dfund">
|
||||
<div class="dfund__container">
|
||||
<header class="dfund-topbar">
|
||||
<button type="button" class="dfund-topbar__back" @click="goBack()">
|
||||
<BasicIcon icon="vuesax-linear:arrow-right-1" size="18" />
|
||||
بازگشت
|
||||
</button>
|
||||
<div class="dfund-topbar__meta">
|
||||
<p class="dfund-topbar__eyebrow">دارایی</p>
|
||||
<h1 class="dfund-topbar__title">داراییها</h1>
|
||||
<p class="dfund-topbar__subtitle">نمای کلی موجودی محصولات و کیف پول</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section
|
||||
class="dfund-summary"
|
||||
:class="{ 'dfund-summary--bazretala': isBazretalaProject() }"
|
||||
>
|
||||
<img
|
||||
:src="fundHeaderBackground"
|
||||
alt=""
|
||||
class="dfund-summary__bg"
|
||||
:class="{ 'dfund-summary__bg--cover': isBazretalaProject() }"
|
||||
/>
|
||||
<div class="dfund-summary__content">
|
||||
<h2 class="dfund-summary__title">موجودی داراییها</h2>
|
||||
|
||||
<div v-if="meta?.has_count_based_products" class="dfund-summary__row">
|
||||
<span>محصولات</span>
|
||||
<strong>{{ countBasedInventory }} عدد</strong>
|
||||
</div>
|
||||
|
||||
<template v-if="isBazretalaProject()">
|
||||
<div class="dfund-summary__row">
|
||||
<span>دارایی نقره</span>
|
||||
<strong>{{ walletStore.walletInfo?.count_silver ?? 0 }} گرم</strong>
|
||||
</div>
|
||||
<div class="dfund-summary__row">
|
||||
<span>دارایی طلایی</span>
|
||||
<strong>{{ walletStore.walletInfo?.count_gold_wallet ?? 0 }} گرم</strong>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="meta?.single_metal && primaryMetalTotal">
|
||||
<div class="dfund-summary__row">
|
||||
<span>{{ primaryMetalTotal.label }}</span>
|
||||
<strong>{{ formatMetalTotal(primaryMetalTotal) }}</strong>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div
|
||||
v-for="metal in metalTotals"
|
||||
:key="`metal-${metal.metal_id}`"
|
||||
class="dfund-summary__row"
|
||||
>
|
||||
<span>{{ metal.label }}</span>
|
||||
<strong>{{ formatMetalTotal(metal) }}</strong>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div
|
||||
v-if="meta?.has_count_based_products && !isBazretalaProject()"
|
||||
class="dfund-summary__row"
|
||||
>
|
||||
<span>مجموع موجودی</span>
|
||||
<strong>{{ countBasedInventory }} عدد</strong>
|
||||
</div>
|
||||
<div class="dfund-summary__row">
|
||||
<span>دارایی ریالی</span>
|
||||
<strong class="number-ltr">{{ usePriceWithoutType(cashWallet) }} ریال</strong>
|
||||
</div>
|
||||
<div class="dfund-summary__row dfund-summary__row--highlight">
|
||||
<span>معادل ریالی مجموع</span>
|
||||
<strong class="number-ltr">{{ usePriceWithoutType(totalRialValue) }} ریال</strong>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="dfund-inventory">
|
||||
<div class="dfund-inventory__header">
|
||||
<h3 class="dfund-inventory__title">لیست داراییها</h3>
|
||||
<span class="dfund-inventory__count">{{ inventoryCards.length }} مورد</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="inventoryCards.length === 0 && !loading"
|
||||
class="dfund-inventory__empty"
|
||||
>
|
||||
<img :src="fundEmptyImage" alt="" class="dfund-inventory__empty-img" />
|
||||
<p v-if="nameProject !== 'abaeigold'">{{ fundEmptyText }}</p>
|
||||
</div>
|
||||
|
||||
<a-spin :spinning="loading">
|
||||
<div v-if="inventoryCards.length" class="dfund-inventory__grid">
|
||||
<button
|
||||
v-for="item in inventoryCards"
|
||||
:key="item.product_id"
|
||||
type="button"
|
||||
class="dfund-inventory__card"
|
||||
@click="openFundInfo(item.product_id)"
|
||||
>
|
||||
<Item :item="item" variant="desktop" />
|
||||
</button>
|
||||
</div>
|
||||
</a-spin>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import { loading } from '@/utils'
|
||||
import { usePriceWithoutType } from '@/utils/usePrice'
|
||||
import { useWalletStore } from '@/store/walletStore'
|
||||
import Item from '../components/Item.vue'
|
||||
import { useFundPageContext } from '../composables/useFundPage'
|
||||
|
||||
const walletStore = useWalletStore()
|
||||
|
||||
const {
|
||||
nameProject,
|
||||
meta,
|
||||
inventoryCards,
|
||||
metalTotals,
|
||||
primaryMetalTotal,
|
||||
cashWallet,
|
||||
totalRialValue,
|
||||
countBasedInventory,
|
||||
fundHeaderBackground,
|
||||
fundEmptyImage,
|
||||
fundEmptyText,
|
||||
isBazretalaProject,
|
||||
formatMetalTotal,
|
||||
openFundInfo,
|
||||
goBack,
|
||||
} = useFundPageContext()
|
||||
</script>
|
||||
@@ -0,0 +1,495 @@
|
||||
/* Premium desktop fund page */
|
||||
|
||||
.dfund {
|
||||
min-height: 100%;
|
||||
background: #f6f7f9;
|
||||
color: #111827;
|
||||
}
|
||||
|
||||
.dfund__container {
|
||||
max-width: 1180px;
|
||||
margin: 0 auto;
|
||||
padding: 28px 36px 40px;
|
||||
}
|
||||
|
||||
.dfund-topbar {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 16px;
|
||||
margin-bottom: 24px;
|
||||
padding-bottom: 24px;
|
||||
border-bottom: 1px solid rgba(15, 23, 42, 0.06);
|
||||
|
||||
&__back {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: #6b7280;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
font-family: inherit;
|
||||
cursor: pointer;
|
||||
padding: 8px 0;
|
||||
flex-shrink: 0;
|
||||
|
||||
&:hover {
|
||||
color: #111827;
|
||||
}
|
||||
}
|
||||
|
||||
&__meta {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
&__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;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
&__subtitle {
|
||||
font-size: 14px;
|
||||
color: #6b7280;
|
||||
margin: 6px 0 0;
|
||||
line-height: 1.6;
|
||||
}
|
||||
}
|
||||
|
||||
.dfund-summary {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border-radius: 16px;
|
||||
margin-bottom: 24px;
|
||||
background: @App-primary-color;
|
||||
color: #fff;
|
||||
|
||||
&--bazretala {
|
||||
background: #000;
|
||||
}
|
||||
|
||||
&__bg {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
opacity: 0.08;
|
||||
pointer-events: none;
|
||||
|
||||
&--cover {
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
opacity: 0.35;
|
||||
}
|
||||
}
|
||||
|
||||
&__content {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
padding: 24px 28px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 16px 24px;
|
||||
}
|
||||
|
||||
&__title {
|
||||
grid-column: 1 / -1;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
margin: 0 0 4px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&__row {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
font-size: 13px;
|
||||
|
||||
span {
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
strong {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
&--highlight {
|
||||
grid-column: 1 / -1;
|
||||
padding-top: 8px;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dfund-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);
|
||||
}
|
||||
|
||||
.dfund-inventory {
|
||||
background: #fff;
|
||||
border: 1px solid rgba(15, 23, 42, 0.06);
|
||||
border-radius: 16px;
|
||||
padding: 24px;
|
||||
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
|
||||
|
||||
&__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
margin: 0;
|
||||
color: #111827;
|
||||
}
|
||||
|
||||
&__count {
|
||||
font-size: 13px;
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
&__grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
&__card {
|
||||
border: none;
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
text-align: inherit;
|
||||
width: 100%;
|
||||
|
||||
&:hover .dfund-card {
|
||||
border-color: rgba(15, 23, 42, 0.12);
|
||||
box-shadow: 0 4px 12px rgba(15, 23, 42, 0.08);
|
||||
}
|
||||
}
|
||||
|
||||
&__empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 48px 24px;
|
||||
text-align: center;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
&__empty-img {
|
||||
width: 160px;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.dfund-card {
|
||||
width: 100%;
|
||||
border: 1px solid rgba(15, 23, 42, 0.08) !important;
|
||||
border-radius: 14px !important;
|
||||
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
.dfund-summary__content {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.dfund-inventory__grid {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.dfund-inventory__grid {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
/* Fund info desktop */
|
||||
|
||||
.dfund-info {
|
||||
min-height: 100%;
|
||||
background: #f6f7f9;
|
||||
color: #111827;
|
||||
}
|
||||
|
||||
.dfund-info__container {
|
||||
max-width: 1180px;
|
||||
margin: 0 auto;
|
||||
padding: 28px 36px 40px;
|
||||
}
|
||||
|
||||
.dfund-info-topbar {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 16px;
|
||||
margin-bottom: 24px;
|
||||
padding-bottom: 24px;
|
||||
border-bottom: 1px solid rgba(15, 23, 42, 0.06);
|
||||
|
||||
&__back {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: #6b7280;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
font-family: inherit;
|
||||
cursor: pointer;
|
||||
padding: 8px 0;
|
||||
flex-shrink: 0;
|
||||
|
||||
&:hover {
|
||||
color: #111827;
|
||||
}
|
||||
}
|
||||
|
||||
&__meta {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
&__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;
|
||||
line-height: 1.2;
|
||||
}
|
||||
}
|
||||
|
||||
.dfund-info__layout {
|
||||
display: grid;
|
||||
grid-template-columns: 280px minmax(0, 1fr);
|
||||
gap: 20px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.dfund-info__hero {
|
||||
padding: 28px 24px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.dfund-info__image {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
margin: 0 auto 16px;
|
||||
border-radius: 16px;
|
||||
background: #e0f2fe;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
|
||||
img {
|
||||
max-width: 80%;
|
||||
max-height: 80%;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
|
||||
.dfund-info__balance {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.dfund-info__balance-value {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
color: @App-primary-color;
|
||||
}
|
||||
|
||||
.dfund-info__balance-unit {
|
||||
font-size: 14px;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.dfund-info__balance-label {
|
||||
margin: 8px 0 0;
|
||||
font-size: 13px;
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
.dfund-info__transactions {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.dfund-info__transactions-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.dfund-info__transactions-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.dfund-info__transactions-count {
|
||||
font-size: 13px;
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
.dfund-info__transactions-list {
|
||||
max-height: 520px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* Fund new desktop */
|
||||
|
||||
.dfund-new {
|
||||
min-height: 100%;
|
||||
background: #f6f7f9;
|
||||
color: #111827;
|
||||
}
|
||||
|
||||
.dfund-new__container {
|
||||
max-width: 640px;
|
||||
margin: 0 auto;
|
||||
padding: 28px 36px 40px;
|
||||
}
|
||||
|
||||
.dfund-new-topbar {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 16px;
|
||||
margin-bottom: 24px;
|
||||
padding-bottom: 24px;
|
||||
border-bottom: 1px solid rgba(15, 23, 42, 0.06);
|
||||
|
||||
&__back {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: #6b7280;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
font-family: inherit;
|
||||
cursor: pointer;
|
||||
padding: 8px 0;
|
||||
flex-shrink: 0;
|
||||
|
||||
&:hover {
|
||||
color: #111827;
|
||||
}
|
||||
}
|
||||
|
||||
&__meta {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
&__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;
|
||||
line-height: 1.2;
|
||||
}
|
||||
}
|
||||
|
||||
.dfund-new__card {
|
||||
padding: 32px 28px;
|
||||
}
|
||||
|
||||
.dfund-new__preview {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.dfund-new__preview-img {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
object-fit: contain;
|
||||
border-radius: 16px;
|
||||
background: #e0f2fe;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.dfund-new__label {
|
||||
display: block;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #374151;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.dfund-new__tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin: 20px 0 28px;
|
||||
}
|
||||
|
||||
.dfund-new__tag {
|
||||
padding: 8px 14px;
|
||||
border-radius: 999px;
|
||||
border: 1px solid rgba(15, 23, 42, 0.1);
|
||||
background: #f3f4f6;
|
||||
color: #4b5563;
|
||||
font-size: 12px;
|
||||
font-family: inherit;
|
||||
cursor: pointer;
|
||||
|
||||
&--active {
|
||||
background: @App-primary-color;
|
||||
border-color: @App-primary-color;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.dfund-new__submit {
|
||||
width: 100%;
|
||||
}
|
||||
+12
-162
@@ -1,173 +1,23 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="bg-white w-full py-3 px-3 text-primary font-bold drop-shadow fixed md:absolute top-0 flex h-12 z-20">
|
||||
<div @click="router.back()">
|
||||
<BasicIcon icon="vuesax-linear:arrow-right-1"/>
|
||||
</div>
|
||||
<div class="mr-2">دارایی ها</div>
|
||||
</div>
|
||||
<div
|
||||
class="w-screen md:w-full h-[70vh] fixed md:absolute overflow-hidden"
|
||||
:class="isBazretalaProject() ? 'bazretala-fund-header' : 'text-tertiary bg-primary'"
|
||||
>
|
||||
<img
|
||||
:src="fundHeaderBackground"
|
||||
alt=""
|
||||
:class="isBazretalaProject()
|
||||
? 'pointer-events-none z-0 absolute inset-0 w-full object-cover object-center'
|
||||
: 'pointer-events-none z-0 w-full absolute bottom-0 left-0 opacity-5'"
|
||||
/>
|
||||
<div
|
||||
class="pt-15 flex flex-col relative z-10"
|
||||
:class="isBazretalaProject() ? 'text-white' : 'text-tertiary'"
|
||||
>
|
||||
<div class="font-bold mr-5 z-20">موجودی دارایی ها</div>
|
||||
<div v-if="meta?.has_count_based_products" class="flex mt-4 justify-center mt-2 w-full z-20">
|
||||
محصولات:
|
||||
<div class="text-l mr-4 font-bold">{{ countBasedInventory }} عدد</div>
|
||||
</div>
|
||||
<template v-if="isBazretalaProject()">
|
||||
<div class="flex justify-center mt-2 w-full z-20">
|
||||
دارایی نقره:
|
||||
<div class="text-l mr-4 font-bold">{{ walletStore.walletInfo?.count_silver ?? 0 }}گرم</div>
|
||||
</div>
|
||||
<div class="flex justify-center mt-2 w-full z-20">
|
||||
دارایی طلایی:
|
||||
<div class="text-l mr-4 font-bold">{{ walletStore.walletInfo?.count_gold_wallet ?? 0 }}گرم</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="meta?.single_metal && primaryMetalTotal">
|
||||
<div class="flex justify-center mt-2 w-full z-20">
|
||||
{{ primaryMetalTotal.label }}:
|
||||
<div class="text-l mr-4 font-bold">{{ formatMetalTotal(primaryMetalTotal) }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div
|
||||
v-for="metal in metalTotals"
|
||||
:key="`metal-${metal.metal_id}`"
|
||||
class="flex justify-center mt-2 w-full z-20"
|
||||
>
|
||||
{{ metal.label }}:
|
||||
<div class="text-l mr-4 font-bold">{{ formatMetalTotal(metal) }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<div v-if="meta?.has_count_based_products && !isBazretalaProject()" class="flex justify-center mt-2 w-full z-20">
|
||||
مجموع موجودی:
|
||||
<div class="text-l mr-4 font-bold">{{ countBasedInventory }} عدد</div>
|
||||
</div>
|
||||
<div class="flex justify-center mt-2 w-full z-20">
|
||||
دارایی ریالی:
|
||||
<div class="text-l mr-4 font-bold">{{ usePriceWithoutType(cashWallet) }}ریال</div>
|
||||
</div>
|
||||
<div class="flex justify-center mt-2 w-full z-20">
|
||||
مجموع دارایی ریالی:
|
||||
<div class="text-l mr-4 font-bold">{{ usePriceWithoutType(cashWallet + metalRialValue) }}ریال</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-[20rem] ">
|
||||
<div class="bg-gray-100 w-screen md:w-full z-20 relative rounded-t-3xl h-[calc(100vh-20rem-70px)] overflow-y-auto pb-15"
|
||||
style="box-shadow: 0px -2px 4px -2px #0000001A;">
|
||||
|
||||
<div v-if="inventoryCards.length === 0 && !loading" class="w-full h-full flex justify-center items-center">
|
||||
<div>
|
||||
<img
|
||||
:src="fundEmptyImage"
|
||||
alt=""
|
||||
:class="isBazretalaProject() ? 'w-48 max-w-[11rem]' : 'w-70'"
|
||||
>
|
||||
<div v-if="nameProject !== 'abaeigold'" class="text-center text-lg">{{ fundEmptyText }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a-spin :spinning="loading">
|
||||
<div :class="loading ? 'h-[40vh]' : ''" class="grid grid-cols-2 gap-3 p-5">
|
||||
<Item
|
||||
v-for="item in inventoryCards"
|
||||
:key="item.product_id"
|
||||
:item="item"
|
||||
@click="router.push({ name: 'fund_info', params: { id: item.product_id } })"
|
||||
/>
|
||||
</div>
|
||||
</a-spin>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fund-page-root">
|
||||
<DesktopFundView v-show="isDesktop" />
|
||||
<MobileFundView v-show="!isDesktop" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import router from '@/router'
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import img from '@/assets/img/user_ly1.svg'
|
||||
import empty from '@/assets/img/cash_empty.svg'
|
||||
import Item from './components/Item.vue'
|
||||
import { onMounted, computed } from 'vue'
|
||||
import { loading } from '@/utils'
|
||||
import { usePriceWithoutType } from '@/utils/usePrice'
|
||||
import { useConfigStore } from '@/store/configStore'
|
||||
import { useWalletAssets } from '@/composables/useWalletAssets'
|
||||
import type { WalletMetalTotal } from '@/models/walletAssets'
|
||||
import { resolveSummaryMetalWeight, fundPageInventoryCards, resolveAssetsRialValue } from '@/utils/productAssets'
|
||||
import { useWalletStore } from '@/store/walletStore'
|
||||
import { getTradeBuyPrice, lastPrice } from '@/utils/price'
|
||||
import {
|
||||
getProjectFundEmptyImage,
|
||||
getProjectFundEmptyText,
|
||||
getProjectFundHeaderBackground,
|
||||
isBazretalaProject,
|
||||
} from '@/utils/config'
|
||||
import { useDesktopBreakpoint } from '@/layouts/composables/useAppLayout'
|
||||
import { useFundPage } from './composables/useFundPage'
|
||||
import DesktopFundView from './desktop/DesktopFundView.vue'
|
||||
import MobileFundView from './mobile/MobileFundView.vue'
|
||||
|
||||
const nameProject = useConfigStore().config.name
|
||||
const { assetsSummary, loadWalletAssets } = useWalletAssets()
|
||||
const walletStore = useWalletStore()
|
||||
const fundHeaderBackground = getProjectFundHeaderBackground(img)
|
||||
const fundEmptyImage = getProjectFundEmptyImage(empty)
|
||||
const fundEmptyText = getProjectFundEmptyText()
|
||||
|
||||
const meta = computed(() => assetsSummary.value?.meta)
|
||||
const inventoryCards = computed(() => fundPageInventoryCards(assetsSummary.value?.inventory_cards ?? []))
|
||||
const metalTotals = computed(() => assetsSummary.value?.metal_totals ?? [])
|
||||
const primaryMetalTotal = computed(() => metalTotals.value[0])
|
||||
const cashWallet = computed(() => assetsSummary.value?.cash_wallet ?? 0)
|
||||
const metalRialValue = computed(() =>
|
||||
resolveAssetsRialValue(assetsSummary.value, getTradeBuyPrice(lastPrice.value))
|
||||
)
|
||||
const countBasedInventory = computed(() =>
|
||||
(assetsSummary.value?.count_products ?? []).reduce((sum, item) => sum + Number(item.quantity ?? 0), 0)
|
||||
)
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
loading.value = true
|
||||
const tasks = [loadWalletAssets(true), getLastPrices()]
|
||||
if (isBazretalaProject()) {
|
||||
tasks.push(walletStore.getMyWallet())
|
||||
}
|
||||
await Promise.all(tasks)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
})
|
||||
|
||||
function formatMetalTotal(metal: WalletMetalTotal) {
|
||||
return `${resolveSummaryMetalWeight(metal, inventoryCards.value)}${metal.unit}`
|
||||
}
|
||||
const isDesktop = useDesktopBreakpoint()
|
||||
useFundPage(isDesktop)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.bazretala-fund-header {
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.bazretala-fund-header::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 1;
|
||||
background: rgba(0, 0, 0, 0.45);
|
||||
pointer-events: none;
|
||||
.fund-page-root {
|
||||
min-height: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<div :class="variant === 'desktop' ? 'dfund-info-edit' : ''">
|
||||
<div v-if="variant !== 'desktop'" class="font-bold text-lg">گنج {{ info?.title }}</div>
|
||||
|
||||
<BasicButton
|
||||
:class="variant === 'desktop' ? 'mt-4 w-full' : 'mt-12 w-full'"
|
||||
icon="vuesax-linear:edit"
|
||||
icon-size="16"
|
||||
@click="$router.push({ name: 'fund_add', query: { id: infoId } })"
|
||||
>
|
||||
<div class="flex w-full justify-right">ویرایش</div>
|
||||
</BasicButton>
|
||||
<BasicButton
|
||||
:loading="loading"
|
||||
:class="variant === 'desktop' ? 'mt-2 w-full !text-red-600' : 'mb-10 mt-2 w-full !text-red-600'"
|
||||
icon="vuesax-linear:trash"
|
||||
icon-size="16"
|
||||
@click="deleteFundConfirm"
|
||||
>
|
||||
<div class="flex w-full justify-right">حذف</div>
|
||||
</BasicButton>
|
||||
|
||||
<BasicButton
|
||||
v-if="variant !== 'desktop'"
|
||||
class="mb-20 mt-2 w-full"
|
||||
type="primary"
|
||||
@click="transactionShow = false"
|
||||
>
|
||||
بازگشت
|
||||
</BasicButton>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
|
||||
import { loading } from '@/utils'
|
||||
import { useFundInfoPageContext } from '../composables/useFundInfoPage'
|
||||
|
||||
interface Props {
|
||||
variant?: 'mobile' | 'desktop'
|
||||
}
|
||||
|
||||
withDefaults(defineProps<Props>(), {
|
||||
variant: 'mobile',
|
||||
})
|
||||
|
||||
const { info, infoId, transactionShow, deleteFundConfirm } = useFundInfoPageContext()
|
||||
</script>
|
||||
@@ -0,0 +1,82 @@
|
||||
<template>
|
||||
<div :class="variant === 'desktop' ? 'dfund-info-form' : ''">
|
||||
<div v-if="variant !== 'desktop'" class="font-bold text-lg">
|
||||
{{ isDeposit ? 'واریز' : 'برداشت' }}
|
||||
</div>
|
||||
<a-form
|
||||
ref="formRef"
|
||||
:model="userFormState"
|
||||
:class="variant === 'desktop' ? '!mt-0' : '!mt-5'"
|
||||
name="basic"
|
||||
@finish="transaction()"
|
||||
>
|
||||
<a-form-item :rules="[required()]" label="مقدار گرم طلا" name="value" class="!block">
|
||||
<BasicInput
|
||||
v-model:value="userFormState.value"
|
||||
addon-before="گرم"
|
||||
place-holder="گرم"
|
||||
type="text"
|
||||
inputmode="decimal"
|
||||
size="large"
|
||||
/>
|
||||
<div v-if="isDeposit" class="mt-2 text-xs font-bold leading-5">
|
||||
<div>{{ formatGoldWalletBalanceText(walletStore?.walletInfo?.gold ?? 0) }}</div>
|
||||
<div v-if="info?.wallet?.gold !== 0">
|
||||
{{ `موجودی قابل برداشت گنج: ${info?.wallet?.gold ?? 0} گرم` }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="mt-2 text-xs font-bold">
|
||||
موجودی گنج {{ info?.title }}: {{ info?.wallet?.gold }} گرم
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<BasicButton
|
||||
:disabled="transButtonDisable"
|
||||
class="w-full py-2 mt-2"
|
||||
html-type="submit"
|
||||
type="primary"
|
||||
>
|
||||
<div>
|
||||
<a-spin v-if="loading" size="small" />
|
||||
<div v-else>{{ isDeposit ? 'واریز' : 'برداشت' }}</div>
|
||||
</div>
|
||||
</BasicButton>
|
||||
<BasicButton
|
||||
v-if="variant !== 'desktop'"
|
||||
class="mb-20 mt-2 w-full"
|
||||
@click="transactionShow = false"
|
||||
>
|
||||
بازگشت
|
||||
</BasicButton>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
|
||||
import BasicInput from '@/components/BasicPacks/BasicInput.vue'
|
||||
import { loading } from '@/utils'
|
||||
import { required } from '@/utils/inputRules'
|
||||
import { formatGoldWalletBalanceText } from '@/utils/productDealMethod'
|
||||
import { useFundInfoPageContext } from '../composables/useFundInfoPage'
|
||||
|
||||
interface Props {
|
||||
variant?: 'mobile' | 'desktop'
|
||||
}
|
||||
|
||||
withDefaults(defineProps<Props>(), {
|
||||
variant: 'mobile',
|
||||
})
|
||||
|
||||
const {
|
||||
info,
|
||||
isDeposit,
|
||||
formRef,
|
||||
userFormState,
|
||||
transButtonDisable,
|
||||
walletStore,
|
||||
transactionShow,
|
||||
transaction,
|
||||
} = useFundInfoPageContext()
|
||||
</script>
|
||||
@@ -0,0 +1,185 @@
|
||||
import { computed, inject, onMounted, provide, reactive, ref, watch, type InjectionKey } from 'vue'
|
||||
import router from '@/router'
|
||||
import { loading } from '@/utils'
|
||||
import { deleteFund, fundDeposit, fundWithdraw, getFundById, getFundTransactionTable } from '@/api/fund'
|
||||
import type { FundTransaction } from '@/models/fund'
|
||||
import type { TableInput, TableOutput } from '@/models/table'
|
||||
import type { Transaction } from '@/models/transaction'
|
||||
import type { FormInstance } from 'ant-design-vue'
|
||||
import { message } from 'ant-design-vue'
|
||||
import { useWalletStore } from '@/store/walletStore'
|
||||
import { useFundUserStore } from '@/store/fundStore'
|
||||
import { getOneProductWallet } from '@/api/products'
|
||||
import type { Product } from '@/models/products'
|
||||
import homeImg from '@/assets/img/cash_home.svg'
|
||||
import giftImg from '@/assets/img/cash_gift.svg'
|
||||
import circulationImg from '@/assets/img/cash_circulation.svg'
|
||||
import loveImg from '@/assets/img/cash_love.svg'
|
||||
import repairsImg from '@/assets/img/cash_repairs.svg'
|
||||
import savingImg from '@/assets/img/cash_saving.svg'
|
||||
|
||||
export const FUND_INFO_PAGE_KEY: InjectionKey<ReturnType<typeof useFundInfoPage>> =
|
||||
Symbol('fundInfoPage')
|
||||
|
||||
export function useFundInfoPage() {
|
||||
const info = ref<Product>()
|
||||
const items = ref<Transaction[]>([])
|
||||
const tableOutput = ref<TableOutput<Transaction> | null>(null)
|
||||
const pagination = ref<TableInput>({})
|
||||
const transactionShow = ref<boolean>()
|
||||
const editShow = ref<boolean>()
|
||||
const showDeleteConfirm = ref<boolean>()
|
||||
const isDeposit = ref<boolean>()
|
||||
const formRef = ref<FormInstance>()
|
||||
const fundStore = useFundUserStore()
|
||||
const walletStore = useWalletStore()
|
||||
|
||||
const infoId: number = parseInt(String(router.currentRoute.value.params.id))
|
||||
const userFormState = reactive<FundTransaction>({
|
||||
value: undefined,
|
||||
fund_id: infoId,
|
||||
})
|
||||
|
||||
watch(transactionShow, (n) => (!n ? (userFormState.value = undefined) : ''))
|
||||
|
||||
const transButtonDisable = computed(() => {
|
||||
if (!loading.value) {
|
||||
if (userFormState.value !== undefined) {
|
||||
if (isDeposit.value) {
|
||||
return userFormState.value > walletStore?.walletInfo?.gold
|
||||
}
|
||||
return userFormState.value > (info.value?.wallet?.gold ?? 0)
|
||||
}
|
||||
return true
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
const itemImg = computed(() => {
|
||||
switch (info.value?.title) {
|
||||
case 'خرید لوازم منزل':
|
||||
return homeImg
|
||||
case 'هدیه':
|
||||
return giftImg
|
||||
case 'گردش':
|
||||
return circulationImg
|
||||
case 'ازدواج':
|
||||
return loveImg
|
||||
case 'تعمیرات':
|
||||
return repairsImg
|
||||
case 'پس انداز':
|
||||
return savingImg
|
||||
default:
|
||||
return savingImg
|
||||
}
|
||||
})
|
||||
|
||||
function deleteFundConfirm() {
|
||||
if (info.value?.wallet === undefined || info.value?.wallet?.gold === 0) {
|
||||
showDeleteConfirm.value = true
|
||||
} else {
|
||||
message.error('ابتدا گنج خود را خالی کنید')
|
||||
editShow.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteFundFunction() {
|
||||
try {
|
||||
loading.value = true
|
||||
showDeleteConfirm.value = false
|
||||
await deleteFund(infoId)
|
||||
await fundStore.getMyFund()
|
||||
router.back()
|
||||
message.success('گنج با موفقیت حذف شد')
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function initInfo() {
|
||||
try {
|
||||
loading.value = true
|
||||
info.value = await getOneProductWallet(infoId)
|
||||
await initTable()
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function initTable() {
|
||||
if (info.value?.wallet) {
|
||||
try {
|
||||
loading.value = true
|
||||
items.value = []
|
||||
Object.assign(pagination.value, { wallet_id: info.value?.wallet?.id })
|
||||
tableOutput.value = await getFundTransactionTable(pagination.value)
|
||||
items.value.push(...tableOutput.value.rows)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function transaction() {
|
||||
formRef.value?.validateFields().then(async () => {
|
||||
try {
|
||||
loading.value = true
|
||||
userFormState.fund_id = infoId
|
||||
isDeposit.value ? await fundDeposit(userFormState) : await fundWithdraw(userFormState)
|
||||
await initInfo()
|
||||
await fundStore.getMyFund()
|
||||
await walletStore.getMyWallet()
|
||||
message.success(`با موفقیت${isDeposit.value ? ' واریز' : ' برداشت'} شد`)
|
||||
transactionShow.value = false
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function goBack() {
|
||||
router.back()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initInfo()
|
||||
})
|
||||
|
||||
const context = {
|
||||
info,
|
||||
items,
|
||||
transactionShow,
|
||||
editShow,
|
||||
showDeleteConfirm,
|
||||
isDeposit,
|
||||
formRef,
|
||||
userFormState,
|
||||
transButtonDisable,
|
||||
itemImg,
|
||||
walletStore,
|
||||
deleteFundConfirm,
|
||||
deleteFundFunction,
|
||||
transaction,
|
||||
goBack,
|
||||
infoId,
|
||||
}
|
||||
|
||||
provide(FUND_INFO_PAGE_KEY, context)
|
||||
return context
|
||||
}
|
||||
|
||||
export function useFundInfoPageContext() {
|
||||
const context = inject(FUND_INFO_PAGE_KEY)
|
||||
if (!context) {
|
||||
throw new Error('useFundInfoPageContext must be used within useFundInfoPage')
|
||||
}
|
||||
return context
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<div class="dfund-info">
|
||||
<div class="dfund-info__container">
|
||||
<header class="dfund-info-topbar">
|
||||
<button type="button" class="dfund-info-topbar__back" @click="goBack()">
|
||||
<BasicIcon icon="vuesax-linear:arrow-right-1" size="18" />
|
||||
بازگشت
|
||||
</button>
|
||||
<div class="dfund-info-topbar__meta">
|
||||
<p class="dfund-info-topbar__eyebrow">جزئیات دارایی</p>
|
||||
<h1 class="dfund-info-topbar__title">{{ info?.title ?? '—' }}</h1>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="dfund-info__layout">
|
||||
<section class="dfund-info__hero dfund-surface">
|
||||
<a-spin :spinning="loading">
|
||||
<div class="dfund-info__image">
|
||||
<img v-if="info?.group_type == 'گوی'" :src="goyImg" alt="" />
|
||||
<img v-if="info?.group_type == 'مکعب'" :src="mokaabImg" alt="" />
|
||||
<img v-if="info?.group_type == 'سکه'" :src="sekkeImg" alt="" />
|
||||
<img v-if="info?.group_type == 'مس'" :src="mesImg" alt="" />
|
||||
<img v-if="info?.group_type == 'نقره'" :src="noghrehImg" alt="" />
|
||||
<img
|
||||
v-if="info?.group_type == 'طلا' || info?.group_type == 'آبشده' || info?.group_type == null"
|
||||
:src="defaultImg"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
</a-spin>
|
||||
<div class="dfund-info__balance">
|
||||
<span class="dfund-info__balance-value">{{ info?.wallet?.gold ?? 0 }}</span>
|
||||
<span class="dfund-info__balance-unit">{{ info?.unit }}</span>
|
||||
</div>
|
||||
<p class="dfund-info__balance-label">موجودی گنج {{ info?.title }}</p>
|
||||
</section>
|
||||
|
||||
<section class="dfund-info__transactions dfund-surface">
|
||||
<div class="dfund-info__transactions-header">
|
||||
<h2 class="dfund-info__transactions-title">تراکنشها</h2>
|
||||
<span class="dfund-info__transactions-count">{{ items.length }} مورد</span>
|
||||
</div>
|
||||
|
||||
<div class="dfund-info__transactions-list">
|
||||
<list-anim v-if="!loading">
|
||||
<Item
|
||||
v-for="item in items"
|
||||
:key="item.id"
|
||||
:item="item"
|
||||
:title="info?.title"
|
||||
/>
|
||||
</list-anim>
|
||||
<TransactionSkeleton v-for="i in 6" v-else :key="i" class="mt-1" />
|
||||
<empty v-if="items.length === 0 && !loading" text="هیچ تراکنشی یافت نشد" />
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import { loading } from '@/utils'
|
||||
import ListAnim from '@/components/ListAnim.vue'
|
||||
import TransactionSkeleton from '@/components/TransactionSkeleton.vue'
|
||||
import Empty from '@/components/empty.vue'
|
||||
import Item from '../components/Item.vue'
|
||||
import goyImg from '@/assets/img/goyImg.svg'
|
||||
import mokaabImg from '@/assets/img/mokaabImg.svg'
|
||||
import sekkeImg from '@/assets/img/sekkeImg.svg'
|
||||
import mesImg from '@/assets/img/mesImg.jpg'
|
||||
import noghrehImg from '@/assets/img/noghrehImg.webp'
|
||||
import defaultImg from '@/assets/img/defaultAbshodeh.svg'
|
||||
import { useFundInfoPageContext } from '../composables/useFundInfoPage'
|
||||
|
||||
const { info, items, goBack } = useFundInfoPageContext()
|
||||
</script>
|
||||
@@ -1,305 +1,79 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="bg-white wrap-fix py-3 px-3 text-primary font-bold drop-shadow flex h-12 z-20 justify-between">
|
||||
<div class="flex ">
|
||||
<div @click="router.back()" class="cursor-pointer">
|
||||
<BasicIcon icon="vuesax-linear:arrow-right-1" />
|
||||
</div>
|
||||
<div class="mr-2">{{ info?.title }}</div>
|
||||
</div>
|
||||
<!-- <div @click="editShow = true">
|
||||
<BasicIcon icon="vuesax-linear:setting-4" />
|
||||
</div>-->
|
||||
</div>
|
||||
<div class="pt-20 flex flex-col justify-center items-center">
|
||||
<a-spin :spinning="loading">
|
||||
<div class="bg-sky-100 w-[120px] aspect-square flex justify-center rounded-xl">
|
||||
<!-- <img v-if="!loading" :src="itemImg" alt="">-->
|
||||
<img v-if="info?.group_type=='گوی'" :src="goyImg">
|
||||
<img v-if="info?.group_type=='مکعب'" :src="mokaabImg">
|
||||
<img v-if="info?.group_type=='سکه'" :src="sekkeImg">
|
||||
<img v-if="info?.group_type=='مس'" :src="mesImg">
|
||||
<img v-if="info?.group_type=='نقره'" :src="noghrehImg">
|
||||
<img v-if="info?.group_type=='طلا' || info?.group_type=='آبشده' || info?.group_type== null" :src="defaultImg">
|
||||
</div>
|
||||
</a-spin>
|
||||
<div class="mt-2 font-bold flex text-xs items-center text-gray-500">
|
||||
<div class="ml-1 text-base text-primary">{{ info?.wallet?.gold?? 0 }}</div>
|
||||
{{info?.unit}}
|
||||
</div>
|
||||
<div class="text-gray-400">موجودی گنج {{ info?.title }}</div>
|
||||
<div class="w-full p-5">
|
||||
<!-- <div class="w-full flex gap-3">
|
||||
<BasicButton class="w-full !bg-[#F3F0E9] !border-0 !rounded" icon="vuesax-linear:add-square" icon-size="18"
|
||||
@click="()=> {transactionShow = true; isDeposit= false}">برداشت
|
||||
</BasicButton>
|
||||
<BasicButton class="w-full !bg-[#F3F0E9] !border-0 !rounded" icon="vuesax-linear:arrow-up" icon-size="18"
|
||||
@click="()=> {transactionShow = true; isDeposit= true}">واریز
|
||||
</BasicButton>
|
||||
</div>-->
|
||||
<div class=" font-bold mt-5">تراکنش ها</div>
|
||||
<!-- <a-spin :spinning="loading">-->
|
||||
<div class="mt-5 pb-17 overflow-y-scroll h-[54vh]">
|
||||
<list-anim v-if="!loading">
|
||||
<Item v-for="item in items" :key="item.id" :item="item" :title="info?.title"/>
|
||||
</list-anim>
|
||||
<TransactionSkeleton v-for="i in 8" v-else :key="i" class="mt-1" />
|
||||
<empty v-if="items.length === 0 && !loading" text="هیچ تراکنشی یافت نشد" />
|
||||
</div>
|
||||
<!-- </a-spin>-->
|
||||
</div>
|
||||
</div>
|
||||
<BasicActionSheet v-model:show="transactionShow">
|
||||
<div class="font-bold text-lg">{{ isDeposit ? 'واریز' : 'برداشت' }}</div>
|
||||
<a-form ref="formRef" :model="userFormState" class="!mt-5" name="basic" @finish="transaction()">
|
||||
<a-form-item :rules="[required()]" label="مقدار گرم طلا" name="value" class="!block">
|
||||
<BasicInput v-model:value="userFormState.value"
|
||||
addon-before="گرم" place-holder="گرم"
|
||||
type="text" inputmode="decimal"
|
||||
size="large" />
|
||||
<div v-if="isDeposit" class="mt-2 text-xs font-bold leading-5">
|
||||
<div>{{ formatGoldWalletBalanceText(walletStore?.walletInfo?.gold ?? 0) }}</div>
|
||||
<div v-if="info?.wallet?.gold !== 0">
|
||||
{{ `موجودی قابل برداشت گنج: ${info?.wallet?.gold ?? 0} گرم` }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="mt-2 text-xs font-bold">موجودی گنج {{ info.title }}: {{ info?.wallet?.gold }} گرم
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<BasicButton
|
||||
:disabled="transButtonDisable"
|
||||
class=" w-full py-2 mt-2"
|
||||
html-type="submit"
|
||||
type="primary"
|
||||
>
|
||||
<div>
|
||||
<a-spin v-if="loading" size="small" />
|
||||
<div v-else>{{ isDeposit ? 'واریز' : 'برداشت' }}</div>
|
||||
</div>
|
||||
</BasicButton>
|
||||
<BasicButton class="mb-20 mt-2 w-full" @click="transactionShow = false">بازگشت</BasicButton>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<div class="fund-info-page-root">
|
||||
<DesktopFundInfoView v-show="isDesktop" />
|
||||
<MobileFundInfoView v-show="!isDesktop" />
|
||||
|
||||
<BasicActionSheet v-if="!isDesktop" v-model:show="transactionShow">
|
||||
<FundTransactionForm />
|
||||
</BasicActionSheet>
|
||||
<BasicActionSheet v-model:show="editShow">
|
||||
<div class="font-bold text-lg">گنج {{ info?.title }}</div>
|
||||
<BasicModal
|
||||
v-else
|
||||
v-model:visible="transactionShow"
|
||||
:title="isDeposit ? 'واریز' : 'برداشت'"
|
||||
width="480px"
|
||||
destroy-on-close
|
||||
custom-footer
|
||||
>
|
||||
<FundTransactionForm variant="desktop" />
|
||||
<template #footer>
|
||||
<div></div>
|
||||
</template>
|
||||
</BasicModal>
|
||||
|
||||
<BasicButton class="mt-12 w-full" icon="vuesax-linear:edit"
|
||||
icon-size="16" @click="$router.push({name: 'fund_add', query:{id:infoId}})">
|
||||
<div class="flex w-full justify-right">ویرایش</div>
|
||||
</BasicButton>
|
||||
<BasicButton :loading="loading" class="mb-10 mt-2 w-full !text-red-600"
|
||||
icon="vuesax-linear:trash"
|
||||
icon-size="16"
|
||||
@click="deleteFundConfirm">
|
||||
<div class="flex w-full justify-right">حذف</div>
|
||||
</BasicButton>
|
||||
|
||||
<BasicButton class="mb-20 mt-2 w-full" type="primary" @click="transactionShow = false">بازگشت</BasicButton>
|
||||
<BasicActionSheet v-if="!isDesktop" v-model:show="editShow">
|
||||
<FundEditActions />
|
||||
</BasicActionSheet>
|
||||
<DialogVant v-model:show="showDeleteConfirm" :closeOnClickOverlay="true" :timeOut="-1">
|
||||
<!-- <template v-slot:img>
|
||||
<img :src="registerDelayImage" alt="" class="opacity-80">
|
||||
</template>-->
|
||||
|
||||
<template v-slot:title>
|
||||
<div class="p-5 text-sm">
|
||||
آیا از حذف گنج خود اطمینان دارید؟
|
||||
</div>
|
||||
<BasicModal
|
||||
v-else
|
||||
v-model:visible="editShow"
|
||||
:title="`گنج ${info?.title ?? ''}`"
|
||||
width="420px"
|
||||
destroy-on-close
|
||||
custom-footer
|
||||
>
|
||||
<FundEditActions variant="desktop" />
|
||||
<template #footer>
|
||||
<div></div>
|
||||
</template>
|
||||
</BasicModal>
|
||||
|
||||
<template v-slot:button>
|
||||
<div class="text-center text-red" @click="deleteFundFunction">
|
||||
حذف
|
||||
</div>
|
||||
<div class="text-center" @click="showDeleteConfirm = false">
|
||||
انصراف
|
||||
</div>
|
||||
<DialogVant v-model:show="showDeleteConfirm" :close-on-click-overlay="true" :time-out="-1">
|
||||
<template #title>
|
||||
<div class="p-5 text-sm">آیا از حذف گنج خود اطمینان دارید؟</div>
|
||||
</template>
|
||||
<template #button>
|
||||
<div class="text-center text-red" @click="deleteFundFunction">حذف</div>
|
||||
<div class="text-center" @click="showDeleteConfirm = false">انصراف</div>
|
||||
</template>
|
||||
|
||||
</DialogVant>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
import router from '@/router'
|
||||
import { computed, onMounted, reactive, ref, watch } from 'vue'
|
||||
import Item from './components/Item.vue'
|
||||
import homeImg from '@/assets/img/cash_home.svg'
|
||||
import giftImg from '@/assets/img/cash_gift.svg'
|
||||
import circulationImg from '@/assets/img/cash_circulation.svg'
|
||||
import loveImg from '@/assets/img/cash_love.svg'
|
||||
import repairsImg from '@/assets/img/cash_repairs.svg'
|
||||
import savingImg from '@/assets/img/cash_saving.svg'
|
||||
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
|
||||
import { loading } from '@/utils'
|
||||
import { deleteFund, fundDeposit, fundWithdraw, getFundById, getFundTransactionTable } from '@/api/fund'
|
||||
import type { Fund, FundTransaction } from '@/models/fund'
|
||||
import type { TableInput, TableOutput } from '@/models/table'
|
||||
import type { Transaction } from '@/models/transaction'
|
||||
import Empty from '@/components/empty.vue'
|
||||
import { required } from '@/utils/inputRules'
|
||||
import type { FormInstance } from 'ant-design-vue'
|
||||
import { message } from 'ant-design-vue'
|
||||
import BasicActionSheet from '@/components/BasicPacks/BasicActionSheet.vue'
|
||||
import { formatGoldWalletBalanceText } from '@/utils/productDealMethod'
|
||||
import BasicInput from '@/components/BasicPacks/BasicInput.vue'
|
||||
import { useWalletStore } from '@/store/walletStore'
|
||||
import ListAnim from '@/components/ListAnim.vue'
|
||||
import TransactionSkeleton from '@/components/TransactionSkeleton.vue'
|
||||
import BasicModal from '@/components/BasicPacks/BasicModal.vue'
|
||||
import DialogVant from '@/components/DialogVant.vue'
|
||||
import { useFundUserStore } from '@/store/fundStore'
|
||||
import { getOneProductWallet } from '@/api/products'
|
||||
import goyImg from '@/assets/img/goyImg.svg'
|
||||
import mokaabImg from '@/assets/img/mokaabImg.svg'
|
||||
import sekkeImg from "@/assets/img/sekkeImg.svg"
|
||||
import mesImg from "@/assets/img/mesImg.jpg"
|
||||
import noghrehImg from "@/assets/img/noghrehImg.webp"
|
||||
import defaultImg from '@/assets/img/defaultAbshodeh.svg'
|
||||
import type { Product } from '@/models/products'
|
||||
|
||||
const info = ref<Product>()
|
||||
const items = ref<Transaction[]>([])
|
||||
const tableOutput = ref<TableOutput<Transaction> | null>(null)
|
||||
const pagination = ref<TableInput>({/*limit: 100, page: 0*/ })
|
||||
const transactionShow = ref<boolean>()
|
||||
const editShow = ref<boolean>()
|
||||
const showDeleteConfirm = ref<boolean>()
|
||||
const isDeposit = ref<boolean>()
|
||||
const formRef = ref<FormInstance>()
|
||||
let fundStore = useFundUserStore()
|
||||
let walletStore = useWalletStore()
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
initInfo()
|
||||
// initTable()
|
||||
})
|
||||
|
||||
function deleteFundConfirm() {
|
||||
if (info.value?.wallet === undefined || info.value?.wallet?.gold === 0) {
|
||||
showDeleteConfirm.value = true
|
||||
} else {
|
||||
message.error('ابتدا گنج خود را خالی کنید')
|
||||
editShow.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteFundFunction() {
|
||||
try {
|
||||
loading.value = true
|
||||
showDeleteConfirm.value = false
|
||||
await deleteFund(infoId)
|
||||
await fundStore.getMyFund()
|
||||
router.back()
|
||||
message.success('گنج با موفقیت حذف شد')
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const infoId: number = parseInt(<string>router.currentRoute.value.params.id)
|
||||
const userFormState = reactive<FundTransaction>({
|
||||
value: undefined,
|
||||
fund_id: infoId
|
||||
})
|
||||
|
||||
watch(transactionShow, (n) => !n ? userFormState.value = undefined : '')
|
||||
|
||||
const transButtonDisable = computed(() => {
|
||||
if (!loading.value) {
|
||||
if (userFormState.value !== undefined) {
|
||||
if (isDeposit.value) {
|
||||
return userFormState.value > walletStore?.walletInfo?.gold
|
||||
} else {
|
||||
return userFormState.value > info.value?.wallet?.gold
|
||||
}
|
||||
// return isDeposit.value ? userFormState.value > walletStore?.walletInfo?.gold : userFormState.value > info.value?.wallet?.gold
|
||||
} else return true
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
async function initInfo() {
|
||||
try {
|
||||
loading.value = true
|
||||
info.value = await getOneProductWallet(infoId)
|
||||
//pagination.value.page=0
|
||||
await initTable()
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function initTable() {
|
||||
if (info.value?.wallet)
|
||||
try {
|
||||
loading.value = true
|
||||
items.value = []
|
||||
Object.assign(pagination.value, { wallet_id: info.value?.wallet?.id })
|
||||
// pagination.value.fund_id = infoId
|
||||
tableOutput.value = await getFundTransactionTable(pagination.value)
|
||||
items.value.push(...tableOutput.value.rows)
|
||||
// console.log(tableOutput.value)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function transaction() {
|
||||
formRef.value?.validateFields().then(async () => {
|
||||
try {
|
||||
loading.value = true
|
||||
userFormState.fund_id = infoId
|
||||
isDeposit.value ? await fundDeposit(userFormState) : await fundWithdraw(userFormState)
|
||||
await initInfo()
|
||||
// await initTable()
|
||||
await fundStore.getMyFund()
|
||||
await walletStore.getMyWallet()
|
||||
fundStore = useWalletStore()
|
||||
walletStore = useWalletStore()
|
||||
message.success(` با موفقیت${isDeposit.value ? ' واریز' : ' برداشت'} شد`)
|
||||
transactionShow.value = false
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const itemImg = computed(() => {
|
||||
switch (info.value?.title) {
|
||||
case 'خرید لوازم منزل':
|
||||
return homeImg
|
||||
case 'هدیه':
|
||||
return giftImg
|
||||
case 'گردش':
|
||||
return circulationImg
|
||||
case 'ازدواج':
|
||||
return loveImg
|
||||
case 'تعمیرات':
|
||||
return repairsImg
|
||||
case 'پس انداز':
|
||||
return savingImg
|
||||
default:
|
||||
return savingImg
|
||||
}
|
||||
})
|
||||
|
||||
import { useDesktopBreakpoint } from '@/layouts/composables/useAppLayout'
|
||||
import { useFundInfoPage } from './composables/useFundInfoPage'
|
||||
import DesktopFundInfoView from './desktop/DesktopFundInfoView.vue'
|
||||
import MobileFundInfoView from './mobile/MobileFundInfoView.vue'
|
||||
import FundTransactionForm from './components/FundTransactionForm.vue'
|
||||
import FundEditActions from './components/FundEditActions.vue'
|
||||
|
||||
const isDesktop = useDesktopBreakpoint()
|
||||
const {
|
||||
info,
|
||||
transactionShow,
|
||||
editShow,
|
||||
showDeleteConfirm,
|
||||
isDeposit,
|
||||
deleteFundFunction,
|
||||
} = useFundInfoPage()
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.fund-info-page-root {
|
||||
min-height: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
class="bg-white wrap-fix py-3 px-3 text-primary font-bold drop-shadow flex h-12 z-20 justify-between"
|
||||
>
|
||||
<div class="flex">
|
||||
<div class="cursor-pointer" @click="goBack()">
|
||||
<BasicIcon icon="vuesax-linear:arrow-right-1" />
|
||||
</div>
|
||||
<div class="mr-2">{{ info?.title }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-20 flex flex-col justify-center items-center">
|
||||
<a-spin :spinning="loading">
|
||||
<div class="bg-sky-100 w-[120px] aspect-square flex justify-center rounded-xl">
|
||||
<img v-if="info?.group_type == 'گوی'" :src="goyImg" alt="" />
|
||||
<img v-if="info?.group_type == 'مکعب'" :src="mokaabImg" alt="" />
|
||||
<img v-if="info?.group_type == 'سکه'" :src="sekkeImg" alt="" />
|
||||
<img v-if="info?.group_type == 'مس'" :src="mesImg" alt="" />
|
||||
<img v-if="info?.group_type == 'نقره'" :src="noghrehImg" alt="" />
|
||||
<img
|
||||
v-if="info?.group_type == 'طلا' || info?.group_type == 'آبشده' || info?.group_type == null"
|
||||
:src="defaultImg"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
</a-spin>
|
||||
<div class="mt-2 font-bold flex text-xs items-center text-gray-500">
|
||||
<div class="ml-1 text-base text-primary">{{ info?.wallet?.gold ?? 0 }}</div>
|
||||
{{ info?.unit }}
|
||||
</div>
|
||||
<div class="text-gray-400">موجودی گنج {{ info?.title }}</div>
|
||||
<div class="w-full p-5">
|
||||
<div class="font-bold mt-5">تراکنش ها</div>
|
||||
<div class="mt-5 pb-17 overflow-y-scroll h-[54vh]">
|
||||
<list-anim v-if="!loading">
|
||||
<Item v-for="item in items" :key="item.id" :item="item" :title="info?.title" />
|
||||
</list-anim>
|
||||
<TransactionSkeleton v-for="i in 8" v-else :key="i" class="mt-1" />
|
||||
<empty v-if="items.length === 0 && !loading" text="هیچ تراکنشی یافت نشد" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import { loading } from '@/utils'
|
||||
import ListAnim from '@/components/ListAnim.vue'
|
||||
import TransactionSkeleton from '@/components/TransactionSkeleton.vue'
|
||||
import Empty from '@/components/empty.vue'
|
||||
import Item from '../components/Item.vue'
|
||||
import goyImg from '@/assets/img/goyImg.svg'
|
||||
import mokaabImg from '@/assets/img/mokaabImg.svg'
|
||||
import sekkeImg from '@/assets/img/sekkeImg.svg'
|
||||
import mesImg from '@/assets/img/mesImg.jpg'
|
||||
import noghrehImg from '@/assets/img/noghrehImg.webp'
|
||||
import defaultImg from '@/assets/img/defaultAbshodeh.svg'
|
||||
import { useFundInfoPageContext } from '../composables/useFundInfoPage'
|
||||
|
||||
const { info, items, goBack } = useFundInfoPageContext()
|
||||
</script>
|
||||
@@ -0,0 +1,161 @@
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
class="bg-white w-full py-3 px-3 text-primary font-bold drop-shadow fixed md:absolute top-0 flex h-12 z-20"
|
||||
>
|
||||
<div @click="goBack()">
|
||||
<BasicIcon icon="vuesax-linear:arrow-right-1" />
|
||||
</div>
|
||||
<div class="mr-2">دارایی ها</div>
|
||||
</div>
|
||||
<div
|
||||
class="w-screen md:w-full h-[70vh] fixed md:absolute overflow-hidden"
|
||||
:class="isBazretalaProject() ? 'bazretala-fund-header' : 'text-tertiary bg-primary'"
|
||||
>
|
||||
<img
|
||||
:src="fundHeaderBackground"
|
||||
alt=""
|
||||
:class="
|
||||
isBazretalaProject()
|
||||
? 'pointer-events-none z-0 absolute inset-0 w-full object-cover object-center'
|
||||
: 'pointer-events-none z-0 w-full absolute bottom-0 left-0 opacity-5'
|
||||
"
|
||||
/>
|
||||
<div
|
||||
class="pt-15 flex flex-col relative z-10"
|
||||
:class="isBazretalaProject() ? 'text-white' : 'text-tertiary'"
|
||||
>
|
||||
<div class="font-bold mr-5 z-20">موجودی دارایی ها</div>
|
||||
<div
|
||||
v-if="meta?.has_count_based_products"
|
||||
class="flex mt-4 justify-center mt-2 w-full z-20"
|
||||
>
|
||||
محصولات:
|
||||
<div class="text-l mr-4 font-bold">{{ countBasedInventory }} عدد</div>
|
||||
</div>
|
||||
<template v-if="isBazretalaProject()">
|
||||
<div class="flex justify-center mt-2 w-full z-20">
|
||||
دارایی نقره:
|
||||
<div class="text-l mr-4 font-bold">
|
||||
{{ walletStore.walletInfo?.count_silver ?? 0 }}گرم
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-center mt-2 w-full z-20">
|
||||
دارایی طلایی:
|
||||
<div class="text-l mr-4 font-bold">
|
||||
{{ walletStore.walletInfo?.count_gold_wallet ?? 0 }}گرم
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="meta?.single_metal && primaryMetalTotal">
|
||||
<div class="flex justify-center mt-2 w-full z-20">
|
||||
{{ primaryMetalTotal.label }}:
|
||||
<div class="text-l mr-4 font-bold">{{ formatMetalTotal(primaryMetalTotal) }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div
|
||||
v-for="metal in metalTotals"
|
||||
:key="`metal-${metal.metal_id}`"
|
||||
class="flex justify-center mt-2 w-full z-20"
|
||||
>
|
||||
{{ metal.label }}:
|
||||
<div class="text-l mr-4 font-bold">{{ formatMetalTotal(metal) }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<div
|
||||
v-if="meta?.has_count_based_products && !isBazretalaProject()"
|
||||
class="flex justify-center mt-2 w-full z-20"
|
||||
>
|
||||
مجموع موجودی:
|
||||
<div class="text-l mr-4 font-bold">{{ countBasedInventory }} عدد</div>
|
||||
</div>
|
||||
<div class="flex justify-center mt-2 w-full z-20">
|
||||
دارایی ریالی:
|
||||
<div class="text-l mr-4 font-bold">{{ usePriceWithoutType(cashWallet) }}ریال</div>
|
||||
</div>
|
||||
<div class="flex justify-center mt-2 w-full z-20">
|
||||
معادل ریالی مجموع دارایی ها:
|
||||
<div class="text-l mr-4 font-bold">{{ usePriceWithoutType(totalRialValue) }}ریال</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-[20rem]">
|
||||
<div
|
||||
class="bg-gray-100 w-screen md:w-full z-20 relative rounded-t-3xl h-[calc(100vh-20rem-70px)] overflow-y-auto pb-15"
|
||||
style="box-shadow: 0px -2px 4px -2px #0000001a"
|
||||
>
|
||||
<div
|
||||
v-if="inventoryCards.length === 0 && !loading"
|
||||
class="w-full h-full flex justify-center items-center"
|
||||
>
|
||||
<div>
|
||||
<img
|
||||
:src="fundEmptyImage"
|
||||
alt=""
|
||||
:class="isBazretalaProject() ? 'w-48 max-w-[11rem]' : 'w-70'"
|
||||
/>
|
||||
<div v-if="nameProject !== 'abaeigold'" class="text-center text-lg">
|
||||
{{ fundEmptyText }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a-spin :spinning="loading">
|
||||
<div :class="loading ? 'h-[40vh]' : ''" class="grid grid-cols-2 gap-3 p-5">
|
||||
<Item
|
||||
v-for="item in inventoryCards"
|
||||
:key="item.product_id"
|
||||
:item="item"
|
||||
@click="openFundInfo(item.product_id)"
|
||||
/>
|
||||
</div>
|
||||
</a-spin>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import { loading } from '@/utils'
|
||||
import { usePriceWithoutType } from '@/utils/usePrice'
|
||||
import { useWalletStore } from '@/store/walletStore'
|
||||
import Item from '../components/Item.vue'
|
||||
import { useFundPageContext } from '../composables/useFundPage'
|
||||
|
||||
const walletStore = useWalletStore()
|
||||
|
||||
const {
|
||||
nameProject,
|
||||
meta,
|
||||
inventoryCards,
|
||||
metalTotals,
|
||||
primaryMetalTotal,
|
||||
cashWallet,
|
||||
totalRialValue,
|
||||
countBasedInventory,
|
||||
fundHeaderBackground,
|
||||
fundEmptyImage,
|
||||
fundEmptyText,
|
||||
isBazretalaProject,
|
||||
formatMetalTotal,
|
||||
openFundInfo,
|
||||
goBack,
|
||||
} = useFundPageContext()
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.bazretala-fund-header {
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.bazretala-fund-header::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 1;
|
||||
background: rgba(0, 0, 0, 0.45);
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,117 @@
|
||||
import { computed, inject, onMounted, provide, ref, type InjectionKey } from 'vue'
|
||||
import router from '@/router'
|
||||
import { loading } from '@/utils'
|
||||
import { usePrefix } from '@/utils/usePrefix'
|
||||
import { createFund, editFund, getFundById } from '@/api/fund'
|
||||
import { message } from 'ant-design-vue/es'
|
||||
import { useFundUserStore } from '@/store/fundStore'
|
||||
import type { Fund } from '@/models/fund'
|
||||
import homeImg from '@/assets/img/cash_home.svg'
|
||||
import giftImg from '@/assets/img/cash_gift.svg'
|
||||
import circulationImg from '@/assets/img/cash_circulation.svg'
|
||||
import loveImg from '@/assets/img/cash_love.svg'
|
||||
import repairsImg from '@/assets/img/cash_repairs.svg'
|
||||
import savingImg from '@/assets/img/cash_saving.svg'
|
||||
|
||||
export const FUND_NEW_PAGE_KEY: InjectionKey<ReturnType<typeof useFundNewPage>> =
|
||||
Symbol('fundNewPage')
|
||||
|
||||
const types = [
|
||||
{ name: 'خرید لوازم منزل' },
|
||||
{ name: 'پس انداز' },
|
||||
{ name: 'گردش' },
|
||||
{ name: 'ازدواج' },
|
||||
{ name: 'تعمیرات' },
|
||||
{ name: 'هدیه' },
|
||||
]
|
||||
|
||||
export function useFundNewPage() {
|
||||
const fundStore = useFundUserStore()
|
||||
const edit_id = computed(() => parseInt(router.currentRoute.value.query.id as string))
|
||||
const name = ref<string>('پس انداز')
|
||||
const { prefixCls } = usePrefix('input_name')
|
||||
const info = ref<Fund>()
|
||||
|
||||
const itemImg = computed(() => {
|
||||
switch (name.value) {
|
||||
case 'خرید لوازم منزل':
|
||||
return homeImg
|
||||
case 'هدیه':
|
||||
return giftImg
|
||||
case 'گردش':
|
||||
return circulationImg
|
||||
case 'ازدواج':
|
||||
return loveImg
|
||||
case 'تعمیرات':
|
||||
return repairsImg
|
||||
case 'پس انداز':
|
||||
return savingImg
|
||||
default:
|
||||
return savingImg
|
||||
}
|
||||
})
|
||||
|
||||
async function getEditInfo() {
|
||||
try {
|
||||
loading.value = true
|
||||
info.value = await getFundById(edit_id.value)
|
||||
name.value = info.value?.title ?? ''
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function ok() {
|
||||
try {
|
||||
loading.value = true
|
||||
if (!name.value) {
|
||||
message.error('ابتدا نام گنج را وارد کنید')
|
||||
return
|
||||
}
|
||||
edit_id.value
|
||||
? await editFund(edit_id.value, { title: name.value })
|
||||
: await createFund({ title: name.value })
|
||||
await fundStore.getMyFund()
|
||||
message.success(`گنج با موفقیت ${edit_id.value ? 'ویرایش' : 'ساخته'} شد`)
|
||||
router.back()
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function goBack() {
|
||||
router.back()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (edit_id.value) {
|
||||
getEditInfo()
|
||||
}
|
||||
})
|
||||
|
||||
const context = {
|
||||
types,
|
||||
edit_id,
|
||||
name,
|
||||
prefixCls,
|
||||
info,
|
||||
itemImg,
|
||||
ok,
|
||||
goBack,
|
||||
}
|
||||
|
||||
provide(FUND_NEW_PAGE_KEY, context)
|
||||
return context
|
||||
}
|
||||
|
||||
export function useFundNewPageContext() {
|
||||
const context = inject(FUND_NEW_PAGE_KEY)
|
||||
if (!context) {
|
||||
throw new Error('useFundNewPageContext must be used within useFundNewPage')
|
||||
}
|
||||
return context
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<div class="dfund-new">
|
||||
<div class="dfund-new__container">
|
||||
<header class="dfund-new-topbar">
|
||||
<button type="button" class="dfund-new-topbar__back" @click="goBack()">
|
||||
<BasicIcon icon="vuesax-linear:arrow-right-1" size="18" />
|
||||
بازگشت
|
||||
</button>
|
||||
<div class="dfund-new-topbar__meta">
|
||||
<p class="dfund-new-topbar__eyebrow">گنج</p>
|
||||
<h1 class="dfund-new-topbar__title">
|
||||
{{ edit_id ? `ویرایش گنج ${name}` : 'صندوق جدید' }}
|
||||
</h1>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<a-spin :spinning="loading">
|
||||
<section class="dfund-new__card dfund-surface">
|
||||
<div class="dfund-new__preview">
|
||||
<img :src="itemImg" alt="" class="dfund-new__preview-img" />
|
||||
</div>
|
||||
|
||||
<div class="dfund-new__field" :class="[prefixCls]">
|
||||
<label class="dfund-new__label">عنوان گنج</label>
|
||||
<van-field
|
||||
v-model="name"
|
||||
label=""
|
||||
placeholder="عنوان را وارد کنید"
|
||||
input-align="center"
|
||||
:show-word-limit="true"
|
||||
maxlength="25"
|
||||
rows="1"
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="dfund-new__tags">
|
||||
<button
|
||||
v-for="item in types"
|
||||
:key="item.name"
|
||||
type="button"
|
||||
class="dfund-new__tag"
|
||||
:class="{ 'dfund-new__tag--active': item.name === name }"
|
||||
@click="name = item.name"
|
||||
>
|
||||
{{ item.name }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<BasicButton class="dfund-new__submit" type="primary" :disabled="loading" @click="ok()">
|
||||
<a-spin v-if="loading" size="small" />
|
||||
<span v-else>{{ edit_id ? 'ویرایش گنج' : 'ساخت گنج' }}</span>
|
||||
</BasicButton>
|
||||
</section>
|
||||
</a-spin>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
|
||||
import { loading } from '@/utils'
|
||||
import { useFundNewPageContext } from '../composables/useFundNewPage'
|
||||
|
||||
const { types, edit_id, name, prefixCls, itemImg, ok, goBack } = useFundNewPageContext()
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@prefix: ~'@{prefixCls}-input_name';
|
||||
|
||||
.@{prefix} {
|
||||
.van-field__value {
|
||||
@apply flex;
|
||||
}
|
||||
|
||||
.van-field__body {
|
||||
@apply w-full mr-5;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,194 +1,23 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="bg-white wrap-fix py-3 px-3 text-primary font-bold drop-shadow flex h-12 z-20 justify-between">
|
||||
<div class="flex ">
|
||||
<div @click="router.back()" class="cursor-pointer">
|
||||
<BasicIcon icon="vuesax-linear:arrow-right-1"/>
|
||||
</div>
|
||||
<div class="mr-2">{{edit_id? `ویرایش گنج ${name}`: 'صندوق جدید'}}</div>
|
||||
</div>
|
||||
<div @click="router.back()">
|
||||
<!-- <BasicIcon icon="vuesax-linear:setting-4"/>-->
|
||||
</div>
|
||||
</div>
|
||||
<a-spin :spinning="loading">
|
||||
<div class="pt-20 flex flex-col justify-center items-center">
|
||||
<div class="bg-sky-100 w-[120px] aspect-square flex justify-center rounded-xl"><img :src="itemImg" alt=""></div>
|
||||
<!-- <div class="mt-1 text-xs">تغییر عکس</div>-->
|
||||
<div class="flex mt-3 w-full relative px-5" :class="[prefixCls]">
|
||||
<!-- <div class="text-primary font-bold mx-auto items-center">پس انداز</div>
|
||||
<div class="absolute left-5 text-gray-400 text-xs">7/25</div>-->
|
||||
<van-field
|
||||
v-model="name"
|
||||
label=""
|
||||
class="font-bold"
|
||||
placeholder="عنوان را وارد کنید"
|
||||
input-align="center"
|
||||
:show-word-limit="true"
|
||||
maxlength="25"
|
||||
rows="1"
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex overflow-x-scroll gap-2 whitespace-nowrap max-w-[320px] mt-2 px-3">
|
||||
<!-- <BasicTags
|
||||
:items="types"
|
||||
color="green"
|
||||
:has-add="false"
|
||||
/>-->
|
||||
<!-- <BasicButton v-for="item in types" size="small">{{item.name}}</BasicButton>-->
|
||||
<div v-for="item in types"
|
||||
class="border-1 px-3 py-2 flex-nowrap rounded text-xs color-transition background-color-transition"
|
||||
:key="item.name"
|
||||
:class="item.name === name? 'bg-primary text-white':'bg-gray-200 text-gray-600'"
|
||||
@click="name = item.name">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="mt-2 font-bold flex text-xs items-center text-gray-500">
|
||||
<div class="ml-1 text-base text-primary">{{ router.currentRoute.value.query.amount }}</div>
|
||||
گرم
|
||||
</div>
|
||||
<div class="text-gray-400">موجودی صندوق {{itemName}}</div>
|
||||
<div class="w-full p-5">
|
||||
<div class="w-full flex gap-3">
|
||||
<BasicButton class="w-full !bg-light" icon="vuesax-linear:add-square" icon-size="18">برداشت</BasicButton>
|
||||
<BasicButton class="w-full !bg-light" icon="vuesax-linear:arrow-up" icon-size="18">واریز</BasicButton>
|
||||
</div>
|
||||
<div class="text-lg font-bold mt-5">تراکنش ها</div>
|
||||
<div class="mt-5 pb-17">
|
||||
<Item v-for="item in items" :is-up="item.isUp" :has-transition="item.hasTransition" :key="item"/>
|
||||
</div>
|
||||
</div>-->
|
||||
<div class="wrap-fix flex justify-center bottom-23 px-5 z-200" @click="ok()">
|
||||
<BasicButton class="rounded w-full px-5 py-2 text-center" type="primary" :disabled="loading">
|
||||
<a-spin v-if="loading" size="small"/>
|
||||
<div v-else>{{edit_id? 'ویرایش گنج':'ساخت گنج'}}</div>
|
||||
</BasicButton>
|
||||
</div>
|
||||
</div>
|
||||
</a-spin>
|
||||
|
||||
<div class="fund-new-page-root">
|
||||
<DesktopFundNewView v-show="isDesktop" />
|
||||
<MobileFundNewView v-show="!isDesktop" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useDesktopBreakpoint } from '@/layouts/composables/useAppLayout'
|
||||
import { useFundNewPage } from './composables/useFundNewPage'
|
||||
import DesktopFundNewView from './desktop/DesktopFundNewView.vue'
|
||||
import MobileFundNewView from './mobile/MobileFundNewView.vue'
|
||||
|
||||
import router from "@/router";
|
||||
import {computed, onMounted, ref} from "vue";
|
||||
import homeImg from "@/assets/img/cash_home.svg";
|
||||
import giftImg from "@/assets/img/cash_gift.svg";
|
||||
import circulationImg from "@/assets/img/cash_circulation.svg";
|
||||
import loveImg from "@/assets/img/cash_love.svg";
|
||||
import repairsImg from "@/assets/img/cash_repairs.svg";
|
||||
import savingImg from "@/assets/img/cash_saving.svg";
|
||||
import {usePrefix} from "@/utils/usePrefix";
|
||||
import {loading} from "@/utils";
|
||||
import {createFund, editFund, getFundById} from "@/api/fund";
|
||||
import {message} from "ant-design-vue/es";
|
||||
import {useFundUserStore} from "@/store/fundStore";
|
||||
import BasicButton from "@/components/BasicPacks/BasicButton.vue";
|
||||
import type {Fund} from "@/models/fund";
|
||||
|
||||
const fundStore = useFundUserStore()
|
||||
|
||||
|
||||
const types = [
|
||||
{
|
||||
name: 'خرید لوازم منزل'
|
||||
},
|
||||
{
|
||||
name: 'پس انداز'
|
||||
},
|
||||
{
|
||||
name: 'گردش'
|
||||
},
|
||||
{
|
||||
name: 'ازدواج'
|
||||
},
|
||||
{
|
||||
name: 'تعمیرات'
|
||||
},
|
||||
{
|
||||
name: 'هدیه'
|
||||
},
|
||||
]
|
||||
|
||||
const edit_id = computed(() => {
|
||||
return parseInt(router.currentRoute.value.query.id as string)
|
||||
})
|
||||
const name = ref<string>('پس انداز')
|
||||
const {prefixCls} = usePrefix('input_name')
|
||||
const info = ref<Fund>()
|
||||
|
||||
async function getEditInfo() {
|
||||
try {
|
||||
loading.value = true
|
||||
info.value = await getFundById(edit_id.value)
|
||||
name.value = info.value?.title?? ''
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (edit_id.value) {
|
||||
getEditInfo()
|
||||
}
|
||||
})
|
||||
|
||||
const itemImg = computed(() => {
|
||||
switch (name.value) {
|
||||
case 'خرید لوازم منزل':
|
||||
return homeImg
|
||||
case 'هدیه':
|
||||
return giftImg
|
||||
case 'گردش':
|
||||
return circulationImg
|
||||
case 'ازدواج':
|
||||
return loveImg
|
||||
case 'تعمیرات':
|
||||
return repairsImg
|
||||
case 'پس انداز':
|
||||
return savingImg
|
||||
default:
|
||||
return savingImg
|
||||
}
|
||||
})
|
||||
|
||||
async function ok() {
|
||||
try {
|
||||
loading.value = true
|
||||
// console.log(name.value)
|
||||
name.value ? edit_id.value? await editFund(edit_id.value,{title: name.value}) :await createFund({title: name.value}) : () => {
|
||||
message.error('ابتدا نام گنج را وارد کنید')
|
||||
return
|
||||
}
|
||||
await fundStore.getMyFund()
|
||||
message.success(`گنج با موفقیت ${edit_id.value? 'ویرایش':'ساخته'} شد`)
|
||||
router.back()
|
||||
// name.value? message.warn('ss'): message.error('ابتدا نام صندوق را وارد کنید')
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const isDesktop = useDesktopBreakpoint()
|
||||
useFundNewPage()
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@prefix: ~'@{prefixCls}-input_name';
|
||||
|
||||
.@{prefix} {
|
||||
.van-field__value {
|
||||
@apply flex;
|
||||
}
|
||||
|
||||
.van-field__body {
|
||||
@apply w-full mr-5;
|
||||
}
|
||||
<style scoped>
|
||||
.fund-new-page-root {
|
||||
min-height: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
class="bg-white wrap-fix py-3 px-3 text-primary font-bold drop-shadow flex h-12 z-20 justify-between"
|
||||
>
|
||||
<div class="flex">
|
||||
<div class="cursor-pointer" @click="goBack()">
|
||||
<BasicIcon icon="vuesax-linear:arrow-right-1" />
|
||||
</div>
|
||||
<div class="mr-2">{{ edit_id ? `ویرایش گنج ${name}` : 'صندوق جدید' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<a-spin :spinning="loading">
|
||||
<div class="pt-20 flex flex-col justify-center items-center">
|
||||
<div class="bg-sky-100 w-[120px] aspect-square flex justify-center rounded-xl">
|
||||
<img :src="itemImg" alt="" />
|
||||
</div>
|
||||
<div class="flex mt-3 w-full relative px-5" :class="[prefixCls]">
|
||||
<van-field
|
||||
v-model="name"
|
||||
label=""
|
||||
class="font-bold"
|
||||
placeholder="عنوان را وارد کنید"
|
||||
input-align="center"
|
||||
:show-word-limit="true"
|
||||
maxlength="25"
|
||||
rows="1"
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex overflow-x-scroll gap-2 whitespace-nowrap max-w-[320px] mt-2 px-3">
|
||||
<div
|
||||
v-for="item in types"
|
||||
:key="item.name"
|
||||
class="border-1 px-3 py-2 flex-nowrap rounded text-xs color-transition background-color-transition"
|
||||
:class="item.name === name ? 'bg-primary text-white' : 'bg-gray-200 text-gray-600'"
|
||||
@click="name = item.name"
|
||||
>
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="wrap-fix flex justify-center bottom-23 px-5 z-200" @click="ok()">
|
||||
<BasicButton class="rounded w-full px-5 py-2 text-center" type="primary" :disabled="loading">
|
||||
<a-spin v-if="loading" size="small" />
|
||||
<div v-else>{{ edit_id ? 'ویرایش گنج' : 'ساخت گنج' }}</div>
|
||||
</BasicButton>
|
||||
</div>
|
||||
</div>
|
||||
</a-spin>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
|
||||
import { loading } from '@/utils'
|
||||
import { useFundNewPageContext } from '../composables/useFundNewPage'
|
||||
|
||||
const { types, edit_id, name, prefixCls, itemImg, ok, goBack } = useFundNewPageContext()
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@prefix: ~'@{prefixCls}-input_name';
|
||||
|
||||
.@{prefix} {
|
||||
.van-field__value {
|
||||
@apply flex;
|
||||
}
|
||||
|
||||
.van-field__body {
|
||||
@apply w-full mr-5;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user