Commit 62246021 by YunaiV

【代码优化】AI:聊天对话 index.vue 代码梳理 80%(message 部分)

parent 1a6afa32
<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 {
......
<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>
......@@ -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="activeRole == 'my-role'"
v-if="activeTab == '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="activeRole" class="tabs" @tab-click="handleTabsClick">
<el-tabs v-model="activeTab" 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 './RoleHeader.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 activeRole = ref<string>('my-role') // 选中的角色 TODO @fan:是不是叫 activeTab 会更明确一点哈。选中的角色,会以为是某个角色
const activeTab = 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) => {
// 设置切换状态
activeRole.value = tab.paneName + ''
activeTab.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 (activeRole.value === 'my-role') {
myPageNo.value = 1
if (activeTab.value === 'my-role') {
myRoleParams.pageNo = 1
await getMyRole()
} else {
publicPageNo.value = 1
publicRoleParams.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') {
publicPageNo.value++
publicRoleParams.pageNo++
await getPublicRole(true)
} else {
myPageNo.value++
myRoleParams.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
}
......
......@@ -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() // 消息弹窗
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment