fix some bugs

This commit is contained in:
2026-06-29 22:17:14 +03:30
parent 2583becda7
commit c7a0ef6b64
7 changed files with 138 additions and 43 deletions
+3 -1
View File
@@ -41,7 +41,7 @@
class="text-center text-xs" class="text-center text-xs"
:class="isBoursecuProject() ? 'text-white' : ''" :class="isBoursecuProject() ? 'text-white' : ''"
> >
نسخه: {{ pkg.version }} نسخه: {{ displayVersion }}
</div> </div>
</div> </div>
<div class="absolute bottom-10"> <div class="absolute bottom-10">
@@ -91,6 +91,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import pkg from '../package.json' import pkg from '../package.json'
import { getDisplayAppVersion } from '@/config/config-cache'
import {useRegisterSW} from 'virtual:pwa-register/vue' import {useRegisterSW} from 'virtual:pwa-register/vue'
import {computed, defineAsyncComponent, h, onMounted, ref, watch} from 'vue' import {computed, defineAsyncComponent, h, onMounted, ref, watch} from 'vue'
import img_topGradiant from '@/views/login/assets/img/gr_top_white.svg' import img_topGradiant from '@/views/login/assets/img/gr_top_white.svg'
@@ -126,6 +127,7 @@ const showDesktopFloatingCredit = computed(() => {
}) })
useRegisterSW() useRegisterSW()
const displayVersion = getDisplayAppVersion(pkg.version)
const config = useConfigStore() const config = useConfigStore()
const splashIndicator = computed(() => h(LoadingOutlined, { const splashIndicator = computed(() => h(LoadingOutlined, {
style: { style: {
+4
View File
@@ -91,6 +91,10 @@ export function getStoredAppVersion() {
return localStorage.getItem(VERSION_STORAGE_KEY) return localStorage.getItem(VERSION_STORAGE_KEY)
} }
export function getDisplayAppVersion(fallbackVersion: string) {
return getStoredAppVersion() || fallbackVersion
}
export function writeStoredAppVersion(version: string) { export function writeStoredAppVersion(version: string) {
localStorage.setItem(VERSION_STORAGE_KEY, String(version).trim()) localStorage.setItem(VERSION_STORAGE_KEY, String(version).trim())
} }
+2
View File
@@ -1,4 +1,5 @@
import type {Order} from "@/models/order"; import type {Order} from "@/models/order";
import type { Product } from '@/models/products'
import type { Wallet } from '@/models/wallet' import type { Wallet } from '@/models/wallet'
export interface Transaction { export interface Transaction {
@@ -32,6 +33,7 @@ export interface Transaction {
balance_gold?: number balance_gold?: number
percentWallet?: number percentWallet?: number
wallet?: Wallet wallet?: Wallet
product?: Product
otp?: string otp?: string
extra_note?: string extra_note?: string
tracked_number: number tracked_number: number
+43 -3
View File
@@ -603,14 +603,54 @@ export function getTradePriceUnitLabel() {
return useSettingsStore().metalTypeLabel return useSettingsStore().metalTypeLabel
} }
/** برچسب قیمت حین معامله — معامله مقداری: نام و واحد همان محصول */ export type TransactionTradeProductSource = {
product?: (ProductUnitSource & { title?: string | null }) | null
wallet?: { product?: (ProductUnitSource & { title?: string | null }) | null } | null
title?: string | null
}
/** محصول معامله‌شده — نه لزوماً همان کیف پول (مثلاً خرید مفتول با کیف کاتد) */
export function resolveTransactionTradeProduct(
item?: TransactionTradeProductSource | null,
): (ProductUnitSource & { title?: string | null }) | null {
if (!item) {
return null
}
const fromTransaction = item.product
if ((fromTransaction?.title ?? '').trim()) {
return fromTransaction ?? null
}
const title = (item.title ?? '').trim()
const match = title.match(/^(?:خرید|فروش)\s+(.+)$/u)
if (match?.[1]?.trim()) {
return {
...(item.wallet?.product ?? {}),
title: match[1].trim(),
}
}
return item.wallet?.product ?? null
}
/** برچسب قیمت حین معامله — نام و واحد همان محصول معامله‌شده */
export function getTransactionTradePriceLabel(product?: (ProductUnitSource & { title?: string | null }) | null) { export function getTransactionTradePriceLabel(product?: (ProductUnitSource & { title?: string | null }) | null) {
if (product && usesQuantityTrade(product)) { if (!product) {
return `قیمت هر ${getWeightUnit()} ${getTradePriceUnitLabel()}`
}
const title = (product.title ?? '').trim()
if (usesQuantityTrade(product)) {
const unit = getProductQuantityUnit(product) const unit = getProductQuantityUnit(product)
const title = (product.title ?? '').trim()
return title ? `قیمت هر ${unit} ${title}` : `قیمت هر ${unit}` return title ? `قیمت هر ${unit} ${title}` : `قیمت هر ${unit}`
} }
if (title) {
return `قیمت هر ${getWeightUnit()} ${title}`
}
return `قیمت هر ${getWeightUnit()} ${getTradePriceUnitLabel()}` return `قیمت هر ${getWeightUnit()} ${getTradePriceUnitLabel()}`
} }
+72 -33
View File
@@ -108,11 +108,7 @@ _axios.interceptors.response.use(
}, },
async function (error) { async function (error) {
const response = error.response const response = error.response
const config = error.config const config = error.config as MyAxiosRequestConfig | undefined
if (response?.data?.message && response.status !== 401) {
checkStatus(response.data.message, response.status, config)
}
if (response?.status === 401) { if (response?.status === 401) {
const hadAuth = Boolean(config?.headers?.Authorization) const hadAuth = Boolean(config?.headers?.Authorization)
@@ -124,42 +120,85 @@ _axios.interceptors.response.use(
scheduleSessionVerify() scheduleSessionVerify()
} }
} }
} else if (response?.status === 403) { return Promise.reject(error)
message.error('شما دسترسی لازم برای انجام این عملیات را ندارید')
} else if (error.response && error.response.status == 422) {
// message.error(error.response.data?.message)
} else if (error.response) {
message.error('خطا در بارگذاری اطلاعات')
} }
// Any status codes that falls outside the range of 2xx cause this function to trigger
// Do something with response error
//const { response, code, message, config } = error || {} if (!shouldShowApiError(config)) {
//const errorMessageMode = config?.requestOptions?.errorMessageMode || 'none' return Promise.reject(error)
//const msg: string = response?.data?.error?.message ?? '' }
//checkStatus(error?.response?.status, msg)
const apiMessage = extractApiErrorMessage(response?.data)
if (response?.status === 403) {
showApiError(apiMessage || 'شما دسترسی لازم برای انجام این عملیات را ندارید', config)
return Promise.reject(error)
}
if (response?.status === 422) {
if (apiMessage) {
showApiError(apiMessage, config)
}
return Promise.reject(error)
}
if (response) {
showApiError(apiMessage || DEFAULT_LOAD_ERROR, config)
return Promise.reject(error)
}
showApiError(DEFAULT_LOAD_ERROR, config)
return Promise.reject(error) return Promise.reject(error)
}) })
function checkStatus(msg: string, code: number, config: any) { const DEFAULT_LOAD_ERROR = 'خطا در بارگذاری اطلاعات'
//const { code, data, message } = data
const errorMessage = get(config, 'meta.errorMessage', 'message') function extractApiErrorMessage(data: unknown): string {
/*if (config.meta) { if (!data || typeof data !== 'object') {
if (config.meta.message) { return ''
errorMessage = config.meta.message
}
}*/
console.log('this is config', config)
if (errorMessage == 'none') return
switch (errorMessage) {
case 'message':
message.error(msg)
break
default:
message.error(msg)
} }
const record = data as Record<string, unknown>
const rawMessage = record.message
if (typeof rawMessage === 'string' && rawMessage.trim()) {
return rawMessage.trim()
}
if (typeof rawMessage === 'number') {
return String(rawMessage)
}
const rawError = record.error
if (typeof rawError === 'string' && rawError.trim()) {
return rawError.trim()
}
const errors = record.errors
if (errors && typeof errors === 'object') {
for (const value of Object.values(errors as Record<string, unknown>)) {
if (Array.isArray(value) && typeof value[0] === 'string' && value[0].trim()) {
return value[0].trim()
}
if (typeof value === 'string' && value.trim()) {
return value.trim()
}
}
}
return ''
} }
function shouldShowApiError(config: MyAxiosRequestConfig | undefined): boolean {
return get(config, 'meta.errorMessage', 'message') !== 'none'
}
function showApiError(msg: string, config: MyAxiosRequestConfig | undefined) {
if (!shouldShowApiError(config)) {
return
}
message.error(msg)
}
const myAxios = { const myAxios = {
//AxiosResponse<T> //AxiosResponse<T>
@@ -15,7 +15,7 @@
</div> </div>
<div v-if="item.order" :class="variant === 'desktop' ? 'dtxn-detail__row' : 'flex justify-between mb-3'"> <div v-if="item.order" :class="variant === 'desktop' ? 'dtxn-detail__row' : 'flex justify-between mb-3'">
<div :class="variant === 'desktop' ? 'dtxn-detail__label' : 'text-primary'"> <div :class="variant === 'desktop' ? 'dtxn-detail__label' : 'text-primary'">
{{ getTransactionTradePriceLabel(item.wallet?.product) }} حین معامله: {{ getTransactionTradePriceLabel(tradeProduct) }} حین معامله:
</div> </div>
<div :class="['flex text-xs items-center number-ltr', variant === 'desktop' ? 'dtxn-detail__value' : '']"> <div :class="['flex text-xs items-center number-ltr', variant === 'desktop' ? 'dtxn-detail__value' : '']">
<div class="text-base ml-1">{{ usePriceWithoutType(item.order?.price ?? 0) }}</div> <div class="text-base ml-1">{{ usePriceWithoutType(item.order?.price ?? 0) }}</div>
@@ -24,7 +24,7 @@
</div> </div>
<div :class="variant === 'desktop' ? 'dtxn-detail__row' : 'flex justify-between mb-3'"> <div :class="variant === 'desktop' ? 'dtxn-detail__row' : 'flex justify-between mb-3'">
<div :class="variant === 'desktop' ? 'dtxn-detail__label' : 'text-primary'"> <div :class="variant === 'desktop' ? 'dtxn-detail__label' : 'text-primary'">
مقدار {{ item.wallet?.product ? item.wallet.product.title : getMeltedGoldTradeLabel() }} مبادله شده: مقدار {{ tradeProductLabel }} مبادله شده:
</div> </div>
<div <div
:class="[ :class="[
@@ -38,10 +38,10 @@
{{ item.unit }} {{ item.unit }}
</div> </div>
<div <div
v-if="shouldShowTransactionTotalWeightLine(item.wallet?.product)" v-if="shouldShowTransactionTotalWeightLine(tradeProduct)"
class="text-gray-500" class="text-gray-500"
> >
{{ getProductTotalWeightLabel(Math.abs(item.gold ?? 0), item.wallet?.product) }} {{ getProductTotalWeightLabel(Math.abs(item.gold ?? 0), tradeProduct) }}
</div> </div>
</div> </div>
</div> </div>
@@ -107,6 +107,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed } from 'vue'
import { formatGoldAmount, usePriceWithoutType } from '@/utils/usePrice' import { formatGoldAmount, usePriceWithoutType } from '@/utils/usePrice'
import type { Transaction } from '@/models/transaction' import type { Transaction } from '@/models/transaction'
import { import {
@@ -118,15 +119,21 @@ import {
getProductUnitWeightLabel, getProductUnitWeightLabel,
getTransactionTradePriceLabel, getTransactionTradePriceLabel,
getWeightUnit, getWeightUnit,
resolveTransactionTradeProduct,
shouldShowTransactionTotalWeightLine, shouldShowTransactionTotalWeightLine,
} from '@/utils/productDealMethod' } from '@/utils/productDealMethod'
import { toJalaliNotime, toTime } from '@/utils/useDateTime' import { toJalaliNotime, toTime } from '@/utils/useDateTime'
withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
item: Transaction item: Transaction
variant?: 'mobile' | 'desktop' variant?: 'mobile' | 'desktop'
}>(), }>(),
{ variant: 'mobile' }, { variant: 'mobile' },
) )
const tradeProduct = computed(() => resolveTransactionTradeProduct(props.item))
const tradeProductLabel = computed(
() => (tradeProduct.value?.title ?? '').trim() || getMeltedGoldTradeLabel(),
)
</script> </script>
@@ -40,6 +40,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed } from 'vue' import { computed } from 'vue'
import pkg from '../../../../../package.json' import pkg from '../../../../../package.json'
import { getDisplayAppVersion } from '@/config/config-cache'
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue' import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
import { useConfigStore } from '@/store/configStore' import { useConfigStore } from '@/store/configStore'
import { import {
@@ -54,7 +55,7 @@ const config = useConfigStore()
const isBoursecu = isBoursecuProject() const isBoursecu = isBoursecuProject()
const isSoroushgold = isSoroushgoldProject() const isSoroushgold = isSoroushgoldProject()
const hasCustomLayout = hasCustomLoginLogoLayout() || isSoroushgold const hasCustomLayout = hasCustomLoginLogoLayout() || isSoroushgold
const version = pkg.version const version = getDisplayAppVersion(pkg.version)
const logo = computed(() => getProjectDesktopLoginBrandLogo(config.config?.avatar)) const logo = computed(() => getProjectDesktopLoginBrandLogo(config.config?.avatar))