| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 |
- #!/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()
|