feat: 优化过滤主题功能,支持下拉选择
This commit is contained in:
@@ -1,14 +1,14 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import { useMqttStore } from '../stores/mqtt.js';
|
import { useMqttStore } from '../stores/mqtt.js';
|
||||||
import { NCard, NSpace, NInput, NButton, NEmpty, useMessage } from 'naive-ui';
|
import { NCard, NSelect, NButton, NEmpty, useMessage } from 'naive-ui';
|
||||||
|
|
||||||
// 全局状态与消息 API
|
// 全局状态与消息 API
|
||||||
const store = useMqttStore();
|
const store = useMqttStore();
|
||||||
const message = useMessage();
|
const message = useMessage();
|
||||||
|
|
||||||
// 主题过滤关键字
|
// 已选中的过滤主题列表
|
||||||
const filter = ref('');
|
const filter = ref([]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 复制主题到剪贴板
|
* 复制主题到剪贴板
|
||||||
@@ -24,22 +24,65 @@ async function copyTopic(topic) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据过滤关键字筛选后的消息列表
|
* 可过滤的主题选项(来自已配置主题和已接收消息)
|
||||||
|
* @type {import('vue').ComputedRef<Array<{label: string, value: string}>>}
|
||||||
|
*/
|
||||||
|
const topicOptions = computed(() => {
|
||||||
|
|
||||||
|
let server = store.activeServer.value;
|
||||||
|
let serverTopics = server?.topics?.map((t) => t.topic) || [];
|
||||||
|
let messageTopics = store.messages.value.map((m) => m.topic);
|
||||||
|
let all = [...new Set([...serverTopics, ...messageTopics])];
|
||||||
|
|
||||||
|
all.sort((a, b) => a.localeCompare(b));
|
||||||
|
|
||||||
|
return all.map((topic) => ({ label: topic, value: topic }));
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断消息主题是否匹配指定的过滤主题(支持 + 单层通配符与 # 多层通配符)
|
||||||
|
* @param {string} filterTopic - 过滤主题,可包含 + 或 #
|
||||||
|
* @param {string} messageTopic - 消息主题
|
||||||
|
* @returns {boolean} 是否匹配
|
||||||
|
*/
|
||||||
|
function topicMatchesFilter(filterTopic, messageTopic) {
|
||||||
|
|
||||||
|
if (filterTopic === '#') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filterTopic.endsWith('/#')) {
|
||||||
|
let prefix = filterTopic.slice(0, -2);
|
||||||
|
return messageTopic === prefix || messageTopic.startsWith(prefix + '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
let filterParts = filterTopic.split('/');
|
||||||
|
let messageParts = messageTopic.split('/');
|
||||||
|
|
||||||
|
if (filterParts.length !== messageParts.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return filterParts.every((part, index) => part === '+' || part === messageParts[index]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据选中主题筛选后的消息列表(支持 + / # 通配符)
|
||||||
* @type {import('vue').ComputedRef<Array<Object>>}
|
* @type {import('vue').ComputedRef<Array<Object>>}
|
||||||
*/
|
*/
|
||||||
const filteredMessages = computed(() => {
|
const filteredMessages = computed(() => {
|
||||||
|
|
||||||
if (!filter.value.trim()) {
|
if (!filter.value || filter.value.length === 0) {
|
||||||
return store.messages.value;
|
return store.messages.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
let f = filter.value.trim().toLowerCase();
|
return store.messages.value.filter((m) =>
|
||||||
|
filter.value.some((f) => topicMatchesFilter(f, m.topic))
|
||||||
|
);
|
||||||
|
|
||||||
return store.messages.value.filter((m) => {
|
});
|
||||||
return m.topic.toLowerCase().includes(f);
|
|
||||||
});
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 清空当前活动服务器的消息列表
|
* 清空当前活动服务器的消息列表
|
||||||
@@ -79,10 +122,8 @@ function formatPayload(payload) {
|
|||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<n-space
|
<div
|
||||||
align="center"
|
style="display: flex; flex-direction: column; gap: 8px; width: 100%"
|
||||||
justify="space-between"
|
|
||||||
style="width: 100%"
|
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<span>消息监控</span>
|
<span>消息监控</span>
|
||||||
@@ -90,20 +131,26 @@ function formatPayload(payload) {
|
|||||||
style="font-size: 12px; opacity: 0.55; margin-left: 8px"
|
style="font-size: 12px; opacity: 0.55; margin-left: 8px"
|
||||||
>实时查看接收和发送的 MQTT 消息</span>
|
>实时查看接收和发送的 MQTT 消息</span>
|
||||||
</div>
|
</div>
|
||||||
<n-space>
|
<div
|
||||||
<n-input
|
style="display: flex; align-items: center; gap: 8px; width: 100%"
|
||||||
|
>
|
||||||
|
<n-select
|
||||||
v-model:value="filter"
|
v-model:value="filter"
|
||||||
size="small"
|
size="small"
|
||||||
placeholder="过滤主题..."
|
placeholder="过滤主题..."
|
||||||
style="width: 180px"
|
style="flex: 1 1 auto; max-width: 480px; min-width: 0"
|
||||||
|
multiple
|
||||||
|
filterable
|
||||||
clearable
|
clearable
|
||||||
|
max-tag-count="responsive"
|
||||||
|
:options="topicOptions"
|
||||||
/>
|
/>
|
||||||
<n-button
|
<n-button
|
||||||
size="small"
|
size="small"
|
||||||
@click="handleClear"
|
@click="handleClear"
|
||||||
>清空消息</n-button>
|
>清空消息</n-button>
|
||||||
</n-space>
|
</div>
|
||||||
</n-space>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<n-empty
|
<n-empty
|
||||||
v-if="filteredMessages.length === 0"
|
v-if="filteredMessages.length === 0"
|
||||||
|
|||||||
Reference in New Issue
Block a user