Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
admin
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
46eb8969
authored
May 25, 2024
by
YunaiV
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
【代码评审】AI:review 聊天对话的实现
parent
4c259cd6
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
105 additions
and
91 deletions
+105
-91
src/views/ai/chat/ChatEmpty.vue
+0
-5
src/views/ai/chat/Conversation.vue
+21
-20
src/views/ai/chat/Message.vue
+3
-1
src/views/ai/chat/components/Header.vue
+0
-2
src/views/ai/chat/index.vue
+29
-12
src/views/ai/chat/role/RoleList.vue
+1
-1
src/views/ai/chat/role/index.vue
+51
-50
No files found.
src/views/ai/chat/ChatEmpty.vue
View file @
46eb8969
<
template
>
<
template
>
<div
class=
"chat-empty"
>
<div
class=
"chat-empty"
>
...
@@ -15,7 +14,6 @@
...
@@ -15,7 +14,6 @@
</
template
>
</
template
>
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
const
router
=
useRouter
()
const
promptList
=
ref
<
any
[]
>
()
// 角色列表
const
promptList
=
ref
<
any
[]
>
()
// 角色列表
promptList
.
value
=
[
promptList
.
value
=
[
{
{
...
@@ -31,9 +29,6 @@ const emits = defineEmits(['onPrompt'])
...
@@ -31,9 +29,6 @@ const emits = defineEmits(['onPrompt'])
const
handlerPromptClick
=
async
({
prompt
})
=>
{
const
handlerPromptClick
=
async
({
prompt
})
=>
{
emits
(
'onPrompt'
,
prompt
)
emits
(
'onPrompt'
,
prompt
)
}
}
onMounted
(
async
()
=>
{
})
</
script
>
</
script
>
<
style
scoped
lang=
"scss"
>
<
style
scoped
lang=
"scss"
>
.chat-empty
{
.chat-empty
{
...
...
src/views/ai/chat/Conversation.vue
View file @
46eb8969
...
@@ -27,7 +27,6 @@
...
@@ -27,7 +27,6 @@
<el-empty
v-if=
"loading"
description=
"."
:v-loading=
"loading"
/>
<el-empty
v-if=
"loading"
description=
"."
:v-loading=
"loading"
/>
<!-- TODO done @fain:置顶、聊天记录、一星期钱、30天前,前端对数据重新做一下分组,或者后端接口改一下 -->
<div
v-for=
"conversationKey in Object.keys(conversationMap)"
:key=
"conversationKey"
>
<div
v-for=
"conversationKey in Object.keys(conversationMap)"
:key=
"conversationKey"
>
<div
class=
"conversation-item classify-title"
v-if=
"conversationMap[conversationKey].length"
>
<div
class=
"conversation-item classify-title"
v-if=
"conversationMap[conversationKey].length"
>
<el-text
class=
"mx-1"
size=
"small"
tag=
"b"
>
{{ conversationKey }}
</el-text>
<el-text
class=
"mx-1"
size=
"small"
tag=
"b"
>
{{ conversationKey }}
</el-text>
...
@@ -47,7 +46,6 @@
...
@@ -47,7 +46,6 @@
<img
class=
"avatar"
:src=
"conversation.roleAvatar"
/>
<img
class=
"avatar"
:src=
"conversation.roleAvatar"
/>
<span
class=
"title"
>
{{ conversation.title }}
</span>
<span
class=
"title"
>
{{ conversation.title }}
</span>
</div>
</div>
<!-- TODO done @fan:缺一个【置顶】按钮,效果改成 hover 上去展示 -->
<div
class=
"button-wrapper"
v-show=
"hoverConversationId === conversation.id"
>
<div
class=
"button-wrapper"
v-show=
"hoverConversationId === conversation.id"
>
<el-button
class=
"btn"
link
@
click
.
stop=
"handlerTop(conversation)"
>
<el-button
class=
"btn"
link
@
click
.
stop=
"handlerTop(conversation)"
>
<el-icon
title=
"置顶"
v-if=
"!conversation.pinned"
><Top
/></el-icon>
<el-icon
title=
"置顶"
v-if=
"!conversation.pinned"
><Top
/></el-icon>
...
@@ -74,6 +72,7 @@
...
@@ -74,6 +72,7 @@
</div>
</div>
<!-- 左底部:工具栏 -->
<!-- 左底部:工具栏 -->
<!-- TODO @fan:下面两个 icon,可以使用类似 <Icon icon="ep:question-filled" /> 替代哈 -->
<div
class=
"tool-box"
>
<div
class=
"tool-box"
>
<div
@
click=
"handleRoleRepository"
>
<div
@
click=
"handleRoleRepository"
>
<Icon
icon=
"ep:user"
/>
<Icon
icon=
"ep:user"
/>
...
@@ -87,7 +86,7 @@
...
@@ -87,7 +86,7 @@
<!-- ============= 额外组件 ============= -->
<!-- ============= 额外组件 ============= -->
<!--
角色仓库抽屉
-->
<!--
角色仓库抽屉
-->
<el-drawer
v-model=
"drawer"
title=
"角色仓库"
size=
"754px"
>
<el-drawer
v-model=
"drawer"
title=
"角色仓库"
size=
"754px"
>
<Role/>
<Role/>
</el-drawer>
</el-drawer>
...
@@ -109,7 +108,7 @@ const activeConversationId = ref<string | null>(null) // 选中的对话,默
...
@@ -109,7 +108,7 @@ const activeConversationId = ref<string | null>(null) // 选中的对话,默
const
hoverConversationId
=
ref
<
string
|
null
>
(
null
)
// 悬浮上去的对话
const
hoverConversationId
=
ref
<
string
|
null
>
(
null
)
// 悬浮上去的对话
const
conversationList
=
ref
([]
as
ChatConversationVO
[])
// 对话列表
const
conversationList
=
ref
([]
as
ChatConversationVO
[])
// 对话列表
const
conversationMap
=
ref
<
any
>
({})
// 对话分组 (置顶、今天、三天前、一星期前、一个月前)
const
conversationMap
=
ref
<
any
>
({})
// 对话分组 (置顶、今天、三天前、一星期前、一个月前)
const
drawer
=
ref
<
boolean
>
(
false
)
// 角色仓库抽屉
const
drawer
=
ref
<
boolean
>
(
false
)
// 角色仓库抽屉
TODO @fan:roleDrawer 会不会好点哈
const
loading
=
ref
<
boolean
>
(
false
)
// 加载中
const
loading
=
ref
<
boolean
>
(
false
)
// 加载中
const
loadingTime
=
ref
<
any
>
()
// 加载中定时器
const
loadingTime
=
ref
<
any
>
()
// 加载中定时器
...
@@ -154,6 +153,7 @@ const handleConversationClick = async (id: string) => {
...
@@ -154,6 +153,7 @@ const handleConversationClick = async (id: string) => {
return
item
.
id
===
id
return
item
.
id
===
id
})
})
// 回调 onConversationClick
// 回调 onConversationClick
// TODO @fan: 这里 idea 会报黄色警告,有办法解下么?
const
res
=
emits
(
'onConversationClick'
,
filterConversation
[
0
])
const
res
=
emits
(
'onConversationClick'
,
filterConversation
[
0
])
// 切换对话
// 切换对话
if
(
res
)
{
if
(
res
)
{
...
@@ -166,18 +166,18 @@ const handleConversationClick = async (id: string) => {
...
@@ -166,18 +166,18 @@ const handleConversationClick = async (id: string) => {
*/
*/
const
getChatConversationList
=
async
()
=>
{
const
getChatConversationList
=
async
()
=>
{
try
{
try
{
// 0
、
加载中
// 0
.
加载中
loadingTime
.
value
=
setTimeout
(()
=>
{
loadingTime
.
value
=
setTimeout
(()
=>
{
loading
.
value
=
true
loading
.
value
=
true
},
50
)
},
50
)
// 1
、
获取 对话数据
// 1
.
获取 对话数据
const
res
=
await
ChatConversationApi
.
getChatConversationMyList
()
const
res
=
await
ChatConversationApi
.
getChatConversationMyList
()
// 2
、
排序
// 2
.
排序
res
.
sort
((
a
,
b
)
=>
{
res
.
sort
((
a
,
b
)
=>
{
return
b
.
createTime
-
a
.
createTime
return
b
.
createTime
-
a
.
createTime
})
})
conversationList
.
value
=
res
conversationList
.
value
=
res
// 3
、
默认选中
// 3
.
默认选中
if
(
!
activeId
?.
value
)
{
if
(
!
activeId
?.
value
)
{
// await handleConversationClick(res[0].id)
// await handleConversationClick(res[0].id)
}
else
{
}
else
{
...
@@ -189,13 +189,13 @@ const getChatConversationList = async () => {
...
@@ -189,13 +189,13 @@ const getChatConversationList = async () => {
// await handleConversationClick(res[0].id)
// await handleConversationClick(res[0].id)
// }
// }
}
}
// 4
、没有
任何对话情况
// 4
. 没有
任何对话情况
if
(
conversationList
.
value
.
length
===
0
)
{
if
(
conversationList
.
value
.
length
===
0
)
{
activeConversationId
.
value
=
null
activeConversationId
.
value
=
null
conversationMap
.
value
=
{}
conversationMap
.
value
=
{}
return
return
}
}
// 5
、
对话根据时间分组(置顶、今天、一天前、三天前、七天前、30天前)
// 5
.
对话根据时间分组(置顶、今天、一天前、三天前、七天前、30天前)
conversationMap
.
value
=
await
conversationTimeGroup
(
conversationList
.
value
)
conversationMap
.
value
=
await
conversationTimeGroup
(
conversationList
.
value
)
}
finally
{
}
finally
{
// 清理定时器
// 清理定时器
...
@@ -253,15 +253,15 @@ const conversationTimeGroup = async (list: ChatConversationVO[]) => {
...
@@ -253,15 +253,15 @@ const conversationTimeGroup = async (list: ChatConversationVO[]) => {
* 对话 - 新建
* 对话 - 新建
*/
*/
const
createConversation
=
async
()
=>
{
const
createConversation
=
async
()
=>
{
// 1
、
新建对话
// 1
.
新建对话
const
conversationId
=
await
ChatConversationApi
.
createChatConversationMy
(
const
conversationId
=
await
ChatConversationApi
.
createChatConversationMy
(
{}
as
unknown
as
ChatConversationVO
{}
as
unknown
as
ChatConversationVO
)
)
// 2
、
获取对话内容
// 2
.
获取对话内容
await
getChatConversationList
()
await
getChatConversationList
()
// 3
、
选中对话
// 3
.
选中对话
await
handleConversationClick
(
conversationId
)
await
handleConversationClick
(
conversationId
)
// 4
、
回调
// 4
.
回调
emits
(
'onConversationCreate'
)
emits
(
'onConversationCreate'
)
}
}
...
@@ -269,21 +269,21 @@ const createConversation = async () => {
...
@@ -269,21 +269,21 @@ const createConversation = async () => {
* 对话 - 更新标题
* 对话 - 更新标题
*/
*/
const
updateConversationTitle
=
async
(
conversation
:
ChatConversationVO
)
=>
{
const
updateConversationTitle
=
async
(
conversation
:
ChatConversationVO
)
=>
{
// 1
、
二次确认
// 1
.
二次确认
const
{
value
}
=
await
ElMessageBox
.
prompt
(
'修改标题'
,
{
const
{
value
}
=
await
ElMessageBox
.
prompt
(
'修改标题'
,
{
inputPattern
:
/^
[\s\S]
*.*
\S[\s\S]
*$/
,
// 判断非空,且非空格
inputPattern
:
/^
[\s\S]
*.*
\S[\s\S]
*$/
,
// 判断非空,且非空格
inputErrorMessage
:
'标题不能为空'
,
inputErrorMessage
:
'标题不能为空'
,
inputValue
:
conversation
.
title
inputValue
:
conversation
.
title
})
})
// 2
、
发起修改
// 2
.
发起修改
await
ChatConversationApi
.
updateChatConversationMy
({
await
ChatConversationApi
.
updateChatConversationMy
({
id
:
conversation
.
id
,
id
:
conversation
.
id
,
title
:
value
title
:
value
}
as
ChatConversationVO
)
}
as
ChatConversationVO
)
message
.
success
(
'重命名成功'
)
message
.
success
(
'重命名成功'
)
// 刷新列表
//
3.
刷新列表
await
getChatConversationList
()
await
getChatConversationList
()
// 过滤当前切换的
//
4.
过滤当前切换的
const
filterConversationList
=
conversationList
.
value
.
filter
(
item
=>
{
const
filterConversationList
=
conversationList
.
value
.
filter
(
item
=>
{
return
item
.
id
===
conversation
.
id
return
item
.
id
===
conversation
.
id
})
})
...
@@ -316,6 +316,7 @@ const deleteChatConversation = async (conversation: ChatConversationVO) => {
...
@@ -316,6 +316,7 @@ const deleteChatConversation = async (conversation: ChatConversationVO) => {
/**
/**
* 对话置顶
* 对话置顶
*/
*/
// TODO @fan:应该是 handleXXX,handler 是名词哈
const
handlerTop
=
async
(
conversation
:
ChatConversationVO
)
=>
{
const
handlerTop
=
async
(
conversation
:
ChatConversationVO
)
=>
{
// 更新对话置顶
// 更新对话置顶
conversation
.
pinned
=
!
conversation
.
pinned
conversation
.
pinned
=
!
conversation
.
pinned
...
@@ -324,9 +325,9 @@ const handlerTop = async (conversation: ChatConversationVO) => {
...
@@ -324,9 +325,9 @@ const handlerTop = async (conversation: ChatConversationVO) => {
await
getChatConversationList
()
await
getChatConversationList
()
}
}
// TODO @fan:类似 ============ 分块的,最后后面也有 ============ 哈
// ============ 角色仓库
// ============ 角色仓库
/**
/**
* 角色仓库抽屉
* 角色仓库抽屉
*/
*/
...
@@ -336,11 +337,11 @@ const handleRoleRepository = async () => {
...
@@ -336,11 +337,11 @@ const handleRoleRepository = async () => {
// ============= 清空对话
// ============= 清空对话
/**
/**
* 清空对话
* 清空对话
*/
*/
const
handleClearConversation
=
async
()
=>
{
const
handleClearConversation
=
async
()
=>
{
// TODO @fan:可以使用 await message.confirm( 简化,然后使用 await 改成同步的逻辑,会更简洁
ElMessageBox
.
confirm
(
ElMessageBox
.
confirm
(
'确认后对话会全部清空,置顶的对话除外。'
,
'确认后对话会全部清空,置顶的对话除外。'
,
'确认提示'
,
'确认提示'
,
...
...
src/views/ai/chat/Message.vue
View file @
46eb8969
...
@@ -57,7 +57,7 @@
...
@@ -57,7 +57,7 @@
</div>
</div>
</div>
</div>
</div>
</div>
<!--
回到底部
-->
<!--
回到底部
-->
<div
v-if=
"isScrolling"
class=
"to-bottom"
@
click=
"handleGoBottom"
>
<div
v-if=
"isScrolling"
class=
"to-bottom"
@
click=
"handleGoBottom"
>
<el-button
:icon=
"ArrowDownBold"
circle
/>
<el-button
:icon=
"ArrowDownBold"
circle
/>
</div>
</div>
...
@@ -106,6 +106,7 @@ const messageList = computed(() => {
...
@@ -106,6 +106,7 @@ const messageList = computed(() => {
const
scrollToBottom
=
async
(
isIgnore
?:
boolean
)
=>
{
const
scrollToBottom
=
async
(
isIgnore
?:
boolean
)
=>
{
await
nextTick
(()
=>
{
await
nextTick
(()
=>
{
// TODO @fan:中文写作习惯,中英文之间要有空格;另外,nextick 哈,idea 如果有绿色波兰线,可以关注下
//注意要使用nexttick以免获取不到dom
//注意要使用nexttick以免获取不到dom
if
(
isIgnore
||
!
isScrolling
.
value
)
{
if
(
isIgnore
||
!
isScrolling
.
value
)
{
messageContainer
.
value
.
scrollTop
=
messageContainer
.
value
.
scrollTop
=
...
@@ -184,6 +185,7 @@ const handlerGoTop = async () => {
...
@@ -184,6 +185,7 @@ const handlerGoTop = async () => {
}
}
// 监听 list
// 监听 list
// TODO @fan:这个木有,是不是删除啦
const
{
list
,
conversationId
}
=
toRefs
(
props
)
const
{
list
,
conversationId
}
=
toRefs
(
props
)
watch
(
list
,
async
(
newValue
,
oldValue
)
=>
{
watch
(
list
,
async
(
newValue
,
oldValue
)
=>
{
console
.
log
(
'watch list'
,
list
)
console
.
log
(
'watch list'
,
list
)
...
...
src/views/ai/chat/components/Header.vue
View file @
46eb8969
...
@@ -45,6 +45,4 @@ defineProps({
...
@@ -45,6 +45,4 @@ defineProps({
flex-direction
:
row
;
flex-direction
:
row
;
}
}
}
}
</
style
>
</
style
>
src/views/ai/chat/index.vue
View file @
46eb8969
...
@@ -10,27 +10,27 @@
...
@@ -10,27 +10,27 @@
/>
/>
<!-- 右侧:对话详情 -->
<!-- 右侧:对话详情 -->
<el-container
class=
"detail-container"
>
<el-container
class=
"detail-container"
>
<!-- 右顶部 TODO 芋艿:右对齐 -->
<el-header
class=
"header"
>
<el-header
class=
"header"
>
<div
class=
"title"
>
<div
class=
"title"
>
{{
activeConversation
?.
title
?
activeConversation
?.
title
:
'对话'
}}
{{
activeConversation
?.
title
?
activeConversation
?.
title
:
'对话'
}}
<span
v-if=
"list.length"
>
(
{{
list
.
length
}}
)
</span>
<span
v-if=
"list.length"
>
(
{{
list
.
length
}}
)
</span>
</div>
</div>
<div
class=
"btns"
v-if=
"activeConversation"
>
<div
class=
"btns"
v-if=
"activeConversation"
>
<!-- TODO @fan:样式改下;这里我已经改成点击后,弹出了 -->
<el-button
type=
"primary"
bg
plain
size=
"small"
@
click=
"openChatConversationUpdateForm"
>
<el-button
type=
"primary"
bg
text=
"plain"
size=
"small"
@
click=
"openChatConversationUpdateForm"
>
<span
v-html=
"activeConversation?.modelName"
></span>
<span
v-html=
"activeConversation?.modelName"
></span>
<Icon
icon=
"ep:setting"
style=
"margin-left: 10px"
/>
<Icon
icon=
"ep:setting"
style=
"margin-left: 10px"
/>
</el-button>
</el-button>
<el-button
size=
"small"
class=
"btn"
@
click=
"handlerMessageClear"
>
<el-button
size=
"small"
class=
"btn"
@
click=
"handlerMessageClear"
>
<!-- TODO @fan:style 部分,可以考虑用 unocss 替代 -->
<img
src=
"@/assets/ai/clear.svg"
style=
"height: 14px;"
/>
<img
src=
"@/assets/ai/clear.svg"
style=
"height: 14px;"
/>
</el-button>
</el-button>
<!-- TODO @fan:下面两个 icon,可以使用类似
<Icon
icon=
"ep:question-filled"
/>
替代哈 -->
<el-button
size=
"small"
:icon=
"Download"
class=
"btn"
/>
<el-button
size=
"small"
:icon=
"Download"
class=
"btn"
/>
<el-button
size=
"small"
:icon=
"Top"
class=
"btn"
@
click=
"handlerGoTop"
/>
<el-button
size=
"small"
:icon=
"Top"
class=
"btn"
@
click=
"handlerGoTop"
/>
</div>
</div>
</el-header>
</el-header>
<!-- main -->
<!-- main
:消息列表
-->
<el-main
class=
"main-container"
>
<el-main
class=
"main-container"
>
<div
>
<div
>
<div
class=
"message-container"
>
<div
class=
"message-container"
>
...
@@ -87,7 +87,7 @@
...
@@ -87,7 +87,7 @@
</el-container>
</el-container>
<!-- ========= 额外组件 ========== -->
<!-- ========= 额外组件 ========== -->
<!-- 更新对话
f
orm -->
<!-- 更新对话
F
orm -->
<ChatConversationUpdateForm
<ChatConversationUpdateForm
ref=
"chatConversationUpdateFormRef"
ref=
"chatConversationUpdateFormRef"
@
success=
"handlerTitleSuccess"
@
success=
"handlerTitleSuccess"
...
@@ -96,6 +96,7 @@
...
@@ -96,6 +96,7 @@
</
template
>
</
template
>
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
// TODO @fan:是不是把 index.vue 相关的,在这里新建一个 index 目录,然后挪进去哈。因为 /ai/chat 还会有其它功能。例如说,现在的 /ai/chat/manager 管理
import
Conversation
from
'./Conversation.vue'
import
Conversation
from
'./Conversation.vue'
import
Message
from
'./Message.vue'
import
Message
from
'./Message.vue'
import
ChatEmpty
from
'./ChatEmpty.vue'
import
ChatEmpty
from
'./ChatEmpty.vue'
...
@@ -120,15 +121,17 @@ const prompt = ref<string>() // prompt
...
@@ -120,15 +121,17 @@ const prompt = ref<string>() // prompt
const
userInfo
=
ref
<
ProfileVO
>
()
// 用户信息
const
userInfo
=
ref
<
ProfileVO
>
()
// 用户信息
const
enableContext
=
ref
<
boolean
>
(
true
)
// 是否开启上下文
const
enableContext
=
ref
<
boolean
>
(
true
)
// 是否开启上下文
// TODO @fan:这几个变量,可以注释在补下哈;另外,fullText 可以明确是生成中的消息 Text,这样更容易理解哈;
const
fullText
=
ref
(
''
);
const
fullText
=
ref
(
''
);
const
displayedText
=
ref
(
''
);
const
displayedText
=
ref
(
''
);
const
textSpeed
=
ref
<
number
>
(
50
);
// Typing speed in milliseconds
const
textSpeed
=
ref
<
number
>
(
50
);
// Typing speed in milliseconds
const
textRoleRunning
=
ref
<
boolean
>
(
false
);
// Typing speed in milliseconds
const
textRoleRunning
=
ref
<
boolean
>
(
false
);
// Typing speed in milliseconds
// chat message 列表
// chat message 列表
// TODO @fan:list、listLoading、listLoadingTime 不能体现出来是消息列表,是不是可以变量再优化下
const
list
=
ref
<
ChatMessageVO
[]
>
([])
// 列表的数据
const
list
=
ref
<
ChatMessageVO
[]
>
([])
// 列表的数据
const
listLoading
=
ref
<
boolean
>
(
false
)
// 是否加载中
const
listLoading
=
ref
<
boolean
>
(
false
)
// 是否加载中
const
listLoadingTime
=
ref
<
any
>
()
// time定时器,如果加载速度很快,就不进入加载中
const
listLoadingTime
=
ref
<
any
>
()
// time
定时器,如果加载速度很快,就不进入加载中
// 判断 消息列表 滚动的位置(用于判断是否需要滚动到消息最下方)
// 判断 消息列表 滚动的位置(用于判断是否需要滚动到消息最下方)
const
messageRef
=
ref
()
const
messageRef
=
ref
()
...
@@ -140,6 +143,7 @@ const defaultRoleAvatar = 'http://test.yudao.iocoder.cn/eaef5f41acb911dd718429a0
...
@@ -140,6 +143,7 @@ const defaultRoleAvatar = 'http://test.yudao.iocoder.cn/eaef5f41acb911dd718429a0
// =========== 自提滚动效果
// =========== 自提滚动效果
// TODO @fan:这个方法,要不加个方法注释
const
textRoll
=
async
()
=>
{
const
textRoll
=
async
()
=>
{
let
index
=
0
;
let
index
=
0
;
try
{
try
{
...
@@ -162,7 +166,7 @@ const textRoll = async () => {
...
@@ -162,7 +166,7 @@ const textRoll = async () => {
}
else
{
}
else
{
textSpeed
.
value
=
100
textSpeed
.
value
=
100
}
}
// 对话结束,就按
30
的速度
// 对话结束,就按
30
的速度
if
(
!
conversationInProgress
.
value
)
{
if
(
!
conversationInProgress
.
value
)
{
textSpeed
.
value
=
10
textSpeed
.
value
=
10
}
}
...
@@ -176,6 +180,7 @@ const textRoll = async () => {
...
@@ -176,6 +180,7 @@ const textRoll = async () => {
// 更新 message
// 更新 message
const
lastMessage
=
list
.
value
[
list
.
value
.
length
-
1
]
const
lastMessage
=
list
.
value
[
list
.
value
.
length
-
1
]
lastMessage
.
content
=
displayedText
.
value
lastMessage
.
content
=
displayedText
.
value
// TODO @fan:ist.value?,还是 ist.value.length 哈?
list
.
value
[
list
.
value
-
1
]
=
lastMessage
list
.
value
[
list
.
value
-
1
]
=
lastMessage
// 滚动到住下面
// 滚动到住下面
await
scrollToBottom
()
await
scrollToBottom
()
...
@@ -212,6 +217,7 @@ function scrollToBottom(isIgnore?: boolean) {
...
@@ -212,6 +217,7 @@ function scrollToBottom(isIgnore?: boolean) {
// ============= 处理聊天输入回车发送 =============
// ============= 处理聊天输入回车发送 =============
// TODO @fan:是不是可以通过 @keydown.enter、@keydown.shift.enter 来实现,回车发送、shift+回车换行;主要看看,是不是可以简化 isComposing 相关的逻辑
const
onCompositionstart
=
()
=>
{
const
onCompositionstart
=
()
=>
{
isComposing
.
value
=
true
isComposing
.
value
=
true
}
}
...
@@ -276,12 +282,14 @@ const onSendBtn = async () => {
...
@@ -276,12 +282,14 @@ const onSendBtn = async () => {
const
doSend
=
async
(
content
:
string
)
=>
{
const
doSend
=
async
(
content
:
string
)
=>
{
if
(
content
.
length
<
2
)
{
if
(
content
.
length
<
2
)
{
// TODO @fan:这个 message.error(`上传文件大小不能超过${props.fileSize}MB!`) 可以替代,这种形式
ElMessage
({
ElMessage
({
message
:
'请输入内容!'
,
message
:
'请输入内容!'
,
type
:
'error'
type
:
'error'
})
})
return
return
}
}
// TODO @fan:这个 message.error(`上传文件大小不能超过${props.fileSize}MB!`) 可以替代,这种形式
if
(
activeConversationId
.
value
==
null
)
{
if
(
activeConversationId
.
value
==
null
)
{
ElMessage
({
ElMessage
({
message
:
'还没创建对话,不能发送!'
,
message
:
'还没创建对话,不能发送!'
,
...
@@ -289,9 +297,9 @@ const doSend = async (content: string) => {
...
@@ -289,9 +297,9 @@ const doSend = async (content: string) => {
})
})
return
return
}
}
// TODO 芋艿:这块交互要在优化;应该是先插入到 UI 界面,里面会有当前的消息,和正在思考中;之后发起请求;
// 清空输入框
// 清空输入框
prompt
.
value
=
''
prompt
.
value
=
''
// TODO @fan:idea 这里会报类型错误,是不是可以解决下哈
const
userMessage
=
{
const
userMessage
=
{
conversationId
:
activeConversationId
.
value
,
conversationId
:
activeConversationId
.
value
,
content
:
content
content
:
content
...
@@ -309,6 +317,7 @@ const doSendStream = async (userMessage: ChatMessageVO) => {
...
@@ -309,6 +317,7 @@ const doSendStream = async (userMessage: ChatMessageVO) => {
fullText
.
value
=
''
fullText
.
value
=
''
try
{
try
{
// 先添加两个假数据,等 stream 返回再替换
// 先添加两个假数据,等 stream 返回再替换
// TODO @fan:idea 这里会报类型错误,是不是可以解决下哈
list
.
value
.
push
({
list
.
value
.
push
({
id
:
-
1
,
id
:
-
1
,
conversationId
:
activeConversationId
.
value
,
conversationId
:
activeConversationId
.
value
,
...
@@ -326,13 +335,14 @@ const doSendStream = async (userMessage: ChatMessageVO) => {
...
@@ -326,13 +335,14 @@ const doSendStream = async (userMessage: ChatMessageVO) => {
createTime
:
new
Date
()
createTime
:
new
Date
()
}
as
ChatMessageVO
)
}
as
ChatMessageVO
)
// 滚动到最下面
// 滚动到最下面
// TODO @fan:可以 await nextTick();然后同步调用 scrollToBottom()
nextTick
(
async
()
=>
{
nextTick
(
async
()
=>
{
await
scrollToBottom
()
await
scrollToBottom
()
})
})
// 开始滚动
// 开始滚动
textRoll
()
textRoll
()
// 发送 event stream
// 发送 event stream
let
isFirstMessage
=
true
let
isFirstMessage
=
true
// TODO @fan:isFirstChunk 会更精准
ChatMessageApi
.
sendStream
(
ChatMessageApi
.
sendStream
(
userMessage
.
conversationId
,
// TODO 芋艿:这里可能要在优化;
userMessage
.
conversationId
,
// TODO 芋艿:这里可能要在优化;
userMessage
.
content
,
userMessage
.
content
,
...
@@ -367,12 +377,14 @@ const doSendStream = async (userMessage: ChatMessageVO) => {
...
@@ -367,12 +377,14 @@ const doSendStream = async (userMessage: ChatMessageVO) => {
},
},
(
error
)
=>
{
(
error
)
=>
{
message
.
alert
(
`对话异常!
${
error
}
`
)
message
.
alert
(
`对话异常!
${
error
}
`
)
// TODO @fan:是不是可以复用 stopStream 方法
// 标记对话结束
// 标记对话结束
conversationInProgress
.
value
=
false
conversationInProgress
.
value
=
false
// 结束 stream 对话
// 结束 stream 对话
conversationInAbortController
.
value
.
abort
()
conversationInAbortController
.
value
.
abort
()
},
},
()
=>
{
()
=>
{
// TODO @fan:是不是可以复用 stopStream 方法
// 标记对话结束
// 标记对话结束
conversationInProgress
.
value
=
false
conversationInProgress
.
value
=
false
// 结束 stream 对话
// 结束 stream 对话
...
@@ -412,6 +424,7 @@ const messageList = computed(() => {
...
@@ -412,6 +424,7 @@ const messageList = computed(() => {
return
[]
return
[]
})
})
// TODO @fan:一般情况下,项目方法注释用 /** */,啊哈,主要保持风格统一,= = 少占点行哈,
/**
/**
* 获取 - message 列表
* 获取 - message 列表
*/
*/
...
@@ -500,6 +513,7 @@ const handleConversationClick = async (conversation: ChatConversationVO) => {
...
@@ -500,6 +513,7 @@ const handleConversationClick = async (conversation: ChatConversationVO) => {
* 对话 - 清理全部对话
* 对话 - 清理全部对话
*/
*/
const
handlerConversationClear
=
async
()
=>
{
const
handlerConversationClear
=
async
()
=>
{
// TODO @fan:需要加一个 对话进行中,不允许切换
activeConversationId
.
value
=
null
activeConversationId
.
value
=
null
activeConversation
.
value
=
null
activeConversation
.
value
=
null
list
.
value
=
[]
list
.
value
=
[]
...
@@ -509,7 +523,7 @@ const handlerConversationClear = async ()=> {
...
@@ -509,7 +523,7 @@ const handlerConversationClear = async ()=> {
* 对话 - 删除
* 对话 - 删除
*/
*/
const
handlerConversationDelete
=
async
(
delConversation
:
ChatConversationVO
)
=>
{
const
handlerConversationDelete
=
async
(
delConversation
:
ChatConversationVO
)
=>
{
// 删除的对话如果是当前选中的,那么
久
重置
// 删除的对话如果是当前选中的,那么
就
重置
if
(
activeConversationId
.
value
===
delConversation
.
id
)
{
if
(
activeConversationId
.
value
===
delConversation
.
id
)
{
await
handlerConversationClear
()
await
handlerConversationClear
()
}
}
...
@@ -532,6 +546,7 @@ const getConversation = async (id: string | null) => {
...
@@ -532,6 +546,7 @@ const getConversation = async (id: string | null) => {
/**
/**
* 对话 - 新建
* 对话 - 新建
*/
*/
// TODO @fan:应该是 handleXXX,handler 是名词哈
const
handlerNewChat
=
async
()
=>
{
const
handlerNewChat
=
async
()
=>
{
// 创建对话
// 创建对话
await
conversationRef
.
value
.
createConversation
()
await
conversationRef
.
value
.
createConversation
()
...
@@ -552,14 +567,14 @@ const handlerMessageDelete = async () => {
...
@@ -552,14 +567,14 @@ const handlerMessageDelete = async () => {
}
}
/**
/**
* 编辑 message
* 编辑 message
:设置为 prompt,可以再次编辑
*/
*/
const
handlerMessageEdit
=
async
(
message
:
ChatMessageVO
)
=>
{
const
handlerMessageEdit
=
async
(
message
:
ChatMessageVO
)
=>
{
prompt
.
value
=
message
.
content
prompt
.
value
=
message
.
content
}
}
/**
/**
*
编辑 message
*
刷新 message:基于指定消息,再次发起对话
*/
*/
const
handlerMessageRefresh
=
async
(
message
:
ChatMessageVO
)
=>
{
const
handlerMessageRefresh
=
async
(
message
:
ChatMessageVO
)
=>
{
await
doSend
(
message
.
content
)
await
doSend
(
message
.
content
)
...
@@ -579,10 +594,12 @@ const handlerMessageClear = async () => {
...
@@ -579,10 +594,12 @@ const handlerMessageClear = async () => {
if
(
!
activeConversationId
.
value
)
{
if
(
!
activeConversationId
.
value
)
{
return
return
}
}
// TODO @fan:需要 try catch 下,不然点击取消会报异常
// 确认提示
// 确认提示
await
message
.
delConfirm
(
"确认清空对话消息?"
)
await
message
.
delConfirm
(
"确认清空对话消息?"
)
// 清空对话
// 清空对话
await
ChatMessageApi
.
deleteByConversationId
(
activeConversationId
.
value
as
string
)
await
ChatMessageApi
.
deleteByConversationId
(
activeConversationId
.
value
as
string
)
// TODO @fan:是不是直接置空就好啦;
// 刷新 message 列表
// 刷新 message 列表
await
getMessageList
()
await
getMessageList
()
}
}
...
...
src/views/ai/chat/role/RoleList.vue
View file @
46eb8969
...
@@ -10,6 +10,7 @@
...
@@ -10,6 +10,7 @@
<el-icon><More
/></el-icon>
<el-icon><More
/></el-icon>
</el-button>
</el-button>
</span>
</span>
<!-- TODO @fan:下面两个 icon,可以使用类似
<Icon
icon=
"ep:question-filled"
/>
替代哈 -->
<template
#
dropdown
>
<template
#
dropdown
>
<el-dropdown-menu>
<el-dropdown-menu>
<el-dropdown-item
:command=
"['edit', role]"
>
<el-dropdown-item
:command=
"['edit', role]"
>
...
@@ -31,7 +32,6 @@
...
@@ -31,7 +32,6 @@
<div
class=
"content-container"
>
<div
class=
"content-container"
>
<div
class=
"title"
>
{{ role.name }}
</div>
<div
class=
"title"
>
{{ role.name }}
</div>
<div
class=
"description"
>
{{ role.description }}
</div>
<div
class=
"description"
>
{{ role.description }}
</div>
</div>
</div>
<div
class=
"btn-container"
>
<div
class=
"btn-container"
>
<el-button
type=
"primary"
size=
"small"
@
click=
"handleUseClick(role)"
>
使用
</el-button>
<el-button
type=
"primary"
size=
"small"
@
click=
"handleUseClick(role)"
>
使用
</el-button>
...
...
src/views/ai/chat/role/index.vue
View file @
46eb8969
<!-- chat 角色仓库 -->
<!-- chat 角色仓库 -->
<
template
>
<
template
>
<el-container
class=
"role-container"
>
<el-container
class=
"role-container"
>
<ChatRoleForm
ref=
"formRef"
@
success=
"handlerAddRoleSuccess"
/>
<ChatRoleForm
ref=
"formRef"
@
success=
"handlerAddRoleSuccess"
/>
<!-- header -->
<!-- header -->
<Header
title=
"角色仓库"
style=
"position: relative"
/>
<Header
title=
"角色仓库"
style=
"position: relative"
/>
<!-- main -->
<!-- main -->
<el-main
class=
"role-main"
>
<el-main
class=
"role-main"
>
<div
class=
"search-container"
>
<div
class=
"search-container"
>
...
@@ -17,9 +17,15 @@
...
@@ -17,9 +17,15 @@
:suffix-icon=
"Search"
:suffix-icon=
"Search"
@
change=
"getActiveTabsRole"
@
change=
"getActiveTabsRole"
/>
/>
<el-button
v-if=
"activeRole == 'my-role'"
type=
"primary"
@
click=
"handlerAddRole"
style=
"margin-left: 20px;"
>
<el-button
v-if=
"activeRole == 'my-role'"
type=
"primary"
@
click=
"handlerAddRole"
style=
"margin-left: 20px"
>
<!-- TODO @fan:下面两个 icon,可以使用类似
<Icon
icon=
"ep:question-filled"
/>
替代哈 -->
<el-icon>
<el-icon>
<User/>
<User
/>
</el-icon>
</el-icon>
添加角色
添加角色
</el-button>
</el-button>
...
@@ -35,7 +41,8 @@
...
@@ -35,7 +41,8 @@
@
on-edit=
"handlerCardEdit"
@
on-edit=
"handlerCardEdit"
@
on-use=
"handlerCardUse"
@
on-use=
"handlerCardUse"
@
on-page=
"handlerCardPage('my')"
@
on-page=
"handlerCardPage('my')"
style=
"margin-top: 20px;"
/>
style=
"margin-top: 20px"
/>
</el-tab-pane>
</el-tab-pane>
<el-tab-pane
label=
"公共角色"
name=
"public-role"
>
<el-tab-pane
label=
"公共角色"
name=
"public-role"
>
<RoleCategoryList
<RoleCategoryList
...
@@ -50,34 +57,33 @@
...
@@ -50,34 +57,33 @@
@
on-edit=
"handlerCardEdit"
@
on-edit=
"handlerCardEdit"
@
on-use=
"handlerCardUse"
@
on-use=
"handlerCardUse"
@
on-page=
"handlerCardPage('public')"
@
on-page=
"handlerCardPage('public')"
style=
"margin-top: 20px;"
style=
"margin-top: 20px"
loading
/>
loading
/>
</el-tab-pane>
</el-tab-pane>
</el-tabs>
</el-tabs>
</el-main>
</el-main>
</el-container>
</el-container>
</
template
>
</
template
>
<!-- setup -->
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
{
ref
}
from
"vue"
;
import
{
ref
}
from
'vue'
import
Header
from
'@/views/ai/chat/components/Header.vue'
import
Header
from
'@/views/ai/chat/components/Header.vue'
import
RoleList
from
'./RoleList.vue'
import
RoleList
from
'./RoleList.vue'
import
ChatRoleForm
from
'@/views/ai/model/chatRole/ChatRoleForm.vue'
import
ChatRoleForm
from
'@/views/ai/model/chatRole/ChatRoleForm.vue'
import
RoleCategoryList
from
'./RoleCategoryList.vue'
import
RoleCategoryList
from
'./RoleCategoryList.vue'
import
{
ChatRoleApi
,
ChatRolePageReqVO
,
ChatRoleVO
}
from
'@/api/ai/model/chatRole'
import
{
ChatRoleApi
,
ChatRolePageReqVO
,
ChatRoleVO
}
from
'@/api/ai/model/chatRole'
import
{
ChatConversationApi
,
ChatConversationVO
}
from
'@/api/ai/chat/conversation'
import
{
ChatConversationApi
,
ChatConversationVO
}
from
'@/api/ai/chat/conversation'
import
{
TabsPaneContext
}
from
"element-plus"
;
import
{
TabsPaneContext
}
from
'element-plus'
import
{
Search
,
User
}
from
"@element-plus/icons-vue"
;
import
{
Search
,
User
}
from
'@element-plus/icons-vue'
// 获取路由
const
router
=
useRouter
()
// 路由对象
const
router
=
useRouter
()
// 属性定义
// 属性定义
const
loading
=
ref
<
boolean
>
(
false
)
// 加载中
const
loading
=
ref
<
boolean
>
(
false
)
// 加载中
const
activeRole
=
ref
<
string
>
(
'my-role'
)
// 选中的角色
const
activeRole
=
ref
<
string
>
(
'my-role'
)
// 选中的角色
TODO @fan:是不是叫 activeTab 会更明确一点哈。选中的角色,会以为是某个角色
const
search
=
ref
<
string
>
(
''
)
// 加载中
const
search
=
ref
<
string
>
(
''
)
// 加载中
// TODO @fan:要不 myPage、pubPage,搞成类似 const queryParams = reactive({ ,分别搞成两个大的参数哈?
const
myPageNo
=
ref
<
number
>
(
1
)
// my 分页下标
const
myPageNo
=
ref
<
number
>
(
1
)
// my 分页下标
const
myPageSize
=
ref
<
number
>
(
50
)
// my 分页大小
const
myPageSize
=
ref
<
number
>
(
50
)
// my 分页大小
const
myRoleList
=
ref
<
ChatRoleVO
[]
>
([])
// my 分页大小
const
myRoleList
=
ref
<
ChatRoleVO
[]
>
([])
// my 分页大小
...
@@ -86,18 +92,16 @@ const publicPageSize = ref<number>(50) // public 分页大小
...
@@ -86,18 +92,16 @@ const publicPageSize = ref<number>(50) // public 分页大小
const
publicRoleList
=
ref
<
ChatRoleVO
[]
>
([])
// public 分页大小
const
publicRoleList
=
ref
<
ChatRoleVO
[]
>
([])
// public 分页大小
const
activeCategory
=
ref
<
string
>
(
'全部'
)
// 选择中的分类
const
activeCategory
=
ref
<
string
>
(
'全部'
)
// 选择中的分类
const
categoryList
=
ref
<
string
[]
>
([])
// 角色分类类别
const
categoryList
=
ref
<
string
[]
>
([])
// 角色分类类别
/** 添加/修改操作 */
const
formRef
=
ref
()
/** tabs 点击 */
// tabs 点击
const
handleTabsClick
=
async
(
tab
:
TabsPaneContext
)
=>
{
const
handleTabsClick
=
async
(
tab
:
TabsPaneContext
)
=>
{
// 设置切换状态
// 设置切换状态
const
activeTabs
=
tab
.
paneName
+
''
activeRole
.
value
=
tab
.
paneName
+
''
activeRole
.
value
=
activeTabs
;
// 切换的时候重新加载数据
// 切换的时候重新加载数据
await
getActiveTabsRole
()
await
getActiveTabsRole
()
}
}
/
/ 获取 my role
/
** 获取 my role 我的角色 */
const
getMyRole
=
async
(
append
?:
boolean
)
=>
{
const
getMyRole
=
async
(
append
?:
boolean
)
=>
{
const
params
:
ChatRolePageReqVO
=
{
const
params
:
ChatRolePageReqVO
=
{
pageNo
:
myPageNo
.
value
,
pageNo
:
myPageNo
.
value
,
...
@@ -105,7 +109,7 @@ const getMyRole = async (append?: boolean) => {
...
@@ -105,7 +109,7 @@ const getMyRole = async (append?: boolean) => {
name
:
search
.
value
,
name
:
search
.
value
,
publicStatus
:
false
publicStatus
:
false
}
}
const
{
total
,
list
}
=
await
ChatRoleApi
.
getMyPage
(
params
)
const
{
total
,
list
}
=
await
ChatRoleApi
.
getMyPage
(
params
)
if
(
append
)
{
if
(
append
)
{
myRoleList
.
value
.
push
.
apply
(
myRoleList
.
value
,
list
)
myRoleList
.
value
.
push
.
apply
(
myRoleList
.
value
,
list
)
}
else
{
}
else
{
...
@@ -113,7 +117,7 @@ const getMyRole = async (append?: boolean) => {
...
@@ -113,7 +117,7 @@ const getMyRole = async (append?: boolean) => {
}
}
}
}
/
/ 获取 public role
/
** 获取 public role 公共角色 */
const
getPublicRole
=
async
(
append
?:
boolean
)
=>
{
const
getPublicRole
=
async
(
append
?:
boolean
)
=>
{
const
params
:
ChatRolePageReqVO
=
{
const
params
:
ChatRolePageReqVO
=
{
pageNo
:
publicPageNo
.
value
,
pageNo
:
publicPageNo
.
value
,
...
@@ -122,7 +126,7 @@ const getPublicRole = async (append?: boolean) => {
...
@@ -122,7 +126,7 @@ const getPublicRole = async (append?: boolean) => {
name
:
search
.
value
,
name
:
search
.
value
,
publicStatus
:
true
publicStatus
:
true
}
}
const
{
total
,
list
}
=
await
ChatRoleApi
.
getMyPage
(
params
)
const
{
total
,
list
}
=
await
ChatRoleApi
.
getMyPage
(
params
)
if
(
append
)
{
if
(
append
)
{
publicRoleList
.
value
.
push
.
apply
(
publicRoleList
.
value
,
list
)
publicRoleList
.
value
.
push
.
apply
(
publicRoleList
.
value
,
list
)
}
else
{
}
else
{
...
@@ -130,7 +134,7 @@ const getPublicRole = async (append?: boolean) => {
...
@@ -130,7 +134,7 @@ const getPublicRole = async (append?: boolean) => {
}
}
}
}
/
/ 获取选中的 tabs 角色
/
** 获取选中的 tabs 角色 */
const
getActiveTabsRole
=
async
()
=>
{
const
getActiveTabsRole
=
async
()
=>
{
if
(
activeRole
.
value
===
'my-role'
)
{
if
(
activeRole
.
value
===
'my-role'
)
{
myPageNo
.
value
=
1
myPageNo
.
value
=
1
...
@@ -141,14 +145,14 @@ const getActiveTabsRole = async () => {
...
@@ -141,14 +145,14 @@ const getActiveTabsRole = async () => {
}
}
}
}
/
/ 获取角色分类列表
/
** 获取角色分类列表 */
const
getRoleCategoryList
=
async
()
=>
{
const
getRoleCategoryList
=
async
()
=>
{
const
res
=
await
ChatRoleApi
.
getCategoryList
()
const
res
=
await
ChatRoleApi
.
getCategoryList
()
const
defaultRole
=
[
'全部'
]
const
defaultRole
=
[
'全部'
]
categoryList
.
value
=
[...
defaultRole
,
...
res
]
categoryList
.
value
=
[...
defaultRole
,
...
res
]
}
}
/
/ 处理分类点击
/
** 处理分类点击 */
const
handlerCategoryClick
=
async
(
category
:
string
)
=>
{
const
handlerCategoryClick
=
async
(
category
:
string
)
=>
{
// 切换选择的分类
// 切换选择的分类
activeCategory
.
value
=
category
activeCategory
.
value
=
category
...
@@ -156,11 +160,18 @@ const handlerCategoryClick = async (category: string) => {
...
@@ -156,11 +160,18 @@ const handlerCategoryClick = async (category: string) => {
await
getActiveTabsRole
()
await
getActiveTabsRole
()
}
}
// 添加角色
/** 添加/修改操作 */
const
formRef
=
ref
()
const
handlerAddRole
=
async
()
=>
{
const
handlerAddRole
=
async
()
=>
{
formRef
.
value
.
open
(
'my-create'
,
null
,
'添加角色'
)
formRef
.
value
.
open
(
'my-create'
,
null
,
'添加角色'
)
}
}
/** 添加角色成功 */
const
handlerAddRoleSuccess
=
async
(
e
)
=>
{
// 刷新数据
await
getActiveTabsRole
()
}
// card 删除
// card 删除
const
handlerCardDelete
=
async
(
role
)
=>
{
const
handlerCardDelete
=
async
(
role
)
=>
{
await
ChatRoleApi
.
deleteMy
(
role
.
id
)
await
ChatRoleApi
.
deleteMy
(
role
.
id
)
...
@@ -173,7 +184,7 @@ const handlerCardEdit = async (role) => {
...
@@ -173,7 +184,7 @@ const handlerCardEdit = async (role) => {
formRef
.
value
.
open
(
'my-update'
,
role
.
id
,
'编辑角色'
)
formRef
.
value
.
open
(
'my-update'
,
role
.
id
,
'编辑角色'
)
}
}
/
/ card 分页
/
** card 分页:获取下一页 */
const
handlerCardPage
=
async
(
type
)
=>
{
const
handlerCardPage
=
async
(
type
)
=>
{
console
.
log
(
'handlerCardPage'
,
type
)
console
.
log
(
'handlerCardPage'
,
type
)
try
{
try
{
...
@@ -190,39 +201,33 @@ const handlerCardPage = async (type) => {
...
@@ -190,39 +201,33 @@ const handlerCardPage = async (type) => {
}
}
}
}
/
/ card 使用
/
** 选择 card 角色:新建聊天对话 */
const
handlerCardUse
=
async
(
role
)
=>
{
const
handlerCardUse
=
async
(
role
)
=>
{
// 1. 创建对话
const
data
:
ChatConversationVO
=
{
const
data
:
ChatConversationVO
=
{
roleId
:
role
.
id
roleId
:
role
.
id
}
as
unknown
as
ChatConversationVO
}
as
unknown
as
ChatConversationVO
// 创建对话
const
conversationId
=
await
ChatConversationApi
.
createChatConversationMy
(
data
)
const
conversation
=
await
ChatConversationApi
.
createChatConversationMy
(
data
)
// 2. 跳转页面
//
调整页面
//
TODO @fan:最好用 name,后续可能会改~~~
router
.
push
({
await
router
.
push
({
path
:
`/ai/chat`
,
path
:
`/ai/chat`
,
query
:
{
query
:
{
conversationId
:
conversation
,
conversationId
:
conversation
Id
}
}
})
})
}
}
// 添加角色成功
/** 初始化 **/
const
handlerAddRoleSuccess
=
async
(
e
)
=>
{
console
.
log
(
e
)
// 刷新数据
await
getActiveTabsRole
()
}
//
onMounted
(
async
()
=>
{
onMounted
(
async
()
=>
{
// 获取分类
// 获取分类
await
getRoleCategoryList
()
await
getRoleCategoryList
()
// 获取 role 数据
// 获取 role 数据
await
getActiveTabsRole
()
await
getActiveTabsRole
()
})
})
// TODO @fan:css 是不是可以融合到 scss 里面呀?
</
script
>
</
script
>
<
style
lang=
"css"
>
<
style
lang=
"css"
>
.el-tabs__content
{
.el-tabs__content
{
position
:
relative
;
position
:
relative
;
height
:
100%
;
height
:
100%
;
...
@@ -232,11 +237,9 @@ onMounted(async () => {
...
@@ -232,11 +237,9 @@ onMounted(async () => {
.el-tabs__nav-scroll
{
.el-tabs__nav-scroll
{
margin
:
10px
20px
;
margin
:
10px
20px
;
}
}
</
style
>
</
style
>
<!-- 样式 -->
<!-- 样式 -->
<
style
scoped
lang=
"scss"
>
<
style
scoped
lang=
"scss"
>
//
跟容器
//
跟容器
.role-container
{
.role-container
{
position
:
absolute
;
position
:
absolute
;
...
@@ -290,6 +293,4 @@ onMounted(async () => {
...
@@ -290,6 +293,4 @@ onMounted(async () => {
}
}
}
}
}
}
</
style
>
</
style
>
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment