changes of boursemes &...
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 79 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 194 KiB |
|
After Width: | Height: | Size: 105 KiB |
|
After Width: | Height: | Size: 129 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 102 KiB |
|
After Width: | Height: | Size: 121 KiB |
@@ -1,6 +1,16 @@
|
||||
import ayandehLogo from '@/assets/img/banks/ayandeh.png'
|
||||
import keshavarziLogo from '@/assets/img/banks/keshavarzi.png'
|
||||
import mellatLogo from '@/assets/img/banks/mellat.png'
|
||||
import melliLogo from '@/assets/img/banks/melli.png'
|
||||
import pasargadLogo from '@/assets/img/banks/pasargad.png'
|
||||
import refahLogo from '@/assets/img/banks/refah.png'
|
||||
import samanLogo from '@/assets/img/banks/saman.png'
|
||||
import sarmayehLogo from '@/assets/img/banks/sarmayeh.png'
|
||||
|
||||
const BANK_ACCENT_COLORS: Record<string, string> = {
|
||||
'بانک پاسارگاد': '#1f7a54',
|
||||
'پاسارگاد': '#1f7a54',
|
||||
'PASARGAD': '#1f7a54',
|
||||
'بانک سامان': '#2f63d8',
|
||||
'سامان': '#2f63d8',
|
||||
'SAMAN': '#2f63d8',
|
||||
@@ -8,10 +18,84 @@ const BANK_ACCENT_COLORS: Record<string, string> = {
|
||||
'پارسیان': '#c9a227',
|
||||
'بانک ملی': '#4b5e96',
|
||||
'ملی': '#4b5e96',
|
||||
'MELLI': '#4b5e96',
|
||||
'بانک ملت': '#c0392b',
|
||||
'ملت': '#c0392b',
|
||||
'MELLAT': '#c0392b',
|
||||
'بانک صادرات': '#1a6fb3',
|
||||
'صادرات': '#1a6fb3',
|
||||
'بانک آینده': '#2b2f6b',
|
||||
'آینده': '#2b2f6b',
|
||||
'AYANDEH': '#2b2f6b',
|
||||
'بانک کشاورزی': '#2e8b57',
|
||||
'کشاورزی': '#2e8b57',
|
||||
'KESHAVARZI': '#2e8b57',
|
||||
'بانک رفاه': '#c0392b',
|
||||
'رفاه': '#c0392b',
|
||||
'REFAH': '#c0392b',
|
||||
'بانک سرمایه': '#c0392b',
|
||||
'سرمایه': '#c0392b',
|
||||
'SARMAYEH': '#c0392b',
|
||||
}
|
||||
|
||||
const BANK_LOGOS: Record<string, string> = {
|
||||
'بانک پاسارگاد': pasargadLogo,
|
||||
'پاسارگاد': pasargadLogo,
|
||||
'PASARGAD': pasargadLogo,
|
||||
'بانک سامان': samanLogo,
|
||||
'سامان': samanLogo,
|
||||
'SAMAN': samanLogo,
|
||||
'بانک ملی': melliLogo,
|
||||
'ملی': melliLogo,
|
||||
'MELLI': melliLogo,
|
||||
'بانک ملت': mellatLogo,
|
||||
'ملت': mellatLogo,
|
||||
'MELLAT': mellatLogo,
|
||||
'بانک آینده': ayandehLogo,
|
||||
'آینده': ayandehLogo,
|
||||
'AYANDEH': ayandehLogo,
|
||||
'بانک کشاورزی': keshavarziLogo,
|
||||
'کشاورزی': keshavarziLogo,
|
||||
'KESHAVARZI': keshavarziLogo,
|
||||
'بانک رفاه': refahLogo,
|
||||
'رفاه': refahLogo,
|
||||
'REFAH': refahLogo,
|
||||
'بانک سرمایه': sarmayehLogo,
|
||||
'سرمایه': sarmayehLogo,
|
||||
'SARMAYEH': sarmayehLogo,
|
||||
}
|
||||
|
||||
const BANK_PERSIAN_NAMES: Record<string, string> = {
|
||||
PASARGAD: 'بانک پاسارگاد',
|
||||
SAMAN: 'بانک سامان',
|
||||
MELLI: 'بانک ملی',
|
||||
MELLAT: 'بانک ملت',
|
||||
AYANDEH: 'بانک آینده',
|
||||
KESHAVARZI: 'بانک کشاورزی',
|
||||
REFAH: 'بانک رفاه',
|
||||
SARMAYEH: 'بانک سرمایه',
|
||||
PARSIAN: 'بانک پارسیان',
|
||||
SADERAT: 'بانک صادرات',
|
||||
'بانک پاسارگاد': 'بانک پاسارگاد',
|
||||
'پاسارگاد': 'بانک پاسارگاد',
|
||||
'بانک سامان': 'بانک سامان',
|
||||
'سامان': 'بانک سامان',
|
||||
'بانک ملی': 'بانک ملی',
|
||||
'ملی': 'بانک ملی',
|
||||
'بانک ملت': 'بانک ملت',
|
||||
'ملت': 'بانک ملت',
|
||||
'بانک آینده': 'بانک آینده',
|
||||
'آینده': 'بانک آینده',
|
||||
'بانک کشاورزی': 'بانک کشاورزی',
|
||||
'کشاورزی': 'بانک کشاورزی',
|
||||
'بانک رفاه': 'بانک رفاه',
|
||||
'رفاه': 'بانک رفاه',
|
||||
'بانک سرمایه': 'بانک سرمایه',
|
||||
'سرمایه': 'بانک سرمایه',
|
||||
'بانک پارسیان': 'بانک پارسیان',
|
||||
'پارسیان': 'بانک پارسیان',
|
||||
'بانک صادرات': 'بانک صادرات',
|
||||
'صادرات': 'بانک صادرات',
|
||||
}
|
||||
|
||||
export function formatShebaForDisplay(value?: string | number | null): string {
|
||||
@@ -64,3 +148,47 @@ export function getBankMonogram(bankName?: string): string {
|
||||
const normalized = trimmed.replace(/^بانک\s+/u, '').trim()
|
||||
return normalized.slice(0, 2) || 'بانک'
|
||||
}
|
||||
|
||||
function findBankEntry<T>(bankName: string | undefined, entries: Record<string, T>): T | undefined {
|
||||
if (!bankName?.trim()) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const trimmed = bankName.trim()
|
||||
if (entries[trimmed]) {
|
||||
return entries[trimmed]
|
||||
}
|
||||
|
||||
const matched = Object.entries(entries).find(([name]) => trimmed.includes(name))
|
||||
return matched?.[1]
|
||||
}
|
||||
|
||||
export function getBankLogoUrl(bankName?: string): string | undefined {
|
||||
return findBankEntry(bankName, BANK_LOGOS)
|
||||
}
|
||||
|
||||
export function getBankDisplayName(bankName?: string): string {
|
||||
if (!bankName?.trim()) {
|
||||
return 'بانک'
|
||||
}
|
||||
|
||||
const trimmed = bankName.trim()
|
||||
if (BANK_PERSIAN_NAMES[trimmed]) {
|
||||
return BANK_PERSIAN_NAMES[trimmed]
|
||||
}
|
||||
|
||||
const upper = trimmed.toUpperCase()
|
||||
if (BANK_PERSIAN_NAMES[upper]) {
|
||||
return BANK_PERSIAN_NAMES[upper]
|
||||
}
|
||||
|
||||
const matched = Object.entries(BANK_PERSIAN_NAMES).find(([name]) => {
|
||||
if (/[\u0600-\u06FF]/u.test(name)) {
|
||||
return trimmed.includes(name)
|
||||
}
|
||||
|
||||
return upper.includes(name)
|
||||
})
|
||||
|
||||
return matched?.[1] ?? trimmed
|
||||
}
|
||||
|
||||
@@ -1,47 +1,45 @@
|
||||
<template>
|
||||
<div
|
||||
class="rounded-lg shadow-md mx-2 bg-gradient-to-l from-primary rounded-lg p-[2px] to-transparent"
|
||||
:class="{ 'dpr-item': variant === 'desktop' }"
|
||||
class="physical-receive-item"
|
||||
:class="{ 'physical-receive-item--desktop': variant === 'desktop' }"
|
||||
>
|
||||
<div class="rounded-lg flex flex-col gap-2 bg-white p-2">
|
||||
<div class="flex justify-between">
|
||||
<div class="font-bold">شماره سند: {{ props.item.id }}</div>
|
||||
<div class="font-bold">{{ toJalali(props.item.created_at) }}</div>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<div class="flex flex-col w-full gap-1">
|
||||
<div
|
||||
v-for="tx in props.item.transaction"
|
||||
:key="tx.id ?? tx.title"
|
||||
class="w-full flex justify-between"
|
||||
>
|
||||
<div class="flex items-center gap-1">
|
||||
<div class="w-7 h-7 flex justify-center rounded-lg bg-gray-100">
|
||||
<img
|
||||
width="30"
|
||||
class="p-1 object-contain"
|
||||
:src="getProductDisplayImage(tx.product)"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
<div>{{ tx.title }}</div>
|
||||
<div class="flex justify-between">
|
||||
<div class="font-bold">شماره سند: {{ props.item.id }}</div>
|
||||
<div class="font-bold">{{ toJalali(props.item.created_at) }}</div>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<div class="flex flex-col w-full gap-1">
|
||||
<div
|
||||
v-for="tx in props.item.transaction"
|
||||
:key="tx.id ?? tx.title"
|
||||
class="w-full flex justify-between"
|
||||
>
|
||||
<div class="flex items-center gap-1">
|
||||
<div class="w-7 h-7 flex justify-center rounded-lg bg-gray-100">
|
||||
<img
|
||||
width="30"
|
||||
class="p-1 object-contain"
|
||||
:src="getProductDisplayImage(tx.product)"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
<div>{{ tx.gold * -1 }} عدد</div>
|
||||
<div>{{ tx.title }}</div>
|
||||
</div>
|
||||
<div>{{ tx.gold * -1 }} عدد</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<div class="font-bold">وضعیت:</div>
|
||||
<ATag color="blue" class="!py-1 !px-2 !ml-0">
|
||||
{{ props.item.sts_str }}
|
||||
</ATag>
|
||||
</div>
|
||||
<ADivider class="!m-1" />
|
||||
<div class="flex flex-col justify-between">
|
||||
<div class="font-bold">آدرس:</div>
|
||||
<div>
|
||||
{{ props.item.address.province }}/{{ props.item.address.city }}/{{ props.item.address.address }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<div class="font-bold">وضعیت:</div>
|
||||
<ATag color="blue" class="!py-1 !px-2 !ml-0">
|
||||
{{ props.item.sts_str }}
|
||||
</ATag>
|
||||
</div>
|
||||
<ADivider class="!m-1" />
|
||||
<div class="flex flex-col justify-between">
|
||||
<div class="font-bold">آدرس:</div>
|
||||
<div>
|
||||
{{ props.item.address.province }}/{{ props.item.address.city }}/{{ props.item.address.address }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -61,3 +59,26 @@ const props = withDefaults(defineProps<Prop>(), {
|
||||
variant: 'mobile',
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.physical-receive-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
margin-inline: 8px;
|
||||
padding: 12px;
|
||||
border-radius: 12px;
|
||||
background: #fff;
|
||||
border: 1px solid rgba(15, 23, 42, 0.08);
|
||||
box-shadow: 0 1px 3px rgba(15, 23, 42, 0.06);
|
||||
}
|
||||
|
||||
.physical-receive-item--desktop {
|
||||
margin: 0;
|
||||
padding: 16px;
|
||||
border-radius: 16px;
|
||||
background: #fff;
|
||||
border: 1px solid rgba(15, 23, 42, 0.06);
|
||||
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -151,11 +151,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.dpr-item {
|
||||
margin: 0 !important;
|
||||
border-radius: 16px !important;
|
||||
}
|
||||
|
||||
.dpr-new {
|
||||
&__grid {
|
||||
display: grid;
|
||||
|
||||
@@ -47,11 +47,6 @@
|
||||
]"
|
||||
>
|
||||
<div class="flex items-center gap-1">
|
||||
<img
|
||||
:src="tradeProductImage"
|
||||
:alt="tradeProductLabel"
|
||||
class="tx-detail-product-thumb"
|
||||
/>
|
||||
<div class="text-base">{{ formatGoldAmount(item.gold) }}</div>
|
||||
{{ item.unit }}
|
||||
</div>
|
||||
@@ -133,7 +128,6 @@ import {
|
||||
resolveTransactionTradeProduct,
|
||||
shouldShowTransactionTotalWeightLine,
|
||||
} from '@/utils/productDealMethod'
|
||||
import { getProductDisplayImage } from '@/utils/productAssets'
|
||||
import { toJalaliNotime, toTime } from '@/utils/useDateTime'
|
||||
|
||||
const props = withDefaults(
|
||||
@@ -148,9 +142,6 @@ const tradeProduct = computed(() => resolveTransactionTradeProduct(props.item))
|
||||
const tradeProductLabel = computed(
|
||||
() => (tradeProduct.value?.title ?? '').trim() || getMeltedGoldTradeLabel(),
|
||||
)
|
||||
const tradeProductImage = computed(() =>
|
||||
getProductDisplayImage(props.item.product ?? tradeProduct.value ?? props.item.wallet?.product ?? null),
|
||||
)
|
||||
const metalWalletProduct = computed(() => {
|
||||
if (props.item.order && tradeProduct.value?.title) {
|
||||
return tradeProduct.value
|
||||
@@ -175,12 +166,4 @@ const showMetalWalletBalance = computed(
|
||||
max-width: 9.5rem;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.tx-detail-product-thumb {
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
border-radius: 0.25rem;
|
||||
object-fit: contain;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
<template>
|
||||
<div class="boursecu-bank-option" :class="{ 'boursecu-bank-option--compact': compact }">
|
||||
<div class="boursecu-bank-option__logo" :style="{ backgroundColor: accentColor }">
|
||||
<span>{{ monogram }}</span>
|
||||
<div
|
||||
class="boursecu-bank-option__logo"
|
||||
:class="{ 'boursecu-bank-option__logo--image': !!logoUrl }"
|
||||
:style="logoUrl ? undefined : { backgroundColor: accentColor }"
|
||||
>
|
||||
<img v-if="logoUrl" :src="logoUrl" :alt="displayName" />
|
||||
<span v-else>{{ monogram }}</span>
|
||||
</div>
|
||||
<div class="boursecu-bank-option__content">
|
||||
<div class="boursecu-bank-option__title">{{ card.bank_name || 'بانک' }}</div>
|
||||
<div class="boursecu-bank-option__title">{{ displayName }}</div>
|
||||
<div class="boursecu-bank-option__sheba">{{ shebaText }}</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -16,6 +21,8 @@ import type { Card } from '@/models/wallet'
|
||||
import {
|
||||
formatShebaForDisplay,
|
||||
getBankAccentColor,
|
||||
getBankDisplayName,
|
||||
getBankLogoUrl,
|
||||
getBankMonogram,
|
||||
} from '@/utils/bankBranding'
|
||||
|
||||
@@ -28,6 +35,8 @@ const props = withDefaults(
|
||||
)
|
||||
|
||||
const accentColor = computed(() => getBankAccentColor(props.card.bank_name))
|
||||
const displayName = computed(() => getBankDisplayName(props.card.bank_name))
|
||||
const logoUrl = computed(() => getBankLogoUrl(props.card.bank_name))
|
||||
const monogram = computed(() => getBankMonogram(props.card.bank_name))
|
||||
const shebaText = computed(() => formatShebaForDisplay(props.card.shaba_number))
|
||||
</script>
|
||||
@@ -55,6 +64,19 @@ const shebaText = computed(() => formatShebaForDisplay(props.card.shaba_number))
|
||||
line-height: 1.1;
|
||||
text-align: center;
|
||||
padding: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.boursecu-bank-option__logo--image {
|
||||
background: #fff;
|
||||
border: 1px solid #e5e7eb;
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
.boursecu-bank-option__logo img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.boursecu-bank-option--compact .boursecu-bank-option__logo {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div ref="el" class="w-full flex flex-col relative h-full test">
|
||||
<CardItem v-for="(item,i) in props?.items" :key="i" v-model:sliderIndex="index" :card-number="item?.cart_number"
|
||||
:color="colors[i%3]"
|
||||
:self-index="i" :shaba="item?.shaba_number" :title="item?.bank_name" :active="item.sts === 2" :id="item?.id"
|
||||
:self-index="i" :shaba="item?.shaba_number" :title="getBankDisplayName(item?.bank_name)" :active="item.sts === 2" :id="item?.id"
|
||||
@cardDeleted="handleCardDeleted"
|
||||
/>
|
||||
<div class="absolute bottom-1 right-0 left-0 z-100 flex justify-center items-center opacity-70 pointer-events-none">
|
||||
@@ -26,6 +26,7 @@ import { computed, onMounted, ref, watch } from 'vue'
|
||||
import { useSwipe } from '@vueuse/core'
|
||||
import CardItem from './CardItem.vue'
|
||||
import type { Card } from '@/models/wallet'
|
||||
import { getBankDisplayName } from '@/utils/bankBranding'
|
||||
|
||||
const el = ref(null)
|
||||
const container = ref<HTMLElement | null>(null)
|
||||
|
||||