完善保险项目和养殖端小程序
This commit is contained in:
@@ -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>
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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 = []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
<a-range-picker
|
||||
v-model:value="searchForm.dateRange"
|
||||
style="width: 100%"
|
||||
placeholder="['开始日期', '结束日期']"
|
||||
:placeholder="['开始日期', '结束日期']"
|
||||
/>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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('加载险种列表失败')
|
||||
|
||||
@@ -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('获取数据失败')
|
||||
|
||||
@@ -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格式
|
||||
|
||||
@@ -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>
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
260
insurance_admin-system/src/views/TokenDebug.vue
Normal file
260
insurance_admin-system/src/views/TokenDebug.vue
Normal 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>
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user