Unify AI recommendation card sizes

This commit is contained in:
Jacky Ser
2026-08-11 14:51:26 +08:00
parent e855d5aa64
commit 78f5ead63a
2 changed files with 44 additions and 56 deletions

View File

@@ -167,15 +167,17 @@ select:focus, input:focus, textarea:focus { border-color: var(--blue); box-shado
.result-panel { padding: 24px 28px 28px; } .result-panel { padding: 24px 28px 28px; }
.result-heading { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 18px; } .result-heading { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 18px; }
.best-match { display: grid; grid-template-columns: 180px 1fr; border: 1px solid #cfdaf0; border-radius: 15px; overflow: hidden; box-shadow: 0 8px 24px rgba(38,70,125,.08); } .recommendation-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: stretch; gap: 10px; }
.match-image-wrap { position: relative; min-height: 270px; background: #eff4fb; } .recommendation-card { min-width: 0; min-height: 442px; display: flex; flex-direction: column; overflow: hidden; border: 1px solid #dce3ed; border-radius: 14px; background: white; box-shadow: 0 8px 24px rgba(38,70,125,.06); }
.match-image-wrap img { width: 100%; height: 100%; object-fit: contain; mix-blend-mode: multiply; } .recommendation-card.is-primary { border-color: #cfdaf0; box-shadow: 0 8px 24px rgba(38,70,125,.1); }
.recommendation-image-wrap { position: relative; height: 132px; flex: 0 0 132px; background: #eff4fb; }
.recommendation-image-wrap img { width: 100%; height: 100%; object-fit: contain; mix-blend-mode: multiply; }
.match-badge { position: absolute; left: 12px; top: 12px; padding: 6px 9px; border-radius: 7px; color: white; background: var(--orange); font-size: 9px; font-weight: 800; } .match-badge { position: absolute; left: 12px; top: 12px; padding: 6px 9px; border-radius: 7px; color: white; background: var(--orange); font-size: 9px; font-weight: 800; }
.match-content { position: relative; padding: 19px 19px 16px; } .recommendation-content { position: relative; flex: 1; display: flex; flex-direction: column; min-width: 0; padding: 14px 13px 12px; }
.match-score { position: absolute; right: 16px; top: 15px; display: grid; text-align: right; color: #7c889a; font-size: 9px; } .match-score { position: absolute; right: 16px; top: 15px; display: grid; text-align: right; color: #7c889a; font-size: 9px; }
.match-score strong { color: var(--blue); font-size: 18px; } .match-score strong { color: var(--blue); font-size: 18px; }
.product-code { margin: 0 0 4px; color: #8b96a8; font-size: 9px; } .product-code { margin: 0 0 4px; color: #8b96a8; font-size: 9px; }
.match-content h3 { max-width: 250px; margin: 0; font-size: 19px; } .recommendation-content h3 { min-height: 38px; max-width: calc(100% - 42px); margin: 0; overflow: hidden; font-size: 14px; line-height: 1.35; }
.product-subtitle { margin: 5px 0 13px; color: #7b8799; font-size: 10px; } .product-subtitle { margin: 5px 0 13px; color: #7b8799; font-size: 10px; }
.metric-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 7px; } .metric-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 7px; }
.metric { padding: 8px 9px; border-radius: 8px; background: #f4f7fb; display: grid; gap: 3px; } .metric { padding: 8px 9px; border-radius: 8px; background: #f4f7fb; display: grid; gap: 3px; }
@@ -186,20 +188,13 @@ select:focus, input:focus, textarea:focus { border-color: var(--blue); box-shado
.price-line span { color: #7c8798; font-size: 9px; } .price-line span { color: #7c8798; font-size: 9px; }
.price-line strong { color: #e55726; font-size: 20px; } .price-line strong { color: #e55726; font-size: 20px; }
.price-line small { color: #9aa4b3; font-size: 8px; } .price-line small { color: #9aa4b3; font-size: 8px; }
.source-line { display: flex; align-items: center; gap: 7px; padding-top: 9px; border-top: 1px solid #edf0f4; } .source-line { display: flex; align-items: center; gap: 7px; margin-top: auto; padding-top: 9px; border-top: 1px solid #edf0f4; }
.source-line span { color: #7c8798; font-size: 9px; } .source-line span { color: #7c8798; font-size: 9px; }
.source-line strong { color: var(--blue); font-size: 10px; } .source-line strong { color: var(--blue); font-size: 10px; }
.source-line small { margin-left: auto; color: #9aa4b3; font-size: 8px; } .source-line small { margin-left: auto; color: #9aa4b3; font-size: 8px; }
.engineer-alert { display: flex; align-items: center; gap: 10px; margin-top: 10px; padding: 10px 12px; border: 1px solid #f0d29e; border-radius: 9px; background: #fff9ef; } .engineer-alert { display: flex; align-items: center; gap: 10px; margin-top: 10px; padding: 10px 12px; border: 1px solid #f0d29e; border-radius: 9px; background: #fff9ef; }
.engineer-alert span { flex: 0 0 auto; padding: 4px 7px; border-radius: 5px; color: #9b5a0a; background: #ffe7bc; font-size: 8px; font-weight: 800; } .engineer-alert span { flex: 0 0 auto; padding: 4px 7px; border-radius: 5px; color: #9b5a0a; background: #ffe7bc; font-size: 8px; font-weight: 800; }
.engineer-alert p { margin: 0; color: #815e2f; font-size: 9px; } .engineer-alert p { margin: 0; color: #815e2f; font-size: 9px; }
.alternative-list { display: grid; grid-template-columns: 1fr 1fr; gap: 9px; margin-top: 10px; }
.alternative-card { min-width: 0; display: grid; grid-template-columns: 58px 1fr; align-items: center; border: 1px solid #e1e6ee; border-radius: 10px; overflow: hidden; }
.alternative-card img { width: 58px; height: 58px; object-fit: cover; background: #f0f3f7; }
.alternative-card div { min-width: 0; padding: 7px 9px; }
.alternative-card span { color: var(--blue); font-size: 8px; font-weight: 700; }
.alternative-card h4 { margin: 2px 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 10px; }
.alternative-card p { margin: 0; color: #8a95a6; font-size: 8px; }
.result-actions { display: flex; gap: 9px; margin-top: 14px; } .result-actions { display: flex; gap: 9px; margin-top: 14px; }
.result-actions .panel-primary { flex: 1; } .result-actions .panel-primary { flex: 1; }
.outline-button { border: 1px solid #cfd7e4; border-radius: 10px; padding: 0 17px; background: white; cursor: pointer; font-size: 11px; font-weight: 650; } .outline-button { border: 1px solid #cfd7e4; border-radius: 10px; padding: 0 17px; background: white; cursor: pointer; font-size: 11px; font-weight: 650; }
@@ -493,10 +488,10 @@ footer > span { color: #9aa4b2; font-size: 10px; }
.selector-shell { border-radius: 16px; } .selector-shell { border-radius: 16px; }
.question-panel, .result-panel { padding: 20px 16px; } .question-panel, .result-panel { padding: 20px 16px; }
.welcome-panel { padding: 55px 20px 35px; } .welcome-panel { padding: 55px 20px 35px; }
.choice-grid, .two-fields, .parameter-grid, .form-grid, .alternative-list { grid-template-columns: 1fr; } .choice-grid, .two-fields, .parameter-grid, .form-grid, .recommendation-grid { grid-template-columns: 1fr; }
.torque-presets { grid-template-columns: repeat(4, 1fr); } .torque-presets { grid-template-columns: repeat(4, 1fr); }
.best-match { grid-template-columns: 1fr; } .recommendation-card { min-height: 0; }
.match-image-wrap { height: 240px; } .recommendation-image-wrap { height: 190px; flex-basis: 190px; }
.capability-strip { grid-template-columns: 1fr 1fr; gap: 24px 0; padding: 28px 16px; } .capability-strip { grid-template-columns: 1fr 1fr; gap: 24px 0; padding: 28px 16px; }
.capability-strip div:nth-child(2) { border-right: 0; } .capability-strip div:nth-child(2) { border-right: 0; }
.section-heading { align-items: flex-start; flex-direction: column; gap: 18px; } .section-heading { align-items: flex-start; flex-direction: column; gap: 18px; }

View File

@@ -788,33 +788,39 @@ export default function Home() {
<button type="button" className="restart-button" onClick={reset}></button> <button type="button" className="restart-button" onClick={reset}></button>
</div> </div>
<div className="best-match"> <div className="recommendation-grid">
<div className="match-image-wrap"> {topMatches.map((match, index) => (
<img src={top.product.image} alt={top.product.name} /> <article className={`recommendation-card ${index === 0 ? "is-primary" : ""}`} key={match.product.id}>
<span className="match-badge">{top.coreCompatible ? "首选推荐" : "待复核候选"}</span> <div className="recommendation-image-wrap">
</div> <img src={match.product.image} alt={match.product.name} />
<div className="match-content"> <span className="match-badge">
<div className="match-score"><span></span><strong>{top.confidence}%</strong></div> {index === 0 ? (match.coreCompatible ? "首选推荐" : "待复核候选") : `${match.confidence}% 匹配`}
<p className="product-code">{top.product.code}</p> </span>
<h3>{top.product.name}</h3> </div>
<p className="product-subtitle">{top.product.category} · {top.product.size || "尺寸待复核"}</p> <div className="recommendation-content">
<div className="metric-grid"> <div className="match-score"><span></span><strong>{match.confidence}%</strong></div>
<Metric label="堵转扭矩" value={`${formatTorque(top.product.torque)} kgf·cm`} /> <p className="product-code">{match.product.code}</p>
<Metric label="电压范围" value={`${top.product.voltageMin}${top.product.voltageMax}V`} /> <h3>{match.product.name}</h3>
<Metric label="空载速度" value={top.product.speed || "目录未标注"} /> <p className="product-subtitle">{match.product.category} · {match.product.size || "尺寸待复核"}</p>
<Metric label="操作角度" value={top.product.angle || "目录未标注"} /> <div className="metric-grid">
<Metric label="控制 / 通讯" value={top.product.control || "目录未标注"} /> <Metric label="堵转扭矩" value={`${formatTorque(match.product.torque)} kgf·cm`} />
<Metric label="齿轮材质" value={top.product.gear} /> <Metric label="电压范围" value={`${match.product.voltageMin}${match.product.voltageMax}V`} />
</div> <Metric label="空载速度" value={match.product.speed || "目录未标注"} />
<ul className="reason-list"> <Metric label="操作角度" value={match.product.angle || "目录未标注"} />
{top.reasons.map((reason) => <li key={reason}> {reason}</li>)} <Metric label="控制 / 通讯" value={match.product.control || "目录未标注"} />
</ul> <Metric label="齿轮材质" value={match.product.gear} />
<div className="source-line"> </div>
<span></span> <ul className="reason-list">
<strong>{top.product.category}</strong> {match.reasons.slice(0, 2).map((reason) => <li key={reason}> {reason}</li>)}
<small></small> </ul>
</div> <div className="source-line">
</div> <span></span>
<strong>{match.product.category}</strong>
<small></small>
</div>
</div>
</article>
))}
</div> </div>
{needsEngineer && ( {needsEngineer && (
@@ -826,19 +832,6 @@ export default function Home() {
</div> </div>
)} )}
<div className="alternative-list">
{topMatches.slice(1).map((match) => (
<div className="alternative-card" key={match.product.id}>
<img src={match.product.image} alt={match.product.name} />
<div>
<span>{match.confidence}% </span>
<h4>{match.product.name}</h4>
<p>{formatTorque(match.product.torque)} kgf·cm · {match.product.category} · {match.product.gear}</p>
</div>
</div>
))}
</div>
{!showSampleForm && ( {!showSampleForm && (
<div className="result-actions"> <div className="result-actions">
<button className="panel-primary" type="button" onClick={() => setShowSampleForm(true)}> <button className="panel-primary" type="button" onClick={() => setShowSampleForm(true)}>