改动结果:
聊天窗口工具栏新增了“表情”按钮,打开表情库弹窗。 表情库会从历史“已下载落盘的表情消息”里自动聚合。 选中后直接通过 send_emoji_message(wxid, md5, total_length) 发原生表情,不是当普通图片发。 仍保持你现在的发送通道和聊天刷新逻辑。 主要改动文件: 后端接口与发送支持:contacts.py 表情资源查询:message_storage.py 前端表情面板与发送交互:contacts_management.html 新增接口: GET /contacts/api/emojis:返回聚合后的表情库(md5、total_length、预览图)。 POST /contacts/api/send_message 新增 type=emoji。 我也做了 Python 语法检查,相关后端文件都通过了。 你可以直接在聊天弹窗里点“表情”试一下。如果表情库为空,通常是该群还没落盘到 image_path,让媒体下载功能先抓几条表情就会出现。
This commit is contained in:
@@ -679,6 +679,7 @@
|
||||
<el-upload class="upload-demo" action="#" :http-request="uploadImage" :show-file-list="false" accept="image/*">
|
||||
<el-button size="small" type="primary" plain icon="el-icon-picture-outline">图片</el-button>
|
||||
</el-upload>
|
||||
<el-button size="small" type="primary" plain icon="el-icon-star-off" @click="openEmojiDialog">表情</el-button>
|
||||
<el-upload class="upload-demo" action="#" :http-request="uploadVoice" :show-file-list="false" accept=".mp3,.wav,audio/*">
|
||||
<el-button size="small" type="primary" plain icon="el-icon-microphone">语音</el-button>
|
||||
</el-upload>
|
||||
@@ -703,6 +704,25 @@
|
||||
<el-button type="primary" @click="sendLinkMessage">发送</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog title="表情库" :visible.sync="emojiDialogVisible" width="52%">
|
||||
<div class="emoji-toolbar">
|
||||
<el-input v-model="emojiKeyword" clearable placeholder="搜索 md5..." size="small"></el-input>
|
||||
<el-button size="small" icon="el-icon-refresh" :loading="emojiLibraryLoading" @click="loadEmojiLibrary">刷新</el-button>
|
||||
</div>
|
||||
<div class="emoji-grid" v-loading="emojiLibraryLoading">
|
||||
{% raw %}
|
||||
<div v-if="!filteredEmojiLibrary.length" class="emoji-empty">暂无可用表情,先在群里让媒体下载插件抓取几条表情。</div>
|
||||
<div v-for="item in filteredEmojiLibrary" :key="item.md5" class="emoji-card">
|
||||
<img class="emoji-thumb" :src="getChatMediaUrl(item.preview_url)" />
|
||||
<div class="emoji-md5">{{ item.md5 }}</div>
|
||||
<div class="emoji-actions">
|
||||
<el-button type="primary" size="mini" @click="sendEmojiItem(item)">发送</el-button>
|
||||
</div>
|
||||
</div>
|
||||
{% endraw %}
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -739,7 +759,11 @@
|
||||
chatDialogVisible: false, currentChatUser: null, messageInput: '', chatMessages: [], chatLoading: false, chatSending: false,
|
||||
chatType: 'personal', chatHistoryTip: '最近 20 条消息',
|
||||
linkDialogVisible: false,
|
||||
linkForm: { url: '', title: '', description: '' }
|
||||
linkForm: { url: '', title: '', description: '' },
|
||||
emojiDialogVisible: false,
|
||||
emojiLibraryLoading: false,
|
||||
emojiLibrary: [],
|
||||
emojiKeyword: ''
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -781,6 +805,11 @@
|
||||
{ label: '插件调用', value: overview.plugin_call_count_30d || 0, note: '近30天插件总触发次数' },
|
||||
{ label: '插件种类', value: overview.plugin_count_30d || 0, note: '本群真实使用到的插件数' }
|
||||
];
|
||||
},
|
||||
filteredEmojiLibrary() {
|
||||
const keyword = (this.emojiKeyword || '').trim().toLowerCase();
|
||||
if (!keyword) return this.emojiLibrary;
|
||||
return this.emojiLibrary.filter(item => (item.md5 || '').toLowerCase().includes(keyword));
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@@ -1319,6 +1348,50 @@
|
||||
this.linkDialogVisible = false;
|
||||
}
|
||||
},
|
||||
openEmojiDialog() {
|
||||
if (!this.currentChatUser || !this.currentChatUser.wxid) return;
|
||||
this.emojiDialogVisible = true;
|
||||
this.loadEmojiLibrary();
|
||||
},
|
||||
async loadEmojiLibrary() {
|
||||
this.emojiLibraryLoading = true;
|
||||
try {
|
||||
const response = await axios.get('/contacts/api/emojis', { params: { limit: 300 } });
|
||||
if (response.data.success) {
|
||||
const list = (response.data.data && response.data.data.emojis) || [];
|
||||
this.emojiLibrary = Array.isArray(list) ? list : [];
|
||||
} else {
|
||||
this.$message.error(response.data.message || '加载表情库失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载表情库失败:', error);
|
||||
this.$message.error('加载表情库失败');
|
||||
} finally {
|
||||
this.emojiLibraryLoading = false;
|
||||
}
|
||||
},
|
||||
async sendEmojiItem(item) {
|
||||
if (!this.currentChatUser || !this.currentChatUser.wxid) return;
|
||||
const md5 = item && item.md5;
|
||||
const totalLength = item && item.total_length;
|
||||
if (!md5 || !totalLength) {
|
||||
this.$message.error('该表情缺少发送参数');
|
||||
return;
|
||||
}
|
||||
const localMessage = this.appendLocalChatMessage({
|
||||
displayType: 'image',
|
||||
content: '[表情]',
|
||||
mediaUrl: this.getChatMediaUrl(item.preview_url || '')
|
||||
});
|
||||
await this.sendChatPayload({
|
||||
wxid: this.currentChatUser.wxid,
|
||||
type: 'emoji',
|
||||
content: {
|
||||
md5: md5,
|
||||
total_length: totalLength
|
||||
}
|
||||
}, '表情消息已提交到 iPad 通道', localMessage.messageId);
|
||||
},
|
||||
handleChatInputKeydown(event) {
|
||||
if (event.key === 'Enter' && !event.shiftKey) {
|
||||
event.preventDefault();
|
||||
@@ -1493,6 +1566,19 @@
|
||||
.message-self .message-sender, .message-self .message-time, .message-self .message-link-title { color: #ffffff; }
|
||||
.input-area { padding: 20px 0 0; }
|
||||
.toolbar { margin-top: 12px; display: flex; gap: 10px; flex-wrap: wrap; }
|
||||
.emoji-toolbar { display: flex; gap: 10px; margin-bottom: 12px; }
|
||||
.emoji-grid {
|
||||
min-height: 280px; max-height: 520px; overflow-y: auto;
|
||||
display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 12px;
|
||||
}
|
||||
.emoji-card {
|
||||
border: 1px solid rgba(148,163,184,0.16); border-radius: 12px; padding: 8px;
|
||||
display: flex; flex-direction: column; gap: 8px; align-items: center; background: #fff;
|
||||
}
|
||||
.emoji-thumb { width: 72px; height: 72px; object-fit: contain; border-radius: 8px; background: rgba(148,163,184,0.08); }
|
||||
.emoji-md5 { font-size: 11px; color: #64748b; word-break: break-all; text-align: center; min-height: 30px; }
|
||||
.emoji-actions { width: 100%; display: flex; justify-content: center; }
|
||||
.emoji-empty { color: #94a3b8; padding: 12px; }
|
||||
@media (max-width: 1200px) {
|
||||
.diagnosis-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user