添加聊天功能

This commit is contained in:
liuwei
2025-05-29 16:03:51 +08:00
parent b18c1aa0e3
commit 32a04efe5a
2 changed files with 415 additions and 1 deletions

View File

@@ -111,6 +111,12 @@
{% raw %}@click="viewUserDetails(scope.row)" {% endraw %}>
查看详情
</el-button>
<el-button
size="mini"
type="success"
{% raw %}@click="openChatDialog(scope.row)" {% endraw %}>
聊天
</el-button>
</template>
</el-table-column>
</el-table>
@@ -347,6 +353,89 @@
<!-- 可以添加更多公共好友相关信息 -->
</el-descriptions>
</el-dialog>
<!-- 聊天对话框 -->
<el-dialog title="聊天" {% raw %}:visible.sync="chatDialogVisible" {% endraw %} width="60%" :close-on-click-modal="false">
<div class="chat-container">
<!-- 消息列表 -->
<div class="message-list" ref="messageList">
<div v-for="(msg, index) in chatMessages" :key="index" class="message-item" :class="{'message-self': msg.isSelf}">
<div class="message-content">
<div v-if="msg.type === 'text'">{{ msg.content }}</div>
<div v-else-if="msg.type === 'image'">
<img :src="msg.content" style="max-width: 200px; max-height: 200px;">
</div>
<div v-else-if="msg.type === 'voice'">
<audio controls :src="msg.content"></audio>
</div>
<div v-else-if="msg.type === 'video'">
<video controls :src="msg.content" style="max-width: 200px;"></video>
</div>
<div v-else-if="msg.type === 'link'">
<a :href="msg.content.url" target="_blank">{{ msg.content.title }}</a>
<p>{{ msg.content.description }}</p>
</div>
</div>
<div class="message-time">{{ msg.time }}</div>
</div>
</div>
<!-- 输入区域 -->
<div class="input-area">
<el-input
type="textarea"
:rows="3"
placeholder="请输入消息..."
{% raw %}v-model="messageInput" {% endraw %}
@keyup.enter.native="sendTextMessage">
</el-input>
<div class="toolbar">
<el-upload
class="upload-demo"
action="#"
:http-request="uploadImage"
:show-file-list="false">
<el-button size="small" type="primary">图片</el-button>
</el-upload>
<el-upload
class="upload-demo"
action="#"
:http-request="uploadVoice"
:show-file-list="false">
<el-button size="small" type="primary">语音</el-button>
</el-upload>
<el-upload
class="upload-demo"
action="#"
:http-request="uploadVideo"
:show-file-list="false">
<el-button size="small" type="primary">视频</el-button>
</el-upload>
<el-button size="small" type="primary" @click="showLinkDialog">链接</el-button>
<el-button size="small" type="primary" @click="sendTextMessage">发送</el-button>
</div>
</div>
</div>
</el-dialog>
<!-- 链接消息对话框 -->
<el-dialog title="发送链接" {% raw %}:visible.sync="linkDialogVisible" {% endraw %} width="30%">
<el-form :model="linkForm" label-width="80px">
<el-form-item label="链接">
<el-input v-model="linkForm.url" placeholder="请输入链接"></el-input>
</el-form-item>
<el-form-item label="标题">
<el-input v-model="linkForm.title" placeholder="请输入标题"></el-input>
</el-form-item>
<el-form-item label="描述">
<el-input type="textarea" v-model="linkForm.description" placeholder="请输入描述"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="linkDialogVisible = false">取消</el-button>
<el-button type="primary" @click="sendLinkMessage">发送</el-button>
</span>
</el-dialog>
</div>
{% endblock %}
@@ -386,7 +475,17 @@
groupMembersCurrentPage: 1,
groupMembersPageSize: 10,
groupMemberSearchQuery: '',
groupMembersLoading: false
groupMembersLoading: false,
chatDialogVisible: false,
currentChatUser: null,
messageInput: '',
chatMessages: [],
linkDialogVisible: false,
linkForm: {
url: '',
title: '',
description: ''
}
};
},
computed: {
@@ -662,6 +761,167 @@
},
handleGroupMembersCurrentChange(page) {
this.groupMembersCurrentPage = page;
},
// 打开聊天对话框
openChatDialog(user) {
this.currentChatUser = user;
this.chatDialogVisible = true;
this.chatMessages = [];
},
// 发送文本消息
async sendTextMessage() {
if (!this.messageInput.trim()) return;
try {
const response = await axios.post('/contacts/api/send_message', {
wxid: this.currentChatUser.wxid,
type: 'text',
content: this.messageInput
});
if (response.data.success) {
this.chatMessages.push({
type: 'text',
content: this.messageInput,
isSelf: true,
time: new Date().toLocaleTimeString()
});
this.messageInput = '';
this.$nextTick(() => {
this.scrollToBottom();
});
}
} catch (error) {
this.$message.error('发送消息失败');
}
},
// 上传图片
async uploadImage(options) {
const file = options.file;
const formData = new FormData();
formData.append('file', file);
formData.append('wxid', this.currentChatUser.wxid);
formData.append('type', 'image');
try {
const response = await axios.post('/contacts/api/send_message', formData);
if (response.data.success) {
this.chatMessages.push({
type: 'image',
content: response.data.url,
isSelf: true,
time: new Date().toLocaleTimeString()
});
this.$nextTick(() => {
this.scrollToBottom();
});
}
} catch (error) {
this.$message.error('发送图片失败');
}
},
// 上传语音
async uploadVoice(options) {
const file = options.file;
const formData = new FormData();
formData.append('file', file);
formData.append('wxid', this.currentChatUser.wxid);
formData.append('type', 'voice');
try {
const response = await axios.post('/contacts/api/send_message', formData);
if (response.data.success) {
this.chatMessages.push({
type: 'voice',
content: response.data.url,
isSelf: true,
time: new Date().toLocaleTimeString()
});
this.$nextTick(() => {
this.scrollToBottom();
});
}
} catch (error) {
this.$message.error('发送语音失败');
}
},
// 上传视频
async uploadVideo(options) {
const file = options.file;
const formData = new FormData();
formData.append('file', file);
formData.append('wxid', this.currentChatUser.wxid);
formData.append('type', 'video');
try {
const response = await axios.post('/contacts/api/send_message', formData);
if (response.data.success) {
this.chatMessages.push({
type: 'video',
content: response.data.url,
isSelf: true,
time: new Date().toLocaleTimeString()
});
this.$nextTick(() => {
this.scrollToBottom();
});
}
} catch (error) {
this.$message.error('发送视频失败');
}
},
// 显示链接对话框
showLinkDialog() {
this.linkForm = {
url: '',
title: '',
description: ''
};
this.linkDialogVisible = true;
},
// 发送链接消息
async sendLinkMessage() {
if (!this.linkForm.url) {
this.$message.warning('请输入链接');
return;
}
try {
const response = await axios.post('/contacts/api/send_message', {
wxid: this.currentChatUser.wxid,
type: 'link',
content: this.linkForm
});
if (response.data.success) {
this.chatMessages.push({
type: 'link',
content: this.linkForm,
isSelf: true,
time: new Date().toLocaleTimeString()
});
this.linkDialogVisible = false;
this.$nextTick(() => {
this.scrollToBottom();
});
}
} catch (error) {
this.$message.error('发送链接失败');
}
},
// 滚动到底部
scrollToBottom() {
const messageList = this.$refs.messageList;
if (messageList) {
messageList.scrollTop = messageList.scrollHeight;
}
}
},
});
@@ -704,5 +964,58 @@
font-size: 18px;
color: #303133;
}
.chat-container {
display: flex;
flex-direction: column;
height: 500px;
}
.message-list {
flex: 1;
overflow-y: auto;
padding: 20px;
background: #f5f5f5;
}
.message-item {
margin-bottom: 15px;
display: flex;
flex-direction: column;
}
.message-self {
align-items: flex-end;
}
.message-content {
max-width: 70%;
padding: 10px;
border-radius: 5px;
background: #fff;
box-shadow: 0 1px 2px rgba(0,0,0,0.1);
}
.message-self .message-content {
background: #95ec69;
}
.message-time {
font-size: 12px;
color: #999;
margin-top: 5px;
}
.input-area {
padding: 20px;
background: #fff;
border-top: 1px solid #eee;
}
.toolbar {
margin-top: 10px;
display: flex;
gap: 10px;
}
</style>
{% endblock %}