fix(ime/lme): eliminate duplicate titles and double prices, convert all calendars and dates to Persian Jalali

This commit is contained in:
alireza 2026-08-26 11:26:46 +03:30
parent 9a36873dbe
commit aec46eb0e6
3 changed files with 36 additions and 32 deletions

View File

@ -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(" -")

View File

@ -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"
>
<div className="space-y-2">
<div className="space-y-1.5">
<div className="text-sm font-bold text-foreground group-hover:text-primary transition-colors line-clamp-2">
{sym.product_name || sym.title}
</div>
@ -368,22 +369,18 @@ export function ImeView() {
)}
</div>
{/* LATEST PRICE PROMINENTLY DISPLAYED ON CARD FACE */}
{/* LATEST PRICE: Clean, prominent single price in Tomans */}
<div className="mt-4 pt-3 border-t border-border/40 space-y-2">
<div className="flex items-baseline justify-between">
<span className="text-xs text-muted-foreground">آخرین قیمت:</span>
<span className="text-xs text-muted-foreground">آخرین نرخ کشفشده:</span>
<div className="text-left font-mono">
{sym.latest_price?.mid ? (
<div>
<div className="text-lg font-bold text-primary">
{sym.latest_price.mid.toLocaleString()} <span className="text-xs font-normal text-muted-foreground">ریال</span>
</div>
<div className="text-[11px] text-muted-foreground">
{(Math.round(sym.latest_price.mid / 10)).toLocaleString()} تومان
</div>
</div>
<span className="text-base sm:text-lg font-bold text-primary">
{(Math.round(sym.latest_price.mid / 10)).toLocaleString()}{" "}
<span className="text-xs font-normal text-muted-foreground">تومان/کیلو</span>
</span>
) : (
<span className="text-xs text-muted-foreground">ثبت معامله ندارد</span>
<span className="text-xs text-muted-foreground">بدون معامله اخیر</span>
)}
</div>
</div>
@ -395,7 +392,7 @@ export function ImeView() {
{sym.latest_price?.date && (
<span className="text-[10px] text-muted-foreground font-mono">
{sym.latest_price.date}
{toJalali(sym.latest_price.date)}
</span>
)}
</div>
@ -446,24 +443,24 @@ export function ImeView() {
<div className="rounded-2xl border border-border/60 bg-card/60 p-3.5">
<div className="text-[11px] text-muted-foreground">آخرین قیمت کشفشده</div>
<div className="text-base sm:text-lg font-bold font-mono text-foreground mt-0.5">
{stats.last.toLocaleString()} ریال
{(Math.round(stats.last / 10)).toLocaleString()} تومان
</div>
<div className="text-[10px] text-muted-foreground mt-0.5">
{(Math.round(stats.last / 10)).toLocaleString()} تومان
{stats.last.toLocaleString()} ریال
</div>
</div>
<div className="rounded-2xl border border-border/60 bg-card/60 p-3.5">
<div className="text-[11px] text-muted-foreground">بالاترین قیمت دوره</div>
<div className="text-base sm:text-lg font-bold font-mono text-foreground mt-0.5">
{stats.max.toLocaleString()} ریال
{(Math.round(stats.max / 10)).toLocaleString()} تومان
</div>
</div>
<div className="rounded-2xl border border-border/60 bg-card/60 p-3.5">
<div className="text-[11px] text-muted-foreground">پایینترین قیمت دوره</div>
<div className="text-base sm:text-lg font-bold font-mono text-foreground mt-0.5">
{stats.min.toLocaleString()} ریال
{(Math.round(stats.min / 10)).toLocaleString()} تومان
</div>
</div>
@ -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)}%)
</div>
</div>
</div>
@ -506,12 +503,17 @@ export function ImeView() {
<XAxis
dataKey="date"
tick={{ fontSize: 10, fill: "var(--muted-foreground)" }}
tickFormatter={(val) => {
const jal = toJalali(val);
const parts = jal.split("/");
return parts.length === 3 ? `${parts[1]}/${parts[2]}` : jal;
}}
minTickGap={35}
/>
<YAxis
domain={["auto", "auto"]}
tick={{ fontSize: 10, fill: "var(--muted-foreground)" }}
tickFormatter={(v) => `${(v / 1000).toLocaleString()}k`}
tickFormatter={(v) => `${(v / 10000).toLocaleString()}k ت`}
orientation="right"
/>
<Tooltip
@ -521,16 +523,16 @@ export function ImeView() {
return (
<div className="rounded-xl border border-border/80 bg-card/95 p-3 text-foreground shadow-2xl backdrop-blur-md space-y-1 min-w-[160px]" dir="rtl">
<div className="text-[11px] text-muted-foreground font-mono pb-1 border-b border-border/40">
تاریخ معامله: {pt.date}
تاریخ معامله: {toJalali(pt.date)}
</div>
<div className="flex items-center justify-between text-xs pt-1">
<span className="text-muted-foreground">قیمت پایانی:</span>
<span className="font-mono font-bold text-primary">
{pt.mid.toLocaleString()} ریال
{(Math.round(pt.mid / 10)).toLocaleString()} تومان
</span>
</div>
<div className="text-[10px] text-muted-foreground">
معادل {(Math.round(pt.mid / 10)).toLocaleString()} تومان
<div className="text-[10px] text-muted-foreground font-mono">
({pt.mid.toLocaleString()} ریال)
</div>
</div>
);

View File

@ -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 (
<div className="rounded-xl border border-border/80 bg-card/95 p-3 text-foreground shadow-2xl backdrop-blur-md space-y-1.5 min-w-[170px]" dir="rtl">
<div className="text-[11px] font-medium text-muted-foreground border-b border-border/40 pb-1 font-mono">
تاریخ: {ptData.date_display || label}
تاریخ: {toJalali(ptData.date || label)}
</div>
{showPrice && ptData.priceVal !== undefined && (