From aec46eb0e6169123b54bc18902a5e55444f14dd7 Mon Sep 17 00:00:00 2001 From: alireza Date: Wed, 26 Aug 2026 11:26:46 +0330 Subject: [PATCH] fix(ime/lme): eliminate duplicate titles and double prices, convert all calendars and dates to Persian Jalali --- backend/ime_metals.py | 12 ++++---- frontend/src/components/ImeView.tsx | 48 +++++++++++++++-------------- frontend/src/components/LmeView.tsx | 8 +++-- 3 files changed, 36 insertions(+), 32 deletions(-) diff --git a/backend/ime_metals.py b/backend/ime_metals.py index d85d3ee..cdccd2f 100644 --- a/backend/ime_metals.py +++ b/backend/ime_metals.py @@ -33,20 +33,20 @@ HEADERS = { def clean_persian_title(title: str) -> tuple[str, str]: """ Removes English symbol codes (e.g. FTKC-BSG017OO-00, KHSS-DRIBRI-00) - and returns (clean_title, manufacturer). + and returns (product_name, manufacturer). + Avoids duplicate manufacturer names. """ if not title: return "", "" parts = [p.strip() for p in title.split(" - ") if p.strip()] if len(parts) >= 3: - if re.search(r'^[A-Za-z0-9_-]+$', parts[1]): - product = parts[0] - manufacturer = parts[2] - return f"{product} ({manufacturer})", manufacturer + product = parts[0] + manufacturer = parts[2] + return product, manufacturer elif len(parts) == 2: if re.search(r'^[A-Za-z0-9_-]+$', parts[1]): return parts[0], "" - return f"{parts[0]} ({parts[1]})", parts[1] + return parts[0], parts[1] cleaned = re.sub(r'\b[A-Za-z0-9]{3,}-[A-Za-z0-9_-]+\b', '', title) cleaned = re.sub(r'\s*-\s*-+\s*', ' - ', cleaned).strip(" -") diff --git a/frontend/src/components/ImeView.tsx b/frontend/src/components/ImeView.tsx index a274e7e..c99b460 100644 --- a/frontend/src/components/ImeView.tsx +++ b/frontend/src/components/ImeView.tsx @@ -20,6 +20,7 @@ import { CartesianGrid } from "recharts"; import { API_BASE } from "@/lib/api"; +import { toJalali } from "@/lib/metals-data"; const API = API_BASE; @@ -355,7 +356,7 @@ export function ImeView() { onClick={() => setSelectedSymbol(sym)} className="group cursor-pointer relative overflow-hidden rounded-2xl border border-border/70 bg-gradient-to-b from-card to-card/40 p-5 backdrop-blur-md transition-all duration-200 hover:shadow-xl hover:-translate-y-1 hover:border-primary flex flex-col justify-between" > -
+
{sym.product_name || sym.title}
@@ -368,22 +369,18 @@ export function ImeView() { )}
- {/* LATEST PRICE PROMINENTLY DISPLAYED ON CARD FACE */} + {/* LATEST PRICE: Clean, prominent single price in Tomans */}
- آخرین قیمت: + آخرین نرخ کشف‌شده:
{sym.latest_price?.mid ? ( -
-
- {sym.latest_price.mid.toLocaleString()} ریال -
-
- {(Math.round(sym.latest_price.mid / 10)).toLocaleString()} تومان -
-
+ + {(Math.round(sym.latest_price.mid / 10)).toLocaleString()}{" "} + تومان/کیلو + ) : ( - ثبت معامله ندارد + بدون معامله اخیر )}
@@ -395,7 +392,7 @@ export function ImeView() { {sym.latest_price?.date && ( - {sym.latest_price.date} + {toJalali(sym.latest_price.date)} )}
@@ -446,24 +443,24 @@ export function ImeView() {
آخرین قیمت کشف‌شده
- {stats.last.toLocaleString()} ریال + {(Math.round(stats.last / 10)).toLocaleString()} تومان
- {(Math.round(stats.last / 10)).toLocaleString()} تومان + {stats.last.toLocaleString()} ریال
بالاترین قیمت دوره
- {stats.max.toLocaleString()} ریال + {(Math.round(stats.max / 10)).toLocaleString()} تومان
پایین‌ترین قیمت دوره
- {stats.min.toLocaleString()} ریال + {(Math.round(stats.min / 10)).toLocaleString()} تومان
@@ -475,7 +472,7 @@ export function ImeView() { }`} > {stats.diff >= 0 ? "+" : ""} - {stats.diff.toLocaleString()} ({stats.pct.toFixed(1)}%) + {(Math.round(stats.diff / 10)).toLocaleString()} تومان ({stats.pct.toFixed(1)}%)
@@ -506,12 +503,17 @@ export function ImeView() { { + const jal = toJalali(val); + const parts = jal.split("/"); + return parts.length === 3 ? `${parts[1]}/${parts[2]}` : jal; + }} minTickGap={35} /> `${(v / 1000).toLocaleString()}k`} + tickFormatter={(v) => `${(v / 10000).toLocaleString()}k ت`} orientation="right" />
- تاریخ معامله: {pt.date} + تاریخ معامله: {toJalali(pt.date)}
قیمت پایانی: - {pt.mid.toLocaleString()} ریال + {(Math.round(pt.mid / 10)).toLocaleString()} تومان
-
- معادل {(Math.round(pt.mid / 10)).toLocaleString()} تومان +
+ ({pt.mid.toLocaleString()} ریال)
); diff --git a/frontend/src/components/LmeView.tsx b/frontend/src/components/LmeView.tsx index 699ceab..8a40288 100644 --- a/frontend/src/components/LmeView.tsx +++ b/frontend/src/components/LmeView.tsx @@ -1,3 +1,4 @@ +import { toJalali } from "@/lib/metals-data"; import { useState, useEffect, useMemo } from "react"; import { Search, @@ -678,8 +679,9 @@ export function LmeView() { tick={{ fontSize: 10, fill: "var(--muted-foreground)" }} tickFormatter={(val) => { if (!val) return ""; - const p = val.split("-"); - return p.length === 3 ? `${p[0]}/${p[1]}` : val; + const jal = toJalali(val); + const p = jal.split("/"); + return p.length === 3 ? `${p[0]}/${p[1]}` : jal; }} minTickGap={40} /> @@ -716,7 +718,7 @@ export function LmeView() { return (
- تاریخ: {ptData.date_display || label} + تاریخ: {toJalali(ptData.date || label)}
{showPrice && ptData.priceVal !== undefined && (