完善保险项目和养殖端小程序

This commit is contained in:
xuqiuyun
2025-09-26 18:45:42 +08:00
parent 00dfa83fd1
commit ec3f472641
58 changed files with 4866 additions and 2233 deletions

View File

@@ -298,24 +298,34 @@ const isModuleIndeterminate = (module) => {
}
// 获取所有角色和权限数据
const fetchData = async () => {
loading.value = true
const loadData = async () => {
try {
loading.value = true
const [rolesResponse, permissionsResponse] = await Promise.all([
rolePermissionAPI.getAllRolesWithPermissions(),
rolePermissionAPI.getAllPermissions()
])
if (rolesResponse.success) {
roles.value = rolesResponse.data
// 处理角色数据
if (rolesResponse.data && rolesResponse.data.status === 'success') {
roles.value = rolesResponse.data.data.roles || []
console.log('加载角色数据成功:', roles.value.length, '个角色')
} else {
console.error('角色数据响应格式错误:', rolesResponse)
message.error('加载角色数据失败: 响应格式错误')
}
if (permissionsResponse.success) {
permissions.value = permissionsResponse.data
// 处理权限数据
if (permissionsResponse.data && permissionsResponse.data.status === 'success') {
permissions.value = permissionsResponse.data.data || []
console.log('加载权限数据成功:', permissions.value.length, '个权限')
} else {
console.error('权限数据响应格式错误:', permissionsResponse)
message.error('加载权限数据失败: 响应格式错误')
}
} catch (error) {
console.error('获取数据失败:', error)
message.error('获取数据失败')
console.error('加载数据失败:', error)
message.error('加载数据失败: ' + error.message)
} finally {
loading.value = false
}
@@ -325,26 +335,47 @@ const fetchData = async () => {
const handleRoleChange = async (roleId) => {
if (!roleId) return
console.log('=== 角色变化处理开始 ===');
console.log('选择的角色ID:', roleId);
try {
const response = await rolePermissionAPI.getRolePermissions(roleId)
if (response.success) {
// 重置选择状态
console.log('获取角色权限API响应:', JSON.stringify(response, null, 2));
if (response.data && response.data.status === 'success') {
// 清空之前的选择
console.log('清空前的权限状态:', JSON.stringify(selectedPermissions, null, 2));
Object.keys(selectedPermissions).forEach(key => {
selectedPermissions[key] = false
})
console.log('清空后的权限状态:', JSON.stringify(selectedPermissions, null, 2));
// 设置当前角色的权限
response.data.permissions.forEach(permission => {
selectedPermissions[permission.id] = true
})
if (response.data.data && response.data.data.allPermissions) {
const assignedPermissions = response.data.data.allPermissions.filter(p => p.assigned);
console.log('角色已分配的权限:', assignedPermissions.length, '个');
console.log('已分配权限详情:', assignedPermissions.map(p => ({ id: p.id, name: p.name, code: p.code })));
assignedPermissions.forEach(permission => {
selectedPermissions[permission.id] = true
})
console.log('设置权限后的状态:', JSON.stringify(selectedPermissions, null, 2));
}
// 默认展开所有模块
// 展开所有模块
activeModules.value = permissionModules.value.map(m => m.module)
console.log('展开的模块:', activeModules.value);
} else {
console.error('获取角色权限详情失败:', response)
message.error('获取角色权限详情失败')
}
} catch (error) {
console.error('获取角色权限失败:', error)
message.error('获取角色权限失败')
}
console.log('=== 角色变化处理结束 ===');
}
// 权限变化处理
@@ -364,9 +395,17 @@ const handleModuleCheckChange = (e, module) => {
// 全选处理
const handleSelectAll = () => {
console.log('=== 全选操作开始 ===');
console.log('全选前的权限状态:', JSON.stringify(selectedPermissions, null, 2));
console.log('当前权限列表长度:', permissions.value.length);
permissions.value.forEach(permission => {
selectedPermissions[permission.id] = true
})
console.log('全选后的权限状态:', JSON.stringify(selectedPermissions, null, 2));
console.log('全选操作完成,选中权限数量:', Object.values(selectedPermissions).filter(Boolean).length);
console.log('=== 全选操作结束 ===');
}
// 全不选处理
@@ -405,27 +444,43 @@ const handleSavePermissions = async () => {
return
}
console.log('=== 保存权限设置开始 ===');
console.log('当前选择的角色ID:', selectedRoleId.value);
console.log('保存前的权限状态:', JSON.stringify(selectedPermissions, null, 2));
saveLoading.value = true
try {
const permissionIds = Object.keys(selectedPermissions)
.filter(id => selectedPermissions[id])
.map(id => parseInt(id))
const response = await rolePermissionAPI.assignRolePermissions(selectedRoleId.value, {
console.log('准备保存的权限ID列表:', permissionIds);
console.log('权限ID数量:', permissionIds.length);
const requestData = {
permissionIds,
mode: 'replace'
})
};
console.log('发送的请求数据:', JSON.stringify(requestData, null, 2));
if (response.success) {
const response = await rolePermissionAPI.assignRolePermissions(selectedRoleId.value, requestData)
console.log('保存权限API响应:', JSON.stringify(response, null, 2));
if (response.data && response.data.status === 'success') {
message.success('权限设置保存成功')
console.log('✅ 权限保存成功');
} else {
message.error(response.message || '保存失败')
console.error('❌ 保存权限设置失败:', response)
message.error('保存权限设置失败')
}
} catch (error) {
console.error('保存权限设置失败:', error)
console.error('保存权限设置异常:', error)
console.error('错误详情:', error.response?.data || error.message)
message.error('保存权限设置失败')
} finally {
saveLoading.value = false
console.log('=== 保存权限设置结束 ===');
}
}
@@ -450,13 +505,13 @@ const handleConfirmCopy = async () => {
}
try {
const response = await rolePermissionAPI.copyRolePermissions(
copyForm.sourceRoleId,
copyForm.targetRoleId,
copyForm.mode
)
const response = await rolePermissionAPI.copyRolePermissions({
sourceRoleId: copyForm.sourceRoleId,
targetRoleId: copyForm.targetRoleId,
mode: copyForm.mode
})
if (response.success) {
if (response.data && response.data.status === 'success') {
message.success('权限复制成功')
copyModalVisible.value = false
@@ -465,7 +520,8 @@ const handleConfirmCopy = async () => {
handleRoleChange(selectedRoleId.value)
}
} else {
message.error(response.message || '复制失败')
console.error('复制权限失败:', response)
message.error('复制权限失败')
}
} catch (error) {
console.error('复制权限失败:', error)
@@ -475,7 +531,7 @@ const handleConfirmCopy = async () => {
// 刷新数据
const handleRefresh = () => {
fetchData()
loadData()
if (selectedRoleId.value) {
handleRoleChange(selectedRoleId.value)
}
@@ -492,7 +548,7 @@ watch(permissions, (newPermissions) => {
// 组件挂载时获取数据
onMounted(() => {
fetchData()
loadData()
})
</script>

View File

@@ -20,6 +20,7 @@ import RangePickerTest from '@/views/RangePickerTest.vue'
import LoginTest from '@/views/LoginTest.vue'
import LivestockPolicyManagement from '@/views/LivestockPolicyManagement.vue'
import SystemSettings from '@/views/SystemSettings.vue'
import TokenDebug from '@/views/TokenDebug.vue'
const routes = [
{
@@ -162,6 +163,12 @@ const routes = [
name: 'LoginTest',
component: LoginTest,
meta: { title: '登录和API测试' }
},
{
path: 'token-debug',
name: 'TokenDebug',
component: TokenDebug,
meta: { title: 'Token调试' }
}
]
}
@@ -177,7 +184,7 @@ router.beforeEach(async (to, from, next) => {
const userStore = useUserStore()
// 如果访问登录页面且已登录,重定向到仪表板
if (to.path === '/login' && (userStore.token || userStore.accessToken)) {
if (to.path === '/login' && userStore.accessToken) {
next('/dashboard')
return
}
@@ -189,7 +196,7 @@ router.beforeEach(async (to, from, next) => {
await userStore.ensureValidToken()
// 检查是否有有效的Token
if (!userStore.accessToken && !userStore.token) {
if (!userStore.accessToken) {
// 尝试自动重新登录
const autoLoginSuccess = await userStore.autoRelogin()

View File

@@ -75,6 +75,14 @@ export const useUserStore = defineStore('user', () => {
})
}
// 兼容性方法 - 支持旧的setToken调用
const setToken = (token) => {
if (token) {
accessToken.value = token
debouncedUpdateStorage('accessToken', token)
}
}
const logout = () => {
// 清除状态
accessToken.value = ''
@@ -199,6 +207,7 @@ export const useUserStore = defineStore('user', () => {
// 方法
setAuthData,
setToken, // 兼容性方法
logout,
refreshAccessToken,
ensureValidToken,

View File

@@ -138,7 +138,7 @@ export const livestockPolicyApi = {
getById: (id) => api.get(`/livestock-policies/${id}`),
updateStatus: (id, data) => api.patch(`/livestock-policies/${id}/status`, data),
getStats: () => api.get('/livestock-policies/stats'),
getLivestockTypes: () => api.get('/livestock-types?status=active')
getLivestockTypes: () => api.get('/livestock-types/active')
}
export const livestockClaimApi = {
@@ -171,7 +171,7 @@ export const permissionAPI = {
getRolePermissions: (roleId) => api.get(`/permissions/roles/${roleId}`)
}
// 角色权限管理API
// 角色权限管理API - 使用统一的请求方法
export const rolePermissionAPI = {
// 获取所有角色及其权限
getAllRolesWithPermissions: () => api.get('/role-permissions/roles'),
@@ -180,18 +180,16 @@ export const rolePermissionAPI = {
getAllPermissions: () => api.get('/role-permissions/permissions'),
// 获取指定角色的详细权限信息
getRolePermissions: (roleId) => api.get(`/role-permissions/roles/${roleId}`),
getRolePermissions: (roleId) => api.get(`/role-permissions/${roleId}`),
// 批量分配角色权限
assignRolePermissions: (roleId, data) => api.post(`/role-permissions/roles/${roleId}/assign`, data),
assignRolePermissions: (roleId, requestData) => api.post(`/role-permissions/${roleId}/assign`, requestData),
// 复制角色权限
copyRolePermissions: (sourceRoleId, targetRoleId, mode) =>
api.post(`/role-permissions/roles/${sourceRoleId}/copy/${targetRoleId}`, { mode }),
copyRolePermissions: (copyData) => api.post('/role-permissions/copy', copyData),
// 检查用户权限
checkUserPermission: (userId, permissionCode) =>
api.get(`/role-permissions/users/${userId}/check/${permissionCode}`),
checkUserPermission: (userId, permissionCode) => api.get(`/role-permissions/check/${userId}/${permissionCode}`),
// 获取权限统计
getPermissionStats: () => api.get('/role-permissions/stats')

View File

@@ -469,18 +469,21 @@ const loadApplications = async () => {
...searchForm
}
const response = await applicationAPI.getList(params)
console.log('申请列表API响应:', response)
// 使用数据验证工具处理响应
const validatedResponse = validateListResponse(response, '保险申请列表')
applications.value = validatedResponse.data
// 设置分页信息
const validatedPagination = validatePagination(validatedResponse.pagination)
pagination.total = validatedPagination.total
if (response.data && response.data.status === 'success') {
// API返回的数据直接是数组格式不是{list: [], total: 146}格式
applications.value = response.data.data || []
pagination.total = response.data.pagination?.total || 0
console.log('申请列表数据设置成功:', applications.value.length, '条')
} else {
console.log('申请列表响应格式错误:', response)
message.error('加载申请数据失败')
applications.value = []
}
} catch (error) {
console.error('加载申请数据失败:', error)
message.error('加载申请数据失败')
// 确保在错误情况下 applications 也是数组
applications.value = []
} finally {
loading.value = false
@@ -490,14 +493,19 @@ const loadApplications = async () => {
const loadInsuranceTypes = async () => {
try {
const response = await insuranceTypeAPI.getList()
console.log('保险类型API响应:', response)
// 使用数据验证工具处理响应
const validatedResponse = validateListResponse(response, '险种列表')
insuranceTypes.value = validatedResponse.data
if (response.data && response.data.status === 'success') {
insuranceTypes.value = response.data.data || []
console.log('保险类型数据设置成功:', insuranceTypes.value.length, '个')
} else {
console.log('保险类型响应格式错误:', response)
message.error('加载险种数据失败')
insuranceTypes.value = []
}
} catch (error) {
console.error('加载险种数据失败:', error)
message.error('加载险种数据失败')
// 确保在错误情况下 insuranceTypes 也是数组
insuranceTypes.value = []
}
}

View File

@@ -366,6 +366,7 @@ import {
RedoOutlined,
FileTextOutlined
} from '@ant-design/icons-vue'
import { claimAPI } from '@/utils/api'
const loading = ref(false)
const modalVisible = ref(false)
@@ -530,60 +531,20 @@ const loadClaims = async () => {
...searchForm
}
// 这里应该是实际的API调用
// const response = await claimAPI.getList(params)
// claimList.value = response.data.list
// pagination.total = response.data.total
console.log('理赔管理API请求参数:', params)
const response = await claimAPI.getList(params)
console.log('理赔管理API响应:', response)
// 模拟数据
claimList.value = [
{
id: 1,
claim_number: 'CLM20240001',
policy_number: 'POL20240001',
applicant_name: '张三',
phone: '13800138000',
claim_amount: 50000,
approved_amount: 45000,
apply_date: '2024-01-15',
accident_date: '2024-01-10',
status: 'approved',
accident_description: '交通事故,车辆前部受损',
process_description: '已核实事故情况,符合理赔条件',
reject_reason: '',
reviewer_name: '李审核员',
review_date: '2024-01-16',
documents: [
{ name: '事故照片.jpg', size: '2.5MB', url: '#' },
{ name: '维修报价单.pdf', size: '1.2MB', url: '#' }
],
created_at: '2024-01-15 10:00:00',
updated_at: '2024-01-16 14:30:00'
},
{
id: 2,
claim_number: 'CLM20240002',
policy_number: 'POL20240002',
applicant_name: '李四',
phone: '13800138001',
claim_amount: 100000,
approved_amount: null,
apply_date: '2024-01-20',
accident_date: '2024-01-18',
status: 'pending',
accident_description: '家庭财产损失,水管爆裂',
process_description: '',
reject_reason: '',
reviewer_name: null,
review_date: null,
documents: [
{ name: '损失评估报告.pdf', size: '3.1MB', url: '#' }
],
created_at: '2024-01-20 14:30:00',
updated_at: '2024-01-20 14:30:00'
}
]
pagination.total = 2
if (response.data && response.data.status === 'success') {
// 后端返回的数据直接是数组格式,不是{list: [], total: 8}格式
claimList.value = response.data.data || []
pagination.total = response.data.pagination?.total || 0
console.log('理赔管理数据设置成功:', claimList.value.length, '条')
} else {
console.log('理赔管理响应格式错误:', response)
message.error(response.data?.message || '加载理赔列表失败')
claimList.value = []
}
} catch (error) {
message.error('加载理赔列表失败')
} finally {

View File

@@ -34,7 +34,7 @@
<a-range-picker
v-model:value="searchForm.dateRange"
style="width: 100%"
placeholder="['开始日期', '结束日期']"
:placeholder="['开始日期', '结束日期']"
/>
</a-col>
<a-col :span="6">

View File

@@ -209,25 +209,33 @@ const loadDashboardData = async () => {
try {
// 获取统计信息
const statsResponse = await dashboardAPI.getStats()
if (statsResponse.status === 'success') {
console.log('统计数据响应:', statsResponse)
if (statsResponse.data && statsResponse.data.status === 'success') {
stats.value = {
totalUsers: statsResponse.data.totalUsers || 0,
totalApplications: statsResponse.data.totalApplications || 0,
totalPolicies: statsResponse.data.totalPolicies || 0,
totalClaims: statsResponse.data.totalClaims || 0
totalUsers: statsResponse.data.data.totalUsers || 0,
totalApplications: statsResponse.data.data.totalApplications || 0,
totalPolicies: statsResponse.data.data.totalPolicies || 0,
totalClaims: statsResponse.data.data.totalClaims || 0
}
console.log('统计数据设置成功:', stats.value)
} else {
console.log('统计数据响应格式错误:', statsResponse)
}
// 获取最近活动
const activitiesResponse = await dashboardAPI.getRecentActivities()
if (activitiesResponse.status === 'success') {
recentActivities.value = activitiesResponse.data.map(activity => ({
console.log('最近活动响应:', activitiesResponse)
if (activitiesResponse.data && activitiesResponse.data.status === 'success') {
recentActivities.value = activitiesResponse.data.data.map(activity => ({
id: activity.id,
type: getLogType(activity.action),
title: getLogTitle('info', activity.action),
description: activity.action,
created_at: activity.createdAt
type: getLogType(activity.type),
title: activity.title,
description: activity.description,
created_at: activity.timestamp || new Date().toISOString()
})) || []
console.log('最近活动设置成功:', recentActivities.value)
} else {
console.log('最近活动响应格式错误:', activitiesResponse)
}
} catch (error) {
console.error('加载仪表板数据失败:', error)
@@ -281,68 +289,80 @@ const loadDashboardData = async () => {
// 加载图表数据
const loadChartData = async () => {
console.log('开始加载图表数据...')
chartLoading.value = true
try {
// 获取申请趋势数据
console.log('正在获取申请趋势数据...')
const applicationTrendResponse = await dashboardAPI.getChartData({
type: 'applications',
period: '7d'
})
if (applicationTrendResponse.status === 'success') {
setupApplicationTrendChart(applicationTrendResponse.data)
console.log('申请趋势响应:', applicationTrendResponse)
if (applicationTrendResponse.data && applicationTrendResponse.data.status === 'success') {
console.log('设置申请趋势图表,数据:', applicationTrendResponse.data.data)
setupApplicationTrendChart(applicationTrendResponse.data.data)
} else {
console.log('申请趋势响应格式错误:', applicationTrendResponse)
}
// 获取保单分布数据
// 获取保单状态分布数据
console.log('正在获取保单状态分布数据...')
const policyDistributionResponse = await dashboardAPI.getChartData({
type: 'policies',
period: '30d'
type: 'policy_status'
})
if (policyDistributionResponse.status === 'success') {
setupPolicyDistributionChart(policyDistributionResponse.data)
console.log('保单状态分布响应:', policyDistributionResponse)
if (policyDistributionResponse.data && policyDistributionResponse.data.status === 'success') {
console.log('设置保单状态分布图表,数据:', policyDistributionResponse.data.data)
setupPolicyDistributionChart(policyDistributionResponse.data.data)
} else {
console.log('保单状态分布响应格式错误:', policyDistributionResponse)
}
} catch (error) {
console.error('加载图表数据失败:', error)
// 使用模拟数据
setupApplicationTrendChart([
{ date: '2024-01-01', count: 5 },
{ date: '2024-01-02', count: 8 },
{ date: '2024-01-03', count: 12 },
{ date: '2024-01-04', count: 7 },
{ date: '2024-01-05', count: 15 },
{ date: '2024-01-06', count: 10 },
{ date: '2024-01-07', count: 18 }
])
setupPolicyDistributionChart([
{ date: '2024-01-01', count: 3 },
{ date: '2024-01-02', count: 5 },
{ date: '2024-01-03', count: 8 },
{ date: '2024-01-04', count: 4 },
{ date: '2024-01-05', count: 12 }
])
console.error('错误详情:', error.response?.data || error.message)
message.error('加载图表数据失败')
} finally {
chartLoading.value = false
console.log('图表数据加载完成')
}
}
// 设置申请趋势图表
const setupApplicationTrendChart = (data) => {
console.log('设置申请趋势图表,接收数据:', data)
if (!data || !Array.isArray(data) || data.length === 0) {
console.warn('申请趋势数据为空或格式错误')
return
}
const dates = data.map(item => item.date)
const counts = data.map(item => item.count)
const counts = data.map(item => item.value || item.count)
console.log('处理后的数据 - 日期:', dates, '数量:', counts)
applicationTrendOption.value = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
type: 'cross',
label: {
backgroundColor: '#6a7985'
}
},
backgroundColor: 'rgba(255, 255, 255, 0.95)',
borderColor: '#ccc',
borderWidth: 1,
textStyle: {
color: '#333'
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
top: '10%',
containLabel: true
},
xAxis: {
@@ -350,15 +370,29 @@ const setupApplicationTrendChart = (data) => {
data: dates,
axisLine: {
lineStyle: {
color: '#8c8c8c'
color: '#d9d9d9'
}
},
axisTick: {
alignWithLabel: true
},
axisLabel: {
color: '#666'
}
},
yAxis: {
type: 'value',
axisLine: {
lineStyle: {
color: '#8c8c8c'
color: '#d9d9d9'
}
},
axisLabel: {
color: '#666'
},
splitLine: {
lineStyle: {
color: '#f0f0f0'
}
}
},
@@ -367,12 +401,25 @@ const setupApplicationTrendChart = (data) => {
name: '申请数量',
type: 'bar',
data: counts,
barWidth: '60%',
itemStyle: {
color: '#1890ff'
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0, color: '#1890ff'
}, {
offset: 1, color: '#40a9ff'
}]
},
borderRadius: [4, 4, 0, 0]
},
emphasis: {
itemStyle: {
color: '#40a9ff'
color: '#0050b3'
}
}
}
@@ -380,27 +427,47 @@ const setupApplicationTrendChart = (data) => {
}
}
// 设置保单分布图表
// 设置保单状态分布图表
const setupPolicyDistributionChart = (data) => {
console.log('设置保单状态分布图表,接收数据:', data)
if (!data || !Array.isArray(data) || data.length === 0) {
console.warn('保单状态分布数据为空或格式错误')
return
}
const chartData = data.map(item => ({
name: item.date,
name: getPolicyStatusLabel(item.status),
value: item.count
}))
console.log('处理后的图表数据:', chartData)
policyDistributionOption.value = {
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b}: {c} ({d}%)'
formatter: '{a} <br/>{b}: {c} ({d}%)',
backgroundColor: 'rgba(255, 255, 255, 0.95)',
borderColor: '#ccc',
borderWidth: 1,
textStyle: {
color: '#333'
}
},
legend: {
orient: 'vertical',
left: 'left'
left: 'left',
top: 'center',
textStyle: {
color: '#666',
fontSize: 12
},
itemGap: 15
},
series: [
{
name: '保单数量',
type: 'pie',
radius: ['40%', '70%'],
radius: ['45%', '75%'],
center: ['65%', '50%'],
avoidLabelOverlap: false,
label: {
show: false,
@@ -409,8 +476,14 @@ const setupPolicyDistributionChart = (data) => {
emphasis: {
label: {
show: true,
fontSize: '18',
fontWeight: 'bold'
fontSize: '16',
fontWeight: 'bold',
color: '#333'
},
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
},
labelLine: {
@@ -418,17 +491,56 @@ const setupPolicyDistributionChart = (data) => {
},
data: chartData,
itemStyle: {
color: function(params) {
const colors = ['#1890ff', '#52c41a', '#faad14', '#f5222d', '#722ed1']
return colors[params.dataIndex % colors.length]
}
borderRadius: 8,
borderColor: '#fff',
borderWidth: 2
}
}
]
}
}
// 获取保单状态标签
const getPolicyStatusLabel = (status) => {
const statusMap = {
'active': '有效',
'expired': '已过期',
'cancelled': '已取消',
'suspended': '暂停'
}
return statusMap[status] || status
}
onMounted(() => {
console.log('Dashboard组件已挂载')
console.log('图表选项初始状态:', {
applicationTrendOption: applicationTrendOption.value,
policyDistributionOption: policyDistributionOption.value
})
// 设置测试图表数据
console.log('设置测试图表数据...')
applicationTrendOption.value = {
title: { text: '测试图表' },
xAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed'] },
yAxis: { type: 'value' },
series: [{ data: [120, 200, 150], type: 'bar' }]
}
policyDistributionOption.value = {
title: { text: '测试饼图' },
series: [{
type: 'pie',
data: [
{ value: 1048, name: '搜索引擎' },
{ value: 735, name: '直接访问' },
{ value: 580, name: '邮件营销' }
]
}]
}
console.log('测试图表设置完成')
loadDashboardData()
})
</script>

View File

@@ -78,7 +78,7 @@
</template>
<script setup>
import { ref, onMounted, onUnmounted, getCurrentInstance } from 'vue';
import { ref, onMounted, onUnmounted, getCurrentInstance, nextTick } from 'vue';
import * as echarts from 'echarts';
import { message } from 'ant-design-vue';
import { dataWarehouseAPI } from '@/utils/api';
@@ -192,13 +192,20 @@ const fetchTypeDistribution = async () => {
const response = await dataWarehouseAPI.getInsuranceTypeDistribution();
console.log('保险类型分布响应:', response);
if (response.data && response.data.success) {
renderTypeDistributionChart(response.data.data);
console.log('保险类型分布数据:', response.data.data);
await nextTick(); // 确保DOM更新
ensureChartReady(typeDistributionChart, () => renderTypeDistributionChart(response.data.data));
} else {
console.log('保险类型分布响应格式错误:', response);
message.error('获取保险类型分布数据失败');
await nextTick();
ensureChartReady(typeDistributionChart, () => renderTypeDistributionChart([]));
}
} catch (error) {
message.error('获取保险类型分布数据失败');
console.error('获取保险类型分布数据错误:', error);
await nextTick();
ensureChartReady(typeDistributionChart, () => renderTypeDistributionChart([]));
}
};
@@ -208,8 +215,11 @@ const fetchStatusDistribution = async () => {
const response = await dataWarehouseAPI.getApplicationStatusDistribution();
console.log('申请状态分布响应:', response);
if (response.data && response.data.success) {
console.log('申请状态分布数据:', response.data.data);
await nextTick(); // 确保DOM更新
renderStatusDistributionChart(response.data.data);
} else {
console.log('申请状态分布响应格式错误:', response);
message.error('获取申请状态分布数据失败');
}
} catch (error) {
@@ -224,8 +234,10 @@ const fetchTrendData = async () => {
const response = await dataWarehouseAPI.getTrendData();
console.log('趋势数据响应:', response);
if (response.data && response.data.success) {
console.log('趋势数据:', response.data.data);
renderTrendChart(response.data.data);
} else {
console.log('趋势数据响应格式错误:', response);
message.error('获取趋势数据失败');
}
} catch (error) {
@@ -240,9 +252,10 @@ const fetchClaimStats = async () => {
const response = await dataWarehouseAPI.getClaimStats();
console.log('赔付统计响应:', response);
if (response && response.data && response.data.success) {
console.log('赔付统计数据:', response.data.data);
renderClaimStatsChart(response.data.data || { statusDistribution: [], monthlyTrend: [] });
} else {
console.warn('赔付统计数据响应格式不正确:', response);
console.log('赔付统计数据响应格式错误:', response);
message.error('获取赔付统计数据失败');
// 使用空数据渲染图表,避免显示错误
renderClaimStatsChart({ statusDistribution: [], monthlyTrend: [] });
@@ -272,6 +285,18 @@ const refreshData = async () => {
}
};
// 确保图表容器准备就绪后初始化
const ensureChartReady = (chartRef, initCallback) => {
const checkReady = () => {
if (chartRef.value && chartRef.value.clientWidth > 0 && chartRef.value.clientHeight > 0) {
initCallback();
} else {
setTimeout(checkReady, 50);
}
};
checkReady();
};
// 处理日期范围变化
const handleDateChange = (dates) => {
dateRange.value = dates;
@@ -281,11 +306,40 @@ const handleDateChange = (dates) => {
// 渲染保险类型分布图表
const renderTypeDistributionChart = (data) => {
if (!typeChartInstance) {
typeChartInstance = echarts.init(typeDistributionChart.value);
console.log('=== 开始渲染保险类型分布图表 ===');
console.log('接收到的数据:', data);
console.log('数据类型:', typeof data);
console.log('是否为数组:', Array.isArray(data));
console.log('数据长度:', data ? data.length : 'N/A');
// 检查DOM元素是否存在
if (!typeDistributionChart.value) {
console.log('DOM元素不存在延迟渲染');
setTimeout(() => renderTypeDistributionChart(data), 200);
return;
}
console.log('保险类型分布数据:', data);
console.log('DOM元素存在开始渲染。尺寸信息:', {
clientWidth: typeDistributionChart.value.clientWidth,
clientHeight: typeDistributionChart.value.clientHeight,
offsetWidth: typeDistributionChart.value.offsetWidth,
offsetHeight: typeDistributionChart.value.offsetHeight
});
console.log('DOM元素已准备好开始初始化图表');
if (!typeChartInstance) {
typeChartInstance = echarts.init(typeDistributionChart.value);
console.log('图表实例已创建');
}
// 验证数据格式
if (!data || !Array.isArray(data) || data.length === 0) {
console.warn('保险类型分布数据为空或格式错误:', data);
return;
}
console.log('保险类型分布数据验证通过:', data);
const option = {
tooltip: {
@@ -318,16 +372,46 @@ const renderTypeDistributionChart = (data) => {
]
};
console.log('设置图表选项:', option);
typeChartInstance.setOption(option);
console.log('保险类型分布图表渲染完成');
};
// 渲染申请状态分布图表
const renderStatusDistributionChart = (data) => {
if (!statusChartInstance) {
statusChartInstance = echarts.init(statusDistributionChart.value);
console.log('=== 开始渲染申请状态分布图表 ===');
console.log('接收到的数据:', data);
console.log('数据类型:', typeof data);
console.log('是否为数组:', Array.isArray(data));
console.log('数据长度:', data ? data.length : 'N/A');
// 检查DOM元素是否存在且有尺寸
if (!statusDistributionChart.value || statusDistributionChart.value.clientWidth === 0 || statusDistributionChart.value.clientHeight === 0) {
console.log('DOM元素未准备好延迟渲染。当前状态:', {
element: statusDistributionChart.value,
clientWidth: statusDistributionChart.value?.clientWidth,
clientHeight: statusDistributionChart.value?.clientHeight,
offsetWidth: statusDistributionChart.value?.offsetWidth,
offsetHeight: statusDistributionChart.value?.offsetHeight
});
setTimeout(() => renderStatusDistributionChart(data), 200);
return;
}
console.log('申请状态分布数据:', data);
console.log('DOM元素已准备好开始初始化图表');
if (!statusChartInstance) {
statusChartInstance = echarts.init(statusDistributionChart.value);
console.log('图表实例已创建');
}
// 验证数据格式
if (!data || !Array.isArray(data) || data.length === 0) {
console.warn('申请状态分布数据为空或格式错误:', data);
return;
}
console.log('申请状态分布数据验证通过:', data);
const option = {
tooltip: {
@@ -360,11 +444,19 @@ const renderStatusDistributionChart = (data) => {
]
};
console.log('设置图表选项:', option);
statusChartInstance.setOption(option);
console.log('申请状态分布图表渲染完成');
};
// 渲染趋势图表
const renderTrendChart = (data) => {
// 检查DOM元素是否存在且有尺寸
if (!trendChart.value || trendChart.value.clientWidth === 0 || trendChart.value.clientHeight === 0) {
setTimeout(() => renderTrendChart(data), 100);
return;
}
if (!trendChartInstance) {
trendChartInstance = echarts.init(trendChart.value);
}
@@ -465,6 +557,12 @@ const renderTrendChart = (data) => {
// 渲染赔付统计图表
const renderClaimStatsChart = (data) => {
// 检查DOM元素是否存在且有尺寸
if (!claimStatsChart.value || claimStatsChart.value.clientWidth === 0 || claimStatsChart.value.clientHeight === 0) {
setTimeout(() => renderClaimStatsChart(data), 100);
return;
}
if (!claimChartInstance) {
claimChartInstance = echarts.init(claimStatsChart.value);
}
@@ -539,7 +637,30 @@ const handleResize = () => {
// 组件挂载时初始化
onMounted(() => {
refreshData();
console.log('=== DataWarehouse组件已挂载 ===');
console.log('图表容器引用:', {
typeDistributionChart: typeDistributionChart.value,
statusDistributionChart: statusDistributionChart.value,
trendChart: trendChart.value,
claimStatsChart: claimStatsChart.value
});
// 延迟一点时间确保DOM完全渲染
setTimeout(() => {
console.log('延迟检查图表容器尺寸:', {
typeDistributionChart: typeDistributionChart.value ? {
clientWidth: typeDistributionChart.value.clientWidth,
clientHeight: typeDistributionChart.value.clientHeight
} : 'null',
statusDistributionChart: statusDistributionChart.value ? {
clientWidth: statusDistributionChart.value.clientWidth,
clientHeight: statusDistributionChart.value.clientHeight
} : 'null'
});
refreshData();
}, 100);
window.addEventListener('resize', handleResize);
});
@@ -626,6 +747,8 @@ onUnmounted(() => {
.chart {
width: 100%;
height: calc(100% - 50px);
min-height: 300px;
min-width: 200px;
}
@media (max-width: 1200px) {

View File

@@ -239,12 +239,15 @@ const fetchInstallationTasks = async () => {
};
const response = await installationTaskApi.getInstallationTasks(params);
console.log('安装任务API响应:', response);
if (response.code === 200) {
tableData.value = response.data.rows || response.data.list || [];
pagination.total = response.data.total || 0;
if (response.data && response.data.status === 'success') {
tableData.value = response.data.data.list || [];
pagination.total = response.data.data.total || 0;
console.log('安装任务数据设置成功:', tableData.value.length, '条');
} else {
message.error(response.message || '获取安装任务列表失败');
console.log('安装任务响应格式错误:', response);
message.error(response.data?.message || '获取安装任务列表失败');
}
} catch (error) {
console.error('获取安装任务列表失败:', error);

View File

@@ -365,12 +365,16 @@ const loadInsuranceTypes = async () => {
}
const response = await insuranceTypeAPI.getList(params)
console.log('险种管理API响应:', response)
if (response.status === 'success') {
typeList.value = response.data.list
pagination.total = response.data.total
if (response.data && response.data.status === 'success') {
// API返回的数据直接是数组格式
typeList.value = response.data.data || []
pagination.total = response.data.pagination?.total || 0
console.log('险种管理数据设置成功:', typeList.value.length, '个')
} else {
message.error(response.message || '加载险种列表失败')
console.log('险种管理响应格式错误:', response)
message.error(response.data?.message || '加载险种列表失败')
}
} catch (error) {
message.error('加载险种列表失败')

View File

@@ -55,7 +55,7 @@
<a-col :span="8">
<a-range-picker
v-model:value="searchForm.dateRange"
placeholder="['开始日期', '结束日期']"
:placeholder="['开始日期', '结束日期']"
style="width: 100%"
/>
</a-col>
@@ -474,10 +474,21 @@ const fetchData = async () => {
}
delete params.dateRange
console.log('生资保单API请求参数:', params)
const response = await livestockPolicyApi.getList(params)
console.log('生资保单API响应:', response)
console.log('响应数据类型:', typeof response)
console.log('响应code:', response.code)
console.log('响应data:', response.data)
if (response.code === 200) {
tableData.value = response.data.list
pagination.total = response.data.total
// 后端返回的数据直接是数组格式,不是{list: [], total: 18}格式
tableData.value = response.data || []
pagination.total = response.pagination?.total || 0
console.log('生资保单数据设置成功:', tableData.value.length, '条')
} else {
console.log('生资保单响应格式错误:', response)
message.error('获取数据失败')
}
} catch (error) {
message.error('获取数据失败')

View File

@@ -107,9 +107,8 @@ const onFinish = async (values) => {
userStore.setAuthData({
accessToken: data.accessToken,
refreshToken: data.refreshToken,
accessTokenExpiresAt: data.accessTokenExpiresAt,
refreshTokenExpiresAt: data.refreshTokenExpiresAt,
user: data.user || data.userInfo // 修复用户信息在data.user中
user: data.user || data.userInfo,
expiresIn: data.accessTokenExpiresIn || 900 // 默认15分钟
})
} else if (data.token) {
// 兼容旧的单Token格式

View File

@@ -1,122 +1,247 @@
<template>
<div style="padding: 20px;">
<h2>登录和API测试</h2>
<div style="margin-bottom: 20px;">
<h3>当前状态</h3>
<p>Token: {{ userStore.token ? '已设置' : '未设置' }}</p>
<p>用户信息: {{ JSON.stringify(userStore.userInfo) }}</p>
</div>
<div class="login-test">
<a-card title="登录测试" style="margin: 20px;">
<a-space direction="vertical" style="width: 100%;">
<div>
<h3>快速登录测试</h3>
<a-form :model="loginForm" @finish="handleLogin">
<a-form-item>
<a-input v-model:value="loginForm.username" placeholder="用户名" />
</a-form-item>
<a-form-item>
<a-input-password v-model:value="loginForm.password" placeholder="密码" />
</a-form-item>
<a-form-item>
<a-button type="primary" html-type="submit" :loading="loginLoading" block>
登录
</a-button>
</a-form-item>
</a-form>
</div>
<div style="margin-bottom: 20px;">
<h3>快速登录</h3>
<a-button type="primary" @click="quickLogin" :loading="loginLoading">
使用 admin/123456 登录
</a-button>
</div>
<div>
<h3>Token状态检查</h3>
<a-descriptions bordered :column="1">
<a-descriptions-item label="Store中的Access Token">
<span v-if="userStore.accessToken">
{{ userStore.accessToken.substring(0, 50) }}...
<br>
<small>长度: {{ userStore.accessToken.length }}</small>
</span>
<span v-else style="color: red;">未找到</span>
</a-descriptions-item>
<a-descriptions-item label="LocalStorage中的Access Token">
<span v-if="localStorageToken">
{{ localStorageToken.substring(0, 50) }}...
<br>
<small>长度: {{ localStorageToken.length }}</small>
</span>
<span v-else style="color: red;">未找到</span>
</a-descriptions-item>
<a-descriptions-item label="是否已登录">
<span :style="{ color: userStore.isLoggedIn ? 'green' : 'red' }">
{{ userStore.isLoggedIn ? '是' : '否' }}
</span>
</a-descriptions-item>
<a-descriptions-item label="Token是否过期">
<span :style="{ color: userStore.isTokenExpired ? 'red' : 'green' }">
{{ userStore.isTokenExpired ? '是' : '否' }}
</span>
</a-descriptions-item>
</a-descriptions>
</div>
<div style="margin-bottom: 20px;">
<h3>测试API调用</h3>
<a-button @click="testStatsAPI" :loading="statsLoading" style="margin-right: 10px;">
测试系统统计API
</a-button>
<a-button @click="testAuthAPI" :loading="authLoading">
测试认证API
</a-button>
</div>
<div>
<h3>API测试</h3>
<a-space>
<a-button @click="testPermissionsAPI" :loading="permissionsLoading">
测试权限API
</a-button>
<a-button @click="testRolesAPI" :loading="rolesLoading">
测试角色API
</a-button>
<a-button @click="refreshStatus">
刷新状态
</a-button>
</a-space>
</div>
<div v-if="apiResults.length">
<h3>API调用结果</h3>
<div v-for="(result, index) in apiResults" :key="index" style="margin-bottom: 10px; padding: 10px; border: 1px solid #ddd;">
<strong>{{ result.name }}:</strong>
<pre>{{ result.data }}</pre>
</div>
</div>
<div v-if="testResults.length > 0">
<h3>测试结果</h3>
<a-list :data-source="testResults" bordered>
<template #renderItem="{ item }">
<a-list-item>
<a-list-item-meta>
<template #title>
<span :style="{ color: item.success ? 'green' : 'red' }">
{{ item.name }} - {{ item.success ? '成功' : '失败' }}
</span>
</template>
<template #description>
<div>
<p><strong>状态:</strong> {{ item.status }}</p>
<p><strong>响应:</strong></p>
<pre style="background: #f5f5f5; padding: 8px; border-radius: 4px; font-size: 12px;">{{ item.response }}</pre>
</div>
</template>
</a-list-item-meta>
</a-list-item>
</template>
</a-list>
</div>
</a-space>
</a-card>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { ref, reactive, onMounted } from 'vue'
import { message } from 'ant-design-vue'
import { useUserStore } from '@/stores/user'
import { authAPI, dashboardAPI } from '@/utils/api'
import { authAPI, rolePermissionAPI } from '@/utils/api'
const userStore = useUserStore()
const loginLoading = ref(false)
const statsLoading = ref(false)
const authLoading = ref(false)
const apiResults = ref([])
const permissionsLoading = ref(false)
const rolesLoading = ref(false)
const testResults = ref([])
const quickLogin = async () => {
const loginForm = reactive({
username: 'admin',
password: '123456'
})
const localStorageToken = ref('')
const refreshStatus = () => {
localStorageToken.value = localStorage.getItem('accessToken') || ''
}
const handleLogin = async () => {
loginLoading.value = true
try {
const response = await authAPI.login({
username: 'admin',
password: '123456'
})
const response = await authAPI.login(loginForm)
if (response.status === 'success') {
userStore.setToken(response.data.token)
userStore.setUserInfo(response.data.user)
message.success('登录成功!')
if (response.data && (response.data.status === 'success' || response.data.code === 200)) {
const data = response.data.data
apiResults.value.unshift({
name: '登录API',
data: JSON.stringify(response, null, 2)
})
if (data.accessToken && data.refreshToken) {
userStore.setAuthData({
accessToken: data.accessToken,
refreshToken: data.refreshToken,
user: data.user || data.userInfo,
expiresIn: data.accessTokenExpiresIn || 900
})
testResults.value.unshift({
name: '登录测试',
success: true,
status: '成功',
response: JSON.stringify({
message: '登录成功',
tokenLength: data.accessToken.length,
user: data.user?.username
}, null, 2)
})
message.success('登录成功')
refreshStatus()
} else {
throw new Error('响应数据格式不正确缺少token信息')
}
} else {
message.error(response.message || '登录失败')
throw new Error(response.data?.message || '登录失败')
}
} catch (error) {
message.error(error.response?.data?.message || '登录失败')
apiResults.value.unshift({
name: '登录API (错误)',
data: JSON.stringify(error.response?.data || error.message, null, 2)
testResults.value.unshift({
name: '登录测试',
success: false,
status: '失败',
response: JSON.stringify(error.response?.data || error.message, null, 2)
})
message.error('登录失败: ' + (error.response?.data?.message || error.message))
} finally {
loginLoading.value = false
}
}
const testStatsAPI = async () => {
statsLoading.value = true
const testPermissionsAPI = async () => {
permissionsLoading.value = true
try {
const response = await dashboardAPI.getStats()
message.success('系统统计API调用成功')
const response = await rolePermissionAPI.getAllPermissions()
apiResults.value.unshift({
name: '系统统计API',
data: JSON.stringify(response, null, 2)
testResults.value.unshift({
name: '权限API测试',
success: response.success,
status: response.success ? '成功' : '失败',
response: JSON.stringify(response, null, 2)
})
if (response.success) {
message.success('权限API测试成功')
} else {
message.error('权限API测试失败: ' + response.error)
}
} catch (error) {
message.error('系统统计API调用失败')
apiResults.value.unshift({
name: '系统统计API (错误)',
data: JSON.stringify(error.response?.data || error.message, null, 2)
testResults.value.unshift({
name: '权限API测试',
success: false,
status: '失败',
response: JSON.stringify(error.message, null, 2)
})
message.error('权限API测试失败: ' + error.message)
} finally {
statsLoading.value = false
permissionsLoading.value = false
}
}
const testAuthAPI = async () => {
authLoading.value = true
const testRolesAPI = async () => {
rolesLoading.value = true
try {
const response = await authAPI.getProfile()
message.success('认证API调用成功')
const response = await rolePermissionAPI.getAllRolesWithPermissions()
apiResults.value.unshift({
name: '用户资料API',
data: JSON.stringify(response, null, 2)
testResults.value.unshift({
name: '角色API测试',
success: response.success,
status: response.success ? '成功' : '失败',
response: JSON.stringify(response, null, 2)
})
if (response.success) {
message.success('角色API测试成功')
} else {
message.error('角色API测试失败: ' + response.error)
}
} catch (error) {
message.error('认证API调用失败')
apiResults.value.unshift({
name: '用户资料API (错误)',
data: JSON.stringify(error.response?.data || error.message, null, 2)
testResults.value.unshift({
name: '角色API测试',
success: false,
status: '失败',
response: JSON.stringify(error.message, null, 2)
})
message.error('角色API测试失败: ' + error.message)
} finally {
authLoading.value = false
rolesLoading.value = false
}
}
</script>
onMounted(() => {
refreshStatus()
})
</script>
<style scoped>
.login-test {
padding: 20px;
}
pre {
white-space: pre-wrap;
word-wrap: break-word;
max-height: 200px;
overflow-y: auto;
}
</style>

View File

@@ -302,6 +302,7 @@ import {
SearchOutlined,
RedoOutlined
} from '@ant-design/icons-vue'
import { policyAPI } from '@/utils/api'
const loading = ref(false)
const modalVisible = ref(false)
@@ -443,51 +444,26 @@ const loadPolicies = async () => {
...searchForm
}
// 这里应该是实际的API调用
// const response = await policyAPI.getList(params)
// policyList.value = response.data.list
// pagination.total = response.data.total
console.log('保单管理API请求参数:', params)
const response = await policyAPI.getList(params)
console.log('保单管理API响应:', response)
console.log('响应数据类型:', typeof response)
console.log('响应data字段:', response.data)
console.log('响应data.status:', response.data?.status)
console.log('响应data.data:', response.data?.data)
console.log('响应data.data长度:', response.data?.data?.length)
// 模拟数据
policyList.value = [
{
id: 1,
policy_number: 'POL20240001',
insurance_type_id: 1,
insurance_type_name: '综合意外险',
policyholder_name: '张三',
insured_name: '张三',
premium_amount: 1200,
coverage_amount: 500000,
start_date: '2024-01-01',
end_date: '2025-01-01',
status: 'active',
phone: '13800138000',
email: 'zhangsan@example.com',
address: '北京市朝阳区',
created_at: '2024-01-01 10:00:00',
updated_at: '2024-01-01 10:00:00'
},
{
id: 2,
policy_number: 'POL20240002',
insurance_type_id: 2,
insurance_type_name: '终身寿险',
policyholder_name: '李四',
insured_name: '李四',
premium_amount: 5000,
coverage_amount: 1000000,
start_date: '2024-01-02',
end_date: '2074-01-02',
status: 'active',
phone: '13800138001',
email: 'lisi@example.com',
address: '上海市浦东新区',
created_at: '2024-01-02 14:30:00',
updated_at: '2024-01-02 14:30:00'
}
]
pagination.total = 2
if (response.data && response.data.status === 'success') {
// 后端返回的数据直接是数组格式,不是{list: [], total: 28}格式
policyList.value = response.data.data || []
pagination.total = response.data.pagination?.total || 0
console.log('保单管理数据设置成功:', policyList.value.length, '条')
console.log('policyList.value:', policyList.value)
} else {
console.log('保单管理响应格式错误:', response)
message.error(response.data?.message || '加载保单列表失败')
policyList.value = []
}
} catch (error) {
message.error('加载保单列表失败')
} finally {

View File

@@ -441,11 +441,14 @@ export default {
}
const response = await supervisionTaskApi.getList(params)
if (response.code === 200) {
tableData.value = response.data.list
pagination.total = response.data.total
console.log('监管任务API响应:', response)
if (response.data && response.data.status === 'success') {
tableData.value = response.data.data.list
pagination.total = response.data.data.total
console.log('监管任务数据设置成功:', tableData.value.length, '条')
} else {
message.error(response.message || '获取数据失败')
console.log('监管任务响应格式错误:', response)
message.error(response.data?.message || '获取数据失败')
}
} catch (error) {
console.error('加载数据失败:', error)

View File

@@ -427,9 +427,14 @@ const fetchTaskList = async () => {
}
const response = await supervisoryTaskApi.getList(params)
if (response.code === 200) {
taskList.value = response.data.list
pagination.total = response.data.total
console.log('监管任务API响应:', response)
if (response.data && response.data.status === 'success') {
taskList.value = response.data.data.list
pagination.total = response.data.data.total
console.log('监管任务数据设置成功:', taskList.value.length, '条')
} else {
console.log('监管任务响应格式错误:', response)
message.error(response.data?.message || '获取任务列表失败')
}
} catch (error) {
console.error('获取任务列表失败:', error)

View File

@@ -422,28 +422,28 @@ const handleTableChange = (pag) => {
const loadLogs = async () => {
loading.value = true
try {
// const params = {
// page: pagination.current,
// pageSize: pagination.pageSize,
// ...searchForm,
// start_time: searchForm.timeRange?.[0]?.format('YYYY-MM-DD HH:mm:ss'),
// end_time: searchForm.timeRange?.[1]?.format('YYYY-MM-DD HH:mm:ss')
// }
// const response = await systemAPI.getLogs(params)
// logList.value = response.data.list
// pagination.total = response.data.total
const params = {
page: pagination.current,
pageSize: pagination.pageSize,
...searchForm,
start_time: searchForm.timeRange?.[0]?.format('YYYY-MM-DD HH:mm:ss'),
end_time: searchForm.timeRange?.[1]?.format('YYYY-MM-DD HH:mm:ss')
}
// 模拟数据
const filteredLogs = logList.value.filter(log => {
if (searchForm.log_type && log.log_type !== searchForm.log_type) return false
if (searchForm.module && log.module !== searchForm.module) return false
if (searchForm.operator && !log.operator.includes(searchForm.operator)) return false
if (searchForm.ip_address && !log.ip_address.includes(searchForm.ip_address)) return false
return true
})
console.log('系统日志API请求参数:', params)
const response = await operationLogAPI.getList(params)
console.log('系统日志API响应:', response)
logList.value = filteredLogs
pagination.total = filteredLogs.length
if (response.data && response.data.status === 'success') {
// 后端返回的数据在data.logs字段中
logList.value = response.data.data.logs || []
pagination.total = response.data.data.total || 0
console.log('系统日志数据设置成功:', logList.value.length, '条')
} else {
console.log('系统日志响应格式错误:', response)
message.error(response.data?.message || '加载日志失败')
logList.value = []
}
} catch (error) {
message.error('加载日志失败')
} finally {

View File

@@ -0,0 +1,260 @@
<template>
<div class="token-debug">
<a-card title="Token调试信息" style="margin: 20px;">
<a-space direction="vertical" style="width: 100%;">
<div>
<h3>LocalStorage中的Token信息:</h3>
<a-descriptions bordered :column="1">
<a-descriptions-item label="Access Token">
<span v-if="tokenInfo.accessToken">
{{ tokenInfo.accessToken.substring(0, 50) }}...
<br>
<small>长度: {{ tokenInfo.accessToken.length }}</small>
</span>
<span v-else style="color: red;">未找到</span>
</a-descriptions-item>
<a-descriptions-item label="Refresh Token">
<span v-if="tokenInfo.refreshToken">
{{ tokenInfo.refreshToken.substring(0, 50) }}...
<br>
<small>长度: {{ tokenInfo.refreshToken.length }}</small>
</span>
<span v-else style="color: red;">未找到</span>
</a-descriptions-item>
<a-descriptions-item label="User Info">
<pre v-if="tokenInfo.userInfo">{{ JSON.stringify(tokenInfo.userInfo, null, 2) }}</pre>
<span v-else style="color: red;">未找到</span>
</a-descriptions-item>
<a-descriptions-item label="Token Expires At">
<span v-if="tokenInfo.tokenExpiresAt">
{{ new Date(tokenInfo.tokenExpiresAt).toLocaleString() }}
<br>
<small :style="{ color: tokenInfo.isExpired ? 'red' : 'green' }">
{{ tokenInfo.isExpired ? '已过期' : '未过期' }}
</small>
</span>
<span v-else style="color: red;">未找到</span>
</a-descriptions-item>
</a-descriptions>
</div>
<div>
<h3>Store中的Token信息:</h3>
<a-descriptions bordered :column="1">
<a-descriptions-item label="Access Token">
<span v-if="userStore.accessToken">
{{ userStore.accessToken.substring(0, 50) }}...
<br>
<small>长度: {{ userStore.accessToken.length }}</small>
</span>
<span v-else style="color: red;">未找到</span>
</a-descriptions-item>
<a-descriptions-item label="Refresh Token">
<span v-if="userStore.refreshToken">
{{ userStore.refreshToken.substring(0, 50) }}...
<br>
<small>长度: {{ userStore.refreshToken.length }}</small>
</span>
<span v-else style="color: red;">未找到</span>
</a-descriptions-item>
<a-descriptions-item label="User Info">
<pre v-if="userStore.userInfo">{{ JSON.stringify(userStore.userInfo, null, 2) }}</pre>
<span v-else style="color: red;">未找到</span>
</a-descriptions-item>
<a-descriptions-item label="Is Logged In">
<span :style="{ color: userStore.isLoggedIn ? 'green' : 'red' }">
{{ userStore.isLoggedIn ? '是' : '否' }}
</span>
</a-descriptions-item>
<a-descriptions-item label="Is Token Expired">
<span :style="{ color: userStore.isTokenExpired ? 'red' : 'green' }">
{{ userStore.isTokenExpired ? '是' : '否' }}
</span>
</a-descriptions-item>
</a-descriptions>
</div>
<div>
<h3>API测试:</h3>
<a-space>
<a-button type="primary" @click="testLogin" :loading="loginLoading">
测试登录
</a-button>
<a-button @click="testPermissionsAPI" :loading="permissionsLoading">
测试权限API
</a-button>
<a-button @click="testRolesAPI" :loading="rolesLoading">
测试角色API
</a-button>
<a-button @click="refreshTokenInfo">
刷新Token信息
</a-button>
</a-space>
</div>
<div v-if="apiTestResults.length > 0">
<h3>API测试结果:</h3>
<a-list :data-source="apiTestResults" bordered>
<template #renderItem="{ item }">
<a-list-item>
<a-list-item-meta>
<template #title>
<span :style="{ color: item.success ? 'green' : 'red' }">
{{ item.name }} - {{ item.success ? '成功' : '失败' }}
</span>
</template>
<template #description>
<div>
<p><strong>状态码:</strong> {{ item.status }}</p>
<p><strong>响应:</strong></p>
<pre style="background: #f5f5f5; padding: 8px; border-radius: 4px; font-size: 12px;">{{ item.response }}</pre>
</div>
</template>
</a-list-item-meta>
</a-list-item>
</template>
</a-list>
</div>
</a-space>
</a-card>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { message } from 'ant-design-vue'
import { useUserStore } from '@/stores/user'
import { authAPI, rolePermissionAPI } from '@/utils/api'
const userStore = useUserStore()
const loginLoading = ref(false)
const permissionsLoading = ref(false)
const rolesLoading = ref(false)
const apiTestResults = ref([])
const tokenInfo = reactive({
accessToken: null,
refreshToken: null,
userInfo: null,
tokenExpiresAt: null,
isExpired: false
})
const refreshTokenInfo = () => {
tokenInfo.accessToken = localStorage.getItem('accessToken')
tokenInfo.refreshToken = localStorage.getItem('refreshToken')
tokenInfo.userInfo = JSON.parse(localStorage.getItem('userInfo') || 'null')
tokenInfo.tokenExpiresAt = parseInt(localStorage.getItem('tokenExpiresAt') || '0')
tokenInfo.isExpired = tokenInfo.tokenExpiresAt ? Date.now() >= tokenInfo.tokenExpiresAt : true
}
const testLogin = async () => {
loginLoading.value = true
try {
const response = await authAPI.login({
username: 'admin',
password: '123456'
})
apiTestResults.value.unshift({
name: '登录测试',
success: true,
status: response.status || '200',
response: JSON.stringify(response.data, null, 2)
})
message.success('登录测试成功')
refreshTokenInfo()
} catch (error) {
apiTestResults.value.unshift({
name: '登录测试',
success: false,
status: error.response?.status || 'Error',
response: JSON.stringify(error.response?.data || error.message, null, 2)
})
message.error('登录测试失败')
} finally {
loginLoading.value = false
}
}
const testPermissionsAPI = async () => {
permissionsLoading.value = true
try {
const response = await rolePermissionAPI.getAllPermissions()
apiTestResults.value.unshift({
name: '权限API测试',
success: response.success,
status: response.success ? '200' : 'Error',
response: JSON.stringify(response, null, 2)
})
if (response.success) {
message.success('权限API测试成功')
} else {
message.error('权限API测试失败')
}
} catch (error) {
apiTestResults.value.unshift({
name: '权限API测试',
success: false,
status: 'Error',
response: JSON.stringify(error.message, null, 2)
})
message.error('权限API测试失败')
} finally {
permissionsLoading.value = false
}
}
const testRolesAPI = async () => {
rolesLoading.value = true
try {
const response = await rolePermissionAPI.getAllRolesWithPermissions()
apiTestResults.value.unshift({
name: '角色API测试',
success: response.success,
status: response.success ? '200' : 'Error',
response: JSON.stringify(response, null, 2)
})
if (response.success) {
message.success('角色API测试成功')
} else {
message.error('角色API测试失败')
}
} catch (error) {
apiTestResults.value.unshift({
name: '角色API测试',
success: false,
status: 'Error',
response: JSON.stringify(error.message, null, 2)
})
message.error('角色API测试失败')
} finally {
rolesLoading.value = false
}
}
onMounted(() => {
refreshTokenInfo()
})
</script>
<style scoped>
.token-debug {
padding: 20px;
}
pre {
white-space: pre-wrap;
word-wrap: break-word;
max-height: 200px;
overflow-y: auto;
}
</style>

View File

@@ -265,35 +265,20 @@ const loadUsers = async () => {
...searchForm
}
// 这里应该是实际的API调用
// const response = await userAPI.getList(params)
// userList.value = response.data.list
// pagination.total = response.data.total
console.log('用户管理API请求参数:', params)
const response = await userAPI.getList(params)
console.log('用户管理API响应:', response)
// 模拟数据
userList.value = [
{
id: 1,
username: 'admin',
real_name: '管理员',
email: 'admin@example.com',
phone: '13800138000',
role_name: '管理员',
status: 'active',
created_at: '2024-01-01 10:00:00'
},
{
id: 2,
username: 'advisor1',
real_name: '张顾问',
email: 'advisor1@example.com',
phone: '13800138001',
role_name: '保险顾问',
status: 'active',
created_at: '2024-01-02 14:30:00'
}
]
pagination.total = 2
if (response.data && response.data.status === 'success') {
// 后端返回的数据在data.users字段中
userList.value = response.data.data.users || []
pagination.total = response.data.data.pagination?.total || 0
console.log('用户管理数据设置成功:', userList.value.length, '条')
} else {
console.log('用户管理响应格式错误:', response)
message.error(response.data?.message || '加载用户列表失败')
userList.value = []
}
} catch (error) {
message.error('加载用户列表失败')
} finally {