feat: chat

This commit is contained in:
dylanmay
2023-09-08 17:36:37 +08:00
parent e6a9dd0e4c
commit e3f8a3a94b
19 changed files with 607 additions and 0 deletions

View File

@ -0,0 +1,18 @@
<template>
<view
class="flex items-center w-full border-b-1 border-b-gray border-b-solid"
style="height: 60px"
>
<label class="text-black text-size-xl font-medium mx-4">{{
chatStore.currentSession?.name
}}</label>
</view>
</template>
<script lang="ts" setup>
import { useChatStore } from '../../store/chatstore'
defineOptions({ name: 'ChatHeader' })
const chatStore = useChatStore()
</script>

View File

@ -0,0 +1,21 @@
<template>
<view
class="flex flex-col items-start w-full border-b-1 border-b-gray border-b-solid flex-1 border-b-1 border-b-gray border-b-solid py-2"
>
<template v-for="item in chatStore.currentSession?.msgList">
<TextMessage v-if="item.messageType === MessageType.TEXT" :key="item.id" :message="item" />
<ImageMessage v-if="item.messageType === MessageType.IMAGE" :key="item.id" :message="item" />
</template>
</view>
</template>
<script lang="ts" setup>
import { useChatStore } from '../../store/chatstore'
import TextMessage from '@/views/chat/components/Message/TextMessage.vue'
import ImageMessage from '@/views/chat/components/Message/ImageMessage.vue'
import { MessageType } from '../../types/index.d.ts'
defineOptions({ name: 'ChatMessage' })
const chatStore = useChatStore()
</script>

View File

@ -0,0 +1,58 @@
<template>
<view
class="flex flex-col items-center w-full border-b-1 border-b-gray border-b-solid"
style="height: 248px"
>
<view class="flex p-2 w-full" style="height: 20px">
<Icon icon="ep:apple" color="var(--top-header-text-color)" class="custom-hover" />
<Icon icon="ep:folder" color="var(--top-header-text-color)" class="custom-hover" />
<Icon icon="ep:chat-line-square" color="var(--top-header-text-color)" class="custom-hover" />
</view>
<ElInput
type="textarea"
class="h-full"
clearable
v-model="chatStore.inputText"
input-style="border: none !important; box-shadow: none !important"
:autosize="{ minRows: 10, maxRows: 11 }"
placeholder="Press Enter to send"
@keydown.enter="onEnter"
/>
</view>
</template>
<script lang="ts" setup>
import TextMessage from '../../model/TextMessage'
import { useChatStore } from '../../store/chatstore'
import { SendStatus, MessageRole, MessageType } from '../../types/index.d.ts'
defineOptions({ name: 'InputSection' })
const chatStore = useChatStore()
const onEnter = () => {
console.log('enter pressed')
const msg = createTextMessage(chatStore.inputText)
chatStore.addMessageToCurrentSession(msg)
chatStore.setInputText('')
}
const createTextMessage = (content: string): TextMessage => {
console.log('====>>>>', content)
const _localId = `${new Date().getTime()}`
// 部分信息从account信息里面获取
const msg = new TextMessage(
_localId,
'https://img0.baidu.com/it/u=1121635512,1294972039&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=889',
'Dylan May',
new Date().getTime(),
false,
content,
MessageRole.SELF,
SendStatus.SUCCESS,
MessageType.TEXT,
chatStore.currentSession?.id || ''
)
return msg
}
</script>

View File

@ -0,0 +1,26 @@
<template>
<view
class="flex w-full"
:class="props.message.role === MessageRole.SELF ? 'flex-row-reverse' : 'flex-row'"
>
<el-avatar shape="square" size="default" class="mx-2" :src="props.message.avatar" />
<view class="flex flex-col">
<label class="text-xs text-gray-4 mb-1">{{ props.message.nickname }}</label>
<slot name="content"></slot>
</view>
</view>
</template>
<script lang="ts" setup>
import { PropType } from 'vue'
import { MessageModelType, MessageRole } from '../../types/index.d.ts'
defineOptions({ name: 'BaseMessage' })
const props = defineProps({
message: {
type: Object as PropType<MessageModelType>,
default: () => {}
}
})
</script>

