This commit is contained in:
zlwu committed 2026-07-21 15:23:59 +08:00
1 parent 417d6c9c51
commit c8fe0cdc20
102 files changed
+19847 -12224

No files matched your search

-1
View File
@@ -1 +0,0 @@
10333
+41 -2
View File
@@ -464,6 +464,12 @@ class OaStartInstanceBody(BaseModel):
source_instance_id: Optional[str] = Field(None, alias="sourceInstanceId")
class OaFlowPreviewBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
form_data: Optional[Dict[str, Any]] = Field(None, alias="formData")
initiator_select_user_ids: Optional[List[str]] = Field(None, alias="initiatorSelectUserIds")
class OaTaskActionBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
comment: Optional[str] = None
@@ -514,14 +520,46 @@ async def get_oa_template(
return error_response(400, str(e))
@router.get("/templates/{app_id}/flow-preview")
@router.post("/templates/{app_id}/flow-preview")
async def preview_oa_template_flow(
app_id: str,
body: OaFlowPreviewBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
"""发起前预览审批链(条件齐后解析最终路径与审批人)。"""
from app.services.oa_engine import OaEngineError, preview_start_flow
try:
tenant_no = _get_tenant_no(db, user)
uid = user.get("user_id") or ""
dept_id = None
if uid:
row = db.query(SysUser).filter(SysUser.id == uid, SysUser.del_flag == 0).first()
if row:
dept_id = row.dept_id
data = preview_start_flow(
db,
tenant_no=tenant_no,
app_id=app_id,
initiator_user_id=uid,
initiator_dept_id=dept_id,
initiator_select_user_ids=body.initiator_select_user_ids,
form_data=body.form_data,
)
return success_response(data)
except OaEngineError as e:
return error_response(400, str(e))
@router.get("/templates/{app_id}/flow-preview")
async def preview_oa_template_flow_get(
app_id: str,
initiator_select_user_ids: Optional[str] = Query(None, alias="initiatorSelectUserIds"),
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
"""发起前预览审批链(解析具体审批人)。"""
"""兼容旧 GET:无 formData,含条件分支时多为待确定占位。"""
from app.services.oa_engine import OaEngineError, preview_start_flow
try:
@@ -542,6 +580,7 @@ async def preview_oa_template_flow(
initiator_user_id=uid,
initiator_dept_id=dept_id,
initiator_select_user_ids=select_ids,
form_data=None,
)
return success_response(data)
except OaEngineError as e:
+5 -1
View File
@@ -8,6 +8,7 @@ from typing import Any, Dict, List, Optional, Tuple
from sqlalchemy import and_
from sqlalchemy.orm import Session
from app.core.db_collation import eq_unicode
from app.core.utils import generate_uuid
from app.models.models import OaApp, OaAppGroup, OaAppVersion, OaRole, OaRoleUser, SysUser
@@ -246,7 +247,10 @@ def delete_role(db: Session, role_id: str, *, tenant_no: str, user_id: Optional[
def list_role_users(db: Session, role_id: str, tenant_no: str) -> List[Dict[str, Any]]:
rows = (
db.query(OaRoleUser, SysUser)
.outerjoin(SysUser, and_(SysUser.id == OaRoleUser.user_id, SysUser.del_flag == 0))
.outerjoin(
SysUser,
and_(eq_unicode(SysUser.id, OaRoleUser.user_id), SysUser.del_flag == 0),
)
.filter(
OaRoleUser.oa_role_id == role_id,
OaRoleUser.tenant_no == tenant_no,
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_services_oa_engine_py", "label": "oa_engine.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L1"}, {"id": "services_oa_engine_oaengineerror", "label": "OaEngineError", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L26"}, {"id": "valueerror", "label": "ValueError", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "services_oa_engine_loads", "label": "_loads()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L30"}, {"id": "services_oa_engine_dumps", "label": "_dumps()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L41"}, {"id": "services_oa_engine_node_type", "label": "_node_type()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L45"}, {"id": "services_oa_engine_subtree_contains", "label": "_subtree_contains()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L49"}, {"id": "services_oa_engine_merge_after_branch_end", "label": "_merge_after_branch_end()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L64"}, {"id": "services_oa_engine_flow_root", "label": "_flow_root()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L91"}, {"id": "services_oa_engine_find_node", "label": "_find_node()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L99"}, {"id": "services_oa_engine_flow_node_key_order", "label": "_flow_node_key_order()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L117"}, {"id": "services_oa_engine_next_task_order_num", "label": "_next_task_order_num()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L142"}, {"id": "services_oa_engine_sort_tasks_for_detail", "label": "_sort_tasks_for_detail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L153"}, {"id": "services_oa_engine_fmt_dt", "label": "_fmt_dt()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L173"}, {"id": "services_oa_engine_terminal_item", "label": "_terminal_item()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L181"}, {"id": "services_oa_engine_task_round", "label": "_task_round()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L196"}, {"id": "services_oa_engine_append_pending_nodes", "label": "_append_pending_nodes()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L206"}, {"id": "services_oa_engine_build_progress_items", "label": "build_progress_items()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L237"}, {"id": "services_oa_engine_add_instance_event", "label": "_add_instance_event()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L309"}, {"id": "services_oa_engine_advanced", "label": "_advanced()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L344"}, {"id": "services_oa_engine_check_initiator_scope", "label": "_check_initiator_scope()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L353"}, {"id": "services_oa_engine_instance_to_dict", "label": "_instance_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L362"}, {"id": "services_oa_engine_task_to_dict", "label": "_task_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L380"}, {"id": "services_oa_engine_instance_progress_summary", "label": "_instance_progress_summary()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L406"}, {"id": "services_oa_engine_enrich_list_rows", "label": "_enrich_lisLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_services_oa_engine_py", "label": "oa_engine.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L1"}, {"id": "services_oa_engine_oaengineerror", "label": "OaEngineError", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L28"}, {"id": "valueerror", "label": "ValueError", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "services_oa_engine_loads", "label": "_loads()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L32"}, {"id": "services_oa_engine_dumps", "label": "_dumps()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L43"}, {"id": "services_oa_engine_node_type", "label": "_node_type()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L47"}, {"id": "services_oa_engine_subtree_contains", "label": "_subtree_contains()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L51"}, {"id": "services_oa_engine_merge_after_branch_end", "label": "_merge_after_branch_end()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L66"}, {"id": "services_oa_engine_flow_root", "label": "_flow_root()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L93"}, {"id": "services_oa_engine_find_node", "label": "_find_node()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L101"}, {"id": "services_oa_engine_flow_node_key_order", "label": "_flow_node_key_order()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L119"}, {"id": "services_oa_engine_next_task_order_num", "label": "_next_task_order_num()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L144"}, {"id": "services_oa_engine_sort_tasks_for_detail", "label": "_sort_tasks_for_detail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L155"}, {"id": "services_oa_engine_fmt_dt", "label": "_fmt_dt()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L175"}, {"id": "services_oa_engine_terminal_item", "label": "_terminal_item()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L183"}, {"id": "services_oa_engine_task_round", "label": "_task_round()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L198"}, {"id": "services_oa_engine_append_pending_nodes", "label": "_append_pending_nodes()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L208"}, {"id": "services_oa_engine_pending_people_for_node", "label": "_pending_people_for_node()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L242"}, {"id": "services_oa_engine_iter_resolved_path_nodes", "label": "_iter_resolved_path_nodes()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L306"}, {"id": "services_oa_engine_append_pending_nodes_on_path", "label": "_append_pending_nodes_on_path()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L337"}, {"id": "services_oa_engine_progress_person", "label": "_progress_person()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L401"}, {"id": "services_oa_engine_aggregate_node_status", "label": "_aggregate_node_status()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L413"}, {"id": "services_oa_engine_group_tasks_by_node", "label": "_group_tasks_by_node()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L431"}, {"id": "services_oa_engine_build_progress_items", "label": "build_progress_items()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L441"}, {"id":Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_services_oa_engine_py", "label": "oa_engine.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L1"}, {"id": "services_oa_engine_oaengineerror", "label": "OaEngineError", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L28"}, {"id": "valueerror", "label": "ValueError", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "services_oa_engine_loads", "label": "_loads()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L32"}, {"id": "services_oa_engine_dumps", "label": "_dumps()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L43"}, {"id": "services_oa_engine_node_type", "label": "_node_type()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L47"}, {"id": "services_oa_engine_subtree_contains", "label": "_subtree_contains()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L51"}, {"id": "services_oa_engine_merge_after_branch_end", "label": "_merge_after_branch_end()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L66"}, {"id": "services_oa_engine_flow_root", "label": "_flow_root()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L93"}, {"id": "services_oa_engine_find_node", "label": "_find_node()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L101"}, {"id": "services_oa_engine_flow_node_key_order", "label": "_flow_node_key_order()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L119"}, {"id": "services_oa_engine_next_task_order_num", "label": "_next_task_order_num()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L144"}, {"id": "services_oa_engine_sort_tasks_for_detail", "label": "_sort_tasks_for_detail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L155"}, {"id": "services_oa_engine_fmt_dt", "label": "_fmt_dt()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L175"}, {"id": "services_oa_engine_terminal_item", "label": "_terminal_item()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L183"}, {"id": "services_oa_engine_task_round", "label": "_task_round()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L198"}, {"id": "services_oa_engine_append_pending_nodes", "label": "_append_pending_nodes()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L208"}, {"id": "services_oa_engine_progress_person", "label": "_progress_person()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L239"}, {"id": "services_oa_engine_aggregate_node_status", "label": "_aggregate_node_status()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L251"}, {"id": "services_oa_engine_group_tasks_by_node", "label": "_group_tasks_by_node()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L269"}, {"id": "services_oa_engine_build_progress_items", "label": "build_progress_items()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L279"}, {"id": "services_oa_engine_add_instance_event", "label": "_add_instance_event()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L385"}, {"id": "services_oa_engine_advanced", "label": "_advanced()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L420"}, {"id": "services_oa_engine_check_initiator_scope", "label": "_check_initiator_scope()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L429"}, {"id": "services_oa_engine_instance_to_dict", "label": "_instaLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_services_oa_engine_py", "label": "oa_engine.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L1"}, {"id": "services_oa_engine_oaengineerror", "label": "OaEngineError", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L28"}, {"id": "valueerror", "label": "ValueError", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "services_oa_engine_loads", "label": "_loads()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L32"}, {"id": "services_oa_engine_dumps", "label": "_dumps()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L43"}, {"id": "services_oa_engine_node_type", "label": "_node_type()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L47"}, {"id": "services_oa_engine_subtree_contains", "label": "_subtree_contains()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L51"}, {"id": "services_oa_engine_merge_after_branch_end", "label": "_merge_after_branch_end()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L66"}, {"id": "services_oa_engine_flow_root", "label": "_flow_root()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L93"}, {"id": "services_oa_engine_find_node", "label": "_find_node()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L101"}, {"id": "services_oa_engine_flow_node_key_order", "label": "_flow_node_key_order()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L119"}, {"id": "services_oa_engine_next_task_order_num", "label": "_next_task_order_num()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L144"}, {"id": "services_oa_engine_sort_tasks_for_detail", "label": "_sort_tasks_for_detail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L155"}, {"id": "services_oa_engine_fmt_dt", "label": "_fmt_dt()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L175"}, {"id": "services_oa_engine_terminal_item", "label": "_terminal_item()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L183"}, {"id": "services_oa_engine_task_round", "label": "_task_round()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L198"}, {"id": "services_oa_engine_append_pending_nodes", "label": "_append_pending_nodes()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L208"}, {"id": "services_oa_engine_pending_people_for_node", "label": "_pending_people_for_node()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L248"}, {"id": "services_oa_engine_iter_resolved_path_nodes", "label": "_iter_resolved_path_nodes()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L312"}, {"id": "services_oa_engine_append_pending_nodes_on_path", "label": "_append_pending_nodes_on_path()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L343"}, {"id": "services_oa_engine_progress_person", "label": "_progress_person()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L425"}, {"id": "services_oa_engine_aggregate_node_status", "label": "_aggregate_node_status()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L437"}, {"id": "services_oa_engine_group_tasks_by_node", "label": "_group_tasks_by_node()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L455"}, {"id": "services_oa_engine_build_progress_items", "label": "build_progress_items()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L465"}, {"id":Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_api_oa_approval_py", "label": "oa_approval.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/oa_approval.py", "source_location": "L1"}, {"id": "api_oa_approval_get_tenant_no", "label": "_get_tenant_no()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/oa_approval.py", "source_location": "L17"}, {"id": "api_oa_approval_oarolecreatebody", "label": "OaRoleCreateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/oa_approval.py", "source_location": "L34"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "api_oa_approval_oaroleupdatebody", "label": "OaRoleUpdateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/oa_approval.py", "source_location": "L43"}, {"id": "api_oa_approval_oaroleusersbody", "label": "OaRoleUsersBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/oa_approval.py", "source_location": "L51"}, {"id": "api_oa_approval_list_oa_roles", "label": "list_oa_roles()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/oa_approval.py", "source_location": "L57"}, {"id": "api_oa_approval_ensure_oa_role_presets", "label": "ensure_oa_role_presets()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/oa_approval.py", "source_location": "L69"}, {"id": "api_oa_approval_create_oa_role", "label": "create_oa_role()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/oa_approval.py", "source_location": "L82"}, {"id": "api_oa_approval_update_oa_role", "label": "update_oa_role()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/oa_approval.py", "source_location": "L105"}, {"id": "api_oa_approval_delete_oa_role", "label": "delete_oa_role()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/oa_approval.py", "source_location": "L130"}, {"id": "api_oa_approval_list_oa_role_users", "label": "list_oa_role_users()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/oa_approval.py", "source_location": "L144"}, {"id": "api_oa_approval_replace_oa_role_users", "label": "replace_oa_role_users()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/oa_approval.py", "source_location": "L156"}, {"id": "api_oa_approval_oagroupcreatebody", "label": "OaGroupCreateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/oa_approval.py", "source_location": "L184"}, {"id": "api_oa_approval_oagroupupdatebody", "label": "OaGroupUpdateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/oa_approval.py", "source_location": "L191"}, {"id": "api_oa_approval_list_oa_groups", "label": "list_oa_groups()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/oa_approval.py", "source_location": "L199"}, {"id": "api_oa_approval_create_oa_group", "label": "create_oa_group()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/oa_approval.py", "source_location": "L208"}, {"id": "api_oa_approval_update_oa_group", "label": "update_oa_group()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/oa_approval.py", "source_location": "L229"}, {"id": "api_oa_approval_delete_oa_group", "label": "delete_oa_group()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/oa_approval.py", "source_location": "L253"}, {"id": "api_oa_approval_oaappcreatebody", "label": "OaAppCreateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/oa_approval.py", "source_location": "L271"}, {"id": "api_oa_approval_oaappupdatebody", "label": "OaAppUpdateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/oa_approval.py", "source_location": "L286"}, {"id": "api_oa_approval_oadraftsavebody", "label": "OaDraftSaveBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/oa_approval.py", "source_location": "L301"}, {"id": "api_oa_approval_list_oa_apps", "label": "list_oa_apps()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/oa_approval.py", "source_location": "L310"}, {"id": "api_oa_approval_create_oa_app", "label": "create_oa_app()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/oa_approval.py", "source_location": "L325"}, {"id": "api_oa_approval_update_oa_app", "label": "update_oa_app()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/oa_approval.py", "source_location": "Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_crud_oa_approval_py", "label": "oa_approval.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/oa_approval.py", "source_location": "L1"}, {"id": "crud_oa_approval_dumps", "label": "_dumps()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/oa_approval.py", "source_location": "L25"}, {"id": "crud_oa_approval_loads", "label": "_loads()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/oa_approval.py", "source_location": "L33"}, {"id": "crud_oa_approval_role_to_dict", "label": "_role_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/oa_approval.py", "source_location": "L49"}, {"id": "crud_oa_approval_ensure_presets", "label": "ensure_presets()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/oa_approval.py", "source_location": "L65"}, {"id": "crud_oa_approval_member_count_map", "label": "_member_count_map()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/oa_approval.py", "source_location": "L106"}, {"id": "crud_oa_approval_list_roles", "label": "list_roles()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/oa_approval.py", "source_location": "L124"}, {"id": "crud_oa_approval_get_role", "label": "get_role()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/oa_approval.py", "source_location": "L144"}, {"id": "crud_oa_approval_create_role", "label": "create_role()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/oa_approval.py", "source_location": "L152"}, {"id": "crud_oa_approval_update_role", "label": "update_role()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/oa_approval.py", "source_location": "L201"}, {"id": "crud_oa_approval_delete_role", "label": "delete_role()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/oa_approval.py", "source_location": "L234"}, {"id": "crud_oa_approval_list_role_users", "label": "list_role_users()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/oa_approval.py", "source_location": "L247"}, {"id": "crud_oa_approval_replace_role_users", "label": "replace_role_users()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/oa_approval.py", "source_location": "L274"}, {"id": "crud_oa_approval_list_oa_role_user_ids", "label": "list_oa_role_user_ids()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/oa_approval.py", "source_location": "L325"}, {"id": "crud_oa_approval_group_to_dict", "label": "_group_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/oa_approval.py", "source_location": "L364"}, {"id": "crud_oa_approval_list_groups", "label": "list_groups()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/oa_approval.py", "source_location": "L376"}, {"id": "crud_oa_approval_get_group", "label": "get_group()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/oa_approval.py", "source_location": "L386"}, {"id": "crud_oa_approval_create_group", "label": "create_group()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/oa_approval.py", "source_location": "L394"}, {"id": "crud_oa_approval_update_group", "label": "update_group()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/oa_approval.py", "source_location": "L426"}, {"id": "crud_oa_approval_delete_group", "label": "delete_group()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/oa_approval.py", "source_location": "L456"}, {"id": "crud_oa_approval_app_to_dict", "label": "_app_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/oa_approval.py", "source_location": "L479"}, {"id": "crud_oa_approval_get_app", "label": "get_app()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/oa_approval.py", "source_location": "L502"}, {"id": "crud_oa_approval_list_apps", "label": "list_apps()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/oa_approval.py", "source_location": "L510"}, {"id": "crud_oa_approval_create_version", "label": "_create_version()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/oa_approval.py", "source_location": "L570"}, {"id": "crud_oa_approval_create_app", "label": "create_app()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/oa_approval.py", "source_location": "L607"}, Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_services_oa_publish_py", "label": "oa_publish.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L1"}, {"id": "services_oa_publish_extract_rules", "label": "_extract_rules()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L87"}, {"id": "services_oa_publish_walk_form_rules", "label": "_walk_form_rules()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L102"}, {"id": "services_oa_publish_count_fillable_fields", "label": "count_fillable_fields()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L110"}, {"id": "services_oa_publish_rule_use_in_condition", "label": "_rule_use_in_condition()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L124"}, {"id": "services_oa_publish_index_condition_fields", "label": "index_condition_fields()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L131"}, {"id": "services_oa_publish_normalize_use_in_condition_required", "label": "normalize_use_in_condition_required()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L146"}, {"id": "services_oa_publish_node_type", "label": "_node_type()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L174"}, {"id": "services_oa_publish_validate_flow_tree", "label": "validate_flow_tree()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L178"}, {"id": "services_oa_publish_validate_condition_rules_against_form", "label": "validate_condition_rules_against_form()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L293"}, {"id": "services_oa_publish_validate_oa_roles_referenced", "label": "validate_oa_roles_referenced()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L328"}, {"id": "services_oa_publish_validate_control_types", "label": "validate_control_types()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L397"}, {"id": "services_oa_publish_validate_draft_for_publish", "label": "validate_draft_for_publish()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L413"}, {"id": "services_oa_publish_publish_app", "label": "publish_app()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L438"}, {"id": "services_oa_publish_rationale_132", "label": "field -> rule\uff08\u4ec5 useInCondition \u4e14 type \u5408\u683c\uff09", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L132"}, {"id": "services_oa_publish_rationale_147", "label": "\u5c31\u5730/\u6df1\u62f7\u8d1d\u7686\u53ef\uff1a\u6253\u6807\u5b57\u6bb5\u5f3a\u5236 required/$required\u3002\u53d1\u5e03\u524d\u8c03\u7528\u3002", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L147"}, {"id": "services_oa_publish_rationale_445", "label": "\u6821\u9a8c\u5e76\u53d1\u5e03\u5f53\u524d\u8349\u7a3f\u3002 \u6210\u529f\u8fd4\u56de (draft_dict_like_published_info, [])\uff1b \u5931\u8d25\u8fd4\u56de ({}, errors)\u3002", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L445"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_backend_app_services_oa_publish_py", "target": "typing", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L4", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_services_oa_publish_py", "target": "sqlalchemy_orm", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L6", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_services_oa_publish_py", "target": "app_crud", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L8"Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_services_oa_publish_py", "label": "oa_publish.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L1"}, {"id": "services_oa_publish_extract_rules", "label": "_extract_rules()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L87"}, {"id": "services_oa_publish_walk_form_rules", "label": "_walk_form_rules()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L102"}, {"id": "services_oa_publish_count_fillable_fields", "label": "count_fillable_fields()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L110"}, {"id": "services_oa_publish_rule_use_in_condition", "label": "_rule_use_in_condition()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L124"}, {"id": "services_oa_publish_index_condition_fields", "label": "index_condition_fields()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L131"}, {"id": "services_oa_publish_normalize_use_in_condition_required", "label": "normalize_use_in_condition_required()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L146"}, {"id": "services_oa_publish_node_type", "label": "_node_type()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L174"}, {"id": "services_oa_publish_validate_flow_tree", "label": "validate_flow_tree()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L178"}, {"id": "services_oa_publish_validate_condition_rules_against_form", "label": "validate_condition_rules_against_form()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L287"}, {"id": "services_oa_publish_validate_oa_roles_referenced", "label": "validate_oa_roles_referenced()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L322"}, {"id": "services_oa_publish_validate_control_types", "label": "validate_control_types()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L391"}, {"id": "services_oa_publish_validate_draft_for_publish", "label": "validate_draft_for_publish()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L407"}, {"id": "services_oa_publish_publish_app", "label": "publish_app()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L432"}, {"id": "services_oa_publish_rationale_132", "label": "field -> rule\uff08\u4ec5 useInCondition \u4e14 type \u5408\u683c\uff09", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L132"}, {"id": "services_oa_publish_rationale_147", "label": "\u5c31\u5730/\u6df1\u62f7\u8d1d\u7686\u53ef\uff1a\u6253\u6807\u5b57\u6bb5\u5f3a\u5236 required/$required\u3002\u53d1\u5e03\u524d\u8c03\u7528\u3002", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L147"}, {"id": "services_oa_publish_rationale_439", "label": "\u6821\u9a8c\u5e76\u53d1\u5e03\u5f53\u524d\u8349\u7a3f\u3002 \u6210\u529f\u8fd4\u56de (draft_dict_like_published_info, [])\uff1b \u5931\u8d25\u8fd4\u56de ({}, errors)\u3002", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L439"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_backend_app_services_oa_publish_py", "target": "typing", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L4", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_services_oa_publish_py", "target": "sqlalchemy_orm", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L6", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_services_oa_publish_py", "target": "app_crud", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py", "source_location": "L8"Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_services_oa_engine_py", "label": "oa_engine.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L1"}, {"id": "services_oa_engine_oaengineerror", "label": "OaEngineError", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L27"}, {"id": "valueerror", "label": "ValueError", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "services_oa_engine_loads", "label": "_loads()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L31"}, {"id": "services_oa_engine_dumps", "label": "_dumps()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L42"}, {"id": "services_oa_engine_node_type", "label": "_node_type()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L46"}, {"id": "services_oa_engine_subtree_contains", "label": "_subtree_contains()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L50"}, {"id": "services_oa_engine_merge_after_branch_end", "label": "_merge_after_branch_end()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L65"}, {"id": "services_oa_engine_flow_root", "label": "_flow_root()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L92"}, {"id": "services_oa_engine_find_node", "label": "_find_node()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L100"}, {"id": "services_oa_engine_flow_node_key_order", "label": "_flow_node_key_order()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L118"}, {"id": "services_oa_engine_next_task_order_num", "label": "_next_task_order_num()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L143"}, {"id": "services_oa_engine_sort_tasks_for_detail", "label": "_sort_tasks_for_detail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L154"}, {"id": "services_oa_engine_fmt_dt", "label": "_fmt_dt()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L174"}, {"id": "services_oa_engine_terminal_item", "label": "_terminal_item()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L182"}, {"id": "services_oa_engine_task_round", "label": "_task_round()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L197"}, {"id": "services_oa_engine_append_pending_nodes", "label": "_append_pending_nodes()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L207"}, {"id": "services_oa_engine_build_progress_items", "label": "build_progress_items()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L238"}, {"id": "services_oa_engine_add_instance_event", "label": "_add_instance_event()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L310"}, {"id": "services_oa_engine_advanced", "label": "_advanced()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L345"}, {"id": "services_oa_engine_check_initiator_scope", "label": "_check_initiator_scope()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L354"}, {"id": "services_oa_engine_instance_to_dict", "label": "_instance_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L363"}, {"id": "services_oa_engine_task_to_dict", "label": "_task_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L381"}, {"id": "services_oa_engine_instance_progress_summary", "label": "_instance_progress_summary()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py", "source_location": "L407"}, {"id": "services_oa_engine_enrich_list_rows", "label": "_enrich_liLine truncated
+484 -47
View File
@@ -2,6 +2,8 @@
from __future__ import annotations
import json
import re
from collections import OrderedDict
from datetime import datetime
from typing import Any, Dict, List, Optional, Tuple
@@ -46,6 +48,48 @@ def _node_type(node: Dict[str, Any]) -> str:
return (node.get("type") or "").strip()
def _subtree_contains(node: Optional[Dict[str, Any]], node_id: str) -> bool:
"""节点子树(含自身、child、条件分支)是否包含指定 id。"""
if not isinstance(node, dict):
return False
if (node.get("id") or "") == node_id:
return True
child = node.get("child")
if isinstance(child, dict) and _subtree_contains(child, node_id):
return True
for g in node.get("conditionGroups") or []:
if isinstance(g, dict) and _subtree_contains(g.get("child"), node_id):
return True
return False
def _merge_after_branch_end(
root: Dict[str, Any], end_id: str
) -> Optional[Dict[str, Any]]:
"""若 end 落在某条件分支组内,且该条件节点有汇合后 child,则返回汇合节点。"""
def walk(node: Optional[Dict[str, Any]]) -> Optional[Dict[str, Any]]:
if not isinstance(node, dict):
return None
if _node_type(node) == "condition":
for g in node.get("conditionGroups") or []:
if not isinstance(g, dict):
continue
if _subtree_contains(g.get("child"), end_id):
merge = node.get("child")
return merge if isinstance(merge, dict) else None
merge_child = node.get("child")
if isinstance(merge_child, dict):
return walk(merge_child)
return None
child = node.get("child")
if isinstance(child, dict):
return walk(child)
return None
return walk(root)
def _flow_root(flow_tree: Any) -> Dict[str, Any]:
if not isinstance(flow_tree, dict):
raise OaEngineError("流程树无效")
@@ -168,19 +212,26 @@ def _append_pending_nodes(
reached_keys: set,
round_no: int,
) -> None:
"""兜底:按整棵树先序挂未到达节点(无路径解析 / 无人员)。"""
order = _flow_node_key_order(flow_root)
for nid, _idx in sorted(order.items(), key=lambda x: x[1]):
node = _find_node(flow_root, nid)
if not node:
continue
nt = _node_type(node)
if nt not in ("approval", "cc") or nid in reached_keys:
if nt not in ("approval", "cc", "end") or nid in reached_keys:
continue
if nt == "end":
title = node.get("name") or "结束"
elif nt == "cc":
title = node.get("name") or "抄送人"
else:
title = node.get("name") or "审批人"
items.append(
{
"kind": "pending_node",
"roundNo": round_no,
"title": node.get("name") or ("抄送人" if nt == "cc" else "审批人"),
"title": title,
"status": "not_reached",
"assigneeUserId": "",
"assigneeUserName": "",
@@ -188,10 +239,229 @@ def _append_pending_nodes(
"commentText": "",
"nodeKey": nid,
"taskType": nt,
"signMode": "",
"people": [],
}
)
def _pending_people_for_node(
db: Session,
*,
node: Dict[str, Any],
tenant_no: str,
initiator_user_id: str,
initiator_dept_id: Optional[str],
advanced: Dict[str, Any],
initiator_select_user_ids: Optional[List[str]],
) -> Tuple[List[Dict[str, Any]], str, str]:
"""解析未到达节点的展示人员与签批模式。返回 (people, sign_mode, resolve_source)。"""
ntype = _node_type(node)
cfg = node.get("approverConfig") or {}
assignee_type = (cfg.get("assigneeType") or cfg.get("assignee_type") or "").strip()
sign_mode = (cfg.get("signMode") or cfg.get("sign_mode") or "").strip()
if ntype == "cc":
sign_mode = "cc"
elif not sign_mode and assignee_type != "initiator_select":
sign_mode = "or"
people: List[Dict[str, Any]] = []
if assignee_type == "initiator_select":
ids = [str(x).strip() for x in (initiator_select_user_ids or []) if str(x).strip()]
for uid in ids:
people.append(
{
"id": uid,
"nickName": "", # 下方统一补名
"status": "not_reached",
"timestamp": "",
"commentText": "",
"taskId": "",
}
)
else:
try:
assignees, _meta = resolve_assignees(
db,
tenant_no=tenant_no,
assignee_config=cfg,
initiator_user_id=initiator_user_id,
initiator_dept_id=initiator_dept_id,
advanced=advanced,
initiator_select_user_ids=initiator_select_user_ids,
)
for uid in assignees:
people.append(
{
"id": uid,
"nickName": "",
"status": "not_reached",
"timestamp": "",
"commentText": "",
"taskId": "",
}
)
except AssigneeResolveError:
people = []
if people:
name_map = _user_name_map(db, [p["id"] for p in people if p.get("id")])
for p in people:
p["nickName"] = name_map.get(p["id"], "") or p["id"]
return people, sign_mode, assignee_type
def _iter_resolved_path_nodes(
root: Optional[Dict[str, Any]], form_data: Optional[Dict[str, Any]]
) -> Optional[List[Dict[str, Any]]]:
"""沿条件命中路径收集节点;无法匹配时返回 None。"""
if not isinstance(root, dict):
return []
data = form_data or {}
out: List[Dict[str, Any]] = []
cur: Optional[Dict[str, Any]] = root
while cur and isinstance(cur, dict):
ntype = _node_type(cur)
if ntype == "end":
out.append(cur)
break
if ntype == "condition":
g = _match_condition_group(cur.get("conditionGroups") or [], data)
if not g:
return None
child = g.get("child")
if isinstance(child, dict):
sub = _iter_resolved_path_nodes(child, data)
if sub is None:
return None
out.extend(sub)
cur = cur.get("child")
continue
out.append(cur)
cur = cur.get("child")
return out
def _append_pending_nodes_on_path(
items: List[Dict[str, Any]],
*,
db: Session,
flow_root: Dict[str, Any],
reached_keys: set,
round_no: int,
tenant_no: str,
initiator_user_id: str,
initiator_dept_id: Optional[str],
advanced: Dict[str, Any],
form_data: Optional[Dict[str, Any]],
initiator_select_user_ids: Optional[List[str]],
) -> None:
"""按命中路径列出全部后续审批/抄送/结束节点(含人员),对齐发起预览。"""
path = _iter_resolved_path_nodes(flow_root, form_data)
if path is None:
already = {
(x.get("nodeKey") or "").strip()
for x in items
if x.get("kind") in ("task", "pending_node") and (x.get("nodeKey") or "").strip()
}
_append_pending_nodes(
items,
flow_root=flow_root,
reached_keys=reached_keys | already,
round_no=round_no,
)
return
for node in path:
ntype = _node_type(node)
if ntype not in ("approval", "cc", "end"):
continue
nid = (node.get("id") or "").strip()
if not nid or nid in reached_keys:
continue
if ntype == "end":
items.append(
{
"kind": "pending_node",
"roundNo": round_no,
"title": node.get("name") or "结束",
"status": "not_reached",
"assigneeUserId": "",
"assigneeUserName": "",
"timestamp": "",
"commentText": "",
"nodeKey": nid,
"taskType": "end",
"signMode": "",
"people": [],
}
)
continue
people, sign_mode, _src = _pending_people_for_node(
db,
node=node,
tenant_no=tenant_no,
initiator_user_id=initiator_user_id,
initiator_dept_id=initiator_dept_id,
advanced=advanced,
initiator_select_user_ids=initiator_select_user_ids,
)
items.append(
{
"kind": "pending_node",
"roundNo": round_no,
"title": node.get("name") or ("抄送人" if ntype == "cc" else "审批人"),
"status": "not_reached",
"assigneeUserId": "",
"assigneeUserName": "",
"timestamp": "",
"commentText": "",
"nodeKey": nid,
"taskType": ntype,
"signMode": sign_mode,
"people": people,
}
)
def _progress_person(t: Any, name_map: Dict[str, str]) -> Dict[str, Any]:
uid = (getattr(t, "assignee_user_id", None) or "").strip()
return {
"id": uid,
"nickName": name_map.get(uid, "") or uid,
"status": getattr(t, "status", None) or "",
"timestamp": _fmt_dt(getattr(t, "update_time", None) or getattr(t, "create_time", None)),
"commentText": getattr(t, "comment_text", None) or "",
"taskId": getattr(t, "id", None) or "",
}
def _aggregate_node_status(statuses: List[str]) -> str:
"""同节点多人任务收成卡片状态:拒绝/打回优先,其次待办,再已同意。"""
sset = [str(s or "").strip() for s in statuses]
if any(s == "rejected" for s in sset):
return "rejected"
if any(s == "returned" for s in sset):
return "returned"
if any(s in ("pending", "running") for s in sset):
return "pending"
if any(s == "approved" for s in sset):
return "approved"
if any(s == "completed" for s in sset):
return "completed"
if sset and all(s == "done" for s in sset):
return "done"
return sset[0] if sset else "pending"
def _group_tasks_by_node(sorted_tasks: List[Any]) -> List[List[Any]]:
"""按 node_key 合并同节点多人(或签/会签/抄送),无 key 的任务各自独立。"""
buckets: OrderedDict[str, List[Any]] = OrderedDict()
for t in sorted_tasks:
nk = (getattr(t, "node_key", None) or "").strip()
key = nk if nk else f"__task_{(getattr(t, 'id', None) or id(t))}"
buckets.setdefault(key, []).append(t)
return list(buckets.values())
def build_progress_items(
*,
inst: Any,
@@ -199,10 +469,15 @@ def build_progress_items(
tasks: List[Any],
name_map: Dict[str, str],
events: Optional[List[Any]] = None,
db: Optional[Session] = None,
advanced: Optional[Dict[str, Any]] = None,
initiator_select_user_ids: Optional[List[str]] = None,
) -> List[Dict[str, Any]]:
"""投影审批进度:发起人 → 树序 tasks → 未到达;终态收尾。
"""投影审批进度:发起人 → 树序 tasks(同节点多人合并)→ 未到达;终态收尾。
钉钉对齐:打回结果落在审批任务节点上,不另插 kind=return;不做同单多轮分段。
或签/会签:同一 nodeKey 只出一张卡片,people 列出各审批人及状态。
进行中:按命中路径把后续审批/抄送节点全部挂为未到达(尽量解析人员)。
"""
events = list(events or [])
sorted_tasks = _sort_tasks_for_detail(list(tasks), flow_root=flow_root)
@@ -226,32 +501,91 @@ def build_progress_items(
"commentText": "",
"nodeKey": "",
"taskType": "",
"signMode": "",
"people": [],
}
]
reached_keys = {
(t.node_key or "").strip() for t in sorted_tasks if (t.node_key or "").strip()
}
for t in sorted_tasks:
for group in _group_tasks_by_node(sorted_tasks):
head = group[0]
people = [_progress_person(t, name_map) for t in group]
statuses = [p["status"] for p in people]
node_status = _aggregate_node_status(statuses)
# 时间:优先取已操作人最新时间,否则取组内最新
acted = [
p
for p in people
if p["status"] in ("approved", "rejected", "returned", "completed")
]
ts_src = acted or people
timestamp = ""
for p in ts_src:
if p.get("timestamp") and (not timestamp or p["timestamp"] > timestamp):
timestamp = p["timestamp"]
comments = [
f"{p['nickName']}:{p['commentText']}"
if len(people) > 1 and p.get("nickName")
else p["commentText"]
for p in people
if (p.get("commentText") or "").strip()
]
sign_mode = (getattr(head, "sign_mode", None) or "").strip()
primary = next(
(p for p in people if p["status"] == node_status),
people[0] if people else None,
)
items.append(
{
"kind": "task",
"roundNo": rn,
"title": t.node_name or t.node_key or "-",
"status": t.status,
"assigneeUserId": t.assignee_user_id,
"assigneeUserName": name_map.get(t.assignee_user_id or "", ""),
"timestamp": _fmt_dt(t.update_time or t.create_time),
"commentText": t.comment_text or "",
"nodeKey": t.node_key or "",
"taskType": t.task_type or "",
"resolveSource": getattr(t, "resolve_source", None) or "",
"taskId": t.id,
"title": head.node_name or head.node_key or "-",
"status": node_status,
"assigneeUserId": (primary or {}).get("id", "") if len(people) == 1 else "",
"assigneeUserName": (primary or {}).get("nickName", "")
if len(people) == 1
else "",
"timestamp": timestamp,
"commentText": ";".join(comments),
"nodeKey": head.node_key or "",
"taskType": head.task_type or "",
"resolveSource": getattr(head, "resolve_source", None) or "",
"signMode": sign_mode,
"taskId": getattr(head, "id", None) or "",
"people": people,
}
)
if inst.status == "running" and isinstance(flow_root, dict):
_append_pending_nodes(
items, flow_root=flow_root, reached_keys=reached_keys, round_no=rn
)
form_data = _loads(getattr(inst, "form_data_json", None), {}) or {}
if not isinstance(form_data, dict):
form_data = {}
# 自选人:优先入参;否则从已有任务里收集
select_ids = list(initiator_select_user_ids or [])
if not select_ids:
for t in sorted_tasks:
src = (getattr(t, "resolve_source", None) or "").strip()
uid = (getattr(t, "assignee_user_id", None) or "").strip()
if src == "initiator_select" and uid and uid not in select_ids:
select_ids.append(uid)
if db is not None:
_append_pending_nodes_on_path(
items,
db=db,
flow_root=flow_root,
reached_keys=reached_keys,
round_no=rn,
tenant_no=getattr(inst, "tenant_no", None) or "",
initiator_user_id=inst.initiator_user_id or "",
initiator_dept_id=getattr(inst, "initiator_dept_id", None),
advanced=advanced or dict(oa_crud.DEFAULT_ADVANCED_SETTINGS),
form_data=form_data,
initiator_select_user_ids=select_ids,
)
else:
_append_pending_nodes(
items, flow_root=flow_root, reached_keys=reached_keys, round_no=rn
)
if inst.status == "completed":
items.append(_terminal_item("done", "流程结束", inst))
@@ -596,6 +930,92 @@ def _preview_people(db: Session, user_ids: List[str]) -> List[Dict[str, str]]:
return out
_FLOW_PREVIEW_PENDING_MSG = "必填信息填写后,流程将自动显示"
_FLOW_PREVIEW_UNMATCHED_MSG = "流程条件无法匹配,请检查表单或联系管理员"
_FORMULA_FIELD_RE = re.compile(r"\{([^{}]+)\}")
def _form_value_present(form_data: Optional[Dict[str, Any]], field: str) -> bool:
"""条件字段是否已有有效值(0 / false 视为已填)。"""
if not field:
return True
data = form_data or {}
if field not in data:
return False
val = data.get(field)
if val is None:
return False
if isinstance(val, str) and not val.strip():
return False
if isinstance(val, (list, tuple, set, dict)) and len(val) == 0:
return False
return True
def _collect_condition_fields(node: Optional[Dict[str, Any]]) -> List[str]:
"""收集流程树中非默认条件分支引用的表单字段(去重保序)。"""
fields: List[str] = []
seen = set()
def add(name: Any) -> None:
key = str(name or "").strip()
if not key or key in seen:
return
seen.add(key)
fields.append(key)
def walk(n: Any) -> None:
if not isinstance(n, dict):
return
if _node_type(n) == "condition":
for g in n.get("conditionGroups") or []:
if not isinstance(g, dict):
continue
rules = g.get("rules")
when = g.get("when")
if g.get("isDefault") or (not rules and not when):
child = g.get("child")
if isinstance(child, dict):
walk(child)
continue
if isinstance(rules, list) and rules:
for r in rules:
if isinstance(r, dict) and r.get("field") is not None:
add(r.get("field"))
elif isinstance(rules, str) and rules.strip():
for m in _FORMULA_FIELD_RE.findall(rules):
add(m)
elif when:
for m in _FORMULA_FIELD_RE.findall(str(when)):
add(m)
child = g.get("child")
if isinstance(child, dict):
walk(child)
join_child = n.get("child")
if isinstance(join_child, dict):
walk(join_child)
return
child = n.get("child")
if isinstance(child, dict):
walk(child)
for g in n.get("conditionGroups") or []:
if isinstance(g, dict) and isinstance(g.get("child"), dict):
walk(g.get("child"))
walk(node)
return fields
def _condition_fields_ready(
root: Optional[Dict[str, Any]], form_data: Optional[Dict[str, Any]]
) -> bool:
fields = _collect_condition_fields(root)
if not fields:
return True
data = form_data or {}
return all(_form_value_present(data, f) for f in fields)
def _walk_preview_nodes(
db: Session,
*,
@@ -605,9 +1025,12 @@ def _walk_preview_nodes(
initiator_dept_id: Optional[str],
advanced: Dict[str, Any],
initiator_select_user_ids: Optional[List[str]],
form_data: Optional[Dict[str, Any]],
steps: List[Dict[str, Any]],
) -> None:
) -> bool:
"""沿最终路径写入 steps。条件无法匹配时返回 False。"""
cur = node
data = form_data or {}
while cur and isinstance(cur, dict):
ntype = _node_type(cur)
if ntype == "start":
@@ -644,33 +1067,24 @@ def _walk_preview_nodes(
if ntype == "condition":
groups = cur.get("conditionGroups") or []
for g in groups:
if not isinstance(g, dict):
continue
steps.append(
{
"id": f"{cur.get('id') or 'cond'}_{(g.get('name') or '分支')}",
"type": "branch",
"name": g.get("name") or "条件分支",
"signMode": "",
"assigneeType": "",
"meta": "条件分支(实际路径以提交时表单为准)",
"people": [],
"resolveError": "",
}
g = _match_condition_group(groups, data)
if not g:
return False
child = g.get("child")
if isinstance(child, dict):
ok = _walk_preview_nodes(
db,
node=child,
tenant_no=tenant_no,
initiator_user_id=initiator_user_id,
initiator_dept_id=initiator_dept_id,
advanced=advanced,
initiator_select_user_ids=initiator_select_user_ids,
form_data=data,
steps=steps,
)
child = g.get("child")
if isinstance(child, dict):
_walk_preview_nodes(
db,
node=child,
tenant_no=tenant_no,
initiator_user_id=initiator_user_id,
initiator_dept_id=initiator_dept_id,
advanced=advanced,
initiator_select_user_ids=initiator_select_user_ids,
steps=steps,
)
if not ok:
return False
cur = cur.get("child")
continue
@@ -720,6 +1134,7 @@ def _walk_preview_nodes(
continue
cur = cur.get("child")
return True
def preview_start_flow(
@@ -730,8 +1145,9 @@ def preview_start_flow(
initiator_user_id: str,
initiator_dept_id: Optional[str] = None,
initiator_select_user_ids: Optional[List[str]] = None,
form_data: Optional[Dict[str, Any]] = None,
) -> Dict[str, Any]:
"""发起前预览审批链(解析具体人员;条件分支展开展示)。"""
"""发起前预览审批链:条件字段齐后只走命中路径并解析人员。"""
app = oa_crud.get_app(db, app_id, tenant_no)
if not app or app.status != "1":
raise OaEngineError("应用不存在或已停用")
@@ -758,8 +1174,16 @@ def preview_start_flow(
if not isinstance(root, dict):
root = flow if isinstance(flow, dict) else {}
data = dict(form_data or {})
if not _condition_fields_ready(root, data):
return {
"resolved": False,
"message": _FLOW_PREVIEW_PENDING_MSG,
"steps": [],
}
steps: List[Dict[str, Any]] = []
_walk_preview_nodes(
ok = _walk_preview_nodes(
db,
node=root,
tenant_no=tenant_no,
@@ -767,9 +1191,16 @@ def preview_start_flow(
initiator_dept_id=dept_id or None,
advanced=_advanced(pub),
initiator_select_user_ids=initiator_select_user_ids,
form_data=data,
steps=steps,
)
return {"steps": steps}
if not ok:
return {
"resolved": False,
"message": _FLOW_PREVIEW_UNMATCHED_MSG,
"steps": [],
}
return {"resolved": True, "message": "", "steps": steps}
def _create_tasks_for_node(
@@ -919,6 +1350,10 @@ def advance_from(
safety += 1
ntype = _node_type(cur)
if ntype == "end":
merge = _merge_after_branch_end(root, cur.get("id") or "")
if merge is not None:
cur = merge
continue
inst.status = "completed"
inst.update_time = datetime.now()
db.add(inst)
@@ -1124,6 +1559,8 @@ def get_instance_detail(db: Session, instance_id: str, *, tenant_no: str) -> Dic
tasks=tasks,
name_map=name_map,
events=events,
db=db,
advanced=adv,
)
# 不再暴露旧单/重提单关联跳转
data["sourceInstanceId"] = ""
+17 -2
View File
@@ -71,7 +71,16 @@ VALID_NODE_TYPES = frozenset({"start", "approval", "cc", "condition", "end"})
ALLOWED_CONTROL_TYPES = FILLABLE_TYPES | LAYOUT_TYPES
CONDITION_ELIGIBLE_TYPES = frozenset(
{"inputNumber", "number", "money", "radio", "select", "datePicker", "date"}
{
"input",
"inputNumber",
"number",
"money",
"radio",
"select",
"datePicker",
"date",
}
)
@@ -255,7 +264,13 @@ def validate_flow_tree(flow_tree: Any) -> List[str]:
else:
gname = g.get("name") or f"分支{i + 1}"
walk(child if isinstance(child, dict) else None, f"{path}/{gname}")
# 条件节点也可有默认 child(部分设计);若无 groups 已报错
# 条件分支汇合后的主链(可选)
merge = node.get("child")
if merge is not None:
if not isinstance(merge, dict):
errors.append(f"{path}:汇合后子节点格式非法")
else:
walk(merge, f"{path}/汇合")
return
child = node.get("child")
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+90 -83
View File
@@ -1,11 +1,11 @@
# Graph Report - app (2026-07-16)
# Graph Report - app (2026-07-17)
## Corpus Check
- Large corpus: 225 files · ~278,668 words. Semantic extraction will be expensive (many Claude tokens). Consider running on a subfolder, or use --no-semantic to run AST-only.
- Large corpus: 225 files · ~280,104 words. Semantic extraction will be expensive (many Claude tokens). Consider running on a subfolder, or use --no-semantic to run AST-only.
## Summary
- 4738 nodes · 26131 edges · 38 communities detected
- Extraction: 31% EXTRACTED · 69% INFERRED · 0% AMBIGUOUS · INFERRED: 17919 edges (avg confidence: 0.6)
- 4764 nodes · 26310 edges · 39 communities detected
- Extraction: 31% EXTRACTED · 69% INFERRED · 0% AMBIGUOUS · INFERRED: 18051 edges (avg confidence: 0.6)
- Token cost: 0 input · 0 output
## Community Hubs (Navigation)
@@ -41,17 +41,18 @@
- [[_COMMUNITY_Community 29|Community 29]]
- [[_COMMUNITY_Community 30|Community 30]]
- [[_COMMUNITY_Community 31|Community 31]]
- [[_COMMUNITY_Community 34|Community 34]]
- [[_COMMUNITY_Community 32|Community 32]]
- [[_COMMUNITY_Community 35|Community 35]]
- [[_COMMUNITY_Community 36|Community 36]]
- [[_COMMUNITY_Community 37|Community 37]]
- [[_COMMUNITY_Community 38|Community 38]]
- [[_COMMUNITY_Community 39|Community 39]]
- [[_COMMUNITY_Community 40|Community 40]]
## God Nodes (most connected - your core abstractions)
1. `success_response()` - 707 edges
2. `error_response()` - 586 edges
3. `SysUser` - 537 edges
1. `success_response()` - 708 edges
2. `error_response()` - 587 edges
3. `SysUser` - 551 edges
4. `BizQcTaskResult` - 333 edges
5. `BizProductionMaterial` - 324 edges
6. `BizProductionMaterialUsage` - 318 edges
@@ -76,108 +77,108 @@
### Community 0 - "Community 0"
Cohesion: 0.01
Nodes (914): attachment_download_url(), create_dept(), create_dict_data(), create_dict_type(), create_express_company(), create_item_unit(), create_menu(), create_post() (+906 more)
Nodes (926): attachment_download_url(), create_dept(), create_dict_data(), create_dict_type(), create_express_company(), create_item_unit(), create_menu(), create_post() (+918 more)
### Community 1 - "Community 1"
Cohesion: 0.01
Nodes (727): generate_uuid(), ApiRequestLogCRUD, delete(), get_multi_with_filters(), allocate_next_biz_no(), _format_biz_no(), _prefix_for(), 业务协议号自动生成:XBCC / JZCC + YYYYMMDD + 6 位序号 (+719 more)
Nodes (746): generate_uuid(), allocate_next_biz_no(), _format_biz_no(), _prefix_for(), 业务协议号自动生成:XBCC / JZCC + YYYYMMDD + 6 位序号, 原子分配下一个业务协议号。 须在 create 事务内调用;使用 MySQL LAST_INSERT_ID 保证并发安全。, create_cell_sample_type(), get_cell_sample_type() (+738 more)
### Community 2 - "Community 2"
Cohesion: 0.01
Nodes (675): AttachmentDownloadUrlBody, DeptCreateBody, DeptUpdateBody, DictDataCreateBody, DictDataUpdateBody, DictTypeCreateBody, DictTypeUpdateBody, ExpressCompanyCreateBody (+667 more)
Nodes (601): AttachmentDownloadUrlBody, DeptCreateBody, DeptUpdateBody, DictDataCreateBody, DictDataUpdateBody, DictTypeCreateBody, DictTypeUpdateBody, ExpressCompanyCreateBody (+593 more)
### Community 3 - "Community 3"
Cohesion: 0.06
Nodes (546): BatchRefundFinanceSubmitBody, 细胞存储 — 采集协议单 / 审核 / 财务确认 / 分期预警 API, 与列表接口一致:按租户 + 角色数据权限判断是否可访问该协议单。, If mother info exists but no customerId, create a customer record and link it., RefundFinanceSubmitBody, Base, 细胞产品 CRUD(biz_cell_product), 解析任务样本投入物,返回祖先链单段(样本终止节点)。 (+538 more)
Cohesion: 0.01
Nodes (339): _normalize_date_bound(), _persist_protocol_sub_resources(), list_ethnics_for_select(), _body_to_payload(), _get_current_user_id(), get_production_reception_by_sample_code(), get_production_reception_detail(), _get_tenant_no() (+331 more)
### Community 4 - "Community 4"
Cohesion: 0.02
Nodes (270): _normalize_date_bound(), format_date(), generate_id(), optional_date(), parse_date(), 将字符串 / date / datetime 转为 date 或 None, camel_to_snake(), get_model_attr() (+262 more)
Cohesion: 0.08
Nodes (373): CellSampleTypeCreateBody, CellSampleTypeUpdateBody, CollectionRegionCreateBody, CollectionRegionUpdateBody, CustomerCreateBody, CustomerUpdateBody, HospitalCreateBody, HospitalUpdateBody (+365 more)
### Community 5 - "Community 5"
Cohesion: 0.02
Nodes (257): eq_unicode(), like_unicode(), MySQL 字符串比较/模糊匹配时统一排序规则,避免 Illegal mix of collations。, 跨表字符串等值比较(JOIN / WHERE)时统一为 utf8mb4_unicode_ci。, 将列显式设为 utf8mb4_unicode_ci。, unicode_ci(), build_void_type_label_map(), format_protocol_status_label() (+249 more)
Cohesion: 0.08
Nodes (259): AuditCreateBody, BatchDetailIdsBody, BatchRefundFinanceSubmitBody, FinanceConfirmBody, FullmoonTodoInsuranceBody, InvoiceRequestCompleteBody, InvoiceRequestCreateBody, PaymentDetailDraftBody (+251 more)
### Community 6 - "Community 6"
Cohesion: 0.02
Nodes (191): list_ethnics_for_select(), AccessLogCreateBody, AccessLogUpdateBody, CleanRoomCreateBody, CleanRoomUpdateBody, create_access_log(), create_uv_disinfect_log(), delete_access_log() (+183 more)
Nodes (198): eq_unicode(), like_unicode(), MySQL 字符串比较/模糊匹配时统一排序规则,避免 Illegal mix of collations。, 跨表字符串等值比较(JOIN / WHERE)时统一为 utf8mb4_unicode_ci。, 将列显式设为 utf8mb4_unicode_ci。, unicode_ci(), batch_review(), _dec() (+190 more)
### Community 7 - "Community 7"
Cohesion: 0.02
Nodes (134): _avatar_url_field(), _build_current_user_payload(), _build_user_info_payload(), get_current_user_profile(), _jwt_user_payload(), logout(), 公共接口(Web 登录、刷新 Token、登出;用户模型对齐 docs/sql/zkxw.sql 基线), Web 端登录用 RSA 公钥(PKCS#1 v1.5,与 JSEncrypt 一致) (+126 more)
Nodes (112): get_designer_data(), _error_json(), 数据库异常:返回 JSON 并保留 CORS 头,避免浏览器只报跨域错误, 未捕获异常:统一 JSON 500,确保跨域场景下仍有 Access-Control-Allow-Origin, sqlalchemy_exception_handler(), unhandled_exception_handler(), BaseHTTPMiddleware, ApiCryptoError (+104 more)
### Community 8 - "Community 8"
Cohesion: 0.03
Nodes (147): auto_create_payment(), get_protocol_nos_used_in_protocols(), _fmt_dt(), get_handover_by_schedule(), get_outbound_handover(), get_outbound_handover_view(), _handover_row_to_dict(), _handover_view_dict() (+139 more)
Cohesion: 0.04
Nodes (141): 发起前预览审批链(条件齐后解析最终路径与审批人)。, 兼容旧 GET:无 formData,含条件分支时多为待确定占位。, _app_to_dict(), create_app(), create_group(), create_role(), _create_version(), delete_app() (+133 more)
### Community 9 - "Community 9"
Cohesion: 0.03
Nodes (140): get_next_cell_product_code(), _ancestor_link_from_cell_product_input(), _ancestor_sample_chain_link(), _apply_cell_product_status_change(), _build_ancestor_chain(), _build_descendant_chain(), _build_facility_path_label(), build_split_product_codes() (+132 more)
Nodes (116): auto_create_payment(), get_protocol_nos_used_in_protocols(), _fmt_dt(), get_handover_by_schedule(), get_outbound_handover(), get_outbound_handover_view(), _handover_row_to_dict(), _handover_view_dict() (+108 more)
### Community 10 - "Community 10"
Cohesion: 0.04
Nodes (98): _app_to_dict(), create_app(), create_group(), create_role(), _create_version(), delete_app(), delete_group(), delete_role() (+90 more)
Nodes (116): build_void_type_label_map(), format_protocol_status_label(), resolve_void_type_label(), join_equipment_ids(), parse_equipment_ids(), 工艺/步骤设备多选:逗号分隔 ID 与名称快照解析, 校验设备列表,返回 (equipment_ids 逗号串, equipment_name 逗号串快照)。, resolve_equipment_list_snapshot() (+108 more)
### Community 11 - "Community 11"
Cohesion: 0.08
Nodes (34): get_designer_data(), create_instance(), create_process_def(), create_task(), get_all_tasks_for_business(), get_instance(), get_latest_version(), get_nodes_by_version() (+26 more)
Cohesion: 0.05
Nodes (104): AccessLogCreateBody, AccessLogUpdateBody, CleanRoomCreateBody, CleanRoomUpdateBody, ExhibitionAppointmentCreateBody, ExhibitionAppointmentUpdateBody, list_storage_slot_stats(), OccupancyCreateBody (+96 more)
### Community 12 - "Community 12"
Cohesion: 0.11
Nodes (39): _amount_for_row(), _batch_map(), deduct_for_task(), _deduct_task_usage_legacy_batch(), _display_remark(), _fmt_date_val(), _linked_qc_task_no_map(), list_linked_task_usages() (+31 more)
Cohesion: 0.45
Nodes (69): BatchStockInBody, BatchStockInItem, BatchStockOutBody, BatchStockOutItem, ConsumableCreateBody, ConsumablePackCreateBody, ConsumablePackUpdateBody, ConsumableUpdateBody (+61 more)
### Community 13 - "Community 13"
Cohesion: 0.12
Nodes (10): get_wechat_pay_client(), get_wechat_pay_v2(), 微信支付工具模块 支持微信支付 V3 API 文档参考: https://pay.weixin.qq.com/docs/v3/apis/index.ht, 统一下单接口 (V3) Args: out_trade_no: 商户订单号 total, 小程序调起支付的二次签名参数(与公众号 JSAPI 规则一致), 统一下单 (V2 API) Args: out_trade_no: 商户订单号 tot, 生成签名 V3 (SHA256 with RSA), wechat_pay() (+2 more)
Cohesion: 0.06
Nodes (66): get_next_cell_product_code(), _ancestor_link_from_cell_product_input(), _ancestor_sample_chain_link(), _apply_cell_product_status_change(), _build_ancestor_chain(), _build_descendant_chain(), _build_facility_path_label(), build_split_product_codes() (+58 more)
### Community 14 - "Community 14"
Cohesion: 0.16
Nodes (22): _code_exists(), create_material(), _dec(), _fmt_dt(), get_material(), get_material_entity(), get_my_usages(), _is_enabled_status() (+14 more)
Cohesion: 0.06
Nodes (49): _jwt_user_payload(), Web 端登录用 RSA 公钥(PKCS#1 v1.5,与 JSEncrypt 一致), Web 端登录:账号为 sys_user.user_no,密码为 sys_user.password(bcrypt)。, refresh_token(), web_login(), web_login_rsa_public_key(), lifespan(), create_access_token() (+41 more)
### Community 15 - "Community 15"
Cohesion: 0.16
Nodes (18): 验证密码(哈希非 bcrypt 或损坏时返回 False,避免抛错), verify_password(), change_password(), create_user(), get_user(), get_user_with_relations(), _hash_password(), list_post_ids_for_user() (+10 more)
Cohesion: 0.12
Nodes (11): get_wechat_pay_client(), get_wechat_pay_v2(), 微信支付工具模块 支持微信支付 V3 API 文档参考: https://pay.weixin.qq.com/docs/v3/apis/index.ht, 统一下单接口 (V3) Args: out_trade_no: 商户订单号 total, 申请退款 Args: out_trade_no: 商户订单号 total_amount, 小程序调起支付的二次签名参数(与公众号 JSAPI 规则一致), 统一下单 (V2 API) Args: out_trade_no: 商户订单号 tot, 生成签名 V3 (SHA256 with RSA) (+3 more)
### Community 16 - "Community 16"
Cohesion: 0.19
Nodes (27): _amount_for_row(), _batch_map(), deduct_for_task(), _deduct_task_usage_legacy_batch(), _display_remark(), _fmt_date_val(), _linked_qc_task_no_map(), list_linked_task_usages() (+19 more)
### Community 17 - "Community 17"
Cohesion: 0.21
Nodes (19): _consumable_row_to_dict(), create_process(), _create_sub_consumable(), _create_sub_data_collection(), _create_sub_output(), _create_sub_reagent(), _data_collection_row_to_dict(), get_process() (+11 more)
### Community 17 - "Community 17"
Cohesion: 0.27
Nodes (11): _accept_conclusion_label(), _base_query(), _ensure_notification(), _fmt_dt(), generate_sms_content(), list_notifications(), _normalize_date_bound(), resolve_notification() (+3 more)
### Community 18 - "Community 18"
Cohesion: 0.24
Nodes (9): 微信消息通知服务 支持微信小程序模板消息推送 使用方式: from app.core.wechat_message import Wech, 发送模板消息 Args: openid: 用户openid templ, send_delivery_notice(), send_delivery_warning(), send_order_status(), send_payment_success(), send_refund_result(), send_urge_notification() (+1 more)
Cohesion: 0.2
Nodes (19): _code_exists(), create_material(), _dec(), _fmt_dt(), get_material(), get_material_entity(), get_my_usages(), _is_enabled_status() (+11 more)
### Community 19 - "Community 19"
Cohesion: 0.23
Nodes (12): Config, ProductBase, ProductCategoryBase, ProductCategoryCreate, ProductCategoryResponse, ProductCreate, ProductResponse, ProductUnitBase (+4 more)
Cohesion: 0.27
Nodes (12): create_equipment(), _dec(), equipment_code_exists(), equipment_is_referenced(), get_equipment(), list_equipments(), _norm_status(), _parse_date() (+4 more)
### Community 20 - "Community 20"
Cohesion: 0.24
Nodes (11): deduct_for_step(), _display_remark(), list_stock_logs(), _parse_receiver_purpose_from_remark(), 试剂变动记录 CRUD(biz_reagent_stock_log), 撤销步骤此前 step_save 扣减,便于重新填报。, 扣减试剂库存并生成变动记录。调用方控制事务,本函数不 commit。, _resolve_receiver_purpose() (+3 more)
Nodes (9): 微信消息通知服务 支持微信小程序模板消息推送 使用方式: from app.core.wechat_message import Wech, 发送模板消息 Args: openid: 用户openid templ, send_delivery_notice(), send_delivery_warning(), send_order_status(), send_payment_success(), send_refund_result(), send_urge_notification() (+1 more)
### Community 21 - "Community 21"
Cohesion: 0.24
Nodes (11): deduct_for_step(), _display_remark(), list_stock_logs(), _parse_receiver_purpose_from_remark(), 耗材变动记录 CRUD(biz_consumable_stock_log), 撤销步骤此前 step_save 扣减,便于重新填报。, 扣减耗材库存并生成变动记录。调用方控制事务,本函数不 commit。, _resolve_receiver_purpose() (+3 more)
Nodes (11): deduct_for_step(), _display_remark(), list_stock_logs(), _parse_receiver_purpose_from_remark(), 试剂变动记录 CRUD(biz_reagent_stock_log), 撤销步骤此前 step_save 扣减,便于重新填报。, 扣减试剂库存并生成变动记录。调用方控制事务,本函数不 commit。, _resolve_receiver_purpose() (+3 more)
### Community 22 - "Community 22"
Cohesion: 0.27
Nodes (11): _build_tree(), _cascade_soft_delete(), _collect_with_ancestors(), create_dept(), get_dept(), list_depts(), list_depts_tree(), 保留匹配节点及其全部上级,供关键词检索后仍能正确组树。 (+3 more)
Cohesion: 0.24
Nodes (11): deduct_for_step(), _display_remark(), list_stock_logs(), _parse_receiver_purpose_from_remark(), 耗材变动记录 CRUD(biz_consumable_stock_log), 撤销步骤此前 step_save 扣减,便于重新填报。, 扣减耗材库存并生成变动记录。调用方控制事务,本函数不 commit。, _resolve_receiver_purpose() (+3 more)
### Community 23 - "Community 23"
Cohesion: 0.29
Nodes (9): _build_tree(), _cascade_soft_delete(), create_menu(), get_menu(), list_menus(), list_menus_tree(), _row_to_dict(), soft_delete_menu() (+1 more)
### Community 24 - "Community 24"
Cohesion: 0.29
Nodes (2): BaseModel, SoftDeleteModel
### Community 25 - "Community 25"
### Community 24 - "Community 24"
Cohesion: 0.38
Nodes (6): derive_legacy_status_from_three(), derive_three_status_from_legacy(), 阶段A兼容:从旧 status 推导三字段。 约束:旧 status 本身混合了支付/配送/订单生命周期,因此只能尽力推断; 若业务侧已有更精确, 阶段A兼容:从三字段反推旧 status(用于旧前端/旧筛选参数兼容)。, ThreeStatus, _to_decimal()
### Community 25 - "Community 25"
Cohesion: 0.6
Nodes (5): _dec(), _fmt_dt(), list_stock_logs(), _row_to_dict(), _user_nick_name_map()
### Community 26 - "Community 26"
Cohesion: 0.5
Nodes (3): BaseSettings, Config, Settings
@@ -187,87 +188,93 @@ Cohesion: 0.5
Nodes (2): _auto_fill_create_dept_id(), ORM before_insert 钩子:当 create_dept_id 为空时,自动从请求上下文填充当前用户部门 ID
### Community 28 - "Community 28"
Cohesion: 0.5
Nodes (2): delete(), get_multi_with_filters()
### Community 29 - "Community 29"
Cohesion: 0.67
Nodes (2): get_menu_list(), 运营端菜单接口(与 web-admin 前端静态路由 sqxp.ts 对齐,5 个一级菜单分组)
### Community 29 - "Community 29"
### Community 30 - "Community 30"
Cohesion: 1.0
Nodes (1): 质检物料金额查看授权:专用角色与菜单权限常量。
### Community 30 - "Community 30"
### Community 31 - "Community 31"
Cohesion: 1.0
Nodes (1): 请求级别的用户上下文变量 通过 contextvars 在请求处理链路中传递当前用户信息, 供 SQLAlchemy 事件监听器等底层机制使用,避免逐层手动传
### Community 31 - "Community 31"
### Community 32 - "Community 32"
Cohesion: 1.0
Nodes (1): API 路由包(骨架:公共鉴权 + 静态菜单 + 运营端占位)
### Community 34 - "Community 34"
### Community 35 - "Community 35"
Cohesion: 1.0
Nodes (1): 发送订单状态通知 Args: openid: 用户openid ord
### Community 35 - "Community 35"
### Community 36 - "Community 36"
Cohesion: 1.0
Nodes (1): 发送支付成功通知 Args: openid: 用户openid ord
### Community 36 - "Community 36"
### Community 37 - "Community 37"
Cohesion: 1.0
Nodes (1): 发送配送通知 Args: openid: 配送员openid task
### Community 37 - "Community 37"
### Community 38 - "Community 38"
Cohesion: 1.0
Nodes (1): 发送配送时效预警 Args: openid: 配送员openid ta
### Community 38 - "Community 38"
### Community 39 - "Community 39"
Cohesion: 1.0
Nodes (1): 发送退款结果通知 Args: openid: 用户openid ord
### Community 39 - "Community 39"
### Community 40 - "Community 40"
Cohesion: 1.0
Nodes (1): 发送催单通知给配送员 Args: deliver_openid: 配送员openid
## Knowledge Gaps
- **134 isolated node(s):** `刷新会话 TTL(refreshToken 续期;已登录用户每次 API 校验通过后滑动续期)`, `写入 refreshToken(用于 one-time 使用/吊销)`, `根据 token 获取当前用户(包含 Redis 会话校验;会话滑动续期)`, `登录凭据 RSA 解密(与前端 JSEncrypt PKCS#1 v1.5 兼容)。`, `加载 RSA 密钥对:优先环境变量,否则使用内置固定默认密钥。` (+129 more)
These have ≤1 connection - possible missing edges or undocumented components.
- **Thin community `Community 24`** (8 nodes): `BaseModel`, `.to_dict()`, `get_active()`, `base.py`, `SoftDeleteModel`, `.restore()`, `.soft_delete()`, `__tablename__()`
- **Thin community `Community 23`** (8 nodes): `BaseModel`, `.to_dict()`, `get_active()`, `base.py`, `SoftDeleteModel`, `.restore()`, `.soft_delete()`, `__tablename__()`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 27`** (4 nodes): `_auto_fill_create_dept_id()`, `get_db()`, `database.py`, `ORM before_insert 钩子:当 create_dept_id 为空时,自动从请求上下文填充当前用户部门 ID`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 28`** (3 nodes): `get_menu_list()`, `menu.py`, `运营端菜单接口(与 web-admin 前端静态路由 sqxp.ts 对齐,5 个一级菜单分组)`
- **Thin community `Community 28`** (4 nodes): `delete()`, `get()`, `get_multi_with_filters()`, `api_request_log.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 29`** (2 nodes): `qc_material_amount_auth_constants.py`, `质检物料金额查看授权:专用角色与菜单权限常量。`
- **Thin community `Community 29`** (3 nodes): `get_menu_list()`, `menu.py`, `运营端菜单接口(与 web-admin 前端静态路由 sqxp.ts 对齐,5 个一级菜单分组)`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 30`** (2 nodes): `context.py`, `请求级别的用户上下文变量 通过 contextvars 在请求处理链路中传递当前用户信息, 供 SQLAlchemy 事件监听器等底层机制使用,避免逐层手动传`
- **Thin community `Community 30`** (2 nodes): `qc_material_amount_auth_constants.py`, `质检物料金额查看授权:专用角色与菜单权限常量。`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 31`** (2 nodes): `__init__.py`, `API 路由包(骨架:公共鉴权 + 静态菜单 + 运营端占位)`
- **Thin community `Community 31`** (2 nodes): `context.py`, `请求级别的用户上下文变量 通过 contextvars 在请求处理链路中传递当前用户信息, 供 SQLAlchemy 事件监听器等底层机制使用,避免逐层手动传`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 34`** (1 nodes): `发送订单状态通知 Args: openid: 用户openid ord`
- **Thin community `Community 32`** (2 nodes): `__init__.py`, `API 路由包(骨架:公共鉴权 + 静态菜单 + 运营端占位)`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 35`** (1 nodes): `发送支付成功通知 Args: openid: 用户openid ord`
- **Thin community `Community 35`** (1 nodes): `发送订单状态通知 Args: openid: 用户openid ord`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 36`** (1 nodes): `发送配送通知 Args: openid: 配送员openid task`
- **Thin community `Community 36`** (1 nodes): `发送支付成功通知 Args: openid: 用户openid ord`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 37`** (1 nodes): `发送配送时效预警 Args: openid: 配送员openid ta`
- **Thin community `Community 37`** (1 nodes): `发送配送通知 Args: openid: 配送员openid task`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 38`** (1 nodes): `发送退款结果通知 Args: openid: 用户openid ord`
- **Thin community `Community 38`** (1 nodes): `发送配送时效预警 Args: openid: 配送员openid ta`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 39`** (1 nodes): `发送催单通知给配送员 Args: deliver_openid: 配送员openid`
- **Thin community `Community 39`** (1 nodes): `发送退款结果通知 Args: openid: 用户openid ord`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 40`** (1 nodes): `发送催单通知给配送员 Args: deliver_openid: 配送员openid`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
## Suggested Questions
_Questions this graph is uniquely positioned to answer:_
- **Why does `SysUser` connect `Community 2` to `Community 0`, `Community 1`, `Community 3`, `Community 5`, `Community 6`, `Community 7`, `Community 8`, `Community 9`, `Community 10`, `Community 11`, `Community 12`, `Community 14`, `Community 15`, `Community 20`, `Community 21`?**
_High betweenness centrality (0.132) - this node is a cross-community bridge._
- **Why does `success_response()` connect `Community 0` to `Community 2`, `Community 6`, `Community 7`, `Community 9`, `Community 11`, `Community 28`?**
_High betweenness centrality (0.047) - this node is a cross-community bridge._
- **Why does `generate_uuid()` connect `Community 1` to `Community 0`, `Community 2`, `Community 4`, `Community 5`, `Community 6`, `Community 7`, `Community 8`, `Community 9`, `Community 10`, `Community 11`, `Community 12`, `Community 14`, `Community 15`, `Community 16`, `Community 17`, `Community 20`, `Community 21`, `Community 22`, `Community 23`?**
- **Why does `SysUser` connect `Community 2` to `Community 1`, `Community 3`, `Community 4`, `Community 5`, `Community 7`, `Community 8`, `Community 9`, `Community 11`, `Community 12`, `Community 14`, `Community 21`, `Community 22`?**
_High betweenness centrality (0.139) - this node is a cross-community bridge._
- **Why does `success_response()` connect `Community 0` to `Community 2`, `Community 3`, `Community 7`, `Community 11`, `Community 13`, `Community 14`, `Community 29`?**
_High betweenness centrality (0.045) - this node is a cross-community bridge._
- **Why does `generate_uuid()` connect `Community 1` to `Community 0`, `Community 2`, `Community 3`, `Community 5`, `Community 6`, `Community 7`, `Community 8`, `Community 9`, `Community 10`, `Community 11`, `Community 13`, `Community 14`, `Community 16`, `Community 17`, `Community 18`, `Community 19`, `Community 21`, `Community 22`?**
_High betweenness centrality (0.037) - this node is a cross-community bridge._
- **Are the 777 inferred relationships involving `str` (e.g. with `unhandled_exception_handler()` and `get_current_user_by_token()`) actually correct?**
_`str` has 777 INFERRED edges - model-reasoned connections that need verification._
- **Are the 706 inferred relationships involving `success_response()` (e.g. with `list_storage_release_reviews()` and `get_storage_release_review_detail()`) actually correct?**
_`success_response()` has 706 INFERRED edges - model-reasoned connections that need verification._
- **Are the 585 inferred relationships involving `error_response()` (e.g. with `_json_error_response()` and `list_storage_release_reviews()`) actually correct?**
_`error_response()` has 585 INFERRED edges - model-reasoned connections that need verification._
- **Are the 535 inferred relationships involving `SysUser` (e.g. with `数据权限过滤(V0.3:基于角色 data_scope 的查询级行级过滤) data_scope 值: 1 = 全部数据 2 = 本部门数据 3` and `从 SysUser 读取用户的 dept_id。`) actually correct?**
_`SysUser` has 535 INFERRED edges - model-reasoned connections that need verification._
- **Are the 780 inferred relationships involving `str` (e.g. with `unhandled_exception_handler()` and `get_current_user_by_token()`) actually correct?**
_`str` has 780 INFERRED edges - model-reasoned connections that need verification._
- **Are the 707 inferred relationships involving `success_response()` (e.g. with `list_storage_release_reviews()` and `get_storage_release_review_detail()`) actually correct?**
_`success_response()` has 707 INFERRED edges - model-reasoned connections that need verification._
- **Are the 586 inferred relationships involving `error_response()` (e.g. with `_json_error_response()` and `list_storage_release_reviews()`) actually correct?**
_`error_response()` has 586 INFERRED edges - model-reasoned connections that need verification._
- **Are the 549 inferred relationships involving `SysUser` (e.g. with `数据权限过滤(V0.3:基于角色 data_scope 的查询级行级过滤) data_scope 值: 1 = 全部数据 2 = 本部门数据 3` and `从 SysUser 读取用户的 dept_id。`) actually correct?**
_`SysUser` has 549 INFERRED edges - model-reasoned connections that need verification._
+4 -4
View File
@@ -57,12 +57,12 @@
</div>
<div id="legend"></div>
</div>
<div id="stats">4738 nodes &middot; 26131 edges &middot; 44 communities</div>
<div id="stats">4764 nodes &middot; 26310 edges &middot; 45 communities</div>
</div>
<script>
const RAW_NODES = [{"id": "init_py", "label": "__init__.py", "color": {"background": "#E15759", "border": "#E15759", "highlight": {"background": "#ffffff", "border": "#E15759"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "__init__.py", "community": 32, "community_name": "Community 32", "source_file": "__init__.py", "file_type": "code", "degree": 0}, {"id": "main_py", "label": "main.py", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "main.py", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "code", "degree": 7}, {"id": "app_main_lifespan", "label": "lifespan()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "lifespan()", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "code", "degree": 4}, {"id": "app_main_error_json", "label": "_error_json()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "_error_json()", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "code", "degree": 3}, {"id": "app_main_sqlalchemy_exception_handler", "label": "sqlalchemy_exception_handler()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "sqlalchemy_exception_handler()", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "code", "degree": 4}, {"id": "app_main_unhandled_exception_handler", "label": "unhandled_exception_handler()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "unhandled_exception_handler()", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "code", "degree": 5}, {"id": "app_main_mask_secret", "label": "_mask_secret()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "_mask_secret()", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "code", "degree": 1}, {"id": "app_main_root", "label": "root()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "root()", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "code", "degree": 1}, {"id": "app_main_health_check", "label": "health_check()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "health_check()", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "code", "degree": 1}, {"id": "app_main_rationale_81", "label": "\u6570\u636e\u5e93\u5f02\u5e38\uff1a\u8fd4\u56de JSON \u5e76\u4fdd\u7559 CORS \u5934\uff0c\u907f\u514d\u6d4f\u89c8\u5668\u53ea\u62a5\u8de8\u57df\u9519\u8bef", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "\u6570\u636e\u5e93\u5f02\u5e38\uff1a\u8fd4\u56de JSON \u5e76\u4fdd\u7559 CORS \u5934\uff0c\u907f\u514d\u6d4f\u89c8\u5668\u53ea\u62a5\u8de8\u57df\u9519\u8bef", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "rationale", "degree": 3}, {"id": "app_main_rationale_92", "label": "\u672a\u6355\u83b7\u5f02\u5e38\uff1a\u7edf\u4e00 JSON 500\uff0c\u786e\u4fdd\u8de8\u57df\u573a\u666f\u4e0b\u4ecd\u6709 Access-Control-Allow-Origin", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "\u672a\u6355\u83b7\u5f02\u5e38\uff1a\u7edf\u4e00 JSON 500\uff0c\u786e\u4fdd\u8de8\u57df\u573a\u666f\u4e0b\u4ecd\u6709 Access-Control-Allow-Origin", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "rationale", "degree": 3}, {"id": "tasks_init_py", "label": "__init__.py", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "__init__.py", "community": 7, "community_name": "Community 7", "source_file": "tasks/__init__.py", "file_type": "code", "degLine truncated
const RAW_EDGES = [{"from": "main_py", "to": "app_main_lifespan", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_error_json", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_sqlalchemy_exception_handler", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_unhandled_exception_handler", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_mask_secret", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_root", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_health_check", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_lifespan", "to": "core_login_crypto_ensure_initialized", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_lifespan", "to": "tasks_init_init_scheduled_tasks", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_lifespan", "to": "tasks_init_shutdown_scheduler", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_error_json", "to": "app_main_sqlalchemy_exception_handler", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_error_json", "to": "app_main_unhandled_exception_handler", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_sqlalchemy_exception_handler", "to": "app_main_rationale_81", "label": "rationale_for", "title": "rationale_for [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_sqlalchemy_exception_handler", "to": "exception", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_unhandled_exception_handler", "to": "app_main_rationale_92", "label": "rationale_for", "title": "rationale_for [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_unhandled_exception_handler", "to": "exception", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_unhandled_exception_handler", "to": "str", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_rationale_81", "to": "core_api_request_log_middleware_apirequestlogmiddleware", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_rationale_81", "to": "core_api_crypto_middleware_apicryptomiddleware", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_rationale_92", "to": "core_api_request_log_middleware_apirequestlogmiddleware", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_rationale_92", "to": "core_api_crypto_middleware_apicryptomiddleware", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "tasks_init_py", "to": "tasks_init_init_scheduled_tasks", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tasks_init_py", "to": "tasks_init_shutdown_scheduler", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_redis_session_enabled", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_get_redis_client", "labeLine truncated
const LEGEND = [{"cid": 0, "color": "#4E79A7", "label": "Community 0", "count": 952}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 804}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 714}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 552}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 303}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 272}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 205}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 196}, {"cid": 8, "color": "#9C755F", "label": "Community 8", "count": 159}, {"cid": 9, "color": "#BAB0AC", "label": "Community 9", "count": 149}, {"cid": 10, "color": "#4E79A7", "label": "Community 10", "count": 119}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 47}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 40}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 29}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 23}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 22}, {"cid": 16, "color": "#B07AA1", "label": "Community 16", "count": 21}, {"cid": 17, "color": "#FF9DA7", "label": "Community 17", "count": 14}, {"cid": 18, "color": "#9C755F", "label": "Community 18", "count": 13}, {"cid": 19, "color": "#BAB0AC", "label": "Community 19", "count": 13}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 12}, {"cid": 21, "color": "#F28E2B", "label": "Community 21", "count": 12}, {"cid": 22, "color": "#E15759", "label": "Community 22", "count": 12}, {"cid": 23, "color": "#76B7B2", "label": "Community 23", "count": 11}, {"cid": 24, "color": "#59A14F", "label": "Community 24", "count": 8}, {"cid": 25, "color": "#EDC948", "label": "Community 25", "count": 7}, {"cid": 26, "color": "#B07AA1", "label": "Community 26", "count": 4}, {"cid": 27, "color": "#FF9DA7", "label": "Community 27", "count": 4}, {"cid": 28, "color": "#9C755F", "label": "Community 28", "count": 3}, {"cid": 29, "color": "#BAB0AC", "label": "Community 29", "count": 2}, {"cid": 30, "color": "#4E79A7", "label": "Community 30", "count": 2}, {"cid": 31, "color": "#F28E2B", "label": "Community 31", "count": 2}, {"cid": 32, "color": "#E15759", "label": "Community 32", "count": 1}, {"cid": 33, "color": "#76B7B2", "label": "Community 33", "count": 1}, {"cid": 34, "color": "#59A14F", "label": "Community 34", "count": 1}, {"cid": 35, "color": "#EDC948", "label": "Community 35", "count": 1}, {"cid": 36, "color": "#B07AA1", "label": "Community 36", "count": 1}, {"cid": 37, "color": "#FF9DA7", "label": "Community 37", "count": 1}, {"cid": 38, "color": "#9C755F", "label": "Community 38", "count": 1}, {"cid": 39, "color": "#BAB0AC", "label": "Community 39", "count": 1}, {"cid": 40, "color": "#4E79A7", "label": "Community 40", "count": 1}, {"cid": 41, "color": "#F28E2B", "label": "Community 41", "count": 1}, {"cid": 42, "color": "#E15759", "label": "Community 42", "count": 1}, {"cid": 43, "color": "#76B7B2", "label": "Community 43", "count": 1}, {"cid": 44, "color": "#59A14F", "label": "Community 44", "count": 0}, {"cid": 45, "color": "#EDC948", "label": "Community 45", "count": 0}, {"cid": 46, "color": "#B07AA1", "label": "Community 46", "count": 0}, {"cid": 47, "color": "#FF9DA7", "label": "Community 47", "count": 0}, {"cid": 48, "color": "#9C755F", "label": "Community 48", "count": 0}, {"cid": 49, "color": "#BAB0AC", "label": "Community 49", "count": 0}, {"cid": 50, "color": "#4E79A7", "label": "Community 50", "count": 0}, {"cid": 51, "color": "#F28E2B", "label": "Community 51", "count": 0}, {"cid": 52, "color": "#E15759", "label": "Community 52", "count": 0}, {"cid": 53, "color": "#76B7B2", "label": "Community 53", "count": 0}, {"cid": 54, "color": "#59A14F", "label": "Community 54", "count": 0}, {"cid": 55, "color": "#EDC948", "label": "Community 55", "count": 0}, {"cid": 56, "color": "#B07AA1", "label": "Community 56", "count": 0}, {"cid": 57, "color": "#FF9DA7", "label": "Community 57", "count": 0}, {"cid": 58, "color": "#9C755F", "label": "Community 58", "count": 0}];
const RAW_NODES = [{"id": "init_py", "label": "__init__.py", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "__init__.py", "community": 33, "community_name": "Community 33", "source_file": "__init__.py", "file_type": "code", "degree": 0}, {"id": "main_py", "label": "main.py", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "main.py", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "code", "degree": 7}, {"id": "app_main_lifespan", "label": "lifespan()", "color": {"background": "#59A14F", "border": "#59A14F", "highlight": {"background": "#ffffff", "border": "#59A14F"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "lifespan()", "community": 14, "community_name": "Community 14", "source_file": "main.py", "file_type": "code", "degree": 4}, {"id": "app_main_error_json", "label": "_error_json()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "_error_json()", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "code", "degree": 3}, {"id": "app_main_sqlalchemy_exception_handler", "label": "sqlalchemy_exception_handler()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "sqlalchemy_exception_handler()", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "code", "degree": 4}, {"id": "app_main_unhandled_exception_handler", "label": "unhandled_exception_handler()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "unhandled_exception_handler()", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "code", "degree": 5}, {"id": "app_main_mask_secret", "label": "_mask_secret()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "_mask_secret()", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "code", "degree": 1}, {"id": "app_main_root", "label": "root()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "root()", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "code", "degree": 1}, {"id": "app_main_health_check", "label": "health_check()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "health_check()", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "code", "degree": 1}, {"id": "app_main_rationale_81", "label": "\u6570\u636e\u5e93\u5f02\u5e38\uff1a\u8fd4\u56de JSON \u5e76\u4fdd\u7559 CORS \u5934\uff0c\u907f\u514d\u6d4f\u89c8\u5668\u53ea\u62a5\u8de8\u57df\u9519\u8bef", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "\u6570\u636e\u5e93\u5f02\u5e38\uff1a\u8fd4\u56de JSON \u5e76\u4fdd\u7559 CORS \u5934\uff0c\u907f\u514d\u6d4f\u89c8\u5668\u53ea\u62a5\u8de8\u57df\u9519\u8bef", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "rationale", "degree": 3}, {"id": "app_main_rationale_92", "label": "\u672a\u6355\u83b7\u5f02\u5e38\uff1a\u7edf\u4e00 JSON 500\uff0c\u786e\u4fdd\u8de8\u57df\u573a\u666f\u4e0b\u4ecd\u6709 Access-Control-Allow-Origin", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "\u672a\u6355\u83b7\u5f02\u5e38\uff1a\u7edf\u4e00 JSON 500\uff0c\u786e\u4fdd\u8de8\u57df\u573a\u666f\u4e0b\u4ecd\u6709 Access-Control-Allow-Origin", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "rationale", "degree": 3}, {"id": "tasks_init_py", "label": "__init__.py", "color": {"background": "#59A14F", "border": "#59A14F", "highlight": {"background": "#ffffff", "border": "#59A14F"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "__init__.py", "community": 14, "community_name": "Community 14", "source_file": "tasks/__init__.py", "file_type": "code", Line truncated
const RAW_EDGES = [{"from": "main_py", "to": "app_main_lifespan", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_error_json", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_sqlalchemy_exception_handler", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_unhandled_exception_handler", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_mask_secret", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_root", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_health_check", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_lifespan", "to": "core_login_crypto_ensure_initialized", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_lifespan", "to": "tasks_init_init_scheduled_tasks", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_lifespan", "to": "tasks_init_shutdown_scheduler", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_error_json", "to": "app_main_sqlalchemy_exception_handler", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_error_json", "to": "app_main_unhandled_exception_handler", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_sqlalchemy_exception_handler", "to": "app_main_rationale_81", "label": "rationale_for", "title": "rationale_for [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_sqlalchemy_exception_handler", "to": "exception", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_unhandled_exception_handler", "to": "app_main_rationale_92", "label": "rationale_for", "title": "rationale_for [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_unhandled_exception_handler", "to": "exception", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_unhandled_exception_handler", "to": "str", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_rationale_81", "to": "core_api_request_log_middleware_apirequestlogmiddleware", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_rationale_81", "to": "core_api_crypto_middleware_apicryptomiddleware", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_rationale_92", "to": "core_api_request_log_middleware_apirequestlogmiddleware", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_rationale_92", "to": "core_api_crypto_middleware_apicryptomiddleware", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "tasks_init_py", "to": "tasks_init_init_scheduled_tasks", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tasks_init_py", "to": "tasks_init_shutdown_scheduler", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_redis_session_enabled", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_get_redis_client", "labeLine truncated
const LEGEND = [{"cid": 0, "color": "#4E79A7", "label": "Community 0", "count": 964}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 829}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 640}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 382}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 378}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 261}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 208}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 181}, {"cid": 8, "color": "#9C755F", "label": "Community 8", "count": 162}, {"cid": 9, "color": "#BAB0AC", "label": "Community 9", "count": 124}, {"cid": 10, "color": "#4E79A7", "label": "Community 10", "count": 123}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 107}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 72}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 70}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 58}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 31}, {"cid": 16, "color": "#B07AA1", "label": "Community 16", "count": 28}, {"cid": 17, "color": "#FF9DA7", "label": "Community 17", "count": 21}, {"cid": 18, "color": "#9C755F", "label": "Community 18", "count": 20}, {"cid": 19, "color": "#BAB0AC", "label": "Community 19", "count": 14}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 13}, {"cid": 21, "color": "#F28E2B", "label": "Community 21", "count": 12}, {"cid": 22, "color": "#E15759", "label": "Community 22", "count": 12}, {"cid": 23, "color": "#76B7B2", "label": "Community 23", "count": 8}, {"cid": 24, "color": "#59A14F", "label": "Community 24", "count": 7}, {"cid": 25, "color": "#EDC948", "label": "Community 25", "count": 6}, {"cid": 26, "color": "#B07AA1", "label": "Community 26", "count": 4}, {"cid": 27, "color": "#FF9DA7", "label": "Community 27", "count": 4}, {"cid": 28, "color": "#9C755F", "label": "Community 28", "count": 4}, {"cid": 29, "color": "#BAB0AC", "label": "Community 29", "count": 3}, {"cid": 30, "color": "#4E79A7", "label": "Community 30", "count": 2}, {"cid": 31, "color": "#F28E2B", "label": "Community 31", "count": 2}, {"cid": 32, "color": "#E15759", "label": "Community 32", "count": 2}, {"cid": 33, "color": "#76B7B2", "label": "Community 33", "count": 1}, {"cid": 34, "color": "#59A14F", "label": "Community 34", "count": 1}, {"cid": 35, "color": "#EDC948", "label": "Community 35", "count": 1}, {"cid": 36, "color": "#B07AA1", "label": "Community 36", "count": 1}, {"cid": 37, "color": "#FF9DA7", "label": "Community 37", "count": 1}, {"cid": 38, "color": "#9C755F", "label": "Community 38", "count": 1}, {"cid": 39, "color": "#BAB0AC", "label": "Community 39", "count": 1}, {"cid": 40, "color": "#4E79A7", "label": "Community 40", "count": 1}, {"cid": 41, "color": "#F28E2B", "label": "Community 41", "count": 1}, {"cid": 42, "color": "#E15759", "label": "Community 42", "count": 1}, {"cid": 43, "color": "#76B7B2", "label": "Community 43", "count": 1}, {"cid": 44, "color": "#59A14F", "label": "Community 44", "count": 1}, {"cid": 45, "color": "#EDC948", "label": "Community 45", "count": 0}, {"cid": 46, "color": "#B07AA1", "label": "Community 46", "count": 0}, {"cid": 47, "color": "#FF9DA7", "label": "Community 47", "count": 0}, {"cid": 48, "color": "#9C755F", "label": "Community 48", "count": 0}, {"cid": 49, "color": "#BAB0AC", "label": "Community 49", "count": 0}, {"cid": 50, "color": "#4E79A7", "label": "Community 50", "count": 0}, {"cid": 51, "color": "#F28E2B", "label": "Community 51", "count": 0}, {"cid": 52, "color": "#E15759", "label": "Community 52", "count": 0}, {"cid": 53, "color": "#76B7B2", "label": "Community 53", "count": 0}, {"cid": 54, "color": "#59A14F", "label": "Community 54", "count": 0}, {"cid": 55, "color": "#EDC948", "label": "Community 55", "count": 0}, {"cid": 56, "color": "#B07AA1", "label": "Community 56", "count": 0}, {"cid": 57, "color": "#FF9DA7", "label": "Community 57", "count": 0}, {"cid": 58, "color": "#9C755F", "label": "Community 58", "count": 0}];
// HTML-escape helper — prevents XSS when injecting graph data into innerHTML
function esc(s) {
File diff suppressed because it is too large. Load diff
+4 -4
View File
@@ -129,7 +129,7 @@
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task_assignee.py": 1781233180.3766735,
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation_sample_collection.py": 1782886678.892387,
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_material_amount_auth.py": 1783919120.0033576,
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/oa_approval.py": 1784098244.5513778,
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/oa_approval.py": 1784268777.2856126,
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py": 1782886679.0930216,
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/menu.py": 1779265729.0381103,
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_region.py": 1782181887.2821388,
@@ -194,7 +194,7 @@
"/Users/wuzilong/work/00code/zkxw/backend/app/api/pre_transit_sample.py": 1782204426.7965167,
"/Users/wuzilong/work/00code/zkxw/backend/app/api/qc_sms_notification.py": 1780326875.7886882,
"/Users/wuzilong/work/00code/zkxw/backend/app/api/research_donation_sample_collection.py": 1780457788.2998126,
"/Users/wuzilong/work/00code/zkxw/backend/app/api/oa_approval.py": 1784098244.5513089,
"/Users/wuzilong/work/00code/zkxw/backend/app/api/oa_approval.py": 1784276041.1519969,
"/Users/wuzilong/work/00code/zkxw/backend/app/api/operations.py": 1782699385.46194,
"/Users/wuzilong/work/00code/zkxw/backend/app/api/menu.py": 1784019084.7225814,
"/Users/wuzilong/work/00code/zkxw/backend/app/api/pilot_delivery.py": 1779655584.820777,
@@ -212,11 +212,11 @@
"/Users/wuzilong/work/00code/zkxw/backend/app/api/protocol_sample_collection.py": 1780457788.2093296,
"/Users/wuzilong/work/00code/zkxw/backend/app/api/leave.py": 1779266168.8693042,
"/Users/wuzilong/work/00code/zkxw/backend/app/api/clinical_payment.py": 1781750841.074568,
"/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py": 1784101603.3058455,
"/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_engine.py": 1784277512.4851213,
"/Users/wuzilong/work/00code/zkxw/backend/app/services/workflow_callback.py": 1778727966.7277644,
"/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py": 1783329884.6125586,
"/Users/wuzilong/work/00code/zkxw/backend/app/services/storage_facility_code.py": 1782289322.2116506,
"/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py": 1784173365.9587312,
"/Users/wuzilong/work/00code/zkxw/backend/app/services/oa_publish.py": 1784273815.281037,
"/Users/wuzilong/work/00code/zkxw/backend/app/services/workflow_engine.py": 1778634664.6293883,
"/Users/wuzilong/work/00code/zkxw/backend/app/services/web_auth_roles.py": 1782122624.7941194,
"/Users/wuzilong/work/00code/zkxw/backend/app/services/protocol_payment_installment.py": 1781432208.0765035,
+128
View File
@@ -510,6 +510,134 @@ class TestBuildProgress(unittest.TestCase):
pending = [x for x in items if x["kind"] == "pending_node"]
self.assertTrue(any(p["nodeKey"] == "a2" for p in pending))
def test_running_shows_all_subsequent_pending_nodes(self):
"""进行中应挂出路径上全部后续节点,而非只露一个空壳。"""
from app.services.oa_engine import build_progress_items
root = {
"id": "s",
"type": "start",
"child": {
"id": "a1",
"type": "approval",
"name": "一级审批",
"child": {
"id": "a2",
"type": "approval",
"name": "二级审批",
"child": {
"id": "a3",
"type": "approval",
"name": "三级审批",
"child": {"id": "e1", "type": "end"},
},
},
},
}
ts = datetime(2026, 7, 17, 11, 0, 0)
t1 = MagicMock(
id="t1",
node_key="a1",
node_name="一级审批",
task_type="approval",
status="pending",
assignee_user_id="u1",
order_num=0,
round_no=1,
create_time=ts,
update_time=ts,
comment_text=None,
resolve_source="users",
sign_mode="or",
)
inst = MagicMock(
status="running",
initiator_user_id="u0",
current_round=1,
create_time=ts,
update_time=ts,
form_data_json="{}",
tenant_no="t1",
initiator_dept_id="",
)
items = build_progress_items(
inst=inst,
flow_root=root,
tasks=[t1],
name_map={"u0": "发起人", "u1": "甲"},
events=[],
)
pending = [x for x in items if x["kind"] == "pending_node"]
self.assertEqual([p["nodeKey"] for p in pending], ["a2", "a3", "e1"])
self.assertEqual([p["title"] for p in pending], ["二级审批", "三级审批", "结束"])
self.assertEqual(pending[-1]["taskType"], "end")
def test_or_sign_same_node_merged_into_one_card(self):
"""或签同节点三人只投影一张进度卡片,people 含各人状态。"""
from app.services.oa_engine import build_progress_items
root = {
"id": "s",
"type": "start",
"child": {
"id": "a1",
"type": "approval",
"name": "部门审批",
"child": {"id": "e1", "type": "end"},
},
}
ts = datetime(2026, 7, 17, 10, 0, 0)
ts2 = datetime(2026, 7, 17, 10, 5, 0)
def mk(tid, uid, status, comment=None, update=None):
return MagicMock(
id=tid,
node_key="a1",
node_name="部门审批",
task_type="approval",
status=status,
assignee_user_id=uid,
order_num=0,
round_no=1,
create_time=ts,
update_time=update or ts,
comment_text=comment,
resolve_source="users",
sign_mode="or",
)
tasks = [
mk("t1", "u1", "approved", "同意", ts2),
mk("t2", "u2", "done"),
mk("t3", "u3", "done"),
]
inst = MagicMock(
status="completed",
initiator_user_id="u0",
current_round=1,
create_time=ts,
update_time=ts2,
)
items = build_progress_items(
inst=inst,
flow_root=root,
tasks=tasks,
name_map={"u0": "发起人", "u1": "甲", "u2": "乙", "u3": "丙"},
events=[],
)
task_items = [x for x in items if x["kind"] == "task"]
self.assertEqual(len(task_items), 1)
card = task_items[0]
self.assertEqual(card["nodeKey"], "a1")
self.assertEqual(card["status"], "approved")
self.assertEqual(card["signMode"], "or")
self.assertEqual(len(card["people"]), 3)
self.assertEqual(
[(p["nickName"], p["status"]) for p in card["people"]],
[("甲", "approved"), ("乙", "done"), ("丙", "done")],
)
self.assertIn("甲:同意", card["commentText"])
def test_terminal_status_excludes_pending_nodes(self):
from app.services.oa_engine import build_progress_items
+150
View File
@@ -0,0 +1,150 @@
"""OA 发起预览:条件字段门闩与单路 walk"""
import unittest
from unittest.mock import MagicMock, patch
from app.services.oa_engine import (
_FLOW_PREVIEW_PENDING_MSG,
_collect_condition_fields,
_condition_fields_ready,
_form_value_present,
_walk_preview_nodes,
)
def _cond_flow():
return {
"id": "s",
"type": "start",
"name": "发起人",
"child": {
"id": "a0",
"type": "approval",
"name": "一级审批",
"approverConfig": {"assigneeType": "users", "userIds": ["u1"], "signMode": "or"},
"child": {
"id": "c1",
"type": "condition",
"conditionGroups": [
{
"name": "条件1",
"rules": [{"field": "days", "op": ">", "value": 3}],
"child": {
"id": "a1",
"type": "approval",
"name": "董事长审批",
"approverConfig": {
"assigneeType": "users",
"userIds": ["u2"],
"signMode": "or",
},
"child": {"id": "e1", "type": "end", "name": "结束"},
},
},
{
"name": "默认",
"isDefault": True,
"rules": [],
"child": {"id": "e2", "type": "end", "name": "结束"},
},
],
},
},
}
class TestFormValuePresent(unittest.TestCase):
def test_empty(self):
self.assertFalse(_form_value_present({}, "days"))
self.assertFalse(_form_value_present({"days": None}, "days"))
self.assertFalse(_form_value_present({"days": ""}, "days"))
self.assertFalse(_form_value_present({"days": " "}, "days"))
self.assertFalse(_form_value_present({"days": []}, "days"))
def test_present(self):
self.assertTrue(_form_value_present({"days": 0}, "days"))
self.assertTrue(_form_value_present({"ok": False}, "ok"))
self.assertTrue(_form_value_present({"days": 5}, "days"))
self.assertTrue(_form_value_present({"t": "事假"}, "t"))
class TestCollectConditionFields(unittest.TestCase):
def test_linear_no_fields(self):
root = {
"id": "s",
"type": "start",
"child": {"id": "e", "type": "end"},
}
self.assertEqual(_collect_condition_fields(root), [])
self.assertTrue(_condition_fields_ready(root, {}))
def test_rules_field(self):
root = _cond_flow()
self.assertEqual(_collect_condition_fields(root), ["days"])
self.assertFalse(_condition_fields_ready(root, {}))
self.assertTrue(_condition_fields_ready(root, {"days": 5}))
def test_when_formula_fields(self):
root = {
"type": "condition",
"conditionGroups": [
{"name": "x", "when": "{days} > 3 and {leaveType} == '事假'", "child": {}},
{"name": "d", "isDefault": True, "rules": []},
],
}
self.assertEqual(_collect_condition_fields(root), ["days", "leaveType"])
class TestWalkPreviewResolvedPath(unittest.TestCase):
def test_hit_condition1(self):
db = MagicMock()
steps = []
with patch("app.services.oa_engine.resolve_assignees", return_value=(["u1"], {})), patch(
"app.services.oa_engine._preview_people",
side_effect=lambda _db, ids: [{"id": i, "nickName": i} for i in ids],
), patch("app.services.oa_engine._assignee_meta", return_value="指定成员"):
ok = _walk_preview_nodes(
db,
node=_cond_flow(),
tenant_no="t1",
initiator_user_id="init",
initiator_dept_id=None,
advanced={},
initiator_select_user_ids=None,
form_data={"days": 5},
steps=steps,
)
self.assertTrue(ok)
types = [s["type"] for s in steps]
names = [s["name"] for s in steps]
self.assertNotIn("branch", types)
self.assertEqual(names, ["发起人", "一级审批", "董事长审批", "结束"])
def test_hit_default(self):
db = MagicMock()
steps = []
with patch("app.services.oa_engine.resolve_assignees", return_value=(["u1"], {})), patch(
"app.services.oa_engine._preview_people",
side_effect=lambda _db, ids: [{"id": i, "nickName": i} for i in ids],
), patch("app.services.oa_engine._assignee_meta", return_value="指定成员"):
ok = _walk_preview_nodes(
db,
node=_cond_flow(),
tenant_no="t1",
initiator_user_id="init",
initiator_dept_id=None,
advanced={},
initiator_select_user_ids=None,
form_data={"days": 1},
steps=steps,
)
self.assertTrue(ok)
names = [s["name"] for s in steps]
self.assertEqual(names, ["发起人", "一级审批", "结束"])
self.assertNotIn("董事长审批", names)
def test_pending_message_constant(self):
self.assertEqual(_FLOW_PREVIEW_PENDING_MSG, "必填信息填写后,流程将自动显示")
if __name__ == "__main__":
unittest.main()
-196
View File
@@ -1,196 +0,0 @@
-- OA 审批(钉钉交互)增量脚本 — 2026-07-14
-- 执行前请备份;可重复执行时注意 IGNORE 语义(部分语句非幂等)
-- ---------------------------------------------------------------------------
-- 1. 组织字段:直属主管 / 部门负责人用户 ID
-- ---------------------------------------------------------------------------
ALTER TABLE sys_user
ADD COLUMN supervisor_user_id VARCHAR(64) NULL COMMENT '直属主管用户ID' AFTER dept_id;
ALTER TABLE sys_dept
ADD COLUMN leader_user_id VARCHAR(64) NULL COMMENT '部门负责人用户ID' AFTER status;
-- ---------------------------------------------------------------------------
-- 2. OA 审批核心表
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS oa_app_group (
id VARCHAR(64) NOT NULL COMMENT '主键ID',
group_name VARCHAR(100) NOT NULL COMMENT '分组名称',
tenant_no VARCHAR(64) NOT NULL DEFAULT 'zkxw' COMMENT '租户编号',
order_num INT NULL COMMENT '排序号',
remark VARCHAR(512) NULL COMMENT '备注',
create_by VARCHAR(64) NULL COMMENT '创建人id',
create_dept_id VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建人部门ID',
create_time DATETIME NOT NULL COMMENT '创建时间',
update_by VARCHAR(64) NULL COMMENT '更新人id',
update_time DATETIME NOT NULL COMMENT '更新时间',
del_flag SMALLINT NOT NULL DEFAULT 0 COMMENT '删除标记',
PRIMARY KEY (id),
KEY idx_oa_app_group_tenant (tenant_no, del_flag)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='OA审批分组';
CREATE TABLE IF NOT EXISTS oa_app (
id VARCHAR(64) NOT NULL COMMENT '主键ID',
group_id VARCHAR(64) NULL COMMENT '分组ID',
app_name VARCHAR(50) NOT NULL COMMENT '表单/应用名称',
icon_url VARCHAR(512) NULL COMMENT '图标',
description VARCHAR(100) NULL COMMENT '表单说明',
initiator_scope VARCHAR(32) NOT NULL DEFAULT 'all' COMMENT '发起范围 all/users',
initiator_user_ids TEXT NULL COMMENT '指定发起人JSON数组',
admin_scope VARCHAR(32) NOT NULL DEFAULT 'all_oa_admin' COMMENT '管理员范围',
admin_user_ids TEXT NULL COMMENT '指定管理员JSON数组',
status CHAR(1) NOT NULL DEFAULT '1' COMMENT '1启用 0停用',
tenant_no VARCHAR(64) NOT NULL DEFAULT 'zkxw' COMMENT '租户编号',
order_num INT NULL COMMENT '排序号',
remark VARCHAR(512) NULL COMMENT '备注',
create_by VARCHAR(64) NULL COMMENT '创建人id',
create_dept_id VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建人部门ID',
create_time DATETIME NOT NULL COMMENT '创建时间',
update_by VARCHAR(64) NULL COMMENT '更新人id',
update_time DATETIME NOT NULL COMMENT '更新时间',
del_flag SMALLINT NOT NULL DEFAULT 0 COMMENT '删除标记',
PRIMARY KEY (id),
KEY idx_oa_app_tenant (tenant_no, del_flag),
KEY idx_oa_app_group (group_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='OA审批应用';
CREATE TABLE IF NOT EXISTS oa_app_version (
id VARCHAR(64) NOT NULL COMMENT '主键ID',
app_id VARCHAR(64) NOT NULL COMMENT '应用ID',
version_no INT NOT NULL COMMENT '版本号',
status VARCHAR(16) NOT NULL DEFAULT 'draft' COMMENT 'draft/published',
is_latest_published CHAR(1) NOT NULL DEFAULT '0' COMMENT '是否最新已发布',
form_schema_json LONGTEXT NULL COMMENT '表单Schema JSON',
flow_tree_json LONGTEXT NULL COMMENT '流程树 JSON',
advanced_settings_json TEXT NULL COMMENT '高级设置 JSON',
tenant_no VARCHAR(64) NOT NULL DEFAULT 'zkxw' COMMENT '租户编号',
order_num INT NULL COMMENT '排序号',
remark VARCHAR(512) NULL COMMENT '备注',
create_by VARCHAR(64) NULL COMMENT '创建人id',
create_dept_id VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建人部门ID',
create_time DATETIME NOT NULL COMMENT '创建时间',
update_by VARCHAR(64) NULL COMMENT '更新人id',
update_time DATETIME NOT NULL COMMENT '更新时间',
del_flag SMALLINT NOT NULL DEFAULT 0 COMMENT '删除标记',
PRIMARY KEY (id),
KEY idx_oa_app_ver_app (app_id, status, del_flag)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='OA审批应用版本';
CREATE TABLE IF NOT EXISTS oa_role (
id VARCHAR(64) NOT NULL COMMENT '主键ID',
role_name VARCHAR(100) NOT NULL COMMENT '角色名称',
role_code VARCHAR(64) NOT NULL COMMENT '角色编码',
role_kind VARCHAR(16) NOT NULL DEFAULT 'custom' COMMENT 'custom/preset',
status CHAR(1) NOT NULL DEFAULT '1' COMMENT '1启用 0停用',
tenant_no VARCHAR(64) NOT NULL DEFAULT 'zkxw' COMMENT '租户编号',
order_num INT NULL COMMENT '排序号',
remark VARCHAR(512) NULL COMMENT '备注',
create_by VARCHAR(64) NULL COMMENT '创建人id',
create_dept_id VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建人部门ID',
create_time DATETIME NOT NULL COMMENT '创建时间',
update_by VARCHAR(64) NULL COMMENT '更新人id',
update_time DATETIME NOT NULL COMMENT '更新时间',
del_flag SMALLINT NOT NULL DEFAULT 0 COMMENT '删除标记',
PRIMARY KEY (id),
UNIQUE KEY uk_oa_role_tenant_code (tenant_no, role_code, del_flag),
KEY idx_oa_role_tenant (tenant_no, del_flag)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='OA工作流角色';
CREATE TABLE IF NOT EXISTS oa_role_user (
id VARCHAR(64) NOT NULL COMMENT '主键ID',
oa_role_id VARCHAR(64) NOT NULL COMMENT '工作流角色ID',
user_id VARCHAR(64) NOT NULL COMMENT '用户ID',
tenant_no VARCHAR(64) NOT NULL DEFAULT 'zkxw' COMMENT '租户编号',
order_num INT NULL COMMENT '排序号',
remark VARCHAR(512) NULL COMMENT '备注',
create_by VARCHAR(64) NULL COMMENT '创建人id',
create_dept_id VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建人部门ID',
create_time DATETIME NOT NULL COMMENT '创建时间',
update_by VARCHAR(64) NULL COMMENT '更新人id',
update_time DATETIME NOT NULL COMMENT '更新时间',
del_flag SMALLINT NOT NULL DEFAULT 0 COMMENT '删除标记',
PRIMARY KEY (id),
KEY idx_oa_role_user_role (oa_role_id, del_flag),
KEY idx_oa_role_user_user (user_id, del_flag)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='OA工作流角色成员';
CREATE TABLE IF NOT EXISTS oa_instance (
id VARCHAR(64) NOT NULL COMMENT '主键ID',
app_id VARCHAR(64) NOT NULL COMMENT '应用ID',
app_version_id VARCHAR(64) NOT NULL COMMENT '锁定的已发布版本ID',
title VARCHAR(200) NULL COMMENT '实例标题',
initiator_user_id VARCHAR(64) NOT NULL COMMENT '发起人',
initiator_dept_id VARCHAR(64) NULL COMMENT '发起人部门',
form_data_json LONGTEXT NULL COMMENT '表单数据 JSON',
status VARCHAR(32) NOT NULL DEFAULT 'running' COMMENT 'running/completed/rejected/cancelled',
tenant_no VARCHAR(64) NOT NULL DEFAULT 'zkxw' COMMENT '租户编号',
order_num INT NULL COMMENT '排序号',
remark VARCHAR(512) NULL COMMENT '备注',
create_by VARCHAR(64) NULL COMMENT '创建人id',
create_dept_id VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建人部门ID',
create_time DATETIME NOT NULL COMMENT '创建时间',
update_by VARCHAR(64) NULL COMMENT '更新人id',
update_time DATETIME NOT NULL COMMENT '更新时间',
del_flag SMALLINT NOT NULL DEFAULT 0 COMMENT '删除标记',
PRIMARY KEY (id),
KEY idx_oa_inst_tenant (tenant_no, del_flag),
KEY idx_oa_inst_initiator (initiator_user_id, status),
KEY idx_oa_inst_app (app_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='OA审批实例';
CREATE TABLE IF NOT EXISTS oa_task (
id VARCHAR(64) NOT NULL COMMENT '主键ID',
instance_id VARCHAR(64) NOT NULL COMMENT '实例ID',
node_key VARCHAR(64) NULL COMMENT '节点key',
node_name VARCHAR(200) NULL COMMENT '节点名称',
task_type VARCHAR(16) NOT NULL DEFAULT 'approval' COMMENT 'approval/cc',
assignee_user_id VARCHAR(64) NOT NULL COMMENT '处理人',
status VARCHAR(32) NOT NULL DEFAULT 'pending' COMMENT 'pending/approved/rejected/done',
comment_text VARCHAR(512) NULL COMMENT '意见',
resolve_source VARCHAR(64) NULL COMMENT '解析来源如 supervisor_fallback_dept_leader',
sign_mode VARCHAR(8) NULL COMMENT 'or/and',
tenant_no VARCHAR(64) NOT NULL DEFAULT 'zkxw' COMMENT '租户编号',
order_num INT NULL COMMENT '排序号',
remark VARCHAR(512) NULL COMMENT '备注',
create_by VARCHAR(64) NULL COMMENT '创建人id',
create_dept_id VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建人部门ID',
create_time DATETIME NOT NULL COMMENT '创建时间',
update_by VARCHAR(64) NULL COMMENT '更新人id',
update_time DATETIME NOT NULL COMMENT '更新时间',
del_flag SMALLINT NOT NULL DEFAULT 0 COMMENT '删除标记',
PRIMARY KEY (id),
KEY idx_oa_task_assignee (assignee_user_id, status, del_flag),
KEY idx_oa_task_instance (instance_id, del_flag)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='OA审批任务';
CREATE TABLE IF NOT EXISTS oa_relation (
id VARCHAR(64) NOT NULL COMMENT '主键ID',
from_instance_id VARCHAR(64) NOT NULL COMMENT '本实例ID',
to_instance_id VARCHAR(64) NOT NULL COMMENT '被关联实例ID',
field_key VARCHAR(64) NULL COMMENT '表单字段key',
tenant_no VARCHAR(64) NOT NULL DEFAULT 'zkxw' COMMENT '租户编号',
order_num INT NULL COMMENT '排序号',
remark VARCHAR(512) NULL COMMENT '备注',
create_by VARCHAR(64) NULL COMMENT '创建人id',
create_dept_id VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建人部门ID',
create_time DATETIME NOT NULL COMMENT '创建时间',
update_by VARCHAR(64) NULL COMMENT '更新人id',
update_time DATETIME NOT NULL COMMENT '更新时间',
del_flag SMALLINT NOT NULL DEFAULT 0 COMMENT '删除标记',
PRIMARY KEY (id),
KEY idx_oa_rel_from (from_instance_id, del_flag)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='OA关联审批';
-- 预置工作流角色(按租户手工或应用启动 ensure;此处示例 zkxw)
-- INSERT 由后端 ensure_presets 幂等完成,避免 UUID 硬编码冲突
-- ---------------------------------------------------------------------------
-- 3. 菜单说明
-- ---------------------------------------------------------------------------
-- 侧栏路由已写入:
-- - web-admin/src/router/modules/sqxp.ts
-- - backend/app/api/menu.py(STATIC_MENU_TREE)
-- 角色权限用的 sys_menu 注册见:
-- docs/sql/patch_2026-07-15_oa_approval_sys_menu.sql
-- (含 OA审批 节点插入,以及旧「工作流管理」伪删除)
@@ -1,158 +0,0 @@
-- =============================================================================
-- OA 审批菜单注册 + 旧「工作流管理」伪删除
-- 日期:2026-07-15
-- 说明:
-- 1. 在「系统管理」顶级(TOP...00005)下注册「OA审批」及三级页面菜单,
-- id / path / component / perms 与 web-admin sqxp.ts、backend menu.py 对齐。
-- 2. 伪删除旧「工作流管理」二级及其三级菜单(OA 已替代),并清理角色菜单关联。
-- =============================================================================
SET NAMES utf8mb4;
-- ---------------------------------------------------------------------------
-- 1. 伪删除旧「工作流管理」及其子菜单
-- ---------------------------------------------------------------------------
UPDATE `sys_menu`
SET `del_flag` = 1,
`update_time` = NOW()
WHERE `del_flag` = 0
AND (
`id` = 'WKF00000000000000000000000000001'
OR `parent_id` = 'WKF00000000000000000000000000001'
OR `id` IN (
'10000000000000000000000000000wf01',
'10000000000000000000000000000wf02',
'10000000000000000000000000000wf03',
'10000000000000000000000000000wf04',
'10000000000000000000000000000wf05'
)
);
DELETE FROM `sys_role_menu`
WHERE `menu_id` IN (
'WKF00000000000000000000000000001',
'10000000000000000000000000000wf01',
'10000000000000000000000000000wf02',
'10000000000000000000000000000wf03',
'10000000000000000000000000000wf04',
'10000000000000000000000000000wf05'
);
-- ---------------------------------------------------------------------------
-- 2. 注册「OA审批」二级目录(挂在系统管理顶级下)
-- ---------------------------------------------------------------------------
INSERT INTO `sys_menu` (
`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`,
`is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`,
`create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`
)
SELECT
'OA000000000000000000000000000001', 'OA审批', 'TOP00000000000000000000000000005', 'M',
'oa-approval', NULL, NULL,
1, '1', '1', 'zkxw', 2, '钉钉式 OA 审批(替代旧工作流管理)',
NULL, '', NOW(), NULL, NOW(), 0
FROM DUAL
WHERE NOT EXISTS (
SELECT 1 FROM `sys_menu` WHERE `id` = 'OA000000000000000000000000000001'
);
-- 若曾假删过同 id,则恢复
UPDATE `sys_menu`
SET `del_flag` = 0,
`menu_name` = 'OA审批',
`parent_id` = 'TOP00000000000000000000000000005',
`menu_type` = 'M',
`path` = 'oa-approval',
`component` = NULL,
`perms` = NULL,
`visible` = '1',
`status` = '1',
`order_num` = 2,
`update_time` = NOW()
WHERE `id` = 'OA000000000000000000000000000001';
-- ---------------------------------------------------------------------------
-- 3. 注册 OA 三级菜单(可见页 + 隐藏详情/设计页)
-- ---------------------------------------------------------------------------
INSERT INTO `sys_menu` (
`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`,
`is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`,
`create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`
)
SELECT * FROM (
SELECT 'OA000000000000000000000000000101' AS id, '审批管理' AS menu_name,
'OA000000000000000000000000000001' AS parent_id, 'C' AS menu_type,
'apps' AS path, '/oa-approval/apps/index' AS component, 'oa:apps:list' AS perms,
1 AS is_frame, '1' AS visible, '1' AS status, 'zkxw' AS tenant_no, 1 AS order_num,
NULL AS remark, NULL AS create_by, '' AS create_dept_id, NOW() AS create_time,
NULL AS update_by, NOW() AS update_time, 0 AS del_flag
UNION ALL
SELECT 'OA000000000000000000000000000102', '工作流角色',
'OA000000000000000000000000000001', 'C',
'roles', '/oa-approval/roles/index', 'oa:roles:list',
1, '1', '1', 'zkxw', 2, NULL, NULL, '', NOW(), NULL, NOW(), 0
UNION ALL
SELECT 'OA000000000000000000000000000103', '发起审批',
'OA000000000000000000000000000001', 'C',
'start', '/oa-approval/start/index', 'oa:start',
1, '1', '1', 'zkxw', 3, NULL, NULL, '', NOW(), NULL, NOW(), 0
UNION ALL
SELECT 'OA000000000000000000000000000104', '待办中心',
'OA000000000000000000000000000001', 'C',
'pending', '/oa-approval/pending/index', 'oa:pending',
1, '1', '1', 'zkxw', 4, NULL, NULL, '', NOW(), NULL, NOW(), 0
UNION ALL
SELECT 'OA000000000000000000000000000105', '已办中心',
'OA000000000000000000000000000001', 'C',
'done', '/oa-approval/done/index', 'oa:done',
1, '1', '1', 'zkxw', 5, NULL, NULL, '', NOW(), NULL, NOW(), 0
UNION ALL
SELECT 'OA000000000000000000000000000106', '我发起的',
'OA000000000000000000000000000001', 'C',
'mine', '/oa-approval/mine/index', 'oa:mine',
1, '1', '1', 'zkxw', 6, NULL, NULL, '', NOW(), NULL, NOW(), 0
UNION ALL
SELECT 'OA000000000000000000000000000107', '抄送我的',
'OA000000000000000000000000000001', 'C',
'cc', '/oa-approval/cc/index', 'oa:cc',
1, '1', '1', 'zkxw', 7, NULL, NULL, '', NOW(), NULL, NOW(), 0
UNION ALL
SELECT 'OA000000000000000000000000000201', '审批设计',
'OA000000000000000000000000000001', 'C',
'designer/:id', '/oa-approval/designer/index', 'oa:designer',
1, '0', '1', 'zkxw', 8, '隐藏页:从审批管理进入', NULL, '', NOW(), NULL, NOW(), 0
UNION ALL
SELECT 'OA000000000000000000000000000202', '审批详情',
'OA000000000000000000000000000001', 'C',
'instances/:id', '/oa-approval/instances/detail', 'oa:instance:detail',
1, '0', '1', 'zkxw', 9, '隐藏页:从任务/列表进入', NULL, '', NOW(), NULL, NOW(), 0
) AS t
WHERE NOT EXISTS (
SELECT 1 FROM `sys_menu` m WHERE m.`id` = t.id
);
-- 幂等:已存在则同步字段并取消伪删除
UPDATE `sys_menu` m
JOIN (
SELECT 'OA000000000000000000000000000101' AS id, '审批管理' AS menu_name, 'apps' AS path,
'/oa-approval/apps/index' AS component, 'oa:apps:list' AS perms, '1' AS visible, 1 AS order_num
UNION ALL SELECT 'OA000000000000000000000000000102', '工作流角色', 'roles', '/oa-approval/roles/index', 'oa:roles:list', '1', 2
UNION ALL SELECT 'OA000000000000000000000000000103', '发起审批', 'start', '/oa-approval/start/index', 'oa:start', '1', 3
UNION ALL SELECT 'OA000000000000000000000000000104', '待办中心', 'pending', '/oa-approval/pending/index', 'oa:pending', '1', 4
UNION ALL SELECT 'OA000000000000000000000000000105', '已办中心', 'done', '/oa-approval/done/index', 'oa:done', '1', 5
UNION ALL SELECT 'OA000000000000000000000000000106', '我发起的', 'mine', '/oa-approval/mine/index', 'oa:mine', '1', 6
UNION ALL SELECT 'OA000000000000000000000000000107', '抄送我的', 'cc', '/oa-approval/cc/index', 'oa:cc', '1', 7
UNION ALL SELECT 'OA000000000000000000000000000201', '审批设计', 'designer/:id', '/oa-approval/designer/index', 'oa:designer', '0', 8
UNION ALL SELECT 'OA000000000000000000000000000202', '审批详情', 'instances/:id', '/oa-approval/instances/detail', 'oa:instance:detail', '0', 9
) s ON m.id = s.id
SET m.`del_flag` = 0,
m.`parent_id` = 'OA000000000000000000000000000001',
m.`menu_type` = 'C',
m.`menu_name` = s.menu_name,
m.`path` = s.path,
m.`component` = s.component,
m.`perms` = s.perms,
m.`visible` = s.visible,
m.`status` = '1',
m.`order_num` = s.order_num,
m.`update_time` = NOW();
@@ -1,14 +0,0 @@
-- OA 审批菜单重命名:待处理 → 待办中心,已处理 → 已办中心
-- 已执行过 patch_2026-07-15_oa_approval_sys_menu.sql 的环境可单独跑本脚本。
UPDATE `sys_menu`
SET `menu_name` = '待办中心',
`update_time` = NOW()
WHERE `id` = 'OA000000000000000000000000000104'
AND `del_flag` = 0;
UPDATE `sys_menu`
SET `menu_name` = '已办中心',
`update_time` = NOW()
WHERE `id` = 'OA000000000000000000000000000105'
AND `del_flag` = 0;
@@ -1,34 +0,0 @@
-- OA 审批进度多轮 + 打回 + 撤销重提关联
-- MySQL 5.7 / utf8mb4
ALTER TABLE oa_instance
ADD COLUMN source_instance_id VARCHAR(64) NULL COMMENT '撤销重提所关联的原实例ID' AFTER status,
ADD COLUMN current_round INT NOT NULL DEFAULT 1 COMMENT '当前提交轮次,从1起' AFTER source_instance_id;
-- status 语义:running / returned / completed / rejected / cancelled
-- returned = 已打回,待发起人修改再提交
ALTER TABLE oa_task
ADD COLUMN round_no INT NOT NULL DEFAULT 1 COMMENT '所属提交轮次' AFTER sign_mode;
CREATE TABLE IF NOT EXISTS oa_instance_event (
id VARCHAR(64) NOT NULL COMMENT '主键ID',
instance_id VARCHAR(64) NOT NULL COMMENT '实例ID',
round_no INT NOT NULL DEFAULT 1 COMMENT '轮次',
event_type VARCHAR(32) NOT NULL COMMENT 'submit/return/withdraw/complete/reject_end',
actor_user_id VARCHAR(64) NULL COMMENT '操作人',
task_id VARCHAR(64) NULL COMMENT '关联任务(打回时)',
node_key VARCHAR(64) NULL COMMENT '节点key',
comment_text VARCHAR(512) NULL COMMENT '意见',
tenant_no VARCHAR(64) NOT NULL DEFAULT 'zkxw' COMMENT '租户编号',
order_num INT NULL COMMENT '排序号',
remark VARCHAR(512) NULL COMMENT '备注',
create_by VARCHAR(64) NULL COMMENT '创建人id',
create_dept_id VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建人部门ID',
create_time DATETIME NOT NULL COMMENT '创建时间',
update_by VARCHAR(64) NULL COMMENT '更新人id',
update_time DATETIME NOT NULL COMMENT '更新时间',
del_flag SMALLINT NOT NULL DEFAULT 0 COMMENT '删除标记',
PRIMARY KEY (id),
KEY idx_oa_evt_inst (instance_id, del_flag, create_time)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='OA实例操作事件(进度轴)';
@@ -0,0 +1,14 @@
-- OA 表与 sys_user 等系统表排序规则对齐
-- 问题:oa_* 建表仅写 DEFAULT CHARSET=utf8mb4,MySQL 5.7 默认 utf8mb4_general_ci;
-- sys_user.id 等为 utf8mb4_unicode_ci,JOIN 报 1267 Illegal mix of collations。
-- 执行前请备份;可重复执行。
ALTER TABLE oa_app_group CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE oa_app CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE oa_app_version CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE oa_role CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE oa_role_user CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE oa_instance CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE oa_task CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE oa_relation CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE oa_instance_event CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
@@ -0,0 +1,52 @@
# 发起审批钉钉式最终路径预览 Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 条件字段未齐时底部占位「必填信息填写后,流程将自动显示」;齐后只展示命中审批链。
**Architecture:** `preview_start_flow` 收集条件字段做 `resolved` 门闩;通过后 `_match_condition_group` 单路 walk。API 改为 POST 传 `formData`。前端防抖刷新 + `OaFlowPreview` 占位态。
**Tech Stack:** FastAPI / SQLAlchemy;Vue 3 + Element Plus;pytest
**Spec:** `docs/superpowers/specs/2026-07-17-oa-start-flow-preview-resolved-path-design.md`
---
## File map
| File | Responsibility |
|------|----------------|
| `backend/app/services/oa_engine.py` | 字段收集、有值判定、单路 preview walk、`resolved` 返回 |
| `backend/app/api/oa_approval.py` | POST `/templates/{id}/flow-preview` |
| `backend/tests/test_oa_flow_preview.py` | 纯函数 + preview 逻辑单测 |
| `web-admin/src/api/oaApproval.ts` | POST 客户端与类型 |
| `web-admin/src/components/oa-approval/OaFlowPreview.vue` | 待确定占位 UI |
| `web-admin/src/views/oa-approval/start/index.vue` | formData 防抖刷新 |
---
### Task 1: 后端门闩与单路 walk + 单测
**Files:**
- Modify: `backend/app/services/oa_engine.py`
- Create: `backend/tests/test_oa_flow_preview.py`
- Modify: `backend/app/api/oa_approval.py`
- [x] **Step 1:** 实现 `_collect_condition_fields`、`_form_value_present`;改 `_walk_preview_nodes` 条件分支为匹配单路;`preview_start_flow` 返回 `{resolved, message, steps}`
- [x] **Step 2:** API 改为 POST,body 含 `formData` / `initiatorSelectUserIds`;保留 GET 转调空 formData(可选兼容)
- [x] **Step 3:** 单测覆盖:无条件 resolved;有条件字段空;命中条件1;走默认
- [x] **Step 4:** `pytest backend/tests/test_oa_flow_preview.py` 通过
### Task 2: 前端 API + 预览组件 + 发起页
**Files:**
- Modify: `web-admin/src/api/oaApproval.ts`
- Modify: `web-admin/src/components/oa-approval/OaFlowPreview.vue`
- Modify: `web-admin/src/views/oa-approval/start/index.vue`
- [x] **Step 1:** `fetchOaFlowPreview` 改为 POST;类型加 `resolved` / `message`
- [x] **Step 2:** `OaFlowPreview` 支持 `resolved===false` 占位文案
- [x] **Step 3:** `start/index.vue` 传入 formData、防抖 watch、绑定 resolved/message
- [x] **Step 4:** 更新 graphify(backend + frontend)
---
@@ -73,13 +73,14 @@
**可勾选 type(实现时映射现有 FormCreate type 名):**
- 输入框:如 `input`(运算符仅 `==` / `!=`)
- 数字:如 `inputNumber`
- 金额:如项目内金额控件 type(若与数字共用则同一逻辑)
- 单选:如 `radio`
- 下拉:如 `select`
- 日期:如 `datePicker` / `date`
附件、说明、布局、公式展示等控件**不展示**该开关。
附件、说明、布局、公式展示等控件**不展示**该开关。开关位于右侧「组件配置」Tab 的基础字段区(`baseRule`),非浮层。
### 4.2 条件分支组(`flow_tree_json`)
@@ -103,7 +104,7 @@ interface ConditionGroup {
| 字段类型 | 可用 op |
|----------|---------|
| 数字 / 金额 / 日期 | `>` `>=` `<` `<=` `==` `!=` |
| 数字 / 金额 / 日期 / 输入框 | `>` `>=` `<` `<=` `==` `!=` |
| 单选 / 下拉 | `==` `!=` |
同组多条 `rules`:引擎现有逻辑拼为 **AND**(与 `oa_engine._match_condition_group` 一致)。
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+127 -129
View File
@@ -1,11 +1,11 @@
# Graph Report - src (2026-07-16)
# Graph Report - src (2026-07-17)
## Corpus Check
- Large corpus: 881 files · ~587,199 words. Semantic extraction will be expensive (many Claude tokens). Consider running on a subfolder, or use --no-semantic to run AST-only.
- Large corpus: 883 files · ~589,944 words. Semantic extraction will be expensive (many Claude tokens). Consider running on a subfolder, or use --no-semantic to run AST-only.
## Summary
- 3025 nodes · 4249 edges · 59 communities detected
- Extraction: 78% EXTRACTED · 22% INFERRED · 0% AMBIGUOUS · INFERRED: 956 edges (avg confidence: 0.8)
- 3054 nodes · 4284 edges · 59 communities detected
- Extraction: 78% EXTRACTED · 22% INFERRED · 0% AMBIGUOUS · INFERRED: 962 edges (avg confidence: 0.8)
- Token cost: 0 input · 0 output
## Community Hubs (Navigation)
@@ -45,35 +45,35 @@
- [[_COMMUNITY_Community 33|Community 33]]
- [[_COMMUNITY_Community 34|Community 34]]
- [[_COMMUNITY_Community 35|Community 35]]
- [[_COMMUNITY_Community 37|Community 37]]
- [[_COMMUNITY_Community 36|Community 36]]
- [[_COMMUNITY_Community 38|Community 38]]
- [[_COMMUNITY_Community 39|Community 39]]
- [[_COMMUNITY_Community 40|Community 40]]
- [[_COMMUNITY_Community 42|Community 42]]
- [[_COMMUNITY_Community 43|Community 43]]
- [[_COMMUNITY_Community 41|Community 41]]
- [[_COMMUNITY_Community 44|Community 44]]
- [[_COMMUNITY_Community 46|Community 46]]
- [[_COMMUNITY_Community 47|Community 47]]
- [[_COMMUNITY_Community 49|Community 49]]
- [[_COMMUNITY_Community 48|Community 48]]
- [[_COMMUNITY_Community 50|Community 50]]
- [[_COMMUNITY_Community 51|Community 51]]
- [[_COMMUNITY_Community 52|Community 52]]
- [[_COMMUNITY_Community 53|Community 53]]
- [[_COMMUNITY_Community 54|Community 54]]
- [[_COMMUNITY_Community 55|Community 55]]
- [[_COMMUNITY_Community 57|Community 57]]
- [[_COMMUNITY_Community 58|Community 58]]
- [[_COMMUNITY_Community 60|Community 60]]
- [[_COMMUNITY_Community 65|Community 65]]
- [[_COMMUNITY_Community 67|Community 67]]
- [[_COMMUNITY_Community 68|Community 68]]
- [[_COMMUNITY_Community 78|Community 78]]
- [[_COMMUNITY_Community 77|Community 77]]
- [[_COMMUNITY_Community 79|Community 79]]
- [[_COMMUNITY_Community 80|Community 80]]
- [[_COMMUNITY_Community 81|Community 81]]
## God Nodes (most connected - your core abstractions)
1. `get()` - 292 edges
2. `push()` - 92 edges
3. `WebSocketClient` - 26 edges
4. `emit()` - 26 edges
1. `get()` - 291 edges
2. `push()` - 93 edges
3. `emit()` - 28 edges
4. `WebSocketClient` - 26 edges
5. `set()` - 20 edges
6. `handleDynamicRoutes()` - 18 edges
7. `parseProtocolStandardImportText()` - 17 edges
@@ -82,208 +82,212 @@
10. `TableCache` - 14 edges
## Surprising Connections (you probably didn't know these)
- `handleBatchDelete()` --calls--> `withFullscreenLoading()` [INFERRED]
views/basic-info/customer/index.vue → utils/fullscreen-loading.ts
- `dash()` --calls--> `formatDisplayOrDash()` [INFERRED]
components/business/infusion-schedule-outbound-chain-view/index.vue → utils/datetime-display.ts
- `dash()` --calls--> `formatDisplayOrDash()` [INFERRED]
components/business/clinical-schedule-payment-detail/index.vue → utils/datetime-display.ts
- `buildInboundMetaFields()` --calls--> `push()` [INFERRED]
utils/production-work-order-card-meta.ts → views/operations/storage-facility/index.vue
- `fmtMoney()` --calls--> `formatMoneyDisplay()` [INFERRED]
components/business/clinical-schedule-payment-detail/index.vue → utils/money-format.ts
- `defaultInstallmentRatios()` --calls--> `push()` [INFERRED]
utils/protocol-payment-installment.ts → views/operations/storage-facility/index.vue
- `handleAttachmentDownload()` --calls--> `downloadAttachmentFile()` [INFERRED]
components/business/infusion-schedule-outbound-chain-view/index.vue → utils/download-attachment.ts
- `subscribeTokenRefresh()` --calls--> `push()` [INFERRED]
utils/http/index.ts → views/operations/storage-facility/index.vue
- `handleForwardSuccess()` --calls--> `emit()` [INFERRED]
views/production/production-work-order/TaskExecutionDialog.vue → components/core/layouts/art-settings-panel/widget/SettingItem.vue
## Communities
### Community 0 - "Community 0"
Cohesion: 0.01
Cohesion: 0.0
Nodes (206): fetchAccessLogList(), fetchActiveRegions(), fetchCategoryList(), fetchCategoryParameters(), fetchCellProductPriceList(), fetchCellProductTypeList(), fetchChannelAccount(), fetchChannelAgreementPrices() (+198 more)
### Community 1 - "Community 1"
Cohesion: 0.01
Nodes (128): fetchCellProductSpecList(), fetchUploadAttachment(), fetchMyProductionTasks(), fetchMyQcTaskList(), fetchQcTaskDetail(), fetchQcTaskList(), FireworkSystem, handleReportUpload() (+120 more)
Cohesion: 0.02
Nodes (98): fetchUploadAttachment(), fetchOaInstanceDetail(), fetchOaTasks(), FireworkSystem, currentPrinterName(), load(), openDetail(), printRow() (+90 more)
### Community 2 - "Community 2"
Cohesion: 0.01
Nodes (14): fetchCreateCheckupInstitution(), fetchCreateCheckupInstitutionInvoice(), fetchDeleteProjectSystemItem(), fetchDeptTree(), fetchGetRoleList(), fetchNotDeletedRegions(), fetchPostBoundUserIds(), fetchRegionList() (+6 more)
### Community 3 - "Community 3"
Cohesion: 0.03
Nodes (89): batchSavePilotCheckup(), deletePilotCheckupActualItem(), fetchCheckupInstitutionList(), fetchCheckupInstitutionPackageDetail(), fetchCheckupInstitutionPackages(), fetchPilotCheckupActualItems(), fetchPilotCheckupDetail(), fetchPilotCheckupList() (+81 more)
### Community 3 - "Community 3"
Cohesion: 0.03
Nodes (59): fetchCheckupInstitutionInvoices(), fetchCheckupInstitutionProjects(), fetchCreateCheckupInstitutionProject(), fetchUpdateCheckupInstitutionProject(), fetchCreateEnvDetectItem(), fetchDeleteEnvDetectItem(), fetchEnvDetectItemDetail(), fetchEnvDetectItemList() (+51 more)
### Community 4 - "Community 4"
Cohesion: 0.03
Nodes (58): fetchCheckupInstitutionInvoices(), fetchCheckupInstitutionProjects(), fetchCreateCheckupInstitutionProject(), fetchUpdateCheckupInstitutionProject(), fetchCreateEnvDetectItem(), fetchDeleteEnvDetectItem(), fetchEnvDetectItemDetail(), fetchEnvDetectItemList() (+50 more)
Nodes (33): fetchGetMenuList(), ComponentLoader, IframeRouteManager, MenuProcessor, RouteRegistry, RouteTransformer, useAppMode(), useAuth() (+25 more)
### Community 5 - "Community 5"
Cohesion: 0.04
Nodes (56): buildInboundBasicSection(), buildInboundCellStorageViewSections(), buildInboundResearchDonationViewSections(), buildReceptionSection(), buildTransportSection(), resolveInboundProtocolStatus(), buildBaseFields(), buildFeeSection() (+48 more)
Cohesion: 0.03
Nodes (59): fetchFullmoonTodoList(), fetchUpdateFullmoonTodoInsurance(), fetchCollectionProtocolAuditList(), fetchCollectionProtocolDetail(), fetchCollectionProtocolList(), fetchCreateProtocolInvoiceRequest(), fetchInvoiceEligiblePayments(), fetchPaymentDetailList() (+51 more)
### Community 6 - "Community 6"
Cohesion: 0.04
Nodes (69): formatNowDatetime(), formatTodayDate(), addPaymentDetail(), applyFqPaymentDefaults(), applyPaymentPresetForMode(), createEmptyTransport(), datetimeToYmd(), defaultInstallmentStartDateYmd() (+61 more)
Cohesion: 0.03
Nodes (51): fetchStorageSlotSelectOptions(), useSettingsHandlers(), useSettingsPanel(), useSettingsState(), RoutePermissionValidator, useCeremony(), useTheme(), if() (+43 more)
### Community 7 - "Community 7"
Cohesion: 0.04
Nodes (41): fetchGetMenuList(), fetchGetMenuCodes(), fetchGetUserInfo(), fetchLogin(), fetchUpdateProfile(), fetchUploadProfileAvatar(), MenuProcessor, RouteRegistry (+33 more)
Cohesion: 0.03
Nodes (57): fetchMyProductionTasks(), fetchMyQcTaskList(), fetchQcTaskDetail(), fetchQcTaskList(), fetchMineTasksForWorkOrders(), useInboundSiblingNavigation(), shouldApplyTriggerSourceFilter(), useQcWorkOrderTabPage() (+49 more)
### Community 8 - "Community 8"
Cohesion: 0.03
Nodes (46): fetchStorageSlotSelectOptions(), useSettingsHandlers(), useSettingsPanel(), useSettingsState(), RoutePermissionValidator, useCeremony(), useTheme(), if() (+38 more)
Nodes (49): fetchCreateOaRole(), fetchDeleteOaRole(), fetchOaAppDraft(), fetchOaAppList(), fetchOaGroupList(), fetchOaRoleList(), fetchOaRoleUsers(), fetchOaTemplateDetail() (+41 more)
### Community 9 - "Community 9"
Cohesion: 0.04
Nodes (43): fetchOaAppDraft(), fetchOaAppList(), fetchOaFlowPreview(), fetchOaGroupList(), fetchOaRoleList(), fetchOaRoleUsers(), fetchOaTemplateDetail(), fetchOaTemplates() (+35 more)
Nodes (51): fetchCellProductSpecList(), buildTemporaryViewSections(), buildInsertedSiblingCard(), resolveShowProtocolPaymentAtGroup(), appendTaskResultSections(), batchTasksForPanelSlot(), buildConfiguredOnlySection(), for() (+43 more)
### Community 10 - "Community 10"
Cohesion: 0.04
Nodes (58): completePilotApplication(), deletePilotApplication(), fetchFullmoonTodoList(), fetchPilotApplicationList(), fetchUpdateFullmoonTodoInsurance(), startPilotApplication(), voidPilotApplication(), fetchCollectionProtocolDetail() (+50 more)
Nodes (47): buildInboundBasicSection(), buildInboundCellStorageViewSections(), buildInboundResearchDonationViewSections(), buildReceptionSection(), buildTransportSection(), resolveInboundProtocolStatus(), buildBaseFields(), buildInboundBasicSection() (+39 more)
### Community 11 - "Community 11"
Cohesion: 0.03
Nodes (24): fetchProductionWorkOrderQcInfo(), fetchQcMaterialBatchDetail(), fetchQcMaterialBatchList(), fetchQcMaterialBatchOptions(), fetchQcMaterialList(), fetchQcMaterialOptions(), fetchUpdateQcMaterialBatch(), dash() (+16 more)
Cohesion: 0.04
Nodes (41): fetchUserList(), fetchAddTaskStep(), fetchCopyTaskStep(), fetchDeleteTaskStep(), fetchDispatchProductionTaskSteps(), fetchForwardProductionTask(), fetchProductionTaskDetail(), fetchProductionTaskEditorInit() (+33 more)
### Community 12 - "Community 12"
Cohesion: 0.04
Nodes (46): fetchCreateCustomer(), fetchCustomerList(), fetchDeleteCustomer(), fetchUpdateCustomer(), updateInfusionScheduleStatus(), handleDialogClose(), handleAdd(), handleBatchDelete() (+38 more)
Nodes (39): fetchEthnicList(), formatNowDatetime(), applyDonationBundleToForm(), createEmptyTransport(), ensureEthnicOptionInList(), handleOpenForAdd(), if(), loadEthnicOptions() (+31 more)
### Community 13 - "Community 13"
Cohesion: 0.04
Nodes (36): handleBlur(), handleFocus(), handleInput(), fetchClinicalReceiptConfirmed(), fetchClinicalRefundConfirmed(), buildConfirmedParams(), buildPendingParams(), formatAmount() (+28 more)
Cohesion: 0.05
Nodes (45): fetchCreateCustomer(), fetchCustomerList(), fetchDeleteCustomer(), fetchUpdateCustomer(), updateInfusionScheduleStatus(), handleDialogClose(), handleAdd(), handleDelete() (+37 more)
### Community 14 - "Community 14"
Cohesion: 0.05
Nodes (48): fetchEthnicList(), applyDonationBundleToForm(), createEmptyTransport(), ensureEthnicOptionInList(), handleOpenForAdd(), if(), loadEthnicOptions(), normalizeSampleRow() (+40 more)
Nodes (34): fetchClinicalPaymentDetail(), fetchClinicalPayments(), fetchClinicalReceiptConfirmed(), fetchClinicalReceiptPending(), fetchClinicalRefundConfirmed(), fetchClinicalRefundPending(), fetchOrderAdjusts(), fetchOrderDetail() (+26 more)
### Community 15 - "Community 15"
Cohesion: 0.05
Nodes (41): fetchOaInstanceDetail(), fetchOaTasks(), fetchProductionReceptionBySampleCode(), fetchProductionReceptionSubmit(), fetchProductionReceptionUpdate(), currentPrinterName(), load(), openDetail() (+33 more)
Cohesion: 0.07
Nodes (35): fetchInfusionScheduleMgmtDetail(), dash(), fmtMoney(), attachmentFullUrl(), dash(), handleAttachmentDownload(), handleAttachmentPreview(), loadDetail() (+27 more)
### Community 16 - "Community 16"
Cohesion: 0.05
Nodes (24): fetchCreateMenu(), fetchDeleteMenu(), fetchMenuTree(), fetchRoleOptions(), fetchUpdateMenu(), collectIds(), postorder(), preorder() (+16 more)
Cohesion: 0.08
Nodes (37): formatDatetimeToMinute(), handleChineseDatetimePaste(), parseChineseDatetimeText(), parseBirthOrder(), parseChineseNumeral(), addSampleHint(), earliestCollectTime(), isMaternalBloodEmpty() (+29 more)
### Community 17 - "Community 17"
Cohesion: 0.06
Nodes (22): fetchCreateMenu(), fetchDeleteMenu(), fetchMenuTree(), fetchRoleOptions(), fetchUpdateMenu(), collectIds(), postorder(), preorder() (+14 more)
### Community 18 - "Community 18"
Cohesion: 0.1
Nodes (2): WebSocketClient, TableCache
### Community 18 - "Community 18"
Cohesion: 0.06
Nodes (29): fetchInfusionScheduleMgmtDetail(), qcAttachmentFullUrl(), qcDownloadAttachment(), qcPreviewAttachment(), handleDownloadAttachment(), attachmentFullUrl(), dash(), handleAttachmentDownload() (+21 more)
### Community 19 - "Community 19"
Cohesion: 0.06
Nodes (11): fetchProductionWorkOrderQcInfo(), auditorDisplay(), dash(), ensureUnitsInOptions(), expressName(), formatYm(), formatYmd(), sampleTypeName() (+3 more)
### Community 20 - "Community 20"
Cohesion: 0.08
Nodes (33): fetchRefreshToken(), toLogin(), base64ToBytes(), bytesToBase64(), decryptJson(), deriveKey(), encryptJson(), fromBase64Url() (+25 more)
### Community 20 - "Community 20"
### Community 21 - "Community 21"
Cohesion: 0.09
Nodes (8): getDefaultLanguage(), checkStorageCompatibility(), StorageConfig, getSystemStorage(), getSysVersion(), StorageKeyManager, StorageCompatibilityManager, validateStorageData()
### Community 21 - "Community 21"
### Community 22 - "Community 22"
Cohesion: 0.07
Nodes (21): fetchDictDataOptions(), fetchDeleteMaterialBatch(), fetchMaterialBatchList(), fetchMaterialBatchOptions(), fetchMaterialList(), fetchMaterialOptions(), fetchUpdateMaterialBatch(), fetchMaterialUsageList() (+13 more)
### Community 22 - "Community 22"
Cohesion: 0.08
Nodes (12): ComponentLoader, IframeRouteManager, RouteTransformer, getFirstMenuPath(), getFirstSecondLevelMenuPath(), isIframe(), isNavigableMenuItem(), isWorkbenchMenuItem() (+4 more)
### Community 23 - "Community 23"
Cohesion: 0.08
Nodes (18): fetchProductionReceptionBySampleCode(), fetchProductionReceptionSubmit(), fetchProductionReceptionUpdate(), onUserSelectVisible(), remoteSearchUsers(), buildPayload(), ensureDefaultHandler(), initDialog() (+10 more)
### Community 24 - "Community 24"
Cohesion: 0.07
Nodes (14): handleBlur(), handleFocus(), handleInput(), formatAmount(), formatAmount(), formatProtocolAmount(), buildFeeSection(), formatInvoiceAmount() (+6 more)
### Community 25 - "Community 25"
Cohesion: 0.08
Nodes (20): createEmptySnapshots(), normalizeConfiguredReagents(), normalizeConsumables(), normalizeDataCollections(), normalizeReagents(), normalizeStepOutputs(), serializeAttachments(), serializeEquipmentIds() (+12 more)
### Community 24 - "Community 24"
Cohesion: 0.09
Nodes (30): fetchAddTaskStep(), fetchCopyTaskStep(), fetchDeleteTaskStep(), fetchDispatchProductionTaskSteps(), fetchForwardProductionTask(), fetchProductionTaskDetail(), fetchProductionTaskEditorInit(), fetchProductionTaskList() (+22 more)
### Community 25 - "Community 25"
### Community 26 - "Community 26"
Cohesion: 0.09
Nodes (22): fetchMineProductionWorkOrderTabStepCounts(), fetchMineProductionWorkOrderTabStepCountsDeduped(), fetchProductionWorkOrderCellProductOptions(), fetchProductionWorkOrderDetail(), fetchProductionWorkOrderList(), fetchProductionWorkOrderQcDispatchOptions(), fetchProductionWorkOrderTabStepCounts(), fetchProductionWorkOrderTabStepCountsDeduped() (+14 more)
### Community 26 - "Community 26"
Cohesion: 0.07
Nodes (14): fetchUserList(), formatHandoverUserLabel(), formatNowDatetime(), fullFileUrl(), handlePreviewAttachment(), isVideoFile(), remoteSearchHandoverUsers(), resetHandoverForm() (+6 more)
### Community 27 - "Community 27"
Cohesion: 0.09
Nodes (12): fetchMineQcWorkOrderTabUnfinishedCounts(), fetchOutboundQcDetail(), fetchQcWorkOrderDetail(), fetchQcWorkOrderList(), fetchQcWorkOrdersBySample(), fetchQcWorkOrderTabUnfinishedCounts(), reload(), reloadTabCounts() (+4 more)
Nodes (27): completePilotApplication(), deletePilotApplication(), fetchPilotApplicationList(), startPilotApplication(), voidPilotApplication(), handleBatchComplete(), handleBatchStart(), handleBatchVoid() (+19 more)
### Community 28 - "Community 28"
Cohesion: 0.1
Nodes (16): fetchUpdateQcMaterialBatch(), fetchMarkQcMaterialUsageFullyUsed(), financeAttachmentsToUrlString(), ensureTabMounted(), handleTabChange(), handleSubmit(), canMarkFullyUsed(), displayPurpose() (+8 more)
### Community 29 - "Community 29"
Cohesion: 0.12
Nodes (20): fetchGetMenuCodes(), fetchGetUserInfo(), fetchLogin(), fetchUpdateProfile(), fetchUploadProfileAvatar(), fetchUserInfo(), buildWebEncryptedLoginBody(), defaultAvatarPathByRole() (+12 more)
### Community 30 - "Community 30"
Cohesion: 0.12
Nodes (15): addCopyButton(), highlightCode(), insertLineNumbers(), isBlockProcessed(), markBlockAsProcessed(), processBlock(), setupHighlightDirective(), setupRippleDirective() (+7 more)
### Community 29 - "Community 29"
### Community 31 - "Community 31"
Cohesion: 0.13
Nodes (18): fetchCellSampleTypeList(), fetchCreateCellSampleType(), fetchDeleteCellSampleType(), fetchUpdateCellSampleType(), handleAdd(), handleDelete(), handleDropdownCommand(), handleEdit() (+10 more)
### Community 30 - "Community 30"
### Community 32 - "Community 32"
Cohesion: 0.11
Nodes (11): fetchOutboundReleaseMaterial(), fetchOutboundReleaseReviewDetail(), fetchOutboundReleaseReviewList(), fetchReleaseReviewList(), handleReset(), handleSearch(), handleToggleSelect(), loadData() (+3 more)
### Community 33 - "Community 33"
Cohesion: 0.19
Nodes (15): fetchAttachmentDownloadUrl(), attachmentFullUrl(), ensureUniqueZipEntryName(), fetchAttachmentBlob(), getAttachmentExtension(), resolveAttachmentFileName(), sanitizeZipPathSegment(), applyInboundLabStorageCodePrefix() (+7 more)
### Community 31 - "Community 31"
Cohesion: 0.2
Nodes (11): fetchMarkQcMaterialUsageFullyUsed(), canMarkFullyUsed(), displayPurpose(), displayReceiver(), displayUseTime(), getChangeTypeLabel(), getChangeTypeTagType(), handleMarkFullyUsed() (+3 more)
### Community 32 - "Community 32"
### Community 34 - "Community 34"
Cohesion: 0.16
Nodes (10): useTable(), useTableImpl(), getColumnChecks(), useTableColumns(), createErrorHandler(), createSmartDebounce(), defaultResponseAdapter(), extractPagination() (+2 more)
### Community 33 - "Community 33"
### Community 35 - "Community 35"
Cohesion: 0.27
Nodes (14): useChart(), useChartComponent(), useChartOps(), colourBlend(), getCssVar(), getDarkColor(), getLightColor(), handleElementThemeColor() (+6 more)
### Community 34 - "Community 34"
Cohesion: 0.33
Nodes (13): buildProtocolPaymentFlowSteps(), dash(), financeReceiptTime(), formatAmount(), hasFinanceReceipt(), hasFinanceRefund(), hasReceiptSubmit(), hasRefundSubmit() (+5 more)
### Community 35 - "Community 35"
### Community 36 - "Community 36"
Cohesion: 0.19
Nodes (6): fetchServiceOrderTxnList(), handleReset(), handleSearch(), handleTabChange(), loadData(), switchTab()
### Community 37 - "Community 37"
Cohesion: 0.21
Nodes (7): handleReset(), handleSearch(), handleToggleSelect(), loadData(), onReviewSubmitted(), rowId(), isSelected()
### Community 38 - "Community 38"
Cohesion: 0.42
Nodes (9): buildPaymentFlowSteps(), dash(), formatAmount(), hasFinanceReceipt(), hasFinanceRefund(), hasReceiptSubmit(), hasRefundSubmit(), receiptSubmitTime() (+1 more)
Cohesion: 0.24
Nodes (8): fullFileUrl(), handlePreviewAttachment(), isVideoFile(), normalizeDisplayValue(), resolveReviewCellType(), resolveReviewQuantity(), resolveReviewSpecText(), uniqueJoined()
### Community 39 - "Community 39"
Cohesion: 0.2
Nodes (4): personTitle(), signBadge(), signBadgeText(), statusText()
### Community 40 - "Community 40"
Cohesion: 0.24
Nodes (4): addMaterialRow(), nextMaterialRowKey(), onRequisitionSelect(), removeMaterialRow()
### Community 40 - "Community 40"
### Community 41 - "Community 41"
Cohesion: 0.25
Nodes (2): handleTouchEnd(), setTransition()
### Community 42 - "Community 42"
### Community 44 - "Community 44"
Cohesion: 0.28
Nodes (4): fetchMyProductionMaterialConsumptions(), handleReset(), handleSearch(), loadData()
### Community 43 - "Community 43"
Cohesion: 0.31
Nodes (4): annotateForkEdges(), chainApiToElements(), walkAncestorBranch(), walkAncestorParents()
### Community 46 - "Community 46"
Cohesion: 0.25
Nodes (4): reload(), reloadTabCounts(), handleMenuJump(), openExternalLink()
### Community 47 - "Community 47"
Cohesion: 0.39
Nodes (6): isIgnorableScriptError(), normalizeErrorMessage(), registerPromiseErrorHandler(), registerResourceErrorHandler(), scriptErrorHandler(), setupErrorHandle()
### Community 47 - "Community 47"
### Community 48 - "Community 48"
Cohesion: 0.36
Nodes (1): TableHeightCalculator
### Community 49 - "Community 49"
### Community 50 - "Community 50"
Cohesion: 0.33
Nodes (2): logApiCryptoBootInfo(), maskSecret()
### Community 50 - "Community 50"
### Community 51 - "Community 51"
Cohesion: 0.38
Nodes (4): handleFocus(), handleInput(), parseDecimalToNumber(), sanitizeDecimalInput()
### Community 51 - "Community 51"
### Community 52 - "Community 52"
Cohesion: 0.4
Nodes (2): isUnfinishedQcWorkOrder(), resolveQcWorkOrderUnfinishedBadgeCount()
### Community 52 - "Community 52"
### Community 53 - "Community 53"
Cohesion: 0.47
Nodes (3): isPaymentDueWithinWarnWindow(), parsePaymentDueYmd(), startOfLocalDay()
@@ -299,10 +303,6 @@ Nodes (2): parseEquipmentIds(), syncEquipmentNamesFromOptions()
Cohesion: 0.5
Nodes (2): focusInput(), handleKeydown()
### Community 58 - "Community 58"
Cohesion: 0.4
Nodes (1): fetchQcMaterialAmountAuthUsers()
### Community 60 - "Community 60"
Cohesion: 0.67
Nodes (2): if(), logSidebarMenu()
@@ -319,28 +319,28 @@ Nodes (2): copyTextToClipboard(), copyTextWithFallback()
Cohesion: 1.0
Nodes (2): getSourceProtocolAttachment(), normalizeAttachmentFiles()
### Community 78 - "Community 78"
### Community 77 - "Community 77"
Cohesion: 1.0
Nodes (2): emptyTabCounts(), useProductionWorkOrderTabStepCounts()
### Community 80 - "Community 80"
### Community 79 - "Community 79"
Cohesion: 1.0
Nodes (2): initialProgress(), useQcWorkOrderAttachmentExport()
### Community 81 - "Community 81"
### Community 80 - "Community 80"
Cohesion: 1.0
Nodes (2): emptyTabCounts(), useQcWorkOrderTabUnfinishedCounts()
## Knowledge Gaps
- **Thin community `Community 17`** (42 nodes): `WebSocketClient`, `.calculateReconnectDelay()`, `.clearAllTimers()`, `.clearConnectionTimers()`, `.clearTimer()`, `.close()`, `.closeCurrentSocketForReconnect()`, `.connect()`, `.connectionStatusText()`, `.constructor()`, `.destroyInstance()`, `.flushMessageQueue()`, `.getInstance()`, `.getReadyStateText()`, `.handleClose()`, `.handleConnectionTimeout()`, `.handleError()`, `.handleMessage()`, `.handleOpen()`, `.init()`, `.isWebSocketConnected()`, `.reconnect()`, `.resetHeartbeat()`, `.send()`, `.startHeartbeat()`, `.startPing()`, `TableCache`, `.cleanupExpired()`, `.clear()`, `.clearByTags()`, `.clearCurrentSearch()`, `.clearPagination()`, `.constructor()`, `.evictLRU()`, `.generateKey()`, `.generateTags()`, `.get()`, `.getStats()`, `.log()`, `.set()`, `index.ts`, `tableCache.ts`
- **Thin community `Community 18`** (42 nodes): `WebSocketClient`, `.calculateReconnectDelay()`, `.clearAllTimers()`, `.clearConnectionTimers()`, `.clearTimer()`, `.close()`, `.closeCurrentSocketForReconnect()`, `.connect()`, `.connectionStatusText()`, `.constructor()`, `.destroyInstance()`, `.flushMessageQueue()`, `.getInstance()`, `.getReadyStateText()`, `.handleClose()`, `.handleConnectionTimeout()`, `.handleError()`, `.handleMessage()`, `.handleOpen()`, `.init()`, `.isWebSocketConnected()`, `.reconnect()`, `.resetHeartbeat()`, `.send()`, `.startHeartbeat()`, `.startPing()`, `TableCache`, `.cleanupExpired()`, `.clear()`, `.clearByTags()`, `.clearCurrentSearch()`, `.clearPagination()`, `.constructor()`, `.evictLRU()`, `.generateKey()`, `.generateTags()`, `.get()`, `.getStats()`, `.log()`, `.set()`, `index.ts`, `tableCache.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 40`** (9 nodes): `cleanupEventListeners()`, `handleTouchEnd()`, `handleTouchMove()`, `handleTouchStart()`, `handleWheelScroll()`, `if()`, `setTransition()`, `setupEventListeners()`, `index.vue`
- **Thin community `Community 41`** (9 nodes): `cleanupEventListeners()`, `handleTouchEnd()`, `handleTouchMove()`, `handleTouchStart()`, `handleWheelScroll()`, `if()`, `setTransition()`, `setupEventListeners()`, `index.vue`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 47`** (8 nodes): `TableHeightCalculator`, `.calculate()`, `.calculateOffset()`, `.calculatePaginationOffset()`, `.constructor()`, `.getHeaderHeight()`, `useTableHeight()`, `useTableHeight.ts`
- **Thin community `Community 48`** (8 nodes): `TableHeightCalculator`, `.calculate()`, `.calculateOffset()`, `.calculatePaginationOffset()`, `.constructor()`, `.getHeaderHeight()`, `useTableHeight()`, `useTableHeight.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 49`** (7 nodes): `App.vue`, `main.ts`, `refreshButtonAutoIcons()`, `refreshPanelTitleIcons()`, `logApiCryptoBootInfo()`, `maskSecret()`, `console.ts`
- **Thin community `Community 50`** (7 nodes): `App.vue`, `main.ts`, `refreshButtonAutoIcons()`, `refreshPanelTitleIcons()`, `logApiCryptoBootInfo()`, `maskSecret()`, `console.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 51`** (6 nodes): `formatQcWorkOrderUnfinishedBadgeCount()`, `isUnfinishedQcWorkOrder()`, `qcWorkOrderUnfinishedBadgeTitle()`, `resolveQcWorkOrderUnfinishedBadgeCount()`, `sumQcWorkOrderGroupUnfinishedBadgeCount()`, `qc-work-order-unfinished-badge.ts`
- **Thin community `Community 52`** (6 nodes): `formatQcWorkOrderUnfinishedBadgeCount()`, `isUnfinishedQcWorkOrder()`, `qcWorkOrderUnfinishedBadgeTitle()`, `resolveQcWorkOrderUnfinishedBadgeCount()`, `sumQcWorkOrderGroupUnfinishedBadgeCount()`, `qc-work-order-unfinished-badge.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 54`** (5 nodes): `formatProtocolDocBatchDeleteConfirm()`, `formatProtocolDocDeleteConfirm()`, `formatProtocolDocSubject()`, `getProtocolDocTypeLabel()`, `protocol-doc-label.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
@@ -348,8 +348,6 @@ Nodes (2): emptyTabCounts(), useQcWorkOrderTabUnfinishedCounts()
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 57`** (5 nodes): `focusInput()`, `handleKeydown()`, `if()`, `search()`, `index.vue`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 58`** (5 nodes): `fetchBatchRevokeQcMaterialAmountAuth()`, `fetchGrantQcMaterialAmountAuth()`, `fetchQcMaterialAmountAuthUsers()`, `fetchRevokeQcMaterialAmountAuth()`, `qc-material-amount-auth.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 60`** (4 nodes): `if()`, `logSidebarMenu()`, `index.vue`, `SidebarSubmenu.vue`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 65`** (3 nodes): `getSettingDefaults()`, `resetToDefaults()`, `setting.ts`
@@ -358,27 +356,27 @@ Nodes (2): emptyTabCounts(), useQcWorkOrderTabUnfinishedCounts()
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 68`** (3 nodes): `getSourceProtocolAttachment()`, `normalizeAttachmentFiles()`, `protocol-source-attachment.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 78`** (3 nodes): `emptyTabCounts()`, `useProductionWorkOrderTabStepCounts()`, `useProductionWorkOrderTabStepCounts.ts`
- **Thin community `Community 77`** (3 nodes): `emptyTabCounts()`, `useProductionWorkOrderTabStepCounts()`, `useProductionWorkOrderTabStepCounts.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 80`** (3 nodes): `initialProgress()`, `useQcWorkOrderAttachmentExport()`, `useQcWorkOrderAttachmentExport.ts`
- **Thin community `Community 79`** (3 nodes): `initialProgress()`, `useQcWorkOrderAttachmentExport()`, `useQcWorkOrderAttachmentExport.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 81`** (3 nodes): `emptyTabCounts()`, `useQcWorkOrderTabUnfinishedCounts()`, `useQcWorkOrderTabUnfinishedCounts.ts`
- **Thin community `Community 80`** (3 nodes): `emptyTabCounts()`, `useQcWorkOrderTabUnfinishedCounts()`, `useQcWorkOrderTabUnfinishedCounts.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
## Suggested Questions
_Questions this graph is uniquely positioned to answer:_
- **Why does `get()` connect `Community 0` to `Community 1`, `Community 2`, `Community 3`, `Community 4`, `Community 6`, `Community 7`, `Community 8`, `Community 9`, `Community 10`, `Community 11`, `Community 12`, `Community 13`, `Community 14`, `Community 15`, `Community 16`, `Community 18`, `Community 21`, `Community 24`, `Community 25`, `Community 26`, `Community 27`, `Community 29`, `Community 35`, `Community 42`, `Community 43`, `Community 58`?**
_High betweenness centrality (0.284) - this node is a cross-community bridge._
- **Why does `push()` connect `Community 1` to `Community 2`, `Community 3`, `Community 4`, `Community 5`, `Community 6`, `Community 8`, `Community 9`, `Community 10`, `Community 11`, `Community 14`, `Community 15`, `Community 17`, `Community 19`, `Community 23`, `Community 24`, `Community 25`, `Community 26`, `Community 27`, `Community 30`, `Community 39`?**
_High betweenness centrality (0.279) - this node is a cross-community bridge._
- **Why does `handleDynamicRoutes()` connect `Community 7` to `Community 8`, `Community 15`, `Community 22`, `Community 25`, `Community 27`?**
_High betweenness centrality (0.046) - this node is a cross-community bridge._
- **Are the 291 inferred relationships involving `get()` (e.g. with `buildNodeCodePathFromFlat()` and `collectLeafFacilityNodesInTreeOrder()`) actually correct?**
_`get()` has 291 INFERRED edges - model-reasoned connections that need verification._
- **Are the 91 inferred relationships involving `push()` (e.g. with `refreshQcMenuBadges()` and `collectLeafFacilityNodesInTreeOrder()`) actually correct?**
_`push()` has 91 INFERRED edges - model-reasoned connections that need verification._
- **Are the 25 inferred relationships involving `emit()` (e.g. with `handleSubmit()` and `handleDialogClose()`) actually correct?**
_`emit()` has 25 INFERRED edges - model-reasoned connections that need verification._
- **Why does `push()` connect `Community 1` to `Community 0`, `Community 2`, `Community 3`, `Community 5`, `Community 6`, `Community 7`, `Community 8`, `Community 9`, `Community 10`, `Community 11`, `Community 12`, `Community 16`, `Community 18`, `Community 19`, `Community 20`, `Community 25`, `Community 26`, `Community 27`, `Community 33`, `Community 40`, `Community 46`?**
_High betweenness centrality (0.263) - this node is a cross-community bridge._
- **Why does `get()` connect `Community 0` to `Community 1`, `Community 2`, `Community 3`, `Community 5`, `Community 6`, `Community 7`, `Community 8`, `Community 9`, `Community 11`, `Community 12`, `Community 13`, `Community 14`, `Community 15`, `Community 17`, `Community 19`, `Community 22`, `Community 23`, `Community 26`, `Community 27`, `Community 29`, `Community 31`, `Community 32`, `Community 36`, `Community 44`?**
_High betweenness centrality (0.251) - this node is a cross-community bridge._
- **Why does `handleDynamicRoutes()` connect `Community 4` to `Community 0`, `Community 1`, `Community 6`, `Community 26`, `Community 29`?**
_High betweenness centrality (0.047) - this node is a cross-community bridge._
- **Are the 290 inferred relationships involving `get()` (e.g. with `buildNodeCodePathFromFlat()` and `collectLeafFacilityNodesInTreeOrder()`) actually correct?**
_`get()` has 290 INFERRED edges - model-reasoned connections that need verification._
- **Are the 92 inferred relationships involving `push()` (e.g. with `refreshQcMenuBadges()` and `collectLeafFacilityNodesInTreeOrder()`) actually correct?**
_`push()` has 92 INFERRED edges - model-reasoned connections that need verification._
- **Are the 27 inferred relationships involving `emit()` (e.g. with `handleSubmit()` and `handleDialogClose()`) actually correct?**
_`emit()` has 27 INFERRED edges - model-reasoned connections that need verification._
- **Are the 19 inferred relationships involving `set()` (e.g. with `buildNodeCodePathFromFlat()` and `collectLeafFacilityNodesInTreeOrder()`) actually correct?**
_`set()` has 19 INFERRED edges - model-reasoned connections that need verification._
+4 -4
View File
@@ -57,12 +57,12 @@
</div>
<div id="legend"></div>
</div>
<div id="stats">3025 nodes &middot; 4249 edges &middot; 345 communities</div>
<div id="stats">3054 nodes &middot; 4284 edges &middot; 344 communities</div>
</div>
<script>
const RAW_NODES = [{"id": "app_vue", "label": "App.vue", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "App.vue", "community": 49, "community_name": "Community 49", "source_file": "App.vue", "file_type": "code", "degree": 3}, {"id": "src_app_refreshbuttonautoicons", "label": "refreshButtonAutoIcons()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshButtonAutoIcons()", "community": 49, "community_name": "Community 49", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "src_app_refreshpaneltitleicons", "label": "refreshPanelTitleIcons()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshPanelTitleIcons()", "community": 49, "community_name": "Community 49", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "main_ts", "label": "main.ts", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.4, "font": {"size": 0, "color": "#ffffff"}, "title": "main.ts", "community": 49, "community_name": "Community 49", "source_file": "main.ts", "file_type": "code", "degree": 4}, {"id": "src_main_masksecret", "label": "maskSecret()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "maskSecret()", "community": 49, "community_name": "Community 49", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "src_main_logapicryptobootinfo", "label": "logApiCryptoBootInfo()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "logApiCryptoBootInfo()", "community": 49, "community_name": "Community 49", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "env_d_ts", "label": "env.d.ts", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "env.d.ts", "community": 117, "community_name": "Community 117", "source_file": "env.d.ts", "file_type": "code", "degree": 0}, {"id": "shims_loose_d_ts", "label": "shims-loose.d.ts", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "shims-loose.d.ts", "community": 118, "community_name": "Community 118", "source_file": "shims-loose.d.ts", "file_type": "code", "degree": 0}, {"id": "directives_index_ts", "label": "index.ts", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "index.ts", "community": 28, "community_name": "Community 28", "source_file": "directives/index.ts", "file_type": "code", "degree": 1}, {"id": "directives_index_setupglobdirectives", "label": "setupGlobDirectives()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.5, "font": {"size": 0, "color": "#ffffff"}, "title": "setupGlobDirectives()", "community": 28, "community_name": "Community 28", "source_file": "directives/index.ts", "file_type": "code", "degree": 5}, {"id": "directives_core_roles_ts", "label": "roles.ts", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "roles.ts", "community": 28, "community_name": "Community 28", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 3}, {"id": "core_roles_checkrolepermission", "label": "checkRolePermission()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "checkRolePermission()", "community": 28, "community_name": "Community 28", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 2}, {"id": "core_roles_removeelement", "label": "removeElement()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "removeElement()", "community": 28, "community_name": "Community 28", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 2}, {"id": "core_roles_setuprolesdirective",Line truncated
const RAW_EDGES = [{"from": "app_vue", "to": "src_app_refreshbuttonautoicons", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_vue", "to": "src_app_refreshpaneltitleicons", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_vue", "to": "main_ts", "label": "imports_from", "title": "imports_from [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_ts", "to": "utils_sys_console_ts", "label": "imports_from", "title": "imports_from [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_ts", "to": "src_main_masksecret", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_ts", "to": "src_main_logapicryptobootinfo", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "src_main_masksecret", "to": "src_main_logapicryptobootinfo", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_index_ts", "to": "directives_index_setupglobdirectives", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_index_setupglobdirectives", "to": "core_auth_setupauthdirective", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "directives_index_setupglobdirectives", "to": "core_roles_setuprolesdirective", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "directives_index_setupglobdirectives", "to": "business_highlight_setuphighlightdirective", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "directives_index_setupglobdirectives", "to": "business_ripple_setuprippledirective", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "directives_core_roles_ts", "to": "core_roles_checkrolepermission", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_roles_ts", "to": "core_roles_removeelement", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_roles_ts", "to": "core_roles_setuprolesdirective", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_roles_checkrolepermission", "to": "core_roles_removeelement", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_auth_ts", "to": "core_auth_checkauthpermission", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_auth_ts", "to": "core_auth_removeelement", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_auth_ts", "to": "core_auth_setupauthdirective", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_checkauthpermission", "to": "core_auth_removeelement", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_business_ripple_ts", "to": "business_ripple_setuprippledirective", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_business_highlight_ts", "to": "business_highlight_highlightcode", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_business_highlight_ts", "to": "business_highlight_insertlinenumbers", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_business_highlight_ts", "to": "business_highlight_addcopybutton", "label": "contains", "title": "contains [EXTRACTED]", "dLine truncated
const LEGEND = [{"cid": 0, "color": "#4E79A7", "label": "Community 0", "count": 404}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 214}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 201}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 122}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 95}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 92}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 91}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 84}, {"cid": 8, "color": "#9C755F", "label": "Community 8", "count": 80}, {"cid": 9, "color": "#BAB0AC", "label": "Community 9", "count": 79}, {"cid": 10, "color": "#4E79A7", "label": "Community 10", "count": 75}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 72}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 72}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 71}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 66}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 61}, {"cid": 16, "color": "#B07AA1", "label": "Community 16", "count": 48}, {"cid": 17, "color": "#FF9DA7", "label": "Community 17", "count": 42}, {"cid": 18, "color": "#9C755F", "label": "Community 18", "count": 42}, {"cid": 19, "color": "#BAB0AC", "label": "Community 19", "count": 41}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 37}, {"cid": 21, "color": "#F28E2B", "label": "Community 21", "count": 37}, {"cid": 22, "color": "#E15759", "label": "Community 22", "count": 37}, {"cid": 23, "color": "#76B7B2", "label": "Community 23", "count": 36}, {"cid": 24, "color": "#59A14F", "label": "Community 24", "count": 36}, {"cid": 25, "color": "#EDC948", "label": "Community 25", "count": 34}, {"cid": 26, "color": "#B07AA1", "label": "Community 26", "count": 34}, {"cid": 27, "color": "#FF9DA7", "label": "Community 27", "count": 25}, {"cid": 28, "color": "#9C755F", "label": "Community 28", "count": 22}, {"cid": 29, "color": "#BAB0AC", "label": "Community 29", "count": 22}, {"cid": 30, "color": "#4E79A7", "label": "Community 30", "count": 20}, {"cid": 31, "color": "#F28E2B", "label": "Community 31", "count": 18}, {"cid": 32, "color": "#E15759", "label": "Community 32", "count": 17}, {"cid": 33, "color": "#76B7B2", "label": "Community 33", "count": 16}, {"cid": 34, "color": "#59A14F", "label": "Community 34", "count": 14}, {"cid": 35, "color": "#EDC948", "label": "Community 35", "count": 14}, {"cid": 36, "color": "#B07AA1", "label": "Community 36", "count": 13}, {"cid": 37, "color": "#FF9DA7", "label": "Community 37", "count": 13}, {"cid": 38, "color": "#9C755F", "label": "Community 38", "count": 10}, {"cid": 39, "color": "#BAB0AC", "label": "Community 39", "count": 10}, {"cid": 40, "color": "#4E79A7", "label": "Community 40", "count": 9}, {"cid": 41, "color": "#F28E2B", "label": "Community 41", "count": 9}, {"cid": 42, "color": "#E15759", "label": "Community 42", "count": 9}, {"cid": 43, "color": "#76B7B2", "label": "Community 43", "count": 9}, {"cid": 44, "color": "#59A14F", "label": "Community 44", "count": 9}, {"cid": 45, "color": "#EDC948", "label": "Community 45", "count": 9}, {"cid": 46, "color": "#B07AA1", "label": "Community 46", "count": 8}, {"cid": 47, "color": "#FF9DA7", "label": "Community 47", "count": 8}, {"cid": 48, "color": "#9C755F", "label": "Community 48", "count": 8}, {"cid": 49, "color": "#BAB0AC", "label": "Community 49", "count": 7}, {"cid": 50, "color": "#4E79A7", "label": "Community 50", "count": 7}, {"cid": 51, "color": "#F28E2B", "label": "Community 51", "count": 6}, {"cid": 52, "color": "#E15759", "label": "Community 52", "count": 6}, {"cid": 53, "color": "#76B7B2", "label": "Community 53", "count": 6}, {"cid": 54, "color": "#59A14F", "label": "Community 54", "count": 5}, {"cid": 55, "color": "#EDC948", "label": "Community 55", "count": 5}, {"cid": 56, "color": "#B07AA1", "label": "Community 56", "count": 5}, {"cid": 57, "color": "#FF9DA7", "label": "Community 57", "count": 5}, {"cid": 58, "color": "#9C755F", "label": "Community 58", "count": 5}, {"cid": 59, "color": "#BAB0AC", "label": "Community 59", "count": 4}, {"cid": 60, "color": "#4E79A7", "label": "Community 60", "count": 4}, {"cid": 61, "color": "#F28E2B", "label": "Community 61", "count": 4}, {"cid": 62, "color": "#E15759", "label": "Community 62", "count": 4}, {"cid": 63, "color": "#76B7B2", "label": "Community 63", "count": 4}, {"cid": 64, "color": "#59A14F", "label": "Community 64", "count": 3}, {"cid": 65, "color": "#EDC948", "label": "Community 65", "count": 3}, {"cid": 66, "color": "#B07AA1", "label": "Community 66", "count": 3}, {"cid": 67, "color": "#FF9DA7", "label": "Community 67", "count": 3}, {"cid": 68, "color": "#9C755F", "label": "Community 68", "count": 3}, {"cid": 69, "color": "#BAB0AC", "label": "Community 69", "count": 3}, {"cid": 70, "color": "#4E79A7", "label": "Community 70", "cLine truncated
const RAW_NODES = [{"id": "app_vue", "label": "App.vue", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "App.vue", "community": 50, "community_name": "Community 50", "source_file": "App.vue", "file_type": "code", "degree": 3}, {"id": "src_app_refreshbuttonautoicons", "label": "refreshButtonAutoIcons()", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshButtonAutoIcons()", "community": 50, "community_name": "Community 50", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "src_app_refreshpaneltitleicons", "label": "refreshPanelTitleIcons()", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshPanelTitleIcons()", "community": 50, "community_name": "Community 50", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "main_ts", "label": "main.ts", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.4, "font": {"size": 0, "color": "#ffffff"}, "title": "main.ts", "community": 50, "community_name": "Community 50", "source_file": "main.ts", "file_type": "code", "degree": 4}, {"id": "src_main_masksecret", "label": "maskSecret()", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "maskSecret()", "community": 50, "community_name": "Community 50", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "src_main_logapicryptobootinfo", "label": "logApiCryptoBootInfo()", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "logApiCryptoBootInfo()", "community": 50, "community_name": "Community 50", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "env_d_ts", "label": "env.d.ts", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "env.d.ts", "community": 117, "community_name": "Community 117", "source_file": "env.d.ts", "file_type": "code", "degree": 0}, {"id": "shims_loose_d_ts", "label": "shims-loose.d.ts", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "shims-loose.d.ts", "community": 118, "community_name": "Community 118", "source_file": "shims-loose.d.ts", "file_type": "code", "degree": 0}, {"id": "directives_index_ts", "label": "index.ts", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "index.ts", "community": 30, "community_name": "Community 30", "source_file": "directives/index.ts", "file_type": "code", "degree": 1}, {"id": "directives_index_setupglobdirectives", "label": "setupGlobDirectives()", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.5, "font": {"size": 0, "color": "#ffffff"}, "title": "setupGlobDirectives()", "community": 30, "community_name": "Community 30", "source_file": "directives/index.ts", "file_type": "code", "degree": 5}, {"id": "directives_core_roles_ts", "label": "roles.ts", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "roles.ts", "community": 30, "community_name": "Community 30", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 3}, {"id": "core_roles_checkrolepermission", "label": "checkRolePermission()", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "checkRolePermission()", "community": 30, "community_name": "Community 30", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 2}, {"id": "core_roles_removeelement", "label": "removeElement()", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "removeElement()", "community": 30, "community_name": "Community 30", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 2}, {"id": "core_roles_setuprolesdirective",Line truncated
const RAW_EDGES = [{"from": "app_vue", "to": "src_app_refreshbuttonautoicons", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_vue", "to": "src_app_refreshpaneltitleicons", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_vue", "to": "main_ts", "label": "imports_from", "title": "imports_from [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_ts", "to": "utils_sys_console_ts", "label": "imports_from", "title": "imports_from [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_ts", "to": "src_main_masksecret", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_ts", "to": "src_main_logapicryptobootinfo", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "src_main_masksecret", "to": "src_main_logapicryptobootinfo", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_index_ts", "to": "directives_index_setupglobdirectives", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_index_setupglobdirectives", "to": "core_auth_setupauthdirective", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "directives_index_setupglobdirectives", "to": "core_roles_setuprolesdirective", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "directives_index_setupglobdirectives", "to": "business_highlight_setuphighlightdirective", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "directives_index_setupglobdirectives", "to": "business_ripple_setuprippledirective", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "directives_core_roles_ts", "to": "core_roles_checkrolepermission", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_roles_ts", "to": "core_roles_removeelement", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_roles_ts", "to": "core_roles_setuprolesdirective", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_roles_checkrolepermission", "to": "core_roles_removeelement", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_auth_ts", "to": "core_auth_checkauthpermission", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_auth_ts", "to": "core_auth_removeelement", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_auth_ts", "to": "core_auth_setupauthdirective", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_checkauthpermission", "to": "core_auth_removeelement", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_business_ripple_ts", "to": "business_ripple_setuprippledirective", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_business_highlight_ts", "to": "business_highlight_highlightcode", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_business_highlight_ts", "to": "business_highlight_insertlinenumbers", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_business_highlight_ts", "to": "business_highlight_addcopybutton", "label": "contains", "title": "contains [EXTRACTED]", "dLine truncated
const LEGEND = [{"cid": 0, "color": "#4E79A7", "label": "Community 0", "count": 578}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 144}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 122}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 96}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 93}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 90}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 89}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 89}, {"cid": 8, "color": "#9C755F", "label": "Community 8", "count": 89}, {"cid": 9, "color": "#BAB0AC", "label": "Community 9", "count": 84}, {"cid": 10, "color": "#4E79A7", "label": "Community 10", "count": 79}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 63}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 63}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 63}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 61}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 48}, {"cid": 16, "color": "#B07AA1", "label": "Community 16", "count": 47}, {"cid": 17, "color": "#FF9DA7", "label": "Community 17", "count": 44}, {"cid": 18, "color": "#9C755F", "label": "Community 18", "count": 42}, {"cid": 19, "color": "#BAB0AC", "label": "Community 19", "count": 42}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 41}, {"cid": 21, "color": "#F28E2B", "label": "Community 21", "count": 37}, {"cid": 22, "color": "#E15759", "label": "Community 22", "count": 37}, {"cid": 23, "color": "#76B7B2", "label": "Community 23", "count": 36}, {"cid": 24, "color": "#59A14F", "label": "Community 24", "count": 36}, {"cid": 25, "color": "#EDC948", "label": "Community 25", "count": 36}, {"cid": 26, "color": "#B07AA1", "label": "Community 26", "count": 34}, {"cid": 27, "color": "#FF9DA7", "label": "Community 27", "count": 34}, {"cid": 28, "color": "#9C755F", "label": "Community 28", "count": 29}, {"cid": 29, "color": "#BAB0AC", "label": "Community 29", "count": 28}, {"cid": 30, "color": "#4E79A7", "label": "Community 30", "count": 22}, {"cid": 31, "color": "#F28E2B", "label": "Community 31", "count": 22}, {"cid": 32, "color": "#E15759", "label": "Community 32", "count": 22}, {"cid": 33, "color": "#76B7B2", "label": "Community 33", "count": 20}, {"cid": 34, "color": "#59A14F", "label": "Community 34", "count": 17}, {"cid": 35, "color": "#EDC948", "label": "Community 35", "count": 16}, {"cid": 36, "color": "#B07AA1", "label": "Community 36", "count": 14}, {"cid": 37, "color": "#FF9DA7", "label": "Community 37", "count": 13}, {"cid": 38, "color": "#9C755F", "label": "Community 38", "count": 13}, {"cid": 39, "color": "#BAB0AC", "label": "Community 39", "count": 12}, {"cid": 40, "color": "#4E79A7", "label": "Community 40", "count": 10}, {"cid": 41, "color": "#F28E2B", "label": "Community 41", "count": 9}, {"cid": 42, "color": "#E15759", "label": "Community 42", "count": 9}, {"cid": 43, "color": "#76B7B2", "label": "Community 43", "count": 9}, {"cid": 44, "color": "#59A14F", "label": "Community 44", "count": 9}, {"cid": 45, "color": "#EDC948", "label": "Community 45", "count": 9}, {"cid": 46, "color": "#B07AA1", "label": "Community 46", "count": 9}, {"cid": 47, "color": "#FF9DA7", "label": "Community 47", "count": 8}, {"cid": 48, "color": "#9C755F", "label": "Community 48", "count": 8}, {"cid": 49, "color": "#BAB0AC", "label": "Community 49", "count": 8}, {"cid": 50, "color": "#4E79A7", "label": "Community 50", "count": 7}, {"cid": 51, "color": "#F28E2B", "label": "Community 51", "count": 7}, {"cid": 52, "color": "#E15759", "label": "Community 52", "count": 6}, {"cid": 53, "color": "#76B7B2", "label": "Community 53", "count": 6}, {"cid": 54, "color": "#59A14F", "label": "Community 54", "count": 5}, {"cid": 55, "color": "#EDC948", "label": "Community 55", "count": 5}, {"cid": 56, "color": "#B07AA1", "label": "Community 56", "count": 5}, {"cid": 57, "color": "#FF9DA7", "label": "Community 57", "count": 5}, {"cid": 58, "color": "#9C755F", "label": "Community 58", "count": 4}, {"cid": 59, "color": "#BAB0AC", "label": "Community 59", "count": 4}, {"cid": 60, "color": "#4E79A7", "label": "Community 60", "count": 4}, {"cid": 61, "color": "#F28E2B", "label": "Community 61", "count": 4}, {"cid": 62, "color": "#E15759", "label": "Community 62", "count": 4}, {"cid": 63, "color": "#76B7B2", "label": "Community 63", "count": 4}, {"cid": 64, "color": "#59A14F", "label": "Community 64", "count": 3}, {"cid": 65, "color": "#EDC948", "label": "Community 65", "count": 3}, {"cid": 66, "color": "#B07AA1", "label": "Community 66", "count": 3}, {"cid": 67, "color": "#FF9DA7", "label": "Community 67", "count": 3}, {"cid": 68, "color": "#9C755F", "label": "Community 68", "count": 3}, {"cid": 69, "color": "#BAB0AC", "label": "Community 69", "count": 3}, {"cid": 70, "color": "#4E79A7", "label": "Community 70", "cLine truncated
// HTML-escape helper — prevents XSS when injecting graph data into innerHTML
function esc(s) {
File diff suppressed because it is too large. Load diff
+23 -21
View File
@@ -1,6 +1,6 @@
{
"/Users/wuzilong/work/00code/zkxw/web-admin/src/App.vue": 1782893851.4905877,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/main.ts": 1784173366.0317953,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/main.ts": 1784274843.7468073,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/env.d.ts": 1781272556.3788364,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/shims-loose.d.ts": 1781272556.417826,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/directives/index.ts": 1781272556.3521712,
@@ -17,8 +17,8 @@
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/common/index.ts": 1781272556.3597305,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/directive/directive.d.ts": 1781272556.3601494,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/api/api.d.ts": 1781272556.3606477,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts": 1784180518.5480022,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/auto-imports.d.ts": 1784180508.1545453,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts": 1784277362.4351091,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/auto-imports.d.ts": 1784277355.5404706,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/store/index.ts": 1781272556.364766,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/router/index.ts": 1782394569.8806834,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/composables/useAttachmentActions.ts": 1783921717.4015942,
@@ -84,7 +84,7 @@
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/mask-sensitive.ts": 1781272556.4029639,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/sample-reception-view-sections.ts": 1783389099.9667985,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/production-labels.ts": 1783306730.912153,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-approval-print.ts": 1784108772.8928564,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-approval-print.ts": 1784276981.3083122,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/inbound-sample-special-mark.ts": 1782889894.1376855,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/production-work-order-category.ts": 1783393556.2431076,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/production-menu-badge.ts": 1783307225.4832592,
@@ -103,6 +103,7 @@
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/production-step-assignee.ts": 1782472559.244021,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/process-material-ui.ts": 1781528129.339137,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-fq-params-change.ts": 1781687645.2065177,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts": 1784277173.1550035,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-flow-steps.ts": 1782806499.3099828,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/loginRsa.ts": 1781272556.4129546,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/chinese-datetime-parse.ts": 1782958233.483039,
@@ -145,8 +146,8 @@
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/http/error.ts": 1781272556.4091117,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/socket/index.ts": 1781272556.4146817,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/router/sidebar-menu-filter.ts": 1781272556.4163456,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/oa-fc-host/App.vue": 1784173366.0334272,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/oa-fc-host/main.ts": 1784173366.0347135,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/oa-fc-host/App.vue": 1784273205.773055,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/oa-fc-host/main.ts": 1784274843.746828,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/core/tables/art-table/index.vue": 1782893852.037499,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/core/tables/art-table-header/index.vue": 1782893852.0053234,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/core/forms/art-search-bar/index.vue": 1782893851.915658,
@@ -228,7 +229,7 @@
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/core/media/art-video-player/index.vue": 1782893851.5118508,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/core/media/art-cutter-img/index.vue": 1782893851.4950457,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/sample-transport-form-section/index.vue": 1782893852.3610222,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/protocol-attachment-mini-readonly/index.vue": 1783921757.1369452,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/protocol-attachment-mini-readonly/index.vue": 1784205395.355872,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/protocol-finance-confirm-fields/index.vue": 1784176800.4318092,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/protocol-finance-confirm-fields/finance-attachments.ts": 1781272556.6256514,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/qc-task-view-dialog/index.vue": 1782894734.8201208,
@@ -260,14 +261,15 @@
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/common/list-datetime-column.vue": 1782893851.4989195,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/common/amount-input/index.vue": 1782893851.5061834,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/common/decimal-input/index.vue": 1782893851.5090024,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaFlowPreview.vue": 1784103286.6667576,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts": 1784105904.181756,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaFlowPreview.vue": 1784276122.848332,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts": 1784272584.166454,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaApprovalPrintSheet.vue": 1784108772.892926,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaFormDesignerEmbed.vue": 1784106491.2979093,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue": 1784103286.5178576,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowBranch.vue": 1784106536.8243594,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/ConditionRuleEditor.vue": 1784106561.55031,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowDesigner.vue": 1784106548.2533798,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaFcRow.vue": 1784277170.6285605,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaFormDesignerEmbed.vue": 1784271049.82102,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue": 1784277386.5617285,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowBranch.vue": 1784273803.9009435,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/ConditionRuleEditor.vue": 1784273504.6858127,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowDesigner.vue": 1784273804.1612618,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/types.ts": 1784106515.9437442,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/hooks/index.ts": 1781272556.653748,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/hooks/core/useFastEnter.ts": 1781272556.6454022,
@@ -312,7 +314,7 @@
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-lab-test-item.ts": 1781272556.666375,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts": 1782710852.6608956,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/sample-sms-notification.ts": 1781272556.666838,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/oaApproval.ts": 1784099959.142847,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/oaApproval.ts": 1784276081.4709907,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/material-stock-check.ts": 1781427280.4992144,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/research-donation.ts": 1782893816.502791,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts": 1783327864.9737554,
@@ -397,15 +399,15 @@
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/system/dept/index.vue": 1784018212.022131,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/system/dict/index.vue": 1783326448.9326534,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/system/leave/index.vue": 1783326448.934463,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/start/index.vue": 1784099881.4392262,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/roles/index.vue": 1784018992.582203,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/start/index.vue": 1784276545.557209,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/roles/index.vue": 1784269877.2911904,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/form-designer-spike/index.vue": 1784018202.8769164,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/done/index.vue": 1784102239.4821205,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/mine/index.vue": 1784173366.0358684,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/designer/index.vue": 1784106499.9728048,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/instances/detail.vue": 1784103227.4305036,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/designer/index.vue": 1784271066.9590933,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/instances/detail.vue": 1784276981.3081641,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/cc/index.vue": 1784173366.0354402,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/apps/index.vue": 1784022023.6119828,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/apps/index.vue": 1784260925.8786883,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/pending/index.vue": 1784102236.6623435,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/output-type/index.vue": 1782893852.8585393,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/index.vue": 1783326448.9373286,
@@ -538,7 +540,7 @@
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-material/QcMaterialBatchAttachmentDialog.vue": 1782893853.076457,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-material-amount-auth/index.vue": 1783919123.1912484,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/pre-transit-sample/index.vue": 1783326448.9852715,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/pre-transit-sample/PreTransitProtocolCardList.vue": 1783925976.6947525,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/pre-transit-sample/PreTransitProtocolCardList.vue": 1784204877.3273342,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/sample-reception/index.vue": 1783389101.2287407,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/sample-reception/SampleReceptionCardList.vue": 1783924089.846302,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/my-qc-task/index.vue": 1783325990.456282,
+15 -6
View File
@@ -182,13 +182,22 @@ export function fetchOaTemplateDetail(appId: string) {
return request.get<any>({ url: `${BASE}/templates/${appId}` })
}
/** 发起前审批流预览(按当前登录人解析审批人) */
export function fetchOaFlowPreview(appId: string, initiatorSelectUserIds?: string[]) {
return request.get<{ steps: OaFlowPreviewStep[] }>({
/** 发起前审批流预览(条件齐后返回最终路径) */
export function fetchOaFlowPreview(
appId: string,
opts?: { formData?: Record<string, any>; initiatorSelectUserIds?: string[] }
) {
return request.post<{
resolved: boolean
message?: string
steps: OaFlowPreviewStep[]
}>({
url: `${BASE}/templates/${appId}/flow-preview`,
params: initiatorSelectUserIds?.length
? { initiatorSelectUserIds: initiatorSelectUserIds.join(',') }
: undefined
data: {
formData: opts?.formData || {},
initiatorSelectUserIds: opts?.initiatorSelectUserIds || undefined
},
showSuccessMessage: false
})
}
@@ -0,0 +1,52 @@
/**
* OA · FormCreate 运行时表单布局
* - 设计器栅格 fcRow 渲染为 ._fd-row(flex),props.gutter 不生效
* - 用负 margin + 列 padding 模拟间距,并用 width 补偿保证占满整行
* - 控件默认拉满列宽,避免日期/输入框定宽导致右侧留白
*/
.form-create {
width: 100%;
--oa-fc-gutter: 20px;
.el-row {
width: 100%;
}
/* 设计器「栅格布局」假 row(对齐 ElRow gutter:负 margin + 列 padding) */
._fd-row {
display: flex;
flex-wrap: wrap;
box-sizing: border-box;
position: relative;
width: 100%;
margin-left: calc(var(--oa-fc-gutter) / -2);
margin-right: calc(var(--oa-fc-gutter) / -2);
> .el-col {
box-sizing: border-box;
padding-left: calc(var(--oa-fc-gutter) / 2);
padding-right: calc(var(--oa-fc-gutter) / 2);
}
}
.el-form-item {
width: 100%;
margin-right: 0;
}
.el-form-item__content {
width: 100%;
}
.el-input,
.el-select,
.el-cascader,
.el-textarea,
.el-input-number,
.el-date-editor,
.el-date-editor.el-input,
.el-date-editor.el-input__wrapper {
width: 100%;
}
}
+3
View File
@@ -25,6 +25,9 @@
// OA 审批 FormCreate 设计器三栏布局
@use './core/oa-fc-designer.scss';
// OA 审批 FormCreate 运行时表单(栅格间距 / 控件铺满)
@use './core/oa-fc-runtime.scss';
// 主题切换过渡优化
@use './core/theme-change.scss';
@@ -1,6 +1,6 @@
<!-- 协议附件 — 迷你缩略图只读(卡片列表用) -->
<template>
<div class="protocol-attachment-mini">
<div class="protocol-attachment-mini" :class="{ 'is-multi': files.length > 1 }">
<div v-if="label" class="protocol-attachment-mini__label">{{ label }}</div>
<span v-if="!files.length" class="protocol-attachment-mini__empty">{{ emptyText }}</span>
<div v-else class="protocol-attachment-mini__list">
@@ -22,12 +22,12 @@
</template>
<template v-else-if="isVideoFile(file)">
<div class="protocol-attachment-mini__icon protocol-attachment-mini__icon--video">
<el-icon :size="20"><VideoPlay /></el-icon>
<el-icon :size="files.length > 1 ? 14 : 20"><VideoPlay /></el-icon>
</div>
</template>
<template v-else>
<div class="protocol-attachment-mini__icon protocol-attachment-mini__icon--doc">
<el-icon :size="20"><Document /></el-icon>
<el-icon :size="files.length > 1 ? 14 : 20"><Document /></el-icon>
</div>
</template>
</div>
@@ -219,4 +219,42 @@
color: #fff;
}
}
/* 多附件时缩小缩略图,便于在卡片内并排展示 */
.protocol-attachment-mini.is-multi {
.protocol-attachment-mini__list {
gap: 4px;
}
.protocol-attachment-mini__item {
width: 48px;
border-radius: 4px;
}
.protocol-attachment-mini__preview {
height: 36px;
}
.protocol-attachment-mini__icon {
width: 22px;
height: 22px;
border-radius: 6px;
}
.protocol-attachment-mini__footer {
padding: 2px 3px;
gap: 1px;
}
.protocol-attachment-mini__name {
font-size: 9px;
}
.protocol-attachment-mini__download {
width: 14px;
height: 14px;
font-size: 9px;
border-radius: 3px;
}
}
</style>
@@ -0,0 +1,10 @@
<!-- 运行时栅格行:对齐设计器 FcRow(._fd-row flex),间距由 oa-fc-runtime.scss 提供 -->
<template>
<div class="_fd-row el-row" v-bind="$attrs">
<slot />
</div>
</template>
<script setup lang="ts">
defineOptions({ name: 'FcRow', inheritAttrs: false })
</script>
@@ -1,11 +1,14 @@
<!-- 发起审批 · 表单底部审批流预览(对齐 docs/mockups/oa-approval-start-flow-preview-demo.html) -->
<template>
<div class="oa-flow-preview">
<div v-loading="loading" class="oa-flow-preview">
<div class="oa-flow-preview__title">
<span>审批流程</span>
<span v-if="hint" class="oa-flow-preview__hint">{{ hint }}</span>
<span v-if="resolved && hint" class="oa-flow-preview__hint">{{ hint }}</span>
</div>
<div v-loading="loading" class="oa-flow-preview__chain">
<div v-if="!resolved" class="oa-flow-preview__pending">
{{ pendingMessage || '必填信息填写后,流程将自动显示' }}
</div>
<div v-else class="oa-flow-preview__chain">
<div v-if="!loading && !steps.length" class="oa-flow-preview__empty">暂无流程配置</div>
<div v-for="(s, idx) in steps" :key="s.id || idx" class="oa-flow-step">
<div class="oa-flow-rail">
@@ -49,15 +52,20 @@
steps?: OaFlowPreviewStep[]
loading?: boolean
hint?: string
resolved?: boolean
pendingMessage?: string
}>(),
{
steps: () => [],
loading: false,
hint: '按当前发起人解析审批人'
hint: '按当前发起人解析审批人',
resolved: true,
pendingMessage: '必填信息填写后,流程将自动显示'
}
)
const steps = computed(() => props.steps || [])
const resolved = computed(() => props.resolved !== false)
function signBadge(s: OaFlowPreviewStep) {
if (s.type === 'cc' || s.signMode === 'cc') return 'cc'
@@ -105,6 +113,14 @@
font-weight: 400;
}
.oa-flow-preview__pending {
padding: 16px 8px 20px;
color: var(--mint-text-muted, #94a3b8);
font-size: 13px;
line-height: 1.5;
text-align: center;
}
.oa-flow-preview__empty {
padding: 8px 0;
color: var(--mint-text-muted, #94a3b8);
@@ -29,6 +29,8 @@
const frameRef = ref<HTMLIFrameElement | null>(null)
const frameReady = ref(false)
let reqSeq = 0
/** 最近一次推入 iframe 的 schema JSON,用于避免保存回写后重复 setRule 清空画布 */
let lastPushedJson = ''
const pending = new Map<
number,
{ resolve: (v: { rule: unknown; option: unknown }) => void; reject: (e: Error) => void }
@@ -62,6 +64,10 @@
}
}
function schemaJson(schema: unknown) {
return JSON.stringify(toPlainSchema(schema))
}
function postToFrame(payload: Record<string, unknown>) {
try {
frameRef.value?.contentWindow?.postMessage(payload, '*')
@@ -70,11 +76,16 @@
}
}
function pushSchemaToFrame() {
/** force=true 时即使内容相同也重新 setRule(用于切回表单 Tab 强制回显) */
function pushSchemaToFrame(force = false) {
if (!frameReady.value) return
const schema = toPlainSchema(props.modelValue)
const json = JSON.stringify(schema)
if (!force && json === lastPushedJson) return
lastPushedJson = json
postToFrame({
type: MSG.SET,
schema: toPlainSchema(props.modelValue)
schema
})
}
@@ -88,7 +99,7 @@
function onFrameLoad() {
if (frameReady.value) {
pushSchemaToFrame()
pushSchemaToFrame(true)
pushFlowRefs()
}
}
@@ -98,11 +109,13 @@
if (!data || typeof data !== 'object') return
if (data.type === MSG.READY) {
frameReady.value = true
pushSchemaToFrame()
lastPushedJson = ''
pushSchemaToFrame(true)
pushFlowRefs()
// 宿主刚就绪时再补推一次,避免 setRule 早于内部 dragForm 初始化
window.setTimeout(() => pushSchemaToFrame(), 50)
window.setTimeout(() => pushSchemaToFrame(), 200)
// 宿主刚就绪时再补推,避免 setRule 早于内部 dragForm / 菜单初始化
window.setTimeout(() => pushSchemaToFrame(true), 50)
window.setTimeout(() => pushSchemaToFrame(true), 200)
window.setTimeout(() => pushSchemaToFrame(true), 500)
return
}
if (data.type === MSG.SCHEMA && typeof data.requestId === 'number') {
@@ -110,6 +123,8 @@
if (!wait) return
pending.delete(data.requestId)
const schema = toPlainSchema(data.schema)
// 与父级即将回写的内容对齐,避免 watch 再次 setRule
lastPushedJson = JSON.stringify(schema)
wait.resolve(schema)
}
}
@@ -136,12 +151,17 @@
})
}
/** 切回「表单设计」Tab 时强制把父级 schema 灌回画布 */
function reapplySchema() {
pushSchemaToFrame(true)
pushFlowRefs()
}
watch(
() => props.modelValue,
() => schemaJson(props.modelValue),
() => {
pushSchemaToFrame()
},
{ deep: true }
pushSchemaToFrame(false)
}
)
watch(
@@ -162,7 +182,7 @@
pending.clear()
})
defineExpose({ fetchSchema })
defineExpose({ fetchSchema, reapplySchema })
</script>
<style scoped lang="scss">
@@ -8,10 +8,7 @@
<div v-if="!items.length" class="oa-flow-preview__empty">暂无任务记录</div>
<div v-for="(item, idx) in items" :key="item.key" class="oa-flow-step">
<div class="oa-flow-rail">
<div
class="oa-flow-dot"
:class="dotClass(item)"
/>
<div class="oa-flow-dot" :class="dotClass(item)" />
<div v-if="idx < items.length - 1" class="oa-flow-line" />
</div>
<div class="oa-flow-card">
@@ -20,7 +17,11 @@
<span v-if="statusBadge(item)" class="oa-flow-badge" :class="statusBadge(item)">
{{ statusText(item.status) }}
</span>
<span v-if="item.taskType === 'cc'" class="oa-flow-badge cc">抄送</span>
<span v-if="signBadge(item)" class="oa-flow-badge" :class="signBadge(item)">
{{ signBadgeText(item) }}
</span>
<span v-else-if="item.taskType === 'cc'" class="oa-flow-badge cc">抄送</span>
<span v-else-if="item.taskType === 'end'" class="oa-flow-badge mute">结束</span>
<template v-if="item.timestamp">
<span class="oa-flow-card__sep">·</span>
<span class="oa-flow-card__meta" :title="item.timestamp">{{ item.timestamp }}</span>
@@ -32,12 +33,21 @@
</span>
</template>
<span
v-if="item.assignee && item.kind !== 'pending_node' && item.kind !== 'terminal'"
v-if="displayPeople(item).length && item.kind !== 'terminal'"
class="oa-flow-card__people"
>
<span class="oa-person-chip">
<span class="oa-person-chip__dot">{{ avatarChar(item.assignee) }}</span>
{{ item.assignee }}
<span
v-for="p in displayPeople(item)"
:key="p.id || p.nickName"
class="oa-person-chip"
:class="personChipClass(p.status)"
:title="personTitle(p)"
>
<span class="oa-person-chip__dot">{{ avatarChar(p.nickName) }}</span>
{{ p.nickName }}
<span v-if="personStatusHint(p.status)" class="oa-person-chip__st">
{{ personStatusHint(p.status) }}
</span>
</span>
</span>
</div>
@@ -53,6 +63,15 @@
<script setup lang="ts">
defineOptions({ name: 'OaProgressChain' })
export type OaProgressPerson = {
id?: string
nickName?: string
status?: string
timestamp?: string
commentText?: string
taskId?: string
}
export type OaProgressChainItem = {
key: string
title: string
@@ -63,6 +82,8 @@
commentText?: string
taskType?: string
kind?: string
signMode?: string
people?: OaProgressPerson[]
}
withDefaults(
@@ -100,6 +121,59 @@
return ''
}
function signBadge(item: OaProgressChainItem) {
if (item.taskType === 'cc' || item.signMode === 'cc') return 'cc'
if (item.signMode === 'and') return 'and'
if (item.signMode === 'or') return 'or'
return ''
}
function signBadgeText(item: OaProgressChainItem) {
const k = signBadge(item)
if (k === 'cc') return '抄送'
if (k === 'and') return '会签'
if (k === 'or') return '或签'
return ''
}
function displayPeople(item: OaProgressChainItem): OaProgressPerson[] {
const list = Array.isArray(item.people) ? item.people.filter((p) => p?.nickName || p?.id) : []
if (list.length) {
return list.map((p) => ({
...p,
nickName: (p.nickName || p.id || '').trim()
}))
}
const name = (item.assignee || '').trim()
if (!name) return []
return [{ nickName: name, status: item.status }]
}
function personChipClass(status?: string) {
const s = status || ''
if (s === 'approved' || s === 'completed') return 'is-ok'
if (s === 'pending' || s === 'running') return 'is-pending'
if (s === 'rejected' || s === 'returned' || s === 'cancelled') return 'is-danger'
if (s === 'done' || s === 'not_reached') return 'is-mute'
return ''
}
function personStatusHint(status?: string) {
const s = status || ''
if (s === 'approved') return '已同意'
if (s === 'rejected') return '已拒绝'
if (s === 'returned') return '已打回'
if (s === 'pending' || s === 'running') return '待处理'
if (s === 'done') return '无需处理'
if (s === 'not_reached') return '未到达'
return ''
}
function personTitle(p: OaProgressPerson) {
const parts = [p.nickName || '', statusText(p.status || ''), p.timestamp || ''].filter(Boolean)
return parts.join(' · ')
}
function dotClass(item: OaProgressChainItem) {
const s = item.status || ''
if (s === 'approved' || s === 'completed' || s === 'done' || s === 'submitted') return 'ok'
@@ -275,6 +349,42 @@
white-space: nowrap;
background: #f1f5f9;
border-radius: 999px;
&.is-ok {
color: #059669;
background: #ecfdf5;
.oa-person-chip__dot {
background: var(--primary, #10b981);
}
}
&.is-pending {
color: #d97706;
background: #fff7ed;
.oa-person-chip__dot {
background: #d97706;
}
}
&.is-danger {
color: #dc2626;
background: #fef2f2;
.oa-person-chip__dot {
background: #ef4444;
}
}
&.is-mute {
color: #94a3b8;
background: #f8fafc;
.oa-person-chip__dot {
background: #94a3b8;
}
}
}
.oa-person-chip__dot {
@@ -289,6 +399,12 @@
border-radius: 50%;
}
.oa-person-chip__st {
margin-left: 2px;
font-size: 10px;
opacity: 0.85;
}
.oa-flow-badge {
flex-shrink: 0;
padding: 0 5px;
@@ -308,6 +424,11 @@
background: #fff7ed;
}
&.and {
color: #2563eb;
background: #eff6ff;
}
&.danger {
color: #dc2626;
background: #fef2f2;
@@ -68,6 +68,16 @@
:disabled="disabled"
@update:model-value="(v) => onValueChange(idx, coerceValue(rule.field, v))"
/>
<el-button
class="cond-rule-editor__del"
text
type="danger"
:disabled="disabled || localRules.length <= 1"
title="删除条件"
@click="removeRule(idx)"
>
<el-icon><Delete /></el-icon>
</el-button>
</div>
<div v-if="idx < localRules.length - 1" class="cond-rule-editor__and">且(AND)</div>
</div>
@@ -86,7 +96,7 @@
<script setup lang="ts">
import { computed, watch } from 'vue'
import { Plus } from '@element-plus/icons-vue'
import { Delete, Plus } from '@element-plus/icons-vue'
import {
opsForFieldType,
type ConditionCandidate,
@@ -207,6 +217,12 @@
}
])
}
function removeRule(idx: number) {
if (localRules.value.length <= 1) return
const next = localRules.value.filter((_, i) => i !== idx)
emitRules(next)
}
</script>
<style scoped lang="scss">
@@ -230,11 +246,16 @@
.cond-rule-editor__row {
display: grid;
grid-template-columns: 1fr auto 1fr;
grid-template-columns: 1fr auto 1fr auto;
gap: 6px;
align-items: center;
margin-bottom: 6px;
}
.cond-rule-editor__del {
padding: 4px;
}
.cond-rule-editor__and {
margin: 0 0 6px;
color: var(--mint-text-muted, #94a3b8);
@@ -36,8 +36,23 @@
<div class="flow-cond-col__title" @click.stop="emit('edit', node)">
{{ branchTitle(g, idx) }}
</div>
<!-- 分支仅有结束节点时,先露出「+」才能往分支内插入 -->
<el-dropdown
v-if="!g.child || g.child.type === 'end'"
trigger="click"
@command="(cmd: string) => onAddInGroup(idx, cmd)"
>
<button type="button" class="flow-plus" title="在本分支添加节点">+</button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="approval">审批人</el-dropdown-item>
<el-dropdown-item command="cc">抄送人</el-dropdown-item>
<el-dropdown-item command="condition">条件分支</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<FlowBranch
v-if="g.child"
v-if="g.child && g.child.type !== 'end'"
:node="g.child"
:depth="depth + 1"
:candidates="candidates"
@@ -48,6 +63,28 @@
<div v-else class="flow-end">流程结束</div>
</div>
</div>
<!-- 条件分支汇合后继续主链 -->
<el-dropdown trigger="click" @command="(cmd: string) => onAdd(cmd)">
<button type="button" class="flow-plus" title="在条件分支后添加节点">+</button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="approval">审批人</el-dropdown-item>
<el-dropdown-item command="cc">抄送人</el-dropdown-item>
<el-dropdown-item command="condition">条件分支</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<FlowBranch
v-if="node.child"
:node="node.child"
:depth="depth"
:candidates="candidates"
@edit="(n) => emit('edit', n)"
@remove="(id) => emit('remove', id)"
@add="(payload) => emit('add', payload)"
/>
<div v-else class="flow-end">流程结束</div>
</template>
<template v-else>
@@ -102,7 +139,14 @@
const emit = defineEmits<{
edit: [node: FlowNode]
remove: [nodeId: string]
add: [payload: { parentId: string; type: 'approval' | 'cc' | 'condition' }]
add: [
payload: {
parentId: string
type: 'approval' | 'cc' | 'condition'
/** 写入条件节点的第 N 个分支;缺省则写入 parent.child(汇合后主链) */
groupIndex?: number
}
]
}>()
function typeLabel(t: string) {
@@ -134,6 +178,12 @@
emit('add', { parentId: props.node.id, type: cmd })
}
}
function onAddInGroup(groupIndex: number, cmd: string) {
if (cmd === 'approval' || cmd === 'cc' || cmd === 'condition') {
emit('add', { parentId: props.node.id, type: cmd, groupIndex })
}
}
</script>
<style scoped lang="scss">
@@ -459,10 +459,35 @@
return null
}
function onAdd(payload: { parentId: string; type: 'approval' | 'cc' | 'condition' }) {
function onAdd(payload: {
parentId: string
type: 'approval' | 'cc' | 'condition'
groupIndex?: number
}) {
const parent = findNode(root.value, payload.parentId)
if (!parent) return
const neu = createNode(payload.type)
// 写入条件节点的某一分支
if (
parent.type === 'condition' &&
typeof payload.groupIndex === 'number' &&
parent.conditionGroups?.[payload.groupIndex]
) {
const g = parent.conditionGroups[payload.groupIndex]
const old = g.child || createEndNode()
if (payload.type === 'condition') {
const groups = neu.conditionGroups || []
const def = groups.find((x) => x.isDefault) || groups[groups.length - 1]
if (def) def.child = old
} else {
neu.child = old
}
g.child = neu
commit()
return
}
const old = parent.child || createEndNode()
if (payload.type === 'condition') {
const groups = neu.conditionGroups || []
@@ -1,5 +1,6 @@
/** 允许「参与流程条件分支」的 FormCreate type */
export const CONDITION_ELIGIBLE_TYPES = new Set([
'input',
'inputNumber',
'number',
'money',
@@ -20,6 +21,7 @@ export interface ConditionCandidate {
}
export function opsForFieldType(type: string): Array<{ value: ConditionOp; label: string }> {
// 单选/下拉为离散选项,仅等于/不等于;输入框常填数字参与区间比较,与数字/金额/日期同套运算符
if (type === 'radio' || type === 'select') {
return [
{ value: '==', label: '等于' },
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_types_import_components_d_ts", "label": "components.d.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_approval_print_ts", "label": "oa-approval-print.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-approval-print.ts", "source_location": "L1"}, {"id": "utils_oa_approval_print_resolvestamp", "label": "resolveStamp()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-approval-print.ts", "source_location": "L80"}, {"id": "utils_oa_approval_print_statustext", "label": "statusText()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-approval-print.ts", "source_location": "L97"}, {"id": "utils_oa_approval_print_formatdateonly", "label": "formatDateOnly()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-approval-print.ts", "source_location": "L101"}, {"id": "utils_oa_approval_print_formatnow", "label": "formatNow()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-approval-print.ts", "source_location": "L107"}, {"id": "utils_oa_approval_print_ishttpurl", "label": "isHttpUrl()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-approval-print.ts", "source_location": "L113"}, {"id": "utils_oa_approval_print_extracturls", "label": "extractUrls()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-approval-print.ts", "source_location": "L117"}, {"id": "utils_oa_approval_print_formatscalar", "label": "formatScalar()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-approval-print.ts", "source_location": "L148"}, {"id": "utils_oa_approval_print_walkrules", "label": "walkRules()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-approval-print.ts", "source_location": "L170"}, {"id": "utils_oa_approval_print_buildformrows", "label": "buildFormRows()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-approval-print.ts", "source_location": "L206"}, {"id": "utils_oa_approval_print_buildflowitems", "label": "buildFlowItems()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-approval-print.ts", "source_location": "L226"}, {"id": "utils_oa_approval_print_buildoaprintmodel", "label": "buildOaPrintModel()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-approval-print.ts", "source_location": "L316"}, {"id": "utils_oa_approval_print_buildoaprintfilename", "label": "buildOaPrintFilename()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-approval-print.ts", "source_location": "L354"}, {"id": "utils_oa_approval_print_canvastopdf", "label": "canvasToPdf()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-approval-print.ts", "source_location": "L367"}, {"id": "utils_oa_approval_print_exportoaapprovalpdf", "label": "exportOaApprovalPdf()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-approval-print.ts", "source_location": "L401"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_approval_print_ts", "target": "vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-approval-print.ts", "source_location": "L5", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_approval_print_ts", "target": "html2canvas", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-approval-print.ts", "source_location": "L6", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_approval_print_ts", "target": "jspdf", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-approval-print.ts", "source_location": "L7", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_approval_print_ts", "target": "utils_oa_approval_print_resolvestamp", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-approval-print.ts", "source_location": "L80", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_approval_print_ts", "target": "utils_oa_approval_print_statustext", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-approval-print.ts", "source_location": "L97", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_approval_print_ts", "target": "utils_oa_approval_print_formatdateonly", "relation": "contains",Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload_ts", "label": "oa-form-create-upload.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L1"}, {"id": "utils_oa_form_create_upload_resolveuploadresponseurl", "label": "resolveUploadResponseUrl()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L25"}, {"id": "utils_oa_form_create_upload_ensureoauploadruleprops", "label": "ensureOaUploadRuleProps()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L39"}, {"id": "utils_oa_form_create_upload_setupformcreateupload", "label": "setupFormCreateUpload()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L98"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload_ts", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L5", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_business", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L6", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_composables_useattachmentactions", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L7", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload_ts", "target": "utils_oa_form_create_upload_resolveuploadresponseurl", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L25", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload_ts", "target": "utils_oa_form_create_upload_ensureoauploadruleprops", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L39", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload_ts", "target": "utils_oa_form_create_upload_setupformcreateupload", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L98", "weight": 1.0}], "raw_calls": [{"caller_nid": "utils_oa_form_create_upload_resolveuploadresponseurl", "callee": "trim", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L26"}, {"caller_nid": "utils_oa_form_create_upload_resolveuploadresponseurl", "callee": "String", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L26"}, {"caller_nid": "utils_oa_form_create_upload_resolveuploadresponseurl", "callee": "attachmentFullUrl", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L30"}, {"caller_nid": "utils_oa_form_create_upload_ensureoauploadruleprops", "callee": "isArray", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L40"}, {"caller_nid": "utils_oa_form_create_upload_ensureoauploadruleprops", "callee": "map", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L41"}]}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_roles_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/roles/index.vue", "source_location": "L1"}, {"id": "roles_index_avatarcolor", "label": "avatarColor()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/roles/index.vue", "source_location": "L390"}, {"id": "roles_index_avatarinitial", "label": "avatarInitial()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/roles/index.vue", "source_location": "L396"}, {"id": "roles_index_resolveuser", "label": "resolveUser()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/roles/index.vue", "source_location": "L401"}, {"id": "roles_index_memberoptionlabel", "label": "memberOptionLabel()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/roles/index.vue", "source_location": "L405"}, {"id": "roles_index_memberoptionsub", "label": "memberOptionSub()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/roles/index.vue", "source_location": "L412"}, {"id": "roles_index_chiptitle", "label": "chipTitle()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/roles/index.vue", "source_location": "L419"}, {"id": "roles_index_onmemberpick", "label": "onMemberPick()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/roles/index.vue", "source_location": "L424"}, {"id": "roles_index_removemember", "label": "removeMember()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/roles/index.vue", "source_location": "L434"}, {"id": "roles_index_loaddata", "label": "loadData()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/roles/index.vue", "source_location": "L438"}, {"id": "roles_index_handlesearch", "label": "handleSearch()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/roles/index.vue", "source_location": "L451"}, {"id": "roles_index_handlereset", "label": "handleReset()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/roles/index.vue", "source_location": "L455"}, {"id": "roles_index_resetform", "label": "resetForm()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/roles/index.vue", "source_location": "L461"}, {"id": "roles_index_handleadd", "label": "handleAdd()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/roles/index.vue", "source_location": "L469"}, {"id": "roles_index_handleedit", "label": "handleEdit()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/roles/index.vue", "source_location": "L477"}, {"id": "roles_index_handlesubmit", "label": "handleSubmit()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/roles/index.vue", "source_location": "L489"}, {"id": "roles_index_handledelete", "label": "handleDelete()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/roles/index.vue", "source_location": "L514"}, {"id": "roles_index_loaduseroptions", "label": "loadUserOptions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/roles/index.vue", "source_location": "L526"}, {"id": "roles_index_handlemembers", "label": "handleMembers()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/roles/index.vue", "source_location": "L545"}, {"id": "roles_index_handlemembersubmit", "label": "handleMemberSubmit()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/roles/index.vue", "source_location": "L560"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_roles_index_vue", "target": "vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/roles/index.vue", "source_location": "L320", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_roles_index_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/roles/index.vue", "source_location": "L321", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_roles_index_vue", "target"Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload_ts", "label": "oa-form-create-upload.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L1"}, {"id": "utils_oa_form_create_upload_resolveuploadresponseurl", "label": "resolveUploadResponseUrl()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L25"}, {"id": "utils_oa_form_create_upload_ensureoauploadruleprops", "label": "ensureOaUploadRuleProps()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L37"}, {"id": "utils_oa_form_create_upload_setupformcreateupload", "label": "setupFormCreateUpload()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L85"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload_ts", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L5", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_business", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L6", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_composables_useattachmentactions", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L7", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload_ts", "target": "utils_oa_form_create_upload_resolveuploadresponseurl", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L25", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload_ts", "target": "utils_oa_form_create_upload_ensureoauploadruleprops", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L37", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload_ts", "target": "utils_oa_form_create_upload_setupformcreateupload", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L85", "weight": 1.0}], "raw_calls": [{"caller_nid": "utils_oa_form_create_upload_resolveuploadresponseurl", "callee": "trim", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L26"}, {"caller_nid": "utils_oa_form_create_upload_resolveuploadresponseurl", "callee": "String", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L26"}, {"caller_nid": "utils_oa_form_create_upload_resolveuploadresponseurl", "callee": "attachmentFullUrl", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L30"}, {"caller_nid": "utils_oa_form_create_upload_ensureoauploadruleprops", "callee": "isArray", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L38"}, {"caller_nid": "utils_oa_form_create_upload_ensureoauploadruleprops", "callee": "map", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L39"}]}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oa_condition_fields_ts", "label": "oa-condition-fields.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts", "source_location": "L1"}, {"id": "oa_approval_oa_condition_fields_opsforfieldtype", "label": "opsForFieldType()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts", "source_location": "L23"}, {"id": "oa_approval_oa_condition_fields_walkrules", "label": "walkRules()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts", "source_location": "L40"}, {"id": "oa_approval_oa_condition_fields_flattenformrules", "label": "flattenFormRules()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts", "source_location": "L50"}, {"id": "oa_approval_oa_condition_fields_listconditioncandidates", "label": "listConditionCandidates()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts", "source_location": "L65"}, {"id": "oa_approval_oa_condition_fields_collectconditionreferencedfields", "label": "collectConditionReferencedFields()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts", "source_location": "L91"}, {"id": "oa_approval_oa_condition_fields_normalizeschemaconditionrequired", "label": "normalizeSchemaConditionRequired()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts", "source_location": "L109"}, {"id": "oa_approval_oa_condition_fields_formatconditionpreview", "label": "formatConditionPreview()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts", "source_location": "L137"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oa_condition_fields_ts", "target": "oa_approval_oa_condition_fields_opsforfieldtype", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts", "source_location": "L23", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oa_condition_fields_ts", "target": "oa_approval_oa_condition_fields_walkrules", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts", "source_location": "L40", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oa_condition_fields_ts", "target": "oa_approval_oa_condition_fields_flattenformrules", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts", "source_location": "L50", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oa_condition_fields_ts", "target": "oa_approval_oa_condition_fields_listconditioncandidates", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts", "source_location": "L65", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oa_condition_fields_ts", "target": "oa_approval_oa_condition_fields_collectconditionreferencedfields", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts", "source_location": "L91", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oa_condition_fields_ts", "target": "oa_approval_oa_condition_fields_normalizeschemaconditionrequired", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts", "source_location": "L109", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oa_condition_fields_ts", "target": "oa_approval_oa_condition_fields_formatconditionpreview", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts", "source_location": "L137", "weight": 1.0}, {"source": "oa_approval_oa_condition_fields_flattenformrules", "target": "oa_approval_oa_condition_fields_walkrules", "relation": "calls", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-aLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_pre_transit_sample_pretransitprotocolcardlist_vue", "label": "PreTransitProtocolCardList.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/pre-transit-sample/PreTransitProtocolCardList.vue", "source_location": "L1"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_pre_transit_sample_pretransitprotocolcardlist_vue", "target": "vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/pre-transit-sample/PreTransitProtocolCardList.vue", "source_location": "L455", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_pre_transit_sample_pretransitprotocolcardlist_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/pre-transit-sample/PreTransitProtocolCardList.vue", "source_location": "L456", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_pre_transit_sample_pretransitprotocolcardlist_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_pre_transit_sample", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/pre-transit-sample/PreTransitProtocolCardList.vue", "source_location": "L457", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_pre_transit_sample_pretransitprotocolcardlist_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_status_tag_registry", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/pre-transit-sample/PreTransitProtocolCardList.vue", "source_location": "L458", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_pre_transit_sample_pretransitprotocolcardlist_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_status_tag_registry", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/pre-transit-sample/PreTransitProtocolCardList.vue", "source_location": "L470", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_pre_transit_sample_pretransitprotocolcardlist_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_components_business_sample_code_with_special_display_index_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/pre-transit-sample/PreTransitProtocolCardList.vue", "source_location": "L471", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_pre_transit_sample_pretransitprotocolcardlist_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_components_business_protocol_attachment_mini_readonly_index_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/pre-transit-sample/PreTransitProtocolCardList.vue", "source_location": "L472", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_pre_transit_sample_pretransitprotocolcardlist_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_protocol_source_attachment", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/pre-transit-sample/PreTransitProtocolCardList.vue", "source_location": "L473", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_pre_transit_sample_pretransitprotocolcardlist_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_composables_useattachmentactions", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/pre-transit-sample/PreTransitProtocolCardList.vue", "source_location": "L474", "weight": 1.0}], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_start_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/start/index.vue", "source_location": "L1"}, {"id": "start_index_validate", "label": "validate()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/start/index.vue", "source_location": "L388"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_start_index_vue", "target": "start_index_validate", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/start/index.vue", "source_location": "L388", "weight": 1.0}], "raw_calls": [{"caller_nid": "start_index_validate", "callee": "warning", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/start/index.vue", "source_location": "L390"}]}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_flow_tree_conditionruleeditor_vue", "label": "ConditionRuleEditor.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/ConditionRuleEditor.vue", "source_location": "L1"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_flow_tree_conditionruleeditor_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/ConditionRuleEditor.vue", "source_location": "L99", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_flow_tree_conditionruleeditor_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oa_condition_fields", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/ConditionRuleEditor.vue", "source_location": "L100", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_flow_tree_conditionruleeditor_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_flow_tree_types", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/ConditionRuleEditor.vue", "source_location": "L105", "weight": 1.0}], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_instances_detail_vue", "label": "detail.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/instances/detail.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_main_ts", "label": "main.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/main.ts", "source_location": "L1"}, {"id": "src_main_masksecret", "label": "maskSecret()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/main.ts", "source_location": "L26"}, {"id": "src_main_logapicryptobootinfo", "label": "logApiCryptoBootInfo()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/main.ts", "source_location": "L32"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_main_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_patch_el_select_filterable", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/main.ts", "source_location": "L1", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_main_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_app_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/main.ts", "source_location": "L2", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_main_ts", "target": "vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/main.ts", "source_location": "L3", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_main_ts", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/main.ts", "source_location": "L4", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_main_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_store", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/main.ts", "source_location": "L8", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_main_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_router", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/main.ts", "source_location": "L9", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_main_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_locales", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/main.ts", "source_location": "L10", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_main_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_assets_styles_core_tailwind_css", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/main.ts", "source_location": "L11", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_main_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_assets_styles_index_scss", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/main.ts", "source_location": "L12", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_main_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_sys_console_ts", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/main.ts", "source_location": "L13", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_main_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_directives", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/main.ts", "source_location": "L14", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_main_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_sys_error_handle", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/main.ts", "source_location": "L15", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_main_ts", "target": "designer", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/main.ts", "source_location": "L16", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_main_ts", "target": "auto_import", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/main.ts", "source_location": "L17", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_main_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload", "relation": "imports_from", "confidence": "EXTRACTED", "source_filLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_start_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/start/index.vue", "source_location": "L1"}, {"id": "start_index_validate", "label": "validate()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/start/index.vue", "source_location": "L375"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_start_index_vue", "target": "start_index_validate", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/start/index.vue", "source_location": "L375", "weight": 1.0}], "raw_calls": [{"caller_nid": "start_index_validate", "callee": "warning", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/start/index.vue", "source_location": "L377"}]}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_oa_fc_host_main_ts", "label": "main.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/oa-fc-host/main.ts", "source_location": "L1"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_oa_fc_host_main_ts", "target": "vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/oa-fc-host/main.ts", "source_location": "L4", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_oa_fc_host_main_ts", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/oa-fc-host/main.ts", "source_location": "L5", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_oa_fc_host_main_ts", "target": "zh_cn", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/oa-fc-host/main.ts", "source_location": "L6", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_oa_fc_host_main_ts", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/oa-fc-host/main.ts", "source_location": "L7", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_oa_fc_host_main_ts", "target": "index_css", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/oa-fc-host/main.ts", "source_location": "L8", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_oa_fc_host_main_ts", "target": "designer", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/oa-fc-host/main.ts", "source_location": "L9", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_oa_fc_host_main_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/oa-fc-host/main.ts", "source_location": "L10", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_oa_fc_host_main_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_oa_fc_host_app_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/oa-fc-host/main.ts", "source_location": "L11", "weight": 1.0}], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oaprogresschain_vue", "label": "OaProgressChain.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L1"}, {"id": "oa_approval_oaprogresschain_statustext", "label": "statusText()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L97"}, {"id": "oa_approval_oaprogresschain_statusbadge", "label": "statusBadge()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L114"}, {"id": "oa_approval_oaprogresschain_signbadge", "label": "signBadge()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L123"}, {"id": "oa_approval_oaprogresschain_signbadgetext", "label": "signBadgeText()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L130"}, {"id": "oa_approval_oaprogresschain_displaypeople", "label": "displayPeople()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L138"}, {"id": "oa_approval_oaprogresschain_personchipclass", "label": "personChipClass()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L151"}, {"id": "oa_approval_oaprogresschain_personstatushint", "label": "personStatusHint()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L160"}, {"id": "oa_approval_oaprogresschain_persontitle", "label": "personTitle()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L171"}, {"id": "oa_approval_oaprogresschain_dotclass", "label": "dotClass()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L176"}, {"id": "oa_approval_oaprogresschain_resolvesourcetext", "label": "resolveSourceText()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L184"}, {"id": "oa_approval_oaprogresschain_avatarchar", "label": "avatarChar()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L196"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oaprogresschain_vue", "target": "oa_approval_oaprogresschain_statustext", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L97", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oaprogresschain_vue", "target": "oa_approval_oaprogresschain_statusbadge", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L114", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oaprogresschain_vue", "target": "oa_approval_oaprogresschain_signbadge", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L123", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oaprogresschain_vue", "target": "oa_approval_oaprogresschain_signbadgetext", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L130", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oaprogresschain_vue", "target": "oa_approval_oaprogresschain_displaypeople", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L138", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oaprogresschain_vue", "target": "oa_approval_oaprogresschain_personchipclass", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vuLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oaformdesignerembed_vue", "label": "OaFormDesignerEmbed.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaFormDesignerEmbed.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_designer_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/designer/index.vue", "source_location": "L1"}, {"id": "designer_index_loaddraft", "label": "loadDraft()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/designer/index.vue", "source_location": "L222"}, {"id": "designer_index_savedraft", "label": "saveDraft()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/designer/index.vue", "source_location": "L258"}, {"id": "designer_index_publish", "label": "publish()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/designer/index.vue", "source_location": "L293"}, {"id": "designer_index_goback", "label": "goBack()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/designer/index.vue", "source_location": "L313"}, {"id": "designer_index_onstepchange", "label": "onStepChange()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/designer/index.vue", "source_location": "L317"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_designer_index_vue", "target": "vue_router", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/designer/index.vue", "source_location": "L113", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_designer_index_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/designer/index.vue", "source_location": "L114", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_designer_index_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/designer/index.vue", "source_location": "L115", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_designer_index_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/designer/index.vue", "source_location": "L116", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_designer_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_business", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/designer/index.vue", "source_location": "L117", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_designer_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_oaapproval", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/designer/index.vue", "source_location": "L118", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_designer_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_flow_tree_flowdesigner_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/designer/index.vue", "source_location": "L119", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_designer_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_flow_tree_types", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/designer/index.vue", "source_location": "L120", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_designer_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oaformdesignerembed_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/designer/index.vue", "source_location": "L121", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_designer_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oa_condition_fields", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/designer/index.vue", "source_location": "L122", "weight": 1.0}, {"source": "users_wuzilong_work_00codLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_types_import_components_d_ts", "label": "components.d.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_flow_tree_flowdesigner_vue", "label": "FlowDesigner.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowDesigner.vue", "source_location": "L1"}, {"id": "flow_tree_flowdesigner_commit", "label": "commit()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowDesigner.vue", "source_location": "L307"}, {"id": "flow_tree_flowdesigner_avatarcolor", "label": "avatarColor()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowDesigner.vue", "source_location": "L359"}, {"id": "flow_tree_flowdesigner_avatarinitial", "label": "avatarInitial()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowDesigner.vue", "source_location": "L365"}, {"id": "flow_tree_flowdesigner_resolveuser", "label": "resolveUser()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowDesigner.vue", "source_location": "L370"}, {"id": "flow_tree_flowdesigner_chiptitle", "label": "chipTitle()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowDesigner.vue", "source_location": "L374"}, {"id": "flow_tree_flowdesigner_memberoptionlabel", "label": "memberOptionLabel()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowDesigner.vue", "source_location": "L379"}, {"id": "flow_tree_flowdesigner_memberoptionsub", "label": "memberOptionSub()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowDesigner.vue", "source_location": "L387"}, {"id": "flow_tree_flowdesigner_onmemberpick", "label": "onMemberPick()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowDesigner.vue", "source_location": "L394"}, {"id": "flow_tree_flowdesigner_removemember", "label": "removeMember()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowDesigner.vue", "source_location": "L403"}, {"id": "flow_tree_flowdesigner_setassigneetype", "label": "setAssigneeType()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowDesigner.vue", "source_location": "L408"}, {"id": "flow_tree_flowdesigner_loadroles", "label": "loadRoles()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowDesigner.vue", "source_location": "L413"}, {"id": "flow_tree_flowdesigner_loadusers", "label": "loadUsers()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowDesigner.vue", "source_location": "L423"}, {"id": "flow_tree_flowdesigner_findnode", "label": "findNode()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowDesigner.vue", "source_location": "L447"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_flow_tree_flowdesigner_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowDesigner.vue", "source_location": "L250", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_flow_tree_flowdesigner_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowDesigner.vue", "source_location": "L251", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_flow_tree_flowdesigner_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_admin", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowDesigner.vue", "source_location": "L252", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_flow_tree_flowdesigner_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_oaapproval", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowDesigner.vue", "source_location": "L253", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_flow_tree_flowdesigner_vue", "target": "users_wuziloLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload_ts", "label": "oa-form-create-upload.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L1"}, {"id": "utils_oa_form_create_upload_resolveuploadresponseurl", "label": "resolveUploadResponseUrl()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L29"}, {"id": "utils_oa_form_create_upload_ensurefcrowuseselrow", "label": "ensureFcRowUsesElRow()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L42"}, {"id": "utils_oa_form_create_upload_ensureuploadrule", "label": "ensureUploadRule()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L58"}, {"id": "utils_oa_form_create_upload_ensureoauploadruleprops", "label": "ensureOaUploadRuleProps()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L97"}, {"id": "utils_oa_form_create_upload_setupformcreateupload", "label": "setupFormCreateUpload()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L126"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload_ts", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L6", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_business", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L7", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_composables_useattachmentactions", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L8", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload_ts", "target": "utils_oa_form_create_upload_resolveuploadresponseurl", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L29", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload_ts", "target": "utils_oa_form_create_upload_ensurefcrowuseselrow", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L42", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload_ts", "target": "utils_oa_form_create_upload_ensureuploadrule", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L58", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload_ts", "target": "utils_oa_form_create_upload_ensureoauploadruleprops", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L97", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload_ts", "target": "utils_oa_form_create_upload_setupformcreateupload", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L126", "weight": 1.0}], "raw_calls": [{"caller_nid": "utils_oa_form_create_upload_resolveuploadresponseurl", "callee": "trim", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L30"}, {"caller_nid": "utils_oa_form_create_upload_resolveuploadresponseurl", "callee": "String", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L30"}, {"caller_nid": "utils_oa_form_create_upload_resolveuploadresponseurl", "callee": "attachmentFullUrl", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L34"}, {"caller_nid": "utils_oa_form_create_upload_ensurefcrowuseselrow", "callee": "String", "souLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_oa_fc_host_app_vue", "label": "App.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/oa-fc-host/App.vue", "source_location": "L1"}, {"id": "oa_fc_host_app_rule", "label": "rule()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/oa-fc-host/App.vue", "source_location": "L46"}, {"id": "oa_fc_host_app_if", "label": "if()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/oa-fc-host/App.vue", "source_location": "L271"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_oa_fc_host_app_vue", "target": "oa_fc_host_app_rule", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/oa-fc-host/App.vue", "source_location": "L46", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_oa_fc_host_app_vue", "target": "oa_fc_host_app_if", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/oa-fc-host/App.vue", "source_location": "L271", "weight": 1.0}], "raw_calls": [{"caller_nid": "oa_fc_host_app_if", "callee": "setTimeout", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/oa-fc-host/App.vue", "source_location": "L272"}]}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_flow_tree_flowbranch_vue", "label": "FlowBranch.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowBranch.vue", "source_location": "L1"}, {"id": "flow_tree_flowbranch_branchtitle", "label": "branchTitle()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowBranch.vue", "source_location": "L160"}, {"id": "flow_tree_flowbranch_nodesummary", "label": "nodeSummary()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowBranch.vue", "source_location": "L167"}, {"id": "flow_tree_flowbranch_onadd", "label": "onAdd()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowBranch.vue", "source_location": "L176"}, {"id": "flow_tree_flowbranch_onaddingroup", "label": "onAddInGroup()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowBranch.vue", "source_location": "L182"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_flow_tree_flowbranch_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oa_condition_fields", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowBranch.vue", "source_location": "L119", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_flow_tree_flowbranch_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_flow_tree_types", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowBranch.vue", "source_location": "L123", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_flow_tree_flowbranch_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_flow_tree_types", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowBranch.vue", "source_location": "L124", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_flow_tree_flowbranch_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_flow_tree_flowbranch_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowBranch.vue", "source_location": "L126", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_flow_tree_flowbranch_vue", "target": "flow_tree_flowbranch_branchtitle", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowBranch.vue", "source_location": "L160", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_flow_tree_flowbranch_vue", "target": "flow_tree_flowbranch_nodesummary", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowBranch.vue", "source_location": "L167", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_flow_tree_flowbranch_vue", "target": "flow_tree_flowbranch_onadd", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowBranch.vue", "source_location": "L176", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_flow_tree_flowbranch_vue", "target": "flow_tree_flowbranch_onaddingroup", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowBranch.vue", "source_location": "L182", "weight": 1.0}], "raw_calls": [{"caller_nid": "flow_tree_flowbranch_branchtitle", "callee": "formatConditionPreview", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowBranch.vue", "source_location": "L162"}, {"caller_nid": "flow_tree_flowbranch_nodesummary", "callee": "summarizeApprover", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowBranch.vue", "source_location": "L173"}, {"caller_nid": "flow_tree_flowbranch_onadd", "callee": "emit", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/flow-tree/FlowBranch.vue", "source_loLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_oa_fc_host_app_vue", "label": "App.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/oa-fc-host/App.vue", "source_location": "L1"}, {"id": "oa_fc_host_app_rule", "label": "rule()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/oa-fc-host/App.vue", "source_location": "L43"}, {"id": "oa_fc_host_app_if", "label": "if()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/oa-fc-host/App.vue", "source_location": "L235"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_oa_fc_host_app_vue", "target": "oa_fc_host_app_rule", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/oa-fc-host/App.vue", "source_location": "L43", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_oa_fc_host_app_vue", "target": "oa_fc_host_app_if", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/oa-fc-host/App.vue", "source_location": "L235", "weight": 1.0}], "raw_calls": [{"caller_nid": "oa_fc_host_app_if", "callee": "setTimeout", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/oa-fc-host/App.vue", "source_location": "L236"}]}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_instances_detail_vue", "label": "detail.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/instances/detail.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_components_business_protocol_attachment_mini_readonly_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/protocol-attachment-mini-readonly/index.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_types_import_components_d_ts", "label": "components.d.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_types_import_components_d_ts", "label": "components.d.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oa_condition_fields_ts", "label": "oa-condition-fields.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts", "source_location": "L1"}, {"id": "oa_approval_oa_condition_fields_opsforfieldtype", "label": "opsForFieldType()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts", "source_location": "L23"}, {"id": "oa_approval_oa_condition_fields_walkrules", "label": "walkRules()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts", "source_location": "L41"}, {"id": "oa_approval_oa_condition_fields_flattenformrules", "label": "flattenFormRules()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts", "source_location": "L51"}, {"id": "oa_approval_oa_condition_fields_listconditioncandidates", "label": "listConditionCandidates()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts", "source_location": "L66"}, {"id": "oa_approval_oa_condition_fields_collectconditionreferencedfields", "label": "collectConditionReferencedFields()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts", "source_location": "L92"}, {"id": "oa_approval_oa_condition_fields_normalizeschemaconditionrequired", "label": "normalizeSchemaConditionRequired()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts", "source_location": "L110"}, {"id": "oa_approval_oa_condition_fields_formatconditionpreview", "label": "formatConditionPreview()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts", "source_location": "L138"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oa_condition_fields_ts", "target": "oa_approval_oa_condition_fields_opsforfieldtype", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts", "source_location": "L23", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oa_condition_fields_ts", "target": "oa_approval_oa_condition_fields_walkrules", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts", "source_location": "L41", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oa_condition_fields_ts", "target": "oa_approval_oa_condition_fields_flattenformrules", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts", "source_location": "L51", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oa_condition_fields_ts", "target": "oa_approval_oa_condition_fields_listconditioncandidates", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts", "source_location": "L66", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oa_condition_fields_ts", "target": "oa_approval_oa_condition_fields_collectconditionreferencedfields", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts", "source_location": "L92", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oa_condition_fields_ts", "target": "oa_approval_oa_condition_fields_normalizeschemaconditionrequired", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts", "source_location": "L110", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oa_condition_fields_ts", "target": "oa_approval_oa_condition_fields_formatconditionpreview", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts", "source_location": "L138", "weight": 1.0}, {"source": "oa_approval_oa_condition_fields_flattenformrules", "target": "oa_approval_oa_condition_fields_walkrules", "relation": "calls", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-aLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_types_import_components_d_ts", "label": "components.d.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oaprogresschain_vue", "label": "OaProgressChain.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L1"}, {"id": "oa_approval_oaprogresschain_statustext", "label": "statusText()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L97"}, {"id": "oa_approval_oaprogresschain_statusbadge", "label": "statusBadge()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L114"}, {"id": "oa_approval_oaprogresschain_signbadge", "label": "signBadge()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L123"}, {"id": "oa_approval_oaprogresschain_signbadgetext", "label": "signBadgeText()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L130"}, {"id": "oa_approval_oaprogresschain_displaypeople", "label": "displayPeople()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L138"}, {"id": "oa_approval_oaprogresschain_personchipclass", "label": "personChipClass()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L151"}, {"id": "oa_approval_oaprogresschain_personstatushint", "label": "personStatusHint()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L160"}, {"id": "oa_approval_oaprogresschain_persontitle", "label": "personTitle()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L170"}, {"id": "oa_approval_oaprogresschain_dotclass", "label": "dotClass()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L175"}, {"id": "oa_approval_oaprogresschain_resolvesourcetext", "label": "resolveSourceText()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L183"}, {"id": "oa_approval_oaprogresschain_avatarchar", "label": "avatarChar()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L195"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oaprogresschain_vue", "target": "oa_approval_oaprogresschain_statustext", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L97", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oaprogresschain_vue", "target": "oa_approval_oaprogresschain_statusbadge", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L114", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oaprogresschain_vue", "target": "oa_approval_oaprogresschain_signbadge", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L123", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oaprogresschain_vue", "target": "oa_approval_oaprogresschain_signbadgetext", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L130", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oaprogresschain_vue", "target": "oa_approval_oaprogresschain_displaypeople", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vue", "source_location": "L138", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oaprogresschain_vue", "target": "oa_approval_oaprogresschain_personchipclass", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaProgressChain.vuLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_instances_detail_vue", "label": "detail.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/instances/detail.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_types_import_components_d_ts", "label": "components.d.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_apps_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/apps/index.vue", "source_location": "L1"}, {"id": "apps_index_loadgroups", "label": "loadGroups()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/apps/index.vue", "source_location": "L364"}, {"id": "apps_index_loaddata", "label": "loadData()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/apps/index.vue", "source_location": "L369"}, {"id": "apps_index_handlesearch", "label": "handleSearch()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/apps/index.vue", "source_location": "L379"}, {"id": "apps_index_resetform", "label": "resetForm()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/apps/index.vue", "source_location": "L383"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_apps_index_vue", "target": "vue_router", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/apps/index.vue", "source_location": "L264", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_apps_index_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/apps/index.vue", "source_location": "L265", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_apps_index_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/apps/index.vue", "source_location": "L266", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_apps_index_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/apps/index.vue", "source_location": "L267", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_apps_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_business", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/apps/index.vue", "source_location": "L280", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_apps_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_oaapproval", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/apps/index.vue", "source_location": "L281", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_apps_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_app_icons", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/apps/index.vue", "source_location": "L291", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_apps_index_vue", "target": "core", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/apps/index.vue", "source_location": "L292", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_apps_index_vue", "target": "apps_index_loadgroups", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/apps/index.vue", "source_location": "L364", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_apps_index_vue", "target": "apps_index_loaddata", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/apps/index.vue", "source_location": "L369", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_apps_index_vue", "target": "apps_index_handlesearch", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/apps/index.vue", "source_location": "L379", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_apps_index_vue", "target": "apps_index_resetform", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/apps/index.vue", "source_location":Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_start_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/start/index.vue", "source_location": "L1"}, {"id": "start_index_validate", "label": "validate()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/start/index.vue", "source_location": "L345"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_start_index_vue", "target": "start_index_validate", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/start/index.vue", "source_location": "L345", "weight": 1.0}], "raw_calls": [{"caller_nid": "start_index_validate", "callee": "warning", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/start/index.vue", "source_location": "L347"}]}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_instances_detail_vue", "label": "detail.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/instances/detail.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_oa_fc_host_app_vue", "label": "App.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/oa-fc-host/App.vue", "source_location": "L1"}, {"id": "oa_fc_host_app_if", "label": "if()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/oa-fc-host/App.vue", "source_location": "L170"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_oa_fc_host_app_vue", "target": "oa_fc_host_app_if", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/oa-fc-host/App.vue", "source_location": "L170", "weight": 1.0}], "raw_calls": [{"caller_nid": "oa_fc_host_app_if", "callee": "setTimeout", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/oa-fc-host/App.vue", "source_location": "L171"}]}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_types_import_components_d_ts", "label": "components.d.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oafcrow_vue", "label": "OaFcRow.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaFcRow.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_start_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/start/index.vue", "source_location": "L1"}, {"id": "start_index_validate", "label": "validate()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/start/index.vue", "source_location": "L385"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_oa_approval_start_index_vue", "target": "start_index_validate", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/start/index.vue", "source_location": "L385", "weight": 1.0}], "raw_calls": [{"caller_nid": "start_index_validate", "callee": "warning", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/start/index.vue", "source_location": "L387"}]}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_types_import_components_d_ts", "label": "components.d.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oaflowpreview_vue", "label": "OaFlowPreview.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaFlowPreview.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_types_import_components_d_ts", "label": "components.d.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload_ts", "label": "oa-form-create-upload.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L1"}, {"id": "utils_oa_form_create_upload_resolveuploadresponseurl", "label": "resolveUploadResponseUrl()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L30"}, {"id": "utils_oa_form_create_upload_ensureuploadrule", "label": "ensureUploadRule()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L38"}, {"id": "utils_oa_form_create_upload_ensureoauploadruleprops", "label": "ensureOaUploadRuleProps()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L75"}, {"id": "utils_oa_form_create_upload_setupformcreateupload", "label": "setupFormCreateUpload()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L103"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload_ts", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L6", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_business", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L7", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_composables_useattachmentactions", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L8", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_components_oa_approval_oafcrow_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L9", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload_ts", "target": "utils_oa_form_create_upload_resolveuploadresponseurl", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L30", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload_ts", "target": "utils_oa_form_create_upload_ensureuploadrule", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L38", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload_ts", "target": "utils_oa_form_create_upload_ensureoauploadruleprops", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L75", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_oa_form_create_upload_ts", "target": "utils_oa_form_create_upload_setupformcreateupload", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L103", "weight": 1.0}], "raw_calls": [{"caller_nid": "utils_oa_form_create_upload_resolveuploadresponseurl", "callee": "trim", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L31"}, {"caller_nid": "utils_oa_form_create_upload_resolveuploadresponseurl", "callee": "String", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L31"}, {"caller_nid": "utils_oa_form_create_upload_resolveuploadresponseurl", "callee": "attachmentFullUrl", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L35"}, {"caller_nid": "utils_oa_form_create_upload_ensureuploadrule", "callee": "has", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-upload.ts", "source_location": "L39"}, {"caller_nid": "utils_oa_form_create_upload_ensureuploadrule", "callee": "String", "source_Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_api_oaapproval_ts", "label": "oaApproval.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/oaApproval.ts", "source_location": "L1"}, {"id": "api_oaapproval_fetchoarolelist", "label": "fetchOaRoleList()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/oaApproval.ts", "source_location": "L9"}, {"id": "api_oaapproval_fetchensureoarolepresets", "label": "fetchEnsureOaRolePresets()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/oaApproval.ts", "source_location": "L16"}, {"id": "api_oaapproval_fetchcreateoarole", "label": "fetchCreateOaRole()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/oaApproval.ts", "source_location": "L23"}, {"id": "api_oaapproval_fetchupdateoarole", "label": "fetchUpdateOaRole()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/oaApproval.ts", "source_location": "L37"}, {"id": "api_oaapproval_fetchdeleteoarole", "label": "fetchDeleteOaRole()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/oaApproval.ts", "source_location": "L53"}, {"id": "api_oaapproval_fetchoaroleusers", "label": "fetchOaRoleUsers()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/oaApproval.ts", "source_location": "L60"}, {"id": "api_oaapproval_fetchreplaceoaroleusers", "label": "fetchReplaceOaRoleUsers()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/oaApproval.ts", "source_location": "L66"}, {"id": "api_oaapproval_fetchoagrouplist", "label": "fetchOaGroupList()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/oaApproval.ts", "source_location": "L78"}, {"id": "api_oaapproval_fetchcreateoagroup", "label": "fetchCreateOaGroup()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/oaApproval.ts", "source_location": "L82"}, {"id": "api_oaapproval_fetchupdateoagroup", "label": "fetchUpdateOaGroup()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/oaApproval.ts", "source_location": "L94"}, {"id": "api_oaapproval_fetchdeleteoagroup", "label": "fetchDeleteOaGroup()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/oaApproval.ts", "source_location": "L105"}, {"id": "api_oaapproval_fetchoaapplist", "label": "fetchOaAppList()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/oaApproval.ts", "source_location": "L112"}, {"id": "api_oaapproval_fetchcreateoaapp", "label": "fetchCreateOaApp()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/oaApproval.ts", "source_location": "L123"}, {"id": "api_oaapproval_fetchupdateoaapp", "label": "fetchUpdateOaApp()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/oaApproval.ts", "source_location": "L131"}, {"id": "api_oaapproval_fetchdeleteoaapp", "label": "fetchDeleteOaApp()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/oaApproval.ts", "source_location": "L139"}, {"id": "api_oaapproval_fetchoaappdraft", "label": "fetchOaAppDraft()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/oaApproval.ts", "source_location": "L146"}, {"id": "api_oaapproval_fetchsaveoaappdraft", "label": "fetchSaveOaAppDraft()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/oaApproval.ts", "source_location": "L150"}, {"id": "api_oaapproval_fetchpublishoaapp", "label": "fetchPublishOaApp()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/oaApproval.ts", "source_location": "L166"}, {"id": "api_oaapproval_fetchoatemplates", "label": "fetchOaTemplates()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/oaApproval.ts", "source_location": "L177"}, {"id": "api_oaapproval_fetchoatemplatedetail", "label": "fetchOaTemplateDetail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/oaApproval.ts", "source_location": "L181"}, {"id": "api_oaapproval_fetchoaflowpreview", "label": "fetchOaFlowPreview()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/oaApproval.ts", "source_location": "L186"}, {"id": "api_oaapproval_fetchstartoainstance", "label": "fetchStartOaInstance()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/oaApproval.ts", "source_location": "L215"}, {"id": "api_oaapproval_fetchoainstancedetail", "label": "fetchOaInstanceDetail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/oaApproval.ts", "sLine truncated
+3
View File
@@ -15,10 +15,13 @@ import { setupGlobDirectives } from './directives'
import { setupErrorHandle } from './utils/sys/error-handle'
import FcDesigner from '@form-create/designer'
import formCreateAutoImport from '@form-create/element-ui/auto-import'
import { setupFormCreateUpload } from '@/utils/oa-form-create-upload'
// FormCreate 按字符串解析 el-input / fc-radio 等,主应用是按需自动导入,不会全局注册;
// 必须挂上官方 auto-import,否则发起审批/详情里动态表单控件会残缺(如单选项只剩文字)。
FcDesigner.formCreate.use(formCreateAutoImport)
// 内置「上传」默认 action=/,改为走附件上传 API,避免 POST 前端原点 404
setupFormCreateUpload(FcDesigner.formCreate)
function maskSecret(value?: string) {
if (!value) return '(empty)'
+198 -108
View File
@@ -8,15 +8,6 @@
:config="designerConfig"
:locale="fcLocale"
/>
<div v-show="showCondFlag" class="oa-cond-flag">
<div class="oa-cond-flag__row">
<el-switch :model-value="flagOn" @change="onFlagChange" />
<div>
<div class="oa-cond-flag__title">参与流程条件分支</div>
<div class="oa-cond-flag__tip">勾选后该字段必填且不可改为选填;可在「3 流程设计」条件中选用</div>
</div>
</div>
</div>
</div>
</template>
@@ -31,6 +22,9 @@
type DesignerApi = {
getRule?: () => unknown
getOption?: () => unknown
/** 含 $FNX 回调的可持久化 JSON(勿用 getRule 直接 postMessage) */
getJson?: () => string
getOptionsJson?: () => string
setRule?: (rule: unknown[]) => void
setOption?: (option: unknown) => void
}
@@ -39,10 +33,32 @@
const fcLocale = formCreateZh
let pendingSchema: { rule: unknown; option: unknown } | null = null
const COND_FIELD = 'formCreateUseInCondition'
const designerConfig = {
showSaveBtn: false,
showDevice: true,
showAi: false
showAi: false,
/** 让右侧「组件配置」能读写 rule.useInCondition */
appendConfigData: [COND_FIELD],
baseRule: {
append: true,
rule() {
return [
{
type: 'switch',
field: COND_FIELD,
title: '参与流程条件分支',
value: false,
info: '勾选后该字段必填且不可改为选填;可在「3 流程设计」条件中选用',
props: {
activeText: '是',
inactiveText: '否'
}
}
]
}
}
}
const MSG = {
@@ -54,19 +70,20 @@
} as const
const flowConditionFields = ref<string[]>([])
const showCondFlag = ref(false)
const flagOn = ref(false)
const lockRequired = ref(false)
let pollTimer: number | null = null
let lastActiveId = ''
let lastFlagOn: boolean | null = null
let lastEligible: boolean | null = null
function getDesigner(): DesignerApi | null {
const inst = designerRef.value as any
if (!inst) return null
// FormCreate 官方内部多用 setupState;优先走这条,避免拿到残缺代理
if (typeof inst.setupState?.setRule === 'function') return inst.setupState
if (typeof inst.setRule === 'function') return inst
if (inst.$ && typeof inst.$.exposed?.setRule === 'function') return inst.$.exposed
if (typeof inst.setupState?.setRule === 'function') return inst.setupState
return inst
return null
}
function getSetupState(): any {
@@ -94,75 +111,165 @@
}
}
function syncActivePanel() {
const rule = getActiveRule()
const type = String(rule?.type || '')
const eligible = !!(rule?.field && CONDITION_ELIGIBLE_TYPES.has(type))
showCondFlag.value = eligible
if (!eligible) {
flagOn.value = false
lockRequired.value = false
lastActiveId = ''
return
}
const id = String(rule._fc_id || rule.field || '')
const on = readFlag(rule)
flagOn.value = on
lockRequired.value = on
if (on) applyFlagToRule(rule, true)
lastActiveId = id
}
function onFlagChange(val: string | number | boolean) {
const on = !!val
const rule = getActiveRule()
if (!rule?.field) return
if (!on) {
const field = String(rule.field)
if (flowConditionFields.value.includes(field)) {
ElMessage.warning('请先在流程设计中删除对该字段的条件')
flagOn.value = true
return
}
applyFlagToRule(rule, false)
flagOn.value = false
lockRequired.value = false
return
}
applyFlagToRule(rule, true)
flagOn.value = true
lockRequired.value = true
// 同步校验面板必填开关
/** 在「组件配置」基础表单中显示/隐藏开关(设计器选中后会重置 hidden,需持续同步) */
function syncCondFieldVisibility(eligible: boolean) {
const state = getSetupState()
const api = state?.baseForm?.api
if (!api) return
try {
const state = getSetupState()
const vapi = state?.validateForm?.api
if (vapi?.setValue) {
const cur = typeof vapi.formData === 'function' ? vapi.formData() : {}
vapi.setValue({ ...cur, $required: true })
if (typeof api.hidden === 'function') {
api.hidden(!eligible, COND_FIELD)
}
const all = typeof api.all === 'function' ? api.all() : []
if (Array.isArray(all)) {
all.forEach((item: any) => {
if (item?.field === COND_FIELD || item?.name === COND_FIELD) {
item.hidden = !eligible
}
})
}
} catch {
/* ignore */
}
}
function readSchema() {
const d = getDesigner()
return {
rule: d?.getRule?.() ?? [],
option: d?.getOption?.() ?? {}
function syncRequiredLock(on: boolean) {
lockRequired.value = on
const state = getSetupState()
const vapi = state?.validateForm?.api
if (!vapi) return
try {
if (on) {
if (typeof vapi.setValue === 'function') {
const cur = typeof vapi.formData === 'function' ? vapi.formData() : {}
vapi.setValue({ ...cur, $required: true })
}
if (typeof vapi.disabled === 'function') {
vapi.disabled(true, '$required')
}
} else if (typeof vapi.disabled === 'function') {
vapi.disabled(false, '$required')
}
} catch {
/* ignore */
}
}
function syncBaseFormFlag(on: boolean) {
const state = getSetupState()
const api = state?.baseForm?.api
if (!api?.setValue) return
try {
const cur = typeof api.formData === 'function' ? api.formData() : {}
api.setValue({ ...cur, [COND_FIELD]: on })
} catch {
/* ignore */
}
}
function syncActivePanel() {
const rule = getActiveRule()
const type = String(rule?.type || '')
const eligible = !!(rule?.field && CONDITION_ELIGIBLE_TYPES.has(type))
const id = rule ? String(rule._fc_id || rule.field || '') : ''
if (!eligible) {
syncCondFieldVisibility(false)
if (lastEligible !== false || id !== lastActiveId) {
syncRequiredLock(false)
}
lastActiveId = id
lastFlagOn = null
lastEligible = false
return
}
syncCondFieldVisibility(true)
let on = readFlag(rule)
// 用户在面板关掉开关,但流程仍引用该字段 → 拦截并回滚
if (
lastFlagOn === true &&
on === false &&
id === lastActiveId &&
flowConditionFields.value.includes(String(rule.field))
) {
ElMessage.warning('请先在流程设计中删除对该字段的条件')
applyFlagToRule(rule, true)
syncBaseFormFlag(true)
on = true
}
if (on) {
applyFlagToRule(rule, true)
}
if (on !== lastFlagOn || id !== lastActiveId || lastEligible !== true) {
syncRequiredLock(on)
syncBaseFormFlag(on)
}
lastActiveId = id
lastFlagOn = on
lastEligible = true
}
/**
* 导出可克隆的纯 JSON schema。
* Upload 等控件的 onSuccess 在运行时是函数(由 $FNX 编译),
* structured clone / postMessage 无法传递函数;必须走 FormCreate 的 toJson(getJson)。
*/
function readSchema(): { rule: unknown; option: unknown } {
const d = getDesigner()
try {
if (typeof d?.getJson === 'function') {
const ruleRaw = JSON.parse(d.getJson() || '[]')
let option: unknown = {}
if (typeof d.getOptionsJson === 'function') {
option = JSON.parse(d.getOptionsJson() || '{}')
} else {
option = JSON.parse(JSON.stringify(d.getOption?.() ?? {}))
}
return {
rule: Array.isArray(ruleRaw) ? ruleRaw : [],
option: option && typeof option === 'object' ? option : {}
}
}
} catch (e) {
console.warn('[oa-fc-host] readSchema getJson failed, fallback', e)
}
// 兜底:剥离函数,至少保证 postMessage 不抛错(可能丢失 onSuccess 等回调)
try {
const plain = JSON.parse(
JSON.stringify({
rule: d?.getRule?.() ?? [],
option: d?.getOption?.() ?? {}
})
)
return {
rule: Array.isArray(plain?.rule) ? plain.rule : [],
option: plain?.option && typeof plain.option === 'object' ? plain.option : {}
}
} catch {
return { rule: [], option: {} }
}
}
function countRules(rules: unknown): number {
return Array.isArray(rules) ? rules.length : 0
}
async function applySchema(schema: any, attempt = 0) {
const rule = Array.isArray(schema?.rule) ? schema.rule : Array.isArray(schema) ? schema : []
const option = schema?.option && typeof schema.option === 'object' ? schema.option : {}
pendingSchema = { rule, option }
const expectCount = countRules(rule)
await nextTick()
const d = getDesigner()
if (!d?.setRule) {
if (attempt < 8) {
window.setTimeout(() => void applySchema(schema, attempt + 1), 40 * (attempt + 1))
if (attempt < 12) {
window.setTimeout(() => void applySchema(schema, attempt + 1), 50 * (attempt + 1))
}
return
}
@@ -172,12 +279,18 @@
if (d.setOption) {
d.setOption(JSON.parse(JSON.stringify(option)))
}
// 校验是否真正落到画布;菜单未就绪时 loadRule 可能静默失败
const applied = countRules(d.getRule?.() ?? [])
if (expectCount > 0 && applied < expectCount && attempt < 12) {
window.setTimeout(() => void applySchema(schema, attempt + 1), 80 * (attempt + 1))
return
}
pendingSchema = null
window.setTimeout(() => syncActivePanel(), 80)
} catch (e) {
console.warn('[oa-fc-host] applySchema failed', e)
if (attempt < 5) {
window.setTimeout(() => void applySchema(schema, attempt + 1), 80)
if (attempt < 12) {
window.setTimeout(() => void applySchema(schema, attempt + 1), 80 * (attempt + 1))
}
}
}
@@ -190,10 +303,23 @@
return
}
if (data.type === MSG.GET) {
window.parent?.postMessage(
{ type: MSG.SCHEMA, schema: readSchema(), requestId: data.requestId },
'*'
)
try {
window.parent?.postMessage(
{ type: MSG.SCHEMA, schema: readSchema(), requestId: data.requestId },
'*'
)
} catch (e) {
console.error('[oa-fc-host] postMessage schema failed', e)
window.parent?.postMessage(
{
type: MSG.SCHEMA,
schema: { rule: [], option: {} },
requestId: data.requestId,
error: 'schema-not-clonable'
},
'*'
)
}
return
}
if (data.type === MSG.FLOW_REFS) {
@@ -224,11 +350,7 @@
void applySchema(pendingSchema)
}
pollTimer = window.setInterval(() => {
const rule = getActiveRule()
const id = rule ? String(rule._fc_id || rule.field || '') : ''
if (id !== lastActiveId || (rule && readFlag(rule) !== flagOn.value)) {
syncActivePanel()
}
syncActivePanel()
}, 250)
})
@@ -271,38 +393,6 @@
height: 100% !important;
}
.oa-cond-flag {
position: absolute;
top: 56px;
right: 12px;
z-index: 30;
width: 292px;
padding: 12px;
background: #ecfdf5;
border: 1px dashed #a7f3d0;
border-radius: 8px;
box-shadow: 0 2px 8px rgb(15 23 42 / 8%);
}
.oa-cond-flag__row {
display: flex;
gap: 10px;
align-items: flex-start;
}
.oa-cond-flag__title {
font-size: 13px;
font-weight: 600;
color: #059669;
}
.oa-cond-flag__tip {
margin-top: 2px;
font-size: 12px;
line-height: 1.4;
color: #64748b;
}
/* 参与分支时锁定「是否必填」 */
.oa-fc-host--lock-required ._fc-r .el-form-item:has([name='$required']),
.oa-fc-host--lock-required ._fc-r .el-form-item:has(.fc-required),
+2
View File
@@ -7,6 +7,7 @@ import zhCn from 'element-plus/es/locale/lang/zh-cn'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import 'element-plus/dist/index.css'
import FcDesigner from '@form-create/designer'
import { setupFormCreateUpload } from '@/utils/oa-form-create-upload'
import App from './App.vue'
const app = createApp(App)
@@ -18,4 +19,5 @@ for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.use(ElementPlus, { locale: zhCn })
app.use(FcDesigner)
app.use(FcDesigner.formCreate)
setupFormCreateUpload(FcDesigner.formCreate)
app.mount('#app')
+29 -4
View File
@@ -238,18 +238,42 @@ function buildFlowItems(detail: any): OaPrintFlowItem[] {
ccBuf = null
}
const peopleNames = (p: any): string[] => {
const people = Array.isArray(p?.people) ? p.people : []
const fromPeople = people
.map((x: any) => {
const n = String(x?.nickName || x?.id || '').trim()
if (!n) return ''
const st = String(x?.status || '')
if (st === 'approved') return `${n}(已同意)`
if (st === 'rejected') return `${n}(已拒绝)`
if (st === 'returned') return `${n}(已打回)`
if (st === 'pending' || st === 'running') return `${n}(待处理)`
if (st === 'done') return `${n}(无需处理)`
return n
})
.filter(Boolean)
if (fromPeople.length) return fromPeople
const name = String(p.assigneeUserName || p.assigneeUserId || '').trim()
return name ? [name] : []
}
for (const p of list) {
const kind = String(p.kind || '')
const taskType = String(p.taskType || '')
const title = String(p.title || '-').trim()
const name = String(p.assigneeUserName || p.assigneeUserId || '').trim()
const names = peopleNames(p)
const name = names.join(',')
const ts = String(p.timestamp || '').trim()
const comment = String(p.commentText || '').trim()
const st = statusText(String(p.status || ''))
const signMode = String(p.signMode || '')
const signLabel = signMode === 'and' ? '会签' : signMode === 'or' ? '或签' : ''
if (taskType === 'cc') {
if (!ccBuf) ccBuf = { names: [], ts }
if (name) ccBuf.names.push(name)
if (names.length) ccBuf.names.push(...names.map((n) => n.replace(/\(.*?\)\s*$/, '')))
else if (name) ccBuf.names.push(name)
if (ts) ccBuf.ts = ts
continue
}
@@ -277,9 +301,10 @@ function buildFlowItems(detail: any): OaPrintFlowItem[] {
})
continue
}
// task
// task(或签/会签同节点多人已合并)
const head = signLabel ? `【${title}·${signLabel}】` : `【${title}】`
items.push({
left: name ? `【${title}】 ${name} ${st}` : `【${title}】 ${st}`,
left: name ? `${head} ${name} ${st}` : `${head} ${st}`,
right: ts,
comment: comment || undefined
})
@@ -0,0 +1,164 @@
/**
* FormCreate 运行时补丁:
* - 内置 upload 默认 action 为「/」,会 POST 到前端原点导致 404;接管为附件上传 API
* - 运行时注册 FcRow(flex ._fd-row),间距与铺满由 oa-fc-runtime.scss 处理
*/
import { ElMessage } from 'element-plus'
import { fetchUploadAttachment } from '@/api/business'
import { attachmentFullUrl } from '@/composables/useAttachmentActions'
import OaFcRow from '@/components/oa-approval/OaFcRow.vue'
type FcFetchOptions = {
source?: string
file?: File
filename?: string
data?: Record<string, unknown>
action?: string
onSuccess?: (res: unknown) => void
onError?: (err: unknown) => void
[key: string]: unknown
}
const FLAG = '__oaUploadConfigured'
const UPLOAD_TYPES = new Set(['upload', 'fcUpload'])
/** 与业务表单 `.form-grid-2` 横向间距对齐(顶层 option.row.gutter / CSS --oa-fc-gutter) */
export const OA_FC_DEFAULT_GUTTER = 20
/** 从上传接口响应中取出可回显的 url(兼容 FormCreate 默认 onSuccess) */
export function resolveUploadResponseUrl(res: any): string {
const raw = String(
res?.data?.url || res?.data?.fileUrl || res?.fileUrl || res?.url || ''
).trim()
if (!raw) return ''
return attachmentFullUrl(raw) || raw
}
function ensureUploadRule(rule: any) {
if (!UPLOAD_TYPES.has(String(rule.type || ''))) return
const props = { ...(rule.props || {}) }
if (!props.action || props.action === '/') {
props.action = '#'
}
const prevSuccess = props.onSuccess
// `$FNX:...` 须留给 FormCreate 编译;替换成函数会丢掉官方 file.url = res.data.url
if (typeof prevSuccess === 'string' && prevSuccess.includes('$FNX')) {
// keep
} else if (typeof prevSuccess === 'function') {
props.onSuccess = (res: any, file: any) => {
try {
prevSuccess(res, file)
} catch {
/* ignore */
}
const url = resolveUploadResponseUrl(res)
// Element Plus 选文件时已写入 blob: URL,必须强制覆盖
if (url && file) {
file.url = url
}
}
} else if (!prevSuccess) {
props.onSuccess = (res: any, file: any) => {
const url = resolveUploadResponseUrl(res)
if (url && file) {
file.url = url
}
}
}
rule.props = props
}
/**
* 运行时补齐 FormCreate rule(upload action / onSuccess)
*/
export function ensureOaUploadRuleProps(rules: unknown): any[] {
if (!Array.isArray(rules)) return []
return rules.map((raw) => {
if (!raw || typeof raw !== 'object') return raw
const rule: any = { ...(raw as object) }
ensureUploadRule(rule)
if (Array.isArray(rule.children)) {
rule.children = ensureOaUploadRuleProps(rule.children)
}
if (Array.isArray(rule.props?.rule)) {
rule.props = {
...rule.props,
rule: ensureOaUploadRuleProps(rule.props.rule)
}
}
if (Array.isArray(rule.control)) {
rule.control = rule.control.map((c: any) => {
if (!c || typeof c !== 'object') return c
if (Array.isArray(c.rule)) {
return { ...c, rule: ensureOaUploadRuleProps(c.rule) }
}
return c
})
}
return rule
})
}
export function setupFormCreateUpload(formCreate: {
fetch?: (opts: FcFetchOptions) => void
component?: (name: string, component: unknown) => void
}) {
if (!formCreate || (formCreate as any)[FLAG]) return
// 主应用 formCreate 默认未挂设计器 FcRow;用 flex 行保证栅格铺满,间距走 CSS
if (typeof formCreate.component === 'function') {
formCreate.component('fcRow', OaFcRow)
formCreate.component('FcRow', OaFcRow)
}
const prevFetch = formCreate.fetch
formCreate.fetch = (options: FcFetchOptions) => {
const isUpload = options?.source === 'upload' || !!options?.file
if (!isUpload) {
if (typeof prevFetch === 'function') {
return prevFetch(options)
}
return
}
void (async () => {
try {
const file = options.file
if (!file) {
throw new Error('未选择文件')
}
const fd = new FormData()
fd.append('file', file)
fd.append('folder', 'oa-approval')
const extra = options.data
if (extra && typeof extra === 'object') {
Object.entries(extra).forEach(([k, v]) => {
if (v != null && k !== 'file' && k !== 'folder') {
fd.append(k, String(v))
}
})
}
const res: any = await fetchUploadAttachment(fd)
const rawUrl = String(res?.fileUrl || res?.data?.fileUrl || '').trim()
if (!rawUrl) {
throw new Error('上传失败:未返回文件地址')
}
// 预览用完整 URL;设计器默认 onSuccess 为 file.url = res.data.url
const url = attachmentFullUrl(rawUrl) || rawUrl
options.onSuccess?.({
data: { url, fileUrl: rawUrl },
fileUrl: rawUrl,
url
})
} catch (e) {
const msg = e instanceof Error ? e.message : '上传失败'
ElMessage.error(msg)
options.onError?.(e)
}
})()
}
;(formCreate as any)[FLAG] = true
}
@@ -260,7 +260,7 @@
</template>
<script setup lang="ts">
import { computed, onMounted, reactive, ref } from 'vue'
import { computed, onActivated, onMounted, reactive, ref } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import type { UploadRequestOptions } from 'element-plus'
@@ -536,10 +536,14 @@
{ debounce: 200 }
)
onMounted(async () => {
async function refresh() {
await loadGroups()
await loadData()
})
}
onMounted(refresh)
// KeepAlive 下从设计器返回时不会再次 onMounted,需在激活时刷新列表
onActivated(refresh)
</script>
<style scoped lang="scss">
@@ -70,6 +70,7 @@
<div v-show="activeStep === 'form'" class="oa-designer__form-step">
<OaFormDesignerEmbed
v-if="formDesignerMounted"
:key="formDesignerEpoch"
ref="formEmbedRef"
v-model="formSchema"
:flow-condition-fields="flowConditionFields"
@@ -108,7 +109,7 @@
</template>
<script setup lang="ts">
import { computed, onMounted, reactive, ref } from 'vue'
import { computed, nextTick, onMounted, reactive, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import type { UploadRequestOptions } from 'element-plus'
@@ -137,10 +138,13 @@
const activeStep = ref('basic')
const draft = ref<any>(null)
/** iframe 表单设计器(与主应用 Tailwind 隔离) */
const formEmbedRef = ref<{ fetchSchema: () => Promise<{ rule: unknown; option: unknown }> } | null>(
null
)
const formEmbedRef = ref<{
fetchSchema: () => Promise<{ rule: unknown; option: unknown }>
reapplySchema?: () => void
} | null>(null)
const formDesignerMounted = ref(false)
/** 每次进入表单 Tab 递增,强制重建 iframe,避免 display:none 后画布丢控件 */
const formDesignerEpoch = ref(0)
const formSchema = ref<{ rule: unknown; option: unknown }>({ rule: [], option: {} })
const basic = reactive({
@@ -268,6 +272,19 @@
advancedSettingsJson: { ...advanced }
})
draft.value = data
// 以服务端回包为准同步本地,避免与 iframe 内容漂移
const fs = data?.formSchemaJson
if (fs) {
try {
const plain = JSON.parse(JSON.stringify(fs))
formSchema.value = {
rule: Array.isArray(plain?.rule) ? plain.rule : Array.isArray(plain) ? plain : [],
option: plain?.option && typeof plain.option === 'object' ? plain.option : {}
}
} catch {
/* keep collected schema */
}
}
} finally {
saving.value = false
}
@@ -307,13 +324,20 @@
}
}
if (name === 'form') {
// 先卸载再挂载:隐藏态 iframe 内 FormCreate 画布易丢控件,重建后按 formSchema 回显
formDesignerMounted.value = false
formDesignerEpoch.value += 1
await nextTick()
formDesignerMounted.value = true
await nextTick()
formEmbedRef.value?.reapplySchema?.()
}
}
onMounted(async () => {
await loadDraft()
if (activeStep.value === 'form') {
formDesignerEpoch.value += 1
formDesignerMounted.value = true
}
})
@@ -153,6 +153,10 @@
import OaProgressChain from '@/components/oa-approval/OaProgressChain.vue'
import { MAX_ADMIN_LIST_PAGE_SIZE } from '@/utils/fetch-paged-list'
import { useUserStore } from '@/store/modules/user'
import {
OA_FC_DEFAULT_GUTTER,
ensureOaUploadRuleProps
} from '@/utils/oa-form-create-upload'
defineOptions({ name: 'OaApprovalInstanceDetail' })
@@ -166,6 +170,7 @@
const viewRule = ref<any[]>([])
const viewOption = ref({
form: { disabled: true, labelPosition: 'top' },
row: { gutter: OA_FC_DEFAULT_GUTTER },
submitBtn: false,
resetBtn: false
})
@@ -182,7 +187,7 @@
const list = detail.value?.progress
if (!Array.isArray(list) || !list.length) return []
return list.map((p: any, idx: number) => ({
key: `${p.kind}-${p.taskId || p.nodeKey || idx}-${p.roundNo || 1}`,
key: `${p.kind}-${p.nodeKey || p.taskId || idx}-${p.roundNo || 1}`,
title: p.title || '-',
status: p.status || 'info',
timestamp: p.timestamp || '',
@@ -191,7 +196,18 @@
commentText: p.commentText || '',
taskType: p.taskType || '',
kind: p.kind || '',
roundNo: p.roundNo || 1
roundNo: p.roundNo || 1,
signMode: p.signMode || '',
people: Array.isArray(p.people)
? p.people.map((x: any) => ({
id: x.id || '',
nickName: x.nickName || x.id || '',
status: x.status || '',
timestamp: x.timestamp || '',
commentText: x.commentText || '',
taskId: x.taskId || ''
}))
: []
}))
})
@@ -246,10 +262,16 @@
function applySchema(schema: any, data: any) {
viewFormData.value = { ...(data || {}) }
const rule = Array.isArray(schema?.rule) ? schema.rule : Array.isArray(schema) ? schema : []
viewRule.value = rule
viewRule.value = ensureOaUploadRuleProps(rule)
const savedGutter = Number(schema?.option?.row?.gutter)
viewOption.value = {
...(schema?.option || {}),
form: { ...(schema?.option?.form || {}), disabled: true, labelPosition: 'top' },
// 顶层字段 col.span 布局用;栅格组件 fcRow 由 ensureOaUploadRuleProps 处理
row: {
...(schema?.option?.row || {}),
gutter: savedGutter > 0 ? savedGutter : OA_FC_DEFAULT_GUTTER
},
submitBtn: false,
resetBtn: false
}
+317 -21
View File
@@ -218,25 +218,81 @@
:close-on-click-modal="false"
>
<el-form label-position="top">
<el-form-item label="绑定用户">
<el-select
v-model="memberUserIds"
multiple
filterable
clearable
collapse-tags
collapse-tags-tooltip
placeholder="请选择用户"
style="width: 100%"
:loading="memberLoading"
>
<el-option
v-for="u in userOptions"
:key="u.id"
:label="`${u.nickName}(${u.userNo})`"
:value="u.id"
/>
</el-select>
<el-form-item>
<template #label>
绑定用户
<span class="form-label-tip">可多选,已选成员将展示在下方列表</span>
</template>
<div v-loading="memberLoading" class="member-picker">
<el-select
v-model="memberPickBuffer"
filterable
clearable
:loading="memberLoading"
placeholder="搜索姓名 / 工号,点击添加"
style="width: 100%"
popper-class="oa-role-member-select-popper"
@change="onMemberPick"
>
<el-option
v-for="u in userOptions"
:key="u.id"
:label="memberOptionLabel(u)"
:value="u.id"
:disabled="memberUserIds.includes(u.id)"
>
<div class="member-option">
<span class="member-avatar" :style="{ background: avatarColor(u.id) }">
{{ avatarInitial(u.nickName) }}
</span>
<span class="member-option__meta">
<span class="member-option__name">{{ u.nickName || '未命名' }}</span>
<span v-if="memberOptionSub(u)" class="member-option__sub">
{{ memberOptionSub(u) }}
</span>
</span>
<el-tag
v-if="memberUserIds.includes(u.id)"
size="small"
type="info"
effect="plain"
class="member-option__tag"
>
已选
</el-tag>
</div>
</el-option>
</el-select>
<div
class="member-chips"
:class="{ 'is-empty': !memberUserIds.length }"
>
<template v-if="memberUserIds.length">
<span v-for="id in memberUserIds" :key="id" class="member-chip">
<span
class="member-avatar member-avatar--sm"
:style="{ background: avatarColor(id) }"
>
{{ avatarInitial(resolveUser(id)?.nickName) }}
</span>
<span class="member-chip__name" :title="chipTitle(id)">
{{ resolveUser(id)?.nickName || id }}
</span>
<button
type="button"
class="member-chip__rm"
:aria-label="`移除 ${resolveUser(id)?.nickName || id}`"
@click="removeMember(id)"
>
×
</button>
</span>
</template>
<template v-else>暂未选择成员,请从上方搜索添加</template>
</div>
<p class="member-picked-count">已选 {{ memberUserIds.length }} 人</p>
</div>
</el-form-item>
</el-form>
<template #footer>
@@ -261,7 +317,7 @@
<script setup lang="ts">
import { formatDisplayOrDash } from '@/utils/datetime-display'
import { onMounted, reactive, ref } from 'vue'
import { nextTick, onMounted, reactive, ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
Plus,
@@ -310,12 +366,74 @@
status: [{ required: true, message: '请选择状态', trigger: 'change' }]
}
type UserOption = { id: string; nickName: string; userNo: string }
const AVATAR_COLORS = [
'#059669',
'#0ea5e9',
'#8b5cf6',
'#d97706',
'#ef4444',
'#14b8a6',
'#6366f1',
'#ec4899'
]
const memberVisible = ref(false)
const memberRole = ref<any>(null)
const memberUserIds = ref<string[]>([])
const memberPickBuffer = ref('')
const memberLoading = ref(false)
const memberSubmitLoading = ref(false)
const userOptions = ref<Array<{ id: string; nickName: string; userNo: string }>>([])
const userOptions = ref<UserOption[]>([])
function avatarColor(id: string) {
let hash = 0
for (let i = 0; i < id.length; i++) hash = (hash * 31 + id.charCodeAt(i)) >>> 0
return AVATAR_COLORS[hash % AVATAR_COLORS.length]
}
function avatarInitial(name?: string) {
const t = (name || '?').trim()
return t ? t.slice(0, 1) : '?'
}
function resolveUser(id: string) {
return userOptions.value.find((u) => u.id === id)
}
function memberOptionLabel(u: UserOption) {
const name = (u.nickName || '').trim() || '未命名'
const no = (u.userNo || '').trim()
if (no && no !== name) return `${name}(${no})`
return name
}
function memberOptionSub(u: UserOption) {
const name = (u.nickName || '').trim()
const no = (u.userNo || '').trim()
if (!no || no === name) return ''
return `账号 ${no}`
}
function chipTitle(id: string) {
const u = resolveUser(id)
return u ? memberOptionLabel(u) : id
}
function onMemberPick(id: string) {
if (!id) return
if (!memberUserIds.value.includes(id)) {
memberUserIds.value = [...memberUserIds.value, id]
}
nextTick(() => {
memberPickBuffer.value = ''
})
}
function removeMember(id: string) {
memberUserIds.value = memberUserIds.value.filter((x) => x !== id)
}
async function loadData() {
loading.value = true
@@ -426,6 +544,8 @@
async function handleMembers(row: any) {
memberRole.value = row
memberPickBuffer.value = ''
memberUserIds.value = []
memberVisible.value = true
memberLoading.value = true
try {
@@ -468,4 +588,180 @@
margin-bottom: 0;
}
}
.member-picker {
width: 100%;
}
.member-chips {
display: flex;
flex-wrap: wrap;
gap: 8px;
min-height: 44px;
margin-top: 12px;
padding: 12px;
background: #f8fafc;
border: 1px dashed #cbd5e1;
border-radius: 8px;
&.is-empty {
align-items: center;
justify-content: center;
color: var(--mint-text-muted, #94a3b8);
font-size: 13px;
}
}
.member-chip {
display: inline-flex;
gap: 8px;
align-items: center;
max-width: 100%;
padding: 4px 8px 4px 4px;
background: #fff;
border: 1px solid var(--mint-border, #e2e8f0);
border-radius: 999px;
}
.member-chip__name {
max-width: 120px;
overflow: hidden;
font-size: 13px;
font-weight: 500;
white-space: nowrap;
text-overflow: ellipsis;
}
.member-chip__rm {
display: grid;
flex-shrink: 0;
place-items: center;
width: 20px;
height: 20px;
padding: 0;
color: var(--mint-text-muted, #64748b);
font-size: 14px;
line-height: 1;
background: #f1f5f9;
border: 0;
border-radius: 50%;
cursor: pointer;
&:hover {
color: #dc2626;
background: #fee2e2;
}
}
.member-picked-count {
margin: 8px 0 0;
color: var(--mint-text-muted, #94a3b8);
font-size: 12px;
}
.member-avatar {
display: inline-flex;
flex-shrink: 0;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
color: #fff;
font-size: 13px;
font-weight: 700;
line-height: 1;
text-align: center;
border-radius: 50%;
&--sm {
width: 28px;
height: 28px;
font-size: 11px;
}
}
</style>
<!-- 下拉挂 body,须非 scoped -->
<style lang="scss">
.oa-role-member-select-popper {
.el-select-dropdown__list {
padding: 8px;
}
.el-select-dropdown__item {
height: auto !important;
min-height: 56px;
margin-bottom: 8px;
padding: 10px 12px !important;
line-height: normal !important;
border-radius: 8px;
&:last-child {
margin-bottom: 0;
}
&.is-disabled {
opacity: 0.55;
}
&.hover,
&:hover {
background: var(--primary-bg, #ecfdf5);
}
}
.member-option {
display: flex;
gap: 12px;
align-items: center;
width: 100%;
min-height: 36px;
}
.member-option__meta {
display: flex;
flex: 1;
flex-direction: column;
gap: 2px;
justify-content: center;
min-width: 0;
}
.member-option__name {
overflow: hidden;
color: var(--mint-text, #0f172a);
font-size: 13px;
font-weight: 600;
white-space: nowrap;
text-overflow: ellipsis;
}
.member-option__sub {
overflow: hidden;
color: var(--mint-text-muted, #64748b);
font-size: 12px;
white-space: nowrap;
text-overflow: ellipsis;
}
.member-option__tag {
flex-shrink: 0;
margin-left: auto;
}
.member-avatar {
display: inline-flex;
flex-shrink: 0;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
color: #fff;
font-size: 13px;
font-weight: 700;
line-height: 1;
text-align: center;
border-radius: 50%;
}
}
</style>
@@ -131,6 +131,8 @@
v-if="!detailLoading"
:steps="flowSteps"
:loading="previewLoading"
:resolved="flowResolved"
:pending-message="flowPendingMessage"
/>
</div>
<template #footer>
@@ -166,6 +168,10 @@
import OaFlowPreview from '@/components/oa-approval/OaFlowPreview.vue'
import { MAX_ADMIN_LIST_PAGE_SIZE } from '@/utils/fetch-paged-list'
import { resolveOaAppIconUrl } from '@/utils/oa-app-icons'
import {
OA_FC_DEFAULT_GUTTER,
ensureOaUploadRuleProps
} from '@/utils/oa-form-create-upload'
defineOptions({ name: 'OaApprovalStart' })
@@ -181,7 +187,11 @@
const picked = ref<any>(null)
const formData = ref<Record<string, any>>({})
const formRule = ref<any[]>([])
const formOption = ref<Record<string, any>>({ submitBtn: false, resetBtn: false })
const formOption = ref<Record<string, any>>({
submitBtn: false,
resetBtn: false,
row: { gutter: OA_FC_DEFAULT_GUTTER }
})
const fapi = ref<any>(null)
const submitting = ref(false)
const needInitiatorSelect = ref(false)
@@ -189,7 +199,10 @@
const userLoading = ref(false)
const userOptions = ref<Array<{ id: string; nickName: string; userNo: string }>>([])
const flowSteps = ref<OaFlowPreviewStep[]>([])
const flowResolved = ref(true)
const flowPendingMessage = ref('必填信息填写后,流程将自动显示')
const previewLoading = ref(false)
let previewTimer: ReturnType<typeof setTimeout> | null = null
const displayGroups = computed(() => {
const kw = (searchKeyword.value || '').trim().toLowerCase()
@@ -267,18 +280,32 @@
async function loadFlowPreview(appId: string) {
previewLoading.value = true
try {
const preview = await fetchOaFlowPreview(
appId,
needInitiatorSelect.value ? [...initiatorSelectUserIds.value] : undefined
)
flowSteps.value = preview?.steps || []
const preview = await fetchOaFlowPreview(appId, {
formData: { ...formData.value },
initiatorSelectUserIds: needInitiatorSelect.value
? [...initiatorSelectUserIds.value]
: undefined
})
flowResolved.value = preview?.resolved !== false
flowPendingMessage.value =
preview?.message || '必填信息填写后,流程将自动显示'
flowSteps.value = flowResolved.value ? preview?.steps || [] : []
} catch {
flowSteps.value = []
flowResolved.value = true
} finally {
previewLoading.value = false
}
}
function scheduleFlowPreview() {
if (!dlgVisible.value || !picked.value?.id) return
if (previewTimer) clearTimeout(previewTimer)
previewTimer = setTimeout(() => {
loadFlowPreview(picked.value.id)
}, 300)
}
async function onPick(t: any) {
picked.value = t
formData.value = {}
@@ -286,19 +313,32 @@
needInitiatorSelect.value = false
initiatorSelectUserIds.value = []
flowSteps.value = []
flowResolved.value = false
flowPendingMessage.value = '必填信息填写后,流程将自动显示'
dlgVisible.value = true
detailLoading.value = true
previewLoading.value = true
try {
const detail = await fetchOaTemplateDetail(t.id)
const schema = detail?.formSchemaJson || {}
formRule.value = Array.isArray(schema.rule) ? schema.rule : Array.isArray(schema) ? schema : []
const rawRule = Array.isArray(schema.rule)
? schema.rule
: Array.isArray(schema)
? schema
: []
formRule.value = ensureOaUploadRuleProps(rawRule)
const savedGutter = Number(schema.option?.row?.gutter)
formOption.value = {
...(schema.option || {}),
form: {
...(schema.option?.form || {}),
labelPosition: 'top'
},
// 顶层字段 col.span 布局用;栅格组件 fcRow 由 ensureOaUploadRuleProps 处理
row: {
...(schema.option?.row || {}),
gutter: savedGutter > 0 ? savedGutter : OA_FC_DEFAULT_GUTTER
},
submitBtn: false,
resetBtn: false
}
@@ -312,17 +352,26 @@
} catch {
formRule.value = []
flowSteps.value = []
flowResolved.value = true
previewLoading.value = false
} finally {
detailLoading.value = false
}
}
watch(
formData,
() => {
scheduleFlowPreview()
},
{ deep: true }
)
watch(
initiatorSelectUserIds,
() => {
if (dlgVisible.value && picked.value?.id && needInitiatorSelect.value) {
loadFlowPreview(picked.value.id)
scheduleFlowPreview()
}
},
{ deep: true }
Loaded 100 of 102 files, more files were not shown because too many files have changed in this diff. Show more