1919 <el-button type =" danger" @click =" handleClear" :icon =" Delete" >
2020 清空报文
2121 </el-button >
22+ <el-select v-model =" searchMode" class =" search-mode-select" >
23+ <el-option label =" 按描述" value =" description" />
24+ <el-option label =" 按报文" value =" hex_data" />
25+ </el-select >
26+ <el-input
27+ v-model =" searchKeyword"
28+ :placeholder =" searchMode === 'description' ? '搜索描述...' : '搜索报文...'"
29+ :prefix-icon =" Search"
30+ clearable
31+ class =" search-input"
32+ />
2233 </div >
2334 <div class =" right-info" >
24- <span class =" msg-count" >共 {{ messages.length }} 条报文</span >
35+ <span class =" msg-count" >
36+ 共 {{ filteredMessages.length }} / {{ messages.length }} 条报文
37+ </span >
2538 <el-tag v-if =" avgStats && avgStats.pair_count > 0" type =" warning" size =" small" >
2639 平均延时: {{ avgStats.avg_latency_ms }} ms ({{ avgStats.pair_count }} 对)
2740 </el-tag >
3144 </div >
3245
3346 <el-table
34- :data =" messages "
47+ :data =" filteredMessages "
3548 stripe
3649 height =" 400"
3750 class =" message-table"
7184<script lang="ts" setup>
7285import { ref , watch , onUnmounted , computed } from ' vue' ;
7386import { getMessages , clearMessages , getAvgTime , type MessageRecord , type AvgTimeStats } from ' @/api/deviceApi' ;
74- import { CaretRight , VideoPause , Delete } from ' @element-plus/icons-vue' ;
87+ import { CaretRight , VideoPause , Delete , Search } from ' @element-plus/icons-vue' ;
7588import { ElMessage , ElMessageBox } from ' element-plus' ;
7689
7790const props = defineProps <{
@@ -91,6 +104,17 @@ const visible = computed({
91104const messages = ref <MessageRecord []>([]);
92105const avgStats = ref <AvgTimeStats | null >(null );
93106const autoRefresh = ref (true );
107+ const searchKeyword = ref (' ' );
108+ const searchMode = ref <' description' | ' hex_data' >(' description' );
109+
110+ const filteredMessages = computed (() => {
111+ const keyword = searchKeyword .value .trim ().toLowerCase ();
112+ if (! keyword ) return messages .value ;
113+ return messages .value .filter (msg => {
114+ const field = searchMode .value === ' description' ? msg .description : msg .hex_data ;
115+ return field ?.toLowerCase ().includes (keyword );
116+ });
117+ });
94118let refreshTimer: ReturnType <typeof setInterval > | null = null ;
95119
96120const fetchMessages = async () => {
@@ -188,6 +212,15 @@ onUnmounted(() => {
188212 .left-actions {
189213 display : flex ;
190214 gap : 8px ;
215+ align-items : center ;
216+
217+ .search-mode-select {
218+ width : 100px ;
219+ }
220+
221+ .search-input {
222+ width : 200px ;
223+ }
191224 }
192225
193226 .right-info {
0 commit comments