频道筛选:text_message 表增加 (channel_id, created_at) 复合索引,主页增加频道筛选输入框,服务端筛选+防抖重载,版本号 backend 1.1.0 / frontend 0.2.0

This commit is contained in:
2026-08-07 19:10:49 +08:00
parent 1c9f94dcf8
commit d919ea2c53
4 changed files with 41 additions and 9 deletions
+3 -3
View File
@@ -439,7 +439,7 @@ type TextMessageRecord struct {
Text *string `gorm:"column:text"`
PayloadHex *string `gorm:"column:payload_hex"`
Topic string `gorm:"column:topic;not null"`
ChannelID *string `gorm:"column:channel_id"`
ChannelID *string `gorm:"column:channel_id;index:idx_text_message_channel_id_created_at,priority:1"`
GatewayID *string `gorm:"column:gateway_id"`
PacketID *int64 `gorm:"column:packet_id;index:idx_text_message_packet_id"`
PacketTo *string `gorm:"column:packet_to"`
@@ -458,7 +458,7 @@ type TextMessageRecord struct {
MQTTRemoteHost *string `gorm:"column:mqtt_remote_host"`
MQTTRemotePort *string `gorm:"column:mqtt_remote_port"`
ContentJSON string `gorm:"column:content_json;not null"`
CreatedAt time.Time `gorm:"column:created_at;autoCreateTime;index:idx_text_message_from_num_created_at,priority:2;index:idx_text_message_created_at"`
CreatedAt time.Time `gorm:"column:created_at;autoCreateTime;index:idx_text_message_from_num_created_at,priority:2;index:idx_text_message_created_at;index:idx_text_message_channel_id_created_at,priority:2"`
}
func (TextMessageRecord) TableName() string {
@@ -707,7 +707,7 @@ func (s *Store) migrate() error {
model any
indexes []string
}{
{label: "text_message", model: &TextMessageRecord{}, indexes: []string{"idx_text_message_from_num_created_at", "idx_text_message_created_at", "idx_text_message_packet_id"}},
{label: "text_message", model: &TextMessageRecord{}, indexes: []string{"idx_text_message_from_num_created_at", "idx_text_message_created_at", "idx_text_message_packet_id", "idx_text_message_channel_id_created_at"}},
{label: "bot_direct_messages", model: &BotDirectMessageRecord{}, indexes: []string{"idx_bot_dm_bot_peer", "idx_bot_dm_bot_created_at"}},
{label: "llm_message_queue", model: &LLMMessageQueueRecord{}, indexes: []string{"idx_llm_queue_bot_created"}},
} {
+1 -1
View File
@@ -84,7 +84,7 @@ func NewRouter(cfg configpkg.WebConfig, consoleLog bool, store *storepkg.Store,
return r
}
const BackendVersion = "1.0.0"
const BackendVersion = "1.1.0"
var CommitVersion = "dev"
+36 -4
View File
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { adminLogout, createNodeBlockingRule, deleteNode, deleteTextMessage, getAdminMe, getHealth, getMapReportViewport, getNodeInfo, getPositions, getTextMessages, purgeNode } from './api'
import AdminBlockingManagement from './components/AdminBlockingManagement.vue'
import AdminBot from './components/AdminBot.vue'
@@ -69,6 +69,7 @@ const mapReportTotal = ref(0)
const mapSources = ref<PublicMapTileSource[]>([fallbackMapSource])
const mapSource = ref<PublicMapTileSource>(fallbackMapSource)
const nodeFilter = ref('')
const channelFilter = ref('')
const pendingDeleteAction = ref<PendingDeleteAction | null>(null)
type DeletableTextMessage = TextMessage & { mergedCount?: number; mergedMessages?: TextMessage[] }
type NodeActionRequest = { nodeId: string; nodeNum: number | null; message?: DeletableTextMessage }
@@ -95,6 +96,7 @@ const nodesById = computed<NodeInfoById>(() => {
})
const normalizedNodeFilter = computed(() => nodeFilter.value.trim().toLowerCase())
const normalizedChannelFilter = computed(() => channelFilter.value.trim())
function nodeMatchesFilterByInfo(node: NodeInfo | null | undefined, keyword: string): boolean {
if (!keyword) {
@@ -298,7 +300,7 @@ function clearSelectedNode() {
}
async function loadInitialChatMessages() {
const response = await getTextMessages(chatPageSize, 0)
const response = await getTextMessages(chatPageSize, 0, normalizedChannelFilter.value ? { channelId: normalizedChannelFilter.value } : '')
messages.value = toChronological(response.items)
chatHasMore.value = response.items.length === chatPageSize
chatInitialized.value = true
@@ -311,7 +313,7 @@ async function loadOlderMessages() {
chatLoadingOlder.value = true
try {
const response = await getTextMessages(chatPageSize, messages.value.length)
const response = await getTextMessages(chatPageSize, messages.value.length, normalizedChannelFilter.value ? { channelId: normalizedChannelFilter.value } : '')
messages.value = mergeMessages(messages.value, toChronological(response.items))
chatHasMore.value = response.items.length === chatPageSize
} catch (err) {
@@ -322,10 +324,23 @@ async function loadOlderMessages() {
}
async function pollLatestMessages() {
const response = await getTextMessages(chatPageSize, 0)
const response = await getTextMessages(chatPageSize, 0, normalizedChannelFilter.value ? { channelId: normalizedChannelFilter.value } : '')
messages.value = mergeMessages(messages.value, toChronological(response.items))
}
let channelFilterTimer: number | undefined
watch(normalizedChannelFilter, () => {
if (channelFilterTimer !== undefined) {
window.clearTimeout(channelFilterTimer)
}
channelFilterTimer = window.setTimeout(() => {
messages.value = []
chatHasMore.value = true
chatInitialized.value = false
loadInitialChatMessages()
}, 400)
})
async function loadNodePage(page: number, showLoading = true) {
if (showLoading) {
nodePageLoading.value = true
@@ -676,6 +691,9 @@ onBeforeUnmount(() => {
if (mapBoundsTimer !== undefined) {
window.clearTimeout(mapBoundsTimer)
}
if (channelFilterTimer !== undefined) {
window.clearTimeout(channelFilterTimer)
}
})
</script>
@@ -739,6 +757,20 @@ onBeforeUnmount(() => {
@click="nodeFilter = ''"
>清除</button>
</div>
<div class="topbar-filter">
<input
type="search"
class="topbar-filter-input"
v-model="channelFilter"
placeholder="筛选频道"
/>
<button
v-if="normalizedChannelFilter"
type="button"
class="topbar-filter-clear"
@click="channelFilter = ''"
>清除</button>
</div>
<a class="topbar-link" href="/signed">签到列表</a>
<a class="topbar-link" href="/help">使用帮助</a>
<a class="topbar-link" href="/admin">管理</a>
+1 -1
View File
@@ -1 +1 @@
export const FRONTEND_VERSION = '0.1.2'
export const FRONTEND_VERSION = '0.2.0'