11/**
2- * 图片阅读器 - 支持压缩包和文件夹图片浏览,带缩放、旋转、拖拽功能
3- */
2+ * 图片阅读å™?- 支æŒåŽ‹ç¼©åŒ…å’Œæ–‡ä»¶å¤¹å›¾ç‰‡æµè§ˆï¼Œå¸¦ç¼©æ”¾ã€æ—‹è½¬ã€æ‹–拽功èƒ? */
43import { useMutation } from "@/shims/react-query"
54import { createFileRoute , Link , useNavigate } from "@tanstack/react-router"
65import {
@@ -64,10 +63,7 @@ export const Route = createFileRoute("/_layout/read")({
6463 path : ( search . path as string ) || "" ,
6564 page : Number ( search . page ) || 0 ,
6665 source : ( search . source as "archive" | "folder" ) || "archive" ,
67- // sourceFolderPath: 仅 source=folder 时有效。
68- // 用于从外部(如 explorer 点击某张图片)跳转到阅读器时定位到特定图片。
69- // 解析后会被 replace 成对应的 page 数字,之后 sourceFolderPath 置空。
70- sourceFolderPath : ( search . sourceFolderPath as string ) || "" ,
66+ // sourceFolderPath: ä»?source=folder 时有效ã€? // 用于从外部(å¦?explorer 点击æŸå¼ 图片)跳转到阅读器时定ä½åˆ°ç‰¹å®šå›¾ç‰‡ã€? // è§£æžåŽä¼šè¢?replace æˆå¯¹åº”çš„ page æ•°å—,之å?sourceFolderPath 置空ã€? sourceFolderPath: (search.sourceFolderPath as string) || "",
7167 mode : ( search . mode as "audio" ) || undefined ,
7268 } ) ,
7369 head : ( ) => ( {
@@ -168,7 +164,7 @@ function ReadPage() {
168164 if ( cancelled ) return
169165 setFolderData ( currentFolderData )
170166 } else {
171- // archive: 打开时先解压一次,再拉 archive 列表与 parent 列表
167+ // archive: æ‰“å¼€æ—¶å…ˆè§£åŽ‹ä¸€æ¬¡ï¼Œå†æ‹‰ archive 列表ä¸? parent 列表
172168 setArchiveImageReady ( false )
173169 const [ extractResult , archiveData , parentData ] = await Promise . all ( [
174170 FilesystemService . extractArchive ( { path, page : 0 } ) ,
@@ -235,8 +231,7 @@ function ReadPage() {
235231 } ) )
236232 } , [ isFolderSource , folderData , listData ] )
237233
238- // Audio tracks(仅 archive source)
239- const audioTracks = useMemo ( ( ) => {
234+ // Audio tracks(仅 archive source� const audioTracks = useMemo(() => {
240235 if ( isFolderSource ) return [ ]
241236 return ( listData ?. entries || [ ] )
242237 . filter ( ( e ) => e . file_type === "audio" )
@@ -427,7 +422,7 @@ function ReadPage() {
427422 const targetPath = isFolderSource ? path : ( extractStatus ?. cache_dir || path )
428423 navigate ( {
429424 to : "/explorer" ,
430- search : { path : targetPath , page : 1 , pageSize : 48 , sortField : "mtime " , sortOrder : "desc " } ,
425+ search : { path : targetPath , page : 1 , pageSize : 48 , sortField : "name " , sortOrder : "asc" , viewMode : "table " } ,
431426 } )
432427 } else if ( key === "v" ) {
433428 e . preventDefault ( )
@@ -499,7 +494,7 @@ function ReadPage() {
499494 const sizeText = currentPathMeta ?. filesize
500495 ? formatFileSize ( currentPathMeta . filesize )
501496 : "-"
502- // 优先用 extractMutation 实时返回的值,fallback 到父目录列表的 DB 缓存
497+ // 优先ç”? extractMutation 实时返回的值,fallback 到父目录列表çš? DB 缓å˜
503498 const avgImageSize = extractStatus ?. avg_image_size ?? currentPathMeta ?. avg_image_size ?? null
504499 const avgImageSizeText = avgImageSize != null ? formatFileSize ( avgImageSize ) : "-"
505500 const archiveVideoCount = currentPathMeta ?. video_count ?? 0
@@ -508,8 +503,7 @@ function ReadPage() {
508503 const cosers = parseMeta ?. cosers ?? [ ]
509504 const tags = parseMeta ?. raw_tags ?? [ ]
510505
511- // 文件被移动后自动跳转新路径
512- const hasError = loadError
506+ // 文件被移动åŽè‡ªåŠ¨è·³è½¬æ–°è·¯å¾? const hasError = loadError
513507 const { resolving, isNotFound, errorMessage } = useResolveMovedFile (
514508 path ,
515509 hasError ? loadError : null ,
@@ -571,7 +565,7 @@ function ReadPage() {
571565 showFolderIcon = { false }
572566 collapseDirCrumbsAfter = { 2 }
573567 currentTo = "/explorer"
574- currentSearch = { { path : extractStatus ?. cache_dir || path , page : 1 , pageSize : 48 , sortField : "mtime " , sortOrder : "desc " } }
568+ currentSearch = { { path : extractStatus ?. cache_dir || path , page : 1 , pageSize : 48 , sortField : "name " , sortOrder : "asc" , viewMode : "table " } }
575569 currentLabel = { fileName }
576570 currentClassName = "reader-toolbar__current-link"
577571 />
@@ -645,17 +639,16 @@ function ReadPage() {
645639 }
646640
647641 if ( ! currentEntry ) {
648- // 无图片提示
649- return (
642+ // æ— å›¾ç‰‡æç¤? return (
650643 < div className = "reader-empty-page" >
651644 < PathBreadcrumb
652645 sourcePath = { path }
653646 homeLabel = { t ( "common.home" ) }
654647 separatorClassName = "size-4 text-muted-foreground"
655648 currentTo = "/explorer"
656649 currentSearch = { isFolderSource
657- ? { path, page : 1 , pageSize : 48 , sortField : "mtime " , sortOrder : "desc " }
658- : { path : extractStatus ?. cache_dir || path , page : 1 , pageSize : 48 , sortField : "mtime " , sortOrder : "desc " } }
650+ ? { path, page : 1 , pageSize : 48 , sortField : "name " , sortOrder : "asc" , viewMode : "table " }
651+ : { path : extractStatus ?. cache_dir || path , page : 1 , pageSize : 48 , sortField : "name " , sortOrder : "asc" , viewMode : "table " } }
659652 currentLabel = { fileName }
660653 />
661654
@@ -666,7 +659,7 @@ function ReadPage() {
666659 < >
667660 < Link
668661 to = "/explorer"
669- search = { { path : extractStatus ?. cache_dir || path , page : 1 , pageSize : 48 , sortField : "mtime " , sortOrder : "desc " } }
662+ search = { { path : extractStatus ?. cache_dir || path , page : 1 , pageSize : 48 , sortField : "name " , sortOrder : "asc" , viewMode : "table " } }
670663 className = { buttonVariants ( {
671664 variant : "default" ,
672665 size : "sm" ,
@@ -727,15 +720,14 @@ function ReadPage() {
727720 : `${ OpenAPI . BASE } /api/v1/fs/archive/file?path=${ encodeURIComponent ( path ) } &entry=${ encodeURIComponent ( currentEntry . entryPath || "" ) } `
728721
729722 // å›¾ç‰‡åŠ è½½å¤±è´¥æ—¶çš„é‡è¯•处ç†
730- // 压缩包文件可能还在后台解压中,404 时自动重试(最多 5 次,递增延迟)
731- const handleImageError = ( e : React . SyntheticEvent < HTMLImageElement > ) => {
723+ // 压缩包文件å¯èƒ½è¿˜åœ¨åŽå°è§£åŽ‹ä¸ï¼?04 时自动é‡è¯•(最å¤?5 次,递增延迟ï¼? const handleImageError = (e: React.SyntheticEvent<HTMLImageElement>) => {
732724 const img = e . currentTarget
733725 setImageLoaded ( false )
734726 const retryCount = Number ( img . dataset . retry || 0 )
735727 const maxRetries = 5
736728 if ( retryCount < maxRetries ) {
737729 img . dataset . retry = String ( retryCount + 1 )
738- // 递增延迟:1s , 2s, 3s, 4s, 5s
730+ // 递增延迟�s , 2s, 3s, 4s, 5s
739731 setTimeout (
740732 ( ) => {
741733 img . src = `${ imageUrl } ${ imageUrl . includes ( "?" ) ? "&" : "?" } _t=${ Date . now ( ) } `
@@ -745,8 +737,7 @@ function ReadPage() {
745737 }
746738 }
747739
748- // 图片加载成功时重置重试计数
749- const handleImageLoad = ( e : React . SyntheticEvent < HTMLImageElement > ) => {
740+ // å›¾ç‰‡åŠ è½½æˆåŠŸæ—¶é‡ç½®é‡è¯•计æ•? const handleImageLoad = (e: React.SyntheticEvent<HTMLImageElement>) => {
750741 e . currentTarget . dataset . retry = "0"
751742 setImageLoaded ( true )
752743 }
@@ -772,7 +763,7 @@ function ReadPage() {
772763
773764 return (
774765 < div className = "reader-page" >
775- { /* ── 顶部工具栏:面包屑导航 + 旋转/全屏/模式切换/文件操作菜单 ── */ }
766+ { /* ── 顶部工具æ :é¢åŒ…屑导èˆ?+ 旋转/å…¨å±/模å¼åˆ‡æ¢/文件æ“作èœå• ── */ }
776767 < nav className = "reader-toolbar" >
777768 < div className = "reader-toolbar__left" >
778769 < PathBreadcrumb
@@ -788,14 +779,14 @@ function ReadPage() {
788779 collapseDirCrumbsAfter = { 2 }
789780 currentTo = "/explorer"
790781 currentSearch = { isFolderSource
791- ? { path, page : 1 , pageSize : 48 , sortField : "mtime " , sortOrder : "desc " }
792- : { path : extractStatus ?. cache_dir || path , page : 1 , pageSize : 48 , sortField : "mtime " , sortOrder : "desc " } }
782+ ? { path, page : 1 , pageSize : 48 , sortField : "name " , sortOrder : "asc" , viewMode : "table " }
783+ : { path : extractStatus ?. cache_dir || path , page : 1 , pageSize : 48 , sortField : "name " , sortOrder : "asc" , viewMode : "table " } }
793784 currentLabel = { fileName }
794785 currentClassName = "reader-toolbar__current-link"
795786 />
796787 </ div >
797788
798- { /* 右侧:工具 */ }
789+ { /* å³ä¾§ï¼šå·¥å…? */ }
799790 < div className = "reader-toolbar__right" >
800791 < div className = "reader-toolbar__actions" >
801792 { /* <Button
@@ -805,7 +796,7 @@ function ReadPage() {
805796 onClick={zoomOut}
806797 title={t("reader.zoomOut")}
807798 >
808- <span className="reader-toolbar__button-symbol">−< /span>
799+ <span className="reader-toolbar__button-symbol">� /span>
809800 </Button>
810801 <Button
811802 variant="ghost"
@@ -859,7 +850,7 @@ function ReadPage() {
859850 < >
860851 < Link
861852 to = "/explorer"
862- search = { { path : extractStatus ?. cache_dir || path , page : 1 , pageSize : 48 , sortField : "mtime " , sortOrder : "desc " } }
853+ search = { { path : extractStatus ?. cache_dir || path , page : 1 , pageSize : 48 , sortField : "name " , sortOrder : "asc" , viewMode : "table " } }
863854 className = { buttonVariants ( {
864855 variant : "ghost" ,
865856 size : "sm" ,
@@ -960,7 +951,7 @@ function ReadPage() {
960951 </ div >
961952 </ nav >
962953
963- { /* ── 图片主舞台:支持鼠标拖拽平移、滚轮缩放、左右翻页按钮、解压进度指示 ── */ }
954+ { /* ── 图片主舞å°ï¼šæ”¯æŒé¼ æ ‡æ‹–æ‹½å¹³ç§»ã€æ»šè½®ç¼©æ”¾ã€å·¦å³ç¿»é¡µæŒ‰é’®ã€è§£åŽ‹è¿›åº¦æŒ‡ç¤?── */ }
964955 < div
965956 className = "reader-image-stage"
966957 onMouseMove = { onMouseMove }
@@ -1020,11 +1011,11 @@ function ReadPage() {
10201011 ) }
10211012 </ div >
10221013
1023- { /* ── 底部 meta 栏:文件信息(时间/大小/均图大小/视频音频数)+ 作者/ coser/tag 可点击跳搜索 + 页码 ── */ }
1014+ { /* ── 底部 meta æ :文件信æ¯ï¼ˆæ—¶é—?大å°/å‡å›¾å¤§å°/视频音频数)+ 作è€? coser/tag å¯ç‚¹å‡»è·³æœç´¢ + 页ç ── */ }
10241015 < div className = "reader-meta-bar" >
10251016 < div className = "reader-meta-bar__left" >
10261017 < div className = "reader-meta-bar__row" >
1027- { /* 文件元数据:hover title 显示 label,只展示值 */ }
1018+ { /* 文件元数æ®ï¼šhover title 显示 label,åªå±•示å€? */ }
10281019 < span title = { t ( "reader.mtime" ) } className = "text-foreground cursor-default" > { mtimeText } </ span >
10291020 < span title = { t ( "reader.size" ) } className = "text-foreground cursor-default" > { sizeText } </ span >
10301021 < span title = { t ( "reader.avgImageSize" ) } className = "text-foreground cursor-default" > { avgImageSizeText } </ span >
0 commit comments