修改养殖端小程序,保险前后端和小程序
This commit is contained in:
@@ -10,7 +10,7 @@
|
||||
v-model:selectedKeys="selectedKeys"
|
||||
theme="dark"
|
||||
mode="inline"
|
||||
:items="menuItems"
|
||||
:items="menus"
|
||||
@click="handleMenuClick"
|
||||
/>
|
||||
</a-layout-sider>
|
||||
@@ -70,7 +70,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, h } from 'vue'
|
||||
import { ref, computed, onMounted, h } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import {
|
||||
MenuUnfoldOutlined,
|
||||
@@ -79,13 +79,23 @@ import {
|
||||
DownOutlined,
|
||||
LogoutOutlined,
|
||||
DashboardOutlined,
|
||||
UserSwitchOutlined,
|
||||
InsuranceOutlined,
|
||||
FileTextOutlined,
|
||||
FileDoneOutlined,
|
||||
SafetyCertificateOutlined
|
||||
SafetyCertificateOutlined,
|
||||
DatabaseOutlined,
|
||||
CheckCircleOutlined,
|
||||
ExclamationCircleOutlined,
|
||||
BellOutlined,
|
||||
SettingOutlined,
|
||||
UserAddOutlined,
|
||||
ShopOutlined,
|
||||
FileProtectOutlined,
|
||||
MedicineBoxOutlined,
|
||||
UserSwitchOutlined,
|
||||
InsuranceOutlined
|
||||
} from '@ant-design/icons-vue'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { menuAPI } from '@/utils/api'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
@@ -93,54 +103,184 @@ const userStore = useUserStore()
|
||||
|
||||
const collapsed = ref(false)
|
||||
const selectedKeys = ref([route.name])
|
||||
const menus = ref([])
|
||||
|
||||
const menuItems = computed(() => [
|
||||
{
|
||||
key: 'Dashboard',
|
||||
icon: () => h(DashboardOutlined),
|
||||
label: '仪表板',
|
||||
title: '仪表板'
|
||||
},
|
||||
{
|
||||
key: 'UserManagement',
|
||||
icon: () => h(UserSwitchOutlined),
|
||||
label: '用户管理',
|
||||
title: '用户管理'
|
||||
},
|
||||
{
|
||||
key: 'InsuranceTypeManagement',
|
||||
icon: () => h(InsuranceOutlined),
|
||||
label: '保险类型管理',
|
||||
title: '保险类型管理'
|
||||
},
|
||||
{
|
||||
key: 'ApplicationManagement',
|
||||
icon: () => h(FileTextOutlined),
|
||||
label: '保险申请管理',
|
||||
title: '保险申请管理'
|
||||
},
|
||||
{
|
||||
key: 'PolicyManagement',
|
||||
icon: () => h(FileDoneOutlined),
|
||||
label: '保单管理',
|
||||
title: '保单管理'
|
||||
},
|
||||
{
|
||||
key: 'ClaimManagement',
|
||||
icon: () => h(SafetyCertificateOutlined),
|
||||
label: '理赔管理',
|
||||
title: '理赔管理'
|
||||
// 图标映射,根据后端返回的icon名称返回对应的组件
|
||||
const iconMap = {
|
||||
DashboardOutlined: () => h(DashboardOutlined),
|
||||
DatabaseOutlined: () => h(DatabaseOutlined),
|
||||
CheckCircleOutlined: () => h(CheckCircleOutlined),
|
||||
FileTextOutlined: () => h(FileTextOutlined),
|
||||
FileDoneOutlined: () => h(FileDoneOutlined),
|
||||
SafetyCertificateOutlined: () => h(SafetyCertificateOutlined),
|
||||
ShopOutlined: () => h(ShopOutlined),
|
||||
FileProtectOutlined: () => h(FileProtectOutlined),
|
||||
MedicineBoxOutlined: () => h(MedicineBoxOutlined),
|
||||
InsuranceOutlined: () => h(InsuranceOutlined),
|
||||
BellOutlined: () => h(BellOutlined),
|
||||
UserAddOutlined: () => h(UserAddOutlined),
|
||||
SettingOutlined: () => h(SettingOutlined),
|
||||
UserSwitchOutlined: () => h(UserSwitchOutlined)
|
||||
};
|
||||
|
||||
// 格式化菜单数据为Ant Design Vue的Menu组件所需格式
|
||||
const formatMenuItems = (menuList) => {
|
||||
return menuList.map(menu => {
|
||||
const menuItem = {
|
||||
key: menu.key,
|
||||
label: menu.name,
|
||||
path: menu.path
|
||||
};
|
||||
|
||||
// 添加图标
|
||||
if (menu.icon && iconMap[menu.icon]) {
|
||||
menuItem.icon = iconMap[menu.icon];
|
||||
}
|
||||
|
||||
// 添加子菜单
|
||||
if (menu.children && menu.children.length > 0) {
|
||||
menuItem.children = formatMenuItems(menu.children);
|
||||
}
|
||||
|
||||
return menuItem;
|
||||
});
|
||||
};
|
||||
|
||||
// 获取动态菜单数据
|
||||
const fetchMenus = async () => {
|
||||
try {
|
||||
const response = await menuAPI.getMenus();
|
||||
if (response.status === 'success') {
|
||||
menus.value = formatMenuItems(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取菜单失败:', error);
|
||||
// 提供默认菜单作为备用
|
||||
menus.value = [
|
||||
{
|
||||
key: 'Dashboard',
|
||||
icon: () => h(DashboardOutlined),
|
||||
label: '仪表板',
|
||||
path: '/dashboard'
|
||||
},
|
||||
{
|
||||
key: 'DataWarehouse',
|
||||
icon: () => h(DatabaseOutlined),
|
||||
label: '数据览仓',
|
||||
path: '/dashboard' // 重定向到仪表板
|
||||
},
|
||||
{
|
||||
key: 'SupervisionTask',
|
||||
icon: () => h(CheckCircleOutlined),
|
||||
label: '监管任务',
|
||||
path: '/dashboard' // 重定向到仪表板
|
||||
},
|
||||
{
|
||||
key: 'PendingInstallationTask',
|
||||
icon: () => h(ExclamationCircleOutlined),
|
||||
label: '待安装任务',
|
||||
path: '/dashboard' // 重定向到仪表板
|
||||
},
|
||||
{
|
||||
key: 'CompletedTask',
|
||||
icon: () => h(FileDoneOutlined),
|
||||
label: '监管任务已结项',
|
||||
path: '/dashboard' // 重定向到仪表板
|
||||
},
|
||||
{
|
||||
key: 'InsuredCustomers',
|
||||
icon: () => h(ShopOutlined),
|
||||
label: '投保客户单',
|
||||
children: [
|
||||
{
|
||||
key: 'ApplicationManagement',
|
||||
label: '参保申请',
|
||||
path: '/applications'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'AgriculturalInsurance',
|
||||
icon: () => h(FileProtectOutlined),
|
||||
label: '生资保单',
|
||||
children: [
|
||||
{
|
||||
key: 'PolicyManagement',
|
||||
label: '生资保单列表',
|
||||
path: '/policies'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'InsuranceTypeManagement',
|
||||
icon: () => h(MedicineBoxOutlined),
|
||||
label: '险种管理',
|
||||
children: [
|
||||
{
|
||||
key: 'InsuranceTypeList',
|
||||
label: '险种管理',
|
||||
path: '/insurance-types'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'CustomerClaims',
|
||||
icon: () => h(ExclamationCircleOutlined),
|
||||
label: '客户理赔',
|
||||
children: [
|
||||
{
|
||||
key: 'ClaimManagement',
|
||||
label: '客户理赔',
|
||||
path: '/claims'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'Notifications',
|
||||
icon: () => h(BellOutlined),
|
||||
label: '消息通知',
|
||||
path: '/dashboard' // 重定向到仪表板
|
||||
},
|
||||
{
|
||||
key: 'UserManagement',
|
||||
icon: () => h(UserAddOutlined),
|
||||
label: '子账号管理',
|
||||
path: '/users'
|
||||
},
|
||||
{
|
||||
key: 'SystemSettings',
|
||||
icon: () => h(SettingOutlined),
|
||||
label: '系统设置',
|
||||
path: '/dashboard' // 重定向到仪表板
|
||||
},
|
||||
{
|
||||
key: 'UserProfile',
|
||||
icon: () => h(UserSwitchOutlined),
|
||||
label: '个人中心',
|
||||
path: '/dashboard' // 重定向到仪表板
|
||||
}
|
||||
];
|
||||
}
|
||||
])
|
||||
};
|
||||
|
||||
const handleMenuClick = ({ key }) => {
|
||||
router.push({ name: key })
|
||||
}
|
||||
// 菜单点击处理
|
||||
const handleMenuClick = (e) => {
|
||||
const menuItem = menus.value.find(item => item.key === e.key);
|
||||
if (menuItem && menuItem.path) {
|
||||
router.push(menuItem.path);
|
||||
}
|
||||
};
|
||||
|
||||
// 退出登录处理
|
||||
const handleLogout = () => {
|
||||
userStore.logout()
|
||||
router.push('/login')
|
||||
}
|
||||
userStore.logout();
|
||||
router.push('/login');
|
||||
};
|
||||
|
||||
// 组件挂载时获取菜单
|
||||
onMounted(() => {
|
||||
fetchMenus();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -4,7 +4,24 @@ import router from './router'
|
||||
import store from './stores'
|
||||
import Antd from 'ant-design-vue'
|
||||
import 'ant-design-vue/dist/reset.css'
|
||||
import dayjs from 'dayjs'
|
||||
import 'dayjs/locale/zh-cn'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
import duration from 'dayjs/plugin/duration'
|
||||
import zhCN from 'ant-design-vue/es/locale/zh_CN'
|
||||
|
||||
// 配置 dayjs
|
||||
dayjs.extend(relativeTime)
|
||||
dayjs.extend(duration)
|
||||
dayjs.locale('zh-cn')
|
||||
|
||||
// 为 Ant Design Vue 配置日期库
|
||||
globalThis.dayjs = dayjs
|
||||
|
||||
// Ant Design Vue 4.x 中不再支持通过 Antd.ConfigProvider.config 配置全局属性
|
||||
// 日期库配置已通过 globalThis.dayjs 完成
|
||||
|
||||
// 创建应用实例
|
||||
const app = createApp(App)
|
||||
|
||||
app.use(router)
|
||||
|
||||
@@ -7,6 +7,7 @@ import InsuranceTypeManagement from '@/views/InsuranceTypeManagement.vue'
|
||||
import ApplicationManagement from '@/views/ApplicationManagement.vue'
|
||||
import PolicyManagement from '@/views/PolicyManagement.vue'
|
||||
import ClaimManagement from '@/views/ClaimManagement.vue'
|
||||
import DataWarehouse from '@/views/DataWarehouse.vue'
|
||||
|
||||
const routes = [
|
||||
{
|
||||
@@ -54,6 +55,12 @@ const routes = [
|
||||
name: 'ClaimManagement',
|
||||
component: ClaimManagement,
|
||||
meta: { title: '理赔管理' }
|
||||
},
|
||||
{
|
||||
path: 'data-warehouse',
|
||||
name: 'DataWarehouse',
|
||||
component: DataWarehouse,
|
||||
meta: { title: '数据览仓' }
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -48,6 +48,11 @@ export const userAPI = {
|
||||
create: (data) => api.post('/users', data),
|
||||
update: (id, data) => api.put(`/users/${id}`, data),
|
||||
delete: (id) => api.delete(`/users/${id}`)
|
||||
};
|
||||
|
||||
export const menuAPI = {
|
||||
getMenus: () => api.get('/menus/public'),
|
||||
getAllMenus: () => api.get('/menus/all')
|
||||
}
|
||||
|
||||
export const insuranceTypeAPI = {
|
||||
@@ -84,4 +89,13 @@ export const dashboardAPI = {
|
||||
getRecentActivities: () => api.get('/system/logs?limit=10')
|
||||
}
|
||||
|
||||
// 数据览仓API
|
||||
export const dataWarehouseAPI = {
|
||||
getOverview: () => api.get('/data-warehouse/overview'),
|
||||
getInsuranceTypeDistribution: () => api.get('/data-warehouse/insurance-types'),
|
||||
getApplicationStatusDistribution: () => api.get('/data-warehouse/application-status'),
|
||||
getTrendData: () => api.get('/data-warehouse/trend'),
|
||||
getClaimStats: () => api.get('/data-warehouse/claim-stats')
|
||||
}
|
||||
|
||||
export default api
|
||||
540
insurance_admin-system/src/views/DataWarehouse.vue
Normal file
540
insurance_admin-system/src/views/DataWarehouse.vue
Normal file
@@ -0,0 +1,540 @@
|
||||
<template>
|
||||
<div class="data-warehouse">
|
||||
<div class="page-header">
|
||||
<h1>数据览仓</h1>
|
||||
<div class="filters">
|
||||
<a-date-picker
|
||||
v-model:value="dateRange"
|
||||
range
|
||||
@change="handleDateChange"
|
||||
style="width: 300px; margin-right: 16px;"
|
||||
/>
|
||||
<a-button type="primary" @click="refreshData">刷新数据</a-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 概览卡片 -->
|
||||
<div class="overview-cards">
|
||||
<a-card class="card-item" hoverable>
|
||||
<div class="card-content">
|
||||
<div class="card-title">总用户数</div>
|
||||
<div class="card-value">{{ overview.totalUsers }}</div>
|
||||
</div>
|
||||
</a-card>
|
||||
<a-card class="card-item" hoverable>
|
||||
<div class="card-content">
|
||||
<div class="card-title">保险申请总数</div>
|
||||
<div class="card-value">{{ overview.totalApplications }}</div>
|
||||
</div>
|
||||
</a-card>
|
||||
<a-card class="card-item" hoverable>
|
||||
<div class="card-content">
|
||||
<div class="card-title">保单总数</div>
|
||||
<div class="card-value">{{ overview.totalPolicies }}</div>
|
||||
</div>
|
||||
</a-card>
|
||||
<a-card class="card-item" hoverable>
|
||||
<div class="card-content">
|
||||
<div class="card-title">理赔总数</div>
|
||||
<div class="card-value">{{ overview.totalClaims }}</div>
|
||||
</div>
|
||||
</a-card>
|
||||
</div>
|
||||
|
||||
<!-- 图表区域 -->
|
||||
<div class="charts-container">
|
||||
<!-- 保险类型分布 -->
|
||||
<a-card title="保险类型分布" class="chart-item">
|
||||
<div ref="typeDistributionChart" class="chart"></div>
|
||||
</a-card>
|
||||
|
||||
<!-- 申请状态分布 -->
|
||||
<a-card title="申请状态分布" class="chart-item">
|
||||
<div ref="statusDistributionChart" class="chart"></div>
|
||||
</a-card>
|
||||
|
||||
<!-- 趋势图 -->
|
||||
<a-card title="近7天业务趋势" class="chart-item full-width">
|
||||
<div ref="trendChart" class="chart"></div>
|
||||
</a-card>
|
||||
|
||||
<!-- 赔付统计 -->
|
||||
<a-card title="按保险类型赔付统计" class="chart-item full-width">
|
||||
<div ref="claimStatsChart" class="chart"></div>
|
||||
</a-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted } from 'vue';
|
||||
import * as echarts from 'echarts';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { dataWarehouseAPI } from '@/utils/api';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
// 数据状态
|
||||
const overview = ref({
|
||||
totalUsers: 0,
|
||||
totalApplications: 0,
|
||||
totalPolicies: 0,
|
||||
totalClaims: 0,
|
||||
activePolicies: 0,
|
||||
approvedClaims: 0,
|
||||
pendingClaims: 0
|
||||
});
|
||||
|
||||
// 正确初始化日期范围为 dayjs 对象
|
||||
const dateRange = ref([dayjs().subtract(7, 'day'), dayjs()]);
|
||||
const loading = ref(false);
|
||||
|
||||
// 图表引用
|
||||
const typeDistributionChart = ref(null);
|
||||
const statusDistributionChart = ref(null);
|
||||
const trendChart = ref(null);
|
||||
const claimStatsChart = ref(null);
|
||||
|
||||
// 图表实例
|
||||
let typeChartInstance = null;
|
||||
let statusChartInstance = null;
|
||||
let trendChartInstance = null;
|
||||
let claimChartInstance = null;
|
||||
|
||||
// 获取概览数据
|
||||
const fetchOverview = async () => {
|
||||
try {
|
||||
const result = await dataWarehouseAPI.getOverview();
|
||||
if (result.status === 'success') {
|
||||
overview.value = result.data;
|
||||
} else {
|
||||
message.error('获取概览数据失败');
|
||||
}
|
||||
} catch (error) {
|
||||
message.error('获取概览数据失败');
|
||||
console.error('获取概览数据错误:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 获取保险类型分布数据
|
||||
const fetchTypeDistribution = async () => {
|
||||
try {
|
||||
const result = await dataWarehouseAPI.getInsuranceTypeDistribution();
|
||||
if (result.status === 'success') {
|
||||
renderTypeDistributionChart(result.data);
|
||||
} else {
|
||||
message.error('获取保险类型分布数据失败');
|
||||
}
|
||||
} catch (error) {
|
||||
message.error('获取保险类型分布数据失败');
|
||||
console.error('获取保险类型分布数据错误:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 获取申请状态分布数据
|
||||
const fetchStatusDistribution = async () => {
|
||||
try {
|
||||
const result = await dataWarehouseAPI.getApplicationStatusDistribution();
|
||||
if (result.status === 'success') {
|
||||
renderStatusDistributionChart(result.data);
|
||||
} else {
|
||||
message.error('获取申请状态分布数据失败');
|
||||
}
|
||||
} catch (error) {
|
||||
message.error('获取申请状态分布数据失败');
|
||||
console.error('获取申请状态分布数据错误:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 获取趋势数据
|
||||
const fetchTrendData = async () => {
|
||||
try {
|
||||
const result = await dataWarehouseAPI.getTrendData();
|
||||
if (result.status === 'success') {
|
||||
renderTrendChart(result.data);
|
||||
} else {
|
||||
message.error('获取趋势数据失败');
|
||||
}
|
||||
} catch (error) {
|
||||
message.error('获取趋势数据失败');
|
||||
console.error('获取趋势数据错误:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 获取赔付统计数据
|
||||
const fetchClaimStats = async () => {
|
||||
try {
|
||||
const result = await dataWarehouseAPI.getClaimStats();
|
||||
if (result.status === 'success') {
|
||||
renderClaimStatsChart(result.data);
|
||||
} else {
|
||||
message.error('获取赔付统计数据失败');
|
||||
}
|
||||
} catch (error) {
|
||||
message.error('获取赔付统计数据失败');
|
||||
console.error('获取赔付统计数据错误:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 刷新所有数据
|
||||
const refreshData = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
await Promise.all([
|
||||
fetchOverview(),
|
||||
fetchTypeDistribution(),
|
||||
fetchStatusDistribution(),
|
||||
fetchTrendData(),
|
||||
fetchClaimStats()
|
||||
]);
|
||||
message.success('数据刷新成功');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 处理日期范围变化
|
||||
const handleDateChange = (dates) => {
|
||||
dateRange.value = dates;
|
||||
// 这里可以根据日期范围筛选数据
|
||||
// refreshData();
|
||||
};
|
||||
|
||||
// 渲染保险类型分布图表
|
||||
const renderTypeDistributionChart = (data) => {
|
||||
if (!typeChartInstance) {
|
||||
typeChartInstance = echarts.init(typeDistributionChart.value);
|
||||
}
|
||||
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{a} <br/>{b}: {c} ({d}%)'
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
left: 'left',
|
||||
data: data.map(item => item.name)
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '保险类型',
|
||||
type: 'pie',
|
||||
radius: '50%',
|
||||
center: ['50%', '50%'],
|
||||
data: data.map(item => ({ value: item.count, name: item.name })),
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
shadowBlur: 10,
|
||||
shadowOffsetX: 0,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.5)'
|
||||
}
|
||||
},
|
||||
label: {
|
||||
formatter: '{b}\n{c} ({d}%)'
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
typeChartInstance.setOption(option);
|
||||
};
|
||||
|
||||
// 渲染申请状态分布图表
|
||||
const renderStatusDistributionChart = (data) => {
|
||||
if (!statusChartInstance) {
|
||||
statusChartInstance = echarts.init(statusDistributionChart.value);
|
||||
}
|
||||
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{a} <br/>{b}: {c} ({d}%)'
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
left: 'left',
|
||||
data: data.map(item => item.name)
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '申请状态',
|
||||
type: 'pie',
|
||||
radius: '50%',
|
||||
center: ['50%', '50%'],
|
||||
data: data.map(item => ({ value: item.count, name: item.name })),
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
shadowBlur: 10,
|
||||
shadowOffsetX: 0,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.5)'
|
||||
}
|
||||
},
|
||||
label: {
|
||||
formatter: '{b}\n{c} ({d}%)'
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
statusChartInstance.setOption(option);
|
||||
};
|
||||
|
||||
// 渲染趋势图表
|
||||
const renderTrendChart = (data) => {
|
||||
if (!trendChartInstance) {
|
||||
trendChartInstance = echarts.init(trendChart.value);
|
||||
}
|
||||
|
||||
const dates = data.map(item => item.date);
|
||||
const newApplications = data.map(item => item.newApplications);
|
||||
const newPolicies = data.map(item => item.newPolicies);
|
||||
const newClaims = data.map(item => item.newClaims);
|
||||
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'cross',
|
||||
label: {
|
||||
backgroundColor: '#6a7985'
|
||||
}
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
data: ['新增申请', '新增保单', '新增理赔']
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: dates
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '新增申请',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
areaStyle: {},
|
||||
emphasis: {
|
||||
focus: 'series'
|
||||
},
|
||||
data: newApplications
|
||||
},
|
||||
{
|
||||
name: '新增保单',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
areaStyle: {},
|
||||
emphasis: {
|
||||
focus: 'series'
|
||||
},
|
||||
data: newPolicies
|
||||
},
|
||||
{
|
||||
name: '新增理赔',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
areaStyle: {},
|
||||
emphasis: {
|
||||
focus: 'series'
|
||||
},
|
||||
data: newClaims
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
trendChartInstance.setOption(option);
|
||||
};
|
||||
|
||||
// 渲染赔付统计图表
|
||||
const renderClaimStatsChart = (data) => {
|
||||
if (!claimChartInstance) {
|
||||
claimChartInstance = echarts.init(claimStatsChart.value);
|
||||
}
|
||||
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow'
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
data: ['赔付金额']
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: data.map(item => item.name),
|
||||
axisLabel: {
|
||||
rotate: 45
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
name: '金额(元)',
|
||||
axisLabel: {
|
||||
formatter: '{value} 元'
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '赔付金额',
|
||||
type: 'bar',
|
||||
data: data.map(item => ({
|
||||
value: item.totalAmount,
|
||||
label: {
|
||||
show: true,
|
||||
position: 'top',
|
||||
formatter: '{c} 元'
|
||||
}
|
||||
}))
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
claimChartInstance.setOption(option);
|
||||
};
|
||||
|
||||
// 处理窗口大小变化,重新调整图表
|
||||
const handleResize = () => {
|
||||
typeChartInstance?.resize();
|
||||
statusChartInstance?.resize();
|
||||
trendChartInstance?.resize();
|
||||
claimChartInstance?.resize();
|
||||
};
|
||||
|
||||
// 组件挂载时初始化
|
||||
onMounted(() => {
|
||||
refreshData();
|
||||
window.addEventListener('resize', handleResize);
|
||||
});
|
||||
|
||||
// 组件卸载时清理
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', handleResize);
|
||||
typeChartInstance?.dispose();
|
||||
statusChartInstance?.dispose();
|
||||
trendChartInstance?.dispose();
|
||||
claimChartInstance?.dispose();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.data-warehouse {
|
||||
padding: 20px;
|
||||
background-color: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.page-header h1 {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.filters {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.overview-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 16px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.card-item {
|
||||
height: 120px;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card-value {
|
||||
font-size: 28px;
|
||||
font-weight: 600;
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.charts-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.chart-item {
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
.chart-item.full-width {
|
||||
grid-column: span 2;
|
||||
}
|
||||
|
||||
.chart {
|
||||
width: 100%;
|
||||
height: calc(100% - 50px);
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
.overview-cards {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.charts-container {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.chart-item.full-width {
|
||||
grid-column: span 1;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.overview-cards {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.filters {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user