From 0f50ec315cb890a01afbe7b6a117e9c300ecfb53 Mon Sep 17 00:00:00 2001 From: safavimohadeseh78 Date: Thu, 5 Nov 2026 17:17:29 +0330 Subject: [PATCH] feat: add required kyc blocking modal and fix copper asset units to kilogram --- components.d.ts | 1 + src/App.vue | 7 +- src/app/setupRouter.ts | 10 + src/components/RequiredKycModal.vue | 352 ++++++++++++++++++ src/utils/authSession.ts | 43 +++ src/utils/bankBranding.ts | 2 +- src/utils/productAssets.ts | 30 +- src/utils/weightUnit.ts | 5 +- src/views/base/assets/index.vue | 16 +- .../home/components/PortfolioOverview.vue | 3 +- .../components/PortfolioProfitInsight.vue | 3 +- .../base/user/composables/useUserPage.ts | 13 +- src/views/base/wallet/components/Item.vue | 4 +- src/views/login/components/Register.vue | 2 +- .../desktop/components/DesktopAuthShell.vue | 4 +- .../components/DesktopRegisterForm.vue | 2 +- .../login/desktop/styles/desktop-auth.less | 27 +- src/views/login/index.vue | 21 +- 18 files changed, 495 insertions(+), 50 deletions(-) create mode 100644 src/components/RequiredKycModal.vue create mode 100644 src/utils/authSession.ts diff --git a/components.d.ts b/components.d.ts index 2dab5e3..e3385b0 100644 --- a/components.d.ts +++ b/components.d.ts @@ -68,6 +68,7 @@ declare module 'vue' { PwaInstallGuideModal: typeof import('./src/components/pwa/PwaInstallGuideModal.vue')['default'] PwaInstallStepIllustration: typeof import('./src/components/pwa/PwaInstallStepIllustration.vue')['default'] RangePicker: typeof import('./src/components/BasicPacks/BaseDatePicker/src/datePick/demo/range-picker.vue')['default'] + RequiredKycModal: typeof import('./src/components/RequiredKycModal.vue')['default'] RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] SelectInRange: typeof import('./src/components/BasicPacks/BaseDatePicker/src/datePick/demo/select-in-range.vue')['default'] diff --git a/src/App.vue b/src/App.vue index 62c5602..901e765 100644 --- a/src/App.vue +++ b/src/App.vue @@ -30,9 +30,10 @@ +
Boolean(getToken()) && (userStore.userInfo?.is_legal === 0 || !userStore.userInfo?.is_legal), +) const settingsStore = useSettingsStore() const showLoginCreditExtras = computed(() => { if (!isLoginRoute.value) return false diff --git a/src/app/setupRouter.ts b/src/app/setupRouter.ts index ba20c09..f49894b 100644 --- a/src/app/setupRouter.ts +++ b/src/app/setupRouter.ts @@ -82,6 +82,16 @@ export function setupRouterGuards() { return goToLogin(next) } + // کاربر احراز هویت نشده نباید بتواند به صفحات داخلی دسترسی پیدا کند + if ( + userStore.userInfo && + (userStore.userInfo.is_legal === 0 || !userStore.userInfo.is_legal) && + !isPublicRoute(to) && + to.name !== 'home' + ) { + return goToHome(next) + } + if (to.name === 'notifyTrigger') { const { useSettingsStore } = await import('@/store/settingsStore') const settingsStore = useSettingsStore() diff --git a/src/components/RequiredKycModal.vue b/src/components/RequiredKycModal.vue new file mode 100644 index 0000000..ba93cc7 --- /dev/null +++ b/src/components/RequiredKycModal.vue @@ -0,0 +1,352 @@ + + + + + diff --git a/src/utils/authSession.ts b/src/utils/authSession.ts new file mode 100644 index 0000000..6577f86 --- /dev/null +++ b/src/utils/authSession.ts @@ -0,0 +1,43 @@ +import router from '@/router' +import { removeToken } from '@/utils' +import { useUserStore } from '@/store/userStore' +import { useWalletStore } from '@/store/walletStore' +import { useWalletAssets } from '@/composables/useWalletAssets' +import { resetHomePageData } from '@/views/base/home/composables/useHomePageData' +import { resetWalletPageData } from '@/views/base/wallet/composables/useWalletPageData' +import { resetAddressPageData } from '@/views/base/address/composables/useAddressPageData' +import { resetTransactionsPageData } from '@/views/base/transactions/composables/useTransactionsPageData' +import { resetProductsPageData } from '@/views/base/products/composables/useProductsPageData' + +export async function performUserLogout() { + try { + const userStore = useUserStore() + const walletStore = useWalletStore() + userStore.userInfo = undefined + walletStore.walletInfo = undefined + try { + const { clearWalletAssets } = useWalletAssets() + clearWalletAssets() + } catch { + // ignore + } + try { resetHomePageData() } catch {} + try { resetWalletPageData() } catch {} + try { resetAddressPageData() } catch {} + try { resetTransactionsPageData() } catch {} + try { resetProductsPageData() } catch {} + } catch (e) { + console.error('Logout cleanup error:', e) + } + + removeToken() + + try { + await router.push({ name: 'login' }) + } catch { + // ignore + } + + window.location.reload() +} + diff --git a/src/utils/bankBranding.ts b/src/utils/bankBranding.ts index acd07de..1ab20c9 100644 --- a/src/utils/bankBranding.ts +++ b/src/utils/bankBranding.ts @@ -7,7 +7,7 @@ interface BankDefinition { aliases: string[] } -const bankLogoModules = import.meta.glob('@/assets/img/banks/*.{png,svg}', { +const bankLogoModules = import.meta.glob('../assets/img/banks/*.{png,svg}', { eager: true, import: 'default', }) diff --git a/src/utils/productAssets.ts b/src/utils/productAssets.ts index 6b1fa22..32b5907 100644 --- a/src/utils/productAssets.ts +++ b/src/utils/productAssets.ts @@ -186,6 +186,14 @@ function sumBoursecuHomeProductInventories( return sum } +export function resolveBoursecuCopperUnit(unit?: string | null): string { + const trimmed = (unit ?? '').trim() + if (!trimmed || trimmed === 'گرم' || trimmed === 'gram' || trimmed === 'g') { + return 'کیلوگرم' + } + return trimmed +} + function findMetalTotalById(metalTotals: WalletMetalTotal[], metalId: number) { return metalTotals.find((metal) => metal.metal_id === metalId) } @@ -195,7 +203,8 @@ function formatBoursecuMetalRowValue(metal: WalletMetalTotal): string { if (metal.metal_id === METAL_GOLD) { return `${amount} عدد` } - return `${amount}${metal.unit ?? ''}` + const unit = metal.metal_id === METAL_COPPER ? resolveBoursecuCopperUnit(metal.unit) : (metal.unit ?? 'کیلوگرم') + return `${amount} ${unit}` } function formatRialNumber(value: number): string { @@ -237,8 +246,11 @@ function buildBoursecuCopperPopupLines(summary: { const metalTotals = summary.metal_totals ?? [] const copperMetal = findMetalTotalById(metalTotals, METAL_COPPER) const shamshMetal = findMetalTotalById(metalTotals, METAL_GOLD) - const weightUnit = copperMetal?.unit || 'کیلوگرم' - const totalWeight = sumBoursecuHomeProductInventories(inventoryCards, countProducts) + const weightUnit = resolveBoursecuCopperUnit(copperMetal?.unit) + const totalWeight = + copperMetal != null && Number(copperMetal.total_weight ?? 0) > 0 + ? Number(copperMetal.total_weight) + : sumBoursecuHomeProductInventories(inventoryCards, countProducts) const katodCard = findBoursecuProductCard(inventoryCards, countProducts, isBoursecuKatodCard) const maftolCard = findBoursecuProductCard(inventoryCards, countProducts, isBoursecuMaftolCard) @@ -319,10 +331,10 @@ export function buildBoursecuHomeAssetRows( const countProducts = summary.count_products ?? [] const metalTotals = summary.metal_totals ?? [] const copperMetal = findMetalTotalById(metalTotals, METAL_COPPER) - const weightUnit = copperMetal?.unit || 'کیلوگرم' + const weightUnit = resolveBoursecuCopperUnit(copperMetal?.unit) const totalCopperWeight = - copperMetal != null - ? Number(copperMetal.total_weight ?? 0) + copperMetal != null && Number(copperMetal.total_weight ?? 0) > 0 + ? Number(copperMetal.total_weight) : sumBoursecuHomeProductInventories(inventoryCards, countProducts) const cash = Number(summary.cash_wallet ?? 0) @@ -387,7 +399,7 @@ export function resolveSummaryMetalWeight( /** متن توضیح مودال دارایی فلزی — بر اساس metal_totals سرور، بدون هاردکد طلا */ export function formatMetalAssetsInfoText(metal: WalletMetalTotal): string { - const unit = metal.unit || 'گرم' + const unit = metal.metal_id === METAL_COPPER ? resolveBoursecuCopperUnit(metal.unit) : (metal.unit || 'کیلوگرم') return `${metal.label}: مجموع کیف محصولات (${metal.product_weight} ${unit}) + موجودی کیف اصلی (${metal.melted_weight} ${unit})` } @@ -510,7 +522,7 @@ export function computeMetalRialValue( const metalId = Number(metal.metal_id ?? 0) const unitPrice = livePricesByMetal?.[metalId] ?? - (metalId === METAL_GOLD ? liveGoldPrice : 0) + (metalId === METAL_COPPER || metalId === METAL_GOLD ? liveGoldPrice : 0) return sum + weight * unitPrice }, 0) @@ -534,7 +546,7 @@ export function formatInventoryCardValue(card: { display_type?: string }): string { const quantity = Number(card.quantity ?? 0) - const unit = card.unit ?? (card.display_type === 'count' ? 'عدد' : 'گرم') + const unit = card.unit ?? (card.display_type === 'count' ? 'عدد' : 'کیلوگرم') const formatted = card.display_type === 'count' ? usePriceWithoutType(quantity, false) diff --git a/src/utils/weightUnit.ts b/src/utils/weightUnit.ts index 3309b20..57d5aa8 100644 --- a/src/utils/weightUnit.ts +++ b/src/utils/weightUnit.ts @@ -6,8 +6,11 @@ export function isKilogramUnit(unit?: string | null) { return value === TRADE_WEIGHT_UNIT_KILOGRAM || value === 'kilogram' || value === 'kg' } -/** واحد نمایش از ستینگ — خالی یا نامعتبر = گرم */ +/** واحد نمایش از ستینگ — در بورس مس پیش‌فرض همیشه کیلوگرم است */ export function resolveTradeWeightUnit(settingValue?: string | number | null) { + if (!settingValue) { + return TRADE_WEIGHT_UNIT_KILOGRAM + } return isKilogramUnit(settingValue?.toString()) ? TRADE_WEIGHT_UNIT_KILOGRAM : TRADE_WEIGHT_UNIT_GRAM } diff --git a/src/views/base/assets/index.vue b/src/views/base/assets/index.vue index 6be79c1..433fbf6 100644 --- a/src/views/base/assets/index.vue +++ b/src/views/base/assets/index.vue @@ -175,8 +175,10 @@ import { formatPortfolioProfitPercent, formatPortfolioProfitText, resolveAssetsRialValue, + resolveBoursecuCopperUnit, resolveMetalAssetsDisplayLabel, } from '@/utils/productAssets' +import { formatWeightAmount } from '@/utils/usePrice' import type { WalletMetalTotal } from '@/models/walletAssets' import { useAssetsPortfolioChart } from './composables/useAssetsPortfolioChart' import assetsCopperBanner from '@/assets/img/assets-copper-banner.webp' @@ -265,10 +267,13 @@ const profitClass = computed(() => { }) const summaryItems = computed(() => { - const items = metalTotals.value.map((metal) => ({ - label: assetsMetalLabel(metal), - value: `${metal.total_weight} ${metal.unit}`, - })) + const items = metalTotals.value.map((metal) => { + const unit = metal.metal_id === 3 ? resolveBoursecuCopperUnit(metal.unit) : (metal.unit || 'کیلوگرم') + return { + label: assetsMetalLabel(metal), + value: `${formatWeightAmount(Number(metal.total_weight ?? 0))} ${unit}`, + } + }) items.push( { label: 'کیف پول ریالی', value: usePrice(cashWallet.value) }, { label: 'ارزش ریالی مس', value: usePrice(metalRialValue.value) }, @@ -287,10 +292,11 @@ const assetRows = computed(() => { const profit = portfolioInsight.value?.unrealized_profit_rial const changeClass = profit == null || profit === 0 ? '' : profit > 0 ? 'is-profit' : 'is-loss' const rows = metalTotals.value.flatMap((metal) => { + const unit = metal.metal_id === 3 ? resolveBoursecuCopperUnit(metal.unit) : (metal.unit || 'کیلوگرم') const head = { key: `metal-${metal.metal_id}`, name: assetsMetalLabel(metal), - balance: `${metal.total_weight} ${metal.unit}`, + balance: `${formatWeightAmount(Number(metal.total_weight ?? 0))} ${unit}`, rial: usePrice(metalRialValue.value), change: pct || '—', changeClass, diff --git a/src/views/base/home/components/PortfolioOverview.vue b/src/views/base/home/components/PortfolioOverview.vue index a42e967..0f698f6 100644 --- a/src/views/base/home/components/PortfolioOverview.vue +++ b/src/views/base/home/components/PortfolioOverview.vue @@ -62,6 +62,7 @@ import { formatPortfolioProfitPercent, formatPortfolioProfitText, resolveAssetsRialValue, + resolveBoursecuCopperUnit, } from '@/utils/productAssets' import { formatWeightAmount, usePriceWithoutType } from '@/utils/usePrice' import { getTradeBuyPrice, lastPrice } from '@/utils/price' @@ -76,7 +77,7 @@ const props = withDefaults( const { assetsSummary } = useWalletAssets() const portfolio = computed(() => assetsSummary.value?.portfolio) -const weightUnit = computed(() => assetsSummary.value?.meta?.weight_unit || 'گرم') +const weightUnit = computed(() => resolveBoursecuCopperUnit(assetsSummary.value?.meta?.weight_unit)) const totalRial = computed(() => Number(portfolio.value?.total_rial_value ?? assetsSummary.value?.total_rial_value ?? 0) diff --git a/src/views/base/home/components/PortfolioProfitInsight.vue b/src/views/base/home/components/PortfolioProfitInsight.vue index 33eabde..567ecb3 100644 --- a/src/views/base/home/components/PortfolioProfitInsight.vue +++ b/src/views/base/home/components/PortfolioProfitInsight.vue @@ -43,6 +43,7 @@ import { formatPortfolioProfitLabel, formatPortfolioProfitPercent, formatPortfolioProfitText, + resolveBoursecuCopperUnit, } from '@/utils/productAssets' const props = withDefaults( @@ -55,7 +56,7 @@ const props = withDefaults( const { assetsSummary } = useWalletAssets() const portfolio = computed(() => assetsSummary.value?.portfolio) -const weightUnit = computed(() => assetsSummary.value?.meta?.weight_unit || 'گرم') +const weightUnit = computed(() => resolveBoursecuCopperUnit(assetsSummary.value?.meta?.weight_unit)) const hasProfitInsight = computed(() => portfolio.value?.unrealized_profit_rial != null) const profitTone = computed(() => formatPortfolioProfitLabel(portfolio.value?.unrealized_profit_rial)) diff --git a/src/views/base/user/composables/useUserPage.ts b/src/views/base/user/composables/useUserPage.ts index edbe0ba..d80e4a2 100644 --- a/src/views/base/user/composables/useUserPage.ts +++ b/src/views/base/user/composables/useUserPage.ts @@ -20,6 +20,7 @@ import { getBoursecuActionIconSrc } from '@/utils/config' import { useDesktopBreakpoint } from '@/layouts/composables/useAppLayout' import { getReferralShareText, getReferralShareTitle, shareReferralText } from '@/utils/referralShare' import { normalizeAuthFormFields } from '@/utils/persianDigits' +import { performUserLogout } from '@/utils/authSession' import { useSettingsStore } from '@/store/settingsStore' import { useTrackingSystemsFeature } from '@/composables/useTrackingSystemsFeature' import { openGoldDayCalculator } from '@/composables/useGoldDayCalculator' @@ -300,18 +301,8 @@ export function useUserPage() { } async function logout() { - userStore.userInfo = undefined - walletStore.walletInfo = undefined - clearWalletAssets() - resetHomePageData() - resetWalletPageData() - resetAddressPageData() - resetTransactionsPageData() - resetProductsPageData() - removeToken() showLogoutConfirm.value = false - await router.push({ name: 'login' }) - window.location.reload() + await performUserLogout() } onMounted(() => { diff --git a/src/views/base/wallet/components/Item.vue b/src/views/base/wallet/components/Item.vue index 7e5d7f1..2c8c41d 100644 --- a/src/views/base/wallet/components/Item.vue +++ b/src/views/base/wallet/components/Item.vue @@ -68,11 +68,11 @@
مقدار {{ getMetalTypeTradeLabel() }} مبادله شده:
{{ formatGoldAmount(item.gold) }}
- گرم + {{ getWeightUnit() }}
-
قیمت هر گرم {{ getTradePriceUnitLabel() }} حین معامله:
+
قیمت هر {{ getWeightUnit() }} {{ getTradePriceUnitLabel() }} حین معامله:
{{ usePriceWithoutType(item.order?.price?? 0) }}
ریال diff --git a/src/views/login/components/Register.vue b/src/views/login/components/Register.vue index 6e20f78..f8b6abe 100644 --- a/src/views/login/components/Register.vue +++ b/src/views/login/components/Register.vue @@ -77,7 +77,7 @@ /> - پشتیبانی +