zlwu 5 ماه پیش
والد
کامیت
69ee0f505c
32فایلهای تغییر یافته به همراه1528 افزوده شده و 1327 حذف شده
  1. 0 0
      backend/app/graphify-out/cache/ast/326b4959effa86fda4b9529bf98bd0f4d3d93576eafeeba2396415024f2f900e.json
  2. 0 0
      backend/app/graphify-out/cache/ast/45e2ec298d3108f56b156091f165b440a508551737e4451367bfbb3336a46f8f.json
  3. 0 0
      backend/app/graphify-out/cache/ast/c5866d7a542313f0f3f83d9cec91cd4f73d821f408e9c99ddd396301042b3588.json
  4. 0 0
      backend/app/graphify-out/cache/ast/eca4b317fc9d650fb41533b6fed422200dbc612a842761a67319b4c22cf2c675.json
  5. 0 0
      backend/app/graphify-out/cache/ast/fd3db7a9453520247e64a2283bd1be56cdfd634dbeb025a5823f7788893a7060.json
  6. 381 356
      backend/graphify-out/.graphify_analysis.json
  7. 147 115
      backend/graphify-out/.graphify_extract.json
  8. 95 100
      backend/graphify-out/GRAPH_REPORT.md
  9. 1 1
      backend/graphify-out/graph.html
  10. 112 112
      backend/graphify-out/graph.json
  11. 5 5
      backend/graphify-out/manifest.json
  12. 401 384
      web-admin/graphify-out/.graphify_analysis.json
  13. 125 143
      web-admin/graphify-out/.graphify_extract.json
  14. 68 72
      web-admin/graphify-out/GRAPH_REPORT.md
  15. 0 0
      web-admin/graphify-out/graph.html
  16. 15 15
      web-admin/graphify-out/manifest.json
  17. 85 12
      web-admin/src/components/business/infusion-schedule-outbound-chain-view/index.vue
  18. 0 0
      web-admin/src/graphify-out/cache/ast/008da19a081990e9cb47a138582473f00757f8708a49fdea19d2bf61edce06c1.json
  19. 0 0
      web-admin/src/graphify-out/cache/ast/07947182b781896a0c6f2eaba6b9a581b6c58211cd4bc7f051cfc0835e3b0477.json
  20. 1 0
      web-admin/src/graphify-out/cache/ast/553163c3d6c0eb66119486cd9a7faec3259b1c6863a3987d7b41f568d1a51bd9.json
  21. 1 0
      web-admin/src/graphify-out/cache/ast/56dfd016d128919008dd543822ab13e121f3b315ddd65ee6912fc2bce675b2a7.json
  22. 0 0
      web-admin/src/graphify-out/cache/ast/769091ca90742d90a1abb189d267e3e0598a72fb25d7a6f1bf4598a7e99d00a0.json
  23. 0 0
      web-admin/src/graphify-out/cache/ast/8129353ca9a980ab75044bd2aabcfb2dcf004caa922d962d344c27715fd1cedf.json
  24. 0 0
      web-admin/src/graphify-out/cache/ast/91d28541185c74178c2271d2ed79ce2e648d3c621dcc05a39df96d51cb177189.json
  25. 1 0
      web-admin/src/graphify-out/cache/ast/98160063a757a09264a2dec6a94526b88ba4d25103e14f0017c0907fd14759ee.json
  26. 1 0
      web-admin/src/graphify-out/cache/ast/9d3361e40246556b8293d97e75fec122c665c46a37afbcb47e041d0803f43efa.json
  27. 1 0
      web-admin/src/graphify-out/cache/ast/a7084b145c20c5aa04adb4efcc2f21fb887f12d73f1505c03d094052e1842bb6.json
  28. 1 0
      web-admin/src/graphify-out/cache/ast/acdff98786074d06cd82711e74e6d077c47760c9f05aa635aceba3593ef4c2e6.json
  29. 1 0
      web-admin/src/graphify-out/cache/ast/bb8306ac7889608e1cfa71660396f34424cc7a8df22a1aaec65e0477f330def9.json
  30. 1 0
      web-admin/src/graphify-out/cache/ast/ebae3bc304c2e95e3aea0bf352e12be8e7df262202f4a287db5d0ca84609c334.json
  31. 0 0
      web-admin/src/graphify-out/cache/ast/fc8644feb3dfadd734b5edffbeccf60c11775995453f5bebddff05b721fcbfd2.json
  32. 85 12
      web-admin/src/views/pilot-service/infusion-schedule-management/ScheduleViewDialog.vue

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
backend/app/graphify-out/cache/ast/326b4959effa86fda4b9529bf98bd0f4d3d93576eafeeba2396415024f2f900e.json


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
backend/app/graphify-out/cache/ast/45e2ec298d3108f56b156091f165b440a508551737e4451367bfbb3336a46f8f.json


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
backend/app/graphify-out/cache/ast/c5866d7a542313f0f3f83d9cec91cd4f73d821f408e9c99ddd396301042b3588.json


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
backend/app/graphify-out/cache/ast/eca4b317fc9d650fb41533b6fed422200dbc612a842761a67319b4c22cf2c675.json


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
backend/app/graphify-out/cache/ast/fd3db7a9453520247e64a2283bd1be56cdfd634dbeb025a5823f7788893a7060.json


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 381 - 356
backend/graphify-out/.graphify_analysis.json


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 147 - 115
backend/graphify-out/.graphify_extract.json


+ 95 - 100
backend/graphify-out/GRAPH_REPORT.md

@@ -1,12 +1,12 @@
 # Graph Report - app  (2026-05-28)
 
 ## Corpus Check
-- 172 files · ~180,690 words
+- 172 files · ~180,865 words
 - Verdict: corpus is large enough that graph structure adds value.
 
 ## Summary
-- 3286 nodes · 14668 edges · 52 communities detected
-- Extraction: 37% EXTRACTED · 63% INFERRED · 0% AMBIGUOUS · INFERRED: 9175 edges (avg confidence: 0.61)
+- 3288 nodes · 14677 edges · 51 communities detected
+- Extraction: 37% EXTRACTED · 63% INFERRED · 0% AMBIGUOUS · INFERRED: 9181 edges (avg confidence: 0.61)
 - Token cost: 0 input · 0 output
 
 ## Community Hubs (Navigation)
@@ -55,13 +55,12 @@
 - [[_COMMUNITY_Community 42|Community 42]]
 - [[_COMMUNITY_Community 43|Community 43]]
 - [[_COMMUNITY_Community 44|Community 44]]
-- [[_COMMUNITY_Community 45|Community 45]]
+- [[_COMMUNITY_Community 47|Community 47]]
 - [[_COMMUNITY_Community 48|Community 48]]
 - [[_COMMUNITY_Community 49|Community 49]]
 - [[_COMMUNITY_Community 50|Community 50]]
 - [[_COMMUNITY_Community 51|Community 51]]
 - [[_COMMUNITY_Community 52|Community 52]]
-- [[_COMMUNITY_Community 53|Community 53]]
 
 ## God Nodes (most connected - your core abstractions)
 1. `success_response()` - 518 edges
@@ -71,7 +70,7 @@
 5. `BizQcMaterialUsage` - 262 edges
 6. `BizQcMaterial` - 260 edges
 7. `BizMaterialStockLog` - 252 edges
-8. `BizPilotPayment` - 250 edges
+8. `BizPilotPayment` - 251 edges
 9. `BizMaterial` - 249 edges
 10. `BizQcItemParam` - 247 edges
 
@@ -90,140 +89,140 @@
 ## Communities
 
 ### Community 0 - "Community 0"
-Cohesion: 0.02
-Nodes (593): attachment_download_url(), create_dept(), create_dict_data(), create_dict_type(), create_express_company(), create_item_unit(), create_menu(), create_post() (+585 more)
+Cohesion: 0.01
+Nodes (604): attachment_download_url(), create_dept(), create_dict_data(), create_dict_type(), create_express_company(), create_item_unit(), create_menu(), create_post() (+596 more)
 
 ### Community 1 - "Community 1"
 Cohesion: 0.01
 Nodes (493): AttachmentDownloadUrlBody, DeptCreateBody, DeptUpdateBody, DictDataCreateBody, DictDataUpdateBody, DictTypeCreateBody, DictTypeUpdateBody, ExpressCompanyCreateBody (+485 more)
 
 ### Community 2 - "Community 2"
-Cohesion: 0.05
-Nodes (414): AuditCreateBody, BatchDetailIdsBody, BatchRefundFinanceSubmitBody, FinanceConfirmBody, FullmoonTodoInsuranceBody, ProtocolCreateBody, ProtocolUpdateBody, 细胞存储 — 采集协议单 / 审核 / 财务确认 / 分期预警 API (+406 more)
+Cohesion: 0.06
+Nodes (270): ProcessDefCreateBody, ProcessDefUpdateBody, PublishVersionBody, 审批意见:前端传 commentText,兼容 comment。, StartInstanceBody, TaskActionBody, Base, ApiRequestLogCRUD (+262 more)
 
 ### Community 3 - "Community 3"
-Cohesion: 0.02
-Nodes (253): generate_uuid(), batch_stock_in(), batch_stock_out(), consumable_code_exists(), create_consumable(), _dec(), get_consumable(), _is_enabled_status() (+245 more)
+Cohesion: 0.05
+Nodes (244): AuditCreateBody, BatchDetailIdsBody, BatchRefundFinanceSubmitBody, FinanceConfirmBody, FullmoonTodoInsuranceBody, ProtocolCreateBody, ProtocolUpdateBody, 细胞存储 — 采集协议单 / 审核 / 财务确认 / 分期预警 API (+236 more)
 
 ### Community 4 - "Community 4"
 Cohesion: 0.02
-Nodes (198): list_collection_regions(), list_protocol_nos(), _ensure_customer_for_mother(), _persist_protocol_sub_resources(), list_ethnics_for_select(), apply_data_scope(), _get_child_dept_ids(), get_user_dept_id() (+190 more)
+Nodes (168): generate_uuid(), _apply_cell_product_status_change(), batch_stock_in(), batch_stock_out(), consumable_code_exists(), create_consumable(), _dec(), get_consumable() (+160 more)
 
 ### Community 5 - "Community 5"
 Cohesion: 0.02
