Merge remote-tracking branch 'origin/modular' into modular
This commit is contained in:
Vendored
+5
@@ -14,12 +14,16 @@ declare module 'vue' {
|
||||
AInput: typeof import('ant-design-vue/es')['Input']
|
||||
AInputPassword: typeof import('ant-design-vue/es')['InputPassword']
|
||||
AModal: typeof import('ant-design-vue/es')['Modal']
|
||||
ARadio: typeof import('ant-design-vue/es')['Radio']
|
||||
ARadioButton: typeof import('ant-design-vue/es')['RadioButton']
|
||||
ARadioGroup: typeof import('ant-design-vue/es')['RadioGroup']
|
||||
ASelect: typeof import('ant-design-vue/es')['Select']
|
||||
ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
|
||||
ASlider: typeof import('ant-design-vue/es')['Slider']
|
||||
ASpin: typeof import('ant-design-vue/es')['Spin']
|
||||
ASwitch: typeof import('ant-design-vue/es')['Switch']
|
||||
ATag: typeof import('ant-design-vue/es')['Tag']
|
||||
ATextarea: typeof import('ant-design-vue/es')['Textarea']
|
||||
ATooltip: typeof import('ant-design-vue/es')['Tooltip']
|
||||
BaseDatePicker: typeof import('./src/components/BasicPacks/BaseDatePicker/src/BaseDatePicker.vue')['default']
|
||||
Basic: typeof import('./src/components/BasicPacks/BaseDatePicker/src/datePick/demo/basic.vue')['default']
|
||||
@@ -63,5 +67,6 @@ declare module 'vue' {
|
||||
TransactionSkeleton: typeof import('./src/components/TransactionSkeleton.vue')['default']
|
||||
VanActionSheet: typeof import('vant/es')['ActionSheet']
|
||||
VanDialog: typeof import('vant/es')['Dialog']
|
||||
VanField: typeof import('vant/es')['Field']
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<div
|
||||
class="text-center w-full flex-flex-col items-center home_appear_fade_in_up"
|
||||
style="text-align: -webkit-center"
|
||||
@click="$emit('click')"
|
||||
>
|
||||
<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="action.icon" />
|
||||
</div>
|
||||
<div class="text-primary">{{ action.label }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
defineProps<{
|
||||
action: {
|
||||
name: string
|
||||
icon: string
|
||||
label: string
|
||||
handler: () => void
|
||||
}
|
||||
}>()
|
||||
|
||||
defineEmits<{
|
||||
click: []
|
||||
}>()
|
||||
</script>
|
||||
@@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<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' })">
|
||||
<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="$emit('logout')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useWindowScroll } from '@vueuse/core'
|
||||
import { useUserStore } from '@/store/userStore'
|
||||
import router from '@/router'
|
||||
import Icon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
const { y } = useWindowScroll()
|
||||
const userStore = useUserStore()
|
||||
|
||||
defineEmits<{
|
||||
logout: []
|
||||
}>()
|
||||
</script>
|
||||
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<div class="flex gap-1">
|
||||
<div>{{ label }}</div>
|
||||
<div class="font-bold">{{ value }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
label: string
|
||||
value: string
|
||||
}>()
|
||||
</script>
|
||||
@@ -0,0 +1,31 @@
|
||||
<template>
|
||||
<div class="bg-primary rounded-lg p-2 py-3 mt-2">
|
||||
<div class="flex justify-center text-tertiary w-full z-20">
|
||||
محصولات:
|
||||
<div 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="$emit('openGoldModal')" icon="vuesax-linear:info-circle" size="18" color="tertiary" />
|
||||
</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="$emit('openRialModal')" icon="vuesax-linear:info-circle" size="18" color="tertiary" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useUserStore } from '@/store/userStore'
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import {usePriceWithoutType} from "../../../../utils/usePrice";
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
defineEmits<{
|
||||
openGoldModal: []
|
||||
openRialModal: []
|
||||
}>()
|
||||
</script>
|
||||
@@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<BasicActionSheet v-model:show="visible">
|
||||
<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="`در این قسمت مجموع کل وزن طلای آبشده (${(walletInfo?.gold ?? 0)?.toFixed(3)}) + ارزش دارایی ها (${(walletInfo?.treasure_sum ?? 0)?.toFixed(3)} ) را مشاهده میفرمایید.`"
|
||||
infoHead="مجموع کل دارایی طلایی"
|
||||
:value="parseFloat((walletInfo?.gold_sum ?? 0).toFixed(2)) + ' گرم'"
|
||||
/>
|
||||
<a-divider class="!my-1" />
|
||||
<BasicInfoItem
|
||||
class="flex justify-between"
|
||||
title="دارایی کیف پول ریالی"
|
||||
is-line
|
||||
:value="usePrice(walletInfo?.cash ?? 0)"
|
||||
/>
|
||||
<a-divider class="!my-1" />
|
||||
<BasicInfoItem
|
||||
class="flex justify-between"
|
||||
title="دارایی کیف پول طلایی"
|
||||
is-line
|
||||
:value="(walletInfo?.count_gold_wallet ?? 0) + ' گرم'"
|
||||
/>
|
||||
<a-divider v-if="nameProject === 'goldsun'" class="!my-1" />
|
||||
<BasicInfoItem
|
||||
v-if="nameProject === 'goldsun'"
|
||||
class="flex justify-between"
|
||||
title="دارایی کیف پول نقره"
|
||||
is-line
|
||||
:value="(walletInfo?.count_silver ?? 0) + ' گرم'"
|
||||
/>
|
||||
<a-divider v-if="nameProject === 'goldsun'" class="!my-1" />
|
||||
<BasicInfoItem
|
||||
v-if="nameProject === 'goldsun'"
|
||||
class="flex justify-between"
|
||||
title="دارایی کیف پول مس"
|
||||
is-line
|
||||
:value="(walletInfo?.count_copper ?? 0) + ' گرم'"
|
||||
/>
|
||||
<a-divider class="!my-1" />
|
||||
<BasicInfoItem
|
||||
class="flex justify-between"
|
||||
title="معادل ریالی مجموع دارایی ها"
|
||||
is-line
|
||||
:value="usePrice(walletInfo?.count_cash_total ?? 0)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</BasicActionSheet>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import BasicActionSheet from '@/components/BasicPacks/BasicActionSheet.vue'
|
||||
import BasicInfoItem from '@/components/BasicPacks/BasicInfoItem.vue'
|
||||
import { useConfigStore } from '@/store/configStore'
|
||||
import {usePrice} from "@/utils/usePrice";
|
||||
|
||||
const props = defineProps<{
|
||||
show: boolean
|
||||
walletInfo: any
|
||||
goldVal: number
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:show': [value: boolean]
|
||||
}>()
|
||||
|
||||
const config = useConfigStore()
|
||||
const nameProject = config.config.name
|
||||
|
||||
const visible = computed({
|
||||
get: () => props.show,
|
||||
set: (val) => emit('update:show', val)
|
||||
})
|
||||
</script>
|
||||
@@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<div class="w-full relative mt-2 flex flex-col justify-center home_appear_fade_in overflow-hidden rounded-lg">
|
||||
<div class="w-full aspect-[2.8/1] min-h-[10rem] max-h-[14rem]">
|
||||
<swiper
|
||||
:modules="bannerSwiperModules"
|
||||
:slides-per-view="1"
|
||||
:space-between="6"
|
||||
:autoplay="{ delay: 4000, disableOnInteraction: false }"
|
||||
:pagination="{ clickable: true }"
|
||||
class="banner-swiper h-full w-full rounded-lg"
|
||||
>
|
||||
<swiper-slide v-for="(banner, index) in banners" :key="index" class="!h-full">
|
||||
<img
|
||||
v-if="banner.show"
|
||||
class="banner-img w-full h-full object-cover rounded-lg block"
|
||||
:src="banner.icon"
|
||||
:alt="banner.caption || ''"
|
||||
:style="(banner.link || banner.typeClick === 'share') ? 'cursor: pointer;' : ''"
|
||||
@click="$emit('bannerClick', banner)"
|
||||
/>
|
||||
</swiper-slide>
|
||||
</swiper>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Swiper, SwiperSlide } from 'swiper/vue'
|
||||
import { Autoplay, Pagination } from 'swiper/modules'
|
||||
import 'swiper/swiper-bundle.css'
|
||||
import 'swiper/css/pagination'
|
||||
|
||||
const bannerSwiperModules = [Autoplay, Pagination]
|
||||
|
||||
defineProps<{
|
||||
banners: any[]
|
||||
}>()
|
||||
|
||||
defineEmits<{
|
||||
bannerClick: [banner: any]
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.banner-swiper {
|
||||
--swiper-pagination-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.banner-swiper .swiper-pagination-bullet {
|
||||
width: 0.5rem;
|
||||
height: 0.5rem;
|
||||
background: rgba(0, 0, 0, 0.35);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.banner-swiper .swiper-pagination-bullet-active {
|
||||
background: #fff;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,61 @@
|
||||
<template>
|
||||
<div class="w-full relative mt-2 border-gray-200 border-1 rounded-lg py-3 flex flex-col justify-center home_appear_fade_in">
|
||||
<div class="w-full items-center flex justify-center">
|
||||
<div class="text-gray-600 text-[12px] ml-2">قیمت خرید از {{ config.config.name_fa }}</div>
|
||||
<div v-if="price" class="flex gap-1 text-xs items-center">
|
||||
<div
|
||||
v-if="percentPriceChanged() !== 0"
|
||||
class="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
|
||||
:size="15"
|
||||
:icon="percentPriceChanged() < 0 ? 'vuesax-linear:received' : 'vuesax-linear:send'"
|
||||
:color="percentPriceChanged() < 0 ? 'red-600' : 'green-600'"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Vue3Odometer
|
||||
:value="displayGoldVal"
|
||||
class="o-text !text-xl font-bold"
|
||||
style="font-family: iran-sans; direction: ltr"
|
||||
/>
|
||||
ریال
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import { useConfigStore } from '@/store/configStore'
|
||||
import {lastPrice, percentPriceChanged, price} from '@/utils/price'
|
||||
import Vue3Odometer from 'vue3-odometer'
|
||||
import 'odometer/themes/odometer-theme-default.css'
|
||||
import {useTowDecimal} from "../../../../utils/usePrice";
|
||||
import {computed} from "vue";
|
||||
|
||||
|
||||
const config = useConfigStore()
|
||||
|
||||
// محاسبه درصد تغییرات به صورت reactive
|
||||
const percentChange = computed(() => {
|
||||
if (! lastPrice?.value?.price_last) return 0
|
||||
return percentPriceChanged()
|
||||
})
|
||||
|
||||
// بررسی بسته بودن بازار
|
||||
const isMarketClosed = computed(() => {
|
||||
return lastPrice?.value?.goldir === 0 && lastPrice?.value?.price_last === 0
|
||||
})
|
||||
|
||||
// مقدار نمایشی برای ادومتر (با مدیریت خطا)
|
||||
const displayGoldVal = computed(() => {
|
||||
if (isMarketClosed.value) return 0
|
||||
return lastPrice?.value?.price_last|| 0
|
||||
})
|
||||
|
||||
// انیمیشن fade-in
|
||||
</script>
|
||||
@@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<DialogVant v-model:show="visible" :closeOnClickOverlay="false" :timeOut="-1">
|
||||
<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="$emit('confirm')">
|
||||
<a-spin :spinning="false" size="small">خروج</a-spin>
|
||||
</div>
|
||||
<div class="text-center" @click="visible = false">انصراف</div>
|
||||
</template>
|
||||
</DialogVant>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import DialogVant from '@/components/DialogVant.vue'
|
||||
import { DotLottieVue } from '@lottiefiles/dotlottie-vue'
|
||||
import {computed} from "vue";
|
||||
|
||||
const props = defineProps<{
|
||||
show: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:show': [value: boolean]
|
||||
confirm: []
|
||||
}>()
|
||||
|
||||
const visible = computed({
|
||||
get: () => props.show,
|
||||
set: (val) => emit('update:show', val)
|
||||
})
|
||||
</script>
|
||||
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="message"
|
||||
class="bg-red-50 text-red-600 text-center font-500 py-4 px-2 mt-2 rounded-lg"
|
||||
v-html="message"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
message: string
|
||||
}>()
|
||||
</script>
|
||||
@@ -0,0 +1,104 @@
|
||||
<template>
|
||||
<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="selectedValue" button-style="solid">
|
||||
<a-radio-button value="DAILY" @click="handleUpdate('DAILY')">24 ساعت اخیر</a-radio-button>
|
||||
<a-radio-button value="WEEKLY" @click="handleUpdate('WEEKLY')">هفته گذشته</a-radio-button>
|
||||
<a-radio-button value="MONTHLY" @click="handleUpdate('MONTHLY')">ماه گذشته</a-radio-button>
|
||||
</a-radio-group>
|
||||
<div id="chart-timeline">
|
||||
<apexchart
|
||||
type="area"
|
||||
height="200"
|
||||
:options="chartOptions"
|
||||
:series="props.priceChartSeries"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import { useConfigStore } from '@/store/configStore'
|
||||
import {usePrice} from "@/utils/usePrice";
|
||||
|
||||
const props = defineProps<{
|
||||
priceChartSeries: any[]
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
updateData: [timeline: string]
|
||||
}>()
|
||||
|
||||
const config = useConfigStore()
|
||||
const selectedValue = ref('DAILY')
|
||||
|
||||
const toPersianNumber = (num: number) => {
|
||||
return num.toString().replace(/\d/g, (d) => '۰۱۲۳۴۵۶۷۸۹'[d])
|
||||
}
|
||||
|
||||
const chartOptions = computed(() => ({
|
||||
chart: {
|
||||
id: 'نوسانات قیمت',
|
||||
type: 'area',
|
||||
height: 200,
|
||||
toolbar: { show: false },
|
||||
zoom: { autoScaleYaxis: true }
|
||||
},
|
||||
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,
|
||||
labels: {
|
||||
formatter: (val: number) => toPersianNumber(usePrice(val)),
|
||||
style: { fontSize: '13px', fontFamily: "'IranSans', sans-serif" }
|
||||
}
|
||||
},
|
||||
xaxis: {
|
||||
show: false,
|
||||
type: 'datetime',
|
||||
axisTicks: { show: false },
|
||||
tooltip: { enabled: false },
|
||||
labels: { show: false }
|
||||
},
|
||||
tooltip: {
|
||||
x: {
|
||||
formatter: (value: number) => {
|
||||
const date = new Date(value)
|
||||
return `${date.toLocaleDateString('fa-IR')} - ${date.toLocaleTimeString('fa-IR', {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
})}`
|
||||
}
|
||||
},
|
||||
formatter: (val: number) => toPersianNumber(usePrice(val)),
|
||||
style: { fontFamily: "'IranSans', sans-serif" }
|
||||
},
|
||||
colors: [config.config.color],
|
||||
fill: {
|
||||
type: 'gradient',
|
||||
gradient: {
|
||||
shadeIntensity: 1,
|
||||
opacityFrom: 0.7,
|
||||
opacityTo: 0.9,
|
||||
stops: [0, 100]
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
const handleUpdate = (timeline: string) => {
|
||||
emit('updateData', timeline)
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,34 @@
|
||||
<template>
|
||||
<div class="w-full flex justify-evenly rounded-lg py-2 home_appear_fade_in mt-6 pb-45">
|
||||
<div class="text-center w-full">
|
||||
<div>بالاترین قیمت امروز</div>
|
||||
<div v-if="price" 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="price" 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>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
import {usePriceWithoutType} from "../../../../utils/usePrice";
|
||||
|
||||
defineProps<{
|
||||
price: any
|
||||
}>()
|
||||
</script>
|
||||
@@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<div class="bg-primary rounded-lg p-2 py-1 mt-2">
|
||||
<div class="p-2">
|
||||
<div
|
||||
v-if="userStore.userInfo?.referral_id"
|
||||
class="text-tertiary 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>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-full flex gap-2 mt-1">
|
||||
<BasicButton
|
||||
icon="vuesax-linear:share"
|
||||
size="small"
|
||||
class="flex-1 !bg-primary !border-tertiary !text-tertiary"
|
||||
icon-size="18"
|
||||
@click.stop="shareCode"
|
||||
>
|
||||
دعوت از دوستان
|
||||
</BasicButton>
|
||||
<BasicButton
|
||||
icon="vuesax-linear:copy"
|
||||
size="small"
|
||||
class="flex-1 !bg-primary !border-tertiary !text-tertiary"
|
||||
icon-size="18"
|
||||
@click.stop="copyCode"
|
||||
>
|
||||
رونوشت
|
||||
</BasicButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useUserStore } from '@/store/userStore'
|
||||
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
|
||||
import { message } from 'ant-design-vue'
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
const shareCode = () => {
|
||||
const text = `⭐️الان طلا بخر؛ آخر ماه سودشو ببر!
|
||||
با خرید طلای آبشده در مقدارهای کم ولی مستمر، سود بیشتری ببر!
|
||||
|
||||
این دعوت نامه از طرف "${userStore.userInfo?.name}" عزیز برای شما ارسال شده تا شما هم از بازار طلا جا نمونید.
|
||||
روی لینک زیر کلیک کنید و ثبت نام خود را تکمیل کنید.
|
||||
|
||||
${window.location.hostname}/login?id=${userStore.userInfo?.referral_id}`
|
||||
|
||||
navigator.share({ title: 'طلا', text })
|
||||
}
|
||||
|
||||
const copyCode = () => {
|
||||
const code = userStore.userInfo?.referral_id
|
||||
if (code) {
|
||||
navigator.clipboard.writeText(code)
|
||||
message.info('کد رونوشت شد')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<BasicModal v-model:visible="visible" :custom-footer="true">
|
||||
<div class="p-2">
|
||||
<div
|
||||
v-if="referralId"
|
||||
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">{{ referralId }}</div>
|
||||
</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>
|
||||
</div>
|
||||
</BasicModal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import BasicModal from '@/components/BasicPacks/BasicModal.vue'
|
||||
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
|
||||
import { message } from 'ant-design-vue'
|
||||
import { useUserStore } from '@/store/userStore'
|
||||
|
||||
const props = defineProps<{
|
||||
show: boolean
|
||||
referralId: string
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:show': [value: boolean]
|
||||
}>()
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
const visible = computed({
|
||||
get: () => props.show,
|
||||
set: (val) => emit('update:show', val)
|
||||
})
|
||||
|
||||
const shareCode = () => {
|
||||
const text = `⭐️الان طلا بخر؛ آخر ماه سودشو ببر!
|
||||
با خرید طلای آبشده در مقدارهای کم ولی مستمر، سود بیشتری ببر!
|
||||
|
||||
این دعوت نامه از طرف "${userStore.userInfo?.name}" عزیز برای شما ارسال شده تا شما هم از بازار طلا جا نمونید.
|
||||
روی لینک زیر کلیک کنید و ثبت نام خود را تکمیل کنید.
|
||||
|
||||
${window.location.hostname}/login?id=${props.referralId}`
|
||||
|
||||
navigator.share({ title: 'طلا', text })
|
||||
}
|
||||
|
||||
const copyCode = () => {
|
||||
if (props.referralId) {
|
||||
navigator.clipboard.writeText(props.referralId)
|
||||
message.info('کد رونوشت شد')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,37 @@
|
||||
import { ref } from 'vue'
|
||||
import { getConstByKey } from '@/api/const'
|
||||
|
||||
export function useBanners() {
|
||||
const banners = ref([])
|
||||
const loading = ref(false)
|
||||
|
||||
const loadBanners = async () => {
|
||||
try {
|
||||
loading.value = true
|
||||
const response = await getConstByKey('header_banner')
|
||||
if (!response) return
|
||||
|
||||
let list = []
|
||||
if (typeof response === 'string') {
|
||||
list = JSON.parse(response)
|
||||
} else if (typeof response === 'object' && !Array.isArray(response) && 'value' in response) {
|
||||
list = typeof response.value === 'string' ? JSON.parse(response.value) : response.value
|
||||
} else if (Array.isArray(response) && response.length > 0) {
|
||||
const first = response[0]
|
||||
if (first.value) {
|
||||
list = typeof first.value === 'string' ? JSON.parse(first.value) : first.value
|
||||
} else if (first.icon) {
|
||||
list = response
|
||||
}
|
||||
}
|
||||
|
||||
banners.value = Array.isArray(list) ? list.filter(b => b.show === true) : []
|
||||
} catch (error) {
|
||||
console.error('Error loading banners:', error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
return { banners, loading, loadBanners }
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import { ref } from 'vue'
|
||||
import { getAllPrices } from '@/api/home'
|
||||
|
||||
export function usePriceChart() {
|
||||
const priceChartSeries = ref([{ name: 'قیمت', data: [] }])
|
||||
const selection = ref('DAILY')
|
||||
const chartLoading = ref(false)
|
||||
|
||||
const toPersianNumber = (num: number) => {
|
||||
return num.toString().replace(/\d/g, (d) => '۰۱۲۳۴۵۶۷۸۹'[d])
|
||||
}
|
||||
|
||||
const fetchPrices = async () => {
|
||||
try {
|
||||
chartLoading.value = true
|
||||
const response = await getAllPrices()
|
||||
const data = response.data?.prices
|
||||
const selectedData = data[selection.value] || []
|
||||
priceChartSeries.value[0].data = selectedData.map((item: any) => [item.timestamp, item.value - 1])
|
||||
} catch (error) {
|
||||
console.error('Error fetching prices:', error)
|
||||
} finally {
|
||||
chartLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const updateChartData = (timeline: string) => {
|
||||
selection.value = timeline
|
||||
fetchPrices()
|
||||
}
|
||||
|
||||
return { priceChartSeries, chartLoading, updateChartData, fetchPrices }
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { ref } from 'vue'
|
||||
import { useFundUserStore } from '@/store/fundStore'
|
||||
|
||||
export function useUserFunds() {
|
||||
const funds = ref([])
|
||||
const loading = ref(false)
|
||||
const fundStore = useFundUserStore()
|
||||
|
||||
const loadFunds = async () => {
|
||||
try {
|
||||
loading.value = true
|
||||
const result = await fundStore.getMyFund()
|
||||
funds.value = result?.rows || []
|
||||
} catch (error) {
|
||||
console.error('Error loading funds:', error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
return { funds, loading, loadFunds }
|
||||
}
|
||||
+232
-1082
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user