Product Conversion
This commit is contained in:
@@ -0,0 +1,175 @@
|
||||
import {
|
||||
computed,
|
||||
inject,
|
||||
provide,
|
||||
ref,
|
||||
type ComputedRef,
|
||||
type InjectionKey,
|
||||
type Ref,
|
||||
} from 'vue'
|
||||
import { getProducts } from '@/api/products'
|
||||
import type { Product } from '@/models/products'
|
||||
import {
|
||||
COPPER_CONVERT_WIRE_FALLBACK,
|
||||
calcCopperWireConvert,
|
||||
type CopperConvertPrices,
|
||||
type CopperConvertResult,
|
||||
type CopperConvertSource,
|
||||
} from '@/utils/copperWireConvert'
|
||||
import { LEGACY_GROUP_KATOD, LEGACY_GROUP_MAFTOL, normalizeProductGroupType } from '@/utils/productCategories'
|
||||
import { getProductBuyPrice } from '@/utils/productPrice'
|
||||
import { getLastPrices, startLastPricePolling, stopLastPricePolling } from '@/utils/price'
|
||||
import { persianToEnglishDigits } from '@/utils/persianDigits'
|
||||
|
||||
export const COPPER_CONVERT_PAGE_KEY: InjectionKey<CopperConvertPageContext> =
|
||||
Symbol('copperConvertPageContext')
|
||||
|
||||
export interface CopperConvertPageContext {
|
||||
loading: Ref<boolean>
|
||||
source: Ref<CopperConvertSource>
|
||||
inputKg: Ref<string>
|
||||
prices: ComputedRef<CopperConvertPrices>
|
||||
result: ComputedRef<CopperConvertResult | null>
|
||||
priceRows: ComputedRef<{ label: string; value: string; missing?: boolean }[]>
|
||||
}
|
||||
|
||||
function parseKg(raw: string): number {
|
||||
const s = persianToEnglishDigits(String(raw ?? ''))
|
||||
.replace(/,/g, '')
|
||||
.replace(/[^\d.]/g, '')
|
||||
const n = Number.parseFloat(s)
|
||||
return Number.isFinite(n) ? n : 0
|
||||
}
|
||||
|
||||
function titleIncludes(product: Product, part: string) {
|
||||
return (product.title ?? '').includes(part)
|
||||
}
|
||||
|
||||
function isKatodProduct(product: Product) {
|
||||
const group = normalizeProductGroupType(product.group_type)
|
||||
return group === LEGACY_GROUP_KATOD || titleIncludes(product, 'کاتد')
|
||||
}
|
||||
|
||||
function isMaftolProduct(product: Product) {
|
||||
const group = normalizeProductGroupType(product.group_type)
|
||||
return group === LEGACY_GROUP_MAFTOL || titleIncludes(product, 'مفتول')
|
||||
}
|
||||
|
||||
function isShamshProduct(product: Product) {
|
||||
const group = normalizeProductGroupType(product.group_type)
|
||||
return group.includes('شمش') || titleIncludes(product, 'شمش')
|
||||
}
|
||||
|
||||
function wireCrossSection(product: Product): '1.5' | '2.5' | null {
|
||||
const t = product.title ?? ''
|
||||
if (/1\.5|۱\.۵/.test(t)) return '1.5'
|
||||
if (/2\.5|۲\.۵/.test(t)) return '2.5'
|
||||
return null
|
||||
}
|
||||
|
||||
function isWireProduct(product: Product) {
|
||||
const t = `${product.group_type ?? ''} ${product.title ?? ''}`
|
||||
return t.includes('سیم') || wireCrossSection(product) != null
|
||||
}
|
||||
|
||||
function pickProduct(
|
||||
products: Product[],
|
||||
matcher: (p: Product) => boolean,
|
||||
): Product | undefined {
|
||||
return products.find((p) => p.active && matcher(p))
|
||||
}
|
||||
|
||||
function resolveWireRingPrice(product: Product | undefined, fallback: number): number {
|
||||
if (!product) return fallback
|
||||
const price = getProductBuyPrice(product)
|
||||
return price > 0 ? price : fallback
|
||||
}
|
||||
|
||||
export function useCopperConvertPage() {
|
||||
const loading = ref(true)
|
||||
const source = ref<CopperConvertSource>('katod')
|
||||
const inputKg = ref('')
|
||||
const catalog = ref<Product[]>([])
|
||||
|
||||
const katodProduct = computed(() => pickProduct(catalog.value, isKatodProduct))
|
||||
const maftolProduct = computed(() => pickProduct(catalog.value, isMaftolProduct))
|
||||
const shamshProduct = computed(() => pickProduct(catalog.value, isShamshProduct))
|
||||
const wire15Product = computed(() =>
|
||||
pickProduct(catalog.value, (p) => isWireProduct(p) && wireCrossSection(p) === '1.5'),
|
||||
)
|
||||
const wire25Product = computed(() =>
|
||||
pickProduct(catalog.value, (p) => isWireProduct(p) && wireCrossSection(p) === '2.5'),
|
||||
)
|
||||
|
||||
const prices = computed<CopperConvertPrices>(() => ({
|
||||
katodPerKg: katodProduct.value ? getProductBuyPrice(katodProduct.value) : 0,
|
||||
maftoulPerKg: maftolProduct.value ? getProductBuyPrice(maftolProduct.value) : 0,
|
||||
shamshPerKg: shamshProduct.value ? getProductBuyPrice(shamshProduct.value) : 0,
|
||||
wireRing15: resolveWireRingPrice(wire15Product.value, COPPER_CONVERT_WIRE_FALLBACK.wireRing15),
|
||||
wireRing25: resolveWireRingPrice(wire25Product.value, COPPER_CONVERT_WIRE_FALLBACK.wireRing25),
|
||||
wireWeightGrams15: COPPER_CONVERT_WIRE_FALLBACK.wireWeightGrams15,
|
||||
wireWeightGrams25: COPPER_CONVERT_WIRE_FALLBACK.wireWeightGrams25,
|
||||
}))
|
||||
|
||||
const result = computed(() =>
|
||||
calcCopperWireConvert(parseKg(inputKg.value), source.value, prices.value),
|
||||
)
|
||||
|
||||
const priceRows = computed(() => {
|
||||
const p = prices.value
|
||||
const row = (label: string, amount: number) => ({
|
||||
label,
|
||||
value: amount > 0 ? `${Math.round(amount).toLocaleString('en-US')} ریال` : '—',
|
||||
missing: amount <= 0,
|
||||
})
|
||||
return [
|
||||
row('قیمت کاتد (هر کیلو)', p.katodPerKg),
|
||||
row('قیمت مفتول (هر کیلو)', p.maftoulPerKg),
|
||||
row('قیمت شمش (هر کیلو)', p.shamshPerKg),
|
||||
row('قیمت حلقه سیم ۱.۵', p.wireRing15),
|
||||
row('قیمت حلقه سیم ۲.۵', p.wireRing25),
|
||||
]
|
||||
})
|
||||
|
||||
async function loadCatalog() {
|
||||
loading.value = true
|
||||
try {
|
||||
await getLastPrices()
|
||||
const list = await getProducts()
|
||||
catalog.value = Array.isArray(list) ? list : []
|
||||
} catch {
|
||||
catalog.value = []
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshLivePrices() {
|
||||
startLastPricePolling()
|
||||
await loadCatalog()
|
||||
}
|
||||
|
||||
function stopLivePrices() {
|
||||
stopLastPricePolling()
|
||||
}
|
||||
|
||||
const ctx: CopperConvertPageContext = {
|
||||
loading,
|
||||
source,
|
||||
inputKg,
|
||||
prices,
|
||||
result,
|
||||
priceRows,
|
||||
}
|
||||
|
||||
provide(COPPER_CONVERT_PAGE_KEY, ctx)
|
||||
return { ...ctx, refreshLivePrices, stopLivePrices, loadCatalog }
|
||||
}
|
||||
|
||||
export function useCopperConvertPageContext() {
|
||||
const ctx = inject(COPPER_CONVERT_PAGE_KEY)
|
||||
if (!ctx) {
|
||||
throw new Error('useCopperConvertPageContext requires useCopperConvertPage')
|
||||
}
|
||||
return ctx
|
||||
}
|
||||
Reference in New Issue
Block a user