feat(feedback): 新增用户反馈提交、分页列表与语音描述
支持 Bug/需求提交、截图与聊天同款语音输入,全站反馈分页浏览与详情页,并从聊天与空间页提供入口。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+28
-35
@@ -4,7 +4,6 @@ import { INSUFFICIENT_BALANCE_NOTICE } from '../hooks/useTKMindChat';
|
||||
import type { CapabilityMap, PortalUser } from '../types';
|
||||
import { useNetworkStatus } from '../hooks/useNetworkStatus';
|
||||
import { getSessionDisplayName } from '../utils/sessions';
|
||||
import { openAvatarPicker } from '../utils/userAvatar';
|
||||
import { BalanceRing } from './BalanceRing';
|
||||
import { HistorySidebar } from './HistorySidebar';
|
||||
import { TKMindAvatar } from './TKMindAvatar';
|
||||
@@ -23,6 +22,7 @@ export function ChatView({
|
||||
onOpenSpace,
|
||||
onOpenPage,
|
||||
onOpenAdmin,
|
||||
onOpenFeedback,
|
||||
}: {
|
||||
user?: PortalUser | null;
|
||||
capabilities?: CapabilityMap;
|
||||
@@ -32,25 +32,32 @@ export function ChatView({
|
||||
onOpenSpace?: (target?: { categoryCode?: MindSpaceSaveCategory; pageId?: string }) => void;
|
||||
onOpenPage?: (pageId: string) => void;
|
||||
onOpenAdmin?: () => void;
|
||||
onOpenFeedback?: () => void;
|
||||
}) {
|
||||
const {
|
||||
session,
|
||||
sessions,
|
||||
sessionsLoading,
|
||||
sessionsLoadingMore,
|
||||
sessionsHasMore,
|
||||
sessionSearchQuery,
|
||||
messages,
|
||||
messageHistoryLoadingMore,
|
||||
messageHistoryHasMore,
|
||||
messageHistoryTotal,
|
||||
chatState,
|
||||
error,
|
||||
notice,
|
||||
pendingTool,
|
||||
memoryLoading,
|
||||
submit,
|
||||
stop,
|
||||
approveTool,
|
||||
newSession,
|
||||
rememberCurrentContext,
|
||||
refreshProjectMemory,
|
||||
switchSession,
|
||||
deleteSession,
|
||||
loadMoreSessions,
|
||||
loadOlderMessages,
|
||||
setSessionSearchQuery,
|
||||
retryConnect,
|
||||
dismissNotice,
|
||||
onSidebarOpen,
|
||||
@@ -71,7 +78,6 @@ export function ChatView({
|
||||
}
|
||||
}, [sidebarOpen, onSidebarOpen]);
|
||||
|
||||
const busy = chatState === 'streaming' || chatState === 'loading' || chatState === 'connecting';
|
||||
const showHomeWelcome = messages.length === 0;
|
||||
|
||||
const handleSelectSession = (sessionId: string) => {
|
||||
@@ -96,18 +102,9 @@ export function ChatView({
|
||||
label: '新会话',
|
||||
onClick: () => void handleNewSession(),
|
||||
},
|
||||
{
|
||||
id: 'remember',
|
||||
label: '记住本轮',
|
||||
onClick: () => void rememberCurrentContext(),
|
||||
disabled: busy || memoryLoading || messages.length === 0,
|
||||
},
|
||||
{
|
||||
id: 'refresh-memory',
|
||||
label: memoryLoading ? '同步中…' : '刷新记忆',
|
||||
onClick: () => void refreshProjectMemory(),
|
||||
disabled: busy || memoryLoading,
|
||||
},
|
||||
...(onOpenFeedback
|
||||
? [{ id: 'feedback', label: '反馈与建议', onClick: () => onOpenFeedback() }]
|
||||
: []),
|
||||
...(onOpenAdmin
|
||||
? [{ id: 'admin', label: '管理', onClick: () => onOpenAdmin() }]
|
||||
: []),
|
||||
@@ -123,10 +120,15 @@ export function ChatView({
|
||||
sessions={sessions}
|
||||
activeSessionId={session?.id}
|
||||
loading={sessionsLoading}
|
||||
loadingMore={sessionsLoadingMore}
|
||||
hasMore={sessionsHasMore}
|
||||
searchQuery={sessionSearchQuery}
|
||||
onClose={() => setSidebarOpen(false)}
|
||||
onSelect={handleSelectSession}
|
||||
onNew={handleNewSession}
|
||||
onDelete={(sessionId) => void deleteSession(sessionId)}
|
||||
onLoadMore={() => void loadMoreSessions()}
|
||||
onSearchChange={setSessionSearchQuery}
|
||||
/>
|
||||
|
||||
<div className={`app${showHomeWelcome ? ' app-home' : ''}`}>
|
||||
@@ -168,24 +170,11 @@ export function ChatView({
|
||||
我的空间
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
className="ghost-btn"
|
||||
disabled={busy || memoryLoading || messages.length === 0}
|
||||
onClick={() => void rememberCurrentContext()}
|
||||
title="把最近几条对话保存到 harness 项目知识库"
|
||||
>
|
||||
记住本轮
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="ghost-btn"
|
||||
disabled={busy || memoryLoading}
|
||||
onClick={() => void refreshProjectMemory()}
|
||||
title="从 harness 和项目文件重新加载长期记忆"
|
||||
>
|
||||
{memoryLoading ? '同步中…' : '刷新记忆'}
|
||||
</button>
|
||||
{onOpenFeedback && (
|
||||
<button type="button" className="ghost-btn" onClick={() => onOpenFeedback()}>
|
||||
反馈
|
||||
</button>
|
||||
)}
|
||||
<button type="button" className="ghost-btn" onClick={() => void handleNewSession()}>
|
||||
新会话
|
||||
</button>
|
||||
@@ -292,6 +281,9 @@ export function ChatView({
|
||||
variant="full"
|
||||
user={user}
|
||||
messages={messages}
|
||||
historyLoadingMore={messageHistoryLoadingMore}
|
||||
historyHasMore={messageHistoryHasMore}
|
||||
historyTotal={messageHistoryTotal}
|
||||
chatState={chatState}
|
||||
pendingTool={pendingTool}
|
||||
session={session}
|
||||
@@ -301,6 +293,7 @@ export function ChatView({
|
||||
void submit(text, undefined, imageUrls, previewImageUrls)
|
||||
}
|
||||
onUploadImage={uploadChatImage}
|
||||
onLoadOlderMessages={loadOlderMessages}
|
||||
onStop={stop}
|
||||
onApproveTool={approveTool}
|
||||
onPageSaved={(result) => {
|
||||
|
||||
Reference in New Issue
Block a user