fix ذشزنلقخعدی
This commit is contained in:
@@ -7,6 +7,8 @@ import boursecuConvertIcon from '@/assets/img/boursecu-convert-icon.png'
|
||||
import boursecuWalletIcon from '@/assets/img/boursecu-wallet-icon.png'
|
||||
import boursecuBuySellIcon from '@/assets/img/boursecu-buy-sell-icon.png'
|
||||
import boursecuAssetsIcon from '@/assets/img/boursecu-assets-icon.png'
|
||||
import boursecuHomeIcon from '@/assets/img/boursecu-home-icon.png'
|
||||
import boursecuSettingsIcon from '@/assets/img/boursecu-settings-icon.png'
|
||||
import bazretalaLoginLogo from '@/assets/img/bazretala-login-logo.png'
|
||||
import bazretalaNavLogo from '@/assets/img/bazretala-nav-logo.png'
|
||||
import bazretalaFundBg from '@/assets/img/bazretala-fund-bg.png'
|
||||
@@ -53,6 +55,14 @@ export function getBoursecuAssetsIcon() {
|
||||
return boursecuAssetsIcon
|
||||
}
|
||||
|
||||
export function getBoursecuHomeIcon() {
|
||||
return boursecuHomeIcon
|
||||
}
|
||||
|
||||
export function getBoursecuSettingsIcon() {
|
||||
return boursecuSettingsIcon
|
||||
}
|
||||
|
||||
export function getBoursecuActionIconSrc(actionId: string): string | undefined {
|
||||
const icons: Record<string, string> = {
|
||||
buySell: boursecuBuySellIcon,
|
||||
@@ -61,6 +71,8 @@ export function getBoursecuActionIconSrc(actionId: string): string | undefined {
|
||||
transactions: boursecuTransactionsIcon,
|
||||
physicalReceive: boursecuPhysicalReceiveIcon,
|
||||
convert: boursecuConvertIcon,
|
||||
home: boursecuHomeIcon,
|
||||
settings: boursecuSettingsIcon,
|
||||
}
|
||||
|
||||
return icons[actionId]
|
||||
@@ -71,12 +83,26 @@ export function hasCustomLoginLogoLayout() {
|
||||
}
|
||||
|
||||
export const BOURSECU_BRAND_RED = '#bc3c3b'
|
||||
export const BOURSECU_BRAND_BLUE = '#2178b5'
|
||||
export const BOURSECU_BRAND_NAV = '#133050'
|
||||
export const BOURSECU_COPPER_BG = '#b87333'
|
||||
export const BOURSECU_COPPER_BG_LIGHT = '#fdf0e6'
|
||||
export const BOURSECU_COPPER_BG_GRADIENT = 'linear-gradient(135deg, #c98a4a 0%, #a86528 100%)'
|
||||
|
||||
export function getProjectBrandRed() {
|
||||
return isBoursecuProject() ? BOURSECU_BRAND_RED : null
|
||||
}
|
||||
|
||||
/** رنگ اصلی دکمهها و چارت — boursecu ثابت آبی، بقیه از تنظیمات tenant */
|
||||
export function getProjectPrimaryColor() {
|
||||
if (isBoursecuProject()) {
|
||||
return BOURSECU_BRAND_BLUE
|
||||
}
|
||||
|
||||
const color = getConfigApp('color')
|
||||
return color != null ? String(color) : undefined
|
||||
}
|
||||
|
||||
export function resolveProjectColor(color?: string | null) {
|
||||
if (!color || !isBoursecuProject()) {
|
||||
return color
|
||||
@@ -240,6 +266,7 @@ export function applyProjectTheme() {
|
||||
}
|
||||
|
||||
document.documentElement.classList.add('project-boursecu')
|
||||
document.documentElement.style.setProperty('--App-primary-color', BOURSECU_BRAND_BLUE)
|
||||
document.documentElement.style.setProperty('--App-brand-nav', BOURSECU_BRAND_NAV)
|
||||
document.documentElement.style.setProperty('--App-brand-red', BOURSECU_BRAND_RED)
|
||||
document.documentElement.style.setProperty('--App-brand-red-50', '#f8ecec')
|
||||
|
||||
@@ -394,10 +394,6 @@ export function formatMetalAssetsInfoText(metal: WalletMetalTotal): string {
|
||||
return `${metal.label}: مجموع کیف محصولات (${metal.product_weight} ${unit}) + موجودی کیف اصلی (${metal.melted_weight} ${unit})`
|
||||
}
|
||||
|
||||
function formatRialNumber(value: number): string {
|
||||
return usePriceWithoutType(value)
|
||||
}
|
||||
|
||||
/** متن توضیح مودال دارایی ریالی */
|
||||
export function formatRialAssetsInfoText(cashWallet: number, metalRialValue: number): string {
|
||||
const total = cashWallet + metalRialValue
|
||||
|
||||
@@ -86,7 +86,24 @@ export function isMeltedProductUsingAppPrice(product?: {
|
||||
group_type?: string | null
|
||||
reading_method?: string | null
|
||||
direct_price?: number | null
|
||||
trade_by_quantity?: boolean | number | null
|
||||
price?: number | null
|
||||
} | null) {
|
||||
return isMeltedTradeGroup(product?.group_type)
|
||||
&& resolveMeltedPriceSource(product) === 'app'
|
||||
if (!product || resolveMeltedPriceSource(product) !== 'app') {
|
||||
return false
|
||||
}
|
||||
|
||||
if (isMeltedTradeGroup(product.group_type)) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (!usesQuantityTrade(product)) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (Number(product.direct_price) === 1) {
|
||||
return false
|
||||
}
|
||||
|
||||
return Number(product.price ?? 0) <= 0
|
||||
}
|
||||
|
||||
@@ -42,6 +42,19 @@ export function isKatodMesGroup(groupType?: string | null) {
|
||||
return normalizeProductGroupType(groupType) === BOURSECU_GROUP_KATOD
|
||||
}
|
||||
|
||||
export function isShamshMesGroup(groupType?: string | null, title?: string | null) {
|
||||
if (!isBoursecuProject()) {
|
||||
return false
|
||||
}
|
||||
|
||||
const group = normalizeProductGroupType(groupType)
|
||||
if (group === 'شمش') {
|
||||
return true
|
||||
}
|
||||
|
||||
return (title ?? '').includes('شمش')
|
||||
}
|
||||
|
||||
export function isGoldOnlyDealGroup(groupType?: string | null) {
|
||||
return isMeltedTradeGroup(groupType)
|
||||
}
|
||||
@@ -51,6 +64,7 @@ export interface ProductUnitSource {
|
||||
direct_price?: number | null
|
||||
group_type?: string | null
|
||||
amount?: number | null
|
||||
trade_by_quantity?: boolean | number | null
|
||||
}
|
||||
|
||||
export function isWeightBasedProductUnit(unit?: string | null) {
|
||||
@@ -111,8 +125,17 @@ export function formatProductWeightAmount(amount?: number | null, product?: Prod
|
||||
return `${value} ${weightUnit}`
|
||||
}
|
||||
|
||||
/** فقط محصول تعدادی (مثل سکه): «هر عدد X گرم» — معامله مقداری با trade_by_quantity نیست */
|
||||
export function shouldShowPerUnitWeightHint(product?: ProductUnitSource | null) {
|
||||
if (!product || !hasProductUnitWeight(product) || usesQuantityTrade(product)) {
|
||||
return false
|
||||
}
|
||||
|
||||
return isCountBasedProduct(product)
|
||||
}
|
||||
|
||||
export function getProductUnitWeightLabel(product?: ProductUnitSource | null) {
|
||||
if (!hasProductUnitWeight(product)) {
|
||||
if (!shouldShowPerUnitWeightHint(product)) {
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -152,12 +175,16 @@ export function formatProductInventoryBalance(product?: (ProductUnitSource & { w
|
||||
return `${quantityPart} · هر عدد ${unitWeight}`
|
||||
}
|
||||
|
||||
/** محصول تعدادی: موجودی wallet.gold = تعداد قلم، نه وزن */
|
||||
/** محصول تعدادی: موجودی wallet.gold = تعداد قلم، نه وزن — معامله مقداری با trade_by_quantity نیست */
|
||||
export function isCountBasedProduct(product?: ProductUnitSource | null) {
|
||||
if (!product) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (usesQuantityTrade(product)) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (isWeightBasedProductUnit(product.unit)) {
|
||||
return false
|
||||
}
|
||||
@@ -567,3 +594,23 @@ export function getMetalTypeTradeLabel() {
|
||||
export function getTradePriceUnitLabel() {
|
||||
return useSettingsStore().metalTypeLabel
|
||||
}
|
||||
|
||||
/** برچسب قیمت حین معامله — معامله مقداری: نام و واحد همان محصول */
|
||||
export function getTransactionTradePriceLabel(product?: (ProductUnitSource & { title?: string | null }) | null) {
|
||||
if (product && usesQuantityTrade(product)) {
|
||||
const unit = getProductQuantityUnit(product)
|
||||
const title = (product.title ?? '').trim()
|
||||
return title ? `قیمت هر ${unit} ${title}` : `قیمت هر ${unit}`
|
||||
}
|
||||
|
||||
return `قیمت هر ${getWeightUnit()} ${getTradePriceUnitLabel()}`
|
||||
}
|
||||
|
||||
/** وزن کل زیر مقدار مبادلهشده — فقط محصول تعدادی (نه trade_by_quantity) */
|
||||
export function shouldShowTransactionTotalWeightLine(product?: ProductUnitSource | null) {
|
||||
if (!product || usesQuantityTrade(product) || !hasProductUnitWeight(product)) {
|
||||
return false
|
||||
}
|
||||
|
||||
return isCountBasedProduct(product)
|
||||
}
|
||||
|
||||
+69
-12
@@ -1,3 +1,4 @@
|
||||
import { ref } from 'vue'
|
||||
import { useSettingsStore } from '@/store/settingsStore'
|
||||
import { lastPrice } from '@/utils/price'
|
||||
|
||||
@@ -13,7 +14,13 @@ export interface EffectiveTradingHours {
|
||||
enforced: boolean
|
||||
}
|
||||
|
||||
let productTradingHours: { start: string; end: string } | null = null
|
||||
const productTradingHours = ref<{ start: string; end: string } | null>(null)
|
||||
const productTradingHoursVersion = ref(0)
|
||||
|
||||
function normalizeTradingTimeSetting(value: unknown, fallback: string): string {
|
||||
const raw = String(value ?? '').trim()
|
||||
return raw || fallback
|
||||
}
|
||||
|
||||
function parseTimeToSeconds(time: string): number {
|
||||
const parts = time.trim().split(':').map(Number)
|
||||
@@ -22,20 +29,56 @@ function parseTimeToSeconds(time: string): number {
|
||||
}
|
||||
|
||||
export function formatTradingTimeDisplay(time: string): string {
|
||||
const parts = time.trim().split(':')
|
||||
const normalized = normalizeTradingTimeSetting(time, '')
|
||||
if (!normalized) {
|
||||
return ''
|
||||
}
|
||||
|
||||
const parts = normalized.split(':')
|
||||
if (parts.length >= 3) {
|
||||
return `${parts[0]}:${parts[1]}:${parts[2]}`
|
||||
}
|
||||
if (parts.length >= 2) {
|
||||
return `${parts[0]}:${parts[1]}:00`
|
||||
}
|
||||
return time
|
||||
return normalized
|
||||
}
|
||||
|
||||
function hasProductTradingWindow(start?: string | null, end?: string | null): boolean {
|
||||
const open = formatTradingTimeDisplay(normalizeTradingTimeSetting(start, '00:00:00'))
|
||||
const close = formatTradingTimeDisplay(normalizeTradingTimeSetting(end, '00:00:00'))
|
||||
if (!open || !close) {
|
||||
return false
|
||||
}
|
||||
|
||||
return open !== close
|
||||
}
|
||||
|
||||
export function setProductTradingHours(start?: string | null, end?: string | null) {
|
||||
if (start && end) {
|
||||
productTradingHours = { start, end }
|
||||
if (!hasProductTradingWindow(start, end)) {
|
||||
productTradingHours.value = null
|
||||
productTradingHoursVersion.value += 1
|
||||
return
|
||||
}
|
||||
|
||||
productTradingHours.value = {
|
||||
start: normalizeTradingTimeSetting(start, '00:00'),
|
||||
end: normalizeTradingTimeSetting(end, '23:59'),
|
||||
}
|
||||
productTradingHoursVersion.value += 1
|
||||
}
|
||||
|
||||
export function syncProductTradingHoursFromProducts(
|
||||
products: Array<{ auto_open_at?: string | null; auto_close_at?: string | null }>,
|
||||
) {
|
||||
for (const product of products) {
|
||||
if (hasProductTradingWindow(product.auto_open_at, product.auto_close_at)) {
|
||||
setProductTradingHours(product.auto_open_at, product.auto_close_at)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
setProductTradingHours(null, null)
|
||||
}
|
||||
|
||||
export function getStoreTradingHours(): StoreTradingHours {
|
||||
@@ -47,13 +90,14 @@ export function getStoreTradingHours(): StoreTradingHours {
|
||||
String(closeRaw ?? 'false').trim().toLowerCase() === 'true'
|
||||
|
||||
return {
|
||||
start: String(settings.getSettingByKey('startDay') ?? '00:00'),
|
||||
end: String(settings.getSettingByKey('endDay') ?? '23:59'),
|
||||
start: normalizeTradingTimeSetting(settings.getSettingByKey('startDay'), '00:00'),
|
||||
end: normalizeTradingTimeSetting(settings.getSettingByKey('endDay'), '23:59'),
|
||||
closePriceEnabled,
|
||||
}
|
||||
}
|
||||
|
||||
export function getEffectiveTradingHours(): EffectiveTradingHours {
|
||||
void productTradingHoursVersion.value
|
||||
const settings = getStoreTradingHours()
|
||||
if (settings.closePriceEnabled) {
|
||||
return {
|
||||
@@ -63,10 +107,10 @@ export function getEffectiveTradingHours(): EffectiveTradingHours {
|
||||
}
|
||||
}
|
||||
|
||||
if (productTradingHours?.start && productTradingHours?.end) {
|
||||
if (productTradingHours.value?.start && productTradingHours.value?.end) {
|
||||
return {
|
||||
start: productTradingHours.start,
|
||||
end: productTradingHours.end,
|
||||
start: productTradingHours.value.start,
|
||||
end: productTradingHours.value.end,
|
||||
enforced: true,
|
||||
}
|
||||
}
|
||||
@@ -92,10 +136,18 @@ export function isStoreClosedBySchedule(now = new Date()): boolean {
|
||||
}
|
||||
|
||||
export function isStoreClosed(): boolean {
|
||||
if (lastPrice.value?.closed === true) {
|
||||
return true
|
||||
void productTradingHoursVersion.value
|
||||
const { closePriceEnabled } = getStoreTradingHours()
|
||||
|
||||
if (closePriceEnabled) {
|
||||
if (lastPrice.value?.closed === true) {
|
||||
return true
|
||||
}
|
||||
|
||||
return isStoreClosedBySchedule()
|
||||
}
|
||||
|
||||
// وقتی close_price خاموش است، صفر بودن قیمت مرجع به معنی بسته بودن فروشگاه نیست.
|
||||
return isStoreClosedBySchedule()
|
||||
}
|
||||
|
||||
@@ -103,5 +155,10 @@ export function getStoreClosedMessage(): string {
|
||||
const { start, end } = getEffectiveTradingHours()
|
||||
const open = formatTradingTimeDisplay(start)
|
||||
const close = formatTradingTimeDisplay(end)
|
||||
|
||||
if (!open || !close) {
|
||||
return 'فروشگاه در حال حاضر بسته است.'
|
||||
}
|
||||
|
||||
return `فروشگاه در حال حاضر بسته است. ساعت کاری از ${open} تا ${close} میباشد.`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user