@huyooo/ai-chat-frontend-vue 0.1.6 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +367 -0
- package/dist/adapter.d.ts +7 -7
- package/dist/adapter.d.ts.map +1 -1
- package/dist/components/ChatPanel.vue.d.ts +120 -9
- package/dist/components/ChatPanel.vue.d.ts.map +1 -1
- package/dist/components/common/ConfirmDialog.vue.d.ts +30 -0
- package/dist/components/common/ConfirmDialog.vue.d.ts.map +1 -0
- package/dist/components/common/CopyButton.vue.d.ts +18 -0
- package/dist/components/common/CopyButton.vue.d.ts.map +1 -0
- package/dist/components/common/IndexingSettings.vue.d.ts +3 -0
- package/dist/components/common/IndexingSettings.vue.d.ts.map +1 -0
- package/dist/components/common/SettingsPanel.vue.d.ts +16 -0
- package/dist/components/common/SettingsPanel.vue.d.ts.map +1 -0
- package/dist/components/common/Toast.vue.d.ts +18 -0
- package/dist/components/common/Toast.vue.d.ts.map +1 -0
- package/dist/components/common/ToggleSwitch.vue.d.ts +10 -0
- package/dist/components/common/ToggleSwitch.vue.d.ts.map +1 -0
- package/dist/components/{chat/ui → header}/ChatHeader.vue.d.ts +5 -3
- package/dist/components/header/ChatHeader.vue.d.ts.map +1 -0
- package/dist/components/input/AtFilePicker.vue.d.ts +21 -0
- package/dist/components/input/AtFilePicker.vue.d.ts.map +1 -0
- package/dist/components/{ChatInput.vue.d.ts → input/ChatInput.vue.d.ts} +16 -14
- package/dist/components/input/ChatInput.vue.d.ts.map +1 -0
- package/dist/components/input/DropdownSelector.vue.d.ts +42 -0
- package/dist/components/input/DropdownSelector.vue.d.ts.map +1 -0
- package/dist/components/input/ImagePreviewModal.vue.d.ts +17 -0
- package/dist/components/input/ImagePreviewModal.vue.d.ts.map +1 -0
- package/dist/components/input/at-views/AtBranchView.vue.d.ts +18 -0
- package/dist/components/input/at-views/AtBranchView.vue.d.ts.map +1 -0
- package/dist/components/input/at-views/AtBrowserView.vue.d.ts +18 -0
- package/dist/components/input/at-views/AtBrowserView.vue.d.ts.map +1 -0
- package/dist/components/input/at-views/AtChatsView.vue.d.ts +18 -0
- package/dist/components/input/at-views/AtChatsView.vue.d.ts.map +1 -0
- package/dist/components/input/at-views/AtDocsView.vue.d.ts +18 -0
- package/dist/components/input/at-views/AtDocsView.vue.d.ts.map +1 -0
- package/dist/components/input/at-views/AtFilesView.vue.d.ts +23 -0
- package/dist/components/input/at-views/AtFilesView.vue.d.ts.map +1 -0
- package/dist/components/input/at-views/AtTerminalsView.vue.d.ts +18 -0
- package/dist/components/input/at-views/AtTerminalsView.vue.d.ts.map +1 -0
- package/dist/components/message/MessageBubble.vue.d.ts +45 -0
- package/dist/components/message/MessageBubble.vue.d.ts.map +1 -0
- package/dist/components/message/PartsRenderer.vue.d.ts +15 -0
- package/dist/components/message/PartsRenderer.vue.d.ts.map +1 -0
- package/dist/components/message/WelcomeMessage.vue.d.ts +14 -0
- package/dist/components/message/WelcomeMessage.vue.d.ts.map +1 -0
- package/dist/components/message/blocks/CodeBlock.vue.d.ts +11 -0
- package/dist/components/message/blocks/CodeBlock.vue.d.ts.map +1 -0
- package/dist/components/{chat/SearchResultBlock.vue.d.ts → message/blocks/TextBlock.vue.d.ts} +3 -4
- package/dist/components/message/blocks/TextBlock.vue.d.ts.map +1 -0
- package/dist/components/message/blocks/index.d.ts +6 -0
- package/dist/components/message/blocks/index.d.ts.map +1 -0
- package/dist/components/message/parts/CollapsibleCard.vue.d.ts +45 -0
- package/dist/components/message/parts/CollapsibleCard.vue.d.ts.map +1 -0
- package/dist/components/{chat/ToolCallBlock.vue.d.ts → message/parts/ErrorPart.vue.d.ts} +4 -5
- package/dist/components/message/parts/ErrorPart.vue.d.ts.map +1 -0
- package/dist/components/{chat/ThinkingBlock.vue.d.ts → message/parts/ImagePart.vue.d.ts} +3 -3
- package/dist/components/message/parts/ImagePart.vue.d.ts.map +1 -0
- package/dist/components/message/parts/SearchPart.vue.d.ts +12 -0
- package/dist/components/message/parts/SearchPart.vue.d.ts.map +1 -0
- package/dist/components/{chat/messages/ExecutionSteps.vue.d.ts → message/parts/TextPart.vue.d.ts} +2 -9
- package/dist/components/message/parts/TextPart.vue.d.ts.map +1 -0
- package/dist/components/message/parts/ThinkingPart.vue.d.ts +12 -0
- package/dist/components/message/parts/ThinkingPart.vue.d.ts.map +1 -0
- package/dist/components/message/parts/ToolCallPart.vue.d.ts +19 -0
- package/dist/components/message/parts/ToolCallPart.vue.d.ts.map +1 -0
- package/dist/components/message/parts/ToolResultPart.vue.d.ts +14 -0
- package/dist/components/message/parts/ToolResultPart.vue.d.ts.map +1 -0
- package/dist/components/message/parts/index.d.ts +12 -0
- package/dist/components/message/parts/index.d.ts.map +1 -0
- package/dist/components/message/tool-results/DefaultToolResult.vue.d.ts +4 -0
- package/dist/components/message/tool-results/DefaultToolResult.vue.d.ts.map +1 -0
- package/dist/components/message/tool-results/SearchResults.vue.d.ts +4 -0
- package/dist/components/message/tool-results/SearchResults.vue.d.ts.map +1 -0
- package/dist/components/message/tool-results/WeatherCard.vue.d.ts +4 -0
- package/dist/components/message/tool-results/WeatherCard.vue.d.ts.map +1 -0
- package/dist/components/message/tool-results/index.d.ts +7 -0
- package/dist/components/message/tool-results/index.d.ts.map +1 -0
- package/dist/components/message/welcome-types.d.ts +28 -0
- package/dist/components/message/welcome-types.d.ts.map +1 -0
- package/dist/composables/useChat.d.ts +99 -44
- package/dist/composables/useChat.d.ts.map +1 -1
- package/dist/composables/useImageUpload.d.ts +55 -0
- package/dist/composables/useImageUpload.d.ts.map +1 -0
- package/dist/index.d.ts +25 -26
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +55871 -1252
- package/dist/style.css +1 -1
- package/dist/types/index.d.ts +113 -53
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/fileIcon.d.ts +13 -0
- package/dist/utils/fileIcon.d.ts.map +1 -0
- package/package.json +12 -6
- package/src/adapter.ts +12 -70
- package/src/components/ChatPanel.vue +329 -110
- package/src/components/common/ConfirmDialog.vue +208 -0
- package/src/components/common/CopyButton.vue +71 -0
- package/src/components/common/IndexingSettings.vue +580 -0
- package/src/components/common/SettingsPanel.vue +293 -0
- package/src/components/common/Toast.vue +90 -0
- package/src/components/common/ToggleSwitch.vue +75 -0
- package/src/components/{chat/ui → header}/ChatHeader.vue +170 -93
- package/src/components/input/AtFilePicker.vue +657 -0
- package/src/components/input/ChatInput.vue +653 -0
- package/src/components/input/DropdownSelector.vue +322 -0
- package/src/components/input/ImagePreviewModal.vue +238 -0
- package/src/components/input/at-views/AtBranchView.vue +63 -0
- package/src/components/input/at-views/AtBrowserView.vue +63 -0
- package/src/components/input/at-views/AtChatsView.vue +63 -0
- package/src/components/input/at-views/AtDocsView.vue +63 -0
- package/src/components/input/at-views/AtFilesView.vue +255 -0
- package/src/components/input/at-views/AtTerminalsView.vue +63 -0
- package/src/components/message/ContentRenderer.vue +61 -0
- package/src/components/message/MessageBubble.vue +411 -0
- package/src/components/message/PartsRenderer.vue +101 -0
- package/src/components/message/ToolResultRenderer.vue +27 -0
- package/src/components/message/WelcomeMessage.vue +308 -0
- package/src/components/message/blocks/CodeBlock.vue +113 -0
- package/src/components/message/blocks/TextBlock.vue +21 -0
- package/src/components/message/blocks/index.ts +6 -0
- package/src/components/message/parts/CollapsibleCard.vue +135 -0
- package/src/components/message/parts/ErrorPart.vue +51 -0
- package/src/components/message/parts/ImagePart.vue +98 -0
- package/src/components/message/parts/SearchPart.vue +101 -0
- package/src/components/message/parts/TextPart.vue +28 -0
- package/src/components/message/parts/ThinkingPart.vue +54 -0
- package/src/components/message/parts/ToolCallPart.vue +460 -0
- package/src/components/message/parts/ToolResultPart.vue +78 -0
- package/src/components/message/parts/index.ts +13 -0
- package/src/components/message/tool-results/DefaultToolResult.vue +43 -0
- package/src/components/message/tool-results/SearchResults.vue +133 -0
- package/src/components/message/tool-results/WeatherCard.vue +139 -0
- package/src/components/message/tool-results/index.ts +7 -0
- package/src/components/message/welcome-types.ts +47 -0
- package/src/composables/useChat.ts +807 -155
- package/src/composables/useImageUpload.ts +228 -0
- package/src/index.ts +93 -46
- package/src/styles.css +47 -0
- package/src/types/index.ts +146 -98
- package/src/utils/fileIcon.ts +49 -0
- package/dist/components/ChatInput.vue.d.ts.map +0 -1
- package/dist/components/chat/SearchResultBlock.vue.d.ts.map +0 -1
- package/dist/components/chat/ThinkingBlock.vue.d.ts.map +0 -1
- package/dist/components/chat/ToolCallBlock.vue.d.ts.map +0 -1
- package/dist/components/chat/messages/ExecutionSteps.vue.d.ts.map +0 -1
- package/dist/components/chat/messages/MessageBubble.vue.d.ts +0 -28
- package/dist/components/chat/messages/MessageBubble.vue.d.ts.map +0 -1
- package/dist/components/chat/ui/ChatHeader.vue.d.ts.map +0 -1
- package/dist/components/chat/ui/WelcomeMessage.vue.d.ts +0 -7
- package/dist/components/chat/ui/WelcomeMessage.vue.d.ts.map +0 -1
- package/dist/preload/preload.d.ts +0 -6
- package/dist/preload/preload.d.ts.map +0 -1
- package/src/components/ChatInput.vue +0 -649
- package/src/components/chat/SearchResultBlock.vue +0 -155
- package/src/components/chat/ThinkingBlock.vue +0 -109
- package/src/components/chat/ToolCallBlock.vue +0 -213
- package/src/components/chat/messages/ExecutionSteps.vue +0 -281
- package/src/components/chat/messages/MessageBubble.vue +0 -272
- package/src/components/chat/ui/WelcomeMessage.vue +0 -135
- package/src/preload/preload.ts +0 -79
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
@click.stop="handleHideTab(session.id)"
|
|
20
20
|
title="关闭标签"
|
|
21
21
|
>
|
|
22
|
-
<
|
|
22
|
+
<Icon icon="lucide:x" width="18" />
|
|
23
23
|
</button>
|
|
24
24
|
</div>
|
|
25
25
|
</template>
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
title="新建对话"
|
|
34
34
|
@click="$emit('new-session')"
|
|
35
35
|
>
|
|
36
|
-
<
|
|
36
|
+
<Icon icon="lucide:plus" width="18" />
|
|
37
37
|
</button>
|
|
38
38
|
|
|
39
39
|
<!-- 历史记录 -->
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
title="历史记录"
|
|
44
44
|
@click.stop="toggleHistory"
|
|
45
45
|
>
|
|
46
|
-
<
|
|
46
|
+
<Icon icon="lucide:clock" width="18" />
|
|
47
47
|
</button>
|
|
48
48
|
|
|
49
49
|
<!-- 历史记录面板 -->
|
|
@@ -51,26 +51,29 @@
|
|
|
51
51
|
<div class="panel-header">
|
|
52
52
|
<span>历史记录</span>
|
|
53
53
|
<button class="icon-btn small" title="新建对话" @click="handleNewFromHistory">
|
|
54
|
-
<
|
|
54
|
+
<Icon icon="lucide:plus" width="18" />
|
|
55
55
|
</button>
|
|
56
56
|
</div>
|
|
57
|
-
<div class="panel-content">
|
|
58
|
-
<
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
<span class="history-date">{{ formatDate(session.updatedAt) }}</span>
|
|
66
|
-
<button
|
|
67
|
-
class="history-delete"
|
|
68
|
-
title="删除"
|
|
69
|
-
@click.stop="$emit('delete-session', session.id)"
|
|
57
|
+
<div class="panel-content chat-scrollbar">
|
|
58
|
+
<template v-for="group in groupedSessions" :key="group.label">
|
|
59
|
+
<div class="history-group-label">{{ group.label }}</div>
|
|
60
|
+
<div
|
|
61
|
+
v-for="session in group.sessions"
|
|
62
|
+
:key="session.id"
|
|
63
|
+
:class="['history-item', { active: session.id === currentSessionId }]"
|
|
64
|
+
@click="handleSelectHistory(session.id)"
|
|
70
65
|
>
|
|
71
|
-
<
|
|
72
|
-
|
|
73
|
-
|
|
66
|
+
<span class="history-title">{{ session.title }}</span>
|
|
67
|
+
<span class="history-time">{{ formatTime(session.updatedAt) }}</span>
|
|
68
|
+
<button
|
|
69
|
+
class="history-action-btn delete"
|
|
70
|
+
title="删除"
|
|
71
|
+
@click.stop="$emit('delete-session', session.id)"
|
|
72
|
+
>
|
|
73
|
+
<Icon icon="lucide:trash-2" width="18" />
|
|
74
|
+
</button>
|
|
75
|
+
</div>
|
|
76
|
+
</template>
|
|
74
77
|
<div v-if="sessions.length === 0" class="empty-state">
|
|
75
78
|
暂无历史对话
|
|
76
79
|
</div>
|
|
@@ -85,35 +88,35 @@
|
|
|
85
88
|
title="更多选项"
|
|
86
89
|
@click.stop="toggleMore"
|
|
87
90
|
>
|
|
88
|
-
<
|
|
91
|
+
<Icon icon="lucide:more-horizontal" width="18" />
|
|
89
92
|
</button>
|
|
90
93
|
|
|
91
94
|
<!-- 更多选项菜单 -->
|
|
92
95
|
<div v-if="moreOpen" class="dropdown-panel more-panel">
|
|
93
96
|
<button class="menu-item" @click="handleMenuAction('clear-all')">
|
|
94
|
-
<
|
|
97
|
+
<Icon icon="lucide:trash-2" width="18" />
|
|
95
98
|
<span>清空所有对话</span>
|
|
96
99
|
</button>
|
|
97
100
|
<button class="menu-item" @click="handleMenuAction('close-others')">
|
|
98
|
-
<
|
|
101
|
+
<Icon icon="lucide:x-circle" width="18" />
|
|
99
102
|
<span>关闭其他对话</span>
|
|
100
103
|
</button>
|
|
101
104
|
<div class="menu-divider"></div>
|
|
102
105
|
<button class="menu-item" @click="handleMenuAction('export')">
|
|
103
|
-
<
|
|
106
|
+
<Icon icon="lucide:download" width="18" />
|
|
104
107
|
<span>导出对话</span>
|
|
105
108
|
</button>
|
|
106
109
|
<button class="menu-item" @click="handleMenuAction('copy-id')">
|
|
107
|
-
<
|
|
110
|
+
<Icon icon="lucide:copy" width="18" />
|
|
108
111
|
<span>复制请求 ID</span>
|
|
109
112
|
</button>
|
|
110
113
|
<div class="menu-divider"></div>
|
|
111
114
|
<button class="menu-item" @click="handleMenuAction('feedback')">
|
|
112
|
-
<
|
|
115
|
+
<Icon icon="lucide:message-square" width="18" />
|
|
113
116
|
<span>反馈</span>
|
|
114
117
|
</button>
|
|
115
118
|
<button class="menu-item" @click="handleMenuAction('settings')">
|
|
116
|
-
<
|
|
119
|
+
<Icon icon="lucide:settings" width="18" />
|
|
117
120
|
<span>Agent 设置</span>
|
|
118
121
|
</button>
|
|
119
122
|
</div>
|
|
@@ -126,7 +129,16 @@
|
|
|
126
129
|
title="关闭"
|
|
127
130
|
@click="$emit('close')"
|
|
128
131
|
>
|
|
129
|
-
<
|
|
132
|
+
<Icon icon="lucide:x" width="18" />
|
|
133
|
+
</button>
|
|
134
|
+
|
|
135
|
+
<!-- 设置按钮 -->
|
|
136
|
+
<button
|
|
137
|
+
class="icon-btn"
|
|
138
|
+
title="设置"
|
|
139
|
+
@click="$emit('settings')"
|
|
140
|
+
>
|
|
141
|
+
<Icon icon="lucide:settings" width="18" />
|
|
130
142
|
</button>
|
|
131
143
|
</div>
|
|
132
144
|
</div>
|
|
@@ -134,19 +146,8 @@
|
|
|
134
146
|
|
|
135
147
|
<script setup lang="ts">
|
|
136
148
|
import { ref, computed, onMounted, onUnmounted } from 'vue';
|
|
137
|
-
import {
|
|
138
|
-
|
|
139
|
-
Plus,
|
|
140
|
-
Clock,
|
|
141
|
-
MoreHorizontal,
|
|
142
|
-
Trash2,
|
|
143
|
-
XCircle,
|
|
144
|
-
Download,
|
|
145
|
-
Copy,
|
|
146
|
-
MessageSquare,
|
|
147
|
-
Settings,
|
|
148
|
-
} from 'lucide-vue-next';
|
|
149
|
-
import type { SessionRecord } from '../../../types';
|
|
149
|
+
import { Icon } from '@iconify/vue';
|
|
150
|
+
import type { SessionRecord } from '../../types';
|
|
150
151
|
|
|
151
152
|
const props = defineProps<{
|
|
152
153
|
sessions: SessionRecord[];
|
|
@@ -158,6 +159,7 @@ const emit = defineEmits<{
|
|
|
158
159
|
'new-session': [];
|
|
159
160
|
'switch-session': [sessionId: string];
|
|
160
161
|
'delete-session': [sessionId: string];
|
|
162
|
+
'hide-session': [sessionId: string, hidden: boolean];
|
|
161
163
|
'close': [];
|
|
162
164
|
'clear-all': [];
|
|
163
165
|
'close-others': [];
|
|
@@ -167,12 +169,9 @@ const emit = defineEmits<{
|
|
|
167
169
|
'settings': [];
|
|
168
170
|
}>();
|
|
169
171
|
|
|
170
|
-
// 隐藏的 tab(关闭但不删除)
|
|
171
|
-
const hiddenTabs = ref<Set<string>>(new Set());
|
|
172
|
-
|
|
173
172
|
// 可见的会话(过滤掉隐藏的)
|
|
174
173
|
const visibleSessions = computed(() =>
|
|
175
|
-
props.sessions.filter((s) => !
|
|
174
|
+
props.sessions.filter((s) => !s.hidden)
|
|
176
175
|
);
|
|
177
176
|
|
|
178
177
|
// 下拉菜单状态
|
|
@@ -186,28 +185,72 @@ function getDisplayTitle(title: string) {
|
|
|
186
185
|
return title === '新对话' ? 'New Chat' : title;
|
|
187
186
|
}
|
|
188
187
|
|
|
189
|
-
//
|
|
190
|
-
function
|
|
188
|
+
// 格式化时间(HH:mm)
|
|
189
|
+
function formatTime(date: Date): string {
|
|
190
|
+
const d = new Date(date);
|
|
191
|
+
const hours = String(d.getHours()).padStart(2, '0');
|
|
192
|
+
const minutes = String(d.getMinutes()).padStart(2, '0');
|
|
193
|
+
return `${hours}:${minutes}`;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// 获取日期分组标签
|
|
197
|
+
function getDateGroupLabel(date: Date): string {
|
|
191
198
|
const d = new Date(date);
|
|
192
199
|
const now = new Date();
|
|
193
|
-
|
|
200
|
+
|
|
201
|
+
// 重置时间部分,只比较日期
|
|
202
|
+
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
|
203
|
+
const target = new Date(d.getFullYear(), d.getMonth(), d.getDate());
|
|
204
|
+
const diff = today.getTime() - target.getTime();
|
|
194
205
|
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
|
|
195
206
|
|
|
196
207
|
if (days === 0) return '今天';
|
|
197
208
|
if (days === 1) return '昨天';
|
|
198
|
-
|
|
199
|
-
|
|
209
|
+
|
|
210
|
+
// 其他显示具体日期
|
|
211
|
+
const month = d.getMonth() + 1;
|
|
212
|
+
const day = d.getDate();
|
|
213
|
+
return `${month}月${day}日`;
|
|
200
214
|
}
|
|
201
215
|
|
|
202
|
-
//
|
|
216
|
+
// 按日期分组会话
|
|
217
|
+
interface SessionGroup {
|
|
218
|
+
label: string;
|
|
219
|
+
sessions: SessionRecord[];
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const groupedSessions = computed<SessionGroup[]>(() => {
|
|
223
|
+
const groups = new Map<string, SessionRecord[]>();
|
|
224
|
+
|
|
225
|
+
for (const session of props.sessions) {
|
|
226
|
+
const label = getDateGroupLabel(session.updatedAt);
|
|
227
|
+
const group = groups.get(label);
|
|
228
|
+
if (group) {
|
|
229
|
+
group.push(session);
|
|
230
|
+
} else {
|
|
231
|
+
groups.set(label, [session]);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// 转换为数组,保持顺序
|
|
236
|
+
return Array.from(groups.entries()).map(([label, sessions]) => ({
|
|
237
|
+
label,
|
|
238
|
+
sessions,
|
|
239
|
+
}));
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
// 隐藏 tab(触发事件由父组件持久化到数据库)
|
|
203
243
|
function handleHideTab(sessionId: string) {
|
|
204
|
-
|
|
244
|
+
emit('hide-session', sessionId, true);
|
|
205
245
|
if (sessionId === props.currentSessionId) {
|
|
206
246
|
const remaining = props.sessions.filter(
|
|
207
|
-
(s) => s.id !== sessionId && !
|
|
247
|
+
(s) => s.id !== sessionId && !s.hidden
|
|
208
248
|
);
|
|
209
249
|
if (remaining.length > 0) {
|
|
210
250
|
emit('switch-session', remaining[0].id);
|
|
251
|
+
} else {
|
|
252
|
+
// 最后一个 tab 被关闭,创建新会话
|
|
253
|
+
emit('new-session');
|
|
211
254
|
}
|
|
212
255
|
}
|
|
213
256
|
}
|
|
@@ -232,13 +275,12 @@ function handleNewFromHistory() {
|
|
|
232
275
|
|
|
233
276
|
// 选择历史
|
|
234
277
|
function handleSelectHistory(sessionId: string) {
|
|
235
|
-
|
|
278
|
+
const session = props.sessions.find((s) => s.id === sessionId);
|
|
236
279
|
// 如果被隐藏了,恢复显示
|
|
237
|
-
if (
|
|
238
|
-
|
|
239
|
-
newHidden.delete(sessionId);
|
|
240
|
-
hiddenTabs.value = newHidden;
|
|
280
|
+
if (session?.hidden) {
|
|
281
|
+
emit('hide-session', sessionId, false);
|
|
241
282
|
}
|
|
283
|
+
emit('switch-session', sessionId);
|
|
242
284
|
historyOpen.value = false;
|
|
243
285
|
}
|
|
244
286
|
|
|
@@ -315,13 +357,12 @@ onUnmounted(() => {
|
|
|
315
357
|
position: relative;
|
|
316
358
|
display: flex;
|
|
317
359
|
align-items: center;
|
|
318
|
-
gap: 4px;
|
|
319
360
|
padding: 4px 8px;
|
|
320
361
|
background: transparent;
|
|
321
362
|
border: none;
|
|
322
363
|
border-radius: 4px;
|
|
323
364
|
color: var(--chat-text-muted, #888);
|
|
324
|
-
font-size:
|
|
365
|
+
font-size: 14px;
|
|
325
366
|
font-weight: 500;
|
|
326
367
|
cursor: pointer;
|
|
327
368
|
transition: all 0.15s;
|
|
@@ -346,27 +387,35 @@ onUnmounted(() => {
|
|
|
346
387
|
}
|
|
347
388
|
|
|
348
389
|
.tab-close {
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
390
|
+
position: absolute;
|
|
391
|
+
right: 0;
|
|
392
|
+
top: 0;
|
|
393
|
+
bottom: 0;
|
|
394
|
+
display: flex;
|
|
395
|
+
align-items: center;
|
|
396
|
+
justify-content: center;
|
|
397
|
+
width: 32px;
|
|
352
398
|
padding: 0;
|
|
353
|
-
|
|
399
|
+
padding-left: 8px;
|
|
400
|
+
background: linear-gradient(to right, transparent, var(--chat-bg, #1e1e1e) 50%);
|
|
354
401
|
border: none;
|
|
355
|
-
border-radius:
|
|
356
|
-
color: var(--chat-text-muted, #
|
|
402
|
+
border-radius: 0 4px 4px 0;
|
|
403
|
+
color: var(--chat-text-muted, #666);
|
|
357
404
|
cursor: pointer;
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
flex-shrink: 0;
|
|
405
|
+
transition: all 0.15s;
|
|
406
|
+
opacity: 0;
|
|
361
407
|
}
|
|
362
408
|
|
|
363
409
|
.tab-item:hover .tab-close {
|
|
364
|
-
|
|
410
|
+
opacity: 1;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
.tab-item.active .tab-close {
|
|
414
|
+
background: linear-gradient(to right, transparent, var(--chat-muted, #3c3c3c) 50%);
|
|
365
415
|
}
|
|
366
416
|
|
|
367
417
|
.tab-close:hover {
|
|
368
418
|
color: var(--chat-text, #fff);
|
|
369
|
-
background: var(--chat-muted, #444);
|
|
370
419
|
}
|
|
371
420
|
|
|
372
421
|
.header-actions {
|
|
@@ -419,7 +468,7 @@ onUnmounted(() => {
|
|
|
419
468
|
}
|
|
420
469
|
|
|
421
470
|
.history-panel {
|
|
422
|
-
width:
|
|
471
|
+
width: 360px;
|
|
423
472
|
}
|
|
424
473
|
|
|
425
474
|
.more-panel {
|
|
@@ -433,21 +482,36 @@ onUnmounted(() => {
|
|
|
433
482
|
justify-content: space-between;
|
|
434
483
|
padding: 10px 12px;
|
|
435
484
|
border-bottom: 1px solid var(--chat-border, #333);
|
|
436
|
-
font-size:
|
|
485
|
+
font-size: 14px;
|
|
437
486
|
font-weight: 500;
|
|
438
487
|
color: var(--chat-text-muted, #888);
|
|
439
488
|
}
|
|
440
489
|
|
|
441
490
|
.panel-content {
|
|
442
|
-
max-height:
|
|
491
|
+
max-height: 400px;
|
|
443
492
|
overflow-y: auto;
|
|
444
493
|
}
|
|
445
494
|
|
|
495
|
+
|
|
496
|
+
/* 日期分组标签 */
|
|
497
|
+
.history-group-label {
|
|
498
|
+
padding: 8px 12px 4px;
|
|
499
|
+
font-size: 14px;
|
|
500
|
+
font-weight: 500;
|
|
501
|
+
color: var(--chat-text-muted, #666);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
.history-group-label:not(:first-child) {
|
|
505
|
+
border-top: 1px solid var(--chat-border, #333);
|
|
506
|
+
margin-top: 4px;
|
|
507
|
+
padding-top: 12px;
|
|
508
|
+
}
|
|
509
|
+
|
|
446
510
|
.history-item {
|
|
447
511
|
display: flex;
|
|
448
512
|
align-items: center;
|
|
449
|
-
gap:
|
|
450
|
-
padding:
|
|
513
|
+
gap: 4px;
|
|
514
|
+
padding: 6px 12px;
|
|
451
515
|
cursor: pointer;
|
|
452
516
|
transition: background 0.15s;
|
|
453
517
|
}
|
|
@@ -462,47 +526,60 @@ onUnmounted(() => {
|
|
|
462
526
|
|
|
463
527
|
.history-title {
|
|
464
528
|
flex: 1;
|
|
465
|
-
font-size:
|
|
529
|
+
font-size: 14px;
|
|
466
530
|
color: var(--chat-text, #ccc);
|
|
467
531
|
overflow: hidden;
|
|
468
532
|
text-overflow: ellipsis;
|
|
469
533
|
white-space: nowrap;
|
|
470
534
|
}
|
|
471
535
|
|
|
472
|
-
.history-
|
|
473
|
-
font-size:
|
|
536
|
+
.history-time {
|
|
537
|
+
font-size: 14px;
|
|
474
538
|
color: var(--chat-text-muted, #666);
|
|
475
539
|
flex-shrink: 0;
|
|
540
|
+
margin-right: 10px;
|
|
476
541
|
}
|
|
477
542
|
|
|
478
|
-
.history-
|
|
479
|
-
display:
|
|
480
|
-
|
|
481
|
-
|
|
543
|
+
.history-actions {
|
|
544
|
+
display: flex;
|
|
545
|
+
align-items: center;
|
|
546
|
+
gap: 2px;
|
|
547
|
+
flex-shrink: 0;
|
|
548
|
+
opacity: 0;
|
|
549
|
+
transition: opacity 0.15s;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
.history-item:hover .history-actions {
|
|
553
|
+
opacity: 1;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
.history-action-btn {
|
|
557
|
+
display: flex;
|
|
558
|
+
align-items: center;
|
|
559
|
+
justify-content: center;
|
|
560
|
+
width: 28px;
|
|
561
|
+
height: 28px;
|
|
482
562
|
padding: 0;
|
|
483
563
|
background: transparent;
|
|
484
564
|
border: none;
|
|
485
|
-
border-radius:
|
|
565
|
+
border-radius: 6px;
|
|
486
566
|
color: var(--chat-text-muted, #666);
|
|
487
567
|
cursor: pointer;
|
|
488
|
-
|
|
489
|
-
justify-content: center;
|
|
490
|
-
flex-shrink: 0;
|
|
568
|
+
transition: all 0.15s;
|
|
491
569
|
}
|
|
492
570
|
|
|
493
|
-
.history-
|
|
494
|
-
|
|
571
|
+
.history-action-btn:hover {
|
|
572
|
+
color: var(--chat-text, #fff);
|
|
495
573
|
}
|
|
496
574
|
|
|
497
|
-
.history-delete:hover {
|
|
575
|
+
.history-action-btn.delete:hover {
|
|
498
576
|
color: var(--chat-destructive, #ef4444);
|
|
499
|
-
background: var(--chat-destructive, #ef444420);
|
|
500
577
|
}
|
|
501
578
|
|
|
502
579
|
.empty-state {
|
|
503
580
|
padding: 20px;
|
|
504
581
|
text-align: center;
|
|
505
|
-
font-size:
|
|
582
|
+
font-size: 14px;
|
|
506
583
|
color: var(--chat-text-muted, #666);
|
|
507
584
|
}
|
|
508
585
|
|
|
@@ -515,7 +592,7 @@ onUnmounted(() => {
|
|
|
515
592
|
background: transparent;
|
|
516
593
|
border: none;
|
|
517
594
|
border-radius: 4px;
|
|
518
|
-
font-size:
|
|
595
|
+
font-size: 14px;
|
|
519
596
|
color: var(--chat-text-muted, #999);
|
|
520
597
|
cursor: pointer;
|
|
521
598
|
transition: all 0.15s;
|