Add silent servo category

This commit is contained in:
Jacky Ser
2026-08-10 23:56:54 +08:00
parent f72de38fb7
commit 9ab7d7c195
2 changed files with 27 additions and 9 deletions

View File

@@ -230,7 +230,7 @@ select:focus, input:focus, textarea:focus { border-color: var(--blue); box-shado
.section-heading > p { max-width: 480px; margin: 0; color: #6e7a8e; line-height: 1.8; font-size: 13px; } .section-heading > p { max-width: 480px; margin: 0; color: #6e7a8e; line-height: 1.8; font-size: 13px; }
.catalog-summary { .catalog-summary {
display: grid; display: grid;
grid-template-columns: repeat(7, 1fr); grid-template-columns: repeat(8, 1fr);
gap: 9px; gap: 9px;
margin-bottom: 22px; margin-bottom: 22px;
} }
@@ -451,6 +451,7 @@ footer > span { color: #9aa4b2; font-size: 10px; }
.hero-copy { max-width: 760px; } .hero-copy { max-width: 760px; }
.selector-shell { width: min(100%, 720px); } .selector-shell { width: min(100%, 720px); }
.how-section { gap: 45px; } .how-section { gap: 45px; }
.catalog-summary { grid-template-columns: repeat(4, 1fr); }
.catalog-grid { grid-template-columns: repeat(2, 1fr); } .catalog-grid { grid-template-columns: repeat(2, 1fr); }
.catalog-image-button { height: 260px; } .catalog-image-button { height: 260px; }
} }
@@ -475,7 +476,6 @@ footer > span { color: #9aa4b2; font-size: 10px; }
.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; }
.catalog-summary { grid-template-columns: repeat(2, 1fr); } .catalog-summary { grid-template-columns: repeat(2, 1fr); }
.catalog-summary button:last-child { grid-column: 1 / -1; }
.catalog-toolbar { top: 64px; } .catalog-toolbar { top: 64px; }
.catalog-grid { grid-template-columns: 1fr; gap: 15px; } .catalog-grid { grid-template-columns: 1fr; gap: 15px; }
.catalog-image-button { height: 280px; } .catalog-image-button { height: 280px; }

View File

@@ -39,6 +39,7 @@ const CATALOG_CATEGORIES = [
"全金属舵机", "全金属舵机",
"大扭矩舵机", "大扭矩舵机",
"积木舵机", "积木舵机",
"静音舵机",
"标准齿轮箱", "标准齿轮箱",
"翻盖电机", "翻盖电机",
]; ];
@@ -63,6 +64,8 @@ function getFeaturedSpecs(product: CatalogProduct) {
} }
const SERVO_CATEGORIES = ["标准舵机", "异形舵机", "全金属舵机", "大扭矩舵机", "积木舵机"]; const SERVO_CATEGORIES = ["标准舵机", "异形舵机", "全金属舵机", "大扭矩舵机", "积木舵机"];
const SILENT_SERVO_CATEGORY = "静音舵机";
const SELECTOR_CATEGORIES = [...SERVO_CATEGORIES, SILENT_SERVO_CATEGORY];
const TORQUE_MIN = 0.09; const TORQUE_MIN = 0.09;
const TORQUE_MAX = 920; const TORQUE_MAX = 920;
const TORQUE_PRESETS = [0.1, 1, 5, 20, 100, 300, 920]; const TORQUE_PRESETS = [0.1, 1, 5, 20, 100, 300, 920];
@@ -80,6 +83,17 @@ function parseNumbers(value = "") {
return (value.match(/\d+(?:\.\d+)?/g) ?? []).map(Number); return (value.match(/\d+(?:\.\d+)?/g) ?? []).map(Number);
} }
function isSilentServo(product: CatalogProduct) {
return SERVO_CATEGORIES.includes(product.category) &&
[product.name, ...Object.values(product.specs)].join(" ").includes("静音");
}
const SILENT_SERVO_COUNT = CATALOG_PRODUCTS.filter(isSilentServo).length;
function getCategoryCount(category: string) {
return category === SILENT_SERVO_CATEGORY ? SILENT_SERVO_COUNT : CATALOG_COUNTS[category];
}
function inferWeight(product: CatalogProduct) { function inferWeight(product: CatalogProduct) {
const listedWeight = parseNumbers(product.specs["重量"])[0]; const listedWeight = parseNumbers(product.specs["重量"])[0];
if (Number.isFinite(listedWeight)) return listedWeight; if (Number.isFinite(listedWeight)) return listedWeight;
@@ -152,6 +166,7 @@ const SELECTOR_PRODUCTS = CATALOG_PRODUCTS.filter((product) =>
voltageMin: voltageValues[0] ?? ratedVoltage, voltageMin: voltageValues[0] ?? ratedVoltage,
voltageMax: voltageValues.at(-1) ?? ratedVoltage, voltageMax: voltageValues.at(-1) ?? ratedVoltage,
weight: inferWeight(product), weight: inferWeight(product),
isSilent: isSilentServo(product),
gear: classifyGear(product.specs["齿轮材质"]), gear: classifyGear(product.specs["齿轮材质"]),
angle: product.specs["可操作角度"] ?? product.specs["操作角度范围"] ?? "", angle: product.specs["可操作角度"] ?? product.specs["操作角度范围"] ?? "",
control, control,
@@ -186,8 +201,9 @@ function getMatches(requirements: Requirements) {
return SELECTOR_PRODUCTS.map((product) => { return SELECTOR_PRODUCTS.map((product) => {
let score = 20; let score = 20;
const reasons: string[] = []; const reasons: string[] = [];
const categoryOk = const categoryOk = requirements.category === "全部舵机" ||
requirements.category === "全部舵机" || requirements.category === product.category; requirements.category === product.category ||
(requirements.category === SILENT_SERVO_CATEGORY && product.isSilent);
const torqueOk = product.torque >= requirements.torque; const torqueOk = product.torque >= requirements.torque;
const voltageOk = requirements.voltage === product.ratedVoltage; const voltageOk = requirements.voltage === product.ratedVoltage;
const weightOk = const weightOk =
@@ -275,7 +291,9 @@ export default function Home() {
const query = catalogQuery.trim().toLowerCase(); const query = catalogQuery.trim().toLowerCase();
return CATALOG_PRODUCTS.filter((product) => { return CATALOG_PRODUCTS.filter((product) => {
const matchesCategory = const matchesCategory =
catalogCategory === "全部产品" || product.category === catalogCategory; catalogCategory === "全部产品" ||
product.category === catalogCategory ||
(catalogCategory === SILENT_SERVO_CATEGORY && isSilentServo(product));
if (!matchesCategory) return false; if (!matchesCategory) return false;
if (!query) return true; if (!query) return true;
const haystack = [ const haystack = [
@@ -427,9 +445,9 @@ export default function Home() {
onChange={(event) => update("category", event.target.value)} onChange={(event) => update("category", event.target.value)}
> >
<option value="全部舵机">243</option> <option value="全部舵机">243</option>
{SERVO_CATEGORIES.map((category) => ( {SELECTOR_CATEGORIES.map((category) => (
<option key={category} value={category}> <option key={category} value={category}>
{category}{CATALOG_COUNTS[category]} {category}{getCategoryCount(category)}
</option> </option>
))} ))}
</select> </select>
@@ -742,7 +760,7 @@ export default function Home() {
<p className="eyebrow"><span /> · 2026.06</p> <p className="eyebrow"><span /> · 2026.06</p>
<h2>280</h2> <h2>280</h2>
</div> </div>
<p>齿</p> <p>齿</p>
</div> </div>
<div className="catalog-summary" aria-label="产品分类统计"> <div className="catalog-summary" aria-label="产品分类统计">
@@ -756,7 +774,7 @@ export default function Home() {
setCatalogLimit(24); setCatalogLimit(24);
}} }}
> >
<strong>{CATALOG_COUNTS[category]}</strong> <strong>{getCategoryCount(category)}</strong>
<span>{category}</span> <span>{category}</span>
</button> </button>
))} ))}