fix: add defensive checks to BudgetChartAnalysis chart data

- Added null checks for overallStats.month/year in gauge charts
- Added null checks for burndown and year burndown charts
- Fixed BaseChart.vue template using undefined 'chartData' variable
- Changed :data="chartData" to :data="data" to use prop directly

Fixes console errors when viewing /budget-v2 page
Verified: 0 errors, only 1 harmless plugin warning

Refs: openspec/changes/migrate-remaining-echarts-to-chartjs
This commit is contained in:
SunCheng
2026-02-16 22:04:10 +08:00
parent 9921cd5fdf
commit d1737f162d
7 changed files with 144 additions and 2 deletions

View File

@@ -261,6 +261,19 @@ const formatMoney = (val) => {
// 月度仪表盘数据 // 月度仪表盘数据
const monthGaugeData = computed(() => { const monthGaugeData = computed(() => {
// 防御性检查:如果数据未加载,返回默认结构
if (!props.overallStats || !props.overallStats.month) {
return {
datasets: [{
data: [0, 100],
backgroundColor: [getCssVar('--chart-axis'), getCssVar('--chart-axis')],
borderWidth: 0,
circumference: 180,
rotation: 270
}]
}
}
const rate = parseFloat(props.overallStats.month.rate || 0) const rate = parseFloat(props.overallStats.month.rate || 0)
const isExpense = props.activeTab === BudgetCategory.Expense const isExpense = props.activeTab === BudgetCategory.Expense
@@ -329,6 +342,19 @@ const monthGaugeOptions = computed(() => {
// 年度仪表盘数据 // 年度仪表盘数据
const yearGaugeData = computed(() => { const yearGaugeData = computed(() => {
// 防御性检查:如果数据未加载,返回默认结构
if (!props.overallStats || !props.overallStats.year) {
return {
datasets: [{
data: [0, 100],
backgroundColor: [getCssVar('--chart-axis'), getCssVar('--chart-axis')],
borderWidth: 0,
circumference: 180,
rotation: 270
}]
}
}
const rate = parseFloat(props.overallStats.year.rate || 0) const rate = parseFloat(props.overallStats.year.rate || 0)
const isExpense = props.activeTab === BudgetCategory.Expense const isExpense = props.activeTab === BudgetCategory.Expense
@@ -493,6 +519,14 @@ const varianceChartOptions = computed(() => {
// 月度燃尽图数据 // 月度燃尽图数据
const burndownChartData = computed(() => { const burndownChartData = computed(() => {
// 防御性检查
if (!props.overallStats || !props.overallStats.month || !props.selectedDate) {
return {
labels: [],
datasets: []
}
}
const refDate = props.selectedDate const refDate = props.selectedDate
const year = refDate.getFullYear() const year = refDate.getFullYear()
const month = refDate.getMonth() const month = refDate.getMonth()
@@ -623,6 +657,14 @@ const burndownChartOptions = computed(() => {
// 年度燃尽图数据 // 年度燃尽图数据
const yearBurndownChartData = computed(() => { const yearBurndownChartData = computed(() => {
// 防御性检查
if (!props.overallStats || !props.overallStats.year || !props.selectedDate) {
return {
labels: [],
datasets: []
}
}
const refDate = props.selectedDate const refDate = props.selectedDate
const year = refDate.getFullYear() const year = refDate.getFullYear()

View File

@@ -5,7 +5,7 @@
<component <component
v-else v-else
:is="chartComponent" :is="chartComponent"
:data="chartData" :data="data"
:options="mergedOptions" :options="mergedOptions"
:plugins="chartPlugins" :plugins="chartPlugins"
@chart:render="onChartRender" @chart:render="onChartRender"

BIN
budget-page.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

BIN
budget-v2-fixed.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

2
null Normal file
View File

@@ -0,0 +1,2 @@
ERROR: Invalid argument/option - 'F:/'.
Type "TASKKILL /?" for usage.

View File

@@ -15,7 +15,7 @@
- [x] 2.7 创建 `chartOptions` computed 属性,使用 `getChartOptions()` - [x] 2.7 创建 `chartOptions` computed 属性,使用 `getChartOptions()`
- [x] 2.8 替换模板为 `<BaseChart type="line" :data="chartData" :options="chartOptions" />` - [x] 2.8 替换模板为 `<BaseChart type="line" :data="chartData" :options="chartOptions" />`
- [x] 2.9 删除 `onBeforeUnmount()` 中的 ECharts cleanup 代码 - [x] 2.9 删除 `onBeforeUnmount()` 中的 ECharts cleanup 代码
- [ ] 2.10 本地浏览器验证图表渲染正确Chrome DevTools - [x] 2.10 本地浏览器验证图表渲染正确Chrome DevTools
## 3. 迁移 DailyTrendChart.vue双系列折线图 ## 3. 迁移 DailyTrendChart.vue双系列折线图

98
warnings.txt Normal file
View File

@@ -0,0 +1,98 @@
Total messages: 12 (Errors: 1, Warnings: 8)
Returning 9 messages for level "warning"
[WARNING] [Vue warn]: Plugin has already been applied to target app. @ http://localhost:5173/node_modules/.vite/deps/chunk-TTLTGI2G.js?v=9b5e80e2:2194
[WARNING] [Vue warn]: Property "chartData" was accessed during render but is not defined on instance.
at <BaseChart type="doughnut" data= {datasets: Array(1)} options= {cutout: 75%, responsive: true, maintainAspectRatio: true, plugins: Object} ... >
at <BudgetChartAnalysis overall-stats= {month: Object, year: Object} budgets= [] active-tab=0 ... >
at <ExpenseBudgetContent key=0 budgets= [] stats= {month: Object, year: Object} ... >
at <VanPullRefresh modelValue=false onUpdate:modelValue=fn onRefresh=fn<onRefresh> >
at <VanConfigProvider theme="light" class="config-provider-full-height" >
at <BudgetV2View onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< undefined > key="budget-v2" >
at <KeepAlive include= [CalendarV2, StatisticsView, StatisticsV2View, BalanceView, BudgetV2View] max=8 >
at <RouterView >
at <VanConfigProvider theme="light" theme-vars= {navBarBackground: var(--bg-primary), navBarTextColor: var(--text-primary), cardBackground: var(--bg-secondary), cellBackground: var(--bg-secondary), background: var(--bg-primary)} class="app-provider" >
at <App> @ http://localhost:5173/node_modules/.vite/deps/chunk-TTLTGI2G.js?v=9b5e80e2:2194
[WARNING] [Vue warn]: Invalid prop: type check failed for prop "data". Expected Object, got Undefined
at <Anonymous key=2 data=undefined options= {responsive: true, maintainAspectRatio: true, animation: Object, plugins: Object, scales: Object} ... >
at <BaseChart type="doughnut" data= {datasets: Array(1)} options= {cutout: 75%, responsive: true, maintainAspectRatio: true, plugins: Object} ... >
at <BudgetChartAnalysis overall-stats= {month: Object, year: Object} budgets= [] active-tab=0 ... >
at <ExpenseBudgetContent key=0 budgets= [] stats= {month: Object, year: Object} ... >
at <VanPullRefresh modelValue=false onUpdate:modelValue=fn onRefresh=fn<onRefresh> >
at <VanConfigProvider theme="light" class="config-provider-full-height" >
at <BudgetV2View onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< undefined > key="budget-v2" >
at <KeepAlive include= [CalendarV2, StatisticsView, StatisticsV2View, BalanceView, BudgetV2View] max=8 >
at <RouterView >
at <VanConfigProvider theme="light" theme-vars= {navBarBackground: var(--bg-primary), navBarTextColor: var(--text-primary), cardBackground: var(--bg-secondary), cellBackground: var(--bg-secondary), background: var(--bg-primary)} class="app-provider" >
at <App> @ http://localhost:5173/node_modules/.vite/deps/chunk-TTLTGI2G.js?v=9b5e80e2:2194
[WARNING] [Vue warn]: Invalid prop: type check failed for prop "data". Expected Object, got Undefined
at <Anonymous ref=fn<reforwardRef> type="doughnut" data=undefined ... >
at <Anonymous key=2 data=undefined options= {responsive: true, maintainAspectRatio: true, animation: Object, plugins: Object, scales: Object} ... >
at <BaseChart type="doughnut" data= {datasets: Array(1)} options= {cutout: 75%, responsive: true, maintainAspectRatio: true, plugins: Object} ... >
at <BudgetChartAnalysis overall-stats= {month: Object, year: Object} budgets= [] active-tab=0 ... >
at <ExpenseBudgetContent key=0 budgets= [] stats= {month: Object, year: Object} ... >
at <VanPullRefresh modelValue=false onUpdate:modelValue=fn onRefresh=fn<onRefresh> >
at <VanConfigProvider theme="light" class="config-provider-full-height" >
at <BudgetV2View onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< undefined > key="budget-v2" >
at <KeepAlive include= [CalendarV2, StatisticsView, StatisticsV2View, BalanceView, BudgetV2View] max=8 >
at <RouterView >
at <VanConfigProvider theme="light" theme-vars= {navBarBackground: var(--bg-primary), navBarTextColor: var(--text-primary), cardBackground: var(--bg-secondary), cellBackground: var(--bg-secondary), background: var(--bg-primary)} class="app-provider" >
at <App> @ http://localhost:5173/node_modules/.vite/deps/chunk-TTLTGI2G.js?v=9b5e80e2:2194
[WARNING] [Vue warn]: Property "chartData" was accessed during render but is not defined on instance.
at <BaseChart type="doughnut" data= {datasets: Array(1)} options= {cutout: 75%, responsive: true, maintainAspectRatio: true, plugins: Object} ... >
at <BudgetChartAnalysis overall-stats= {month: Object, year: Object} budgets= [] active-tab=0 ... >
at <ExpenseBudgetContent key=0 budgets= [] stats= {month: Object, year: Object} ... >
at <VanPullRefresh modelValue=false onUpdate:modelValue=fn onRefresh=fn<onRefresh> >
at <VanConfigProvider theme="light" class="config-provider-full-height" >
at <BudgetV2View onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< undefined > key="budget-v2" >
at <KeepAlive include= [CalendarV2, StatisticsView, StatisticsV2View, BalanceView, BudgetV2View] max=8 >
at <RouterView >
at <VanConfigProvider theme="light" theme-vars= {navBarBackground: var(--bg-primary), navBarTextColor: var(--text-primary), cardBackground: var(--bg-secondary), cellBackground: var(--bg-secondary), background: var(--bg-primary)} class="app-provider" >
at <App> @ http://localhost:5173/node_modules/.vite/deps/chunk-TTLTGI2G.js?v=9b5e80e2:2194
[WARNING] [Vue warn]: Invalid prop: type check failed for prop "data". Expected Object, got Undefined
at <Anonymous key=2 data=undefined options= {responsive: true, maintainAspectRatio: true, animation: Object, plugins: Object, scales: Object} ... >
at <BaseChart type="doughnut" data= {datasets: Array(1)} options= {cutout: 75%, responsive: true, maintainAspectRatio: true, plugins: Object} ... >
at <BudgetChartAnalysis overall-stats= {month: Object, year: Object} budgets= [] active-tab=0 ... >
at <ExpenseBudgetContent key=0 budgets= [] stats= {month: Object, year: Object} ... >
at <VanPullRefresh modelValue=false onUpdate:modelValue=fn onRefresh=fn<onRefresh> >
at <VanConfigProvider theme="light" class="config-provider-full-height" >
at <BudgetV2View onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< undefined > key="budget-v2" >
at <KeepAlive include= [CalendarV2, StatisticsView, StatisticsV2View, BalanceView, BudgetV2View] max=8 >
at <RouterView >
at <VanConfigProvider theme="light" theme-vars= {navBarBackground: var(--bg-primary), navBarTextColor: var(--text-primary), cardBackground: var(--bg-secondary), cellBackground: var(--bg-secondary), background: var(--bg-primary)} class="app-provider" >
at <App> @ http://localhost:5173/node_modules/.vite/deps/chunk-TTLTGI2G.js?v=9b5e80e2:2194
[WARNING] [Vue warn]: Invalid prop: type check failed for prop "data". Expected Object, got Undefined
at <Anonymous ref=fn<reforwardRef> type="doughnut" data=undefined ... >
at <Anonymous key=2 data=undefined options= {responsive: true, maintainAspectRatio: true, animation: Object, plugins: Object, scales: Object} ... >
at <BaseChart type="doughnut" data= {datasets: Array(1)} options= {cutout: 75%, responsive: true, maintainAspectRatio: true, plugins: Object} ... >
at <BudgetChartAnalysis overall-stats= {month: Object, year: Object} budgets= [] active-tab=0 ... >
at <ExpenseBudgetContent key=0 budgets= [] stats= {month: Object, year: Object} ... >
at <VanPullRefresh modelValue=false onUpdate:modelValue=fn onRefresh=fn<onRefresh> >
at <VanConfigProvider theme="light" class="config-provider-full-height" >
at <BudgetV2View onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< undefined > key="budget-v2" >
at <KeepAlive include= [CalendarV2, StatisticsView, StatisticsV2View, BalanceView, BudgetV2View] max=8 >
at <RouterView >
at <VanConfigProvider theme="light" theme-vars= {navBarBackground: var(--bg-primary), navBarTextColor: var(--text-primary), cardBackground: var(--bg-secondary), cellBackground: var(--bg-secondary), background: var(--bg-primary)} class="app-provider" >
at <App> @ http://localhost:5173/node_modules/.vite/deps/chunk-TTLTGI2G.js?v=9b5e80e2:2194
[WARNING] [Vue warn]: Unhandled error during execution of mounted hook
at <Anonymous ref=fn<reforwardRef> type="doughnut" data=undefined ... >
at <Anonymous key=2 data=undefined options= {responsive: true, maintainAspectRatio: true, animation: Object, plugins: Object, scales: Object} ... >
at <BaseChart type="doughnut" data= {datasets: Array(1)} options= {cutout: 75%, responsive: true, maintainAspectRatio: true, plugins: Object} ... >
at <BudgetChartAnalysis overall-stats= {month: Object, year: Object} budgets= [] active-tab=0 ... >
at <ExpenseBudgetContent key=0 budgets= [] stats= {month: Object, year: Object} ... >
at <VanPullRefresh modelValue=false onUpdate:modelValue=fn onRefresh=fn<onRefresh> >
at <VanConfigProvider theme="light" class="config-provider-full-height" >
at <BudgetV2View onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > key="budget-v2" >
at <KeepAlive include= [CalendarV2, StatisticsView, StatisticsV2View, BalanceView, BudgetV2View] max=8 >
at <RouterView >
at <VanConfigProvider theme="light" theme-vars= {navBarBackground: var(--bg-primary), navBarTextColor: var(--text-primary), cardBackground: var(--bg-secondary), cellBackground: var(--bg-secondary), background: var(--bg-primary)} class="app-provider" >
at <App> @ http://localhost:5173/node_modules/.vite/deps/chunk-TTLTGI2G.js?v=9b5e80e2:2194
TypeError: Cannot read properties of undefined (reading 'labels')
at cloneData (http://localhost:5173/node_modules/.vite/deps/vue-chartjs.js?v=9b5e80e2:109:28)
at renderChart (http://localhost:5173/node_modules/.vite/deps/vue-chartjs.js?v=9b5e80e2:140:26)
at http://localhost:5173/node_modules/.vite/deps/chunk-TTLTGI2G.js?v=9b5e80e2:5221:40
at callWithErrorHandling (http://localhost:5173/node_modules/.vite/deps/chunk-TTLTGI2G.js?v=9b5e80e2:2342:19)
at callWithAsyncErrorHandling (http://localhost:5173/node_modules/.vite/deps/chunk-TTLTGI2G.js?v=9b5e80e2:2349:17)
at hook.__weh.hook.__weh (http://localhost:5173/node_modules/.vite/deps/chunk-TTLTGI2G.js?v=9b5e80e2:5201:19)
at flushPostFlushCbs (http://localhost:5173/node_modules/.vite/deps/chunk-TTLTGI2G.js?v=9b5e80e2:2527:28)
at flushJobs (http://localhost:5173/node_modules/.vite/deps/chunk-TTLTGI2G.js?v=9b5e80e2:2569:5)