93 lines
2.8 KiB
Python
93 lines
2.8 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""
|
||
HTML渲染器
|
||
"""
|
||
|
||
from datetime import datetime
|
||
from pathlib import Path
|
||
import re
|
||
from decimal import Decimal
|
||
from typing import Any, Dict, Optional, Union, List
|
||
|
||
from jinja2 import Environment, FileSystemLoader
|
||
|
||
|
||
class HTMLRenderer:
|
||
"""
|
||
HTML渲染器,支持:
|
||
基于模板,根据数据字典渲染HTML文档
|
||
"""
|
||
|
||
def __init__(self, template_path: Path):
|
||
"""
|
||
初始化HTML渲染器
|
||
:param template_path: 模板路径
|
||
"""
|
||
# 实例化jinja2环境
|
||
self.environment = Environment(
|
||
loader=FileSystemLoader(searchpath=template_path.parent)
|
||
)
|
||
# 加载指定模板
|
||
self.template = self.environment.get_template(template_path.name)
|
||
|
||
def render(self, obj: Dict[str, Any], output_path: Path) -> None:
|
||
"""
|
||
根据数据字典渲染HTML文档
|
||
:param obj: 数据字典
|
||
:param output_path: HTML文档输出路径
|
||
:return: 无
|
||
"""
|
||
try:
|
||
with open(
|
||
file=output_path,
|
||
mode="w",
|
||
encoding="utf-8",
|
||
) as file:
|
||
file.write(self.template.render(obj=self._format(obj)))
|
||
# 在模板中需以obj获取键值
|
||
|
||
except Exception as exception:
|
||
print(f"根据数据字典渲染HTML文档发生异常:{str(exception)}")
|
||
|
||
def _format(
|
||
self,
|
||
input: Union[str, None, datetime, Decimal, List[Any], Dict[str, Any]],
|
||
format: Optional[str] = None,
|
||
) -> Any:
|
||
"""
|
||
格式化数据
|
||
:param input: 数据
|
||
:param format: 格式,默认为空值
|
||
:return: 格式化后的数据
|
||
"""
|
||
match input:
|
||
# 若为字典,则递归格式化
|
||
case dict():
|
||
for key, value in input.items():
|
||
# 若键值为datetime
|
||
if isinstance(value, datetime):
|
||
# 若键名后缀形如_time,则格式为"%Y-%m-%d %H:%M:%S",否则默认为"%Y-%m-%d"
|
||
if re.search(r"_time$", key):
|
||
format = r"%Y-%m-%d %H:%M:%S"
|
||
|
||
input[key] = self._format(value, format=format)
|
||
return input
|
||
|
||
# 若为列表,则递归格式化
|
||
case list():
|
||
for idx, item in enumerate(input):
|
||
input[idx] = self._format(item)
|
||
return input
|
||
|
||
case None:
|
||
return ""
|
||
|
||
case datetime():
|
||
# 若键值为datetime(9999, 12, 31),则返回字符串"长期"
|
||
if input == datetime(9999, 12, 31):
|
||
return "长期"
|
||
return input.strftime(format=(format or r"%Y-%m-%d"))
|
||
|
||
case _:
|
||
return input
|