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>
@@ -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

@@ -0,0 +1,9 @@
<svg width="428" height="258" viewBox="0 0 428 258" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="428" height="258" fill="url(#paint0_linear_484_10473)"/>
<defs>
<linearGradient id="paint0_linear_484_10473" x1="214" y1="0" x2="214" y2="258" gradientUnits="userSpaceOnUse">
<stop offset="0.526042" stop-color="white" stop-opacity="0"/>
<stop offset="1" stop-color="white"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 421 B

+28
View File
@@ -0,0 +1,28 @@
<svg width="693" height="550" viewBox="0 0 693 550" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.7">
<path d="M691.87 47.604C685.785 46.8139 679.637 46.4225 673.481 46.4331C617.828 46.4331 609.525 73.5524 568.007 81.6437C559.69 83.2139 551.188 83.9721 542.668 83.9037C507.243 83.9037 491.009 72.9084 473.172 62.8265C458.084 54.2902 441.836 46.4331 411.855 46.4331C356.203 46.4331 347.899 73.5524 306.381 81.6437C298.064 83.2139 289.563 83.9721 281.042 83.9037C245.617 83.9037 229.383 72.9084 211.546 62.8265C196.459 54.2902 180.211 46.4331 150.229 46.4331C94.6187 46.4799 86.3289 73.611 44.7557 81.6906C36.4434 83.2607 27.9462 84.019 19.4304 83.9505C13.2787 83.9616 7.13522 83.5702 1.05469 82.7796" stroke="#F3F0E9" stroke-miterlimit="10"/>
<path d="M691.87 80.988C676.423 89.7819 660.092 98.0957 629.323 98.0957C599.342 98.0957 583.094 90.2269 568.007 81.7023C550.17 71.6321 533.936 60.6251 498.511 60.6251C489.995 60.5576 481.498 61.3158 473.185 62.885C431.667 70.9764 423.364 98.0957 367.712 98.0957C337.73 98.0957 321.482 90.2269 306.395 81.7023C288.558 71.6321 272.324 60.6251 236.899 60.6251C228.378 60.5567 219.877 61.3149 211.56 62.885C170.111 70.9764 161.738 98.0957 106.086 98.0957C76.1047 98.0957 59.8567 90.2269 44.7693 81.7023C31.9478 74.4658 19.9 66.7492 1.06836 62.967" stroke="#F3F0E9" stroke-miterlimit="10"/>
<path d="M1.05469 98.3885C8.96575 101.226 16.5045 104.759 23.5476 108.927C41.3845 118.997 57.6187 130.004 93.0437 130.004C101.564 130.073 110.066 129.314 118.383 127.744C159.901 119.653 168.204 92.5337 223.856 92.5337C253.838 92.5337 270.072 100.403 285.173 108.927C303.01 118.997 319.244 130.004 354.669 130.004C363.19 130.073 371.691 129.314 380.008 127.744C421.526 119.653 429.83 92.5337 485.482 92.5337C515.463 92.5337 531.684 100.403 546.785 108.927C564.622 118.997 580.87 130.004 616.295 130.004C624.811 130.073 633.308 129.314 641.62 127.744C663.726 123.447 676.437 113.693 691.87 105.602" stroke="#F3F0E9" stroke-miterlimit="10"/>
<path d="M1.05469 116.117C8.13886 112.883 15.7045 110.473 23.5476 108.95C31.8646 107.38 40.3663 106.622 48.8867 106.691C84.3118 106.691 100.546 117.686 118.383 127.768C133.484 136.304 149.718 144.161 179.7 144.161C235.352 144.161 243.655 117.042 285.173 108.95C293.49 107.38 301.992 106.622 310.512 106.691C345.937 106.691 362.171 117.686 380.008 127.768C395.11 136.304 411.344 144.161 441.325 144.161C496.963 144.161 505.267 117.042 546.785 108.95C555.102 107.38 563.604 106.622 572.124 106.691C607.549 106.691 623.783 117.686 641.62 127.768C654.732 135.18 668.728 142.1 691.87 143.786" stroke="#F3F0E9" stroke-miterlimit="10"/>
<path d="M691.87 25.836C686.661 23.1194 681.77 20.2271 676.769 17.4051C661.668 8.86883 645.447 1 615.493 1C559.841 1 551.538 28.1193 510.02 36.2107C501.694 37.7826 493.183 38.5408 484.653 38.4706C449.228 38.4706 432.994 27.4753 415.157 17.3934C400.056 8.86883 383.822 1 353.84 1C298.188 1 289.885 28.1193 248.367 36.2107C240.05 37.7808 231.548 38.539 223.027 38.4706C187.602 38.4706 171.368 27.4753 153.531 17.3934C138.43 8.86883 122.251 1 92.2147 1C43.5951 1 31.0637 21.7025 1.05469 32.3348" stroke="#F3F0E9" stroke-miterlimit="10"/>
<path d="M691.87 15.4732C686.786 15.7946 681.738 16.4405 676.768 17.4053C635.25 25.4966 626.947 52.616 571.281 52.616C541.3 52.616 525.065 44.7471 509.964 36.2226C492.127 26.1524 475.893 15.1454 440.468 15.1454C431.957 15.0787 423.465 15.837 415.157 17.4053C373.708 25.4966 365.335 52.616 309.683 52.616C279.702 52.616 263.467 44.7471 248.366 36.2226C230.529 26.1524 214.295 15.1454 178.87 15.1454C170.35 15.0769 161.848 15.8352 153.531 17.4053C112.082 25.4966 103.71 52.616 48.0575 52.616C27.112 52.616 12.8812 48.7752 1.08203 43.5528" stroke="#F3F0E9" stroke-miterlimit="10"/>
<path d="M691.87 196.023L688.485 197.908C670.648 207.978 654.414 218.985 618.989 218.985C610.473 219.054 601.976 218.295 593.664 216.725C552.146 208.646 543.842 181.515 488.19 181.515C458.209 181.515 441.974 189.383 426.873 197.908C409.036 207.978 392.802 218.985 357.377 218.985C348.857 219.054 340.355 218.295 332.038 216.725C290.52 208.634 282.217 181.515 226.564 181.515C196.583 181.515 180.349 189.383 165.248 197.908C147.411 207.978 131.177 218.985 95.7517 218.985C87.2312 219.054 78.7295 218.295 70.4125 216.725C40.0167 210.812 27.43 194.7 1.05469 186.479" stroke="#F3F0E9" stroke-miterlimit="10"/>
<path d="M691.87 198.622C690.765 198.365 689.632 198.119 688.485 197.908C680.173 196.338 671.676 195.58 663.16 195.648C627.735 195.648 611.501 206.643 593.664 216.725C578.563 225.262 562.328 233.119 532.347 233.119C476.695 233.119 468.391 205.999 426.873 197.908C418.556 196.338 410.055 195.58 401.534 195.648C366.109 195.648 349.875 206.643 332.038 216.725C316.937 225.262 300.703 233.119 270.721 233.119C215.069 233.119 206.766 205.999 165.248 197.908C156.931 196.338 148.429 195.58 139.909 195.648C104.484 195.648 88.2494 206.643 70.4125 216.725C55.3251 225.262 39.091 233.119 9.10959 233.119C6.34633 233.119 3.58307 233.048 1.05469 232.92" stroke="#F3F0E9" stroke-miterlimit="10"/>
<path d="M1.05469 263.528C8.00946 264.573 15.0615 265.083 22.1246 265.051C57.5496 265.051 73.7837 254.055 91.6206 243.973C106.708 235.437 122.956 227.58 152.937 227.58C208.589 227.58 216.893 254.699 258.411 262.791C266.728 264.361 275.23 265.119 283.75 265.051C319.175 265.051 335.409 254.055 353.246 243.973C368.334 235.437 384.582 227.58 414.563 227.58C470.215 227.58 478.519 254.699 520.037 262.791C528.354 264.361 536.855 265.119 545.376 265.051C580.801 265.051 597.035 254.055 614.872 243.973C629.959 235.437 646.207 227.58 676.189 227.58C681.431 227.563 686.669 227.833 691.87 228.388" stroke="#F3F0E9" stroke-miterlimit="10"/>
<path d="M1.05469 260.367C17.3579 250.999 33.7026 241.725 66.2953 241.725C74.8106 241.653 83.3077 242.407 91.6206 243.974C133.152 252.053 141.456 279.184 197.108 279.184C227.076 279.184 243.324 271.315 258.411 262.791C276.248 252.721 292.482 241.714 327.907 241.714C336.428 241.645 344.929 242.404 353.246 243.974C394.764 252.065 403.068 279.184 458.72 279.184C488.701 279.184 504.949 271.315 520.037 262.791C537.873 252.721 554.108 241.714 589.533 241.714C598.053 241.645 606.555 242.404 614.872 243.974C648.031 250.437 660.023 269.056 691.87 276.269" stroke="#F3F0E9" stroke-miterlimit="10"/>
<path d="M1.05469 137.662C8.27682 136.531 15.6092 135.982 22.9535 136.023C78.6056 136.023 86.9092 163.142 128.427 171.234C136.744 172.804 145.246 173.562 153.766 173.493C189.191 173.493 205.425 162.498 223.262 152.416C238.35 143.88 254.598 136.023 284.579 136.023C340.231 136.023 348.535 163.142 390.053 171.234C398.37 172.804 406.871 173.562 415.392 173.493C450.817 173.493 467.051 162.498 484.888 152.416C499.975 143.88 516.223 136.023 546.205 136.023C601.857 136.023 610.16 163.154 651.678 171.234C659.991 172.804 668.488 173.562 677.004 173.493C681.972 173.505 686.936 173.263 691.87 172.768" stroke="#F3F0E9" stroke-miterlimit="10"/>
<path d="M1.05469 168.529C17.6343 178.013 33.9789 187.639 67.1105 187.639C97.0918 187.639 113.34 179.77 128.427 171.245C146.264 161.175 162.498 150.168 197.923 150.168C206.444 150.1 214.945 150.858 223.262 152.428C264.711 160.519 273.084 187.639 328.736 187.639C358.717 187.639 374.965 179.77 390.053 171.245C407.89 161.175 424.124 150.168 459.549 150.168C468.069 150.1 476.571 150.858 484.888 152.428C526.337 160.519 534.71 187.639 590.362 187.639C620.343 187.639 636.591 179.77 651.678 171.245C663.685 164.465 674.973 157.264 691.87 153.283" stroke="#F3F0E9" stroke-miterlimit="10"/>
<path d="M691.87 321.163C682.019 318.001 670.261 315.929 654.884 315.929C599.246 315.929 590.942 343.06 549.41 351.139C541.098 352.709 532.601 353.468 524.085 353.399C488.66 353.399 472.412 342.404 454.575 332.322C439.474 323.786 423.253 315.929 393.272 315.929C337.62 315.929 329.316 343.048 287.798 351.139C279.481 352.709 270.98 353.468 262.459 353.399C227.034 353.399 210.8 342.404 192.963 332.322C177.862 323.786 161.628 315.929 131.646 315.929C75.9943 315.929 67.6907 343.048 26.1727 351.139C17.9281 352.697 9.50135 353.455 1.05469 353.399" stroke="#F3F0E9" stroke-miterlimit="10"/>
<path d="M691.87 340.343C668.382 351.444 653.599 367.544 610.727 367.544C580.745 367.544 564.498 359.676 549.41 351.151C531.573 341.081 515.339 330.074 479.914 330.074C471.394 330.005 462.892 330.764 454.575 332.334C413.126 340.425 404.753 367.544 349.115 367.544C319.134 367.544 302.9 359.676 287.798 351.151C269.961 341.081 253.727 330.074 218.302 330.074C209.782 330.005 201.28 330.764 192.963 332.334C151.445 340.425 143.142 367.544 87.4895 367.544C57.5081 367.544 41.274 359.676 26.1727 351.151C18.1178 346.584 10.3392 341.854 1.05469 338.025" stroke="#F3F0E9" stroke-miterlimit="10"/>
<path d="M1.05469 376.221C2.43632 376.936 3.67979 377.662 4.9647 378.399C22.8016 388.469 39.0357 399.476 74.4607 399.476C82.9812 399.545 91.4828 398.787 99.7998 397.217C141.318 389.125 149.621 362.006 205.274 362.006C235.255 362.006 251.503 369.875 266.59 378.399C284.427 388.469 300.661 399.476 336.086 399.476C344.607 399.545 353.108 398.787 361.425 397.217C402.943 389.125 411.247 362.006 466.885 362.006C496.867 362.006 513.101 369.875 528.202 378.399C546.039 388.469 562.273 399.476 597.698 399.476C606.219 399.545 614.72 398.787 623.037 397.217C653.212 391.362 665.868 375.402 691.87 367.135" stroke="#F3F0E9" stroke-miterlimit="10"/>
<path d="M1.05469 379.231C2.32579 378.938 3.62452 378.657 4.9647 378.399C13.2817 376.829 21.7834 376.071 30.3038 376.139C65.7288 376.139 81.963 387.135 99.7998 397.216C114.887 405.753 131.135 413.61 161.117 413.61C216.769 413.61 225.072 386.479 266.59 378.399C274.903 376.829 283.4 376.071 291.916 376.139C327.341 376.139 343.589 387.135 361.425 397.216C376.527 405.753 392.747 413.61 422.728 413.61C478.38 413.61 486.684 386.491 528.202 378.399C536.519 376.829 545.021 376.071 553.541 376.139C588.966 376.139 605.2 387.135 623.037 397.216C638.138 405.753 654.373 413.61 684.354 413.61C686.965 413.61 689.466 413.551 691.87 413.434" stroke="#F3F0E9" stroke-miterlimit="10"/>
<path d="M691.87 303.048C678.441 298.903 668.59 292.72 658.2 286.854C643.098 278.318 626.864 270.46 596.869 270.46C541.231 270.46 532.927 297.58 491.409 305.671C483.092 307.241 474.591 307.999 466.07 307.931C430.645 307.931 414.411 296.936 396.574 286.854C381.487 278.318 365.239 270.46 335.257 270.46C279.605 270.46 271.302 297.58 229.784 305.671C221.467 307.241 212.965 307.999 204.445 307.931C169.02 307.931 152.785 296.936 134.949 286.854C119.861 278.318 103.613 270.46 73.6317 270.46C36.1757 270.46 20.1765 282.744 1.05469 293.247" stroke="#F3F0E9" stroke-miterlimit="10"/>
<path d="M691.87 284.805C689.208 284.664 686.445 284.594 683.58 284.594C675.064 284.525 666.567 285.284 658.255 286.854C616.723 294.933 608.42 322.064 552.767 322.064C522.786 322.064 506.566 314.196 491.465 305.671C473.628 295.601 457.38 284.594 421.955 284.594C413.439 284.525 404.942 285.284 396.629 286.854C355.098 294.933 346.794 322.064 291.156 322.064C261.174 322.064 244.926 314.196 229.839 305.671C212.002 295.601 195.768 284.594 160.343 284.594C151.822 284.525 143.321 285.284 135.004 286.854C93.5549 294.945 85.1822 322.064 29.5301 322.064C19.9287 322.165 10.3539 321.188 1.05469 319.16" stroke="#F3F0E9" stroke-miterlimit="10"/>
<path d="M691.871 456.97C684.15 459.798 676.786 463.278 669.889 467.357C652.066 477.427 635.818 488.434 600.407 488.434C591.891 488.502 583.394 487.744 575.081 486.174C533.55 478.094 525.246 450.963 469.608 450.963C439.612 450.963 423.364 458.844 408.277 467.357C390.454 477.427 374.206 488.434 338.795 488.434C330.279 488.502 321.782 487.744 313.47 486.174C271.938 478.094 263.634 450.963 207.982 450.963C177.987 450.963 161.739 458.844 146.651 467.357C128.828 477.427 112.58 488.434 77.1693 488.434C68.6339 488.498 60.118 487.732 51.7887 486.151C29.4063 481.806 16.6815 471.924 1 463.727" stroke="#F3F0E9" stroke-miterlimit="10"/>
<path d="M691.871 474.301C684.936 471.176 677.545 468.841 669.889 467.357C661.558 465.783 653.043 465.025 644.508 465.097C609.097 465.097 592.849 476.081 575.026 486.174C559.939 494.71 543.704 502.568 513.709 502.568C458.057 502.568 449.754 475.437 408.222 467.357C399.91 465.787 391.412 465.029 382.897 465.097C347.485 465.097 331.237 476.081 313.414 486.174C298.327 494.71 282.079 502.568 252.084 502.568C196.432 502.568 188.128 475.437 146.596 467.357C138.284 465.787 129.787 465.029 121.271 465.097C85.8598 465.097 69.6118 476.081 51.7887 486.174C38.5665 493.657 24.4601 500.624 1 502.24" stroke="#F3F0E9" stroke-miterlimit="10"/>
<path d="M1.05469 534.464H3.54162C38.9666 534.464 55.2008 523.469 73.0376 513.387C88.1389 504.851 104.373 496.994 134.354 496.994C190.006 496.994 198.31 524.113 239.828 532.204C248.145 533.774 256.647 534.533 265.167 534.464C300.592 534.464 316.826 523.469 334.663 513.387C349.764 504.851 365.999 496.994 395.98 496.994C451.632 496.994 459.936 524.125 501.454 532.204C509.766 533.774 518.263 534.533 526.779 534.464C562.204 534.464 578.438 523.469 596.275 513.387C611.362 504.851 627.61 496.994 657.592 496.994C669.229 496.823 680.818 498.315 691.87 501.408" stroke="#F3F0E9" stroke-miterlimit="10"/>
<path d="M1.05469 520.073C12.8124 514.933 26.9188 511.162 47.6433 511.162C56.1637 511.094 64.6654 511.852 72.9824 513.422C114.5 521.513 122.804 548.633 178.456 548.633C208.437 548.633 224.672 540.764 239.773 532.239C257.61 522.169 273.844 511.162 309.269 511.162C317.789 511.094 326.291 511.852 334.608 513.422C376.126 521.513 384.43 548.633 440.082 548.633C470.063 548.633 486.297 540.764 501.398 532.239C519.235 522.169 535.469 511.162 570.894 511.162C579.41 511.094 587.907 511.852 596.22 513.422C635.154 520.998 644.881 545.319 691.815 548.328" stroke="#F3F0E9" stroke-miterlimit="10"/>
<path d="M691.87 438.762C681.062 441.687 669.764 443.099 658.421 442.942C649.901 443.015 641.399 442.26 633.082 440.694C591.564 432.603 583.26 405.483 527.622 405.483C497.64 405.483 481.406 413.352 466.305 421.877C448.468 431.947 432.234 442.954 396.809 442.954C388.289 443.022 379.787 442.264 371.47 440.694C330.021 432.603 321.648 405.483 265.996 405.483C236.015 405.483 219.781 413.352 204.679 421.877C186.843 431.947 170.608 442.954 135.183 442.954C126.654 443.024 118.143 442.266 109.817 440.694C68.3677 432.591 60.0779 405.472 4.3706 405.472C3.24687 405.472 2.14157 405.472 1.05469 405.472" stroke="#F3F0E9" stroke-miterlimit="10"/>
<path d="M691.87 419.98C663.671 421.947 649.039 431.69 633.082 440.683C617.994 449.219 601.746 457.076 571.779 457.076C516.127 457.076 507.823 429.957 466.305 421.865C457.987 420.299 449.486 419.545 440.966 419.617C405.541 419.617 389.307 430.612 371.47 440.694C356.369 449.231 340.134 457.088 310.153 457.088C254.501 457.088 246.197 429.968 204.679 421.877C196.362 420.307 187.861 419.549 179.34 419.617C143.915 419.617 127.681 430.612 109.844 440.694C94.7431 449.231 78.5089 457.088 48.5275 457.088C27.3057 457.088 12.9643 453.142 1.05469 447.814" stroke="#F3F0E9" stroke-miterlimit="10"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 14 KiB

