提交消息列表功能
This commit is contained in:
371
admin/dashboard/templates/message_list.html
Normal file
371
admin/dashboard/templates/message_list.html
Normal file
@@ -0,0 +1,371 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}消息列表{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div id="app">
|
||||
<h1>消息列表</h1>
|
||||
|
||||
<!-- 筛选条件 -->
|
||||
<el-card class="filter-card">
|
||||
<el-form :inline="true" size="small">
|
||||
<el-form-item label="群组">
|
||||
<el-select v-model="filter.groupId" placeholder="选择群组" clearable>
|
||||
<el-option
|
||||
v-for="group in groups"
|
||||
:key="group.id"
|
||||
:label="group.name"
|
||||
:value="group.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="日期范围">
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="yyyy-MM-dd"
|
||||
:picker-options="pickerOptions">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="搜索内容">
|
||||
<el-input v-model="filter.searchText" placeholder="搜索消息内容" clearable></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="searchMessages">搜索</el-button>
|
||||
<el-button @click="resetFilter">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<!-- 消息列表 -->
|
||||
<el-card class="message-card">
|
||||
<el-table
|
||||
:data="messages"
|
||||
style="width: 100%"
|
||||
size="small"
|
||||
v-loading="loading"
|
||||
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">
|
||||
{{ scope.row.content }}
|
||||
</div>
|
||||
|
||||
<!-- 图片消息 -->
|
||||
<div v-else-if="scope.row.message_type == 3">
|
||||
<div>【图片消息】</div>
|
||||
<img v-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>
|
||||
{{ scope.row.content || `【消息类型: ${scope.row.message_type}】` }}
|
||||
</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
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="pagination.page"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-size="pagination.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="pagination.total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 消息详情对话框 -->
|
||||
<el-dialog title="消息详情" :visible.sync="detailDialogVisible" width="60%">
|
||||
<div v-if="selectedMessage">
|
||||
<el-descriptions :column="1" border>
|
||||
<el-descriptions-item label="时间">{{ selectedMessage.timestamp }}</el-descriptions-item>
|
||||
<el-descriptions-item label="群组">{{ selectedMessage.group_name }}</el-descriptions-item>
|
||||
<el-descriptions-item label="发送者">{{ selectedMessage.sender_name }}</el-descriptions-item>
|
||||
<el-descriptions-item label="消息类型">{{ getMessageTypeName(selectedMessage.message_type) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="内容">{{ selectedMessage.content }}</el-descriptions-item>
|
||||
|
||||
<!-- 图片或视频消息 -->
|
||||
<el-descriptions-item v-if="selectedMessage.message_type == 3 || selectedMessage.message_type == 43" label="媒体内容">
|
||||
<img v-if="selectedMessage.message_type == 3 && selectedMessage.message_thumb" :src="selectedMessage.message_thumb" style="max-width: 100%;">
|
||||
<video v-if="selectedMessage.message_type == 43 && selectedMessage.attachment_url" :src="selectedMessage.attachment_url" controls style="max-width: 100%;"></video>
|
||||
</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item label="原始XML" v-if="selectedMessage.message_xml">
|
||||
<pre style="white-space: pre-wrap; word-break: break-all;">{{ selectedMessage.message_xml }}</pre>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 图片预览 -->
|
||||
<el-dialog :visible.sync="imageDialogVisible" append-to-body width="80%" class="image-dialog">
|
||||
<img v-if="selectedMessage && selectedMessage.message_thumb" :src="selectedMessage.message_thumb" style="max-width: 100%;">
|
||||
</el-dialog>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
new Vue({
|
||||
el: '#app',
|
||||
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
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 设置默认日期为今天
|
||||
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})`;
|
||||
}
|
||||
},
|
||||
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 %}
|
||||
Reference in New Issue
Block a user