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
62246021
authored
Jul 08, 2024
by
YunaiV
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
【代码优化】AI:聊天对话 index.vue 代码梳理 80%(message 部分)
parent
1a6afa32
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
129 additions
and
177 deletions
+129
-177
src/views/ai/chat/index/components/conversation/ConversationList.vue
+61
-102
src/views/ai/chat/index/components/role/RoleCategoryList.vue
+13
-7
src/views/ai/chat/index/components/role/RoleHeader.vue
+0
-0
src/views/ai/chat/index/components/role/RoleList.vue
+14
-26
src/views/ai/chat/index/components/role/RoleRepository.vue
+35
-38
src/views/ai/chat/index/index.vue
+6
-4
No files found.
src/views/ai/chat/index/components/conversation/ConversationList.vue
View file @
62246021
<!-- AI 对话 -->
<
template
>
<el-aside
width=
"260px"
class=
"conversation-container
"
style=
"height:
100%"
>
<el-aside
width=
"260px"
class=
"conversation-container
h-
100%"
>
<!-- 左顶部:对话 -->
<div
style=
"height:
100%"
>
<div
class=
"h-
100%"
>
<el-button
class=
"w-1/1 btn-new-conversation"
type=
"primary"
@
click=
"createConversation"
>
<Icon
icon=
"ep:plus"
class=
"mr-5px"
/>
新建对话
...
...
@@ -23,8 +23,9 @@
<!-- 左中间:对话列表 -->
<div
class=
"conversation-list"
>
<!-- 情况一:加载中 -->
<el-empty
v-if=
"loading"
description=
"."
:v-loading=
"loading"
/>
<!-- 情况二:按照 group 分组,展示聊天会话 list 列表 -->
<div
v-for=
"conversationKey in Object.keys(conversationMap)"
:key=
"conversationKey"
>
<div
class=
"conversation-item classify-title"
...
...
@@ -50,7 +51,7 @@
<span
class=
"title"
>
{{ conversation.title }}
</span>
</div>
<div
class=
"button-wrapper"
v-show=
"hoverConversationId === conversation.id"
>
<el-button
class=
"btn"
link
@
click
.
stop=
"handle
r
Top(conversation)"
>
<el-button
class=
"btn"
link
@
click
.
stop=
"handleTop(conversation)"
>
<el-icon
title=
"置顶"
v-if=
"!conversation.pinned"
><Top
/></el-icon>
<el-icon
title=
"置顶"
v-if=
"conversation.pinned"
><Bottom
/></el-icon>
</el-button>
...
...
@@ -68,13 +69,12 @@
</div>
</div>
</div>
<!--
底部站
位 -->
<div
style=
"height: 160px; width:
100%"
></div>
<!--
底部占
位 -->
<div
class=
"h-160px w-
100%"
></div>
</div>
</div>
<!-- 左底部:工具栏 -->
<!-- TODO @fan:下面两个 icon,可以使用类似 <Icon icon="ep:question-filled" /> 替代哈 -->
<div
class=
"tool-box"
>
<div
@
click=
"handleRoleRepository"
>
<Icon
icon=
"ep:user"
/>
...
...
@@ -86,19 +86,16 @@
</div>
</div>
<!-- ============= 额外组件 ============= -->
<!-- 角色仓库抽屉 -->
<el-drawer
v-model=
"
drawer
"
title=
"角色仓库"
size=
"754px"
>
<Role
/>
<el-drawer
v-model=
"
roleRepositoryOpen
"
title=
"角色仓库"
size=
"754px"
>
<Role
Repository
/>
</el-drawer>
</el-aside>
</template>
<
script
setup
lang=
"ts"
>
import
{
ChatConversationApi
,
ChatConversationVO
}
from
'@/api/ai/chat/conversation'
import
{
ref
}
from
'vue'
import
Role
from
'../role/index.vue'
import
RoleRepository
from
'../role/RoleRepository.vue'
import
{
Bottom
,
Top
}
from
'@element-plus/icons-vue'
import
roleAvatarDefaultImg
from
'@/assets/ai/gpt.svg'
...
...
@@ -106,11 +103,10 @@ const message = useMessage() // 消息弹窗
// 定义属性
const
searchName
=
ref
<
string
>
(
''
)
// 对话搜索
const
activeConversationId
=
ref
<
string
|
null
>
(
null
)
// 选中的对话,默认为 null
const
hoverConversationId
=
ref
<
string
|
null
>
(
null
)
// 悬浮上去的对话
const
activeConversationId
=
ref
<
number
|
null
>
(
null
)
// 选中的对话,默认为 null
const
hoverConversationId
=
ref
<
number
|
null
>
(
null
)
// 悬浮上去的对话
const
conversationList
=
ref
([]
as
ChatConversationVO
[])
// 对话列表
const
conversationMap
=
ref
<
any
>
({})
// 对话分组 (置顶、今天、三天前、一星期前、一个月前)
const
drawer
=
ref
<
boolean
>
(
false
)
// 角色仓库抽屉 TODO @fan:roleDrawer 会不会好点哈
const
loading
=
ref
<
boolean
>
(
false
)
// 加载中
const
loadingTime
=
ref
<
any
>
()
// 加载中定时器
...
...
@@ -130,75 +126,58 @@ const emits = defineEmits([
'onConversationDelete'
])
/**
* 对话 - 搜索
*/
/** 搜索对话 */
const
searchConversation
=
async
(
e
)
=>
{
// 恢复数据
if
(
!
searchName
.
value
.
trim
().
length
)
{
conversationMap
.
value
=
await
conversationTimeGroup
(
conversationList
.
value
)
conversationMap
.
value
=
await
getConversationGroupByCreateTime
(
conversationList
.
value
)
}
else
{
// 过滤
const
filterValues
=
conversationList
.
value
.
filter
((
item
)
=>
{
return
item
.
title
.
includes
(
searchName
.
value
.
trim
())
})
conversationMap
.
value
=
await
conversationTimeGroup
(
filterValues
)
conversationMap
.
value
=
await
getConversationGroupByCreateTime
(
filterValues
)
}
}
/**
* 对话 - 点击
*/
const
handleConversationClick
=
async
(
id
:
string
)
=>
{
/** 点击对话 */
const
handleConversationClick
=
async
(
id
:
number
)
=>
{
// 过滤出选中的对话
const
filterConversation
=
conversationList
.
value
.
filter
((
item
)
=>
{
return
item
.
id
===
id
})
// 回调 onConversationClick
//
TODO @fan: 这里 idea 会报黄色警告,有办法解下么?
const
re
s
=
emits
(
'onConversationClick'
,
filterConversation
[
0
])
//
noinspection JSVoidFunctionReturnValueUsed
const
succes
s
=
emits
(
'onConversationClick'
,
filterConversation
[
0
])
// 切换对话
if
(
re
s
)
{
if
(
succes
s
)
{
activeConversationId
.
value
=
id
}
}
/**
* 对话 - 获取列表
*/
/** 获取对话列表 */
const
getChatConversationList
=
async
()
=>
{
try
{
//
0.
加载中
// 加载中
loadingTime
.
value
=
setTimeout
(()
=>
{
loading
.
value
=
true
},
50
)
// 1. 获取 对话数据
const
res
=
await
ChatConversationApi
.
getChatConversationMyList
()
// 2. 排序
res
.
sort
((
a
,
b
)
=>
{
// 1.1 获取 对话数据
conversationList
.
value
=
await
ChatConversationApi
.
getChatConversationMyList
()
// 1.2 排序
conversationList
.
value
.
sort
((
a
,
b
)
=>
{
return
b
.
createTime
-
a
.
createTime
})
conversationList
.
value
=
res
// 3. 默认选中
if
(
!
activeId
?.
value
)
{
// await handleConversationClick(res[0].id)
}
else
{
// tip: 删除的刚好是选中的,那么需要重新挑选一个来进行选中
// const filterConversationList = conversationList.value.filter(item => {
// return item.id === activeId.value
// })
// if (filterConversationList.length
<=
0
)
{
// await handleConversationClick(res[0].id)
// }
}
// 4. 没有任何对话情况
// 1.3 没有任何对话情况
if
(
conversationList
.
value
.
length
===
0
)
{
activeConversationId
.
value
=
null
conversationMap
.
value
=
{}
return
}
// 5. 对话根据时间分组(置顶、今天、一天前、三天前、七天前、30天前)
conversationMap
.
value
=
await
conversationTimeGroup
(
conversationList
.
value
)
// 2. 对话根据时间分组(置顶、今天、一天前、三天前、七天前、30 天前)
conversationMap
.
value
=
await
getConversationGroupByCreateTime
(
conversationList
.
value
)
}
finally
{
// 清理定时器
if
(
loadingTime
.
value
)
{
...
...
@@ -209,8 +188,10 @@ const getChatConversationList = async () => {
}
}
const
conversationTimeGroup
=
async
(
list
:
ChatConversationVO
[])
=>
{
/** 按照 creteTime 创建时间,进行分组 */
const
getConversationGroupByCreateTime
=
async
(
list
:
ChatConversationVO
[])
=>
{
// 排序、指定、时间分组(今天、一天前、三天前、七天前、30天前)
// noinspection NonAsciiCharacters
const
groupMap
=
{
置顶
:
[],
今天
:
[],
...
...
@@ -233,7 +214,7 @@ const conversationTimeGroup = async (list: ChatConversationVO[]) => {
continue
}
// 计算时间差(单位:毫秒)
const
diff
=
now
-
conversation
.
upd
ateTime
const
diff
=
now
-
conversation
.
cre
ateTime
// 根据时间间隔判断
if
(
diff
<
oneDay
)
{
groupMap
[
'今天'
].
push
(
conversation
)
...
...
@@ -250,9 +231,7 @@ const conversationTimeGroup = async (list: ChatConversationVO[]) => {
return
groupMap
}
/**
* 对话 - 新建
*/
/** 新建对话 */
const
createConversation
=
async
()
=>
{
// 1. 新建对话
const
conversationId
=
await
ChatConversationApi
.
createChatConversationMy
(
...
...
@@ -266,9 +245,7 @@ const createConversation = async () => {
emits
(
'onConversationCreate'
)
}
/**
* 对话 - 更新标题
*/
/** 修改对话的标题 */
const
updateConversationTitle
=
async
(
conversation
:
ChatConversationVO
)
=>
{
// 1. 二次确认
const
{
value
}
=
await
ElMessageBox
.
prompt
(
'修改标题'
,
{
...
...
@@ -296,9 +273,7 @@ const updateConversationTitle = async (conversation: ChatConversationVO) => {
}
}
/**
* 删除聊天对话
*/
/** 删除聊天对话 */
const
deleteChatConversation
=
async
(
conversation
:
ChatConversationVO
)
=>
{
try
{
// 删除的二次确认
...
...
@@ -313,41 +288,10 @@ const deleteChatConversation = async (conversation: ChatConversationVO) => {
}
catch
{}
}
/**
* 对话置顶
*/
// TODO @fan:应该是 handleXXX,handler 是名词哈
const
handlerTop
=
async
(
conversation
:
ChatConversationVO
)
=>
{
// 更新对话置顶
conversation
.
pinned
=
!
conversation
.
pinned
await
ChatConversationApi
.
updateChatConversationMy
(
conversation
)
// 刷新对话
await
getChatConversationList
()
}
// TODO @fan:类似 ============ 分块的,最后后面也有 ============ 哈
// ============ 角色仓库
/**
* 角色仓库抽屉
*/
const
handleRoleRepository
=
async
()
=>
{
drawer
.
value
=
!
drawer
.
value
}
// ============= 清空对话
/**
* 清空对话
*/
/** 清空对话 */
const
handleClearConversation
=
async
()
=>
{
// TODO @fan:可以使用 await message.confirm( 简化,然后使用 await 改成同步的逻辑,会更简洁
ElMessageBox
.
confirm
(
'确认后对话会全部清空,置顶的对话除外。'
,
'确认提示'
,
{
confirmButtonText
:
'确认'
,
cancelButtonText
:
'取消'
,
type
:
'warning'
})
.
then
(
async
()
=>
{
try
{
await
message
.
confirm
(
'确认后对话会全部清空,置顶的对话除外。'
)
await
ChatConversationApi
.
deleteChatConversationMyByUnpinned
()
ElMessage
({
message
:
'操作成功!'
,
...
...
@@ -359,26 +303,41 @@ const handleClearConversation = async () => {
await
getChatConversationList
()
// 回调 方法
emits
(
'onConversationClear'
)
})
.
catch
(()
=>
{})
}
catch
{}
}
/** 对话置顶 */
const
handleTop
=
async
(
conversation
:
ChatConversationVO
)
=>
{
// 更新对话置顶
conversation
.
pinned
=
!
conversation
.
pinned
await
ChatConversationApi
.
updateChatConversationMy
(
conversation
)
// 刷新对话
await
getChatConversationList
()
}
// ============ 组件 onMounted
// ============ 角色仓库 ============
/** 角色仓库抽屉 */
const
roleRepositoryOpen
=
ref
<
boolean
>
(
false
)
// 角色仓库是否打开
const
handleRoleRepository
=
async
()
=>
{
roleRepositoryOpen
.
value
=
!
roleRepositoryOpen
.
value
}
/** 监听选中的对话 */
const
{
activeId
}
=
toRefs
(
props
)
watch
(
activeId
,
async
(
newValue
,
oldValue
)
=>
{
// 更新选中
activeConversationId
.
value
=
newValue
as
string
})
// 定义 public 方法
defineExpose
({
createConversation
})
/** 初始化 */
onMounted
(
async
()
=>
{
// 获取 对话列表
await
getChatConversationList
()
// 默认选中
if
(
props
.
activeId
!=
null
)
{
if
(
props
.
activeId
)
{
activeConversationId
.
value
=
props
.
activeId
}
else
{
// 首次默认选中第一个
...
...
src/views/ai/chat/index/components/role/RoleCategoryList.vue
View file @
62246021
<
template
>
<div
class=
"category-list"
>
<div
class=
"category"
v-for=
"(category) in categoryList"
:key=
"category"
>
<el-button
plain
round
size=
"small"
v-if=
"category !== active"
@
click=
"handleCategoryClick(category)"
>
{{
category
}}
</el-button>
<el-button
plain
round
size=
"small"
v-else
type=
"primary"
@
click=
"handleCategoryClick(category)"
>
{{
category
}}
</el-button>
<div
class=
"category"
v-for=
"category in categoryList"
:key=
"category"
>
<el-button
plain
round
size=
"small"
:type=
"category === active ? 'primary' : ''"
@
click=
"handleCategoryClick(category)"
>
{{
category
}}
</el-button>
</div>
</div>
</
template
>
<
script
setup
lang=
"ts"
>
import
{
PropType
}
from
"vue"
;
import
{
PropType
}
from
'vue'
// 定义属性
defineProps
({
...
...
@@ -25,11 +32,10 @@ defineProps({
// 定义回调
const
emits
=
defineEmits
([
'onCategoryClick'
])
/
/ 处理分类点击事件
const
handleCategoryClick
=
async
(
category
)
=>
{
/
** 处理分类点击事件 */
const
handleCategoryClick
=
async
(
category
:
string
)
=>
{
emits
(
'onCategoryClick'
,
category
)
}
</
script
>
<
style
scoped
lang=
"scss"
>
.category-list
{
...
...
src/views/ai/chat/index/components/Header.vue
→
src/views/ai/chat/index/components/
role/Role
Header.vue
View file @
62246021
File moved
src/views/ai/chat/index/components/role/RoleList.vue
View file @
62246021
...
...
@@ -2,21 +2,21 @@
<div
class=
"card-list"
ref=
"tabsRef"
@
scroll=
"handleTabsScroll"
>
<div
class=
"card-item"
v-for=
"role in roleList"
:key=
"role.id"
>
<el-card
class=
"card"
body-class=
"card-body"
>
<!--
更多
-->
<!--
更多操作
-->
<div
class=
"more-container"
v-if=
"showMore"
>
<el-dropdown
@
command=
"handleMoreClick"
>
<span
class=
"el-dropdown-link"
>
<el-button
type=
"text"
>
<el-button
type=
"text"
>
<el-icon><More
/></el-icon>
</el-button>
</span>
<!-- TODO @fan:下面两个 icon,可以使用类似
<Icon
icon=
"ep:question-filled"
/>
替代哈 -->
<template
#
dropdown
>
<el-dropdown-menu>
<el-dropdown-item
:command=
"['edit', role]"
>
<el-dropdown-item
:command=
"['edit', role]"
>
<el-icon><EditPen
/></el-icon>
编辑
</el-dropdown-item>
<el-dropdown-item
:command=
"['delete', role]"
style=
"color: red;"
>
<el-dropdown-item
:command=
"['delete', role]"
style=
"color: red"
>
<el-icon><Delete
/></el-icon>
<span>
删除
</span>
</el-dropdown-item>
...
...
@@ -24,9 +24,9 @@
</
template
>
</el-dropdown>
</div>
<!--
头像
-->
<!--
角色信息
-->
<div>
<img
class=
"avatar"
:src=
"role.avatar"
/>
<img
class=
"avatar"
:src=
"role.avatar"
/>
</div>
<div
class=
"right-container"
>
<div
class=
"content-container"
>
...
...
@@ -43,9 +43,9 @@
</template>
<
script
setup
lang=
"ts"
>
import
{
ChatRoleVO
}
from
'@/api/ai/model/chatRole'
import
{
PropType
,
ref
}
from
"vue"
;
import
{
Delete
,
EditPen
,
More
}
from
"@element-plus/icons-vue"
;
import
{
ChatRoleVO
}
from
'@/api/ai/model/chatRole'
import
{
PropType
,
ref
}
from
'vue'
import
{
Delete
,
EditPen
,
More
}
from
'@element-plus/icons-vue'
const
tabsRef
=
ref
<
any
>
()
// tabs ref
...
...
@@ -65,10 +65,11 @@ const props = defineProps({
default
:
false
}
})
// 定义钩子
const
emits
=
defineEmits
([
'onDelete'
,
'onEdit'
,
'onUse'
,
'onPage'
])
/
/ more 点击
/
** 操作:编辑、删除 */
const
handleMoreClick
=
async
(
data
)
=>
{
const
type
=
data
[
0
]
const
role
=
data
[
1
]
...
...
@@ -79,28 +80,20 @@ const handleMoreClick = async (data) => {
}
}
/
/ 使用
/
** 选中 */
const
handleUseClick
=
(
role
)
=>
{
emits
(
'onUse'
,
role
)
}
/** 滚动 */
const
handleTabsScroll
=
async
()
=>
{
if
(
tabsRef
.
value
)
{
const
{
scrollTop
,
scrollHeight
,
clientHeight
}
=
tabsRef
.
value
;
console
.
log
(
'scrollTop'
,
scrollTop
)
const
{
scrollTop
,
scrollHeight
,
clientHeight
}
=
tabsRef
.
value
if
(
scrollTop
+
clientHeight
>=
scrollHeight
-
20
&&
!
props
.
loading
)
{
console
.
log
(
'分页'
)
// page.value++;
// fetchData(page.value);
await
emits
(
'onPage'
)
}
}
}
onMounted
(()
=>
{
console
.
log
(
'props'
,
props
.
roleList
)
})
</
script
>
<
style
lang=
"scss"
>
...
...
@@ -114,11 +107,9 @@ onMounted(() => {
flex-direction
:
row
;
justify-content
:
flex-start
;
position
:
relative
;
}
</
style
>
<
style
scoped
lang=
"scss"
>
//
卡片列表
.card-list
{
display
:
flex
;
...
...
@@ -180,9 +171,6 @@ onMounted(() => {
margin-top
:
2px
;
}
}
}
}
</
style
>
src/views/ai/chat/index/components/role/
index
.vue
→
src/views/ai/chat/index/components/role/
RoleRepository
.vue
View file @
62246021
...
...
@@ -3,7 +3,7 @@
<el-container
class=
"role-container"
>
<ChatRoleForm
ref=
"formRef"
@
success=
"handlerAddRoleSuccess"
/>
<!-- header -->
<
Header
title=
"角色仓库"
style=
"position:
relative"
/>
<
RoleHeader
title=
"角色仓库"
class=
"
relative"
/>
<!-- main -->
<el-main
class=
"role-main"
>
<div
class=
"search-container"
>
...
...
@@ -18,10 +18,10 @@
@
change=
"getActiveTabsRole"
/>
<el-button
v-if=
"active
Role
== 'my-role'"
v-if=
"active
Tab
== 'my-role'"
type=
"primary"
@
click=
"handlerAddRole"
style=
"margin-left:
20px"
class=
"ml-
20px"
>
<!-- TODO @fan:下面两个 icon,可以使用类似
<Icon
icon=
"ep:question-filled"
/>
替代哈 -->
<el-icon>
...
...
@@ -31,7 +31,7 @@
</el-button>
</div>
<!-- tabs -->
<el-tabs
v-model=
"active
Role
"
class=
"tabs"
@
tab-click=
"handleTabsClick"
>
<el-tabs
v-model=
"active
Tab
"
class=
"tabs"
@
tab-click=
"handleTabsClick"
>
<el-tab-pane
class=
"role-pane"
label=
"我的角色"
name=
"my-role"
>
<RoleList
:loading=
"loading"
...
...
@@ -41,7 +41,7 @@
@
on-edit=
"handlerCardEdit"
@
on-use=
"handlerCardUse"
@
on-page=
"handlerCardPage('my')"
style=
"margin-top:
20px"
class=
"mt-
20px"
/>
</el-tab-pane>
<el-tab-pane
label=
"公共角色"
name=
"public-role"
>
...
...
@@ -57,7 +57,7 @@
@
on-edit=
"handlerCardEdit"
@
on-use=
"handlerCardUse"
@
on-page=
"handlerCardPage('public')"
style=
"margin-top:
20px"
class=
"mt-
20px"
loading
/>
</el-tab-pane>
...
...
@@ -68,27 +68,30 @@
<
script
setup
lang=
"ts"
>
import
{
ref
}
from
'vue'
import
Header
from
'../
Header.vue'
import
RoleHeader
from
'./Role
Header.vue'
import
RoleList
from
'./RoleList.vue'
import
ChatRoleForm
from
'@/views/ai/model/chatRole/ChatRoleForm.vue'
import
RoleCategoryList
from
'./RoleCategoryList.vue'
import
{
ChatRoleApi
,
ChatRolePageReqVO
,
ChatRoleVO
}
from
'@/api/ai/model/chatRole'
import
{
ChatConversationApi
,
ChatConversationVO
}
from
'@/api/ai/chat/conversation'
import
{
TabsPaneContext
}
from
'element-plus'
import
{
Search
,
User
}
from
'@element-plus/icons-vue'
import
{
TabsPaneContext
}
from
'element-plus'
const
router
=
useRouter
()
// 路由对象
// 属性定义
const
loading
=
ref
<
boolean
>
(
false
)
// 加载中
const
active
Role
=
ref
<
string
>
(
'my-role'
)
// 选中的角色 TODO @fan:是不是叫 activeTab 会更明确一点哈。选中的角色,会以为是某个角色
const
active
Tab
=
ref
<
string
>
(
'my-role'
)
// 选中的角色 Tab
const
search
=
ref
<
string
>
(
''
)
// 加载中
// TODO @fan:要不 myPage、pubPage,搞成类似 const queryParams = reactive({ ,分别搞成两个大的参数哈?
const
myPageNo
=
ref
<
number
>
(
1
)
// my 分页下标
const
myPageSize
=
ref
<
number
>
(
50
)
// my 分页大小
const
myRoleParams
=
reactive
({
pageNo
:
1
,
pageSize
:
50
})
const
myRoleList
=
ref
<
ChatRoleVO
[]
>
([])
// my 分页大小
const
publicPageNo
=
ref
<
number
>
(
1
)
// public 分页下标
const
publicPageSize
=
ref
<
number
>
(
50
)
// public 分页大小
const
publicRoleParams
=
reactive
({
pageNo
:
1
,
pageSize
:
50
})
const
publicRoleList
=
ref
<
ChatRoleVO
[]
>
([])
// public 分页大小
const
activeCategory
=
ref
<
string
>
(
'全部'
)
// 选择中的分类
const
categoryList
=
ref
<
string
[]
>
([])
// 角色分类类别
...
...
@@ -96,7 +99,7 @@ const categoryList = ref<string[]>([]) // 角色分类类别
/** tabs 点击 */
const
handleTabsClick
=
async
(
tab
:
TabsPaneContext
)
=>
{
// 设置切换状态
active
Role
.
value
=
tab
.
paneName
+
''
active
Tab
.
value
=
tab
.
paneName
+
''
// 切换的时候重新加载数据
await
getActiveTabsRole
()
}
...
...
@@ -104,12 +107,11 @@ const handleTabsClick = async (tab: TabsPaneContext) => {
/** 获取 my role 我的角色 */
const
getMyRole
=
async
(
append
?:
boolean
)
=>
{
const
params
:
ChatRolePageReqVO
=
{
pageNo
:
myPageNo
.
value
,
pageSize
:
myPageSize
.
value
,
...
myRoleParams
,
name
:
search
.
value
,
publicStatus
:
false
}
const
{
total
,
list
}
=
await
ChatRoleApi
.
getMyPage
(
params
)
const
{
list
}
=
await
ChatRoleApi
.
getMyPage
(
params
)
if
(
append
)
{
myRoleList
.
value
.
push
.
apply
(
myRoleList
.
value
,
list
)
}
else
{
...
...
@@ -120,8 +122,7 @@ const getMyRole = async (append?: boolean) => {
/** 获取 public role 公共角色 */
const
getPublicRole
=
async
(
append
?:
boolean
)
=>
{
const
params
:
ChatRolePageReqVO
=
{
pageNo
:
publicPageNo
.
value
,
pageSize
:
publicPageSize
.
value
,
...
publicRoleParams
,
category
:
activeCategory
.
value
===
'全部'
?
''
:
activeCategory
.
value
,
name
:
search
.
value
,
publicStatus
:
true
...
...
@@ -136,20 +137,18 @@ const getPublicRole = async (append?: boolean) => {
/** 获取选中的 tabs 角色 */
const
getActiveTabsRole
=
async
()
=>
{
if
(
active
Role
.
value
===
'my-role'
)
{
my
PageNo
.
value
=
1
if
(
active
Tab
.
value
===
'my-role'
)
{
my
RoleParams
.
pageNo
=
1
await
getMyRole
()
}
else
{
public
PageNo
.
value
=
1
public
RoleParams
.
pageNo
=
1
await
getPublicRole
()
}
}
/** 获取角色分类列表 */
const
getRoleCategoryList
=
async
()
=>
{
const
res
=
await
ChatRoleApi
.
getCategoryList
()
const
defaultRole
=
[
'全部'
]
categoryList
.
value
=
[...
defaultRole
,
...
res
]
categoryList
.
value
=
[
'全部'
,
...(
await
ChatRoleApi
.
getCategoryList
())]
}
/** 处理分类点击 */
...
...
@@ -165,6 +164,10 @@ const formRef = ref()
const
handlerAddRole
=
async
()
=>
{
formRef
.
value
.
open
(
'my-create'
,
null
,
'添加角色'
)
}
/** 编辑角色 */
const
handlerCardEdit
=
async
(
role
)
=>
{
formRef
.
value
.
open
(
'my-update'
,
role
.
id
,
'编辑角色'
)
}
/** 添加角色成功 */
const
handlerAddRoleSuccess
=
async
(
e
)
=>
{
...
...
@@ -172,28 +175,22 @@ const handlerAddRoleSuccess = async (e) => {
await
getActiveTabsRole
()
}
/
/ card 删除
/
** 删除角色 */
const
handlerCardDelete
=
async
(
role
)
=>
{
await
ChatRoleApi
.
deleteMy
(
role
.
id
)
// 刷新数据
await
getActiveTabsRole
()
}
// card 编辑
const
handlerCardEdit
=
async
(
role
)
=>
{
formRef
.
value
.
open
(
'my-update'
,
role
.
id
,
'编辑角色'
)
}
/** card 分页:获取下一页 */
/** 角色分页:获取下一页 */
const
handlerCardPage
=
async
(
type
)
=>
{
console
.
log
(
'handlerCardPage'
,
type
)
try
{
loading
.
value
=
true
if
(
type
===
'public'
)
{
public
PageNo
.
value
++
public
RoleParams
.
pageNo
++
await
getPublicRole
(
true
)
}
else
{
my
PageNo
.
value
++
my
RoleParams
.
pageNo
++
await
getMyRole
(
true
)
}
}
finally
{
...
...
@@ -208,10 +205,10 @@ const handlerCardUse = async (role) => {
roleId
:
role
.
id
}
as
unknown
as
ChatConversationVO
const
conversationId
=
await
ChatConversationApi
.
createChatConversationMy
(
data
)
// 2. 跳转页面
// TODO @fan:最好用 name,后续可能会改~~~
await
router
.
push
({
path
:
`/ai/chat`
,
name
:
'AiChat'
,
query
:
{
conversationId
:
conversationId
}
...
...
src/views/ai/chat/index/index.vue
View file @
62246021
...
...
@@ -19,11 +19,10 @@
<div
class=
"btns"
v-if=
"activeConversation"
>
<el-button
type=
"primary"
bg
plain
size=
"small"
@
click=
"openChatConversationUpdateForm"
>
<span
v-html=
"activeConversation?.modelName"
></span>
<Icon
icon=
"ep:setting"
style=
"margin-left:
10px"
/>
<Icon
icon=
"ep:setting"
class=
"ml-
10px"
/>
</el-button>
<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"
class=
"h-14px"
/>
</el-button>
<!-- TODO @fan:下面两个 icon,可以使用类似
<Icon
icon=
"ep:question-filled"
/>
替代哈 -->
<el-button
size=
"small"
:icon=
"Download"
class=
"btn"
/>
...
...
@@ -76,7 +75,7 @@
<div
class=
"prompt-btns"
>
<div>
<el-switch
v-model=
"enableContext"
/>
<span
style=
"font-size: 14px; color:
#8f8f8f"
>
上下文
</span>
<span
class=
"ml-5px text-14px text-
#8f8f8f"
>
上下文
</span>
</div>
<el-button
type=
"primary"
...
...
@@ -119,6 +118,9 @@ import MessageLoading from './components/message/MessageLoading.vue'
import
MessageNewConversation
from
'./components/message/MessageNewConversation.vue'
import
{
Download
,
Top
}
from
'@element-plus/icons-vue'
/** AI 聊天对话 列表 */
defineOptions
({
name
:
'AiChat'
})
const
route
=
useRoute
()
// 路由
const
message
=
useMessage
()
// 消息弹窗
...
...
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