Переглянути джерело

修复聊天列表页的操作提示可见性

LSamien 1 місяць тому
батько
коміт
8a91eaf66d

+ 7 - 2
src/client/views/ConversationsView.vue

@@ -79,7 +79,7 @@ const searchItems = computed<SidebarItem[]>(() => [false, true].map(archived =>
   return { id: archived ? 'archived' : 'unarchived', title: archived ? '已归档' : '未归档', children: items, emptyText: archived ? '没有已归档聊天' : '没有未归档聊天' }
 }))
 const archivedIds = computed(() => new Set(conversations.value.filter(c => c.archived).map(c => c.id)))
-const lifecycleId = ref(''), searchActionError = ref(''), lifecycleAction = ref<WorkspaceLifecycleAction>()
+const lifecycleId = ref(''), searchActionError = ref(''), lifecycleError = ref(''), lifecycleAction = ref<WorkspaceLifecycleAction>()
 const composer = ref<InstanceType<typeof ComposerShell>>()
 const timeline = ref<InstanceType<typeof MessageTimeline>>()
 const quoted = ref<UiMessage | null>(null)
@@ -552,7 +552,7 @@ async function action(operation: 'pin' | 'archive', id = active.value?.id) {
 async function changeLifecycle(operation: WorkspaceLifecycleAction, id: string, fromSearch = false) {
   const conversation = conversations.value.find(c => c.id === id)
   if (!conversation || lifecycleId.value) return
-  const actionError = fromSearch ? searchActionError : error
+  const actionError = fromSearch ? searchActionError : lifecycleError
   actionError.value = ''
   lifecycleId.value = id
   lifecycleAction.value = operation
@@ -746,6 +746,7 @@ onBeforeUnmount(() => {
       </template>
       <template #footer><p v-if="searchActionError" class="search-delete-error" role="alert">{{ searchActionError }}</p></template>
     </FloatingResourceSearch>
+    <Teleport to="body"><div v-if="lifecycleError" class="lifecycle-error" role="alert"><span>{{ lifecycleError }}</span><button type="button" aria-label="关闭聊天操作提示" @click="lifecycleError = ''"><AppIcon name="close" :size="16" /></button></div></Teleport>
     <PreviewModal v-if="preview" :item="preview" :items="media" @close="preview = null" />
     <ImagePreviewLightbox v-model="mediaIndex" :images="lightboxMedia" />
     <RemoteAgentPicker v-if="remotePickerOpen && !auth.isBotOnly" @close="remotePickerOpen = false" @added="remoteAdded" />
@@ -959,4 +960,8 @@ onBeforeUnmount(() => {
 .search-restore:hover:not(:disabled){background:var(--surface-hover)}
 .search-restore:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
 .search-restore:disabled{opacity:.5;cursor:wait}
+.lifecycle-error{position:fixed;z-index:220;left:50%;bottom:max(24px,env(safe-area-inset-bottom));transform:translateX(-50%);display:flex;align-items:flex-start;gap:12px;width:max-content;max-width:min(520px,calc(100vw - 32px));padding:14px 16px;border:1px solid var(--line);border-radius:12px;background:var(--surface-raised);box-shadow:var(--shadow-float);color:var(--danger);font-size:13px;line-height:1.6}
+.lifecycle-error button{display:grid;place-items:center;flex:0 0 28px;width:28px;height:28px;border:0;border-radius:6px;background:transparent;color:var(--text-secondary);cursor:pointer}
+.lifecycle-error button:hover{background:var(--surface-hover)}
+.lifecycle-error button:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
 </style>

+ 12 - 0
tests/client/conversationSearchDelete.test.ts

@@ -110,4 +110,16 @@ describe('archived chat deletion from search', () => {
     expect(document.querySelector('[role="dialog"] [role="alert"]')?.textContent).toContain('「管理群」的管理者,请先转交管理权')
     expect(vi.mocked(apiRequest).mock.calls.some(([, options]) => options?.method === 'POST')).toBe(false)
   })
+  it('shows menu failures outside the chat pane so the list-only layout can display them', async () => {
+    await setup('direct', async () => {}, [{ id: 'group', name: '管理群', administrator: true }], false)
+    document.querySelector<HTMLButtonElement>('[aria-label="关闭搜索"]')!.click()
+    wrapper!.findComponent({ name: 'ConversationList' }).vm.$emit('archive', 'archived')
+    await flushPromises()
+    const alert = document.querySelector('.lifecycle-error')!
+    expect(alert.textContent).toContain('请先转交管理权')
+    expect(alert.parentElement).toBe(document.body)
+    document.querySelector<HTMLButtonElement>('[aria-label="关闭聊天操作提示"]')!.click()
+    await flushPromises()
+    expect(document.querySelector('.lifecycle-error')).toBeNull()
+  })
 })