af-mobile-client-vue3 1.4.55 → 1.4.57

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "af-mobile-client-vue3",
3
3
  "type": "module",
4
- "version": "1.4.55",
4
+ "version": "1.4.57",
5
5
  "packageManager": "pnpm@10.13.1",
6
6
  "description": "Vue + Vite component lib",
7
7
  "engines": {
package/src/App.vue CHANGED
@@ -99,6 +99,7 @@ input[type='password']::-ms-clear {
99
99
  <style scoped>
100
100
  .app-wrapper {
101
101
  width: 100%;
102
+ height: 100vh;
102
103
  position: relative;
103
104
  }
104
105
  </style>
@@ -6,7 +6,6 @@ import MateChatHeader from '@af-mobile-client-vue3/components/common/MateChat/co
6
6
  import { PromptList } from '@af-mobile-client-vue3/components/common/MateChat/components/PromptList'
7
7
  import { useMateChat } from '@af-mobile-client-vue3/components/common/MateChat/composables/useMateChat'
8
8
  import { useDebounceFn } from '@vueuse/core'
9
- import { Button as VanButton } from 'vant'
10
9
  import { computed, nextTick, ref, watch } from 'vue'
11
10
  import 'vant/es/image-preview/style'
12
11
 
@@ -110,6 +109,7 @@ function handleSelectSession(session: { chatId: string, title: string, lastTime:
110
109
  :app-id="props.config.appId"
111
110
  :app-key="props.config.appKey"
112
111
  @select-session="handleSelectSession"
112
+ @new-conversation="newConversation"
113
113
  />
114
114
  <McLayoutContent
115
115
  v-if="startPage"
@@ -161,20 +161,13 @@ function handleSelectSession(session: { chatId: string, title: string, lastTime:
161
161
  style="flex: 1"
162
162
  @item-click="onSubmit($event.label)"
163
163
  />
164
- <VanButton
165
- style="margin-left: auto"
166
- icon="add"
167
- title="新建对话"
168
- size="small"
169
- round
170
- @click="newConversation"
171
- />
172
164
  </div>
173
165
  <McLayoutSender>
174
166
  <McInput
175
167
  :value="inputValue"
176
168
  placeholder="请输入您的问题,我会为您解答"
177
169
  :max-length="2000"
170
+ :autosize="true"
178
171
  @change="(e) => (inputValue = e)"
179
172
  @submit="onSubmit"
180
173
  />
@@ -186,7 +179,7 @@ function handleSelectSession(session: { chatId: string, title: string, lastTime:
186
179
  .chat-card {
187
180
  width: 100%;
188
181
  max-width: 1200px;
189
- height: calc(100vh - 40px);
182
+ height: 100%;
190
183
  background: #ffffff;
191
184
  border-radius: 24px;
192
185
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);
@@ -205,7 +198,6 @@ function handleSelectSession(session: { chatId: string, title: string, lastTime:
205
198
  /* 移动端适配 */
206
199
  @media (max-width: 768px) {
207
200
  .chat-card {
208
- height: calc(100vh - 16px);
209
201
  border-radius: 16px;
210
202
  padding: 8px;
211
203
  }
@@ -2,12 +2,13 @@
2
2
  import type { ChatHistoryItem } from '@af-mobile-client-vue3/components/common/MateChat/types'
3
3
  import { getHistories } from '@af-mobile-client-vue3/components/common/MateChat/apiService'
4
4
  import { useChatHistoryCache } from '@af-mobile-client-vue3/components/common/MateChat/composables/useChatHistoryCache'
5
- import { Empty, Icon, Loading, Popup } from 'vant'
5
+ import { Empty, Icon, Loading, Popup, Popover as VanPopover } from 'vant'
6
6
  import { ref } from 'vue'
7
7
  import 'vant/es/popup/style'
8
8
  import 'vant/es/empty/style'
9
9
  import 'vant/es/loading/style'
10
10
  import 'vant/es/icon/style'
11
+ import 'vant/es/popover/style'
11
12
 
12
13
  interface Props {
13
14
  /**
@@ -47,6 +48,10 @@ interface Emits {
47
48
  * 选择某条历史会话
48
49
  */
49
50
  (e: 'selectSession', session: SessionItem): void
51
+ /**
52
+ * 新建对话
53
+ */
54
+ (e: 'newConversation'): void
50
55
  }
51
56
 
52
57
  const props = withDefaults(defineProps<Props>(), {
@@ -58,6 +63,12 @@ const emit = defineEmits<Emits>()
58
63
  const showHistory = ref(false)
59
64
  const isLoading = ref(false)
60
65
  const sessionList = ref<SessionItem[]>([])
66
+ const showMenu = ref(false)
67
+
68
+ const menuActions: { text: string, key: 'new' | 'history', icon: string }[] = [
69
+ { text: '新对话', key: 'new', icon: 'add-o' },
70
+ { text: '历史对话', key: 'history', icon: 'clock-o' },
71
+ ]
61
72
 
62
73
  // 使用历史会话缓存
63
74
  const { getCachedHistory, setCachedHistory } = useChatHistoryCache()
@@ -72,6 +83,20 @@ function handleSelectSession(session: SessionItem) {
72
83
  showHistory.value = false
73
84
  }
74
85
 
86
+ /**
87
+ * 处理下拉菜单点击
88
+ */
89
+ function handleMenuSelect(action: { text: string, key: 'new' | 'history', icon?: string }) {
90
+ showMenu.value = false
91
+ if (action.key === 'new') {
92
+ emit('newConversation')
93
+ return
94
+ }
95
+ if (action.key === 'history') {
96
+ handleOpenHistory()
97
+ }
98
+ }
99
+
75
100
  /**
76
101
  * 格式化时间字符串为日期时间字符串
77
102
  */
@@ -139,11 +164,24 @@ async function fetchSessions() {
139
164
 
140
165
  <template>
141
166
  <div class="matechat-header-wrapper">
142
- <McHeader :logo-img="showTitle ? props.logoImage : ''" :title="showTitle ? props.title : ''" :logo-clickable="false">
167
+ <McHeader
168
+ :logo-img="showTitle ? props.logoImage : ''"
169
+ :title="showTitle ? props.title : ''"
170
+ :logo-clickable="false"
171
+ >
143
172
  <template #operationArea>
144
- <div class="matechat-header-history-btn" @click="handleOpenHistory">
145
- <Icon name="clock-o" size="16" />
146
- </div>
173
+ <VanPopover
174
+ v-model:show="showMenu"
175
+ placement="bottom-end"
176
+ :actions="menuActions"
177
+ @select="handleMenuSelect"
178
+ >
179
+ <template #reference>
180
+ <div class="matechat-header-history-btn">
181
+ <Icon name="ellipsis" size="16" />
182
+ </div>
183
+ </template>
184
+ </VanPopover>
147
185
  </template>
148
186
  </McHeader>
149
187
 
@@ -204,15 +242,17 @@ async function fetchSessions() {
204
242
  justify-content: center;
205
243
  width: 32px;
206
244
  height: 32px;
207
- border-radius: 50%;
208
- background-color: rgba(255, 255, 255, 0.8);
245
+ border-radius: 8px;
246
+ background-color: rgba(255, 255, 255, 0.9);
247
+ border: 1px solid rgba(0, 0, 0, 0.08);
248
+ box-shadow: 0 1px 3px rgba(15, 23, 42, 0.12);
209
249
  cursor: pointer;
210
250
  transition: all 0.2s ease;
211
251
 
212
252
  &:hover {
213
- background-color: rgba(255, 255, 255, 1);
214
- transform: translateY(-1px);
215
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
253
+ background-color: #ffffff;
254
+ transform: translateY(-0.5px);
255
+ box-shadow: 0 2px 6px rgba(15, 23, 42, 0.16);
216
256
  }
217
257
  }
218
258
 
@@ -221,7 +261,6 @@ async function fetchSessions() {
221
261
  width: 320px;
222
262
  max-width: 80vw;
223
263
  background-color: #ffffff;
224
- border-radius: 16px;
225
264
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.15);
226
265
  padding: 16px 16px 12px;
227
266
  box-sizing: border-box;
@@ -260,7 +299,7 @@ async function fetchSessions() {
260
299
 
261
300
  &__item {
262
301
  padding: 10px 8px;
263
- border-radius: 8px;
302
+ border-radius: 0;
264
303
  cursor: pointer;
265
304
  transition: all 0.2s ease;
266
305
 
@@ -138,97 +138,77 @@ export function useMateChat(config: MateChatConfig) {
138
138
  return
139
139
  }
140
140
 
141
- // 流式:使用 FastGPT SSE,增量更新最后一条模型消息内容,并在前缀为 {"msgType":"transfer"} 时转人工
142
- const transferPrefix = '{"msgType":"transfer"'
143
- let checkedTransfer = false
144
- let transferHandled = false
145
- let prefixBuffer = ''
141
+ // 流式:使用 FastGPT SSE,增量更新最后一条模型消息内容
142
+ // 规则:
143
+ // 1)每次收到 chunk 都立即累加到 msg.content,保证实时流式效果
144
+ // 2)在累加后的内容上做一次“是否为转人工 JSON 消息”的前缀粗判:以 {"msgType 开头
145
+ // 3)如果判断为转人工,则保持 loading 状态,等待 onComplete 再统一处理整条消息
146
+ // 4)如果判断不是转人工,则当作普通文本流式展示,onComplete 时仅结束 loading
147
+ const transferPrefix = '{"msgType'
148
+ let checkedTransfer = false // 是否已经做过类型判定
149
+ let isTransferMessage = false // 是否判定为转人工消息
146
150
 
147
151
  const callbacks: ChatStreamCallbacks = {
148
152
  onMessage(chunk) {
149
- if (transferHandled) {
153
+ const msg = messages.value[loadingMessageIndex]
154
+ if (!msg) {
150
155
  return
151
156
  }
157
+ // 1. 实时累加内容,保证流式体验
158
+ msg.content += chunk
152
159
 
153
- // 尚未判断是否为转人工前缀
160
+ // 2. 如果还没有做过类型判定,基于当前累积内容做一次前缀粗判
154
161
  if (!checkedTransfer) {
155
- const trimmed = chunk.trimStart()
156
- if (!trimmed) {
157
- // 纯空白,等待下一帧
162
+ const trimmed = msg.content.trimStart()
163
+ // 内容太短,无法判断,继续等待更多 chunk
164
+ if (!trimmed || trimmed.length < transferPrefix.length) {
158
165
  return
159
166
  }
160
167
 
161
- // 第一个有效字符不是 { ,本次不会是转人工 JSON,后续直接按普通文本处理
162
- if (!prefixBuffer && trimmed[0] !== '{') {
163
- checkedTransfer = true
164
- const msg = messages.value[loadingMessageIndex]
165
- if (!msg) {
166
- return
167
- }
168
- msg.content += chunk
169
- msg.loading = true
170
- return
171
- }
172
-
173
- // 有可能是 JSON,累积前缀做精准匹配
174
- prefixBuffer += trimmed
175
-
176
- // 如果当前前缀还是 transferPrefix 的前缀,继续等后续 chunk
177
- if (transferPrefix.startsWith(prefixBuffer)) {
178
- // 还没完整匹配上整个标识,继续等待
179
- if (prefixBuffer.length < transferPrefix.length) {
180
- return
181
- }
168
+ if (trimmed.startsWith(transferPrefix)) {
169
+ // {"msgType 开头,标记为“可能是转人工消息”
170
+ isTransferMessage = true
182
171
  }
183
-
184
- if (prefixBuffer.startsWith(transferPrefix)) {
185
- // 确认是转人工:移除 loading 模型气泡,插入客服气泡
186
- messages.value.splice(loadingMessageIndex, 1)
187
- messages.value.push({
188
- from: 'service',
189
- content: '您好,客服xxx工号xxx为你服务。功能开发中,敬请期待。',
190
- })
191
- transferHandled = true
192
- checkedTransfer = true
193
- // 更新缓存:追加用户消息和客服消息(在 onComplete 中统一处理)
194
- return
172
+ else {
173
+ // 不以 {"msgType 开头,当作普通文本处理
174
+ isTransferMessage = false
175
+ msg.loading = false
195
176
  }
196
-
197
- // 前缀与约定不匹配,当作普通内容处理,并不再尝试转人工识别
198
177
  checkedTransfer = true
199
- const msg = messages.value[loadingMessageIndex]
200
- if (!msg) {
201
- return
202
- }
203
- msg.content += prefixBuffer
204
- msg.loading = true
205
- prefixBuffer = ''
206
- return
207
178
  }
208
-
209
- // 已经判断过不会转人工,正常流式追加内容
210
- const msg = messages.value[loadingMessageIndex]
211
- if (!msg) {
212
- return
213
- }
214
- msg.content += chunk
215
- msg.loading = true
216
179
  },
217
180
  onComplete() {
218
- if (transferHandled) {
219
- // 转人工情况:更新缓存
220
- appendMessages(chatId.value, [
221
- { from: 'user', content: evt },
222
- { from: 'service', content: '您好,客服xxx工号xxx为你服务。功能开发中,敬请期待。' },
223
- ])
224
- return
225
- }
226
181
  const msg = messages.value[loadingMessageIndex]
227
182
  if (!msg) {
228
183
  return
229
184
  }
185
+ // 根据前面判定结果决定如何处理整条消息
186
+ if (isTransferMessage) {
187
+ // 尝试按 JSON 解析,判断是否真的是转人工指令
188
+ try {
189
+ const parsed = JSON.parse(msg.content.trim())
190
+ if (parsed && parsed.msgType === 'transfer') {
191
+ // 确认为转人工:移除模型气泡,插入客服气泡
192
+ messages.value.splice(loadingMessageIndex, 1)
193
+ messages.value.push({
194
+ from: 'service',
195
+ content: '您好,客服xxx工号xxx为你服务。功能开发中,敬请期待。',
196
+ })
197
+ // 转人工情况:更新缓存
198
+ appendMessages(chatId.value, [
199
+ { from: 'user', content: evt },
200
+ { from: 'service', content: '您好,客服xxx工号xxx为你服务。功能开发中,敬请期待。' },
201
+ ])
202
+ return
203
+ }
204
+ }
205
+ catch {
206
+ // 解析失败则回退为普通文本处理
207
+ }
208
+ }
209
+
210
+ // 普通消息:结束 loading,按完整文本渲染并写入缓存
230
211
  msg.loading = false
231
- // 流式完成后更新缓存:追加用户消息和完整的模型回复
232
212
  appendMessages(chatId.value, [
233
213
  { from: 'user', content: evt },
234
214
  { from: 'model', content: msg.content, loading: false },
@@ -41,6 +41,21 @@ const finalLoading = computed(() => forceLoading.value || isLoading.value || !!c
41
41
  // 当前使用的配置
42
42
  const currentConfig = ref<MateChatConfig | null>(null)
43
43
 
44
+ const defaultBackgroundGradient = 'background: linear-gradient(to bottom, #d0c9ff 0%, #e6d6f0 8%, #f1dbea 12%, #c8dcfb 40%, #abc6f6 60%, #87aefe 90%)'
45
+ // 琉璃配色
46
+ // background: linear-gradient(to bottom, #a8f0ed 0%, #a8e6cf 8%, #c5b3ff 12%, #e0b3ff 40%, #fff4b8 60%, #ffb8d1 90%);
47
+ // 紫罗兰配色
48
+ // background: linear-gradient(to bottom, #d0c9ff 0%, #e6d6f0 8%, #f1dbea 12%, #c8dcfb 40%, #abc6f6 60%, #87aefe 90%);
49
+ // 蓝白配色
50
+ // 'linear-gradient(to bottom, #1c57e0 0%, #3b82f6 20%, #60a5fa 40%, #93c5fd 60%, #dbeafe 80%, #ffffff 100%)'
51
+ // 计算背景渐变样式
52
+ const backgroundStyle = computed(() => {
53
+ const gradient = currentConfig.value?.backgroundGradient || defaultBackgroundGradient
54
+ return {
55
+ background: gradient,
56
+ }
57
+ })
58
+
44
59
  // 存储原始配置数据
45
60
  const rawConfigs = ref<MateChatConfigs | MateChatConfig | null>(null)
46
61
 
@@ -305,7 +320,7 @@ onMounted(() => {
305
320
  </script>
306
321
 
307
322
  <template>
308
- <div id="mate-chat-view">
323
+ <div id="mate-chat-view" :style="backgroundStyle">
309
324
  <!-- 密码输入对话框 -->
310
325
  <PasswordDialog
311
326
  ref="passwordDialogRef"
@@ -351,9 +366,9 @@ onMounted(() => {
351
366
  #mate-chat-view {
352
367
  /* 外层渐变背景容器 */
353
368
  width: 100%;
354
- min-height: 100vh;
355
- background: linear-gradient(to bottom, #a8f0ed 0%, #a8e6cf 8%, #c5b3ff 12%, #e0b3ff 40%, #fff4b8 60%, #ffb8d1 90%);
356
- /* background: linear-gradient(to bottom, #d0c9ff 0%, #e6d6f0 8%, #f1dbea 12%, #c8dcfb 40%, #abc6f6 60%, #87aefe 90%); */
369
+ height: 100%;
370
+ min-height: 100%;
371
+ /* 背景色通过 :style 绑定从配置中获取 */
357
372
  padding: 20px;
358
373
  display: flex;
359
374
  justify-content: center;
@@ -381,7 +396,7 @@ onMounted(() => {
381
396
 
382
397
  /* 移动端适配 */
383
398
  @media (max-width: 768px) {
384
- height: calc(100vh - 16px);
399
+ height: calc(100% - 18px);
385
400
  border-radius: 16px;
386
401
  padding: 8px;
387
402
  }
@@ -1,236 +1,241 @@
1
- /**
2
- * MateChat 提示项接口
3
- */
4
- export interface MateChatPromptItem {
5
- value: string
6
- label: string
7
- iconConfig?: {
8
- name: string
9
- color?: string
10
- }
11
- desc?: string
12
- }
13
-
14
- /**
15
- * MateChat 配置接口
16
- */
17
- export interface MateChatConfig {
18
- /**
19
- * 可选密码,如果存在则需要密码验证
20
- */
21
- password?: string
22
- /**
23
- * FastGPT 应用 ID
24
- */
25
- appId: string
26
- /**
27
- * FastGPT API Key
28
- */
29
- appKey: string
30
- /**
31
- * 介绍文案
32
- */
33
- description: string[]
34
- /**
35
- * 首屏推荐问题列表
36
- */
37
- introPrompt: MateChatPromptItem[]
38
- /**
39
- * 底部快捷问题列表
40
- */
41
- simplePrompt: MateChatPromptItem[]
42
- /**
43
- * 客服名称
44
- */
45
- serviceName: string
46
- /**
47
- * 是否使用流式对话
48
- */
49
- useStream: boolean
50
- }
51
-
52
- /**
53
- * 配置中心返回的多个配置对象
54
- * key 为配置名称,value 为 MateChatConfig
55
- */
56
- export type MateChatConfigs = Record<string, MateChatConfig>
57
-
58
- // ==================== API 相关类型定义 ====================
59
-
60
- /**
61
- * 聊天消息接口
62
- */
63
- export interface ChatMessage {
64
- role: 'user' | 'assistant' | 'system'
65
- content: string
66
- }
67
-
68
- /**
69
- * 聊天请求参数接口
70
- */
71
- export interface ChatCompletionsRequest {
72
- chatId: string
73
- stream: boolean
74
- detail: boolean
75
- messages: ChatMessage[]
76
- customUid?: string
77
- }
78
-
79
- /**
80
- * 聊天响应使用情况接口
81
- */
82
- export interface ChatUsage {
83
- prompt_tokens: number
84
- completion_tokens: number
85
- total_tokens: number
86
- }
87
-
88
- /**
89
- * 聊天响应选择项接口
90
- */
91
- export interface ChatChoice {
92
- message: {
93
- role: 'assistant'
94
- content: string
95
- }
96
- finish_reason: string
97
- index: number
98
- }
99
-
100
- /**
101
- * 聊天响应接口
102
- */
103
- export interface ChatCompletionsResponse {
104
- id: string
105
- model: string
106
- usage: ChatUsage
107
- choices: ChatChoice[]
108
- }
109
-
110
- /**
111
- * 业务层聊天结果
112
- */
113
- export interface ChatBizResult {
114
- /**
115
- * normal: 普通回复
116
- * transfer: 转人工
117
- */
118
- type: 'normal' | 'transfer'
119
- /**
120
- * 大模型原始返回内容
121
- */
122
- content: string
123
- }
124
-
125
- /**
126
- * 流式对话回调
127
- */
128
- export interface ChatStreamCallbacks {
129
- /**
130
- * 每次收到 FastGPT SSE 的增量内容时触发
131
- */
132
- onMessage?: (chunk: string) => void
133
- /**
134
- * 流结束时触发(包括收到 [DONE] 或正常读取结束)
135
- */
136
- onComplete?: () => void
137
- /**
138
- * 请求或解析发生异常时触发
139
- */
140
- onError?: (error: unknown) => void
141
- }
142
-
143
- /**
144
- * 历史会话项接口
145
- */
146
- export interface ChatHistoryItem {
147
- chatId: string
148
- updateTime: string
149
- appId: string
150
- customTitle: string
151
- title: string
152
- top: boolean
153
- [key: string]: any
154
- }
155
-
156
- /**
157
- * 历史会话查询请求参数接口
158
- */
159
- export interface GetHistoriesRequest {
160
- appId: string
161
- outLinkUid: string
162
- offset: number
163
- pageSize: number
164
- source: string
165
- }
166
-
167
- /**
168
- * 历史会话查询响应接口
169
- */
170
- export interface GetHistoriesResponse {
171
- code: number
172
- statusText: string
173
- message: string
174
- data: {
175
- list: ChatHistoryItem[]
176
- total: number
177
- }
178
- }
179
-
180
- /**
181
- * 历史会话记录项接口
182
- */
183
- export interface ChatRecordItem {
184
- _id: string
185
- dataId: string
186
- hideInUI: boolean
187
- obj: 'Human' | 'AI'
188
- value: Array<{
189
- type: string
190
- text: {
191
- content: string
192
- }
193
- }>
194
- customFeedbacks: any[]
195
- time: string
196
- durationSeconds?: number
197
- llmModuleAccount?: number
198
- totalQuoteList?: any[]
199
- historyPreviewLength?: number
200
- [key: string]: any
201
- }
202
-
203
- /**
204
- * 获取历史会话记录请求参数接口
205
- */
206
- export interface GetPaginationRecordsRequest {
207
- appId: string
208
- chatId: string
209
- offset: number
210
- pageSize: number
211
- loadCustomFeedbacks: boolean
212
- }
213
-
214
- /**
215
- * 获取历史会话记录响应接口
216
- */
217
- export interface GetPaginationRecordsResponse {
218
- code: number
219
- statusText: string
220
- message: string
221
- data: {
222
- list: ChatRecordItem[]
223
- total: number
224
- }
225
- }
226
-
227
- // ==================== MateChat 组件内部类型 ====================
228
-
229
- /**
230
- * MateChat 组件内部使用的消息结构
231
- */
232
- export interface MateChatMessage {
233
- from: 'user' | 'model' | 'service'
234
- content: string
235
- loading?: boolean
236
- }
1
+ /**
2
+ * MateChat 提示项接口
3
+ */
4
+ export interface MateChatPromptItem {
5
+ value: string
6
+ label: string
7
+ iconConfig?: {
8
+ name: string
9
+ color?: string
10
+ }
11
+ desc?: string
12
+ }
13
+
14
+ /**
15
+ * MateChat 配置接口
16
+ */
17
+ export interface MateChatConfig {
18
+ /**
19
+ * 可选密码,如果存在则需要密码验证
20
+ */
21
+ password?: string
22
+ /**
23
+ * FastGPT 应用 ID
24
+ */
25
+ appId: string
26
+ /**
27
+ * FastGPT API Key
28
+ */
29
+ appKey: string
30
+ /**
31
+ * 介绍文案
32
+ */
33
+ description: string[]
34
+ /**
35
+ * 首屏推荐问题列表
36
+ */
37
+ introPrompt: MateChatPromptItem[]
38
+ /**
39
+ * 底部快捷问题列表
40
+ */
41
+ simplePrompt: MateChatPromptItem[]
42
+ /**
43
+ * 客服名称
44
+ */
45
+ serviceName: string
46
+ /**
47
+ * 是否使用流式对话
48
+ */
49
+ useStream: boolean
50
+ /**
51
+ * 背景渐变颜色(CSS linear-gradient 字符串)
52
+ * 如果不提供,使用默认蓝白渐变
53
+ */
54
+ backgroundGradient?: string
55
+ }
56
+
57
+ /**
58
+ * 配置中心返回的多个配置对象
59
+ * key 为配置名称,value 为 MateChatConfig
60
+ */
61
+ export type MateChatConfigs = Record<string, MateChatConfig>
62
+
63
+ // ==================== API 相关类型定义 ====================
64
+
65
+ /**
66
+ * 聊天消息接口
67
+ */
68
+ export interface ChatMessage {
69
+ role: 'user' | 'assistant' | 'system'
70
+ content: string
71
+ }
72
+
73
+ /**
74
+ * 聊天请求参数接口
75
+ */
76
+ export interface ChatCompletionsRequest {
77
+ chatId: string
78
+ stream: boolean
79
+ detail: boolean
80
+ messages: ChatMessage[]
81
+ customUid?: string
82
+ }
83
+
84
+ /**
85
+ * 聊天响应使用情况接口
86
+ */
87
+ export interface ChatUsage {
88
+ prompt_tokens: number
89
+ completion_tokens: number
90
+ total_tokens: number
91
+ }
92
+
93
+ /**
94
+ * 聊天响应选择项接口
95
+ */
96
+ export interface ChatChoice {
97
+ message: {
98
+ role: 'assistant'
99
+ content: string
100
+ }
101
+ finish_reason: string
102
+ index: number
103
+ }
104
+
105
+ /**
106
+ * 聊天响应接口
107
+ */
108
+ export interface ChatCompletionsResponse {
109
+ id: string
110
+ model: string
111
+ usage: ChatUsage
112
+ choices: ChatChoice[]
113
+ }
114
+
115
+ /**
116
+ * 业务层聊天结果
117
+ */
118
+ export interface ChatBizResult {
119
+ /**
120
+ * normal: 普通回复
121
+ * transfer: 转人工
122
+ */
123
+ type: 'normal' | 'transfer'
124
+ /**
125
+ * 大模型原始返回内容
126
+ */
127
+ content: string
128
+ }
129
+
130
+ /**
131
+ * 流式对话回调
132
+ */
133
+ export interface ChatStreamCallbacks {
134
+ /**
135
+ * 每次收到 FastGPT SSE 的增量内容时触发
136
+ */
137
+ onMessage?: (chunk: string) => void
138
+ /**
139
+ * 流结束时触发(包括收到 [DONE] 或正常读取结束)
140
+ */
141
+ onComplete?: () => void
142
+ /**
143
+ * 请求或解析发生异常时触发
144
+ */
145
+ onError?: (error: unknown) => void
146
+ }
147
+
148
+ /**
149
+ * 历史会话项接口
150
+ */
151
+ export interface ChatHistoryItem {
152
+ chatId: string
153
+ updateTime: string
154
+ appId: string
155
+ customTitle: string
156
+ title: string
157
+ top: boolean
158
+ [key: string]: any
159
+ }
160
+
161
+ /**
162
+ * 历史会话查询请求参数接口
163
+ */
164
+ export interface GetHistoriesRequest {
165
+ appId: string
166
+ outLinkUid: string
167
+ offset: number
168
+ pageSize: number
169
+ source: string
170
+ }
171
+
172
+ /**
173
+ * 历史会话查询响应接口
174
+ */
175
+ export interface GetHistoriesResponse {
176
+ code: number
177
+ statusText: string
178
+ message: string
179
+ data: {
180
+ list: ChatHistoryItem[]
181
+ total: number
182
+ }
183
+ }
184
+
185
+ /**
186
+ * 历史会话记录项接口
187
+ */
188
+ export interface ChatRecordItem {
189
+ _id: string
190
+ dataId: string
191
+ hideInUI: boolean
192
+ obj: 'Human' | 'AI'
193
+ value: Array<{
194
+ type: string
195
+ text: {
196
+ content: string
197
+ }
198
+ }>
199
+ customFeedbacks: any[]
200
+ time: string
201
+ durationSeconds?: number
202
+ llmModuleAccount?: number
203
+ totalQuoteList?: any[]
204
+ historyPreviewLength?: number
205
+ [key: string]: any
206
+ }
207
+
208
+ /**
209
+ * 获取历史会话记录请求参数接口
210
+ */
211
+ export interface GetPaginationRecordsRequest {
212
+ appId: string
213
+ chatId: string
214
+ offset: number
215
+ pageSize: number
216
+ loadCustomFeedbacks: boolean
217
+ }
218
+
219
+ /**
220
+ * 获取历史会话记录响应接口
221
+ */
222
+ export interface GetPaginationRecordsResponse {
223
+ code: number
224
+ statusText: string
225
+ message: string
226
+ data: {
227
+ list: ChatRecordItem[]
228
+ total: number
229
+ }
230
+ }
231
+
232
+ // ==================== MateChat 组件内部类型 ====================
233
+
234
+ /**
235
+ * MateChat 组件内部使用的消息结构
236
+ */
237
+ export interface MateChatMessage {
238
+ from: 'user' | 'model' | 'service'
239
+ content: string
240
+ loading?: boolean
241
+ }