为基础资料维护页面增加导入导出

This commit is contained in:
2026-10-09 21:13:43 +08:00
parent a62803ccf0
commit a8af1f542b
20 changed files with 2134 additions and 15 deletions
@@ -102,3 +102,47 @@ class ExcelUtil:
excel_data = file.getvalue()
return excel_data
@classmethod
def read_text_table(cls, contents: bytes) -> tuple[list[str], list[tuple[int, dict[str, str]]]]:
"""按文本读取首个工作表,保留 Excel 行号,避免编码被当成数字。"""
from openpyxl import load_workbook
try:
workbook = load_workbook(io.BytesIO(contents), data_only=False, read_only=True)
except Exception as exc:
raise ValueError('导入文件无法读取,请上传 xls 或 xlsx 模板') from exc
try:
worksheet = workbook.active
rows = worksheet.iter_rows(values_only=True)
try:
header_row = next(rows)
except StopIteration as exc:
raise ValueError('导入文件没有表头') from exc
headers = [cls._cell_text(cell) for cell in header_row]
while headers and headers[-1] == '':
headers.pop()
parsed_rows: list[tuple[int, dict[str, str]]] = []
for offset, row in enumerate(rows, start=2):
values = [cls._cell_text(row[index] if index < len(row) else None) for index in range(len(headers))]
if not any(values):
continue
parsed_rows.append((offset, dict(zip(headers, values, strict=True))))
return headers, parsed_rows
finally:
workbook.close()
@staticmethod
def _cell_text(value: object) -> str:
"""把单元格归一成去掉首尾空白的文本。"""
if value is None:
return ''
if isinstance(value, bool):
return '1' if value else '0'
if isinstance(value, int):
return str(value)
if isinstance(value, float):
if value.is_integer():
return str(int(value))
return format(value, 'f').rstrip('0').rstrip('.')
return str(value).strip()