+654
View File
@@ -0,0 +1,654 @@
<template>
<div class="w-full flex flex-col">
<img :src="config.config.avatar" alt="" class="z-100 rounded-full aspect-square self-center w-42 " STYLE="margin-bottom: 60px">
<!-- <div class="font-bold text-center text-xl">{{ URLUserType() === 'single' ? 'ورود' : 'ورود همکار' }}</div>-->
<!-- <div v-if="URLUserType() === 'single'" class="font-bold text-center text-xl">ورود</div>-->
<!-- <div v-else class="font-bold text-center text-xl">ورود همکار</div>-->
<a-form ref="formRef" :model="userFormState" class="!mt-5" name="basic" @finish="phoneVerification">
<!-- <a-segmented v-model:value="value" :options="data" />-->
<div class="flex justify-evenly w-full px-2 h-11 items-center bg-gray-50 relative rounded mb-5">
<div :class="isSMS?'text-primary':'text-gray-400'" class="w-full text-center z-2"
@click.stop="setIsSMS(true) ">
ورود با پیامک
</div>
<div :class="!isSMS?'text-primary':'text-gray-400'" class="w-full text-center z-2"
@click.stop="setIsSMS(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>
<!-- <transition name="fade" mode="out-in">-->
<a-form-item v-if="!stepTwoVerify" :rules="[required('شماره تلفن'),mobileValidation()]"
class="home_appear_fade_in_down" label="شماره تلفن"
name="mobile">
<BasicInput v-model:value="userFormState.mobile" place-holder="شماره تلفن" size="large" inputmode="decimal"/>
</a-form-item>
<!-- </transition>-->
<!-- <transition name="fade" mode="out-in">-->
<a-form-item v-if="!isSMS" :rules="[required('کلمه عبور')]" class="home_appear_fade_in_down" label="کلمه عبور"
name="password">
<!-- <BasicInput v-model:value="userFormState.password" size="large" place-holder="کلمه عبور"/>-->
<AInputPassword v-model:value="userFormState.password" place-holder="کلمه عبور" size="large"/>
</a-form-item>
<div v-else-if="!stepTwoVerify" class="h-[90px]"></div>
<div v-else>
<AFormItem
:rules="[
{
required: true,
message: 'کد ارسال شده را وارد نمایید',
},
{
min: 4,
max: 4,
message: 'کد ارسال شده را وارد نمایید',
},
]"
class="error-token"
name="token"
>
<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-change="handleOnChange"
@on-complete="handleOnComplete"
/>
</AFormItem>
<div class="flex items-center my-[23px] justify-center">
<span class="text-gray-400 mt-1">{{ userFormState.mobile }}</span>
<div class="flex items-center text-gray-700 mr-2" @click="stepTwoVerify = false">
<span class="ml-1">ویرایش شماره</span>
<BasicIcon icon="vuesax-linear:edit" size="20" />
</div>
</div>
<div class="mb-2 w-full">
<AButton :disabled="!enableSendAgainCode" class="w-full" type="dashed" @click="reSendCode">
<div v-if="!enableSendAgainCode" class="flex w-full justify-center">
<span>ارسال مجدد کد در </span>
<span class="text-primary mx-1">{{ time }}</span>
<span> دیگر </span>
</div>
<div v-else>
ارسال مجدد کد تایید
</div>
</AButton>
</div>
</div>
<!-- </transition>-->
<a-form-item>
<!-- <div class="flex text-gray-600 text-xs my-2">با ورود یا ثبت نام
<div class="mx-1 font-bold">شرایط و قوانین</div>
را میپذیرم
</div>-->
<BasicButton
:disabled="loading"
class=" w-full py-2"
html-type="submit"
type="primary"
>
<div>
<a-spin v-if="loading" size="small" />
<div v-else>{{ !isSMS ? 'ورود' : stepTwoVerify ? 'ورود' : 'ارسال کد' }}</div>
</div>
</BasicButton>
<BasicButton
v-if="getToken() && userStore.userInfo?.finger_print"
:disabled="loading"
class=" w-full py-2 mt-2"
@click="enterFingerPrint"
>
<div>
ورود با اثر انگشت
</div>
</BasicButton>
<div class="flex gap-1 justify-center mt-5 text-xs" @click="$emit('register',true)">اگر حساب کاربری ندارید
<div class="font-bold text-[#0A1B37]">از این قسمت</div>
ثبت نام کنید.
</div>
</a-form-item>
</a-form>
<!-- <div v-if="URLUserType() === 'single'" class="fixed bottom-5 left-0 right-0 text-center">
<a class="w-full text-center"
href="https://abshode.peransagold.com/">ورود
همکار</a>
</div>-->
</div>
</template>
<script lang="ts" setup>
import { mobileValidation, required } from '@/utils/inputRules'
// import type {UserMobile} from "@/models/login";
import BasicInput from '@/components/BasicPacks/BasicInput.vue'
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
import { authenticateWithFingerprint, getToken, loading, removeToken, setToken, URLUserType } from '@/utils'
import { reactive, ref } from 'vue'
import OtpInput from 'vue3-otp-input'
import type { Login } from '@/models/login'
import type { FormInstance } from 'ant-design-vue'
import { message } from 'ant-design-vue'
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
import useCountdownTimer from '@/utils/useCountdownTimer'
import { loginCustomer, verifyToken } from '@/api/login'
import router from '@/router'
import { useUserStore } from '@/store/userStore'
import { useWalletStore } from '@/store/walletStore'
import logo from '@/assets/img/logo.png'
import { fingerPosition, setTruth } from '@/main'
import {useConfigStore} from "@/store/configStore";
const { time, onFinish, reset } = useCountdownTimer('00:02:00', 'mm:ss')
const enableSendAgainCode = ref<boolean>(false)
const stepTwoVerify = ref<boolean>(false)
const formRef = ref<FormInstance>()
const config=useConfigStore()
const userStore = useUserStore()
const walletStore = useWalletStore()
const data = reactive(['ورود با پیامک', 'ورود با کلمه عبور'])
const value = ref(data[0])
const refOtpInput = ref<InstanceType<typeof OtpInput> | null>(null)
const userFormState = reactive<Login>({
provider: 'customer'
})
//time
onFinish(() => {
enableSendAgainCode.value = true
})
async function reSendCode() {
userFormState.token = undefined
// refOtpInput.value?.clearInput()
enableSendAgainCode.value = false
await loginCustomer(userFormState)
reset()
}
const isSMS = ref<boolean>(true)
function setIsSMS(val: boolean) {
isSMS.value = val
if (!val) stepTwoVerify.value = false
userFormState.token = ''
userFormState.password = ''
// 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.
}
async function enterFingerPrint() {
const fingerPrint = await authenticateWithFingerprint()
if (fingerPrint) {
setTruth()
await router.push({ name: 'home' })
} else {
message.error('خطا در اعتبارسنجی')
}
}
function useStyle() {
if (isSMS.value) return 'right: 2%;'
// if (isDeposit.value) return 'animation-direction: normal'
// else return 'animation-direction: reverse'
else return ' right: 98%; transform: translate(100%, 0);'
}
function handleOnChange(value: string) {
userFormState.token = value
// formRef.value?.validateFields()
}
async function handleOnComplete(value: string) {
userFormState.token = value
phoneVerification()
}
async function login(accessToken: string | undefined) {
setToken(accessToken)
await userStore.getMyInfo()
// console.log(URLUserType())
// console.log(userStore.userInfo?.type)
/* if (userStore.userInfo?.type === (URLUserType() === 'customer' ? 1 : 2)) {*/
await walletStore.getMyWallet()
setTruth()
await router.push({ name: 'home' })
/* } else {
removeToken()
userStore.removeInformation()
message.error('شما مجوز ورود به این بخش را ندارید')
}*/
}
function phoneVerification() {
formRef.value?.validateFields().then(async () => {
try {
loading.value = true
if (isSMS.value) {
if (!stepTwoVerify.value) {
userFormState.token = undefined
userFormState.password = undefined
userFormState.provider = 'customer'
const { id } = await loginCustomer(userFormState)
userFormState.id = id
stepTwoVerify.value = true
getcode()
reset()
} else {
const { access_token } = await verifyToken(userFormState)
await login(access_token)
}
} else {
userFormState.token = undefined
const { access_token } = await loginCustomer(userFormState)
await login(access_token)
}
} catch (e) {
console.log(e)
} finally {
loading.value = false
}
})
}
const getcode=()=>{
if ('OTPCredential' in window) {
console.log('run')
const ac = new AbortController();
navigator.credentials
.get({
otp: { transport: ['sms'] },
signal: ac.signal,
})
.then((otp) => {
console.log('otp recived');
userFormState.token = otp?.code;
refOtpInput.value.fillInput(otp?.code)
phoneVerification();
ac.abort();
})
.catch((err) => {
ac.abort();
console.log(err);
});
} else {
console.log('not supported');
}
}
</script>
<style lang="less">
.animate.right {
right: 0;
}
.animate.right.move {
right: 100%;
transform: translate(100%, 0);
}
</style>
<!--
<template>
<div class="w-full flex flex-col">
<img :src="logo" alt="" class="z-100 w-full aspect-square self-center h-20">
<img :src="logoFull" alt="" class="z-100 w-50 aspect-square self-center mb-5 h-10">
&lt;!&ndash; <div class="font-bold text-center text-xl">{{ URLUserType() === 'single' ? 'ورود' : 'ورود همکار' }}</div>&ndash;&gt;
&lt;!&ndash; <div v-if="URLUserType() === 'single'" class="font-bold text-center text-xl">ورود</div>&ndash;&gt;
&lt;!&ndash; <div v-else class="font-bold text-center text-xl">ورود همکار</div>&ndash;&gt;
<a-form ref="formRef" :model="userFormState" class="!mt-5" name="basic" @finish="phoneVerification">
&lt;!&ndash; <a-segmented v-model:value="value" :options="data" />&ndash;&gt;
<div class="flex justify-evenly w-full px-2 h-11 items-center bg-gray-50 relative rounded mb-5">
<div :class="isSMS?'text-primary':'text-gray-400'" class="w-full text-center z-2"
@click.stop="setIsSMS(true) ">
ورود با پیامک
</div>
<div :class="!isSMS?'text-primary':'text-gray-400'" class="w-full text-center z-2"
@click.stop="setIsSMS(false) ">
ورود با کلمه عبور
</div>
&lt;!&ndash; <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>&ndash;&gt;
<div ref="bganim" :style="useStyle()"
class="absolute bg-white h-8 w-1/2 rounded-lg animate right"></div>
</div>
&lt;!&ndash; <transition name="fade" mode="out-in">&ndash;&gt;
<a-form-item v-if="!stepTwoVerify" :rules="[required('شماره تلفن'),mobileValidation()]"
class="home_appear_fade_in_down" label="شماره تلفن"
name="mobile">
<BasicInput v-model:value="userFormState.mobile" place-holder="شماره تلفن" size="large" type="number" />
</a-form-item>
&lt;!&ndash; </transition>&ndash;&gt;
&lt;!&ndash; <transition name="fade" mode="out-in">&ndash;&gt;
<a-form-item v-if="!isSMS" :rules="[required('کلمه عبور')]" class="home_appear_fade_in_down" label="کلمه عبور"
name="password">
&lt;!&ndash; <BasicInput v-model:value="userFormState.password" size="large" place-holder="کلمه عبور"/>&ndash;&gt;
<AInputPassword v-model:value="userFormState.password" place-holder="کلمه عبور" size="large" />
</a-form-item>
<div v-else-if="!stepTwoVerify" class="h-[90px]"></div>
<div v-else>
<AFormItem
:rules="[
{
required: true,
message: 'کد ارسال شده را وارد نمایید',
},
{
min: 4,
max: 4,
message: 'کد ارسال شده را وارد نمایید',
},
]"
class="error-token"
name="token"
>
<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-change="handleOnChange"
@on-complete="handleOnComplete"
/>
</AFormItem>
<div class="flex items-center my-[23px] justify-center">
<span class="text-gray-400 mt-1">{{ userFormState.mobile }}</span>
<div class="flex items-center text-gray-700 mr-2" @click="stepTwoVerify = false">
<span class="ml-1">ویرایش شماره</span>
<BasicIcon icon="vuesax-linear:edit" size="20" />
</div>
</div>
<div class="mb-2 w-full">
<AButton :disabled="!enableSendAgainCode" class="w-full" type="dashed" @click="reSendCode">
<div v-if="!enableSendAgainCode" class="flex w-full justify-center">
<span>ارسال مجدد کد در </span>
<span class="text-primary mx-1">{{ time }}</span>
<span> دیگر </span>
</div>
<div v-else>
ارسال مجدد کد تایید
</div>
</AButton>
</div>
</div>
&lt;!&ndash; </transition>&ndash;&gt;
<a-form-item>
&lt;!&ndash; <div class="flex text-gray-600 text-xs my-2">با ورود یا ثبت نام
<div class="mx-1 font-bold">شرایط و قوانین</div>
را میپذیرم
</div>&ndash;&gt;
<BasicButton
:disabled="loading"
class=" w-full py-2"
html-type="submit"
type="primary"
>
<div>
<a-spin v-if="loading" size="small" />
<div v-else>{{ !isSMS ? 'ورود' : stepTwoVerify ? 'ورود' : 'ارسال کد' }}</div>
</div>
</BasicButton>
<BasicButton
v-if="getToken() && userStore.userInfo?.finger_print"
:disabled="loading"
class=" w-full py-2 mt-2"
@click="enterFingerPrint"
>
<div>
ورود با اثر انگشت
</div>
</BasicButton>
<div class="flex gap-1 justify-center mt-5 text-xs" @click="$emit('register',true)">اگر حساب کاربری ندارید
<div class="font-bold text-[#0A1B37]">از این قسمت</div>
ثبت نام کنید.
</div>
</a-form-item>
</a-form>
&lt;!&ndash; <div v-if="URLUserType() === 'single'" class="fixed bottom-5 left-0 right-0 text-center">
<a class="w-full text-center"
href="https://abshode.peransagold.com/">ورود
همکار</a>
</div>&ndash;&gt;
</div>
</template>
<script lang="ts" setup>
import { mobileValidation, required } from '@/utils/inputRules'
// import type {UserMobile} from "@/models/login";
import BasicInput from '@/components/BasicPacks/BasicInput.vue'
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
import {
authenticateWithFingerprint,
getToken,
loading,
removeToken,
setFingerPrint,
setToken,
URLUserType
} from '@/utils'
import { onMounted, reactive, ref } from 'vue'
import OtpInput from 'vue3-otp-input'
import type { Login } from '@/models/login'
import type { FormInstance } from 'ant-design-vue'
import { message } from 'ant-design-vue'
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
import useCountdownTimer from '@/utils/useCountdownTimer'
import { loginCustomer, verifyToken } from '@/api/login'
import router from '@/router'
import { useUserStore } from '@/store/userStore'
import { useWalletStore } from '@/store/walletStore'
import logo from '@/assets/img/logo.svg'
import { fingerPosition, setFingerPosition, setFingerTimeOut, setTruth } from '@/main'
const { time, onFinish, reset } = useCountdownTimer('00:02:00', 'mm:ss')
const enableSendAgainCode = ref<boolean>(false)
const stepTwoVerify = ref<boolean>(false)
const formRef = ref<FormInstance>()
const userStore = useUserStore()
const walletStore = useWalletStore()
const data = reactive(['ورود با پیامک', 'ورود با کلمه عبور'])
const value = ref(data[0])
const refOtpInput = ref<InstanceType<typeof VOtpInput> | null>(null)
const userFormState = reactive<Login>({
provider: 'customer'
})
//time
onFinish(() => {
enableSendAgainCode.value = true
})
const isAuthenticated = ref(false);
onMounted(async () => {
if (getToken()) {
const result = await authenticateWithFingerprint();
setFingerPosition(result)
if (result) {
isAuthenticated.value = true;
await router.push({ name: 'home' }); // Redirect to home on successful authentication
} else {
isAuthenticated.value = false;
// Handle failed authentication
}
}
});
async function reSendCode() {
userFormState.token = undefined
// refOtpInput.value?.clearInput()
enableSendAgainCode.value = false
await loginCustomer(userFormState)
reset()
}
const isSMS = ref<boolean>(true)
function setIsSMS(val: boolean) {
isSMS.value = val
if (!val) stepTwoVerify.value = false
userFormState.token = ''
userFormState.password = ''
// 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.
}
async function enterFingerPrint() {
const fingerPrint = await authenticateWithFingerprint()
if (fingerPrint) {
setTruth()
await router.push({ name: 'home' })
} else {
message.error('خطا در اعتبارسنجی')
}
}
function useStyle() {
if (isSMS.value) return 'right: 2%;'
// if (isDeposit.value) return 'animation-direction: normal'
// else return 'animation-direction: reverse'
else return ' right: 98%; transform: translate(100%, 0);'
}
function handleOnChange(value: string) {
userFormState.token = value
// formRef.value?.validateFields()
}
async function handleOnComplete(value: string) {
userFormState.token = value
phoneVerification()
}
async function login(accessToken: string | undefined) {
setToken(accessToken)
setFingerTimeOut(router.currentRoute.value)
await userStore.getMyInfo()
// console.log(URLUserType())
// console.log(userStore.userInfo?.type)
/* if (userStore.userInfo?.type === (URLUserType() === 'customer' ? 1 : 2)) {*/
await walletStore.getMyWallet()
setTruth()
await router.push({ name: 'home' })
/* } else {
removeToken()
userStore.removeInformation()
message.error('شما مجوز ورود به این بخش را ندارید')
}*/
}
function phoneVerification() {
formRef.value?.validateFields().then(async () => {
try {
loading.value = true
if (isSMS.value) {
if (!stepTwoVerify.value) {
userFormState.token = undefined
userFormState.password = undefined
userFormState.provider = 'customer'
const { id } = await loginCustomer(userFormState)
userFormState.id = id
stepTwoVerify.value = true
getcode()
reset()
} else {
const { access_token } = await verifyToken(userFormState)
await login(access_token)
}
} else {
userFormState.token = undefined
const { access_token } = await loginCustomer(userFormState)
await login(access_token)
}
} catch (e) {
console.log(e)
} finally {
loading.value = false
}
})
}
const getcode=()=>{
if ('OTPCredential' in window) {
console.log('run')
const ac = new AbortController();
navigator.credentials
.get({
otp: { transport: ['sms'] },
signal: ac.signal,
})
.then((otp) => {
console.log('otp recived');
userFormState.token = otp?.code;
refOtpInput.value.fillInput(otp?.code)
phoneVerification();
ac.abort();
})
.catch((err) => {
ac.abort();
console.log(err);
});
} else {
console.log('not supported');
}
}
</script>
<style lang="less">
.animate.right {
right: 0;
}
.animate.right.move {
right: 100%;
transform: translate(100%, 0);
}
</style>-->
@@ -0,0 +1,54 @@
<template>
<div class="w-full p-8">
<div class="font-bold text-center text-xl">ورود / ثبت نام</div>
<a-form :model="userFormState" name="basic" @finish="phoneVerification" class="!mt-5">
<a-form-item label="شماره تلفن همراه" name="mobile" :rules="[lengthValidation(11),required]">
<BasicInput v-model:value="userFormState.mobile" type="tel" size="large" place-holder="شماره تلفن همراه"/>
<div class="text-xs mt-1 text-gray-400">مالکیت شماره باید به نام خودتان باشد</div>
</a-form-item>
<a-form-item>
<!-- <div class="flex text-gray-600 text-xs my-2">با ورود یا ثبت نام
<div class="mx-1 font-bold">شرایط و قوانین</div>
را میپذیرم
</div>-->
<BasicButton
class=" w-full py-2"
:disabled="loading"
type="primary"
html-type="submit"
>
<div>
<a-spin v-if="loading" size="small"/>
<div v-else>ادامه</div>
</div>
</BasicButton>
</a-form-item>
</a-form>
</div>
</template>
<script setup lang="ts">
import {lengthValidation, required} from "@/utils/inputRules";
import type {UserMobile} from "@/models/login";
import BasicInput from "@/components/BasicPacks/BasicInput.vue";
import BasicButton from "@/components/BasicPacks/BasicButton.vue";
import {loading} from "@/utils";
import {ref} from "vue";
import router from "@/router";
const userFormState = ref<UserMobile>({
mobile: '',
})
function phoneVerification() {
router.push({name: 'home' })
}
</script>
<style scoped>
</style>
+198
View File
@@ -0,0 +1,198 @@
<template>
<div class="w-full flex flex-col">
<img :src="config.config.avatar" alt="" class="z-100 rounded-full aspect-square self-center w-42 " STYLE="">
<div class="font-bold text-center text-xl">ثبت نام</div>
<a-form ref="formRef" :model="userFormState" class="!mt-5" name="basic"
@finish="registerAccount">
<a-form-item :rules="[required()]" class="home_appear_fade_in_down" label="نام" name="fname">
<BasicInput v-model:value="userFormState.fname" place-holder="نام" />
</a-form-item>
<a-form-item :rules="[required()]" class="home_appear_fade_in_down" label="نام خانوادگی" name="lname">
<BasicInput v-model:value="userFormState.lname" place-holder="نام خانوادگی" />
</a-form-item>
<a-form-item :rules="[required(),mobileValidation()]" class="home_appear_fade_in_down" label="شماره تلفن"
name="mobile">
<BasicInput v-model:value="userFormState.mobile" place-holder="شماره تلفن" inputmode="decimal"/>
</a-form-item>
<a-form-item :rules="[required()]" class="home_appear_fade_in_down" label="کلمه عبور" name="password">
<!-- <BasicInput v-model:value="userFormState.password" size="large" place-holder="کلمه عبور"/>-->
<AInputPassword v-model:value="userFormState.password" place-holder="کلمه عبور" />
</a-form-item>
<a-form-item :rules="[required()]" class="home_appear_fade_in_down" label="کد معرف" name="referral_id">
<BasicInput :disabled="disableForm" v-model:value="userFormState.referral_id" place-holder="کد معرف"/>
</a-form-item>
<!-- <a-form-item v-if="URLUserType() === 'customer'" :rules="[required()]" class="home_appear_fade_in_down"
label="نام فروشگاه" name="shop_name">
<BasicInput v-model:value="userFormState.shop_name" place-holder="نام فروشگاه"/>
</a-form-item>-->
<a-form-item>
<BasicButton
:disabled="loading"
class=" w-full py-2 mt-4"
html-type="submit"
type="primary"
>
<div>
<a-spin v-if="loading" size="small" />
<div v-else>ثبت نام</div>
</div>
</BasicButton>
<div class="flex gap-1 justify-center mt-5 text-xs" @click="$emit('register',false)">اگر حساب کاربری دارید
<div class="font-bold text-[#0A1B37]">از این قسمت</div>
وارد شوید.
</div>
</a-form-item>
</a-form>
<DialogVantOneButton v-model:show="registeredInfo" :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-center text-sm">
ثبت نام شما با موفقیت انجام شد. پس از تایید ادمین، شما میتوانید با اطلاعات خود، وارد اپلیکیشن شوید.
</div>
</template>
<template v-slot:button>
<div class="text-center" @click="$emit('register',false)">
متوجه شدم
</div>
</template>
</DialogVantOneButton>
<!-- <van-dialog/>-->
<!--
<div v-else>
<AFormItem
class="error-token"
:rules="[
{
required: true,
message: 'کد ارسال شده را وارد نمایید',
},
{
min: 4,
max: 4,
message: 'کد ارسال شده را وارد نمایید',
},
]"
name="token"
>
<OtpInput
style="direction: ltr"
class="mt-5 justify-center"
ref="refOtpInput"
autocomplete="one-time-code"
input-classes="otp-input"
separator=""
value=""
:num-inputs="4"
:should-auto-focus="true"
:is-input-num="true"
@on-change="handleOnChange"
@on-complete="handleOnComplete"
/>
</AFormItem>
<div class="flex items-center my-[23px] justify-center">
<span class="text-gray-400 mt-1">{{ userFormState.mobile }}</span>
<div class="flex items-center text-gray-700 mr-2" @click="stepTwoVerify = false">
<span class="ml-1">ویرایش شماره</span>
<BasicIcon icon="vuesax-linear:edit" size="20"/>
</div>
</div>
<div class="mb-2 w-full">
<AButton type="dashed" class="w-full" @click="reSendCode"> ارسال مجدد کد تایید</AButton>
</div>
</div>
-->
</div>
</template>
<script lang="ts" setup>
import { mobileValidation, required } from '@/utils/inputRules'
import type { User } from '@/models/login'
import BasicInput from '@/components/BasicPacks/BasicInput.vue'
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
import { loading, URLUserType } from '@/utils'
import { onMounted, reactive, ref } from 'vue'
import type { FormInstance } from 'ant-design-vue'
import { message } from 'ant-design-vue'
import registerDelayImage from '@/assets/img/registerDelay.svg'
import DialogVantOneButton from '@/components/DialogVantOneButton.vue'
import { registerCustomer } from '@/api/login'
import router from '@/router'
import logo from "@/assets/img/logo.png";
// const stepTwoVerify = ref<boolean>(false)
const registeredInfo = ref<boolean>(false)
const userFormState = reactive<User>({
access_token: ''
})
const formRef = ref<FormInstance>()
const disableForm=ref(false)
/*function handleOnChange(value: string) {
userFormState.token = value
// formRef.value?.validateFields()
}
async function handleOnComplete(value: string) {
userFormState.token = value
registerAccount()
}*/
onMounted(() => {
if (router.currentRoute.value.query.id){
userFormState.referral_id = router.currentRoute.value.query.id
disableForm.value=true
}
})
function registerAccount() {
// console.log('test')
formRef.value?.validateFields().then(async () => {
try {
// console.log('test',stepTwoVerify.value)
loading.value = true
// if (!stepTwoVerify.value) {
URLUserType() === 'single' ? userFormState.type = 2 : userFormState.type = 1
// console.log(userFormState)
if (!userFormState.referral_id || userFormState.referral_id === '') delete userFormState.referral_id
const { id } = await registerCustomer(userFormState)
registeredInfo.value = true
// console.log(registeredInfo.value)
// userFormState.id = id
// stepTwoVerify.value = true
// } else {
// userFormState.mobile = undefined
// userFormState.password = undefined
// userFormState.fname = undefined
// userFormState.lname = undefined
// userFormState.shop_name = undefined
// await verifyToken(userFormState)
// }
} catch (e) {
console.log(e)
if (e.response?.status === 422) {
// message.error('این شماره همراه قبلا ثبت نام کرده است')
}
} finally {
loading.value = false
}
})
}
</script>
<style scoped>
</style>
+48
View File
@@ -0,0 +1,48 @@
<template>
<div class="flex items-center h-[92vh] justify-center ">
<!-- <PhoneVerify/>-->
<div class="fixed top-0 right-0 left-0 h-1/3 w-screen flex">
<img :src="img_topGradiant" alt="" class="absolute z-10 w-screen h-full object-cover">
<img :src="img_pattern" alt="" class="absolute w-screen h-full object-none">
</div>
<div class="fixed bottom-0 right-0 left-0 h-1/3 w-screen">
<img :src="img_bottomGradiant" alt="" class="absolute z-10 w-screen h-full object-cover">
<img :src="img_pattern" alt="" class="absolute w-screen h-full object-none">
</div>
<div class="z-1000 w-full p-5">
<transition mode="out-in" name="fade">
<Login v-if="!enterType" @register="setEnterType"/>
<Register v-else @register="setEnterType"/>
</transition>
</div>
</div>
</template>
<script lang="ts" setup>
import Login from "@/views/login/components/Login.vue";
import Register from "@/views/login/components/Register.vue";
import { onMounted, ref } from 'vue'
import img_topGradiant from './assets/img/gr_top_white.svg'
import img_bottomGradiant from './assets/img/gr_bottom_white.svg'
import img_pattern from './assets/img/pattern.svg'
import router from '@/router'
const enterType = ref<boolean>(false)
function setEnterType(val: boolean) {
enterType.value = val
}
onMounted(() => {
if (router.currentRoute.value.query.id)
enterType.value = true
})
</script>
<style>
</style>