diff --git a/src/utils/productAssets.ts b/src/utils/productAssets.ts
index dbf9a88..346fdf6 100644
--- a/src/utils/productAssets.ts
+++ b/src/utils/productAssets.ts
@@ -47,6 +47,138 @@ export function getTotalMetalLabel(metalId: number): string {
return `کل دارایی ${getMetalLabel(metalId)}`
}
+/** boursecu home — ترتیب نمایش: مس، طلا، سایر فلزها */
+export function resolveBoursecuAssetMetalTotals(
+ metalTotals: WalletMetalTotal[]
+): WalletMetalTotal[] {
+ if (!metalTotals.length) {
+ return []
+ }
+
+ const ordered: WalletMetalTotal[] = []
+ const copper = metalTotals.find((metal) => metal.metal_id === METAL_COPPER)
+ const gold = metalTotals.find((metal) => metal.metal_id === METAL_GOLD)
+
+ if (copper) {
+ ordered.push(copper)
+ }
+ if (gold) {
+ ordered.push(gold)
+ }
+
+ for (const metal of metalTotals) {
+ if (!ordered.some((item) => item.metal_id === metal.metal_id)) {
+ ordered.push(metal)
+ }
+ }
+
+ return ordered
+}
+
+export function resolveMetalAssetsDisplayLabel(
+ metal: WalletMetalTotal,
+ isBoursecuLayout: boolean
+): string {
+ if (!isBoursecuLayout) {
+ return metal.label
+ }
+
+ switch (metal.metal_id) {
+ case METAL_COPPER:
+ return 'دارایی مس'
+ case METAL_GOLD:
+ return 'دارایی طلایی'
+ case METAL_SILVER:
+ return 'دارایی نقره'
+ default:
+ return metal.label
+ }
+}
+
+export type HomeAssetRowInfo = 'metal' | 'rial' | 'none'
+
+export interface HomeAssetRow {
+ id: string
+ label: string
+ value: string
+ metal?: WalletMetalTotal
+ info: HomeAssetRowInfo
+}
+
+function formatInventoryCardProductLabel(card: WalletInventoryCard): string {
+ return `دارایی ${card.title}`
+}
+
+function findMetalTotalById(metalTotals: WalletMetalTotal[], metalId: number) {
+ return metalTotals.find((metal) => metal.metal_id === metalId)
+}
+
+/** boursecu home — هر محصول / فلز / ریال از customer/wallet/assets جدا نمایش داده میشود */
+export function buildBoursecuHomeAssetRows(
+ summary: {
+ inventory_cards?: WalletInventoryCard[]
+ count_products?: WalletInventoryCard[]
+ metal_totals?: WalletMetalTotal[]
+ total_rial_value?: number
+ } | null | undefined
+): HomeAssetRow[] {
+ if (!summary) {
+ return []
+ }
+
+ const rows: HomeAssetRow[] = []
+ const metalTotals = summary.metal_totals ?? []
+ const inventoryCards = summary.inventory_cards ?? []
+ const countProducts = summary.count_products ?? []
+
+ for (const card of inventoryCards) {
+ if (card.display_type === 'count') {
+ continue
+ }
+
+ rows.push({
+ id: `inventory-${card.product_id}`,
+ label: formatInventoryCardProductLabel(card),
+ value: formatInventoryCardValue(card),
+ metal: findMetalTotalById(metalTotals, card.metal_id),
+ info: 'metal',
+ })
+ }
+
+ for (const metal of metalTotals) {
+ if (metal.metal_id === METAL_COPPER) {
+ continue
+ }
+
+ rows.push({
+ id: `metal-${metal.metal_id}`,
+ label: resolveMetalAssetsDisplayLabel(metal, true),
+ value: `${Number(metal.total_weight ?? 0)}${metal.unit ?? ''}`,
+ metal,
+ info: 'metal',
+ })
+ }
+
+ for (const card of countProducts) {
+ rows.push({
+ id: `count-${card.product_id}`,
+ label: formatInventoryCardProductLabel(card),
+ value: formatInventoryCardValue(card),
+ metal: findMetalTotalById(metalTotals, card.metal_id),
+ info: 'metal',
+ })
+ }
+
+ rows.push({
+ id: 'rial-total',
+ label: 'دارایی ریالی',
+ value: `${formatRialNumber(summary.total_rial_value ?? 0)} ریال`,
+ info: 'rial',
+ })
+
+ return rows
+}
+
export function sumInventoryCardsWeight(
cards: Array<{ metal_id?: number; quantity?: number }>,
metalId: number
diff --git a/src/views/base/home/components/AssetsSection.vue b/src/views/base/home/components/AssetsSection.vue
index 4da29b9..166181e 100644
--- a/src/views/base/home/components/AssetsSection.vue
+++ b/src/views/base/home/components/AssetsSection.vue
@@ -1,14 +1,34 @@
محصولات:
{{ countBasedInventory }} عدد
-
+
+
+
+ {{ row.label }}:
+
{{ row.value }}
+
+
+
+
+
{{ primaryMetalTotal.label }}:
{{ formatMetalTotal(primaryMetalTotal) }}
@@ -20,7 +40,8 @@
/>
-
+
+
+
+
+ دارایی ریالی:
+
{{ usePriceWithoutType(totalRialValue) }} ریال
+
+
-
- دارایی ریالی:
-
{{ usePriceWithoutType(totalRialValue) }} ریال
-
-
@@ -57,29 +79,36 @@ import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
import { usePriceWithoutType } from '@/utils/usePrice'
import { useWalletAssets } from '@/composables/useWalletAssets'
import type { WalletMetalTotal } from '@/models/walletAssets'
-import { resolveSummaryMetalWeight } from '@/utils/productAssets'
+import {
+ buildBoursecuHomeAssetRows,
+ resolveSummaryMetalWeight,
+ type HomeAssetRow,
+} from '@/utils/productAssets'
const props = withDefaults(
defineProps<{
plain?: boolean
+ boursecuLayout?: boolean
}>(),
- { plain: false }
+ { plain: false, boursecuLayout: false }
)
-/** Display-only — wallet assets are loaded once in useHomePageData.initHomePageData() */
-const { assetsSummary } = useWalletAssets()
-
-defineEmits<{
+const emit = defineEmits<{
openGoldModal: [metal: WalletMetalTotal]
openRialModal: []
}>()
+const { assetsSummary } = useWalletAssets()
+
const rowClass = computed(() => (props.plain ? 'text-primary' : 'text-tertiary'))
const iconColor = computed(() => (props.plain ? 'primary' : 'tertiary'))
const meta = computed(() => assetsSummary.value?.meta)
const metalTotals = computed(() => assetsSummary.value?.metal_totals ?? [])
const primaryMetalTotal = computed(() => metalTotals.value[0])
+const boursecuAssetRows = computed(() =>
+ props.boursecuLayout ? buildBoursecuHomeAssetRows(assetsSummary.value) : []
+)
const totalRialValue = computed(() => assetsSummary.value?.total_rial_value ?? 0)
const inventoryCards = computed(() => assetsSummary.value?.inventory_cards ?? [])
const countBasedInventory = computed(() =>
@@ -89,4 +118,15 @@ const countBasedInventory = computed(() =>
function formatMetalTotal(metal: WalletMetalTotal) {
return `${resolveSummaryMetalWeight(metal, inventoryCards.value)}${metal.unit}`
}
+
+function handleRowInfo(row: HomeAssetRow) {
+ if (row.info === 'rial') {
+ emit('openRialModal')
+ return
+ }
+
+ if (row.metal) {
+ emit('openGoldModal', row.metal)
+ }
+}
diff --git a/src/views/base/home/components/PriceStats.vue b/src/views/base/home/components/PriceStats.vue
index 5fedcd8..2862caa 100644
--- a/src/views/base/home/components/PriceStats.vue
+++ b/src/views/base/home/components/PriceStats.vue
@@ -32,21 +32,35 @@
diff --git a/src/views/base/home/composables/usePriceChart.ts b/src/views/base/home/composables/usePriceChart.ts
index 1982ffe..2208e08 100644
--- a/src/views/base/home/composables/usePriceChart.ts
+++ b/src/views/base/home/composables/usePriceChart.ts
@@ -5,7 +5,7 @@ import { getProductsCatalog } from '@/composables/useProductsCatalog'
import { getHomeLayoutId } from '../layouts/registry'
import { getProductBuyPrice, resolvePriceOffsetRatio } from '@/utils/productPrice'
import { isKatodMesGroup, isMaftolMesGroup } from '@/utils/productDealMethod'
-import { getTradeBuyPrice, lastPrice } from '@/utils/price'
+import { getTradeBuyPrice, getTradeSellPrice, lastPrice } from '@/utils/price'
export type ChartMetalType = 'katod' | 'maftol'
@@ -48,6 +48,26 @@ function applyChartRatio(basePrice: number, ratio: number) {
return Math.round(basePrice + basePrice * ratio)
}
+/** بالاترین/پایینترین امروز — برای boursecu با نسبت مفتول نسبت به کاتد */
+export function resolveMetalDayRangePrices(options: {
+ price: { up?: { buy?: number; sell?: number }; buy?: number; sell?: number; price_last?: number } | null | undefined
+ metal: ChartMetalType
+ isBoursecuLayout: boolean
+ maftolRatio: number
+}) {
+ const baseHigh = options.price?.up?.buy ?? getTradeBuyPrice(options.price as Parameters[0])
+ const baseLow = options.price?.up?.sell ?? getTradeSellPrice(options.price as Parameters[0])
+
+ if (!options.isBoursecuLayout || options.metal === 'katod') {
+ return { high: baseHigh, low: baseLow }
+ }
+
+ return {
+ high: applyChartRatio(baseHigh, options.maftolRatio),
+ low: applyChartRatio(baseLow, options.maftolRatio),
+ }
+}
+
function deriveMaftolChartRatio(maftolProduct?: Product, katodProduct?: Product) {
const offsetRatio = resolvePriceOffsetRatio(maftolProduct?.price_offset_percent)
if (offsetRatio) {
diff --git a/src/views/base/home/desktop/components/DesktopAssetsMetrics.vue b/src/views/base/home/desktop/components/DesktopAssetsMetrics.vue
index 2096e42..aa885cd 100644
--- a/src/views/base/home/desktop/components/DesktopAssetsMetrics.vue
+++ b/src/views/base/home/desktop/components/DesktopAssetsMetrics.vue
@@ -4,7 +4,8 @@ import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
import { usePriceWithoutType } from '@/utils/usePrice'
import { useWalletAssets } from '@/composables/useWalletAssets'
import type { WalletMetalTotal } from '@/models/walletAssets'
-import { resolveSummaryMetalWeight } from '@/utils/productAssets'
+import { buildBoursecuHomeAssetRows, resolveSummaryMetalWeight } from '@/utils/productAssets'
+import { useHomePageContext } from '../../composables/useHomePage'
const emit = defineEmits<{
openGoldModal: [metal: WalletMetalTotal]
@@ -12,6 +13,8 @@ const emit = defineEmits<{
}>()
const { assetsSummary } = useWalletAssets()
+const ctx = useHomePageContext()
+const isBoursecuLayout = computed(() => ctx.isBoursecuHomeLayout.value)
const meta = computed(() => assetsSummary.value?.meta)
const metalTotals = computed(() => assetsSummary.value?.metal_totals ?? [])
@@ -41,6 +44,20 @@ const metrics = computed(() => {
})
}
+ if (isBoursecuLayout.value) {
+ buildBoursecuHomeAssetRows(assetsSummary.value).forEach((row) => {
+ items.push({
+ id: row.id,
+ label: row.label,
+ value: row.value,
+ metal: row.metal,
+ showInfo: row.info !== 'none',
+ onInfo: row.info === 'rial' ? 'rial' : 'gold',
+ })
+ })
+ return items
+ }
+
if (meta.value?.single_metal && metalTotals.value[0]) {
const metal = metalTotals.value[0]
items.push({
diff --git a/src/views/base/home/desktop/components/DesktopPriceRange.vue b/src/views/base/home/desktop/components/DesktopPriceRange.vue
index a9bcb3b..1f80fb1 100644
--- a/src/views/base/home/desktop/components/DesktopPriceRange.vue
+++ b/src/views/base/home/desktop/components/DesktopPriceRange.vue
@@ -1,10 +1,24 @@
diff --git a/src/views/base/home/layouts/sections/AssetsSectionBlock.vue b/src/views/base/home/layouts/sections/AssetsSectionBlock.vue
index afc9610..62f6b91 100644
--- a/src/views/base/home/layouts/sections/AssetsSectionBlock.vue
+++ b/src/views/base/home/layouts/sections/AssetsSectionBlock.vue
@@ -10,6 +10,7 @@ const isPlainAssets = computed(() => ctx.isBoursecuHomeLayout.value)
diff --git a/src/views/base/home/layouts/sections/PriceStatsSection.vue b/src/views/base/home/layouts/sections/PriceStatsSection.vue
index 2b194c6..5d17187 100644
--- a/src/views/base/home/layouts/sections/PriceStatsSection.vue
+++ b/src/views/base/home/layouts/sections/PriceStatsSection.vue
@@ -3,11 +3,19 @@ import { computed, inject } from 'vue'
import PriceStats from '../../components/PriceStats.vue'
import { price } from '@/utils/price'
import { HOME_PAGE_CONTEXT_KEY } from '../../composables/useHomePage'
+import { usePriceChart } from '../../composables/usePriceChart'
const ctx = inject(HOME_PAGE_CONTEXT_KEY)!
+const { maftolChartRatio } = usePriceChart()
const layout = computed(() => (ctx.isBoursecuHomeLayout.value ? 'boursecu' : 'default'))
+const selectedMetal = computed(() => ctx.selectedChartMetal.value)
-
+
diff --git a/src/views/base/rules/components/RulesContentPanel.vue b/src/views/base/rules/components/RulesContentPanel.vue
index a101fd0..c12d6ce 100644
--- a/src/views/base/rules/components/RulesContentPanel.vue
+++ b/src/views/base/rules/components/RulesContentPanel.vue
@@ -55,7 +55,7 @@ const { rulesTitle, rulesBlocks } = useRulesPageContext()
.rules-paragraph {
margin: 0 0 1rem;
- text-align: justify;
+ text-align: right;
line-height: 1.9;
word-break: normal;
overflow-wrap: break-word;
diff --git a/src/views/base/rules/desktop/styles/desktop-rules.less b/src/views/base/rules/desktop/styles/desktop-rules.less
index 9487519..157dde9 100644
--- a/src/views/base/rules/desktop/styles/desktop-rules.less
+++ b/src/views/base/rules/desktop/styles/desktop-rules.less
@@ -151,7 +151,7 @@
margin: 0 0 14px;
font-size: 14px;
line-height: 1.9;
- text-align: justify;
+ text-align: right;
color: inherit;
word-break: normal;
overflow-wrap: break-word;
diff --git a/src/views/base/rules/mobile/MobileRulesView.vue b/src/views/base/rules/mobile/MobileRulesView.vue
index 82a9ee6..698cd14 100644
--- a/src/views/base/rules/mobile/MobileRulesView.vue
+++ b/src/views/base/rules/mobile/MobileRulesView.vue
@@ -10,7 +10,7 @@
-