-Nodes (188): eq_unicode(), like_unicode(), MySQL 字符串比较/模糊匹配时统一排序规则,避免 Illegal mix of collations。, 跨表字符串等值比较(JOIN / WHERE)时统一为 utf8mb4_unicode_ci。, 将列显式设为 utf8mb4_unicode_ci。, unicode_ci(), _format_attachment_file_size(), get_protocol_nos_used_in_protocols() (+180 more)
+Nodes (146): _ensure_customer_for_mother(), _persist_protocol_sub_resources(), delete(), get_multi_with_filters(), _add_months_yyyymmdd(), align_fq_payment_details_payload(), _apply_payment_detail_list_filters(), _apply_submit_receipt_finance() (+138 more)
 
 ### Community 6 - "Community 6"
-Cohesion: 0.03
-Nodes (93): _avatar_url_field(), _build_user_info_payload(), get_web_auth_menu_codes(), _jwt_user_payload(), logout(), 公共接口(Web 登录、刷新 Token、登出;用户模型对齐 docs/sql/zkxw.sql 基线), 登出:吊销 Redis 会话(若已配置 REDIS_HOST)。, 获取当前用户菜单权限标识(sys_menu.perms,经角色继承)。 (+85 more)
+Cohesion: 0.02
+Nodes (144): list_ethnics_for_select(), apply_data_scope(), _get_child_dept_ids(), get_user_dept_id(), _resolve_user_role_scopes(), list_ethnics(), 民族码表 CRUD(全局 sys_ethnic), _row_to_dict() (+136 more)
 
 ### Community 7 - "Community 7"
-Cohesion: 0.03
-Nodes (94): get_designer_data(), ProcessDefCreateBody, ProcessDefUpdateBody, PublishVersionBody, 审批意见:前端传 commentText,兼容 comment。, StartInstanceBody, TaskActionBody, _error_json() (+86 more)
+Cohesion: 0.02
+Nodes (73): _error_json(), lifespan(), 数据库异常:返回 JSON 并保留 CORS 头,避免浏览器只报跨域错误, 未捕获异常:统一 JSON 500,确保跨域场景下仍有 Access-Control-Allow-Origin, sqlalchemy_exception_handler(), unhandled_exception_handler(), BaseHTTPMiddleware, parse_admin_request_json() (+65 more)
 
 ### Community 8 - "Community 8"
-Cohesion: 0.07
-Nodes (68): AccessLogCreateBody, AccessLogUpdateBody, CleanRoomCreateBody, CleanRoomUpdateBody, ExhibitionAppointmentCreateBody, ExhibitionAppointmentUpdateBody, OccupancyCreateBody, 运营支撑 API(洁净室、进出记录、仓储设施、储位、展厅预约) (+60 more)
+Cohesion: 0.04
+Nodes (122): eq_unicode(), like_unicode(), MySQL 字符串比较/模糊匹配时统一排序规则,避免 Illegal mix of collations。, 跨表字符串等值比较(JOIN / WHERE)时统一为 utf8mb4_unicode_ci。, 将列显式设为 utf8mb4_unicode_ci。, unicode_ci(), _format_attachment_file_size(), urls_to_attachment_list() (+114 more)
 
 ### Community 9 - "Community 9"
-Cohesion: 0.35
-Nodes (61): BatchStockInBody, BatchStockInItem, BatchStockOutBody, BatchStockOutItem, ConsumableCreateBody, ConsumablePackCreateBody, ConsumablePackUpdateBody, ConsumableUpdateBody (+53 more)
+Cohesion: 0.04
+Nodes (77): get_protocol_nos_used_in_protocols(), create_dict_type(), dict_type_code_exists(), get_dict_type(), list_dict_types(), _row_to_dict(), soft_delete_dict_type(), update_dict_type() (+69 more)
 
 ### Community 10 - "Community 10"
-Cohesion: 0.06
-Nodes (60): auto_create_payment(), complete_application(), create_infusion_plan(), create_schedule(), _create_schedule_products(), _format_yyyy_mm_dd(), _generate_application_no(), get_application() (+52 more)
+Cohesion: 0.07
+Nodes (68): AccessLogCreateBody, AccessLogUpdateBody, CleanRoomCreateBody, CleanRoomUpdateBody, ExhibitionAppointmentCreateBody, ExhibitionAppointmentUpdateBody, OccupancyCreateBody, 运营支撑 API(洁净室、进出记录、仓储设施、储位、展厅预约) (+60 more)
 
 ### Community 11 - "Community 11"
-Cohesion: 0.07
-Nodes (52): 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() (+44 more)
+Cohesion: 0.35
+Nodes (61): BatchStockInBody, BatchStockInItem, BatchStockOutBody, BatchStockOutItem, ConsumableCreateBody, ConsumablePackCreateBody, ConsumablePackUpdateBody, ConsumableUpdateBody (+53 more)
 
 ### Community 12 - "Community 12"
-Cohesion: 0.09
-Nodes (49): allocate_next_biz_no(), _format_biz_no(), _prefix_for(), 业务协议号自动生成:XBCC / JZCC + YYYYMMDD + 6 位序号, 原子分配下一个业务协议号。     须在 create 事务内调用;使用 MySQL LAST_INSERT_ID 保证并发安全。, create_collection_protocol(), _active_link_query(), assert_biz_no_available() (+41 more)
+Cohesion: 0.06
+Nodes (54): _avatar_url_field(), _build_user_info_payload(), _jwt_user_payload(), logout(), 公共接口(Web 登录、刷新 Token、登出;用户模型对齐 docs/sql/zkxw.sql 基线), 登出:吊销 Redis 会话(若已配置 REDIS_HOST)。, 与 web-admin `userInfo` 字段约定一致。, Web 端登录用 RSA 公钥(PKCS#1 v1.5,与 JSEncrypt 一致) (+46 more)
 
 ### Community 13 - "Community 13"
-Cohesion: 0.07
-Nodes (13): BaseStorage, convert_heic_to_jpeg(), get_storage(), LocalStorage, MinIOStorage, OSSStorage, process_image_content(), QiniuStorage (+5 more)
+Cohesion: 0.06
+Nodes (44): get_designer_data(), list_params_by_item(), _row_to_dict(), save_params_for_item(), list_results_by_task(), _list_saved_results_by_task(), _merge_saved_into_template(), _resolve_task_item_ref() (+36 more)
 
 ### Community 14 - "Community 14"
-Cohesion: 0.1
-Nodes (36): _fmt_dt(), get_handover_by_schedule(), get_outbound_handover(), get_outbound_handover_view(), _handover_row_to_dict(), _handover_view_dict(), _parse_handover_time(), 获取出库交接编辑数据(物料 + 交接信息 + 摘要)。 (+28 more)
+Cohesion: 0.08
+Nodes (53): auto_generate_schedules(), complete_application(), create_infusion_plan(), create_schedule(), _create_schedule_products(), _format_yyyy_mm_dd(), _generate_application_no(), get_application() (+45 more)
 
 ### Community 15 - "Community 15"
-Cohesion: 0.11
-Nodes (34): api_delete_actual_item(), api_delete_checkup(), api_delete_reserve_item(), api_get_checkup_detail(), api_list_actual_items(), api_list_checkups(), api_list_pending_patients(), api_list_reserve_items() (+26 more)
+Cohesion: 0.09
+Nodes (48): allocate_next_biz_no(), _format_biz_no(), _prefix_for(), 业务协议号自动生成:XBCC / JZCC + YYYYMMDD + 6 位序号, 原子分配下一个业务协议号。     须在 create 事务内调用;使用 MySQL LAST_INSERT_ID 保证并发安全。, create_collection_protocol(), _active_link_query(), assert_biz_no_available() (+40 more)
 
 ### Community 16 - "Community 16"
 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)
+Nodes (32): get_next_cell_product_code(), _ancestor_link_from_cell_product_input(), _ancestor_sample_chain_link(), _build_ancestor_chain(), _build_descendant_chain(), _build_facility_path_label(), build_split_product_codes(), create_cell_products_batch() (+24 more)
 
 ### Community 17 - "Community 17"
-Cohesion: 0.17
-Nodes (12): BusinessException, InvalidStatusTransitionException, log_delivery_operation(), log_operation(), log_order_operation(), log_settlement_operation(), log_user_operation(), OrderLockedException (+4 more)
+Cohesion: 0.16
+Nodes (32): _create_insurance_company(), _create_insurance_company_invoice(), _create_insurance_project_price(), delete_insurance_company(), delete_insurance_company_invoice(), delete_insurance_project_price(), _fmt_dt(), _generate_uuid() (+24 more)
 
 ### Community 18 - "Community 18"
-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)
+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 19 - "Community 19"
-Cohesion: 0.22
-Nodes (19): _fmt_dt(), InsuranceCompanyCreateBody, InsuranceCompanyInvoiceCreateBody, InsuranceCompanyInvoiceUpdateBody, InsuranceCompanyUpdateBody, InsuranceProjectPriceCreateBody, InsuranceProjectPriceUpdateBody, _list_insurance_companies() (+11 more)
+Cohesion: 0.18
+Nodes (18): company_code_exists(), create_company(), get_company(), list_companies(), list_company_options(), _row_to_dict(), soft_delete_company(), update_company() (+10 more)
 
 ### Community 20 - "Community 20"
-Cohesion: 0.2
-Nodes (14): deduct_for_task(), _display_remark(), list_usages(), list_usages_by_task(), _parse_receiver_purpose_from_remark(), 查询质检任务关联的物料使用记录(task_complete)。, 撤销任务此前 task_complete 扣减,便于重新填报物料使用。, 兼容旧数据:领用人/用途曾拼接在 remark 中。 (+6 more)
-
-### Community 21 - "Community 21"
 Cohesion: 0.25
 Nodes (13): batch_issue_protocol_nos(), batch_revoke_protocol_nos(), create_protocol_no(), get_protocol_no(), list_protocol_nos(), _parse_issued_time(), protocol_no_exists(), 采集协议号池 CRUD(biz_collection_protocol_no) (+5 more)
 
+### Community 21 - "Community 21"
+Cohesion: 0.26
+Nodes (11): _base_query(), _ensure_notification(), _fmt_dt(), generate_sms_content(), list_notifications(), _normalize_date_bound(), resolve_notification(), _row_to_dict() (+3 more)
+
 ### Community 22 - "Community 22"
 Cohesion: 0.26
 Nodes (12): batch_issue_sample_codes(), batch_revoke_sample_codes(), create_sample_code(), get_sample_code(), list_sample_codes(), _parse_issued_time(), 样本编码池 CRUD(biz_sample_code), _resolve_issued_user_display_name() (+4 more)
 
 ### Community 23 - "Community 23"
