fix: 财务数据可视化图表
This commit is contained in:
@@ -65,7 +65,7 @@ const chartTabs: TabOption[] = [
|
||||
|
||||
<template>
|
||||
<div class="p-5">
|
||||
<AnalysisOverview :items="overviewItems" />
|
||||
<AnalysisOverview :items="overviewItems" :my-card="false" />
|
||||
<AnalysisChartsTabs :tabs="chartTabs" class="mt-5">
|
||||
<template #trends>
|
||||
<AnalyticsTrends />
|
||||
|
||||
@@ -40,15 +40,15 @@ const [FormModal, formModalApi] = useVbenModal({
|
||||
connectedComponent: FormModalDemo,
|
||||
});
|
||||
|
||||
// const showModal = (data = {}, isUpdate = false) => {
|
||||
// formModalApi.setData({
|
||||
// // 表单值
|
||||
// values: data,
|
||||
// update: isUpdate,
|
||||
// gridApi,
|
||||
// });
|
||||
// formModalApi.open();
|
||||
// };
|
||||
const showModal = (data = {}, isUpdate = false) => {
|
||||
formModalApi.setData({
|
||||
// 表单值
|
||||
values: data,
|
||||
update: isUpdate,
|
||||
gridApi,
|
||||
});
|
||||
formModalApi.open();
|
||||
};
|
||||
|
||||
const openPcWindows = (id: number) => {
|
||||
openPcWindowsApi(id).then(() => {
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
const prefix = 'visualization-chart/';
|
||||
/**
|
||||
* 诊所对账单
|
||||
* @param data
|
||||
*/
|
||||
export async function getReconciliationChartApi(data: any) {
|
||||
return requestClient.get<any>(`${prefix}curve-chart`, { params: data });
|
||||
}
|
||||
279
apps/web-antd/src/views/finance/visualization-chart/index.vue
Normal file
279
apps/web-antd/src/views/finance/visualization-chart/index.vue
Normal file
@@ -0,0 +1,279 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { Page } from '@vben/common-ui';
|
||||
import {
|
||||
EchartsUI,
|
||||
type EchartsUIType,
|
||||
useEcharts,
|
||||
} from '@vben/plugins/echarts';
|
||||
|
||||
import { Button, Card, RangePicker } from 'ant-design-vue';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import { getReconciliationChartApi } from '#/views/finance/visualization-chart/api';
|
||||
|
||||
// 图表相关
|
||||
const lineChartRef = ref<EchartsUIType>();
|
||||
const pieChartRef = ref<EchartsUIType>();
|
||||
const mapChartRef = ref<EchartsUIType>();
|
||||
|
||||
const { renderEcharts: renderLine } = useEcharts(lineChartRef);
|
||||
const { renderEcharts: renderPie } = useEcharts(pieChartRef);
|
||||
const { renderEcharts: renderMap } = useEcharts(mapChartRef);
|
||||
|
||||
// 模拟数据(替换为真实数据接口)
|
||||
const chartData = ref();
|
||||
|
||||
// 初始化图表配置
|
||||
const initCharts = () => {
|
||||
// 折线图
|
||||
renderLine({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
formatter: '{b}<br/>{a}: ¥{c}',
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: chartData.value.line.month,
|
||||
axisLabel: { rotate: 45 },
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLabel: { formatter: '¥{value}' },
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: chartData.value.line.legend[0],
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
data: chartData.value.line.sale_money.map(Number),
|
||||
areaStyle: {
|
||||
color: {
|
||||
type: 'linear',
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [
|
||||
{ offset: 0, color: 'rgba(58,77,233,0.8)' },
|
||||
{ offset: 1, color: 'rgba(58,77,233,0.1)' },
|
||||
],
|
||||
},
|
||||
},
|
||||
lineStyle: { width: 3, color: '#3a4de9' },
|
||||
itemStyle: { color: '#3a4de9' },
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// 饼图
|
||||
renderPie({
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{b}: ¥{c} ({d}%)',
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
radius: ['40%', '70%'],
|
||||
data: chartData.value.drug.data.map((item) => ({
|
||||
name: item.name,
|
||||
value: Number.parseFloat(item.value),
|
||||
})),
|
||||
itemStyle: {
|
||||
borderRadius: 5,
|
||||
borderColor: '#fff',
|
||||
borderWidth: 2,
|
||||
},
|
||||
label: {
|
||||
formatter: '{b|{b}}\n{hr|}\n¥{d|{c}}',
|
||||
rich: {
|
||||
b: { fontSize: 14, lineHeight: 20 },
|
||||
hr: {
|
||||
borderColor: '#a8a8a8',
|
||||
width: '100%',
|
||||
borderWidth: 1,
|
||||
height: 0,
|
||||
},
|
||||
d: { color: '#4c4c4c', fontSize: 12, padding: [5, 0] },
|
||||
},
|
||||
},
|
||||
color: ['#36c6d9', '#659be0'],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// 地图(这里使用柱状图替代)
|
||||
renderMap({
|
||||
tooltip: { trigger: 'item', formatter: '¥{c}' },
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: chartData.value.address.address,
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLabel: { formatter: '¥{value}' },
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'bar',
|
||||
data: chartData.value.address.money.map(Number),
|
||||
itemStyle: {
|
||||
color: {
|
||||
type: 'linear',
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [
|
||||
{ offset: 0, color: '#36c6d9' },
|
||||
{ offset: 1, color: '#659be0' },
|
||||
],
|
||||
},
|
||||
borderRadius: [5, 5, 0, 0],
|
||||
},
|
||||
barWidth: '60%',
|
||||
},
|
||||
],
|
||||
});
|
||||
};
|
||||
|
||||
// onMounted(() => {
|
||||
// // initCharts();
|
||||
// });
|
||||
|
||||
// 时间选择器相关
|
||||
const searchTime = ref([dayjs().startOf('month'), dayjs()]);
|
||||
const handleTimeChange = (dates: [dayjs.Dayjs, dayjs.Dayjs]) => {
|
||||
console.log('时间范围变化:', dates);
|
||||
// 这里可以添加数据更新逻辑
|
||||
getData();
|
||||
};
|
||||
|
||||
const getData = () => {
|
||||
getReconciliationChartApi({
|
||||
search_time: searchTime.value,
|
||||
}).then((res) => {
|
||||
chartData.value = res;
|
||||
initCharts();
|
||||
});
|
||||
};
|
||||
|
||||
const reload = () => {
|
||||
searchTime.value = [dayjs().startOf('month'), dayjs()]
|
||||
getData();
|
||||
}
|
||||
getData();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page>
|
||||
<!-- 搜索区域 -->
|
||||
<div class="search-container">
|
||||
<RangePicker
|
||||
v-model:value="searchTime"
|
||||
style="width: 300px"
|
||||
@change="handleTimeChange"
|
||||
/>
|
||||
<Button type="link" @click="getData">刷新</Button>
|
||||
<Button type="link" @click="reload">重置</Button>
|
||||
</div>
|
||||
|
||||
<!-- 图表容器 -->
|
||||
<div class="charts-grid">
|
||||
<div class="chart-card">
|
||||
<!-- 总金额展示 -->
|
||||
<!-- <div class="total-money">-->
|
||||
<!-- <span>总销售金额:</span>-->
|
||||
<!-- </div>-->
|
||||
<Card title="每日销售趋势">
|
||||
<template #extra>
|
||||
<div class="amount">
|
||||
总销售金额:¥{{ chartData?.total_money || 0 }}
|
||||
</div>
|
||||
</template>
|
||||
<EchartsUI ref="lineChartRef" class="chart" />
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 图表容器 -->
|
||||
<div class="charts-grid">
|
||||
<div class="chart-card">
|
||||
<Card title="药品销售占比">
|
||||
<EchartsUI ref="pieChartRef" class="chart" />
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<div class="chart-card">
|
||||
<Card title="地区销售分布">
|
||||
<EchartsUI ref="mapChartRef" class="chart" />
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</Page>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.search-container {
|
||||
padding: 16px;
|
||||
margin-bottom: 16px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.total-money {
|
||||
padding: 24px;
|
||||
margin-bottom: 16px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.total-money h3 {
|
||||
color: #666;
|
||||
margin-bottom: 8px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.amount {
|
||||
color: #3a4de9;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.charts-grid {
|
||||
display: grid;
|
||||
gap: 16px;
|
||||
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
|
||||
}
|
||||
|
||||
.chart-card {
|
||||
padding: 16px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.chart-card h4 {
|
||||
margin: 0 0 12px 0;
|
||||
color: #333;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.chart {
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.charts-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.chart {
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.amount {
|
||||
font-size: 24px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user