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
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
72 additions
and
79 deletions
+72
-79
src/views/ai/chat/index/components/conversation/ConversationList.vue
+0
-0
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
+17
-29
src/views/ai/chat/index/components/role/RoleRepository.vue
+36
-39
src/views/ai/chat/index/index.vue
+6
-4
No files found.
src/views/ai/chat/index/components/conversation/ConversationList.vue
View file @
62246021
This diff is collapsed.
Click to expand it.
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
<
template
>
<div
class=
"card-list"
ref=
"tabsRef"
@
scroll=
"handleTabsScroll"
>
<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"
>
<span
class=
"el-dropdown-link"
>
<el-button
type=
"text"
>
<el-icon><More
/></el-icon>
</el-button>
</span>
</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
...
...
@@ -2,8 +2,8 @@
<
template
>
<el-container
class=
"role-container"
>
<ChatRoleForm
ref=
"formRef"
@
success=
"handlerAddRoleSuccess"
/>
<!--
header -->
<
Header
title=
"角色仓库"
style=
"position:
relative"
/>
<!-- header -->
<
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