-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.23
+Nodes (12): create_collection_region(), create_hospital(), get_collection_region(), get_hospital(), _hospital_names_by_region_ids(), _hospital_to_dict(), list_collection_regions(), list_hospitals() (+4 more)
 
 ### Community 24 - "Community 24"
-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)
+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 25 - "Community 25"
-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 (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 26 - "Community 26"
-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)
+Cohesion: 0.23
+Nodes (12): Config, ProductBase, ProductCategoryBase, ProductCategoryCreate, ProductCategoryResponse, ProductCreate, ProductResponse, ProductUnitBase (+4 more)
 
 ### Community 27 - "Community 27"
-Cohesion: 0.31
-Nodes (8): create_dict_type(), dict_type_code_exists(), get_dict_type(), list_dict_types(), 字典类型 CRUD(sys_dict_type), _row_to_dict(), soft_delete_dict_type(), update_dict_type()
+Cohesion: 0.27
+Nodes (11): _build_tree(), _cascade_soft_delete(), _collect_with_ancestors(), create_dept(), get_dept(), list_depts(), list_depts_tree(), 保留匹配节点及其全部上级,供关键词检索后仍能正确组树。 (+3 more)
 
 ### Community 28 - "Community 28"
-Cohesion: 0.31
-Nodes (8): create_sop_document(), get_sop_document(), list_sop_documents(), SOP文档 CRUD(biz_sop_document), _row_to_dict(), soft_delete_sop_document(), sop_code_exists(), update_sop_document()
+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 29 - "Community 29"
+Cohesion: 0.36
+Nodes (9): deduct_for_task(), _display_remark(), list_usages(), list_usages_by_task(), _parse_receiver_purpose_from_remark(), _resolve_receiver_purpose(), revert_task_material_usages(), _row_to_dict() (+1 more)
+
+### Community 30 - "Community 30"
 Cohesion: 0.31
 Nodes (8): create_express_company(), express_code_exists(), get_express_company(), list_express_companies(), 快递公司 CRUD(biz_express_company), _row_to_dict(), soft_delete_express_company(), update_express_company()
 
-### Community 30 - "Community 30"
+### Community 31 - "Community 31"
 Cohesion: 0.38
 Nodes (9): create_check_item(), get_check_item(), item_code_exists(), list_active_check_items(), list_check_items(), _order_query(), _row_to_dict(), soft_delete_check_item() (+1 more)
 
-### Community 31 - "Community 31"
+### Community 32 - "Community 32"
 Cohesion: 0.27
 Nodes (8): create_dict_data(), get_dict_data(), list_dict_data(), list_dict_data_options(), 字典数据 CRUD(sys_dict_data), _row_to_dict(), soft_delete_dict_data(), update_dict_data()
 
-### Community 32 - "Community 32"
-Cohesion: 0.31
-Nodes (8): category_code_exists(), create_process_category(), get_process_category(), list_process_categories(), 工艺工序分类 CRUD(biz_process_category), _row_to_dict(), soft_delete_process_category(), update_process_category()
-
 ### Community 33 - "Community 33"
 Cohesion: 0.31
-Nodes (8): create_item_unit(), get_item_unit(), list_item_units(), 物品单位 CRUD(biz_item_unit), _row_to_dict(), soft_delete_item_unit(), unit_code_exists(), update_item_unit()
+Nodes (8): category_code_exists(), create_process_category(), get_process_category(), list_process_categories(), 工艺工序分类 CRUD(biz_process_category), _row_to_dict(), soft_delete_process_category(), update_process_category()
 
 ### Community 34 - "Community 34"
 Cohesion: 0.31
@@ -234,104 +233,100 @@ Cohesion: 0.31
 Nodes (8): create_output_type(), get_output_type(), list_output_types(), 工艺产出物类型 CRUD(biz_output_type), _row_to_dict(), soft_delete_output_type(), type_code_exists(), update_output_type()
 
 ### Community 36 - "Community 36"
-Cohesion: 0.36
-Nodes (7): create_post(), get_post(), list_posts(), post_code_exists(), _row_to_dict(), soft_delete_post(), update_post()
+Cohesion: 0.39
+Nodes (8): create_lab_item(), get_lab_item(), item_code_exists(), list_active_lab_items(), list_lab_items(), _row_to_dict(), soft_delete_lab_item(), update_lab_item()
 
 ### Community 37 - "Community 37"
 Cohesion: 0.36
-Nodes (7): create_tenant(), get_tenant(), list_tenants(), _row_to_dict(), soft_delete_tenant(), tenant_no_exists(), update_tenant()
-
-### Community 38 - "Community 38"
-Cohesion: 0.36
 Nodes (7): create_site(), get_site(), list_sites(), _row_to_dict(), site_code_exists(), soft_delete_site(), update_site()
 
-### Community 39 - "Community 39"
+### Community 38 - "Community 38"
 Cohesion: 0.29
 Nodes (2): BaseModel, SoftDeleteModel
 
-### Community 40 - "Community 40"
+### Community 39 - "Community 39"
 Cohesion: 0.38
 Nodes (6): derive_legacy_status_from_three(), derive_three_status_from_legacy(), 阶段A兼容:从旧 status 推导三字段。     约束:旧 status 本身混合了支付/配送/订单生命周期,因此只能尽力推断;     若业务侧已有更精确, 阶段A兼容:从三字段反推旧 status(用于旧前端/旧筛选参数兼容)。, ThreeStatus, _to_decimal()
 
-### Community 41 - "Community 41"
+### Community 40 - "Community 40"
 Cohesion: 0.5
 Nodes (3): BaseSettings, Config, Settings
 
-### Community 42 - "Community 42"
+### Community 41 - "Community 41"
 Cohesion: 0.5
 Nodes (2): _auto_fill_create_dept_id(), ORM before_insert 钩子:当 create_dept_id 为空时,自动从请求上下文填充当前用户部门 ID
 
-### Community 43 - "Community 43"
+### Community 42 - "Community 42"
 Cohesion: 0.67
 Nodes (2): get_menu_list(), 运营端菜单接口(与 web-admin 前端静态路由 sqxp.ts 对齐,13 个一级菜单)
 
-### Community 44 - "Community 44"
+### Community 43 - "Community 43"
 Cohesion: 1.0
 Nodes (1): 请求级别的用户上下文变量  通过 contextvars 在请求处理链路中传递当前用户信息, 供 SQLAlchemy 事件监听器等底层机制使用,避免逐层手动传
 
-### Community 45 - "Community 45"
+### Community 44 - "Community 44"
 Cohesion: 1.0
 Nodes (1): API 路由包(骨架:公共鉴权 + 静态菜单 + 运营端占位)
 
-### Community 48 - "Community 48"
+### Community 47 - "Community 47"
 Cohesion: 1.0
 Nodes (1): 发送订单状态通知                  Args:             openid: 用户openid             ord
 
-### Community 49 - "Community 49"
+### Community 48 - "Community 48"
 Cohesion: 1.0
 Nodes (1): 发送支付成功通知                  Args:             openid: 用户openid             ord
 
-### Community 50 - "Community 50"
+### Community 49 - "Community 49"
 Cohesion: 1.0
 Nodes (1): 发送配送通知                  Args:             openid: 配送员openid             task
 
-### Community 51 - "Community 51"
+### Community 50 - "Community 50"
 Cohesion: 1.0
 Nodes (1): 发送配送时效预警                  Args:             openid: 配送员openid             ta
 
-### Community 52 - "Community 52"
+### Community 51 - "Community 51"
 Cohesion: 1.0
 Nodes (1): 发送退款结果通知                  Args:             openid: 用户openid             ord
 
-### Community 53 - "Community 53"
+### Community 52 - "Community 52"
 Cohesion: 1.0
 Nodes (1): 发送催单通知给配送员                  Args:             deliver_openid: 配送员openid
 
 ## Knowledge Gaps
 - **97 isolated node(s):** `刷新会话 TTL(refreshToken 续期;已登录用户每次 API 校验通过后滑动续期)`, `写入 refreshToken(用于 one-time 使用/吊销)`, `根据 token 获取当前用户(包含 Redis 会话校验;会话滑动续期)`, `登录凭据 RSA 解密(与前端 JSEncrypt PKCS#1 v1.5 兼容)。`, `Base64 密文 -> JSON 对象(须含 username、password、ts 毫秒时间戳)。` (+92 more)
   These have ≤1 connection - possible missing edges or undocumented components.
