widthdraw and deposit

This commit is contained in:
2026-06-09 21:04:22 +03:30
parent 95516ee2d8
commit 689c51c27d
26 changed files with 1228 additions and 522 deletions
+2 -2
View File
@@ -164,7 +164,7 @@
<div class="flex justify-between mt-3">
<div>مظنه:</div>
<div class="flex items-center">
<div class="font-bold">{{ usePriceWithoutType(((props?.ProductItem?.price_profit) + (props?.ProductItem?.price))) }}</div>
<div class="font-bold">{{ usePriceWithoutType(Math.round(basePriceValue ?? 0)) }}</div>
<div class="text-xs mr-1">ریال</div>
</div>
</div>
@@ -656,6 +656,7 @@ async function ok() {
method: "cash",
number: form.value.goldValue ?? 0
})
confirmAction.value = false
await walletStore.getMyWallet()
await router.push({ name: 'transactions' })
form.value = {
@@ -664,7 +665,6 @@ async function ok() {
percentWallet: undefined,
method: 'cash'
}
// refreshTable()
await fundStore.getMyFund()
message.success('سفارش شما با موفقیت انجام شد')
} catch (e) {
+34 -71
View File
@@ -1,91 +1,54 @@
<template>
<div v-if="item" class="bg-white flex flex-col items-center p-3 rounded-xl">
<!-- <img v-lazy="{ src: itemImg, loading: logo,error: logo}" alt="" class="w-[87px] ">-->
<img v-if="props.item.group_type=='گوی'" :src="goyImg">
<img v-if="props.item.group_type=='مکعب'" :src="mokaabImg">
<img v-if="props.item.group_type=='سکه'" :src="sekkeImg">
<img v-if="props.item.group_type=='مس'" :src="mesImg">
<img v-if="props.item.group_type=='نقره'" :src="noghrehImg">
<!-- <img :src="props.item.img" alt="image">-->
<img v-if="props.item.group_type=='طلا'|| props.item.group_type=='آبشده'|| props.item.group_type== null" :src="defaultImg">
<div class="mt-3">{{props.item?.title?? '-'}}</div>
<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">
<div class="flex gap-1">
<div class="font-bold">{{ props.item?.wallet?.gold ?? '-' }}</div>
{{ getProductQuantityUnit(props.item) }}
<div class="font-bold">{{ item.quantity ?? '-' }}</div>
{{ item.unit }}
</div>
<div v-if="getProductUnitWeightLabel(props.item)" class="text-xs text-gray-500">
هر عدد {{ getProductUnitWeightLabel(props.item) }}
<div v-if="item.unit_weight" class="text-xs text-gray-500">
هر عدد {{ item.unit_weight }}
</div>
</div>
<!-- {{props.item?.wallet[0]?.cash}}-->
</div>
</template>
<script setup lang="ts">
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 {computed} from "vue"
import type {Fund} from "@/models/fund"
import defaultImg from "@/assets/img/defaultAbshodeh.svg"
import goyImg from "@/assets/img/goyImg.svg"
import mokaabImg from "@/assets/img/mokaabImg.svg"
import sekkeImg from "@/assets/img/sekkeImg.svg"
import type { Product } from '@/models/products'
import mesImg from "@/assets/img/mesImg.jpg";
import noghrehImg from "@/assets/img/noghrehImg.webp";
import { getProductQuantityUnit, getProductUnitWeightLabel } from '@/utils/productDealMethod'
/*function itemImg() {
import { computed, ref, watch } from 'vue'
import type { WalletInventoryCard } from '@/models/walletAssets'
import { getProductDisplayImage } from '@/utils/productAssets'
}*/
interface Prop {
item: Product
item: WalletInventoryCard
}
const props = defineProps<Prop>()
const imageSrc = ref('')
const itemImg = computed(() => {
switch (props.item?.title) {
case 'خرید لوازم منزل':
return homeImg
case 'هدیه':
return giftImg
case 'گردش':
return circulationImg
case 'ازدواج':
return loveImg
case 'تعمیرات':
return repairsImg
case 'پس انداز':
return savingImg
default: return savingImg
}
})
const displayImage = computed(() => imageSrc.value || resolveImage())
/*const itemName = computed(() => {
switch (props.type) {
case 'home':
return 'خرید لوازم منزل'
case 'gift':
return 'هدیه'
case 'circulation':
return 'گردش'
case 'love':
return 'ازدواج'
case 'repairs':
return 'تعمیرات'
case 'saving':
return 'پس انداز'
default: return null
}
})*/
watch(
() => props.item,
() => {
imageSrc.value = resolveImage()
},
{ immediate: true, deep: true }
)
function resolveImage() {
return getProductDisplayImage({
title: props.item.title,
group_type: props.item.group_type,
file: props.item.file,
})
}
function onImageError() {
imageSrc.value = getProductDisplayImage({
title: props.item.title,
group_type: props.item.group_type,
file: null,
})
}
</script>
<style scoped>
</style>
+71 -113
View File
@@ -9,158 +9,116 @@
<div class="text-tertiary bg-primary w-screen md:w-full h-[70vh] fixed md:absolute overflow-hidden">
<img :src="img" alt="" class="w-full absolute bottom-0 left-0 opacity-5 pointer-events-none z-0" />
<div class="pt-15 flex flex-col relative z-10">
<div class="text-tertiary font-bold mr-5 z-20">موجودی دارایی ها</div>
<div class="flex mt-4 justify-center mt-2 w-full z-20">
محصولات:
<div class="text-l mr-4 font-bold">{{ walletStore.walletInfo?.count_product ?? 0}}عدد</div>
<div class="text-tertiary 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="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>
<div v-if="nameProject === 'goldsun'" 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 v-if="nameProject === 'goldsun'" class="flex justify-center mt-2 w-full z-20">
دارایی مس:
<div class="text-l mr-4 font-bold">{{ walletStore.walletInfo?.count_copper ?? 0}}گرم</div>
</div>
<div v-if="isBoursecuProject()" class="flex justify-center mt-2 w-full z-20">
مجموع موجودی:
<div class="text-l mr-4 font-bold">{{ inventory }} عدد</div>
</div>
<div v-if="!isBoursecuProject()" class="flex justify-center mt-2 w-full z-20">
{{ metalAssetLabel }}:
<div class="text-l mr-4 font-bold">{{ walletStore.walletInfo?.count_gold ?? 0 }}{{ getWeightUnit() }}</div>
</div>
<div class="flex justify-center mt-2 w-full z-20">
دارایی ریالی:
<div class="text-l mr-4 font-bold">{{ usePriceWithoutType(walletStore.walletInfo?.count_cash ?? 0) }}ریال</div>
</div>
<div class="flex justify-center mt-2 w-full z-20">
معادل ریالی مجموع دارایی ها:
<div class="text-l mr-4 font-bold">{{ usePriceWithoutType(walletStore.walletInfo?.count_cash_total ?? 0) }}ریال</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" 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="items.length === 0 && !loading" class="w-full h-full flex justify-center items-center">
<div v-if="inventoryCards.length === 0 && !loading" class="w-full h-full flex justify-center items-center">
<div>
<img :src="empty" alt="" class="w-70 ">
<div v-if="nameProject !== 'abaeigold' " class="text-center text-lg">یک گنج جدید بساز!</div>
<div v-if="nameProject !== 'abaeigold'" class="text-center text-lg">یک گنج جدید بساز!</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 items.filter(x => x.title !== 'آبشده نقدی')" :item="item"
@click="router.push({name: 'fund_info', params:{id:item.id}})"
<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="fixed w-full flex justify-center bottom-23 z-200 md:right-0">
<div class="rounded-3xl bg-[#0A1B37] text-white px-5 py-2" @click="router.push({name: 'fund_add'})">افزودن گنج
</div>
</div>-->
</div>
</template>
<script lang="ts" setup>
import router from "@/router";
import BasicIcon from "@/components/BasicPacks/BasicIcon.vue";
import BasicModal from "@/components/BasicPacks/BasicModal.vue";
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, ref, computed } from "vue";
import {loading} from "@/utils";
import type {TableOutput} from "@/models/table";
import type {Fund} from "@/models/fund";
import {useFundUserStore} from "@/store/fundStore";
import { getMe } from '@/api/me'
import type { User } from '@/models/login'
import {usePriceWithoutType} from "../../../utils/usePrice";
import {useWalletStore} from "@/store/walletStore";
import {useConfigStore} from "@/store/configStore";
import { isBoursecuProject } from '@/utils/config'
import { formatBoursecuAssetAmount, getMetalAssetLabel, getWeightUnit } from '@/utils/productDealMethod'
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'
const nameProject = useConfigStore().config.name
const metalAssetLabel = computed(() => getMetalAssetLabel())
const { assetsSummary, loadWalletAssets } = useWalletAssets()
const items = ref<Fund[]>([])
const tableOutput = ref<TableOutput<Fund> | null>(null)
const fundStore = useFundUserStore()
const walletStore = useWalletStore()
const userInfo = ref<User>()
const weight = ref<number>(0)
const total = ref<number>(0)
const inventory = computed(() =>
items.value
.filter(x => x.title !== 'آبشده نقدی')
.reduce((sum, x) => sum + (x?.wallet?.gold ?? 0), 0)
const meta = computed(() => assetsSummary.value?.meta)
const inventoryCards = computed(() => 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)
)
onMounted(() => {
initTable()
})
async function initTable() {
onMounted(async () => {
try {
userInfo.value = await getMe()
loading.value = true
tableOutput.value = fundStore.myFunds ?? await fundStore.getMyFund() ?? null
console.log(tableOutput.value)
items.value.push(...tableOutput.value?.rows ?? [])
items.value.forEach(x => {
total.value += ((x?.wallet?.gold) ?? 0) * ((x?.price) ?? 0)
if (x.title !== 'آبشده نقدی' && x.title !== 'سکه')
weight.value += ((x?.wallet?.gold) ?? 0) * ((x?.amount) ?? 0)
})
await loadWalletAssets(true)
} catch (e) {
console.log(e)
} finally {
loading.value = false
}
})
function summaryMetalWeight(metal: WalletMetalTotal) {
if (inventoryCards.value.length > 0) {
return metal.product_weight
}
return metal.total_weight
}
/*watch(()=> router.currentRoute.value.name, () =>{
console.log('salammmmmmmmmmmmmmmmmmmmmmmmmmm')
})*/
/*
const items = [
{
type: 'home',
amount: 2.7
},
{
type: 'gift',
amount: 13.1
},
{
type: 'saving',
amount: 6.4
},
{
type: 'repairs',
amount: 16.6
},
{
type: 'circulation',
amount: 5.4
},
{
type: 'love',
amount: 3.7
},
]
*/
function formatMetalTotal(metal: WalletMetalTotal) {
return `${summaryMetalWeight(metal)}${metal.unit}`
}
</script>
<style scoped>
</style>
</style>
+37 -29
View File
@@ -6,11 +6,11 @@
<div class="flex justify-evenly w-full px-2 h-11 items-center bg-gray-50 relative rounded ">
<div :class="isBuy?'text-tertiary':'text-gray-400'" class="w-full text-center z-2"
@click.stop="setIsBuy(true) ">
خرید {{ meltedGoldLabel }} {{ props?.ProductItem?.title }}
خرید {{ tradeProductLabel }}
</div>
<div :class="!isBuy?'text-tertiary':'text-gray-400'" class="w-full text-center z-2"
@click.stop="setIsBuy(false) ">
فروش {{ meltedGoldLabel }} {{ props?.ProductItem?.title }}
فروش {{ tradeProductLabel }}
</div>
<!-- <div ref="bganim" class="absolute bg-white h-8 w-1/2 rounded-lg " :style="`transform: translateX(${isbuy? '0':'-100%'}); left: ${isbuy? '0':'100%'}`"></div>-->
<div ref="bganim" :style="useStyle()"
@@ -53,9 +53,9 @@
type="price" @onchange="calculateGold" />
</a-form-item>
<a-form-item :rules="[justNumber()]">
<BasicInput v-model:value="form.goldValue" addon-before="گرم" :addon-bg-color="useConfigStore().config.color"
<BasicInput v-model:value="form.goldValue" :addon-before="weightUnit" :addon-bg-color="useConfigStore().config.color"
addon-text-color="white"
place-holder="مقدار طلا"
:place-holder="amountFieldLabel"
size="large" type="text" inputmode="decimal" @onchange="calculateCash" />
</a-form-item>
<div v-if="cashValidationMessage" class="text-red-700 text-xs font-bold mt-2">
@@ -133,7 +133,7 @@
<div class="flex gap-2 items-center">
<div class="">{{ feeInGrams }}</div>
<div>
گرم
{{ weightUnit }}
</div>
</div>
</div>
@@ -157,13 +157,13 @@
<div>وزن:</div>
<div class="flex items-center">
<div class="font-bold">{{ form.goldValue }}</div>
<div class="text-xs mr-1">گرم</div>
<div class="text-xs mr-1">{{ weightUnit }}</div>
</div>
</div>
<div class="flex justify-between mt-3">
<div>مظنه:</div>
<div class="flex items-center">
<div class="font-bold">{{ usePriceWithoutType(isBuy ? getTradeBuyPrice(lastPrice) : getTradeSellPrice(lastPrice)) }}</div>
<div class="font-bold">{{ usePriceWithoutType(Math.round(goldPriceValue)) }}</div>
<div class="text-xs mr-1">ریال</div>
</div>
</div>
@@ -171,7 +171,7 @@
<div>کارمزد:</div>
<div class="flex items-center gap-2">
<div class="font-bold text-xl">{{ feeInGrams }}</div>
<div class="text-xs mr-1">گرم</div>
<div class="text-xs mr-1">{{ weightUnit }}</div>
</div>
</div>
<div >(معادل {{ equivalentPrice }} ریال)</div>
@@ -236,7 +236,8 @@ import type { Product } from '@/models/products'
import { useFundUserStore } from '@/store/fundStore'
import {useConfigStore} from "@/store/configStore";
import { calcFeeInGrams, loadServiceFeeFromSettings } from '@/utils/serviceFee'
import { formatCashWalletBalanceText, formatGoldWalletBalanceText } from '@/utils/productDealMethod'
import { formatCashWalletBalanceText, formatGoldWalletBalanceText, getWeightUnit } from '@/utils/productDealMethod'
import { isMeltedTradeGroup } from '@/utils/productCategories'
import { useSettingsStore } from '@/store/settingsStore'
import { storeToRefs } from 'pinia'
import {
@@ -250,6 +251,7 @@ const walletStore = useWalletStore()
const userStore = useUserStore()
const settingsStore = useSettingsStore()
const { meltedGoldLabel } = storeToRefs(settingsStore)
const weightUnit = computed(() => getWeightUnit())
const fundStore = useFundUserStore()
const confirmAction = ref<boolean>(false)
const noCompleteVisible = ref<boolean>(false)
@@ -267,6 +269,12 @@ interface Prop {
const props = withDefaults(defineProps<Prop>(), {})
const isBuy = ref<boolean>(true)
const tradeProductLabel = computed(() => {
const title = props.ProductItem?.title?.trim()
return title || meltedGoldLabel.value
})
const amountFieldLabel = computed(() => `مقدار ${tradeProductLabel.value}`)
const buyPagination = ref<TableEngineInput>({
filters: [{
field: 'type',
@@ -288,8 +296,8 @@ const sellPagination = ref<TableEngineInput>({
const unitPrice = computed(() => {
const product = props.ProductItem
if (product?.group_type === 'آبشده') {
return isBuy.value ? getProductBuyPrice(product) : getProductSellPrice(product)
if (isMeltedTradeGroup(product?.group_type)) {
return isBuy.value ? getProductBuyPrice(product!) : getProductSellPrice(product!)
}
return isBuy.value ? getTradeBuyPrice(lastPrice.value) : getTradeSellPrice(lastPrice.value)
})
@@ -307,6 +315,11 @@ const cashValidationMessage = computed(() =>
productCashValidationMessage(props.ProductItem, form.value?.goldCash, isBuy.value, usePriceWithoutType)
)
const priceUnavailable = computed(() => {
const unit = unitPrice.value
return !unit || Number.isNaN(unit) || unit <= 0
})
const disableTransaction = computed(() =>
loading.value ||
form.value?.goldValue === undefined ||
@@ -321,8 +334,7 @@ const disableTransaction = computed(() =>
(maxOrderCash.value != null && (form.value?.goldCash ?? 0) > maxOrderCash.value) ||
cashValidationMessage.value !== '' ||
(!isBuy.value && form.value.goldValue > walletStore?.walletInfo?.gold) ||
!lastPrice.value ||
(isBuy.value ? getTradeBuyPrice(lastPrice.value) <= 0 : getTradeSellPrice(lastPrice.value) <= 0))
priceUnavailable.value)
function refreshTable() {
sellItems.value = []
@@ -498,7 +510,8 @@ const limitedPrice = computed(() => {
})
function syncFormWithLatestPrice() {
if (!lastPrice.value) return
const unit = unitPrice.value
if (!unit || Number.isNaN(unit)) return
const goldValue = form.value.goldValue
if (goldValue !== undefined && goldValue !== null && goldValue !== '' && !isNaN(Number(goldValue))) {
@@ -513,7 +526,7 @@ function syncFormWithLatestPrice() {
}
watch(
() => [getTradeBuyPrice(lastPrice.value), getTradeSellPrice(lastPrice.value), isBuy.value],
() => [unitPrice.value, isBuy.value, props.ProductItem?.id],
() => {
syncFormWithLatestPrice()
}
@@ -521,20 +534,20 @@ watch(
function calculateCash(val: number) {
priceErrorVisible.value = false
if (!lastPrice.value) return
const unit = unitPrice.value
if (!unit || Number.isNaN(unit)) return
const unit = isBuy.value ? getTradeBuyPrice(lastPrice.value) : getTradeSellPrice(lastPrice.value)
form.value.goldCash = val ? parseFloat((val * unit).toFixed(0)) : undefined
}
function calculateGold(val: number) {
if (!lastPrice.value) return
const unit = unitPrice.value
if (!unit || Number.isNaN(unit)) return
const unit = isBuy.value ? getTradeBuyPrice(lastPrice.value) : getTradeSellPrice(lastPrice.value)
if (isBuy.value) {
if (val) {
form.value.goldValue = toFixedDownThreeChar(parseFloat(String(val / unit)))
priceErrorVisible.value = parseInt(finalPrice.value) > 0
priceErrorVisible.value = parseInt(String(finalPrice.value)) > 0
} else if (val.toString() === '') {
form.value.goldValue = undefined
priceErrorVisible.value = false
@@ -544,7 +557,7 @@ function calculateGold(val: number) {
}
} else if (val) {
form.value.goldValue = toFixedDownThreeChar(parseFloat(String(val / unit)))
priceErrorVisible.value = parseInt(finalPrice.value) > 0
priceErrorVisible.value = parseInt(String(finalPrice.value)) > 0
} else if (val.toString() === '') {
form.value.goldValue = undefined
priceErrorVisible.value = false
@@ -590,12 +603,7 @@ const formatter = (value: number) => {
const price = computed((): Price => <Price>lastPrice.value ?? 0)
const goldPriceValue = computed(() => {
if (!lastPrice.value?.price) return 0
return isBuy.value
? getTradeBuyPrice(lastPrice.value)
: getTradeSellPrice(lastPrice.value)
})
const goldPriceValue = computed(() => unitPrice.value)
async function initPrice() {
try {
@@ -625,10 +633,11 @@ async function ok() {
infoVisible.value = true
await createOrder({
direction: isBuy.value ? 1 : 2,
price: isBuy.value ? getTradeBuyPrice(lastPrice.value) : getTradeSellPrice(lastPrice.value),
price: Math.round(unitPrice.value),
amount: form.value.goldValue ?? 0,
abshode_id: props.ProductItem?.id,
})
confirmAction.value = false
await walletStore.getMyWallet()
await router.push({ name: 'transactions' })
form.value = {
@@ -636,7 +645,6 @@ async function ok() {
goldCash: undefined,
percentWallet: undefined
}
// refreshTable()
message.success('سفارش شما با موفقیت انجام شد')
await fundStore.getMyFund()
} catch (e) {
@@ -1,36 +1,82 @@
<template>
<div class="bg-primary rounded-lg p-2 py-3 mt-2">
<div class="flex justify-center text-tertiary w-full z-20">
<div v-if="meta?.has_count_based_products" class="flex justify-center text-tertiary w-full z-20">
محصولات:
<div class="text-l mr-2 font-bold">{{ userStore?.userInfo?.wallet?.count_product ?? 0 }} عدد</div>
</div>
<div v-if="!isBoursecuProject()" class="flex mt-2 justify-center text-tertiary w-full z-20">
{{ metalAssetLabel }}:
<div class="text-l mr-2 font-bold">{{ (userStore?.userInfo?.wallet?.count_gold ?? 0).toFixed(3) }} {{ weightUnit }}</div>
<BasicIcon @click="$emit('openGoldModal')" icon="vuesax-linear:info-circle" size="18" color="tertiary" />
<div class="text-l mr-2 font-bold">{{ countBasedInventory }} عدد</div>
</div>
<template v-if="meta?.single_metal && primaryMetalTotal">
<div class="flex mt-2 justify-center text-tertiary w-full z-20">
{{ primaryMetalTotal.label }}:
<div class="text-l mr-2 font-bold">{{ formatMetalTotal(primaryMetalTotal) }}</div>
<BasicIcon
icon="vuesax-linear:info-circle"
size="18"
color="tertiary"
@click="$emit('openGoldModal')"
/>
</div>
</template>
<template v-else>
<div
v-for="metal in metalTotals"
:key="metal.metal_id"
class="flex mt-2 justify-center text-tertiary w-full z-20"
>
{{ metal.label }}:
<div class="text-l mr-2 font-bold">{{ formatMetalTotal(metal) }}</div>
<BasicIcon
v-if="metal.metal_id === metalTotals[0]?.metal_id"
icon="vuesax-linear:info-circle"
size="18"
color="tertiary"
@click="$emit('openGoldModal')"
/>
</div>
</template>
<div class="flex mt-2 justify-center text-tertiary w-full z-20">
دارایی ریالی:
<div class="text-l mr-2 font-bold">{{ usePriceWithoutType(userStore?.userInfo?.wallet?.count_cash ?? 0) }} ریال</div>
<div class="text-l mr-2 font-bold">{{ usePriceWithoutType(cashWallet) }} ریال</div>
<BasicIcon @click="$emit('openRialModal')" icon="vuesax-linear:info-circle" size="18" color="tertiary" />
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { useUserStore } from '@/store/userStore'
import { computed, onMounted } from 'vue'
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
import {usePriceWithoutType} from "../../../../utils/usePrice";
import { isBoursecuProject } from '@/utils/config'
import { getMetalAssetLabel, getWeightUnit } from '@/utils/productDealMethod'
import { usePriceWithoutType } from '@/utils/usePrice'
import { useWalletAssets } from '@/composables/useWalletAssets'
import type { WalletMetalTotal } from '@/models/walletAssets'
const userStore = useUserStore()
const metalAssetLabel = computed(() => getMetalAssetLabel())
const weightUnit = computed(() => getWeightUnit())
const { assetsSummary, loadWalletAssets } = useWalletAssets()
defineEmits<{
openGoldModal: []
openRialModal: []
}>()
</script>
const meta = computed(() => assetsSummary.value?.meta)
const metalTotals = computed(() => assetsSummary.value?.metal_totals ?? [])
const primaryMetalTotal = computed(() => metalTotals.value[0])
const cashWallet = computed(() => assetsSummary.value?.cash_wallet ?? 0)
const inventoryCards = computed(() => assetsSummary.value?.inventory_cards ?? [])
const countBasedInventory = computed(() =>
(assetsSummary.value?.count_products ?? []).reduce((sum, item) => sum + Number(item.quantity ?? 0), 0)
)
onMounted(() => {
void loadWalletAssets()
})
function summaryMetalWeight(metal: WalletMetalTotal) {
if (inventoryCards.value.length > 0) {
return metal.product_weight
}
return metal.total_weight
}
function formatMetalTotal(metal: WalletMetalTotal) {
return `${summaryMetalWeight(metal)}${metal.unit}`
}
</script>
+44 -50
View File
@@ -5,50 +5,27 @@
<div class="w-full text-center font-bold">موجودی ها</div>
<div class="h-30vh overflow-y-auto">
<div class="mt-5">
<BasicInfoItem
<template v-for="metal in metalTotals" :key="metal.metal_id">
<BasicInfoItem
class="flex justify-between"
:title="`مجموعه کل دارایی ${settingsStore.metalTypeLabel}`"
:title="metal.label"
is-line
:info="`در این قسمت مجموع کل وزن ${settingsStore.metalTypeLabel} آبشده (${(walletInfo?.gold ?? 0)?.toFixed(3)}) + ارزش دارایی ها (${(walletInfo?.treasure_sum ?? 0)?.toFixed(3)} ) را مشاهده میفرمایید.`"
:infoHead="`مجموع کل دارایی ${settingsStore.metalTypeLabel}`"
:value="parseFloat((walletInfo?.gold_sum ?? 0).toFixed(2)) + ' ' + weightUnit"
:value="formatMetalTotal(metal)"
/>
<a-divider class="!my-1" />
</template>
<BasicInfoItem
class="flex justify-between"
title="دارایی کیف پول ریالی"
is-line
:value="usePrice(cashWallet)"
/>
<a-divider class="!my-1" />
<BasicInfoItem
class="flex justify-between"
title="دارایی کیف پول ریالی"
is-line
:value="usePrice(walletInfo?.cash ?? 0)"
/>
<a-divider class="!my-1" />
<BasicInfoItem
class="flex justify-between"
:title="`دارایی کیف پول ${settingsStore.metalTypeLabel}`"
is-line
:value="(walletInfo?.count_gold_wallet ?? 0) + ' ' + weightUnit"
/>
<a-divider v-if="nameProject === 'goldsun'" class="!my-1" />
<BasicInfoItem
v-if="nameProject === 'goldsun'"
class="flex justify-between"
title="دارایی کیف پول نقره"
is-line
:value="(walletInfo?.count_silver ?? 0) + ' گرم'"
/>
<a-divider v-if="nameProject === 'goldsun'" class="!my-1" />
<BasicInfoItem
v-if="nameProject === 'goldsun'"
class="flex justify-between"
title="دارایی کیف پول مس"
is-line
:value="(walletInfo?.count_copper ?? 0) + ' گرم'"
/>
<a-divider class="!my-1" />
<BasicInfoItem
class="flex justify-between"
title="معادل ریالی مجموع دارایی ها"
is-line
:value="usePrice(walletInfo?.count_cash_total ?? 0)"
class="flex justify-between"
title="معادل ریالی مجموع دارایی ها"
is-line
:value="usePrice(totalRialValue)"
/>
</div>
</div>
@@ -58,13 +35,12 @@
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { computed, onMounted, watch } from 'vue'
import BasicActionSheet from '@/components/BasicPacks/BasicActionSheet.vue'
import BasicInfoItem from '@/components/BasicPacks/BasicInfoItem.vue'
import { useConfigStore } from '@/store/configStore'
import { useSettingsStore } from '@/store/settingsStore'
import { getWeightUnit } from '@/utils/productDealMethod'
import {usePrice} from "@/utils/usePrice";
import { usePrice } from '@/utils/usePrice'
import { useWalletAssets } from '@/composables/useWalletAssets'
import type { WalletMetalTotal } from '@/models/walletAssets'
const props = defineProps<{
show: boolean
@@ -76,13 +52,31 @@ const emit = defineEmits<{
'update:show': [value: boolean]
}>()
const config = useConfigStore()
const nameProject = config.config.name
const settingsStore = useSettingsStore()
const weightUnit = computed(() => getWeightUnit())
const { assetsSummary, loadWalletAssets } = useWalletAssets()
const visible = computed({
get: () => props.show,
set: (val) => emit('update:show', val)
set: (val) => emit('update:show', val),
})
</script>
const metalTotals = computed(() => assetsSummary.value?.metal_totals ?? [])
const cashWallet = computed(() => assetsSummary.value?.cash_wallet ?? 0)
const totalRialValue = computed(() => assetsSummary.value?.total_rial_value ?? 0)
onMounted(() => {
void loadWalletAssets()
})
watch(
() => props.show,
(open) => {
if (open) {
void loadWalletAssets(true)
}
}
)
function formatMetalTotal(metal: WalletMetalTotal) {
return `${metal.total_weight} ${metal.unit}`
}
</script>
+2
View File
@@ -82,6 +82,7 @@ import {useWindowScroll} from '@vueuse/core'
import {loading, removeToken} from '@/utils'
import {useUserStore} from '@/store/userStore'
import {useWalletStore} from '@/store/walletStore'
import { useWalletAssets } from '@/composables/useWalletAssets'
import {useConfigStore} from '@/store/configStore'
import {useFundUserStore} from '@/store/fundStore'
import {usePrice, usePriceWithoutType} from '../../../utils/usePrice'
@@ -204,6 +205,7 @@ function copyCode() {
async function logout() {
userStore.userInfo = undefined
walletStore.walletInfo = undefined
useWalletAssets().clearWalletAssets()
removeToken()
await router.push({name: 'login'})
window.location.reload()
@@ -54,7 +54,7 @@
:show-search="false"
value-name="value"
:allow-clear="false"
:placeholder="isBuy?'نحوه خرید را انتخاب کنید':' نحوه فروش را انتخاب کنید'"
:placeholder="getProductDealMethodPlaceholder(isBuy)"
size="large"
:has-tooltip="false" />
</a-form-item>
@@ -103,7 +103,9 @@
<div v-else-if="isBuy && form.method === 'cash'" class="font-bold text-xs">
{{ cashWalletBalanceText }}
</div>
<div class="font-bold text-xs" v-else>{{ `موجودی محصول: ${getInventoryById(props?.ProductItem?.id)} ${getProductQuantityUnit(props?.ProductItem)}` }}
<div class="font-bold text-xs" v-else>
<div>{{ `موجودی محصول: ${getInventoryById(props?.ProductItem?.id)} ${getProductQuantityUnit(props?.ProductItem)}` }}</div>
<div v-if="isMetalReceiveDeal" class="mt-1">{{ sellMetalWalletBalanceText }}</div>
</div>
</Transition>
<Transition mode="out-in" name="fade">
@@ -225,10 +227,15 @@
</div>
<div class="flex justify-between mt-3">
<div>{{ isBuy ? 'قیمت قابل پرداخت:' : 'مبلغ دریافتی:' }}</div>
<div>{{ isBuy ? 'قیمت قابل پرداخت:' : (isMetalReceiveDeal ? 'دریافت:' : 'مبلغ دریافتی:') }}</div>
<div class="flex items-center">
<div>{{ usePriceWithoutType(form.goldCash ?? 0) }}</div>
<div class="text-xs mr-1">ریال</div>
<template v-if="!isBuy && isMetalReceiveDeal">
<div>{{ sellReceivedMetalText }}</div>
</template>
<template v-else>
<div>{{ usePriceWithoutType(form.goldCash ?? 0) }}</div>
<div class="text-xs mr-1">ریال</div>
</template>
</div>
</div>
@@ -269,9 +276,13 @@ import { useFundUserStore } from '@/store/fundStore'
import {
getDefaultProductDealMethod,
getProductDealMethodOptions,
getProductDealMethodPlaceholder,
formatCashWalletBalanceText,
formatGoldWalletBalanceText,
formatMainMetalWalletBalanceText,
formatMainMetalReceiveText,
calcSellReceivedMetalWeight,
isMainMetalWalletDealMethod,
formatProductWeightAmount,
getProductQuantityUnit,
getProductTotalWeightLabel,
@@ -286,7 +297,17 @@ import {
productMinOrderCash
} from '@/utils/productOrderLimit'
const typeDeal = computed(() => getProductDealMethodOptions(props?.ProductItem?.group_type))
const typeDeal = computed(() => getProductDealMethodOptions(props?.ProductItem?.group_type, isBuy.value))
const isMetalReceiveDeal = computed(() =>
!isBuy.value && isMainMetalWalletDealMethod(form.value.method)
)
const sellReceivedMetalText = computed(() =>
formatMainMetalReceiveText(
calcSellReceivedMetalWeight(form.value.goldValue, props?.ProductItem)
)
)
const productGroupType = computed(() => props?.ProductItem?.group_type)
const isCountBasedProductItem = computed(() => isCountBasedProduct(props?.ProductItem))
@@ -314,6 +335,10 @@ const buyMetalWalletBalanceText = computed(() =>
: goldWalletBalanceText.value
)
const sellMetalWalletBalanceText = computed(() =>
formatMainMetalWalletBalanceText(walletStore?.walletInfo?.gold ?? 0)
)
const cashWalletBalanceText = computed(() =>
formatCashWalletBalanceText(
usePriceWithoutType(walletStore?.walletInfo?.cash ?? 0),
@@ -339,6 +364,7 @@ interface Prop {
}
const props = withDefaults(defineProps<Prop>(), {})
const emit = defineEmits<{ ordered: [] }>()
const isBuy = ref<boolean>(true)
const buyTotalPrice = computed(() => {
const item = props?.ProductItem
@@ -520,7 +546,7 @@ const form = ref<Gold>({
})
function resetDealMethod() {
form.value.method = getDefaultProductDealMethod(props?.ProductItem?.group_type)
form.value.method = getDefaultProductDealMethod(props?.ProductItem?.group_type, isBuy.value)
}
watch(
@@ -772,20 +798,21 @@ async function ok() {
method: form.value.method,
number: form.value.goldValue ?? 0
})
confirmAction.value = false
emit('ordered')
await userStore.getMyInfo()
await walletStore.getMyWallet()
await fundStore.getMyFund()
message.success('سفارش شما با موفقیت انجام شد')
await router.push({ name: 'transactions' })
form.value = {
goldValue: undefined,
goldCash: undefined,
percentWallet: undefined,
method: getDefaultProductDealMethod(props?.ProductItem?.group_type)
method: getDefaultProductDealMethod(props?.ProductItem?.group_type, isBuy.value)
}
// refreshTable()
await fundStore.getMyFund()
message.success('سفارش شما با موفقیت انجام شد')
} catch (e) {
// console.log(e)
// await initPrice()
} finally {
loading.value = false
infoVisible.value = false
@@ -11,7 +11,7 @@
<!-- <div v-if="props.ProductItem.group_type!='آبشده'" class="text-secondary font-500">{{ props.ProductItem.amount }}گرم</div>-->
<!-- <div v-else class="text-secondary font-500">حداقل خرید یک گرم</div>-->
<!-- <div>{{usePrice((props.ProductItem.price ?? 0) + (props.ProductItem.cash_fee_buy ?? 0))}}</div>-->
<div v-if="props.ProductItem.group_type=='آبشده'">{{usePrice(goldPriceValue)}}</div>
<div v-if="isMeltedTradeGroup(props.ProductItem.group_type)">{{usePrice(goldPriceValue)}}</div>
<div v-else>{{usePrice(price)}}</div>
<!-- <div v-if="props.ProductItem.group_type!='آبشده'" class="text-xs text-gray-400">شامل 33 هزار تومان اجرت</div>-->
<!-- <div v-else class="text-xs text-gray-400">محاسبه بر اساس قیمت روز</div>-->
@@ -33,6 +33,7 @@ import {usePrice} from '@/utils/usePrice';
import {getFileUrl} from '@/utils/file';
import {computed, ref} from "vue";
import { getProductBuyPrice } from '@/utils/productPrice'
import { isMeltedTradeGroup } from '@/utils/productCategories'
interface Prop {
ProductItem: Product
@@ -58,6 +59,8 @@ const defaultImages: Record<string, string> = {
'مس': mesImg,
'نقره': noghrehImg,
'سکه پارسیان': parsianImg,
'کاتد مس': defaultImg,
'طلا': defaultImg,
}
const displayImage = computed(() => {
@@ -111,7 +114,7 @@ const goldPriceValue = computed(() => getProductBuyPrice(props.ProductItem))
<div class="m-1 flex flex-col gap-1 justify-center">
<div class="text-base font-500">{{ props.ProductItem.title }}</div>
<br>
<div v-if="props.ProductItem.group_type=='آبشده'">{{usePrice(goldPriceValue)}}</div>
<div v-if="isMeltedTradeGroup(props.ProductItem.group_type)">{{usePrice(goldPriceValue)}}</div>
<div v-else>{{usePrice(price)}}</div>
</div>
</div>
+17 -5
View File
@@ -30,16 +30,16 @@
<!-- </BasicActionSheet>-->
<BasicActionSheet placement="bottom" v-model:show="showFilter">
<div class="">
<indexGold v-if="['آبشده'].includes(selectedProduct?.group_type) && !isBoursecuProject()"
<div v-if="showFilter" :key="orderSheetKey">
<indexGold v-if="isMeltedTradeGroup(selectedProduct?.group_type)"
:ProductItem="selectedProduct"
>
</indexGold>
<CopperSilver v-else-if="['مس','نقره'].includes(selectedProduct?.group_type) && !isBoursecuDealProductGroup(selectedProduct?.group_type)"
<CopperSilver v-else-if="isMetalCommodityGroup(selectedProduct?.group_type) && !isBoursecuDealProductGroup(selectedProduct?.group_type)"
:ProductItem="selectedProduct"
>
</CopperSilver>
<DealProduct v-else :ProductItem="selectedProduct"></DealProduct>
<DealProduct v-else :ProductItem="selectedProduct" @ordered="onProductOrdered"></DealProduct>
</div>
</BasicActionSheet>
@@ -105,12 +105,13 @@ import { cloneDeep } from 'lodash'
import img from "@/assets/img/user_ly1.svg";
import BasicModal from "@/components/BasicPacks/BasicModal.vue";
import { isProductPriceInactive } from '@/utils/productPrice'
import { isBoursecuProject } from '@/utils/config'
import { isMetalCommodityGroup, isMeltedTradeGroup } from '@/utils/productCategories'
import { isBoursecuDealProductGroup } from '@/utils/productDealMethod'
import { loadServiceFeeFromSettings } from '@/utils/serviceFee'
const activekey = ref('طلا' ||'آبشده')
const showFilter = ref(false)
const orderSheetKey = ref(0)
const selectedProduct = ref<Product>()
const closeTime = ref<string>('')
const openTime = ref<string>('')
@@ -137,10 +138,21 @@ function clickProduct(item?: Product) {
return
}
orderSheetKey.value += 1
selectedProduct.value = cloneDeep(item)
showFilter.value = true
}
function onProductOrdered() {
showFilter.value = false
}
watch(showFilter, (open) => {
if (!open) {
orderSheetKey.value += 1
}
})
function changeTab() {
if (activekey.value != 'همه') {
items.value = firstItems.value?.filter((val) =>