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:
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -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
BIN
budget-page.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 81 KiB |
BIN
budget-v2-fixed.png
Normal file
BIN
budget-v2-fixed.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 167 KiB |
2
null
Normal file
2
null
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ERROR: Invalid argument/option - 'F:/'.
|
||||||
|
Type "TASKKILL /?" for usage.
|
||||||
@@ -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
98
warnings.txt
Normal 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)
|
||||||
Reference in New Issue
Block a user