@@ -27,6 +27,7 @@ import {
2727 PopoverContent ,
2828 Spinner ,
2929 Input ,
30+ DatePicker ,
3031} from "@heroui/react" ;
3132import { Snippet } from "@/components/ui/snippet" ;
3233import React , { useEffect } from "react" ;
@@ -67,6 +68,7 @@ import { useSearchParams } from "next/navigation";
6768import { FileLogViewer } from "@/components/ui/file-log-viewer" ;
6869import { useTunnelSSE } from "@/lib/hooks/use-sse" ;
6970import { useMetricsTrend } from "@/lib/hooks/use-metrics-trend" ;
71+ import { parseDate , getLocalTimeZone } from "@internationalized/date" ;
7072
7173interface TunnelInfo {
7274 id : string ;
@@ -347,10 +349,10 @@ export default function TunnelDetailPage({
347349 const [ isUpdatingRestart , setIsUpdatingRestart ] = React . useState ( false ) ;
348350
349351 // 文件日志相关状态
350- const [ logDays , setLogDays ] = React . useState < string > ( "1" ) ;
352+ const [ logDate , setLogDate ] = React . useState < string > ( "" ) ; // 改为logDate
353+ const [ availableLogDates , setAvailableLogDates ] = React . useState < string [ ] > ( [ ] ) ; // 新增:可用日志日期列表
351354 const [ logLoading , setLogLoading ] = React . useState ( false ) ;
352355 const [ logClearing , setLogClearing ] = React . useState ( false ) ;
353- const [ logCount , setLogCount ] = React . useState ( 0 ) ;
354356 const [ logRefreshTrigger , setLogRefreshTrigger ] = React . useState ( 0 ) ;
355357 const [ clearPopoverOpen , setClearPopoverOpen ] = React . useState ( false ) ;
356358 const [ exportLoading , setExportLoading ] = React . useState ( false ) ;
@@ -765,11 +767,50 @@ export default function TunnelDetailPage({
765767 udp_out_rates : [ ] ,
766768 } ) ;
767769
770+ // 获取可用的日志日期列表
771+ const fetchAvailableLogDates = React . useCallback ( async ( ) => {
772+ if ( ! tunnelInfo ?. endpointId || ! tunnelInfo ?. instanceId ) return ;
773+
774+ try {
775+ const response = await fetch (
776+ `/api/endpoints/${ tunnelInfo . endpointId } /file-logs/dates?instanceId=${ tunnelInfo . instanceId } `
777+ ) ;
778+
779+ if ( ! response . ok ) {
780+ throw new Error ( '获取可用日志日期失败' ) ;
781+ }
782+
783+ const data = await response . json ( ) ;
784+
785+ if ( data . success && Array . isArray ( data . dates ) ) {
786+ setAvailableLogDates ( data . dates ) ;
787+
788+ // 如果没有选中日期,则默认选择最新的可用日期
789+ if ( ! logDate && data . dates . length > 0 ) {
790+ const latestDate = data . dates [ 0 ] ; // 日期已经按最新排序
791+ setLogDate ( latestDate ) ;
792+ }
793+ } else {
794+ setAvailableLogDates ( [ ] ) ;
795+ }
796+ } catch ( error ) {
797+ console . error ( '获取可用日志日期失败:' , error ) ;
798+ setAvailableLogDates ( [ ] ) ;
799+ }
800+ } , [ tunnelInfo ?. endpointId , tunnelInfo ?. instanceId , logDate ] ) ;
801+
768802 // 初始加载数据
769803 React . useEffect ( ( ) => {
770804 fetchTunnelDetails ( ) ;
771805 } , [ fetchTunnelDetails ] ) ;
772806
807+ // 当隧道信息加载完成后,获取可用的日志日期
808+ React . useEffect ( ( ) => {
809+ if ( tunnelInfo ?. endpointId && tunnelInfo ?. instanceId ) {
810+ fetchAvailableLogDates ( ) ;
811+ }
812+ } , [ tunnelInfo ?. endpointId , tunnelInfo ?. instanceId , fetchAvailableLogDates ] ) ;
813+
773814 // 组件卸载时清理全局变量引用和useRef数据
774815 React . useEffect ( ( ) => {
775816 return ( ) => {
@@ -2121,32 +2162,37 @@ export default function TunnelDetailPage({
21212162 < div className = "flex items-center gap-3" >
21222163 < div className = "flex items-center gap-2" >
21232164 < h3 className = "text-lg font-semibold" > 日志</ h3 >
2124-
2125- < Chip variant = "flat" color = "primary" size = "sm" >
2126- { logCount } 条记录
2127- </ Chip >
2165+ { /* <Chip variant="flat" color="primary" size="sm">
2166+ {logCount} 条记录 {logDate ? `(${logDate})` : ''}
2167+ </Chip> */ }
21282168 </ div >
21292169 </ div >
21302170 < div className = "flex items-center gap-2" >
2131- { /* 天数选择 */ }
2132- < Select
2171+ { /* 日期选择 */ }
2172+ < DatePicker
21332173 size = "sm"
2134- placeholder = "选择天数"
2135- selectedKeys = { [ logDays ] }
2136- onSelectionChange = { ( keys ) => {
2137- const selected = Array . from ( keys ) [ 0 ] as string ;
2138- if ( selected ) setLogDays ( selected ) ;
2174+ className = "w-40"
2175+ isDisabled = { availableLogDates . length === 0 }
2176+ value = { logDate ? parseDate ( logDate ) : null }
2177+ onChange = { ( date ) => {
2178+ if ( date ) {
2179+ const newDate = date . toString ( ) ;
2180+ setLogDate ( newDate ) ;
2181+ // 触发日志刷新以获取新日期的日志内容
2182+ setLogRefreshTrigger ( prev => prev + 1 ) ;
2183+ }
21392184 } }
2140- className = "w-20"
2141- classNames = { {
2142- trigger : "min-h-unit-8 h-8" ,
2143- value : "text-xs" ,
2185+ isDateUnavailable = { ( date ) => {
2186+ // 如果availableLogDates为空,则禁用所有日期
2187+ if ( availableLogDates . length === 0 ) return true ;
2188+
2189+ // 只允许选择可用日期列表中的日期
2190+ const dateString = date . toString ( ) ;
2191+ return ! availableLogDates . includes ( dateString ) ;
21442192 } }
2145- >
2146- < SelectItem key = "1" > 1天</ SelectItem >
2147- < SelectItem key = "3" > 3天</ SelectItem >
2148- < SelectItem key = "7" > 7天</ SelectItem >
2149- </ Select >
2193+ showMonthAndYearPickers
2194+ granularity = "day"
2195+ />
21502196
21512197 { /* 刷新按钮 */ }
21522198 < Tooltip content = "刷新日志" placement = "top" >
@@ -2208,7 +2254,6 @@ export default function TunnelDetailPage({
22082254 color = "danger"
22092255 isIconOnly
22102256 isLoading = { logClearing }
2211- isDisabled = { logCount === 0 }
22122257 className = "h-8 w-8 min-w-0"
22132258 >
22142259 < FontAwesomeIcon icon = { faTrash } className = "text-xs" />
@@ -2252,9 +2297,8 @@ export default function TunnelDetailPage({
22522297 < FileLogViewer
22532298 endpointId = { tunnelInfo ?. endpointId || "" }
22542299 instanceId = { tunnelInfo ?. instanceId || "" }
2255- days = { logDays }
2256- onDaysChange = { setLogDays }
2257- onLogsChange = { ( logs ) => setLogCount ( logs . length ) }
2300+ date = { logDate }
2301+ onDateChange = { setLogDate }
22582302 onLoadingChange = { setLogLoading }
22592303 onClearingChange = { setLogClearing }
22602304 triggerRefresh = { logRefreshTrigger }
0 commit comments