频道筛选框从 topbar 移至聊天卡片内,ChatPanel v-model:channelFilter 双向绑定
This commit is contained in:
@@ -757,20 +757,6 @@ onBeforeUnmount(() => {
|
|||||||
@click="nodeFilter = ''"
|
@click="nodeFilter = ''"
|
||||||
>清除</button>
|
>清除</button>
|
||||||
</div>
|
</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="/signed">签到列表</a>
|
||||||
<a class="topbar-link" href="/help">使用帮助</a>
|
<a class="topbar-link" href="/help">使用帮助</a>
|
||||||
<a class="topbar-link" href="/admin">管理</a>
|
<a class="topbar-link" href="/admin">管理</a>
|
||||||
@@ -824,6 +810,7 @@ onBeforeUnmount(() => {
|
|||||||
|
|
||||||
<section class="workspace">
|
<section class="workspace">
|
||||||
<ChatPanel
|
<ChatPanel
|
||||||
|
v-model:channelFilter="channelFilter"
|
||||||
:messages="filteredMessages"
|
:messages="filteredMessages"
|
||||||
:nodes-by-id="nodesById"
|
:nodes-by-id="nodesById"
|
||||||
:selected-node-id="selectedNodeId"
|
:selected-node-id="selectedNodeId"
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ const props = defineProps<{
|
|||||||
loadingOlder: boolean
|
loadingOlder: boolean
|
||||||
hasMoreMessages: boolean
|
hasMoreMessages: boolean
|
||||||
isAdmin: boolean
|
isAdmin: boolean
|
||||||
|
channelFilter: string
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
type GroupedTextMessage = TextMessage & { mergedCount: number; mergedMessages: TextMessage[] }
|
type GroupedTextMessage = TextMessage & { mergedCount: number; mergedMessages: TextMessage[] }
|
||||||
@@ -18,6 +19,7 @@ const emit = defineEmits<{
|
|||||||
'load-older': []
|
'load-older': []
|
||||||
'delete-message': [message: GroupedTextMessage]
|
'delete-message': [message: GroupedTextMessage]
|
||||||
'delete-and-block-node': [payload: { nodeId: string; nodeNum: number | null; message: GroupedTextMessage }]
|
'delete-and-block-node': [payload: { nodeId: string; nodeNum: number | null; message: GroupedTextMessage }]
|
||||||
|
'update:channelFilter': [value: string]
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const panelRef = ref<HTMLElement | null>(null)
|
const panelRef = ref<HTMLElement | null>(null)
|
||||||
@@ -192,6 +194,22 @@ onUpdated(() => {
|
|||||||
<span class="badge">{{ groupedMessages.length }}</span>
|
<span class="badge">{{ groupedMessages.length }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="chat-filter">
|
||||||
|
<input
|
||||||
|
type="search"
|
||||||
|
class="chat-filter-input"
|
||||||
|
:value="channelFilter"
|
||||||
|
placeholder="筛选频道"
|
||||||
|
@input="emit('update:channelFilter', ($event.target as HTMLInputElement).value)"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
v-if="channelFilter.trim()"
|
||||||
|
type="button"
|
||||||
|
class="chat-filter-clear"
|
||||||
|
@click="emit('update:channelFilter', '')"
|
||||||
|
>清除</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div v-if="loadingOlder" class="chat-loading">正在加载更早消息...</div>
|
<div v-if="loadingOlder" class="chat-loading">正在加载更早消息...</div>
|
||||||
<div v-else-if="!hasMoreMessages && messages.length > 0" class="chat-end">没有更多历史消息</div>
|
<div v-else-if="!hasMoreMessages && messages.length > 0" class="chat-end">没有更多历史消息</div>
|
||||||
<div v-if="messages.length === 0" class="empty">暂无聊天消息</div>
|
<div v-if="messages.length === 0" class="empty">暂无聊天消息</div>
|
||||||
|
|||||||
@@ -358,6 +358,53 @@ h3 {
|
|||||||
background: var(--color-primary-soft);
|
background: var(--color-primary-soft);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chat-filter {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
background: var(--color-surface-soft);
|
||||||
|
position: sticky;
|
||||||
|
z-index: 9;
|
||||||
|
top: 53px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-filter-input {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
border: 1px solid var(--color-border-strong);
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
padding: 6px 10px;
|
||||||
|
color: var(--color-heading);
|
||||||
|
background: var(--color-surface);
|
||||||
|
outline: none;
|
||||||
|
font-size: 13px;
|
||||||
|
transition: border-color 0.16s ease, box-shadow 0.16s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-filter-input:focus {
|
||||||
|
border-color: var(--color-primary);
|
||||||
|
box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-primary) 20%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-filter-clear {
|
||||||
|
flex-shrink: 0;
|
||||||
|
border: 1px solid var(--color-border-strong);
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
padding: 5px 10px;
|
||||||
|
color: var(--color-heading);
|
||||||
|
background: var(--color-surface);
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-filter-clear:hover {
|
||||||
|
border-color: var(--color-primary);
|
||||||
|
color: var(--color-primary-hover);
|
||||||
|
background: var(--color-primary-soft);
|
||||||
|
}
|
||||||
|
|
||||||
.chat-item {
|
.chat-item {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
|
|||||||
Reference in New Issue
Block a user