U:调整index中函数分布

This commit is contained in:
jimmy committed 2025-07-07 15:50:46 +08:00
1 parent e737713ef5
commit 60fd29876e
3 files changed
+100 -153

No files matched your search

@@ -107,14 +107,23 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed } from 'vue' import { ref, computed } from 'vue'
import { storeToRefs } from 'pinia'
import TrafficChart from './components/TrafficChart.vue' import TrafficChart from './components/TrafficChart.vue'
// 假设我们有一个连接状态的store,将来可以添加
// import { useConnectionStore } from '@/stores/connection'
// Props // Props - 只保留布局相关的
const props = defineProps<{ const props = defineProps<{
width: number width: number
selectedConnection: any | null
}>() }>()
// 从store获取选中的连接 - 将来可以从pinia获取
// const connectionStore = useConnectionStore()
// const { selectedConnection } = storeToRefs(connectionStore)
// 临时使用ref,将来替换为store
const selectedConnection = ref<any>(null)
// 状态文本映射 // 状态文本映射
const getStatusText = (status: string) => { const getStatusText = (status: string) => {
const statusMap: Record<string, string> = { const statusMap: Record<string, string> = {
@@ -129,11 +138,11 @@ const getStatusText = (status: string) => {
// 流量数据 // 流量数据
const trafficData = computed(() => { const trafficData = computed(() => {
if (!props.selectedConnection) { if (!selectedConnection.value) {
return { upload: '0 B', download: '0 B', total: '0 B' } return { upload: '0 B', download: '0 B', total: '0 B' }
} }
// 模拟数据 // 模拟数据 - 将来可以从store或API获取真实数据
return { return {
upload: '1.2 MB', upload: '1.2 MB',
download: '5.8 MB', download: '5.8 MB',
@@ -143,9 +152,20 @@ const trafficData = computed(() => {
// 图表数据 // 图表数据
const chartData = computed(() => { const chartData = computed(() => {
// 生成模拟的流量图表数据 // 生成模拟的流量图表数据 - 将来可以从store获取真实数据
return Array.from({ length: 20 }, () => Math.random() * 100) return Array.from({ length: 20 }, () => Math.random() * 100)
}) })
// 提供一个方法让外部组件设置选中的连接(过渡期使用)
// 将来可以移除,直接通过store管理
const setSelectedConnection = (connection: any) => {
selectedConnection.value = connection
}
// 暴露方法给父组件(如果需要的话)
defineExpose({
setSelectedConnection
})
</script> </script>
<style scoped> <style scoped>
@@ -11,8 +11,7 @@
<div class="header-actions"> <div class="header-actions">
<div class="search-area"> <div class="search-area">
<n-input <n-input
:value="searchQuery" v-model:value="searchQuery"
@update:value="$emit('update:searchQuery', $event)"
placeholder="搜索连接、域名或IP..." placeholder="搜索连接、域名或IP..."
size="medium" size="medium"
> >
@@ -61,17 +60,13 @@ import { ref, computed, onMounted, watch, onUnmounted, nextTick } from 'vue'
import { NButton, NInput, NIcon } from 'naive-ui' import { NButton, NInput, NIcon } from 'naive-ui'
import { SearchOutline } from '@vicons/ionicons5' import { SearchOutline } from '@vicons/ionicons5'
import EventTimeline from './components/EventTimeline.vue' import EventTimeline from './components/EventTimeline.vue'
import { FlashOutline } from '@vicons/ionicons5'
import { useApplicationStore } from '@/stores/application' import { useApplicationStore } from '@/stores/application'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { ResponseModel, SubscriptionInfo, SubscriptionProcessInfo } from '@/types/response' import { ResponseModel, SubscriptionInfo, SubscriptionProcessInfo } from '@/types/response'
import { httpClient } from '@/utils/http' import { httpClient } from '@/utils/http'
import { useWebSocketStore } from '@/stores/websocketStore' import { useWebSocketStore } from '@/stores/websocketStore'
import { useProcessStore } from '@/stores/processInfo' import { useProcessStore } from '@/stores/processInfo'
import { ApplicationType } from '@/types/infoModel'
import ConnectionsTable1 from '@/views/MonitorView/components/ConnectionsTable1.vue' import ConnectionsTable1 from '@/views/MonitorView/components/ConnectionsTable1.vue'
import ConnectionsTable from '@/views/MonitorView/components/ConnectionsTable.vue'
import UnifiedConnectionsList from '@/views/MonitorView/components/UnifiedConnectionsList.vue'
const webSocketStore = useWebSocketStore() const webSocketStore = useWebSocketStore()
const { isOpen } = storeToRefs(webSocketStore) const { isOpen } = storeToRefs(webSocketStore)
@@ -83,10 +78,15 @@ const processStore = useProcessStore()
const { processInfos } = storeToRefs(processStore) const { processInfos } = storeToRefs(processStore)
processStore.subscribe() processStore.subscribe()
// Props - 只保留必要的布局相关属性
const props = defineProps<{
width?: number // 可选的宽度,如果父组件需要控制
}>()
// 组件引用 // 组件引用
const mainViewRef = ref<HTMLElement>() const mainViewRef = ref<HTMLElement>()
// 布局尺寸控制 // 内部管理的布局尺寸
const headerHeight = ref(80) const headerHeight = ref(80)
const timelineHeight = ref(200) const timelineHeight = ref(200)
const mainViewHeight = ref(600) const mainViewHeight = ref(600)
@@ -106,6 +106,11 @@ const timelineResizing = ref<{
startHeight: 0, startHeight: 0,
}) })
// 内部管理的状态
const searchQuery = ref('')
const isTimelinePaused = ref(false)
const expandedProcesses = ref<number[]>([])
// 计算ConnectionsTable1的可用高度 // 计算ConnectionsTable1的可用高度
const connectionsTableHeight = computed(() => { const connectionsTableHeight = computed(() => {
const totalHeight = mainViewHeight.value const totalHeight = mainViewHeight.value
@@ -113,6 +118,43 @@ const connectionsTableHeight = computed(() => {
return `${Math.max(200, totalHeight - usedHeight)}px` return `${Math.max(200, totalHeight - usedHeight)}px`
}) })
// 过滤后的连接数据
const filteredConnections = computed(() => {
const connections = processInfos.value || []
// 如果有搜索条件,进行过滤
if (searchQuery.value) {
const query = searchQuery.value.toLowerCase()
return connections.filter(process => {
// 搜索进程名
if (process.processName.toLowerCase().includes(query)) {
return true
}
// 搜索连接信息
return process.connections.some(conn =>
conn.localEndpoint.address.includes(query) ||
conn.remoteEndpoint.address.includes(query) ||
conn.localEndpoint.port.toString().includes(query) ||
conn.remoteEndpoint.port.toString().includes(query)
)
})
}
return connections
})
// 模拟事件数据 - 将来可以从pinia获取
const events = computed(() => [
{
id: 1,
time: new Date().toLocaleTimeString(),
type: 'connection',
eventType: '连接建立',
description: 'chrome.exe → google.com:443',
},
// ... 更多事件数据
])
// Timeline拖拽逻辑 // Timeline拖拽逻辑
const startTimelineResize = (event: MouseEvent) => { const startTimelineResize = (event: MouseEvent) => {
event.preventDefault() event.preventDefault()
@@ -157,39 +199,28 @@ const updateMainViewHeight = () => {
} }
} }
// 展开的进程ID列表 // 事件处理函数
const expandedProcesses = ref<number[]>([]) const handleFilter = () => {
console.log('打开过滤器')
}
// 过滤后的连接数据 const handleRefresh = () => {
const filteredConnections = computed(() => { console.log('刷新数据')
const connections = processInfos.value || [] processStore.refresh?.()
}
// 如果有搜索条件,进行过滤 const handleClearEvents = () => {
if (props.searchQuery) { console.log('清空事件')
const query = props.searchQuery.toLowerCase() }
return connections.filter(process => {
// 搜索进程名
if (process.processName.toLowerCase().includes(query)) {
return true
}
// 搜索连接信息
return process.connections.some(conn =>
conn.localEndpoint.address.includes(query) ||
conn.remoteEndpoint.address.includes(query) ||
conn.localEndpoint.port.toString().includes(query) ||
conn.remoteEndpoint.port.toString().includes(query)
)
})
}
return connections
})
// 监听选中应用的变化
watch(selectedApp, (newVal, oldVal) => { watch(selectedApp, (newVal, oldVal) => {
// 进行更新,先把原始数据清空 // 进行更新,先把原始数据清空
processStore.clear() processStore.clear()
// 重置展开状态 // 重置展开状态
expandedProcesses.value = [] expandedProcesses.value = []
// 清空搜索
searchQuery.value = ''
console.log(newVal.id, '==========') console.log(newVal.id, '==========')
}) })
@@ -208,7 +239,6 @@ onMounted(() => {
[isOpen, selectedApp], [isOpen, selectedApp],
([newValue, newValue1]) => { ([newValue, newValue1]) => {
if (newValue && newValue1 && newValue1.processIds && newValue1.processIds.length > 0) { if (newValue && newValue1 && newValue1.processIds && newValue1.processIds.length > 0) {
// ApplicationType
// 发送请求【请求订阅软件列表】 // 发送请求【请求订阅软件列表】
const subAppInfo: SubscriptionProcessInfo = { const subAppInfo: SubscriptionProcessInfo = {
subscriptionType: 'ProcessInfo', subscriptionType: 'ProcessInfo',
@@ -251,40 +281,6 @@ onUnmounted(() => {
console.error('取消订阅进程信息失败:', err) console.error('取消订阅进程信息失败:', err)
}) })
}) })
// Props - 移除不再需要的height相关props
const props = defineProps<{
searchQuery: string
connections: Array<unknown>
events: Array<unknown>
}>()
// Emits - 移除resize相关emit
const emit = defineEmits<{
'update:searchQuery': [value: string]
selectConnection: [connection: unknown]
}>()
// Local state
const isMonitoring = ref(true)
const isTimelinePaused = ref(false)
// 处理过滤
const handleFilter = () => {
console.log('打开过滤器')
}
// 处理刷新
const handleRefresh = () => {
console.log('刷新数据')
// 可以在这里触发数据重新加载
processStore.refresh?.()
}
// 清空事件
const handleClearEvents = () => {
console.log('清空事件')
}
</script> </script>
<style scoped> <style scoped>
@@ -392,7 +388,6 @@ const handleClearEvents = () => {
} }
/* 响应式设计 */ /* 响应式设计 */
/* 中等屏幕:隐藏标题和副标题 */
@media (max-width: 1200px) { @media (max-width: 1200px) {
.header-info { .header-info {
display: none; display: none;
@@ -407,7 +402,6 @@ const handleClearEvents = () => {
} }
} }
/* 小屏幕:搜索框开始使用弹性布局 */
@media (max-width: 900px) { @media (max-width: 900px) {
.main-header { .main-header {
padding: 0 16px; padding: 0 16px;
@@ -432,7 +426,6 @@ const handleClearEvents = () => {
} }
} }
/* 超小屏幕:进一步优化 */
@media (max-width: 600px) { @media (max-width: 600px) {
.main-header { .main-header {
padding: 0 12px; padding: 0 12px;
@@ -458,7 +451,6 @@ const handleClearEvents = () => {
} }
} }
/* 超窄屏幕:只保留搜索框 */
@media (max-width: 480px) { @media (max-width: 480px) {
.filter-buttons { .filter-buttons {
display: none; display: none;
@@ -14,16 +14,7 @@
<!-- 中间主视图区域 --> <!-- 中间主视图区域 -->
<div class="main-panel-wrapper"> <div class="main-panel-wrapper">
<MonitorMainPanel <MonitorMainPanel :width="mainPanelWidth" />
:headerHeight="mainHeaderHeight"
:timelineHeight="timelineHeight"
:searchQuery="searchQuery"
:connections="mockConnections"
:events="mockEvents"
@update:searchQuery="searchQuery = $event"
@resizeTimeline="startResize('timeline', $event)"
@selectConnection="handleConnectionSelect"
/>
</div> </div>
<!-- 右侧分割线 --> <!-- 右侧分割线 -->
@@ -33,10 +24,7 @@
<!-- 右侧检查器面板 --> <!-- 右侧检查器面板 -->
<div class="inspector-wrapper" :style="{ width: inspectorWidth + 'px' }"> <div class="inspector-wrapper" :style="{ width: inspectorWidth + 'px' }">
<MonitorInspector <MonitorInspector :width="inspectorWidth" />
:width="inspectorWidth"
:selectedConnection="selectedConnection"
/>
</div> </div>
</div> </div>
</div> </div>
@@ -47,7 +35,7 @@ defineOptions({
name: 'MonitorView', name: 'MonitorView',
}) })
import { ref, onMounted, onUnmounted, provide } from 'vue' import { ref, computed, onMounted, onUnmounted } from 'vue'
import MonitorSidebar from './MonitorSidebar.vue' import MonitorSidebar from './MonitorSidebar.vue'
import MonitorMainPanel from './MonitorMainPanel.vue' import MonitorMainPanel from './MonitorMainPanel.vue'
import MonitorInspector from './MonitorInspector.vue' import MonitorInspector from './MonitorInspector.vue'
@@ -55,83 +43,43 @@ import MonitorInspector from './MonitorInspector.vue'
// 布局尺寸控制 // 布局尺寸控制
const sidebarWidth = ref(400) const sidebarWidth = ref(400)
const inspectorWidth = ref(350) const inspectorWidth = ref(350)
const timelineHeight = ref(200)
const mainHeaderHeight = ref(80)
// 调整分割条范围限制 // 调整分割条范围限制
const MIN_SIDEBAR_WIDTH = 200 const MIN_SIDEBAR_WIDTH = 200
const MAX_SIDEBAR_WIDTH = 600 const MAX_SIDEBAR_WIDTH = 600
const MIN_INSPECTOR_WIDTH = 250 const MIN_INSPECTOR_WIDTH = 250
const MAX_INSPECTOR_WIDTH = 650 const MAX_INSPECTOR_WIDTH = 650
const MIN_TIMELINE_HEIGHT = 100
const MAX_TIMELINE_HEIGHT = 800
// 响应式数据 // 计算主面板的可用宽度
const searchQuery = ref('') const mainPanelWidth = computed(() => {
const selectedConnection = ref<any>(null) // 这里可以根据需要计算,如果不需要传递具体宽度,可以移除这个computed
return window.innerWidth - sidebarWidth.value - inspectorWidth.value - 8 // 8px为分割线宽度
const mockConnections = ref([
{
id: 1,
process: 'chrome.exe',
localAddress: '192.168.1.100',
remoteAddress: 'google.com',
status: 'established',
traffic: '542 KB/s',
},
// ... 更多连接数据
])
const mockEvents = ref([
{
id: 1,
time: new Date().toLocaleTimeString(),
type: 'connection',
eventType: '连接建立',
description: 'chrome.exe → google.com:443',
},
// ... 更多事件数据
])
// 提供布局配置给子组件
provide('layoutConfig', {
sidebarWidth,
inspectorWidth,
timelineHeight,
mainHeaderHeight,
}) })
// 拖拽状态 // 拖拽状态
const resizing = ref<{ const resizing = ref<{
type: 'sidebar' | 'inspector' | 'timeline' | null type: 'sidebar' | 'inspector' | null
startX: number startX: number
startY: number
startWidth: number startWidth: number
startHeight: number
}>({ }>({
type: null, type: null,
startX: 0, startX: 0,
startY: 0,
startWidth: 0, startWidth: 0,
startHeight: 0,
}) })
// 开始拖拽 // 开始拖拽
const startResize = (type: 'sidebar' | 'inspector' | 'timeline', event: MouseEvent) => { const startResize = (type: 'sidebar' | 'inspector', event: MouseEvent) => {
event.preventDefault() event.preventDefault()
resizing.value = { resizing.value = {
type, type,
startX: event.clientX, startX: event.clientX,
startY: event.clientY, startWidth: type === 'sidebar' ? sidebarWidth.value : inspectorWidth.value,
startWidth:
type === 'sidebar' ? sidebarWidth.value : type === 'inspector' ? inspectorWidth.value : 0,
startHeight: type === 'timeline' ? timelineHeight.value : 0,
} }
document.addEventListener('mousemove', handleResize) document.addEventListener('mousemove', handleResize)
document.addEventListener('mouseup', stopResize) document.addEventListener('mouseup', stopResize)
document.body.style.cursor = type === 'timeline' ? 'row-resize' : 'col-resize' document.body.style.cursor = 'col-resize'
document.body.style.userSelect = 'none' document.body.style.userSelect = 'none'
} }
@@ -139,7 +87,7 @@ const startResize = (type: 'sidebar' | 'inspector' | 'timeline', event: MouseEve
const handleResize = (event: MouseEvent) => { const handleResize = (event: MouseEvent) => {
if (!resizing.value.type) return if (!resizing.value.type) return
const { type, startX, startY, startWidth, startHeight } = resizing.value const { type, startX, startWidth } = resizing.value
if (type === 'sidebar') { if (type === 'sidebar') {
const deltaX = event.clientX - startX const deltaX = event.clientX - startX
@@ -152,13 +100,6 @@ const handleResize = (event: MouseEvent) => {
Math.max(MIN_INSPECTOR_WIDTH, startWidth + deltaX), Math.max(MIN_INSPECTOR_WIDTH, startWidth + deltaX),
) )
inspectorWidth.value = newWidth inspectorWidth.value = newWidth
} else if (type === 'timeline') {
const deltaY = startY - event.clientY
const newHeight = Math.min(
MAX_TIMELINE_HEIGHT,
Math.max(MIN_TIMELINE_HEIGHT, startHeight + deltaY),
)
timelineHeight.value = newHeight
} }
} }
@@ -171,16 +112,10 @@ const stopResize = () => {
document.body.style.userSelect = '' document.body.style.userSelect = ''
} }
// 处理连接选中
const handleConnectionSelect = (connection: any) => {
selectedConnection.value = connection
}
// 重置布局 // 重置布局
const resetLayout = () => { const resetLayout = () => {
sidebarWidth.value = 400 sidebarWidth.value = 400
inspectorWidth.value = 350 inspectorWidth.value = 350
timelineHeight.value = 200
} }
// 键盘快捷键 // 键盘快捷键