为基础资料维护页面增加导入导出
This commit is contained in:
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user