@@ -160,6 +160,7 @@ type IpLocation = {
160160
161161type ProxyRequestDetail = {
162162 id: number
163+ event_type? : ' request' | ' block' | ' unblock'
163164 timestamp_ms: number
164165 server_id: string
165166 server_name: string
@@ -298,7 +299,7 @@ type AuthMode = 'loading' | 'setup' | 'login' | 'app'
298299type Page = ' home' | ' server' | ' clients' | ' notifications' | ' backup' | ' logs' | ' account'
299300type ClientStatusFilter = ' all' | ' blocked' | ' allowed'
300301type LogKindFilter = ' all' | ' playback' | ' general'
301- type LogViewFilter = ' playback' | ' proxy' | ' general'
302+ type LogViewFilter = ' playback' | ' blocked ' | ' proxy' | ' general'
302303type EncryptionPublicKey =
303304 | { kind: ' webcrypto' ; key: CryptoKey }
304305 | { kind: ' forge' ; key: forge .pki .rsa .PublicKey }
@@ -461,6 +462,7 @@ const activityLogLoadStep = 80
461462const requestDetailLoadStep = 100
462463const logViewLabels: Record <LogViewFilter , string > = {
463464 playback: ' 播放日志' ,
465+ blocked: ' 拦截日志明细' ,
464466 proxy: ' 反代请求明细' ,
465467 general: ' 信息' ,
466468}
@@ -526,12 +528,19 @@ const canLoadMoreGeneralLogs = computed(() =>
526528 && generalLogLimit .value < activityLogMaxLimit ,
527529)
528530const canLoadMoreRequestDetails = computed (() =>
529- selectedLogView .value === ' proxy '
531+ isRequestDetailLogView .value
530532 && requestDetailRows .value .length >= requestDetailLimit .value
531533 && requestDetailLimit .value < requestDetailDisplayMax ,
532534)
535+ const isRequestDetailLogView = computed (() => selectedLogView .value === ' proxy' || selectedLogView .value === ' blocked' )
533536const logLevelOptions = computed (() => {
534- if (selectedLogView .value === ' proxy' ) {
537+ if (selectedLogView .value === ' blocked' ) {
538+ return [
539+ { value: ' all' , label: ' 全部级别' },
540+ { value: ' blocked' , label: ' BLOCKED - 已拦截' },
541+ ]
542+ }
543+ if (isRequestDetailLogView .value ) {
535544 return [
536545 { value: ' all' , label: ' 全部级别' },
537546 { value: ' success' , label: ' SUCCESS - 成功' },
@@ -567,11 +576,11 @@ const filteredRequestDetailRows = computed(() =>
567576 }),
568577)
569578const visibleLogCount = computed (() => {
570- if (selectedLogView .value === ' proxy ' ) return filteredRequestDetailRows .value .length
579+ if (isRequestDetailLogView .value ) return filteredRequestDetailRows .value .length
571580 return visibleActivityLogRows .value .length
572581})
573582const canLoadMoreSelectedLogs = computed (() => {
574- if (selectedLogView .value === ' proxy ' ) return canLoadMoreRequestDetails .value
583+ if (isRequestDetailLogView .value ) return canLoadMoreRequestDetails .value
575584 if (selectedLogView .value === ' general' ) return canLoadMoreGeneralLogs .value
576585 return canLoadMorePlaybackLogs .value
577586})
@@ -790,14 +799,7 @@ async function refreshUpdateCheck(force = true) {
790799 updateChecking .value = true
791800 updateCheckError .value = ' '
792801 try {
793- updateCheck .value = await api <UpdateCheck >(` /api/app-info/update-check${force ? ' ?force=1' : ' ' } ` )
794- if (force ) {
795- showNotice (
796- updateCheck .value .has_update
797- ? ` 发现新版本 ${updateCheck .value .latest_version } `
798- : ` 已是最新版本 ${updateCheck .value .current_version } ` ,
799- )
800- }
802+ updateCheck .value = await api <UpdateCheck >(` /api/app-info/update-check${force ? ' ?force=true' : ' ' } ` )
801803 } catch (err ) {
802804 updateCheck .value = null
803805 updateCheckError .value = err instanceof Error ? err .message : String (err )
@@ -1593,7 +1595,10 @@ async function fetchProxyRequestDetails() {
15931595 if (logKeywordFilter .value .trim ()) params .set (' keyword' , logKeywordFilter .value .trim ())
15941596 if (logSince .value ) params .set (' since_ms' , String (new Date (logSince .value ).getTime ()))
15951597 if (logUntil .value ) params .set (' until_ms' , String (new Date (logUntil .value ).getTime ()))
1596- return api <ProxyRequestDetail []>(` /api/monitoring/request-details?${params .toString ()} ` )
1598+ const endpoint = selectedLogView .value === ' blocked'
1599+ ? ' /api/monitoring/block-logs'
1600+ : ' /api/monitoring/request-details'
1601+ return api <ProxyRequestDetail []>(` ${endpoint }?${params .toString ()} ` )
15971602}
15981603
15991604function loadMorePlaybackLogs() {
@@ -1615,7 +1620,7 @@ function loadMoreRequestDetails() {
16151620}
16161621
16171622function loadMoreSelectedLogs() {
1618- if (selectedLogView .value === ' proxy ' ) return loadMoreRequestDetails ()
1623+ if (isRequestDetailLogView .value ) return loadMoreRequestDetails ()
16191624 if (selectedLogView .value === ' general' ) return loadMoreGeneralLogs ()
16201625 return loadMorePlaybackLogs ()
16211626}
@@ -1628,6 +1633,7 @@ function handleScrollableLogListScroll(event: Event, loadMore: () => void) {
16281633}
16291634
16301635function requestSeverity(row : ProxyRequestDetail ) {
1636+ if (row .event_type === ' unblock' ) return ' success'
16311637 if (row .blocked ) return ' blocked'
16321638 if (row .cache_hit ) return ' cache'
16331639 if (row .status_code >= 500 ) return ' error'
@@ -1637,6 +1643,8 @@ function requestSeverity(row: ProxyRequestDetail) {
16371643}
16381644
16391645function requestSeverityLabel(row : ProxyRequestDetail ) {
1646+ if (row .event_type === ' block' ) return ' 封禁动作'
1647+ if (row .event_type === ' unblock' ) return ' 解除封禁'
16401648 const severity = requestSeverity (row )
16411649 if (severity === ' blocked' ) return ' 已拦截'
16421650 if (severity === ' cache' ) return ' 缓存'
@@ -1940,14 +1948,22 @@ function logLevelLabel(level: ActivityLogEntry['level']) {
19401948}
19411949
19421950function requestPathTypeLabel(type : string ) {
1951+ if (type === ' rate_limit_action' ) return ' 封禁动作'
19431952 if (type === ' video_stream' ) return ' 视频流'
19441953 if (type === ' playback_info' ) return ' 播放信息'
19451954 if (type === ' system_info' ) return ' 系统信息'
19461955 if (type === ' base_html_player' ) return ' 播放器脚本'
19471956 return ' 普通代理'
19481957}
19491958
1959+ function requestRowTitle(row : ProxyRequestDetail ) {
1960+ if (row .event_type === ' block' ) return ` 封禁 ${row .playback_ip || ' --' } `
1961+ if (row .event_type === ' unblock' ) return ` 解除封禁 ${row .playback_ip || ' --' } `
1962+ return ` ${row .method } ${row .path } `
1963+ }
1964+
19501965function requestOutcomeClass(row : ProxyRequestDetail ) {
1966+ if (row .event_type === ' unblock' ) return ' ok'
19511967 if (row .blocked ) return ' blocked'
19521968 if (row .cache_hit ) return ' cache'
19531969 if (row .status_code >= 500 ) return ' error'
@@ -2021,6 +2037,7 @@ onBeforeUnmount(stopDashboardPolling)
20212037 {{ appInfo.version || '版本读取中' }}
20222038 <span v-if =" updateChecking" class =" brand-version-badge" >检查中</span >
20232039 <span v-else-if =" updateCheck?.has_update" class =" brand-version-badge update" >有更新</span >
2040+ <span v-else-if =" updateCheck" class =" brand-version-badge latest" >最新</span >
20242041 <span v-else-if =" updateCheckError" class =" brand-version-badge error" >失败</span >
20252042 </small >
20262043 </button >
@@ -2899,23 +2916,24 @@ onBeforeUnmount(stopDashboardPolling)
28992916 <div >
29002917 <h2 >日志</h2 >
29012918 <p class =" muted" >
2902- 单列表查看播放日志、反代请求明细和运行信息,页面打开时每 3 秒自动刷新。
2919+ 单列表查看播放日志、拦截日志明细、 反代请求明细和运行信息,页面打开时每 3 秒自动刷新。
29032920 </p >
29042921 </div >
29052922 <div class =" panel-actions" >
29062923 <span class =" status-dot" >{{ logsLoading ? '刷新中' : '实时刷新' }}</span >
29072924 <button class =" secondary" :disabled =" logsLoading" @click =" refreshActivityLogs" >
29082925 {{ logsLoading ? '刷新中' : '刷新' }}
29092926 </button >
2910- <button v-if =" selectedLogView !== 'proxy' " class =" secondary" @click =" exportLogs" >导出 CSV</button >
2927+ <button v-if =" !isRequestDetailLogView " class =" secondary" @click =" exportLogs" >导出 CSV</button >
29112928 </div >
29122929 </div >
29132930 <div v-if =" logsError" class =" notice error" >{{ logsError }}</div >
2914- <div :class =" ['log-toolbar', 'compact', { proxy: selectedLogView === 'proxy' }]" >
2931+ <div :class =" ['log-toolbar', 'compact', { proxy: isRequestDetailLogView }]" >
29152932 <label >
29162933 <span >日志类型</span >
29172934 <select v-model =" selectedLogView" @change =" handleLogViewChange" >
29182935 <option value =" playback" >播放日志</option >
2936+ <option value =" blocked" >拦截日志明细</option >
29192937 <option value =" proxy" >反代请求明细</option >
29202938 <option value =" general" >信息</option >
29212939 </select >
@@ -2937,14 +2955,15 @@ onBeforeUnmount(stopDashboardPolling)
29372955 </option >
29382956 </select >
29392957 </label >
2940- <label v-if =" selectedLogView === 'proxy' " >
2958+ <label v-if =" isRequestDetailLogView " >
29412959 <span >请求类型</span >
29422960 <select v-model =" selectedRequestPathType" @change =" refreshLogsWithReset" >
29432961 <option value =" all" >全部请求</option >
29442962 <option value =" video_stream" >视频流</option >
29452963 <option value =" playback_info" >播放信息</option >
29462964 <option value =" system_info" >系统信息</option >
29472965 <option value =" base_html_player" >播放器脚本</option >
2966+ <option v-if =" selectedLogView === 'blocked'" value =" rate_limit_action" >封禁动作</option >
29482967 <option value =" proxy" >普通代理</option >
29492968 </select >
29502969 </label >
@@ -2968,7 +2987,7 @@ onBeforeUnmount(stopDashboardPolling)
29682987 <div class =" log-console-meta" >
29692988 <span >{{ selectedLogViewLabel }}</span >
29702989 <strong >{{ visibleLogCount }}</strong >
2971- <span v-if =" selectedLogView === 'proxy' " >
2990+ <span v-if =" isRequestDetailLogView " >
29722991 单次最多 {{ requestDetailDisplayMax }} 条,保留 {{ requestDetailPersistDays }} 天或最近 {{ requestDetailPersistMax }} 条
29732992 </span >
29742993 <span v-else >内存最多保留最近 {{ activityLogMaxLimit }} 条可视化日志</span >
@@ -2979,7 +2998,7 @@ onBeforeUnmount(stopDashboardPolling)
29792998 class =" log-console-list"
29802999 @scroll =" handleScrollableLogListScroll($event, loadMoreSelectedLogs)"
29813000 >
2982- <template v-if =" selectedLogView !== ' proxy ' " >
3001+ <template v-if =" ! isRequestDetailLogView " >
29833002 <article
29843003 v-for =" entry in visibleActivityLogRows"
29853004 :key =" `activity-${entry.id}`"
@@ -3013,17 +3032,17 @@ onBeforeUnmount(stopDashboardPolling)
30133032 <span class =" request-time" >{{ formatLogTime(row.timestamp_ms) }}</span >
30143033 </div >
30153034 <div class =" request-path" >
3016- <strong >{{ row.method }} {{ row.path }}</strong >
3035+ <strong >{{ requestRowTitle( row) }}</strong >
30173036 <span >{{ row.detail }}</span >
30183037 </div >
30193038 </div >
30203039 <div class =" request-state" >
30213040 <span >{{ row.outcome }}</span >
3022- <span >{{ row.path_type }}</span >
3023- <span >HTTP {{ row.status_code }}</span >
3024- <span >{{ row.duration_ms }}ms</span >
3025- <span >{{ row.cache_hit ? '缓存命中' : '未命中' }}</span >
3026- <span >{{ row.blocked ? '已拦截' : '未拦截' }}</span >
3041+ <span >{{ requestPathTypeLabel( row.path_type) }}</span >
3042+ <span v-if = " row.event_type !== 'block' && row.event_type !== 'unblock' " >HTTP {{ row.status_code }}</span >
3043+ <span v-if = " row.event_type !== 'block' && row.event_type !== 'unblock' " >{{ row.duration_ms }}ms</span >
3044+ <span v-if = " row.event_type !== 'block' && row.event_type !== 'unblock' " >{{ row.cache_hit ? '缓存命中' : '未命中' }}</span >
3045+ <span >{{ row.event_type === 'unblock' ? '已解除' : row. blocked ? '已拦截' : '未拦截' }}</span >
30273046 </div >
30283047 </article >
30293048 </template >
0 commit comments