Files
shanxia2.0/web-admin/scripts/add-list-index-columns.py
T
2026-08-23 09:47:38 +08:00

147 lines
4.5 KiB
Python

#!/usr/bin/env python3
"""为 web-admin 中缺少序号的 el-table 批量插入序号列。"""
from __future__ import annotations
import re
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1] / "src"
SKIP_FILES = {
ROOT / "components/bx/base/BaseTable.vue",
}
def find_table_spans(text: str) -> list[tuple[int, int]]:
spans: list[tuple[int, int]] = []
for m in re.finditer(r"<el-table(?:\s|>)", text):
start = m.start()
end_m = re.search(r"</el-table>", text[start:])
if not end_m:
continue
spans.append((start, start + end_m.end()))
return spans
def extract_first_column(block: str) -> tuple[int, int, str] | None:
table_open = re.search(r"<el-table\b[^>]*>", block)
if not table_open:
return None
pos = table_open.end()
m = re.search(r"(\s*)<el-table-column\b", block[pos:])
if not m:
return None
col_start = pos + m.start() + len(m.group(1))
rest = block[col_start:]
self_close = re.match(r"(<el-table-column\b[^>]*?/>)", rest, re.DOTALL)
if self_close:
col_end = col_start + len(self_close.group(1))
return col_start, col_end, block[col_start:col_end]
open_end = rest.find(">")
if open_end == -1:
return None
close = rest.find("</el-table-column>", open_end)
if close == -1:
return None
col_end = col_start + close + len("</el-table-column>")
return col_start, col_end, block[col_start:col_end]
def leading_indent(block: str, col_start: int) -> str:
line_start = block.rfind("\n", 0, col_start) + 1
return re.match(r"[ \t]*", block[line_start:col_start]).group(0)
def build_index_column(indent: str, paginated: bool) -> str:
if paginated:
return (
f"{indent}<el-table-column\n"
f"{indent} type=\"index\"\n"
f"{indent} label=\"序号\"\n"
f"{indent} width=\"68\"\n"
f"{indent} align=\"center\"\n"
f"{indent} header-align=\"center\"\n"
f"{indent} :index=\"(index) => (pagination.page - 1) * pagination.pageSize + index + 1\"\n"
f"{indent}/>"
)
return (
f'{indent}<el-table-column type="index" label="序号" width="68" '
f'align="center" header-align="center" />'
)
def should_use_pagination(block: str, file_text: str) -> bool:
if "pagination.page" not in file_text:
return False
table_open = re.search(r"<el-table\b[^>]*>", block)
if not table_open:
return False
opening = table_open.group(0)
if 'size="small"' in opening or "size='small'" in opening:
return False
if "sub-table" in opening:
return False
return True
def insert_index_into_block(block: str, file_text: str) -> str | None:
if 'type="index"' in block or "type='index'" in block:
return None
first = extract_first_column(block)
if not first:
return None
col_start, col_end, first_col = first
indent = leading_indent(block, col_start)
paginated = should_use_pagination(block, file_text)
index_col = build_index_column(indent, paginated)
is_select = re.search(r'type="(selection|radio)"', first_col) is not None
if is_select:
insert_at = col_end
new_block = block[:insert_at] + "\n" + index_col + block[insert_at:]
else:
line_start = block.rfind("\n", 0, col_start) + 1
new_block = block[:line_start] + index_col + "\n" + block[line_start:]
return new_block
def process_file(path: Path) -> bool:
if path in SKIP_FILES:
return False
text = path.read_text(encoding="utf-8")
if not re.search(r"<el-table(?:\s|>)", text):
return False
spans = find_table_spans(text)
if not spans:
return False
changed = False
offset = 0
for start, end in spans:
start += offset
end += offset
block = text[start:end]
new_block = insert_index_into_block(block, text)
if not new_block:
continue
text = text[:start] + new_block + text[end:]
offset += len(new_block) - len(block)
changed = True
if changed:
path.write_text(text, encoding="utf-8")
return changed
def main() -> int:
changed_files: list[str] = []
for path in sorted(ROOT.rglob("*.vue")):
if process_file(path):
changed_files.append(str(path.relative_to(ROOT.parents[0])))
print(f"Updated {len(changed_files)} files")
for f in changed_files:
print(f" {f}")
return 0
if __name__ == "__main__":
sys.exit(main())