删除风险管理

This commit is contained in:
dzl
2025-09-11 11:33:04 +08:00
parent cac388087e
commit 0e7168eb74
3 changed files with 0 additions and 465 deletions

View File

@@ -69,11 +69,6 @@
<template #title>匹配管理</template>
</el-menu-item> -->
<el-menu-item v-if="userStore.isAdmin" index="/risk-management">
<el-icon><Warning /></el-icon>
<template #title>风险管理</template>
</el-menu-item>
<el-menu-item v-if="userStore.isAdmin" index="/agents">
<el-icon><Avatar /></el-icon>
<template #title>代理管理</template>

View File

@@ -152,16 +152,6 @@ const routes = [
// requiresAdmin: true
// }
// },
{
path: 'risk-management',
name: 'RiskManagement',
component: () => import('@/views/RiskManagement.vue'),
meta: {
title: '风险管理 - 炬融圈',
icon: 'Warning',
requiresAdmin: true
}
},
{
path: 'agents',
name: 'Agents',

View File

@@ -1,450 +0,0 @@
<template>
<div class="risk-management">
<div class="page-header">
<h1>风险管理</h1>
<div class="header-actions">
<el-button @click="checkTimeouts" :loading="checking" type="primary">
<el-icon><Refresh /></el-icon>
手动检查超时
</el-button>
<el-button @click="loadData" :loading="loading">
<el-icon><Refresh /></el-icon>
刷新数据
</el-button>
</div>
</div>
<!-- 统计卡片 -->
<div class="stats-cards">
<el-card class="stat-card">
<div class="stat-content">
<div class="stat-number">{{ stats?.totalRiskUsers || 0 }}</div>
<div class="stat-label">风险用户</div>
</div>
</el-card>
<el-card class="stat-card">
<div class="stat-content">
<div class="stat-number">{{ stats?.totalBlacklistedUsers || 0 }}</div>
<div class="stat-label">拉黑用户</div>
</div>
</el-card>
<el-card class="stat-card">
<div class="stat-content">
<div class="stat-number">{{ stats?.totalOverdueTransfers || 0 }}</div>
<div class="stat-label">超时转账</div>
</div>
</el-card>
<el-card class="stat-card">
<div class="stat-content">
<div class="stat-number">{{ stats?.todayOverdueTransfers || 0 }}</div>
<div class="stat-label">今日超时</div>
</div>
</el-card>
</div>
<!-- 标签页 -->
<el-tabs v-model="activeTab" class="risk-tabs">
<!-- 风险用户 -->
<el-tab-pane label="风险用户" name="riskUsers">
<div class="table-container">
<el-table :data="riskUsers" v-loading="loading" stripe>
<el-table-column prop="id" label="用户ID" width="80" />
<el-table-column prop="username" label="用户名" width="120" />
<el-table-column prop="real_name" label="真实姓名" width="120" />
<el-table-column prop="phone" label="手机号" width="130" />
<el-table-column prop="risk_reason" label="风险原因" min-width="200" />
<el-table-column prop="created_at" label="标记时间" width="180">
<template #default="{ row }">
{{ formatDate(row.created_at) }}
</template>
</el-table-column>
<el-table-column label="状态" width="100">
<template #default="{ row }">
<el-tag v-if="row.is_blacklisted" type="danger">已拉黑</el-tag>
<el-tag v-else type="warning">风险用户</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="200">
<template #default="{ row }">
<el-button
v-if="!row.is_blacklisted"
@click="blacklistUser(row)"
type="danger"
size="small"
>
拉黑
</el-button>
<el-button
v-else
@click="unblacklistUser(row)"
type="success"
size="small"
>
解除拉黑
</el-button>
<el-button @click="viewUserDetail(row)" size="small">
查看详情
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-tab-pane>
<!-- 超时转账 -->
<el-tab-pane label="超时转账" name="overdueTransfers">
<div class="table-container">
<el-table :data="overdueTransfers" v-loading="loading" stripe>
<el-table-column prop="id" label="转账ID" width="80" />
<el-table-column prop="from_username" label="发送方" width="120" />
<el-table-column prop="to_username" label="接收方" width="120" />
<el-table-column prop="amount" label="金额" width="100">
<template #default="{ row }">
¥{{ row.amount }}
</template>
</el-table-column>
<el-table-column prop="deadline_at" label="截止时间" width="180">
<template #default="{ row }">
{{ formatDate(row.deadline_at) }}
</template>
</el-table-column>
<el-table-column prop="overdue_at" label="超时时间" width="180">
<template #default="{ row }">
{{ formatDate(row.overdue_at) }}
</template>
</el-table-column>
<el-table-column label="状态" width="100">
<template #default="{ row }">
<el-tag type="danger">已超时</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="120">
<template #default="{ row }">
<el-button @click="viewTransferDetail(row)" size="small">
查看详情
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-tab-pane>
</el-tabs>
<!-- 用户详情对话框 -->
<el-dialog v-model="userDetailVisible" title="用户详情" width="600px">
<div v-if="selectedUser" class="user-detail">
<el-descriptions :column="2" border>
<el-descriptions-item label="用户ID">{{ selectedUser.id }}</el-descriptions-item>
<el-descriptions-item label="用户名">{{ selectedUser.username }}</el-descriptions-item>
<el-descriptions-item label="真实姓名">{{ selectedUser.real_name || '未设置' }}</el-descriptions-item>
<el-descriptions-item label="手机号">{{ selectedUser.phone || '未设置' }}</el-descriptions-item>
<el-descriptions-item label="余额">¥{{ selectedUser.balance }}</el-descriptions-item>
<el-descriptions-item label="风险原因" :span="2">{{ selectedUser.risk_reason }}</el-descriptions-item>
<el-descriptions-item label="拉黑原因" :span="2" v-if="selectedUser.blacklist_reason">
{{ selectedUser.blacklist_reason }}
</el-descriptions-item>
<el-descriptions-item label="注册时间">{{ formatDate(selectedUser.created_at) }}</el-descriptions-item>
<el-descriptions-item label="拉黑时间" v-if="selectedUser.blacklisted_at">
{{ formatDate(selectedUser.blacklisted_at) }}
</el-descriptions-item>
</el-descriptions>
</div>
</el-dialog>
<!-- 转账详情对话框 -->
<el-dialog v-model="transferDetailVisible" title="转账详情" width="600px">
<div v-if="selectedTransfer" class="transfer-detail">
<el-descriptions :column="2" border>
<el-descriptions-item label="转账ID">{{ selectedTransfer.id }}</el-descriptions-item>
<el-descriptions-item label="金额">¥{{ selectedTransfer.amount }}</el-descriptions-item>
<el-descriptions-item label="发送方">{{ selectedTransfer.from_username }}</el-descriptions-item>
<el-descriptions-item label="接收方">{{ selectedTransfer.to_username }}</el-descriptions-item>
<el-descriptions-item label="创建时间">{{ formatDate(selectedTransfer.created_at) }}</el-descriptions-item>
<el-descriptions-item label="截止时间">{{ formatDate(selectedTransfer.deadline_at) }}</el-descriptions-item>
<el-descriptions-item label="超时时间">{{ formatDate(selectedTransfer.overdue_at) }}</el-descriptions-item>
<el-descriptions-item label="状态">
<el-tag type="danger">已超时</el-tag>
</el-descriptions-item>
<el-descriptions-item label="描述" :span="2">
{{ selectedTransfer.description || '无' }}
</el-descriptions-item>
</el-descriptions>
</div>
</el-dialog>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Refresh } from '@element-plus/icons-vue'
import api from '../utils/api'
const loading = ref(false)
const checking = ref(false)
const activeTab = ref('riskUsers')
const riskUsers = ref([])
const overdueTransfers = ref([])
const stats = ref({
totalRiskUsers: 0,
totalBlacklistedUsers: 0,
totalOverdueTransfers: 0,
todayOverdueTransfers: 0
})
const userDetailVisible = ref(false)
const transferDetailVisible = ref(false)
const selectedUser = ref(null)
const selectedTransfer = ref(null)
// 加载数据
const loadData = async () => {
loading.value = true
try {
await Promise.all([
loadRiskUsers(),
loadOverdueTransfers(),
loadStats()
])
} catch (error) {
console.error('加载数据失败:', error)
ElMessage.error('加载数据失败')
} finally {
loading.value = false
}
}
/**
* 加载风险用户
*/
const loadRiskUsers = async () => {
try {
const response = await api.get('/risk/users')
if (response.data && Array.isArray(response.data.data.users)) {
riskUsers.value = response.data.data.users
} else {
riskUsers.value = []
}
} catch (error) {
console.error('加载风险用户失败:', error)
// 确保即使出错也有默认空数组
riskUsers.value = []
}
}
/**
* 加载超时转账
*/
const loadOverdueTransfers = async () => {
try {
const response = await api.get('/risk/overdue-transfers')
if (response.data && Array.isArray(response.data.data.transfers)) {
overdueTransfers.value = response.data.data.transfers
} else {
overdueTransfers.value = []
}
} catch (error) {
console.error('加载超时转账失败:', error)
// 确保即使出错也有默认空数组
overdueTransfers.value = []
}
}
/**
* 加载统计数据
*/
const loadStats = async () => {
try {
const response = await api.get('/risk/stats')
if (response.data && response.data.data) {
stats.value = {
totalRiskUsers: response.data.data.riskUsersCount || 0,
totalBlacklistedUsers: response.data.data.blacklistedUsersCount || 0,
totalOverdueTransfers: response.data.data.overdueTransfersCount || 0,
todayOverdueTransfers: response.data.data.todayOverdueCount || 0
}
} else {
// 如果响应数据格式不正确,使用默认值
stats.value = {
totalRiskUsers: 0,
totalBlacklistedUsers: 0,
totalOverdueTransfers: 0,
todayOverdueTransfers: 0
}
}
} catch (error) {
console.error('加载统计数据失败:', error)
// 确保即使出错也有默认值
stats.value = {
totalRiskUsers: 0,
totalBlacklistedUsers: 0,
totalOverdueTransfers: 0,
todayOverdueTransfers: 0
}
}
}
// 手动检查超时
const checkTimeouts = async () => {
checking.value = true
try {
await api.post('/risk/check-timeouts')
ElMessage.success('检查完成')
await loadData()
} catch (error) {
console.error('检查超时失败:', error)
ElMessage.error('检查超时失败')
} finally {
checking.value = false
}
}
// 拉黑用户
const blacklistUser = async (user) => {
try {
const { value: reason } = await ElMessageBox.prompt(
'请输入拉黑原因',
'拉黑用户',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
inputPattern: /.+/,
inputErrorMessage: '拉黑原因不能为空'
}
)
await api.post(`/risk/blacklist/${user.id}`, { reason })
ElMessage.success('用户已拉黑')
await loadData()
} catch (error) {
if (error !== 'cancel') {
console.error('拉黑用户失败:', error)
ElMessage.error('拉黑用户失败')
}
}
}
// 解除拉黑
const unblacklistUser = async (user) => {
try {
await ElMessageBox.confirm(
`确定要解除用户 ${user.username} 的拉黑状态吗?`,
'解除拉黑',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
)
await api.post(`/risk/unblacklist/${user.id}`)
ElMessage.success('已解除拉黑')
await loadData()
} catch (error) {
if (error !== 'cancel') {
console.error('解除拉黑失败:', error)
ElMessage.error('解除拉黑失败')
}
}
}
// 查看用户详情
const viewUserDetail = (user) => {
selectedUser.value = user
userDetailVisible.value = true
}
// 查看转账详情
const viewTransferDetail = (transfer) => {
selectedTransfer.value = transfer
transferDetailVisible.value = true
}
// 格式化日期
const formatDate = (dateString) => {
if (!dateString) return '-'
return new Date(dateString).toLocaleString('zh-CN')
}
onMounted(() => {
loadData()
})
</script>
<style scoped>
.risk-management {
padding: 20px;
}
.page-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.page-header h1 {
margin: 0;
color: #303133;
}
.header-actions {
display: flex;
gap: 10px;
}
.stats-cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
margin-bottom: 20px;
}
.stat-card {
text-align: center;
}
.stat-content {
padding: 10px;
}
.stat-number {
font-size: 32px;
font-weight: bold;
color: #409EFF;
margin-bottom: 5px;
}
.stat-label {
font-size: 14px;
color: #909399;
}
.risk-tabs {
background: white;
border-radius: 4px;
padding: 20px;
}
.table-container {
margin-top: 20px;
}
.user-detail,
.transfer-detail {
padding: 20px 0;
}
:deep(.el-descriptions__label) {
font-weight: bold;
}
:deep(.el-table) {
font-size: 14px;
}
:deep(.el-table th) {
background-color: #f5f7fa;
}
</style>