소스 검색

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

YunaiV 9 달 전
부모
커밋
6224602152

+ 65 - 106
src/views/ai/chat/index/components/conversation/ConversationList.vue

@@ -1,8 +1,8 @@
 <!--  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="handlerTop(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">
+      <RoleRepository />
     </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 res = emits('onConversationClick', filterConversation[0])
+  // noinspection JSVoidFunctionReturnValueUsed
+  const success = emits('onConversationClick', filterConversation[0])
   // 切换对话
-  if (res) {
+  if (success) {
     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.updateTime
+    const diff = now - conversation.createTime
     // 根据时间间隔判断
     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,11 +288,26 @@ const deleteChatConversation = async (conversation: ChatConversationVO) => {
   } catch {}
 }
 
-/**
- * 对话置顶
- */
-// TODO @fan:应该是 handleXXX,handler 是名词哈
-const handlerTop = async (conversation: ChatConversationVO) => {
+/** 清空对话 */
+const handleClearConversation = async () => {
+  try {
+    await message.confirm('确认后对话会全部清空,置顶的对话除外。')
+    await ChatConversationApi.deleteChatConversationMyByUnpinned()
+    ElMessage({
+      message: '操作成功!',
+      type: 'success'
+    })
+    // 清空 对话 和 对话内容
+    activeConversationId.value = null
+    // 获取 对话列表
+    await getChatConversationList()
+    // 回调 方法
+    emits('onConversationClear')
+  } catch {}
+}
+
+/** 对话置顶 */
+const handleTop = async (conversation: ChatConversationVO) => {
   // 更新对话置顶
   conversation.pinned = !conversation.pinned
   await ChatConversationApi.updateChatConversationMy(conversation)
@@ -325,60 +315,29 @@ const handlerTop = async (conversation: ChatConversationVO) => {
   await getChatConversationList()
 }
 
-// TODO @fan:类似 ============ 分块的,最后后面也有 ============ 哈
-// ============ 角色仓库
+// ============ 角色仓库 ============
 
-/**
- * 角色仓库抽屉
- */
+/** 角色仓库抽屉 */
+const roleRepositoryOpen = ref<boolean>(false) // 角色仓库是否打开
 const handleRoleRepository = async () => {
-  drawer.value = !drawer.value
-}
-
-// ============= 清空对话
-
-/**
- * 清空对话
- */
-const handleClearConversation = async () => {
-  // TODO @fan:可以使用 await message.confirm( 简化,然后使用 await 改成同步的逻辑,会更简洁
-  ElMessageBox.confirm('确认后对话会全部清空,置顶的对话除外。', '确认提示', {
-    confirmButtonText: '确认',
-    cancelButtonText: '取消',
-    type: 'warning'
-  })
-    .then(async () => {
-      await ChatConversationApi.deleteChatConversationMyByUnpinned()
-      ElMessage({
-        message: '操作成功!',
-        type: 'success'
-      })
-      // 清空 对话 和 对话内容
-      activeConversationId.value = null
-      // 获取 对话列表
-      await getChatConversationList()
-      // 回调 方法
-      emits('onConversationClear')
-    })
-    .catch(() => {})
+  roleRepositoryOpen.value = !roleRepositoryOpen.value
 }
 
-// ============ 组件 onMounted
-
+/** 监听选中的对话 */
 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 {
     // 首次默认选中第一个

+ 13 - 7
src/views/ai/chat/index/components/role/RoleCategoryList.vue

@@ -1,13 +1,20 @@
 <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 {

+ 0 - 0
src/views/ai/chat/index/components/Header.vue → src/views/ai/chat/index/components/role/RoleHeader.vue


+ 17 - 29
src/views/ai/chat/index/components/role/RoleList.vue

@@ -1,22 +1,22 @@
 <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>

+ 36 - 39
src/views/ai/chat/index/components/role/index.vue → src/views/ai/chat/index/components/role/RoleRepository.vue

@@ -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
     }

+ 6 - 4
src/views/ai/chat/index/index.vue

@@ -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() // 消息弹窗