feat: v1.2 数据可视化与统计增强
新增功能: - uCharts 集成,支持环形图和折线图 - 统计页分类占比环形图 - 统计页每日趋势折线图 - 统计页增加最大单笔和对比上月指标 - 首页今日支出卡片 组件: - ChartWrapper 通用图表组件(支持 pie/line/column) - 支持 H5 和微信小程序双端 依赖: - 新增 @qiun/ucharts 图表库
This commit is contained in:
93
client/src/components/ChartWrapper/ChartWrapper.vue
Normal file
93
client/src/components/ChartWrapper/ChartWrapper.vue
Normal file
@@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<view class="chart-wrap">
|
||||
<canvas
|
||||
:canvas-id="canvasId"
|
||||
:id="canvasId"
|
||||
class="chart-canvas"
|
||||
:style="{ width: width + 'rpx', height: height + 'rpx' }"
|
||||
@tap="onTap"
|
||||
></canvas>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, watch, nextTick } from 'vue'
|
||||
// @ts-ignore
|
||||
import uCharts from '@qiun/ucharts/u-charts.min.js'
|
||||
|
||||
const props = defineProps<{
|
||||
canvasId: string
|
||||
type: 'pie' | 'line' | 'column'
|
||||
chartData: any
|
||||
width?: number
|
||||
height?: number
|
||||
}>()
|
||||
|
||||
const emit = defineEmits(['tap'])
|
||||
|
||||
let chartInstance: any = null
|
||||
|
||||
function drawChart() {
|
||||
if (!props.chartData) return
|
||||
|
||||
const query = uni.createSelectorQuery().in(getCurrentInstance()?.proxy)
|
||||
query.select(`#${props.canvasId}`)
|
||||
.fields({ node: true, size: true })
|
||||
.exec((res) => {
|
||||
if (!res[0]) return
|
||||
|
||||
const canvas = res[0].node
|
||||
const ctx = canvas.getContext('2d')
|
||||
|
||||
const dpr = uni.getSystemInfoSync().pixelRatio
|
||||
canvas.width = res[0].width * dpr
|
||||
canvas.height = res[0].height * dpr
|
||||
ctx.scale(dpr, dpr)
|
||||
|
||||
const config: any = {
|
||||
context: ctx,
|
||||
canvas2d: true,
|
||||
pixelRatio: dpr,
|
||||
width: res[0].width,
|
||||
height: res[0].height,
|
||||
animation: true,
|
||||
background: '#FFFFFF',
|
||||
padding: [15, 15, 15, 15],
|
||||
...props.chartData
|
||||
}
|
||||
|
||||
chartInstance = new uCharts(config)
|
||||
})
|
||||
}
|
||||
|
||||
import { getCurrentInstance } from 'vue'
|
||||
|
||||
function onTap(e: any) {
|
||||
chartInstance?.touchLegend(e)
|
||||
emit('tap', e)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
setTimeout(drawChart, 100)
|
||||
})
|
||||
})
|
||||
|
||||
watch(() => props.chartData, () => {
|
||||
nextTick(() => {
|
||||
setTimeout(drawChart, 100)
|
||||
})
|
||||
}, { deep: true })
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.chart-wrap {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.chart-canvas {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user