1404/10/28-base

This commit is contained in:
2026-01-18 13:01:46 +03:30
parent f95b0cef95
commit 9d96ae106b
455 changed files with 58164 additions and 0 deletions
+11
View File
@@ -0,0 +1,11 @@
<script lang="ts" setup>
</script>
<template>
<div class="text-center">صفحه مورد نظر یافت نشد</div>
</template>
<style scoped>
</style>
@@ -0,0 +1,9 @@
<svg width="428" height="331" viewBox="0 0 428 331" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="428" height="331" transform="matrix(1 0 0 -1 0 331)" fill="url(#paint0_linear_455_10939)"/>
<defs>
<linearGradient id="paint0_linear_455_10939" x1="214" y1="0" x2="214" y2="331" gradientUnits="userSpaceOnUse">
<stop stop-color="white" stop-opacity="0"/>
<stop offset="1" stop-color="white"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 438 B

+169
View File
@@ -0,0 +1,169 @@
<template>
<div>
<div class="bg-white wrap-fix z-200001 py-3 px-3 text-primary font-bold drop-shadow flex">
<div @click="router.back()" class="cursor-pointer">
<BasicIcon icon="vuesax-linear:arrow-right-1" />
</div>
<div class="mr-2">درباره ما</div>
</div>
<div class="pt-20">
<div>
<img :src="img" alt="" class="mt-2 w-full absolute bottom-0" />
</div>
<div class="text-justify text-base z-200000 relative">
<div class="px-10">
<!-- <img :src="logoFull" class="mb-20 mt-5" />-->
<div class="overflow-y-auto h-65vh">
<div class="bg-primary text-white rounded-[12px] p-4 text-xs leading-5">
<div class="w-full h-1px my-3 bg-tertiary"></div>
<div>
طلا علاوه بر کاربرد در ساخت زیورآلات، از دوران کهن به عنوان یک فلز ارزشمند و دارایی
مقاوم در برابر تورم شناخته می‌شود، به طوری که سرمایه‌گذاران حرفه‌ای همواره بخشی از
سبد سرمایه‌گذاری‌شان را به طلا اختصاص می‌دهند.
</div>
<div class="mt-3">
با وجود گسترش فناوری‌های نوین در همه حوزه‌ها، ما در شرکت پخش طلای حاجی ابوالفتح با
تلفیق تجربه سنتی خود در بازار طلا و با دانش تخصصی خود و با بهره‌گیری از سوابق موفق
قبلی در حوزه فینتک، اقدام به ایجاد گلد نمودیم.
</div>
<div class="mt-3">
مهم‌ترین ارزش پیشنهادی گلد، امکان پس انداز تدریجی طلا با سرمایه‌های خرد و بدون
پرداخت هزینه‌های جانبی است و در این راستا گلد دات آی آر تمام تلاش خود را نموده است تا از
ابتدای سال 1401 با رونمایی محصول اولیه، برای همه افراد با هر سطحی از دارایی، بستری
امن و مطمئن ایجاد نماید.
</div>
<div class="mt-3">
علاوه بر این گلد به عنوان یک واحد فناور از سال 1403 با رونمایی نسخه کاملا آنلاین
و نرم افزاری وارد فاز جدیدی از خرید و فروش طلای آب شده، شده است.
</div>
<div class="w-full h-1px my-3 bg-tertiary"></div>
</div>
</div>
</div>
<div class="wrap-fix bottom-0 px-10 py-6 flex gap-2 bg-white">
<a class="w-full" href="tel:09123113112">
<BasicButton class="w-full" type="primary">تماس با پشتیبانی</BasicButton>
</a>
<a href="https://t.me/saminn_gold">
<img src="@/assets/img/telegram.png" alt="" class="h-10 w-10"/>
</a>
</div>
</div>
</div>
<!-- <ActionSheet v-model:show="editPassVisible">salam</ActionSheet>-->
</div>
</template>
<script lang="ts" setup>
import { onMounted, reactive, ref } from 'vue'
import img from '@/assets/img/user_ly1.svg'
import gr_bottom from './assets/img/gr_bottom_white.svg'
import { loading } from '@/utils'
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
import BasicActionSheet from '@/components/BasicPacks/BasicActionSheet.vue'
import { lengthValidation, required } from '@/utils/inputRules'
import BasicInput from '@/components/BasicPacks/BasicInput.vue'
import type { User } from '@/models/login'
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
import router from '@/router'
import type { FormInstance } from 'ant-design-vue'
import { message } from 'ant-design-vue'
import { updateMe } from '@/api/me'
import { useUserStore } from '@/store/userStore'
import BaseDatePicker from '@/components/BasicPacks/BaseDatePicker'
import img_pattern from "@/views/login/assets/img/pattern.svg";
const userFormState = ref<User>({
fname: '',
lname: '',
mobile: undefined,
birth_date: '',
phone_number: '',
province: '',
city: '',
n_code: undefined
})
const formRef = ref<FormInstance>()
const userStore = useUserStore()
// const editPassVisible = ref<boolean>(false)
const editPassVisible = ref<boolean>(false)
function setForm() {
userFormState.value = userStore.userInfo
}
function copyCode() {
// nextTick(() => {
const val = userStore.userInfo?.referral_id
navigator.clipboard.writeText(val)
message.info('کد رونوشت شد')
// })
}
function shareCode() {
// nextTick(() => {
const val = `⭐️الان طلا بخر؛ آخر ماه سودشو ببر!
با خرید طلای آبشده در مقدارهای کم ولی مستمر، سود بیشتری ببر!
این دعوت نامه از طرف "${userStore.userInfo?.name}" عزیز برای شما ارسال شده تا شما هم از بازار طلای گلد دات آی آر جا نمونید.
روی لینک زیر کلیک کنید و ثبت نام خود را تکمیل کنید.
gold.ir/login?id=${userStore.userInfo?.referral_id}`
navigator.share({
title: 'گلد دات آی آر',
text: val
})
// message.info('کد رونوشت شد')
// })
}
const resetData = () => {
formRef.value?.resetFields()
userFormState.value = {
fname: '',
lname: '',
mobile: undefined,
birth_date: '',
phone_number: '',
province: '',
city: '',
n_code: undefined
}
}
onMounted(() => {
setForm()
})
function ok() {
formRef.value?.validateFields().then(async () => {
try {
loading.value = true
await updateMe(userFormState.value)
await userStore.getMyInfo()
editPassVisible.value = false
message.success('اطلاعات شما با موفقیت به روز رسانی شد')
} catch (e) {
console.log(e)
} finally {
loading.value = false
}
})
}
</script>
<style scoped>
/*.fade-enter-active,
.fade-leave-active {
transition: opacity 0.2s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}*/
/*.trans{
transition: height 1s;
}*/
</style>
+156
View File
@@ -0,0 +1,156 @@
<template>
<div @click="infoVisible = true" class="shadow mb-2 p-2 rounded-lg">
<div class="flex justify-between">
<div>
<div class="font-semibold text-base mb-2">{{item.address }}</div>
</div>
</div>
<div class="flex flex-col gap-2 mt-2">
<BasicInfoItem is-line title="استان" :value="item.province"/>
<BasicInfoItem is-line title="شهر" :value="item.city"/>
<BasicInfoItem is-line title="کد پستی" :value="item.zip"/>
<BasicInfoItem is-line title="شماره تلفن" :value="item.phone"/>
</div>
<a-divider class="!my-3" />
<div class="flex justify-between mt-1">
<div class="mb-2">{{toJalali(item.created_at)}}</div>
<div class="flex gap-2 ">
<BasicIcon color="red" icon="vuesax-linear:trash" @click.stop="deleteConfirmVisible = true" class="p-1"/>
<BasicIcon color="green" icon="vuesax-linear:edit" @click.stop="emits('edit',item)" class="p-1"/>
</div>
</div>
</div>
<!-- <teleport to="app">-->
<DialogVant v-model:show="deleteConfirmVisible" teleport="body" :closeOnClickOverlay="false" :timeOut="-1">
<!-- <template v-slot:img>
<img :src="registerDelayImage" alt="" class="opacity-80">
</template>-->
<template v-slot:title>
<div class="flex flex-col items-center">
<div class="p-5 text-sm">
آیا از حذف آدرس اطمینان دارید؟
</div>
</div>
</template>
<template v-slot:button>
<div class="text-center text-red flex items-center justify-center" @click="deleteItem">
<a-spin :spinning="deleteLoading" size="small">
تایید
</a-spin>
</div>
<div class="text-center" @click="deleteConfirmVisible = false">
انصراف
</div>
</template>
</DialogVant>
<!-- </teleport>-->
</template>
<script lang="ts" setup>
import { computed, onMounted, ref } from 'vue'
import { toJalali } from '../../../../utils/useDateTime'
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
import BasicInfoItem from '@/components/BasicPacks/BasicInfoItem.vue'
import DialogVant from '@/components/DialogVant.vue'
import { updatePriceTrigger } from '@/api/triggerPrice'
import { loading } from '@/utils'
import type { Address } from '@/models/address'
import { deleteAddress } from '@/api/address'
const infoVisible = ref<boolean>(false)
const isActive = ref<boolean>(false)
const deleteLoading = ref(false)
const deleteConfirmVisible = ref(false)
interface Prop {
item: Address
}
function changeActive(val: boolean) {
console.log(val)
try {
loading.value = true
updatePriceTrigger(props?.item.id, {is_active: val})
} catch (e) {
console.log(e)
isActive.value = !isActive.value
} finally {
loading.value = false
}
}
function returnPriceCondition(val: string) {
switch (val) {
case '==': return 'مساوی'
case '<': return 'کوچکتر'
// case '==': return 'مساوی'
}
/* if (val === '=='){
return 'مساوی'
} else if (val === '<'){
return 'کوچکتر'
}*/
}
async function deleteItem() {
try {
deleteLoading.value = true
await deleteAddress(props.item.id)
deleteConfirmVisible.value = false
emits('refresh')
} catch (e) {
console.log(e)
} finally {
deleteLoading.value = false
}
}
function returnAction(val: string) {
switch (val) {
case 'sms': return 'پیامک'
case 'email': return 'ایمیل'
case 'notify': return 'نوتیفیکیشن'
// case '==': return 'مساوی'
}
/* if (val === '=='){
return 'مساوی'
} else if (val === '<'){
return 'کوچکتر'
}*/
}
const props = withDefaults(defineProps<Prop>(), {})
const emits = defineEmits(['edit','refresh'])
/*const title = computed(() => {
if (isUp.value) {
if (isGold.value) {
return 'واریز ریالی'
} else {
return 'خرید طلا'
}
} else {
if (isGold.value) {
return 'برداشت ریالی'
} else {
return 'فروش طلا'
}
}
})*/
</script>
<style scoped>
</style>
@@ -0,0 +1,150 @@
<template>
<div >
<a-form ref="formRef" :model="address" class="!mt-5" name="basic"
@finish="ok()">
<div class="font-bold text-lg mb-2">آدرس</div>
<div class="flex flex-col gap-4 pb-30 w-full h-65vh overflow-y-auto">
<a-form-item label="استان" name="province" :rules="[required()]">
<BasicSelect
v-model:value="address.province"
:items="provinceList"
@change="changeProvince"
valueName="title"
keyName="title"
/>
</a-form-item>
<a-form-item label="شهر" name="city" :rules="[required()]">
<BasicSelect
:disabled="!cityList"
v-model:value="address.city"
valueName="title"
:items="cityList"
keyName="title"
/>
</a-form-item>
<a-form-item
label="کد پستی" name="zip" :rules="[required()]">
<BasicInput placeholder="کد پستی را وارد نمایید" v-model:value="address.zip" />
</a-form-item>
<a-form-item
label="تلفن تماس" name="phone" :rules="[required()]"
>
<BasicInput placeholder="تلفن تماس را وارد نمایید" v-model:value="address.phone" />
</a-form-item>
<!-- <FormItem label="کد پستی" name="">
<Input placeholder="کد پستی را وارد نمایید" />
</FormItem>-->
<a-form-item
label="آدرس کامل"
name="address"
:rules="[required()]"
>
<BasicTextArea placeholder="آدرس کامل را وارد نمایید" v-model:value="address.address" />
</a-form-item>
</div>
</a-form>
<div class="absolute bottom-18 right-0 w-full p-4 bg-white flex justify-center !text-white ">
<BasicButton class=" w-full !text-white " type="primary" @click="handleOk">ثبت آدرس
</BasicButton>
</div>
</div>
</template>
<script setup lang="ts">
import {required} from "@/utils/inputRules";
import BasicSelect from "@/components/BasicPacks/BasicSelect.vue";
import BasicButton from "@/components/BasicPacks/BasicButton.vue";
import BasicInput from "@/components/BasicPacks/BasicInput.vue";
import BasicTextArea from "@/components/BasicPacks/BasicTextArea.vue";
import {loading} from "@/utils";
import {createAddress, getCity, getProvince, updateAddress} from "@/api/address";
import {FormInstance, message} from "ant-design-vue";
import {Address} from "@/models/address";
import {createPriceTrigger, updatePriceTrigger} from "@/api/triggerPrice";
import {onMounted, ref} from "vue";
const formRef = ref<FormInstance>()
const provinceList = ref<any[]>([])
const cityList = ref<any[]>()
const emits = defineEmits([ 'onOk'])
const addAddressVisible=ref<boolean>(false)
const editId = ref<number | undefined>(undefined)
const address = ref<Address>({
city: '',
province: '',
phone: '',
address: '',
zip: '',
default_address: false
})
function resetFields() {
editId.value = undefined
address.value = {
city: '',
province: '',
phone: '',
address: '',
zip: '',
default_address: false
}
}
onMounted(async () => {
resetFields()
provinceList.value = await getProvince()
})
const handleOk = (e: MouseEvent) => {
formRef.value?.validate().then(async () => {
editId.value ? await updateAddress(editId.value, address.value) : await createAddress(address.value)
addAddressVisible.value = false
message.success('آدرس با موفقیت ثبت شد')
emits('onOk')
resetFields()
})
.catch((error) => {
console.log('error', error)
})
}
const changeProvince = async (obj: any) => {
try {
loading.value = true
cityList.value = undefined
address.value.city = undefined
cityList.value = await getCity(obj.id)
} catch (e) {
message.error('خطا در دریافت شهرها')
} finally {
loading.value = false
}
}
async function ok() {
formRef.value?.validateFields().then(async () => {
try {
loading.value = true
editId.value ? await updatePriceTrigger(editId.value, address.value) : await createPriceTrigger(address.value)
message.success('آدرس با موفقیت ایجاد شد')
addAddressVisible.value = false
emits('onOk')
//
} catch (e) {
console.log(e)
} finally {
loading.value = false
}
})
}
</script>
<style scoped>
</style>
+242
View File
@@ -0,0 +1,242 @@
<template>
<div>
<div class="bg-white py-3 px-3 text-primary font-bold drop-shadow wrap-fix flex z-10">
<div @click="router.back()">
<BasicIcon icon="vuesax-linear:arrow-right-1" />
</div>
<div class="mr-2">آدرس ها</div>
</div>
<div>
<img :src="img" alt="" class="mt-2 w-full absolute bottom-0" />
</div>
<!-- <a-spin :spinning="loading">-->
<div ref="el" :class="loading? 'h-screen': ''" class="px-3 pt-16 pb-2 overflow-y-scroll"
style="max-height: calc(100vh - 50px)">
<list-anim v-if="!loading" class="pb-12vh">
<Item v-for="item in items" :key="item.id" :item="item" @edit="openEdit" @refresh="initItems" />
<!-- <TransactionSkeleton v-if="loadingMore" class="mt-1 mb-8" />-->
</list-anim>
<div v-if="loading">
<TransactionSkeleton v-for="i in 13" :key="i" class="mt-1" />
</div>
</div>
<!-- </a-spin>-->
<BasicActionSheet v-model:show="addAddressVisible" teleport="body">
<a-form ref="formRef" :model="address" class="!mt-5" name="basic"
@finish="ok()">
<div class="font-bold text-lg mb-2">آدرس</div>
<div class="flex flex-col gap-4 pb-20 w-full h-65vh overflow-y-auto">
<a-form-item label="استان" name="province" :rules="[required()]">
<BasicSelect
v-model:value="address.province"
:items="provinceList"
@change="changeProvince"
valueName="title"
keyName="title"
/>
</a-form-item>
<a-form-item label="شهر" name="city" :rules="[required()]">
<BasicSelect
:disabled="!cityList"
v-model:value="address.city"
valueName="title"
:items="cityList"
keyName="title"
/>
</a-form-item>
<a-form-item
label="کد پستی" name="zip" :rules="[required()]">
<BasicInput placeholder="کد پستی را وارد نمایید" v-model:value="address.zip" />
</a-form-item>
<a-form-item
label="تلفن تماس" name="phone" :rules="[required()]"
>
<BasicInput placeholder="تلفن تماس را وارد نمایید" v-model:value="address.phone" />
</a-form-item>
<!-- <FormItem label="کد پستی" name="">
<Input placeholder="کد پستی را وارد نمایید" />
</FormItem>-->
<a-form-item
label="آدرس کامل"
name="address"
:rules="[required()]"
>
<BasicTextArea placeholder="آدرس کامل را وارد نمایید" v-model:value="address.address" />
</a-form-item>
</div>
<BasicButton class="absolute bottom-20 w-full !text-white" type="primary" @click="handleOk">ثبت آدرس
</BasicButton>
</a-form>
</BasicActionSheet>
<!-- <div class="bg-primary w-3rem h-3rem flex items-center justify-center rounded-lg fixed bottom-12vh left-8vw"
@click="openAdd()">
<BasicIcon icon="vuesax-linear:add" color="white" />
</div>-->
<Transition mode="out-in" name="fade">
<div
class="wrap-fix bottom-0 h-[16vh] bg-[#FBFBFC] shadow-lg rounded-3xl flex justify-center pt-3 z-200"
style="box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 26px 11px"
@click="openAdd()">
<BasicIcon icon="vuesax-linear:add" />
<div>افزودن آدرس جدید</div>
</div>
</Transition>
</div>
</template>
<script lang="ts" setup>
import { createPriceTrigger, getPriceTriggers, updatePriceTrigger } from '@/api/triggerPrice'
const radioStyle = reactive({
display: '',
height: '30px',
lineHeight: '30px'
})
import type { SelectItem } from '@/models/SelectItem'
// import Item from "./components/Item.vue";
/*import {lengthValidation, required} from "@/utils/inputRules";
import {loading} from "@/utils";
import BasicButton from "@/components/BasicPacks/BasicButton.vue";
import BasicActionSheet from "@/components/BasicPacks/BasicActionSheet.vue";
import BasicInput from "@/components/BasicPacks/BasicInput.vue";*/
import { onMounted, reactive, ref } from 'vue'
import type { TableEngineInput, TableOutput } from '@/models/table'
import { loading, loadingMore } from '@/utils'
// import {getOrders} from "@/api/order";
import { getTransactionTable } from '@/api/transaction'
import type { Transaction } from '@/models/transaction'
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
import BasicActionSheet from '@/components/BasicPacks/BasicActionSheet.vue'
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
import BaseDatePicker from '@/components/BasicPacks/BaseDatePicker/src/BaseDatePicker.vue'
import { useInfiniteScroll, useScroll } from '@vueuse/core'
import ListAnim from '@/components/ListAnim.vue'
import TransactionSkeleton from '@/components/TransactionSkeleton.vue'
import { DotLottieVue } from '@lottiefiles/dotlottie-vue'
import { mobileValidation, required } from '@/utils/inputRules'
import BasicInput from '@/components/BasicPacks/BasicInput.vue'
import type { User } from '@/models/login'
import { type FormInstance, message } from 'ant-design-vue'
import type { PriceTrigger } from '@/models/PriceTrigger'
import BasicSelect from '@/components/BasicPacks/BasicSelect.vue'
import Item from './components/Item.vue'
import { cloneDeep } from 'lodash'
import router from '@/router'
import type { Address } from '@/models/address'
import { createAddress, getCity, getProvince, tableAddress, updateAddress } from '@/api/address'
import BasicTextArea from '@/components/BasicPacks/BasicTextArea.vue'
import img from "@/assets/img/user_ly1.svg";
const provinceList = ref<any[]>([])
const cityList = ref<any[]>()
const items = ref<PriceTrigger[]>([])
const addAddressVisible = ref<boolean>(false)
const editId = ref<number | undefined>(undefined)
const el = ref()
const address = ref<Address>({
city: '',
province: '',
phone: '',
address: '',
zip: '',
default_address: false
})
const formRef = ref<FormInstance>()
onMounted(async () => {
await initItems()
provinceList.value = await getProvince()
})
function resetFields() {
editId.value = undefined
address.value = {
city: '',
province: '',
phone: '',
address: '',
zip: '',
default_address: false
}
}
function openAdd() {
resetFields()
editId.value = undefined
addAddressVisible.value = true
}
const handleOk = (e: MouseEvent) => {
formRef.value?.validate().then(async () => {
editId.value ? await updateAddress(editId.value, address.value) : await createAddress(address.value)
await initItems()
addAddressVisible.value = false
message.success('آدرس با موفقیت ثبت شد')
resetFields()
})
.catch((error) => {
console.log('error', error)
})
}
async function initItems() {
try {
items.value = []
const data = await tableAddress({ page: 0, limit: 150 })
items.value = data.rows
// console.log(items.value)
} catch (e) {
console.log(e)
} finally {
loading.value = false
loadingMore.value = false
}
}
const changeProvince = async (obj: any) => {
try {
loading.value = true
cityList.value = undefined
address.value.city = undefined
cityList.value = await getCity(obj.id)
} catch (e) {
message.error('خطا در دریافت شهرها')
} finally {
loading.value = false
}
}
function openEdit(val: PriceTrigger) {
address.value = cloneDeep(val)
editId.value = address.value.id
addAddressVisible.value = true
}
async function ok() {
formRef.value?.validateFields().then(async () => {
try {
loading.value = true
editId.value ? await updatePriceTrigger(editId.value, address.value) : await createPriceTrigger(address.value)
message.success('آدرس با موفقیت ایجاد شد')
await initItems()
addAddressVisible.value = false
//
} catch (e) {
console.log(e)
} finally {
loading.value = false
}
})
}
</script>
<style scoped>
</style>
@@ -0,0 +1,37 @@
<template>
<div class="border-solid border-1 border-[#E5E7EB] p-2 mt-3 rounded-[8px]">
<div>
<div class="flex items-center justify-between">
<div class="font-bold">{{item.name}}</div>
<div class="flex text-[#9CA3AF]">
<div>{{toJalaliNotime(item.created_at)}}</div>
<BasicIcon icon="vuesax-linear:calendar" class="w-4 h-4 content-center mr-1" />
</div>
</div>
<div class="flex items-center justify-between">
<div class="mt-2 rounded-[8px] p-2 text-xs" :class="item.is_legal === 0? 'bg-red-100 text-red-600':'bg-green-100 test-green-600'">{{item.is_legal === 0? 'احراز هویت نشده':'احراز هویت شده'}}</div>
<div class="flex text-[#9CA3AF]">
<div>{{toJalali(item.created_at, 'HH:mm')}}</div>
<BasicIcon icon="vuesax-linear:clock" class="w-4 h-4 mr-1" />
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
import type { User } from '@/models/login'
import { toJalali, toJalaliNotime } from '../../../../utils/useDateTime'
interface Prop {
item: User
}
const props = defineProps<Prop>()
</script>
<style scoped>
</style>
@@ -0,0 +1,41 @@
<template>
<div class="border-solid border-1 border-[#E5E7EB] p-2 mt-3 rounded-[8px]">
<div>
<div class="flex items-center justify-between">
<div class="font-bold">{{item.customer.name}}</div>
<div class="flex text-[#9CA3AF]">
<div>{{toJalaliNotime(item.created_at)}}</div>
<BasicIcon icon="vuesax-linear:calendar" class="w-4 h-4 content-center mr-1" />
</div>
</div>
<div class="flex items-center justify-between">
<div class="flex items-center">
<div>مبلغ پاداش :</div>
<div class="mr-4">{{item.gold}}</div>
</div>
<!-- <div class="mt-2 rounded-[8px] p-2 text-xs" :class="item.is_legal === 0? 'bg-red-100 text-red-600':'bg-green-100 test-green-600'">{{item.is_legal === 0? 'احراز هویت نشده':'احراز هویت شده'}}</div>-->
<div class="flex text-[#9CA3AF]">
<div>{{toJalali(item.created_at, 'HH:mm')}}</div>
<BasicIcon icon="vuesax-linear:clock" class="w-4 h-4 mr-1" />
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
import { toJalali, toJalaliNotime } from '../../../../utils/useDateTime'
import type { Gifts } from '@/models/gifts'
interface Prop {
item: Gifts
}
const props = defineProps<Prop>()
</script>
<style scoped>
</style>
+161
View File
@@ -0,0 +1,161 @@
<template>
<div>
<div class="bg-white w-full py-3 px-3 text-primary font-bold drop-shadow flex">
<div @click="router.back()">
<BasicIcon icon="vuesax-linear:arrow-right-1" />
</div>
<div class="mr-2">کسب درآمد</div>
</div>
</div>
<div class="p-4">
<div class="text-center p-3 border-solid border-1 rounded-[8px] border-[#0A1B37] ">
<div class="flex items-center">
<div class=" bg-[#DBEAFE] h-10 w-10 rounded-100% flex justify-center items-center">
<img :src="coin" />
</div>
<div class="mr-4">
<div class="flex ">
<div class="font-bold">دعوت دوستان</div>
<!-- <div class="text-xs ">راهنمای کسب درآمد</div>-->
</div>
<div class="text-center mt-2 text-xs">هر دعوت موفق 10 سوت طلا هدیه</div>
</div>
</div>
<div class="flex justify-center mt-4">
<div class="text-[10px] content-center ">کد بازاریابی</div>
<div class="mr-2 font-bold">{{userStore.userInfo.referral_id}}</div>
</div>
<div class="flex mt-4 gap-2">
<BasicButton icon="vuesax-linear:share" size="small" class="flex-1" icon-size="18" @click.stop="shareCode()">
اشتراک گذاری
</BasicButton>
<BasicButton icon="vuesax-linear:copy" size="small" class="flex-1" icon-size="18" @click.stop="copyCode()">
رونوشت
</BasicButton>
</div>
</div>
<div class="grid grid-cols-2 gap-4 mt-4 ">
<div class="text-center bg-[#DBEAFE] p-2 rounded-[8px]">
<div class="font-bold text-[#2563EB] text-md">
{{data?.usersSum}} عدد
</div>
<div class="text-xs text-[#2563EB] mt-2">تعداد زیر مجموعه</div>
</div>
<div class="text-center bg-[#FEF9C3] p-2 rounded-[8px]">
<div class="font-bold text-[#CA8A04] text-md">
{{data?.giftsSum}} سوت
</div>
<div class="text-xs text-[#CA8A04] mt-2">میزان کل پاداش ها</div>
</div>
</div>
<div class="flex justify-evenly w-full px-2 h-11 items-center bg-gray-50 relative rounded-lg mt-6 ">
<div :class="isTransaction?'text-primary bg-white h-8 w-1/2 rounded-lg':'text-gray-400'" class="w-full text-center z-2 flex items-center justify-center"
@click.stop="setIsTransaction(true) ">
پاداش ها
</div>
<div :class="!isTransaction?'text-primary bg-white h-8 w-1/2 rounded-lg':'text-gray-400'" class="w-full text-center z-2 flex items-center justify-center"
@click.stop="setIsTransaction(false) ">
فهرست زیر مجموعه
</div>
</div>
<!-- //**************************************-->
<!-- <div class="flex mt-6">-->
<!-- <div class="bg-[#0A1B37] p-2 rounded-[8px] w-full">-->
<!-- <div class="text-white text-center">فهرست زیرمجموعه</div>-->
<!-- </div>-->
<!-- <div class="bg-[#0A1B37] p-2 rounded-[8px] w-full mr-2">-->
<!-- <div class="text-white text-center">پاداش ها</div>-->
<!-- </div>-->
<!-- </div>-->
<div class="border-solid border-1 border-[#E5E7EB] mt-6 "></div>
<div v-if="isTransaction">
<GiftCard v-for="(val,i) in data?.gifts" :key="i" :item="val"/>
</div>
<div v-else>
<EarnCard v-for="(val,i) in data?.users" :key="i" :item="val"/>
</div>
</div>
</template>
<script lang="ts" setup>
import router from '@/router'
import coin from '@/assets/img/coin.png'
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
import { useUserStore } from '@/store/userStore'
import { type FormInstance, message } from 'ant-design-vue'
import { onMounted, reactive, ref } from 'vue'
import type { EarnMoney } from '@/models/earnMoney'
import { loading } from '@/utils'
import { getEarnMoney } from '@/api/earnMoney'
import EarnCard from '@/views/base/earnMoney/components/EarnCard.vue'
import TransactionCard from '@/views/base/transactions/components/Item.vue'
import GiftCard from '@/views/base/earnMoney/components/GiftCard.vue'
const data = ref<EarnMoney>()
const userStore = useUserStore()
const isTransaction = ref<boolean>(false)
function setIsTransaction(value: boolean) {
isTransaction.value = value
}
function copyCode() {
// nextTick(() => {
const val = userStore.userInfo?.referral_id
navigator.clipboard.writeText(val)
message.info('کد رونوشت شد')
// })
}
function shareCode() {
// nextTick(() => {
const val = `⭐️الان طلا بخر؛ آخر ماه سودشو ببر!
با خرید طلای آبشده در مقدارهای کم ولی مستمر، سود بیشتری ببر!
این دعوت نامه از طرف "${userStore.userInfo?.name}" عزیز برای شما ارسال شده تا شما هم از بازار طلای گلد دات آی آر جا نمونید.
روی لینک زیر کلیک کنید و ثبت نام خود را تکمیل کنید.
gold.ir/login?id=${userStore.userInfo?.referral_id}`
navigator.share({
title: ' گلد',
text: val
})
// message.info('کد رونوشت شد')
// })
}
async function earnMoney() {
try {
loading.value = true
data.value = await getEarnMoney()
} catch (e) {
console.log(e)
} finally {
loading.value = false
}
}
function subsetList(){
}
onMounted(async () => {
earnMoney()
})
function useStyle() {
if (data.value?.User) return 'right: 2%;'
// if (isbuy.value) return 'animation-direction: normal'
// else return 'animation-direction: reverse'
else return ' right: 98%; transform: translate(100%, 0);'
}
</script>
<style scoped>
</style>
+78
View File
@@ -0,0 +1,78 @@
<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 :src="props.item.img" alt="image">-->
<img v-if="props.item.group_type=='آبشده'|| props.item.group_type== null" :src="defaultImg">
<div class="mt-3">{{props.item?.title?? '-'}}</div>
<div class="mt-1 flex gap-1"> <div class="font-bold"> {{props.item?.wallet?.gold?? '-'}} </div> {{props.item?.unit}} </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'
/*function itemImg() {
}*/
interface Prop {
item: Product
}
const props = defineProps<Prop>()
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 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
}
})*/
</script>
<style scoped>
</style>
+157
View File
@@ -0,0 +1,157 @@
<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="bg-[#EFCED9] w-screen md:w-full h-[70vh] fixed md:absolute">
<div class="pt-15 flex flex-col">
<div class="text-gray-500 font-bold mr-5 z-20">موجودی دارایی ها</div>
<div class="flex justify-center mt-2 w-full z-20">
محصولات:
<div class="text-l mr-4 font-bold">{{ walletStore.walletInfo?.count_product ?? 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 ?? 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 ?? 0) }}ریال</div>
</div>
<!-- <div class="flex items-baseline justify-center mt-2 w-full z-20">
<div class="text-3xl font-bold">{{ inventory }}</div>
/عدد
</div>
<div class="flex items-baseline justify-center mt-2 w-full z-20">
<div class="text-3xl font-bold">{{ (weight + ((userInfo?.gold) ?? 0)).toFixed(3)}}</div>
/گرم
</div>-->
<img :src="img" alt="" class="mt-[-4rem] mr-10 max-w-[22rem] self-end">
</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>
<img :src="empty" alt="" class="w-70 ">
<div 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>
</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 img from '@/assets/img/cash_img.svg'
import empty from '@/assets/img/cash_empty.svg'
import Item from './components/Item.vue'
import {onMounted, ref} from "vue";
import {loading} from "@/utils";
import type {TableOutput} from "@/models/table";
import type {Fund} from "@/models/fund";
import {useFundUserStore} from "@/store/fundStore";
import goyImg from '@/assets/img/goyImg.svg'
import mokaabImg from '@/assets/img/mokaabImg.svg'
import defaultImg from '@/assets/img/defaultAbshodeh.svg'
import { getMe } from '@/api/me'
import type { User } from '@/models/login'
import {usePriceWithoutType} from "../../../utils/usePrice";
import {useWalletStore} from "@/store/walletStore";
const openModal = ref<boolean>(false)
const items = ref<Fund[]>([])
const tableOutput = ref<TableOutput<Fund> | null>(null)
const inventory = ref<number>(0)
const fundStore = useFundUserStore()
const walletStore = useWalletStore()
const userInfo = ref<User>()
const weight = ref<number>(0)
const total = ref<number>(0)
onMounted(() => {
initTable()
})
async function initTable() {
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 => {
console.log(x.wallet)
if (x.title !== 'آبشده نقدی')
inventory.value += x?.wallet?.gold ?? 0
total.value += ((x?.wallet?.gold) ?? 0) * ((x?.price) ?? 0)
if (x.title !== 'آبشده نقدی' && x.title !== 'سکه')
weight.value += ((x?.wallet?.gold) ?? 0) * ((x?.amount) ?? 0)
// console.log(inventory.value)
})
// console.log(tableOutput.value)
} catch (e) {
console.log(e)
} finally {
loading.value = false
}
}
/*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
},
]
*/
</script>
<style scoped>
</style>
@@ -0,0 +1,122 @@
<template>
<div @click="infoVisible = true">
<div class="flex">
<div :class="isUp? 'bg-green-50':'bg-red-50'"
class="rounded-lg p-3 h-fit w-fit flex justify-center items-center ">
<Icon :class="isUp? 'text-green-600':'text-red-600'"
:icon="`vuesax-linear:${isUp? 'arrow-up-2':'arrow-down-2'}`"/>
</div>
<div class="w-full mr-3">
<div class="flex justify-between w-full">
<div>{{ item.title }}</div>
<div>{{ toJalaliNotime(item.expire_at) }}</div>
</div>
<div class="flex justify-between mt-2">
<div :class="item.gold >= 0? 'text-green-600':'text-red-600'" class="text-gray-500 text-xs number-ltr">
</div>
<div class="text-gray-500 flex gap-1 text-xs items-center">
<div :class="item.gold > 0 ? 'text-green-600':'text-red-600'" class="text-base number-ltr">
{{ item.gold }}
</div>
{{item.unit}}
</div>
</div>
</div>
</div>
<!-- <div v-if="isGold" class="flex w-full justify-between mt-2">
<div class="text-gray-500">قیمت معامله</div>
<div class="text-gray-500 flex gap-1 text-xs items-center">
<div class="text-base">{{ usePriceWithoutType(Math.abs(item.cash) / Math.abs(item.gold)) }}</div>
ریال
</div>
</div>-->
<!-- <div v-else class="h-8"></div>-->
<a-divider class="!my-3"/>
<BasicActionSheet v-model:show="infoVisible">
<div class="font-bold text-lg">{{ props.item.title }}</div>
<div class="pb-20 mt-5">
<div class="flex justify-between mb-3">
<div class="text-primary">مقدار {{props.title}} مبادله شده:</div>
<div :class="item.gold >= 0? 'text-green-600' : 'text-red-600'" class="flex text-xs items-center">
<div class="text-base ml-1 number-ltr">{{ item.gold }}</div>
{{item.unit}}
</div>
</div>
<div class="flex justify-between mb-3">
<div class="text-primary">موجودی {{ props.title }}:</div>
<div class="flex text-xs text-yellow-700 items-center">
<div class="text-base ml-1">{{ item.balance_gold }}</div>
{{item.unit}}
</div>
</div>
<!-- <div class="flex justify-between mb-3">
<div class="text-primary">موجودی کیف پول:</div>
<div class="flex text-xs items-center" :class="isUp? 'text-green-600' : 'text-red-600'"><div class="text-base">{{usePriceWithoutType(12000000)}}</div>ریال</div>
</div>
<div class="flex justify-between mb-3">
<div class="text-primary">موجودی کیف طلا:</div>
<div class="flex items-center" :class="isUp? 'text-red-600' : 'text-green-600'">60 گرم</div>
</div>-->
<div class="flex justify-between mb-3">
<div class="text-primary">وضعیت:</div>
<div class="flex text-xs items-center">
<ATag :color="item.active? 'blue': 'red'" class="!py-1 !px-6 !ml-0">{{
item.active ? 'موفق' : 'نا موفق'
}}
</ATag>
</div>
</div>
<div class="flex justify-between mb-3">
<div class="text-primary">تاریخ:</div>
<div>{{ toJalaliNotime(item.expire_at) }}</div>
</div>
<div class="flex justify-between mb-3">
<div class="text-primary">زمان:</div>
<div>{{ toTime(item.expire_at) }}</div>
</div>
<BasicButton class="w-full mt-5" @click="infoVisible = false">بازگشت</BasicButton>
</div>
</BasicActionSheet>
</div>
</template>
<script lang="ts" setup>
import Icon from "@/components/BasicPacks/BasicIcon.vue";
import BasicActionSheet from "@/components/BasicPacks/BasicActionSheet.vue";
import {computed, ref} from "vue";
import BasicButton from "@/components/BasicPacks/BasicButton.vue";
import type {Transaction} from "@/models/transaction";
import {toJalaliNotime, toTime} from "../../../../../utils/useDateTime";
const infoVisible = ref<boolean>(false)
interface Prop {
item: Transaction
title?: string
}
const props = withDefaults(defineProps<Prop>(), {})
const isUp = computed(() => props.item.type === 3 || props.item.type === 1)
// const isGold = computed(() => props.item.type === 1 || props.item.type === 2 || props.item.type === 10)
/*const title = computed(() => {
if (isUp.value) {
if (isGold.value) {
return 'واریز ریالی'
} else {
return 'خرید طلا'
}
} else {
if (isGold.value) {
return 'برداشت ریالی'
} else {
return 'فروش طلا'
}
}
})*/
</script>
<style scoped>
</style>
+300
View File
@@ -0,0 +1,300 @@
<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=='آبشده'|| 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>موجودی کیف طلا: {{ walletStore?.walletInfo?.gold }} گرم</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>
</BasicActionSheet>
<BasicActionSheet v-model:show="editShow">
<div class="font-bold text-lg">گنج {{ info?.title }}</div>
<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>
<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>
</template>
<template v-slot: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 BasicInput from '@/components/BasicPacks/BasicInput.vue'
import { useWalletStore } from '@/store/walletStore'
import ListAnim from '@/components/ListAnim.vue'
import TransactionSkeleton from '@/components/TransactionSkeleton.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 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
}
})
</script>
<style scoped>
</style>
+194
View File
@@ -0,0 +1,194 @@
<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-[#0A1B37] 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>
</template>
<script setup lang="ts">
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
}
}
</script>
<style lang="less">
@prefix: ~'@{prefixCls}-input_name';
.@{prefix} {
.van-field__value {
@apply flex;
}
.van-field__body {
@apply w-full mr-5;
}
}
</style>
@@ -0,0 +1,24 @@
<template>
<div ref="skeletonRatio" class="h-fit">
<content-loader :width="skeletonSize.width" class="bg-white" height="100vh">
<rect :width="skeletonSize.width" height="88" rx="3" ry="3" x="0" y="0"/>
</content-loader>
</div>
</template>
<script lang="ts" setup>
import {reactive, ref, watch} from "vue";
import {useElementSize} from "@vueuse/core";
import {ContentLoader} from "vue-content-loader";
const skeletonRatio = ref(null)
const skeletonSize = reactive(
useElementSize(skeletonRatio, {width: 0, height: 0}, {box: 'border-box'})
)
watch(skeletonSize, () => {
console.log(skeletonSize)
})
</script>
<style scoped>
</style>
+651
View File
@@ -0,0 +1,651 @@
<template>
<div class="h-35rem overflow-y-auto">
<div class=" !overflow-y-scroll bg-white py-3 text-primary font-bold flex justify-evenly">
<!-- <div @click="isBuy = false" class="w-full text-center" :class="!isBuy?'text-primary':'text-gray-400'">خرید طلا</div>
<div @click="isBuy = true" class="w-full text-center" :class="isBuy?'text-primary':'text-gray-400'">فروش طلا</div>-->
<div class="flex justify-evenly w-full px-2 h-11 items-center bg-gray-50 relative rounded ">
<div :class="isBuy?'text-secondary':'text-gray-400'" class="w-full text-center z-2"
@click.stop="setIsBuy(true) ">
خرید طلا {{ props?.ProductItem?.title }}
</div>
<div :class="!isBuy?'text-secondary':'text-gray-400'" class="w-full text-center z-2"
@click.stop="setIsBuy(false) ">
فروش طلا {{ props?.ProductItem?.title }}
</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()"
class="absolute bg-white h-8 w-1/2 rounded-lg animate right"></div>
</div>
</div>
<div v-if="userStore" class=" mt-5 mb-25vh pb-2">
<a-spin :spinning="!price">
<div v-if="!loading" :class="!isBuy? ' bg-red-100' : ' bg-green-100'"
class="w-full relative rounded-lg h-[88px] flex flex-col justify-center background-color-transition">
<img :src="img1" alt="" class="h-[88px] absolute">
<div class="w-full items-center flex flex-col">
<div class="text-gray-700 font-bold">{{ !isBuy ? 'قیمت فروش' : 'قیمت خرید' }}</div>
<div v-if="price" class="flex gap-1 mt-3 text-xs items-center">
<div :class="!isBuy? 'text-red-700' : 'text-green-700'" class="font-bold text-2xl color-transition">
{{ usePriceWithoutType(goldPriceValue) }}
</div>
ریال
</div>
</div>
</div>
<div v-else class="w-full h-[88px]">
<GoldSkeleton class="w-full" />
</div>
<div v-if="limitedPrice !== undefined && userStore?.userInfo.trade_active !== 1"
class="text-red text-xs flex gap-1 items-center justify-center my-2">
<Icon icon="vuesax-linear:info-circle" size="16" />
حداقل مبلغ اولیه برای ثبت سفارش {{ usePriceWithoutType(limitedPrice.value as number ?? 0) }} ریال می باشد.
</div>
</a-spin>
<a-form :model="form" class="!mt-5" name="basic" @finish="okConfirm()">
<div class="border-gray-200 border-1 rounded-xl p-5 h-58 relative">
<bg_main />
<div class="z-100 relative">
<a-form-item>
<BasicInput v-model:value="form.goldCash" addon-before="ریال" addon-bg-color="#0A1B37"
addon-text-color="white"
place-holder="ارزش کل"
size="large"
type="price" @onchange="calculateGold" />
</a-form-item>
<a-form-item :rules="[justNumber()]">
<BasicInput v-model:value="form.goldValue" addon-before="گرم" addon-bg-color="#0A1B37"
addon-text-color="white"
place-holder="مقدار طلا"
size="large" type="text" inputmode="decimal" @onchange="calculateCash" />
</a-form-item>
<!-- {{walletStore?.walletInfo?.gold}}-->
<Transition mode="out-in" name="fade">
<div v-if="!isBuy" class="font-bold text-xs">
<div> {{ `موجودی کیف طلا: ${walletStore?.walletInfo?.gold ?? 0} گرم` }}</div>
<!-- <div v-if="walletStore?.walletInfo?.gold_block !== 0">
{{ `موجودی قابل برداشت طلا: ${walletStore?.walletInfo?.gold_block ?? 0} گرم` }}
</div>-->
</div>
<div v-else class="font-bold text-xs">
{{ `موجودی کیف پول: ${usePriceWithoutType(walletStore?.walletInfo?.cash ?? 0)} ریال` }}
</div>
</Transition>
<Transition mode="out-in" name="fade">
<a-form-item v-if="walletStore?.walletInfo" class="!mt-3 ">
<!-- {{ isBuy }}-->
<a-slider v-model:value="form.percentWallet"
:disabled="isBuy? walletStore?.walletInfo?.cash <= 0: false"
:max="100"
:min="0"
:step="10"
:tip-formatter="null"
class="!my-1"
@change="percentChange" />
</a-form-item>
</Transition>
<!-- <Transition mode="out-in" name="fade">
<div v-if="priceErrorVisible" class="flex gap-1 items-center text-xs mt-[-15px] text-orange-600">
<BasicIcon icon="vuesax-linear:danger" />
ارزش کل وارد شده بر حسب گرم طلا محاسبه خواهد شد و قیمت وارد شده معادل {{ usePrice(finalPrice) }} می
باشد!
</div>
</Transition>-->
<Transition mode="out-in" name="fade">
<div v-if="priceErrorVisible" class="flex gap-1 items-center text-xs mt-[-15px] text-blue-600">
<BasicIcon icon="vuesax-linear:info-circle" />
ارزش کل وارد شده بر حسب گرم طلا محاسبه خواهد شد و قیمت وارد شده معادل {{ usePrice(parseInt(finalPrice.toFixed(0))) }} می
باشد!
</div>
</Transition>
</div>
</div>
<GoldLoading v-model:show="infoVisible" />
<a-form-item>
<BasicButton
v-if="walletStore"
:disabled="disableTransaction"
class=" w-full py-2 mt-5"
html-type="submit"
type="primary"
>
<div>
<a-spin v-if="loading" size="small" />
<div v-else>{{ !isBuy ? 'فروش' : 'خرید' }}</div>
</div>
</BasicButton>
<div v-if="!isBuy && form.goldValue > walletStore?.walletInfo?.gold"
class="text-red-700 text-xs font-bold mt-2">
مقدار گرم طلای وارد شده جهت فروش ({{ form.goldValue }}گرم) بیشتر از مقدار موجودی شما
({{ walletStore?.walletInfo?.gold }}گرم) می باشد.
</div>
<!-- <div>{{form?.goldValue? true: false}}</div>-->
<div v-if="isBuy? ((form?.goldValue || form.goldValue === 0)? form?.goldCash < 500000: false) : false"
class="text-red-700 text-xs font-bold mt-2">
حداقل مقدار طلا جهت خرید 500,000 ریال می باشد.
</div>
</a-form-item>
<div class=" w-full bottom-18 px-6 rounded-xl py-1 border-1 bg-white">
<!-- <BasicInfoItem is-line title="کارمزد" :value="parseFloat(((form.goldValue?? 0)*0.005).toFixed(3))" />-->
<!-- <BasicInfoItem is-line title="کارمزد" :value="parseFloat(((form.goldValue?? 0)*0.005).toFixed(3))" />-->
<div class="flex justify-between items-center">
<div>کارمزد:</div>
<div class="flex gap-2 items-center">
<div class="">{{ parseFloat(((form.goldValue ?? 0) * 0.01).toFixed(4)) }}</div>
<!-- <div class="font-bold text-2xl">{{ 0 }}</div>-->
<div>
گرم
</div>
</div>
</div>
</div>
</a-form>
<!-- <div ref="el" :class="loading? 'h-screen': ''"
class="px-3 overflow-y-scroll w-full h-[49vh] pb-25 max-h-[35vh]">
&lt;!&ndash; <div v-for="item in items">ss</div>&ndash;&gt;
<list-anim v-if="!loading" :numberItemsAnim="4">
<Item v-for="item in isBuy? buyItems: sellItems" :key="item.id" :item="item" />
<TransactionSkeleton v-if="loadingMore" class="mt-1 mb-8" />
</list-anim>
<TransactionSkeleton v-for="i in 13" v-else :key="i" class="mt-1" />
</div>-->
</div>
<BasicActionSheet v-model:show="confirmAction">
<div class="font-bold text-lg"></div>
<div class="w-full rounded-lg bg-gray-50 p-3">
<div class="flex justify-between ">
<div>وزن:</div>
<div class="flex items-center">
<div class="font-bold">{{ form.goldValue }}</div>
<div class="text-xs mr-1">گرم</div>
</div>
</div>
<div class="flex justify-between mt-3">
<div>مظنه:</div>
<div class="flex items-center">
<div class="font-bold">{{ usePriceWithoutType(isBuy ? price.buy ?? 0 : price.sell ?? 0) }}</div>
<div class="text-xs mr-1">ریال</div>
</div>
</div>
<div class="flex justify-between mt-3">
<div>کارمزد:</div>
<div class="flex items-center gap-2">
<div class="font-bold text-xl">{{ parseFloat(((form.goldValue ?? 0) * 0.01).toFixed(4)) }}</div>
<div class="text-xs mr-1">گرم</div>
</div>
</div>
<div >(معادل {{ equivalentPrice }} ریال)</div>
<div class="flex justify-between mt-3">
<div>{{ isBuy ? 'قیمت قابل پرداخت:' : 'مبلغ دریافتی:' }}</div>
<div class="flex items-center">
<div class="font-bold">{{ usePriceWithoutType(payablePrice.toFixed(0)) }}</div>
<div class="text-xs mr-1">ریال</div>
</div>
</div>
</div>
<BasicButton class="mb-20 mt-5 w-full" type="primary" @click="ok(); confirmAction= false">ثبت نهایی</BasicButton>
</BasicActionSheet>
<van-dialog v-model:show="noCompleteVisible" class="completeButtonStyle" confirm-button-text="تکمیل اطلاعات"
show-confirm-button @confirm="router.push({name: 'user',query:{showEdit: true}})">
<div class="flex flex-col items-center p-2">
<BasicIcon class="home_appear_fade_in_up text-center" color="orange"
icon="vuesax-linear:info-circle"
size="50" />
<!-- <div class="home_appear_fade_in_up delay-100">به روز رسانی</div>-->
<div class="home_appear_fade_in_up mt-2 text-justify text-center">برای ثبت سفارش، لطفا اطلاعات خود را تکمیل کنید
یا در صورت تکمیل اطلاعات، منتظر تایید اطلاعات خود بمانید.
</div>
</div>
</van-dialog>
</div>
</template>
<script lang="ts" setup>
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
import img1 from '@/assets/img/home_ly2.svg'
import { usePrice, usePriceWithoutType } from '@/utils/usePrice'
import BasicInput from '@/components/BasicPacks/BasicInput.vue'
import type { Gold } from '@/models/gold'
import { isIphone, loading, loadingMore, toFixedDownThreeChar } from '@/utils'
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
import router from '@/router'
import { useWalletStore } from '@/store/walletStore'
import { createOrder } from '@/api/order'
import { message } from 'ant-design-vue'
import type { Price } from '@/models/home'
import { getLastPrice } from '@/api/home'
import Icon from '@/components/BasicPacks/BasicIcon.vue'
import { useUserStore } from '@/store/userStore'
import BasicActionSheet from '@/components/BasicPacks/BasicActionSheet.vue'
import { justNumber } from '@/utils/inputRules'
import GoldSkeleton from '@/views/base/gold/components/GoldSkeleton.vue'
import GoldLoading from '@/components/GoldLoading.vue'
import { update } from 'lodash'
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
import TransactionSkeleton from '@/components/TransactionSkeleton.vue'
import ListAnim from '@/components/ListAnim.vue'
import Item from '@/views/base/wallet/components/Item.vue'
import type { Transaction } from '@/models/transaction'
import type { TableEngineInput, TableOutput } from '@/models/table'
import { useInfiniteScroll } from '@vueuse/core'
import { getTransactionTable } from '@/api/transaction'
import { getLastPrices, getUpPrice, lastPrice, setIntervalGetAllPrice, stopPriceInterval } from '@/utils/price'
import type { Product } from '@/models/products'
import { useFundUserStore } from '@/store/fundStore'
// import Bg_main from "@/components/bg_main.vue";
const infoVisible = ref(false)
const walletStore = useWalletStore()
const userStore = useUserStore()
const fundStore = useFundUserStore()
const confirmAction = ref<boolean>(false)
const noCompleteVisible = ref<boolean>(false)
const buyItems = ref<Transaction[]>([])
const sellItems = ref<Transaction[]>([])
const priceErrorVisible = ref<boolean>(false)
const buyTableOutput = ref<TableOutput<Transaction> | null>(null)
const sellTableOutput = ref<TableOutput<Transaction> | null>(null)
const el = ref()
interface Prop {
ProductItem?: Product
}
const props = withDefaults(defineProps<Prop>(), {})
const isBuy = ref<boolean>(true)
const buyPagination = ref<TableEngineInput>({
filters: [{
field: 'type',
cr: 'and',
type: 'number',
op: 'eq',
value: 1
}], limit: 6, page: 0
})
const sellPagination = ref<TableEngineInput>({
filters: [{
field: 'type',
cr: 'and',
type: 'number',
op: 'eq',
value: 2
}], limit: 6, page: 0
})
const finalPrice = computed(() => (form.value?.goldValue * (isBuy.value ? price.value?.buy ?? 0 : price.value?.sell ?? 0)))
// const payablePrice = computed(() => finalPrice.value + finalPrice.value * 0.007)
const payablePrice = computed(() => finalPrice.value)
const equivalentPrice = computed(() => usePriceWithoutType(((isBuy ? price.value?.buy ?? 0 : price.value?.sell ?? 0) * (parseFloat(((form.value?.goldValue ?? 0) * 0.01).toFixed(4))) ).toFixed(0)) )
const disableTransaction = computed(() =>
loading.value ||
form.value?.goldValue === undefined ||
form.value?.goldValue === '' ||
form.value?.goldCash === '' ||
form.value?.goldCash === undefined ||
(isBuy.value ? (form.value?.goldCash ?? 0) < 500000 : (form.value?.goldValue ?? 0) < 0.001) ||
(!isBuy.value && form.value.goldValue > walletStore?.walletInfo?.gold) ||
price.value?.buy === undefined)
function refreshTable() {
sellItems.value = []
buyItems.value = []
sellPagination.value = {
filters: [{
field: 'type',
cr: 'and',
type: 'number',
op: 'eq',
value: 2
}], limit: 6, page: 0
}
buyPagination.value = {
filters: [{
field: 'type',
cr: 'and',
type: 'number',
op: 'eq',
value: 1
}], limit: 6, page: 0
}
initSellTable()
initBuyTable()
}
async function initBuyTable() {
try {
buyPagination.value.page === 0 ? loading.value = true : loadingMore.value = true
buyTableOutput.value = await getTransactionTable(buyPagination.value)
buyItems.value.push(...buyTableOutput.value.rows)
// console.log(tableOutput.value)
} catch (e) {
console.log(e)
} finally {
loading.value = false
loadingMore.value = false
}
}
async function initSellTable() {
try {
sellPagination.value.page === 0 ? loading.value = true : loadingMore.value = true
sellTableOutput.value = await getTransactionTable(sellPagination.value)
sellItems.value.push(...sellTableOutput.value.rows)
// console.log(tableOutput.value)
} catch (e) {
console.log(e)
} finally {
loading.value = false
loadingMore.value = false
}
}
// if (!userStore.isSingle) {
/*useInfiniteScroll(
el,
async () => {
// load more
// console.log('salamss')
if (!userStore.isSingle) {
if (isbuy.value) {
// console.log((buyeTableOutput.value.query.page))
// console.log(buyeTableOutput.value.query.total)
// console.log((buyeTableOutput.value.query.page + 1) * buyPagination.value.limit < buyeTableOutput.value.query.total)
if (
buyeTableOutput.value &&
(buyPagination.value.page + 1) * buyPagination.value.limit < buyeTableOutput.value.query.total
) {
// console.log('gfgf')
buyPagination.value.page++
await initbuyTable()
}
} else {
if (
sellTableOutput.value &&
(sellPagination.value.page + 1) * sellPagination.value.limit < sellTableOutput.value.query.total
) {
// console.log('gfgf')
sellPagination.value.page++
await initsellTable()
}
}
}
},
{ distance: 12 }
)*/
// }
onMounted(async () => {
switch (router.currentRoute.value.query.state) {
case 'sell':
isBuy.value = false
break
case 'buy':
isBuy.value = true
break
}
await initPrice()
/* await initSellTable()
await initBuyTable()*/
})
onUnmounted(() => {
stopPriceInterval()
})
const form = ref<Gold>({
goldCash: undefined,
goldValue: undefined,
percentWallet: undefined
})
const allowedAsciiCodeFloat = [46, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57]
const allowedAsciiCodeInt = [48, 49, 50, 51, 52, 53, 54, 55, 56, 57]
watch(form.value, () => {
if (form.value.goldValue) {
const lastCharGoldStr: string = form.value.goldValue.toString()
if (!allowedAsciiCodeFloat.includes(lastCharGoldStr.slice(-1).charCodeAt(0))) {
form.value.goldValue = isNaN(parseFloat(lastCharGoldStr.slice(0, -1))) ? null : parseFloat(lastCharGoldStr.slice(0, -1))
calculateCash(form.value.goldValue)
}
}
if (form.value.goldCash) {
const lastCharCashStr: string = form.value.goldCash.toString()
if (!allowedAsciiCodeInt.includes(lastCharCashStr.slice(-1).charCodeAt(0))) {
form.value.goldCash = isNaN(parseFloat(lastCharCashStr.slice(0, -1))) ? null : parseFloat(lastCharCashStr.slice(0, -1))
calculateGold(form.value.goldCash)
}
}
})
onMounted(() => {
console.log(userStore.userInfo?.is_legal === 2)
if (userStore.userInfo?.is_legal === 0) {
noCompleteVisible.value = true
}
})
function percentChange(val: number) {
if (val !== 0)
if (isBuy.value) {
form.value.goldCash = unitCashCalculator.value * val
calculateGold(form.value.goldCash)
calculateCash(form.value.goldValue)
} else {
// console.log((unitGoldCalculator.value * val).toFixed(2))
// form.value.goldValue = parseFloat((unitGoldCalculator.value * val).toFixed(2))
form.value.goldValue = toFixedDownThreeChar(parseFloat(unitGoldCalculator.value * val))
calculateCash(form.value.goldValue)
}
else {
form.value.goldValue = undefined
form.value.goldCash = undefined
}
}
const unitGoldCalculator = computed(() => {
// console.log(walletStore?.walletInfo?.gold / 100)
return (walletStore?.walletInfo?.gold ?? 0) / 100
})
const unitCashCalculator = computed(() => {
return (walletStore?.walletInfo?.cash ?? 0) / 100
})
const limitedPrice = computed(() => {
if (walletStore.limitedPrice)
return walletStore?.limitedPrice[0]
})
function calculateCash(val: number) {
priceErrorVisible.value = false
// console.log(val)
if (price.value) {
if (isBuy.value) {
if (val) form.value.goldCash = parseFloat((val * price?.value?.buy).toFixed(0))
else form.value.goldCash = undefined
} else {
if (val) form.value.goldCash = parseFloat((val * price?.value?.sell).toFixed(0))
else form.value.goldCash = undefined
}
}
}
function calculateGold(val: number) {
// console.log(val)
// form.value.goldCash = usePriceWithoutType(form.value.goldCash)
if (price.value) {
if (isBuy.value) {
if (val) {
form.value.goldValue = toFixedDownThreeChar(parseFloat(val / price?.value?.buy))
if (parseInt(finalPrice.value) > 0) priceErrorVisible.value = true
if (parseInt(finalPrice.value) === 0) priceErrorVisible.value = false
} else if (val.toString() === '') {
form.value.goldValue = undefined
priceErrorVisible.value = false
} else {
form.value.goldValue = 0
priceErrorVisible.value = false
}
} else {
if (val) {
form.value.goldValue = toFixedDownThreeChar(parseFloat((val / price?.value?.sell)))
if (parseInt(finalPrice.value) > 0) priceErrorVisible.value = true
if (parseInt(finalPrice.value) === 0) priceErrorVisible.value = false
} else if (val.toString() === '') {
// console.log('sasasasasasa')
form.value.goldValue = undefined
priceErrorVisible.value = false
} else {
form.value.goldValue = 0
priceErrorVisible.value = false
}
}
}
}
/*watch(form.value?.goldValue, (n)=>{
console.log('salammmm', n)
})*/
const bganim = ref(null)
function useStyle() {
if (isBuy.value) return 'right: 2%;'
// if (isbuy.value) return 'animation-direction: normal'
// else return 'animation-direction: reverse'
else return ' right: 98%; transform: translate(100%, 0);'
}
function setIsBuy(val: boolean) {
isBuy.value = val
form.value.goldValue = undefined
form.value.goldCash = undefined
form.value.percentWallet = 0
priceErrorVisible.value = false
// console.log(bganim.value.classList)
// bganim?.value?.classList.add(val?'right':'left')
// bganim?.value?.style.transform = `translateX(${val ? '0' : '-100'});`
// bganim?.value?.style.animationDirection = val? 'normal':'reverse'
// val? bganim?.value?.classList?.add("move") : bganim?.value?.classList?.remove("move")
// const el = bganim.value?.
// el.
}
const formatter = (value: number) => {
return `${value}%`
}
const price = computed((): Price => <Price>lastPrice.value ?? 0)
const goldPriceValue = computed(() => {
if (!price.value) return 0
return isBuy.value
? (price.value.buy ?? 0)
: (price.value.sell ?? 0)
})
async function initPrice() {
try {
// chartLoading.value = true
await getLastPrices()
await getUpPrice()
await setIntervalGetAllPrice()
loading.value = true
} catch (e) {
console.log(e)
} finally {
loading.value = false
// chartLoading.value = false
}
}
function okConfirm() {
confirmAction.value = true
}
async function ok() {
try {
loading.value = true
infoVisible.value = true
await createOrder({
direction: isBuy.value ? 1 : 2,
price: isBuy.value ? price.value?.buy : price.value?.sell,
amount: form.value.goldValue ?? 0
})
await walletStore.getMyWallet()
await router.push({ name: 'transactions' })
form.value = {
goldValue: undefined,
goldCash: undefined,
percentWallet: undefined
}
// refreshTable()
message.success('سفارش شما با موفقیت انجام شد')
await fundStore.getMyFund()
} catch (e) {
// console.log(e)
// await initPrice()
} finally {
loading.value = false
infoVisible.value = false
}
}
</script>
<style lang="less">
/*.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}*/
/*.completeButtonStyle{
background: blue;
}*/
.completeButtonStyle .van-dialog__confirm .van-button__content {
background: #0A1B37;
color: white;
}
.left {
transform: translateX(0);
left: 0;
}
.toggle-transe-parent {
animation: ease-in-out infinite alternate swingParent;
}
@keyframes swingParent {
from {
transform: translateX(0);
left: 0;
}
to {
left: 100%;
transform: translateX(-100%);
}
}
.animate.right {
right: 0;
}
.animate.right.move {
right: 100%;
transform: translate(100%, 0);
}
</style>
@@ -0,0 +1,63 @@
<template>
<div ref="skeletonRatio" class="h-fit">
<content-loader :width="skeletonSize.width" class="bg-white" height="100vh">
<rect :width="skeletonSize.width" height="5" rx="3" ry="3" x="0" y="0"/>
<rect :width="skeletonSize.width" height="5" rx="3" ry="3" x="0" y="84"/>
<rect :width="5" height="85" rx="3" ry="3" x="0" y="0"/>
<rect :width="5" :x="skeletonSize.width-5" height="85" rx="3" ry="3" y="0"/>
<rect :width="2" :x="skeletonSize.width/2" height="60" rx="3" ry="3" y="15"/>
<rect :width="skeletonSize.width/2-20" :x="10" height="20" rx="10" ry="10" y="15"/>
<rect :width="skeletonSize.width/2-20" :x="skeletonSize.width/2 + 10" height="20" rx="10" ry="10" y="15"/>
<rect :width="skeletonSize.width/2-40" :x="20" height="10" rx="5" ry="5" y="40"/>
<rect :width="skeletonSize.width/2-40" :x="skeletonSize.width/2 + 20" height="10" rx="5" ry="5" y="40"/>
<rect :width="skeletonSize.width/2-30" :x="15" height="18" rx="10" ry="10" y="60"/>
<rect :width="skeletonSize.width/2-30" :x="skeletonSize.width/2 + 15" height="18" rx="10" ry="10" y="60"/>
<circle :cx="skeletonSize.width/4-skeletonSize.width/8" cy="145" r="20"/>
<circle :cx="skeletonSize.width/4+skeletonSize.width/8" cy="145" r="20"/>
<circle :cx="skeletonSize.width/2+ skeletonSize.width/8" cy="145" r="20"/>
<circle :cx="skeletonSize.width - skeletonSize.width/8" cy="145" r="20"/>
<rect :width="50" :x="skeletonSize.width/4-skeletonSize.width/8 - 25" height="15" rx="3" ry="3" y="170"/>
<rect :width="50" :x="skeletonSize.width/4+skeletonSize.width/8 - 25" height="15" rx="3" ry="3" y="170"/>
<rect :width="50" :x="skeletonSize.width/2+ skeletonSize.width/8 - 25" height="15" rx="3" ry="3" y="170"/>
<rect :width="50" :x="skeletonSize.width - skeletonSize.width/8 - 25" height="15" rx="3" ry="3" y="170"/>
<rect :width="skeletonSize.width - 45" :x="45" height="20" rx="3" ry="3" y="230"/>
<rect :width="skeletonSize.width" :x="0" height="80" rx="3" ry="3" y="260"/>
<rect :width="skeletonSize.width/2 - 5" :x="0" height="50" rx="3" ry="3" y="360"/>
<rect :width="skeletonSize.width/2 - 5" :x="skeletonSize.width/2 + 5" height="50" rx="3" ry="3" y="360"/>
<rect :width="skeletonSize.width" :x="0" height="170" rx="3" ry="3" y="440"/>
<!-- <rect height="20" rx="3" ry="3" width="100" x="0" y="0"/>
<rect :width="skeletonSize.width/4 + 40" :x="skeletonSize.width/2" height="20" rx="3" ry="3" y="0"/>
<rect height="20" rx="3" ry="3" width="80" x="0" y="30"/>
<rect :x="skeletonSize.width - 40" height="40" rx="12" ry="12" width="40" y="0"/>
<rect :width="skeletonSize.width" :x="0" :y="skeletonSize.height-5" height="2" rx="12" ry="12"/>-->
<!-- <circle :cx="skeletonSize.width - 20" :cy="skeletonSize.height/2 - 10" r="20" />-->
<!-- <rect :x="10" y="20" rx="3" ry="3" :width="skeletonSize.width - 20" height="150"/>
<circle :cx="skeletonSize.width/2" cy="170" r="15" />
<rect :x="skeletonSize.width/2 - skeletonSize.width/3 -10" y="190" rx="3" ry="3" :width="skeletonSize.width/3 + skeletonSize.width/3 + 20" height="20"/>
<rect :x="skeletonSize.width/2 - skeletonSize.width/3 +20" y="220" rx="3" ry="3" :width="skeletonSize.width/3 + skeletonSize.width/3 - 40" height="20"/>-->
<!-- <rect x="90" y="0" rx="3" ry="3" width="80" height="20" />
<rect x="180" y="0" rx="3" ry="3" width="80" height="20" />
<rect x="270" y="0" rx="3" ry="3" width="80" height="20" ♥/>-->
</content-loader>
</div>
</template>
<script lang="ts" setup>
import {reactive, ref, watch} from "vue";
import {useElementSize} from "@vueuse/core";
import {ContentLoader} from "vue-content-loader";
const skeletonRatio = ref(null)
const skeletonSize = reactive(
useElementSize(skeletonRatio, {width: 0, height: 0}, {box: 'border-box'})
)
/*watch(skeletonSize, () => {
console.log(skeletonSize)
})*/
</script>
<style scoped>
</style>
@@ -0,0 +1,46 @@
<template>
<div v-if="props.ProductItem.wallet" class="bg-gradient-to-l from-primary rounded-lg p-px to-transparent ">
<div class="flex flex-col gap-7 rounded-lg p-4 w-56 bg-white ">
<div class="flex justify-between items-center font-medium text-sm">
<div class="text-primary">موجودی {{ props.ProductItem.title }}</div>
<BasicIcon v-if="props.ProductItem.group_type=='گوی'" stroke-width="1" size="50" color="#0A1B37" class="rotate-310" icon="vuesax-linear:grammerly"/>
<BasicIcon v-else-if="props.ProductItem.group_type=='سکه'" stroke-width="1" size="50" color="#0A1B37" class="rotate-310" icon="vuesax-linear:coin"/>
<BasicIcon v-else-if="props.ProductItem.group_type=='شمش'" stroke-width="1" size="50" color="#0A1B37" class="rotate-310" icon="vuesax-linear:slider-vertical"/>
<BasicIcon v-else-if="props.ProductItem.group_type=='مکعب'" stroke-width="1" size="50" color="#0A1B37" class="rotate-310" icon="vuesax-linear:keyboard"/>
<BasicIcon v-else-if="props.ProductItem.group_type=='آبشده'" stroke-width="1" size="50" color="#0A1B37" class="rotate-310" icon="vuesax-linear:slider-vertical"/>
<BasicIcon v-else stroke-width="1" size="50" color="#0A1B37" class="rotate-310" icon="vuesax-linear:slider-vertical"/>
</div>
<div class="flex justify-between px-2 items-center ">
<BasicIcon v-if="props.ProductItem.group_type=='گوی'" stroke-width="1" size="26" color="#0A1B37" class="rotate-310" icon="vuesax-linear:grammerly"/>
<BasicIcon v-else-if="props.ProductItem.group_type=='سکه'" stroke-width="1" size="26" color="#0A1B37" class="rotate-310" icon="vuesax-linear:coin"/>
<BasicIcon v-else-if="props.ProductItem.group_type=='شمش'" stroke-width="1" size="26" color="#0A1B37" class="rotate-310" icon="vuesax-linear:slider-vertical"/>
<BasicIcon v-else-if="props.ProductItem.group_type=='مکعب'" stroke-width="1" size="26" color="#0A1B37" class="rotate-310" icon="vuesax-linear:keyboard"/>
<BasicIcon v-else stroke-width="1" size="26" color="#0A1B37" class="rotate-310" icon="vuesax-linear:slider-vertical"/> <div class="flex justify-between gap-2 items-center">
<span v-if="props.ProductItem.group_type=='آبشده'" class="font-bold text-secondary">{{userWallet.walletInfo?.gold??0}}</span>
<span v-else class="font-bold text-secondary">{{props?.ProductItem.wallet?.gold??0}}</span>
<span class="text-gray-400">{{props?.ProductItem?.unit}}</span>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import BasicIcon from "@/components/BasicPacks/BasicIcon.vue";
import type {PInventory} from "@/models/products";
import {useWalletStore} from "../../../../store/walletStore";
interface Prop {
ProductItem: PInventory
}
const userWallet=useWalletStore()
const props = withDefaults(defineProps<Prop>(), {})
</script>
<style scoped>
.text-secondary{
font-size: large;
--un-text-opacity: 1;
color: #ac842f !important;
}
</style>
+364
View File
@@ -0,0 +1,364 @@
<template>
<div class="">
<!-- <div class="bg-primary h-30 mt-[-3rem] z-100000000000"></div>-->
<div class="fixed h-[60vh] bg-[#0A1B37] w-screen">
<div class="flex w-full justify-around mt-18">
<div class="text-center">
<div class="text-[#E5D7CE] text-xs ">موجودی کیف طلا</div>
<div class="flex justify-center mt-1 text-[#B79379] gap-1 items-center text-xs">
<div class="text-white text-lg">{{ walletStore?.walletInfo?.gold ?? 0 }}</div>
گرم
</div>
</div>
<div class="text-center">
<div class="text-[#E5D7CE] text-xs ">سقف اعتبار خرید طلا</div>
<div class="flex justify-center mt-1 text-[#B79379] gap-1 items-center text-xs">
<div class="text-white text-lg">{{ userStore?.userInfo?.gram ?? 0 }}</div>
گرم
</div>
</div>
<div class="text-center">
<div class="text-[#E5D7CE] text-xs ">موجودی کیف پول</div>
<div class="flex justify-center mt-1 text-[#B79379] gap-1 items-center text-xs">
<div class="text-white text-lg">
{{ walletStore?.walletInfo?.cash === undefined ? 0 : usePriceWithoutType(walletStore.walletInfo?.cash) }}
</div>
ریال
</div>
</div>
</div>
</div>
<div class="pt-[9rem] relative">
<img :src="img" alt="" class="w-screen h-[8rem]">
<!-- <div class="w-screen bg-white w-screen h-[calc(100vh-16rem-70px)] px-5">-->
<div v-if="userStore.userInfo && !loading" class="bg-white w-screen h-fit px-5 m-[-1px]">
<!-- <a-alert :message="``" type="warning" show-icon/>-->
<!-- {{limitedPrice === undefined}}-->
<div v-if="limitedPrice !== undefined && userStore?.userInfo.trade_active !== 1"
class="text-red text-xs flex gap-1 items-center justify-center mb-2">
<Icon icon="vuesax-linear:info-circle" size="16"/>
حداقل مبلغ اولیه برای ثبت سفارش {{ usePriceWithoutType(limitedPrice.value as number ?? 0) }} ریال می باشد.
</div>
<div class="bg-gray-50 w-full flex justify-evenly rounded-lg py-2">
<div class="text-center w-full">
<div>قیمت خرید از گلد دات آی آر</div>
<div class="text-[10px] text-gray-500">(هر گرم طلای 18 عیار)</div>
<div class="flex w-full mt-3 justify-evenly">
<!-- <div class="text-[10px] gap-1 flex bg-green-100 rounded-xl px-1 text-green-600 items-center">
<Icon icon="vuesax-linear:received" size="10"/>
<div>2%</div>
</div>-->
<div v-if="price" class="flex text-gray-500 text-xs items-center gap-1">
<div class="text-primary font-bold text-base">{{ usePriceWithoutType(price.buy ?? 0) }}</div>
ریال
</div>
</div>
</div>
<a-divider class="bg-gray-200 !h-auto !my-2" type="vertical"/>
<div class="text-center w-full">
<div>قیمت فروش به گنج طل</div>
<div class="text-[10px] text-gray-500">(هر گرم طلای 18 عیار)</div>
<div class="flex w-full mt-3 justify-evenly">
<!-- <div class="text-[10px] gap-1 flex bg-red-100 rounded-xl px-1 text-red-600 items-center">
<Icon icon="vuesax-linear:send" size="10"/>
<div>3%</div>
</div>-->
<div v-if="price" class="flex text-gray-500 text-xs items-center gap-1">
<div class="text-primary font-bold text-base">{{ usePriceWithoutType(price.sell ?? 0) }}</div>
ریال
</div>
</div>
</div>
</div>
<div class="flex justify-between mt-8">
<div class="text-center w-full flex-flex-col items-center" style="text-align: -webkit-center"
@click="isSingle?router.push({name:'single_gold', query:{state: 'sell'}}): router.push({name:'gold', query:{state: 'sell'}})">
<div class="rounded-full w-[42px] h-[42px] bg-orange-100 flex items-center justify-center">
<Icon class="text-orange-600" icon="vuesax-linear:money-send"/>
</div>
<div class="text-primary">فروش</div>
</div>
<div class="text-center w-full flex-flex-col items-center" style="text-align: -webkit-center"
@click="router.push({name:'wallet', query:{state: 'deposit'}})">
<div class="rounded-full w-[42px] h-[42px] bg-green-100 flex items-center justify-center">
<Icon class="text-green-600" icon="vuesax-linear:card-add"/>
</div>
<div class="text-primary">واریز نقدی</div>
</div>
<div class="text-center w-full flex-flex-col items-center" style="text-align: -webkit-center"
@click="router.push({name:'gold', query:{state: 'buy'}})">
<div class="rounded-full w-[42px] h-[42px] bg-blue-100 flex items-center justify-center">
<Icon class="text-blue-600" icon="vuesax-linear:money-receive"/>
</div>
<div class="text-primary">خرید</div>
</div>
<div class="text-center w-full flex-flex-col items-center" style="text-align: -webkit-center"
@click="router.push({name: 'fund'})">
<div class="rounded-full w-[42px] h-[42px] bg-yellow-100 flex items-center justify-center">
<Icon class="text-yellow-600" icon="vuesax-linear:archive-1"/>
</div>
<div class="text-primary">گنج</div>
</div>
</div>
<div class="mt-10 font-bold">نمودار نوسانات قیمت هر گرم طلای 18 عیار</div>
<div class="w-full mt-2 relative bg-gray-100 rounded-lg h-[88px] flex flex-col justify-center">
<img :src="img1" alt="" class="h-[88px] absolute">
<div class="w-full items-center flex flex-col">
<div class="text-gray-600">قیمت لحظه ای طلا</div>
<div v-if="price" class="flex gap-1 mt-3 text-xs items-center">
<div class="font-bold text-2xl">{{ usePriceWithoutType(price.price_last ?? 0) }}</div>
ریال
</div>
</div>
</div>
<div class="flex justify-around mt-8">
<div v-if="lastPrice" class="flex flex-col items-center">
<div class="text-xs">بالاترین قیمت خرید امروز</div>
<div class="text-green-600 flex gap-1 text-xs items-center">
<div class="text-base">{{ usePriceWithoutType(lastPrice.buy ?? 0) }}</div>
ریال
</div>
</div>
<div v-if="lastPrice" class="flex flex-col items-center">
<div class="text-xs">بالاترین قیمت فروش امروز</div>
<div class="text-red-600 flex gap-1 text-xs items-center">
<div class="text-base">{{ usePriceWithoutType(lastPrice.sell ?? 0) }}</div>
ریال
</div>
</div>
</div>
<a-spin :spinning="chartLoading">
<div id="chart" class="pb-20 mt-7 overflow-x-auto">
<apexchart :options="chartOptions" :series="series" :style="`width: ${chartWidth}`" height="350"
type="candlestick"></apexchart>
</div>
</a-spin>
</div>
<div v-else class="bg-white w-screen h-[40vh] px-5 m-[-1px] flex justify-center">
<a-spin :spinning="true"/>
</div>
</div>
<div :class="y>130? 'bg-white shadow opacity-95': ''"
class=" px-4 py-2 top-0 fixed w-screen background-color-transition ">
<div class="flex justify-between my-2">
<div class="flex items-center gap-2" @click.stop="router.push({name: 'user'})">
<!-- <img :src="testimg" alt="" class="w-[24px] h-[24px]">-->
<div :class="y>130? 'text-primary': 'text-white'" class="color-transition font-bold">
{{ userStore.userInfo?.mobile }}
</div>
</div>
<Icon :color="y>130? 'primary': 'white'" class="color-transition" icon="vuesax-linear:logout"
@click="showLogoutConfirm = true"/>
</div>
</div>
<DialogVant v-model:show="showLogoutConfirm" :closeOnClickOverlay="false" :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>
</template>
<template v-slot:button>
<div class="text-center text-red" @click="logout">
خروج
</div>
<div class="text-center" @click="showLogoutConfirm = false">
انصراف
</div>
</template>
</DialogVant>
</div>
</template>
<script lang="ts" setup>
import img from '@/assets/img/home_ly1.svg'
import img1 from '@/assets/img/home_ly2.svg'
import Icon from "@/components/BasicPacks/BasicIcon.vue";
import {usePriceWithoutType} from "../../../utils/usePrice";
import {computed, onMounted, ref, watch} from "vue";
import router from "@/router";
import * as echarts from 'echarts'
import {useWindowScroll} from '@vueuse/core'
import {loading, removeToken} from "@/utils";
import {useUserStore} from "@/store/userStore";
import {useWalletStore} from "@/store/walletStore";
import DialogVant from "@/components/DialogVant.vue";
import type {Price} from "@/models/home";
import {getChart, getLastPrice, getPrice} from "@/api/home";
import {toJalali} from "@/utils/useDateTime";
const userStore = useUserStore()
const walletStore = useWalletStore()
const chartLoading = ref<boolean>(false)
const {x, y} = useWindowScroll()
const series = ref<Chart[]>([{data: []}])
const price = ref<Price>()
const lastPrice = ref<Price>()
const main = ref(null)
const upColor = '#ec0000';
const upBorderColor = '#8A0000';
const downColor = '#00da3c';
const downBorderColor = '#008F28';
// const limitedPrice: Const = walletStore?.limitedPrice
watch(main, (n) => {
if (main.value !== null) {
// console.log('saaaa')
const echart = echarts.init(main.value, null, {
renderer: 'canvas'
})
echart.setOption({
xAxis: {
data: dates.value.values,
show: true,
},
yAxis: {
show: false,
scale: true,
},
series: [
{
type: 'candlestick',
data: series.value
}
]
})
}
})
onMounted(() => {
})
const limitedPrice = computed(() => {
if (walletStore.limitedPrice)
return walletStore?.limitedPrice[0]
})
const limitedBuyGold = computed(() => {
if (walletStore.limitedBuyGold)
return walletStore?.limitedBuyGold[0]
})
const chartWidth = computed(() => {
if (series.value.length < 30)
return '100vw'
else if (series.value.length < 60)
return '200vw'
else if (series.value.length < 90)
return '300vw'
else if (series.value.length < 120)
return '400vw'
else if (series.value.length < 160)
return '500vw'
else if (series.value.length < 190)
return '600vw'
else if (series.value.length < 210)
return '700vw'
else if (series.value.length < 240)
return '800vw'
else if (series.value.length < 270)
return '900vw'
else if (series.value.length < 300)
return '1000vw'
else if (series.value.length < 330)
return '1100vw'
else if (series.value.length < 360)
return '1200vw'
else if (series.value.length < 390)
return '1300vw'
})
async function initChart() {
try {
chartLoading.value = true
const data = await getChart()
data.forEach(item => {
series.value[0].data.push({
x: toJalali(item[0]),
y: item[1]
})
// console.log(x)
})
console.log(series.value)
} catch (e) {
console.log(e)
} finally {
chartLoading.value = false
}
}
async function initPrice() {
try {
loading.value = true
const data = await getPrice()
const dataLast = await getLastPrice()
price.value = data
lastPrice.value = dataLast
console.log(series.value)
} catch (e) {
console.log(e)
} finally {
loading.value = false
}
}
onMounted(() => {
initChart()
initPrice()
})
const chartOptions = ref(
{
chart: {
type: 'candlestick',
height: 600,
toolbar: {
autoSelected: 'pan',
show: false
},
},
title: {
// text: 'CandleStick Chart',
align: 'left'
},
xaxis: {
type: 'datetime',
labels: {
show: false
}
},
yaxis: {
show: false,
showAlways: false,
showForNullSeries: false,
tooltip: {
enabled: true
}
}
}
)
const showLogoutConfirm = ref<boolean>()
async function logout() {
// baseConfirm('آیا از حساب کاربری خارج می شوید؟',async () => {
removeToken()
await router.push({name: 'login'})
// console.log('salam')
// })
}
</script>
<style scoped>
</style>
+891
View File
@@ -0,0 +1,891 @@
<template>
<div class=" mt-20">
<!-- <div class="flex gap-7 overflow-x-scroll px-5">
<ProductInventory v-for="item in productInventorys" :ProductItem="item" class="shadow-lg my-5" :key="item.id"></ProductInventory>
</div>-->
<div>
<div
v-if="userStore.userInfo && !loading"
class="bg-white w-screen md:w-auto h-fit px-5 m-[-1px]"
>
<div
v-if="limitedPrice !== undefined && userStore?.userInfo.trade_active !== 1"
class="text-red text-xs flex gap-1 items-center justify-center mb-2"
>
<Icon icon="vuesax-linear:info-circle" size="16" />
حداقل مبلغ اولیه برای ثبت سفارش
{{ usePriceWithoutType(limitedPrice.value as number ?? 0) }} ریال می باشد.
</div>
<!-- <div class="bg-white">
<MySlider v-if="cardItems.length > 0" :items="cardItems" class=" pb-[20vh] "
style="touch-action: none" />
</div>-->
<!-- <div class="bg-gradient-to-l mt-3 p-1 shadow-lg from-primary rounded-lg p-px to-transparent ">-->
<div class="mt-3 p-1 shadow-lg from-primary rounded-lg p-px to-transparent">
<div class=" p-2 py-6 rounded-lg bg-tertiary">
<div class="flex justify-between ">
<!-- <div
class="text-center w-full flex-flex-col items-center home_appear_fade_in_up"
style="text-align: -webkit-center"
@click="router.push({ name: 'buyProduct', query: { state: 'sell' } })"
>
<div
class="rounded-full w-[42px] h-[42px] bg-primary flex items-center justify-center"
style="border: solid 1px #0A1B37"
>
<Icon class="text-tertiary" icon="vuesax-linear:money-send" />
</div>
<div class="text-primary">فروش</div>
</div>-->
<div
class="text-center w-full flex-flex-col items-center home_appear_fade_in_up"
style="text-align: -webkit-center"
@click="router.push({ name: 'buyProduct' })"
>
<div
class="rounded-full w-[50px] h-[50px] bg-primary flex items-center justify-center"
style="border: solid 1px #0A1B37"
>
<Icon class="text-tertiary" icon="vuesax-linear:money-receive" />
</div>
<div class="text-primary">خرید و فروش</div>
</div>
<div
class="text-center w-full flex-flex-col items-center home_appear_fade_in_down"
style="text-align: -webkit-center"
@click="router.push({ name: 'wallet', query: { state: 'deposit' } })"
>
<div
class="rounded-full w-[50px] h-[50px] bg-primary flex items-center justify-center"
style="border: solid 1px #0A1B37"
>
<Icon class="text-tertiary" icon="vuesax-linear:card-add" />
</div>
<div class="text-primary">واریز نقدی</div>
</div>
<div
class="text-center w-full flex-flex-col items-center home_appear_fade_in_up"
style="text-align: -webkit-center"
@click="openWholeBalanceVisible()"
>
<div
class="rounded-full w-[50px] h-[50px] bg-primary flex items-center justify-center "
style="border: solid 1px #0A1B37"
>
<Icon class="text-tertiary" icon="vuesax-linear:receipt-item" />
</div>
<div class="text-primary">موجودی</div>
</div>
<div
class="text-center w-full flex-flex-col items-center home_appear_fade_in_down"
style="text-align: -webkit-center"
@click="router.push({ name: 'fund' })"
>
<div
class="rounded-full w-[50px] h-[50px] bg-primary flex items-center justify-center"
style=" border: solid 1px #0A1B37"
>
<Icon class="text-tertiary font-bold" icon="vuesax-linear:cup" />
</div>
<div class="text-primary">دارایی ها</div>
</div>
</div>
</div>
<!-- <ADivider></ADivider>-->
<div>
<!-- <div @click="router.push({ name: 'fund' })">-->
<div class="bg-primary rounded-lg p-2 py-6 mt-2">
<div 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 class="flex mt-2 justify-center text-tertiary w-full z-20">
دارایی طلایی:
<div class="text-l mr-2 font-bold">{{ (userStore?.userInfo?.wallet?.count_gold ?? 0).toFixed(3)}}گرم</div>
<BasicIcon @click="openGoldModal" icon="vuesax-linear:info-circle" size="18" color="orange" />
</div>
<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>
<BasicIcon @click="openRialModal" icon="vuesax-linear:info-circle" size="18" color="orange" />
</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">
<BasicInfoItem
title="دارایی ریالی"
is-line
:info="`در این قسمت مجموع کیف پول ریالی (${usePrice(walletStore?.walletInfo?.count_cash_wallet ?? 0) }) + معادل ریالی محصولات (${ usePrice(walletStore?.walletInfo?.count_cash_wallets ?? 0)} ) را مشاهده میفرمایید.`"
infoHead="مجموع کل دارایی ریالی"
:value="usePriceWithoutType(walletStore.walletInfo?.count_cash ?? 0) + ' ریال'"
/>
</div>-->
</div>
<!-- <div class="flex justify-between">
<div class="text-center font-bold">دارایی شما</div>
<div class="flex items-center gap-2 mr-4">
<span class="text-base font-bold">{{ usePriceWithoutType(walletStore.walletInfo?.cash ?? 0) }}</span>
<span class="text-xs text-base">ریال</span>
</div>
<div class="flex items-center gap-2 ml-4">
<span class="text-base font-bold">{{ walletStore.walletInfo?.gold_sum.toFixed(3) }}</span>
<span class="text-xs text-base">گرم</span>
</div>
</div>-->
<!-- <div class="flex justify-between items-center ">
<div class="text-sm">
موجودی کیف پول شما:
</div>
<div class="flex items-center gap-2">
<span class="text-base font-bold">{{ usePrice(walletStore.walletInfo?.cash ?? 0) }}</span>
</div>
</div>
<div class="flex justify-between items-center ">
<div class="text-sm">
موجودی کیف طلای شما:
</div>
<div class="flex items-center gap-2">
<span class="text-base font-bold">{{ walletStore.walletInfo?.gold }}</span>
<span class="text-xs text-gray-500">گرم</span>
</div>
</div>-->
<!-- <div class="flex justify-between items-center ">
<div class="text-sm">
ارزش کل طلا های شما:
</div>
<div class="flex items-center gap-2">
<span class="text-base font-bold">{{ walletStore.walletInfo?.gold_sum }}</span>
<span class="text-xs text-gray-500">گرم</span>
</div>
</div>-->
<!-- <div class="flex justify-between items-center ">
<div class="text-sm">
</div>
<div class="flex items-center gap-2">
<div v-if="walletStore.walletInfo?.gold_sum*goldVal">
<Vue3Odometer
:value="walletStore.walletInfo?.gold_sum*goldVal"
class="o-text !text-base font-bold"
style="font-family: iran-sans; direction: ltr"
v-if="key % 2 === 0"
/>
</div>
<span class="text-xs text-gray-500">ریال</span>
</div>
</div>-->
</div>
<div
class="w-full relative mt-5 border-gray-200 border-1 rounded-lg h-[88px] flex flex-col justify-center home_appear_fade_in"
>
<div class="w-full items-center flex flex-col">
<div class="text-gray-600">قیمت خرید از گلد دات آی آر</div>
<div v-if="price" class="flex gap-1 mt-3 text-xs items-center">
<!-- <div id="odometer" class="font-bold text-2xl odometer animated fadeIn">
&lt;!&ndash; {{ usePriceWithoutType(useCounterAnim(price.price_last) ?? 0) }}&ndash;&gt;
</div>-->
<!-- <div id="odometer" class="odometer animated fadeIn"></div>-->
<div v-if="percentPriceChanged()!=0"
class="bg-green-100 text-green-600 flex flex-row-reverse rounded-lg justify-between items-center gap-2 px-3"
:class="percentPriceChanged()>=0?'bg-green-100 text-green-600':'bg-red-100 text-red-600'">
<div dir="ltr">{{ useTowDecimal(percentPriceChanged()) }}%</div>
<div>
<icon v-if="percentPriceChanged()<0" size="15px" icon="vuesax-linear:received" color="red-600"></icon>
<icon v-else size="15px" icon="vuesax-linear:send" color="green-600"></icon>
</div>
</div>
<Vue3Odometer
:value="goldVal"
class="o-text !text-2xl font-bold"
style="font-family: iran-sans; direction: ltr"
v-if="key % 2 === 0"
/>
ریال
</div>
</div>
</div>
<div class="flex mt-5 gap-1 bg-primary text-[#CEA34C] font-bold justify-center rounded-lg py-5"
@click="router.push({ name: 'buyProduct', query: { cat: 'coin'} })">
<div>خرید و فروش</div>
</div>
<!-- <div class="mt-10 font-bold home_appear_fade_in" @click="update">
نوسانات قیمت هر گرم طلای 18 عیار
</div>-->
<!-- <a-spin :spinning="chartLoading" class="relative">
<div ref="target" class="absolute"></div>
<div v-if="!chartLoading" id="chart" class="pb-20 mt-7 overflow-x-auto">
&lt;!&ndash; <apexchart v-if="targetIsVisible" :options="chartOptions" :series="test_series"
:style="`width: ${chartWidth}`"
height="350"
type="candlestick"></apexchart>&ndash;&gt;
</div>
</a-spin>-->
<!-- <a-spin :spinning="chartLoading" >-->
<!-- <div ref="target" class="absolute"></div>-->
<!-- <div id="chart" class="mt-7">-->
<div class="bg-gray-50 w-full flex justify-evenly rounded-lg py-4 mt-4 h-[15rem]">
<div class="w-full text-center pt-2">
<a-radio-group v-model:value="value" button-style="solid">
<a-radio-button value="a" @click="updateData('DAILY')">24 ساعت اخیر</a-radio-button>
<a-radio-button value="b" @click="updateData('WEEKLY')">هفته گذشته</a-radio-button>
<a-radio-button value="c" @click="updateData('MONTHLY')">ماه گذشته</a-radio-button>
</a-radio-group>
<div id="chart-timeline">
<apexchart
type="area"
height="200"
ref="chart"
:options="priceChartOptions"
:series="priceChartSeries"
></apexchart>
</div>
</div>
</div>
<div class=" w-full flex justify-evenly rounded-lg py-2 home_appear_fade_in mt-6 pb-25">
<div class="text-center w-full">
<div>بالاترین قیمت امروز</div>
<div v-if="lastPrice" class="flex flex-col items-center mt-3">
<div class="text-green-600 flex gap-1 text-xs items-center">
<div class="text-base">{{ usePriceWithoutType(price?.buy ?? 0) }}</div>
ریال
</div>
</div>
</div>
<a-divider class="bg-gray-200 !h-auto !my-2" type="vertical" />
<div class="text-center w-full">
<div>پایین ترین قیمت امروز</div>
<div class="flex w-full mt-3 justify-evenly">
<div v-if="lastPrice" class="flex flex-col items-center">
<div class="text-red-600 flex gap-1 text-xs items-center">
<div class="text-base">{{ usePriceWithoutType(price?.sell ?? 0) }}</div>
ریال
</div>
</div>
</div>
</div>
</div>
</div>
<div v-else class="bg-white w-screen md:w-auto h-[80vh] px-5 m-[-1px] flex justify-center ">
<HomeSkeleton class="w-full" />
</div>
<!-- <div class="relative pt-15 overflow-hidden ">-->
<!-- <div class="absolute left&#45;&#45;12 top-0">-->
<!-- <img :src="image">-->
<!-- </div>-->
<!-- <div class="bg-primary pb-30"-->
<!-- style="background: linear-gradient(to bottom, #fff,#fff, #0A1B37, #0A1B37);"-->
<!-- >-->
<!-- <div class=" text-tertiary text-2xl pt-6 pr-5 pl-50" style="font-size: 26px;font-weight: 600; color: #0A1B37" >ارسال کالا بعد از ثبت سفارش</div>-->
<!-- <div class="pr-5 pl-8 pt-10 text-tertiary ">میتوانید با خرید محصولات بعد از ثبت سفارش درخواست ارسال را-->
<!-- ثبت کرده و زیر 24 ساعت خرید خود را دریافت کنید-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
</div>
<div
:class="y > 50 ? 'bg-white shadow opacity-95' : ''"
class="px-4 py-2 top-0 z-5 wrap-fix background-color-transition"
>
<div class="flex justify-between my-2">
<div class="flex items-center gap-2" @click.stop="router.push({ name: 'user' })">
<!-- <img :src="testimg" alt="" class="w-[24px] h-[24px]">-->
<div
class="z-100000 rounded-full border-1"
:class="y > 50 ? 'text-primary border-primary' : 'text-primary border-primary'"
>
<Icon icon="vuesax-linear:user" size="20" />
</div>
<div :class="y > 50 ? 'text-primary' : 'text-primary'" class="color-transition font-bold">
{{ userStore.userInfo?.name }}
</div>
</div>
<Icon
:color="y > 50 ? '#0A1B37' : '#0A1B37'"
class="color-transition"
icon="vuesax-linear:logout"
@click="showLogoutConfirm = true"
/>
</div>
</div>
<DialogVant v-model:show="showLogoutConfirm" :closeOnClickOverlay="false" :timeOut="-1">
<!-- <template v-slot:img>
<img :src="registerDelayImage" alt="" class="opacity-80">
</template>-->
<template v-slot:title>
<div class="flex flex-col items-center">
<DotLottieVue
class="w-11rem h-11rem"
autoplay
src="https://lottie.host/129cf3a1-df84-4758-a856-58c133ae6013/R5RqclXA8G.json"
/>
<div class="p-5 text-sm">آیا از خروج خود اطمینان دارید؟</div>
</div>
</template>
<template v-slot:button>
<div class="text-center text-red flex items-center justify-center" @click="logout">
<a-spin :spinning="logoutLoading" size="small"> خروج</a-spin>
</div>
<div class="text-center" @click="showLogoutConfirm = false">انصراف</div>
</template>
</DialogVant>
</div>
<BasicActionSheet v-model:show="wholeBalanceVisible">
<div class="pb-20">
<div>
<div class="w-full text-center font-bold">موجودی ها</div>
<div class="h-30vh overflow-y-auto">
<div class="mt-5">
<BasicInfoItem
class="flex justify-between"
title="مجموعه کل دارایی طلایی"
is-line
:info="`در این قسمت مجموع کل وزن طلای آبشده (${(walletStore.walletInfo?.gold ?? 0)?.toFixed(3)}) + ارزش دارایی ها (${(walletStore.walletInfo?.treasure_sum ?? 0)?.toFixed(3)} ) را مشاهده میفرمایید.`"
infoHead="مجموع کل دارایی طلایی"
:value="parseFloat((walletStore.walletInfo?.gold_sum ?? 0).toFixed(2)) + ' گرم'"
/>
<!-- <a-divider class="!my-1" />
<BasicInfoItem
class="flex justify-between"
title="میزان طلای آبشده"
is-line
:value="parseFloat((walletStore.walletInfo?.gold ?? 0)?.toFixed(3)) + ' گرم'"
/>
<a-divider class="!my-1" />
<BasicInfoItem
class="flex justify-between"
title="ارزش گنج ها"
is-line
:value="parseFloat((walletStore.walletInfo?.treasure_sum ?? 0)?.toFixed(3)) + ' گرم'"
/>-->
<a-divider class="!my-1" />
<BasicInfoItem
class="flex justify-between"
title="دارایی کیف پول ریالی"
is-line
:value="usePrice(walletStore.walletInfo?.cash ?? 0)"
/>
<a-divider class="!my-1" />
<BasicInfoItem
class="flex justify-between"
title="دارایی کیف پول طلایی"
is-line
:value="(walletStore.walletInfo?.count_gold_wallet ?? 0) + ' گرم'"
/>
<a-divider class="!my-1" />
<!-- <BasicInfoItem class="flex justify-between" title="دارایی کیف پول(به گرم)" is-line
:value="((walletStore.walletInfo?.cash?? 0) / (goldVal?? 0)).toFixed(2)+ ' گرم'" />
<a-divider class="!my-1" />-->
<BasicInfoItem
class="flex justify-between"
title="ارزش کل دارایی شما"
is-line
:value="
usePrice(
(
(walletStore.walletInfo?.gold_sum ?? 0) * (goldVal ?? 0) +
(walletStore.walletInfo?.cash ?? 0)
).toFixed(0)
)
"
/>
</div>
</div>
</div>
</div>
</BasicActionSheet>
</template>
<script lang="tsx" setup>
import img from '@/assets/img/home_ly1.svg'
import img1 from '@/assets/img/home_ly2.svg'
import Icon from '@/components/BasicPacks/BasicIcon.vue'
import { usePrice, usePriceWithoutType, useTowDecimal } from '../../../utils/usePrice'
import {computed, createVNode, onMounted, onUnmounted, ref, watch, watchEffect} from 'vue'
import router from '@/router'
import * as echarts from 'echarts'
import { useIntersectionObserver, useWindowScroll } from '@vueuse/core'
import { loading, removeToken } from '@/utils'
import { useUserStore } from '@/store/userStore'
import { useWalletStore } from '@/store/walletStore'
import DialogVant from '@/components/DialogVant.vue'
import type { Price } from '@/models/home'
import { getAllPrices, getChart, getLastPrice, getPrice } from '@/api/home'
// import odometer from 'odometer/odometer'
import Vue3Odometer from 'vue3-odometer'
import 'odometer/themes/odometer-theme-default.css'
import HomeSkeleton from '@/views/base/home/components/HomeSkeleton.vue'
import { toJalaliNotime } from '@/utils/useDateTime'
import {
getLastPrices,
getUpPrice,
lastPrice,
percentPriceChanged,
price,
setIntervalGetAllPrice,
stopPriceInterval
} from '@/utils/price'
import { DotLottieVue } from '@lottiefiles/dotlottie-vue'
import BasicActionSheet from '@/components/BasicPacks/BasicActionSheet.vue'
import BasicInfoItem from '@/components/BasicPacks/BasicInfoItem.vue'
import MySlider from '@/views/base/wallet/components/mySlider/MySlider.vue'
import type { Card, PWallet, Wallet } from '@/models/wallet'
import { getActivatedCards } from '@/api/wallet'
import banner1 from '@/assets/img/banner/banner1.png'
import banner2 from '@/assets/img/banner/banner2.png'
import image from '@/assets/img/image.svg'
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
import ProductInventory from '@/views/base/home/components/ProductInventory.vue'
import type { PInventory, Product } from '@/models/products'
import { getProductInventory } from '@/api/products'
import type { Fund } from '@/models/fund'
import type { TableOutput } from '@/models/table'
import { useFundUserStore } from '@/store/fundStore'
import {Modal} from "ant-design-vue";
import {ExclamationCircleOutlined} from "@ant-design/icons-vue";
import {message} from "ant-design-vue/es";
const userStore = useUserStore()
const walletStore = useWalletStore()
const chartLoading = ref<boolean>(false)
const wholeBalanceVisible = ref<boolean>(false)
const { x, y } = useWindowScroll()
const series = ref<Chart[]>([{ data: [] }])
const key = ref<number>(0)
const cardItems = [banner1, banner2]
const main = ref(null)
const logoutLoading = ref(false)
const productInventorys = ref<PInventory[] | undefined>()
const value = ref<string>('a')
const items = ref<Fund[]>([])
const tableOutput = ref<TableOutput<Fund> | null>(null)
const inventory = ref<number>(0)
const sumGold = ref<number>(0)
const fundStore = useFundUserStore()
async function initTable() {
try {
loading.value = true
tableOutput.value = fundStore.myFunds ?? await fundStore.getMyFund() ?? null
items.value.push(...tableOutput.value?.rows ?? [])
} catch (e) {
console.log(e)
} finally {
loading.value = false
}
}
onUnmounted(() => {
stopPriceInterval()
})
/*
onMounted(() => {
animateNum(2)
})
*/
const goldVal = ref<number | undefined>()
function openWholeBalanceVisible() {
items.value.forEach(x => {
if (x.title !== 'آبشده نقدی')
inventory.value += x?.wallet?.gold ?? 0
})
wholeBalanceVisible.value = true
}
function sumOfGold() {
items.value.forEach(x => {
if (x.title !== 'آبشده نقدی')
return sumGold.value += x?.wallet?.gold ?? 0
})
}
function update() {
setInterval(() => {
goldVal.value = lastPrice?.value.price_last
}, 500)
}
const target = ref(null)
const targetIsVisible = ref(false)
const isHidden = ref<boolean>(false)
const { stop } = useIntersectionObserver(target, ([{ isIntersecting }], observerElement) => {
targetIsVisible.value = isIntersecting
console.log('saaaaa', targetIsVisible.value)
})
watch(main, (n) => {
if (main.value !== null) {
// console.log('saaaa')
const echart = echarts.init(main.value, null, {
renderer: 'candlestick'
})
echart.setOption({
xAxis: {
data: dates.value.values,
show: true
},
yAxis: {
show: false,
scale: true
},
series: [
{
type: 'candlestick',
data: series.value
}
]
})
}
})
//whole prices
const priceChartSeries = ref<{ data: [number, number][] }[]>([
{
name: 'قیمت',
data: []
}
])
const selection = ref('DAILY')
const chartRef = ref<ApexCharts | null>(null)
const priceChartOptions = ref({
chart: {
id: 'نوسانات قیمت',
type: 'candlestick',
height: 200,
toolbar: {
show: false // Disable the toolbar to remove download and other options
},
zoom: {
autoScaleYaxis: true
},
events: {
mounted(chart) {
chartRef.value = chart
}
}
},
grid: {
padding: {
top: 0,
right: 0,
bottom: 0,
left: 0
},
yaxis: {
lines: {
show: false
}
}
},
stroke: {
width: 2
},
dataLabels: {
enabled: false,
// formatter: (val) => toPersianNumber(val),
style: {
fontFamily: '\'IranSans\', sans-serif'
}
},
yaxis: {
tickAmount: 8,
show: false,
title: {
style: {
fontSize: '13px',
fontFamily: '\'IranSans\', sans-serif',
fontWeight: 'bold'
}
},
labels: {
formatter: (val) => toPersianNumber(usePrice(val)),
style: {
fontSize: '13px',
fontFamily: '\'IranSans\', sans-serif'
}
}
},
xaxis: {
show: false,
type: 'datetime',
axisTicks: {
show: false
},
tooltip: {
enabled: false
},
labels: {
show: false,
rotate: -45,
style: {
fontFamily: '\'IranSans\', sans-serif'
}
// formatter: (val) => toPersianNumber(toJalaliNotime(new Date(val).toString()))
},
axisBorder: {
show: false
}
},
tooltip: {
x: {
// formatter: (val) => toPersianNumber(toJalaliNotime(new Date(val).toString()))
formatter: (value) => {
const date = new Date(value)
return `${date.toLocaleDateString('fa-IR')} - ${date.toLocaleTimeString('fa-IR', {
hour: '2-digit',
minute: '2-digit'
})}`
}
},
formatter: (val) => toPersianNumber(usePrice(val)),
style: {
fontFamily: '\'IranSans\', sans-serif'
// fontWeight: 'bold'
},
markers: {
show: false
}
},
colors: ['#0A1B37'],
fill: {
type: 'gradient',
gradient: {
shadeIntensity: 1,
opacityFrom: 0.7,
opacityTo: 0.9,
stops: [0, 100]
}
}
})
const toPersianNumber = (num) => {
return num.toString().replace(/\d/g, (d) => '۰۱۲۳۴۵۶۷۸۹'[d])
}
const fetchPrices = async () => {
try {
const response = await getAllPrices()
const data = response.data?.prices
const selectedData = data[selection.value] || []
priceChartSeries.value[0].data = selectedData.map((item) => [item.timestamp, item.value - 1])
// console.log(priceChartSeries.value[0].data)
chartRef.value?.updateOptions({
series: priceChartSeries.value
})
} catch (error) {
console.error('خطا در دریافت داده‌ها', error)
}
}
const updateData = (timeline) => {
selection.value = timeline
fetchPrices()
}
const limitedPrice = computed(() => {
if (walletStore.limitedPrice) return walletStore?.limitedPrice[0]
})
const test_series = [
{
name: 'candle',
data: []
}
]
async function initChart() {
try {
// chartLoading.value = true
const data = await getChart()
/* data.forEach(item => {
test_series[0].data.push({
x: toJalali(item[0]),
y: item[1]
})
// console.log(x)
})*/
data.forEach((item) => {
test_series[0].data.push({
x: item[0],
y: item[1]
})
// console.log(x)
})
// console.log(test_series)
} catch (e) {
console.log(e)
} finally {
// chartLoading.value = false
}
}
async function initPrice() {
try {
// loading.value = true
const val = price?.value?.price_last
await getLastPrices()
await getUpPrice()
await setIntervalGetAllPrice()
// console.log('runhome')
if (val !== price?.value?.price_last) {
update()
/* key.value++
key.value++*/
}
/* price.value = data
lastPrice.value = dataLast*/
goldVal.value = 0
// console.log(price?.value.price_last)
if (userStore.isFirst) {
const timer = setInterval(function() {
update()
// if (current == end) {
userStore.isFirst = false
clearInterval(timer)
// }
}, 100)
} else {
goldVal.value = price.value?.price_last
}
// console.log(series.value)
} catch (e) {
console.log(e)
} finally {
// loading.value = false
}
}
async function initProductInventory() {
try {
// loading.value = true
// let { rows } = await getProductInventory()
// fundStore.myFunds
// productInventorys.value = fundStore.myFunds?.rows
productInventorys.value = items.value.sort((a, b) => {
if (a.wallet?.gold ?? 0 < b.wallet?.gold ?? 0)
return -1
if (a.wallet?.gold ?? 0 > b.wallet?.gold ?? 0)
return 1
return 0
})
// console.log(productInventorys.value)
} catch (e) {
console.log(e)
} finally {
// loading.value = false
}
}
onMounted(async () => {
try {
loading.value = true
await initTable()
await initProductInventory()
// await initChart()
await initPrice()
await fetchPrices()
update()
} catch (e) {
console.log(e)
} finally {
loading.value = false
}
})
onUnmounted(() => {
stopPriceInterval()
// console.log('okhome')
})
const showLogoutConfirm = ref<boolean>()
async function logout() {
logoutLoading.value = true
// baseConfirm('آیا از حساب کاربری خارج می شوید؟',async () => {
userStore.userInfo = undefined
walletStore.walletInfo = undefined
/* userStore.$reset()
walletStore.$reset()*/
removeToken()
await router.push({ name: 'login' })
logoutLoading.value = true
window.location.reload()
// console.log('salam')
// })
}
async function openGoldModal() {
Modal.confirm({
title: `در این قسمت مجموع کل وزن طلای آبشده (${(walletStore.walletInfo?.gold ?? 0)?.toFixed(3)}) + ارزش دارایی ها (${(walletStore.walletInfo?.count_gold_wallets ?? 0)?.toFixed(3)} ) را مشاهده میفرمایید.`,
okText: 'متوجه شدم',
centered: true,
cancelButtonProps: { style: { display: 'none' } },
})
}
async function openRialModal() {
Modal.confirm({
title: `در این قسمت مجموع کیف پول ریالی (${usePrice(walletStore?.walletInfo?.count_cash_wallet ?? 0) }) + معادل ریالی محصولات (${ usePrice(walletStore?.walletInfo?.count_cash_wallets ?? 0)} ) را مشاهده میفرمایید.`,
okText: 'متوجه شدم',
centered: true,
cancelButtonProps: { style: { display: 'none' } },
})
}
</script>
<style lang="less">
.odometer {
font-size: 60px;
//margin: 200px 0;
text-align: center;
width: 100%;
animation-duration: 3s;
}
label:focus-within {
box-shadow: none !important
}
.chart-container {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
display: flex;
}
apexchart {
width: 100% !important;
height: 100% !important;
padding: 0 !important;
margin: 0 !important;
}
</style>
<script setup lang="ts">
</script>
+389
View File
@@ -0,0 +1,389 @@
<template>
<div class="">
<!-- <div class="bg-primary h-30 mt-[-3rem] z-100000000000"></div>-->
<div class="fixed h-[60vh] bg-[#0A1B37] w-screen">
<div class="flex w-full justify-around mt-18">
<div class="text-center">
<div class="text-[#E5D7CE] text-xs ">موجودی کیف طلا</div>
<div class="flex justify-center mt-1 text-[#B79379] gap-1 items-center text-xs">
<div class="text-white text-lg">{{ walletStore?.walletInfo?.gold ?? 0 }}</div>
گرم
</div>
</div>
<div class="text-center">
<div class="text-[#E5D7CE] text-xs ">سقف اعتبار خرید طلا</div>
<div class="flex justify-center mt-1 text-[#B79379] gap-1 items-center text-xs">
<div class="text-white text-lg">{{ userStore?.userInfo?.gram ?? 0 }}</div>
گرم
</div>
</div>
<div class="text-center">
<div class="text-[#E5D7CE] text-xs ">موجودی کیف پول</div>
<div class="flex justify-center mt-1 text-[#B79379] gap-1 items-center text-xs">
<div class="text-white text-lg">
{{ walletStore?.walletInfo?.cash === undefined ? 0 : usePriceWithoutType(walletStore.walletInfo?.cash) }}
</div>
ریال
</div>
</div>
</div>
</div>
<div class="pt-[9rem] relative">
<img :src="img" alt="" class="w-screen h-[8rem]">
<!-- <div class="w-screen bg-white w-screen h-[calc(100vh-16rem-70px)] px-5">-->
<div v-if="userStore.userInfo && !loading" class="bg-white w-screen h-fit px-5 m-[-1px]">
<!-- <a-alert :message="``" type="warning" show-icon/>-->
<!-- {{limitedPrice === undefined}}-->
<div v-if="limitedPrice !== undefined && userStore?.userInfo.trade_active !== 1"
class="text-red text-xs flex gap-1 items-center justify-center mb-2">
<Icon icon="vuesax-linear:info-circle" size="16"/>
حداقل مبلغ اولیه برای ثبت سفارش {{ usePriceWithoutType(limitedPrice.value as number ?? 0) }} ریال می باشد.
</div>
<div class="bg-gray-50 w-full flex justify-evenly rounded-lg py-2">
<div class="text-center w-full">
<div>قیمت خرید از گلد دات آی آر</div>
<div class="text-[10px] text-gray-500">(هر گرم طلای 18 عیار)</div>
<div class="flex w-full mt-3 justify-evenly">
<!-- <div class="text-[10px] gap-1 flex bg-green-100 rounded-xl px-1 text-green-600 items-center">
<Icon icon="vuesax-linear:received" size="10"/>
<div>2%</div>
</div>-->
<div v-if="price" class="flex text-gray-500 text-xs items-center gap-1">
<div class="text-primary font-bold text-base">{{ usePriceWithoutType(price.buy ?? 0) }}</div>
ریال
</div>
</div>
</div>
<a-divider class="bg-gray-200 !h-auto !my-2" type="vertical"/>
<div class="text-center w-full">
<div>قیمت فروش به گلد دات آی آر</div>
<div class="text-[10px] text-gray-500">(هر گرم طلای 18 عیار)</div>
<div class="flex w-full mt-3 justify-evenly">
<!-- <div class="text-[10px] gap-1 flex bg-red-100 rounded-xl px-1 text-red-600 items-center">
<Icon icon="vuesax-linear:send" size="10"/>
<div>3%</div>
</div>-->
<div v-if="price" class="flex text-gray-500 text-xs items-center gap-1">
<div class="text-primary font-bold text-base">{{ usePriceWithoutType(price.sell ?? 0) }}</div>
ریال
</div>
</div>
</div>
</div>
<div class="flex justify-between mt-8">
<div class="text-center w-full flex-flex-col items-center" style="text-align: -webkit-center"
@click="router.push({name:'gold', query:{state: 'sell'}})">
<div class="rounded-full w-[42px] h-[42px] bg-orange-100 flex items-center justify-center">
<Icon class="text-orange-600" icon="vuesax-linear:money-send"/>
</div>
<div class="text-primary">فروش</div>
</div>
<div class="text-center w-full flex-flex-col items-center" style="text-align: -webkit-center"
@click="router.push({name:'wallet', query:{state: 'deposit'}})">
<div class="rounded-full w-[42px] h-[42px] bg-green-100 flex items-center justify-center">
<Icon class="text-green-600" icon="vuesax-linear:card-add"/>
</div>
<div class="text-primary">واریز نقدی</div>
</div>
<div class="text-center w-full flex-flex-col items-center" style="text-align: -webkit-center"
@click="router.push({name:'gold', query:{state: 'buy'}})">
<div class="rounded-full w-[42px] h-[42px] bg-blue-100 flex items-center justify-center">
<Icon class="text-blue-600" icon="vuesax-linear:money-receive"/>
</div>
<div class="text-primary">خرید</div>
</div>
<div class="text-center w-full flex-flex-col items-center" style="text-align: -webkit-center"
@click="router.push({name: 'fund'})">
<div class="rounded-full w-[42px] h-[42px] bg-yellow-100 flex items-center justify-center">
<Icon class="text-yellow-600" icon="vuesax-linear:archive-1"/>
</div>
<div class="text-primary">صندوق</div>
</div>
</div>
<div class="mt-10 font-bold">نمودار نوسانات قیمت هر گرم طلای 18 عیار</div>
<div class="w-full mt-2 relative bg-gray-100 rounded-lg h-[88px] flex flex-col justify-center">
<img :src="img1" alt="" class="h-[88px] absolute">
<div class="w-full items-center flex flex-col">
<div class="text-gray-600">قیمت لحظه ای طلا</div>
<div v-if="price" class="flex gap-1 mt-3 text-xs items-center">
<div class="font-bold text-2xl">{{ usePriceWithoutType(price.price_last ?? 0) }}</div>
ریال
</div>
</div>
</div>
<div class="flex justify-around mt-8">
<div v-if="lastPrice" class="flex flex-col items-center">
<div class="text-xs">بالاترین قیمت خرید امروز</div>
<div class="text-green-600 flex gap-1 text-xs items-center">
<div class="text-base">{{ usePriceWithoutType(lastPrice.buy ?? 0) }}</div>
ریال
</div>
</div>
<div v-if="lastPrice" class="flex flex-col items-center">
<div class="text-xs">بالاترین قیمت فروش امروز</div>
<div class="text-red-600 flex gap-1 text-xs items-center">
<div class="text-base">{{ usePriceWithoutType(lastPrice.sell ?? 0) }}</div>
ریال
</div>
</div>
</div>
<a-spin :spinning="chartLoading">
<!-- <div id="chart" class="pb-20 mt-7 overflow-x-auto">
&lt;!&ndash; <apexchart :options="chartOptions" :series="series" :style="`width: ${chartWidth}`" height="350"
type="candlestick"></apexchart>&ndash;&gt;
<div ref="main" class="w-full aspect-square"></div>
</div>-->
<div class="overflow-x-auto pb-10">
<div ref="main" :style="`width: ${chartWidth}`" class="h-[20rem]"></div>
</div>
</a-spin>
</div>
<div v-else class="bg-white w-screen h-[40vh] px-5 m-[-1px] flex justify-center">
<a-spin :spinning="true"/>
</div>
</div>
<div :class="y>130? 'bg-white shadow opacity-95': ''"
class=" px-4 py-2 top-0 fixed w-screen background-color-transition ">
<div class="flex justify-between my-2">
<div class="flex items-center gap-2" @click.stop="router.push({name: 'user'})">
<!-- <img :src="testimg" alt="" class="w-[24px] h-[24px]">-->
<div :class="y>130? 'text-primary': 'text-white'" class="color-transition font-bold">
{{ userStore.userInfo?.mobile }}
</div>
</div>
<Icon :color="y>130? 'primary': 'white'" class="color-transition" icon="vuesax-linear:logout"
@click="showLogoutConfirm = true"/>
</div>
</div>
<DialogVant v-model:show="showLogoutConfirm" :closeOnClickOverlay="false" :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>
</template>
<template v-slot:button>
<div class="text-center text-red" @click="logout">
خروج
</div>
<div class="text-center" @click="showLogoutConfirm = false">
انصراف
</div>
</template>
</DialogVant>
</div>
</template>
<script lang="ts" setup>
import img from '@/assets/img/home_ly1.svg'
import img1 from '@/assets/img/home_ly2.svg'
import Icon from "@/components/BasicPacks/BasicIcon.vue";
import {usePriceWithoutType} from "../../../utils/usePrice";
import {computed, onMounted, ref, watch} from "vue";
import router from "@/router";
import * as echarts from 'echarts'
import {useWindowScroll} from '@vueuse/core'
import {loading, removeToken} from "@/utils";
import {useUserStore} from "@/store/userStore";
import {useWalletStore} from "@/store/walletStore";
import DialogVant from "@/components/DialogVant.vue";
import type {Price} from "@/models/home";
import {getChart, getLastPrice, getPrice} from "@/api/home";
const userStore = useUserStore()
const walletStore = useWalletStore()
const chartLoading = ref<boolean>(false)
const {x, y} = useWindowScroll()
const series = ref<Array<Array<number>>>([])
const dates = ref<Array<string>>([])
const price = ref<Price>()
const lastPrice = ref<Price>()
const main = ref(null)
const upColor = '#ec0000';
const upBorderColor = '#8A0000';
const downColor = '#00da3c';
const downBorderColor = '#008F28';
// const limitedPrice: Const = walletStore?.limitedPrice
watch(main, (n) => {
if (main.value !== null) {
// console.log('saaaa')
const echart = echarts.init(main.value, null, {
renderer: 'canvas'
})
echart.setOption({
xAxis: {
data: dates.value.values,
show: true,
},
yAxis: {
show: false,
scale: true,
},
series: [
{
type: 'candlestick',
data: series.value
}
]
})
}
})
onMounted(() => {
})
const limitedPrice = computed(() => {
if (walletStore.limitedPrice)
return walletStore?.limitedPrice[0]
})
const limitedBuyGold = computed(() => {
if (walletStore.limitedBuyGold)
return walletStore?.limitedBuyGold[0]
})
const chartWidth = computed(() => {
if (series.value.length < 30)
return '100vw'
else if (series.value.length < 60)
return '200vw'
else if (series.value.length < 90)
return '300vw'
else if (series.value.length < 120)
return '400vw'
else if (series.value.length < 160)
return '500vw'
else if (series.value.length < 190)
return '600vw'
else if (series.value.length < 210)
return '700vw'
else if (series.value.length < 240)
return '800vw'
else if (series.value.length < 270)
return '900vw'
else if (series.value.length < 300)
return '1000vw'
else if (series.value.length < 330)
return '1100vw'
else if (series.value.length < 360)
return '1200vw'
else if (series.value.length < 390)
return '1300vw'
})
function splitData(rawData) {
const categoryData = [];
const values = [];
for (var i = 0; i < rawData.length; i++) {
categoryData.push(rawData[i].splice(0, 1)[0]);
values.push(rawData[i]);
}
return {
categoryData: categoryData,
values: values
};
}
async function initChart() {
try {
chartLoading.value = true
const data = await getChart()
/* data.forEach(item => {
series.value[0].data.push({
x: toJalali(item[0]),
y: item[1]
})
// console.log(x)
})*/
data.forEach(item => {
series.value.push(item[1])
dates.value.push(item[0])
})
// series.value = data
// series.value = splitData(data)
console.log(dates.value)
console.log(series.value)
} catch (e) {
console.log(e)
} finally {
chartLoading.value = false
}
}
async function initPrice() {
try {
loading.value = true
const data = await getPrice()
const dataLast = await getLastPrice()
price.value = data
lastPrice.value = dataLast
console.log(series.value)
} catch (e) {
console.log(e)
} finally {
loading.value = false
}
}
onMounted(() => {
initChart()
initPrice()
})
const chartOptions = ref(
{
chart: {
type: 'candlestick',
height: 600,
toolbar: {
autoSelected: 'pan',
show: false
},
},
title: {
// text: 'CandleStick Chart',
align: 'left'
},
xaxis: {
type: 'datetime',
labels: {
show: false
}
},
yaxis: {
show: false,
showAlways: false,
showForNullSeries: false,
tooltip: {
enabled: true
}
}
}
)
const showLogoutConfirm = ref<boolean>()
async function logout() {
// baseConfirm('آیا از حساب کاربری خارج می شوید؟',async () => {
removeToken()
await router.push({name: 'login'})
window.location.reload()
// console.log('salam')
// })
}
</script>
<style scoped>
</style>
+866
View File
@@ -0,0 +1,866 @@
<template>
<div class="h-35rem overflow-y-auto">
<!-- <div class="bg-primary h-30 mt-[-3rem] z-100000000000"></div>-->
<div class="h-[60vh] bg-[#0A1B37] wrap-fix">
<div class="w-full justify-around mt-18">
<div class="flex flex-col w-full justify-center items-center">
<div class="text-center">
<div class="text-[#E5D7CE] text-xs">مجموع دارایی طلایی</div>
<transition mode="out-in" name="fade">
<div
v-if="!isHidden"
class="flex justify-center mt-1 text-[#B79379] gap-1 items-center text-xs"
@click="isHidden = true"
>
<div class="text-white text-base">{{ walletStore.walletInfo?.gold_sum ?? 0 }}</div>
گرم
</div>
<div
v-else
class="flex gap-2 items-center justify-center mt-3 mb-2"
@click="isHidden = false"
>
<div class="bg-white rounded-full w-2 h-2" />
<div class="bg-white rounded-full w-2 h-2" />
<div class="bg-white rounded-full w-2 h-2" />
<div class="bg-white rounded-full w-2 h-2" />
</div>
</transition>
</div>
<div class="text-white flex" @click="wholeBalanceVisible = true">
<div class="ml-[-1.5rem]">موجودی ها</div>
<DotLottieVue
class="w-5rem h-5rem mt-[-1.6rem] ml-[-2rem]"
autoplay
loop
src="https://lottie.host/3d46ebb3-a580-41eb-ade7-b8829c32b071/PJPuSKbpze.json"
/>
</div>
</div>
<!-- <div class="text-center">
<div class="text-[#E5D7CE] text-xs ">موجودی کیف طلا</div>
<transition mode="out-in" name="fade">
<div v-if="!isHidden" class="flex justify-center mt-1 text-[#B79379] gap-1 items-center text-xs"
@click="isHidden = true">
<div class="text-white text-base">{{ walletStore?.walletInfo?.gold ?? 0 }}</div>
گرم
</div>
<div v-else class="flex gap-2 items-center justify-center mt-3" @click="isHidden = false">
<div class="bg-white rounded-full w-2 h-2" />
<div class="bg-white rounded-full w-2 h-2" />
<div class="bg-white rounded-full w-2 h-2" />
<div class="bg-white rounded-full w-2 h-2" />
</div>
</transition>
</div>
<div class="text-center">
<div class="text-[#E5D7CE] text-xs ">مجموع دارایی طلایی</div>
<transition mode="out-in" name="fade">
<div v-if="!isHidden" class="flex justify-center mt-1 text-[#B79379] gap-1 items-center text-xs"
@click="isHidden = true">
<div class="text-white text-base">{{ walletStore.walletInfo?.gold_sum ?? 0 }}</div>
گرم
</div>
<div v-else class="flex gap-2 items-center justify-center mt-3" @click="isHidden = false">
<div class="bg-white rounded-full w-2 h-2" />
<div class="bg-white rounded-full w-2 h-2" />
<div class="bg-white rounded-full w-2 h-2" />
<div class="bg-white rounded-full w-2 h-2" />
</div>
</transition>
</div>
<div class="text-center">
<div class="text-[#E5D7CE] text-xs ">موجودی کیف پول</div>
<transition mode="out-in" name="fade">
<div v-if="!isHidden"
class="flex justify-center mt-1 text-[#B79379] gap-1 items-center text-xs"
@click.stop="isHidden = true;console.log('sssssss')">
<div class="text-white text-base">
{{
walletStore?.walletInfo?.cash === undefined ? 0 : usePriceWithoutType(walletStore.walletInfo?.cash)
}}
</div>
ریال
</div>
<div v-else class="flex gap-2 items-center justify-center mt-3" @click="isHidden = false">
<div class="bg-white rounded-full w-2 h-2" />
<div class="bg-white rounded-full w-2 h-2" />
<div class="bg-white rounded-full w-2 h-2" />
<div class="bg-white rounded-full w-2 h-2" />
</div>
</transition>
</div>-->
</div>
</div>
<div class="top-[9rem] relative pb-30">
<img :src="img" alt="" class="w-screen h-[8rem]" />
<div
v-if="userStore.userInfo && !loading"
class="bg-white w-screen md:w-auto h-fit px-5 m-[-1px]"
>
<div
v-if="limitedPrice !== undefined && userStore?.userInfo.trade_active !== 1"
class="text-red text-xs flex gap-1 items-center justify-center mb-2"
>
<Icon icon="vuesax-linear:info-circle" size="16" />
حداقل مبلغ اولیه برای ثبت سفارش
{{ usePriceWithoutType(limitedPrice.value as number ?? 0) }} ریال می باشد.
</div>
<!-- <div class="bg-white">
<MySlider v-if="cardItems.length > 0" :items="cardItems" class=" pb-[20vh] "
style="touch-action: none" />
</div>-->
<div
class="w-full relative bg-gray-100 rounded-lg h-[88px] flex flex-col justify-center home_appear_fade_in"
>
<img :src="img1" alt="" class="h-[88px] absolute" />
<div class="w-full items-center flex flex-col">
<div class="text-gray-600">قیمت لحظه ای طلا</div>
<div v-if="price" class="flex gap-1 mt-3 text-xs items-center">
<!-- <div id="odometer" class="font-bold text-2xl odometer animated fadeIn">
&lt;!&ndash; {{ usePriceWithoutType(useCounterAnim(price.price_last) ?? 0) }}&ndash;&gt;
</div>-->
<!-- <div id="odometer" class="odometer animated fadeIn"></div>-->
<Vue3Odometer
:value="goldVal"
class="o-text !text-2xl font-bold"
style="font-family: iran-sans; direction: ltr"
v-if="key % 2 === 0"
/>
ریال
</div>
</div>
</div>
<div class="flex justify-between mt-8">
<div
class="text-center w-full flex-flex-col items-center home_appear_fade_in_up"
style="text-align: -webkit-center"
@click="router.push({ name: 'gold', query: { state: 'sell' } })"
>
<div
class="rounded-full w-[42px] h-[42px] bg-orange-100 flex items-center justify-center"
>
<Icon class="text-orange-600" icon="vuesax-linear:money-send" />
</div>
<div class="text-primary">فروش</div>
</div>
<div
class="text-center w-full flex-flex-col items-center home_appear_fade_in_down"
style="text-align: -webkit-center"
@click="router.push({ name: 'wallet', query: { state: 'deposit' } })"
>
<div
class="rounded-full w-[42px] h-[42px] bg-green-100 flex items-center justify-center"
>
<Icon class="text-green-600" icon="vuesax-linear:card-add" />
</div>
<div class="text-primary">واریز نقدی</div>
</div>
<div
class="text-center w-full flex-flex-col items-center home_appear_fade_in_up"
style="text-align: -webkit-center"
@click="router.push({ name: 'gold', query: { state: 'buy' } })"
>
<div
class="rounded-full w-[42px] h-[42px] bg-blue-100 flex items-center justify-center"
>
<Icon class="text-blue-600" icon="vuesax-linear:money-receive" />
</div>
<div class="text-primary">خرید</div>
</div>
<div
class="text-center w-full flex-flex-col items-center home_appear_fade_in_down"
style="text-align: -webkit-center"
@click="router.push({ name: 'fund' })"
>
<div
class="rounded-full w-[42px] h-[42px] bg-yellow-100 flex items-center justify-center"
>
<Icon class="text-yellow-600" icon="vuesax-linear:archive-1" />
</div>
<div class="text-primary">گنج</div>
</div>
</div>
<!-- <div class="mt-10 font-bold home_appear_fade_in" @click="update">
نوسانات قیمت هر گرم طلای 18 عیار
</div>-->
<!-- <a-spin :spinning="chartLoading" class="relative">
<div ref="target" class="absolute"></div>
<div v-if="!chartLoading" id="chart" class="pb-20 mt-7 overflow-x-auto">
&lt;!&ndash; <apexchart v-if="targetIsVisible" :options="chartOptions" :series="test_series"
:style="`width: ${chartWidth}`"
height="350"
type="candlestick"></apexchart>&ndash;&gt;
</div>
</a-spin>-->
<!-- <a-spin :spinning="chartLoading" >-->
<!-- <div ref="target" class="absolute"></div>-->
<!-- <div id="chart" class="mt-7">-->
<div class="bg-gray-50 w-full flex justify-evenly rounded-lg py-4 mt-4 h-[15rem]">
<div class="w-full text-center pt-2">
<a-radio-group v-model:value="value" button-style="solid">
<a-radio-button value="a" @click="updateData('DAILY')">24 ساعت اخیر</a-radio-button>
<a-radio-button value="b" @click="updateData('WEEKLY')">هفته گذشته</a-radio-button>
<a-radio-button value="c" @click="updateData('MONTHLY')">ماه گذشته</a-radio-button>
</a-radio-group>
<div id="chart-timeline">
<apexchart
type="area"
height="200"
ref="chart"
:options="priceChartOptions"
:series="priceChartSeries"
></apexchart>
</div>
</div>
</div>
<div class=" w-full flex justify-evenly rounded-lg py-2 home_appear_fade_in mt-6">
<div class="text-center w-full">
<div>بالاترین قیمت امروز</div>
<div v-if="lastPrice" class="flex flex-col items-center mt-3">
<div class="text-green-600 flex gap-1 text-xs items-center">
<div class="text-base">{{ usePriceWithoutType(price.buy ?? 0) }}</div>
ریال
</div>
</div>
</div>
<a-divider class="bg-gray-200 !h-auto !my-2" type="vertical" />
<div class="text-center w-full">
<div>پایین ترین قیمت امروز</div>
<div class="flex w-full mt-3 justify-evenly">
<div v-if="lastPrice" class="flex flex-col items-center">
<div class="text-red-600 flex gap-1 text-xs items-center">
<div class="text-base">{{ usePriceWithoutType(price.sell ?? 0) }}</div>
ریال
</div>
</div>
</div>
</div>
<!-- <div class="text-center w-full">
<div>قیمت خرید از گلد دات آی آر</div>
<div class="text-[10px] text-gray-500">(هر گرم طلای 18 عیار)</div>
<div class="flex w-full mt-3 justify-evenly">
&lt;!&ndash; <div class="text-[10px] gap-1 flex bg-green-100 rounded-xl px-1 text-green-600 items-center">
<Icon icon="vuesax-linear:received" size="10"/>
<div>2%</div>
</div>&ndash;&gt;
<div v-if="price" class="flex text-gray-500 text-xs items-center gap-1">
<div class="text-primary font-bold text-base">
{{ usePriceWithoutType(lastPrice.buy ?? 0) }}
</div>
ریال
</div>
</div>
</div>
<a-divider class="bg-gray-200 !h-auto !my-2" type="vertical" />
<div class="text-center w-full">
<div>قیمت فروش به گلد دات آی آر</div>
<div class="text-[10px] text-gray-500">(هر گرم طلای 18 عیار)</div>
<div class="flex w-full mt-3 justify-evenly">
&lt;!&ndash; <div class="text-[10px] gap-1 flex bg-red-100 rounded-xl px-1 text-red-600 items-center">
<Icon icon="vuesax-linear:send" size="10"/>
<div>3%</div>
</div>&ndash;&gt;
<div v-if="price" class="flex text-gray-500 text-xs items-center gap-1">
<div class="text-primary font-bold text-base">
{{ usePriceWithoutType(lastPrice.sell ?? 0) }}
</div>
ریال
</div>
</div>
</div>-->
</div>
<!-- </a-spin>-->
</div>
<div v-else class="bg-white w-screen md:w-auto h-[80vh] px-5 m-[-1px] flex justify-center">
<HomeSkeleton class="w-full" />
</div>
</div>
<div
:class="y > 130 ? 'bg-white shadow opacity-95' : ''"
class="px-4 py-2 top-0 wrap-fix background-color-transition"
>
<div class="flex justify-between my-2">
<div class="flex items-center gap-2" @click.stop="router.push({ name: 'user' })">
<!-- <img :src="testimg" alt="" class="w-[24px] h-[24px]">-->
<div
class="z-100000 rounded-full border-1"
:class="y > 130 ? 'text-primary border-primary' : 'text-white border-white'"
>
<Icon icon="vuesax-linear:user" size="20" />
</div>
<div :class="y > 130 ? 'text-primary' : 'text-white'" class="color-transition font-bold">
{{ userStore.userInfo?.name }}
</div>
</div>
<Icon
:color="y > 130 ? 'primary' : 'white'"
class="color-transition"
icon="vuesax-linear:logout"
@click="showLogoutConfirm = true"
/>
</div>
</div>
<DialogVant v-model:show="showLogoutConfirm" :closeOnClickOverlay="false" :timeOut="-1">
<!-- <template v-slot:img>
<img :src="registerDelayImage" alt="" class="opacity-80">
</template>-->
<template v-slot:title>
<div class="flex flex-col items-center">
<DotLottieVue
class="w-11rem h-11rem"
autoplay
src="https://lottie.host/129cf3a1-df84-4758-a856-58c133ae6013/R5RqclXA8G.json"
/>
<div class="p-5 text-sm">آیا از خروج خود اطمینان دارید؟</div>
</div>
</template>
<template v-slot:button>
<div class="text-center text-red flex items-center justify-center" @click="logout">
<a-spin :spinning="logoutLoading" size="small"> خروج </a-spin>
</div>
<div class="text-center" @click="showLogoutConfirm = false">انصراف</div>
</template>
</DialogVant>
</div>
<BasicActionSheet v-model:show="wholeBalanceVisible">
<div class="pb-20">
<div>
<div class="w-full text-center font-bold">موجودی ها</div>
<div class="h-30vh overflow-y-auto">
<div class="mt-5">
<BasicInfoItem
class="flex justify-between"
title="مجموعه کل دارایی طلایی"
is-line
info="در این قسمت مجموع کل وزن طلایی که در گنج های خود و کیف اصلی طلایی دارید را مشاهده میفرمایید."
infoHead="مجموع کل دارایی طلایی"
:value="parseFloat((walletStore.walletInfo?.gold_sum ?? 0).toFixed(2)) + ' گرم'"
/>
<a-divider class="!my-1" />
<BasicInfoItem
class="flex justify-between"
title="دارایی کیف پول"
is-line
:value="usePrice(walletStore.walletInfo?.cash ?? 0)"
/>
<a-divider class="!my-1" />
<BasicInfoItem
class="flex justify-between"
title="دارایی کیف طلا"
is-line
:value="parseFloat((walletStore.walletInfo?.gold ?? 0)?.toFixed(2)) + ' گرم'"
/>
<a-divider class="!my-1" />
<BasicInfoItem
class="flex justify-between"
title="ارزش ریالی کیف طلا"
is-line
:value="
usePrice(((walletStore.walletInfo?.gold ?? 0) * (goldVal ?? 0) ?? 0).toFixed(0))
"
/>
<a-divider class="!my-1" />
<!-- <BasicInfoItem class="flex justify-between" title="دارایی کیف پول(به گرم)" is-line
:value="((walletStore.walletInfo?.cash?? 0) / (goldVal?? 0)).toFixed(2)+ ' گرم'" />
<a-divider class="!my-1" />-->
<BasicInfoItem
class="flex justify-between"
title="مجموعه دارایی کلی (به ریال)"
is-line
:value="
usePrice(
(
(walletStore.walletInfo?.gold_sum ?? 0) * (goldVal ?? 0) +
(walletStore.walletInfo?.cash ?? 0)
).toFixed(0)
)
"
/>
<a-divider class="!my-1" />
<!-- <BasicInfoItem class="flex justify-between" title="مجموعه دارایی کلی (به گرم)" is-line
:value="((((walletStore.walletInfo?.cash?? 0)/(goldVal?? 0) )+ (walletStore.walletInfo?.gold_sum?? 0))).toFixed(2)+ ' گرم'" />
<a-divider class="!my-1" />-->
<BasicInfoItem
class="flex justify-between"
title="مجموعه دارایی قابل برداشت (به ریال)"
is-line
:value="
usePrice(
(
(walletStore.walletInfo?.gold ?? 0) * (goldVal ?? 0) +
(walletStore.walletInfo?.cash ?? 0)
).toFixed(0)
)
"
/>
<a-divider class="!my-1" />
<BasicInfoItem
class="flex justify-between"
title="مجموعه دارایی قابل برداشت (به گرم)"
is-line
:value="
parseFloat((
(walletStore.walletInfo?.cash ?? 0) / (goldVal ?? 0) +
(walletStore.walletInfo?.gold ?? 0)
).toFixed(2)) + ' گرم'
"
/>
<a-divider class="!my-1" />
</div>
</div>
</div>
</div>
</BasicActionSheet>
</template>
<script lang="tsx" setup>
import img from '@/assets/img/home_ly1.svg'
import img1 from '@/assets/img/home_ly2.svg'
import Icon from '@/components/BasicPacks/BasicIcon.vue'
import { usePrice, usePriceWithoutType } from '../../../utils/usePrice'
import {computed, onMounted, onUnmounted, ref, watch, watchEffect} from 'vue'
import router from '@/router'
import * as echarts from 'echarts'
import { useIntersectionObserver, useWindowScroll } from '@vueuse/core'
import { loading, removeToken } from '@/utils'
import { useUserStore } from '@/store/userStore'
import { useWalletStore } from '@/store/walletStore'
import DialogVant from '@/components/DialogVant.vue'
import type { Price } from '@/models/home'
import { getAllPrices, getChart, getLastPrice, getPrice } from '@/api/home'
// import odometer from 'odometer/odometer'
import Vue3Odometer from 'vue3-odometer'
import 'odometer/themes/odometer-theme-default.css'
import HomeSkeleton from '@/views/base/home/components/HomeSkeleton.vue'
import { toJalaliNotime } from '@/utils/useDateTime'
import { getLastPrices, lastPrice, price, setIntervalGetAllPrice, stopPriceInterval } from '@/utils/price'
import { DotLottieVue } from '@lottiefiles/dotlottie-vue'
import BasicActionSheet from '@/components/BasicPacks/BasicActionSheet.vue'
import BasicInfoItem from '@/components/BasicPacks/BasicInfoItem.vue'
import MySlider from '@/views/base/wallet/components/mySlider/MySlider.vue'
import type { Card } from '@/models/wallet'
import { getActivatedCards } from '@/api/wallet'
import banner1 from '@/assets/img/banner/banner1.png'
import banner2 from '@/assets/img/banner/banner2.png'
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
const userStore = useUserStore()
const walletStore = useWalletStore()
const chartLoading = ref<boolean>(false)
const wholeBalanceVisible = ref<boolean>(false)
const { x, y } = useWindowScroll()
const series = ref<Chart[]>([{ data: [] }])
const key = ref<number>(0)
const cardItems = [banner1, banner2]
const main = ref(null)
const logoutLoading = ref(false)
const value = ref<string>('a')
/*
onMounted(() => {
animateNum(2)
})
*/
const goldVal = ref<number | undefined>()
function update() {
setInterval(() => {
goldVal.value = lastPrice?.value.price_last
}, 500)
}
const target = ref(null)
const targetIsVisible = ref(false)
const isHidden = ref<boolean>(false)
const { stop } = useIntersectionObserver(target, ([{ isIntersecting }], observerElement) => {
targetIsVisible.value = isIntersecting
console.log('saaaaa', targetIsVisible.value)
})
watch(main, (n) => {
if (main.value !== null) {
// console.log('saaaa')
const echart = echarts.init(main.value, null, {
renderer: 'canvas'
})
echart.setOption({
xAxis: {
data: dates.value.values,
show: true
},
yAxis: {
show: false,
scale: true
},
series: [
{
type: 'candlestick',
data: series.value
}
]
})
}
})
//whole prices
const priceChartSeries = ref<{ data: [number, number][] }[]>([
{
name: 'قیمت',
data: []
}
])
const selection = ref('DAILY')
const chartRef = ref<ApexCharts | null>(null)
const priceChartOptions = ref({
chart: {
id: 'نوسانات قیمت',
type: 'area',
height: 200,
toolbar: {
show: false // Disable the toolbar to remove download and other options
},
zoom: {
autoScaleYaxis: true
},
events: {
mounted(chart) {
chartRef.value = chart
}
},
},
grid: {
padding: {
top: 0,
right: 0,
bottom: 0,
left: 0
},
yaxis: {
lines: {
show: false
}
}
},
stroke: {
width: 2
},
dataLabels: {
enabled: false,
// formatter: (val) => toPersianNumber(val),
style: {
fontFamily: "'IranSans', sans-serif",
}
},
yaxis: {
tickAmount: 8,
show: false,
title: {
style: {
fontSize: '13px',
fontFamily: "'IranSans', sans-serif",
fontWeight: 'bold'
}
},
labels: {
formatter: (val) => toPersianNumber(usePrice(val)),
style: {
fontSize: '13px',
fontFamily: "'IranSans', sans-serif",
},
},
},
xaxis: {
show: false,
type: 'datetime',
axisTicks: {
show: false
},
tooltip: {
enabled: false
},
labels: {
show: false,
rotate: -45,
style: {
fontFamily: "'IranSans', sans-serif",
},
// formatter: (val) => toPersianNumber(toJalaliNotime(new Date(val).toString()))
},
axisBorder: {
show: false
},
},
tooltip: {
x: {
// formatter: (val) => toPersianNumber(toJalaliNotime(new Date(val).toString()))
formatter: (value) => {
const date = new Date(value)
return `${date.toLocaleDateString('fa-IR')} - ${date.toLocaleTimeString('fa-IR', {
hour: '2-digit',
minute: '2-digit'
})}`
},
},
formatter: (val) => toPersianNumber(usePrice(val)),
style: {
fontFamily: "'IranSans', sans-serif",
// fontWeight: 'bold'
},
markers:{
show: false
}
},
colors: ['#0A1B37'],
fill: {
type: 'gradient',
gradient: {
shadeIntensity: 1,
opacityFrom: 0.7,
opacityTo: 0.9,
stops: [0, 100]
},
},
})
const toPersianNumber = (num) => {
return num.toString().replace(/\d/g, (d) => '۰۱۲۳۴۵۶۷۸۹'[d])
}
const fetchPrices = async () => {
try {
const response = await getAllPrices()
const data = response.data.prices
const selectedData = data[selection.value] || []
priceChartSeries.value[0].data = selectedData.map((item) => [item.timestamp, item.value - 1])
// console.log(priceChartSeries.value[0].data)
chartRef.value?.updateOptions({
series: priceChartSeries.value,
})
} catch (error) {
console.error('خطا در دریافت داده‌ها', error)
}
}
const updateData = (timeline) => {
selection.value = timeline
fetchPrices()
}
const limitedPrice = computed(() => {
if (walletStore.limitedPrice) return walletStore?.limitedPrice[0]
})
const limitedBuyGold = computed(() => {
if (walletStore.limitedBuyGold) return walletStore?.limitedBuyGold[0]
})
const chartWidth = computed(() => {
if (series.value.length < 30) return '100vw'
else if (series.value.length < 60) return '200vw'
else if (series.value.length < 90) return '300vw'
else if (series.value.length < 120) return '400vw'
else if (series.value.length < 160) return '500vw'
else if (series.value.length < 190) return '600vw'
else if (series.value.length < 210) return '700vw'
else if (series.value.length < 240) return '800vw'
else if (series.value.length < 270) return '900vw'
else if (series.value.length < 300) return '1000vw'
else if (series.value.length < 330) return '1100vw'
else if (series.value.length < 360) return '1200vw'
else if (series.value.length < 390) return '1300vw'
})
const test_series = [
{
name: 'candle',
data: []
}
]
async function initChart() {
try {
chartLoading.value = true
const data = await getChart()
/* data.forEach(item => {
test_series[0].data.push({
x: toJalali(item[0]),
y: item[1]
})
// console.log(x)
})*/
data.forEach((item) => {
test_series[0].data.push({
x: item[0],
y: item[1]
})
// console.log(x)
})
// console.log(test_series)
} catch (e) {
console.log(e)
} finally {
chartLoading.value = false
}
}
async function initPrice() {
try {
loading.value = true
const val = price?.value?.price_last
await getLastPrices()
// await setIntervalGetPrice()
if (val !== price?.value?.price_last) {
update()
/* key.value++
key.value++*/
}
/* price.value = data
lastPrice.value = dataLast*/
goldVal.value = 0
// console.log(price?.value.price_last)
if (userStore.isFirst) {
const timer = setInterval(function () {
update()
// if (current == end) {
userStore.isFirst = false
clearInterval(timer)
// }
}, 100)
} else {
goldVal.value = price.value?.price_last
}
// console.log(series.value)
} catch (e) {
console.log(e)
} finally {
loading.value = false
}
}
onMounted(async () => {
await initChart()
await initPrice()
await fetchPrices()
// console.log('okkkkkkhome')
update()
})
onUnmounted(() => {
// stopPriceInterval()
// console.log('okhome')
})
const chartOptions = ref({
chart: {
type: 'candlestick',
height: 600,
toolbar: {
autoSelected: 'pan',
show: false
}
},
title: {
// text: 'CandleStick Chart',
align: 'left'
},
xaxis: {
type: 'datetime',
labels: {
show: false
},
tooltip: {
formatter: function (val, opts) {
// console.log(val, toJalali(val))
return toJalaliNotime(val)
}
}
},
yaxis: {
show: false,
showAlways: false,
showForNullSeries: false,
tooltip: {
enabled: true
}
},
tooltip: {
custom: function ({ seriesIndex, dataPointIndex, w }) {
const o = w.globals.seriesCandleO[seriesIndex][dataPointIndex]
const h = w.globals.seriesCandleH[seriesIndex][dataPointIndex]
const l = w.globals.seriesCandleL[seriesIndex][dataPointIndex]
const c = w.globals.seriesCandleC[seriesIndex][dataPointIndex]
return (
'<div class="apexcharts-tooltip-candlestick p-2">' +
'<div>باز: <span class="value">' +
o +
'</span></div>' +
'<div>بیشترین: <span class="value">' +
h +
'</span></div>' +
'<div>کمترین: <span class="value">' +
l +
'</span></div>' +
'<div>بسته: <span class="value">' +
c +
'</span></div>' +
'</div>'
)
}
}
})
const showLogoutConfirm = ref<boolean>()
async function logout() {
logoutLoading.value = true
// baseConfirm('آیا از حساب کاربری خارج می شوید؟',async () => {
userStore.userInfo = undefined
walletStore.walletInfo = undefined
/* userStore.$reset()
walletStore.$reset()*/
removeToken()
await router.push({ name: 'login' })
logoutLoading.value = true
window.location.reload()
// console.log('salam')
// })
}
</script>
<style lang="less">
.odometer {
font-size: 60px;
//margin: 200px 0;
text-align: center;
width: 100%;
animation-duration: 3s;
}
label:focus-within {
box-shadow: none !important
}
.chart-container {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
display: flex;
}
apexchart {
width: 100% !important;
height: 100% !important;
padding: 0 !important;
margin: 0 !important;
}
</style>
+384
View File
@@ -0,0 +1,384 @@
<template>
<div >
<Transition>
<div v-if="popVisible" class="top-0 bottom-0 bg-primary wrap-fix z-2000 opacity-60"
@click="popVisible = false">
</div>
</Transition>
<Transition name="slide-fade">
<div v-if="popVisible" class="wrap-fix bottom-11vh z-2000">
<div class="relative flex flex-col items-center ">
<div class="flex items-center justify-center bg-white rounded-full w-[30px] h-[30px] mb-2"
@click="popVisible = !popVisible">
<BasicIcon
icon="vuesax-linear:close-circle"
/>
</div>
<div class="flex flex-col items-center gap-2">
<BasicButton icon-size="16" class="!font-bold w-15rem"
@click="$router.push({name: 'user'}); popVisible = false">
<div class="flex gap-2 items-center">
<BasicIcon icon="vuesax-linear:user" size="16" class="absolute right-2" />
<div>حساب کاربری</div>
</div>
</BasicButton>
<BasicButton icon-size="16" class="!font-bold w-15rem"
@click="$router.push({name: 'notifyTrigger'}); popVisible = false">
<div class="flex gap-2 items-center">
<BasicIcon icon="vuesax-linear:bill" size="16" class="absolute right-2" />
<div>هشدار قیمت</div>
</div>
</BasicButton>
<BasicButton icon-size="16" class="!font-bold w-15rem"
@click="$router.push({name: 'about'}); popVisible = false">
<div class="flex gap-2 items-center">
<BasicIcon icon="vuesax-linear:info-circle" size="16" class="absolute right-2" />
<div>درباره ما</div>
</div>
</BasicButton>
<!-- <BasicButton icon-size="16" class="!font-bold w-15rem"-->
<!-- @click="$router.push({name: 'physicalReceive'}); popVisible = false">-->
<!-- <div class="flex gap-2 items-center">-->
<!-- <BasicIcon icon="vuesax-linear:direct-inbox" size="16" class="absolute right-2" />-->
<!-- <div>دریافت طلای فیزیکی</div>-->
<!-- </div>-->
<!-- </BasicButton>-->
<BasicButton icon-size="16" class="!font-bold w-15rem"
@click="$router.push({name: 'rules'}); popVisible = false">
<div class="flex gap-2 items-center">
<BasicIcon icon="vuesax-linear:task" size="16" class="absolute right-2" />
<div>قوانین و مقررات</div>
</div>
</BasicButton>
<!-- <BasicButton icon-size="16" class="!font-bold w-50vw md:w-full"
@click="$router.push({name: 'permissions'}); popVisible = false">
<div class="flex gap-2 items-center">
<BasicIcon icon="vuesax-linear:archive-book" size="16" class="absolute right-2" />
<div>مجوز ها</div>
</div>
</BasicButton>-->
<!-- <BasicButton icon-size="16" class="!font-bold w-50vw md:w-full"
@click="$router.push({name: 'earnMoney'}); popVisible = false">
<div class="flex gap-2 items-center">
<BasicIcon icon="vuesax-linear:dollar-circle" size="16" class="absolute right-2" />
<div>کسب درآمد</div>
</div>
</BasicButton>-->
</div>
</div>
</div>
</Transition>
<div class=" !h-[calc(100vh-72px)] ">
<router-view v-slot="{ Component, route }">
<!-- Use any custom transition and to `fade` -->
<transition :name="route.meta.transition || 'fade'">
<component :is="Component" class="!h-[calc(100vh-72px)]" />
</transition>
</router-view>
</div>
<!-- <canvas ref="canvas" id="canvas1" width="400" height="80" class="w-full"></canvas>-->
<div class="bottom-appbar w-auto mx-auto">
<div class="tabs">
<div :class="setNavColor('home')" class="tab" @click="setRoute('home')">
<Icon icon="vuesax-linear:home" />
<div class="text-xs mt-1 font-bold">صفحه اصلی</div>
</div>
<div :class="setNavColor('transactions')" class="tab" @click="setRoute('transactions')">
<Icon icon="vuesax-linear:receipt-item" />
<div class="text-xs mt-1 font-bold">گزارش</div>
</div>
<div class="main_in" @click="setRoute('buyProduct')">
<div class="text-white circle_in">
<div class="circle_into " @click="popVisible = !popVisible">
<img
class="p-2"
:src="config.config.avatar"
/>
</div>
<!-- <div class="flex justify-center">خرید </div>
<div class="flex justify-center">محصول </div>-->
</div>
</div>
<!-- <div :class="setNavColor('buyProduct')" class="tab" @click="setRoute('buyProduct')">
<Icon icon="vuesax-linear:coin" />
<div class="text-xs mt-1 font-bold">خرید محصول</div>
</div>-->
<div :class="setNavColor('wallet')" class="tab" @click="setRoute('wallet')">
<Icon icon="vuesax-linear:wallet-1" />
<div class="text-xs mt-1 font-bold">کیف پول</div>
</div>
<div :class="setNavColor('setting')" class="tab" @click="setRoute('user')">
<Icon icon="vuesax-linear:setting-2" />
<div class="text-xs mt-1 font-bold">تنظیمات</div>
</div>
</div>
<!-- <div class="w-[80px] h-[80px] border-1">
</div>-->
<div class="main">
<div class="circle">
</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { computed, ref } from 'vue'
import Icon from '@/components/BasicPacks/BasicIcon.vue'
import router from '@/router'
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
import type { Transaction } from '@/models/transaction'
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
import {useConfigStore} from "@/store/configStore";
/*onMounted(async () => {
const c = await document.getElementById("canvas1");
const ctx = c.getContext("2d");
console.log(ctx)
ctx.beginPath();
ctx.moveTo(0,20);
ctx.lineTo(165,20)
ctx.arc(200, 50, 45, 3.9, 5.5, false);
ctx.lineTo(400,20)
ctx.stroke();
})*/
const currentRoute = computed(() => router.currentRoute.value.name)
const config=useConfigStore()
const popVisible = ref(false)
function setNavColor(val: string) {
if (currentRoute.value === val) {
return 'text-primary'
} else {
return 'text-gray-400'
}
}
function setRoute(val: string) {
popVisible.value = false
router.push({ name: val })
}
</script>
<style lang="less">
.bottom-appbar {
z-index: 5000;
height: 80px;
position: fixed;
display: flex;
justify-content: space-evenly;
bottom: 0;
right: 0;
left:0;
@media screen and (min-width: 426px) {
width: 426px;
margin: 0 auto;
}
.tabs {
display: flex;
height: 90%;
bottom: 0;
width: 100%;
background: white;
//background-color: red;
justify-content: space-between;
position: absolute;
z-index: 400;
//border: 1px dashed primary;
box-shadow: 0px -2px 4px -2px #0000001A;
.tab {
width: 80px;
text-align: center;
flex-flow: column;
display: flex;
align-items: center;
justify-content: center;
align-content: center;
}
.main_in {
height: 70px;
width: 70px;
.circle_in {
margin-top: -10px;
border-radius: 100%;
height: 100%;
width: 100%;
z-index: 20;
display: flex;
//border: 1px dashed primary;
justify-content: center;
align-content: center;
flex-wrap: wrap;
background-color: #0A1B37;
.circle_into {
overflow:hidden;
@apply bg-primary;
border-radius: 100%;
width: 90%;
display: flex;
justify-content: center;
align-content: center;
flex-wrap: wrap;
height: 90%;
border: white 1px solid;
}
}
}
}
.main {
height: 70px;
width: 70px;
position: relative;
.circle {
border-radius: 100%;
height: 100%;
width: 100%;
z-index: 20;
//border: 1px dashed primary;
box-shadow: 0px -5px 4px -2px #0000001A;
position: absolute;
}
}
}
/*.wrapper{
max-width: 400px;
margin: 0px auto;
}
.page{
width: 100vw;
height: 100vh;
padding: 20px;
box-sizing: border-box;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
img{
max-width: 60%;
height: auto;
display: block;
}
}
.bottom-appbar {
height: 70px;
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 20;
.tabs {
display: flex;
flex-direction: row;
height: 100%;
.tab {
&--left {
width: 100%;
border-top-right-radius: 30px;
border-top: 1px solid rgba(167, 161, 161, 0.69);
box-shadow: 0px 6px 7px 0px rgba(23, 23, 23, 0.28);
}
&--right {
width: 100%;
border-top-left-radius: 30px;
border-top: 1px solid rgba(167, 161, 161, 0.69);
box-shadow: 15px 4px 15px 0px rgba(23, 23, 23, 0.28);
}
&--fab {
width: 180px;
height: 100%;
background: transparent;
border: none;
display: flex;
.top {
width: 100%;
height: 50%;
border-bottom-left-radius: 100px;
border-bottom-right-radius: 100px;
background-color: transparent;
box-shadow: 0px 30px 0px 25px #fff;
border-bottom: 1px solid rgba(167, 161, 161, 0.69);
display: flex;
}
}
background-color: #fff;
width: 33.4%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
border-top: 1px solid #eee;
box-shadow: 1x 1x 3px #ccc, -1px -1px 3px #ccc;
font-size: 24px;
span {
font-size: 12px;
}
i {
font-size: 24px;
}
&.is-active {
color: #fd9d97;
}
}
.fab {
border-radius: 50%;
background-color: #fe989c;
display: flex;
justify-content: center;
align-items: center;
width: 70px;
height: 70px;
font-weight: bold;
font-size: 22px;
color: #fff;
position: relative;
justify-content: center;
transform: translate(2px,-60%);
}
}
}*/
.v-enter-active,
.v-leave-active {
transition: opacity 0.5s ease;
}
.v-enter-from,
.v-leave-to {
opacity: 0;
}
.slide-fade-enter-active {
transition: all 0.3s ease-out;
}
.slide-fade-leave-active {
transition: all 0.4s cubic-bezier(1, 0.5, 0.8, 1);
}
.slide-fade-enter-from,
.slide-fade-leave-to {
transform: translateX(20px);
opacity: 0;
}
</style>
@@ -0,0 +1,221 @@
<template>
<div class="">
<div ref="el" class="px-3 pt-15"
>
<div class="flex gap-2">
<BasicSelect v-model:value="selectedProduct" :items="items"
class="w-full"
key-name="id"
:show-search="false"
value-name="title"
size="large"
placeholder="لطفا محصول را انتخاب کنید"
:has-tooltip="false"/>
<BasicButton :disabled-b="selectedProduct==null" type="primary" @click="handleAdd">افزودن</BasicButton>
</div>
<div class="h-70vh rounded-lg bg-white mt-2 border-gray-200 border-1 overflow-y-auto p-2">
<div v-for="(val,index) in selectedProducts" class="rounded-lg p-2 bg-gray-100 mb-2">
<div class="flex">
<div class="bg-gray-100 m-2 rounded-lg w-28 h-28 flex justify-center p-2">
<img v-if="val.product.group_type=='گوی'" :src="goyImg">
<img v-if="val.product.group_type=='مکعب'" :src="mokaabImg">
<img v-if="val.product.group_type=='سکه'" :src="sekkeImg">
</div>
<div class="w-full">
<div class="flex justify-between">
<div class="font-bold text-lg">
{{ val.product.title }}
</div>
<BasicButton icon="vuesax-linear:trash" icon-class="text-red" @click="handleRemove(val.product.id)"/>
</div>
<div class="flex mt-3 justify-between items-center">
<div>تعداد موجودی:</div>
<div class="flex gap-1 items-center">
<div class="font-bold">{{ val.product.wallet.gold }}</div>
<div>{{ val.product.unit }}</div>
</div>
</div>
<div class="flex justify-between items-center mt-2">
<div>تعداد درخواستی:</div>
<div class="flex gap-1 items-center w-40%">
<BasicInput v-model:value="val.count" addon-before="عدد"/>
</div>
</div>
</div>
</div>
</div>
</div>
<BasicButton :disabled-b="selectedProducts.length==0" class="w-full absolute bottom-10 mt-2"
@click="handelFirstSubmit()">ثبت
</BasicButton>
</div>
<!-- <ActionSheet v-model:show="editPassVisible">salam</ActionSheet>-->
</div>
<BasicActionSheet v-model:show="showAddress">
<div class="h-120 flex flex-col ">
<div class="text-center">
انتخاب آدرس
</div>
<div class="overflow-y-scroll h-85">
<ARadioGroup v-model:value="selectedAddressID">
<div class="flex flex-col ">
<div class="text-base rounded-lg p-4 m-2 shadow-md font-medium" v-for="item in address">
<ARadio :value="item.id">{{ item.province }} / {{ item.city }} / {{ item.address }}</ARadio>
</div>
</div>
</ARadioGroup>
</div>
<div class="flex gap-2 pt-2">
<BasicButton class=" " @click="showAddress=false;addAddressVisible=true">افزودن آدرس +</BasicButton>
<BasicButton class="w-2/3 " type="primary" @click="handelsubmit">ثبت نهایی</BasicButton>
</div>
</div>
</BasicActionSheet>
<BasicActionSheet v-model:show="addAddressVisible" >
<div class=" ">
<New_EditAddress @onOk="handleAddress"></New_EditAddress>
</div>
</BasicActionSheet>
</template>
<script lang="ts" setup>
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
import router from '@/router'
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
import BasicSelect from '@/components/BasicPacks/BasicSelect.vue'
import {onMounted, ref} from 'vue'
import {loading} from '@/utils'
import {getProductInventory} from '@/api/products'
import type {CountPInventory, PInventory} from '@/models/products'
import goyImg from '@/assets/img/goyImg.svg'
import mokaabImg from '@/assets/img/mokaabImg.svg'
import sekkeImg from '@/assets/img/sekkeImg.svg'
import defaultImg from '@/assets/img/defaultAbshodeh.svg'
import {usePrice} from '@/utils/usePrice'
import BasicInput from '@/components/BasicPacks/BasicInput.vue'
import {cloneDeep} from 'lodash'
import BasicActionSheet from "@/components/BasicPacks/BasicActionSheet.vue"
import {getCity, tableAddress} from "@/api/address"
import type {Address} from "@/models/address"
import Item from "@/views/base/address/components/Item.vue"
import {physicalReceiveApi} from "@/api/physicalreceive"
import {message} from "ant-design-vue"
import {required} from "@/utils/inputRules"
import BasicTextArea from "@/components/BasicPacks/BasicTextArea.vue"
import New_EditAddress from "@/views/base/address/components/New_EditAddress.vue"
const items = ref<PInventory[]>()
const baseItems = ref<PInventory[]>()
const selectedAddressID = ref<number>()
const selectedProduct = ref<number>()
const productsByWalletId = ref<Array>([])
const address = ref<Address>()
const selectedProducts = ref<CountPInventory[]>([])
const showAddress = ref<boolean>(false)
const addAddressVisible = ref<boolean>(false)
function handleAdd() {
console.log(selectedProducts.value)
selectedProducts.value?.push({
count: 0,
product: items.value?.find(x => x.id === selectedProduct.value)
})
items.value?.splice(items.value?.findIndex(x => x.id === selectedProduct.value), 1)
selectedProduct.value = undefined
}
function handleAddress() {
getAddress()
addAddressVisible.value = false
showAddress.value = true
}
function handleRemove(id: number) {
const findItem = baseItems.value?.find(x => x.id === id)
console.log(baseItems.value, id)
if (findItem) {
items.value?.push(findItem)
}
selectedProducts.value?.splice(selectedProducts.value?.findIndex(x => x.product.id === id), 1)
}
async function initProductWallet() {
try {
loading.value = true
items.value = (await getProductInventory()).rows.filter(x => (x.title !== 'آبشده نقدی' && x.wallet?.gold && x.wallet?.gold > 0))
baseItems.value = cloneDeep(items.value)
} catch (e) {
console.log(e)
} finally {
loading.value = false
}
}
async function handelFirstSubmit() {
try {
const zeroAmount = selectedProducts.value.map(item => item.count <= 0)
if (zeroAmount.includes(true)) {
message.error(`لطفاً تعداد درخواستی محصول را وارد کنید.`)
}
else {
showAddress.value = true
}
} catch (e) {
console.log(e)
}
}
async function handelsubmit() {
try {
loading.value = true
productsByWalletId.value = selectedProducts.value.map((val) => {
return {
wallet_id: val.product.wallet.id,
value: val.count
}
})
await physicalReceiveApi({
address_id: selectedAddressID.value,
wallets: productsByWalletId.value
}
)
await initProductWallet()
message.success("درخواست شما با موفقیت ارسال شد")
selectedProducts.value = []
} catch (e) {
console.log(e)
} finally {
loading.value = false
showAddress.value = false
}
}
onMounted(async () => {
await initProductWallet()
await getAddress()
})
async function getAddress(){
let {rows} = await tableAddress({page: 0, limit: 150})
address.value = rows
}
</script>
<style scoped>
/*.fade-enter-active,
.fade-leave-active {
transition: opacity 0.2s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}*/
/*.trans{
transition: height 1s;
}*/
</style>
@@ -0,0 +1,57 @@
<template>
<div class="rounded-lg shadow-md mx-2 bg-gradient-to-l from-primary rounded-lg p-[2px] to-transparent ">
<div class="rounded-lg flex flex-col gap-2 bg-white p-2 ">
<div class="flex justify-between ">
<div class="font-bold">شماره سند: {{ props.item.id }}</div>
<div class="font-bold">{{ toJalali(props.item.created_at) }}</div>
</div>
<div class="flex justify-between">
<div class="flex flex-col w-full gap-1 ">
<div class="w-full flex justify-between" v-for="item in props.item.transaction">
<div class="flex items-center gap-1 ">
<div class="w-7 h-7 flex justify-center rounded-lg bg-gray-100 ">
<img width="30" class="p-1" :src="item.product.group_type=='گوی'?goyImg:mokaabImg">
</div>
<div>{{ item.title }}</div>
</div>
<div>{{ item.gold * -1 }} عدد</div>
</div>
</div>
</div>
<div class="flex justify-between">
<div class="font-bold">وضعیت:</div>
<ATag color="blue" class="!py-1 !px-2 !ml-0">
{{ props.item.sts_str }}
</ATag>
</div>
<ADivider class="!m-1"></ADivider>
<div class="flex flex-col justify-between">
<div class="font-bold">آدرس:</div>
<div>{{ props.item.address.province }}/{{ props.item.address.city }}/{{ props.item.address.address }}</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import type {Physicalreceive} from "@/models/physicalreceive";
import {toJalali} from "../../../../utils/useDateTime";
import goyImg from "@/assets/img/goyImg.svg"
import mokaabImg from "@/assets/img/mokaabImg.svg"
interface Prop {
item: Physicalreceive
}
const props = withDefaults(defineProps<Prop>(), {})</script>
<style scoped>
</style>
@@ -0,0 +1,39 @@
<template>
<div>
<div class="flex flex-col gap-4 pt-13 pb-35 px-2">
<RequestItem v-for="item in requestItems" :item="item"></RequestItem>
</div>
<Transition mode="out-in" name="fade">
<div
class="wrap-fix bottom-0 h-[19vh] bg-[#FBFBFC] shadow-lg rounded-3xl flex justify-center pt-3 z-200"
style="box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 26px 11px"
@click="openAdd()">
<BasicIcon icon="vuesax-linear:add" />
<div class="cursor-pointer">افزودن درخواست جدید</div>
</div>
</Transition>
</div>
</template>
<script setup lang="ts">
import {onMounted, ref} from "vue";
import {getPhysicalReceiveList} from "@/api/physicalreceive";
import type {Physicalreceive} from "@/models/physicalreceive";
import RequestItem from "@/views/base/physicalReceive/components/RequestItem.vue";
import BasicIcon from "@/components/BasicPacks/BasicIcon.vue";
import router from "@/router";
const requestItems = ref<Physicalreceive[]>([])
const openAdd = () => {
router.push('physicalReceive/new')
}
onMounted(async () => {
let {rows} = await getPhysicalReceiveList()
requestItems.value = rows
console.log(rows)
})
</script>
<style scoped>
</style>
+43
View File
@@ -0,0 +1,43 @@
<template>
<div style="max-height: calc(100vh - 50px)">
<div class="bg-white py-3 px-3 z-100000 text-primary font-bold drop-shadow flex flex-col wrap-fix">
<div class="flex">
<div @click="router.back()">
<BasicIcon icon="vuesax-linear:arrow-right-1"/>
</div>
<div v-if="route.name=='list'" class="mr-2">دریافت طلای فیزیکی</div>
<div v-else class="mr-2">دریافت طلای فیزیکی-درخواست جدید</div>
</div>
</div>
<div>
<router-view></router-view>
</div>
</div>
</template>
<script lang="ts" setup>
import {ref} from "vue";
import RequestList from "@/views/base/physicalReceive/components/RequestList.vue";
import NewRequest from "@/views/base/physicalReceive/components/NewRequest.vue";
import router from "@/router";
import BasicIcon from "@/components/BasicPacks/BasicIcon.vue";
import {useRoute} from "vue-router";
const activekey=ref(1)
const route=useRoute()
</script>
<style scoped>
/*.fade-enter-active,
.fade-leave-active {
transition: opacity 0.2s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}*/
/*.trans{
transition: height 1s;
}*/
</style>
@@ -0,0 +1,161 @@
<template>
<div @click="infoVisible = true" class="shadow mb-2 p-2 rounded-lg">
<div class="flex justify-between">
<div>
<div class="font-bold text-base mb-2">{{usePrice(item.target_price) }}</div>
</div>
<div class="flex gap-2 ">
<BasicIcon color="red" icon="vuesax-linear:trash" @click.stop="deleteConfirmVisible = true" class="p-1"/>
<BasicIcon color="green" icon="vuesax-linear:edit" @click.stop="emits('edit',item)" class="p-1"/>
</div>
</div>
<div class="flex flex-col gap-2 mt-2">
<BasicInfoItem is-line title="جهت قیمت" :value="returnPriceCondition(item.price_condition)"/>
<BasicInfoItem is-line title="نوع هشدار" :value="returnAction(item.action)"/>
</div>
<a-divider class="!my-3" />
<div class="flex justify-between mt-1">
<div class="mb-2">{{toJalali(item.created_at)}}</div>
<a-switch v-model:checked="isActive" checked-children="فعال" un-checked-children="غیر فعال" @change="changeActive"/>
</div>
</div>
<!-- <teleport to="app">-->
<DialogVant v-model:show="deleteConfirmVisible" teleport="body" :closeOnClickOverlay="false" :timeOut="-1">
<!-- <template v-slot:img>
<img :src="registerDelayImage" alt="" class="opacity-80">
</template>-->
<template v-slot:title>
<div class="flex flex-col items-center">
<div class="p-5 text-sm">
آیا از حذف هشدار اطمینان دارید؟
</div>
</div>
</template>
<template v-slot:button>
<div class="text-center text-red flex items-center justify-center" @click="deleteItem">
<a-spin :spinning="deleteLoading" size="small">
تایید
</a-spin>
</div>
<div class="text-center" @click="deleteConfirmVisible = false">
انصراف
</div>
</template>
</DialogVant>
<!-- </teleport>-->
</template>
<script lang="ts" setup>
import { usePrice, usePriceWithoutType } from '../../../../utils/usePrice'
import BasicActionSheet from '@/components/BasicPacks/BasicActionSheet.vue'
import { computed, onMounted, ref } from 'vue'
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
import { toJalali, toJalaliNotime, toJalaliOutOfUTC, toTime } from '../../../../utils/useDateTime'
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
import type { PriceTrigger } from '@/models/PriceTrigger'
import BasicInfoItem from '@/components/BasicPacks/BasicInfoItem.vue'
import DialogVant from '@/components/DialogVant.vue'
import { DotLottieVue } from '@lottiefiles/dotlottie-vue'
import { deletePriceTrigger, updatePriceTrigger } from '@/api/triggerPrice'
import { loading } from '@/utils'
const infoVisible = ref<boolean>(false)
const isActive = ref<boolean>(false)
const deleteLoading = ref(false)
const deleteConfirmVisible = ref(false)
interface Prop {
item: PriceTrigger
}
onMounted(()=> isActive.value = props.item.is_active)
function changeActive(val: boolean) {
console.log(val)
try {
loading.value = true
updatePriceTrigger(props?.item.id, {is_active: val})
} catch (e) {
console.log(e)
isActive.value = !isActive.value
} finally {
loading.value = false
}
}
function returnPriceCondition(val: string) {
switch (val) {
case '==': return 'مساوی'
case '<': return 'کوچکتر'
// case '==': return 'مساوی'
}
/* if (val === '=='){
return 'مساوی'
} else if (val === '<'){
return 'کوچکتر'
}*/
}
async function deleteItem() {
try {
deleteLoading.value = true
await deletePriceTrigger(props.item.id)
deleteConfirmVisible.value = false
emits('refresh')
} catch (e) {
console.log(e)
} finally {
deleteLoading.value = false
}
}
function returnAction(val: string) {
switch (val) {
case 'sms': return 'پیامک'
case 'email': return 'ایمیل'
case 'notify': return 'نوتیفیکیشن'
// case '==': return 'مساوی'
}
/* if (val === '=='){
return 'مساوی'
} else if (val === '<'){
return 'کوچکتر'
}*/
}
const props = withDefaults(defineProps<Prop>(), {})
const emits = defineEmits(['edit','refresh'])
const isUp = computed(() => props.item.type === 3 || props.item.type === 1 || props.item.type === 8)
const isGold = computed(() => props.item.type === 1 || props.item.type === 2 || props.item.type === 10)
/*const title = computed(() => {
if (isUp.value) {
if (isGold.value) {
return 'واریز ریالی'
} else {
return 'خرید طلا'
}
} else {
if (isGold.value) {
return 'برداشت ریالی'
} else {
return 'فروش طلا'
}
}
})*/
</script>
<style scoped>
</style>
+197
View File
@@ -0,0 +1,197 @@
<template>
<div>
<div class="bg-white py-3 px-3 text-primary font-bold drop-shadow wrap-fix flex z-10">
<div @click="router.back()">
<BasicIcon icon="vuesax-linear:arrow-right-1" />
</div>
<div class="mr-2">هشدارهای فعلی</div>
</div>
<!-- <a-spin :spinning="loading">-->
<div ref="el" :class="loading? 'h-screen': ''" class="px-3 pt-16 pb-2 overflow-y-scroll"
style="max-height: calc(100vh - 50px)">
<list-anim v-if="!loading" class="pb-12vh">
<Item v-for="item in items" :key="item.id" :item="item" @edit="openEdit" @refresh="initItems" />
<!-- <TransactionSkeleton v-if="loadingMore" class="mt-1 mb-8" />-->
</list-anim>
<div v-if="loading">
<TransactionSkeleton v-for="i in 13" :key="i" class="mt-1" />
</div>
</div>
<!-- </a-spin>-->
<BasicActionSheet v-model:show="addTriggerVisible" teleport="body">
<a-form ref="formRef" :model="form" class="!mt-5" name="basic"
@finish="ok()">
<div class="flex flex-col gap-4 pb-12 w-full">
<div class="font-bold text-lg">هشدار قیمت</div>
<a-form-item :rules="[required()]" class="home_appear_fade_in_down" label="جهت قیمت" name="price_condition">
<BasicSelect :items="typeItems" v-model:value="form.price_condition" :show-search="false" value-name="value"
key-name="key"
placeholder="انتخاب نوع جهت قیمت"
size="large"></BasicSelect>
</a-form-item>
<a-form-item :rules="[required()]" class="home_appear_fade_in_down" label="قیمت" name="target_price">
<BasicInput v-model:value="form.target_price" place-holder="وارد کردن قیمت" type="price" size="large"
addon-before="ریال" />
</a-form-item>
<a-form-item :rules="[required()]" class="home_appear_fade_in_down" name="action"
label="نوع هشدار را انتخاب کنید">
<a-radio-group v-model:value="form.action">
<a-radio :style="radioStyle" value="sms">ارسال پیامک</a-radio>
<a-radio :style="radioStyle" value="email">ارسال ایمیل</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item>
<a-spin :spinning="loading">
<BasicButton class="w-full" type="primary" html-type="submit">
{{ editId ? 'ویرایش هشدار' : 'ثبت هشدار' }}
</BasicButton>
</a-spin>
</a-form-item>
</div>
</a-form>
</BasicActionSheet>
<!-- <div class="bg-primary w-3rem h-3rem flex items-center justify-center rounded-lg fixed bottom-12vh left-8vw"
@click="openAdd()">
<BasicIcon icon="vuesax-linear:add" color="white" />
</div>-->
<Transition mode="out-in" name="fade">
<div
class="wrap-fix bottom-0 h-[16vh] bg-[#FBFBFC] shadow-lg rounded-3xl flex justify-center pt-3 z-200"
style="box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 26px 11px"
@click="openAdd()">
<BasicIcon icon="vuesax-linear:add" />
<div>افزودن هشدار جدید</div>
</div>
</Transition>
</div>
</template>
<script lang="ts" setup>
import { createPriceTrigger, getPriceTriggers, updatePriceTrigger } from '@/api/triggerPrice'
const radioStyle = reactive({
display: '',
height: '30px',
lineHeight: '30px'
})
import type { SelectItem } from '@/models/SelectItem'
// import Item from "./components/Item.vue";
/*import {lengthValidation, required} from "@/utils/inputRules";
import {loading} from "@/utils";
import BasicButton from "@/components/BasicPacks/BasicButton.vue";
import BasicActionSheet from "@/components/BasicPacks/BasicActionSheet.vue";
import BasicInput from "@/components/BasicPacks/BasicInput.vue";*/
import { onMounted, reactive, ref } from 'vue'
import type { TableEngineInput, TableOutput } from '@/models/table'
import { loading, loadingMore } from '@/utils'
// import {getOrders} from "@/api/order";
import { getTransactionTable } from '@/api/transaction'
import type { Transaction } from '@/models/transaction'
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
import BasicActionSheet from '@/components/BasicPacks/BasicActionSheet.vue'
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
import BaseDatePicker from '@/components/BasicPacks/BaseDatePicker/src/BaseDatePicker.vue'
import { useInfiniteScroll, useScroll } from '@vueuse/core'
import ListAnim from '@/components/ListAnim.vue'
import TransactionSkeleton from '@/components/TransactionSkeleton.vue'
import { DotLottieVue } from '@lottiefiles/dotlottie-vue'
import { mobileValidation, required } from '@/utils/inputRules'
import BasicInput from '@/components/BasicPacks/BasicInput.vue'
import type { User } from '@/models/login'
import { type FormInstance, message } from 'ant-design-vue'
import type { PriceTrigger } from '@/models/PriceTrigger'
import BasicSelect from '@/components/BasicPacks/BasicSelect.vue'
import Item from './components/Item.vue'
import { cloneDeep } from 'lodash'
import router from '@/router'
const items = ref<PriceTrigger[]>([])
const addTriggerVisible = ref<boolean>(false)
const editId = ref<number | undefined>(undefined)
const el = ref()
const form = ref<PriceTrigger>({
price_condition: '',
is_active: true,
action: '',
target_price: ''
})
const formRef = ref<FormInstance>()
onMounted(() => {
initItems()
})
function resetFields() {
form.value = {
price_condition: '',
is_active: true,
action: '',
target_price: ''
}
}
function openAdd() {
resetFields()
editId.value = undefined
addTriggerVisible.value = true
}
async function initItems() {
try {
items.value = []
items.value = await getPriceTriggers()
// console.log(items.value)
} catch (e) {
console.log(e)
} finally {
loading.value = false
loadingMore.value = false
}
}
function openEdit(val: PriceTrigger) {
form.value = cloneDeep(val)
editId.value = form.value.id
addTriggerVisible.value = true
}
async function ok() {
formRef.value?.validateFields().then(async () => {
try {
loading.value = true
editId.value ? await updatePriceTrigger(editId.value, form.value) : await createPriceTrigger(form.value)
message.success('هشدار با موفقیت ایجاد شد')
await initItems()
addTriggerVisible.value = false
//
} catch (e) {
console.log(e)
} finally {
loading.value = false
}
})
}
const typeItems: SelectItem[] = [
{
value: 'بزرگتر',
key: '>'
},
{
value: 'کوچکتر',
key: '<'
},
{
value: 'مساوی',
key: '=='
}
]
</script>
<style scoped>
</style>
@@ -0,0 +1,721 @@
<template>
<div class="h-35rem overflow-y-auto">
<div class=" !overflow-y-scroll bg-white py-3 text-primary font-bold flex justify-evenly">
<!-- <div @click="isBuy = false" class="w-full text-center" :class="!isBuy?'text-primary':'text-gray-400'">خرید طلا</div>
<div @click="isBuy = true" class="w-full text-center" :class="isBuy?'text-primary':'text-gray-400'">فروش طلا</div>-->
<div class="flex justify-evenly w-full px-2 h-11 items-center bg-gray-50 relative rounded ">
<div :class="isBuy?'text-secondary':'text-gray-400'" class="w-full text-center z-2"
@click.stop="setIsBuy(true) "
:style="!props?.ProductItem?.open_buy ? 'pointer-events: none; opacity: 0.5;' : ''">
خرید {{ props?.ProductItem?.title }}
</div>
<div :class="!isBuy?'text-secondary':'text-gray-400'" class="w-full text-center z-2"
@click.stop="setIsBuy(false) "
:style="!props?.ProductItem?.open_sell ? 'pointer-events: none; opacity: 0.5;' : ''"
>
فروش {{ props?.ProductItem?.title }}
</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()"
class="absolute bg-white h-8 w-1/2 rounded-lg animate right"></div>
</div>
</div>
<div v-if="userStore" class=" mt-5 pb-2 mb-19vh">
<!-- <a-spin :spinning="loading">-->
<div v-if="!loading" :class="!isBuy? ' bg-red-100' : ' bg-green-100'"
class="w-full relative rounded-lg h-[88px] flex flex-col justify-center background-color-transition">
<img :src="img1" alt="" class="h-[88px] absolute">
<div class="w-full items-center flex flex-col">
<div class="text-gray-700 font-bold">{{ !isBuy ? 'قیمت فروش' : 'قیمت خرید' }}</div>
<div v-if="price" class="flex gap-1 mt-3 text-xs items-center">
<div :class="!isBuy? 'text-red-700' : 'text-green-700'" class="font-bold text-2xl color-transition">
{{ usePriceWithoutType(isBuy ? ((props?.ProductItem?.price ?? 0) + (props?.ProductItem?.cash_fee_buy ?? 0)) : ((props?.ProductItem?.price ?? 0) - (props?.ProductItem?.cash_fee_sell ?? 0))) }}
</div>
ریال
</div>
</div>
</div>
<div v-else class="w-full h-[88px]">
<GoldSkeleton class="w-full" />
</div>
<div v-if="limitedPrice !== undefined && userStore?.userInfo.trade_active !== 1"
class="text-red text-xs flex gap-1 items-center justify-center my-2">
<Icon icon="vuesax-linear:info-circle" size="16" />
حداقل مبلغ اولیه برای ثبت سفارش {{ usePriceWithoutType(limitedPrice.value as number ?? 0) }} ریال می باشد.
</div>
<!-- </a-spin>-->
<a-form ref="refInput" :model="form" class="!mt-5" name="basic" @finish="okConfirm()">
<div class="border-gray-200 border-1 rounded-xl p-5 relative">
<bg_main />
<div class="z-100 relative">
<a-form-item name="method" :rules="[required()]">
<BasicSelect v-model:value="form.method" :items="typeDeal"
key-name="key"
:show-search="false"
value-name="value"
:allow-clear="false"
:placeholder="isBuy?'نحوه خرید را انتخاب کنید':' نحوه فروش را انتخاب کنید'"
size="large"
:has-tooltip="false" />
</a-form-item>
<a-form-item v-if="isBuy" name="goldValue"
:rules="[justNumber2(props?.ProductItem?.price , form.method , props?.ProductItem?.amount, true)]">
<BasicInput v-model:value="form.goldValue" addon-before="تعداد" addon-bg-color="#0A1B37"
addon-text-color="white"
place-holder="تعداد"
size="large" type="number" inputmode="number" @onchange="calculateCash" />
</a-form-item>
<a-form-item v-else name="goldValue"
:rules="[justNumber3(props?.ProductItem?.sellPrice, productNum ,false)]">
<BasicInput v-model:value="form.goldValue" addon-before="تعداد" addon-bg-color="#0A1B37"
addon-text-color="white"
place-holder="تعداد"
size="large" type="number" inputmode="number" @onchange="calculateCash" />
</a-form-item>
<div class="flex justify-between">
<div> قیمت کل</div>
<div>{{ usePrice(form.goldCash ?? 0) }}</div>
</div>
<div v-if="props?.ProductItem?.group_type !== 'سکه'" class="flex justify-between">
<div> وزن کل</div>
<div>{{ form.goldVazn ?? 0 }} گرم</div>
</div>
<!-- {{walletStore?.walletInfo?.gold}}-->
<Transition mode="out-in" name="fade" class="mt-2">
<div v-if="isBuy&&form.method=='gold'" class="font-bold text-xs">
<div> {{ `موجودی کیف طلا: ${walletStore?.walletInfo?.gold ?? 0} گرم` }}</div>
</div>
<div v-else-if="isBuy" class="font-bold text-xs">
{{ `موجودی کیف پول: ${usePriceWithoutType(walletStore?.walletInfo?.cash ?? 0)} ریال` }}
</div>
<div class="font-bold text-xs" v-else>{{ `موجودی محصول: ${getInventoryById(props?.ProductItem?.id)}` }}
</div>
</Transition>
<Transition mode="out-in" name="fade">
<div v-if="priceErrorVisible" class="flex gap-1 items-center text-xs mt-[-15px] text-orange-600">
<BasicIcon icon="vuesax-linear:danger" />
ارزش کل وارد شده بر حسب گرم طلا محاسبه خواهد شد و قیمت وارد شده معادل {{ usePrice(finalPrice) }} می
باشد!
</div>
</Transition>
</div>
</div>
<GoldLoading v-model:show="infoVisible" title="" />
<a-form-item>
<BasicButton
v-if="walletStore"
:disabled="disableTransaction"
class=" w-full py-2 mt-5"
html-type="submit"
type="primary"
>
<div>
<a-spin v-if="loading" size="small" />
<div v-else>{{ !isBuy ? 'فروش' : 'خرید' }}</div>
</div>
</BasicButton>
<!-- <div class=" w-full !z-100 px-6 rounded-xl py-1 border-1 bg-white mt-2">
&lt;!&ndash; <BasicInfoItem is-line title="کارمزد" :value="parseFloat(((form.goldValue?? 0)*0.005).toFixed(3))" />&ndash;&gt;
&lt;!&ndash; <BasicInfoItem is-line title="کارمزد" :value="parseFloat(((form.goldValue?? 0)*0.005).toFixed(3))" />&ndash;&gt;
<div class="flex justify-between items-center">
<div>کارمزد:</div>
<div class="flex gap-2 items-center">
&lt;!&ndash; <div class="line-through">{{ parseFloat(((form.goldValue ?? 0) * 0.005).toFixed(3)) }}</div>&ndash;&gt;
&lt;!&ndash; <div>{{props.ProductItem.price}}</div>&ndash;&gt;
<div v-if="isBuy && form.method=='cash' " class="">{{
usePriceWithoutType(buyFee ?? 0)
}}
</div>
<div v-if="isBuy && form.method!='cash'" class="">{{
buyFeeGeram ?? 0
}}
</div>
<div v-if="!isBuy && form.method=='cash' " class="">{{
usePriceWithoutType(sellFee ?? 0)
}}
</div>
<div v-if="!isBuy && form.method!='cash'" class="">{{
sellFeeGeram ?? 0
}}
</div>
<div>
{{ form.method == "cash" ? "ریال" : "گرم" }}
</div>
</div>
</div>
</div>-->
<!-- <div v-if="!isBuy && form.goldValue > walletStore?.walletInfo?.gold"
class="text-red-700 text-xs font-bold mt-2">
مقدار گرم طلای وارد شده جهت فروش ({{ form.goldValue }}گرم) بیشتر از مقدار موجودی شما
({{ walletStore?.walletInfo?.gold }}گرم) می باشد.
</div>
&lt;!&ndash; <div>{{form?.goldValue? true: false}}</div>&ndash;&gt;
<div v-if="isBuy? ((form?.goldValue || form.goldValue === 0)? form?.goldCash < 500000: false) : false"
class="text-red-700 text-xs font-bold mt-2">
حداقل مقدار طلا جهت خرید 500,000 ریال می باشد.
</div>-->
</a-form-item>
</a-form>
</div>
<van-dialog v-model:show="noCompleteVisible" class="completeButtonStyle" confirm-button-text="تکمیل اطلاعات"
show-confirm-button @confirm="router.push('user')">
<div class="flex flex-col items-center p-2">
<BasicIcon class="home_appear_fade_in_up text-center" color="orange"
icon="vuesax-linear:info-circle"
size="50" />
<!-- <div class="home_appear_fade_in_up delay-100">به روز رسانی</div>-->
<div class="home_appear_fade_in_up mt-2 text-justify text-center">برای ثبت سفارش، لطفا اطلاعات خود را تکمیل کنید
یا در صورت تکمیل اطلاعات، منتظر تایید اطلاعات خود بمانید.
</div>
</div>
</van-dialog>
</div>
<BasicActionSheet v-model:show="confirmAction">
<div class="font-bold text-lg"></div>
<div class="w-full rounded-lg bg-gray-50 p-3">
<div class="flex justify-between ">
<div>تعداد:</div>
<div class="flex items-center">
<div class="font-bold">{{ form.goldValue }}</div>
<div class="text-xs mr-1"> عدد</div>
<div class="text-base font-bold mr-1"> عدد {{ props?.ProductItem?.title }}</div>
</div>
</div>
<div class="flex justify-between mt-3">
<div>قیمت:</div>
<div class="flex items-center">
<div class="font-bold">
{{ usePriceWithoutType(isBuy ? props?.ProductItem.price ?? 0 : props?.ProductItem?.sellPrice ?? 0) }}
</div>
<div class="text-xs mr-1">ریال</div>
</div>
</div>
<div class="flex justify-between mt-3">
<div>کارمزد:</div>
<div class="flex items-center gap-2">
<div v-if="isBuy" class="">{{
buyFee
}}
</div>
<!-- <div class="font-bold line-through">{{ 0 }}</div>-->
<div v-else class="">{{
sellFee
}}
</div>
<div class="text-xs mr-1">ریال</div>
</div>
</div>
<div class="flex justify-between mt-3">
<div>{{ isBuy ? 'قیمت قابل پرداخت:' : 'مبلغ دریافتی:' }}</div>
<div class="flex items-center">
<div class="font-bold">{{ usePriceWithoutType(payablePrice.toFixed(0)) }}</div>
<div class="text-xs mr-1">ریال</div>
</div>
</div>
</div>
<BasicButton class="mb-20 mt-5 w-full" type="primary" @click="ok(); confirmAction= false">ثبت نهایی</BasicButton>
</BasicActionSheet>
</template>
<script lang="ts" setup>
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
import img1 from '@/assets/img/home_ly2.svg'
import {useFormat, usePrice, usePriceWithoutType, useTowDecimal} from '@/utils/usePrice'
import BasicInput from '@/components/BasicPacks/BasicInput.vue'
import type { Gold } from '@/models/gold'
import { loading, loadingMore, toFixedDownThreeChar } from '@/utils'
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
import router from '@/router'
import { useWalletStore } from '@/store/walletStore'
import { createOrder } from '@/api/order'
import { FormInstance, message } from 'ant-design-vue'
import type { Price } from '@/models/home'
// import {getLastPrice} from '@/api/home'
import Icon from '@/components/BasicPacks/BasicIcon.vue'
import { useUserStore } from '@/store/userStore'
import BasicActionSheet from '@/components/BasicPacks/BasicActionSheet.vue'
import { justNumber, justNumber2, justNumber3, required, ruleNumber } from '@/utils/inputRules'
import GoldSkeleton from '@/views/base/gold/components/GoldSkeleton.vue'
import GoldLoading from '@/components/GoldLoading.vue'
// import {update} from 'lodash'
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
import type { Transaction } from '@/models/transaction'
import type { TableEngineInput, TableOutput } from '@/models/table'
import { useInfiniteScroll } from '@vueuse/core'
import { getTransactionTable } from '@/api/transaction'
import { getLastPrices, lastPrice, setIntervalGetAllPrice, stopPriceInterval } from '@/utils/price'
import { Product } from '@/models/products'
import BasicSelect from '@/components/BasicPacks/BasicSelect.vue'
import { SelectItem } from '@/models/SelectItem'
import Bg_main from '@/components/bg_main.vue'
import { useFundUserStore } from '@/store/fundStore'
// import Bg_main from "@/components/bg_main.vue";
const typeDeal: SelectItem[] = [
{
value: 'نقدی',
key: 'cash'
},
{
value: ' طلایی',
key: 'gold'
}
]
const infoVisible = ref(false)
const walletStore = useWalletStore()
const userStore = useUserStore()
const confirmAction = ref<boolean>(false)
const noCompleteVisible = ref<boolean>(false)
const buyItems = ref<Transaction[]>([])
const sellItems = ref<Transaction[]>([])
const priceErrorVisible = ref<boolean>(false)
const buyTableOutput = ref<TableOutput<Transaction> | null>(null)
const sellTableOutput = ref<TableOutput<Transaction> | null>(null)
const fundStore = useFundUserStore()
const refInput = ref<FormInstance>()
const el = ref()
interface Prop {
ProductItem?: Product
}
const props = withDefaults(defineProps<Prop>(), {})
const isBuy = ref<boolean>(true)
const buyFee = computed(() => ((props?.ProductItem?.amount * (props?.ProductItem?.percent_fee_buy ?? 0) * (props?.ProductItem?.price ?? 0)).toFixed(0)))
const sellFee = computed(() => ((props?.ProductItem?.amount * (props?.ProductItem?.percent_fee_sell ?? 0) * (props?.ProductItem?.sellPrice ?? 0)).toFixed(0)))
const sellFeeGeram = computed(() => {
if (form.value.goldVazn)
return (form.value.goldVazn * props.ProductItem?.percent_fee_sell).toFixed(3)
})
const buyFeeGeram = computed(() => {
if (form.value.goldVazn)
return (form.value.goldVazn * props.ProductItem?.percent_fee_buy).toFixed(3)
})
const buyPagination = ref<TableEngineInput>({
filters: [{
field: 'type',
cr: 'and',
type: 'number',
op: 'eq',
value: 1
}], limit: 6, page: 0
})
const sellPagination = ref<TableEngineInput>({
filters: [{
field: 'type',
cr: 'and',
type: 'number',
op: 'eq',
value: 2
}], limit: 6, page: 0
})
const finalPrice = computed(() => (form.value?.goldValue * (isBuy.value ? props.ProductItem?.price ?? 0 : props.ProductItem?.sellPrice ?? 0)))
// const payablePrice = computed(() => finalPrice.value + finalPrice.value * 0.007)
const payablePrice = computed(() => finalPrice.value)
const disableTransaction = computed(() =>
loading.value ||
form.value?.goldValue === undefined ||
form.value?.goldValue === '' ||
form.value?.goldCash === '' ||
form.value?.goldCash === undefined ||
(isBuy.value ? (form.value?.goldCash ?? 0) < 500000 : (form.value?.goldValue ?? 0) < 0.001) ||
// (!isBuy.value && form.value.goldValue > walletStore?.walletInfo?.gold) ||
price.value?.buy === undefined)
function refreshTable() {
sellItems.value = []
buyItems.value = []
sellPagination.value = {
filters: [{
field: 'type',
cr: 'and',
type: 'number',
op: 'eq',
value: 2
}], limit: 6, page: 0
}
buyPagination.value = {
filters: [{
field: 'type',
cr: 'and',
type: 'number',
op: 'eq',
value: 1
}], limit: 6, page: 0
}
/* initSellTable()
initBuyTable()*/
}
async function initBuyTable() {
try {
buyPagination.value.page === 0 ? loading.value = true : loadingMore.value = true
buyTableOutput.value = await getTransactionTable(buyPagination.value)
buyItems.value.push(...buyTableOutput.value.rows)
// console.log(tableOutput.value)
} catch (e) {
console.log(e)
} finally {
loading.value = false
loadingMore.value = false
}
}
async function initSellTable() {
try {
sellPagination.value.page === 0 ? loading.value = true : loadingMore.value = true
sellTableOutput.value = await getTransactionTable(sellPagination.value)
sellItems.value.push(...sellTableOutput.value.rows)
// console.log(tableOutput.value)
} catch (e) {
console.log(e)
} finally {
loading.value = false
loadingMore.value = false
}
}
// if (!userStore.isSingle) {
/*useInfiniteScroll(
el,
async () => {
// load more
// console.log('salamss')
if (!userStore.isSingle) {
if (isbuy.value) {
// console.log((buyeTableOutput.value.query.page))
// console.log(buyeTableOutput.value.query.total)
// console.log((buyeTableOutput.value.query.page + 1) * buyPagination.value.limit < buyeTableOutput.value.query.total)
if (
buyeTableOutput.value &&
(buyPagination.value.page + 1) * buyPagination.value.limit < buyeTableOutput.value.query.total
) {
// console.log('gfgf')
buyPagination.value.page++
await initbuyTable()
}
} else {
if (
sellTableOutput.value &&
(sellPagination.value.page + 1) * sellPagination.value.limit < sellTableOutput.value.query.total
) {
// console.log('gfgf')
sellPagination.value.page++
await initsellTable()
}
}
}
},
{distance: 12}
)*/
// }
onMounted(async () => {
switch (router.currentRoute.value.query.state) {
case 'sell':
isBuy.value = false
break
case 'buy':
isBuy.value = true
break
}
/* await initSellTable()
await initBuyTable()*/
})
const form = ref<Gold>({
goldCash: undefined,
goldValue: undefined,
percentWallet: undefined,
method: 'cash',
goldVazn:undefined
})
const allowedAsciiCodeFloat = [46, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57]
// const allowedAsciiCodeInt = [48, 49, 50, 51, 52, 53, 54, 55, 56, 57]
watch(form.value, () => {
if (form.value.goldValue) {
form.value.goldValue = parseFloat(form.value.goldValue)
const lastCharGoldStr: string = form.value.goldValue.toString()
if (!allowedAsciiCodeFloat.includes(lastCharGoldStr.slice(-1).charCodeAt(0))) {
calculateCash(form.value.goldValue)
}
}
})
onMounted(() => {
console.log(userStore.userInfo?.is_legal === 2)
if (userStore.userInfo?.is_legal === 0) {
noCompleteVisible.value = true
}
})
const productNum = ref<number>(0)
const getInventoryById = (id: number) => {
userStore?.productWallet?.forEach((val) => {
if (val.product_id == id)
productNum.value = val.gold
})
return productNum.value ?? 0
}
/*function percentChange(val: number) {
if (val !== 0)
if (isBuy.value) {
form.value.goldCash = unitCashCalculator.value * val
calculateGold(form.value.goldCash)
calculateCash(form.value.goldValue)
} else {
// console.log((unitGoldCalculator.value * val).toFixed(2))
// form.value.goldValue = parseFloat((unitGoldCalculator.value * val).toFixed(2))
form.value.goldValue = toFixedDownThreeChar(parseFloat(unitGoldCalculator.value * val))
calculateCash(form.value.goldValue)
}
else {
form.value.goldValue = undefined
form.value.goldCash = undefined
}
}*/
const unitGoldCalculator = computed(() => {
// console.log(walletStore?.walletInfo?.gold / 100)
return (walletStore?.walletInfo?.gold ?? 0) / 100
})
const unitCashCalculator = computed(() => {
return (walletStore?.walletInfo?.cash ?? 0) / 100
})
const limitedPrice = computed(() => {
if (walletStore.limitedPrice)
return walletStore?.limitedPrice[0]
})
function calculateCash(val: number) {
priceErrorVisible.value = false
// console.log(val)
if (price.value) {
form.value.goldVazn = parseFloat((val * (( props?.ProductItem?.price) + (props?.ProductItem?.cash_fee_buy)))/lastPrice.value?.buy).toFixed(1)
console.log(val,props?.ProductItem?.price,props?.ProductItem?.cash_fee_buy,lastPrice.value?.buy)
if (isBuy.value) {
if (val){
form.value.goldCash = parseFloat(val * (( props?.ProductItem?.price) + (props?.ProductItem?.cash_fee_buy))).toFixed(0)
}
else {
form.value.goldCash = 0
form.value.goldVazn = 0
}
}
else {
if (val)
form.value.goldCash = parseFloat((val * props?.ProductItem?.price) + (props?.ProductItem?.cash_fee_sell)).toFixed(0)
else{
form.value.goldCash = 0
form.value.goldVazn = 0
}
}
console.log(form.value.goldVazn)
}
}
/*function calculateGold(val: number) {
// console.log(val)
// form.value.goldCash = usePriceWithoutType(form.value.goldCash)
if (price.value) {
if (isBuy.value) {
if (val) {
form.value.goldValue = toFixedDownThreeChar(parseFloat(val / price?.value?.buy))
if (parseInt(finalPrice.value) > 0) priceErrorVisible.value = true
if (parseInt(finalPrice.value) === 0) priceErrorVisible.value = false
} else if (val.toString() === '') {
form.value.goldValue = undefined
priceErrorVisible.value = false
} else {
form.value.goldValue = 0
priceErrorVisible.value = false
}
} else {
if (val) {
form.value.goldValue = toFixedDownThreeChar(parseFloat((val / price?.value?.sell)))
if (parseInt(finalPrice.value) > 0) priceErrorVisible.value = true
if (parseInt(finalPrice.value) === 0) priceErrorVisible.value = false
} else if (val.toString() === '') {
// console.log('sasasasasasa')
form.value.goldValue = undefined
priceErrorVisible.value = false
} else {
form.value.goldValue = 0
priceErrorVisible.value = false
}
}
}
}*/
/*watch(form.value?.goldValue, (n)=>{
console.log('salammmm', n)
})*/
const bganim = ref(null)
function useStyle() {
if (isBuy.value) return 'right: 2%;'
// if (isbuy.value) return 'animation-direction: normal'
// else return 'animation-direction: reverse'
else return ' right: 98%; transform: translate(100%, 0);'
}
function setIsBuy(val: boolean) {
isBuy.value = val
form.value.goldValue = undefined
form.value.goldCash = undefined
form.value.percentWallet = 0
priceErrorVisible.value = false
// console.log(bganim.value.classList)
// bganim?.value?.classList.add(val?'right':'left')
// bganim?.value?.style.transform = `translateX(${val ? '0' : '-100'});`
// bganim?.value?.style.animationDirection = val? 'normal':'reverse'
// val? bganim?.value?.classList?.add("move") : bganim?.value?.classList?.remove("move")
// const el = bganim.value?.
// el.
}
const formatter = (value: number) => {
return `${value}%`
}
const price = computed((): Price => <Price>lastPrice.value ?? 0)
onMounted(async () => {
// await initPrice()
// await setIntervalGetPrice()
// console.log('okkkkkkkkgold')
})
async function initPrice() {
try {
// chartLoading.value = true
await getLastPrices()
// await setIntervalGetPrice()
loading.value = true
price.value = lastPrice.value
props.ProductItem.price = lastPrice.value?.buy * props.ProductItem?.amount
props.ProductItem.sellPrice = lastPrice.value?.sell * props.ProductItem?.amount
} catch (e) {
console.log(e)
} finally {
loading.value = false
// chartLoading.value = false
}
}
// onMounted(() => {
// initPrice()
// })
function okConfirm() {
confirmAction.value = true
refInput.value?.validateFields()
}
async function ok() {
try {
loading.value = true
infoVisible.value = true
await createOrder({
direction: isBuy.value ? 1 : 2,
product_id: props.ProductItem.id,
method: form.value.method,
number: form.value.goldValue ?? 0
})
await walletStore.getMyWallet()
await router.push({ name: 'transactions' })
form.value = {
goldValue: undefined,
goldCash: undefined,
percentWallet: undefined,
method: 'cash'
}
// refreshTable()
await fundStore.getMyFund()
message.success('سفارش شما با موفقیت انجام شد')
} catch (e) {
// console.log(e)
// await initPrice()
} finally {
loading.value = false
infoVisible.value = false
}
}
</script>
<style lang="less">
/*.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}*/
/*.completeButtonStyle{
background: blue;
}*/
.completeButtonStyle .van-dialog__confirm .van-button__content {
background: #0A1B37;
color: white;
}
.left {
transform: translateX(0);
left: 0;
}
.toggle-transe-parent {
animation: ease-in-out infinite alternate swingParent;
}
@keyframes swingParent {
from {
transform: translateX(0);
left: 0;
}
to {
left: 100%;
transform: translateX(-100%);
}
}
.animate.right {
right: 0;
}
.animate.right.move {
right: 100%;
transform: translate(100%, 0);
}
.text-secondary{
color: #d3a233 !important;
}
</style>
@@ -0,0 +1,61 @@
<template>
<div class="flex bg-white border-1 border-gray-200 rounded-lg"
:class="props.ProductItem.show ? 'bg-white opacity-100' : 'bg-gray-200 opacity-50'">
<div class="bg-gray-100 m-2 rounded-lg w-28 h-28 flex justify-center p-2">
<img v-if="props.ProductItem.group_type=='گوی'" :src="goyImg">
<img v-if="props.ProductItem.group_type=='مکعب'" :src="mokaabImg">
<img v-if="props.ProductItem.group_type=='سکه'" :src="sekkeImg">
<img v-if="props.ProductItem.group_type=='سکه پارسیان'" :src="parsianImg">
<img v-if="props.ProductItem.group_type=='آبشده'|| props.ProductItem.group_type== null" :src="defaultImg">
</div>
<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!='آبشده'" class=" font-500">{{ amountProduct}}</div>-->
<!-- <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!='آبشده'" class="text-xs text-gray-400">شامل 33 هزار تومان اجرت</div>-->
<!-- <div v-else class="text-xs text-gray-400">محاسبه بر اساس قیمت روز</div>-->
</div>
</div>
</template>
<script setup lang="ts">
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 parsianImg from "@/assets/img/parsianImg.svg"
import type {Product} from "@/models/products";
import {usePrice} from "../../../../utils/usePrice";
import {computed, ref} from "vue";
interface Prop {
ProductItem: Product
}
const amountProduct=computed(()=>{
if (0<props.ProductItem.amount && props.ProductItem.amount<1){
return `${props.ProductItem.amount*1000}سوت`
}else return `${props.ProductItem.amount}گرم`
})
const props = withDefaults(defineProps<Prop>(), {})
// const typeOfProduct=(val:string)=>{
// if (val.includes('گوی'))
// return 'گوی'
// if (val.includes('شمش'))
// return 'شمش'
// if (val.includes('مکعب'))
// return 'مکعب'
// if (val.includes('24 عیار'))
// return '24 عیار'
//
// return 'آب شده'
// }
</script>
<style scoped>
</style>
+199
View File
@@ -0,0 +1,199 @@
<template>
<div class="bottom-0 fixed top-0">
<img :src="img" alt="" class=" w-inherit "
:style="{ backgroundRepeat: 'repeat', }"
/>
</div>
<a-spin :spinning="loading">
<div class=" !h-full overflow-y-scroll">
<div class="w-full flex justify-center top-0 py-5">
<ARadioGroup size="large" @change="changeTab" v-model:value="activekey" button-style="solid">
<ARadioButton class="cats" value="همه">همه</ARadioButton>
<ARadioButton class="cats" v-for="item in typeItems" :value="item">{{ item }}</ARadioButton>
</ARadioGroup>
</div>
<div class="mx-5 pb-30 pt-2" style="color: #1b2b07">
<div class="mt-3" v-for="item in items">
<ProductItem :ProductItem="item" @click="clickProduct(item)"></ProductItem>
</div>
</div>
</div>
</a-spin>
<!-- <BasicActionSheet v-model:show="showFilter">-->
<!-- <indexGold ></indexGold>-->
<!-- </BasicActionSheet>-->
<BasicActionSheet placement="bottom" v-model:show="showFilter">
<div class="">
<indexGold v-if="selectedProduct?.group_type=='آبشده'" :ProductItem="selectedProduct"></indexGold>
<DealProduct v-else :ProductItem="selectedProduct"></DealProduct>
</div>
</BasicActionSheet>
<BasicModal
v-model:visible="isAfterCloseTime"
custom-footer
:closable="false"
>
<div class="text-center">
<div class="font-bold text-red-600">مشتریان گرامی</div>
<div class="mt-2 leading-relaxed">
<p>فروشگاه در حال حاضر بسته است.</p>
<p>ساعت کاری فروشگاه از {{ openTime }} تا {{ closeTime }} می‌باشد.</p>
<p>از همراهی و اعتماد شما سپاسگزاریم.🤍</p>
</div>
</div>
<template #footer>
<a-button type="primary" class="w-full" @click="isAfterCloseTime = false">
متوجه شدم
</a-button>
</template>
</BasicModal>
</template>
<script setup lang="ts">
import { onMounted, onUnmounted, ref, watch } from 'vue'
import router from '@/router'
import ProductItem from '@/views/base/products/components/ProductItem.vue'
import { getProducts } from '@/api/products'
import {
getLastPrices,
lastPrice,
stopPriceInterval
} from '@/utils/price'
import { loading } from '@/utils'
import { Price } from '@/models/home'
import type { Product } from '@/models/products'
import BasicActionSheet from '@/components/BasicPacks/BasicActionSheet.vue'
import indexGold from '@/views/base/gold/index.vue'
import DealProduct from '@/views/base/products/components/DealProduct.vue'
import { cloneDeep } from 'lodash'
import img from "@/assets/img/user_ly1.svg";
import BasicModal from "@/components/BasicPacks/BasicModal.vue";
const activekey = ref('آبشده')
const showFilter = ref()
const selectedProduct = ref<Product>()
const closeTime = ref<string>('')
const openTime = ref<string>('')
const isAfterCloseTime = ref<boolean>(false)
watch([openTime, closeTime], ([open, close]) => {
if (!open || !close) return
const now = new Date()
const currentSeconds = now.getHours() * 3600 + now.getMinutes() * 60 + now.getSeconds()
const [oh, om, os] = open.split(':').map(Number)
const [ch, cm, cs] = close.split(':').map(Number)
const openSeconds = oh * 3600 + om * 60 + os
const closeSeconds = ch * 3600 + cm * 60 + cs
isAfterCloseTime.value = currentSeconds < openSeconds || currentSeconds > closeSeconds
})
function clickProduct(item: Product) {
if(item?.show){
showFilter.value = true
selectedProduct.value = cloneDeep(item)
}
}
function changeTab() {
if (activekey.value != 'همه') {
items.value = firstItems.value?.filter((val) =>
val.group_type == activekey.value
)
} else items.value = firstItems.value
}
const firstItems = ref<Product[]>()
const price = ref<Price>()
const items = ref<Product[]>()
const typeItems = ref([])
onMounted(async () => {
try {
loading.value = true
items.value = await getProducts()
if (items.value?.length) {
closeTime.value = items.value[0].auto_close_at
openTime.value = items.value[0].auto_open_at
}
items.value?.forEach((val, index) => {
if (!typeItems.value.includes(val.group_type)){
typeItems.value.push(val.group_type)
}
// typeItems.value[index] = val.group_type
})
firstItems.value = items.value
await initPrice()
// await setIntervalGetLastPrice()
// console.log('run product')
} catch (e) {
console.log(e)
} finally {
loading.value = false
if (router.currentRoute.value.query.cat=="coin"){
activekey.value="سکه"
changeTab()
}
if (router.currentRoute.value.query.state) {
if (router.currentRoute.value.query.product) {
clickProduct(items.value?.find(x => x.title === 'سکه'))
} else {
clickProduct(items.value?.find(x => x.title === 'آبشده نقدی'))
}
}
}
})
onUnmounted(() => {
stopPriceInterval()
// console.log('stop product')
// console.log('okgold')
})
// watch(lastPrice, async () => {
// // console.log(items);
// items.value?.forEach((val) => {
// // console.log(lastPrice.value)
// if (val.group_type == 'آبشده') {
// val.price = lastPrice.value?.price_last
// val.sellPrice = lastPrice.value?.sell
// } else {
// val.price = val.amount * lastPrice.value?.price_last
// val.sellPrice = val.amount * lastPrice.value?.sell
//
// // console.log(lastPrice.value?.price_last + "*" + val.amount + ' ' + val.price)
// }
//
// })
// })
async function initPrice() {
try {
// chartLoading.value = true
await getLastPrices()
// await setIntervalGetPrice()
loading.value = true
price.value = lastPrice.value
} catch (e) {
console.log(e)
} finally {
loading.value = false
// chartLoading.value = false
}
}
</script>
<style lang="less">
.cats:hover span {
--un-text-opacity: 1;
color: rgba(206, 163, 76, var(--un-text-opacity))!important;
}
</style>
+285
View File
@@ -0,0 +1,285 @@
<template>
<div>
<div class="wrap-fix z-1 bg-white py-3 px-3 text-primary font-bold drop-shadow flex">
<div @click="router.back()" class="cursor-pointer">
<BasicIcon icon="vuesax-linear:arrow-right-1" />
</div>
<div class="mr-2">قوانین و مقررات</div>
</div>
<div class="pt-20">
<div>
<img :src="img" alt="" class="mt-2 w-full absolute bottom-0" />
</div>
<div class="text-justify text-base z-200000 relative">
<div class="px-10">
<!-- <div class="h-20vh flex justify-center">
<img :src="logoFull" class="mb-20 h-15vh mt-5" />
</div>-->
<div class="overflow-y-auto h-60vh pb-20 border-primary">
<div
class="mt-5 text-5 border-solid border-2 border-primary text-primary rounded-[12px] p-4"
>
<div class="font-bold text-sm text-primary">
قوانین و مقررات معاملات طلا در بستر گلد دات آی آر
</div>
<div class="w-full h-1px my-3 bg-secondary"></div>
<div class="mt-5 text-xs leading-5">
• کاربران موظفند قبل از ثبت‌ نام، تمامی مفاد این تعهدنامه را مطالعه نموده و صرفاً در
صورت پذیرش آن اقدام به ثبت‌نام نمایند.
</div>
<div class="mt-5 text-xs leading-5">
• کاربران گلد دات آی آر می‌پذیرند که کلیه‌ی فعالیت‌های آن‌ها در گلد دات آی آر، در چارچوب قوانین
جمهوری اسلامی ایران بوده و هیچ گونه فعالیتی خارج از این چارچوب انجام نخواهد شد.
</div>
<div class="mt-5 text-xs leading-5">
• احراز هویت برای استفاده از خدمات گلد دات آی آر ضروری بوده و کاربران موظفند اطلاعات صحیح
خود را بارگذاری نمایند؛ بدیهی است در صورت وجود هرگونه تخلف در احراز هویت، مسئولیت به
عهده‌ی فرد متخلف بوده و گلد دات آی آر حق توقف ارائه خدمات به کاربر مذکور و ارجاع موارد
تخلف به مراجع ذی‌صلاح را خواهد داشت.
</div>
<div class="mt-5 text-xs leading-5">
• گلد دات آی آر خود را ملزم به حفظ اطلاعات شخصی کاربران در چارچوب قوانین قضایی کشور
می‌داند.
</div>
<div class="mt-5 text-xs leading-5">
• کاربران گلد دات آی آر تعهد می‌دهند که از قرار دادن حساب خود در اختیار دیگران خودداری
نمایند. از خدمات سایت، تنها برای حساب شخصی خود استفاده نموده و مسئولیت استفاده از
خدمات گلد دات آی آر برای فردی دیگر، به عهده کاربر خواهد بود. شماره حساب اعلام شده به سایت
باید متعلق به کاربر بوده و کاربران مجاز به دادن شماره حساب متعلق به اشخاص دیگر
نیستند.
</div>
<div class="mt-5 text-xs leading-5">
• کاربران می‌پذیرند در صورت تشخیص کارشناسان پشتیبانی، جهت حفظ امنیت دارایی حساب
کاربری‌شان با اطلاع قبلی نسبت به برقراری تماس تصویری با تیم پشتیبان همکاری نمایند.
</div>
<div class="mt-5 text-xs leading-5">
• هرگونه سهل‌انگاری کاربران در حفظ اطلاعات شخصی و امنیتی از جمله: رمز عبور کاربر،
سرقت گوشی کاربر، سرقت کارت ملی و مدارک شناسایی کاربر، سپردن مدارک شخصی و موبایل به
فرد ثالث و ... به عهده‌ی شخص کاربر بوده و گلد دات آی آر هیچ گونه مسئولیتی در این موارد
نخواهد داشت.
</div>
<div class="mt-5 text-xs leading-5">
• اکیداً توصیه می‌شود از رمز عبوری پیچیده، امن و همچنین کد شناسایی دو عاملی استفاده
شود.
</div>
<div class="mt-5 text-xs leading-5">
• گلد دات آی آر این اطمینان را می‌دهد که دارایی‌های کاربران را نزد خود به امانت و به
بهترین شکل و با بالاترین استانداردهای امنیتی ممکن حفظ نماید؛ در صورت بروز هرگونه
مشکل امنیتی، گلد دات آی آر متعهد به جبران خسارت خواهد بود.
</div>
<div class="mt-5 text-xs leading-5">
• به عنوان پلتفرم معاملات برخط فلزات گران‌بها، هیچ‌گونه مسئولیتی در قبال تصمیمات
اقتصادی فی مابین کاربران و سود و زیان حاصل از آن بر عهده گلد دات آی آر نمی‌باشد.
</div>
<div class="mt-5 text-xs leading-5">
• گلد دات آی آر حق اصلاح و تغییر قوانین و مقررات ذکر شده در این صفحه را چه به صورت کلی و
چه به صورت جزئی دارد و نسخه نهایی را در این صفحه در معرض دید قرار می‌دهد. استفاده از
خدمات گلد دات آی آر پس از اعمال تغییرات، به معنای پذیرش همه تغییرات می‌باشد.
</div>
<div class="mt-5 text-xs leading-5">
• از لحظه خرید کاربران تا زمان تحویل طلای خریداری شده، مسئولیت حفظ و نگهداری اصل طلا
بر عهده گلد دات آی آر می‌باشد.
</div>
<div class="mt-5 text-xs leading-5">
• کاربران گلد دات آی آر اذعان می‌دارند که از ریسک‌های اقتصادی مربوط به سرمایه‌گذاری در
حوزه طلا مطلع بوده و با علم بر این موضوع اقدام به تبادل و سرمایه‌گذاری می‌کنند.
</div>
<div class="mt-5 text-xs leading-5">
• گلد دات آی آر متعهد می‌شود در حد توان از حریم شخصی شما محافظت کند و در این راستا،
تکنولوژی مورد نیاز در سایت و پلتفرم را برای هر چه مطمئن‌تر و امن‌تر شدن استفاده شما،
توسعه دهد.
</div>
<div class="mt-5 text-xs leading-5">
• در صورت بروز نوسان شدید در قیمت طلا و هرگونه رویداد برهم‌زننده نظم حاکم بر بازار
طلا، گلد دات آی آر می‌تواند برای خرید و فروش طلا توسط کاربر سقف تعیین کند تا دو طرف متضرر
نشوند.
</div>
<div class="mt-5 text-xs leading-5">
• گلد دات آی آر مجاز است بدون اطلاع قبلی و به صلاح‌دید شخصی نسبت به توقف سفارش‌گیری جدید،
معاملات (از جمله سفارش‌های باز) را متوقف کند؛ بدیهی است که کلیه سفارش‌های تکمیل‌شده
قبل از توقف سفارش‌گیری، پردازش و تحویل داده خواهد شد.
</div>
<div class="mt-5 text-xs leading-5">
• در صورت بروز هرگونه اختلال در اینترنت و خدمات زیرساخت به دلایل حاکمیتی، هیچ‌گونه
مسئولیتی به عهده گلد دات آی آر نمی‌باشد.
</div>
<div class="mt-5 text-xs leading-5">
• درخواست برداشت ریال از حساب کاربری در سریع‌ترین زمان ممکن پس از ثبت، بررسی خواهد
شد. زمان واریز پول به حساب کاربران بر اساس محدودیت‌های انتقال وجه بین بانکی، متفاوت
خواهد بود. برای اطلاعات بیشتر، به قوانین انتقال وجه بین بانکی (پایا، ساتنا) مراجعه
فرمایید.
</div>
<div class="mt-5 text-xs leading-5">
• کاربر می‌پذیرد که به جز در موارد مورد تعهد، حق هیچ‌گونه داعیه، طلب و شکایت از
سایت، مدیران، کارمندان و افراد مرتبط با این سایت را نخواهد داشت.
</div>
<div class="mt-5 text-xs leading-5">
• اگر کاربر تحت هر عنوان اشتباهاً یا من غیر حق، وجوهی را به حساب کاربر منظور یا در
محاسبات خود هر نوع اشتباهی نماید، گلد دات آی آر هر زمان مجاز و مختار است راساً و مستقلاً و
بدون انجام هیچ‌گونه تشریفات اداری و قضایی و دریافت اجازه کتبی از متعهد (صاحب حساب)
در رفع اشتباه و برداشت از حساب‌های وی اقدام نماید و تشخیص نسبت به وقوع اشتباه یا
پرداخت بدون حق و لزوم برداشت از حساب معتبر خواهد بود و کاربر حق هرگونه اعتراض و
ادعایی را در خصوص نحوه عملکرد گلد دات آی آر از هر جهت از خود ساقط می‌نماید.
</div>
<div class="mt-5 text-xs leading-5">
• در صورت بروز هرگونه مشکل یا ابهام در هر یک از معاملات (مانند دستکاری قیمت، اختلال
در وب‌سرویس‌ها، انجام معامله خارج از دامنه نوسان و ...)، گلد دات آی آر حق دارد مستقلاً آن
معامله را ابطال کرده و دارایی‌های هر یک از طرفین را به حساب خودشان عودت دهد. بدیهی
است در صورتی که اشکال از سمت گلد دات آی آر باشد، شرکت موظف خواهد بود که جبران خسارت نماید
و در غیر این صورت، کاربر حق هرگونه اعتراض و ادعایی در خصوص نحوه عملکرد از هر جهت را
از خود ساقط می‌نماید.
</div>
<div class="mt-5 text-xs leading-5">
• در صورت فوت یا حجر کاربر، گلد دات آی آر پیرو قوانین جمهوری اسلامی ایران می‌باشد. کاربر
با علم و اطلاع از مقررات این بند نسبت به افتتاح حساب کاربری در گلد دات آی آر اقدام نموده و
کاربر، اشخاص ثالث، ورثه یا قائم‌مقام قانونی ایشان حق اعتراض و یا ادعایی در آینده در
این خصوص نخواهند داشت.
</div>
<div class="mt-5 text-xs leading-5">
• هزینه خدمات و کارمزد تراکنش‌های مالی انجام شده در مطابق با توضیحات ارائه شده در
صفحه راهنمای استفاده از گلد دات آی آر گلد می‌باشد.
</div>
<div class="mt-5 text-xs leading-5">
• تمامی علائم تجاری، طرح‌های گرافیکی، رابط کاربری، رابط بصری، عکس، لوگو، کدهای
نرم‌افزار، ساختار، نحوه بیان، تنظیم مطالب و محتوای موجود در گلد دات آی آر و شبکه‌های متعلق
به گلد دات آی آر و به‌طور کلی، سایر حقوق و امتیازات مربوطه منحصراً در مالکیت گلد دات آی آر
می‌باشد و هیچ شخصی حق استفاده از آن را بدون رضایت گلد دات آی آر ندارد.
</div>
<div class="mt-5 text-xs leading-5">
• اگر هر یک از مفاد این موافقت‌نامه بر اساس هر قانون لازم‌الاجرا، نامعتبر یا غیرقابل
اجرا تشخیص داده شود، این امر بر اعتبار هیچ ماده دیگری تأثیری نخواهد داشت و بقیه
مقررات اجرا می‌شود.
</div>
</div>
</div>
</div>
<div class="wrap-fix bottom-0 px-10 py-6 flex gap-2 bg-white">
<a class="w-full" href="tel:09190909884">
<BasicButton class="w-full" type="primary">تماس با پشتیبانی</BasicButton>
</a>
<!-- <BasicButton type="primary" @click="$router.push({name: 'permissions'})">
<div>مجوز ها</div>
</BasicButton>-->
<a href="https://t.me/saminn_gold">
<img src="@/assets/img/telegram.png" alt="" class="h-10 w-10"/>
</a>
</div>
</div>
</div>
<!-- <ActionSheet v-model:show="editPassVisible">salam</ActionSheet>-->
</div>
</template>
<script lang="ts" setup>
import { onMounted, reactive, ref } from 'vue'
import img from '@/assets/img/user_ly1.svg'
// import gr_bottom from './assets/img/gr_bottom_white.svg'
import { loading } from '@/utils'
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
import BasicActionSheet from '@/components/BasicPacks/BasicActionSheet.vue'
import { lengthValidation, required } from '@/utils/inputRules'
import BasicInput from '@/components/BasicPacks/BasicInput.vue'
import type { User } from '@/models/login'
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
import router from '@/router'
import type { FormInstance } from 'ant-design-vue'
import { message } from 'ant-design-vue'
import { updateMe } from '@/api/me'
import { useUserStore } from '@/store/userStore'
import BaseDatePicker from '@/components/BasicPacks/BaseDatePicker'
const userFormState = ref<User>({
fname: '',
lname: '',
mobile: undefined,
birth_date: '',
phone_number: '',
province: '',
city: '',
n_code: undefined
})
const formRef = ref<FormInstance>()
const userStore = useUserStore()
// const editPassVisible = ref<boolean>(false)
const editPassVisible = ref<boolean>(false)
function setForm() {
userFormState.value = userStore.userInfo
}
function copyCode() {
// nextTick(() => {
const val = userStore.userInfo?.referral_id
navigator.clipboard.writeText(val)
message.info('کد رونوشت شد')
// })
}
function shareCode() {
// nextTick(() => {
const val = `⭐️الان طلا بخر؛ آخر ماه سودشو ببر!
با خرید طلای آبشده در مقدارهای کم ولی مستمر، سود بیشتری ببر!
این دعوت نامه از طرف "${userStore.userInfo?.name}" عزیز برای شما ارسال شده تا شما هم از بازار طلای گلد داتت آی آر جا نمونید.
روی لینک زیر کلیک کنید و ثبت نام خود را تکمیل کنید.
gold.ir/login?id=${userStore.userInfo?.referral_id}`
navigator.share({
title: ' گلد',
text: val
})
// message.info('کد رونوشت شد')
// })
}
const resetData = () => {
formRef.value?.resetFields()
userFormState.value = {
fname: '',
lname: '',
mobile: undefined,
birth_date: '',
phone_number: '',
province: '',
city: '',
n_code: undefined
}
}
onMounted(() => {
setForm()
})
function ok() {
formRef.value?.validateFields().then(async () => {
try {
loading.value = true
await updateMe(userFormState.value)
await userStore.getMyInfo()
editPassVisible.value = false
message.success('اطلاعات شما با موفقیت به روز رسانی شد')
} catch (e) {
console.log(e)
} finally {
loading.value = false
}
})
}
</script>
<style scoped>
/*.fade-enter-active,
.fade-leave-active {
transition: opacity 0.2s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}*/
/*.trans{
transition: height 1s;
}*/
</style>
@@ -0,0 +1,149 @@
<template>
<div class="bg-white wra-fix z-1 py-3 px-3 text-primary font-bold drop-shadow flex">
<div @click="router.back()" class="cursor-pointer">
<BasicIcon icon="vuesax-linear:arrow-right-1" />
</div>
<div class="mr-2">مجوز ها</div>
</div>
<div class="pt-20">
<div class="">
<img :src="img" alt="" class="mt-2 w-full absolute bottom-0">
</div>
<div class="px-1 text-justify text-base z-200000 relative">
<div>
<!-- <img :src="logoFull" class="mb-20 mt-5 px-10" />-->
<div class="overflow-y-auto h-65vh pb-20 border-primary">
<div class=" font-bold text-sm text-primary text-center">جواز کسب و کار</div>
<!-- <img :src="permission1" alt="" class="w-full">-->
<div class="mt-5 text-xs"></div>
<div class="wrap-fix bottom-0 px-2 py-6 flex gap-2 bg-white">
<a class="w-full" href="tel:09190909884">
<BasicButton class="w-full" type="primary">تماس با پشتیبانی</BasicButton>
</a>
<a href="https://t.me/saminn_gold">
<img src="@/assets/img/telegram.png" alt="" class="h-10 w-10"/>
</a>
</div>
</div>
</div>
</div>
<!-- <ActionSheet v-model:show="editPassVisible">salam</ActionSheet>-->
</div>
</template>
<script lang="ts" setup>
import { onMounted, reactive, ref } from 'vue'
import img from '@/assets/img/user_ly1.svg'
// import gr_bottom from './assets/img/gr_bottom_white.svg'
import { loading } from '@/utils'
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
import BasicActionSheet from '@/components/BasicPacks/BasicActionSheet.vue'
import { lengthValidation, required } from '@/utils/inputRules'
import BasicInput from '@/components/BasicPacks/BasicInput.vue'
import type { User } from '@/models/login'
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
import router from '@/router'
import type { FormInstance } from 'ant-design-vue'
import { message } from 'ant-design-vue'
import { updateMe } from '@/api/me'
import { useUserStore } from '@/store/userStore'
import BaseDatePicker from '@/components/BasicPacks/BaseDatePicker'
const userFormState = ref<User>({
fname: '',
lname: '',
mobile: undefined,
birth_date: '',
phone_number: '',
province: '',
city: '',
n_code: undefined
})
const formRef = ref<FormInstance>()
const userStore = useUserStore()
// const editPassVisible = ref<boolean>(false)
const editPassVisible = ref<boolean>(false)
function setForm() {
userFormState.value = userStore.userInfo
}
function copyCode() {
// nextTick(() => {
const val = userStore.userInfo?.referral_id
navigator.clipboard.writeText(val)
message.info('کد رونوشت شد')
// })
}
function shareCode() {
// nextTick(() => {
const val = `⭐️الان طلا بخر؛ آخر ماه سودشو ببر!
با خرید طلای آبشده در مقدارهای کم ولی مستمر، سود بیشتری ببر!
این دعوت نامه از طرف "${userStore.userInfo?.name}" عزیز برای شما ارسال شده تا شما هم از بازار طلای گلد جا نمونید.
روی لینک زیر کلیک کنید و ثبت نام خود را تکمیل کنید.
gold.ir/login?id=${userStore.userInfo?.referral_id}`
navigator.share({
title: ' گلد',
text: val
})
// message.info('کد رونوشت شد')
// })
}
const resetData = () => {
formRef.value?.resetFields()
userFormState.value = {
fname: '',
lname: '',
mobile: undefined,
birth_date: '',
phone_number: '',
province: '',
city: '',
n_code: undefined
}
}
onMounted(() => {
setForm()
})
function ok() {
formRef.value?.validateFields().then(async () => {
try {
loading.value = true
await updateMe(userFormState.value)
await userStore.getMyInfo()
editPassVisible.value = false
message.success('اطلاعات شما با موفقیت به روز رسانی شد')
} catch (e) {
console.log(e)
} finally {
loading.value = false
}
})
}
</script>
<style scoped>
/*.fade-enter-active,
.fade-leave-active {
transition: opacity 0.2s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}*/
/*.trans{
transition: height 1s;
}*/
</style>
@@ -0,0 +1,171 @@
<template>
<div @click="infoVisible = true">
<!-- {{ item}}-->
<div class="flex">
<div :class="isUp? 'bg-green-50':'bg-red-50'" class="rounded-lg p-3 h-fit w-fit flex justify-center items-center">
<Icon :class="isUp? 'text-green-600':'text-red-600'"
:icon="`vuesax-linear:${isUp? 'arrow-up-2':'arrow-down-2'}`" />
</div>
<div class="w-full mr-3">
<div class="flex justify-between w-full">
<div>{{ item.title }}</div>
<div>{{ toJalaliOutOfUTC(item.expire_at) }}</div>
</div>
<div class="flex justify-between mt-2">
<div :class="item.gold >= 0? 'text-green-600':'text-red-600'"
class="text-gray-500 text-xs number-ltr">{{ item.gold }}
<div>{{item.unit}}</div>
</div>
<div class="text-gray-500 flex gap-1 text-xs items-center number-ltr">
<div :class="item.cash > 0 ? 'text-green-600':'text-red-600'" class="text-base">
{{ usePriceWithoutType(item.cash?? 0) }}
</div>
ریال
</div>
</div>
</div>
</div>
<div v-if="isGold" class="flex w-full justify-between mt-2">
<div class="text-gray-500">قیمت معامله:</div>
<div class="text-gray-500 flex gap-1 text-xs items-center">
<!-- <div class="text-base">{{ typeof parseInt((Math.abs(item.cash) / Math.abs(item.gold)).toFixed(0)) }}</div>-->
<div class="text-base">{{ usePriceWithoutType(parseInt((Math.abs(item.cash) / Math.abs(item.gold)).toFixed(0))) }}</div>
ریال
</div>
</div>
<div class="flex w-full justify-between mt-2">
<div class="text-gray-500">وضعیت :</div>
<div class="text-gray-500 flex gap-1 text-xs items-center">
<ATag class="!py-1 !px-6 !ml-0" color="blue">
{{ item.order?.sts_str ?? item.withdraw?.sts_str }}
</ATag>
</div>
</div>
<!-- <div v-else class="h-8"></div>-->
<a-divider class="!my-3" />
<BasicActionSheet v-model:show="infoVisible">
<div class="font-bold text-lg">{{ props.item.title }}</div>
<div class="pb-20 mt-5">
<div class="flex justify-between mb-3">
<div class="text-primary">مبلغ:</div>
<div :class="item.cash > 0? 'text-green-600' : 'text-red-600'" class="flex text-xs items-center number-ltr">
<div class="text-base ml-1">{{ usePriceWithoutType(item.cash?? 0) }}</div>
ریال
</div>
</div>
<div v-if="item.order" class="flex justify-between mb-3">
<div class="text-primary">قیمت هر گرم طلا حین معامله:</div>
<div class="flex text-xs items-center number-ltr">
<div class="text-base ml-1">{{ usePriceWithoutType(item.order?.price?? 0) }}</div>
ریال
</div>
</div>
<div class="flex justify-between mb-3">
<div class="text-primary">مقدار {{item.wallet?.product? item.wallet.product.title: 'آبشده' }} مبادله شده:</div>
<div :class="item.gold >= 0? 'text-green-600' : 'text-red-600'" class="flex text-xs items-center number-ltr">
<div class="text-base ml-1">{{ item.gold }}</div>
{{item.unit}}
</div>
</div>
<div class="flex justify-between mb-3">
<div class="text-primary">موجودی کیف پول:</div>
<div :class="item.cash > 0? 'text-green-600' : 'text-red-600'" class="flex text-xs items-center number-ltr">
<div class="text-base">{{ usePriceWithoutType(item.balance_cash ?? 0) }}</div>
ریال
</div>
</div>
<div class="flex justify-between mb-3" v-if="item.wallet?.product">
<div class="text-primary">موجودی {{item.wallet.product.title}}:</div>
<div class="flex text-xs text-yellow-700 items-center">
<div class="text-base ml-1">{{ item.balance_gold }}</div>
{{item.wallet.product.unit}}
</div>
</div>
<div class="flex justify-between mb-3" v-else>
<div class="text-primary">موجودی کیف آبشده:</div>
<div class="flex text-xs text-yellow-700 items-center">
<div class="text-base ml-1">{{ item.balance_gold }}</div>
گرم
</div>
</div>
<!-- <div class="flex justify-between mb-3">
<div class="text-primary">موجودی کیف پول:</div>
<div class="flex text-xs items-center" :class="isUp? 'text-green-600' : 'text-red-600'"><div class="text-base">{{usePriceWithoutType(12000000)}}</div>ریال</div>
</div>
<div class="flex justify-between mb-3">
<div class="text-primary">موجودی کیف طلا:</div>
<div class="flex items-center" :class="isUp? 'text-red-600' : 'text-green-600'">60 گرم</div>
</div>-->
<div class="flex justify-between mb-3">
<div class="text-primary">وضعیت:</div>
<div class="flex text-xs items-center">
<ATag :color="item.active? 'blue': 'blue'" class="!py-1 !px-6 !ml-0">
{{ item.order?.sts_str ?? item.withdraw?.sts_str }}
</ATag>
</div>
</div>
<div class="flex justify-between mb-3">
<div class="text-primary">تاریخ:</div>
<div>{{ toJalaliNotime(item.expire_at) }}</div>
</div>
<div class="flex justify-between mb-3">
<div class="text-primary">زمان:</div>
<div>{{ toTime(item.expire_at) }}</div>
</div>
<!-- <div class="flex justify-between mb-3">
<div class="text-primary">وضعیت معامله:</div>
<div class="flex text-xs items-center">
<ATag class="!py-1 !px-6 !ml-0" color="orange">
معاملات باز
</ATag>
</div>
</div>-->
<div v-if="item.eaj" class="flex justify-between mb-3">
<div class="text-primary">مهلت ارسال فیش:</div>
<div>{{ item.eaj }}</div>
</div>
<BasicButton class="w-full mt-5" @click="infoVisible = false">بازگشت</BasicButton>
</div>
</BasicActionSheet>
</div>
</template>
<script lang="ts" setup>
import Icon from '@/components/BasicPacks/BasicIcon.vue'
import { usePriceWithoutType } from '../../../../utils/usePrice'
import BasicActionSheet from '@/components/BasicPacks/BasicActionSheet.vue'
import { computed, ref } from 'vue'
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
import type { Transaction } from '@/models/transaction'
import { toJalaliNotime, toJalaliOutOfUTC, toTime } from '../../../../utils/useDateTime'
const infoVisible = ref<boolean>(false)
interface Prop {
item: Transaction
}
const props = withDefaults(defineProps<Prop>(), {})
const isUp = computed(() => props.item.type === 3 || props.item.type === 1 || props.item.type === 8 || props.item.type === 9)
const isGold = computed(() => props.item.type === 1 || props.item.type === 2 || props.item.type === 10)
/*const title = computed(() => {
if (isUp.value) {
if (isGold.value) {
return 'واریز ریالی'
} else {
return 'خرید طلا'
}
} else {
if (isGold.value) {
return 'برداشت ریالی'
} else {
return 'فروش طلا'
}
}
})*/
</script>
<style scoped>
</style>
+213
View File
@@ -0,0 +1,213 @@
<template>
<div >
<!-- <teleport to="body">-->
<!-- <div class="fixed top-0 right-0 left-0 bottom-0"></div>-->
<!-- </teleport>-->
<div class="absolute inset-0 bg-cover bg-center opacity-60"></div>
<div
class="bg-white w-full transaction-list py-3 px-3 font-bold drop-shadow flex justify-between z-10"
>
<div>لیست تراکنش ها</div>
<BasicIcon icon="vuesax-linear:filter" @click="showFilter = true" />
</div>
<!-- <a-spin :spinning="loading">-->
<div
ref="el"
:class="loading ? 'h-screen' : ''"
class="px-3 pt-16 pb-10 "
>
<!-- <div v-for="item in items">ss</div>-->
<list-anim v-if="!loading">
<Item v-for="item in items" :key="item.id" :item="item" />
<div ref="observer" v-show="!loading" class="w-full opacity-0 relative">
در حال بارگذاری
</div>
<TransactionSkeleton v-if="loadingMore" class="mt-1 mb-8" />
</list-anim>
<TransactionSkeleton v-for="i in 13" v-else :key="i" class="mt-1" />
<div v-if="items.length <= 0" class="flex flex-col items-center justify-center h-80vh">
<DotLottieVue
class="w-11rem h-11rem"
autoplay
src="https://lottie.host/51d3315a-cf88-4c18-bb4d-a31511fd4325/KjSBzcMbi6.json"
/>
<div class="font-bold">تراکنشی موجود نیست</div>
</div>
</div>
<!-- </a-spin>-->
<BasicActionSheet v-model:show="showFilter">
<div class="font-bold text-lg">فیلتر</div>
<div class="pb-20 mt-5">
<a-form-item class="w-full gap-2 !flex-col" label="تاریخ" name="password">
<BaseDatePicker v-model:value="dateFilter" class="w-full" size="large" />
</a-form-item>
<BasicButton class="w-full mt-5" type="primary" @click="applyFilter"
>اعمال فیلتر</BasicButton
>
<BasicButton class="w-full mt-2" @click="showFilter = false">بازگشت</BasicButton>
</div>
</BasicActionSheet>
</div>
</template>
<script lang="ts" setup>
import Item from './components/Item.vue'
/*import {lengthValidation, required} from "@/utils/inputRules";
import {loading} from "@/utils";
import BasicButton from "@/components/BasicPacks/BasicButton.vue";
import BasicActionSheet from "@/components/BasicPacks/BasicActionSheet.vue";
import BasicInput from "@/components/BasicPacks/BasicInput.vue";*/
import { onMounted, ref } from 'vue'
import type { TableEngineInput, TableOutput } from '@/models/table'
import { loading, loadingMore } from '@/utils'
// import {getOrders} from "@/api/order";
import { getTransactionTable } from '@/api/transaction'
import type { Transaction } from '@/models/transaction'
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
import BasicActionSheet from '@/components/BasicPacks/BasicActionSheet.vue'
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
import BaseDatePicker from '@/components/BasicPacks/BaseDatePicker/src/BaseDatePicker.vue'
import {useInfiniteScroll, useIntersectionObserver, useScroll} from '@vueuse/core'
import ListAnim from '@/components/ListAnim.vue'
import TransactionSkeleton from '@/components/TransactionSkeleton.vue'
import { DotLottieVue } from '@lottiefiles/dotlottie-vue'
import img from "@/assets/img/user_ly1.svg";
const pagination = ref<TableEngineInput>({ filters: [], limit: 7, page: 0 })
const items = ref<Transaction[]>([])
const tableOutput = ref<TableOutput<Transaction> | null>(null)
const showFilter = ref<boolean>(false)
const dateFilter = ref<string>()
const observer = ref()
// const { y } = useScroll(el)
async function initTable() {
try {
if (dateFilter.value) {
pagination.value.filters = []
pagination.value.filters.push({
field: 'created_at',
cr: 'and',
type: 'date',
op: 'eq',
value: dateFilter.value
})
} else {
pagination.value.filters = []
}
pagination.value.page === 0 ? (loading.value = true) : (loadingMore.value = true)
tableOutput.value = await getTransactionTable(pagination.value)
items.value.push(...tableOutput.value.rows)
// console.log(tableOutput.value)
} catch (e) {
console.log(e)
} finally {
loading.value = false
loadingMore.value = false
}
}
async function applyFilter() {
pagination.value.page = 0
items.value = []
await initTable()
showFilter.value = false
}
onMounted(() => {
initTable()
})
/*useInfiniteScroll(
el,
async () => {
// load more
// console.log('salamss')
if (
tableOutput.value &&
(pagination.value.page + 1) * pagination.value.limit < tableOutput.value.query.total
) {
// console.log('gfgf')
pagination.value.page++
await initTable()
}
},
{ distance: 12 }
)*/
useIntersectionObserver(
observer,
async ([{isIntersecting}]) => {
if ( isIntersecting &&
tableOutput.value &&
(pagination.value.page + 1) * pagination.value.limit < tableOutput.value.query.total
) {
// console.log('gfgf')
pagination.value.page++
await initTable()
}
},
{
root: null,
rootMargin: '300px',
threshold: 0.01
}
)
/*const items = [
{
isUp: true,
hasTransition: true
},
{
isUp: false,
hasTransition: false
},
{
isUp: true,
hasTransition: false
},
{
isUp: true,
hasTransition: true
},
{
isUp: false,
hasTransition: false
},
{
isUp: true,
hasTransition: false
},
{
isUp: true,
hasTransition: true
},
{
isUp: true,
hasTransition: true
},
{
isUp: false,
hasTransition: false
},
{
isUp: true,
hasTransition: true
},
]*/
</script>
<style scoped lang="less">
.transaction-list {
position: fixed;
right: 0;
left: 0;
@media screen and (min-width: 426px) {
width: 426px;
left: auto;
right: auto;
}
}
</style>
@@ -0,0 +1,9 @@
<svg width="428" height="331" viewBox="0 0 428 331" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="428" height="331" transform="matrix(1 0 0 -1 0 331)" fill="url(#paint0_linear_455_10939)"/>
<defs>
<linearGradient id="paint0_linear_455_10939" x1="214" y1="0" x2="214" y2="331" gradientUnits="userSpaceOnUse">
<stop stop-color="white" stop-opacity="0"/>
<stop offset="1" stop-color="white"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 438 B

+466
View File
@@ -0,0 +1,466 @@
<template>
<div class="relative">
<div>
<!-- <img :src="gr_bottom" alt="" class="absolute bottom-20">-->
<img :src="img" alt="" class="mt-2 w-full absolute bottom-0" />
</div>
<div class="bg-white w-full py-3 px-3 text-primary font-bold drop-shadow flex">
<div @click="router.back()" class="cursor-pointer">
<BasicIcon icon="vuesax-linear:arrow-right-1" />
</div>
<div class="mr-2 mt-2">اطلاعات حساب کاربری</div>
</div>
<div class="pt-16 pb-8 z-30 relative">
<div
class="border-gray-200 border-1 rounded-xl p-5 trans flex flex-col items-center mx-5 z-1000 relative bg-white shadow-lg"
>
<div class="text-primary font-bold w-full text-center flex justify-between">
نام و نام خانوادگی:
<div class="mr-2">{{ userStore.userInfo?.name }}</div>
</div>
<div class="text-primary font-bold w-full text-center flex justify-between">
شماره تلفن همراه:
<div class="mr-2">{{ userStore.userInfo?.mobile }}</div>
</div>
<div
v-if="userStore.userInfo?.referral_id"
class="text-primary font-bold w-full text-center flex justify-between gap-2 items-center"
>
کد معرف:
<div class="flex gap-2">
<div class="mr-2">{{ userStore.userInfo?.referral_id }}</div>
<!-- <BasicIcon icon="vuesax-linear:copy" color="#2563EB" class="cursor-pointer" size="18"
@click.stop="copyCode()" />
&lt;!&ndash; vuesax-linear:hierarchy-3&ndash;&gt;
<BasicIcon icon="vuesax-linear:share" color="#2563EB" class="cursor-pointer" size="18"
@click.stop="shareCode()" />-->
</div>
</div>
<div class="w-full flex gap-2 mt-1">
<BasicButton
icon="vuesax-linear:share"
size="small"
class="flex-1"
icon-size="18"
@click.stop="shareCode()"
>
اشتراک گذاری
</BasicButton>
<BasicButton
icon="vuesax-linear:copy"
size="small"
class="flex-1"
icon-size="18"
@click.stop="copyCode()"
>
رونوشت
</BasicButton>
</div>
<BasicButton
class="mt-5 w-full"
icon=""
iconSize="18"
size="large"
type="primary"
@click="editPassVisible = true"
>
<div class="flex">
<BasicIcon icon="vuesax-linear:eye" class="absolute right-8" />
<div>ویرایش اطلاعات کاربری</div>
</div>
</BasicButton>
<div class="h-40vh overflow-y-auto mt-4">
<BasicButton
class="mt-2 w-full"
icon=""
iconSize="18"
size="large"
@click="editPasswordVisible = true"
:key="10"
>
<div class="flex">
<BasicIcon icon="vuesax-linear:lock" class="absolute right-8" />
<div>تغییر رمز عبور</div>
</div>
</BasicButton>
<BasicButton
class="w-full mt-2"
size="large"
@click="$router.push({ name: 'address' })"
>
<div class="flex">
<BasicIcon icon="vuesax-linear:map" class="absolute right-8" />
<div>آدرس ها</div>
</div>
</BasicButton>
<BasicButton
class="w-full mt-2"
size="large"
@click="$router.push({ name: 'notifyTrigger' })"
>
<div class="flex">
<BasicIcon icon="vuesax-linear:bill" class="absolute right-8" />
<div>هشدار قیمت</div>
</div>
</BasicButton>
<BasicButton
class="mt-2 w-full"
icon=""
iconSize="18"
size="large"
@click="$router.push({ name: 'about' })"
>
<div class="flex">
<BasicIcon icon="vuesax-linear:info-circle" class="absolute right-8" />
<div>درباره ما</div>
</div>
</BasicButton>
<BasicButton
class="mt-2 w-full"
icon=""
iconSize="18"
size="large"
@click="$router.push({ name: 'physicalReceive' })"
>
<div class="flex">
<BasicIcon icon="vuesax-linear:direct-inbox" class="absolute right-8" />
<div>دریافت طلای فیزیکی</div>
</div>
</BasicButton>
<BasicButton
class="mt-2 w-full"
icon=""
iconSize="18"
size="large"
@click="$router.push({ name: 'rules' })"
>
<div class="flex">
<BasicIcon icon="vuesax-linear:task" class="absolute right-8" />
<div>قوانین و مقررات</div>
</div>
</BasicButton>
<!-- <BasicButton
class="mt-2 w-full"
icon=""
iconSize="18"
size="large"
@click="$router.push({ name: 'permissions' })"
>
<div class="flex">
<BasicIcon icon="vuesax-linear:archive-book" class="absolute right-8" />
<div>مجوز ها</div>
</div>
</BasicButton>-->
<!-- <BasicButton
class="mt-2 w-full"
icon=""
iconSize="18"
size="large"
@click="$router.push({ name: 'earnMoney' })"
>
<div class="flex">
<BasicIcon icon="vuesax-linear:dollar-circle" class="absolute right-8" />
<div>کسب درآمد</div>
</div>
</BasicButton>-->
</div>
</div>
</div>
<BasicActionSheet v-model:show="editPassVisible">
<div class="flex justify-center justify-between">
<div class="font-bold text-lg">ویرایش اطلاعات</div>
<div class="flex flex-col justify-center items-center">
<BasicIcon :icon="isLegal.icon" size="30" :class="isLegal.color" />
<p class="text-[10px] mt-1" :class="isLegal.color">{{ isLegal.title }}</p>
</div>
</div>
<div class="h60vh overflow-y-auto pb20">
<a-form ref="formRef" :model="userFormState" class="!mt-5" name="basic" @finish="ok">
<a-form-item :rules="[isValidPersian()]" label="نام" name="fname">
<BasicInput v-model:value="userFormState.fname" />
</a-form-item>
<a-form-item :rules="[isValidPersian()]" label="نام خانوادگی" name="lname">
<BasicInput v-model:value="userFormState.lname" />
</a-form-item>
<a-form-item label="تاریخ تولد" name="birth_date">
<BaseDatePicker v-model:value="userFormState.birth_date" class="w-full" inputReadOnly />
</a-form-item>
<a-form-item :rules="[requireNationalCode()]" label="شماره ملی" name="n_code">
<BasicInput v-model:value="userFormState.n_code" type="number" :disabled="userFormState.is_legal == 1 || userFormState.is_legal == 2" />
</a-form-item>
<a-form-item label="نام شهر" name="city">
<BasicInput v-model:value="userFormState.city" />
</a-form-item>
<a-form-item>
<div class="wrap-fix md:w-[395px] bottom-5 px-3">
<BasicButton
:disabled="loading"
class="w-full py-2 mb-20"
html-type="submit"
type="primary"
>
<div>
<a-spin v-if="loading" size="small" />
<div v-else>ثبت</div>
</div>
</BasicButton>
</div>
</a-form-item>
</a-form>
</div>
</BasicActionSheet>
<BasicActionSheet v-model:show="editPasswordVisible">
<div class="font-bold text-lg">ویرایش رمزعبور</div>
<div class="h30vh overflow-y-auto pb20">
<a-form
ref="formPassRef"
:model="userPassForm"
class="!mt-5"
name="basic"
@finish="submitPassForm"
>
<a-form-item label="کلمه عبور جدید" :rules="passwordRules()" name="password">
<BasicInput v-model:value="userPassForm.password" isPassword place-holder="کلمه عبور " />
<div
:class="[
guideTypePassword.color,
userPassForm.password.length >= 6 ? 'block' : 'hidden'
]"
class="text-[12px] mt-1"
>
{{ guideTypePassword.text }}
</div>
</a-form-item>
<a-form-item>
<div class="wrap-fix md:w-[395px] bottom-5 px-3">
<BasicButton
:disabled="loading"
class="w-full py-2 mb-20"
html-type="submit"
type="primary"
>
<div>
<a-spin v-if="loading" size="small" />
<div v-else>ثبت</div>
</div>
</BasicButton>
</div>
</a-form-item>
</a-form>
</div>
</BasicActionSheet>
</div>
</template>
<script lang="ts" setup>
import { onMounted, reactive, ref, computed } from 'vue'
import img from '@/assets/img/user_ly1.svg'
import gr_bottom from './assets/img/gr_bottom_white.svg'
import { loading } from '@/utils'
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
import BasicActionSheet from '@/components/BasicPacks/BasicActionSheet.vue'
import {
lengthValidation,
required,
requireNationalCode,
passwordRules,
guideTypePassword,
isValidPersian,
} from '@/utils/inputRules'
import BasicInput from '@/components/BasicPacks/BasicInput.vue'
import type { User, Password } from '@/models/login'
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
import router from '@/router'
import type { FormInstance } from 'ant-design-vue'
import { message } from 'ant-design-vue'
import { updateMe, updatePass } from '@/api/me'
import { useUserStore } from '@/store/userStore'
import BaseDatePicker from '@/components/BasicPacks/BaseDatePicker'
const userFormState = ref<User>({
fname: '',
lname: '',
mobile: undefined,
birth_date: '',
city: '',
n_code: undefined
})
const userPassForm = ref<Password>({
password: ''
})
const formRef = ref<FormInstance>()
const formPassRef = ref<FormInstance>()
const userStore = useUserStore()
// const editPassVisible = ref<boolean>(false)
const editPassVisible = ref<boolean>(false)
const editPasswordVisible = ref<boolean>(false)
function setForm() {
userFormState.value = userStore.userInfo
}
function copyCode() {
// nextTick(() => {
const val = userStore.userInfo?.referral_id
navigator.clipboard.writeText(val)
message.info('کد رونوشت شد')
// })
}
const isLegal = computed(() => {
const result = {
title: '',
color: '',
icon: ''
}
switch (userFormState.value.is_legal) {
case 0:
result.title = 'احراز هویت نشده'
result.color = 'reject'
result.icon = 'vuesax-linear:close-circle'
break
case 1:
result.title = 'احراز هویت شده'
result.color = 'success'
result.icon = 'vuesax-linear:verify'
break
case 2:
result.title = 'احراز هویت شده'
result.color = 'success'
result.icon = 'vuesax-linear:verify'
break
}
return result
})
function shareCode() {
// nextTick(() => {
const val = `⭐️الان طلا بخر؛ آخر ماه سودشو ببر!
با خرید طلای آبشده در مقدارهای کم ولی مستمر، سود بیشتری ببر!
این دعوت نامه از طرف "${userStore.userInfo?.name}" عزیز برای شما ارسال شده تا شما هم از بازار طلای گلد دات آی آر جا نمونید.
روی لینک زیر کلیک کنید و ثبت نام خود را تکمیل کنید.
gold.ir/login?id=${userStore.userInfo?.referral_id}`
navigator.share({
title: ' گلد دات آی آر',
text: val
})
// message.info('کد رونوشت شد')
// })
}
const resetData = () => {
formRef.value?.resetFields()
userFormState.value = {
fname: '',
lname: '',
mobile: undefined,
birth_date: '',
city: '',
n_code: undefined
}
}
onMounted(() => {
setForm()
})
function ok() {
formRef.value?.validateFields().then(async () => {
try {
loading.value = true
await updateMe(userFormState.value)
await userStore.getMyInfo()
editPassVisible.value = false
message.success('اطلاعات شما با موفقیت به روز رسانی شد')
location.reload()
} catch (e) {
console.log(e)
} finally {
loading.value = false
}
})
}
function submitPassForm() {
formPassRef.value?.validateFields().then(async () => {
try {
loading.value = true
await updatePass(userPassForm.value)
await userStore.getMyInfo()
editPassVisible.value = false
message.success('پسورد شما با موفقیت به روز رسانی شد')
editPasswordVisible.value = false
} catch (e) {
console.log(e)
} finally {
loading.value = false
}
})
}
onMounted(() => {
console.log(userStore.userInfo?.is_legal === 2)
if (userStore.userInfo?.is_legal === 0) {
editPassVisible.value = true
}
})
</script>
<style scoped>
/*.fade-enter-active,
.fade-leave-active {
transition: opacity 0.2s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}*/
/*.trans{
transition: height 1s;
}*/
.midLevel {
color: orange;
}
.week,
.reject {
color: red;
}
.success {
color: green;
}
.background-image-container {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
z-index: 0;
}
.background-image-container img {
width: 100%;
height: auto;
}
.relative {
position: relative;
z-index: 40;
}
.relative {
overflow-y: auto;
max-height: 100vh;
//scroll-behavior: smooth;
}
.fixed {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 50; /* بالاتر از همه */
}
</style>
@@ -0,0 +1,104 @@
<template>
<div
:style="findPositionStyle(props.selfIndex)"
class="card relative"
@click="localValue = props.selfIndex"
>
<!-- <img :src="ly1" class="absolute h-full w-full object-cover rounded-2xl" alt="">-->
<!-- <img :src="ly2 " class="absolute h-full w-full object-cover rounded-2xl" alt="">-->
<div class="flex flex-col items-center">
<img :src="img" alt="" class="w-full h-full" />
<div class="mt-[1.5vh] text-white w-full text-center text-xl font-bold" dir="ltr">
{{ useCardNumber(props.cardNumber) }}
</div>
<div class="mt-3 text-white text-lg">{{ useShabaNumber(props.shaba) }}</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { computed } from 'vue'
import { useCardNumber, useShabaNumber } from '@/utils/useCardNumber'
interface Prop {
sliderIndex: number
selfIndex: number
img: string
color?: string
}
const localValue = computed({
get() {
return props.sliderIndex
},
set(value) {
emits('update:sliderIndex', value)
}
})
const props = defineProps<Prop>()
const emits = defineEmits(['update:sliderIndex'])
function findPositionStyle(pos: number) {
// console.log(localValue.value)
// console.log(pos,index)
let debug
if (pos === props.sliderIndex) {
debug = `width: 100%; z-index: 100; opacity: 1;/* margin-top: -160px;*/ top: 20%; position: absolute; background-color: ${props.color};`
} /*if (pos > index.value)*/ else {
// debug = `w-[${100 - Math.abs(index.value-pos) * 2}%] z-${100 - Math.abs(index.value-pos)}`
debug = `width: ${100 - Math.abs(props.sliderIndex - pos) * 3}%;
z-index: ${100 - Math.abs(props.sliderIndex - pos)};
opacity: ${1 - Math.abs((props.sliderIndex - pos) * 15) / 100};
/*
margin-top: ${-160 - Math.abs((props.sliderIndex - pos) * 15)}px;
*/
position: absolute;
top : ${
pos > props.sliderIndex
? checkTopLimit(topDetail(true, pos) as number)
? 100
: 35 +
Math.abs((props.sliderIndex - pos) * (35 - Math.abs((props.sliderIndex - pos) * 4)))
: checkTopLimit(topDetail(false, pos) as number)
? 0
: 35 - Math.abs((props.sliderIndex - pos) * (35 - Math.abs((props.sliderIndex - pos) * 4)))
}%;
background-color: ${props.color};`
}
// console.log(debug)
return debug
}
/**
* /!*checkTopLimit(topDetail(true, pos) as number) ? 100 :*!/ topDetail(true, pos) :
* /!*checkTopLimit(topDetail(false, pos) as number) ? 0 :*!/ topDetail(false, pos)
*/
function topDetail(isAfterIndex: boolean, pos: number) {
if (isAfterIndex)
return 35 + Math.abs((props.sliderIndex - pos) * (35 - Math.abs((props.sliderIndex - pos) * 4)))
else
return (
35 - Math.abs((props.sliderIndex - pos) * (35 - Math.abs((props.sliderIndex - pos) * 4))) < 0
)
}
function checkTopLimit(val: number) {
return val > 100 || val < 0
}
</script>
<style lang="sass" scoped>
.card
height: fit-content
width: 100%
align-self: center
border-radius: 24px
transition: .5s
.card:first-child
margin-top: 0 !important
</style>
+178
View File
@@ -0,0 +1,178 @@
<template>
<div >
<div class="flex">
<div :class="isUp? 'bg-green-50':'bg-red-50'" class="rounded-lg p-4 h-fit w-fit flex justify-center items-center">
<Icon :class="isUp? 'text-green-600':'text-red-600'"
:icon="`vuesax-linear:${isUp? 'tick-circle':'close-circle'}`"/>
</div>
<div class=" w-full mr-2 ">
<div class="flex w-full text-xs ">{{item.note ?? '-'}}</div>
<div class="flex mt-1 text-xs">
<div>وضعیت:</div>
<div :class="'text-green-600'" class="mr-1" v-if="item.transaction[0]">موفق</div>
<div :class="'text-red-600'" class="mr-1" v-else>ناموفق</div>
</div>
<div class="flex mt-1 text-xs ">
<div class="w-4rem">کد پیگیری: </div>
<div class=" mr-1">{{item.tracked_number ?? '-'}}</div>
</div>
</div>
<div class="w-full mr-3">
<div class="flex justify-between w-full">
<div>{{ item.type_str }}</div>
<div>{{ toJalaliNotime(item.created_at) }}</div>
</div>
<div class="flex justify-between mt-2">
<div :class="item.gold >= 0? 'text-green-600':'text-red-600'" class="text-gray-500 text-xs number-ltr">
<!-- {{ item.gold }}
<div>گرم</div>-->
</div>
<div class="text-gray-500 flex gap-1 text-xs items-center">
<div :class="item.cash > 0 ? 'text-green-600':'text-red-600'" class="text-base number-ltr">
{{ usePriceWithoutType(item.cash ?? 0) }}
</div>
ریال
</div>
</div>
</div>
</div>
<div v-if="isGold" class="flex w-full justify-between mt-2">
<div class="text-gray-500">قیمت معامله:</div>
<div class="text-gray-500 flex gap-1 text-xs items-center">
<div class="text-base">{{ usePriceWithoutType((Math.abs(item.cash) / Math.abs(item.gold)).toFixed(0)) }}</div>
ریال
</div>
</div>
<!-- <div class="flex w-full justify-between mt-2">
<div class="text-gray-500">وضعیت :</div>
<div class="text-gray-500 flex gap-1 text-xs items-center">
<ATag class="!py-1 !px-6 !ml-0" color="blue">
{{ item.order?.sts_str ?? '' }}
</ATag>
</div>
</div>-->
<!-- <div v-else class="h-8"></div>-->
<a-divider class="!my-3"/>
<BasicActionSheet v-model:show="infoVisible">
<div class="font-bold text-lg">{{ props.item.type_str }}</div>
<div class="pb-20 mt-5">
<div class="flex justify-between mb-3">
<div class="text-black">مبلغ:</div>
<div :class="item.cash > 0? 'text-green-600' : 'text-red-600'" class="flex text-xs items-center">
<div class="text-base ml-1 number-ltr">{{ usePriceWithoutType(item.cash) }}</div>
ریال
</div>
</div>
<div class="flex justify-between mb-3">
<div class="text-black">مقدار طلا مبادله شده:</div>
<div :class="item.gold >= 0? 'text-green-600' : 'text-red-600'" class="flex text-xs items-center">
<div class="text-base ml-1 number-ltr">{{ item.gold }}</div>
گرم
</div>
</div>
<div v-if="item.order" class="flex justify-between mb-3">
<div class="text-black">قیمت هر گرم طلا حین معامله:</div>
<div class="flex text-xs items-center number-ltr">
<div class="text-base ml-1">{{ usePriceWithoutType(item.order?.price?? 0) }}</div>
ریال
</div>
</div>
<div class="flex justify-between mb-3">
<div class="text-black">موجودی کیف پول:</div>
<div :class="item.cash > 0? 'text-green-600' : 'text-red-600'" class="flex text-xs items-center">
<div class="text-base number-ltr">{{ usePriceWithoutType(item.balance_cash ?? 0) }}</div>
ریال
</div>
</div>
<div class="flex justify-between mb-3">
<div class="text-black">موجودی کیف طلا:</div>
<div class="flex text-xs text-yellow-700 items-center">
<div class="text-base ml-1">{{ item.balance_gold }}</div>
گرم
</div>
</div>
<!-- <div class="flex justify-between mb-3">
<div class="text-black">موجودی کیف پول:</div>
<div class="flex text-xs items-center" :class="isUp? 'text-green-600' : 'text-red-600'"><div class="text-base">{{usePriceWithoutType(12000000)}}</div>ریال</div>
</div>
<div class="flex justify-between mb-3">
<div class="text-black">موجودی کیف طلا:</div>
<div class="flex items-center" :class="isUp? 'text-red-600' : 'text-green-600'">60 گرم</div>
</div>-->
<div class="flex justify-between mb-3">
<div class="text-black">وضعیت:</div>
<div class="flex text-xs items-center">
<ATag :color="item.active? 'blue': 'red'" class="!py-1 !px-6 !ml-0">{{
item.order?.sts_str
}}
</ATag>
</div>
</div>
<div class="flex justify-between mb-3">
<div class="text-black">تاریخ:</div>
<div>{{ toJalaliNotime(item.expire_at) }}</div>
</div>
<div class="flex justify-between mb-3">
<div class="text-black">زمان:</div>
<div>{{ toTime(item.expire_at) }}</div>
</div>
<!-- <div class="flex justify-between mb-3">
<div class="text-black">وضعیت معامله:</div>
<div class="flex text-xs items-center">
<ATag class="!py-1 !px-6 !ml-0" color="orange">
معاملات باز
</ATag>
</div>
</div>-->
<div v-if="item.eaj" class="flex justify-between mb-3">
<div class="text-black">مهلت ارسال فیش:</div>
<div>{{ item.eaj }}</div>
</div>
<BasicButton class="w-full mt-5" @click="infoVisible = false">بازگشت</BasicButton>
</div>
</BasicActionSheet>
</div>
</template>
<script lang="ts" setup>
import Icon from "@/components/BasicPacks/BasicIcon.vue";
import {usePriceWithoutType} from "../../../../utils/usePrice";
import BasicActionSheet from "@/components/BasicPacks/BasicActionSheet.vue";
import {computed, ref} from "vue";
import BasicButton from "@/components/BasicPacks/BasicButton.vue";
import type {Transaction} from "@/models/transaction";
import {toJalaliNotime, toJalaliOutOfUTC, toTime} from "../../../../utils/useDateTime";
const infoVisible = ref<boolean>(false)
interface Prop {
item: Transaction
}
const props = withDefaults(defineProps<Prop>(), {})
// const isUp = computed(() => props.item.type === 3 || props.item.type === 1)
const isUp = computed(() => props.item.transaction[0])
const isGold = computed(() => props.item.type === 1 || props.item.type === 2 || props.item.type === 10)
/*const title = computed(() => {
if (isUp.value) {
if (isGold.value) {
return 'واریز ریالی'
} else {
return 'خرید طلا'
}
} else {
if (isGold.value) {
return 'برداشت ریالی'
} else {
return 'فروش طلا'
}
}
})*/
</script>
<style scoped>
</style>
@@ -0,0 +1,429 @@
<template>
<van-dialog
class="updateButton"
confirm-button-text="متوجه شدم"
:show-confirm-button="false"
@confirm="update()"
>
<div class="flex flex-col items-center p-2 mt-7 mb-3">
<div class="typewriter">
<div class="slide"><i></i></div>
<div class="paper"></div>
<div class="keyboard"></div>
</div>
<div class="font-bold mt-5">در حال انجام تراکنش</div>
<div class="home_appear_fade_in_up mt-2 text-sm mb-5">
سفارش شما در حال پیگیری است، لطفا صبور باشید!
</div>
</div>
</van-dialog>
</template>
<script setup lang="ts">
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
import { update } from 'lodash'
import { ref } from 'vue'
interface Prop {
title: string
info?: string
infoHead?: string
isLine?: boolean
value?: string | number
}
const props = withDefaults(defineProps<Prop>(), {
isLine: false
})
</script>
<style scoped lang="less">
/* From Uiverse.io by Nawsome */
.typewriter {
--blue: #5c86ff;
--blue-dark: #275efe;
--key: #fff;
--paper: #eef0fd;
--text: #d3d4ec;
--tool: #fbc56c;
--duration: 3s;
position: relative;
-webkit-animation: bounce05 var(--duration) linear infinite;
animation: bounce05 var(--duration) linear infinite;
}
.typewriter .slide {
width: 92px;
height: 20px;
border-radius: 3px;
margin-left: 14px;
transform: translateX(14px);
background: linear-gradient(var(--blue), var(--blue-dark));
-webkit-animation: slide05 var(--duration) ease infinite;
animation: slide05 var(--duration) ease infinite;
}
.typewriter .slide:before,
.typewriter .slide:after,
.typewriter .slide i:before {
content: '';
position: absolute;
background: var(--tool);
}
.typewriter .slide:before {
width: 2px;
height: 8px;
top: 6px;
left: 100%;
}
.typewriter .slide:after {
left: 94px;
top: 3px;
height: 14px;
width: 6px;
border-radius: 3px;
}
.typewriter .slide i {
display: block;
position: absolute;
right: 100%;
width: 6px;
height: 4px;
top: 4px;
background: var(--tool);
}
.typewriter .slide i:before {
right: 100%;
top: -2px;
width: 4px;
border-radius: 2px;
height: 14px;
}
.typewriter .paper {
position: absolute;
left: 24px;
top: -26px;
width: 40px;
height: 46px;
border-radius: 5px;
background: var(--paper);
transform: translateY(46px);
-webkit-animation: paper05 var(--duration) linear infinite;
animation: paper05 var(--duration) linear infinite;
}
.typewriter .paper:before {
content: '';
position: absolute;
left: 6px;
right: 6px;
top: 7px;
border-radius: 2px;
height: 4px;
transform: scaleY(0.8);
background: var(--text);
box-shadow:
0 12px 0 var(--text),
0 24px 0 var(--text),
0 36px 0 var(--text);
}
.typewriter .keyboard {
width: 120px;
height: 56px;
margin-top: -10px;
z-index: 1;
position: relative;
}
.typewriter .keyboard:before,
.typewriter .keyboard:after {
content: '';
position: absolute;
}
.typewriter .keyboard:before {
top: 0;
left: 0;
right: 0;
bottom: 0;
border-radius: 7px;
background: linear-gradient(135deg, var(--blue), var(--blue-dark));
transform: perspective(10px) rotateX(2deg);
transform-origin: 50% 100%;
}
.typewriter .keyboard:after {
left: 2px;
top: 25px;
width: 11px;
height: 4px;
border-radius: 2px;
box-shadow:
15px 0 0 var(--key),
30px 0 0 var(--key),
45px 0 0 var(--key),
60px 0 0 var(--key),
75px 0 0 var(--key),
90px 0 0 var(--key),
22px 10px 0 var(--key),
37px 10px 0 var(--key),
52px 10px 0 var(--key),
60px 10px 0 var(--key),
68px 10px 0 var(--key),
83px 10px 0 var(--key);
-webkit-animation: keyboard05 var(--duration) linear infinite;
animation: keyboard05 var(--duration) linear infinite;
}
@keyframes bounce05 {
85%,
92%,
100% {
transform: translateY(0);
}
89% {
transform: translateY(-4px);
}
95% {
transform: translateY(2px);
}
}
@keyframes slide05 {
5% {
transform: translateX(14px);
}
15%,
30% {
transform: translateX(6px);
}
40%,
55% {
transform: translateX(0);
}
65%,
70% {
transform: translateX(-4px);
}
80%,
89% {
transform: translateX(-12px);
}
100% {
transform: translateX(14px);
}
}
@keyframes paper05 {
5% {
transform: translateY(46px);
}
20%,
30% {
transform: translateY(34px);
}
40%,
55% {
transform: translateY(22px);
}
65%,
70% {
transform: translateY(10px);
}
80%,
85% {
transform: translateY(0);
}
92%,
100% {
transform: translateY(46px);
}
}
@keyframes keyboard05 {
5%,
12%,
21%,
30%,
39%,
48%,
57%,
66%,
75%,
84% {
box-shadow:
15px 0 0 var(--key),
30px 0 0 var(--key),
45px 0 0 var(--key),
60px 0 0 var(--key),
75px 0 0 var(--key),
90px 0 0 var(--key),
22px 10px 0 var(--key),
37px 10px 0 var(--key),
52px 10px 0 var(--key),
60px 10px 0 var(--key),
68px 10px 0 var(--key),
83px 10px 0 var(--key);
}
9% {
box-shadow:
15px 2px 0 var(--key),
30px 0 0 var(--key),
45px 0 0 var(--key),
60px 0 0 var(--key),
75px 0 0 var(--key),
90px 0 0 var(--key),
22px 10px 0 var(--key),
37px 10px 0 var(--key),
52px 10px 0 var(--key),
60px 10px 0 var(--key),
68px 10px 0 var(--key),
83px 10px 0 var(--key);
}
18% {
box-shadow:
15px 0 0 var(--key),
30px 0 0 var(--key),
45px 0 0 var(--key),
60px 2px 0 var(--key),
75px 0 0 var(--key),
90px 0 0 var(--key),
22px 10px 0 var(--key),
37px 10px 0 var(--key),
52px 10px 0 var(--key),
60px 10px 0 var(--key),
68px 10px 0 var(--key),
83px 10px 0 var(--key);
}
27% {
box-shadow:
15px 0 0 var(--key),
30px 0 0 var(--key),
45px 0 0 var(--key),
60px 0 0 var(--key),
75px 0 0 var(--key),
90px 0 0 var(--key),
22px 12px 0 var(--key),
37px 10px 0 var(--key),
52px 10px 0 var(--key),
60px 10px 0 var(--key),
68px 10px 0 var(--key),
83px 10px 0 var(--key);
}
36% {
box-shadow:
15px 0 0 var(--key),
30px 0 0 var(--key),
45px 0 0 var(--key),
60px 0 0 var(--key),
75px 0 0 var(--key),
90px 0 0 var(--key),
22px 10px 0 var(--key),
37px 10px 0 var(--key),
52px 12px 0 var(--key),
60px 12px 0 var(--key),
68px 12px 0 var(--key),
83px 10px 0 var(--key);
}
45% {
box-shadow:
15px 0 0 var(--key),
30px 0 0 var(--key),
45px 0 0 var(--key),
60px 0 0 var(--key),
75px 0 0 var(--key),
90px 2px 0 var(--key),
22px 10px 0 var(--key),
37px 10px 0 var(--key),
52px 10px 0 var(--key),
60px 10px 0 var(--key),
68px 10px 0 var(--key),
83px 10px 0 var(--key);
}
54% {
box-shadow:
15px 0 0 var(--key),
30px 2px 0 var(--key),
45px 0 0 var(--key),
60px 0 0 var(--key),
75px 0 0 var(--key),
90px 0 0 var(--key),
22px 10px 0 var(--key),
37px 10px 0 var(--key),
52px 10px 0 var(--key),
60px 10px 0 var(--key),
68px 10px 0 var(--key),
83px 10px 0 var(--key);
}
63% {
box-shadow:
15px 0 0 var(--key),
30px 0 0 var(--key),
45px 0 0 var(--key),
60px 0 0 var(--key),
75px 0 0 var(--key),
90px 0 0 var(--key),
22px 10px 0 var(--key),
37px 10px 0 var(--key),
52px 10px 0 var(--key),
60px 10px 0 var(--key),
68px 10px 0 var(--key),
83px 12px 0 var(--key);
}
72% {
box-shadow:
15px 0 0 var(--key),
30px 0 0 var(--key),
45px 2px 0 var(--key),
60px 0 0 var(--key),
75px 0 0 var(--key),
90px 0 0 var(--key),
22px 10px 0 var(--key),
37px 10px 0 var(--key),
52px 10px 0 var(--key),
60px 10px 0 var(--key),
68px 10px 0 var(--key),
83px 10px 0 var(--key);
}
81% {
box-shadow:
15px 0 0 var(--key),
30px 0 0 var(--key),
45px 0 0 var(--key),
60px 0 0 var(--key),
75px 0 0 var(--key),
90px 0 0 var(--key),
22px 10px 0 var(--key),
37px 12px 0 var(--key),
52px 10px 0 var(--key),
60px 10px 0 var(--key),
68px 10px 0 var(--key),
83px 10px 0 var(--key);
}
}
</style>
@@ -0,0 +1,158 @@
<template>
<div
:style="findPositionStyle(props.selfIndex)"
class="card relative"
@click="localValue = props.selfIndex"
>
<div class="p-3 flex flex-col items-center">
<div class="flex justify-between w-full">
<div class="text-white font-bold text-lg w-full">{{ props.title }}</div>
<div
class="text-white px-2 flex justify-center items-center rounded-lg w-5rem"
:class="active ? 'bg-green-600' : 'bg-red-600'"
>
{{ active ? 'فعال' : 'غیر فعال' }}
</div>
</div>
<div
v-if="props.cardNumber"
class="mt-[1.5vh] text-white w-full text-center text-xl font-bold"
dir="ltr"
>
{{ useCardNumber(props.cardNumber) }}
</div>
<div v-if="props.shaba" class="mt-3 text-white text-lg">
{{ useShabaNumber(props.shaba) }}
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { computed } from 'vue'
import { useCardNumber, useShabaNumber } from '@/utils/useCardNumber'
interface Prop {
sliderIndex: number
selfIndex: number
title?: string
cardNumber?: string
shaba?: string
color?: string
active?: boolean
}
const localValue = computed({
get() {
return props.sliderIndex
},
set(value) {
emits('update:sliderIndex', value)
}
})
const props = defineProps<Prop>()
const emits = defineEmits(['update:sliderIndex'])
function findPositionStyle(pos: number) {
// console.log(localValue.value)
// console.log(pos,index)
let debug
if (pos === props.sliderIndex) {
debug = `width: 100%; z-index: 100; opacity: 1;/* margin-top: -160px;*/ top: 20%; position: absolute; background-color: ${props.color};`
} /*if (pos > index.value)*/ else {
// debug = `w-[${100 - Math.abs(index.value-pos) * 2}%] z-${100 - Math.abs(index.value-pos)}`
debug = `width: ${100 - Math.abs(props.sliderIndex - pos) * 10}%;
z-index: ${100 - Math.abs(props.sliderIndex - pos)};
position: absolute;
top : ${
pos > props.sliderIndex
? checkTopLimit(topDetail(true, pos) as number)
? 100
: 20 +
Math.abs((props.sliderIndex - pos) * (18 - Math.abs((props.sliderIndex - pos) * 4)))
: checkTopLimit(topDetail(false, pos) as number)
? 0
: 20 - Math.abs((props.sliderIndex - pos) * (18 - Math.abs((props.sliderIndex - pos) * 4)))
}%;
background-color: ${props.color};`
}
console.log(debug, topDetail(true, pos))
return debug
}
/*
function findPositionStyle(pos: number) {
// console.log(localValue.value)
// console.log(pos,index)
let debug
if (pos === props.sliderIndex) {
debug = `width: 100%; z-index: 100; opacity: 1;/!* margin-top: -160px;*!/ top: 20%; position: absolute; background-color: ${props.color};`
} else /!*if (pos > index.value)*!/{
// debug = `w-[${100 - Math.abs(index.value-pos) * 2}%] z-${100 - Math.abs(index.value-pos)}`
debug = `width: ${100 - Math.abs(props.sliderIndex - pos) * 10}%;
z-index: ${100 - Math.abs(props.sliderIndex - pos)};
/!*
opacity: ${1 - Math.abs((props.sliderIndex - pos) * 15) / 100};
*!/
/!*
margin-top: ${-160 - Math.abs((props.sliderIndex - pos) * 15)}px;
*!/
position: absolute;
top : ${pos > props.sliderIndex ?
checkTopLimit(topDetail(true, pos) as number) ? 100 :
(20 + Math.abs((props.sliderIndex - pos) * (18 - (Math.abs((props.sliderIndex - pos) * 4))))) :
checkTopLimit(topDetail(false, pos) as number) ? 0 :
(20 - Math.abs((props.sliderIndex - pos) * (18 - (Math.abs((props.sliderIndex - pos) * 4)))))}%;
background-color: ${props.color};`
}
console.log(debug)
return debug
}
*/
/**
* /!*checkTopLimit(topDetail(true, pos) as number) ? 100 :*!/ topDetail(true, pos) :
* /!*checkTopLimit(topDetail(false, pos) as number) ? 0 :*!/ topDetail(false, pos)
*/
function topDetail(isAfterIndex: boolean, pos: number) {
/* console.log((20 - Math.abs((props.sliderIndex - pos) * (24 - (Math.abs((props.sliderIndex - pos) * 4))))), pos)
console.log(Math.abs((props.sliderIndex - pos)) * (24 - (Math.abs((props.sliderIndex - pos) * 4))))*/
console.log(
20 - Math.abs((props.sliderIndex - pos) * (24 - Math.abs((props.sliderIndex - pos) * 4)))
)
/* if (isAfterIndex) console.log(20 + Math.abs(props.sliderIndex - pos))
else console.log(20 - Math.abs(props.sliderIndex - pos))*/
if (isAfterIndex)
return 20 + Math.abs((props.sliderIndex - pos) * (18 - Math.abs((props.sliderIndex - pos) * 4)))
else
return 20 - Math.abs((props.sliderIndex - pos) * (18 - Math.abs((props.sliderIndex - pos) * 4)))
}
/*
function topDetail(isAfterIndex: boolean, pos: number) {
console.log(pos, isAfterIndex, (20 + Math.abs((props.sliderIndex - pos) * (24 - (Math.abs((props.sliderIndex - pos) * 4))))))
if (isAfterIndex) return (20 + Math.abs((props.sliderIndex - pos) * (24 - (Math.abs((props.sliderIndex - pos) * 4)))))
else return (20 - Math.abs((props.sliderIndex - pos) * (24 - (Math.abs((props.sliderIndex - pos) * 4))))) < 0 //12*64
}
*/
function checkTopLimit(val: number) {
return val > 100 || val < 0
}
</script>
<style lang="sass" scoped>
.card
height: 22vh
width: 100%
align-self: center
border-radius: 24px
transition: .5s
.card:first-child
margin-top: 0 !important
</style>
@@ -0,0 +1,162 @@
<template lang="pug">
.container
.slider
.slide(data-slide='1' style="background-color: green")
.slide(data-slide='2' style="background-color: red")
.slide(data-slide='3' style="background-color: orange")
.slide.slide--active(data-slide='4' style="background-color: blue")
.slide(data-slide='5' style="background-color: violet")
.slide(data-slide='5' style="background-color: primary")
.slide(data-slide='5' style="background-color: pink")
.slide(data-slide='5' style="background-color: teal")
.controls
#back Back
#forvard Forvard
</template>
<script setup>
document.addEventListener('DOMContentLoaded', function () {
renderSlider('.slider');
});
const nextSlide = () => {
let activeSlide = document.querySelector('.slide--active');
let nextSlide = activeSlide.nextElementSibling;
if (nextSlide) {
activeSlide.classList.remove('slide--active');
nextSlide.classList.remove('next');
nextSlide.classList.add('slide--active');
renderSlides();
renderBtns();
}
}
const renderBtns = () => {
let nextBtn = document.querySelector('#forvard');
let prevBtn = document.querySelector('#back');
let activeSlide = document.querySelector('.slide--active');
let prevSlide = activeSlide.previousElementSibling;
!prevSlide ? prevBtn.classList.add('disabled')
: prevBtn.classList.remove('disabled');
let nextSlide = activeSlide.nextElementSibling;
!nextSlide ? nextBtn.classList.add('disabled')
: nextBtn.classList.remove('disabled');
}
const prevSlide = () => {
let activeSlide = document.querySelector('.slide--active');
let prevSlide = activeSlide.previousElementSibling;
if (prevSlide) {
activeSlide.classList.remove('slide--active');
prevSlide.classList.remove('prev');
prevSlide.classList.add('slide--active');
renderSlides();
renderBtns();
}
}
const renderSlides = () => {
let slides = document.querySelectorAll('.slide');
if (!slides) {
return;
}
let activeSlide = document.querySelector('.slide--active');
if (!activeSlide) {
activeSlide = slides.item(0);
activeSlide.classList.add('slide--active');
}
[].forEach.call(slides, function (slide) {
slide.classList.remove('prev', 'next')
});
let prevSlide = activeSlide.previousElementSibling;
prevSlide && prevSlide.classList.add('prev');
let nextSlide = activeSlide.nextElementSibling;
nextSlide && nextSlide.classList.add('next');
}
const renderSlider = (element) => {
const slider = document.querySelector(element);
if (slider) {
let nextButton = document.querySelector("#forvard");
nextButton.addEventListener('click', function () {
nextSlide();
})
let prevButton = document.querySelector("#back");
prevButton.addEventListener('click', function () {
prevSlide();
})
renderSlides();
}
}
</script>
<style lang="sass" scoped>
.container
display: flex
flex-flow: column
justify-content: center
margin: 50px auto 0
width: 500px
height: 300px
.controls
display: flex
justify-content: center
div
padding: 12px 14px
cursor: pointer
border: 1px solid #fff
color: #fff
font-size: 16px
font-weight: bold
margin: 0 5px
border-radius: 10px
&.disabled
opacity: 0
cursor: default
.slider
position: relative
width: 100%
height: 100%
.slide
position: absolute
top: 25%
left: 10%
width: 80%
height: 50%
background-color: red
border: 1px solid #fff
border-radius: 15px
opacity: 0
transition: all 0.7s ease-out
&--active
opacity: 1
z-index: 9
.prev,
.next
opacity: .3
.prev
transform: translate(0, -30%) scale(0.8)
.next
transform: translate(0, 30%) scale(0.8)
</style>
@@ -0,0 +1,259 @@
<template>
<div ref="container" class=" h-[38vh] flex items-center">
<div ref="el" class="w-full flex flex-col relative h-full test">
<CardItem v-for="(item,i) in props?.items" :key="i" v-model:sliderIndex="index" :card-number="item?.cart_number"
:color="colors[i%3]"
:self-index="i" :shaba="item?.shaba_number" :title="item?.bank_name" :active="item.sts === 2"/>
<div class="absolute bottom-15vh right-0 left-0 z-100 flex justify-center items-center opacity-70">
<div class="flex gap-1 bg-gray-500 px-2 py-1 rounded-lg">
<Transition name="slide-up" mode="out-in" v-for="i in items.length" :key="i">
<div v-if="i - 1 === index" class="w-2 h-2 rounded-full bg-primary"/>
<div v-else class="w-2 h-2 rounded-full bg-white"/>
</Transition>
</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { computed, onMounted, ref, watch } from 'vue'
// import {usePointerSwipe} from '@vueuse/core'
// import type {UseSwipeDirection} from '@vueuse/core'
// import type { UseSwipeDirection } from '@vueuse/core'
import { useSwipe } from '@vueuse/core'
import CardItem from './CardItem.vue'
import type { Card } from '@/models/wallet'
const el = ref(null)
const container = ref<HTMLElement | null>(null)
interface Prop {
items: Array<Card>
id: number | string
}
const props = defineProps<Prop>()
const emits = defineEmits(['update:id'])
const localValue = computed({
get() {
return props.id
},
set(value) {
emits('update:id', value)
}
})
// const decideSwip = ref<boolean>(false)
const { direction, isSwiping, lengthX, lengthY } = useSwipe(el/*, {
onSwipeStart(){
console.log('salam')
},
onSwipe(e: PointerEvent, direction: UseSwipeDirection) {
console.log('container',direction)
if (!decideSwip.value){
if (direction === 'up') {
index.value++
} else if (direction === 'down') {
index.value--
}
decideSwip.value = true
}
},
onSwipeEnd(e: PointerEvent){
console.log('container1')
decideSwip.value = false
}
}*/)
function getRandomColor() {
var letters = '0123456789ABCDEF'
var color = '#'
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)]
}
return color
}
const colors = ['#4B84EB', '#889BCD', '#C9A68D']
watch(isSwiping, () => {
// console.log(direction.value)
if (isSwiping.value) {
// console.log('salam')
if (direction.value === 'up' && props.items.length - 1 > index.value) {
index.value++
} else if (direction.value === 'down' && index.value > 0) {
index.value--
}
// console.log(index.value)
}
})
const index = ref<number>(props.items.length - 1)
onMounted(()=> localValue.value = props.items[index.value]?.id)
watch(index, (n: number)=> {
console.log(n)
localValue.value = props.items[n]?.id
})
/*
const items = [
{
title: 'بانک ملی',
cardNumber: 6219861918606103,
shaba: 'IR590560611828005106225701',
color: getRandomColor()
},
{
title: 'بانک ملی',
cardNumber: 6219861918606103,
shaba: 'IR590560611828005106225701',
color: getRandomColor()
},
{
title: 'بانک ملت',
cardNumber: 6219861918606103,
shaba: 'IR590560611828005106225701',
color: getRandomColor()
},
{
title: 'بانک سامان',
cardNumber: 6219861918606103,
shaba: 'IR590560611828005106225701',
color: getRandomColor()
},
{
title: 'بانک پاسارگاد',
cardNumber: 6219861918606103,
shaba: 'IR590560611828005106225701',
color: getRandomColor()
},
{
title: 'بانک صادرات',
cardNumber: 6219861918606103,
shaba: 'IR590560611828005106225701',
color: getRandomColor()
},
{
title: 'بانک ملی',
cardNumber: 6219861918606103,
shaba: 'IR590560611828005106225701',
color: getRandomColor()
},
{
title: 'بانک ملت',
cardNumber: 6219861918606103,
shaba: 'IR590560611828005106225701',
color: getRandomColor()
},
{
title: 'بانک سامان',
cardNumber: 6219861918606103,
shaba: 'IR590560611828005106225701',
color: getRandomColor()
},
{
title: 'بانک پاسارگاد',
cardNumber: 6219861918606103,
shaba: 'IR590560611828005106225701',
color: getRandomColor()
},
]
*/
// const indexCss = computed(()=> index.value)
// watch(index,()=>{
// key++
// console.log(key)
// })
// let key = 0
/*function findPosition(pos: number) {
// console.log(pos,index)
let debug
if (pos === index.value){
debug = 'w-full z-100'
}
else /!*if (pos > index.value)*!/{
debug = `w-[${100 - Math.abs(index.value-pos) * 2}%] z-${100 - Math.abs(index.value-pos)}`
}
console.log(debug)
return debug
}*/
/*
function mouseUp() {
index.value--
}
function mouseDown() {
console.log('salam')
index.value++
}
*/
/*function findPositionStyle(pos: number) {
// console.log(pos,index)
let debug
if (pos === index.value) {
debug = 'width: 100; z-index: 100; opacity: 1; margin-top: -200px;'
} else /!*if (pos > index.value)*!/{
// debug = `w-[${100 - Math.abs(index.value-pos) * 2}%] z-${100 - Math.abs(index.value-pos)}`
debug = `width: ${100 - Math.abs(index.value - pos) * 3}%;
z-index: ${100 - Math.abs(index.value - pos)};
opacity: ${1 - Math.abs((index.value - pos) * 15) / 100};
margin-top: ${-200 - Math.abs((index.value - pos) * 4)}px;`
}
// console.log(debug)
return debug
}*/
</script>
<style lang="less" scoped>
.slide-up-enter-active,
.slide-up-leave-active {
transition: all 0.25s ease-out;
}
.slide-up-enter-from {
opacity: 0;
transform: translateY(3px);
}
.slide-up-leave-to {
opacity: 0;
transform: translateY(-3px);
}
//.test .card:first-child
// margin-top: 0 !important
//.card
// height: 215px
// width: 100%
// align-self: center
// border-radius: 24px
// transition: .5s
//
//.card:first-child
// margin-top: 0 !important
//$total-items: 30
//@for $i from 1 through $total-items
// .card:nth-child(#{$i})
// @if($i > v-bind(indexCss))
// width: calc(percentage(100 - ($i * 4)) / 100)
// @if($i == v-bind(indexCss))
// width: 100%
// @if($i < v-bind(indexCss))
// width: calc(percentage(100 - ($i * 4)) / 100)
//.animate > div:nth-child(#{$i})
// animation-delay: .08s * $i
</style>
@@ -0,0 +1,262 @@
<template>
<div ref="container" class=" h-[25vh] flex items-center">
<div ref="el" class="w-full flex flex-col relative h-full test">
<!-- <div class="card bg-primary" :style="findPositionStyle(1)" @click="index = 1"></div>
<div class="card bg-red" :style="findPositionStyle(2)" @click="index = 2"></div>
<div class="card bg-yellow" :style="findPositionStyle(3)" @click="index = 3"></div>
<div class="card bg-pink relative" :style="findPositionStyle(4)" @click="index = 4">
<img :src="ly1" class="absolute h-full" alt="">
<img :src="ly2" class="absolute h-full" alt="">
</div>-->
<!-- <CardItem v-model:sliderIndex="index" color="primary" :self-index="1"/>
<CardItem v-model:sliderIndex="index" color="yellow" :self-index="2"/>
<CardItem v-model:sliderIndex="index" color="pink" :self-index="3"/>-->
<!-- <div class="card bg-pink" :style="findPositionStyle(5)" @click="index = 5"></div>
<div class="card bg-pink" :style="findPositionStyle(6)" @click="index = 6"></div>
<div class="card bg-pink" :style="findPositionStyle(7)" @click="index = 7"></div>
<div class="card bg-pink" :style="findPositionStyle(8)" @click="index = 8"></div>
<div class="card bg-pink" :style="findPositionStyle(9)" @click="index = 9"></div>-->
<CardItem v-for="(item,i) in props?.items" :key="i" v-model:sliderIndex="index"
:color="colors[i%3]"
:self-index="i" :img="item"/>
</div>
</div>
</template>
<script lang="ts" setup>
import { onMounted, onUnmounted, ref, watch } from 'vue'
// import {usePointerSwipe} from '@vueuse/core'
// import type {UseSwipeDirection} from '@vueuse/core'
// import type { UseSwipeDirection } from '@vueuse/core'
import { useSwipe } from '@vueuse/core'
import CardItem from '@/views/base/wallet/components/CardItem.vue'
import type { Card } from '@/models/wallet'
const el = ref(null)
const container = ref<HTMLElement | null>(null)
interface Prop {
items: string[]
}
const props = defineProps<Prop>()
// const decideSwip = ref<boolean>(false)
const { direction, isSwiping, lengthX, lengthY } = useSwipe(el/*, {
onSwipeStart(){
console.log('salam')
},
onSwipe(e: PointerEvent, direction: UseSwipeDirection) {
console.log('container',direction)
if (!decideSwip.value){
if (direction === 'up') {
index.value++
} else if (direction === 'down') {
index.value--
}
decideSwip.value = true
}
},
onSwipeEnd(e: PointerEvent){
console.log('container1')
decideSwip.value = false
}
}*/)
function getRandomColor() {
var letters = '0123456789ABCDEF'
var color = '#'
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)]
}
return color
}
const colors = ['#4B84EB', '#889BCD', '#C9A68D']
// Automatic slider logic
let interval: ReturnType<typeof setInterval>
const intervalTime = 10000 // Time interval for sliding (in milliseconds)
const startAutoSlide = () => {
interval = setInterval(() => {
if (index.value < props.items.length - 1) {
index.value++
} else {
index.value = 0 // Reset to first card when reaching the end
}
}, intervalTime)
}
const stopAutoSlide = () => {
clearInterval(interval)
}
onMounted(() => {
startAutoSlide() // Start sliding when component mounts
})
onUnmounted(() => {
stopAutoSlide() // Clear interval when component is destroyed
})
watch(isSwiping, () => {
// console.log(direction.value)
if (isSwiping.value) {
// console.log('salam')
if (direction.value === 'up' && props.items.length - 1 > index.value) {
index.value++
} else if (direction.value === 'down' && index.value > 0) {
index.value--
}
// console.log(index.value)
}
})
const index = ref<number>(0)
/*
const items = [
{
title: 'بانک ملی',
cardNumber: 6219861918606103,
shaba: 'IR590560611828005106225701',
color: getRandomColor()
},
{
title: 'بانک ملی',
cardNumber: 6219861918606103,
shaba: 'IR590560611828005106225701',
color: getRandomColor()
},
{
title: 'بانک ملت',
cardNumber: 6219861918606103,
shaba: 'IR590560611828005106225701',
color: getRandomColor()
},
{
title: 'بانک سامان',
cardNumber: 6219861918606103,
shaba: 'IR590560611828005106225701',
color: getRandomColor()
},
{
title: 'بانک پاسارگاد',
cardNumber: 6219861918606103,
shaba: 'IR590560611828005106225701',
color: getRandomColor()
},
{
title: 'بانک صادرات',
cardNumber: 6219861918606103,
shaba: 'IR590560611828005106225701',
color: getRandomColor()
},
{
title: 'بانک ملی',
cardNumber: 6219861918606103,
shaba: 'IR590560611828005106225701',
color: getRandomColor()
},
{
title: 'بانک ملت',
cardNumber: 6219861918606103,
shaba: 'IR590560611828005106225701',
color: getRandomColor()
},
{
title: 'بانک سامان',
cardNumber: 6219861918606103,
shaba: 'IR590560611828005106225701',
color: getRandomColor()
},
{
title: 'بانک پاسارگاد',
cardNumber: 6219861918606103,
shaba: 'IR590560611828005106225701',
color: getRandomColor()
},
]
*/
// const indexCss = computed(()=> index.value)
// watch(index,()=>{
// key++
// console.log(key)
// })
// let key = 0
/*function findPosition(pos: number) {
// console.log(pos,index)
let debug
if (pos === index.value){
debug = 'w-full z-100'
}
else /!*if (pos > index.value)*!/{
debug = `w-[${100 - Math.abs(index.value-pos) * 2}%] z-${100 - Math.abs(index.value-pos)}`
}
console.log(debug)
return debug
}*/
/*
function mouseUp() {
index.value--
}
function mouseDown() {
console.log('salam')
index.value++
}
*/
/*function findPositionStyle(pos: number) {
// console.log(pos,index)
let debug
if (pos === index.value) {
debug = 'width: 100; z-index: 100; opacity: 1; margin-top: -200px;'
} else /!*if (pos > index.value)*!/{
// debug = `w-[${100 - Math.abs(index.value-pos) * 2}%] z-${100 - Math.abs(index.value-pos)}`
debug = `width: ${100 - Math.abs(index.value - pos) * 3}%;
z-index: ${100 - Math.abs(index.value - pos)};
opacity: ${1 - Math.abs((index.value - pos) * 15) / 100};
margin-top: ${-200 - Math.abs((index.value - pos) * 4)}px;`
}
// console.log(debug)
return debug
}*/
</script>
<style lang="sass" scoped>
//.test .card:first-child
// margin-top: 0 !important
//.card
// height: 215px
// width: 100%
// align-self: center
// border-radius: 24px
// transition: .5s
//
//.card:first-child
// margin-top: 0 !important
//$total-items: 30
//@for $i from 1 through $total-items
// .card:nth-child(#{$i})
// @if($i > v-bind(indexCss))
// width: calc(percentage(100 - ($i * 4)) / 100)
// @if($i == v-bind(indexCss))
// width: 100%
// @if($i < v-bind(indexCss))
// width: calc(percentage(100 - ($i * 4)) / 100)
//.animate > div:nth-child(#{$i})
// animation-delay: .08s * $i
</style>
@@ -0,0 +1,162 @@
<template lang="pug">
.container
.slider
.slide(data-slide='1' style="background-color: green")
.slide(data-slide='2' style="background-color: red")
.slide(data-slide='3' style="background-color: orange")
.slide.slide--active(data-slide='4' style="background-color: blue")
.slide(data-slide='5' style="background-color: violet")
.slide(data-slide='5' style="background-color: primary")
.slide(data-slide='5' style="background-color: pink")
.slide(data-slide='5' style="background-color: teal")
.controls
#back Back
#forvard Forvard
</template>
<script setup>
document.addEventListener('DOMContentLoaded', function () {
renderSlider('.slider');
});
const nextSlide = () => {
let activeSlide = document.querySelector('.slide--active');
let nextSlide = activeSlide.nextElementSibling;
if (nextSlide) {
activeSlide.classList.remove('slide--active');
nextSlide.classList.remove('next');
nextSlide.classList.add('slide--active');
renderSlides();
renderBtns();
}
}
const renderBtns = () => {
let nextBtn = document.querySelector('#forvard');
let prevBtn = document.querySelector('#back');
let activeSlide = document.querySelector('.slide--active');
let prevSlide = activeSlide.previousElementSibling;
!prevSlide ? prevBtn.classList.add('disabled')
: prevBtn.classList.remove('disabled');
let nextSlide = activeSlide.nextElementSibling;
!nextSlide ? nextBtn.classList.add('disabled')
: nextBtn.classList.remove('disabled');
}
const prevSlide = () => {
let activeSlide = document.querySelector('.slide--active');
let prevSlide = activeSlide.previousElementSibling;
if (prevSlide) {
activeSlide.classList.remove('slide--active');
prevSlide.classList.remove('prev');
prevSlide.classList.add('slide--active');
renderSlides();
renderBtns();
}
}
const renderSlides = () => {
let slides = document.querySelectorAll('.slide');
if (!slides) {
return;
}
let activeSlide = document.querySelector('.slide--active');
if (!activeSlide) {
activeSlide = slides.item(0);
activeSlide.classList.add('slide--active');
}
[].forEach.call(slides, function (slide) {
slide.classList.remove('prev', 'next')
});
let prevSlide = activeSlide.previousElementSibling;
prevSlide && prevSlide.classList.add('prev');
let nextSlide = activeSlide.nextElementSibling;
nextSlide && nextSlide.classList.add('next');
}
const renderSlider = (element) => {
const slider = document.querySelector(element);
if (slider) {
let nextButton = document.querySelector("#forvard");
nextButton.addEventListener('click', function () {
nextSlide();
})
let prevButton = document.querySelector("#back");
prevButton.addEventListener('click', function () {
prevSlide();
})
renderSlides();
}
}
</script>
<style lang="sass" scoped>
.container
display: flex
flex-flow: column
justify-content: center
margin: 50px auto 0
width: 500px
height: 300px
.controls
display: flex
justify-content: center
div
padding: 12px 14px
cursor: pointer
border: 1px solid #fff
color: #fff
font-size: 16px
font-weight: bold
margin: 0 5px
border-radius: 10px
&.disabled
opacity: 0
cursor: default
.slider
position: relative
width: 100%
height: 100%
.slide
position: absolute
top: 25%
left: 10%
width: 80%
height: 50%
background-color: red
border: 1px solid #fff
border-radius: 15px
opacity: 0
transition: all 0.7s ease-out
&--active
opacity: 1
z-index: 9
.prev,
.next
opacity: .3
.prev
transform: translate(0, -30%) scale(0.8)
.next
transform: translate(0, 30%) scale(0.8)
</style>
+687
View File
@@ -0,0 +1,687 @@
<template>
<div>
<div class="absolute inset-0 bg-cover bg-center opacity-60" :style="{ backgroundImage: `url(${img})` }"></div>
<div class="bg-white py-3 px-3 text-primary font-bold drop-shadow z-[1999] wrap-fix">کیف پول</div>
<div
class="bg-white wrap-fix py-3 top-11 px-3 text-primary font-bold flex justify-evenly z-[1999]"
>
<div class="flex justify-evenly w-full px-2 h-11 items-center bg-gray-50 relative rounded">
<div
:class="isDeposit ? 'text-primary' : 'text-gray-400'"
class="w-full text-center z-2"
@click="setIsDeposit(true)"
>
واریز
</div>
<div
:class="!isDeposit ? 'text-primary' : 'text-gray-400'"
class="w-full text-center z-2"
@click="setIsDeposit(false)"
>
برداشت
</div>
<!-- <div ref="bganim" class="absolute bg-white h-8 w-1/2 rounded-lg " :style="`transform: translateX(${isDeposit? '0':'-100%'}); left: ${isDeposit? '0':'100%'}`"></div>-->
<div
ref="bganim"
:style="useStyle()"
class="absolute bg-white h-8 w-1/2 rounded-lg animate right"
></div>
</div>
</div>
<div class="px-5 pt-26 pb-2">
<a-form :model="form" class="!mt-5" name="basic" @finish="ok()">
<div class="border-gray-200 border-1 rounded-xl p-5 trans h-40 relative">
<bg_main />
<div class="z-100 relative">
<a-form-item :rules="[required()]">
<BasicInput
v-model:value="form.value"
addon-before="ریال"
addon-bg-color="#0A1B37"
addon-text-color="white"
place-holder="مبلغ"
size="large"
type="price"
/>
</a-form-item>
<Transition mode="out-in" name="fade">
<div v-if="!isDeposit">
<div class="font-bold text-xs">
{{
`موجودی کیف پول: ${usePriceWithoutType(
walletStore?.walletInfo?.cash ?? 0
)} ریال`
}}
</div>
<a-form-item v-if="walletStore?.walletInfo" class="!mt-3">
<a-slider
v-model:value="form.percentWallet"
:disabled="walletStore?.walletInfo?.cash <= 0"
:max="100"
:min="0"
:step="10"
:tip-formatter="formatter"
@change="percentChange"
/>
</a-form-item>
</div>
<div v-else class="flex gap-2 mt-3">
<BasicButton class="w-full font-bold !px-1" @click="form.value = 10000000">
{{ usePriceWithoutType(10000000) }}
</BasicButton>
<BasicButton class="w-full font-bold !px-1" @click="form.value = 50000000">
{{ usePriceWithoutType(50000000) }}
</BasicButton>
<BasicButton class="w-full font-bold !px-1" @click="form.value = 100000000">
{{ usePriceWithoutType(100000000) }}
</BasicButton>
</div>
</Transition>
</div>
</div>
<a-form-item>
<BasicButton
:disabled="disableButton"
class="w-full py-2 mt-5"
html-type="submit"
type="primary"
>
<div>
<a-spin v-if="loading" size="small" />
<div v-else>{{ isDeposit ? 'واریز' : 'برداشت' }}</div>
</div>
</BasicButton>
</a-form-item>
</a-form>
<div
v-if="isDeposit"
ref="el"
:class="loading ? 'h-screen' : ''"
class="px-3 overflow-y-scroll w-full h-[49vh] pb-16"
style="max-height: calc(100vh - 50px)"
>
<list-anim v-if="!loading" :numberItemsAnim="4">
<Item
v-for="item in isDeposit ? depositItems : withdrawItems"
:key="item.id"
:item="item"
/>
<TransactionSkeleton v-if="loadingMore" class="mt-1 mb-8" />
</list-anim>
<TransactionSkeleton v-for="i in 13" v-else :key="i" class="mt-1" />
</div>
<!-- <Slider/>-->
<Transition mode="out-in" name="fade">
<template v-if="!isDeposit">
<!-- <MySlider v-if="cardItems.length > 0" :items="cardItems" class="mt-[5vh] pb-[25vh] mb-[16vh]"
style="touch-action: none"/>-->
<CardSlider
v-if="cardItems.length > 0"
:items="cardItems"
v-model:id="form.card_id"
class="card-slider-wrap mt-[2vh] px-3 fixed bottom-10 right-0 left-0"
style="touch-action: none"
/>
<div
v-else-if="!loading && cardItems.length === 0"
class="h-30 flex items-center justify-center"
>
هیچ کارتی یافت نشد
</div>
</template>
</Transition>
</div>
<Transition mode="out-in" name="fade">
<div
v-if="!isDeposit"
class="add-card fixed bottom-0 h-[18vh] bg-[#FBFBFC] w-full shadow-lg rounded-3xl flex justify-center pt-3 z-200"
style="box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 26px 11px"
@click="showAddCard = true"
>
<div>افزودن کارت جدید</div>
<BasicIcon icon="vuesax-linear:add" />
<BasicActionSheet v-model:show="showAddCard" class="!max-h-[95vh]">
<div class="font-bold text-lg">افزودن کارت</div>
<div class="mt-4 text-red-600 font-bold">توجه : حتما شماره کارت صاحب حساب نرم افزار وارد شود.</div>
<div class="pb-20 mt-5">
<a-form :model="cardForm">
<a-form-item
:rules="required()"
class="w-full gap-2 !flex-col"
label="نام بانک"
name="bank_name"
>
<BasicInput v-model:value="cardForm.bank_name" />
</a-form-item>
<!-- <a-form-item
:rules="cardNumberValidation()"
class="w-full gap-2 !flex-col"
label="شماره کارت"
name="cart_number"
>
<BasicInput v-model:value="cardForm.cart_number" type="number" />
</a-form-item>-->
<!-- <a-form-item
v-if="walletStore.walletInfo"
class="w-full gap-2 !flex-col"
label="تاریخ تولد"
name="cart_number"
>
<BaseDatePicker v-model:value="cardForm.birth_date" class="w-full" inputReadOnly/>
</a-form-item>-->
<!-- <a-form-item
:rules="required()"
class="w-full gap-2 !flex-col"
label="شماره حساب"
name="account_number"
>
<BasicInput v-model:value="cardForm.account_number" type="number" />
</a-form-item>-->
<a-form-item
:rules="required()"
class="w-full gap-2 !flex-col"
label="شماره شبا"
name="shaba_number"
>
<BasicInput v-model:value="cardForm.shaba_number" />
</a-form-item>
<BasicButton
:disabled="loading"
class="w-full mt-5 md:mt-10"
type="primary"
@click="addCard"
>
<a-spin v-if="loading" size="small" />
<div v-else>ثبت</div>
</BasicButton>
<BasicButton class="w-full mt-2" @click="showAddCard = false">بازگشت</BasicButton>
</a-form>
</div>
</BasicActionSheet>
</div>
</Transition>
<DialogVant v-model:show="showConfirmCode" :closeOnClickOverlay="true" :timeOut="-1">
<template v-slot:title>
<div>
<div class="flex justify-end">
<BasicIcon
@click="showConfirmCode = false"
icon="vuesax-linear:close-circle"
size="30"
class="text-red"
/>
</div>
<div class="p-5 text-sm">لطفا کد ارسالی را وارد کنید.</div>
<div>
<OtpInput
ref="refOtpInput"
:is-input-num="true"
:num-inputs="4"
:should-auto-focus="true"
autocomplete="one-time-code"
class="mt-5 justify-center"
input-classes="otp-input"
separator=""
style="direction: ltr"
value=""
@on-complete="handleOnComplete"
/>
</div>
</div>
</template>
<template v-slot:button>
<div></div>
<div class="flex justify-end">
<BasicButton @click="showConfirmCode = false" class="py-2" type="primary">
بستن
</BasicButton>
</div>
</template>
</DialogVant>
<SkeletonLoading v-model:show="infoVisible" />
<!--
<transaction mode="out-in" name="fade">
<div v-if="isDeposit"
class="bg-white fixed right-0 left-0 bottom-0 top-20 z-100 op-90 flex justify-center items-center">
<div class="flex flex-col justify-center mt-[-20vh] items-center px-5">
<DotLottieVue class="w-80vw " autoplay loop
src="https://lottie.host/203d9dc9-a102-43a6-864a-2d3eef2daf4d/xNBrLOheY7.json" />
<div class="flex justify-center items-center text-justify text-primary font-bold">
با توجه به اختلال پیش آمده در سامانه پیپینگ
برای شارژ کیف پول خود از طریق لینک زیر اقدام نمایید:
</div>
<a class="mt-2 w-full " href="https://www.payping.ir/d/Hzy0">
<BasicButton class="w-full">https://www.payping.ir/d/Hzy0</BasicButton>
</a>
<div class="w-full">
<div class="text-justify mt-2 text-primary font-bold">
و یا مبلغ مورد نظر خود را به شماره حساب:
</div>
</div>
<BasicButton icon="vuesax-linear:copy" class="flex-1 w-full mt-1" icon-size="18" @click.stop="copyCode('838-40-89997745-1')">
838-40-89997745-1
</BasicButton>
<div class="w-full">
<div class="text-justify mt-2 text-primary font-bold">
با شماره شبا:
</div>
<BasicButton icon="vuesax-linear:copy" class="flex-1 w-full mt-1" icon-size="18" @click.stop="copyCode('IR550560083804089997745001')">
IR550560083804089997745001
</BasicButton>
</div>
<div class="w-full">
<div class="text-justify mt-2 text-primary font-bold flex">
به نام
<div class="mx-1 font-extrabold text-blue-600">پديده طلاي شقايق</div>
بانک سامان واریز نمایید.
</div>
<div class="text-justify mt-2 text-primary font-bold">
توجه داشته باشید بعد از پرداخت موفق، رسید خود را به شماره 09190909884 در واتس اپ ارسال نمایید.
</div>
</div>
<a class="mt-1 w-full " href="https://wa.me/09190909884">
<BasicButton class="w-full !text-green-600" icon="vuesax-linear:whatsapp">شماره واتساپ</BasicButton>
</a>
</div>
</div>
</transaction>
-->
<BasicModal
v-model:visible="chargeAccountModal"
custom-footer
:closable="false"
>
<div class="text-center">
<div class=" font-bold text-red-600">مشتریان گرامی</div>
<div class="mt-2">
<span>جهت شارژ حساب کاربری خود، کلمه "شماره حساب" را برای پشتیبانی ارسال نمایید.</span>
</div>
<BasicButton class="mt-4">
<a class="w-full" href="https://wa.me/989123113112">
پیام به پشتیبانی
</a>
</BasicButton>
</div>
<template #footer>
<a-button type="primary" class="w-full" @click="chargeAccountModal = false">
متوجه شدم
</a-button>
</template>
</BasicModal>
</div>
</template>
<script lang="ts" setup>
import { computed, onMounted, ref } from 'vue'
import { usePriceWithoutType } from '@/utils/usePrice'
import { loading, loadingMore } from '@/utils'
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
import router from '@/router'
import { useWalletStore } from '@/store/walletStore'
import Bg_main from '@/components/bg_main.vue'
import type { Transaction } from '@/models/transaction'
import { createCard, deposit, getActivatedCards, withdraw, confirmCode } from '@/api/wallet'
import { useInfiniteScroll } from '@vueuse/core'
import { message } from 'ant-design-vue'
import ListAnim from '@/components/ListAnim.vue'
import TransactionSkeleton from '@/components/TransactionSkeleton.vue'
import Item from './components/Item.vue'
import type { TableEngineInput, TableOutput } from '@/models/table'
import {getTransactionTable, getTransactionTable2} from '@/api/transaction'
import BasicInput from '@/components/BasicPacks/BasicInput.vue'
import CardSlider from './components/UISlider/index.vue'
import BasicActionSheet from '@/components/BasicPacks/BasicActionSheet.vue'
import type { Card } from '@/models/wallet'
import { cardNumberValidation , required } from '@/utils/inputRules'
import { useUserStore } from '@/store/userStore'
import { DotLottieVue } from '@lottiefiles/dotlottie-vue'
import OtpInput from 'vue3-otp-input'
import DialogVant from '@/components/DialogVant.vue'
import SkeletonLoading from './components/SkeletonLoading.vue'
import BaseDatePicker from "@/components/BasicPacks/BaseDatePicker";
import img from "@/assets/img/user_ly1.svg";
import BasicModal from "@/components/BasicPacks/BasicModal.vue";
const isDeposit = ref<boolean>(true)
const walletStore = useWalletStore()
const userStore = useUserStore()
const showAddCard = ref<boolean>(false)
const chargeAccountModal = ref<boolean>(false)
const showConfirmCode = ref<boolean>(false)
const refOtpInput = ref<InstanceType<typeof VOtpInput> | null>(null)
onMounted(() => {
if (router.currentRoute.value.query.state === 'deposit') {
isDeposit.value = true
}
walletStore.getMyWallet()
isDeposit.value = true
})
const form = ref<Transaction>({
value: undefined,
percentWallet: 0,
card_id: undefined
})
const infoVisible = ref<boolean>(false)
const cardForm = ref<Card>({
birth_date: 0,
account_number: '',
bank_name: '',
cart_number: '',
shaba_number: ''
})
const disableButton = computed(() => {
if (!loading.value) {
if (walletStore?.walletInfo?.cash && !isDeposit.value) {
if (cardItems.value.length > 0) {
return (
walletStore?.walletInfo?.cash <= 0 ||
walletStore?.walletInfo?.cash < parseInt(form.value?.value) ||
isNaN(parseInt(form.value?.value)) ||
parseInt(form.value?.value) < 1000000
)
} else return true
} else if (isDeposit.value) {
return isNaN(parseInt(form.value?.value)) || parseInt(form.value?.value) < 1000000
} else return false
} else {
return true
}
})
const bganim = ref(null)
const unitCalculator = computed(() => {
return (walletStore?.walletInfo?.cash ?? 0) / 100
})
function copyCode(val: string) {
// nextTick(() => {
navigator.clipboard.writeText(val)
message.info('کد رونوشت شد')
// })
}
const cardItems = ref<Card[]>([])
const cardTableOutput = ref<TableOutput<Card> | null>(null)
const resetData = () => {
form.value.value = undefined
form.value.percentWallet = 0
}
async function addCard() {
try {
loading.value = true
await createCard(cardForm.value)
await getCards()
showAddCard.value = false
cardForm.value = {
birth_date: 0,
account_number: '',
bank_name: '',
cart_number: '',
shaba_number: ''
}
message.success('کارت وارد شده با موفقیت افزوده شد و پس از تایید نمایش داده خواهد شد.')
} catch (e) {
console.log(e)
} finally {
loading.value = false
}
}
async function getCards() {
try {
/* cardTableOutput.value = await getCardsTable()
cardItems.value.push(...cardTableOutput.value.rows)*/
cardItems.value = (await getActivatedCards()) ?? []
form.value.card_id = (await cardItems.value.length) ? cardItems.value[0].id : undefined
} catch (e) {
console.log(e)
}
}
function setIsDeposit(val: boolean) {
isDeposit.value = val
form.value.value = undefined
form.value.percentWallet = 0
// console.log(bganim.value.classList)
// bganim?.value?.classList.add(val?'right':'left')
// bganim?.value?.style.transform = `translateX(${val ? '0' : '-100'});`
// bganim?.value?.style.animationDirection = val? 'normal':'reverse'
// val? bganim?.value?.classList?.add("move") : bganim?.value?.classList?.remove("move")
// const el = bganim.value?.
// el.
}
function useStyle() {
if (isDeposit.value) return 'right: 2%;'
// if (isDeposit.value) return 'animation-direction: normal'
// else return 'animation-direction: reverse'
else return ' right: 98%; transform: translate(100%, 0);'
}
const formatter = (value: number) => {
return `${value}%`
}
function percentChange(val: number) {
if (val !== 0) form.value.value = parseInt((unitCalculator.value * val).toFixed())
else form.value.value = undefined
}
async function ok() {
try {
if (form.value.value !== undefined) {
loading.value = true
if (!isDeposit.value) {
await confirmCode({ value: form.value.value })
showConfirmCode.value = await true
}
if (isDeposit.value) {
chargeAccountModal.value = true
/*const data = await deposit(form.value)
window.location.href = data
await walletStore.getMyWallet()
resetData()
message.success('عملیات با موفقیت انجام شد')*/
}
} else {
message.error('ابتدا مبلغ را وارد کنید')
}
} catch (e) {
console.log(e)
} finally {
loading.value = false
}
}
//table
const items = ref<Transaction[]>([])
const depositItems = ref<Transaction[]>([])
const withdrawItems = ref<Transaction[]>([])
const depositTableOutput = ref<TableOutput<Transaction> | null>(null)
const withdrawTableOutput = ref<TableOutput<Transaction> | null>(null)
const depositPagination = ref<TableEngineInput>({
filters: [
/*{
field: 'type',
cr: 'and',
type: 'number',
op: 'eq',
value: 3
}*/
],
limit: 6,
page: 0
})
const withdrawPagination = ref<TableEngineInput>({
filters: [
{
field: 'type',
cr: 'and',
type: 'number',
op: 'eq',
value: 4
}
],
limit: 6,
page: 0
})
const el = ref()
// const {y} = useScroll(el)
onMounted(async () => {
cardForm.value.birth_date = userStore.userInfo?.birth_date
await initWithdrawTable()
await initDepositTable()
await getCards()
})
if (!userStore.isSingle) {
useInfiniteScroll(
el,
async () => {
// load more
// if (!userStore.isSingle) {
if (isDeposit.value) {
if (
depositTableOutput.value &&
(depositPagination.value.page + 1) * depositPagination.value.limit <
depositTableOutput.value.query.total
) {
depositPagination.value.page++
console.log('Updated Page:', depositPagination.value.page)
await initDepositTable()
}
} else {
if (
withdrawTableOutput.value &&
(withdrawPagination.value.page + 1) * withdrawPagination.value.limit <
withdrawTableOutput.value.query.total
) {
// console.log('gfgf')
withdrawPagination.value.page++
await initWithdrawTable()
}
}
// }
},
{ distance: 12 }
)
}
async function initDepositTable() {
try {
depositPagination.value.page === 0 ? (loading.value = true) : (loadingMore.value = true)
depositTableOutput.value = await getTransactionTable2(depositPagination.value)
depositItems.value.push(...depositTableOutput.value.rows)
// console.log(tableOutput.value)
} catch (e) {
console.log(e)
} finally {
loading.value = false
loadingMore.value = false
}
}
async function initWithdrawTable() {
try {
withdrawPagination.value.page === 0 ? (loading.value = true) : (loadingMore.value = true)
withdrawTableOutput.value = await getTransactionTable(withdrawPagination.value)
withdrawItems.value.push(...withdrawTableOutput.value.rows)
// console.log(tableOutput.value)
} catch (e) {
console.log(e)
} finally {
loading.value = false
loadingMore.value = false
}
}
async function handleOnComplete(value: string) {
try {
infoVisible.value = true
showConfirmCode.value = false
await withdraw({ ...form.value, otp: value })
await walletStore.getMyWallet()
await message.success('عملیات با موفقیت انجام شد')
resetData()
} catch (e) {
console.log(e)
}
infoVisible.value = false
refOtpInput.value?.clearInput()
}
</script>
<style scoped>
/*.right {
left: 100%;
transform: translateX(-100%);
}*/
.left {
transform: translateX(0);
left: 0;
}
/*.fade-enter-active,
.fade-leave-active {
transition: opacity 0.2s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}*/
/*.trans{
transition: height 1s;
}*/
.toggle-transe-parent {
animation: ease-in-out infinite alternate swingParent;
}
@keyframes swingParent {
from {
transform: translateX(0);
left: 0;
}
to {
left: 100%;
transform: translateX(-100%);
}
}
.animate.right {
right: 0;
}
.animate.right.move {
right: 100%;
transform: translate(100%, 0);
}
@media screen and (min-width: 426px) {
:deep(.ant-form-item .ant-form-item-label) {
margin-top: 30px !important;
}
}
@media screen and (min-width: 426px) {
.card-slider-wrap {
width: 426px;
margin: 0 auto;
}
}
@media screen and (min-width: 426px) {
.add-card {
position: absolute;
}
}
</style>