Compare commits
1
Commits
kashkool
...
mian-test2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12382656e8 |
Binary file not shown.
+18
-12
@@ -3,14 +3,7 @@
|
|||||||
<transition mode="out-in" name="fade">
|
<transition mode="out-in" name="fade">
|
||||||
<AConfigProvider
|
<AConfigProvider
|
||||||
v-if="!showSplash"
|
v-if="!showSplash"
|
||||||
:theme="{
|
:theme="antDesignTheme"
|
||||||
token: {
|
|
||||||
colorPrimary: colors.primary,
|
|
||||||
colorLink: colors.primary,
|
|
||||||
colorLinkActive: colors.primary,
|
|
||||||
colorLinkHover: colors['primary-rgba']
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
direction="rtl"
|
direction="rtl"
|
||||||
>
|
>
|
||||||
<router-view v-slot="{ Component, route }">
|
<router-view v-slot="{ Component, route }">
|
||||||
@@ -68,10 +61,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { colors } from './themeConfig'
|
|
||||||
import pkg from '../package.json'
|
|
||||||
import { getDisplayAppVersion } from '@/config/config-cache'
|
import { getDisplayAppVersion } from '@/config/config-cache'
|
||||||
import { computed, defineAsyncComponent, h, onMounted, ref } from 'vue'
|
import { computed, defineAsyncComponent, h, onMounted, ref } from 'vue'
|
||||||
|
import pkg from '../package.json'
|
||||||
import img_topGradiant from '@/views/login/assets/img/gr_top_white.svg'
|
import img_topGradiant from '@/views/login/assets/img/gr_top_white.svg'
|
||||||
import img_pattern from '@/views/login/assets/img/pattern.svg'
|
import img_pattern from '@/views/login/assets/img/pattern.svg'
|
||||||
import { LoadingOutlined } from '@ant-design/icons-vue'
|
import { LoadingOutlined } from '@ant-design/icons-vue'
|
||||||
@@ -83,6 +75,7 @@ import {
|
|||||||
} from '@/utils/supportMessenger'
|
} from '@/utils/supportMessenger'
|
||||||
import { useDraggableFloatingButton } from '@/utils/useDraggableFloatingButton'
|
import { useDraggableFloatingButton } from '@/utils/useDraggableFloatingButton'
|
||||||
import { useApplyDesktopLayoutClass } from '@/layouts/composables/useAppLayout'
|
import { useApplyDesktopLayoutClass } from '@/layouts/composables/useAppLayout'
|
||||||
|
import { getProjectBranding } from '@/utils/project'
|
||||||
|
|
||||||
import img_bottomGradiant from '@/views/login/assets/img/gr_bottom_white.svg'
|
import img_bottomGradiant from '@/views/login/assets/img/gr_bottom_white.svg'
|
||||||
import logoFull from '@/assets/img/logo_full_.png'
|
import logoFull from '@/assets/img/logo_full_.png'
|
||||||
@@ -100,6 +93,19 @@ const indicator = h(LoadingOutlined, {
|
|||||||
const displayVersion = getDisplayAppVersion(pkg.version)
|
const displayVersion = getDisplayAppVersion(pkg.version)
|
||||||
const showSplash = ref(true)
|
const showSplash = ref(true)
|
||||||
|
|
||||||
|
const antDesignTheme = computed(() => {
|
||||||
|
const primary = getProjectBranding().accentColor
|
||||||
|
|
||||||
|
return {
|
||||||
|
token: {
|
||||||
|
colorPrimary: primary,
|
||||||
|
colorLink: primary,
|
||||||
|
colorLinkActive: primary,
|
||||||
|
colorLinkHover: primary,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
useApplyDesktopLayoutClass()
|
useApplyDesktopLayoutClass()
|
||||||
|
|
||||||
const supportLink = computed(() =>
|
const supportLink = computed(() =>
|
||||||
@@ -141,7 +147,7 @@ const supportAccentColor = computed(() => {
|
|||||||
case 'soroush':
|
case 'soroush':
|
||||||
return '#2563eb'
|
return '#2563eb'
|
||||||
default:
|
default:
|
||||||
return colors.primary || '#334155'
|
return getProjectBranding().accentColor
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -181,7 +187,7 @@ onMounted(async () => {
|
|||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
.updateButton .van-dialog__confirm .van-button__text {
|
.updateButton .van-dialog__confirm .van-button__text {
|
||||||
color: @primary-color !important;
|
color: @theme-primary !important;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
setHasFingerPrint
|
setHasFingerPrint
|
||||||
} from '@/app/authBoot'
|
} from '@/app/authBoot'
|
||||||
import { recoverMobileViewportAfterAuth } from '@/layouts/composables/useMobileScrollReset'
|
import { recoverMobileViewportAfterAuth } from '@/layouts/composables/useMobileScrollReset'
|
||||||
|
import { getProjectDefaultRoute, isGhatreProject } from '@/utils/project'
|
||||||
|
|
||||||
export function setupRouterGuards() {
|
export function setupRouterGuards() {
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
@@ -44,13 +45,17 @@ export function setupRouterGuards() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function goToHome(to: RouteLocationNormalized, next: NavigationGuardNext) {
|
function goToHome(to: RouteLocationNormalized, next: NavigationGuardNext) {
|
||||||
if (to.name !== 'buyProduct') {
|
const defaultRoute = getProjectDefaultRoute()
|
||||||
return next({ name: 'buyProduct' })
|
if (to.name !== defaultRoute) {
|
||||||
|
return next({ name: defaultRoute })
|
||||||
}
|
}
|
||||||
return next()
|
return next()
|
||||||
}
|
}
|
||||||
|
|
||||||
router.beforeEach(async (to, from, next) => {
|
router.beforeEach(async (to, from, next) => {
|
||||||
|
if (to.name === 'home' && isGhatreProject()) {
|
||||||
|
return next({ name: 'buyProduct' })
|
||||||
|
}
|
||||||
authStore.setLoading(true)
|
authStore.setLoading(true)
|
||||||
clearFingerTimeout()
|
clearFingerTimeout()
|
||||||
setFingerTimeOut(to)
|
setFingerTimeOut(to)
|
||||||
@@ -88,7 +93,7 @@ export function setupRouterGuards() {
|
|||||||
if (getFingerPosition()) {
|
if (getFingerPosition()) {
|
||||||
if (getToken()) {
|
if (getToken()) {
|
||||||
if (to.name === 'login') {
|
if (to.name === 'login') {
|
||||||
return next({ name: from.name || 'buyProduct' })
|
return next({ name: from.name || getProjectDefaultRoute() })
|
||||||
}
|
}
|
||||||
return next()
|
return next()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,8 @@ body {
|
|||||||
|
|
||||||
:root {
|
:root {
|
||||||
color-scheme: only light;
|
color-scheme: only light;
|
||||||
|
--app-primary-color: #a72b77;
|
||||||
|
--project-hero-gradient: linear-gradient(145deg, #a72b77 0%, #711d4d 40%, #a72b77 100%);
|
||||||
--app-safe-top: env(safe-area-inset-top, 0px);
|
--app-safe-top: env(safe-area-inset-top, 0px);
|
||||||
--app-safe-bottom: env(safe-area-inset-bottom, 0px);
|
--app-safe-bottom: env(safe-area-inset-bottom, 0px);
|
||||||
--app-credit-bar-inner: 0px;
|
--app-credit-bar-inner: 0px;
|
||||||
@@ -78,6 +80,16 @@ body {
|
|||||||
--app-z-modal: 5500;
|
--app-z-modal: 5500;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:root[data-project='ghatre'] {
|
||||||
|
--app-primary-color: #521620;
|
||||||
|
--project-hero-gradient: linear-gradient(145deg, #521620 0%, #7a2a1e 40%, #521620 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[data-project='kashkool'] {
|
||||||
|
--app-primary-color: #a72b77;
|
||||||
|
--project-hero-gradient: linear-gradient(145deg, #a72b77 0%, #711d4d 40%, #a72b77 100%);
|
||||||
|
}
|
||||||
|
|
||||||
.ant-form-item {
|
.ant-form-item {
|
||||||
margin-bottom: 10px !important;
|
margin-bottom: 10px !important;
|
||||||
|
|
||||||
@@ -164,7 +176,7 @@ body {
|
|||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
//display: none;
|
//display: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
border: 1px solid #a72b77 !important;
|
border: 1px solid var(--app-primary-color, #a72b77) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,18 +374,18 @@ body {
|
|||||||
}
|
}
|
||||||
.ant-radio-group-solid
|
.ant-radio-group-solid
|
||||||
.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):hover{
|
.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):hover{
|
||||||
color: #a72b77 !important;
|
color: var(--app-primary-color, #a72b77) !important;
|
||||||
}
|
}
|
||||||
.ant-input-group-addon{
|
.ant-input-group-addon{
|
||||||
background-color: #a72b77 !important;
|
background-color: var(--app-primary-color, #a72b77) !important;
|
||||||
color: #e0be7f !important;
|
color: #e0be7f !important;
|
||||||
}
|
}
|
||||||
.ant-slider-track{
|
.ant-slider-track{
|
||||||
background-color: #a72b77 !important;
|
background-color: var(--app-primary-color, #a72b77) !important;
|
||||||
|
|
||||||
}
|
}
|
||||||
.ant-slider-handle {
|
.ant-slider-handle {
|
||||||
background-color: #a72b77 !important;
|
background-color: var(--app-primary-color, #a72b77) !important;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
@primary-color: #a72b77;
|
@primary-color: #a72b77;
|
||||||
@secondary-color: #a72b77;
|
@secondary-color: #a72b77;
|
||||||
@App-primary-color: #a72b77;
|
@App-primary-color: #a72b77;
|
||||||
|
@theme-primary: var(--app-primary-color, #a72b77);
|
||||||
@prefixCls-font-family: 'iran-sans';
|
@prefixCls-font-family: 'iran-sans';
|
||||||
@prefixCls-background-color: #fff;
|
@prefixCls-background-color: #fff;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import { computed } from 'vue'
|
||||||
|
import {
|
||||||
|
getProjectBranding,
|
||||||
|
getProjectId,
|
||||||
|
isBoursecuProject,
|
||||||
|
isGhatreProject,
|
||||||
|
isKashkoolProject,
|
||||||
|
type ProjectBranding,
|
||||||
|
type ProjectId,
|
||||||
|
} from '@/utils/project'
|
||||||
|
|
||||||
|
export function useProject() {
|
||||||
|
const projectId = computed<ProjectId>(() => getProjectId())
|
||||||
|
const branding = computed<ProjectBranding>(() => getProjectBranding())
|
||||||
|
|
||||||
|
const isGhatre = computed(() => isGhatreProject())
|
||||||
|
const isKashkool = computed(() => isKashkoolProject())
|
||||||
|
const isBoursecu = computed(() => isBoursecuProject())
|
||||||
|
|
||||||
|
const projectNameFa = computed(() => branding.value.nameFa)
|
||||||
|
const heroGradient = computed(() => branding.value.heroGradient)
|
||||||
|
const accentColor = computed(() => branding.value.accentColor)
|
||||||
|
const fundLabel = computed(() => branding.value.fundLabel)
|
||||||
|
const showHomeRoute = computed(() => branding.value.showHomeRoute)
|
||||||
|
const defaultRoute = computed(() => branding.value.defaultRoute)
|
||||||
|
|
||||||
|
return {
|
||||||
|
projectId,
|
||||||
|
branding,
|
||||||
|
isGhatre,
|
||||||
|
isKashkool,
|
||||||
|
isBoursecu,
|
||||||
|
projectNameFa,
|
||||||
|
heroGradient,
|
||||||
|
accentColor,
|
||||||
|
fundLabel,
|
||||||
|
showHomeRoute,
|
||||||
|
defaultRoute,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,14 +15,33 @@ export function getRawAppConfig() {
|
|||||||
return appConfig ?? window.__APP_CONFIG__ ?? null
|
return appConfig ?? window.__APP_CONFIG__ ?? null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isPlainObject(value: unknown): value is Record<string, any> {
|
||||||
|
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
||||||
|
}
|
||||||
|
|
||||||
export function getTenantConfig() {
|
export function getTenantConfig() {
|
||||||
const rawConfig = getRawAppConfig()
|
const rawConfig = getRawAppConfig()
|
||||||
|
if (!rawConfig) return {}
|
||||||
|
|
||||||
if (rawConfig?.user && typeof rawConfig.user === 'object') {
|
const user = rawConfig.user
|
||||||
return rawConfig.user
|
|
||||||
|
if (isPlainObject(user)) {
|
||||||
|
return {
|
||||||
|
...user,
|
||||||
|
name: rawConfig.name ?? user.name,
|
||||||
|
name_fa: rawConfig.name_fa ?? user.name_fa,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rawConfig && Object.keys(rawConfig).length > 0) {
|
if (Array.isArray(user) && isPlainObject(user[0])) {
|
||||||
|
return {
|
||||||
|
...user[0],
|
||||||
|
name: rawConfig.name ?? user[0].name,
|
||||||
|
name_fa: rawConfig.name_fa ?? user[0].name_fa,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Object.keys(rawConfig).length > 0) {
|
||||||
return rawConfig
|
return rawConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,37 @@
|
|||||||
import { getConfig } from '@/config/app-config'
|
import { getConfig } from '@/config/app-config'
|
||||||
import { isPwaManifestReady } from '@/modules/pwa/manifest'
|
import { isPwaManifestReady } from '@/modules/pwa/manifest'
|
||||||
|
import { getProjectBranding } from '@/utils/project'
|
||||||
|
|
||||||
export function applyAppConfig() {
|
export function applyAppConfig() {
|
||||||
if (isPwaManifestReady()) return
|
applyProjectTheme()
|
||||||
|
|
||||||
|
if (isPwaManifestReady()) {
|
||||||
|
setTitle()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
setTitle()
|
setTitle()
|
||||||
setFavicon()
|
setFavicon()
|
||||||
setAppleTouchIconFallback()
|
setAppleTouchIconFallback()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function applyProjectTheme() {
|
||||||
|
const branding = getProjectBranding()
|
||||||
|
const root = document.documentElement
|
||||||
|
const primary = branding.accentColor
|
||||||
|
|
||||||
|
root.style.setProperty('--project-accent', primary)
|
||||||
|
root.style.setProperty('--project-hero-gradient', branding.heroGradient)
|
||||||
|
root.style.setProperty('--app-primary-color', primary)
|
||||||
|
root.style.setProperty('--primary-color', primary)
|
||||||
|
root.dataset.project = branding.id
|
||||||
|
|
||||||
|
const secondaryColor = getConfig<string>('secondary_color')
|
||||||
|
if (secondaryColor) {
|
||||||
|
root.style.setProperty('--secondary-color', secondaryColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function setTitle() {
|
function setTitle() {
|
||||||
document.title = getConfig('name_fa', 'در حال بارگذاری...')
|
document.title = getConfig('name_fa', 'در حال بارگذاری...')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,11 +92,16 @@ export async function fetchFreshAppConfig(rounds = CONFIG_RETRY_ROUNDS): Promise
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function loadAppConfig(): Promise<AppConfig> {
|
export async function loadAppConfig(): Promise<AppConfig> {
|
||||||
const cachedConfig = readCachedAppConfig()
|
try {
|
||||||
|
return await fetchFreshAppConfig()
|
||||||
|
} catch (error) {
|
||||||
|
const cachedConfig = readCachedAppConfig()
|
||||||
|
|
||||||
if (cachedConfig) {
|
if (cachedConfig) {
|
||||||
return cachedConfig
|
console.warn('Using cached app config because fresh fetch failed', error)
|
||||||
|
return cachedConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
throw error
|
||||||
}
|
}
|
||||||
|
|
||||||
return await fetchFreshAppConfig()
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import type { AppNavItem } from '../types'
|
import type { AppNavItem } from '../types'
|
||||||
|
import { getProjectBranding, isGhatreProject } from '@/utils/project'
|
||||||
|
|
||||||
/** تبهای پایین موبایل — کاربر لاگینشده */
|
/** تبهای پایین موبایل — کاربر لاگینشده (کشکول) */
|
||||||
export const AUTH_PRIMARY_NAV: AppNavItem[] = [
|
export const AUTH_PRIMARY_NAV: AppNavItem[] = [
|
||||||
{ id: 'home', routeName: 'home', label: 'صفحه اصلی', icon: 'vuesax-linear:home' },
|
{ id: 'home', routeName: 'home', label: 'صفحه اصلی', icon: 'vuesax-linear:home' },
|
||||||
{ id: 'transactions', routeName: 'transactions', label: 'گزارش', icon: 'vuesax-linear:receipt-item' },
|
{ id: 'transactions', routeName: 'transactions', label: 'گزارش', icon: 'vuesax-linear:receipt-item' },
|
||||||
@@ -8,6 +9,14 @@ export const AUTH_PRIMARY_NAV: AppNavItem[] = [
|
|||||||
{ id: 'cart', routeName: 'cart', label: 'سبد خرید', icon: 'vuesax-linear:shopping-cart' },
|
{ id: 'cart', routeName: 'cart', label: 'سبد خرید', icon: 'vuesax-linear:shopping-cart' },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
/** تبهای پایین موبایل — کاربر لاگینشده (قطره) */
|
||||||
|
export const GHATRE_AUTH_PRIMARY_NAV: AppNavItem[] = [
|
||||||
|
{ id: 'buyProduct', routeName: 'buyProduct', label: 'فروشگاه', icon: 'vuesax-linear:coin' },
|
||||||
|
{ id: 'transactions', routeName: 'transactions', label: 'گزارش', icon: 'vuesax-linear:receipt-item' },
|
||||||
|
{ id: 'wallet', routeName: 'wallet', label: 'کیف پول', icon: 'vuesax-linear:wallet-1' },
|
||||||
|
{ id: 'cart', routeName: 'cart', label: 'سبد خرید', icon: 'vuesax-linear:shopping-cart' },
|
||||||
|
]
|
||||||
|
|
||||||
/** تبهای پایین موبایل — مهمان */
|
/** تبهای پایین موبایل — مهمان */
|
||||||
export const GUEST_PRIMARY_NAV: AppNavItem[] = [
|
export const GUEST_PRIMARY_NAV: AppNavItem[] = [
|
||||||
{ id: 'buyProduct', routeName: 'buyProduct', label: 'فروشگاه', icon: 'vuesax-linear:coin' },
|
{ id: 'buyProduct', routeName: 'buyProduct', label: 'فروشگاه', icon: 'vuesax-linear:coin' },
|
||||||
@@ -31,9 +40,16 @@ export const AUTH_SECONDARY_NAV: AppNavItem[] = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
export function getPrimaryNavItems(isAuthenticated: boolean): AppNavItem[] {
|
export function getPrimaryNavItems(isAuthenticated: boolean): AppNavItem[] {
|
||||||
return isAuthenticated ? AUTH_PRIMARY_NAV : GUEST_PRIMARY_NAV
|
if (!isAuthenticated) return GUEST_PRIMARY_NAV
|
||||||
|
return isGhatreProject() ? GHATRE_AUTH_PRIMARY_NAV : AUTH_PRIMARY_NAV
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getSecondaryNavItems(isAuthenticated: boolean): AppNavItem[] {
|
export function getSecondaryNavItems(isAuthenticated: boolean): AppNavItem[] {
|
||||||
return isAuthenticated ? AUTH_SECONDARY_NAV : []
|
if (!isAuthenticated) return []
|
||||||
|
|
||||||
|
const fundLabel = getProjectBranding().fundLabel
|
||||||
|
|
||||||
|
return AUTH_SECONDARY_NAV.map((item) =>
|
||||||
|
item.id === 'fund' ? { ...item, label: fundLabel } : item
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ defineEmits<{
|
|||||||
height: 18px;
|
height: 18px;
|
||||||
padding: 0 4px;
|
padding: 0 4px;
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
background: #a72b77;
|
background: var(--app-primary-color, #a72b77);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<aside class="desktop-sidebar">
|
<aside class="desktop-sidebar">
|
||||||
<div class="desktop-sidebar__brand">
|
<div class="desktop-sidebar__brand">
|
||||||
<img :src="navLogo" alt="کشکول گلد" class="desktop-sidebar__logo" />
|
<img :src="navLogo" :alt="projectNameFa" class="desktop-sidebar__logo" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<nav class="desktop-sidebar__section" aria-label="منوی اصلی">
|
<nav class="desktop-sidebar__section" aria-label="منوی اصلی">
|
||||||
@@ -45,7 +45,9 @@ import { useCartStore } from '@/store/cartStore'
|
|||||||
import { getPrimaryNavItems, getSecondaryNavItems } from '../config/navigation'
|
import { getPrimaryNavItems, getSecondaryNavItems } from '../config/navigation'
|
||||||
import { useAppNavigation } from '../composables/useAppNavigation'
|
import { useAppNavigation } from '../composables/useAppNavigation'
|
||||||
import DesktopNavItem from './DesktopNavItem.vue'
|
import DesktopNavItem from './DesktopNavItem.vue'
|
||||||
|
import { useProject } from '@/composables/useProject'
|
||||||
|
|
||||||
|
const { projectNameFa } = useProject()
|
||||||
const cartStore = useCartStore()
|
const cartStore = useCartStore()
|
||||||
const authenticated = computed(() => isToken())
|
const authenticated = computed(() => isToken())
|
||||||
const navLogo = logoFull
|
const navLogo = logoFull
|
||||||
|
|||||||
@@ -110,15 +110,15 @@
|
|||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: rgba(167, 43, 119, 0.06);
|
background: rgba(167, 43, 119, 0.06);
|
||||||
color: @primary-color;
|
color: @theme-primary;
|
||||||
}
|
}
|
||||||
|
|
||||||
&--active {
|
&--active {
|
||||||
background: rgba(167, 43, 119, 0.1);
|
background: rgba(167, 43, 119, 0.1);
|
||||||
color: @primary-color;
|
color: @theme-primary;
|
||||||
|
|
||||||
.desktop-nav-item__icon {
|
.desktop-nav-item__icon {
|
||||||
color: @primary-color;
|
color: @theme-primary;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,7 +85,7 @@
|
|||||||
&__price {
|
&__price {
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: @App-primary-color;
|
color: @theme-primary;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,7 +114,7 @@
|
|||||||
&__total {
|
&__total {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: @App-primary-color;
|
color: @theme-primary;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +153,7 @@
|
|||||||
.dproduct-info__price {
|
.dproduct-info__price {
|
||||||
font-size: 22px;
|
font-size: 22px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: @App-primary-color;
|
color: @theme-primary;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dproduct-info__desc {
|
.dproduct-info__desc {
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
|
|
||||||
&.text-primary .tab__icon,
|
&.text-primary .tab__icon,
|
||||||
&.text-primary .tab__icon .ant-badge {
|
&.text-primary .tab__icon .ant-badge {
|
||||||
color: @primary-color;
|
color: @theme-primary;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.text-gray-400 .tab__icon,
|
&.text-gray-400 .tab__icon,
|
||||||
@@ -68,11 +68,11 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background-color: #a72b77;
|
background-color: @theme-primary;
|
||||||
|
|
||||||
.circle_into {
|
.circle_into {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background-color: @primary-color;
|
background-color: @theme-primary;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
width: 56px;
|
width: 56px;
|
||||||
height: 56px;
|
height: 56px;
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
padding: 0.75rem;
|
padding: 0.75rem;
|
||||||
padding-top: calc(0.75rem + var(--app-safe-top, env(safe-area-inset-top, 0px)));
|
padding-top: calc(0.75rem + var(--app-safe-top, env(safe-area-inset-top, 0px)));
|
||||||
background: #fff;
|
background: #fff;
|
||||||
color: @primary-color;
|
color: @theme-primary;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
@@ -67,7 +67,7 @@
|
|||||||
z-index: 1999;
|
z-index: 1999;
|
||||||
padding: 0.75rem;
|
padding: 0.75rem;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
color: @primary-color;
|
color: @theme-primary;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-7
@@ -1,4 +1,5 @@
|
|||||||
import {createRouter, createWebHistory} from 'vue-router'
|
import {createRouter, createWebHistory} from 'vue-router'
|
||||||
|
import { getProjectDefaultRoute } from '@/utils/project'
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(import.meta.env.BASE_URL),
|
history: createWebHistory(import.meta.env.BASE_URL),
|
||||||
@@ -8,16 +9,10 @@ const router = createRouter({
|
|||||||
name: 'login',
|
name: 'login',
|
||||||
component: () => import('../views/login/index.vue')
|
component: () => import('../views/login/index.vue')
|
||||||
},
|
},
|
||||||
/* {
|
|
||||||
path: '/',
|
|
||||||
name: 'null',
|
|
||||||
redirect: {name: 'home'},
|
|
||||||
// component: () => import('../views/login/index.vue')
|
|
||||||
},*/
|
|
||||||
{
|
{
|
||||||
path: `/`,
|
path: `/`,
|
||||||
name: 'main',
|
name: 'main',
|
||||||
redirect: {name: 'buyProduct'},
|
redirect: () => ({ name: getProjectDefaultRoute() }),
|
||||||
component: () => import('../views/base/index.vue'),
|
component: () => import('../views/base/index.vue'),
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
|
|||||||
+17
-6
@@ -1,8 +1,19 @@
|
|||||||
export function getConfigApp(key: string) {
|
import { getTenantConfig } from '@/config/app-config'
|
||||||
const config = window.__APP_CONFIG__ ? window.__APP_CONFIG__.user : {}
|
|
||||||
|
|
||||||
if (config) {
|
export function getConfigApp(key: string) {
|
||||||
return config[key]
|
const config = getTenantConfig()
|
||||||
}
|
const value = config?.[key]
|
||||||
return null
|
|
||||||
|
return value ?? null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
getProjectId,
|
||||||
|
getProjectBranding,
|
||||||
|
getProjectDefaultRoute,
|
||||||
|
isGhatreProject,
|
||||||
|
isKashkoolProject,
|
||||||
|
isBoursecuProject,
|
||||||
|
} from '@/utils/project'
|
||||||
|
|
||||||
|
export type { ProjectId, ProjectBranding } from '@/utils/project'
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
function normalizeGroupType(value: unknown): string {
|
||||||
|
return String(value ?? '').trim().toLowerCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isKatodMesGroup(groupType: unknown): boolean {
|
||||||
|
const type = normalizeGroupType(groupType)
|
||||||
|
return type.includes('کاتد') || type.includes('katod')
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isMaftolMesGroup(groupType: unknown): boolean {
|
||||||
|
const type = normalizeGroupType(groupType)
|
||||||
|
return type.includes('مفتول') || type.includes('maftol')
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isShamshMesGroup(groupType: unknown, title?: unknown): boolean {
|
||||||
|
const type = normalizeGroupType(groupType)
|
||||||
|
const name = normalizeGroupType(title)
|
||||||
|
|
||||||
|
return (
|
||||||
|
type.includes('شمش') ||
|
||||||
|
type.includes('shamsh') ||
|
||||||
|
name.includes('شمش') ||
|
||||||
|
name.includes('shamsh')
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,155 @@
|
|||||||
|
import { getRawAppConfig } from '@/config/app-config'
|
||||||
|
import type { AppConfig } from '@/config/types'
|
||||||
|
|
||||||
|
export type ProjectId = 'ghatre' | 'kashkool' | 'boursecu'
|
||||||
|
|
||||||
|
export interface ProjectBranding {
|
||||||
|
id: ProjectId
|
||||||
|
nameFa: string
|
||||||
|
heroGradient: string
|
||||||
|
accentColor: string
|
||||||
|
borderAccent: string
|
||||||
|
fundLabel: string
|
||||||
|
fundHeroBg: string
|
||||||
|
idCardLabel: string
|
||||||
|
buyPriceLabel: string
|
||||||
|
defaultRoute: string
|
||||||
|
showHomeRoute: boolean
|
||||||
|
referralDomain: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const PROJECT_BRANDING: Record<ProjectId, ProjectBranding> = {
|
||||||
|
ghatre: {
|
||||||
|
id: 'ghatre',
|
||||||
|
nameFa: 'قطره',
|
||||||
|
heroGradient: 'linear-gradient(145deg, #521620 0%, #7a2a1e 40%, #521620 100%)',
|
||||||
|
accentColor: '#521620',
|
||||||
|
borderAccent: '#521620',
|
||||||
|
fundLabel: 'قلک',
|
||||||
|
fundHeroBg: '#EFCED9',
|
||||||
|
idCardLabel: 'شناسه شما در قطره',
|
||||||
|
buyPriceLabel: 'قیمت خرید از قطره',
|
||||||
|
defaultRoute: 'buyProduct',
|
||||||
|
showHomeRoute: false,
|
||||||
|
referralDomain: 'ghatre.gold',
|
||||||
|
},
|
||||||
|
kashkool: {
|
||||||
|
id: 'kashkool',
|
||||||
|
nameFa: 'کشکول',
|
||||||
|
heroGradient: 'linear-gradient(145deg, #a72b77 0%, #711d4d 40%, #a72b77 100%)',
|
||||||
|
accentColor: '#a72b77',
|
||||||
|
borderAccent: '#a72b77',
|
||||||
|
fundLabel: 'دارایی ها',
|
||||||
|
fundHeroBg: '',
|
||||||
|
idCardLabel: 'شناسه شما در کشکول',
|
||||||
|
buyPriceLabel: 'قیمت خرید از کشکول',
|
||||||
|
defaultRoute: 'home',
|
||||||
|
showHomeRoute: true,
|
||||||
|
referralDomain: 'kh.kashkolgold.ir',
|
||||||
|
},
|
||||||
|
boursecu: {
|
||||||
|
id: 'boursecu',
|
||||||
|
nameFa: 'بورسکو',
|
||||||
|
heroGradient: 'linear-gradient(145deg, #1e2229 0%, #374151 40%, #1e2229 100%)',
|
||||||
|
accentColor: '#1e2229',
|
||||||
|
borderAccent: '#1e2229',
|
||||||
|
fundLabel: 'دارایی ها',
|
||||||
|
fundHeroBg: '',
|
||||||
|
idCardLabel: 'شناسه شما',
|
||||||
|
buyPriceLabel: 'قیمت خرید',
|
||||||
|
defaultRoute: 'home',
|
||||||
|
showHomeRoute: true,
|
||||||
|
referralDomain: '',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeProjectName(value: unknown): string {
|
||||||
|
return String(value ?? '')
|
||||||
|
.trim()
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/\s+/g, '')
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolveProjectNameFromConfig(raw: AppConfig | null | undefined): string {
|
||||||
|
if (!raw) return ''
|
||||||
|
|
||||||
|
const candidates: unknown[] = [
|
||||||
|
raw.name,
|
||||||
|
typeof raw.user === 'object' && raw.user !== null && !Array.isArray(raw.user)
|
||||||
|
? (raw.user as Record<string, unknown>).name
|
||||||
|
: undefined,
|
||||||
|
Array.isArray(raw.user) && raw.user[0] && typeof raw.user[0] === 'object'
|
||||||
|
? (raw.user[0] as Record<string, unknown>).name
|
||||||
|
: undefined,
|
||||||
|
]
|
||||||
|
|
||||||
|
for (const value of candidates) {
|
||||||
|
const normalized = normalizeProjectName(value)
|
||||||
|
if (normalized) return normalized
|
||||||
|
}
|
||||||
|
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
function getProjectNameRaw(): string {
|
||||||
|
return resolveProjectNameFromConfig(getRawAppConfig())
|
||||||
|
}
|
||||||
|
|
||||||
|
function matchesProjectName(name: string, aliases: string[]): boolean {
|
||||||
|
return aliases.some((alias) => name.includes(normalizeProjectName(alias)))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getProjectId(): ProjectId {
|
||||||
|
const name = getProjectNameRaw()
|
||||||
|
|
||||||
|
if (name === 'ghatreh') {
|
||||||
|
return 'ghatre'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name === 'kashkolgold') {
|
||||||
|
return 'kashkool'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matchesProjectName(name, ['boursecu', 'bourse', 'بورسکو', 'بورس'])) {
|
||||||
|
return 'boursecu'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matchesProjectName(name, ['ghatre', 'qatre', 'قطره'])) {
|
||||||
|
return 'ghatre'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matchesProjectName(name, ['kashkool', 'kashkol', 'کشکول'])) {
|
||||||
|
return 'kashkool'
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'kashkool'
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isGhatreProject(): boolean {
|
||||||
|
return getProjectId() === 'ghatre'
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isKashkoolProject(): boolean {
|
||||||
|
return getProjectId() === 'kashkool'
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isBoursecuProject(): boolean {
|
||||||
|
return getProjectId() === 'boursecu'
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getProjectBranding(): ProjectBranding {
|
||||||
|
const id = getProjectId()
|
||||||
|
const defaults = PROJECT_BRANDING[id]
|
||||||
|
|
||||||
|
return {
|
||||||
|
...defaults,
|
||||||
|
nameFa: defaults.nameFa,
|
||||||
|
accentColor: defaults.accentColor,
|
||||||
|
borderAccent: defaults.borderAccent,
|
||||||
|
heroGradient: defaults.heroGradient,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getProjectDefaultRoute(): string {
|
||||||
|
return getProjectBranding().defaultRoute
|
||||||
|
}
|
||||||
@@ -95,7 +95,7 @@
|
|||||||
height: 56px;
|
height: 56px;
|
||||||
border-radius: 14px;
|
border-radius: 14px;
|
||||||
background: rgba(9, 61, 81, 0.08);
|
background: rgba(9, 61, 81, 0.08);
|
||||||
color: @App-primary-color;
|
color: @theme-primary;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,7 +125,7 @@
|
|||||||
border: 1px solid rgba(9, 61, 81, 0.15);
|
border: 1px solid rgba(9, 61, 81, 0.15);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
background: rgba(9, 61, 81, 0.03);
|
background: rgba(9, 61, 81, 0.03);
|
||||||
color: @App-primary-color;
|
color: @theme-primary;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__divider {
|
&__divider {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { useWalletAssets } from '@/composables/useWalletAssets'
|
|||||||
import type { WalletMetalTotal } from '@/models/walletAssets'
|
import type { WalletMetalTotal } from '@/models/walletAssets'
|
||||||
import { fundPageInventoryCards, formatMetalTotal as buildMetalTotalLabel } from '@/utils/productAssets'
|
import { fundPageInventoryCards, formatMetalTotal as buildMetalTotalLabel } from '@/utils/productAssets'
|
||||||
import { getLastPrices } from '@/utils/price'
|
import { getLastPrices } from '@/utils/price'
|
||||||
|
import { getProjectBranding, isGhatreProject } from '@/utils/project'
|
||||||
import img from '@/assets/img/user_ly1.svg'
|
import img from '@/assets/img/user_ly1.svg'
|
||||||
import empty from '@/assets/img/cash_empty.svg'
|
import empty from '@/assets/img/cash_empty.svg'
|
||||||
|
|
||||||
@@ -20,6 +21,8 @@ export interface FundPageContext {
|
|||||||
fundHeaderBackground: string
|
fundHeaderBackground: string
|
||||||
fundEmptyImage: string
|
fundEmptyImage: string
|
||||||
fundEmptyText: string
|
fundEmptyText: string
|
||||||
|
fundLabel: string
|
||||||
|
fundBalanceLabel: string
|
||||||
formatMetalTotal: (metal: WalletMetalTotal) => string
|
formatMetalTotal: (metal: WalletMetalTotal) => string
|
||||||
openFundInfo: (productId: number) => void
|
openFundInfo: (productId: number) => void
|
||||||
goBack: () => void
|
goBack: () => void
|
||||||
@@ -70,6 +73,8 @@ export function useFundPage(_isDesktop: Ref<boolean>) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const branding = getProjectBranding()
|
||||||
|
|
||||||
const context: FundPageContext = {
|
const context: FundPageContext = {
|
||||||
meta,
|
meta,
|
||||||
inventoryCards,
|
inventoryCards,
|
||||||
@@ -80,7 +85,9 @@ export function useFundPage(_isDesktop: Ref<boolean>) {
|
|||||||
countBasedInventory,
|
countBasedInventory,
|
||||||
fundHeaderBackground: img,
|
fundHeaderBackground: img,
|
||||||
fundEmptyImage: empty,
|
fundEmptyImage: empty,
|
||||||
fundEmptyText: 'یک گنج جدید بساز!',
|
fundEmptyText: isGhatreProject() ? 'یک قلک جدید بساز!' : 'یک گنج جدید بساز!',
|
||||||
|
fundLabel: branding.fundLabel,
|
||||||
|
fundBalanceLabel: isGhatreProject() ? `موجودی ${branding.fundLabel} ها` : `موجودی ${branding.fundLabel}`,
|
||||||
formatMetalTotal,
|
formatMetalTotal,
|
||||||
openFundInfo,
|
openFundInfo,
|
||||||
goBack,
|
goBack,
|
||||||
|
|||||||
@@ -7,16 +7,16 @@
|
|||||||
بازگشت
|
بازگشت
|
||||||
</button>
|
</button>
|
||||||
<div class="dfund-topbar__meta">
|
<div class="dfund-topbar__meta">
|
||||||
<p class="dfund-topbar__eyebrow">دارایی</p>
|
<p class="dfund-topbar__eyebrow">{{ fundLabel }}</p>
|
||||||
<h1 class="dfund-topbar__title">داراییها</h1>
|
<h1 class="dfund-topbar__title">{{ fundLabel }}</h1>
|
||||||
<p class="dfund-topbar__subtitle">نمای کلی موجودی محصولات و کیف پول</p>
|
<p class="dfund-topbar__subtitle">نمای کلی موجودی محصولات و کیف پول</p>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<section class="dfund-summary dfund-summary--ghatreh">
|
<section class="dfund-summary" :class="isGhatre ? 'dfund-summary--ghatreh' : ''">
|
||||||
<img :src="fundHeaderBackground" alt="" class="dfund-summary__bg" />
|
<img :src="fundHeaderBackground" alt="" class="dfund-summary__bg" />
|
||||||
<div class="dfund-summary__content">
|
<div class="dfund-summary__content">
|
||||||
<h2 class="dfund-summary__title">موجودی داراییها</h2>
|
<h2 class="dfund-summary__title">{{ fundBalanceLabel }}</h2>
|
||||||
|
|
||||||
<div v-if="meta?.has_count_based_products" class="dfund-summary__row">
|
<div v-if="meta?.has_count_based_products" class="dfund-summary__row">
|
||||||
<span>محصولات</span>
|
<span>محصولات</span>
|
||||||
@@ -93,6 +93,9 @@ import { loading } from '@/utils'
|
|||||||
import { usePriceWithoutType } from '@/utils/usePrice'
|
import { usePriceWithoutType } from '@/utils/usePrice'
|
||||||
import Item from '../components/Item.vue'
|
import Item from '../components/Item.vue'
|
||||||
import { useFundPageContext } from '../composables/useFundPage'
|
import { useFundPageContext } from '../composables/useFundPage'
|
||||||
|
import { useProject } from '@/composables/useProject'
|
||||||
|
|
||||||
|
const { isGhatre } = useProject()
|
||||||
|
|
||||||
const {
|
const {
|
||||||
meta,
|
meta,
|
||||||
@@ -105,6 +108,8 @@ const {
|
|||||||
fundHeaderBackground,
|
fundHeaderBackground,
|
||||||
fundEmptyImage,
|
fundEmptyImage,
|
||||||
fundEmptyText,
|
fundEmptyText,
|
||||||
|
fundLabel,
|
||||||
|
fundBalanceLabel,
|
||||||
formatMetalTotal,
|
formatMetalTotal,
|
||||||
openFundInfo,
|
openFundInfo,
|
||||||
goBack,
|
goBack,
|
||||||
|
|||||||
@@ -73,7 +73,7 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
margin-bottom: 24px;
|
margin-bottom: 24px;
|
||||||
background: @App-primary-color;
|
background: @theme-primary;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
|
||||||
&--bazretala {
|
&--bazretala {
|
||||||
@@ -339,7 +339,7 @@
|
|||||||
.dfund-info__balance-value {
|
.dfund-info__balance-value {
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: @App-primary-color;
|
color: @theme-primary;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dfund-info__balance-unit {
|
.dfund-info__balance-unit {
|
||||||
@@ -495,8 +495,8 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&--active {
|
&--active {
|
||||||
background: @App-primary-color;
|
background: @theme-primary;
|
||||||
border-color: @App-primary-color;
|
border-color: @theme-primary;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,17 +6,21 @@
|
|||||||
<div class="cursor-pointer" @click="goBack()">
|
<div class="cursor-pointer" @click="goBack()">
|
||||||
<BasicIcon icon="vuesax-linear:arrow-right-1" />
|
<BasicIcon icon="vuesax-linear:arrow-right-1" />
|
||||||
</div>
|
</div>
|
||||||
<div class="mr-2">دارایی ها</div>
|
<div class="mr-2">{{ fundLabel }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="fund-mobile-root__hero text-tertiary bg-primary">
|
<div
|
||||||
|
class="fund-mobile-root__hero text-tertiary"
|
||||||
|
:class="isGhatre ? 'fund-mobile-root__hero--ghatre' : 'bg-primary'"
|
||||||
|
:style="isGhatre ? { backgroundColor: fundHeroBg } : undefined"
|
||||||
|
>
|
||||||
<img
|
<img
|
||||||
:src="fundHeaderBackground"
|
:src="fundHeaderBackground"
|
||||||
alt=""
|
alt=""
|
||||||
class="fund-mobile-root__hero-bg"
|
class="fund-mobile-root__hero-bg"
|
||||||
/>
|
/>
|
||||||
<div class="fund-mobile-root__hero-content flex flex-col">
|
<div class="fund-mobile-root__hero-content flex flex-col">
|
||||||
<div class="font-bold mr-5 z-20">موجودی دارایی ها</div>
|
<div class="font-bold mr-5 z-20">{{ fundBalanceLabel }}</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-if="meta?.has_count_based_products"
|
v-if="meta?.has_count_based_products"
|
||||||
@@ -91,10 +95,15 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||||
|
import { computed } from 'vue'
|
||||||
import { loading } from '@/utils'
|
import { loading } from '@/utils'
|
||||||
import { usePriceWithoutType } from '@/utils/usePrice'
|
import { usePriceWithoutType } from '@/utils/usePrice'
|
||||||
import Item from '../components/Item.vue'
|
import Item from '../components/Item.vue'
|
||||||
import { useFundPageContext } from '../composables/useFundPage'
|
import { useFundPageContext } from '../composables/useFundPage'
|
||||||
|
import { useProject } from '@/composables/useProject'
|
||||||
|
|
||||||
|
const { isGhatre, branding } = useProject()
|
||||||
|
const fundHeroBg = computed(() => branding.value.fundHeroBg)
|
||||||
|
|
||||||
const {
|
const {
|
||||||
meta,
|
meta,
|
||||||
@@ -107,6 +116,8 @@ const {
|
|||||||
fundHeaderBackground,
|
fundHeaderBackground,
|
||||||
fundEmptyImage,
|
fundEmptyImage,
|
||||||
fundEmptyText,
|
fundEmptyText,
|
||||||
|
fundLabel,
|
||||||
|
fundBalanceLabel,
|
||||||
formatMetalTotal,
|
formatMetalTotal,
|
||||||
openFundInfo,
|
openFundInfo,
|
||||||
goBack,
|
goBack,
|
||||||
|
|||||||
@@ -47,7 +47,7 @@
|
|||||||
height: 56px;
|
height: 56px;
|
||||||
border-radius: 14px;
|
border-radius: 14px;
|
||||||
background: rgba(167, 43, 119, 0.08);
|
background: rgba(167, 43, 119, 0.08);
|
||||||
color: @App-primary-color;
|
color: @theme-primary;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +126,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.basic-icon {
|
.basic-icon {
|
||||||
color: @App-primary-color;
|
color: @theme-primary;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
margin-top: 2px;
|
margin-top: 2px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
import { computed, inject, provide, type InjectionKey } from 'vue'
|
||||||
|
import router from '@/router'
|
||||||
|
import { useSettingsStore } from '@/store/settingsStore'
|
||||||
|
import { getStoreClosedMessage, isStoreClosed } from '@/utils/storeHours'
|
||||||
|
import { isKashkoolProject } from '@/utils/project'
|
||||||
|
import { getHomeLayoutId } from '../layouts/registry'
|
||||||
|
import { useBanners } from './useBanners'
|
||||||
|
import { usePriceChart } from './usePriceChart'
|
||||||
|
import { initHomePageData } from './useHomePageData'
|
||||||
|
import type { HomeActionItem } from '../layouts/types'
|
||||||
|
|
||||||
|
export const HOME_PAGE_CONTEXT_KEY: InjectionKey<ReturnType<typeof createHomePageContext>> =
|
||||||
|
Symbol('homePageContext')
|
||||||
|
|
||||||
|
function createHomePageContext() {
|
||||||
|
const settingsStore = useSettingsStore()
|
||||||
|
const { banners } = useBanners()
|
||||||
|
const chart = usePriceChart()
|
||||||
|
|
||||||
|
const isBoursecuHomeLayout = computed(() => getHomeLayoutId() === 'boursecu')
|
||||||
|
const isGaroosi = computed(() => isKashkoolProject())
|
||||||
|
const bannerEnabled = computed(() => settingsStore.isSettingTruthy('banner_enabled'))
|
||||||
|
const showClosedMessage = computed(() => isStoreClosed())
|
||||||
|
const closedMessage = computed(() => getStoreClosedMessage())
|
||||||
|
|
||||||
|
const mainActions = computed<HomeActionItem[]>(() => [
|
||||||
|
{
|
||||||
|
name: 'buySell',
|
||||||
|
icon: 'vuesax-linear:money-receive',
|
||||||
|
label: 'خرید و فروش',
|
||||||
|
handler: () => router.push({ name: 'gold' }),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'deposit',
|
||||||
|
icon: 'vuesax-linear:card-add',
|
||||||
|
label: 'واریز نقدی',
|
||||||
|
handler: () => router.push({ name: 'wallet', query: { state: 'deposit' } }),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'balance',
|
||||||
|
icon: 'vuesax-linear:receipt-item',
|
||||||
|
label: 'موجودی',
|
||||||
|
handler: () => {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'fund',
|
||||||
|
icon: 'vuesax-linear:archive-1',
|
||||||
|
label: 'دارایی ها',
|
||||||
|
handler: () => router.push({ name: 'fund' }),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'earn',
|
||||||
|
icon: 'vuesax-linear:dollar-circle',
|
||||||
|
label: 'کسب درآمد',
|
||||||
|
handler: () => router.push({ name: 'earnMoney' }),
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
function openGoldModal() {}
|
||||||
|
function openRialModal() {}
|
||||||
|
function handleBannerClick() {}
|
||||||
|
|
||||||
|
void initHomePageData()
|
||||||
|
|
||||||
|
return {
|
||||||
|
isBoursecuHomeLayout,
|
||||||
|
isGaroosi,
|
||||||
|
bannerEnabled,
|
||||||
|
banners,
|
||||||
|
showClosedMessage,
|
||||||
|
closedMessage,
|
||||||
|
mainActions,
|
||||||
|
priceChartSeries: chart.priceChartSeries,
|
||||||
|
chartSelection: chart.chartSelection,
|
||||||
|
selectedChartMetal: chart.selectedChartMetal,
|
||||||
|
updateChartData: chart.updateChartData,
|
||||||
|
setChartMetal: chart.setChartMetal,
|
||||||
|
openGoldModal,
|
||||||
|
openRialModal,
|
||||||
|
handleBannerClick,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useHomePageProvider() {
|
||||||
|
const context = createHomePageContext()
|
||||||
|
provide(HOME_PAGE_CONTEXT_KEY, context)
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useHomePageContext() {
|
||||||
|
const existing = inject(HOME_PAGE_CONTEXT_KEY, null)
|
||||||
|
if (existing) return existing
|
||||||
|
return useHomePageProvider()
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
export async function loadHomeFunds(_force = false) {
|
||||||
|
return Promise.resolve()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resetHomeFunds() {
|
||||||
|
// no-op — fund list is loaded via wallet assets on the home page
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
<template v-else-if="userStore.userInfo">
|
<template v-else-if="userStore.userInfo">
|
||||||
<section class="dhome-hero-row">
|
<section class="dhome-hero-row">
|
||||||
<div class="dhome-surface dhome-hero-price">
|
<div class="dhome-surface dhome-hero-price">
|
||||||
<span class="dhome-label">قیمت خرید از کشکول گلد</span>
|
<span class="dhome-label">{{ branding.buyPriceLabel }}</span>
|
||||||
<div class="dhome-hero-price__value-row">
|
<div class="dhome-hero-price__value-row">
|
||||||
<span
|
<span
|
||||||
v-if="percentPriceChanged() !== 0"
|
v-if="percentPriceChanged() !== 0"
|
||||||
@@ -174,8 +174,9 @@ import DesktopHomeTopbar from '@/views/base/home/components/DesktopHomeTopbar.vu
|
|||||||
import HomeSkeleton from '@/views/base/home/components/HomeSkeleton.vue'
|
import HomeSkeleton from '@/views/base/home/components/HomeSkeleton.vue'
|
||||||
import bannerImg from '@/assets/img/banner/2.png'
|
import bannerImg from '@/assets/img/banner/2.png'
|
||||||
import { message } from 'ant-design-vue'
|
import { message } from 'ant-design-vue'
|
||||||
|
import { useProject } from '@/composables/useProject'
|
||||||
|
|
||||||
const emit = defineEmits<{ logout: []; openBalance: [] }>()
|
const { branding, projectNameFa } = useProject()
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const walletStore = useWalletStore()
|
const walletStore = useWalletStore()
|
||||||
const { assetsSummary, loadWalletAssets } = useWalletAssets()
|
const { assetsSummary, loadWalletAssets } = useWalletAssets()
|
||||||
@@ -263,7 +264,7 @@ function shareReferral() {
|
|||||||
const text = `⭐️الان طلا بخر؛ آخر ماه سودشو ببر!
|
const text = `⭐️الان طلا بخر؛ آخر ماه سودشو ببر!
|
||||||
این دعوت نامه از طرف "${userStore.userInfo?.name}" برای شما ارسال شده.
|
این دعوت نامه از طرف "${userStore.userInfo?.name}" برای شما ارسال شده.
|
||||||
kh.kashkolgold.ir/login?id=${userStore.userInfo?.referral_id}`
|
kh.kashkolgold.ir/login?id=${userStore.userInfo?.referral_id}`
|
||||||
navigator.share({ title: 'کشکول گلد', text })
|
navigator.share({ title: projectNameFa.value, text })
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
|||||||
@@ -8,10 +8,12 @@ import { computed } from 'vue'
|
|||||||
import { getHomeLayoutId } from '../layouts/registry'
|
import { getHomeLayoutId } from '../layouts/registry'
|
||||||
import BoursecuDesktopHome from './layouts/BoursecuDesktopHome.vue'
|
import BoursecuDesktopHome from './layouts/BoursecuDesktopHome.vue'
|
||||||
import DefaultDesktopHome from './layouts/DefaultDesktopHome.vue'
|
import DefaultDesktopHome from './layouts/DefaultDesktopHome.vue'
|
||||||
|
import { useHomePageProvider } from '../composables/useHomePage'
|
||||||
|
|
||||||
defineEmits<{
|
defineEmits<{
|
||||||
logout: []
|
logout: []
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
useHomePageProvider()
|
||||||
const layoutId = computed(() => getHomeLayoutId())
|
const layoutId = computed(() => getHomeLayoutId())
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -420,7 +420,7 @@
|
|||||||
height: 36px;
|
height: 36px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
background: #f3f4f6;
|
background: #f3f4f6;
|
||||||
color: @App-primary-color;
|
color: @theme-primary;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
transition: background 0.15s ease;
|
transition: background 0.15s ease;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
@@ -498,7 +498,7 @@
|
|||||||
height: 40px;
|
height: 40px;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
color: @App-primary-color;
|
color: @theme-primary;
|
||||||
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.05);
|
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -628,7 +628,7 @@
|
|||||||
transition: background 0.15s ease, color 0.15s ease;
|
transition: background 0.15s ease, color 0.15s ease;
|
||||||
|
|
||||||
&--active {
|
&--active {
|
||||||
background: @App-primary-color;
|
background: @theme-primary;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="home-page-root">
|
<div class="home-page-root">
|
||||||
<GhatrehHomeDesktopView
|
<GhatrehHomeDesktopView
|
||||||
v-show="isDesktop"
|
v-if="isDesktop && !isGhatre"
|
||||||
@logout="showLogoutConfirm = true"
|
@logout="showLogoutConfirm = true"
|
||||||
@open-balance="openWholeBalanceVisible()"
|
@open-balance="openWholeBalanceVisible()"
|
||||||
/>
|
/>
|
||||||
<div v-show="!isDesktop" class="home-mobile-root pb-[calc(var(--app-bottom-chrome-height)+1rem)]">
|
<div v-show="!isDesktop || isGhatre" class="home-mobile-root pb-[calc(var(--app-bottom-chrome-height)+1rem)]">
|
||||||
<div class="app-header-scroll-sentinel" aria-hidden="true" />
|
<div class="app-header-scroll-sentinel" aria-hidden="true" />
|
||||||
<div
|
<div
|
||||||
v-if="!loading"
|
v-if="!loading"
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="px-5 py-5 shadow-lg rounded-2xl text-white relative overflow-hidden shadow-lg"
|
class="px-5 py-5 shadow-lg rounded-2xl text-white relative overflow-hidden shadow-lg"
|
||||||
style=" background: linear-gradient(145deg, #a72b77 0%, #711d4d 40%, #a72b77 100%); "
|
:style="{ background: heroGradient }"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="absolute inset-0 opacity-20"
|
class="absolute inset-0 opacity-20"
|
||||||
@@ -24,13 +24,13 @@
|
|||||||
<div class="relative z-10">
|
<div class="relative z-10">
|
||||||
<div class="flex font-bold text-lg items-center gap-2 mb-3">
|
<div class="flex font-bold text-lg items-center gap-2 mb-3">
|
||||||
<img src='@/assets/img/logo.png' alt='' class='h-8 drop-shadow-md' />
|
<img src='@/assets/img/logo.png' alt='' class='h-8 drop-shadow-md' />
|
||||||
<div class="tracking-wide">کشکول گلد </div>
|
<div class="tracking-wide">{{ projectNameFa }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-between items-end mb-3">
|
<div class="flex justify-between items-end mb-3">
|
||||||
<div class="text-sm" />
|
<div class="text-sm" />
|
||||||
<div>
|
<div>
|
||||||
<div class="text-xs opacity-75" style="justify-self: end;">شناسه شما در کشکول گلد</div>
|
<div class="text-xs opacity-75" style="justify-self: end;">{{ branding.idCardLabel }}</div>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div v-if="userStore?.userInfo?.virtual_card_number" class="ml-2 " @click.stop="copyCode()">
|
<div v-if="userStore?.userInfo?.virtual_card_number" class="ml-2 " @click.stop="copyCode()">
|
||||||
<BasicIcon
|
<BasicIcon
|
||||||
@@ -75,7 +75,7 @@
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="rounded-full w-[42px] h-[42px] bg-primary flex items-center justify-center"
|
class="rounded-full w-[42px] h-[42px] bg-primary flex items-center justify-center"
|
||||||
style="border: solid 1px #a72b77"
|
:style="actionBorderStyle"
|
||||||
|
|
||||||
>
|
>
|
||||||
<Icon class="text-tertiary" icon="vuesax-linear:money-send" />
|
<Icon class="text-tertiary" icon="vuesax-linear:money-send" />
|
||||||
@@ -89,7 +89,7 @@
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="rounded-full w-[50px] h-[50px] bg-primary flex items-center justify-center"
|
class="rounded-full w-[50px] h-[50px] bg-primary flex items-center justify-center"
|
||||||
style="border: solid 1px #a72b77"
|
:style="actionBorderStyle"
|
||||||
|
|
||||||
>
|
>
|
||||||
<Icon class="text-white" icon="vuesax-linear:money-receive" />
|
<Icon class="text-white" icon="vuesax-linear:money-receive" />
|
||||||
@@ -103,7 +103,7 @@
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="rounded-full w-[50px] h-[50px] bg-primary flex items-center justify-center"
|
class="rounded-full w-[50px] h-[50px] bg-primary flex items-center justify-center"
|
||||||
style="border: solid 1px #a72b77"
|
:style="actionBorderStyle"
|
||||||
|
|
||||||
>
|
>
|
||||||
<Icon class="text-white" icon="vuesax-linear:card-add" />
|
<Icon class="text-white" icon="vuesax-linear:card-add" />
|
||||||
@@ -117,7 +117,7 @@
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="rounded-full w-[50px] h-[50px] bg-primary flex items-center justify-center "
|
class="rounded-full w-[50px] h-[50px] bg-primary flex items-center justify-center "
|
||||||
style="border: solid 1px #a72b77"
|
:style="actionBorderStyle"
|
||||||
>
|
>
|
||||||
<Icon class="text-white" icon="vuesax-linear:receipt-item" />
|
<Icon class="text-white" icon="vuesax-linear:receipt-item" />
|
||||||
</div>
|
</div>
|
||||||
@@ -130,7 +130,7 @@
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="rounded-full w-[50px] h-[50px] bg-primary flex items-center justify-center"
|
class="rounded-full w-[50px] h-[50px] bg-primary flex items-center justify-center"
|
||||||
style=" border: solid 1px #a72b77"
|
:style="actionBorderStyle"
|
||||||
>
|
>
|
||||||
<Icon class="text-white font-bold" icon="vuesax-linear:archive-1" />
|
<Icon class="text-white font-bold" icon="vuesax-linear:archive-1" />
|
||||||
</div>
|
</div>
|
||||||
@@ -143,7 +143,7 @@
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="rounded-full w-[50px] h-[50px] bg-primary flex items-center justify-center"
|
class="rounded-full w-[50px] h-[50px] bg-primary flex items-center justify-center"
|
||||||
style=" border: solid 1px #a72b77"
|
:style="actionBorderStyle"
|
||||||
|
|
||||||
>
|
>
|
||||||
<Icon class="text-white font-bold" icon="vuesax-linear:dollar-circle" />
|
<Icon class="text-white font-bold" icon="vuesax-linear:dollar-circle" />
|
||||||
@@ -245,7 +245,7 @@
|
|||||||
>
|
>
|
||||||
|
|
||||||
<div class="w-full items-center flex flex-col">
|
<div class="w-full items-center flex flex-col">
|
||||||
<div class="text-gray-600">قیمت خرید از کشکول گلد</div>
|
<div class="text-gray-600">{{ branding.buyPriceLabel }}</div>
|
||||||
<div v-if="price" class="flex gap-1 mt-3 text-xs items-center">
|
<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">
|
<!-- <div id="odometer" class="font-bold text-2xl odometer animated fadeIn">
|
||||||
<!– {{ usePriceWithoutType(useCounterAnim(price.price_last) ?? 0) }}–>
|
<!– {{ usePriceWithoutType(useCounterAnim(price.price_last) ?? 0) }}–>
|
||||||
@@ -437,7 +437,7 @@
|
|||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
<div>🔥یه فرصت طلایی واقعی جلوتِ !🔥</div>
|
<div>🔥یه فرصت طلایی واقعی جلوتِ !🔥</div>
|
||||||
<div>دوستاتو همین الان به کشکول گلد دعوت کن!</div>
|
<div>دوستاتو همین الان به {{ projectNameFa }} دعوت کن!</div>
|
||||||
<div>اونا اولین خریدشونو کاملاً بدون کارمزد انجام میدن،۱۰٪ از کارمزد ۱۰ معاملهی اولشون هم، مستقیم میاد تو حساب تو!</div>
|
<div>اونا اولین خریدشونو کاملاً بدون کارمزد انجام میدن،۱۰٪ از کارمزد ۱۰ معاملهی اولشون هم، مستقیم میاد تو حساب تو!</div>
|
||||||
<div>زود باش، این فرصت همیشه باز نیست! ⏳✨</div>
|
<div>زود باش، این فرصت همیشه باز نیست! ⏳✨</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -471,6 +471,7 @@ import Vue3Odometer from 'vue3-odometer'
|
|||||||
import 'odometer/themes/odometer-theme-default.css'
|
import 'odometer/themes/odometer-theme-default.css'
|
||||||
import HomeSkeleton from '@/views/base/home/components/HomeSkeleton.vue'
|
import HomeSkeleton from '@/views/base/home/components/HomeSkeleton.vue'
|
||||||
import GhatrehHomeDesktopView from '@/views/base/home/desktop/GhatrehHomeDesktopView.vue'
|
import GhatrehHomeDesktopView from '@/views/base/home/desktop/GhatrehHomeDesktopView.vue'
|
||||||
|
import { useProject } from '@/composables/useProject'
|
||||||
import {
|
import {
|
||||||
getLastPrices,
|
getLastPrices,
|
||||||
getTradeBuyPrice,
|
getTradeBuyPrice,
|
||||||
@@ -498,6 +499,10 @@ import AppHeader from '@/views/base/home/components/AppHeader.vue'
|
|||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const walletStore = useWalletStore()
|
const walletStore = useWalletStore()
|
||||||
const isDesktop = useDesktopBreakpoint()
|
const isDesktop = useDesktopBreakpoint()
|
||||||
|
const { branding, projectNameFa, heroGradient, isGhatre, accentColor } = useProject()
|
||||||
|
const actionBorderStyle = computed(() => ({
|
||||||
|
border: `solid 1px ${accentColor.value}`,
|
||||||
|
}))
|
||||||
const chartLoading = ref<boolean>(false)
|
const chartLoading = ref<boolean>(false)
|
||||||
const openModal = ref<boolean>(false)
|
const openModal = ref<boolean>(false)
|
||||||
const wholeBalanceVisible = ref<boolean>(false)
|
const wholeBalanceVisible = ref<boolean>(false)
|
||||||
@@ -708,7 +713,7 @@ const priceChartOptions = ref({
|
|||||||
show: false
|
show: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
colors: ['#a72b77'],
|
colors: [accentColor.value],
|
||||||
fill: {
|
fill: {
|
||||||
type: 'gradient',
|
type: 'gradient',
|
||||||
gradient: {
|
gradient: {
|
||||||
@@ -720,6 +725,11 @@ const priceChartOptions = ref({
|
|||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
watch(accentColor, (color) => {
|
||||||
|
priceChartOptions.value.colors = [color]
|
||||||
|
}, { immediate: true })
|
||||||
|
|
||||||
const toPersianNumber = (num) => {
|
const toPersianNumber = (num) => {
|
||||||
return num.toString().replace(/\d/g, (d) => '۰۱۲۳۴۵۶۷۸۹'[d])
|
return num.toString().replace(/\d/g, (d) => '۰۱۲۳۴۵۶۷۸۹'[d])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<template>
|
||||||
|
<HomeDesktopView @logout="$emit('logout')" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import HomeDesktopView from '../desktop/HomeDesktopView.vue'
|
||||||
|
|
||||||
|
defineEmits<{
|
||||||
|
logout: []
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import type { HomeLayoutConfig } from '../types'
|
||||||
|
|
||||||
|
export const boursecuHomeLayoutConfig: HomeLayoutConfig = {
|
||||||
|
id: 'boursecu',
|
||||||
|
wrapperClass: 'dhome--boursecu',
|
||||||
|
sections: [
|
||||||
|
{ id: 'assets', visible: true },
|
||||||
|
{ id: 'currentPrice', visible: true },
|
||||||
|
{ id: 'priceChart', visible: true },
|
||||||
|
{ id: 'boursecuQuickActions', visible: true },
|
||||||
|
],
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import type { HomeQuickActionItem } from '../types'
|
||||||
|
|
||||||
|
export const boursecuQuickActions: HomeQuickActionItem[] = [
|
||||||
|
{
|
||||||
|
id: 'buy',
|
||||||
|
label: 'خرید',
|
||||||
|
icon: 'vuesax-linear:money-receive',
|
||||||
|
route: { name: 'gold', query: { state: 'buy' } },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'sell',
|
||||||
|
label: 'فروش',
|
||||||
|
icon: 'vuesax-linear:money-send',
|
||||||
|
route: { name: 'gold', query: { state: 'sell' } },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'wallet',
|
||||||
|
label: 'کیف پول',
|
||||||
|
icon: 'vuesax-linear:wallet-1',
|
||||||
|
route: { name: 'wallet' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'transactions',
|
||||||
|
label: 'گزارش',
|
||||||
|
icon: 'vuesax-linear:receipt-item',
|
||||||
|
route: { name: 'transactions' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'fund',
|
||||||
|
label: 'دارایی ها',
|
||||||
|
icon: 'vuesax-linear:archive-1',
|
||||||
|
route: { name: 'fund' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'shop',
|
||||||
|
label: 'فروشگاه',
|
||||||
|
icon: 'vuesax-linear:coin',
|
||||||
|
route: { name: 'buyProduct' },
|
||||||
|
},
|
||||||
|
]
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import type { HomeLayoutConfig } from '../types'
|
||||||
|
|
||||||
|
export const defaultHomeLayoutConfig: HomeLayoutConfig = {
|
||||||
|
id: 'default',
|
||||||
|
sections: [
|
||||||
|
{ id: 'currentPrice', visible: true },
|
||||||
|
{ id: 'assets', visible: true },
|
||||||
|
{ id: 'mainActions', visible: true },
|
||||||
|
{ id: 'priceChart', visible: true },
|
||||||
|
{ id: 'banners', visible: true },
|
||||||
|
],
|
||||||
|
}
|
||||||
@@ -87,8 +87,8 @@
|
|||||||
transition: border-color 0.15s ease, color 0.15s ease;
|
transition: border-color 0.15s ease, color 0.15s ease;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
border-color: @App-primary-color;
|
border-color: @theme-primary;
|
||||||
color: @App-primary-color;
|
color: @theme-primary;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -251,7 +251,7 @@
|
|||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
background: @App-primary-color;
|
background: @theme-primary;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
|||||||
@@ -46,7 +46,7 @@
|
|||||||
height: 56px;
|
height: 56px;
|
||||||
border-radius: 14px;
|
border-radius: 14px;
|
||||||
background: rgba(167, 43, 119, 0.08);
|
background: rgba(167, 43, 119, 0.08);
|
||||||
color: @App-primary-color;
|
color: @theme-primary;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@
|
|||||||
border: 1px solid rgba(167, 43, 119, 0.15);
|
border: 1px solid rgba(167, 43, 119, 0.15);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
background: rgba(167, 43, 119, 0.03);
|
background: rgba(167, 43, 119, 0.03);
|
||||||
color: @App-primary-color;
|
color: @theme-primary;
|
||||||
|
|
||||||
&__title {
|
&__title {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
|||||||
@@ -44,8 +44,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&--active {
|
&--active {
|
||||||
background: @App-primary-color;
|
background: @theme-primary;
|
||||||
border-color: @App-primary-color;
|
border-color: @theme-primary;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,7 +93,7 @@
|
|||||||
height: 64px;
|
height: 64px;
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
background: linear-gradient(135deg, #f0f4ff 0%, #e8eeff 100%);
|
background: linear-gradient(135deg, #f0f4ff 0%, #e8eeff 100%);
|
||||||
color: @App-primary-color;
|
color: @theme-primary;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,8 +174,8 @@
|
|||||||
|
|
||||||
&--primary {
|
&--primary {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: @App-primary-color;
|
background: @theme-primary;
|
||||||
border-color: @App-primary-color;
|
border-color: @theme-primary;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
|
|||||||
@@ -75,7 +75,7 @@
|
|||||||
|
|
||||||
&--active {
|
&--active {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
color: @App-primary-color;
|
color: @theme-primary;
|
||||||
box-shadow: 0 1px 3px rgba(15, 23, 42, 0.08);
|
box-shadow: 0 1px 3px rgba(15, 23, 42, 0.08);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -182,8 +182,8 @@
|
|||||||
transition: border-color 0.15s ease, background 0.15s ease, color 0.15s ease;
|
transition: border-color 0.15s ease, background 0.15s ease, color 0.15s ease;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
border-color: @App-primary-color;
|
border-color: @theme-primary;
|
||||||
color: @App-primary-color;
|
color: @theme-primary;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -255,13 +255,13 @@
|
|||||||
transition: border-color 0.15s ease, color 0.15s ease;
|
transition: border-color 0.15s ease, color 0.15s ease;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
border-color: @App-primary-color;
|
border-color: @theme-primary;
|
||||||
color: @App-primary-color;
|
color: @theme-primary;
|
||||||
}
|
}
|
||||||
|
|
||||||
&--primary {
|
&--primary {
|
||||||
background: @App-primary-color;
|
background: @theme-primary;
|
||||||
border-color: @App-primary-color;
|
border-color: @theme-primary;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
padding: 10px 16px;
|
padding: 10px 16px;
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@ export default defineConfig({
|
|||||||
],
|
],
|
||||||
theme: {
|
theme: {
|
||||||
colors: {
|
colors: {
|
||||||
"primary": "#a72b77",
|
"primary": "var(--app-primary-color, #a72b77)",
|
||||||
"secondary": "#ffffff",
|
"secondary": "#ffffff",
|
||||||
"tertiary": "#e0be7f"
|
"tertiary": "#e0be7f"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user