Toggle navigation
Toggle navigation
This project
Loading...
Sign in
万朱浩
/
Venue-Ops
Go to a project
Toggle navigation
Projects
Groups
Snippets
Help
Toggle navigation pinning
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Authored by
马一丁
2025-12-16 12:55:51 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
2a6c3a8628db59275efc8d60981ffa647cec071a
2a6c3a86
1 parent
786fec57
Incomplete chart normalization in "ChartReviewService" causes missing critical fields
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
73 additions
and
8 deletions
ReportEngine/utils/chart_review_service.py
ReportEngine/utils/chart_review_service.py
View file @
2a6c3a8
...
...
@@ -297,30 +297,58 @@ class ChartReviewService:
chapter_context
:
Dict
[
str
,
Any
]
|
None
=
None
)
->
None
:
"""
规范化图表数据,从章节上下文补充缺失数据。
规范化图表数据,补全缺失字段(如props、scales、datasets),提升容错性。
与 HTMLRenderer._normalize_chart_block() 保持一致:
- 确保 props 存在
- 将顶层 scales 合并进 props.options
- 确保 data 存在
- 尝试使用章节级 data 作为兜底
- 自动生成 labels
"""
if
not
isinstance
(
block
,
dict
):
return
if
block
.
get
(
"type"
)
!=
"widget"
:
return
widget_type
=
block
.
get
(
"widgetType"
,
""
)
if
not
(
isinstance
(
widget_type
,
str
)
and
widget_type
.
startswith
(
"chart.js"
)):
return
# 确保 props 存在
props
=
block
.
get
(
"props"
)
if
not
isinstance
(
props
,
dict
):
block
[
"props"
]
=
{}
props
=
block
[
"props"
]
# 将顶层 scales 合并进 options,避免配置丢失
scales
=
block
.
get
(
"scales"
)
if
isinstance
(
scales
,
dict
):
options
=
props
.
get
(
"options"
)
if
isinstance
(
props
.
get
(
"options"
),
dict
)
else
{}
props
[
"options"
]
=
self
.
_merge_dicts
(
options
,
{
"scales"
:
scales
})
# 确保 data 存在
data
=
block
.
get
(
"data"
)
if
not
isinstance
(
data
,
dict
):
return
data
=
{}
block
[
"data"
]
=
data
# 尝试从章节上下文补充 datasets
datasets
=
data
.
get
(
"datasets"
)
if
not
datasets
or
(
isinstance
(
datasets
,
list
)
and
len
(
datasets
)
==
0
):
if
isinstance
(
chapter_context
,
dict
):
chapter_data
=
chapter_context
.
get
(
"data"
)
# 如果 datasets 为空,尝试使用章节级 data 填充
if
chapter_context
and
self
.
_is_chart_data_empty
(
data
):
chapter_data
=
chapter_context
.
get
(
"data"
)
if
isinstance
(
chapter_context
,
dict
)
else
None
if
isinstance
(
chapter_data
,
dict
):
fallback_ds
=
chapter_data
.
get
(
"datasets"
)
if
isinstance
(
fallback_ds
,
list
)
and
len
(
fallback_ds
)
>
0
:
merged_data
=
copy
.
deepcopy
(
data
)
merged_data
[
"datasets"
]
=
copy
.
deepcopy
(
fallback_ds
)
if
not
merged_data
.
get
(
"labels"
)
and
isinstance
(
chapter_data
.
get
(
"labels"
),
list
):
merged_data
[
"labels"
]
=
copy
.
deepcopy
(
chapter_data
[
"labels"
])
block
[
"data"
]
=
merged_data
#
如果缺少 labels 且数据点包含 x 值,自动生成
#
若仍缺少 labels 且数据点包含 x 值,自动生成便于 fallback 和坐标刻度
data_ref
=
block
.
get
(
"data"
)
if
isinstance
(
data_ref
,
dict
)
and
not
data_ref
.
get
(
"labels"
):
datasets_ref
=
data_ref
.
get
(
"datasets"
)
...
...
@@ -335,9 +363,46 @@ class ChartReviewService:
else
:
label_text
=
f
"点{idx + 1}"
labels_from_data
.
append
(
str
(
label_text
))
if
labels_from_data
:
data_ref
[
"labels"
]
=
labels_from_data
@staticmethod
def
_is_chart_data_empty
(
data
:
Dict
[
str
,
Any
]
|
None
)
->
bool
:
"""检查图表数据是否为空或缺少有效 datasets"""
if
not
isinstance
(
data
,
dict
):
return
True
datasets
=
data
.
get
(
"datasets"
)
if
not
isinstance
(
datasets
,
list
)
or
len
(
datasets
)
==
0
:
return
True
for
ds
in
datasets
:
if
not
isinstance
(
ds
,
dict
):
continue
series
=
ds
.
get
(
"data"
)
if
isinstance
(
series
,
list
)
and
len
(
series
)
>
0
:
return
False
return
True
@staticmethod
def
_merge_dicts
(
base
:
Dict
[
str
,
Any
]
|
None
,
override
:
Dict
[
str
,
Any
]
|
None
)
->
Dict
[
str
,
Any
]:
"""
递归合并两个字典,override 覆盖 base,均为新副本,避免副作用。
"""
result
=
copy
.
deepcopy
(
base
)
if
isinstance
(
base
,
dict
)
else
{}
if
not
isinstance
(
override
,
dict
):
return
result
for
key
,
value
in
override
.
items
():
if
isinstance
(
value
,
dict
)
and
isinstance
(
result
.
get
(
key
),
dict
):
result
[
key
]
=
ChartReviewService
.
_merge_dicts
(
result
[
key
],
value
)
else
:
result
[
key
]
=
copy
.
deepcopy
(
value
)
return
result
def
_format_error_reason
(
self
,
validation_result
:
ValidationResult
|
None
)
->
str
:
"""格式化错误原因"""
if
not
validation_result
:
...
...
Please
register
or
login
to post a comment