473 lines
20 KiB
HTML
473 lines
20 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}群机器人管理 - 机器人管理后台{% endblock %}
|
|
|
|
{% block content %}
|
|
<!-- 群机器人管理 -->
|
|
<div>
|
|
<el-row :gutter="20">
|
|
<el-col :span="24">
|
|
<el-card shadow="hover">
|
|
<div slot="header" class="clearfix">
|
|
<span>群机器人管理</span>
|
|
<el-button
|
|
type="primary"
|
|
size="small"
|
|
style="float: right; margin-left: 10px;"
|
|
@click="showAddGroupDialog">
|
|
添加群组
|
|
</el-button>
|
|
<el-input
|
|
placeholder="搜索群组..."
|
|
v-model="searchQuery"
|
|
style="width: 200px; float: right"
|
|
clearable>
|
|
</el-input>
|
|
</div>
|
|
|
|
<!-- 群组列表 -->
|
|
<el-table
|
|
:data="filteredGroups"
|
|
style="width: 100%"
|
|
border
|
|
@selection-change="handleSelectionChange">
|
|
<el-table-column type="selection" width="55"></el-table-column>
|
|
<el-table-column label="群组信息">
|
|
<template slot-scope="scope">
|
|
{% raw %}{{ scope.row.group_name || scope.row.group_id }} ({{ scope.row.group_id }}){% endraw %}
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="机器人状态" width="120">
|
|
<template slot-scope="scope">
|
|
<el-tag
|
|
:type="scope.row.robot_status === 'enabled' ? 'success' : 'danger'">
|
|
{% raw %}{{ scope.row.robot_status === 'enabled' ? '已启用' : '已关闭' }}{% endraw %}
|
|
</el-tag>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="操作" width="280">
|
|
<template slot-scope="scope">
|
|
<el-button
|
|
size="mini"
|
|
type="primary"
|
|
@click="viewGroupPermissions(scope.row)">
|
|
查看权限
|
|
</el-button>
|
|
<el-button
|
|
size="mini"
|
|
:type="scope.row.robot_status === 'enabled' ? 'danger' : 'success'"
|
|
@click="toggleRobotStatus(scope.row)">
|
|
{% raw %}{{ scope.row.robot_status === 'enabled' ? '关闭' : '启用' }}{% endraw %}
|
|
</el-button>
|
|
<el-button
|
|
size="mini"
|
|
type="info"
|
|
@click="viewMessageTrend(scope.row)">
|
|
消息趋势
|
|
</el-button>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
|
|
<!-- 批量操作按钮 -->
|
|
<div style="margin-top: 20px" v-if="selectedGroups.length > 0">
|
|
<el-alert
|
|
title="批量操作"
|
|
type="info"
|
|
:closable="false">
|
|
<span>已选择 {% raw %}{{ selectedGroups.length }}{% endraw %} 个群组</span>
|
|
</el-alert>
|
|
<div style="margin-top: 10px">
|
|
<el-button type="success" size="small" @click="batchEnableRobot">批量启用</el-button>
|
|
<el-button type="danger" size="small" @click="batchDisableRobot">批量关闭</el-button>
|
|
<el-button type="warning" size="small" @click="batchRemoveGroups">批量移除</el-button>
|
|
</div>
|
|
</div>
|
|
</el-card>
|
|
</el-col>
|
|
</el-row>
|
|
|
|
<!-- 群组权限管理对话框 -->
|
|
<el-dialog
|
|
:title="currentGroupName + ' 功能权限管理'"
|
|
:visible.sync="permissionDialogVisible"
|
|
width="70%">
|
|
<el-table :data="permissions" style="width: 100%" border>
|
|
<el-table-column prop="feature_id" label="功能ID" width="80"></el-table-column>
|
|
<el-table-column prop="feature_description" label="功能描述"></el-table-column>
|
|
<el-table-column label="状态" width="100">
|
|
<template slot-scope="scope">
|
|
<el-tag
|
|
:type="scope.row.status === 'enabled' ? 'success' : 'danger'">
|
|
{% raw %}{{ scope.row.status === 'enabled' ? '已启用' : '已关闭' }}{% endraw %}
|
|
</el-tag>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="操作" width="120">
|
|
<template slot-scope="scope">
|
|
<el-switch
|
|
v-model="scope.row.statusBool"
|
|
active-color="#13ce66"
|
|
inactive-color="#ff4949"
|
|
@change="togglePermission(scope.row)">
|
|
</el-switch>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
<div slot="footer" class="dialog-footer">
|
|
<el-button @click="enableAllPermissions" type="success">一键启用全部</el-button>
|
|
<el-button @click="disableAllPermissions" type="danger">一键关闭全部</el-button>
|
|
<el-button @click="permissionDialogVisible = false">关闭</el-button>
|
|
</div>
|
|
</el-dialog>
|
|
|
|
<!-- 添加群组对话框 -->
|
|
<el-dialog
|
|
title="添加群组"
|
|
:visible.sync="addGroupDialogVisible"
|
|
width="30%">
|
|
<el-form :model="addGroupForm" :rules="addGroupRules" ref="addGroupForm">
|
|
<el-form-item label="群组ID" prop="groupId">
|
|
<el-input v-model="addGroupForm.groupId" placeholder="请输入群组ID"></el-input>
|
|
</el-form-item>
|
|
</el-form>
|
|
<span slot="footer" class="dialog-footer">
|
|
<el-button @click="addGroupDialogVisible = false">取消</el-button>
|
|
<el-button type="primary" @click="submitAddGroup">确定</el-button>
|
|
</span>
|
|
</el-dialog>
|
|
|
|
<!-- 群组消息趋势对话框 -->
|
|
<el-dialog
|
|
title="群组消息趋势"
|
|
:visible.sync="messageTrendDialogVisible"
|
|
width="70%">
|
|
<div class="chart-container">
|
|
<h3>{% raw %}{{ currentGroupName }}{% endraw %} 消息趋势</h3>
|
|
<canvas id="messageTrendChart" width="800" height="400"></canvas>
|
|
</div>
|
|
</el-dialog>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script>
|
|
new Vue({
|
|
el: '#app',
|
|
mixins: [baseApp],
|
|
data() {
|
|
return {
|
|
groups: [],
|
|
permissions: [],
|
|
currentGroupId: null,
|
|
currentGroupName: '',
|
|
searchQuery: '',
|
|
selectedGroups: [],
|
|
permissionDialogVisible: false,
|
|
// 添加群组相关数据
|
|
addGroupDialogVisible: false,
|
|
addGroupForm: {
|
|
groupId: ''
|
|
},
|
|
addGroupRules: {
|
|
groupId: [
|
|
{ required: true, message: '请输入群组ID', trigger: 'blur' },
|
|
{ pattern: /^\S+$/, message: '群组ID不能包含空格', trigger: 'blur' }
|
|
]
|
|
},
|
|
// 添加消息趋势相关数据
|
|
messageTrendDialogVisible: false,
|
|
messageTrendData: {
|
|
dates: [],
|
|
counts: []
|
|
}
|
|
}
|
|
},
|
|
computed: {
|
|
filteredGroups() {
|
|
if (!this.searchQuery) return this.groups;
|
|
const query = this.searchQuery.toLowerCase();
|
|
return this.groups.filter(group =>
|
|
(group.group_id && group.group_id.toLowerCase().includes(query)) ||
|
|
(group.group_name && group.group_name.toLowerCase().includes(query))
|
|
);
|
|
}
|
|
},
|
|
mounted() {
|
|
this.currentView = '6'; // 设置当前菜单项
|
|
this.loadGroups();
|
|
},
|
|
methods: {
|
|
loadGroups() {
|
|
axios.get('/api/robot/groups')
|
|
.then(response => {
|
|
if (response.data.success) {
|
|
this.groups = response.data.data || [];
|
|
} else {
|
|
this.$message.error('加载群组失败');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('加载群组失败:', error);
|
|
this.$message.error('加载群组失败: ' + error.message);
|
|
});
|
|
},
|
|
handleSelectionChange(selection) {
|
|
this.selectedGroups = selection.map(item => item.group_id);
|
|
},
|
|
viewGroupPermissions(group) {
|
|
this.currentGroupId = group.group_id;
|
|
this.currentGroupName = group.group_name || group.group_id;
|
|
|
|
axios.get(`/api/robot/group/${group.group_id}/permissions`)
|
|
.then(response => {
|
|
if (response.data.success) {
|
|
// 添加布尔值属性用于switch组件
|
|
const permissionsData = response.data.data || [];
|
|
this.permissions = permissionsData.map(p => ({
|
|
...p,
|
|
statusBool: p.status === 'enabled'
|
|
}));
|
|
this.permissionDialogVisible = true;
|
|
} else {
|
|
this.$message.error('加载权限失败');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('加载权限失败:', error);
|
|
this.$message.error('加载权限失败: ' + error.message);
|
|
});
|
|
},
|
|
togglePermission(permission) {
|
|
const newStatus = permission.statusBool ? 'enabled' : 'disabled';
|
|
|
|
axios.post(`/api/robot/group/${this.currentGroupId}/permissions`, {
|
|
feature_id: permission.feature_id,
|
|
status: newStatus
|
|
})
|
|
.then(response => {
|
|
if (response.data.success) {
|
|
permission.status = newStatus;
|
|
this.$message.success('更新权限成功');
|
|
} else {
|
|
// 恢复原状态
|
|
permission.statusBool = !permission.statusBool;
|
|
this.$message.error('更新权限失败');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
// 恢复原状态
|
|
permission.statusBool = !permission.statusBool;
|
|
console.error('更新权限失败:', error);
|
|
this.$message.error('更新权限失败: ' + error.message);
|
|
});
|
|
},
|
|
enableAllPermissions() {
|
|
this.updateAllPermissions('enabled');
|
|
},
|
|
disableAllPermissions() {
|
|
this.updateAllPermissions('disabled');
|
|
},
|
|
updateAllPermissions(status) {
|
|
axios.post(`/api/robot/group/${this.currentGroupId}/permissions`, {
|
|
status: status
|
|
})
|
|
.then(response => {
|
|
if (response.data.success) {
|
|
// 更新本地数据
|
|
this.permissions.forEach(p => {
|
|
p.status = status;
|
|
p.statusBool = status === 'enabled';
|
|
});
|
|
this.$message.success('批量更新权限成功');
|
|
} else {
|
|
this.$message.error('批量更新权限失败');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('批量更新权限失败:', error);
|
|
this.$message.error('批量更新权限失败: ' + error.message);
|
|
});
|
|
},
|
|
toggleRobotStatus(group) {
|
|
const newStatus = group.robot_status === 'enabled' ? 'disabled' : 'enabled';
|
|
|
|
axios.post(`/api/robot/group/${group.group_id}/status`, {
|
|
status: newStatus
|
|
})
|
|
.then(response => {
|
|
if (response.data.success) {
|
|
group.robot_status = newStatus;
|
|
this.$message.success('更新机器人状态成功');
|
|
} else {
|
|
this.$message.error('更新机器人状态失败');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('更新机器人状态失败:', error);
|
|
this.$message.error('更新机器人状态失败: ' + error.message);
|
|
});
|
|
},
|
|
showAddGroupDialog() {
|
|
this.addGroupForm.groupId = '';
|
|
this.addGroupDialogVisible = true;
|
|
},
|
|
submitAddGroup() {
|
|
this.$refs.addGroupForm.validate(valid => {
|
|
if (valid) {
|
|
axios.post('/api/robot/group', {
|
|
group_id: this.addGroupForm.groupId
|
|
})
|
|
.then(response => {
|
|
if (response.data.success) {
|
|
this.addGroupDialogVisible = false;
|
|
this.$message.success('添加群组成功');
|
|
// 重新加载群组列表
|
|
this.loadGroups();
|
|
} else {
|
|
this.$message.error('添加群组失败');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('添加群组失败:', error);
|
|
this.$message.error('添加群组失败: ' + error.message);
|
|
});
|
|
}
|
|
});
|
|
},
|
|
batchEnableRobot() {
|
|
this.batchUpdateRobotStatus('enabled');
|
|
},
|
|
batchDisableRobot() {
|
|
this.batchUpdateRobotStatus('disabled');
|
|
},
|
|
batchUpdateRobotStatus(status) {
|
|
if (this.selectedGroups.length === 0) {
|
|
this.$message.warning('请先选择群组');
|
|
return;
|
|
}
|
|
|
|
axios.post('/api/robot/batch_operation', {
|
|
operation: 'update_status',
|
|
group_ids: this.selectedGroups,
|
|
status: status
|
|
})
|
|
.then(response => {
|
|
if (response.data.success) {
|
|
// 更新本地数据
|
|
this.groups.forEach(g => {
|
|
if (this.selectedGroups.includes(g.group_id)) {
|
|
g.robot_status = status;
|
|
}
|
|
});
|
|
this.$message.success('批量更新状态成功');
|
|
} else {
|
|
this.$message.error('批量更新状态失败');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('批量更新状态失败:', error);
|
|
this.$message.error('批量更新状态失败: ' + error.message);
|
|
});
|
|
},
|
|
batchRemoveGroups() {
|
|
if (this.selectedGroups.length === 0) {
|
|
this.$message.warning('请先选择群组');
|
|
return;
|
|
}
|
|
|
|
this.$confirm(`确定要批量移除 ${this.selectedGroups.length} 个群组吗? 此操作将清除这些群组的所有设置。`, '警告', {
|
|
confirmButtonText: '确定',
|
|
cancelButtonText: '取消',
|
|
type: 'danger'
|
|
}).then(() => {
|
|
axios.post('/api/robot/batch_operation', {
|
|
operation: 'remove_groups',
|
|
group_ids: this.selectedGroups
|
|
})
|
|
.then(response => {
|
|
if (response.data.success) {
|
|
// 从列表中移除这些群组
|
|
this.groups = this.groups.filter(g => !this.selectedGroups.includes(g.group_id));
|
|
this.selectedGroups = [];
|
|
this.$message.success('批量移除成功');
|
|
} else {
|
|
this.$message.error('批量移除失败');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('批量移除失败:', error);
|
|
this.$message.error('批量移除失败: ' + error.message);
|
|
});
|
|
}).catch(() => {});
|
|
},
|
|
// 添加查看消息趋势的方法
|
|
viewMessageTrend(group) {
|
|
this.currentGroupId = group.group_id;
|
|
this.currentGroupName = group.group_name || group.group_id;
|
|
|
|
// 获取消息趋势数据
|
|
const days = parseInt(this.timeRange || 7);
|
|
axios.get(`/api/robot/group/${group.group_id}/message_trend?days=${days}`)
|
|
.then(response => {
|
|
if (response.data.success) {
|
|
this.messageTrendData = response.data.data || { dates: [], counts: [] };
|
|
this.messageTrendDialogVisible = true;
|
|
|
|
// 在下一个DOM更新周期渲染图表
|
|
this.$nextTick(() => {
|
|
this.renderMessageTrendChart();
|
|
});
|
|
} else {
|
|
this.$message.error('加载消息趋势失败');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('加载消息趋势失败:', error);
|
|
this.$message.error('加载消息趋势失败: ' + error.message);
|
|
});
|
|
},
|
|
// 渲染消息趋势图表
|
|
renderMessageTrendChart() {
|
|
const ctx = document.getElementById('messageTrendChart').getContext('2d');
|
|
|
|
// 销毁旧图表
|
|
if (this.charts && this.charts.messageTrendChart) {
|
|
this.charts.messageTrendChart.destroy();
|
|
}
|
|
|
|
// 确保charts对象存在
|
|
if (!this.charts) {
|
|
this.charts = {};
|
|
}
|
|
|
|
// 创建新图表
|
|
this.charts.messageTrendChart = new Chart(ctx, {
|
|
type: 'line',
|
|
data: {
|
|
labels: this.messageTrendData.dates,
|
|
datasets: [
|
|
{
|
|
label: '消息数量',
|
|
data: this.messageTrendData.counts,
|
|
fill: false,
|
|
backgroundColor: 'rgba(75, 192, 192, 0.6)',
|
|
borderColor: 'rgba(75, 192, 192, 1)',
|
|
tension: 0.1
|
|
}
|
|
]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
scales: {
|
|
y: {
|
|
beginAtZero: true
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
});
|
|
</script>
|
|
{% endblock %} |