147 lines
4.5 KiB
Python
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())
|