feat: chat
This commit is contained in:
parent
26be536b40
commit
afada6fa72
@ -303,7 +303,7 @@ import { t } from '@/locales'
|
|||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const {
|
const {
|
||||||
query: { mode, question }
|
query: { mode, question },
|
||||||
} = route as any
|
} = route as any
|
||||||
const quickInputRef = ref()
|
const quickInputRef = ref()
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
@ -321,8 +321,8 @@ const props = withDefaults(
|
|||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
applicationDetails: () => ({}),
|
applicationDetails: () => ({}),
|
||||||
available: true
|
available: true,
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
const emit = defineEmits(['update:chatId', 'update:loading', 'update:showUserInput'])
|
const emit = defineEmits(['update:chatId', 'update:loading', 'update:showUserInput'])
|
||||||
const chartOpenId = ref<string>()
|
const chartOpenId = ref<string>()
|
||||||
@ -336,7 +336,7 @@ const chatId_context = computed({
|
|||||||
set: (v) => {
|
set: (v) => {
|
||||||
chartOpenId.value = v
|
chartOpenId.value = v
|
||||||
emit('update:chatId', v)
|
emit('update:chatId', v)
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
const localLoading = computed({
|
const localLoading = computed({
|
||||||
get: () => {
|
get: () => {
|
||||||
@ -344,7 +344,7 @@ const localLoading = computed({
|
|||||||
},
|
},
|
||||||
set: (v) => {
|
set: (v) => {
|
||||||
emit('update:loading', v)
|
emit('update:loading', v)
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const upload = ref()
|
const upload = ref()
|
||||||
@ -418,7 +418,7 @@ const uploadFile = async (file: any, fileList: any) => {
|
|||||||
formData.append('file', file.raw, file.name)
|
formData.append('file', file.raw, file.name)
|
||||||
//
|
//
|
||||||
const extension = file.name.split('.').pop().toUpperCase() // 获取文件后缀名并转为小写
|
const extension = file.name.split('.').pop().toUpperCase() // 获取文件后缀名并转为小写
|
||||||
console.log(documentExtensions)
|
console.log(documentExtensions)
|
||||||
if (imageExtensions.includes(extension)) {
|
if (imageExtensions.includes(extension)) {
|
||||||
uploadImageList.value.push(file)
|
uploadImageList.value.push(file)
|
||||||
} else if (documentExtensions.includes(extension)) {
|
} else if (documentExtensions.includes(extension)) {
|
||||||
@ -447,13 +447,13 @@ console.log(documentExtensions)
|
|||||||
props.applicationDetails.id as string,
|
props.applicationDetails.id as string,
|
||||||
chatId_context.value as string,
|
chatId_context.value as string,
|
||||||
formData,
|
formData,
|
||||||
localLoading
|
localLoading,
|
||||||
)
|
)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
fileList.splice(0, fileList.length)
|
fileList.splice(0, fileList.length)
|
||||||
uploadImageList.value.forEach((file: any) => {
|
uploadImageList.value.forEach((file: any) => {
|
||||||
const f = response.data.filter(
|
const f = response.data.filter(
|
||||||
(f: any) => f.name.replaceAll(' ', '') === file.name.replaceAll(' ', '')
|
(f: any) => f.name.replaceAll(' ', '') === file.name.replaceAll(' ', ''),
|
||||||
)
|
)
|
||||||
if (f.length > 0) {
|
if (f.length > 0) {
|
||||||
file.url = f[0].url
|
file.url = f[0].url
|
||||||
@ -462,7 +462,7 @@ console.log(documentExtensions)
|
|||||||
})
|
})
|
||||||
uploadDocumentList.value.forEach((file: any) => {
|
uploadDocumentList.value.forEach((file: any) => {
|
||||||
const f = response.data.filter(
|
const f = response.data.filter(
|
||||||
(f: any) => f.name.replaceAll(' ', '') == file.name.replaceAll(' ', '')
|
(f: any) => f.name.replaceAll(' ', '') == file.name.replaceAll(' ', ''),
|
||||||
)
|
)
|
||||||
if (f.length > 0) {
|
if (f.length > 0) {
|
||||||
file.url = f[0].url
|
file.url = f[0].url
|
||||||
@ -471,7 +471,7 @@ console.log(documentExtensions)
|
|||||||
})
|
})
|
||||||
uploadAudioList.value.forEach((file: any) => {
|
uploadAudioList.value.forEach((file: any) => {
|
||||||
const f = response.data.filter(
|
const f = response.data.filter(
|
||||||
(f: any) => f.name.replaceAll(' ', '') === file.name.replaceAll(' ', '')
|
(f: any) => f.name.replaceAll(' ', '') === file.name.replaceAll(' ', ''),
|
||||||
)
|
)
|
||||||
if (f.length > 0) {
|
if (f.length > 0) {
|
||||||
file.url = f[0].url
|
file.url = f[0].url
|
||||||
@ -480,7 +480,7 @@ console.log(documentExtensions)
|
|||||||
})
|
})
|
||||||
uploadVideoList.value.forEach((file: any) => {
|
uploadVideoList.value.forEach((file: any) => {
|
||||||
const f = response.data.filter(
|
const f = response.data.filter(
|
||||||
(f: any) => f.name.replaceAll(' ', '') === file.name.replaceAll(' ', '')
|
(f: any) => f.name.replaceAll(' ', '') === file.name.replaceAll(' ', ''),
|
||||||
)
|
)
|
||||||
if (f.length > 0) {
|
if (f.length > 0) {
|
||||||
file.url = f[0].url
|
file.url = f[0].url
|
||||||
@ -489,7 +489,7 @@ console.log(documentExtensions)
|
|||||||
})
|
})
|
||||||
uploadOtherList.value.forEach((file: any) => {
|
uploadOtherList.value.forEach((file: any) => {
|
||||||
const f = response.data.filter(
|
const f = response.data.filter(
|
||||||
(f: any) => f.name.replaceAll(' ', '') === file.name.replaceAll(' ', '')
|
(f: any) => f.name.replaceAll(' ', '') === file.name.replaceAll(' ', ''),
|
||||||
)
|
)
|
||||||
if (f.length > 0) {
|
if (f.length > 0) {
|
||||||
file.url = f[0].url
|
file.url = f[0].url
|
||||||
@ -520,7 +520,7 @@ const handlePaste = (event: ClipboardEvent) => {
|
|||||||
size: rawFile.size,
|
size: rawFile.size,
|
||||||
raw: rawFile, // 原始文件对象
|
raw: rawFile, // 原始文件对象
|
||||||
status: 'ready', // 文件状态
|
status: 'ready', // 文件状态
|
||||||
percentage: 0 // 上传进度
|
percentage: 0, // 上传进度
|
||||||
}
|
}
|
||||||
|
|
||||||
// 手动触发上传逻辑(模拟 on-change 事件)
|
// 手动触发上传逻辑(模拟 on-change 事件)
|
||||||
@ -544,7 +544,7 @@ const handleDrop = (event: DragEvent) => {
|
|||||||
size: rawFile.size,
|
size: rawFile.size,
|
||||||
raw: rawFile,
|
raw: rawFile,
|
||||||
status: 'ready',
|
status: 'ready',
|
||||||
percentage: 0
|
percentage: 0,
|
||||||
}
|
}
|
||||||
uploadFile(elFile, [elFile])
|
uploadFile(elFile, [elFile])
|
||||||
})
|
})
|
||||||
@ -566,7 +566,7 @@ const uploadOtherList = ref<Array<any>>([])
|
|||||||
const showDelete = ref('')
|
const showDelete = ref('')
|
||||||
|
|
||||||
const isDisabledChat = computed(
|
const isDisabledChat = computed(
|
||||||
() => !(inputValue.value.trim() && (props.appId || props.applicationDetails?.name))
|
() => !(inputValue.value.trim() && (props.appId || props.applicationDetails?.name)),
|
||||||
)
|
)
|
||||||
// 是否显示移动端语音按钮
|
// 是否显示移动端语音按钮
|
||||||
const isMicrophone = ref(false)
|
const isMicrophone = ref(false)
|
||||||
@ -605,7 +605,7 @@ class RecorderManage {
|
|||||||
const recorder = new Recorder({
|
const recorder = new Recorder({
|
||||||
type: 'mp3',
|
type: 'mp3',
|
||||||
bitRate: 128,
|
bitRate: 128,
|
||||||
sampleRate: 16000
|
sampleRate: 16000,
|
||||||
})
|
})
|
||||||
if (!this.recorder) {
|
if (!this.recorder) {
|
||||||
recorder.open(() => {
|
recorder.open(() => {
|
||||||
@ -625,7 +625,7 @@ class RecorderManage {
|
|||||||
const recorder = new Recorder({
|
const recorder = new Recorder({
|
||||||
type: 'mp3',
|
type: 'mp3',
|
||||||
bitRate: 128,
|
bitRate: 128,
|
||||||
sampleRate: 16000
|
sampleRate: 16000,
|
||||||
})
|
})
|
||||||
recorder.open(() => {
|
recorder.open(() => {
|
||||||
this.recorder = recorder
|
this.recorder = recorder
|
||||||
@ -648,9 +648,9 @@ class RecorderManage {
|
|||||||
MsgAlert(t('common.tip'), err, {
|
MsgAlert(t('common.tip'), err, {
|
||||||
confirmButtonText: t('chat.tip.confirm'),
|
confirmButtonText: t('chat.tip.confirm'),
|
||||||
dangerouslyUseHTMLString: true,
|
dangerouslyUseHTMLString: true,
|
||||||
customClass: 'record-tip-confirm'
|
customClass: 'record-tip-confirm',
|
||||||
})
|
})
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -666,7 +666,7 @@ class RecorderManage {
|
|||||||
MsgAlert(t('common.tip'), err, {
|
MsgAlert(t('common.tip'), err, {
|
||||||
confirmButtonText: t('chat.tip.confirm'),
|
confirmButtonText: t('chat.tip.confirm'),
|
||||||
dangerouslyUseHTMLString: true,
|
dangerouslyUseHTMLString: true,
|
||||||
customClass: 'record-tip-confirm'
|
customClass: 'record-tip-confirm',
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
MsgAlert(
|
MsgAlert(
|
||||||
@ -678,8 +678,8 @@ class RecorderManage {
|
|||||||
{
|
{
|
||||||
confirmButtonText: t('chat.tip.confirm'),
|
confirmButtonText: t('chat.tip.confirm'),
|
||||||
dangerouslyUseHTMLString: true,
|
dangerouslyUseHTMLString: true,
|
||||||
customClass: 'record-tip-confirm'
|
customClass: 'record-tip-confirm',
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -775,7 +775,7 @@ function autoSendMessage() {
|
|||||||
document_list: uploadDocumentList.value,
|
document_list: uploadDocumentList.value,
|
||||||
audio_list: uploadAudioList.value,
|
audio_list: uploadAudioList.value,
|
||||||
video_list: uploadVideoList.value,
|
video_list: uploadVideoList.value,
|
||||||
other_list: uploadOtherList.value
|
other_list: uploadOtherList.value,
|
||||||
})
|
})
|
||||||
inputValue.value = ''
|
inputValue.value = ''
|
||||||
uploadImageList.value = []
|
uploadImageList.value = []
|
||||||
@ -794,7 +794,7 @@ function autoSendMessage() {
|
|||||||
|
|
||||||
function sendChatHandle(event?: any) {
|
function sendChatHandle(event?: any) {
|
||||||
const isMobile = /Mobi|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
|
const isMobile = /Mobi|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
|
||||||
navigator.userAgent
|
navigator.userAgent,
|
||||||
)
|
)
|
||||||
// 如果是移动端,且按下回车键,不直接发送
|
// 如果是移动端,且按下回车键,不直接发送
|
||||||
if ((isMobile || mode === 'mobile') && event?.key === 'Enter') {
|
if ((isMobile || mode === 'mobile') && event?.key === 'Enter') {
|
||||||
@ -816,7 +816,7 @@ function sendChatHandle(event?: any) {
|
|||||||
}
|
}
|
||||||
const insertNewlineAtCursor = (event?: any) => {
|
const insertNewlineAtCursor = (event?: any) => {
|
||||||
const textarea = quickInputRef.value.$el.querySelector(
|
const textarea = quickInputRef.value.$el.querySelector(
|
||||||
'.el-textarea__inner'
|
'.el-textarea__inner',
|
||||||
) as HTMLTextAreaElement
|
) as HTMLTextAreaElement
|
||||||
const startPos = textarea.selectionStart
|
const startPos = textarea.selectionStart
|
||||||
const endPos = textarea.selectionEnd
|
const endPos = textarea.selectionEnd
|
||||||
@ -887,22 +887,10 @@ onMounted(() => {
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.ai-chat {
|
.ai-chat {
|
||||||
&__operate {
|
&__operate {
|
||||||
background: #f3f7f9;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
|
|
||||||
&:before {
|
|
||||||
background: linear-gradient(0deg, #f3f7f9 0%, rgba(243, 247, 249, 0) 100%);
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
width: 100%;
|
|
||||||
top: -16px;
|
|
||||||
left: 0;
|
|
||||||
height: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.operate-textarea) {
|
:deep(.operate-textarea) {
|
||||||
box-shadow: 0px 6px 24px 0px rgba(31, 35, 41, 0.08);
|
box-shadow: 0px 6px 24px 0px rgba(31, 35, 41, 0.08);
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="chat-pc layout-bg"
|
class="chat-pc"
|
||||||
:class="classObj"
|
:class="classObj"
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
:style="{
|
:style="{
|
||||||
@ -8,12 +8,11 @@
|
|||||||
'--el-color-primary-light-9': hexToRgba(applicationDetail?.custom_theme?.theme_color, 0.1),
|
'--el-color-primary-light-9': hexToRgba(applicationDetail?.custom_theme?.theme_color, 0.1),
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
11111111111
|
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="chat-pc__left border-r">
|
<div class="chat-pc__left border-r">
|
||||||
<div class="p-24 pb-0">
|
<div class="p-16-24 pb-0">
|
||||||
<div class="flex align-center">
|
<div class="flex align-center mb-16">
|
||||||
<div class="mr-12 ml-24 flex">
|
<div class="flex">
|
||||||
<el-avatar
|
<el-avatar
|
||||||
v-if="isAppIcon(applicationDetail?.icon)"
|
v-if="isAppIcon(applicationDetail?.icon)"
|
||||||
shape="square"
|
shape="square"
|
||||||
@ -92,7 +91,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="chat-pc__right">
|
<div class="chat-pc__right">
|
||||||
<div class="right-header border-b mb-24 p-16-24 flex-between">
|
<div class="mb-24 p-16-24 flex-between">
|
||||||
<h4 class="ellipsis-1" style="width: 66%">
|
<h4 class="ellipsis-1" style="width: 66%">
|
||||||
{{ currentChatName }}
|
{{ currentChatName }}
|
||||||
</h4>
|
</h4>
|
||||||
@ -394,6 +393,7 @@ onMounted(() => {
|
|||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.chat-pc {
|
.chat-pc {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
background: #eef1f4;
|
||||||
|
|
||||||
&__header {
|
&__header {
|
||||||
background: var(--app-header-bg-color);
|
background: var(--app-header-bg-color);
|
||||||
@ -409,8 +409,10 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
&__left {
|
&__left {
|
||||||
padding-top: calc(var(--app-header-height) - 8px);
|
background:
|
||||||
background: #ffffff;
|
linear-gradient(187.61deg, rgba(235, 241, 255, 0.5) 39.6%, rgba(231, 249, 255, 0.5) 94.3%),
|
||||||
|
#eef1f4;
|
||||||
|
|
||||||
width: 280px;
|
width: 280px;
|
||||||
|
|
||||||
.add-button {
|
.add-button {
|
||||||
@ -418,22 +420,16 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.left-height {
|
.left-height {
|
||||||
height: calc(100vh - var(--app-header-height) - 135px);
|
height: calc(100vh - var(--app-header-height) - 85px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__right {
|
&__right {
|
||||||
width: calc(100% - 280px);
|
width: calc(100% - 280px);
|
||||||
padding-top: calc(var(--app-header-height));
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
||||||
.right-header {
|
|
||||||
background: #ffffff;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.right-height {
|
.right-height {
|
||||||
height: calc(100vh - var(--app-header-height) * 2 - 24px);
|
height: calc(100vh - var(--app-header-height) * 2 - 24px);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user