187 lines
5.6 KiB
Python
187 lines
5.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Add ListToolbarEndActions (refresh-only) to list pages missing it."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[1] / "src" / "views"
|
|
|
|
REFRESH_HANDLERS = [
|
|
"fetchData",
|
|
"loadData",
|
|
"getList",
|
|
"handleQuery",
|
|
"handleSearch",
|
|
"loadList",
|
|
"refresh",
|
|
"loadWfDef",
|
|
"refreshPending",
|
|
]
|
|
|
|
TOOLBAR_SNIPPET = """
|
|
<ListToolbarEndActions :loading="loading" @refresh="{handler}" />
|
|
"""
|
|
|
|
IMPORT_COMPONENT = "import ListToolbarEndActions from '@/components/business/list-toolbar-end-actions/index.vue'\n"
|
|
|
|
TARGETS = [
|
|
"system/role/index.vue",
|
|
"system/post/index.vue",
|
|
"system/tenant/index.vue",
|
|
"system/site/index.vue",
|
|
"system/dept/index.vue",
|
|
"system/menu/index.vue",
|
|
"system/operlog/index.vue",
|
|
"system/leave/index.vue",
|
|
"system/dict/index.vue",
|
|
"system/workflow/process/index.vue",
|
|
"system/workflow/task-pending/index.vue",
|
|
"system/workflow/task-completed/index.vue",
|
|
"system/workflow/my-applications/index.vue",
|
|
"crm/product-category/index.vue",
|
|
"crm/contract/approval/index.vue",
|
|
"crm/contract/template/index.vue",
|
|
"crm/contract/change/index.vue",
|
|
"crm/customer/pool/RuleIndex.vue",
|
|
"pl/vehicle-maintenance-apply/index.vue",
|
|
"pl/vehicle-maintenance-process/index.vue",
|
|
"pl/vehicle-recharge-apply/index.vue",
|
|
"pl/vehicle-recharge-record/index.vue",
|
|
"pl/vehicle-urea-apply/index.vue",
|
|
"pl/vehicle-urea-disburse/index.vue",
|
|
"pl/inventory/document-reminder.vue",
|
|
"pl/inventory/ledger.vue",
|
|
"bx/expense-item/index.vue",
|
|
"bx/advance/apply/index.vue",
|
|
"bx/reimburse/apply/index.vue",
|
|
"bx/view/todo/index.vue",
|
|
"pl/vehicle/index.vue",
|
|
"pl/self-vehicle/index.vue",
|
|
"pl/plan/index.vue",
|
|
"pl/plan-archive/index.vue",
|
|
"pl/plan-cert/index.vue",
|
|
"demo/product/index.vue",
|
|
"bx/advance/approve/index.vue",
|
|
"bx/advance/issue/index.vue",
|
|
"bx/reimburse/approve/index.vue",
|
|
"bx/payment/index.vue",
|
|
"bx/workflow/advance/index.vue",
|
|
"bx/workflow/reimburse/index.vue",
|
|
"pl/freight/components/UnsettledPlanPanel.vue",
|
|
"pl/freight/components/SettlementBillPanel.vue",
|
|
"pl/freight/components/DisbursePanel.vue",
|
|
"pl/freight/components/ApprovalPendingPanel.vue",
|
|
"pl/freight/components/ApprovalDonePanel.vue",
|
|
"pl/freight/components/SettledPanel.vue",
|
|
]
|
|
|
|
|
|
def detect_refresh_handler(content: str) -> str | None:
|
|
for name in REFRESH_HANDLERS:
|
|
if re.search(rf"\b(?:async\s+)?function\s+{name}\s*\(", content):
|
|
return name
|
|
if re.search(rf"\bconst\s+{name}\s*=", content):
|
|
return name
|
|
return None
|
|
|
|
|
|
def has_loading_ref(content: str) -> bool:
|
|
if re.search(r"\bconst\s+loading\s*=\s*ref\(", content):
|
|
return True
|
|
if re.search(r"\{[^}]*\bloading\b[^}]*\}\s*=", content):
|
|
return True
|
|
return False
|
|
|
|
|
|
def find_toolbar_insert_point(content: str) -> re.Match | None:
|
|
"""Find end of first list-toolbar-row block before list-body."""
|
|
row_start = re.search(r'<div class="list-toolbar-row[^"]*"', content)
|
|
if not row_start:
|
|
return None
|
|
# From row start, find closing </div></div> before list-body
|
|
rest = content[row_start.start() :]
|
|
pattern = re.compile(
|
|
r"(<div class=\"list-toolbar-row[^\"]*\"[\s\S]*?)"
|
|
r"(\s*</div>\s*</div>\s*)"
|
|
r"(?:<!--[\s\S]*?-->\s*)?"
|
|
r"(<div class=\"list-body)",
|
|
re.MULTILINE,
|
|
)
|
|
return pattern.search(rest)
|
|
|
|
|
|
def insert_component_import(content: str) -> str | None:
|
|
"""Append ListToolbarEndActions import after existing import block."""
|
|
if IMPORT_COMPONENT in content:
|
|
return content
|
|
script_match = re.search(r'(<script setup lang="ts"[^>]*>\n)', content)
|
|
if not script_match:
|
|
return None
|
|
script_start = script_match.end()
|
|
import_stmt = re.compile(
|
|
r"^import[\s\S]*?from\s+['\"][^'\"]+['\"]\s*;?\s*$",
|
|
re.MULTILINE,
|
|
)
|
|
insert_at = script_start
|
|
for match in import_stmt.finditer(content, script_start):
|
|
insert_at = match.end()
|
|
if content[insert_at : insert_at + 1] == "\n":
|
|
insert_at += 1
|
|
return content[:insert_at] + IMPORT_COMPONENT + content[insert_at:]
|
|
|
|
|
|
def apply_file(path: Path) -> str:
|
|
content = path.read_text(encoding="utf-8")
|
|
if "ListToolbarEndActions" in content:
|
|
return "skip"
|
|
if "list-toolbar-row" not in content:
|
|
return "no-toolbar"
|
|
if not has_loading_ref(content):
|
|
return "no-loading"
|
|
|
|
handler = detect_refresh_handler(content)
|
|
if not handler:
|
|
return "no-handler"
|
|
|
|
match = find_toolbar_insert_point(content)
|
|
if not match:
|
|
return "no-match"
|
|
|
|
row_start = re.search(r'<div class="list-toolbar-row[^"]*"', content)
|
|
assert row_start
|
|
abs_start = row_start.start() + match.start(1)
|
|
abs_end = row_start.start() + match.end(1)
|
|
|
|
snippet = TOOLBAR_SNIPPET.format(handler=handler)
|
|
content = content[:abs_end] + snippet + content[abs_end:]
|
|
|
|
updated = insert_component_import(content)
|
|
if updated is None:
|
|
return "no-script"
|
|
content = updated
|
|
|
|
path.write_text(content, encoding="utf-8")
|
|
return "ok"
|
|
|
|
|
|
def main() -> None:
|
|
results: dict[str, list[str]] = {}
|
|
for rel in TARGETS:
|
|
path = ROOT / rel
|
|
if not path.exists():
|
|
results.setdefault("missing", []).append(rel)
|
|
continue
|
|
status = apply_file(path)
|
|
results.setdefault(status, []).append(rel)
|
|
|
|
for status, files in sorted(results.items()):
|
|
print(f"[{status}] {len(files)}")
|
|
for f in files:
|
|
print(f" - {f}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|