This commit is contained in:
zlwu committed 2026-07-05 14:01:19 +08:00
1 parent 54b27a3f0e
commit 31be9bfd95
41 files changed
+8981 -5121

No files matched your search

+1 -1
View File
@@ -1 +1 @@
25852
47422
+37 -2
View File
@@ -33,6 +33,7 @@ from app.schemas.pl.plan import (
PlanCreate,
PlanCreateFull,
HazardCertReadyBody,
PlanInboundSlipTemplateSave,
PlanListQuery,
PlanListResponse,
PlanProductCertsUpdate,
@@ -72,9 +73,9 @@ _PLAN_NO_SEQ_WIDTH = 3
def _generate_plan_no(db: Session) -> str:
"""生成计划编号 SXDDHYYYYMMDD###(当日 3 位序号,每日重置)"""
"""生成计划编号 POYYYYMMDD###(当日 3 位序号,每日重置)"""
today = date.today()
prefix = f"SXDDH{today.strftime('%Y%m%d')}"
prefix = f"PO{today.strftime('%Y%m%d')}"
# uk_plan_no 对全表生效(含软删),取号时不能过滤 del_flag
rows = (
@@ -1022,6 +1023,40 @@ def archive_plan(
return get_plan(id, db, user)
# =============================================================================
# 入库单打印模板
# =============================================================================
@router.get("/{id}/inbound-slip-template")
def get_inbound_slip_template(
id: str,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> str:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
plan = _get_plan(db, tenant_no, id, user)
return plan.slip_template_content or ""
@router.put("/{id}/inbound-slip-template", status_code=status.HTTP_204_NO_CONTENT)
def save_inbound_slip_template(
id: str,
payload: PlanInboundSlipTemplateSave,
db: Session = Depends(get_db),
user: DbUserContext = Depends(get_db_current_user),
) -> None:
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
plan = _get_plan(db, tenant_no, id, user)
if plan.plan_type != "inbound":
raise HTTPException(status_code=400, detail="仅入库单计划支持保存入库单打印模板")
if plan.transport_status != "arranged":
raise HTTPException(status_code=400, detail="请先完成运输安排后再保存入库单打印模板")
plan.slip_template_content = payload.slip_template_content or ""
plan.update_by = user.id
db.commit()
# =============================================================================
# 删除计划
# =============================================================================
+2 -1
View File
@@ -232,7 +232,7 @@ class PlPlan(Base):
id = Column(String(64), primary_key=True, comment="主键ID")
# 编号信息
plan_no = Column(String(32), nullable=False, unique=True, comment="计划订单编号 SXDDHYYYYMMDD###")
plan_no = Column(String(32), nullable=False, unique=True, comment="计划订单编号 POYYYYMMDD###")
plan_date = Column(Date, nullable=False, comment="计划日期")
# 基本信息
@@ -297,6 +297,7 @@ class PlPlan(Base):
# 通知信息
notify_message = Column(Text, nullable=True, comment="通知信息(标准模板)")
slip_template_content = Column(Text, nullable=True, comment="入库单打印模板内容(富文本HTML)")
# 跟进人
follow_user_id = Column(String(64), nullable=True, comment="跟进人ID")
+5
View File
@@ -217,6 +217,11 @@ class PlanWithProducts(PlanRead):
products: list[PlanProductRead] = []
class PlanInboundSlipTemplateSave(BaseModel):
slip_template_content: str = Field(..., alias="slipTemplateContent", description="入库单打印模板HTML")
model_config = {"populate_by_name": True}
# =============================================================================
# 从合同创建计划
# =============================================================================
@@ -122,7 +122,6 @@
"120": "Community 120",
"121": "Community 121",
"122": "Community 122",
"123": "Community 123",
"124": "Community 124",
"125": "Community 125",
"126": "Community 126",
@@ -136,11 +135,9 @@
"134": "Community 134",
"135": "Community 135",
"136": "Community 136",
"137": "Community 137",
"138": "Community 138",
"139": "Community 139",
"140": "Community 140",
"141": "Community 141",
"142": "Community 142",
"143": "Community 143",
"144": "Community 144",
@@ -151,7 +148,6 @@
"149": "Community 149",
"150": "Community 150",
"151": "Community 151",
"152": "Community 152",
"153": "Community 153",
"154": "Community 154",
"155": "Community 155",
+19 -39
View File
@@ -5,12 +5,12 @@
- Verdict: corpus is large enough that graph structure adds value.
## Summary
- 5150 nodes · 35327 edges · 164 communities (162 shown, 2 thin omitted)
- 5150 nodes · 35327 edges · 160 communities (158 shown, 2 thin omitted)
- Extraction: 51% EXTRACTED · 49% INFERRED · 0% AMBIGUOUS · INFERRED: 17344 edges (avg confidence: 0.5)
- Token cost: 0 input · 0 output
## Graph Freshness
- Built from commit: `33c038b8`
- Built from commit: `54b27a3f`
- Run `git rev-parse HEAD` and compare to check if the graph is stale.
- Run `graphify update .` after code changes (no API cost).
@@ -129,7 +129,6 @@
- [[_COMMUNITY_Community 111|Community 111]]
- [[_COMMUNITY_Community 112|Community 112]]
- [[_COMMUNITY_Community 122|Community 122]]
- [[_COMMUNITY_Community 123|Community 123]]
- [[_COMMUNITY_Community 124|Community 124]]
- [[_COMMUNITY_Community 125|Community 125]]
- [[_COMMUNITY_Community 126|Community 126]]
@@ -143,11 +142,9 @@
- [[_COMMUNITY_Community 134|Community 134]]
- [[_COMMUNITY_Community 135|Community 135]]
- [[_COMMUNITY_Community 136|Community 136]]
- [[_COMMUNITY_Community 137|Community 137]]
- [[_COMMUNITY_Community 138|Community 138]]
- [[_COMMUNITY_Community 139|Community 139]]
- [[_COMMUNITY_Community 140|Community 140]]
- [[_COMMUNITY_Community 141|Community 141]]
- [[_COMMUNITY_Community 143|Community 143]]
- [[_COMMUNITY_Community 144|Community 144]]
- [[_COMMUNITY_Community 145|Community 145]]
@@ -157,7 +154,6 @@
- [[_COMMUNITY_Community 149|Community 149]]
- [[_COMMUNITY_Community 150|Community 150]]
- [[_COMMUNITY_Community 151|Community 151]]
- [[_COMMUNITY_Community 152|Community 152]]
- [[_COMMUNITY_Community 153|Community 153]]
- [[_COMMUNITY_Community 154|Community 154]]
- [[_COMMUNITY_Community 155|Community 155]]
@@ -194,7 +190,7 @@
- `int` --uses--> `LocalStorage` [INFERRED]
scripts/run_db_auto_generate_plans.py → app/core/storage.py
## Communities (164 total, 2 thin omitted)
## Communities (160 total, 2 thin omitted)
### Community 0 - "Community 0"
Cohesion: 0.14
@@ -285,8 +281,8 @@ Cohesion: 0.07
Nodes (61): CertRead, date, int, Session, str, CertRead, Session, str (+53 more)
### Community 22 - "Community 22"
Cohesion: 0.22
Nodes (36): Any, Session, str, PlFreightSettlement, PlFreightSettlementApproval, _advance_after_approval(), _approval_to_dict(), can_user_approve_settlement() (+28 more)
Cohesion: 0.17
Nodes (45): Any, Decimal, Session, str, PlFreightSettlement, _advance_after_approval(), _approval_to_dict(), can_user_approve_settlement() (+37 more)
### Community 23 - "Community 23"
Cohesion: 0.23
@@ -337,8 +333,8 @@ Cohesion: 0.22
Nodes (29): Engine, Path, build_id_maps(), clip_text(), count_rows(), export_mapping(), fetch_rows(), legacy_id_to_str() (+21 more)
### Community 35 - "Community 35"
Cohesion: 0.05
Nodes (47): FreightSettlementDisburseBody, FreightSettlementSubmitApprovalBody, FreightSettlementUpdate, int, PlPlan, PlFreightSettlementApproval, PlFreightSettlementTransport, PlRemittanceVoucher (+39 more)
Cohesion: 0.04
Nodes (67): datetime, FreightSettlementDisburseBody, FreightSettlementSubmitApprovalBody, FreightSettlementUpdate, int, PlPlan, PlTransport, PlFreightSettlement (+59 more)
### Community 36 - "Community 36"
Cohesion: 0.19
@@ -397,8 +393,8 @@ Cohesion: 0.31
Nodes (20): Any, bool, CrmOpportunity, datetime, int, Session, str, create_opportunity_follow() (+12 more)
### Community 50 - "Community 50"
Cohesion: 0.08
Nodes (25): bool, _clear_settlement_approval_records(), 软删除结算单历史审批记录(重新提交审批前清理), 软删除结算单历史审批记录(重新提交审批前清理), 软删除结算单历史审批记录(重新提交审批前清理), 草稿结算单按当前运输单运费刷新明细快照与合计。, 草稿结算单按当前运输单运费刷新明细快照与合计。, 草稿/已驳回结算单按当前运输单运费刷新明细快照与合计。 (+17 more)
Cohesion: 0.17
Nodes (12): _clear_settlement_approval_records(), 软删除结算单历史审批记录(重新提交审批前清理), 软删除结算单历史审批记录(重新提交审批前清理), 软删除结算单历史审批记录(重新提交审批前清理), 草稿结算单按当前运输单运费刷新明细快照与合计。, 草稿结算单按当前运输单运费刷新明细快照与合计。, 软删除结算单历史审批记录(重新提交审批前清理), 软删除结算单历史审批记录(重新提交审批前清理) (+4 more)
### Community 51 - "Community 51"
Cohesion: 0.07
@@ -449,8 +445,8 @@ Cohesion: 0.08
Nodes (76): bool, DbInboundOutbound, int, PublicInventoryFeedback, PublicInventoryPageRead, Session, str, UploadFile (+68 more)
### Community 63 - "Community 63"
Cohesion: 0.24
Nodes (12): Session, str, iter_user_menu_perm_codes(), _map_role_name_to_web(), Web 管理端登录:基于 V0.3 sys_user / sys_user_role / sys_role 的角色与菜单权限解析, 将 sys_role.role_name 映射为 web-admin 使用的 role 字符串。, 根据用户关联角色解析 Web 端 role(admin / super_admin)。, 根据用户关联角色解析 Web 端 role(admin / super_admin)。 (+4 more)
Cohesion: 0.14
Nodes (19): Session, str, Session, str, get_user_menu_codes(), 菜单 code 权限守卫(V0.3:通过 sys_user_role → sys_role_menu → sys_menu.perms), 读取用户授权的菜单权限标识集合(与前端 meta.menuCode / perms 对齐)。, 接口菜单权限守卫。super_admin 直接放行。 (+11 more)
### Community 64 - "Community 64"
Cohesion: 0.11
@@ -518,7 +514,7 @@ Nodes (10): add_scope_before_order(), ensure_import(), patch_base_data(), patch_
### Community 80 - "Community 80"
Cohesion: 0.10
Nodes (17): get_menu_list(), 运营端菜单接口(与 web-admin 前端静态路由 sqxp.ts 对齐,14 个一级菜单), Session, str, _auto_fill_create_dept_id(), get_db(), ORM before_insert 钩子:当 create_dept_id 为空时,自动从请求上下文填充当前用户部门 ID, ORM before_insert 钩子:当 create_dept_id 为空时,自动从请求上下文填充当前用户部门 ID (+9 more)
Nodes (17): get_menu_list(), 运营端菜单接口(与 web-admin 前端静态路由 sqxp.ts 对齐,14 个一级菜单), Any, Session, str, _auto_fill_create_dept_id(), get_db(), ORM before_insert 钩子:当 create_dept_id 为空时,自动从请求上下文填充当前用户部门 ID (+9 more)
### Community 81 - "Community 81"
Cohesion: 0.40
@@ -610,7 +606,7 @@ Nodes (142): bool, VehicleCreate, VehicleUpdate, bool, DbUserContext, float, int
### Community 104 - "Community 104"
Cohesion: 0.13
Nodes (42): 公共接口(Web 登录、刷新 Token、登出;用户模型对齐 docs/sql/shanxia2.0.sql 基线), refresh_token(), bool, Redis, Request, Session, str, _T (+34 more)
Nodes (42): 公共接口(Web 登录、刷新 Token、登出;用户模型对齐 docs/sql/shanxia2.0.sql 基线), refresh_token(), bool, Redis, Request, str, _T, bool (+34 more)
### Community 105 - "Community 105"
Cohesion: 0.50
@@ -644,10 +640,6 @@ Nodes (30): BxUserContext, int, Session, str, approve_reimburse(), approved_by_m
Cohesion: 0.12
Nodes (17): create_new_version(), Java: toContract — 返回 contractId, Java: createNewVersion — 返回新报价单 id, Java: toContract — 返回 contractId, Java: createNewVersion — 返回新报价单 id, Java: toContract — 返回 contractId, Java: createNewVersion — 返回新报价单 id, Java: createNewVersion — 返回新报价单 id (+9 more)
### Community 123 - "Community 123"
Cohesion: 0.12
Nodes (17): PlFreightSettlement, 运费结算表 pl_freight_settlement, 计划-运输关联表 pl_plan_transport, 运输计划现场链接 pl_transport_site_link(与地磅出入库单解耦), 运输计划现场链接 pl_transport_site_link(与地磅出入库单解耦), 运费结算表 pl_freight_settlement, 计划-运输关联表 pl_plan_transport, 运费结算表 pl_freight_settlement (+9 more)
### Community 124 - "Community 124"
Cohesion: 0.38
Nodes (15): Any, bool, int, Session, str, create_post(), get_post(), list_posts() (+7 more)
@@ -669,8 +661,8 @@ Cohesion: 0.33
Nodes (14): Any, int, Session, str, create_dict_data(), get_dict_data(), list_dict_data(), list_dict_data_options() (+6 more)
### Community 129 - "Community 129"
Cohesion: 0.15
Nodes (14): get_current_user_profile(), get_web_auth_menu_codes(), logout(), 登出:吊销 Redis 会话(若已配置 REDIS_HOST)。, 登出:吊销 Redis 会话(若已配置 REDIS_HOST)。, 登出:吊销 Redis 会话(若已配置 REDIS_HOST)。, 获取当前用户信息(与 sys_user 字段对应)。, 获取当前用户信息(与 sys_user 字段对应)。 (+6 more)
Cohesion: 0.11
Nodes (21): get_current_user_profile(), get_web_auth_menu_codes(), logout(), 登出:吊销 Redis 会话(若已配置 REDIS_HOST)。, 登出:吊销 Redis 会话(若已配置 REDIS_HOST)。, 登出:吊销 Redis 会话(若已配置 REDIS_HOST)。, 获取当前用户信息(与 sys_user 字段对应)。, 获取当前用户信息(与 sys_user 字段对应)。 (+13 more)
### Community 130 - "Community 130"
Cohesion: 0.15
@@ -689,8 +681,8 @@ Cohesion: 0.44
Nodes (8): bool, int, Session, str, ApiRequestLogCRUD, SysApiRequestLog, SysApiRequestLogHis, SysApiRequestLog
### Community 134 - "Community 134"
Cohesion: 0.17
Nodes (12): 审批记录已全部完成但结算单仍停留在 approving 时自动纠正(兼容历史脏数据), 审批记录已全部完成但结算单仍停留在 approving 时自动纠正(兼容历史脏数据), 审批记录已全部完成但结算单仍停留在 approving 时自动纠正(兼容历史脏数据), 审批记录已全部完成但结算单仍停留在 approving 时自动纠正(兼容历史脏数据), 审批记录已全部完成但结算单仍停留在 approving 时自动纠正(兼容历史脏数据), 审批记录已全部完成但结算单仍停留在 approving 时自动纠正(兼容历史脏数据), 审批记录已全部完成但结算单仍停留在 approving 时自动纠正(兼容历史脏数据), 审批记录已全部完成但结算单仍停留在 approving 时自动纠正(兼容历史脏数据) (+4 more)
Cohesion: 0.09
Nodes (23): bool, 审批记录已全部完成但结算单仍停留在 approving 时自动纠正(兼容历史脏数据), 审批记录已全部完成但结算单仍停留在 approving 时自动纠正(兼容历史脏数据), 审批记录已全部完成但结算单仍停留在 approving 时自动纠正(兼容历史脏数据), 已有汇款凭证但结算单仍停留在 approved 时自动纠正(兼容历史脏数据), 审批记录已全部完成但结算单仍停留在 approving 时自动纠正(兼容历史脏数据), 审批记录已全部完成但结算单仍停留在 approving 时自动纠正(兼容历史脏数据), 已有汇款凭证但结算单仍停留在 approved 时自动纠正(兼容历史脏数据) (+15 more)
### Community 135 - "Community 135"
Cohesion: 0.25
@@ -700,10 +692,6 @@ Nodes (7): 1. 上传到服务器, 2. 服务器首次启动, 3. 日常运维, 4.
Cohesion: 0.18
Nodes (11): Java: statisticsStatus, Java: statisticsStatus, Java: statisticsStatus, Java: statisticsStatus, Java: statisticsStatus, Java: statisticsStatus, Java: statisticsStatus, Java: statisticsStatus (+3 more)
### Community 137 - "Community 137"
Cohesion: 0.24
Nodes (10): datetime, Decimal, PlTransport, 运输单运费变更后,同步关联草稿结算单的明细快照与合计。, 运输单运费变更后,同步关联草稿结算单的明细快照与合计。, 运输单运费变更后,同步关联草稿结算单的明细快照与合计。, 运输单运费变更后,同步关联草稿结算单的明细快照与合计。, _recalc_settlement_total_freight_from_links() (+2 more)
### Community 138 - "Community 138"
Cohesion: 0.39
Nodes (6): _inject_user_info_after_tenant(), patch_contract_routes(), patch_quote_routes(), patch_route_file(), Path, str
@@ -716,10 +704,6 @@ Nodes (10): 批量纠正已有汇款凭证但仍为 approved 的结算单, 批
Cohesion: 0.83
Nodes (3): _add_user_info_kwarg(), patch_file(), str
### Community 141 - "Community 141"
Cohesion: 0.25
Nodes (7): Any, Session, str, get_db_current_user_optional(), 与门户 JWT / apply_data_scope 所需的 user_info 字段对齐。, 有 Bearer 且为 admin/super_admin 时返回上下文,否则 None(供三方 H5 无登录调用)。, 有 Bearer 且为 admin/super_admin 时返回上下文,否则 None(供三方 H5 无登录调用)。
### Community 143 - "Community 143"
Cohesion: 0.32
Nodes (22): Any, CrmOpportunity, Decimal, int, Session, str, batch_add_opportunity_products(), _calc_subtotal() (+14 more)
@@ -756,10 +740,6 @@ Nodes (11): generate_contract_no(), Java: generateContractNo — {供方编码}/
Cohesion: 0.50
Nodes (4): datetime, object, parse_optional_plan_datetime(), 运输计划相关日期时间解析:前端 date-picker 仅传 YYYY-MM-DD。
### Community 152 - "Community 152"
Cohesion: 0.36
Nodes (7): bool, Redis, get_sync_redis_client(), 共享 Redis 客户端(同步:会话鉴权;异步:API 加密 nonce)。, 同步 Redis(auth 会话等,在线程池中调用)。, _redis_common_kwargs(), redis_enabled()
### Community 153 - "Community 153"
Cohesion: 0.15
Nodes (16): _avatar_url_field(), _build_user_info_payload(), _jwt_user_payload(), 与 web-admin `userInfo` 字段约定一致。, 与 web-admin `userInfo` 字段约定一致。, Web 端登录:账号为 sys_user.user_no,密码为 sys_user.password(bcrypt)。, Web 端登录:账号为 sys_user.user_no,密码为 sys_user.password(bcrypt)。, Web 端登录:账号为 sys_user.user_no,密码为 sys_user.password(bcrypt)。 (+8 more)
@@ -812,11 +792,11 @@ Nodes (3): public_quote_share(), 公开分享查看报价单 — Java: GET /shar
## Suggested Questions
_Questions this graph is uniquely positioned to answer:_
- **Why does `Session` connect `Community 3` to `Community 0`, `Community 1`, `Community 2`, `Community 4`, `Community 6`, `Community 8`, `Community 9`, `Community 10`, `Community 11`, `Community 14`, `Community 15`, `Community 16`, `Community 17`, `Community 18`, `Community 19`, `Community 20`, `Community 23`, `Community 25`, `Community 27`, `Community 28`, `Community 30`, `Community 31`, `Community 32`, `Community 33`, `Community 35`, `Community 36`, `Community 37`, `Community 39`, `Community 40`, `Community 41`, `Community 44`, `Community 45`, `Community 46`, `Community 47`, `Community 49`, `Community 51`, `Community 52`, `Community 54`, `Community 55`, `Community 56`, `Community 57`, `Community 59`, `Community 61`, `Community 63`, `Community 64`, `Community 65`, `Community 67`, `Community 68`, `Community 69`, `Community 71`, `Community 73`, `Community 74`, `Community 75`, `Community 77`, `Community 78`, `Community 80`, `Community 84`, `Community 85`, `Community 87`, `Community 92`, `Community 93`, `Community 96`, `Community 97`, `Community 98`, `Community 99`, `Community 102`, `Community 103`, `Community 104`, `Community 106`, `Community 108`, `Community 109`, `Community 112`, `Community 122`, `Community 123`, `Community 124`, `Community 125`, `Community 126`, `Community 127`, `Community 128`, `Community 129`, `Community 130`, `Community 131`, `Community 133`, `Community 136`, `Community 141`, `Community 143`, `Community 146`, `Community 147`, `Community 149`, `Community 150`, `Community 153`, `Community 154`, `Community 155`, `Community 157`, `Community 159`, `Community 163`?**
- **Why does `Session` connect `Community 3` to `Community 0`, `Community 1`, `Community 2`, `Community 4`, `Community 6`, `Community 8`, `Community 9`, `Community 10`, `Community 11`, `Community 14`, `Community 15`, `Community 16`, `Community 17`, `Community 18`, `Community 19`, `Community 20`, `Community 23`, `Community 25`, `Community 27`, `Community 28`, `Community 30`, `Community 31`, `Community 32`, `Community 33`, `Community 35`, `Community 36`, `Community 37`, `Community 39`, `Community 40`, `Community 41`, `Community 44`, `Community 45`, `Community 46`, `Community 47`, `Community 49`, `Community 51`, `Community 52`, `Community 54`, `Community 55`, `Community 56`, `Community 57`, `Community 59`, `Community 61`, `Community 63`, `Community 64`, `Community 65`, `Community 67`, `Community 68`, `Community 69`, `Community 71`, `Community 73`, `Community 74`, `Community 75`, `Community 77`, `Community 78`, `Community 80`, `Community 84`, `Community 85`, `Community 87`, `Community 92`, `Community 93`, `Community 96`, `Community 97`, `Community 98`, `Community 99`, `Community 102`, `Community 103`, `Community 104`, `Community 106`, `Community 108`, `Community 109`, `Community 112`, `Community 122`, `Community 124`, `Community 125`, `Community 126`, `Community 127`, `Community 128`, `Community 129`, `Community 130`, `Community 131`, `Community 133`, `Community 136`, `Community 143`, `Community 146`, `Community 147`, `Community 149`, `Community 150`, `Community 153`, `Community 154`, `Community 155`, `Community 157`, `Community 159`, `Community 163`?**
_High betweenness centrality (0.233) - this node is a cross-community bridge._
- **Why does `BaseModel` connect `Community 100` to `Community 0`, `Community 1`, `Community 2`, `Community 132`, `Community 7`, `Community 8`, `Community 11`, `Community 12`, `Community 20`, `Community 21`, `Community 23`, `Community 24`, `Community 156`, `Community 29`, `Community 158`, `Community 30`, `Community 160`, `Community 32`, `Community 162`, `Community 44`, `Community 45`, `Community 48`, `Community 51`, `Community 60`, `Community 62`, `Community 66`, `Community 69`, `Community 71`, `Community 73`, `Community 75`, `Community 77`, `Community 81`, `Community 84`, `Community 86`, `Community 87`, `Community 103`, `Community 105`, `Community 107`, `Community 112`?**
_High betweenness centrality (0.073) - this node is a cross-community bridge._
- **Why does `SysUser` connect `Community 87` to `Community 129`, `Community 130`, `Community 3`, `Community 131`, `Community 2`, `Community 6`, `Community 5`, `Community 8`, `Community 137`, `Community 10`, `Community 11`, `Community 12`, `Community 13`, `Community 14`, `Community 16`, `Community 17`, `Community 19`, `Community 20`, `Community 22`, `Community 24`, `Community 153`, `Community 27`, `Community 31`, `Community 32`, `Community 33`, `Community 35`, `Community 36`, `Community 37`, `Community 39`, `Community 50`, `Community 52`, `Community 56`, `Community 64`, `Community 69`, `Community 73`, `Community 85`, `Community 103`, `Community 104`?**
- **Why does `SysUser` connect `Community 87` to `Community 129`, `Community 130`, `Community 3`, `Community 131`, `Community 2`, `Community 6`, `Community 134`, `Community 8`, `Community 5`, `Community 10`, `Community 11`, `Community 12`, `Community 13`, `Community 14`, `Community 16`, `Community 17`, `Community 19`, `Community 20`, `Community 22`, `Community 24`, `Community 153`, `Community 27`, `Community 31`, `Community 32`, `Community 33`, `Community 35`, `Community 36`, `Community 37`, `Community 39`, `Community 52`, `Community 56`, `Community 64`, `Community 69`, `Community 73`, `Community 85`, `Community 103`, `Community 104`?**
_High betweenness centrality (0.047) - this node is a cross-community bridge._
- **Are the 251 inferred relationships involving `str` (e.g. with `AdvanceApplyCreate` and `AdvanceApplyOut`) actually correct?**
_`str` has 251 INFERRED edges - model-reasoned connections that need verification._
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_pl_plan_py", "label": "plan.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L1"}, {"id": "pl_plan_generate_plan_no", "label": "_generate_plan_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L74"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L74"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L74"}, {"id": "pl_plan_determine_plan_type", "label": "_determine_plan_type()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L97"}, {"id": "pl_plan_get_plan_type_label", "label": "_get_plan_type_label()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L102"}, {"id": "pl_plan_generate_notify_message", "label": "_generate_notify_message()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L111"}, {"id": "plplan", "label": "PlPlan", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L111"}, {"id": "pl_plan_list_plans", "label": "list_plans()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L132"}, {"id": "date", "label": "date", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L132"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L132"}, {"id": "dbusercontext", "label": "DbUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L132"}, {"id": "planlistresponse", "label": "PlanListResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L132"}, {"id": "pl_plan_count_plans_by_contract", "label": "count_plans_by_contract()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L243"}, {"id": "pl_plan_create_plan", "label": "create_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L271"}, {"id": "plancreate", "label": "PlanCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L271"}, {"id": "planread", "label": "PlanRead", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L271"}, {"id": "pl_plan_create_plan_full", "label": "create_plan_full()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L354"}, {"id": "plancreatefull", "label": "PlanCreateFull", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L354"}, {"id": "planwithproducts", "label": "PlanWithProducts", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L354"}, {"id": "pl_plan_create_from_contract", "label": "create_from_contract()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L460"}, {"id": "createfromcontractrequest", "label": "CreateFromContractRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L460"}, {"id": "pl_plan_get_plan", "label": "get_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L567"}, {"id": "pl_plan_update_plan", "label": "update_plan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L614"}, {"id": "planupdate", "label": "PlanUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L614"}, {"id": "pl_plan_patch_plan_product_certs", "label": "patch_plan_product_certs()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py", "source_location": "L729"}, {"id": "planproductcertsupdate", "label": "PlanProductCertsUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/apiLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_models_pl_models_py", "label": "pl_models.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L1"}, {"id": "models_pl_models_plcarrier", "label": "PlCarrier", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L28"}, {"id": "base", "label": "Base", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "models_pl_models_plvehicle", "label": "PlVehicle", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L57"}, {"id": "models_pl_models_plpersonnel", "label": "PlPersonnel", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L83"}, {"id": "models_pl_models_pltransportaddress", "label": "PlTransportAddress", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L105"}, {"id": "models_pl_models_plcert", "label": "PlCert", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L129"}, {"id": "models_pl_models_pldriver", "label": "PlDriver", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L155"}, {"id": "models_pl_models_plvehiclepersonnel", "label": "PlVehiclePersonnel", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L181"}, {"id": "models_pl_models_plvehicledriver", "label": "PlVehicleDriver", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L202"}, {"id": "models_pl_models_plplan", "label": "PlPlan", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L227"}, {"id": "models_pl_models_plplanproduct", "label": "PlPlanProduct", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L322"}, {"id": "models_pl_models_plplanchange", "label": "PlPlanChange", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L377"}, {"id": "models_pl_models_pltransport", "label": "PlTransport", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L404"}, {"id": "models_pl_models_pltransportdblink", "label": "PlTransportDbLink", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L466"}, {"id": "models_pl_models_plplantransport", "label": "PlPlanTransport", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L488"}, {"id": "models_pl_models_pltransportsitelink", "label": "PlTransportSiteLink", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L507"}, {"id": "models_pl_models_pltransportapproval", "label": "PlTransportApproval", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L540"}, {"id": "models_pl_models_plfreightsettlement", "label": "PlFreightSettlement", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L569"}, {"id": "models_pl_models_plfreightsettlementapproval", "label": "PlFreightSettlementApproval", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L601"}, {"id": "models_pl_models_plfreightsettlementtransport", "label": "PlFreightSettlementTransport", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L628"}, {"id": "models_pl_models_plremittancevoucher", "label": "PlRemittanceVoucher", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L648"}, {"id": "models_pl_models_plinventory", "label": "PlInventory", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L675"}, {"id": "models_pl_models_plinventorytransaction", "label": "PlInventoryTransaction", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py", "source_location": "L707"}, {"id": "models_pl_models_plinventorywarning", "label": "PlInventoryWarning", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0Line truncated
+1 -1
View File
@@ -1 +1 @@
{"/Users/zlwu/work/00code/shanxia2.0/backend/start-prod.sh":{"size":7357,"mtime_ns":1782639355476060453,"hash":"ca89869446be74a2bf2367b3b28f448580220859a39a84ad9613ac5fe35a8433"},"/Users/zlwu/work/00code/shanxia2.0/backend/start.sh":{"size":9548,"mtime_ns":1780114661446983244,"hash":"4d632863e8a0cd81194b491d83a0218a4157435ae812dec76a6f6197b4d48e57"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/__init__.py":{"size":21,"mtime_ns":1780113982281973984,"hash":"60a04ff08fd97084e83ea809fd13feda6d2848be20ebf309e31fc1dad7523230"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py":{"size":6280,"mtime_ns":1782790852770448643,"hash":"8f9da799977bee7134d87a26ff8434ac5ef8eabb0b7368dd537eee49ad7fd00b"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/tasks/__init__.py":{"size":2207,"mtime_ns":1783208067881286091,"hash":"313e6da0e91d743ce891dd283458c79b50b24c4d909dc96ca7b3fd9d2bfa5013"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/auth.py":{"size":7457,"mtime_ns":1782790841500516545,"hash":"34bac56e1c2cb6215f4b5fa2dc32d77d4b4abca51428819eebf4afd269cc51cf"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/api_crypto.py":{"size":1870,"mtime_ns":1780108930724444498,"hash":"c04b748aea86890a5971f749523c7b17dbad1ddd6f9f7f07a5679d159c984e33"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/login_crypto.py":{"size":3858,"mtime_ns":1780108930725155710,"hash":"b82d51afabf2293a9cb1fb2e5f994c383948e7f47ea95fe674686b4f3f3342b1"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/config.py":{"size":6698,"mtime_ns":1782790876685112837,"hash":"9d955a6baa70f78ddfcf29407d9711915a04e59a7f616254d06d25d25e8d0327"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/wechat_pay.py":{"size":23585,"mtime_ns":1780108930725768130,"hash":"3d52265ce65d21e7103f94afa1e8547aee0823b5ea6d65c50317436ac81fb4fc"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/api_request_log_middleware.py":{"size":11971,"mtime_ns":1782701669198208175,"hash":"0b84c32828939e6102bb3647691fa8f04b1f68e0e0e9f28127374cc44e19a11c"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/database.py":{"size":1510,"mtime_ns":1782790847265601586,"hash":"8bc9c8ae62e2be2c6920036582ba448dfcd1711c41cebb62274ff6bc6ee14b0b"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/security.py":{"size":728,"mtime_ns":1780108930725470004,"hash":"df0f01115064f7b8de1c81dbe9a6db39360c236610b68c33b3234a51d7f0025b"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/request_payload.py":{"size":2842,"mtime_ns":1780108930725350836,"hash":"e9937151530ab1417ef297aef59111977725cf90be2a8fa76c00a0618789aba0"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/__init__.py":{"size":61,"mtime_ns":1780108930724312414,"hash":"3dd1842ee59b0c804176b03b4b8a323bd4a252b7feb1bbc32db64f3a8928570e"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/response.py":{"size":1824,"mtime_ns":1780108930725412462,"hash":"f1739352d65ea8287d76e282a59553aa8d63c97e35764c64ac378aa5bd9c347e"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/menu_guard.py":{"size":1611,"mtime_ns":1780108930725223002,"hash":"3e26077288c3620a4780038b891a326206b45bffe00aca545bdae30172487235"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/db_collation.py":{"size":548,"mtime_ns":1780108930725025043,"hash":"0c680e25a18244ca839a7de6ed1f4313b33bc8da118d89c463aee1b6af00c6f9"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/context.py":{"size":421,"mtime_ns":1780108930724824458,"hash":"83a10aee67162374993c10a30bf8bb8bd9c4b35cf48f42c832415ccebd91660f"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/utils.py":{"size":1498,"mtime_ns":1780108930725607296,"hash":"09323693661c1d4560458b86a954128ccff82bbaf6522da0b44f24da99ddf9ea"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/storage.py":{"size":14141,"mtime_ns":1782855136810943216,"hash":"3ae2c413c10898a8adb3d6773870bafbfbc18c739c10e0e8b4f765b4b5ca6c08"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/order_status_compat.py":{"size":2828,"mtime_ns":1780108930725284669,"hash":"5349e5a0745ee6734c4a995337779307adefc46f453906171988a77de2081540"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/exceptions.py":{"size":4946,"mtime_ns":1780108930725084335,"hash":"79c997d964bca1a4f12f2b92fb1f181fdb9e2b3cf72eae39f4cc164d23794fd7"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/data_scope.py":{"size":8043,"mtime_ns":1782648925694296304,"hash":"626dff86937e5cacec634ecbc61cd53d3763d760223a1d4ec7cd11f64e59a220"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/admin_request_json.py":{"size":2669,"mtime_ns":1780108930724378914,"hash":"4f68b3cf84291e7bddad6ecf4bb4d29ca5e1ec246a9f7f9c4cf5909d0ec1174a"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/api_crypto_middleware.py":{"size":10876,"mtime_ns":1782790001926627098,"hash":"b39f128b6612589ea6ac5babd30752e9585b3af07b82bb1ad53c9e3c0d90816f"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/wechat_message.py":{"size":11194,"mtime_ns":1780108930725684255,"hash":"5086070deb14d99d1a69e419b2299ec4Line truncated
{"/Users/zlwu/work/00code/shanxia2.0/backend/start-prod.sh":{"size":7357,"mtime_ns":1782639355476060453,"hash":"ca89869446be74a2bf2367b3b28f448580220859a39a84ad9613ac5fe35a8433"},"/Users/zlwu/work/00code/shanxia2.0/backend/start.sh":{"size":9548,"mtime_ns":1780114661446983244,"hash":"4d632863e8a0cd81194b491d83a0218a4157435ae812dec76a6f6197b4d48e57"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/__init__.py":{"size":21,"mtime_ns":1780113982281973984,"hash":"60a04ff08fd97084e83ea809fd13feda6d2848be20ebf309e31fc1dad7523230"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py":{"size":6280,"mtime_ns":1782790852770448643,"hash":"8f9da799977bee7134d87a26ff8434ac5ef8eabb0b7368dd537eee49ad7fd00b"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/tasks/__init__.py":{"size":2207,"mtime_ns":1783208067881286091,"hash":"313e6da0e91d743ce891dd283458c79b50b24c4d909dc96ca7b3fd9d2bfa5013"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/auth.py":{"size":7457,"mtime_ns":1782790841500516545,"hash":"34bac56e1c2cb6215f4b5fa2dc32d77d4b4abca51428819eebf4afd269cc51cf"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/api_crypto.py":{"size":1870,"mtime_ns":1780108930724444498,"hash":"c04b748aea86890a5971f749523c7b17dbad1ddd6f9f7f07a5679d159c984e33"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/login_crypto.py":{"size":3858,"mtime_ns":1780108930725155710,"hash":"b82d51afabf2293a9cb1fb2e5f994c383948e7f47ea95fe674686b4f3f3342b1"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/config.py":{"size":6698,"mtime_ns":1782790876685112837,"hash":"9d955a6baa70f78ddfcf29407d9711915a04e59a7f616254d06d25d25e8d0327"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/wechat_pay.py":{"size":23585,"mtime_ns":1780108930725768130,"hash":"3d52265ce65d21e7103f94afa1e8547aee0823b5ea6d65c50317436ac81fb4fc"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/api_request_log_middleware.py":{"size":11971,"mtime_ns":1782701669198208175,"hash":"0b84c32828939e6102bb3647691fa8f04b1f68e0e0e9f28127374cc44e19a11c"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/database.py":{"size":1510,"mtime_ns":1782790847265601586,"hash":"8bc9c8ae62e2be2c6920036582ba448dfcd1711c41cebb62274ff6bc6ee14b0b"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/security.py":{"size":728,"mtime_ns":1780108930725470004,"hash":"df0f01115064f7b8de1c81dbe9a6db39360c236610b68c33b3234a51d7f0025b"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/request_payload.py":{"size":2842,"mtime_ns":1780108930725350836,"hash":"e9937151530ab1417ef297aef59111977725cf90be2a8fa76c00a0618789aba0"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/__init__.py":{"size":61,"mtime_ns":1780108930724312414,"hash":"3dd1842ee59b0c804176b03b4b8a323bd4a252b7feb1bbc32db64f3a8928570e"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/response.py":{"size":1824,"mtime_ns":1780108930725412462,"hash":"f1739352d65ea8287d76e282a59553aa8d63c97e35764c64ac378aa5bd9c347e"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/menu_guard.py":{"size":1611,"mtime_ns":1780108930725223002,"hash":"3e26077288c3620a4780038b891a326206b45bffe00aca545bdae30172487235"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/db_collation.py":{"size":548,"mtime_ns":1780108930725025043,"hash":"0c680e25a18244ca839a7de6ed1f4313b33bc8da118d89c463aee1b6af00c6f9"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/context.py":{"size":421,"mtime_ns":1780108930724824458,"hash":"83a10aee67162374993c10a30bf8bb8bd9c4b35cf48f42c832415ccebd91660f"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/utils.py":{"size":1498,"mtime_ns":1780108930725607296,"hash":"09323693661c1d4560458b86a954128ccff82bbaf6522da0b44f24da99ddf9ea"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/storage.py":{"size":14141,"mtime_ns":1782855136810943216,"hash":"3ae2c413c10898a8adb3d6773870bafbfbc18c739c10e0e8b4f765b4b5ca6c08"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/order_status_compat.py":{"size":2828,"mtime_ns":1780108930725284669,"hash":"5349e5a0745ee6734c4a995337779307adefc46f453906171988a77de2081540"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/exceptions.py":{"size":4946,"mtime_ns":1780108930725084335,"hash":"79c997d964bca1a4f12f2b92fb1f181fdb9e2b3cf72eae39f4cc164d23794fd7"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/data_scope.py":{"size":8043,"mtime_ns":1782648925694296304,"hash":"626dff86937e5cacec634ecbc61cd53d3763d760223a1d4ec7cd11f64e59a220"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/admin_request_json.py":{"size":2669,"mtime_ns":1780108930724378914,"hash":"4f68b3cf84291e7bddad6ecf4bb4d29ca5e1ec246a9f7f9c4cf5909d0ec1174a"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/api_crypto_middleware.py":{"size":10876,"mtime_ns":1782790001926627098,"hash":"b39f128b6612589ea6ac5babd30752e9585b3af07b82bb1ad53c9e3c0d90816f"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/wechat_message.py":{"size":11194,"mtime_ns":1780108930725684255,"hash":"5086070deb14d99d1a69e419b2299ec4Line truncated
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,3 @@
-- 运输计划:入库单打印模板字段
ALTER TABLE `pl_plan`
ADD COLUMN `slip_template_content` longtext COMMENT '入库单打印模板内容(富文本HTML)' AFTER `notify_message`;
+1
View File
@@ -200,6 +200,7 @@ CREATE TABLE `pl_plan` (
`total_amount` decimal(15,2) NOT NULL DEFAULT 0.00 COMMENT '计划总金额',
`freight_amount` decimal(15,2) NOT NULL DEFAULT 0.00 COMMENT '运费合计',
`notify_message` text COMMENT '通知信息(标准模板)',
`slip_template_content` longtext COMMENT '入库单打印模板内容(富文本HTML)',
`follow_user_id` varchar(64) DEFAULT NULL COMMENT '跟进人ID',
`follow_user_name` varchar(100) DEFAULT NULL COMMENT '跟进人姓名',
`tenant_no` varchar(64) NOT NULL DEFAULT 'shanxia2.0' COMMENT '租户编号',
+68 -48
View File
@@ -280,7 +280,7 @@
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/contract.py": {
"mtime": 1783211762.1940238,
"mtime": 1783213253.0757277,
"ast_hash": "6553f54ca1fd19086c170095f402a628",
"semantic_hash": ""
},
@@ -2605,8 +2605,8 @@
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/TinyMceEditor/index.vue": {
"mtime": 1782858534.8800476,
"ast_hash": "d35ad85f0c5f6ce6b9773da098ef0343",
"mtime": 1783224524.6634538,
"ast_hash": "a70073e3b36f3aca938df83c01f9b036",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/business/dialog-form-body/index.vue": {
@@ -5445,7 +5445,7 @@
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/bx/view/all/index.vue": {
"mtime": 1783211762.1940372,
"mtime": 1783213253.075741,
"ast_hash": "d7dc9f42bdc6aa47322e24fd8fdc066d",
"semantic_hash": ""
},
@@ -5455,7 +5455,7 @@
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/bx/view/mine/index.vue": {
"mtime": 1783211762.194047,
"mtime": 1783213253.07575,
"ast_hash": "851271a034705cc1ea02ed4748e034cb",
"semantic_hash": ""
},
@@ -5835,8 +5835,8 @@
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/backend/app/models/pl_models.py": {
"mtime": 1783155234.106063,
"ast_hash": "136320e75299b9b7d4892a6a4d94f389",
"mtime": 1783217965.3388255,
"ast_hash": "f6b3135324475dce0e933a957329457b",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/plan.py": {
@@ -5865,8 +5865,8 @@
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/plan.py": {
"mtime": 1783162783.5871694,
"ast_hash": "8cde574a535714dd8c13df27d01f5d92",
"mtime": 1783217965.2781696,
"ast_hash": "9961581dfea2a51f19f646f2631f4c83",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/transport.py": {
@@ -5895,18 +5895,18 @@
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/api/pl/index.ts": {
"mtime": 1783162782.5416315,
"ast_hash": "9a5c5d3cf7d90fb5ec2458603d6e4fc9",
"mtime": 1783219978.8417377,
"ast_hash": "01d6b4f86bf31801ae9d858162bbbe13",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/pl/transport/index.vue": {
"mtime": 1783155795.8390322,
"ast_hash": "3262b278c06c02bf786823570d8af00f",
"mtime": 1783228510.1433656,
"ast_hash": "a97bc90703a7deccc4d796579ed87c5b",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/pl/vehicle/index.vue": {
"mtime": 1783203214.342301,
"ast_hash": "66538f5900a6e5d43496be1a8fefc5a2",
"mtime": 1783228520.1533694,
"ast_hash": "3cbd030f833ebb9e3265498edf702f52",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/pl/driver/index.vue": {
@@ -5915,8 +5915,8 @@
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/pl/plan/index.vue": {
"mtime": 1783177426.8603058,
"ast_hash": "332988059831dc38ce16bff141af0987",
"mtime": 1783228730.7496412,
"ast_hash": "4683b91eebeca579dc6acce0d3e92579",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/pl/freight/index.vue": {
@@ -6005,8 +6005,8 @@
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/utils/pl-display.ts": {
"mtime": 1783209150.8483658,
"ast_hash": "5dc2e972e3be5633115c97b1be0feaa8",
"mtime": 1783228509.2363229,
"ast_hash": "d1d31713a7b3557c30805bfdaac88d4d",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/business/pl-vehicle-view-panel/index.vue": {
@@ -6020,8 +6020,8 @@
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/pl/self-vehicle/index.vue": {
"mtime": 1783203214.3423305,
"ast_hash": "5ec32286dedd895e68e64a0a3926259d",
"mtime": 1783228520.7463562,
"ast_hash": "8465294f9b44e43495efeb56ea6c5dfb",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/business/pl-vehicle-personnel-view-list/PersonnelViewPanel.vue": {
@@ -6095,13 +6095,13 @@
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/pl/plan-cert/index.vue": {
"mtime": 1783206401.5502546,
"ast_hash": "00d4f59805ce3247096d5b418bea0a1a",
"mtime": 1783228509.67719,
"ast_hash": "223b5db908ee89f8f0592373fb35667f",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/business/pl-plan-arrange-dialog/index.vue": {
"mtime": 1783209884.1979477,
"ast_hash": "3c473a0c75ac45a948280598d34f1136",
"mtime": 1783220025.6834707,
"ast_hash": "04a43442dce3109d539f8a0155230e40",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/backend/app/api/pl/public_transport.py": {
@@ -6295,18 +6295,18 @@
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/pl/plan-archive/index.vue": {
"mtime": 1783177433.9466665,
"ast_hash": "285edac01bd960a2248b4a4b49145d7b",
"mtime": 1783228509.6771562,
"ast_hash": "ff06d6ba07d3ca7deb3665a0044ce43b",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/business/pl-freight-settlement-form-dialog/index.vue": {
"mtime": 1783174322.8677242,
"ast_hash": "dd849d4395f50deef6b8d994fd63c090",
"mtime": 1783228577.4242618,
"ast_hash": "abbf4a692da0c5d540714e03e44a5ed4",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/business/pl-freight-disburse-dialog/index.vue": {
"mtime": 1783174323.7918797,
"ast_hash": "f41eccc2143f477fc3a2d126318669d7",
"mtime": 1783228558.6161494,
"ast_hash": "a56aa60f9d962b8ca315af534cf53efc",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/business/pl-freight-approval-dialog/index.vue": {
@@ -6315,8 +6315,8 @@
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/business/pl-freight-settlement-view-dialog/index.vue": {
"mtime": 1783213125.0846496,
"ast_hash": "8b89f6e272cdf9125021b746c4bea07f",
"mtime": 1783228561.928852,
"ast_hash": "31f6a533791ac73ed6122bf4efd8fc91",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/pl/freight/freight-status.ts": {
@@ -6325,8 +6325,8 @@
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/pl/freight/components/UnsettledPlanPanel.vue": {
"mtime": 1783173845.7667825,
"ast_hash": "55a36ed7281b48c2b1d73870e90ea09b",
"mtime": 1783228557.3250911,
"ast_hash": "91b220722fed9281b116173717dea54a",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/pl/freight/components/DisbursePanel.vue": {
@@ -6470,23 +6470,23 @@
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/pl/vehicle-recharge-record/index.vue": {
"mtime": 1783206729.7073312,
"ast_hash": "e697110d023bcc4c0748720ec7b96b22",
"mtime": 1783228526.8183672,
"ast_hash": "0cad018d21e7fc36b3cdb64864642b20",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/pl/vehicle-recharge-apply/index.vue": {
"mtime": 1783177627.257999,
"ast_hash": "fc2e0e2dc64b3a964f44de9a7d3620f7",
"mtime": 1783228537.4992151,
"ast_hash": "4062b24b77dbefa73ad7c9b227448039",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/pl/vehicle-maintenance-apply/index.vue": {
"mtime": 1783177621.5897706,
"ast_hash": "da1ce10da30cee9a69051a2c9b4a21e6",
"mtime": 1783228537.8917356,
"ast_hash": "2b0fc30390eaafa54333b9f20e2478ef",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/pl/vehicle-maintenance-process/index.vue": {
"mtime": 1783174317.1971097,
"ast_hash": "5cdba934e1ce9f9a9012d70901e6dc3d",
"mtime": 1783228547.5552845,
"ast_hash": "9b93fc4cdd1ec9b0031925dc68155eb8",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/vehicle_maintenance.py": {
@@ -6520,13 +6520,13 @@
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/pl/vehicle-urea-disburse/index.vue": {
"mtime": 1783174316.8975265,
"ast_hash": "24828de56d14b1a1869c8803bbef1fdd",
"mtime": 1783228548.0908864,
"ast_hash": "3d5b70c6b9e89296a9e3046cc7f14df6",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/pl/vehicle-urea-apply/index.vue": {
"mtime": 1783177617.916142,
"ast_hash": "677296cca057006f9548a965a1648187",
"mtime": 1783228538.5463428,
"ast_hash": "e7a32a07efe2a37cd0362c25bc86af61",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/oper_log_decorator.py": {
@@ -6740,7 +6740,7 @@
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/utils/bx/table-summary.ts": {
"mtime": 1783211762.1942492,
"mtime": 1783213253.0757968,
"ast_hash": "c61438627a15e9cba3f45d861686f746",
"semantic_hash": ""
},
@@ -6768,5 +6768,25 @@
"mtime": 1783208067.0009675,
"ast_hash": "99f93482c1d14f0ec792e2cc4a5cf9a8",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/utils/pl-inbound-slip-template.ts": {
"mtime": 1783230504.0601523,
"ast_hash": "a9510a97430300acac6d68e4864291d4",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/business/pl-inbound-slip-print-dialog/index.vue": {
"mtime": 1783230381.5186107,
"ast_hash": "a1a32251fd20ee4e018170fa69444b24",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/public/sxshzyz.jpg": {
"mtime": 1783219885.109014,
"ast_hash": "9a2762f94dc667b3dd0e77535f3aa98d",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/public/sxshzyz.png": {
"mtime": 1783226135.9899065,
"ast_hash": "0feefa7ab791d2d332016d558c187316",
"semantic_hash": ""
}
}
@@ -245,6 +245,7 @@
"243": "Community 243",
"244": "Community 244",
"245": "Community 245",
"246": "Community 246",
"247": "Community 247",
"248": "Community 248",
"249": "Community 249",
@@ -284,6 +285,8 @@
"283": "Community 283",
"284": "Community 284",
"285": "Community 285",
"286": "Community 286",
"287": "Community 287",
"288": "Community 288",
"289": "Community 289",
"290": "Community 290",
@@ -312,6 +315,7 @@
"313": "Community 313",
"314": "Community 314",
"315": "Community 315",
"316": "Community 316",
"317": "Community 317",
"318": "Community 318",
"319": "Community 319",
@@ -331,6 +335,7 @@
"333": "Community 333",
"334": "Community 334",
"335": "Community 335",
"336": "Community 336",
"337": "Community 337",
"338": "Community 338",
"339": "Community 339",
@@ -338,6 +343,7 @@
"341": "Community 341",
"342": "Community 342",
"343": "Community 343",
"344": "Community 344",
"345": "Community 345",
"346": "Community 346",
"347": "Community 347",
@@ -361,6 +367,7 @@
"365": "Community 365",
"366": "Community 366",
"367": "Community 367",
"368": "Community 368",
"369": "Community 369",
"370": "Community 370",
"371": "Community 371",
@@ -547,6 +554,7 @@
"552": "Community 552",
"553": "Community 553",
"554": "Community 554",
"555": "Community 555",
"556": "Community 556",
"557": "Community 557",
"558": "Community 558",
@@ -620,6 +628,7 @@
"626": "Community 626",
"627": "Community 627",
"628": "Community 628",
"629": "Community 629",
"630": "Community 630",
"631": "Community 631",
"632": "Community 632",
@@ -652,6 +661,7 @@
"659": "Community 659",
"660": "Community 660",
"661": "Community 661",
"662": "Community 662",
"663": "Community 663",
"664": "Community 664",
"665": "Community 665",
@@ -662,9 +672,11 @@
"670": "Community 670",
"671": "Community 671",
"672": "Community 672",
"673": "Community 673",
"674": "Community 674",
"675": "Community 675",
"676": "Community 676",
"677": "Community 677",
"678": "Community 678",
"679": "Community 679",
"680": "Community 680",
@@ -695,6 +707,7 @@
"705": "Community 705",
"706": "Community 706",
"707": "Community 707",
"708": "Community 708",
"709": "Community 709",
"710": "Community 710",
"711": "Community 711",
@@ -706,18 +719,24 @@
"717": "Community 717",
"718": "Community 718",
"719": "Community 719",
"720": "Community 720",
"721": "Community 721",
"722": "Community 722",
"723": "Community 723",
"724": "Community 724",
"725": "Community 725",
"726": "Community 726",
"727": "Community 727",
"728": "Community 728",
"729": "Community 729",
"730": "Community 730",
"731": "Community 731",
"732": "Community 732",
"733": "Community 733",
"734": "Community 734",
"735": "Community 735",
"736": "Community 736",
"737": "Community 737",
"738": "Community 738",
"740": "Community 740"
}
-1
View File
@@ -1 +0,0 @@
25877
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 596 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

+5 -1
View File
@@ -534,7 +534,11 @@ export const planApi = {
request.post<Plan>(`/transport/plan/${id}/archive`, data),
delete: (id: string) => request.delete(`/transport/plan/${id}`),
createFromContract: (data: { contractId: string; planDate: string; followUserId?: string; followUserName?: string }) =>
request.post<Plan>('/transport/plan/create-from-contract', data)
request.post<Plan>('/transport/plan/create-from-contract', data),
getInboundSlipTemplate: (id: string) =>
request.get<string>(`/transport/plan/${id}/inbound-slip-template`),
saveInboundSlipTemplate: (id: string, slipTemplateContent: string) =>
request.put(`/transport/plan/${id}/inbound-slip-template`, { slipTemplateContent })
}
// =============================================================================
@@ -51,6 +51,12 @@ interface Props {
toolbar?: boolean;
contractNo?: string; // 合同编号,用于提取供方编码
supplierCode?: string; // 供应商编码,直接传入(优先级高于从contractNo提取)
/** TinyMCE 编辑区 body 内边距,默认 20px;入库单等紧凑预览可传 0 */
contentBodyPadding?: string;
/** TinyMCE 表格单元格内边距,默认 10px;入库单等可传 4px */
tableCellPadding?: string;
/** 追加到 TinyMCE content_style(如入库单打印专用 CSS) */
contentStyleExtra?: string;
}
const props = withDefaults(defineProps<Props>(), {
@@ -59,7 +65,10 @@ const props = withDefaults(defineProps<Props>(), {
height: 600,
toolbar: true,
contractNo: '',
supplierCode: ''
supplierCode: '',
contentBodyPadding: '20px',
tableCellPadding: '10px',
contentStyleExtra: ''
});
const emit = defineEmits(['update:modelValue']);
@@ -188,7 +197,7 @@ const editorInit = computed(() => {
font-size: 14px;
line-height: 1.6;
color: #333;
padding: 20px;
padding: ${props.contentBodyPadding};
position: relative;
min-height: 100vh;
width: 100%;
@@ -206,7 +215,7 @@ const editorInit = computed(() => {
}
table td, table th {
border: 1px solid #ddd !important;
padding: 10px !important;
padding: ${props.tableCellPadding} !important;
}
table th {
background-color: #f5f5f5 !important;
@@ -250,6 +259,7 @@ const editorInit = computed(() => {
position: absolute !important;
z-index: 999 !important;
}
${props.contentStyleExtra || ''}
`,
// 保留所有 HTML
@@ -126,8 +126,10 @@
min-width="160"
show-overflow-tooltip
/>
<el-table-column prop="licensePlate" label="车牌号" min-width="110" align="center">
<template #default="{ row }">{{ row.licensePlate || '—' }}</template>
<el-table-column prop="licensePlate" label="车牌号" min-width="160" show-overflow-tooltip align="center">
<template #default="{ row }">
{{ formatPlVehiclePlateDisplay(row.licensePlate, row.trailerNo) }}
</template>
</el-table-column>
<el-table-column prop="driverName" label="司机" min-width="90" align="center">
<template #default="{ row }">{{ row.driverName || '—' }}</template>
@@ -178,6 +180,7 @@
import { Check, Close } from '@element-plus/icons-vue'
import { freightApi, type FreightSettlement } from '@/api/pl'
import AttachmentUploadField from '@/components/business/attachment-upload-field/index.vue'
import { formatPlVehiclePlateDisplay } from '@/utils/pl-display'
import { formatMoneyDisplay } from '@/utils/money-format'
const emit = defineEmits<{ success: [] }>()
@@ -100,8 +100,10 @@
min-width="160"
show-overflow-tooltip
/>
<el-table-column prop="licensePlate" label="车牌号" min-width="110" align="center">
<template #default="{ row }">{{ row.licensePlate || '—' }}</template>
<el-table-column prop="licensePlate" label="车牌号" min-width="160" show-overflow-tooltip align="center">
<template #default="{ row }">
{{ formatPlVehiclePlateDisplay(row.licensePlate, row.trailerNo, vehicleTrailerLookup) }}
</template>
</el-table-column>
<el-table-column prop="driverName" label="司机" min-width="90" align="center">
<template #default="{ row }">{{ row.driverName || '—' }}</template>
@@ -244,11 +246,14 @@
<el-table-column
prop="licensePlate"
label="车牌号"
min-width="110"
min-width="160"
show-overflow-tooltip
align="center"
header-align="center"
>
<template #default="{ row }">{{ row.licensePlate || '—' }}</template>
<template #default="{ row }">
{{ formatPlVehiclePlateDisplay(row.licensePlate, row.trailerNo, vehicleTrailerLookup) }}
</template>
</el-table-column>
<el-table-column
prop="driverName"
@@ -376,10 +381,15 @@
<el-table-column
prop="licensePlate"
label="车牌号"
min-width="110"
min-width="160"
show-overflow-tooltip
align="center"
header-align="center"
/>
>
<template #default="{ row }">
{{ formatPlVehiclePlateDisplay(row.licensePlate, undefined, vehicleTrailerLookup) }}
</template>
</el-table-column>
<el-table-column
prop="transportCompany"
label="运输公司"
@@ -440,11 +450,15 @@
import { Check, Close, Delete, Plus, RefreshLeft, Search } from '@element-plus/icons-vue'
import {
freightApi,
vehicleApi,
type FreightSettlement,
type Transport,
type UnsettledPlanItem
type UnsettledPlanItem,
type Vehicle
} from '@/api/pl'
import AttachmentUploadField from '@/components/business/attachment-upload-field/index.vue'
import { pickBxList } from '@/utils/http/bx'
import { buildVehicleTrailerLookup, formatPlVehiclePlateDisplay } from '@/utils/pl-display'
import { formatMoneyDisplay } from '@/utils/money-format'
import { formatDateTime } from '@/utils/format'
import { getPlanTypeLabel, getPlanTypeTagType, isEditableDraftSettlement } from '@/views/pl/freight/freight-status'
@@ -456,6 +470,7 @@ type EditableTransport = Pick<
| 'id'
| 'transportNo'
| 'licensePlate'
| 'trailerNo'
| 'driverName'
| 'carrierName'
| 'transportMedium'
@@ -473,6 +488,8 @@ const attachmentRef = ref<InstanceType<typeof AttachmentUploadField>>()
const invoiceAttachmentUrlsStr = ref('')
const editableTransports = ref<EditableTransport[]>([])
const removedTransports = ref<EditableTransport[]>([])
const vehicleOptions = ref<Vehicle[]>([])
const vehicleTrailerLookup = computed(() => buildVehicleTrailerLookup(vehicleOptions.value))
const addDialogVisible = ref(false)
const addLoading = ref(false)
@@ -529,6 +546,7 @@ function cloneTransportRows(rows: Transport[] = []): EditableTransport[] {
id: row.id,
transportNo: row.transportNo,
licensePlate: row.licensePlate,
trailerNo: row.trailerNo,
driverName: row.driverName,
carrierName: row.carrierName,
transportMedium: row.transportMedium,
@@ -552,12 +570,22 @@ function planToTransportRow(plan: UnsettledPlanItem): EditableTransport {
}
}
async function loadVehicleOptions() {
try {
const res = await vehicleApi.list({ page: 1, pageSize: 500 })
vehicleOptions.value = pickBxList(res)
} catch {
vehicleOptions.value = []
}
}
async function open(id: string) {
visible.value = true
loading.value = true
invoiceAttachmentUrlsStr.value = ''
removedTransports.value = []
try {
await loadVehicleOptions()
const res = await freightApi.get(id)
settlement.value = (res.data ?? res) as FreightSettlement
form.invoiceNo = settlement.value.invoiceNo || ''
@@ -93,8 +93,10 @@
min-width="160"
show-overflow-tooltip
/>
<el-table-column prop="licensePlate" label="车牌号" min-width="110" align="center">
<template #default="{ row }">{{ row.licensePlate || '—' }}</template>
<el-table-column prop="licensePlate" label="车牌号" min-width="160" show-overflow-tooltip align="center">
<template #default="{ row }">
{{ formatPlVehiclePlateDisplay(row.licensePlate, row.trailerNo) }}
</template>
</el-table-column>
<el-table-column prop="driverName" label="司机" min-width="90" align="center">
<template #default="{ row }">{{ row.driverName || '—' }}</template>
@@ -199,6 +201,7 @@ import {
getSettlementStatusTagType,
mapApprovalFlowToNodes
} from '@/views/pl/freight/freight-status'
import { formatPlVehiclePlateDisplay } from '@/utils/pl-display'
import { formatMoneyDisplay } from '@/utils/money-format'
import { formatDateTime } from '@/utils/format'
@@ -0,0 +1,324 @@
<!-- 入库单打印:富文本预览/编辑 + 打印/PDF -->
<template>
<el-dialog
v-model="visible"
:title="isPreviewMode ? '预览入库单' : '编辑入库单'"
width="1500px"
align-center
append-to-body
destroy-on-close
class="dialog-form-layout pl-inbound-slip-print-dialog"
modal-class="order-module-dialog-mask"
:close-on-click-modal="false"
@closed="handleClosed"
>
<TinyMceEditor
v-model="slipContent"
:height="editorHeight"
:disabled="isPreviewMode"
:toolbar="!isPreviewMode"
content-body-padding="0"
table-cell-padding="4px"
:content-style-extra="INBOUND_SLIP_PRINT_CSS"
/>
<template #footer>
<div class="inbound-slip-print-actions">
<el-button class="btn-ghost" @click="visible = false">
<el-icon><Close /></el-icon>关闭
</el-button>
<el-button class="btn-ghost" @click="isPreviewMode = !isPreviewMode">
<el-icon><View /></el-icon>{{ isPreviewMode ? '编辑模式' : '预览模式' }}
</el-button>
<el-button class="btn-ghost" :loading="saveLoading" @click="handleSaveTemplate">
<el-icon><DocumentChecked /></el-icon>保存模板
</el-button>
<el-button class="btn-ghost" @click="handlePrint">
<el-icon><Printer /></el-icon>打印
</el-button>
<el-button class="btn-main" type="primary" :loading="pdfGenerating" @click="handleGeneratePdf">
<el-icon><Download /></el-icon>生成 PDF
</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { Close, DocumentChecked, Download, Printer, View } from '@element-plus/icons-vue'
import html2canvas from 'html2canvas'
import jsPDF from 'jspdf'
import { fetchProductDetail } from '@/api/crm/product'
import { planApi, type Plan } from '@/api/pl'
import TinyMceEditor from '@/components/TinyMceEditor/index.vue'
import { useDictStore } from '@/store/modules/dict'
import {
generateInboundSlipTemplate,
INBOUND_SLIP_DOC_MAX_WIDTH,
INBOUND_SLIP_PRINT_CSS,
prepareInboundSlipPdfGridCells,
replaceInboundSlipPlaceholders,
restoreInboundSlipPlaceholders,
type InboundSlipRenderContext
} from '@/utils/pl-inbound-slip-template'
const visible = ref(false)
const slipContent = ref('')
const isPreviewMode = ref(false)
const saveLoading = ref(false)
const pdfGenerating = ref(false)
const currentPlanId = ref('')
const currentPlan = ref<Plan | null>(null)
const editorHeight = computed(() => {
if (typeof window === 'undefined') return 780
return Math.min(860, Math.max(720, window.innerHeight - 200))
})
async function waitForImagesLoaded(container: HTMLElement) {
const imgs = Array.from(container.querySelectorAll('img'))
await Promise.all(
imgs.map(
(img) =>
new Promise<void>((resolve) => {
if (img.complete && img.naturalWidth > 0) {
resolve()
return
}
img.onload = () => resolve()
img.onerror = () => resolve()
})
)
)
}
function getPdfCanvasScale() {
const dpr = typeof window !== 'undefined' ? window.devicePixelRatio || 1 : 1
return Math.min(4, Math.max(3, dpr * 2))
}
async function buildSlipRenderContext(plan: Plan): Promise<InboundSlipRenderContext> {
const dictStore = useDictStore()
await dictStore.loadAllDict()
const productIds = [...new Set((plan.products || []).map(item => String(item.productId || '').trim()).filter(Boolean))]
const productCodeById: Record<string, string> = {}
await Promise.all(
productIds.map(async (productId) => {
try {
const res = await fetchProductDetail({ id: productId })
const data = (res as { data?: { productNo?: string }; productNo?: string }).data ?? res
const productNo = String((data as { productNo?: string }).productNo || '').trim()
if (productNo) {
productCodeById[productId] = productNo
}
} catch {
// 单个产品查询失败时保留计划明细中的冗余字段
}
})
)
return {
productCodeById,
getUnitLabel: (unitCode: string) => dictStore.getLabel('crm_product_unit', unitCode) || unitCode
}
}
async function open(planId: string) {
currentPlanId.value = planId
isPreviewMode.value = false
try {
ElMessage.info({ message: '正在生成入库单...', duration: 800 })
const res = await planApi.get(planId)
const plan = (res.data ?? res) as Plan
currentPlan.value = plan
let htmlContent = ''
try {
const templateRes = await planApi.getInboundSlipTemplate(planId)
const saved = (templateRes.data ?? templateRes) as string
if (saved?.trim()) {
htmlContent = saved
} else {
htmlContent = generateInboundSlipTemplate(plan)
}
} catch {
htmlContent = generateInboundSlipTemplate(plan)
}
const renderCtx = await buildSlipRenderContext(plan)
slipContent.value = replaceInboundSlipPlaceholders(htmlContent, plan, renderCtx)
visible.value = true
} catch (error) {
console.error('打开入库单打印失败', error)
ElMessage.error('加载入库单失败')
}
}
function handleClosed() {
slipContent.value = ''
currentPlanId.value = ''
currentPlan.value = null
isPreviewMode.value = false
}
async function refreshPlan() {
if (!currentPlanId.value) return null
const res = await planApi.get(currentPlanId.value)
const plan = (res.data ?? res) as Plan
currentPlan.value = plan
return plan
}
async function handleSaveTemplate() {
if (!currentPlanId.value) {
ElMessage.warning('无法获取计划ID')
return
}
saveLoading.value = true
try {
const plan = (await refreshPlan()) || currentPlan.value
if (!plan) throw new Error('计划数据无效')
const finalTemplate = restoreInboundSlipPlaceholders(slipContent.value, plan)
await planApi.saveInboundSlipTemplate(currentPlanId.value, finalTemplate)
ElMessage.success('模板保存成功')
} catch (error) {
console.error('保存入库单模板失败', error)
ElMessage.error('保存模板失败')
} finally {
saveLoading.value = false
}
}
function handlePrint() {
const printWindow = window.open('', '_blank')
if (!printWindow) {
ElMessage.error('无法打开打印窗口,请检查浏览器拦截设置')
return
}
printWindow.document.write(`
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>打印入库单</title>
<style>
body { margin: 0 auto; padding: 0; background: #fff; width: ${INBOUND_SLIP_DOC_MAX_WIDTH}; box-sizing: border-box; }
${INBOUND_SLIP_PRINT_CSS}
@media print {
body { margin: 0; padding: 0; }
img { print-color-adjust: exact; -webkit-print-color-adjust: exact; }
}
</style>
</head>
<body>${slipContent.value}</body>
</html>
`)
printWindow.document.close()
setTimeout(() => {
printWindow.focus()
printWindow.print()
}, 600)
}
async function handleGeneratePdf() {
if (!currentPlan.value) {
ElMessage.error('计划信息不存在')
return
}
pdfGenerating.value = true
try {
let htmlContent = slipContent.value
if (htmlContent.includes('{{')) {
const plan = (await refreshPlan()) || currentPlan.value
if (plan) {
const renderCtx = await buildSlipRenderContext(plan)
htmlContent = replaceInboundSlipPlaceholders(htmlContent, plan, renderCtx)
}
}
const tempDiv = document.createElement('div')
tempDiv.style.cssText = `position:absolute;left:-9999px;top:0;width:${INBOUND_SLIP_DOC_MAX_WIDTH};background:#fff;padding:0;`
tempDiv.innerHTML = htmlContent
const styleEl = document.createElement('style')
styleEl.textContent = INBOUND_SLIP_PRINT_CSS
tempDiv.prepend(styleEl)
document.body.appendChild(tempDiv)
await waitForImagesLoaded(tempDiv)
await new Promise<void>((resolve) => {
requestAnimationFrame(() => requestAnimationFrame(() => resolve()))
})
prepareInboundSlipPdfGridCells(tempDiv)
await new Promise<void>((resolve) => {
requestAnimationFrame(() => resolve())
})
const canvas = await html2canvas(tempDiv, {
scale: getPdfCanvasScale(),
useCORS: true,
allowTaint: true,
backgroundColor: '#ffffff',
onclone: (_doc, clone) => {
prepareInboundSlipPdfGridCells(clone as HTMLElement)
}
})
document.body.removeChild(tempDiv)
const imgWidth = 210
const pageHeight = 297
const imgHeight = (canvas.height * imgWidth) / canvas.width
const pdf = new jsPDF({ orientation: 'portrait', unit: 'mm', format: 'a4' })
const imgData = canvas.toDataURL('image/png')
if (imgHeight <= pageHeight) {
pdf.addImage(imgData, 'PNG', 0, 0, imgWidth, imgHeight)
} else {
let heightLeft = imgHeight
let position = 0
pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight)
heightLeft -= pageHeight
while (heightLeft > 0) {
position = -(imgHeight - heightLeft)
pdf.addPage()
pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight)
heightLeft -= pageHeight
}
}
const fileName = (currentPlan.value.planNo || '入库单').replace(/[/\\:*?"<>|]/g, '-')
pdf.save(`${fileName}入库单.pdf`)
ElMessage.success('PDF 生成成功')
} catch (error) {
console.error('生成 PDF 失败', error)
ElMessage.error('生成 PDF 失败,请重试')
} finally {
pdfGenerating.value = false
}
}
defineExpose({ open })
</script>
<style scoped lang="scss">
.inbound-slip-print-actions {
display: flex;
flex-wrap: wrap;
gap: 8px;
justify-content: flex-end;
}
</style>
<style lang="scss">
.el-dialog.pl-inbound-slip-print-dialog.dialog-form-layout {
max-height: var(--dialog-max-height, calc(100vh - 32px));
}
.el-dialog.pl-inbound-slip-print-dialog.dialog-form-layout .el-dialog__body {
min-height: min(820px, calc(100vh - 150px));
}
</style>
@@ -249,6 +249,8 @@
:bundle="vehicleBundle"
/>
<PlInboundSlipPrintDialog ref="inboundSlipPrintRef" />
<template #footer>
<div class="dialog-footer pl-arrange-footer">
<template v-if="arrangeSuccess">
@@ -286,6 +288,12 @@
>
<el-icon><CopyDocument /></el-icon>复制磅单二维码
</el-button>
<el-button
v-if="showInboundSlipPrint"
@click="handlePrintInboundSlip"
>
<el-icon><Printer /></el-icon>入库单打印
</el-button>
</template>
<template v-else>
<el-button @click="innerVisible = false">
@@ -301,7 +309,7 @@
</template>
<script setup lang="ts">
import { Check, Close, CopyDocument } from '@element-plus/icons-vue'
import { Check, Close, CopyDocument, Printer } from '@element-plus/icons-vue'
import {
carrierApi,
planApi,
@@ -316,6 +324,7 @@ import {
type VehiclePersonnelRow
} from '@/api/pl'
import DbPoundSlipQrcodeDialog from '@/components/business/db/DbPoundSlipQrcodeDialog.vue'
import PlInboundSlipPrintDialog from '@/components/business/pl-inbound-slip-print-dialog/index.vue'
import PlAddressWithLibrary from '@/components/business/pl-address-with-library/index.vue'
import PlVehicleSummaryStrip from '@/components/business/pl-vehicle-summary-strip/index.vue'
import PlVehicleViewDialog from '@/components/business/pl-vehicle-view-dialog/index.vue'
@@ -329,6 +338,7 @@ import { useDictStore } from '@/store/modules/dict'
import { isTonProductUnit } from '@/utils/crm-product-display'
import { formatDate } from '@/utils/format'
import { pickBxData, pickBxList } from '@/utils/http/bx'
import { canPrintInboundSlip } from '@/utils/pl-inbound-slip-template'
const dictStore = useDictStore()
@@ -371,6 +381,7 @@ const {
copyPoundSlipQrcode
} = usePlPlanArrangeActions()
const tabsRef = ref<InstanceType<typeof PlPlanViewTabs> | null>(null)
const inboundSlipPrintRef = ref<InstanceType<typeof PlInboundSlipPrintDialog> | null>(null)
const formRef = ref()
const plan = ref<Partial<Plan>>({})
const products = ref<PlanProduct[]>([])
@@ -417,6 +428,9 @@ const dialogTitle = computed(() => {
})
const isRearrange = computed(() => plan.value.transportStatus === 'arranged')
const showInboundSlipPrint = computed(
() => arrangeSuccess.value && canPrintInboundSlip(plan.value as Plan)
)
function getUnitLabel(unit: string) {
return dictStore.getLabel('crm_product_unit', unit) || unit
@@ -819,6 +833,15 @@ async function handleSubmit() {
submitLoading.value = false
}
}
function handlePrintInboundSlip() {
const planId = plan.value.id
if (!planId) {
ElMessage.warning('计划信息无效')
return
}
inboundSlipPrintRef.value?.open(planId)
}
</script>
<style scoped lang="scss">
+34
View File
@@ -24,6 +24,40 @@ export function getPlVehicleTypeTagType(type: string) {
return type === 'self' ? 'success' : 'warning'
}
type VehicleTrailerLookup = ReadonlyMap<string, string> | Record<string, string | undefined | null>
function resolveTrailerFromLookup(plate: string, lookup?: VehicleTrailerLookup) {
if (!lookup || !plate) return ''
if (lookup instanceof Map) return lookup.get(plate)?.trim() || ''
return lookup[plate]?.trim() || ''
}
/** 按车牌构建挂车号查找表(仅 licensePlate 的业务列表用) */
export function buildVehicleTrailerLookup(
vehicles: Array<{ licensePlate?: string | null; trailerNo?: string | null }> = []
) {
const map = new Map<string, string>()
for (const vehicle of vehicles) {
const plate = vehicle.licensePlate?.trim()
const trailer = vehicle.trailerNo?.trim()
if (plate && trailer) map.set(plate, trailer)
}
return map
}
/** 列表/摘要:车牌号(挂车号) */
export function formatPlVehiclePlateDisplay(
licensePlate?: string | null,
trailerNo?: string | null,
trailerLookup?: VehicleTrailerLookup
) {
const plate = licensePlate?.trim() || ''
const trailer = trailerNo?.trim() || resolveTrailerFromLookup(plate, trailerLookup)
if (!plate && !trailer) return '—'
if (plate && trailer) return `${plate}(${trailer})`
return plate || trailer
}
export function getPlCarrierStatusLabel(status: string) {
return status === '1' ? '合作中' : '已终止'
}
File diff suppressed because it is too large. Load diff
@@ -136,9 +136,14 @@
v-if="isColumnVisible('licensePlate')"
prop="licensePlate"
label="车牌号"
min-width="110"
min-width="160"
show-overflow-tooltip
align="center"
/>
>
<template #default="{ row }">
{{ formatPlVehiclePlateDisplay(row.licensePlate, undefined, vehicleTrailerLookup) }}
</template>
</el-table-column>
<el-table-column
v-if="isColumnVisible('transportCompany')"
prop="transportCompany"
@@ -190,10 +195,11 @@ import ListQuickSearchInput from '@/components/business/list-quick-search-input/
import ListToolbarEndActions from '@/components/business/list-toolbar-end-actions/index.vue'
import { usePersistedListColumns } from '@/composables/usePersistedListColumns'
import { DocumentAdd, RefreshLeft, Search } from '@element-plus/icons-vue'
import { carrierApi, freightApi, type Carrier, type UnsettledPlanItem } from '@/api/pl'
import { carrierApi, freightApi, vehicleApi, type Carrier, type UnsettledPlanItem, type Vehicle } from '@/api/pl'
import { pickBxList } from '@/utils/http/bx'
import PlPlanViewDialog from '@/components/business/pl-plan-view-dialog/index.vue'
import { getPlanTypeLabel, getPlanTypeTagType } from '@/views/pl/freight/freight-status'
import { buildVehicleTrailerLookup, formatPlVehiclePlateDisplay } from '@/utils/pl-display'
import { formatMoneyDisplay } from '@/utils/money-format'
import { formatDateTime } from '@/utils/format'
@@ -220,6 +226,8 @@ const {
const loading = ref(false)
const createLoading = ref(false)
const carrierList = ref<Carrier[]>([])
const vehicleOptions = ref<Vehicle[]>([])
const vehicleTrailerLookup = computed(() => buildVehicleTrailerLookup(vehicleOptions.value))
const planList = ref<UnsettledPlanItem[]>([])
const selectedRows = ref<UnsettledPlanItem[]>([])
const planViewVisible = ref(false)
@@ -299,6 +307,15 @@ async function loadCarrierList() {
}
}
async function loadVehicleOptions() {
try {
const res = await vehicleApi.list({ page: 1, pageSize: 500 })
vehicleOptions.value = pickBxList(res)
} catch {
vehicleOptions.value = []
}
}
function handlePageChange() {
fetchData()
}
@@ -345,6 +362,7 @@ function refresh() {
onMounted(() => {
loadCarrierList()
loadVehicleOptions()
fetchData()
})
@@ -221,9 +221,14 @@
v-if="isColumnVisible('licensePlate')"
prop="licensePlate"
label="车牌号"
min-width="120"
min-width="160"
show-overflow-tooltip
align="center"
/>
>
<template #default="{ row }">
{{ formatPlVehiclePlateDisplay(row.licensePlate, row.trailerNo) }}
</template>
</el-table-column>
<el-table-column
v-if="isColumnVisible('personnelSummary')"
prop="personnelSummary"
@@ -312,6 +317,7 @@ import ListToolbarDateShortcuts from '@/components/core/list-toolbar-date-shortc
import { useDbInstantSearch } from '@/composables/useDbInstantSearch'
import { useListDateShortcut } from '@/composables/useListDateShortcut'
import {
formatPlVehiclePlateDisplay,
getPlPlanArchiveStatusLabel,
getPlPlanArchiveStatusTagType
} from '@/utils/pl-display'
+8 -2
View File
@@ -233,9 +233,14 @@
v-if="isColumnVisible('licensePlate')"
prop="licensePlate"
label="车牌号"
min-width="120"
min-width="160"
show-overflow-tooltip
align="center"
/>
>
<template #default="{ row }">
{{ formatPlVehiclePlateDisplay(row.licensePlate, row.trailerNo) }}
</template>
</el-table-column>
<el-table-column
v-if="isColumnVisible('personnelSummary')"
prop="personnelSummary"
@@ -331,6 +336,7 @@ import PlPlanViewDialog from '@/components/business/pl-plan-view-dialog/index.vu
import ListToolbarDateShortcuts from '@/components/core/list-toolbar-date-shortcuts/index.vue'
import { useDbInstantSearch } from '@/composables/useDbInstantSearch'
import { useListDateShortcut } from '@/composables/useListDateShortcut'
import { formatPlVehiclePlateDisplay } from '@/utils/pl-display'
import { syncViewRowFromFlatList } from '@/utils/view-dialog-refresh'
const loading = ref(false)
+35 -2
View File
@@ -108,6 +108,13 @@
>
<el-icon><Van /></el-icon>{{ arrangeTransportLabel(selectedPlan) }}
</el-button>
<el-button
class="btn-ghost"
:disabled="selectedRows.length !== 1"
@click="handleToolbarPrintInboundSlip"
>
<el-icon><Printer /></el-icon>入库单打印
</el-button>
<el-button
v-if="selectedPlan && canVoidPlan(selectedPlan)"
class="btn-ghost"
@@ -241,9 +248,14 @@
v-if="isColumnVisible('licensePlate')"
prop="licensePlate"
label="车牌号"
min-width="120"
min-width="160"
show-overflow-tooltip
align="center"
/>
>
<template #default="{ row }">
{{ formatPlVehiclePlateDisplay(row.licensePlate, row.trailerNo) }}
</template>
</el-table-column>
<el-table-column
v-if="isColumnVisible('personnelSummary')"
prop="personnelSummary"
@@ -302,6 +314,12 @@
>
<el-icon><Van /></el-icon>{{ arrangeTransportLabel(viewingPlan) }}
</el-button>
<el-button
class="btn-ghost"
@click="handlePrintInboundSlip(viewingPlan)"
>
<el-icon><Printer /></el-icon>入库单打印
</el-button>
<el-button
v-if="canVoidPlan(viewingPlan)"
class="btn-ghost"
@@ -330,6 +348,8 @@
:plan-id="arrangePlanId"
@success="handlePlanMutationSuccess"
/>
<PlInboundSlipPrintDialog ref="inboundSlipPrintRef" />
</div>
</template>
@@ -339,11 +359,13 @@ import {
Delete,
Edit,
Plus,
Printer,
RefreshLeft,
Search,
Van
} from '@element-plus/icons-vue'
import { planApi, type Plan } from '@/api/pl'
import PlInboundSlipPrintDialog from '@/components/business/pl-inbound-slip-print-dialog/index.vue'
import PlPlanArrangeDialog from '@/components/business/pl-plan-arrange-dialog/index.vue'
import PlPlanFormDialog from '@/components/business/pl-plan-form-dialog/index.vue'
import ListQuickSearchInput from '@/components/business/list-quick-search-input/index.vue'
@@ -355,6 +377,7 @@ import ListToolbarDateShortcuts from '@/components/core/list-toolbar-date-shortc
import { useDbInstantSearch } from '@/composables/useDbInstantSearch'
import { useListDateShortcut } from '@/composables/useListDateShortcut'
import { canDeleteByCreator, CREATOR_DELETE_TIP } from '@/utils/creator-delete'
import { formatPlVehiclePlateDisplay } from '@/utils/pl-display'
import { syncViewRowFromFlatList } from '@/utils/view-dialog-refresh'
const route = useRoute()
const router = useRouter()
@@ -369,6 +392,7 @@ const viewPlanId = ref('')
const viewDialogRef = ref<InstanceType<typeof PlPlanViewDialog>>()
const arrangeDialogVisible = ref(false)
const arrangePlanId = ref('')
const inboundSlipPrintRef = ref<InstanceType<typeof PlInboundSlipPrintDialog>>()
const planList = ref<Plan[]>([])
const listColumnDefs = [
@@ -631,6 +655,15 @@ function handleArrange(row: Plan) {
arrangeDialogVisible.value = true
}
function handlePrintInboundSlip(row: Plan) {
inboundSlipPrintRef.value?.open(row.id)
}
function handleToolbarPrintInboundSlip() {
if (selectedRows.value.length !== 1) return
handlePrintInboundSlip(selectedRows.value[0])
}
function handleToolbarEdit() {
if (selectedRows.value.length !== 1) return
handleEdit(selectedRows.value[0])
@@ -118,7 +118,9 @@
header-align="center"
>
<template #default="{ row }">
<el-link type="primary" @click="handleView(row)">{{ row.licensePlate }}</el-link>
<el-link type="primary" @click="handleView(row)">
{{ formatPlVehiclePlateDisplay(row.licensePlate, row.trailerNo) }}
</el-link>
</template>
</el-table-column>
<el-table-column label="车辆类型" min-width="90" align="center" header-align="center" v-if="isColumnVisible('vehicleType')">
@@ -400,6 +402,7 @@ import { pickBxList, pickBxPageResult } from '@/utils/http/bx'
import { DEFAULT_LIST_PAGE_SIZE } from '@/utils/table/tableConfig'
import { formatDateTime } from '@/utils/format'
import {
formatPlVehiclePlateDisplay,
getPlVehicleStatusLabel,
getPlVehicleStatusTagType
} from '@/utils/pl-display'
+8 -2
View File
@@ -109,9 +109,14 @@
v-if="isColumnVisible('licensePlate')"
prop="licensePlate"
label="车牌号"
min-width="120"
min-width="160"
show-overflow-tooltip
align="center"
/>
>
<template #default="{ row }">
{{ formatPlVehiclePlateDisplay(row.licensePlate, row.trailerNo) }}
</template>
</el-table-column>
<el-table-column
v-if="isColumnVisible('driverName')"
prop="driverName"
@@ -250,6 +255,7 @@ import ListQuickSearchInput from '@/components/business/list-quick-search-input/
import ListToolbarEndActions from '@/components/business/list-toolbar-end-actions/index.vue'
import { usePersistedListColumns } from '@/composables/usePersistedListColumns'
import { useDbInstantSearch } from '@/composables/useDbInstantSearch'
import { formatPlVehiclePlateDisplay } from '@/utils/pl-display'
import { formatMoneyDisplay } from '@/utils/money-format'
import { formatDateTime } from '@/utils/format'
@@ -133,9 +133,14 @@
v-if="isColumnVisible('licensePlate')"
prop="licensePlate"
label="车牌号"
min-width="120"
min-width="160"
show-overflow-tooltip
align="center"
/>
>
<template #default="{ row }">
{{ formatPlVehiclePlateDisplay(row.licensePlate, undefined, vehicleTrailerLookup) }}
</template>
</el-table-column>
<el-table-column
v-if="isColumnVisible('maintenanceType')"
prop="maintenanceType"
@@ -388,6 +393,8 @@ import AttachmentUploadField from '@/components/business/attachment-upload-field
import SystemViewDialog, { type ViewSection } from '@/components/business/system-view-dialog/index.vue'
import { useUserStore } from '@/store/modules/user'
import {
buildVehicleTrailerLookup,
formatPlVehiclePlateDisplay,
getPlMaintenanceApplyStatusLabel,
getPlMaintenanceApplyStatusTagType,
getPlMaintenanceTypeLabel,
@@ -432,6 +439,7 @@ const cancelLoadingMap = reactive<Record<string, boolean>>({})
const tableData = ref<VehicleMaintenanceApply[]>([])
const selectedRows = ref<VehicleMaintenanceApply[]>([])
const vehicleOptions = ref<Vehicle[]>([])
const vehicleTrailerLookup = computed(() => buildVehicleTrailerLookup(vehicleOptions.value))
const dateRange = ref<string[]>([])
const quickSearchKeyword = ref('')
@@ -175,9 +175,14 @@
v-if="isColumnVisible('licensePlate')"
prop="licensePlate"
label="车牌号"
min-width="110"
min-width="160"
show-overflow-tooltip
align="center"
/>
>
<template #default="{ row }">
{{ formatPlVehiclePlateDisplay(row.licensePlate, undefined, vehicleTrailerLookup) }}
</template>
</el-table-column>
<el-table-column
v-if="isColumnVisible('maintenanceType')"
prop="maintenanceType"
@@ -425,6 +430,8 @@ import AttachmentUploadField from '@/components/business/attachment-upload-field
import SystemViewDialog, { type ViewSection } from '@/components/business/system-view-dialog/index.vue'
import { useUserStore } from '@/store/modules/user'
import {
buildVehicleTrailerLookup,
formatPlVehiclePlateDisplay,
getPlMaintenanceApplyStatusLabel,
getPlMaintenanceApplyStatusTagType,
getPlMaintenanceTypeLabel,
@@ -474,6 +481,7 @@ const deleteLoadingMap = reactive<Record<string, boolean>>({})
const selectedRows = ref<VehicleMaintenanceProcessBoardItem[]>([])
const tableData = ref<VehicleMaintenanceProcessBoardItem[]>([])
const vehicleOptions = ref<Vehicle[]>([])
const vehicleTrailerLookup = computed(() => buildVehicleTrailerLookup(vehicleOptions.value))
const applyDateRange = ref<string[]>([])
const processDateRange = ref<string[]>([])
const quickSearchKeyword = ref('')
@@ -121,9 +121,14 @@
v-if="isColumnVisible('licensePlate')"
prop="licensePlate"
label="车牌号"
min-width="120"
min-width="160"
show-overflow-tooltip
align="center"
/>
>
<template #default="{ row }">
{{ formatPlVehiclePlateDisplay(row.licensePlate, undefined, vehicleTrailerLookup) }}
</template>
</el-table-column>
<el-table-column
v-if="isColumnVisible('rechargeType')"
prop="rechargeType"
@@ -327,6 +332,8 @@ import AttachmentUploadField from '@/components/business/attachment-upload-field
import SystemViewDialog, { type ViewSection } from '@/components/business/system-view-dialog/index.vue'
import { useUserStore } from '@/store/modules/user'
import {
buildVehicleTrailerLookup,
formatPlVehiclePlateDisplay,
getPlRechargeApplyStatusLabel,
getPlRechargeApplyStatusTagType,
getPlRechargeTypeLabel,
@@ -369,6 +376,7 @@ const cancelLoadingMap = reactive<Record<string, boolean>>({})
const tableData = ref<VehicleRechargeApply[]>([])
const selectedRows = ref<VehicleRechargeApply[]>([])
const vehicleOptions = ref<Vehicle[]>([])
const vehicleTrailerLookup = computed(() => buildVehicleTrailerLookup(vehicleOptions.value))
const dateRange = ref<string[]>([])
const quickSearchKeyword = ref('')
@@ -189,9 +189,14 @@
v-if="isColumnVisible('licensePlate')"
prop="licensePlate"
label="车牌号"
min-width="110"
min-width="160"
show-overflow-tooltip
align="center"
/>
>
<template #default="{ row }">
{{ formatPlVehiclePlateDisplay(row.licensePlate, undefined, vehicleTrailerLookup) }}
</template>
</el-table-column>
<el-table-column
v-if="isColumnVisible('rechargeType')"
prop="rechargeType"
@@ -437,6 +442,8 @@ import AttachmentUploadField from '@/components/business/attachment-upload-field
import SystemViewDialog, { type ViewSection } from '@/components/business/system-view-dialog/index.vue'
import { useUserStore } from '@/store/modules/user'
import {
buildVehicleTrailerLookup,
formatPlVehiclePlateDisplay,
getPlRechargeApplyStatusLabel,
getPlRechargeApplyStatusTagType,
getPlRechargeTypeLabel,
@@ -479,6 +486,7 @@ const deleteLoadingMap = reactive<Record<string, boolean>>({})
const tableData = ref<VehicleRechargeDisburseBoardItem[]>([])
const selectedRows = ref<VehicleRechargeDisburseBoardItem[]>([])
const vehicleOptions = ref<Vehicle[]>([])
const vehicleTrailerLookup = computed(() => buildVehicleTrailerLookup(vehicleOptions.value))
const applyDateRange = ref<string[]>([])
const rechargeDateRange = ref<string[]>([])
const quickSearchKeyword = ref('')
@@ -115,9 +115,14 @@
v-if="isColumnVisible('licensePlate')"
prop="licensePlate"
label="车牌号"
min-width="120"
min-width="160"
show-overflow-tooltip
align="center"
/>
>
<template #default="{ row }">
{{ formatPlVehiclePlateDisplay(row.licensePlate, undefined, vehicleTrailerLookup) }}
</template>
</el-table-column>
<el-table-column
v-if="isColumnVisible('applyDate')"
prop="applyDate"
@@ -343,6 +348,8 @@ import AttachmentUploadField from '@/components/business/attachment-upload-field
import SystemViewDialog, { type ViewSection } from '@/components/business/system-view-dialog/index.vue'
import { useUserStore } from '@/store/modules/user'
import {
buildVehicleTrailerLookup,
formatPlVehiclePlateDisplay,
getPlUreaApplyStatusLabel,
getPlUreaApplyStatusTagType,
PL_UREA_UNIT_PRESETS
@@ -387,6 +394,7 @@ const cancelLoadingMap = reactive<Record<string, boolean>>({})
const tableData = ref<VehicleUreaApply[]>([])
const selectedRows = ref<VehicleUreaApply[]>([])
const vehicleOptions = ref<Vehicle[]>([])
const vehicleTrailerLookup = computed(() => buildVehicleTrailerLookup(vehicleOptions.value))
const dateRange = ref<string[]>([])
const quickSearchKeyword = ref('')
@@ -189,9 +189,14 @@
v-if="isColumnVisible('licensePlate')"
prop="licensePlate"
label="车牌号"
min-width="110"
min-width="160"
show-overflow-tooltip
align="center"
/>
>
<template #default="{ row }">
{{ formatPlVehiclePlateDisplay(row.licensePlate, undefined, vehicleTrailerLookup) }}
</template>
</el-table-column>
<el-table-column
v-if="isColumnVisible('disburseNo')"
prop="disburseNo"
@@ -394,7 +399,12 @@ import { fetchUserOptions } from '@/api/admin'
import AttachmentUploadField from '@/components/business/attachment-upload-field/index.vue'
import SystemViewDialog, { type ViewSection } from '@/components/business/system-view-dialog/index.vue'
import { useUserStore } from '@/store/modules/user'
import { getPlUreaApplyStatusLabel, getPlUreaApplyStatusTagType } from '@/utils/pl-display'
import {
buildVehicleTrailerLookup,
formatPlVehiclePlateDisplay,
getPlUreaApplyStatusLabel,
getPlUreaApplyStatusTagType
} from '@/utils/pl-display'
type DialogMode = 'disburse' | 'edit' | 'supplement'
@@ -439,6 +449,7 @@ const deleteLoadingMap = reactive<Record<string, boolean>>({})
const selectedRows = ref<VehicleUreaDisburseBoardItem[]>([])
const tableData = ref<VehicleUreaDisburseBoardItem[]>([])
const vehicleOptions = ref<Vehicle[]>([])
const vehicleTrailerLookup = computed(() => buildVehicleTrailerLookup(vehicleOptions.value))
const applyDateRange = ref<string[]>([])
const disburseDateRange = ref<string[]>([])
const quickSearchKeyword = ref('')
+4 -1
View File
@@ -126,7 +126,9 @@
header-align="center"
>
<template #default="{ row }">
<el-link type="primary" @click="handleView(row)">{{ row.licensePlate }}</el-link>
<el-link type="primary" @click="handleView(row)">
{{ formatPlVehiclePlateDisplay(row.licensePlate, row.trailerNo) }}
</el-link>
</template>
</el-table-column>
<el-table-column label="车辆类型" min-width="100" align="center" header-align="center" v-if="isColumnVisible('vehicleType')">
@@ -417,6 +419,7 @@ import { useDbInstantSearch } from '@/composables/useDbInstantSearch'
import { pickBxList, pickBxPageResult } from '@/utils/http/bx'
import { DEFAULT_LIST_PAGE_SIZE } from '@/utils/table/tableConfig'
import { formatDateTime } from '@/utils/format'
import { formatPlVehiclePlateDisplay } from '@/utils/pl-display'
import {
PL_VEHICLE_CERT_NAME_OPTIONS,
splitVehicleCertsByPart,