From b055cd4a5d7dc483e9142d50e2948a8b54ee9c9c Mon Sep 17 00:00:00 2001 From: safavimohadeseh78 Date: Wed, 3 Jun 2026 11:57:40 +0330 Subject: [PATCH] change prices &... --- components.d.ts | 2 + src/api/avatar.ts | 15 +++ src/components/ProfileAvatarUpload.vue | 119 ++++++++++++++++++ src/models/home.ts | 1 + src/models/login.ts | 6 +- src/themeConfig.ts | 4 +- src/utils/file.ts | 12 ++ src/views/base/about/index.vue | 2 +- src/views/base/copper&silver/index.vue | 43 ++++++- src/views/base/educate/index.vue | 2 +- src/views/base/gold/index.vue | 43 ++++++- src/views/base/home/components/PriceChart.vue | 4 +- .../base/products/components/DealProduct.vue | 20 ++- src/views/base/rules/index.vue | 2 +- .../base/rules/permissions/permissions.vue | 2 +- src/views/base/user/index.vue | 53 +++++++- 16 files changed, 305 insertions(+), 25 deletions(-) create mode 100644 src/api/avatar.ts create mode 100644 src/components/ProfileAvatarUpload.vue diff --git a/components.d.ts b/components.d.ts index e9be9b0..2da2181 100644 --- a/components.d.ts +++ b/components.d.ts @@ -25,6 +25,7 @@ declare module 'vue' { ATag: typeof import('ant-design-vue/es')['Tag'] ATextarea: typeof import('ant-design-vue/es')['Textarea'] ATooltip: typeof import('ant-design-vue/es')['Tooltip'] + AUpload: typeof import('ant-design-vue/es')['Upload'] BaseDatePicker: typeof import('./src/components/BasicPacks/BaseDatePicker/src/BaseDatePicker.vue')['default'] Basic: typeof import('./src/components/BasicPacks/BaseDatePicker/src/datePick/demo/basic.vue')['default'] BasicActionSheet: typeof import('./src/components/BasicPacks/BasicActionSheet.vue')['default'] @@ -54,6 +55,7 @@ declare module 'vue' { ListAnim: typeof import('./src/components/ListAnim.vue')['default'] Mode: typeof import('./src/components/BasicPacks/BaseDatePicker/src/datePick/demo/mode.vue')['default'] PresettedRanges: typeof import('./src/components/BasicPacks/BaseDatePicker/src/datePick/demo/presetted-ranges.vue')['default'] + ProfileAvatarUpload: typeof import('./src/components/ProfileAvatarUpload.vue')['default'] RangePicker: typeof import('./src/components/BasicPacks/BaseDatePicker/src/datePick/demo/range-picker.vue')['default'] RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] diff --git a/src/api/avatar.ts b/src/api/avatar.ts new file mode 100644 index 0000000..197fcf9 --- /dev/null +++ b/src/api/avatar.ts @@ -0,0 +1,15 @@ +import useAxios from '@/utils/useAxios' + +export interface AvatarUploadResponse { + id: number + src?: string + full_src?: string + title?: string +} + +/** POST multipart — expects backend route POST /customer/avatar */ +export const uploadAvatar = async (file: File) => { + const formData = new FormData() + formData.append('file', file) + return useAxios.postForm('/customer/avatar', formData) +} diff --git a/src/components/ProfileAvatarUpload.vue b/src/components/ProfileAvatarUpload.vue new file mode 100644 index 0000000..fe26ead --- /dev/null +++ b/src/components/ProfileAvatarUpload.vue @@ -0,0 +1,119 @@ + + + diff --git a/src/models/home.ts b/src/models/home.ts index 452282a..870c033 100644 --- a/src/models/home.ts +++ b/src/models/home.ts @@ -15,6 +15,7 @@ export interface Series { export interface Price { sell: number buy: number + price: number price_last: number goldir:number } \ No newline at end of file diff --git a/src/models/login.ts b/src/models/login.ts index c3781bf..7e2ba7e 100644 --- a/src/models/login.ts +++ b/src/models/login.ts @@ -19,7 +19,11 @@ export interface User { name: string; active: boolean; mobile: string; - avatar_id?: any; + avatar_id?: number | null; + avatar_url?: string | null; + full_src?: string | null; + avatar?: { id?: number; src?: string; full_src?: string; url?: string }; + file?: { id?: number; src?: string; full_src?: string; url?: string }; last_seen_at: string; default_address_id?: any; sts?: any; diff --git a/src/themeConfig.ts b/src/themeConfig.ts index 850a221..9c6ae2e 100644 --- a/src/themeConfig.ts +++ b/src/themeConfig.ts @@ -10,8 +10,8 @@ const projectName = getConfigApp('name') export const baseURL: string = projectBase // export const baseURL: string = 'https://api-gholaktala.z23.ir/' -// const baseUploadURL: string = '/site/file' -// const uploadURL: string = baseURL + baseUploadURL +/** Customer profile image upload (backend: POST /customer/avatar) */ +export const avatarUploadURL: string = `${projectBase.replace(/\/$/, '')}/customer/avatar` // const baseURLStorage: string = baseURL + '/v1' const prefixCls: string = 'noname' // const version: string = pkg.version diff --git a/src/utils/file.ts b/src/utils/file.ts index aaeaffc..e0370dc 100644 --- a/src/utils/file.ts +++ b/src/utils/file.ts @@ -1,13 +1,16 @@ import { baseURL } from '@/themeConfig' +import type { User } from '@/models/login' export interface ProductFile { id?: number url?: string | null src?: string + full_src?: string } export function getFileUrl(file?: ProductFile | null): string | null { if (!file) return null + if (file.full_src) return file.full_src if (file.url) return file.url if (!file.src) return null if (/^https?:\/\//i.test(file.src)) return file.src @@ -15,3 +18,12 @@ export function getFileUrl(file?: ProductFile | null): string | null { const path = file.src.replace(/^\//, '') return `${base}/${path}` } + +/** Resolve profile avatar URL from GET /customer/me payload */ +export function getUserAvatarUrl(user?: User | null): string | null { + if (!user) return null + if (typeof user.avatar_url === 'string' && user.avatar_url) return user.avatar_url + if (typeof user.full_src === 'string' && user.full_src) return user.full_src + const nested = user.avatar || user.file + return getFileUrl(nested as ProductFile | undefined) +} diff --git a/src/views/base/about/index.vue b/src/views/base/about/index.vue index 1cfcfc1..1e37691 100644 --- a/src/views/base/about/index.vue +++ b/src/views/base/about/index.vue @@ -40,7 +40,7 @@
- + تماس با پشتیبانی diff --git a/src/views/base/copper&silver/index.vue b/src/views/base/copper&silver/index.vue index 1809891..51b7c45 100644 --- a/src/views/base/copper&silver/index.vue +++ b/src/views/base/copper&silver/index.vue @@ -308,8 +308,17 @@ const finalPrice = computed(() => { } }) -const payablePrice = computed(() => finalPrice.value) -const equivalentPrice = computed(() => usePriceWithoutType(((isBuy ? price.value?.buy ?? 0 : price.value?.sell ?? 0) * (parseFloat(((form.value?.goldValue ?? 0) * 0.01).toFixed(4))) ).toFixed(0)) ) +const payablePrice = computed(() => + isBuy.value ? finalPrice.value + feeInRial.value : finalPrice.value - feeInRial.value +) +const feeInGrams = computed(() => + parseFloat(((form.value?.goldValue ?? 0) * 0.01).toFixed(4)) +) +const unitPrice = computed(() => + (props?.ProductItem?.price_profit ?? 0) + (props?.ProductItem?.price ?? 0) +) +const feeInRial = computed(() => unitPrice.value * feeInGrams.value) +const equivalentPrice = computed(() => usePriceWithoutType(feeInRial.value.toFixed(0))) const disableTransaction = computed(() => loading.value || @@ -506,6 +515,28 @@ const limitedPrice = computed(() => { } } }*/ +function syncFormWithLatestPrice() { + if (!price.value) return + + const goldValue = form.value.goldValue + if (goldValue !== undefined && goldValue !== null && goldValue !== '' && !isNaN(Number(goldValue))) { + calculateCash(Number(goldValue)) + return + } + + const goldCash = form.value.goldCash + if (goldCash !== undefined && goldCash !== null && goldCash !== '' && !isNaN(Number(goldCash))) { + calculateGold(Number(goldCash)) + } +} + +watch( + () => [basePriceValue.value, isBuy.value], + () => { + syncFormWithLatestPrice() + } +) + function calculateCash(val: number) { priceErrorVisible.value = false if (price.value) { @@ -597,10 +628,10 @@ const formatter = (value: number) => { const price = computed((): Price => lastPrice.value ?? 0) const goldPriceValue = computed(() => { - if (!price.value) return 0 - return isBuy.value - ? (price.value.buy ?? 0) - : (price.value.sell ?? 0) + if (!lastPrice.value?.price) return 0 + return isBuy.value + ? (lastPrice.value.buy ?? 0) + : (lastPrice.value.sell ?? 0) }) async function initPrice() { diff --git a/src/views/base/educate/index.vue b/src/views/base/educate/index.vue index 8c12de3..ae612ab 100644 --- a/src/views/base/educate/index.vue +++ b/src/views/base/educate/index.vue @@ -89,7 +89,7 @@
- + تماس با پشتیبانی diff --git a/src/views/base/gold/index.vue b/src/views/base/gold/index.vue index 6dbfefb..a5be94c 100644 --- a/src/views/base/gold/index.vue +++ b/src/views/base/gold/index.vue @@ -167,7 +167,7 @@
کارمزد:
-
{{ parseFloat(((form.goldValue ?? 0) * (Number(feeAmount))).toFixed(4)) }}
+
{{ feeInGrams }}
گرم
@@ -274,10 +274,18 @@ const sellPagination = ref({ }], limit: 6, page: 0 }) -const finalPrice = computed(() => (form.value?.goldValue * (isBuy.value ? price.value?.buy ?? 0 : price.value?.sell ?? 0))) -// const payablePrice = computed(() => finalPrice.value + finalPrice.value * 0.007) -const payablePrice = computed(() => finalPrice.value) -const equivalentPrice = computed(() => usePriceWithoutType(((isBuy ? price.value?.buy ?? 0 : price.value?.sell ?? 0) * (parseFloat(((form.value?.goldValue ?? 0) * 0.01).toFixed(4))) ).toFixed(0)) ) +const unitPrice = computed(() => + isBuy.value ? price.value?.buy ?? 0 : price.value?.sell ?? 0 +) +const feeInGrams = computed(() => + parseFloat(((form.value?.goldValue ?? 0) * Number(feeAmount.value)).toFixed(4)) +) +const finalPrice = computed(() => (form.value?.goldValue ?? 0) * unitPrice.value) +const feeInRial = computed(() => unitPrice.value * feeInGrams.value) +const equivalentPrice = computed(() => usePriceWithoutType(feeInRial.value.toFixed(0))) +const payablePrice = computed(() => + isBuy.value ? finalPrice.value + feeInRial.value : finalPrice.value - feeInRial.value +) const disableTransaction = computed(() => loading.value || @@ -472,6 +480,28 @@ const limitedPrice = computed(() => { return walletStore?.limitedPrice[0] }) +function syncFormWithLatestPrice() { + if (!price.value) return + + const goldValue = form.value.goldValue + if (goldValue !== undefined && goldValue !== null && goldValue !== '' && !isNaN(Number(goldValue))) { + calculateCash(Number(goldValue)) + return + } + + const goldCash = form.value.goldCash + if (goldCash !== undefined && goldCash !== null && goldCash !== '' && !isNaN(Number(goldCash))) { + calculateGold(Number(goldCash)) + } +} + +watch( + () => [lastPrice.value?.buy, lastPrice.value?.sell, isBuy.value], + () => { + syncFormWithLatestPrice() + } +) + function calculateCash(val: number) { priceErrorVisible.value = false // console.log(val) @@ -556,7 +586,8 @@ const formatter = (value: number) => { const price = computed((): Price => lastPrice.value ?? 0) const goldPriceValue = computed(() => { - if (!price.value) return 0 + // if (!price.value) return 0 + if (!lastPrice.value?.price) return 0 return isBuy.value ? (price.value.buy ?? 0) : (price.value.sell ?? 0) diff --git a/src/views/base/home/components/PriceChart.vue b/src/views/base/home/components/PriceChart.vue index 3dfaadb..8d650b8 100644 --- a/src/views/base/home/components/PriceChart.vue +++ b/src/views/base/home/components/PriceChart.vue @@ -66,7 +66,7 @@ const chartOptions = computed(() => { tickAmount: 8, show: false, labels: { - formatter: (val: number) => toPersianNumber(usePrice(val)), + formatter: (val: number) => toPersianNumber(usePrice(val, true, 'ه.ریال')), style: { fontSize: '13px', fontFamily } } }, @@ -87,7 +87,7 @@ const chartOptions = computed(() => { })}` } }, - formatter: (val: number) => toPersianNumber(usePrice(val)), + formatter: (val: number) => toPersianNumber(usePrice(val, true, 'ه.ریال')), style: { fontFamily } }, colors: [config.config.color], diff --git a/src/views/base/products/components/DealProduct.vue b/src/views/base/products/components/DealProduct.vue index 88b9236..38c1817 100644 --- a/src/views/base/products/components/DealProduct.vue +++ b/src/views/base/products/components/DealProduct.vue @@ -652,6 +652,24 @@ onMounted(async () => { }) async function initPrice() { + try { + // chartLoading.value = true + await getLastPrices() + // await setIntervalGetPrice() + loading.value = true + price.value = lastPrice.value + /*props.ProductItem.price = lastPrice.value?.buy * props.ProductItem?.amount + props.ProductItem.sellPrice = lastPrice.value?.sell * props.ProductItem?.amount*/ + props.ProductItem.price = lastPrice?.value?.price? (lastPrice?.value?.price + props.ProductItem?.cash_fee_buy) * props.ProductItem?.amount: 0 + props.ProductItem.sellPrice = lastPrice?.value?.price? (lastPrice?.value?.price - props.ProductItem?.percent_fee_sell) * props.ProductItem?.amount:0 + } catch (e) { + console.log(e) + } finally { + loading.value = false + // chartLoading.value = false + } +} +/*async function initPrice() { try { // chartLoading.value = true await getLastPrices() @@ -666,7 +684,7 @@ async function initPrice() { loading.value = false // chartLoading.value = false } -} +}*/ // onMounted(() => { // initPrice() diff --git a/src/views/base/rules/index.vue b/src/views/base/rules/index.vue index 55b2552..93de17e 100644 --- a/src/views/base/rules/index.vue +++ b/src/views/base/rules/index.vue @@ -45,7 +45,7 @@
- + تماس با پشتیبانی diff --git a/src/views/base/rules/permissions/permissions.vue b/src/views/base/rules/permissions/permissions.vue index 54e4331..70bfa01 100644 --- a/src/views/base/rules/permissions/permissions.vue +++ b/src/views/base/rules/permissions/permissions.vue @@ -17,7 +17,7 @@
- + تماس با پشتیبانی diff --git a/src/views/base/user/index.vue b/src/views/base/user/index.vue index 2de93f9..8e4629c 100644 --- a/src/views/base/user/index.vue +++ b/src/views/base/user/index.vue @@ -14,6 +14,17 @@
+
نام و نام خانوادگی:
{{ userStore.userInfo?.name }}
@@ -189,6 +200,12 @@
+ @@ -266,7 +283,7 @@