Skip to content

Commit 53501ed

Browse files
committed
fix: codereview
1 parent 55f90c3 commit 53501ed

24 files changed

Lines changed: 388 additions & 1275 deletions

File tree

packages/plugins/robot/src/Main.vue

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
<div class="robot">
33
<toolbar-base
44
content="AI对话框"
5-
:icon="options.icon?.default || options?.icon"
6-
:options="options"
5+
:icon="props.options.icon?.default || props.options?.icon"
6+
:options="props.options"
77
@click-api="openAIRobot"
88
>
99
</toolbar-base>
@@ -79,8 +79,7 @@
7979
<script setup lang="ts">
8080
import { computed, h, onMounted, ref, watch } from 'vue'
8181
import { ToolbarBase } from '@opentiny/tiny-engine-common'
82-
import { TinyNotify } from '@opentiny/vue'
83-
import { META_APP, useLayout } from '@opentiny/tiny-engine-meta-register'
82+
import { META_APP, useLayout, useNotify } from '@opentiny/tiny-engine-meta-register'
8483
import { type PopupConfig, type PromptProps, TrIconButton } from '@opentiny/tiny-robot'
8584
import { IconThink, IconNewSession } from '@opentiny/tiny-robot-svgs'
8685
import RobotChat from './components/chat/RobotChat.vue'
@@ -94,7 +93,7 @@ import useModelConfig from './composables/core/useConfig'
9493
import { ChatMode } from './types/mode.types'
9594
import apiService from './services/api'
9695
97-
const { options } = defineProps({
96+
const props = defineProps({
9897
options: {
9998
type: Object,
10099
default: () => ({})
@@ -172,7 +171,9 @@ const handleDeleteConversation = (action: any, item: any) => {
172171
173172
const handleAbortRequest = () => {
174173
abortRequest()
175-
messages.value.at(-1)!.aborted = true
174+
if (messages.value.at(-1)) {
175+
messages.value.at(-1)!.aborted = true
176+
}
176177
}
177178
178179
const isVisualModel = computed(() => {
@@ -193,20 +194,16 @@ const isToolsModel = computed(() => {
193194
194195
const handleChatModeChange = (type: string) => {
195196
changeChatMode(type)
196-
// singleAttachmentItems.value = []
197-
// imageUrl.value = ''
198197
}
199198
200199
const checkApiKey = () => {
201200
const provider = getSelectedModelInfo().service
202201
203202
if (!provider?.baseUrl || (!provider?.apiKey && !provider?.allowEmptyApiKey)) {
204-
TinyNotify({
203+
useNotify({
205204
type: 'warning',
206205
title: '未设置API Key,请检查设置',
207-
message: '请先设置大模型API Key后重试。',
208-
position: 'top-right',
209-
duration: 5000
206+
message: '请先设置大模型API Key后重试。'
210207
})
211208
setTimeout(() => {
212209
showSetting.value = true
@@ -249,18 +246,21 @@ const openAIRobot = () => {
249246
// 当前Robot的bubbleRenderers无法做到响应式更新,因此Agent模式的type要与Chat模式不同
250247
const bubbleRenderers = { 'agent-content': AgentRenderer, 'agent-loading': AgentRenderer }
251248
252-
const handleFileSelected = (formData: FormData, updateAttachment: (resourceUrl: string) => void) => {
249+
const handleFileSelected = async (formData: FormData, updateAttachment: (resourceUrl: string) => void) => {
253250
try {
254-
apiService.uploadFile(formData).then((res: any) => {
255-
updateAttachment(res?.resourceUrl)
256-
if (!inputMessage.value) {
257-
inputMessage.value = '生成图片中UI效果'
258-
}
259-
})
251+
const { resourceUrl } = await apiService.uploadFile(formData)
252+
updateAttachment(resourceUrl)
253+
if (!inputMessage.value) {
254+
inputMessage.value = '生成图片中UI效果'
255+
}
260256
} catch (error) {
261257
// eslint-disable-next-line no-console
262258
console.error('上传失败', error)
263259
updateAttachment('')
260+
useNotify({
261+
message: '文件上传失败,请重试',
262+
type: 'error'
263+
})
264264
}
265265
}
266266

packages/plugins/robot/src/components/chat/FooterButton.vue

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
2-
<tiny-tooltip :content="tooltipContent" placement="top" effect="light" :open-delay="500">
3-
<div :class="['footer-button-wrapper', active ? 'active' : '']" @click="handleVisibleToggle">
2+
<tiny-tooltip :content="props.tooltipContent" placement="top" effect="light" :open-delay="500">
3+
<div :class="['footer-button-wrapper', props.active ? 'active' : '']" @click="handleVisibleToggle">
44
<div class="button">
55
<slot name="icon"></slot>
66
<span class="text">
@@ -14,7 +14,7 @@
1414
<script lang="ts" setup>
1515
import { TinyTooltip } from '@opentiny/vue'
1616
17-
const { active, tooltipContent } = defineProps({
17+
const props = defineProps({
1818
active: {
1919
type: Boolean,
2020
default: false
@@ -28,7 +28,7 @@ const { active, tooltipContent } = defineProps({
2828
const emit = defineEmits(['update:active'])
2929
3030
const handleVisibleToggle = () => {
31-
emit('update:active', !active)
31+
emit('update:active', !props.active)
3232
}
3333
</script>
3434

@@ -44,7 +44,7 @@ const handleVisibleToggle = () => {
4444
border: 1px solid rgb(194, 194, 194);
4545
cursor: pointer;
4646
box-sizing: border-box;
47-
background-color: var(--te-common-bg-container);
47+
background-color: var(--te-base-gray-10);
4848
4949
&:hover {
5050
background-color: rgba(0, 0, 0, 0.08);

packages/plugins/robot/src/components/chat/RobotChat.vue

Lines changed: 51 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<tr-welcome title="AI助手" description="您好,我是您的开发小助手" :icon="welcomeIcon" class="robot-welcome">
1616
</tr-welcome>
1717
<tr-prompts
18-
:items="promptItems"
18+
:items="props.promptItems"
1919
:wrap="true"
2020
item-class="prompt-item"
2121
class="tiny-prompts"
@@ -33,26 +33,25 @@
3333
ref="senderRef"
3434
mode="multiple"
3535
v-model="inputMessage"
36-
:placeholder="GeneratingStatus.includes(status) ? '正在思考中...' : '请输入您的问题'"
36+
:placeholder="GeneratingStatus.includes(props.status) ? '正在思考中...' : '请输入您的问题'"
3737
:clearable="true"
38-
:loading="GeneratingStatus.includes(status)"
38+
:loading="GeneratingStatus.includes(props.status)"
3939
:showWordLimit="true"
4040
:maxLength="4000"
4141
@submit="handleSendMessage"
4242
@cancel="handleAbortRequest"
43-
:allowFiles="singleAttachmentItems.length < 1 && allowFiles"
43+
:allowFiles="selectedAttachments.length < 1 && props.allowFiles"
4444
uploadTooltip="支持上传1张图片"
4545
@files-selected="handleSingleFilesSelected"
4646
>
47-
<template #header v-if="singleAttachmentItems.length > 0">
47+
<template #header v-if="selectedAttachments.length > 0">
4848
<div>
4949
<tr-attachments
5050
ref="singleAttachmentRef"
51-
v-model:items="singleAttachmentItems"
51+
v-model:items="selectedAttachments"
5252
variant="card"
5353
wrap
54-
@file-remove="handleSingleFileRemove"
55-
@file-retry="handleSingleFileRetry"
54+
@retry="handleSingleFileRetry"
5655
>
5756
</tr-attachments>
5857
</div>
@@ -67,8 +66,7 @@
6766
</template>
6867

6968
<script setup lang="ts">
70-
import { ref, computed, h, resolveComponent, type Component, type CSSProperties, type PropType } from 'vue'
71-
import { Notify } from '@opentiny/vue'
69+
import { ref, computed, h, resolveComponent, type Component, type CSSProperties, type PropType, watch } from 'vue'
7270
import {
7371
TrBubbleList,
7472
TrBubbleProvider,
@@ -78,12 +76,14 @@ import {
7876
TrWelcome,
7977
TrAttachments,
8078
type BubbleRoleConfig,
81-
type PromptProps
79+
type PromptProps,
80+
type RawFileAttachment
8281
} from '@opentiny/tiny-robot'
8382
import { type ChatMessage, GeneratingStatus } from '@opentiny/tiny-robot-kit'
8483
import { LoadingRenderer, MarkdownRenderer, ImgRenderer } from '../renderers'
84+
import { useNotify } from '@opentiny/tiny-engine-meta-register'
8585
86-
const { promptItems, status, promptClickHandler, allowFiles, bubbleRenderers, beforeSubmit } = defineProps({
86+
const props = defineProps({
8787
promptItems: {
8888
type: Array as PropType<PromptProps[]>,
8989
default: () => []
@@ -108,71 +108,69 @@ const { promptItems, status, promptClickHandler, allowFiles, bubbleRenderers, be
108108
109109
const emit = defineEmits(['fileSelected', 'sendMessage', 'abort'])
110110
111-
const singleAttachmentItems = ref([])
111+
const selectedAttachments = ref([])
112112
113113
const robotVisible = defineModel<boolean>('show', { required: true })
114114
const fullscreen = defineModel<boolean>('fullscreen')
115115
const inputMessage = defineModel<string>('input', { required: true })
116116
const messages = defineModel<ChatMessage[]>('messages', { required: true })
117117
118-
const imageUrl = ref('')
118+
watch(
119+
() => props.allowFiles,
120+
(value) => {
121+
if (!value) {
122+
selectedAttachments.value = []
123+
}
124+
}
125+
)
119126
120127
// 处理文件选择事件
121-
const handleSingleFilesSelected = (files: FileList | null, retry = false) => {
128+
const handleSingleFilesSelected = (files: File[] | null, retry = false) => {
129+
if (!files?.length) return
122130
if (retry) {
123-
singleAttachmentItems.value[0].status = 'uploading'
124-
singleAttachmentItems.value[0].isUploading = true
125-
singleAttachmentItems.value[0].messageType = 'uploading'
131+
Object.assign(selectedAttachments.value[0], {
132+
status: 'uploading'
133+
})
126134
} else {
127-
if (!files.length) return
128-
129-
if (files && files.length > 1) {
130-
Notify({
135+
if (files.length > 1) {
136+
useNotify({
131137
type: 'error',
132-
message: '当前仅支持上传一张图片',
133-
position: 'top-right',
134-
duration: 5000
138+
message: '当前仅支持上传一张图片'
135139
})
136140
return
137141
}
138142
139-
if (files && files.length > 0) {
140-
// 将选中的文件转换为 Attachment 格式并添加到附件列表
141-
const newAttachments = Array.from(files).map((file) => ({
142-
size: file.size,
143-
rawFile: file
144-
}))
145-
singleAttachmentItems.value.push(...newAttachments)
146-
}
143+
// 将选中的文件转换为 Attachment 格式并添加到附件列表
144+
const newAttachments = Array.from(files).map((file) => ({
145+
size: file.size,
146+
rawFile: file
147+
}))
148+
selectedAttachments.value.push(...newAttachments)
147149
}
148150
149151
// 开始上传
150152
const formData = new FormData()
151-
const fileData = retry ? files : files[0]
153+
const fileData = files[0]
152154
formData.append('file', fileData)
153155
154156
const updateAttachment = (resourceUrl: string) => {
155157
if (resourceUrl) {
156-
singleAttachmentItems.value[0].status = 'done'
157-
singleAttachmentItems.value[0].isUploading = false
158-
singleAttachmentItems.value[0].messageType = 'success'
159-
singleAttachmentItems.value[0].url = resourceUrl
158+
Object.assign(selectedAttachments.value[0], {
159+
status: 'success',
160+
url: resourceUrl
161+
})
160162
} else {
161-
singleAttachmentItems.value[0].status = 'error'
162-
singleAttachmentItems.value[0].isUploading = false
163-
singleAttachmentItems.value[0].messageType = 'error'
163+
Object.assign(selectedAttachments.value[0], {
164+
status: 'error'
165+
})
164166
}
165167
}
166168
167169
emit('fileSelected', formData, updateAttachment)
168170
}
169171
170-
const handleSingleFileRemove = () => {
171-
imageUrl.value = ''
172-
}
173-
174-
const handleSingleFileRetry = (file: any) => {
175-
handleSingleFilesSelected(file.file, true)
172+
const handleSingleFileRetry = (file: RawFileAttachment) => {
173+
handleSingleFilesSelected([file.rawFile], true)
176174
}
177175
178176
const getSvgIcon = (name: string, style?: CSSProperties) => {
@@ -185,7 +183,7 @@ const contentRenderers = computed(() => ({
185183
markdown: MarkdownRenderer,
186184
loading: LoadingRenderer,
187185
img: ImgRenderer,
188-
...bubbleRenderers
186+
...props.bubbleRenderers
189187
}))
190188
191189
const roles: Record<string, BubbleRoleConfig> = {
@@ -214,7 +212,7 @@ const handleSendMessage = async (content: string) => {
214212
return
215213
}
216214
217-
let result = beforeSubmit?.(content)
215+
let result = props.beforeSubmit?.(content)
218216
if (result && typeof result.then === 'function') {
219217
result = await result
220218
}
@@ -226,7 +224,7 @@ const handleSendMessage = async (content: string) => {
226224
role: 'user',
227225
content: messageContent
228226
}
229-
const files = singleAttachmentItems.value.filter((item) => item.status === 'done')
227+
const files = selectedAttachments.value.filter((item) => item.status === 'done')
230228
if (files.length > 0) {
231229
const fileMessages: ChatMessage[] = files.map((file) => ({
232230
role: 'user',
@@ -259,7 +257,7 @@ const handleSendMessage = async (content: string) => {
259257
}
260258
messages.value.push(userMessage)
261259
inputMessage.value = ''
262-
singleAttachmentItems.value = []
260+
selectedAttachments.value = []
263261
emit('sendMessage')
264262
}
265263
@@ -268,8 +266,8 @@ const handleAbortRequest = () => {
268266
}
269267
270268
const handlePromptItemClick = (ev: unknown, item: { description?: string }) => {
271-
if (promptClickHandler && typeof promptClickHandler === 'function') {
272-
promptClickHandler(item)
269+
if (props.promptClickHandler && typeof props.promptClickHandler === 'function') {
270+
props.promptClickHandler(item)
273271
} else {
274272
handleSendMessage(item.description)
275273
}

0 commit comments

Comments
 (0)