feat(convert): read quantity from the asset so the leftover can be split across 1.5 and 2.5 wire.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -50,3 +50,4 @@
|
|||||||
- 2026-10-21 | نمودار خانه = کارت لندینگ | `home/components/LandingLiveChartMain.vue` + `useLandingLiveChart.ts` + `styles/landing-live-chart-main.less` | موبایل PriceChartSection و دسکتاپ DesktopChartSection/Panel همین کارت؛ استایل از main.less
|
- 2026-10-21 | نمودار خانه = کارت لندینگ | `home/components/LandingLiveChartMain.vue` + `useLandingLiveChart.ts` + `styles/landing-live-chart-main.less` | موبایل PriceChartSection و دسکتاپ DesktopChartSection/Panel همین کارت؛ استایل از main.less
|
||||||
- 2026-10-21 | چیدمان کارت نمودار خانه | همان دو فایل vue/less | هدر: نام+وضعیت راست، تب محصول چپ؛ قیمت راست و تغییر چپ؛ تب بازه کنار عنوان نمودار
|
- 2026-10-21 | چیدمان کارت نمودار خانه | همان دو فایل vue/less | هدر: نام+وضعیت راست، تب محصول چپ؛ قیمت راست و تغییر چپ؛ تب بازه کنار عنوان نمودار
|
||||||
- 2026-10-21 | تب نمودار = محصول فعال | `useLandingLiveChart.ts` + `LandingLiveChartMain.vue` | تب از کاتالوگ `active && show`؛ داده با `price_offset_percent` همان محصول
|
- 2026-10-21 | تب نمودار = محصول فعال | `useLandingLiveChart.ts` + `LandingLiveChartMain.vue` | تب از کاتالوگ `active && show`؛ داده با `price_offset_percent` همان محصول
|
||||||
|
- 2026-10-31 | مقدار تبدیل کاتد/مفتول/شمش | `convert/components/CopperConvertCalculator.vue` + `useCopperConvertPage.ts` | زبانه مقدار تا موجودی؛ مانده با زبانه ۱.۵ (تا کل مانده) و ۲.۵ (تا باقیمانده بعد از ۱.۵)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="copper-convert" dir="rtl">
|
<div class="copper-convert" dir="rtl">
|
||||||
<p class="copper-convert__lead">
|
<p class="copper-convert__lead">
|
||||||
وزن دارایی را وارد کنید؛ معادل مفتول و تعداد حلقه سیم ۱.۵ و ۲.۵ با قیمت روز محاسبه میشود.
|
مقدار کاتد، مفتول یا شمش از دارایی شما خوانده میشود. با زبانه از صفر تا همان موجودی انتخاب کنید. معادل مفتول و حلقه سیم ۱.۵ و ۲.۵ با قیمت روز حساب میشود.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<a-spin :spinning="loading">
|
<a-spin :spinning="loading">
|
||||||
@@ -59,18 +59,33 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="copper-convert__weight">
|
<div class="copper-convert__weight">
|
||||||
<label class="copper-convert__field-label" for="copper-convert-kg">مقدار</label>
|
<label class="copper-convert__field-label">مقدار</label>
|
||||||
<div class="copper-convert__weight-wrap">
|
<div class="copper-convert__weight-wrap">
|
||||||
<input
|
<span class="copper-convert__weight-value" dir="ltr">{{ formatAssetAmount(sliderAmount) }}</span>
|
||||||
id="copper-convert-kg"
|
<span class="copper-convert__weight-unit">{{ assetUnit }}</span>
|
||||||
v-model="inputKg"
|
</div>
|
||||||
class="copper-convert__weight-input"
|
<p class="copper-convert__asset-hint">
|
||||||
type="text"
|
<template v-if="assetAmount > 0">از دارایی شما؛ انتهای زبانه {{ formatAssetAmount(assetAmount) }} {{ assetUnit }} است</template>
|
||||||
inputmode="decimal"
|
<template v-else>موجودی این دارایی صفر است.</template>
|
||||||
placeholder="مثلاً ۱۰"
|
</p>
|
||||||
autocomplete="off"
|
<div
|
||||||
|
class="app-touch-slider copper-convert__slider"
|
||||||
|
@touchstart.stop
|
||||||
|
@touchmove.stop
|
||||||
|
@pointerdown.stop
|
||||||
|
>
|
||||||
|
<a-slider
|
||||||
|
v-model:value="sliderAmount"
|
||||||
|
:min="0"
|
||||||
|
:max="assetAmount > 0 ? assetAmount : 1"
|
||||||
|
:step="sliderStep"
|
||||||
|
:disabled="assetAmount <= 0"
|
||||||
|
:tip-formatter="sliderTip"
|
||||||
/>
|
/>
|
||||||
<span class="copper-convert__weight-unit">کیلوگرم</span>
|
</div>
|
||||||
|
<div class="copper-convert__slider-scale">
|
||||||
|
<span>۰</span>
|
||||||
|
<span dir="ltr">{{ formatAssetAmount(assetAmount) }} {{ assetUnit }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -86,25 +101,11 @@
|
|||||||
<span class="copper-convert__ring-badge">۱.۵ mm²</span>
|
<span class="copper-convert__ring-badge">۱.۵ mm²</span>
|
||||||
<p class="copper-convert__ring-count" dir="ltr">{{ formatRings(result.rings15ByValue) }}</p>
|
<p class="copper-convert__ring-count" dir="ltr">{{ formatRings(result.rings15ByValue) }}</p>
|
||||||
<p class="copper-convert__ring-caption">حلقه سیم</p>
|
<p class="copper-convert__ring-caption">حلقه سیم</p>
|
||||||
<p
|
|
||||||
v-if="result.rings15ByWeight != null"
|
|
||||||
class="copper-convert__ring-sub"
|
|
||||||
dir="ltr"
|
|
||||||
>
|
|
||||||
≈ {{ formatRings(result.rings15ByWeight) }} بر اساس وزن حلقه
|
|
||||||
</p>
|
|
||||||
</article>
|
</article>
|
||||||
<article class="copper-convert__ring-card">
|
<article class="copper-convert__ring-card">
|
||||||
<span class="copper-convert__ring-badge">۲.۵ mm²</span>
|
<span class="copper-convert__ring-badge">۲.۵ mm²</span>
|
||||||
<p class="copper-convert__ring-count" dir="ltr">{{ formatRings(result.rings25ByValue) }}</p>
|
<p class="copper-convert__ring-count" dir="ltr">{{ formatRings(result.rings25ByValue) }}</p>
|
||||||
<p class="copper-convert__ring-caption">حلقه سیم</p>
|
<p class="copper-convert__ring-caption">حلقه سیم</p>
|
||||||
<p
|
|
||||||
v-if="result.rings25ByWeight != null"
|
|
||||||
class="copper-convert__ring-sub"
|
|
||||||
dir="ltr"
|
|
||||||
>
|
|
||||||
≈ {{ formatRings(result.rings25ByWeight) }} بر اساس وزن حلقه
|
|
||||||
</p>
|
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -120,7 +121,72 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<p v-else-if="inputKg && !loading" class="copper-convert__warn">
|
<section v-if="result && remainderAmount > 0" class="copper-convert__split">
|
||||||
|
<div class="copper-convert__result-head">
|
||||||
|
<span class="copper-convert__result-kicker">مانده دارایی</span>
|
||||||
|
<span class="copper-convert__result-title">تقسیم بین دو سیم</span>
|
||||||
|
</div>
|
||||||
|
<p class="copper-convert__asset-hint">
|
||||||
|
مانده {{ formatAssetAmount(remainderAmount) }} {{ assetUnit }} است. زبانهٔ ۱.۵ تا کل مانده میرود؛ زبانهٔ ۲.۵ فقط تا آنچه بعد از ۱.۵ میماند.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="copper-convert__weight">
|
||||||
|
<label class="copper-convert__field-label">سیم ۱.۵ mm²</label>
|
||||||
|
<div class="copper-convert__weight-wrap">
|
||||||
|
<span class="copper-convert__weight-value" dir="ltr">{{ formatAssetAmount(wire15Amount) }}</span>
|
||||||
|
<span class="copper-convert__weight-unit">{{ assetUnit }}</span>
|
||||||
|
</div>
|
||||||
|
<p class="copper-convert__asset-hint">معادل {{ formatRings(wire15Rings) }} حلقه</p>
|
||||||
|
<div
|
||||||
|
class="app-touch-slider copper-convert__slider"
|
||||||
|
@touchstart.stop
|
||||||
|
@touchmove.stop
|
||||||
|
@pointerdown.stop
|
||||||
|
>
|
||||||
|
<a-slider
|
||||||
|
v-model:value="wire15Amount"
|
||||||
|
:min="0"
|
||||||
|
:max="remainderAmount"
|
||||||
|
:step="sliderStep"
|
||||||
|
:tip-formatter="sliderTip"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="copper-convert__slider-scale">
|
||||||
|
<span>۰</span>
|
||||||
|
<span dir="ltr">{{ formatAssetAmount(remainderAmount) }} {{ assetUnit }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="copper-convert__weight">
|
||||||
|
<label class="copper-convert__field-label">سیم ۲.۵ mm²</label>
|
||||||
|
<div class="copper-convert__weight-wrap">
|
||||||
|
<span class="copper-convert__weight-value" dir="ltr">{{ formatAssetAmount(wire25Amount) }}</span>
|
||||||
|
<span class="copper-convert__weight-unit">{{ assetUnit }}</span>
|
||||||
|
</div>
|
||||||
|
<p class="copper-convert__asset-hint">معادل {{ formatRings(wire25Rings) }} حلقه</p>
|
||||||
|
<div
|
||||||
|
class="app-touch-slider copper-convert__slider"
|
||||||
|
@touchstart.stop
|
||||||
|
@touchmove.stop
|
||||||
|
@pointerdown.stop
|
||||||
|
>
|
||||||
|
<a-slider
|
||||||
|
v-model:value="wire25Amount"
|
||||||
|
:min="0"
|
||||||
|
:max="wire25Max > 0 ? wire25Max : 1"
|
||||||
|
:step="sliderStep"
|
||||||
|
:disabled="wire25Max <= 0"
|
||||||
|
:tip-formatter="sliderTip"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="copper-convert__slider-scale">
|
||||||
|
<span>۰</span>
|
||||||
|
<span dir="ltr">{{ formatAssetAmount(wire25Max) }} {{ assetUnit }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<p v-if="!result && amountAttempted && !loading" class="copper-convert__warn">
|
||||||
مقدار معتبر وارد کنید و از فعال بودن قیمت کاتد/مفتول در سامانه مطمئن شوید.
|
مقدار معتبر وارد کنید و از فعال بودن قیمت کاتد/مفتول در سامانه مطمئن شوید.
|
||||||
</p>
|
</p>
|
||||||
</a-spin>
|
</a-spin>
|
||||||
@@ -132,7 +198,24 @@ import { computed } from 'vue'
|
|||||||
import { useCopperConvertPageContext } from '../composables/useCopperConvertPage'
|
import { useCopperConvertPageContext } from '../composables/useCopperConvertPage'
|
||||||
import type { CopperConvertSource } from '@/utils/copperWireConvert'
|
import type { CopperConvertSource } from '@/utils/copperWireConvert'
|
||||||
|
|
||||||
const { loading, source, inputKg, result, priceRows } = useCopperConvertPageContext()
|
const {
|
||||||
|
loading,
|
||||||
|
source,
|
||||||
|
assetAmount,
|
||||||
|
assetUnit,
|
||||||
|
sliderAmount,
|
||||||
|
sliderStep,
|
||||||
|
remainderAmount,
|
||||||
|
wire15Amount,
|
||||||
|
wire25Amount,
|
||||||
|
wire25Max,
|
||||||
|
wire15Rings,
|
||||||
|
wire25Rings,
|
||||||
|
result,
|
||||||
|
priceRows,
|
||||||
|
} = useCopperConvertPageContext()
|
||||||
|
|
||||||
|
const amountAttempted = computed(() => sliderAmount.value > 0)
|
||||||
|
|
||||||
const sourceOptions = computed(() => [
|
const sourceOptions = computed(() => [
|
||||||
{ label: 'کاتد', value: 'katod' as CopperConvertSource },
|
{ label: 'کاتد', value: 'katod' as CopperConvertSource },
|
||||||
@@ -143,6 +226,17 @@ const sourceOptions = computed(() => [
|
|||||||
const metalPriceRows = computed(() => priceRows.value.slice(0, 3))
|
const metalPriceRows = computed(() => priceRows.value.slice(0, 3))
|
||||||
const wirePriceRows = computed(() => priceRows.value.slice(3))
|
const wirePriceRows = computed(() => priceRows.value.slice(3))
|
||||||
|
|
||||||
|
function formatAssetAmount(value: number) {
|
||||||
|
if (!Number.isFinite(value)) return '0'
|
||||||
|
const rounded = Math.round(value * 1000) / 1000
|
||||||
|
if (Number.isInteger(rounded)) return rounded.toLocaleString('en-US')
|
||||||
|
return rounded.toLocaleString('en-US', { maximumFractionDigits: 3 })
|
||||||
|
}
|
||||||
|
|
||||||
|
function sliderTip(value?: number) {
|
||||||
|
return `${formatAssetAmount(Number(value ?? 0))} ${assetUnit.value}`
|
||||||
|
}
|
||||||
|
|
||||||
function formatRial(value: number) {
|
function formatRial(value: number) {
|
||||||
return Math.round(value).toLocaleString('en-US')
|
return Math.round(value).toLocaleString('en-US')
|
||||||
}
|
}
|
||||||
@@ -178,7 +272,8 @@ function formatRings(value: number) {
|
|||||||
|
|
||||||
.copper-convert__panel,
|
.copper-convert__panel,
|
||||||
.copper-convert__form,
|
.copper-convert__form,
|
||||||
.copper-convert__result {
|
.copper-convert__result,
|
||||||
|
.copper-convert__split {
|
||||||
padding: 0.875rem;
|
padding: 0.875rem;
|
||||||
border-radius: 0.875rem;
|
border-radius: 0.875rem;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
@@ -273,7 +368,8 @@ function formatRings(value: number) {
|
|||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
.copper-convert__form {
|
.copper-convert__form,
|
||||||
|
.copper-convert__split {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0.65rem;
|
gap: 0.65rem;
|
||||||
@@ -326,23 +422,36 @@ function formatRings(value: number) {
|
|||||||
box-shadow: inset 0 1px 2px rgba(15, 39, 68, 0.04);
|
box-shadow: inset 0 1px 2px rgba(15, 39, 68, 0.04);
|
||||||
}
|
}
|
||||||
|
|
||||||
.copper-convert__weight-input {
|
.copper-convert__weight-value {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
border: none;
|
|
||||||
outline: none;
|
|
||||||
background: transparent;
|
|
||||||
font-size: 1.125rem;
|
font-size: 1.125rem;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
color: #0f172a;
|
color: #0f172a;
|
||||||
text-align: right;
|
|
||||||
direction: ltr;
|
direction: ltr;
|
||||||
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.copper-convert__weight-input::placeholder {
|
.copper-convert__asset-hint {
|
||||||
color: #94a3b8;
|
margin: 0.35rem 0 0;
|
||||||
font-weight: 500;
|
font-size: 0.6875rem;
|
||||||
font-size: 0.875rem;
|
line-height: 1.5;
|
||||||
|
color: #64748b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copper-convert__slider {
|
||||||
|
margin-top: 0.15rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copper-convert__slider-scale {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-top: -0.15rem;
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #64748b;
|
||||||
}
|
}
|
||||||
|
|
||||||
.copper-convert__weight-unit {
|
.copper-convert__weight-unit {
|
||||||
|
|||||||
@@ -5,12 +5,15 @@ import {
|
|||||||
onUnmounted,
|
onUnmounted,
|
||||||
provide,
|
provide,
|
||||||
ref,
|
ref,
|
||||||
|
watch,
|
||||||
type ComputedRef,
|
type ComputedRef,
|
||||||
type InjectionKey,
|
type InjectionKey,
|
||||||
type Ref,
|
type Ref,
|
||||||
} from 'vue'
|
} from 'vue'
|
||||||
import { getProducts } from '@/api/products'
|
import { getProducts } from '@/api/products'
|
||||||
|
import { useWalletAssets } from '@/composables/useWalletAssets'
|
||||||
import type { Product } from '@/models/products'
|
import type { Product } from '@/models/products'
|
||||||
|
import type { WalletInventoryCard } from '@/models/walletAssets'
|
||||||
import {
|
import {
|
||||||
COPPER_CONVERT_WIRE_FALLBACK,
|
COPPER_CONVERT_WIRE_FALLBACK,
|
||||||
calcCopperWireConvert,
|
calcCopperWireConvert,
|
||||||
@@ -19,9 +22,10 @@ import {
|
|||||||
type CopperConvertSource,
|
type CopperConvertSource,
|
||||||
} from '@/utils/copperWireConvert'
|
} from '@/utils/copperWireConvert'
|
||||||
import { LEGACY_GROUP_KATOD, LEGACY_GROUP_MAFTOL, normalizeProductGroupType } from '@/utils/productCategories'
|
import { LEGACY_GROUP_KATOD, LEGACY_GROUP_MAFTOL, normalizeProductGroupType } from '@/utils/productCategories'
|
||||||
|
import { getProductWeightUnit } from '@/utils/productDealMethod'
|
||||||
import { getProductBuyPrice } from '@/utils/productPrice'
|
import { getProductBuyPrice } from '@/utils/productPrice'
|
||||||
import { getLastPrices, startLastPricePolling, stopLastPricePolling } from '@/utils/price'
|
import { getLastPrices, startLastPricePolling, stopLastPricePolling } from '@/utils/price'
|
||||||
import { persianToEnglishDigits } from '@/utils/persianDigits'
|
import { weightToGrams } from '@/utils/weightUnit'
|
||||||
|
|
||||||
export const COPPER_CONVERT_PAGE_KEY: InjectionKey<CopperConvertPageContext> =
|
export const COPPER_CONVERT_PAGE_KEY: InjectionKey<CopperConvertPageContext> =
|
||||||
Symbol('copperConvertPageContext')
|
Symbol('copperConvertPageContext')
|
||||||
@@ -29,18 +33,45 @@ export const COPPER_CONVERT_PAGE_KEY: InjectionKey<CopperConvertPageContext> =
|
|||||||
export interface CopperConvertPageContext {
|
export interface CopperConvertPageContext {
|
||||||
loading: Ref<boolean>
|
loading: Ref<boolean>
|
||||||
source: Ref<CopperConvertSource>
|
source: Ref<CopperConvertSource>
|
||||||
inputKg: Ref<string>
|
assetAmount: ComputedRef<number>
|
||||||
|
assetUnit: ComputedRef<string>
|
||||||
|
sliderAmount: Ref<number>
|
||||||
|
sliderStep: ComputedRef<number>
|
||||||
|
remainderAmount: ComputedRef<number>
|
||||||
|
wire15Amount: Ref<number>
|
||||||
|
wire25Amount: Ref<number>
|
||||||
|
wire25Max: ComputedRef<number>
|
||||||
|
wire15Rings: ComputedRef<number>
|
||||||
|
wire25Rings: ComputedRef<number>
|
||||||
prices: ComputedRef<CopperConvertPrices>
|
prices: ComputedRef<CopperConvertPrices>
|
||||||
result: ComputedRef<CopperConvertResult | null>
|
result: ComputedRef<CopperConvertResult | null>
|
||||||
priceRows: ComputedRef<{ label: string; value: string; missing?: boolean }[]>
|
priceRows: ComputedRef<{ label: string; value: string; missing?: boolean }[]>
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseKg(raw: string): number {
|
function roundAmount(value: number): number {
|
||||||
const s = persianToEnglishDigits(String(raw ?? ''))
|
return Math.round(value * 1000) / 1000
|
||||||
.replace(/,/g, '')
|
}
|
||||||
.replace(/[^\d.]/g, '')
|
|
||||||
const n = Number.parseFloat(s)
|
function cardMatchesSource(card: WalletInventoryCard, src: CopperConvertSource) {
|
||||||
return Number.isFinite(n) ? n : 0
|
const group = normalizeProductGroupType(card.group_type)
|
||||||
|
const title = card.title ?? ''
|
||||||
|
if (src === 'katod') return group === LEGACY_GROUP_KATOD || title.includes('کاتد')
|
||||||
|
if (src === 'maftoul') return group === LEGACY_GROUP_MAFTOL || title.includes('مفتول')
|
||||||
|
return group.includes('شمش') || title.includes('شمش')
|
||||||
|
}
|
||||||
|
|
||||||
|
function cardQuantity(card: WalletInventoryCard): number {
|
||||||
|
const qty = Number(card.quantity ?? 0)
|
||||||
|
return Number.isFinite(qty) && qty > 0 ? qty : 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function quantityToKg(quantity: number, unit: string, product?: Product): number {
|
||||||
|
if (quantity <= 0) return 0
|
||||||
|
if (unit.includes('کیلو')) return quantity
|
||||||
|
if (unit.includes('گرم')) return quantity / 1000
|
||||||
|
const perPiece = Number(product?.amount ?? 0)
|
||||||
|
if (perPiece > 0) return weightToGrams(quantity * perPiece, getProductWeightUnit(product)) / 1000
|
||||||
|
return quantity
|
||||||
}
|
}
|
||||||
|
|
||||||
function titleIncludes(product: Product, part: string) {
|
function titleIncludes(product: Product, part: string) {
|
||||||
@@ -90,8 +121,71 @@ function resolveWireRingPrice(product: Product | undefined, fallback: number): n
|
|||||||
export function useCopperConvertPage() {
|
export function useCopperConvertPage() {
|
||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
const source = ref<CopperConvertSource>('katod')
|
const source = ref<CopperConvertSource>('katod')
|
||||||
const inputKg = ref('')
|
const sliderAmount = ref(0)
|
||||||
|
const wire15Amount = ref(0)
|
||||||
|
const wire25Amount = ref(0)
|
||||||
const catalog = ref<Product[]>([])
|
const catalog = ref<Product[]>([])
|
||||||
|
const { assetsSummary, loadWalletAssets } = useWalletAssets()
|
||||||
|
|
||||||
|
const assetCards = computed(() => {
|
||||||
|
const summary = assetsSummary.value
|
||||||
|
if (!summary) return [] as WalletInventoryCard[]
|
||||||
|
const src = source.value
|
||||||
|
const fromInventory = (summary.inventory_cards ?? []).filter((card) =>
|
||||||
|
cardMatchesSource(card, src),
|
||||||
|
)
|
||||||
|
return fromInventory.length
|
||||||
|
? fromInventory
|
||||||
|
: (summary.count_products ?? []).filter((card) => cardMatchesSource(card, src))
|
||||||
|
})
|
||||||
|
|
||||||
|
const assetUnit = computed(() => {
|
||||||
|
const units = [...new Set(assetCards.value.map((card) => (card.unit ?? '').trim()).filter(Boolean))]
|
||||||
|
if (units.length === 1) return units[0]
|
||||||
|
return 'کیلوگرم'
|
||||||
|
})
|
||||||
|
|
||||||
|
const assetAmount = computed(() => {
|
||||||
|
const cards = assetCards.value
|
||||||
|
if (!cards.length) return 0
|
||||||
|
const units = [...new Set(cards.map((card) => (card.unit ?? '').trim()).filter(Boolean))]
|
||||||
|
if (units.length > 1) {
|
||||||
|
return roundAmount(
|
||||||
|
cards.reduce((sum, card) => sum + quantityToKg(cardQuantity(card), card.unit ?? '', undefined), 0),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return roundAmount(cards.reduce((sum, card) => sum + cardQuantity(card), 0))
|
||||||
|
})
|
||||||
|
|
||||||
|
const sliderStep = computed(() => (assetUnit.value.includes('عدد') ? 1 : 0.001))
|
||||||
|
|
||||||
|
const remainderAmount = computed(() =>
|
||||||
|
roundAmount(Math.max(0, assetAmount.value - sliderAmount.value)),
|
||||||
|
)
|
||||||
|
|
||||||
|
const wire25Max = computed(() =>
|
||||||
|
roundAmount(Math.max(0, remainderAmount.value - wire15Amount.value)),
|
||||||
|
)
|
||||||
|
|
||||||
|
watch(source, () => {
|
||||||
|
sliderAmount.value = assetAmount.value
|
||||||
|
wire15Amount.value = 0
|
||||||
|
wire25Amount.value = 0
|
||||||
|
})
|
||||||
|
|
||||||
|
watch([remainderAmount, wire15Amount], () => {
|
||||||
|
if (wire15Amount.value > remainderAmount.value) wire15Amount.value = remainderAmount.value
|
||||||
|
if (wire25Amount.value > wire25Max.value) wire25Amount.value = wire25Max.value
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(
|
||||||
|
assetAmount,
|
||||||
|
(amount, prev) => {
|
||||||
|
const previous = prev ?? 0
|
||||||
|
if (sliderAmount.value === previous || sliderAmount.value > amount) sliderAmount.value = amount
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
)
|
||||||
|
|
||||||
const katodProduct = computed(() => pickProduct(catalog.value, isKatodProduct))
|
const katodProduct = computed(() => pickProduct(catalog.value, isKatodProduct))
|
||||||
const maftolProduct = computed(() => pickProduct(catalog.value, isMaftolProduct))
|
const maftolProduct = computed(() => pickProduct(catalog.value, isMaftolProduct))
|
||||||
@@ -113,10 +207,38 @@ export function useCopperConvertPage() {
|
|||||||
wireWeightGrams25: COPPER_CONVERT_WIRE_FALLBACK.wireWeightGrams25,
|
wireWeightGrams25: COPPER_CONVERT_WIRE_FALLBACK.wireWeightGrams25,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const result = computed(() =>
|
const sourceProduct = computed(() => {
|
||||||
calcCopperWireConvert(parseKg(inputKg.value), source.value, prices.value),
|
if (source.value === 'katod') return katodProduct.value
|
||||||
|
if (source.value === 'maftoul') return maftolProduct.value
|
||||||
|
return shamshProduct.value
|
||||||
|
})
|
||||||
|
|
||||||
|
const selectedKg = computed(() =>
|
||||||
|
quantityToKg(sliderAmount.value, assetUnit.value, sourceProduct.value),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const result = computed(() =>
|
||||||
|
calcCopperWireConvert(selectedKg.value, source.value, prices.value),
|
||||||
|
)
|
||||||
|
|
||||||
|
const wire15Rings = computed(() => {
|
||||||
|
const converted = calcCopperWireConvert(
|
||||||
|
quantityToKg(wire15Amount.value, assetUnit.value, sourceProduct.value),
|
||||||
|
source.value,
|
||||||
|
prices.value,
|
||||||
|
)
|
||||||
|
return converted?.rings15ByValue ?? 0
|
||||||
|
})
|
||||||
|
|
||||||
|
const wire25Rings = computed(() => {
|
||||||
|
const converted = calcCopperWireConvert(
|
||||||
|
quantityToKg(wire25Amount.value, assetUnit.value, sourceProduct.value),
|
||||||
|
source.value,
|
||||||
|
prices.value,
|
||||||
|
)
|
||||||
|
return converted?.rings25ByValue ?? 0
|
||||||
|
})
|
||||||
|
|
||||||
const priceRows = computed(() => {
|
const priceRows = computed(() => {
|
||||||
const p = prices.value
|
const p = prices.value
|
||||||
const row = (label: string, amount: number) => ({
|
const row = (label: string, amount: number) => ({
|
||||||
@@ -136,8 +258,11 @@ export function useCopperConvertPage() {
|
|||||||
async function loadCatalog() {
|
async function loadCatalog() {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
try {
|
try {
|
||||||
await getLastPrices()
|
const [, list] = await Promise.all([
|
||||||
const list = await getProducts()
|
getLastPrices(),
|
||||||
|
getProducts(),
|
||||||
|
loadWalletAssets(),
|
||||||
|
])
|
||||||
catalog.value = Array.isArray(list) ? list : []
|
catalog.value = Array.isArray(list) ? list : []
|
||||||
} catch {
|
} catch {
|
||||||
catalog.value = []
|
catalog.value = []
|
||||||
@@ -158,7 +283,16 @@ export function useCopperConvertPage() {
|
|||||||
const ctx: CopperConvertPageContext = {
|
const ctx: CopperConvertPageContext = {
|
||||||
loading,
|
loading,
|
||||||
source,
|
source,
|
||||||
inputKg,
|
assetAmount,
|
||||||
|
assetUnit,
|
||||||
|
sliderAmount,
|
||||||
|
sliderStep,
|
||||||
|
remainderAmount,
|
||||||
|
wire15Amount,
|
||||||
|
wire25Amount,
|
||||||
|
wire25Max,
|
||||||
|
wire15Rings,
|
||||||
|
wire25Rings,
|
||||||
prices,
|
prices,
|
||||||
result,
|
result,
|
||||||
priceRows,
|
priceRows,
|
||||||
|
|||||||
Reference in New Issue
Block a user