Compare commits
2 Commits
5006822ec2
...
023d556977
| Author | SHA1 | Date | |
|---|---|---|---|
| 023d556977 | |||
| b47565bdfc |
@@ -6,26 +6,40 @@
|
||||
<div ref="listRef" class="flex-1 overflow-y-auto px-6 py-6 space-y-6">
|
||||
<div v-for="msg in messages" :key="msg.id" class="flex items-start gap-3"
|
||||
:class="msg.role === 'user' ? 'justify-end' : 'justify-start'">
|
||||
|
||||
<!-- AI avatar -->
|
||||
<div v-if="msg.role === 'ai'"
|
||||
class="w-9 h-9 rounded-full bg-blue-500 flex items-center justify-center text-white font-bold shrink-0">
|
||||
N
|
||||
</div>
|
||||
<img v-if="msg.role === 'ai'" class="w-9 h-9 rounded-full shrink-0" src="@assets/images/login/blue_logo.png" />
|
||||
|
||||
<!-- 气泡 -->
|
||||
<!-- 消息气泡 -->
|
||||
<div class="max-w-[70%]">
|
||||
<div class="px-4 py-3 text-sm text-gray-700" :class="msg.role === 'user' ? 'bg-[#f7f9fc] rounded-md' : ''">
|
||||
<div class="flex items-start gap-2 pt-0.5 mb-2" :class="msg.role === 'user' ? 'flex-row-reverse' : 'flex-row'">
|
||||
<span class="text-xs text-[#4E5969]"> ZHINIAN</span>
|
||||
<span class="text-xs text-[#86909C]"> 20:30</span>
|
||||
</div>
|
||||
<div class="text-sm text-gray-700" :class="msg.role === 'user' ? 'bg-[#f7f9fc] rounded-md px-2 py-2' : ''">
|
||||
{{ msg.content }}
|
||||
</div>
|
||||
|
||||
<!-- AI 标识 -->
|
||||
<div v-if="msg.role === 'ai'" class="mt-1 text-xs text-gray-400 ">
|
||||
<div v-if="msg.role === 'ai'" class="mt-2 text-xs text-gray-400 ">
|
||||
本回答由 AI 生成
|
||||
</div>
|
||||
|
||||
<!-- AI 操作按钮 -->
|
||||
<div v-if="msg.role === 'ai'" class="mt-4 text-gray-500 flex items-center justify-between gap-4 ">
|
||||
<RiFileCopyLine size="16px" @click="copyFileClick(msg)" />
|
||||
<div class="flex items-center gap-4">
|
||||
<RiShareForwardLine size="16px" @click="shareForwardClick(msg)"/>
|
||||
<RiDownload2Line size="16px" @click="downloadClick(msg)" />
|
||||
<RiThumbUpLine size="16px" @click="thumbUpClick(msg)" />
|
||||
<RiThumbDownLine size="16px" @click="thumbDownClick(msg)" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- User avatar -->
|
||||
<div v-if="msg.role === 'user'" class="w-9 h-9 rounded-full bg-blue-200 shrink-0"></div>
|
||||
<img v-if="msg.role === 'user'" class="w-9 h-9 rounded-full shrink-0" src="@assets/images/login/user_icon.png" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -58,8 +72,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { RiLink, RiSendPlaneFill } from '@remixicon/vue'
|
||||
|
||||
import { RiLink, RiSendPlaneFill, RiFileCopyLine, RiShareForwardLine, RiDownload2Line, RiThumbUpLine, RiThumbDownLine } from '@remixicon/vue'
|
||||
|
||||
type Message = {
|
||||
id: number
|
||||
@@ -81,4 +94,23 @@ const messages = ref<Message[]>(
|
||||
),
|
||||
}))
|
||||
)
|
||||
|
||||
/// actions 实现复制、分享、下载、点赞等功能
|
||||
const copyFileClick = (msg: Message) => {
|
||||
console.log('copy file', msg)
|
||||
}
|
||||
const shareForwardClick = (msg: Message) => {
|
||||
console.log('share forward', msg)
|
||||
}
|
||||
const downloadClick = (msg: Message) => {
|
||||
console.log('download', msg)
|
||||
}
|
||||
const thumbUpClick = (msg: Message) => {
|
||||
console.log('thumb up', msg)
|
||||
}
|
||||
const thumbDownClick = (msg: Message) => {
|
||||
console.log('thumb down', msg)
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
@@ -1,29 +1,28 @@
|
||||
<template>
|
||||
<aside class="w-64 h-screen box-border flex flex-col">
|
||||
<header class="flex items-center justify-between mb-3">
|
||||
<div class="flex items-center gap-2">
|
||||
<img class="w-20 h-20 rounded-md object-cover" src="@assets/images/login/white_logo.png" />
|
||||
<div class="font-bold text-gray-800">YINIAN</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="mb-3 pl-4 pr-4">
|
||||
<button class="bg-white rounded-lg px-3 py-2 border shadow-sm w-full text-center">+ 新对话</button>
|
||||
<aside class="w-50 h-screen box-border flex flex-col">
|
||||
<div class="flex items-center m-2">
|
||||
<img class="w-10 h-10 rounded-md" src="@assets/images/login/white_logo.png" />
|
||||
<div class="font-bold text-gray-80">YINIAN</div>
|
||||
</div>
|
||||
|
||||
<div class="overflow-y-auto p-4">
|
||||
<section v-for="group in groups" :key="group.title" class="mb-3">
|
||||
<div class="flex items-center justify-between text-sm text-gray-500 py-2">
|
||||
<div class="flex justify-center m-2 bg-white rounded-lg p-2.5 border-[##E5E8EE] shadow-sm text-center" @click="addNewChat">
|
||||
<RiAddLine /> 新对话
|
||||
</div>
|
||||
|
||||
<div class="overflow-y-auto p-2 ">
|
||||
<section v-for="(group, index) in groups" :key="group.title" class="mb-3">
|
||||
<div class="flex items-center justify-between text-sm text-gray-500" @click="selectGroupKey(index)">
|
||||
<span>{{ group.title }}</span>
|
||||
<RiArrowDownSLine />
|
||||
<RiArrowDownSLine v-show="group.selected" color="rgba(153,160,174,1)" />
|
||||
<RiArrowRightSLine v-show="!group.selected" color="rgba(153,160,174,1)" />
|
||||
</div>
|
||||
|
||||
<ul class="list-none p-1 mr-4">
|
||||
<li v-for="item in group.items" :key="item.id" @click="select(item.id)" :class="[
|
||||
<ul class="list-none mt-1.5" v-if="group.selected">
|
||||
<li v-for="item in group.items" :key="item.id" @click="selectedHistoryMessage(item.id)" :class="[
|
||||
'flex items-center gap-2 p-2 text-gray-600 rounded-lg cursor-pointer transition-colors',
|
||||
item.id === selectedId ? 'bg-white shadow-md border border-gray-200' : 'hover:bg-gray-50'
|
||||
item.id === selectedId ? 'bg-white shadow-sm border-[##E5E8EE]' : 'hover:bg-gray-50'
|
||||
]">
|
||||
<span class="w-2 h-2 rounded-full bg-sky-200 flex-none"></span>
|
||||
<span class="w-2 h-2 rounded-full bg-[#BEDBFF] flex-none"></span>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="truncate text-sm">{{ item.title }}</div>
|
||||
</div>
|
||||
@@ -38,13 +37,16 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { RiArrowDownSLine } from '@remixicon/vue'
|
||||
import { RiAddLine, RiArrowRightSLine, RiArrowDownSLine } from '@remixicon/vue'
|
||||
|
||||
/// 记录选择的历史消息ID
|
||||
const selectedId = ref<number | null>(2)
|
||||
|
||||
/// 历史消息分组数据
|
||||
const groups = ref([
|
||||
{
|
||||
title: '近3天',
|
||||
selected: false,
|
||||
items: [
|
||||
{ id: 1, title: '这是一段对话' },
|
||||
{ id: 2, title: '这是一段对话' },
|
||||
@@ -55,6 +57,7 @@ const groups = ref([
|
||||
},
|
||||
{
|
||||
title: '近7天',
|
||||
selected: false,
|
||||
items: [
|
||||
{ id: 6, title: '这是一段对话' },
|
||||
{ id: 7, title: '这是一段对话' },
|
||||
@@ -64,6 +67,7 @@ const groups = ref([
|
||||
},
|
||||
{
|
||||
title: '近15天',
|
||||
selected: false,
|
||||
items: [
|
||||
{ id: 10, title: '这是一段对话' },
|
||||
{ id: 11, title: '这是一段对话' },
|
||||
@@ -74,6 +78,7 @@ const groups = ref([
|
||||
},
|
||||
{
|
||||
title: '近30天',
|
||||
selected: false,
|
||||
items: [
|
||||
{ id: 15, title: '这是一段对话' },
|
||||
{ id: 16, title: '这是一段对话' },
|
||||
@@ -83,6 +88,7 @@ const groups = ref([
|
||||
},
|
||||
{
|
||||
title: '近60天',
|
||||
selected: false,
|
||||
items: [
|
||||
{ id: 19, title: '这是一段对话' },
|
||||
{ id: 20, title: '这是一段对话' },
|
||||
@@ -93,6 +99,7 @@ const groups = ref([
|
||||
},
|
||||
{
|
||||
title: '近90天',
|
||||
selected: false,
|
||||
items: [
|
||||
{ id: 24, title: '这是一段对话' },
|
||||
{ id: 25, title: '这是一段对话' },
|
||||
@@ -102,7 +109,23 @@ const groups = ref([
|
||||
}
|
||||
])
|
||||
|
||||
function select(id: number) {
|
||||
/// 选择历史消息
|
||||
const selectedHistoryMessage = (id: number) => {
|
||||
selectedId.value = id
|
||||
}
|
||||
|
||||
/// 选择分组展开/收起
|
||||
const selectGroupKey = (index: number) => {
|
||||
groups.value.forEach((group, i) => {
|
||||
if (i === index) {
|
||||
group.selected = !group.selected
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// TODO: 添加新对话
|
||||
const addNewChat = () => {
|
||||
console.log('add new chat')
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user