@@ -205,15 +205,15 @@ const isDetecting = ref(true);
205205// --- 环境检测 ---
206206const detectEnvironment = async () => {
207207 if (typeof window === " undefined" ) return ;
208-
208+
209209 const ua = navigator .userAgent .toLowerCase ();
210-
210+
211211 // 1. 基础 UA 检测
212212 if (ua .includes (" win" )) userPlatform .value = " windows" ;
213213 else if (ua .includes (" mac" )) userPlatform .value = " macos" ;
214214 else if (ua .includes (" linux" ) || ua .includes (" x11" )) userPlatform .value = " linux" ;
215- else if (ua .includes (" android" )) userPlatform .value = " linux" ;
216-
215+ else if (ua .includes (" android" )) userPlatform .value = " linux" ;
216+
217217 // 基础架构检测
218218 if (ua .includes (" arm64" ) || ua .includes (" aarch64" )) {
219219 userArch .value = " arm64" ;
@@ -231,13 +231,13 @@ const detectEnvironment = async () => {
231231 " architecture" ,
232232 " bitness" ,
233233 ]);
234-
234+
235235 if (uaData .platform === " macOS" ) userPlatform .value = " macos" ;
236236 else if (uaData .platform === " Windows" ) userPlatform .value = " windows" ;
237237 else if (uaData .platform === " Linux" ) userPlatform .value = " linux" ;
238238
239239 if (uaData .architecture === " arm" ) userArch .value = " arm64" ;
240- else if (uaData .architecture === " x86" ) userArch .value = " x64" ;
240+ else if (uaData .architecture === " x86" ) userArch .value = " x64" ;
241241 } catch (e ) {
242242 console .debug (" UAData detection failed" , e );
243243 }
@@ -279,13 +279,13 @@ const getExtensionName = (name: string) => {
279279// 架构显示文案
280280const getArchDisplay = (name : string , platformId : string ) => {
281281 const n = name .toLowerCase ();
282-
282+
283283 if (n .includes (" arm64" ) || n .includes (" aarch64" )) return " ARM64" ;
284284 if (n .includes (" x64" ) || n .includes (" x86_64" ) || n .includes (" amd64" )) return " x64" ;
285285 if (n .includes (" ia32" ) || n .includes (" x86" )) return " 32位 (x86)" ;
286286
287287 if (platformId === " macos" ) return " macOS 通用" ;
288-
288+
289289 return " 标准架构 (x64)" ;
290290};
291291
@@ -301,15 +301,15 @@ const sortAssets = (assets: GitHubAsset[]) => {
301301 return assets .sort ((a , b ) => {
302302 const nA = a .name .toLowerCase ();
303303 const nB = b .name .toLowerCase ();
304-
304+
305305 // 简单的权重系统
306306 let scoreA = 0 ;
307307 let scoreB = 0 ;
308308
309309 // 优先 x64 (通常更通用)
310310 if (nA .includes (" x64" ) || nA .includes (" amd64" )) scoreA += 10 ;
311311 if (nB .includes (" x64" ) || nB .includes (" amd64" )) scoreB += 10 ;
312-
312+
313313 // 优先 setup / dmg / appimage
314314 if (/ \. (exe| dmg| appimage)$ / i .test (nA )) scoreA += 5 ;
315315 if (/ \. (exe| dmg| appimage)$ / i .test (nB )) scoreB += 5 ;
@@ -341,52 +341,64 @@ const recommendedAssets = computed(() => {
341341 let result: GitHubAsset [] = [];
342342
343343 if (p === " windows" ) {
344- const validAssets = assets .filter (f => {
344+ const validAssets = assets .filter (( f ) => {
345345 const n = f .name .toLowerCase ();
346- return (n .endsWith (" .exe" ) || n .endsWith (" .zip" )) &&
347- ! n .endsWith (" .blockmap" ) &&
348- ! n .includes (" debug" );
346+ return (
347+ (n .endsWith (" .exe" ) || n .endsWith (" .zip" )) &&
348+ ! n .endsWith (" .blockmap" ) &&
349+ ! n .includes (" debug" )
350+ );
349351 });
350352
351- const installable = validAssets .filter (f => ! isPortable (f .name ) && f .name .endsWith (" .exe" ));
352- const portable = validAssets .filter (f => isPortable (f .name ) || f .name .endsWith (" .zip" ));
353+ const installable = validAssets .filter (( f ) => ! isPortable (f .name ) && f .name .endsWith (" .exe" ));
354+ const portable = validAssets .filter (( f ) => isPortable (f .name ) || f .name .endsWith (" .zip" ));
353355
354356 // 查找最佳匹配
355- let setupAsset = installable .find (f => isArchCompatible (f .name , arch ));
356- let portableAsset = portable .find (f => isArchCompatible (f .name , arch ));
357-
357+ let setupAsset = installable .find (( f ) => isArchCompatible (f .name , arch ));
358+ let portableAsset = portable .find (( f ) => isArchCompatible (f .name , arch ));
359+
358360 // 如果是 x64 环境,确保没有错误地匹配到不带架构标识的 32 位包(如果有的话),优先匹配明确标有 x64 的
359361 if (arch === " x64" ) {
360- const setupX64 = installable .find (f => f .name .toLowerCase ().includes (" x64" ) || f .name .toLowerCase ().includes (" amd64" ));
361- if (setupX64 ) setupAsset = setupX64 ;
362-
363- const portableX64 = portable .find (f => (f .name .toLowerCase ().includes (" x64" ) || f .name .toLowerCase ().includes (" amd64" )));
364- if (portableX64 ) portableAsset = portableX64 ;
362+ const setupX64 = installable .find (
363+ (f ) => f .name .toLowerCase ().includes (" x64" ) || f .name .toLowerCase ().includes (" amd64" ),
364+ );
365+ if (setupX64 ) setupAsset = setupX64 ;
366+
367+ const portableX64 = portable .find (
368+ (f ) => f .name .toLowerCase ().includes (" x64" ) || f .name .toLowerCase ().includes (" amd64" ),
369+ );
370+ if (portableX64 ) portableAsset = portableX64 ;
365371 }
366372
367373 if (setupAsset ) result .push (setupAsset );
368374 if (portableAsset ) result .push (portableAsset );
369-
370375 } else if (p === " macos" ) {
371376 // macOS 策略:
372377 // 优先 DMG
373- const dmg = assets .find (f => {
378+ const dmg = assets .find (( f ) => {
374379 const n = f .name .toLowerCase ();
375380 return n .endsWith (" .dmg" ) && ! n .includes (" blockmap" ) && isArchCompatible (f .name , arch );
376381 });
377-
382+
378383 // 如果没有找到精确匹配 arm64 的 dmg (例如只有 universal 或 x64),尝试找任意 dmg
379- const fallbackDmg = assets .find (f => f .name .toLowerCase ().endsWith (" .dmg" ) && ! f .name .includes (" blockmap" ));
384+ const fallbackDmg = assets .find (
385+ (f ) => f .name .toLowerCase ().endsWith (" .dmg" ) && ! f .name .includes (" blockmap" ),
386+ );
380387
381388 if (dmg ) result .push (dmg );
382- else if (fallbackDmg && p === " macos" ) result .push (fallbackDmg );
383-
389+ else if (fallbackDmg && p === " macos" ) result .push (fallbackDmg );
384390 } else if (p === " linux" ) {
385391 // Linux 策略:
386392 // 优先 AppImage, 其次 Deb
387- const appImage = assets .find (f => f .name .toLowerCase ().endsWith (" .appimage" ) && isArchCompatible (f .name , arch ));
388- const deb = assets .find (f => f .name .toLowerCase ().endsWith (" .deb" ) && isArchCompatible (f .name , arch ));
389- const rpm = assets .find (f => f .name .toLowerCase ().endsWith (" .rpm" ) && isArchCompatible (f .name , arch ));
393+ const appImage = assets .find (
394+ (f ) => f .name .toLowerCase ().endsWith (" .appimage" ) && isArchCompatible (f .name , arch ),
395+ );
396+ const deb = assets .find (
397+ (f ) => f .name .toLowerCase ().endsWith (" .deb" ) && isArchCompatible (f .name , arch ),
398+ );
399+ const rpm = assets .find (
400+ (f ) => f .name .toLowerCase ().endsWith (" .rpm" ) && isArchCompatible (f .name , arch ),
401+ );
390402
391403 if (appImage ) result .push (appImage );
392404 else if (deb ) result .push (deb );
@@ -395,7 +407,10 @@ const recommendedAssets = computed(() => {
395407
396408 // 兜底:如果完全没找到推荐,且是 Windows,给一个最通用的
397409 if (result .length === 0 && p === " windows" ) {
398- const fallback = assets .find (f => f .name .toLowerCase ().endsWith (" .exe" ) && ! f .name .includes (" arm64" ) && ! isPortable (f .name ));
410+ const fallback = assets .find (
411+ (f ) =>
412+ f .name .toLowerCase ().endsWith (" .exe" ) && ! f .name .includes (" arm64" ) && ! isPortable (f .name ),
413+ );
399414 if (fallback ) result .push (fallback );
400415 }
401416
@@ -406,7 +421,7 @@ const classifiedAssets = computed<PlatformGroup[]>(() => {
406421 if (! latestRelease .value ) return [];
407422 const rawAssets = latestRelease .value .assets ;
408423
409- const validAssets = rawAssets .filter (f => {
424+ const validAssets = rawAssets .filter (( f ) => {
410425 const n = f .name .toLowerCase ();
411426 // 过滤掉 metadata 和 debug 文件
412427 return ! n .endsWith (" .blockmap" ) && ! n .endsWith (" .yml" ) && ! n .includes (" debug" );
@@ -422,14 +437,18 @@ const classifiedAssets = computed<PlatformGroup[]>(() => {
422437 title: " 安装程序" ,
423438 desc: " 推荐 · 自动更新" ,
424439 assets: sortAssets (
425- validAssets .filter (f => / \. (exe| msi)$ / i .test (f .name ) && ! isPortable (f .name ))
440+ validAssets .filter (( f ) => / \. (exe| msi)$ / i .test (f .name ) && ! isPortable (f .name )),
426441 ),
427442 },
428443 {
429444 title: " 绿色便携版" ,
430445 desc: " 解压即用 · 数据随身" ,
431446 assets: sortAssets (
432- validAssets .filter (f => isPortable (f .name ) || (f .name .endsWith (" .zip" ) && ! f .name .toLowerCase ().includes (" mac" )))
447+ validAssets .filter (
448+ (f ) =>
449+ isPortable (f .name ) ||
450+ (f .name .endsWith (" .zip" ) && ! f .name .toLowerCase ().includes (" mac" )),
451+ ),
433452 ),
434453 },
435454 ],
@@ -442,14 +461,14 @@ const classifiedAssets = computed<PlatformGroup[]>(() => {
442461 {
443462 title: " 磁盘镜像" ,
444463 desc: " 推荐 · 拖拽安装" ,
445- assets: validAssets .filter (f => f .name .toLowerCase ().endsWith (" .dmg" )),
464+ assets: validAssets .filter (( f ) => f .name .toLowerCase ().endsWith (" .dmg" )),
446465 },
447466 {
448467 title: " 压缩归档" ,
449468 desc: " 手动安装" ,
450- assets: validAssets .filter (f => {
451- const n = f .name .toLowerCase ();
452- return n .endsWith (" .zip" ) && (n .includes (" mac" ) || n .includes (" darwin" ));
469+ assets: validAssets .filter (( f ) => {
470+ const n = f .name .toLowerCase ();
471+ return n .endsWith (" .zip" ) && (n .includes (" mac" ) || n .includes (" darwin" ));
453472 }),
454473 },
455474 ],
@@ -462,27 +481,27 @@ const classifiedAssets = computed<PlatformGroup[]>(() => {
462481 {
463482 title: " AppImage" ,
464483 desc: " 通用运行包" ,
465- assets: sortAssets (validAssets .filter (f => f .name .toLowerCase ().endsWith (" .appimage" ))),
484+ assets: sortAssets (validAssets .filter (( f ) => f .name .toLowerCase ().endsWith (" .appimage" ))),
466485 },
467486 {
468487 title: " Debian 包" ,
469488 desc: " Debian / Ubuntu / Linux Mint..." ,
470- assets: sortAssets (validAssets .filter (f => f .name .toLowerCase ().endsWith (" .deb" ))),
489+ assets: sortAssets (validAssets .filter (( f ) => f .name .toLowerCase ().endsWith (" .deb" ))),
471490 },
472491 {
473492 title: " RPM 包" ,
474493 desc: " Red Hat / Fedora / AlmaLinux..." ,
475- assets: sortAssets (validAssets .filter (f => f .name .toLowerCase ().endsWith (" .rpm" ))),
494+ assets: sortAssets (validAssets .filter (( f ) => f .name .toLowerCase ().endsWith (" .rpm" ))),
476495 },
477496 {
478497 title: " Pacman 包" ,
479498 desc: " Arch Linux / Manjaro..." ,
480- assets: sortAssets (validAssets .filter (f => f .name .toLowerCase ().endsWith (" .pacman" ))),
499+ assets: sortAssets (validAssets .filter (( f ) => f .name .toLowerCase ().endsWith (" .pacman" ))),
481500 },
482501 {
483502 title: " 其他格式" ,
484503 desc: " 归档包" ,
485- assets: sortAssets (validAssets .filter (f => / \. (tar\. gz)$ / i .test (f .name ))),
504+ assets: sortAssets (validAssets .filter (( f ) => / \. (tar\. gz)$ / i .test (f .name ))),
486505 },
487506 ],
488507 },
@@ -506,7 +525,7 @@ const formatFileSize = (bytes: number) =>
506525 bytes ? ` ${(bytes / 1024 / 1024 ).toFixed (1 )} MB ` : " 未知" ;
507526const formatDate = (s : string ) =>
508527 new Date (s ).toLocaleDateString (" zh-CN" , { year: " numeric" , month: " long" , day: " numeric" });
509-
528+
510529// 注意:marked 在前端使用时建议配合 dompurify 防止 XSS。
511530const renderMarkdown = (t : string ) => marked .parse (t );
512531
@@ -961,7 +980,7 @@ const scrollToPlatforms = () => {
961980 font-size : 1.2rem ;
962981 padding : 4px 12px ;
963982 }
964-
983+
965984 .v-date {
966985 font-size : 0.85rem ;
967986 }
@@ -990,7 +1009,7 @@ const scrollToPlatforms = () => {
9901009
9911010 .recommend-card {
9921011 padding : 1.25rem ;
993-
1012+
9941013 .card-header {
9951014 flex-direction : column ;
9961015 align-items : flex-start ;
@@ -1013,7 +1032,7 @@ const scrollToPlatforms = () => {
10131032 gap : 12px ;
10141033 padding : 14px ;
10151034 }
1016-
1035+
10171036 .btn-title {
10181037 font-size : 1rem ;
10191038 }
@@ -1024,7 +1043,7 @@ const scrollToPlatforms = () => {
10241043 justify-content : flex-end ;
10251044 }
10261045 }
1027-
1046+
10281047 .section-divider h2 {
10291048 font-size : 1.5rem ;
10301049 }
@@ -1033,7 +1052,7 @@ const scrollToPlatforms = () => {
10331052 .block-title h3 {
10341053 font-size : 1.2rem ;
10351054 }
1036-
1055+
10371056 .files-grid {
10381057 grid-template-columns : 1fr ;
10391058 }
@@ -1048,7 +1067,7 @@ const scrollToPlatforms = () => {
10481067 .arch-guide {
10491068 display : flex ;
10501069 flex-direction : column ;
1051-
1070+
10521071 .guide-divider {
10531072 display : none ;
10541073 }
0 commit comments