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-11-15 18:01:55 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
904df342942336205f4c108d487c59533d565d86
904df342
1 parent
a12ac423
Optimize the Rendering Process
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
77 additions
and
6 deletions
ReportEngine/renderers/html_renderer.py
ReportEngine/renderers/html_renderer.py
View file @
904df34
...
...
@@ -1028,6 +1028,75 @@ class HTMLRenderer:
"""
return
f
'<div class="kpi-grid">{cards}</div>'
def
_merge_dicts
(
self
,
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
]
=
self
.
_merge_dicts
(
result
[
key
],
value
)
else
:
result
[
key
]
=
copy
.
deepcopy
(
value
)
return
result
def
_looks_like_chart_dataset
(
self
,
candidate
:
Any
)
->
bool
:
"""启发式判断对象是否包含Chart.js常见的labels/datasets结构"""
if
not
isinstance
(
candidate
,
dict
):
return
False
labels
=
candidate
.
get
(
"labels"
)
datasets
=
candidate
.
get
(
"datasets"
)
return
isinstance
(
labels
,
list
)
or
isinstance
(
datasets
,
list
)
def
_coerce_chart_data_structure
(
self
,
data
:
Dict
[
str
,
Any
])
->
Dict
[
str
,
Any
]:
"""
兼容LLM输出的Chart.js完整配置(含type/data/options)。
若data中嵌套一个真正的labels/datasets结构,则提取并返回该结构。
"""
if
not
isinstance
(
data
,
dict
):
return
{}
if
self
.
_looks_like_chart_dataset
(
data
):
return
data
for
key
in
(
"data"
,
"chartData"
,
"payload"
):
nested
=
data
.
get
(
key
)
if
self
.
_looks_like_chart_dataset
(
nested
):
return
copy
.
deepcopy
(
nested
)
return
data
def
_prepare_widget_payload
(
self
,
block
:
Dict
[
str
,
Any
]
)
->
tuple
[
Dict
[
str
,
Any
],
Dict
[
str
,
Any
]]:
"""
预处理widget数据,兼容部分block将Chart.js配置写入data字段的情况。
返回:
tuple(props, data): 归一化后的props与chart数据
"""
props
=
copy
.
deepcopy
(
block
.
get
(
"props"
)
or
{})
raw_data
=
block
.
get
(
"data"
)
data_copy
=
copy
.
deepcopy
(
raw_data
)
if
isinstance
(
raw_data
,
dict
)
else
raw_data
widget_type
=
block
.
get
(
"widgetType"
)
or
""
chart_like
=
isinstance
(
widget_type
,
str
)
and
widget_type
.
startswith
(
"chart.js"
)
if
chart_like
and
isinstance
(
data_copy
,
dict
):
inline_options
=
data_copy
.
pop
(
"options"
,
None
)
inline_type
=
data_copy
.
pop
(
"type"
,
None
)
normalized_data
=
self
.
_coerce_chart_data_structure
(
data_copy
)
if
isinstance
(
inline_options
,
dict
):
props
[
"options"
]
=
self
.
_merge_dicts
(
props
.
get
(
"options"
),
inline_options
)
if
isinstance
(
inline_type
,
str
)
and
inline_type
and
not
props
.
get
(
"type"
):
props
[
"type"
]
=
inline_type
elif
isinstance
(
data_copy
,
dict
):
normalized_data
=
data_copy
else
:
normalized_data
=
{}
return
props
,
normalized_data
def
_render_widget
(
self
,
block
:
Dict
[
str
,
Any
])
->
str
:
"""
渲染Chart.js等交互组件的占位容器,并记录配置JSON。
...
...
@@ -1042,11 +1111,12 @@ class HTMLRenderer:
canvas_id
=
f
"chart-{self.chart_counter}"
config_id
=
f
"chart-config-{self.chart_counter}"
props
,
normalized_data
=
self
.
_prepare_widget_payload
(
block
)
payload
=
{
"widgetId"
:
block
.
get
(
"widgetId"
),
"widgetType"
:
block
.
get
(
"widgetType"
),
"props"
:
block
.
get
(
"props"
,
{}),
"data"
:
block
.
get
(
"data"
,
{}),
"props"
:
props
,
"data"
:
normalized_data
,
"dataRef"
:
block
.
get
(
"dataRef"
),
}
config_json
=
json
.
dumps
(
payload
,
ensure_ascii
=
False
)
.
replace
(
"</"
,
"<
\\
/"
)
...
...
@@ -1054,9 +1124,9 @@ class HTMLRenderer:
f
'<script type="application/json" id="{config_id}">{config_json}</script>'
)
title
=
block
.
get
(
"props"
,
{})
.
get
(
"title"
)
title
=
props
.
get
(
"title"
)
title_html
=
f
'<div class="chart-title">{self._escape_html(title)}</div>'
if
title
else
""
fallback_html
=
self
.
_render_widget_fallback
(
block
)
fallback_html
=
self
.
_render_widget_fallback
(
normalized_data
)
return
f
"""
<div class="chart-card">
{title_html}
...
...
@@ -1067,9 +1137,10 @@ class HTMLRenderer:
</div>
"""
def
_render_widget_fallback
(
self
,
block
:
Dict
[
str
,
Any
])
->
str
:
def
_render_widget_fallback
(
self
,
data
:
Dict
[
str
,
Any
])
->
str
:
"""渲染图表数据的文本兜底视图,避免Chart.js加载失败时出现空白"""
data
=
block
.
get
(
"data"
)
or
{}
if
not
isinstance
(
data
,
dict
):
return
""
labels
=
data
.
get
(
"labels"
)
or
[]
datasets
=
data
.
get
(
"datasets"
)
or
[]
if
not
labels
or
not
datasets
:
...
...
Please
register
or
login
to post a comment