|
@@ -21,9 +21,9 @@
|
|
<i class="fas fa-key"></i>
|
|
<i class="fas fa-key"></i>
|
|
修改密码
|
|
修改密码
|
|
</div>
|
|
</div>
|
|
- <div class="dropdown-item" @click="handleResetPassword">
|
|
|
|
- <i class="fas fa-redo"></i>
|
|
|
|
- 重置密码
|
|
|
|
|
|
+ <div class="dropdown-item" @click="handleCreateInvitation">
|
|
|
|
+ <i class="fas fa-user-plus"></i>
|
|
|
|
+ 创建邀请
|
|
</div>
|
|
</div>
|
|
<div class="dropdown-item" @click="handleLogout">
|
|
<div class="dropdown-item" @click="handleLogout">
|
|
<i class="fas fa-sign-out-alt"></i>
|
|
<i class="fas fa-sign-out-alt"></i>
|
|
@@ -230,7 +230,7 @@
|
|
|
|
|
|
<!-- 音频控制按钮 -->
|
|
<!-- 音频控制按钮 -->
|
|
<div
|
|
<div
|
|
- v-if="message.role === 'assistant' && message.audioData"
|
|
|
|
|
|
+ v-if="message.role === 'assistant'"
|
|
class="audio-controls"
|
|
class="audio-controls"
|
|
>
|
|
>
|
|
<button class="audio-btn" @click="handleAudioClick(message)">
|
|
<button class="audio-btn" @click="handleAudioClick(message)">
|
|
@@ -657,6 +657,7 @@ import DocumentPreview from "../components/DocumentPreview/index.vue";
|
|
import KnowledgeResults from "../components/KnowledgeResults/index.vue";
|
|
import KnowledgeResults from "../components/KnowledgeResults/index.vue";
|
|
import ChangePasswordDialog from '../components/ChangePasswordDialog.vue'
|
|
import ChangePasswordDialog from '../components/ChangePasswordDialog.vue'
|
|
import { useRouter } from 'vue-router'
|
|
import { useRouter } from 'vue-router'
|
|
|
|
+import { message } from 'ant-design-vue';
|
|
|
|
|
|
// 初始化 markdown-it
|
|
// 初始化 markdown-it
|
|
const md = new MarkdownIt({
|
|
const md = new MarkdownIt({
|
|
@@ -699,6 +700,7 @@ const isPlaying = ref(false);
|
|
|
|
|
|
// 添加当前播放消息的 ID
|
|
// 添加当前播放消息的 ID
|
|
const currentPlayingId = ref(null);
|
|
const currentPlayingId = ref(null);
|
|
|
|
+const currentAudioSource = ref(null);
|
|
|
|
|
|
// 添加新的响应式变量
|
|
// 添加新的响应式变量
|
|
const isUploading = ref(false);
|
|
const isUploading = ref(false);
|
|
@@ -1062,6 +1064,13 @@ const scrollToBottom = () => {
|
|
const session_id = ref("");
|
|
const session_id = ref("");
|
|
// 修改发送消息方法
|
|
// 修改发送消息方法
|
|
const sendMessage = async () => {
|
|
const sendMessage = async () => {
|
|
|
|
+ // 检查登录状态
|
|
|
|
+ const token = localStorage.getItem('token');
|
|
|
|
+ if (!token) {
|
|
|
|
+ router.push('/login');
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
if (
|
|
if (
|
|
(!inputContent.value.trim() && attachedFiles.value.length === 0) ||
|
|
(!inputContent.value.trim() && attachedFiles.value.length === 0) ||
|
|
isTyping.value
|
|
isTyping.value
|
|
@@ -1374,13 +1383,67 @@ const handleFileDrop = async (event) => {
|
|
|
|
|
|
// 添加音频点击处理方法
|
|
// 添加音频点击处理方法
|
|
const handleAudioClick = (message) => {
|
|
const handleAudioClick = (message) => {
|
|
- if (currentPlayingId.value === message.id) {
|
|
|
|
- stopAudio();
|
|
|
|
- } else {
|
|
|
|
- playAudioMessage(message.audioData, message.id);
|
|
|
|
|
|
+ if(message.audioData){
|
|
|
|
+ if (currentPlayingId.value === message.id) {
|
|
|
|
+ stopAudio();
|
|
|
|
+ } else {
|
|
|
|
+ playAudioMessage(message.audioData, message.id);
|
|
|
|
+ }
|
|
|
|
+ }else{
|
|
|
|
+ // 用户消息的文本转语音处理
|
|
|
|
+ playUserMessage(message.content, message.id);
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+// 添加播放用户消息的方法
|
|
|
|
+const playUserMessage = async (text, messageId) => {
|
|
|
|
+ try {
|
|
|
|
+ // 如果当前有音频在播放,先停止
|
|
|
|
+ if (currentPlayingId.value) {
|
|
|
|
+ stopAudio();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const response = await axios.post(`${import.meta.env.VITE_BASE_AI_API}/api/voices/play_text`, {
|
|
|
|
+ text: text
|
|
|
|
+ }, {
|
|
|
|
+ headers: {
|
|
|
|
+ 'Authorization': `JWT ${localStorage.getItem('token')}`
|
|
|
|
+ },
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ if(response.data.code === 200){
|
|
|
|
+ // 创建音频元素
|
|
|
|
+ const audio = new Audio(`${import.meta.env.VITE_BASE_AI_API}${response.data.audio_url}`);
|
|
|
|
+
|
|
|
|
+ // 保存当前播放的音频和ID
|
|
|
|
+ currentAudioSource.value = audio;
|
|
|
|
+ currentPlayingId.value = messageId;
|
|
|
|
+
|
|
|
|
+ // 播放结束时清理
|
|
|
|
+ audio.onended = () => {
|
|
|
|
+ currentPlayingId.value = null;
|
|
|
|
+ currentAudioSource.value = null;
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ // 开始播放
|
|
|
|
+ await audio.play();
|
|
|
|
+ }
|
|
|
|
+ } catch (error) {
|
|
|
|
+ console.error('播放文本失败:', error);
|
|
|
|
+ message.error('播放失败,请稍后重试');
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+/* // 停止音频播放的函数
|
|
|
|
+const stopAudio = () => {
|
|
|
|
+ if (currentAudioSource.value) {
|
|
|
|
+ currentAudioSource.value.pause();
|
|
|
|
+ currentAudioSource.value.currentTime = 0;
|
|
|
|
+ currentAudioSource.value = null;
|
|
|
|
+ currentPlayingId.value = null;
|
|
|
|
+ }
|
|
|
|
+} */
|
|
|
|
+
|
|
// 修改音频播放方法
|
|
// 修改音频播放方法
|
|
const playAudioMessage = async (audioBase64, messageId) => {
|
|
const playAudioMessage = async (audioBase64, messageId) => {
|
|
try {
|
|
try {
|
|
@@ -1417,6 +1480,11 @@ const stopAudio = () => {
|
|
audioPlayer.value.pause();
|
|
audioPlayer.value.pause();
|
|
audioPlayer.value = null;
|
|
audioPlayer.value = null;
|
|
}
|
|
}
|
|
|
|
+ if (currentAudioSource.value) {
|
|
|
|
+ currentAudioSource.value.pause();
|
|
|
|
+ currentAudioSource.value.currentTime = 0;
|
|
|
|
+ currentAudioSource.value = null;
|
|
|
|
+ }
|
|
isPlaying.value = false;
|
|
isPlaying.value = false;
|
|
currentPlayingId.value = null;
|
|
currentPlayingId.value = null;
|
|
};
|
|
};
|
|
@@ -1433,7 +1501,7 @@ const renderMarkdown = (content) => {
|
|
};
|
|
};
|
|
|
|
|
|
// 添加新的响应式变量
|
|
// 添加新的响应式变量
|
|
-const rightMenuWidth = ref(600); // 默认宽度
|
|
|
|
|
|
+const rightMenuWidth = ref(450); // 默认宽度
|
|
const minWidth = 0; // 最小宽度
|
|
const minWidth = 0; // 最小宽度
|
|
const maxWidth = 800; // 最大宽度
|
|
const maxWidth = 800; // 最大宽度
|
|
|
|
|
|
@@ -1772,6 +1840,54 @@ const updateCollapsedState = () => {
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+ const handleCreateInvitation = async () => {
|
|
|
|
+ try {
|
|
|
|
+ const response = await axios.post(`${import.meta.env.VITE_BASE_AI_API}/user/create_invitation`, {}, {
|
|
|
|
+ headers: {
|
|
|
|
+ 'Authorization': `JWT ${localStorage.getItem('token')}`
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ console.log(response);
|
|
|
|
+ if (response.data.code === 200) {
|
|
|
|
+ message.success('创建邀请成功');
|
|
|
|
+ // 从当前窗口location获取基础URL
|
|
|
|
+ const baseUrl = `${window.location.protocol}//${window.location.host}`;
|
|
|
|
+ // 跳转到完整URL
|
|
|
|
+ window.location.href = `${baseUrl}${response.data.data.invitation_link}`;
|
|
|
|
+ } else {
|
|
|
|
+ message.error(response.data.message || '创建邀请失败');
|
|
|
|
+ }
|
|
|
|
+ } catch (error) {
|
|
|
|
+ console.error('创建邀请失败:', error);
|
|
|
|
+ message.error(error.response?.data?.message || '创建邀请失败,请稍后重试');
|
|
|
|
+ }
|
|
|
|
+ showDropdown.value = false; // 关闭下拉菜单
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+/* return {
|
|
|
|
+ loginForm,
|
|
|
|
+ formData,
|
|
|
|
+ rules,
|
|
|
|
+ loading,
|
|
|
|
+ rememberMe,
|
|
|
|
+ loginType,
|
|
|
|
+ countdown,
|
|
|
|
+ handleLogin,
|
|
|
|
+ sendVerificationCode,
|
|
|
|
+ switchToMobileLogin,
|
|
|
|
+ switchToAccountLogin,
|
|
|
|
+ switchToWechatLogin,
|
|
|
|
+ wechatLoginModal,
|
|
|
|
+ wechatQrCode,
|
|
|
|
+ getWechatQrCode,
|
|
|
|
+ handleWechatLoginCancel,
|
|
|
|
+ handleCreateInvitation
|
|
|
|
+ }; */
|
|
|
|
+
|
|
|
|
+ // These variables are already declared above
|
|
|
|
+ /* const currentAudioSource = ref(null);
|
|
|
|
+ const currentPlayingId = ref(null); */
|
|
|
|
+
|
|
</script>
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
<style scoped>
|
|
@@ -1871,12 +1987,13 @@ const updateCollapsedState = () => {
|
|
border-right: 1px solid rgba(0, 0, 0, 0.06);
|
|
border-right: 1px solid rgba(0, 0, 0, 0.06);
|
|
position: absolute;
|
|
position: absolute;
|
|
left: 0;
|
|
left: 0;
|
|
- transform: translateX(0);
|
|
|
|
|
|
+ /* transform: translateX(0); */
|
|
transition: all 0.3s ease;
|
|
transition: all 0.3s ease;
|
|
z-index: 2;
|
|
z-index: 2;
|
|
}
|
|
}
|
|
|
|
|
|
.menu.collapsed {
|
|
.menu.collapsed {
|
|
|
|
+ display: none;
|
|
transform: translateX(-260px);
|
|
transform: translateX(-260px);
|
|
width: 0;
|
|
width: 0;
|
|
}
|
|
}
|
|
@@ -1903,6 +2020,7 @@ const updateCollapsedState = () => {
|
|
right: 0;
|
|
right: 0;
|
|
top: 0;
|
|
top: 0;
|
|
bottom: 0;
|
|
bottom: 0;
|
|
|
|
+ justify-content: space-between;
|
|
}
|
|
}
|
|
|
|
|
|
.menu:not(.collapsed) + .chat {
|
|
.menu:not(.collapsed) + .chat {
|
|
@@ -1915,11 +2033,11 @@ const updateCollapsedState = () => {
|
|
}
|
|
}
|
|
|
|
|
|
.layout:has(.right_menu:not(.collapsed)) .chat {
|
|
.layout:has(.right_menu:not(.collapsed)) .chat {
|
|
- right: 600px;
|
|
|
|
|
|
+ right: 450px;
|
|
}
|
|
}
|
|
|
|
|
|
.right_menu:not(.collapsed) ~ .chat {
|
|
.right_menu:not(.collapsed) ~ .chat {
|
|
- right: 600px;
|
|
|
|
|
|
+ right: 450px;
|
|
}
|
|
}
|
|
|
|
|
|
.messages {
|
|
.messages {
|
|
@@ -2539,7 +2657,7 @@ const updateCollapsedState = () => {
|
|
display: flex;
|
|
display: flex;
|
|
flex-direction: column;
|
|
flex-direction: column;
|
|
gap: 16px;
|
|
gap: 16px;
|
|
- margin: 0 auto;
|
|
|
|
|
|
+ margin: 30px auto 0;
|
|
}
|
|
}
|
|
|
|
|
|
.message-item {
|
|
.message-item {
|
|
@@ -2601,7 +2719,7 @@ const updateCollapsedState = () => {
|
|
|
|
|
|
/* 当右侧菜单展开时,给聊天区域添加右边距 */
|
|
/* 当右侧菜单展开时,给聊天区域添加右边距 */
|
|
.right_menu:not(.collapsed) + .chat {
|
|
.right_menu:not(.collapsed) + .chat {
|
|
- margin-right: 600px;
|
|
|
|
|
|
+ margin-right: 450px;
|
|
}
|
|
}
|
|
|
|
|
|
.collapse-left-button{
|
|
.collapse-left-button{
|
|
@@ -3113,7 +3231,7 @@ const updateCollapsedState = () => {
|
|
/* 移动端菜单调整 */
|
|
/* 移动端菜单调整 */
|
|
position: fixed;
|
|
position: fixed;
|
|
width: 100%;
|
|
width: 100%;
|
|
- height: 100%;
|
|
|
|
|
|
+ height: 93%;
|
|
z-index: 1000;
|
|
z-index: 1000;
|
|
transform: translateX(-100%);
|
|
transform: translateX(-100%);
|
|
}
|
|
}
|
|
@@ -3123,8 +3241,9 @@ const updateCollapsedState = () => {
|
|
}
|
|
}
|
|
|
|
|
|
.collapse-left-button {
|
|
.collapse-left-button {
|
|
|
|
+ z-index: 999;
|
|
/* 移动端收缩按钮调整 */
|
|
/* 移动端收缩按钮调整 */
|
|
- display: none;
|
|
|
|
|
|
+ /* display: none; */
|
|
}
|
|
}
|
|
|
|
|
|
.chat {
|
|
.chat {
|
|
@@ -3642,6 +3761,7 @@ button,
|
|
font-size: 14px;
|
|
font-size: 14px;
|
|
transition: all 0.3s;
|
|
transition: all 0.3s;
|
|
white-space: nowrap;
|
|
white-space: nowrap;
|
|
|
|
+ color: #000000a6;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -3810,7 +3930,7 @@ button,
|
|
right: 0;
|
|
right: 0;
|
|
top: 0;
|
|
top: 0;
|
|
bottom: 0;
|
|
bottom: 0;
|
|
- width: 600px;
|
|
|
|
|
|
+ width: 450px;
|
|
background: #fff;
|
|
background: #fff;
|
|
border-left: 1px solid rgba(0, 0, 0, 0.06);
|
|
border-left: 1px solid rgba(0, 0, 0, 0.06);
|
|
display: flex;
|
|
display: flex;
|
|
@@ -3903,13 +4023,13 @@ button,
|
|
}
|
|
}
|
|
|
|
|
|
.right_menu:not(.collapsed) ~ .chat {
|
|
.right_menu:not(.collapsed) ~ .chat {
|
|
- right: 600px;
|
|
|
|
|
|
+ right: 450px;
|
|
}
|
|
}
|
|
|
|
|
|
/* 移动端适配 */
|
|
/* 移动端适配 */
|
|
@media screen and (max-width: 768px) {
|
|
@media screen and (max-width: 768px) {
|
|
.right_menu {
|
|
.right_menu {
|
|
- width: 100%;
|
|
|
|
|
|
+ width: 93%;
|
|
}
|
|
}
|
|
|
|
|
|
.right_menu:not(.collapsed) ~ .chat {
|
|
.right_menu:not(.collapsed) ~ .chat {
|