Files
abot/admin/dashboard/templates/message_list.html
2025-04-02 11:46:13 +08:00

414 lines
17 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends "base.html" %}
{% block title %}消息列表{% endblock %}
{% block content %}
<!-- 消息列表 -->
<div>
<!-- 筛选条件 -->
<el-card class="filter-card">
<el-form {% raw %}:inline="true"{% endraw %} size="small">
<el-form-item label="群组">
<el-select {% raw %}v-model="filter.groupId"{% endraw %} placeholder="选择群组" clearable>
<el-option
{% raw %}v-for="group in groups"
:key="group.id"
:label="group.name"
:value="group.id"{% endraw %}>
</el-option>
</el-select>
</el-form-item>
<!-- 其他筛选条件保持不变 -->
<el-form-item label="日期范围">
<el-date-picker
{% raw %}v-model="dateRange"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="yyyy-MM-dd"
:picker-options="pickerOptions"{% endraw %}>
</el-date-picker>
</el-form-item>
<el-form-item label="搜索内容">
<el-input {% raw %}v-model="filter.searchText"{% endraw %} placeholder="搜索消息内容" clearable></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" {% raw %}@click="searchMessages"{% endraw %}>搜索</el-button>
<el-button {% raw %}@click="resetFilter"{% endraw %}>重置</el-button>
</el-form-item>
</el-form>
</el-card>
<!-- 消息列表内容保持不变 -->
<el-card class="message-card">
<el-table
{% raw %}:data="messages"
style="width: 100%"
size="small"
v-loading="loading"{% endraw %}
border>
<!-- 表格列保持不变 -->
<el-table-column
prop="timestamp"
label="时间"
width="150">
</el-table-column>
<el-table-column
prop="group_name"
label="群组"
width="150">
</el-table-column>
<el-table-column
prop="sender_name"
label="发送者"
width="120">
</el-table-column>
<el-table-column
prop="content"
label="内容">
<template slot-scope="scope">
<!-- 文本消息 -->
<div v-if="scope.row.message_type == 1">
{% raw %}{{ scope.row.content }}{% endraw %}
</div>
<!-- 图片消息 -->
<div v-else-if="scope.row.message_type == 3">
<div>【图片消息】</div>
<!-- 优先使用image_path显示图片如果没有则回退到message_thumb -->
<img v-if="scope.row.image_path" :src="getImageUrl(scope.row.image_path)" class="message-thumb" @click="showImage(scope.row)">
<img v-else-if="scope.row.message_thumb" :src="scope.row.message_thumb" class="message-thumb" @click="showImage(scope.row)">
</div>
<!-- 视频消息 -->
<div v-else-if="scope.row.message_type == 43">
<div>【视频消息】</div>
<img v-if="scope.row.message_thumb" :src="scope.row.message_thumb" class="message-thumb" @click="showVideo(scope.row)">
</div>
<!-- 其他类型消息 -->
<div v-else>
{% raw %}{{ scope.row.content || `【消息类型: ${scope.row.message_type}】` }}{% endraw %}
</div>
</template>
</el-table-column>
<el-table-column
label="操作"
width="100">
<template slot-scope="scope">
<el-button type="text" size="small" @click="showMessageDetail(scope.row)">详情</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div class="pagination-container">
<el-pagination
{% raw %}@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pagination.page"
:page-sizes="[10, 20, 50, 100]"
:page-size="pagination.pageSize"{% endraw %}
layout="total, sizes, prev, pager, next, jumper"
{% raw %}:total="pagination.total"{% endraw %}>
</el-pagination>
</div>
</el-card>
<!-- 对话框保持不变 -->
<!-- 消息详情对话框 -->
<el-dialog title="消息详情" {% raw %}:visible.sync="detailDialogVisible"{% endraw %} width="60%">
<div {% raw %}v-if="selectedMessage"{% endraw %}>
<el-descriptions {% raw %}:column="1"{% endraw %} border>
<el-descriptions-item label="时间">{% raw %}{{ selectedMessage.timestamp }}{% endraw %}</el-descriptions-item>
<el-descriptions-item label="群组">{% raw %}{{ selectedMessage.group_name }}{% endraw %}</el-descriptions-item>
<el-descriptions-item label="发送者">{% raw %}{{ selectedMessage.sender_name }}{% endraw %}</el-descriptions-item>
<el-descriptions-item label="消息类型">{% raw %}{{ getMessageTypeName(selectedMessage.message_type) }}{% endraw %}</el-descriptions-item>
<el-descriptions-item label="内容">{% raw %}{{ selectedMessage.content }}{% endraw %}</el-descriptions-item>
<!-- 图片或视频消息 -->
<el-descriptions-item {% raw %}v-if="selectedMessage.message_type == 3 || selectedMessage.message_type == 43"{% endraw %} label="媒体内容">
<img {% raw %}v-if="selectedMessage.message_type == 3 && selectedMessage.image_path" :src="getImageUrl(selectedMessage.image_path)"{% endraw %} style="max-width: 100%;">
<img {% raw %}v-else-if="selectedMessage.message_type == 3 && selectedMessage.message_thumb" :src="selectedMessage.message_thumb"{% endraw %} style="max-width: 100%;">
<video {% raw %}v-if="selectedMessage.message_type == 43 && selectedMessage.attachment_url" :src="selectedMessage.attachment_url"{% endraw %} controls style="max-width: 100%;"></video>
</el-descriptions-item>
<el-descriptions-item label="原始XML" {% raw %}v-if="selectedMessage.message_xml"{% endraw %}>
<pre style="white-space: pre-wrap; word-break: break-all;">{% raw %}{{ selectedMessage.message_xml }}{% endraw %}</pre>
</el-descriptions-item>
</el-descriptions>
</div>
</el-dialog>
<!-- 图片预览 -->
<el-dialog {% raw %}:visible.sync="imageDialogVisible"{% endraw %} append-to-body width="80%" class="image-dialog">
<img {% raw %}v-if="selectedMessage && selectedMessage.image_path" :src="getImageUrl(selectedMessage.image_path)"{% endraw %} style="max-width: 100%;">
<img {% raw %}v-else-if="selectedMessage && selectedMessage.message_thumb" :src="selectedMessage.message_thumb"{% endraw %} style="max-width: 100%;">
</el-dialog>
</div>
{% endblock %}
{% block scripts %}
<script>
new Vue({
el: '#app',
mixins: [baseApp],
data() {
return {
loading: false,
groups: [],
messages: [],
filter: {
groupId: '',
startDate: '',
endDate: '',
searchText: ''
},
dateRange: [],
pagination: {
page: 1,
pageSize: 20,
total: 0,
totalPages: 0
},
pickerOptions: {
shortcuts: [{
text: '今天',
onClick(picker) {
const end = new Date();
const start = new Date();
picker.$emit('pick', [start, end]);
}
}, {
text: '最近一周',
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
picker.$emit('pick', [start, end]);
}
}, {
text: '最近一个月',
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
picker.$emit('pick', [start, end]);
}
}]
},
detailDialogVisible: false,
imageDialogVisible: false,
selectedMessage: null
}
},
mounted() {
this.currentView = '7'; // 设置当前菜单项
// 设置默认日期为今天
const today = new Date();
this.dateRange = [this.formatDate(today), this.formatDate(today)];
this.filter.startDate = this.formatDate(today);
this.filter.endDate = this.formatDate(today);
// 加载群组列表
this.loadGroups();
// 加载消息列表
this.loadMessages();
},
methods: {
formatDate(date) {
const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, '0');
const day = date.getDate().toString().padStart(2, '0');
return `${year}-${month}-${day}`;
},
loadGroups() {
axios.get('/api/groups')
.then(response => {
if (response.data && response.data.groups) {
this.groups = response.data.groups.map(group => ({
id: group.group_id,
name: group.group_name || group.group_id
}));
}
})
.catch(error => {
console.error('加载群组失败:', error);
this.$message.error('加载群组失败');
});
},
loadMessages() {
this.loading = true;
// 构建查询参数
const params = {
page: this.pagination.page,
page_size: this.pagination.pageSize
};
if (this.filter.groupId) {
params.group_id = this.filter.groupId;
}
if (this.filter.startDate) {
params.start_date = this.filter.startDate;
}
if (this.filter.endDate) {
params.end_date = this.filter.endDate;
}
if (this.filter.searchText) {
params.search_text = this.filter.searchText;
}
axios.get('/api/messages', { params })
.then(response => {
this.messages = response.data.messages || [];
this.pagination.total = response.data.total || 0;
this.pagination.totalPages = response.data.total_pages || 0;
})
.catch(error => {
console.error('加载消息失败:', error);
this.$message.error('加载消息失败');
})
.finally(() => {
this.loading = false;
});
},
searchMessages() {
// 更新日期范围
if (this.dateRange && this.dateRange.length === 2) {
this.filter.startDate = this.dateRange[0];
this.filter.endDate = this.dateRange[1];
}
// 重置页码并加载消息
this.pagination.page = 1;
this.loadMessages();
},
resetFilter() {
// 重置筛选条件
this.filter.groupId = '';
this.filter.searchText = '';
// 设置日期为今天
const today = new Date();
this.dateRange = [this.formatDate(today), this.formatDate(today)];
this.filter.startDate = this.formatDate(today);
this.filter.endDate = this.formatDate(today);
// 重置页码并加载消息
this.pagination.page = 1;
this.loadMessages();
},
handleSizeChange(size) {
this.pagination.pageSize = size;
this.loadMessages();
},
handleCurrentChange(page) {
this.pagination.page = page;
this.loadMessages();
},
showMessageDetail(message) {
this.selectedMessage = message;
this.detailDialogVisible = true;
},
showImage(message) {
this.selectedMessage = message;
this.imageDialogVisible = true;
},
showVideo(message) {
this.selectedMessage = message;
this.detailDialogVisible = true;
},
getMessageTypeName(type) {
const typeMap = {
1: '文本消息',
3: '图片消息',
43: '视频消息',
49: '链接消息'
};
return typeMap[type] || `未知类型(${type})`;
},
getImageUrl(imagePath) {
// 如果路径为空,返回空字符串
if (!imagePath) return '';
// 如果已经是完整URL直接返回
if (imagePath.startsWith('http://') || imagePath.startsWith('https://')) {
return imagePath;
}
// 提取文件名和路径
const pathParts = imagePath.split(/[\/\\]/);
const fileName = pathParts[pathParts.length - 1];
// 如果路径包含群ID通常是倒数第二个部分
if (pathParts.length >= 2) {
const groupId = pathParts[pathParts.length - 2];
// 检查是否是群ID格式通常以@chatroom结尾
if (groupId.includes('@chatroom')) {
return `/static/images/${groupId}/${fileName}`;
}
}
// 检查路径中是否包含static/images
if (imagePath.includes('static/images') || imagePath.includes('static\\images')) {
// 提取static/images后面的部分
const parts = imagePath.split(/static[\/\\]images[\/\\]/);
if (parts.length > 1) {
return `/static/images/${parts[1]}`;
}
}
// 如果以上都不匹配,则直接使用文件名
return `/static/images/${fileName}`;
}
},
watch: {
dateRange(val) {
if (val && val.length === 2) {
this.filter.startDate = val[0];
this.filter.endDate = val[1];
}
}
}
});
</script>
<style>
.filter-card {
margin-bottom: 20px;
}
.message-card {
margin-bottom: 20px;
}
.pagination-container {
margin-top: 20px;
text-align: right;
}
.message-thumb {
max-width: 100px;
max-height: 100px;
cursor: pointer;
}
.image-dialog .el-dialog__body {
text-align: center;
}
</style>
{% endblock %}