View File

@ -0,0 +1,28 @@
<template>
<BaseMesageLayout>
<template #content>
<view>
<label>{{ props.message.content }}</label>
</view>
</template>
</BaseMesageLayout>
</template>
<script lang="ts" setup>
import { PropType } from 'vue'
import { useChatStore } from '../../store/chatstore'
import { onMounted } from 'vue'
import { MessageModelType } from '../../types'
import BaseMesageLayout from '../Message/BaseMessage.vue'
defineOptions({ name: 'ImageMessage' })
const props = defineProps({
message: {
type: Object as PropType<MessageModelType>,
default: () => {}
}
})
const { sessionList, setCurrentConversation, setCurrentSessionIndex } = useChatStore()
</script>

View File

@ -0,0 +1,27 @@
<template>
<BaseMesageLayout :message="props.message">
<template #content>
<view class="p-3 bg-gray-2 rounded">
<label>{{ props.message.content }}</label>
</view>
</template>
</BaseMesageLayout>
</template>
<script lang="ts" setup>
import { PropType } from 'vue'
import { useChatStore } from '../../store/chatstore'
import BaseMesageLayout from '../Message/BaseMessage.vue'
import { MessageModelType } from '../../types/index'
defineOptions({ name: 'TextMessage' })
const props = defineProps({
message: {
type: Object as PropType<MessageModelType>,
default: () => {}
}
})
const { sessionList, setCurrentConversation, setCurrentSessionIndex } = useChatStore()
</script>

View File

@ -0,0 +1,33 @@
<template>
<view class="flex flex-col items-center h-full py-2 b-1 b-gray b-solid" style="width: 248px">
<view class="flex flex-col w-full">
<SessionItem
v-for="(item, index) in sessionList"
:key="item.id"
:index="index"
:conversation="item"
@click="() => onSessionItemClick(index)"
/>
</view>
</view>
</template>
<script lang="ts" setup>
import SessionItem from '../SessionItem/Index.vue'
import { useChatStore } from '../../store/chatstore'
import { onMounted } from 'vue'
defineOptions({ name: 'Session' })
const { sessionList, setCurrentConversation, setCurrentSessionIndex } = useChatStore()
onMounted(() => {
// set default conversation
setCurrentConversation()
})
const onSessionItemClick = (index: number) => {
setCurrentSessionIndex(index)
setCurrentConversation()
}
</script>

View File

@ -0,0 +1,47 @@
<template>
<view class="flex py-2 border-b-gray-3 border-b-solid items-center px-2" :class="bgColor()">
<el-avatar shape="square" size="default" class="mr-2" />
<view class="flex flex-col flex-1">
<label
class="text-black-c text-size-sm font-medium text-ellipsis text-nowrap"
:class="fontColor()"
>{{ props.conversation.name }}</label
>
<label class="text-gray-f text-size-sm text-ellipsis text-nowrap mr-1" :class="fontColor()">{{
props.conversation.description
}}</label>
</view>
<view class="flex items-end h-full">
<label class="text-gray-f text-size-sm text-nowrap" :class="fontColor()">{{
formatPast(new Date(props.conversation.updateTime))
}}</label>
</view>
</view>
</template>
<script lang="ts" setup>
import { PropType } from 'vue'
import { ConversationModelType } from '../../types'
import { formatPast } from '@/utils/formatTime'
import { useChatStore } from '../../store/chatstore'
defineOptions({ name: 'SessionItem' })
const props = defineProps({
conversation: {
type: Object as PropType<ConversationModelType>,
default: () => {}
},
index: Number
})
const chatStore = useChatStore()
const bgColor = () => {
return props.index === chatStore.currentSessionIndex ? 'bg-blue' : 'bg-white'
}
const fontColor = () => {
return props.index === chatStore.currentSessionIndex ? 'text-white' : 'text-gray-f'
}
</script>

View File

@ -0,0 +1,9 @@
<template>
<view class="flex flex-col items-center bg-gray h-full py-2" style="width: 80px">
<el-avatar shape="square" />
</view>
</template>
<script lang="ts" setup>
defineOptions({ name: 'ToolSection' })
</script>