-- **Thin community `Community 39`** (8 nodes): `BaseModel`, `.to_dict()`, `get_active()`, `base.py`, `SoftDeleteModel`, `.restore()`, `.soft_delete()`, `__tablename__()`
+- **Thin community `Community 38`** (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 42`** (4 nodes): `_auto_fill_create_dept_id()`, `get_db()`, `database.py`, `ORM before_insert 钩子:当 create_dept_id 为空时,自动从请求上下文填充当前用户部门 ID`
+- **Thin community `Community 41`** (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 43`** (3 nodes): `get_menu_list()`, `menu.py`, `运营端菜单接口(与 web-admin 前端静态路由 sqxp.ts 对齐,13 个一级菜单)`
+- **Thin community `Community 42`** (3 nodes): `get_menu_list()`, `menu.py`, `运营端菜单接口(与 web-admin 前端静态路由 sqxp.ts 对齐,13 个一级菜单)`
   Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 44`** (2 nodes): `context.py`, `请求级别的用户上下文变量  通过 contextvars 在请求处理链路中传递当前用户信息, 供 SQLAlchemy 事件监听器等底层机制使用,避免逐层手动传`
+- **Thin community `Community 43`** (2 nodes): `context.py`, `请求级别的用户上下文变量  通过 contextvars 在请求处理链路中传递当前用户信息, 供 SQLAlchemy 事件监听器等底层机制使用,避免逐层手动传`
   Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 45`** (2 nodes): `__init__.py`, `API 路由包(骨架:公共鉴权 + 静态菜单 + 运营端占位)`
+- **Thin community `Community 44`** (2 nodes): `__init__.py`, `API 路由包(骨架:公共鉴权 + 静态菜单 + 运营端占位)`
   Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 48`** (1 nodes): `发送订单状态通知                  Args:             openid: 用户openid             ord`
+- **Thin community `Community 47`** (1 nodes): `发送订单状态通知                  Args:             openid: 用户openid             ord`
   Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 49`** (1 nodes): `发送支付成功通知                  Args:             openid: 用户openid             ord`
+- **Thin community `Community 48`** (1 nodes): `发送支付成功通知                  Args:             openid: 用户openid             ord`
   Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 50`** (1 nodes): `发送配送通知                  Args:             openid: 配送员openid             task`
+- **Thin community `Community 49`** (1 nodes): `发送配送通知                  Args:             openid: 配送员openid             task`
   Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 51`** (1 nodes): `发送配送时效预警                  Args:             openid: 配送员openid             ta`
+- **Thin community `Community 50`** (1 nodes): `发送配送时效预警                  Args:             openid: 配送员openid             ta`
   Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 52`** (1 nodes): `发送退款结果通知                  Args:             openid: 用户openid             ord`
+- **Thin community `Community 51`** (1 nodes): `发送退款结果通知                  Args:             openid: 用户openid             ord`
   Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 53`** (1 nodes): `发送催单通知给配送员                  Args:             deliver_openid: 配送员openid`
+- **Thin community `Community 52`** (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 1` to `Community 2`, `Community 3`, `Community 4`, `Community 6`, `Community 7`, `Community 8`, `Community 9`, `Community 14`, `Community 15`, `Community 19`, `Community 20`, `Community 21`, `Community 22`, `Community 24`?**
-  _High betweenness centrality (0.121) - this node is a cross-community bridge._
-- **Why does `success_response()` connect `Community 0` to `Community 1`, `Community 4`, `Community 6`, `Community 7`, `Community 43`, `Community 11`, `Community 15`, `Community 19`?**
-  _High betweenness centrality (0.069) - this node is a cross-community bridge._
-- **Why does `generate_uuid()` connect `Community 3` to `Community 0`, `Community 1`, `Community 2`, `Community 4`, `Community 5`, `Community 6`, `Community 7`, `Community 8`, `Community 11`, `Community 12`, `Community 14`, `Community 18`, `Community 20`, `Community 21`, `Community 22`, `Community 24`, `Community 25`, `Community 26`, `Community 27`, `Community 28`, `Community 29`, `Community 30`, `Community 31`, `Community 32`, `Community 33`, `Community 34`, `Community 35`, `Community 36`, `Community 37`, `Community 38`?**
-  _High betweenness centrality (0.061) - this node is a cross-community bridge._
+- **Why does `SysUser` connect `Community 1` to `Community 2`, `Community 3`, `Community 4`, `Community 9`, `Community 10`, `Community 11`, `Community 12`, `Community 17`, `Community 20`, `Community 22`?**
+  _High betweenness centrality (0.123) - this node is a cross-community bridge._
+- **Why does `success_response()` connect `Community 0` to `Community 1`, `Community 6`, `Community 42`, `Community 12`, `Community 13`, `Community 16`, `Community 17`?**
+  _High betweenness centrality (0.088) - this node is a cross-community bridge._
+- **Why does `generate_uuid()` connect `Community 4` to `Community 0`, `Community 1`, `Community 2`, `Community 3`, `Community 5`, `Community 6`, `Community 7`, `Community 8`, `Community 9`, `Community 10`, `Community 12`, `Community 13`, `Community 14`, `Community 15`, `Community 16`, `Community 19`, `Community 20`, `Community 21`, `Community 22`, `Community 23`, `Community 24`, `Community 27`, `Community 28`, `Community 29`, `Community 30`, `Community 31`, `Community 32`, `Community 33`, `Community 34`, `Community 35`, `Community 36`, `Community 37`?**
+  _High betweenness centrality (0.059) - this node is a cross-community bridge._
 - **Are the 517 inferred relationships involving `success_response()` (e.g. with `list_storage_release_reviews()` and `get_storage_release_review_detail()`) actually correct?**
   _`success_response()` has 517 INFERRED edges - model-reasoned connections that need verification._
 - **Are the 505 inferred relationships involving `str` (e.g. with `unhandled_exception_handler()` and `extract_login_credentials()`) actually correct?**

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 1
backend/graphify-out/graph.html


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 112 - 112
backend/graphify-out/graph.json


+ 5 - 5
backend/graphify-out/manifest.json

@@ -37,7 +37,7 @@
   "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/process_route.py": 1779367496.1718137,
   "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/auth.py": 1778578258.0939043,
   "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/delivery.py": 1778578258.0949655,
-  "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/outbound_release_review.py": 1779808997.3299003,
+  "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/outbound_release_review.py": 1779968230.0408957,
   "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/price_list.py": 1778578258.096609,
   "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/user.py": 1778578258.099944,
   "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_work_order.py": 1779924314.060957,
@@ -73,7 +73,7 @@
   "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process_route.py": 1779587424.6859367,
   "/Users/wuzilong/work/00code/zkxw/backend/app/crud/sample_code.py": 1779279460.690872,
   "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task_result.py": 1779331731.6720955,
-  "/Users/wuzilong/work/00code/zkxw/backend/app/crud/outbound_release_review.py": 1779940526.705119,
+  "/Users/wuzilong/work/00code/zkxw/backend/app/crud/outbound_release_review.py": 1779968239.1429183,
   "/Users/wuzilong/work/00code/zkxw/backend/app/crud/post.py": 1779265648.38155,
   "/Users/wuzilong/work/00code/zkxw/backend/app/crud/sample_reception_check_result.py": 1779255909.8554008,
   "/Users/wuzilong/work/00code/zkxw/backend/app/crud/user.py": 1778775532.8870275,
@@ -94,7 +94,7 @@
   "/Users/wuzilong/work/00code/zkxw/backend/app/crud/biz_no_generator.py": 1779882385.4674172,
   "/Users/wuzilong/work/00code/zkxw/backend/app/crud/pilot_infusion_confirm.py": 1779828818.7646794,
   "/Users/wuzilong/work/00code/zkxw/backend/app/crud/reagent_stock_log.py": 1779515479.6599197,
-  "/Users/wuzilong/work/00code/zkxw/backend/app/crud/pilot_infusion_schedule_mgmt.py": 1779944265.1860178,
+  "/Users/wuzilong/work/00code/zkxw/backend/app/crud/pilot_infusion_schedule_mgmt.py": 1779969579.5921302,
   "/Users/wuzilong/work/00code/zkxw/backend/app/crud/clean_room.py": 1778775238.2993922,
   "/Users/wuzilong/work/00code/zkxw/backend/app/crud/__init__.py": 1778605691.3816392,
   "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_entry_sms_notification.py": 1779691734.0972729,
@@ -139,9 +139,9 @@
   "/Users/wuzilong/work/00code/zkxw/backend/app/crud/leave.py": 1779265839.500242,
   "/Users/wuzilong/work/00code/zkxw/backend/app/crud/output_type.py": 1779265703.7363207,
   "/Users/wuzilong/work/00code/zkxw/backend/app/crud/exhibition_appointment.py": 1778801075.5211918,
-  "/Users/wuzilong/work/00code/zkxw/backend/app/crud/clinical_payment.py": 1779944085.1689148,
+  "/Users/wuzilong/work/00code/zkxw/backend/app/crud/clinical_payment.py": 1779969576.9773977,
   "/Users/wuzilong/work/00code/zkxw/backend/app/api/storage_release_review.py": 1779526635.1455016,
-  "/Users/wuzilong/work/00code/zkxw/backend/app/api/outbound_release_review.py": 1779940529.0275311,
+  "/Users/wuzilong/work/00code/zkxw/backend/app/api/outbound_release_review.py": 1779968232.5759368,
   "/Users/wuzilong/work/00code/zkxw/backend/app/api/public.py": 1779313409.0685387,
   "/Users/wuzilong/work/00code/zkxw/backend/app/api/material.py": 1779526648.041865,
   "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py": 1779965447.565143,

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 401 - 384
web-admin/graphify-out/.graphify_analysis.json


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 125 - 143
web-admin/graphify-out/.graphify_extract.json


+ 68 - 72
web-admin/graphify-out/GRAPH_REPORT.md

@@ -1,7 +1,7 @@
 # Graph Report - src  (2026-05-28)
 
 ## Corpus Check
-- Large corpus: 672 files · ~417,381 words. Semantic extraction will be expensive (many Claude tokens). Consider running on a subfolder, or use --no-semantic to run AST-only.
+- Large corpus: 672 files · ~418,149 words. Semantic extraction will be expensive (many Claude tokens). Consider running on a subfolder, or use --no-semantic to run AST-only.
 
 ## Summary
 - 1934 nodes · 2494 edges · 50 communities detected
@@ -39,10 +39,10 @@
 - [[_COMMUNITY_Community 27|Community 27]]
 - [[_COMMUNITY_Community 28|Community 28]]
 - [[_COMMUNITY_Community 29|Community 29]]
-- [[_COMMUNITY_Community 31|Community 31]]
+- [[_COMMUNITY_Community 30|Community 30]]
 - [[_COMMUNITY_Community 32|Community 32]]
 - [[_COMMUNITY_Community 33|Community 33]]
-- [[_COMMUNITY_Community 34|Community 34]]
+- [[_COMMUNITY_Community 35|Community 35]]
 - [[_COMMUNITY_Community 36|Community 36]]
 - [[_COMMUNITY_Community 37|Community 37]]
 - [[_COMMUNITY_Community 38|Community 38]]
@@ -52,7 +52,7 @@
 - [[_COMMUNITY_Community 44|Community 44]]
 - [[_COMMUNITY_Community 45|Community 45]]
 - [[_COMMUNITY_Community 46|Community 46]]
-- [[_COMMUNITY_Community 47|Community 47]]
+- [[_COMMUNITY_Community 48|Community 48]]
 - [[_COMMUNITY_Community 49|Community 49]]
 - [[_COMMUNITY_Community 50|Community 50]]
 - [[_COMMUNITY_Community 51|Community 51]]
@@ -73,16 +73,16 @@
 10. `buildOutboundPilotContextSections()` - 12 edges
 
 ## Surprising Connections (you probably didn't know these)
-- `handleBatchDelete()` --calls--> `withFullscreenLoading()`  [INFERRED]
-  views/basic-info/customer/index.vue → utils/fullscreen-loading.ts
 - `subscribeTokenRefresh()` --calls--> `push()`  [INFERRED]
   utils/http/index.ts → views/operations/storage-facility/index.vue
 - `handleUnauthorizedResponse()` --calls--> `fetchRefreshToken()`  [INFERRED]
   utils/http/index.ts → api/auth.ts
+- `fetchLeaveList()` --calls--> `get()`  [INFERRED]
+  api/leave.ts → views/production/process/ProcessRouteTab.vue
+- `fetchLeaveDetail()` --calls--> `get()`  [INFERRED]
+  api/leave.ts → views/production/process/ProcessRouteTab.vue
 - `fetchSampleReceptionCheckItemList()` --calls--> `get()`  [INFERRED]
   api/sample-reception-check-item.ts → views/production/process/ProcessRouteTab.vue
-- `fetchSampleReceptionCheckItemsActive()` --calls--> `get()`  [INFERRED]
-  api/sample-reception-check-item.ts → views/production/process/ProcessRouteTab.vue
 
 ## Communities
 
@@ -96,15 +96,15 @@ Nodes (85): batchSavePilotCheckup(), deletePilotCheckupActualItem(), fetchChecku
 
 ### Community 2 - "Community 2"
 Cohesion: 0.03
-Nodes (40): fetchGetUserInfo(), clickTab(), handleTouchEnd(), setTransition(), useSettingsHandlers(), useSettingsPanel(), useSettingsState(), IframeRouteManager (+32 more)
+Nodes (40): fetchGetMenuList(), fetchGetMenuCodes(), fetchGetUserInfo(), fetchLogin(), fetchRefreshToken(), clickTab(), handleTouchEnd(), setTransition() (+32 more)
 
 ### Community 3 - "Community 3"
 Cohesion: 0.03
-Nodes (34): updateInfusionScheduleStatus(), submitOutboundReleaseReview(), fetchProductionTaskDetail(), fetchProductionTaskList(), fetchUpdateProductionTask(), fetchStorageReleaseReviewDetail(), fetchStorageReleaseReviewList(), submitStorageReleaseReview() (+26 more)
+Nodes (36): fetchAllConsumablePacks(), fetchAllConsumables(), fetchAllConsumableStockLogs(), fetchAllOutputTypes(), fetchAllProcessCategories(), fetchAllProcesses(), fetchAllReagents(), fetchAllReagentStockLogs() (+28 more)
 
 ### Community 4 - "Community 4"
 Cohesion: 0.03
-Nodes (36): fetchAllConsumablePacks(), fetchAllConsumables(), fetchAllConsumableStockLogs(), fetchAllOutputTypes(), fetchAllProcessCategories(), fetchAllProcesses(), fetchAllReagents(), fetchAllReagentStockLogs() (+28 more)
+Nodes (37): fetchCreateCustomer(), fetchCustomerList(), fetchDeleteCustomer(), fetchUpdateCustomer(), submitOutboundReleaseReview(), fetchStorageReleaseReviewDetail(), fetchStorageReleaseReviewList(), submitStorageReleaseReview() (+29 more)
 
 ### Community 5 - "Community 5"
 Cohesion: 0.04
@@ -116,32 +116,32 @@ Nodes (34): toLogin(), base64ToBytes(), bytesToBase64(), decryptJson(), deriveKe
 
 ### Community 7 - "Community 7"
 Cohesion: 0.04
-Nodes (30): fetchCollectionRegionList(), fetchCreateCollectionRegion(), fetchCreateHospital(), fetchDeleteCollectionRegion(), fetchDeleteHospital(), fetchHospitalList(), fetchUpdateCollectionRegion(), fetchUpdateHospital() (+22 more)
+Nodes (28): fetchAttachmentDownloadUrl(), fullFileUrl(), handleDownloadAttachment(), handlePreviewAttachment(), isVideoFile(), handleReceptionAttachmentDownload(), handleDownloadAttachment(), attachmentFullUrl() (+20 more)
 
 ### Community 8 - "Community 8"
-Cohesion: 0.04
-Nodes (28): fetchAttachmentDownloadUrl(), fullFileUrl(), handleDownloadAttachment(), handlePreviewAttachment(), isVideoFile(), handleReceptionAttachmentDownload(), handleDownloadAttachment(), attachmentFullUrl() (+20 more)
+Cohesion: 0.05
+Nodes (30): fetchCollectionRegionList(), fetchCreateCollectionRegion(), fetchCreateHospital(), fetchDeleteCollectionRegion(), fetchDeleteHospital(), fetchHospitalList(), fetchUpdateCollectionRegion(), fetchUpdateHospital() (+22 more)
 
 ### Community 9 - "Community 9"
-Cohesion: 0.06
-Nodes (28): fetchFullmoonTodoList(), fetchUpdateFullmoonTodoInsurance(), fetchCollectionProtocolAuditList(), fetchCollectionProtocolDetail(), fetchCollectionProtocolList(), fetchPaymentDetailList(), fetchReceiptConfirmedList(), fetchReceiptConfirmList() (+20 more)
+Cohesion: 0.08
+Nodes (7): updateInfusionScheduleStatus(), handleSubmit(), handleReset(), handleSearch(), WebSocketClient, TableCache, emit()
 
 ### Community 10 - "Community 10"
 Cohesion: 0.06
-Nodes (27): for(), set(), walk(), annotateForkEdges(), chainApiToElements(), walkAncestorBranch(), walkAncestorParents(), if() (+19 more)
+Nodes (28): fetchFullmoonTodoList(), fetchUpdateFullmoonTodoInsurance(), fetchCollectionProtocolAuditList(), fetchCollectionProtocolDetail(), fetchCollectionProtocolList(), fetchPaymentDetailList(), fetchReceiptConfirmedList(), fetchReceiptConfirmList() (+20 more)
 
 ### Community 11 - "Community 11"
-Cohesion: 0.1
-Nodes (2): WebSocketClient, TableCache
+Cohesion: 0.06
+Nodes (27): for(), set(), walk(), annotateForkEdges(), chainApiToElements(), walkAncestorBranch(), walkAncestorParents(), if() (+19 more)
 
 ### Community 12 - "Community 12"
-Cohesion: 0.07
-Nodes (20): fetchCreateMenu(), fetchDeleteMenu(), fetchMenuTree(), fetchUpdateMenu(), collectIds(), postorder(), preorder(), applyTreeExpand() (+12 more)
-
-### Community 13 - "Community 13"
 Cohesion: 0.09
 Nodes (8): getDefaultLanguage(), checkStorageCompatibility(), StorageConfig, getSystemStorage(), getSysVersion(), StorageKeyManager, StorageCompatibilityManager, validateStorageData()
 
+### Community 13 - "Community 13"
+Cohesion: 0.07
+Nodes (20): fetchCreateMenu(), fetchDeleteMenu(), fetchMenuTree(), fetchUpdateMenu(), collectIds(), postorder(), preorder(), applyTreeExpand() (+12 more)
+
 ### Community 14 - "Community 14"
 Cohesion: 0.07
 Nodes (18): fetchClinicalPaymentDetail(), fetchClinicalPayments(), fetchClinicalReceiptConfirmed(), fetchClinicalReceiptPending(), fetchClinicalRefundConfirmed(), fetchClinicalRefundPending(), fetchOrderAdjusts(), fetchOrderDetail() (+10 more)
@@ -151,48 +151,48 @@ Cohesion: 0.08
 Nodes (11): maskIdCard(), buildOutboundPilotContextSections(), applicationStatusLabel(), applicationStatusTagType(), infusionMethodLabel(), infusionStatusLabel(), infusionStatusTagType(), qcStatusLabel() (+3 more)
 
 ### Community 16 - "Community 16"
-Cohesion: 0.09
-Nodes (22): fetchCreateSite(), fetchDeleteSite(), fetchSiteList(), fetchUpdateSite(), fetchUserList(), formatHandoverUserLabel(), formatNowDatetime(), remoteSearchHandoverUsers() (+14 more)
+Cohesion: 0.12
+Nodes (22): completePilotApplication(), deletePilotApplication(), fetchPilotApplicationList(), startPilotApplication(), voidPilotApplication(), handleBatchComplete(), handleBatchStart(), handleBatchVoid() (+14 more)
 
 ### Community 17 - "Community 17"
-Cohesion: 0.1
-Nodes (8): fetchGetMenuList(), fetchGetMenuCodes(), fetchLogin(), fetchRefreshToken(), MenuProcessor, useAppMode(), useAuth(), buildWebEncryptedLoginBody()
+Cohesion: 0.12
+Nodes (20): fetchCreateUser(), fetchDeleteUser(), fetchResetPassword(), fetchUpdateUser(), fetchUserDetail(), formatUserDeptDisplay(), handleAdd(), handleBatchDelete() (+12 more)
 
 ### Community 18 - "Community 18"
 Cohesion: 0.12
-Nodes (22): completePilotApplication(), deletePilotApplication(), fetchPilotApplicationList(), startPilotApplication(), voidPilotApplication(), handleBatchComplete(), handleBatchStart(), handleBatchVoid() (+14 more)
+Nodes (19): fetchCreateSite(), fetchDeleteSite(), fetchSiteList(), fetchUpdateSite(), fetchUserList(), remoteSearchHandoverUsers(), formatContactUserLabel(), handleAdd() (+11 more)
 
 ### Community 19 - "Community 19"
 Cohesion: 0.12
-Nodes (20): fetchCreateUser(), fetchDeleteUser(), fetchResetPassword(), fetchUpdateUser(), fetchUserDetail(), formatUserDeptDisplay(), handleAdd(), handleBatchDelete() (+12 more)
+Nodes (15): addCopyButton(), highlightCode(), insertLineNumbers(), isBlockProcessed(), markBlockAsProcessed(), processBlock(), setupHighlightDirective(), setupRippleDirective() (+7 more)
 
 ### Community 20 - "Community 20"
-Cohesion: 0.12
-Nodes (15): addCopyButton(), highlightCode(), insertLineNumbers(), isBlockProcessed(), markBlockAsProcessed(), processBlock(), setupHighlightDirective(), setupRippleDirective() (+7 more)
+Cohesion: 0.1
+Nodes (6): fetchProductionTaskDetail(), fetchProductionTaskList(), fetchUpdateProductionTask(), handleClose(), handleSubmit(), loadTaskDetail()
 
 ### Community 21 - "Community 21"
 Cohesion: 0.14
 Nodes (16): fetchCheckupInstitutionList(), fetchPilotCheckupList(), canEditCheckup(), canFillCheckupInfo(), canMarkChecked(), handleDropdownCommand(), handleEdit(), handleReset() (+8 more)
 
 ### Community 22 - "Community 22"
-Cohesion: 0.15
-Nodes (11): fetchEthnicList(), addSample(), applyDonationBundleToForm(), confirmBatchTransportApply(), createEmptyTransport(), ensureEthnicOptionInList(), handleOpenForAdd(), loadEthnicOptions() (+3 more)
+Cohesion: 0.09
+Nodes (5): fetchMaterialList(), fetchMaterialOptions(), fetchMaterialStockLogList(), fetchQcMaterialList(), fetchQcMaterialOptions()
 
 ### Community 23 - "Community 23"
 Cohesion: 0.12
 Nodes (12): fetchApproveTask(), fetchBusinessAllTasks(), fetchCompletedTasks(), fetchDesignerData(), fetchInstanceDetail(), fetchMyInstances(), fetchPendingTasks(), fetchProcessDefList() (+4 more)
 
 ### Community 24 - "Community 24"
-Cohesion: 0.16
-Nodes (14): fetchCreateCustomer(), fetchCustomerList(), fetchDeleteCustomer(), fetchUpdateCustomer(), handleAdd(), handleBatchDelete(), handleDelete(), handleDropdownCommand() (+6 more)
+Cohesion: 0.15
+Nodes (11): fetchEthnicList(), addSample(), applyDonationBundleToForm(), confirmBatchTransportApply(), createEmptyTransport(), ensureEthnicOptionInList(), handleOpenForAdd(), loadEthnicOptions() (+3 more)
 
 ### Community 25 - "Community 25"
-Cohesion: 0.16
-Nodes (10): useTable(), useTableImpl(), getColumnChecks(), useTableColumns(), createErrorHandler(), createSmartDebounce(), defaultResponseAdapter(), extractPagination() (+2 more)
+Cohesion: 0.13
+Nodes (8): fetchOutboundReleaseMaterial(), fetchOutboundReleaseReviewDetail(), fetchOutboundReleaseReviewList(), fetchReleaseReviewList(), handleReset(), handleSearch(), loadData(), onReviewSubmitted()
 
 ### Community 26 - "Community 26"
-Cohesion: 0.14
-Nodes (8): fetchOutboundReleaseMaterial(), fetchOutboundReleaseReviewDetail(), fetchOutboundReleaseReviewList(), fetchReleaseReviewList(), handleReset(), handleSearch(), loadData(), onReviewSubmitted()
+Cohesion: 0.16
+Nodes (10): useTable(), useTableImpl(), getColumnChecks(), useTableColumns(), createErrorHandler(), createSmartDebounce(), defaultResponseAdapter(), extractPagination() (+2 more)
 
 ### Community 27 - "Community 27"
 Cohesion: 0.2
@@ -203,45 +203,45 @@ Cohesion: 0.27
 Nodes (14): useChart(), useChartComponent(), useChartOps(), colourBlend(), getCssVar(), getDarkColor(), getLightColor(), handleElementThemeColor() (+6 more)
 
 ### Community 29 - "Community 29"
+Cohesion: 0.14
+Nodes (8): useSettingsHandlers(), useSettingsPanel(), useSettingsState(), useCeremony(), useTheme(), themeAnimation(), toggleTheme(), toggleTransition()
+
+### Community 30 - "Community 30"
 Cohesion: 0.18
 Nodes (5): fetchServiceOrderTxnList(), handleReset(), handleSearch(), handleTabChange(), loadData()
 
-### Community 31 - "Community 31"
+### Community 32 - "Community 32"
 Cohesion: 0.17
 Nodes (3): fetchResearchDonationAuditList(), fetchResearchDonationDetail(), fetchResearchDonationList()
 
-### Community 32 - "Community 32"
-Cohesion: 0.18
-Nodes (3): fetchMaterialList(), fetchMaterialOptions(), fetchMaterialStockLogList()
-
 ### Community 33 - "Community 33"
-Cohesion: 0.2
-Nodes (2): fetchQcMaterialList(), fetchQcMaterialOptions()
-
-### Community 34 - "Community 34"
 Cohesion: 0.28
 Nodes (1): FireworkSystem
 
-### Community 36 - "Community 36"
+### Community 35 - "Community 35"
 Cohesion: 0.39
 Nodes (6): isIgnorableScriptError(), normalizeErrorMessage(), registerPromiseErrorHandler(), registerResourceErrorHandler(), scriptErrorHandler(), setupErrorHandle()
 
-### Community 37 - "Community 37"
+### Community 36 - "Community 36"
 Cohesion: 0.36
 Nodes (1): TableHeightCalculator
 
-### Community 38 - "Community 38"
+### Community 37 - "Community 37"
 Cohesion: 0.25
 Nodes (2): fetchQcTaskDetail(), fetchQcTaskList()
 
-### Community 39 - "Community 39"
+### Community 38 - "Community 38"
 Cohesion: 0.25
 Nodes (3): fetchOutboundQcDetail(), fetchQcWorkOrderDetail(), fetchQcWorkOrderList()
 
-### Community 40 - "Community 40"
+### Community 39 - "Community 39"
 Cohesion: 0.33
 Nodes (2): logApiCryptoBootInfo(), maskSecret()
 
+### Community 40 - "Community 40"
+Cohesion: 0.29
+Nodes (2): fetchLeaveDetail(), fetchLeaveList()
+
 ### Community 41 - "Community 41"
 Cohesion: 0.47
 Nodes (3): isPaymentDueWithinWarnWindow(), parsePaymentDueYmd(), startOfLocalDay()
@@ -258,9 +258,9 @@ Nodes (2): fetchQcThirdPartyItemList(), fetchQcThirdPartyItemsActive()
 Cohesion: 0.33
 Nodes (2): fetchQcThirdPartyCompanyList(), fetchQcThirdPartyCompanyOptions()
 
-### Community 47 - "Community 47"
-Cohesion: 0.33
-Nodes (2): fetchQcLabTestItemList(), fetchQcLabTestItemsActive()
+### Community 48 - "Community 48"
+Cohesion: 0.5
+Nodes (3): reload(), handleMenuJump(), openExternalLink()
 
 ### Community 49 - "Community 49"
 Cohesion: 0.5
@@ -287,19 +287,17 @@ Cohesion: 1.0
 Nodes (2): defaultAvatarPathByRole(), resolveUserAvatarUrl()
 
 ## Knowledge Gaps
-- **Thin community `Community 11`** (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 27`** (17 nodes): `ComponentLoader`, `.constructor()`, `.createEmptyComponent()`, `.createErrorComponent()`, `.load()`, `.loadIframe()`, `.loadLayout()`, `.load()`, `RouteTransformer`, `.extractFirstSegment()`, `.handleFirstLevelRoute()`, `.handleIframeRoute()`, `.handleNormalRoute()`, `.isFirstLevelRoute()`, `.transform()`, `ComponentLoader.ts`, `RouteTransformer.ts`
   Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 33`** (10 nodes): `fetchBatchStockInQcMaterial()`, `fetchBatchStockOutQcMaterial()`, `fetchCreateQcMaterial()`, `fetchDeleteQcMaterial()`, `fetchQcMaterialList()`, `fetchQcMaterialOptions()`, `fetchStockInQcMaterial()`, `fetchStockOutQcMaterial()`, `fetchUpdateQcMaterial()`, `qc-material.ts`
+- **Thin community `Community 33`** (9 nodes): `FireworkSystem`, `.constructor()`, `.createFirework()`, `.createParticle()`, `.getAvailableParticle()`, `.initializePool()`, `.preloadAllImages()`, `.preloadImage()`, `index.vue`
   Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 34`** (9 nodes): `FireworkSystem`, `.constructor()`, `.createFirework()`, `.createParticle()`, `.getAvailableParticle()`, `.initializePool()`, `.preloadAllImages()`, `.preloadImage()`, `index.vue`
+- **Thin community `Community 36`** (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 37`** (8 nodes): `TableHeightCalculator`, `.calculate()`, `.calculateOffset()`, `.calculatePaginationOffset()`, `.constructor()`, `.getHeaderHeight()`, `useTableHeight()`, `useTableHeight.ts`
+- **Thin community `Community 37`** (8 nodes): `fetchCompleteQcTask()`, `fetchCreateQcTask()`, `fetchDeleteQcTask()`, `fetchQcTaskDetail()`, `fetchQcTaskList()`, `fetchStartQcTask()`, `fetchUpdateQcTaskAttachments()`, `qc-task.ts`
   Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 38`** (8 nodes): `fetchCompleteQcTask()`, `fetchCreateQcTask()`, `fetchDeleteQcTask()`, `fetchQcTaskDetail()`, `fetchQcTaskList()`, `fetchStartQcTask()`, `fetchUpdateQcTaskAttachments()`, `qc-task.ts`
+- **Thin community `Community 39`** (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 40`** (7 nodes): `App.vue`, `main.ts`, `refreshButtonAutoIcons()`, `refreshPanelTitleIcons()`, `logApiCryptoBootInfo()`, `maskSecret()`, `console.ts`
+- **Thin community `Community 40`** (7 nodes): `fetchCreateLeave()`, `fetchDeleteLeave()`, `fetchLeaveDetail()`, `fetchLeaveList()`, `fetchSubmitLeave()`, `fetchUpdateLeave()`, `leave.ts`
   Too small to be a meaningful cluster - may be noise or needs more connections extracted.
 - **Thin community `Community 44`** (6 nodes): `fetchCreateSampleReceptionCheckItem()`, `fetchDeleteSampleReceptionCheckItem()`, `fetchSampleReceptionCheckItemList()`, `fetchSampleReceptionCheckItemsActive()`, `fetchUpdateSampleReceptionCheckItem()`, `sample-reception-check-item.ts`
   Too small to be a meaningful cluster - may be noise or needs more connections extracted.
@@ -307,8 +305,6 @@ Nodes (2): defaultAvatarPathByRole(), resolveUserAvatarUrl()
   Too small to be a meaningful cluster - may be noise or needs more connections extracted.
 - **Thin community `Community 46`** (6 nodes): `fetchCreateQcThirdPartyCompany()`, `fetchDeleteQcThirdPartyCompany()`, `fetchQcThirdPartyCompanyList()`, `fetchQcThirdPartyCompanyOptions()`, `fetchUpdateQcThirdPartyCompany()`, `qc-third-party-company.ts`
   Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 47`** (6 nodes): `fetchCreateQcLabTestItem()`, `fetchDeleteQcLabTestItem()`, `fetchQcLabTestItemList()`, `fetchQcLabTestItemsActive()`, `fetchUpdateQcLabTestItem()`, `qc-lab-test-item.ts`
-  Too small to be a meaningful cluster - may be noise or needs more connections extracted.
 - **Thin community `Community 49`** (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 50`** (4 nodes): `if()`, `logSidebarMenu()`, `index.vue`, `SidebarSubmenu.vue`
@@ -325,12 +321,10 @@ Nodes (2): defaultAvatarPathByRole(), resolveUserAvatarUrl()
 ## 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 7`, `Community 9`, `Community 10`, `Community 12`, `Community 14`, `Community 16`, `Community 17`, `Community 18`, `Community 19`, `Community 21`, `Community 22`, `Community 23`, `Community 24`, `Community 26`, `Community 29`, `Community 31`, `Community 32`, `Community 33`, `Community 38`, `Community 39`, `Community 44`, `Community 45`, `Community 46`, `Community 47`, `Community 51`, `Community 52`?**
-  _High betweenness centrality (0.265) - this node is a cross-community bridge._
-- **Why does `push()` connect `Community 1` to `Community 0`, `Community 34`, `Community 4`, `Community 5`, `Community 6`, `Community 8`, `Community 9`, `Community 10`, `Community 11`, `Community 15`, `Community 16`, `Community 22`?**
-  _High betweenness centrality (0.114) - this node is a cross-community bridge._
-- **Why does `handleDynamicRoutes()` connect `Community 2` to `Community 17`?**
-  _High betweenness centrality (0.042) - this node is a cross-community bridge._
+- **Why does `get()` connect `Community 0` to `Community 1`, `Community 2`, `Community 3`, `Community 4`, `Community 8`, `Community 10`, `Community 11`, `Community 13`, `Community 14`, `Community 16`, `Community 17`, `Community 18`, `Community 20`, `Community 21`, `Community 22`, `Community 23`, `Community 24`, `Community 25`, `Community 30`, `Community 32`, `Community 37`, `Community 38`, `Community 40`, `Community 44`, `Community 45`, `Community 46`, `Community 51`, `Community 52`?**
+  _High betweenness centrality (0.269) - this node is a cross-community bridge._
+- **Why does `push()` connect `Community 1` to `Community 0`, `Community 33`, `Community 3`, `Community 5`, `Community 6`, `Community 7`, `Community 9`, `Community 10`, `Community 11`, `Community 15`, `Community 48`, `Community 18`, `Community 24`?**
+  _High betweenness centrality (0.122) - this node is a cross-community bridge._
 - **Are the 202 inferred relationships involving `get()` (e.g. with `collectLeafFacilityNodesInTreeOrder()` and `buildTreePathLabelFromFlat()`) actually correct?**
   _`get()` has 202 INFERRED edges - model-reasoned connections that need verification._
 - **Are the 35 inferred relationships involving `push()` (e.g. with `collectLeafFacilityNodesInTreeOrder()` and `fetchAllPagedRecords()`) actually correct?**
@@ -338,4 +332,6 @@ _Questions this graph is uniquely positioned to answer:_
 - **Are the 15 inferred relationships involving `emit()` (e.g. with `handleSubmit()` and `handleBlur()`) actually correct?**
   _`emit()` has 15 INFERRED edges - model-reasoned connections that need verification._
 - **Should `Community 0` be split into smaller, more focused modules?**
-  _Cohesion score 0.01 - nodes in this community are weakly interconnected._
+  _Cohesion score 0.01 - nodes in this community are weakly interconnected._
+- **Should `Community 1` be split into smaller, more focused modules?**
+  _Cohesion score 0.03 - nodes in this community are weakly interconnected._

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
web-admin/graphify-out/graph.html


+ 15 - 15
web-admin/graphify-out/manifest.json

@@ -17,7 +17,7 @@
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/types/common/index.ts": 1778582068.0254738,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/types/directive/directive.d.ts": 1778582068.026978,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/types/api/api.d.ts": 1778582068.0246184,
-  "/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts": 1779965311.460909,
+  "/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts": 1779968658.3992856,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/auto-imports.d.ts": 1779965275.9913518,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/types/store/index.ts": 1778582068.0293276,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/types/router/index.ts": 1778775532.895603,
@@ -47,7 +47,7 @@
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/status-tag-registry.ts": 1779826490.6921933,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/fetch-paged-list.ts": 1778775532.895782,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/sort-order.ts": 1779790341.2952042,
-  "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/outbound-qc-pilot-view-sections.ts": 1779801033.9457984,
+  "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/outbound-qc-pilot-view-sections.ts": 1779968915.1401246,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/tree-path.ts": 1779790341.776808,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/mask-sensitive.ts": 1778984825.4182227,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/production-labels.ts": 1779801619.5827582,
@@ -185,7 +185,7 @@
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/infusion-schedule-outbound-chain-view/index.vue": 1779830492.0922873,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/work-order-remark-dialog/index.vue": 1779965478.2090704,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/clinical-schedule-payment-detail/index.vue": 1779944059.476768,
-  "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/outbound-material-form-sections/index.vue": 1779830388.1680186,
+  "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/outbound-material-form-sections/index.vue": 1779969249.1980019,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/protocol-payment-detail-readonly/index.vue": 1779885197.8109932,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/system-view-dialog/index.vue": 1779889640.2061684,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/production-task-view-dialog/index.vue": 1779790325.572335,
@@ -208,7 +208,7 @@
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/sample-reception-check-item.ts": 1779007909.2933023,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production.ts": 1779790323.3656075,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/infusion-schedule-handover.ts": 1779828287.9085703,
-  "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/outbound-release-review.ts": 1779940548.5759916,
+  "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/outbound-release-review.ts": 1779968240.1929023,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-third-party-item.ts": 1779017836.101254,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/storage-release-review.ts": 1779615813.3431153,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/workflow.ts": 1779790323.5709383,
@@ -310,16 +310,16 @@
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/sop/index.vue": 1779882001.8321233,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-task/index.vue": 1779925496.7869844,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/reagent/index.vue": 1779863928.5798419,
-  "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue": 1779965472.7313037,
+  "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue": 1779968582.0555966,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts": 1779790360.26504,
-  "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue": 1779790359.9189978,
+  "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue": 1779968053.649664,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/CompleteProductionTaskDialog.vue": 1779790359.5464847,
-  "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskInputEnhancedTable.vue": 1779927445.154478,
-  "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskExecutionDialog.vue": 1779925652.4510176,
+  "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskInputEnhancedTable.vue": 1779967895.2461958,
+  "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskExecutionDialog.vue": 1779968052.0510938,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/EditTaskInfoDialog.vue": 1779925648.9018784,
-  "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskOutputList.vue": 1779525781.6822913,
+  "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskOutputList.vue": 1779967896.0077794,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue": 1779925648.243228,
-  "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue": 1779949083.556124,
+  "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue": 1779967394.775425,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskOutputProductDialog.vue": 1779925660.055737,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/consumable-pack/index.vue": 1779863746.111673,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/consumable/index.vue": 1779863845.5777776,
@@ -330,8 +330,8 @@
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/process-category/OutputTypeTab.vue": 1779864078.964701,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/index/index.vue": 1779525781.6949234,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue": 1779965568.1579607,
-  "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue": 1779948870.746249,
-  "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue": 1779889633.846836,
+  "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue": 1779967264.0130916,
+  "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue": 1779968819.1387105,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/sample-reception-check-item/index.vue": 1779857055.2939715,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/lab-test-item/index.vue": 1779864504.1085482,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/lab-test-item/ThirdPartyCompanyTab.vue": 1779864511.579237,
@@ -367,15 +367,15 @@
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-refund-confirm/index.vue": 1779941952.780368,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/index.vue": 1779943711.951672,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-confirm/RefundConfirmTab.vue": 1779943344.5801125,
-  "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/outbound-release-review/index.vue": 1779940973.1366372,
+  "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/outbound-release-review/index.vue": 1779968249.318922,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/outbound-release-review/OutboundReleaseViewDialog.vue": 1779927107.3150873,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/outbound-release-review/OutboundReleaseReviewDialog.vue": 1779824973.037717,
-  "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/outbound-release-review/OutboundReleaseMaterialDialog.vue": 1779829323.2023485,
+  "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/outbound-release-review/OutboundReleaseMaterialDialog.vue": 1779969378.1624427,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/index.vue": 1779944723.8596022,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/ApplicationDetailDialog.vue": 1779841841.9942307,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/PilotApplicationTab.vue": 1779940944.365843,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/ApplicationViewDialog.vue": 1779944085.8337502,
-  "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/InfusionScheduleTab.vue": 1779940945.395297,
+  "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/InfusionScheduleTab.vue": 1779969771.7272167,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/ApplicationFormDialog.vue": 1779940036.5255854,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue": 1779940970.6155307,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/ClinicalPaymentTab.vue": 1779944565.962619,

+ 85 - 12
web-admin/src/components/business/infusion-schedule-outbound-chain-view/index.vue

@@ -102,24 +102,52 @@
                         v-for="(att, attIdx) in parsePaperAttachments(row.attachmentUrl)"
                         :key="attIdx"
                         class="paper-att-card"
+                        :class="{
+                          'paper-att-card--image': isImageFile(att),
+                          'paper-att-card--video': isVideoFile(att)
+                        }"
+                        :title="att.fileName"
                       >
-                        <el-icon class="paper-att-card__icon"><Document /></el-icon>
-                        <span class="paper-att-card__name" :title="att.fileName">{{
-                          att.fileName || '附件'
-                        }}</span>
+                        <div
+                          class="paper-att-card__preview"
+                          :class="{
+                            'is-clickable': isImageFile(att) || isVideoFile(att)
+                          }"
+                          @click="
+                            (isImageFile(att) || isVideoFile(att)) &&
+                              handlePreviewPaperAttachment(att)
+                          "
+                        >
+                          <img
+                            v-if="isImageFile(att)"
+                            :src="attachmentFullUrl(att.attachmentUrl)"
+                            :alt="att.fileName || '附件'"
+                          />
+                          <template v-else-if="isVideoFile(att)">
+                            <div class="paper-att-card__type-icon paper-att-card__type-icon--video">
+                              <el-icon><VideoPlay /></el-icon>
+                            </div>
+                          </template>
+                          <template v-else>
+                            <el-icon class="paper-att-card__type-icon paper-att-card__type-icon--doc">
+                              <Document />
+                            </el-icon>
+                            <span class="paper-att-card__name">{{ att.fileName || '附件' }}</span>
+                          </template>
+                        </div>
                         <div class="paper-att-card__actions">
                           <el-icon
-                            v-if="isImageFile(att)"
+                            v-if="isImageFile(att) || isVideoFile(att)"
                             class="paper-att-card__action"
                             title="预览"
-                            @click="handlePreviewPaperAttachment(att)"
+                            @click.stop="handlePreviewPaperAttachment(att)"
                           >
                             <View />
                           </el-icon>
                           <el-icon
                             class="paper-att-card__action"
                             title="下载"
-                            @click="handleDownloadPaperAttachment(att)"
+                            @click.stop="handleDownloadPaperAttachment(att)"
                           >
                             <Download />
                           </el-icon>
@@ -274,7 +302,7 @@
 
 <script setup lang="ts">
   import { ref, computed, watch } from 'vue'
-  import { Document, Download, View } from '@element-plus/icons-vue'
+  import { Document, Download, View, VideoPlay } from '@element-plus/icons-vue'
   import SampleProductionInfoCards from '@/components/business/sample-production-info-cards/index.vue'
   import SampleQcInfoCards from '@/components/business/sample-qc-info-cards/index.vue'
   import ProtocolAttachmentReadonly from '@/views/cell-storage/protocol/ProtocolAttachmentReadonly.vue'
@@ -621,17 +649,62 @@
     background: #f8fafc;
     display: flex;
     flex-direction: column;
+    align-items: stretch;
+    justify-content: center;
+    padding: 0;
+    position: relative;
+    overflow: hidden;
+  }
+
+  .paper-att-card__preview {
+    flex: 1;
+    min-height: 0;
+    display: flex;
+    flex-direction: column;
     align-items: center;
     justify-content: center;
     padding: 6px 4px;
-    position: relative;
     overflow: hidden;
+
+    &.is-clickable {
+      cursor: pointer;
+    }
+
+    img {
+      width: 100%;
+      height: 100%;
+      object-fit: cover;
+      display: block;
+    }
+  }
+
+  .paper-att-card--image,
+  .paper-att-card--video {
+    .paper-att-card__preview {
+      padding: 0;
+    }
   }
 
-  .paper-att-card__icon {
-    color: #0284c7;
-    font-size: 18px;
+  .paper-att-card__type-icon {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    font-size: 22px;
     margin-bottom: 2px;
+
+    &--doc {
+      color: #0284c7;
+    }
+
+    &--video {
+      width: 36px;
+      height: 36px;
+      border-radius: 8px;
+      background: #ede9fe;
+      color: #7c3aed;
+      font-size: 20px;
+      margin-bottom: 4px;
+    }
   }
 
   .paper-att-card__name {

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
web-admin/src/graphify-out/cache/ast/008da19a081990e9cb47a138582473f00757f8708a49fdea19d2bf61edce06c1.json


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
web-admin/src/graphify-out/cache/ast/07947182b781896a0c6f2eaba6b9a581b6c58211cd4bc7f051cfc0835e3b0477.json


+ 1 - 0
web-admin/src/graphify-out/cache/ast/553163c3d6c0eb66119486cd9a7faec3259b1c6863a3987d7b41f568d1a51bd9.json

@@ -0,0 +1 @@
+{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_pilot_application_infusionscheduletab_vue", "label": "InfusionScheduleTab.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/InfusionScheduleTab.vue", "source_location": "L1"}, {"id": "pilot_application_infusionscheduletab_if", "label": "if()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/InfusionScheduleTab.vue", "source_location": "L593"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_pilot_application_infusionscheduletab_vue", "target": "pilot_application_infusionscheduletab_if", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/InfusionScheduleTab.vue", "source_location": "L593", "weight": 1.0}], "raw_calls": []}

+ 1 - 0
web-admin/src/graphify-out/cache/ast/56dfd016d128919008dd543822ab13e121f3b315ddd65ee6912fc2bce675b2a7.json

@@ -0,0 +1 @@
+{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_outbound_release_review_outboundreleasematerialdialog_vue", "label": "OutboundReleaseMaterialDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/outbound-release-review/OutboundReleaseMaterialDialog.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
web-admin/src/graphify-out/cache/ast/769091ca90742d90a1abb189d267e3e0598a72fb25d7a6f1bf4598a7e99d00a0.json


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
web-admin/src/graphify-out/cache/ast/8129353ca9a980ab75044bd2aabcfb2dcf004caa922d962d344c27715fd1cedf.json


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
web-admin/src/graphify-out/cache/ast/91d28541185c74178c2271d2ed79ce2e648d3c621dcc05a39df96d51cb177189.json


+ 1 - 0
web-admin/src/graphify-out/cache/ast/98160063a757a09264a2dec6a94526b88ba4d25103e14f0017c0907fd14759ee.json

@@ -0,0 +1 @@
+{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_taskexecutiondialog_vue", "label": "TaskExecutionDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskExecutionDialog.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}

+ 1 - 0
web-admin/src/graphify-out/cache/ast/9d3361e40246556b8293d97e75fec122c665c46a37afbcb47e041d0803f43efa.json

@@ -0,0 +1 @@
+{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_components_business_outbound_material_form_sections_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/outbound-material-form-sections/index.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}

+ 1 - 0
web-admin/src/graphify-out/cache/ast/a7084b145c20c5aa04adb4efcc2f21fb887f12d73f1505c03d094052e1842bb6.json

@@ -0,0 +1 @@
+{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_outboundqcviewdialog_vue", "label": "OutboundQcViewDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}

+ 1 - 0
web-admin/src/graphify-out/cache/ast/acdff98786074d06cd82711e74e6d077c47760c9f05aa635aceba3593ef4c2e6.json

@@ -0,0 +1 @@
+{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_workordertasksublist_vue", "label": "WorkOrderTaskSubList.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}

+ 1 - 0
web-admin/src/graphify-out/cache/ast/bb8306ac7889608e1cfa71660396f34424cc7a8df22a1aaec65e0477f330def9.json

@@ -0,0 +1 @@
+{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_taskinputenhancedtable_vue", "label": "TaskInputEnhancedTable.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskInputEnhancedTable.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}

+ 1 - 0
web-admin/src/graphify-out/cache/ast/ebae3bc304c2e95e3aea0bf352e12be8e7df262202f4a287db5d0ca84609c334.json

@@ -0,0 +1 @@
+{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_taskoutputlist_vue", "label": "TaskOutputList.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskOutputList.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
web-admin/src/graphify-out/cache/ast/fc8644feb3dfadd734b5edffbeccf60c11775995453f5bebddff05b721fcbfd2.json


+ 85 - 12
web-admin/src/views/pilot-service/infusion-schedule-management/ScheduleViewDialog.vue

@@ -105,24 +105,52 @@
                       v-for="(att, attIdx) in parsePaperAttachments(row.attachmentUrl)"
                       :key="attIdx"
                       class="paper-att-card"
+                      :class="{
+                        'paper-att-card--image': isImageFile(att),
+                        'paper-att-card--video': isVideoFile(att)
+                      }"
+                      :title="att.fileName"
                     >
-                      <el-icon class="paper-att-card__icon"><Document /></el-icon>
-                      <span class="paper-att-card__name" :title="att.fileName">{{
-                        att.fileName || '附件'
-                      }}</span>
+                      <div
+                        class="paper-att-card__preview"
+                        :class="{
+                          'is-clickable': isImageFile(att) || isVideoFile(att)
+                        }"
+                        @click="
+                          (isImageFile(att) || isVideoFile(att)) &&
+                            handlePreviewPaperAttachment(att)
+                        "
+                      >
+                        <img
+                          v-if="isImageFile(att)"
+                          :src="attachmentFullUrl(att.attachmentUrl)"
+                          :alt="att.fileName || '附件'"
+                        />
+                        <template v-else-if="isVideoFile(att)">
+                          <div class="paper-att-card__type-icon paper-att-card__type-icon--video">
+                            <el-icon><VideoPlay /></el-icon>
+                          </div>
+                        </template>
+                        <template v-else>
+                          <el-icon class="paper-att-card__type-icon paper-att-card__type-icon--doc">
+                            <Document />
+                          </el-icon>
+                          <span class="paper-att-card__name">{{ att.fileName || '附件' }}</span>
+                        </template>
+                      </div>
                       <div class="paper-att-card__actions">
                         <el-icon
-                          v-if="isImageFile(att)"
+                          v-if="isImageFile(att) || isVideoFile(att)"
                           class="paper-att-card__action"
                           title="预览"
-                          @click="handlePreviewPaperAttachment(att)"
+                          @click.stop="handlePreviewPaperAttachment(att)"
                         >
                           <View />
                         </el-icon>
                         <el-icon
                           class="paper-att-card__action"
                           title="下载"
-                          @click="handleDownloadPaperAttachment(att)"
+                          @click.stop="handleDownloadPaperAttachment(att)"
                         >
                           <Download />
                         </el-icon>
@@ -192,7 +220,7 @@
 
 <script setup lang="ts">
   import { ref, computed, watch } from 'vue'
-  import { Document, Download, View } from '@element-plus/icons-vue'
+  import { Document, Download, View, VideoPlay } from '@element-plus/icons-vue'
   import SystemViewDialog, {
     type ViewSection,
     type TagType
@@ -746,17 +774,62 @@
     background: #f8fafc;
     display: flex;
     flex-direction: column;
+    align-items: stretch;
+    justify-content: center;
+    padding: 0;
+    position: relative;
+    overflow: hidden;
+  }
+
+  .paper-att-card__preview {
+    flex: 1;
+    min-height: 0;
+    display: flex;
+    flex-direction: column;
     align-items: center;
     justify-content: center;
     padding: 6px 4px;
-    position: relative;
     overflow: hidden;
+
+    &.is-clickable {
+      cursor: pointer;
+    }
+
+    img {
+      width: 100%;
+      height: 100%;
+      object-fit: cover;
+      display: block;
+    }
+  }
+
+  .paper-att-card--image,
+  .paper-att-card--video {
+    .paper-att-card__preview {
+      padding: 0;
+    }
   }
 
-  .paper-att-card__icon {
-    color: #0284c7;
-    font-size: 18px;
+  .paper-att-card__type-icon {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    font-size: 22px;
     margin-bottom: 2px;
+
+    &--doc {
+      color: #0284c7;
+    }
+
+    &--video {
+      width: 36px;
+      height: 36px;
+      border-radius: 8px;
+      background: #ede9fe;
+      color: #7c3aed;
+      font-size: 20px;
+      margin-bottom: 4px;
+    }
   }
 
   .paper-att-card__name {

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است