提交
This commit is contained in:
1 parent
c2cba3e668
commit
2142b33cfa
24 files changed
+4834
-3684
No files matched your search
BIN
Binary file not shown.
+1
-1
@@ -1 +1 @@
|
||||
6907
|
||||
27076
|
||||
@@ -26,6 +26,7 @@ from app.schemas.pl import (
|
||||
CarrierRead,
|
||||
CarrierUpdate,
|
||||
carrier_to_read,
|
||||
CertRead,
|
||||
DriverCreate,
|
||||
DriverListResponse,
|
||||
DriverRead,
|
||||
@@ -45,6 +46,7 @@ from app.schemas.pl import (
|
||||
from app.services.pl_cert_service import (
|
||||
certs_to_read,
|
||||
list_owner_certs,
|
||||
list_owner_certs_batch,
|
||||
nearest_expire_date,
|
||||
save_owner_certs,
|
||||
)
|
||||
@@ -276,12 +278,16 @@ def _vehicle_to_read(
|
||||
vehicle: PlVehicle,
|
||||
summary: Optional[str] = None,
|
||||
default_driver_name: Optional[str] = None,
|
||||
*,
|
||||
cert_list: Optional[list[CertRead]] = None,
|
||||
) -> VehicleRead:
|
||||
data = VehicleRead.model_validate(vehicle)
|
||||
if summary is not None:
|
||||
data.personnel_summary = summary
|
||||
if default_driver_name is not None:
|
||||
data.default_driver_name = default_driver_name
|
||||
if cert_list is not None:
|
||||
data.cert_list = cert_list
|
||||
return data
|
||||
|
||||
|
||||
@@ -296,7 +302,7 @@ def _vehicle_to_detail(
|
||||
)
|
||||
base = _vehicle_to_read(vehicle, summary, default_name)
|
||||
return VehicleDetailRead(
|
||||
**base.model_dump(by_alias=False),
|
||||
**base.model_dump(by_alias=False, exclude={"cert_list"}),
|
||||
personnel_list=personnel_list,
|
||||
cert_list=cert_list,
|
||||
)
|
||||
@@ -373,8 +379,15 @@ def list_vehicles(
|
||||
summaries = load_vehicle_personnel_summaries(
|
||||
db, tenant_no, [v.id for v in vehicles]
|
||||
)
|
||||
certs_by_owner = list_owner_certs_batch(
|
||||
db, tenant_no, "vehicle", [v.id for v in vehicles]
|
||||
)
|
||||
items = [
|
||||
_vehicle_to_read(v, *summaries.get(v.id, ("", None)))
|
||||
_vehicle_to_read(
|
||||
v,
|
||||
*summaries.get(v.id, ("", None)),
|
||||
cert_list=certs_to_read(certs_by_owner.get(v.id, [])),
|
||||
)
|
||||
for v in vehicles
|
||||
]
|
||||
return VehicleListResponse(total=len(items), list=items)
|
||||
@@ -385,10 +398,17 @@ def list_vehicles(
|
||||
summaries = load_vehicle_personnel_summaries(
|
||||
db, tenant_no, [v.id for v in vehicles]
|
||||
)
|
||||
certs_by_owner = list_owner_certs_batch(
|
||||
db, tenant_no, "vehicle", [v.id for v in vehicles]
|
||||
)
|
||||
return VehicleListResponse(
|
||||
total=total,
|
||||
list=[
|
||||
_vehicle_to_read(v, *summaries.get(v.id, ("", None)))
|
||||
_vehicle_to_read(
|
||||
v,
|
||||
*summaries.get(v.id, ("", None)),
|
||||
cert_list=certs_to_read(certs_by_owner.get(v.id, [])),
|
||||
)
|
||||
for v in vehicles
|
||||
],
|
||||
)
|
||||
@@ -591,11 +611,17 @@ def _get_vehicle(db: Session, tenant_no: str, vehicle_id: str, user: DbUserConte
|
||||
|
||||
|
||||
def _personnel_to_read(
|
||||
db: Session, tenant_no: str, personnel: PlPersonnel
|
||||
db: Session,
|
||||
tenant_no: str,
|
||||
personnel: PlPersonnel,
|
||||
*,
|
||||
cert_list: Optional[list[CertRead]] = None,
|
||||
) -> PersonnelRead:
|
||||
nearest = nearest_expire_date(db, tenant_no, "personnel", personnel.id)
|
||||
data = PersonnelRead.model_validate(personnel)
|
||||
data.nearest_expire_date = nearest
|
||||
if cert_list is not None:
|
||||
data.cert_list = cert_list
|
||||
return data
|
||||
|
||||
|
||||
@@ -607,7 +633,7 @@ def _personnel_to_detail(
|
||||
list_owner_certs(db, tenant_no, "personnel", personnel.id)
|
||||
)
|
||||
return PersonnelDetailRead(
|
||||
**base.model_dump(by_alias=False),
|
||||
**base.model_dump(by_alias=False, exclude={"cert_list"}),
|
||||
cert_list=cert_list,
|
||||
)
|
||||
|
||||
@@ -653,9 +679,19 @@ def list_personnel(
|
||||
total = query.count()
|
||||
offset = (page - 1) * page_size
|
||||
rows = query.offset(offset).limit(page_size).all()
|
||||
personnel_ids = [p.id for p in rows]
|
||||
certs_by_owner = list_owner_certs_batch(db, tenant_no, "personnel", personnel_ids)
|
||||
return PersonnelListResponse(
|
||||
total=total,
|
||||
list=[_personnel_to_read(db, tenant_no, p) for p in rows],
|
||||
list=[
|
||||
_personnel_to_read(
|
||||
db,
|
||||
tenant_no,
|
||||
p,
|
||||
cert_list=certs_to_read(certs_by_owner.get(p.id, [])),
|
||||
)
|
||||
for p in rows
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -247,6 +247,7 @@ class VehicleRead(VehicleBase):
|
||||
tenant_no: str = Field(alias="tenantNo")
|
||||
order_num: Optional[int] = Field(default=None, alias="orderNum")
|
||||
personnel_summary: Optional[str] = Field(default=None, alias="personnelSummary")
|
||||
cert_list: Optional[list[CertRead]] = Field(default=None, alias="certList")
|
||||
create_by: Optional[str] = Field(default=None, alias="createBy")
|
||||
create_dept_id: Optional[str] = Field(default=None, alias="createDeptId")
|
||||
create_time: datetime = Field(alias="createTime")
|
||||
@@ -313,6 +314,7 @@ class PersonnelRead(PersonnelBase):
|
||||
tenant_no: str = Field(alias="tenantNo")
|
||||
order_num: Optional[int] = Field(default=None, alias="orderNum")
|
||||
nearest_expire_date: Optional[date] = Field(default=None, alias="nearestExpireDate")
|
||||
cert_list: Optional[list[CertRead]] = Field(default=None, alias="certList")
|
||||
create_by: Optional[str] = Field(default=None, alias="createBy")
|
||||
create_dept_id: Optional[str] = Field(default=None, alias="createDeptId")
|
||||
create_time: datetime = Field(alias="createTime")
|
||||
|
||||
@@ -18,7 +18,6 @@ def carrier_qualification_complete(carrier: PlCarrier) -> bool:
|
||||
_urls_nonempty(carrier.business_license_urls)
|
||||
and _urls_nonempty(carrier.road_transport_license_urls)
|
||||
and _urls_nonempty(carrier.transport_agreement_urls)
|
||||
and carrier.transport_agreement_expire_date is not None
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -27,6 +27,28 @@ def list_owner_certs(
|
||||
)
|
||||
|
||||
|
||||
def list_owner_certs_batch(
|
||||
db: Session, tenant_no: str, owner_type: str, owner_ids: list[str]
|
||||
) -> dict[str, list[PlCert]]:
|
||||
if not owner_ids:
|
||||
return {}
|
||||
rows = (
|
||||
db.query(PlCert)
|
||||
.filter(
|
||||
PlCert.tenant_no == tenant_no,
|
||||
PlCert.owner_type == owner_type,
|
||||
PlCert.owner_id.in_(owner_ids),
|
||||
PlCert.del_flag == 0,
|
||||
)
|
||||
.order_by(PlCert.order_num.asc(), PlCert.create_time.asc())
|
||||
.all()
|
||||
)
|
||||
grouped: dict[str, list[PlCert]] = {}
|
||||
for cert in rows:
|
||||
grouped.setdefault(cert.owner_id, []).append(cert)
|
||||
return grouped
|
||||
|
||||
|
||||
def certs_to_read(certs: list[PlCert]) -> list[CertRead]:
|
||||
return [
|
||||
CertRead(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Graph Report - backend (2026-07-12)
|
||||
|
||||
## Corpus Check
|
||||
- 248 files · ~173,671 words
|
||||
- 248 files · ~173,666 words
|
||||
- Verdict: corpus is large enough that graph structure adds value.
|
||||
|
||||
## Summary
|
||||
@@ -10,7 +10,7 @@
|
||||
- Token cost: 0 input · 0 output
|
||||
|
||||
## Graph Freshness
|
||||
- Built from commit: `ffc89d9b`
|
||||
- Built from commit: `c2cba3e6`
|
||||
- Run `git rev-parse HEAD` and compare to check if the graph is stale.
|
||||
- Run `graphify update .` after code changes (no API cost).
|
||||
|
||||
|
||||
backend/graphify-out/cache/ast/7d12991ffd2e3d7b768aaa587d7f9ae1ed4d641f65ec3f053ed103fc74a5a005.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_services_pl_carrier_service_py", "label": "pl_carrier_service.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_carrier_service.py", "source_location": "L1"}, {"id": "services_pl_carrier_service_urls_nonempty", "label": "_urls_nonempty()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_carrier_service.py", "source_location": "L12"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_carrier_service.py", "source_location": "L12"}, {"id": "bool", "label": "bool", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_carrier_service.py", "source_location": "L12"}, {"id": "services_pl_carrier_service_carrier_qualification_complete", "label": "carrier_qualification_complete()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_carrier_service.py", "source_location": "L16"}, {"id": "plcarrier", "label": "PlCarrier", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_carrier_service.py", "source_location": "L16"}, {"id": "services_pl_carrier_service_carrier_agreement_expired", "label": "carrier_agreement_expired()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_carrier_service.py", "source_location": "L24"}, {"id": "date", "label": "date", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_carrier_service.py", "source_location": "L24"}, {"id": "services_pl_carrier_service_carrier_audit_approved", "label": "carrier_audit_approved()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_carrier_service.py", "source_location": "L32"}, {"id": "services_pl_carrier_service_carrier_eligible_for_transport", "label": "carrier_eligible_for_transport()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_carrier_service.py", "source_location": "L36"}, {"id": "services_pl_carrier_service_assert_carrier_eligible_for_transport", "label": "assert_carrier_eligible_for_transport()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_carrier_service.py", "source_location": "L48"}, {"id": "services_pl_carrier_service_normalize_carrier_urls", "label": "normalize_carrier_urls()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_carrier_service.py", "source_location": "L68"}, {"id": "services_pl_carrier_service_validate_carrier_qualification_fields", "label": "validate_carrier_qualification_fields()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_carrier_service.py", "source_location": "L75"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_pl_carrier_service_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_carrier_service.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_pl_carrier_service_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_carrier_service.py", "source_location": "L5", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_pl_carrier_service_py", "target": "fastapi", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_carrier_service.py", "source_location": "L7", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_pl_carrier_service_py", "target": "app_models_pl_models", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_carrier_service.py", "source_location": "L9", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_pl_carrier_service_py", "target": "services_pl_carrier_service_urls_nonempty", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_carrier_service.py", "source_location": "L12", "weight": 1.0}, {"source": "services_pl_carrier_service_urls_nonempty", "target": "str", "relation": "references", "context": "generic_arg", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_carrier_service.py", "source_location": "L12", "weight": 1.0}, {"source": "services_pl_carrier_service_urls_nLine truncated
|
||||
+1
-1
@@ -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":6716,"mtime_ns":1783761682571576393,"hash":"bbe64081c9790941eb2fa8f9c18ee39daf151068b3503f1fdb74c2cb9f7b5b45"},"/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":6716,"mtime_ns":1783761682571576393,"hash":"bbe64081c9790941eb2fa8f9c18ee39daf151068b3503f1fdb74c2cb9f7b5b45"},"/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
|
||||
@@ -31011,7 +31011,7 @@
|
||||
"label": "carrier_agreement_expired()",
|
||||
"file_type": "code",
|
||||
"source_file": "app/services/pl_carrier_service.py",
|
||||
"source_location": "L25",
|
||||
"source_location": "L24",
|
||||
"id": "services_pl_carrier_service_carrier_agreement_expired",
|
||||
"community": 4,
|
||||
"norm_label": "carrier_agreement_expired()"
|
||||
@@ -31020,7 +31020,7 @@
|
||||
"label": "date",
|
||||
"file_type": "code",
|
||||
"source_file": "app/services/pl_carrier_service.py",
|
||||
"source_location": "L25",
|
||||
"source_location": "L24",
|
||||
"id": "app_services_pl_carrier_service_py_date",
|
||||
"community": 4,
|
||||
"norm_label": "date"
|
||||
@@ -31029,7 +31029,7 @@
|
||||
"label": "carrier_audit_approved()",
|
||||
"file_type": "code",
|
||||
"source_file": "app/services/pl_carrier_service.py",
|
||||
"source_location": "L33",
|
||||
"source_location": "L32",
|
||||
"id": "services_pl_carrier_service_carrier_audit_approved",
|
||||
"community": 4,
|
||||
"norm_label": "carrier_audit_approved()"
|
||||
@@ -31038,7 +31038,7 @@
|
||||
"label": "carrier_eligible_for_transport()",
|
||||
"file_type": "code",
|
||||
"source_file": "app/services/pl_carrier_service.py",
|
||||
"source_location": "L37",
|
||||
"source_location": "L36",
|
||||
"id": "services_pl_carrier_service_carrier_eligible_for_transport",
|
||||
"community": 4,
|
||||
"norm_label": "carrier_eligible_for_transport()"
|
||||
@@ -31047,7 +31047,7 @@
|
||||
"label": "assert_carrier_eligible_for_transport()",
|
||||
"file_type": "code",
|
||||
"source_file": "app/services/pl_carrier_service.py",
|
||||
"source_location": "L49",
|
||||
"source_location": "L48",
|
||||
"id": "services_pl_carrier_service_assert_carrier_eligible_for_transport",
|
||||
"community": 4,
|
||||
"norm_label": "assert_carrier_eligible_for_transport()"
|
||||
@@ -31056,7 +31056,7 @@
|
||||
"label": "normalize_carrier_urls()",
|
||||
"file_type": "code",
|
||||
"source_file": "app/services/pl_carrier_service.py",
|
||||
"source_location": "L69",
|
||||
"source_location": "L68",
|
||||
"id": "services_pl_carrier_service_normalize_carrier_urls",
|
||||
"community": 4,
|
||||
"norm_label": "normalize_carrier_urls()"
|
||||
@@ -31065,7 +31065,7 @@
|
||||
"label": "validate_carrier_qualification_fields()",
|
||||
"file_type": "code",
|
||||
"source_file": "app/services/pl_carrier_service.py",
|
||||
"source_location": "L76",
|
||||
"source_location": "L75",
|
||||
"id": "services_pl_carrier_service_validate_carrier_qualification_fields",
|
||||
"community": 4,
|
||||
"norm_label": "validate_carrier_qualification_fields()"
|
||||
@@ -355014,9 +355014,9 @@
|
||||
"source_file": "app/api/pl/plan.py",
|
||||
"source_location": "L55",
|
||||
"weight": 1.0,
|
||||
"confidence_score": 1.0,
|
||||
"source": "app_api_pl_plan_py",
|
||||
"target": "services_pl_plan_service_validate_hazard_cert_ready_for_transport",
|
||||
"confidence_score": 1.0
|
||||
"target": "services_pl_plan_service_validate_hazard_cert_ready_for_transport"
|
||||
},
|
||||
{
|
||||
"relation": "imports",
|
||||
@@ -355302,9 +355302,9 @@
|
||||
"source_file": "app/api/pl/plan.py",
|
||||
"source_location": "L85",
|
||||
"weight": 1.0,
|
||||
"confidence_score": 1.0,
|
||||
"source": "pl_plan_rationale_85",
|
||||
"target": "pl_plan_generate_plan_no",
|
||||
"confidence_score": 1.0
|
||||
"target": "pl_plan_generate_plan_no"
|
||||
},
|
||||
{
|
||||
"relation": "uses",
|
||||
@@ -356476,9 +356476,9 @@
|
||||
"source_file": "app/api/pl/plan.py",
|
||||
"source_location": "L121",
|
||||
"weight": 1.0,
|
||||
"confidence_score": 1.0,
|
||||
"source": "pl_plan_rationale_121",
|
||||
"target": "pl_plan_normalize_subpack_slip_no",
|
||||
"confidence_score": 1.0
|
||||
"target": "pl_plan_normalize_subpack_slip_no"
|
||||
},
|
||||
{
|
||||
"relation": "calls",
|
||||
@@ -356614,9 +356614,9 @@
|
||||
"source_file": "app/api/pl/plan.py",
|
||||
"source_location": "L154",
|
||||
"weight": 1.0,
|
||||
"confidence_score": 1.0,
|
||||
"source": "pl_plan_rationale_154",
|
||||
"target": "pl_plan_ensure_subpack_slip_no",
|
||||
"confidence_score": 1.0
|
||||
"target": "pl_plan_ensure_subpack_slip_no"
|
||||
},
|
||||
{
|
||||
"relation": "uses",
|
||||
@@ -359341,9 +359341,9 @@
|
||||
"source_file": "app/api/pl/plan.py",
|
||||
"source_location": "L448",
|
||||
"weight": 1.0,
|
||||
"confidence_score": 1.0,
|
||||
"source": "pl_plan_rationale_448",
|
||||
"target": "pl_plan_create_plan_full",
|
||||
"confidence_score": 1.0
|
||||
"target": "pl_plan_create_plan_full"
|
||||
},
|
||||
{
|
||||
"relation": "uses",
|
||||
@@ -361376,9 +361376,9 @@
|
||||
"source_file": "app/api/pl/plan.py",
|
||||
"source_location": "L834",
|
||||
"weight": 1.0,
|
||||
"confidence_score": 1.0,
|
||||
"source": "pl_plan_rationale_834",
|
||||
"target": "pl_plan_patch_plan_product_certs",
|
||||
"confidence_score": 1.0
|
||||
"target": "pl_plan_patch_plan_product_certs"
|
||||
},
|
||||
{
|
||||
"relation": "uses",
|
||||
@@ -362056,9 +362056,9 @@
|
||||
"source_file": "app/api/pl/plan.py",
|
||||
"source_location": "L902",
|
||||
"weight": 1.0,
|
||||
"confidence_score": 1.0,
|
||||
"source": "pl_plan_rationale_902",
|
||||
"target": "pl_plan_get_plan_arrange_info",
|
||||
"confidence_score": 1.0
|
||||
"target": "pl_plan_get_plan_arrange_info"
|
||||
},
|
||||
{
|
||||
"relation": "uses",
|
||||
@@ -362250,9 +362250,9 @@
|
||||
"source_file": "app/api/pl/plan.py",
|
||||
"source_location": "L1016",
|
||||
"weight": 1.0,
|
||||
"confidence_score": 1.0,
|
||||
"source": "pl_plan_rationale_1016",
|
||||
"target": "pl_plan_cancel_plan",
|
||||
"confidence_score": 1.0
|
||||
"target": "pl_plan_cancel_plan"
|
||||
},
|
||||
{
|
||||
"relation": "rationale_for",
|
||||
@@ -452721,5 +452721,5 @@
|
||||
}
|
||||
],
|
||||
"hyperedges": [],
|
||||
"built_at_commit": "ffc89d9b57bbaab7a896d352ecd3490e29f8bab1"
|
||||
"built_at_commit": "c2cba3e6686ec33b687bc004150df8717ee53a08"
|
||||
}
|
||||
+29
-19
@@ -445,7 +445,7 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/contract.py": {
|
||||
"mtime": 1783845455.3648205,
|
||||
"mtime": 1783848308.6951036,
|
||||
"ast_hash": "6553f54ca1fd19086c170095f402a628",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -920,8 +920,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_carrier_service.py": {
|
||||
"mtime": 1783176693.3633482,
|
||||
"ast_hash": "bded41d6221c370a4a575df2a2932842",
|
||||
"mtime": 1783848338.6043966,
|
||||
"ast_hash": "fed11a0ecf60f2e55671c4f97efc16e7",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/services/pl_dibang_bridge_service.py": {
|
||||
@@ -2530,8 +2530,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/utils/pl-personnel-cert.ts": {
|
||||
"mtime": 1783845064.4713657,
|
||||
"ast_hash": "0e5d989ac54b364a5983a5f9af9fd6d6",
|
||||
"mtime": 1783849542.7557807,
|
||||
"ast_hash": "b063105c550403d69893f65d3da2f70c",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/utils/patch-el-select-filterable.ts": {
|
||||
@@ -2685,8 +2685,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/utils/pl-vehicle-cert.ts": {
|
||||
"mtime": 1783844738.0471256,
|
||||
"ast_hash": "873ca5c7a0f7afbfa44925292f3f68ff",
|
||||
"mtime": 1783849840.3343875,
|
||||
"ast_hash": "d7537c9326ca88ffb699852e5ce1832b",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/utils/protocol-payment-installment.ts": {
|
||||
@@ -3585,8 +3585,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/business/pl-cert-form-list/index.vue": {
|
||||
"mtime": 1783844774.5544193,
|
||||
"ast_hash": "675188fc7671fde3487a942e3b9af0d3",
|
||||
"mtime": 1783849061.800741,
|
||||
"ast_hash": "952e011c4aa5d0432a808ad15fd11e88",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/business/product-view-dialog/index.vue": {
|
||||
@@ -3980,8 +3980,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/api/pl/index.ts": {
|
||||
"mtime": 1783845066.0273972,
|
||||
"ast_hash": "fa2ffcb5318c1ed1a6a06855422880d9",
|
||||
"mtime": 1783849851.9140031,
|
||||
"ast_hash": "b4a408e66eb8617b69385fcf85fb61d5",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/api/pl/public-transport.ts": {
|
||||
@@ -4165,8 +4165,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/pl/vehicle/index.vue": {
|
||||
"mtime": 1783845088.2792692,
|
||||
"ast_hash": "23f9cedc7e3b87b4d670e429cf736a55",
|
||||
"mtime": 1783849865.9450529,
|
||||
"ast_hash": "f9e41919cf3d272be092e81cdfe5e099",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/pl/vehicle-recharge-record/index.vue": {
|
||||
@@ -4290,18 +4290,18 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/pl/self-vehicle/index.vue": {
|
||||
"mtime": 1783845096.14697,
|
||||
"ast_hash": "25357bf2f887716989f8197285b5964e",
|
||||
"mtime": 1783849866.0242345,
|
||||
"ast_hash": "fa30de07b7abafca0ece57dd6b0fd8fb",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/pl/carrier/index.vue": {
|
||||
"mtime": 1783841744.362471,
|
||||
"ast_hash": "1fcfd92cfd0d2b344d2110d7164b4b2a",
|
||||
"mtime": 1783848560.1515188,
|
||||
"ast_hash": "f1d3d5928211e9ad85159f91829d7cf5",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/pl/personnel/index.vue": {
|
||||
"mtime": 1783845137.1568706,
|
||||
"ast_hash": "f12fbbc1e2a8e2e7cc1d3c6df3ceff6f",
|
||||
"mtime": 1783849448.5590773,
|
||||
"ast_hash": "d71558db33a5c5531066cf3983b02a7a",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/pl/vehicle-maintenance-process/index.vue": {
|
||||
@@ -7418,5 +7418,15 @@
|
||||
"mtime": 1783845019.9129975,
|
||||
"ast_hash": "f97c57b5fac34dc5d47491e9de4c1769",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/business/pl-personnel-cert-badges/index.vue": {
|
||||
"mtime": 1783849544.4685943,
|
||||
"ast_hash": "65e1bb7e36f003b903fe47d3e6aaf85c",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/business/pl-vehicle-cert-badges/index.vue": {
|
||||
"mtime": 1783849842.8025723,
|
||||
"ast_hash": "d20bf8839872ffdd5c9939159ded0772",
|
||||
"semantic_hash": ""
|
||||
}
|
||||
}
|
||||
@@ -267,12 +267,14 @@
|
||||
"265": "Community 265",
|
||||
"266": "Community 266",
|
||||
"267": "Community 267",
|
||||
"268": "Community 268",
|
||||
"269": "Community 269",
|
||||
"270": "Community 270",
|
||||
"271": "Community 271",
|
||||
"272": "Community 272",
|
||||
"273": "Community 273",
|
||||
"274": "Community 274",
|
||||
"275": "Community 275",
|
||||
"276": "Community 276",
|
||||
"277": "Community 277",
|
||||
"278": "Community 278",
|
||||
@@ -616,6 +618,7 @@
|
||||
"616": "Community 616",
|
||||
"617": "Community 617",
|
||||
"618": "Community 618",
|
||||
"619": "Community 619",
|
||||
"620": "Community 620",
|
||||
"621": "Community 621",
|
||||
"622": "Community 622",
|
||||
@@ -679,6 +682,7 @@
|
||||
"680": "Community 680",
|
||||
"681": "Community 681",
|
||||
"682": "Community 682",
|
||||
"683": "Community 683",
|
||||
"684": "Community 684",
|
||||
"685": "Community 685",
|
||||
"686": "Community 686",
|
||||
@@ -707,6 +711,7 @@
|
||||
"709": "Community 709",
|
||||
"710": "Community 710",
|
||||
"711": "Community 711",
|
||||
"712": "Community 712",
|
||||
"713": "Community 713",
|
||||
"714": "Community 714",
|
||||
"715": "Community 715",
|
||||
@@ -720,15 +725,10 @@
|
||||
"723": "Community 723",
|
||||
"724": "Community 724",
|
||||
"725": "Community 725",
|
||||
"727": "Community 727",
|
||||
"728": "Community 728",
|
||||
"729": "Community 729",
|
||||
"730": "Community 730",
|
||||
"732": "Community 732",
|
||||
"733": "Community 733",
|
||||
"735": "Community 735",
|
||||
"736": "Community 736",
|
||||
"737": "Community 737",
|
||||
"738": "Community 738",
|
||||
"739": "Community 739",
|
||||
"742": "Community 742"
|
||||
"737": "Community 737"
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
+3742
-3195
File diff suppressed because it is too large.
Load diff
@@ -99,6 +99,7 @@ export interface Vehicle {
|
||||
loadCapacity?: number
|
||||
vehicleStatus: string
|
||||
remark?: string
|
||||
certList?: CertRead[]
|
||||
createTime: string
|
||||
}
|
||||
|
||||
@@ -152,6 +153,7 @@ export interface Personnel {
|
||||
status: string
|
||||
remark?: string
|
||||
nearestExpireDate?: string
|
||||
certList?: CertRead[]
|
||||
createTime: string
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,13 @@
|
||||
|
||||
<div v-if="!certList.length" class="cert-empty">{{ emptyHint }}</div>
|
||||
|
||||
<el-table v-else-if="layout === 'table'" :data="certList" stripe class="list-table cert-form-table">
|
||||
<el-table
|
||||
v-else-if="layout === 'table'"
|
||||
:data="certList"
|
||||
stripe
|
||||
class="list-table cert-form-table"
|
||||
:row-class-name="showVehiclePartColumn ? getCertRowClassName : undefined"
|
||||
>
|
||||
<el-table-column type="index" label="序号" min-width="68" align="center" header-align="center" />
|
||||
<el-table-column
|
||||
v-if="showVehiclePartColumn"
|
||||
@@ -298,6 +304,13 @@ function handleVehiclePartChange(row: CertRowWithKey, value: string) {
|
||||
row.vehiclePart = normalizeVehicleCertPart(value)
|
||||
}
|
||||
|
||||
function getCertRowClassName({ row }: { row: CertRowWithKey }) {
|
||||
if (!props.showVehiclePartColumn) return ''
|
||||
return normalizeVehicleCertPart(row.vehiclePart) === PL_VEHICLE_CERT_PART_TRAILER
|
||||
? 'cert-row-trailer'
|
||||
: 'cert-row-head'
|
||||
}
|
||||
|
||||
const certList = defineModel<CertRowWithKey[]>('modelValue', { default: () => [] })
|
||||
|
||||
watch(
|
||||
@@ -407,6 +420,14 @@ defineExpose({ hasUploading, clearUploadRefs, refreshRequiredSlots })
|
||||
.cert-form-table {
|
||||
border-top: 1px solid var(--mint-border, #d9e8e2);
|
||||
|
||||
:deep(.cert-row-head td.el-table__cell) {
|
||||
background-color: #ecfdf5 !important;
|
||||
}
|
||||
|
||||
:deep(.cert-row-trailer td.el-table__cell) {
|
||||
background-color: #fffbeb !important;
|
||||
}
|
||||
|
||||
:deep(.el-select),
|
||||
:deep(.el-input),
|
||||
:deep(.el-date-editor) {
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
<template>
|
||||
<div v-if="badges.length" class="pl-personnel-cert-badges">
|
||||
<el-tooltip
|
||||
v-for="badge in badges"
|
||||
:key="badge.requiredName"
|
||||
:content="badge.title"
|
||||
placement="top"
|
||||
>
|
||||
<span
|
||||
class="pl-personnel-cert-badges__item"
|
||||
:class="`pl-personnel-cert-badges__item--${badge.status}`"
|
||||
>
|
||||
{{ badge.shortLabel }}
|
||||
</span>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import type { CertRead } from '@/api/pl'
|
||||
import { getPersonnelRequiredCertBadges } from '@/utils/pl-personnel-cert'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
personnelType?: string | null
|
||||
certList?: CertRead[]
|
||||
}>(),
|
||||
{
|
||||
personnelType: '',
|
||||
certList: () => []
|
||||
}
|
||||
)
|
||||
|
||||
const badges = computed(() =>
|
||||
getPersonnelRequiredCertBadges(props.personnelType, props.certList || [])
|
||||
)
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.pl-personnel-cert-badges {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.pl-personnel-cert-badges__item {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 20px;
|
||||
height: 20px;
|
||||
padding: 0 4px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
line-height: 1;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.pl-personnel-cert-badges__item--missing {
|
||||
background: #f1f5f9;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.pl-personnel-cert-badges__item--valid {
|
||||
background: #ecfdf5;
|
||||
color: #059669;
|
||||
}
|
||||
|
||||
.pl-personnel-cert-badges__item--expiring {
|
||||
background: #fffbeb;
|
||||
color: #d97706;
|
||||
}
|
||||
|
||||
.pl-personnel-cert-badges__item--expired {
|
||||
background: #fef2f2;
|
||||
color: #dc2626;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,135 @@
|
||||
<template>
|
||||
<span v-if="badgeGroups.length" class="pl-vehicle-cert-badges">
|
||||
<span class="pl-vehicle-cert-badges__paren">(</span>
|
||||
<template v-for="(group, groupIndex) in badgeGroups" :key="group.key">
|
||||
<span v-if="groupIndex > 0" class="pl-vehicle-cert-badges__divider">|</span>
|
||||
<span class="pl-vehicle-cert-badges__group">
|
||||
<el-tooltip
|
||||
v-for="badge in group.badges"
|
||||
:key="`${group.key}-${badge.requiredName}`"
|
||||
:content="badge.title"
|
||||
placement="top"
|
||||
>
|
||||
<span
|
||||
class="pl-vehicle-cert-badges__item"
|
||||
:class="`pl-vehicle-cert-badges__item--${badge.status}`"
|
||||
>
|
||||
{{ badge.shortLabel }}
|
||||
</span>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
</template>
|
||||
<span class="pl-vehicle-cert-badges__paren">)</span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import type { CertRead } from '@/api/pl'
|
||||
import {
|
||||
PL_VEHICLE_CERT_PART_HEAD,
|
||||
PL_VEHICLE_CERT_PART_TRAILER,
|
||||
getVehiclePartRequiredCertBadges,
|
||||
type PlVehicleCertCheckType
|
||||
} from '@/utils/pl-vehicle-cert'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
vehicleType?: PlVehicleCertCheckType
|
||||
certList?: CertRead[]
|
||||
trailerNo?: string | null
|
||||
}>(),
|
||||
{
|
||||
vehicleType: 'self',
|
||||
certList: () => [],
|
||||
trailerNo: ''
|
||||
}
|
||||
)
|
||||
|
||||
const hasTrailer = computed(() => Boolean(props.trailerNo?.trim()))
|
||||
|
||||
const badgeGroups = computed(() => {
|
||||
const groups = [
|
||||
{
|
||||
key: PL_VEHICLE_CERT_PART_HEAD,
|
||||
badges: getVehiclePartRequiredCertBadges({
|
||||
vehicleType: props.vehicleType,
|
||||
certList: props.certList || [],
|
||||
part: PL_VEHICLE_CERT_PART_HEAD,
|
||||
partLabel: hasTrailer.value ? '主车' : ''
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
if (hasTrailer.value) {
|
||||
groups.push({
|
||||
key: PL_VEHICLE_CERT_PART_TRAILER,
|
||||
badges: getVehiclePartRequiredCertBadges({
|
||||
vehicleType: props.vehicleType,
|
||||
certList: props.certList || [],
|
||||
part: PL_VEHICLE_CERT_PART_TRAILER,
|
||||
partLabel: '挂车'
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
return groups
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.pl-vehicle-cert-badges {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
gap: 4px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.pl-vehicle-cert-badges__paren,
|
||||
.pl-vehicle-cert-badges__divider {
|
||||
font-size: 12px;
|
||||
color: var(--mint-text-muted, #64748b);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.pl-vehicle-cert-badges__group {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.pl-vehicle-cert-badges__item {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 20px;
|
||||
height: 20px;
|
||||
padding: 0 4px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
line-height: 1;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.pl-vehicle-cert-badges__item--missing {
|
||||
background: #f1f5f9;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.pl-vehicle-cert-badges__item--valid {
|
||||
background: #ecfdf5;
|
||||
color: #059669;
|
||||
}
|
||||
|
||||
.pl-vehicle-cert-badges__item--expiring {
|
||||
background: #fffbeb;
|
||||
color: #d97706;
|
||||
}
|
||||
|
||||
.pl-vehicle-cert-badges__item--expired {
|
||||
background: #fef2f2;
|
||||
color: #dc2626;
|
||||
}
|
||||
</style>
|
||||
@@ -72,6 +72,16 @@ export function getRequiredPersonnelCertNamesByType(
|
||||
return PL_PERSONNEL_DRIVER_REQUIRED_CERT_NAMES
|
||||
}
|
||||
|
||||
/** 车辆关联人员:从人员主数据类型映射为关联角色(司机/押运员) */
|
||||
export function mapPersonnelTypeToVehicleRole(
|
||||
personnelType?: string | null
|
||||
): 'driver' | 'escort' | undefined {
|
||||
if (personnelType === 'driver') return 'driver'
|
||||
if (personnelType === 'escort') return 'escort'
|
||||
if (personnelType === 'both') return 'driver'
|
||||
return undefined
|
||||
}
|
||||
|
||||
export function validatePersonnelTypeRoleCompat(
|
||||
personnelType: string | undefined,
|
||||
role: string | undefined,
|
||||
@@ -176,3 +186,102 @@ export function getPersonnelCertMissingSuffix(
|
||||
}
|
||||
return hasPersonnelMasterCertMissing(certList) ? PL_PERSONNEL_CERT_MISSING_SUFFIX : ''
|
||||
}
|
||||
|
||||
export const PL_PERSONNEL_CERT_SHORT_LABELS: Record<string, string> = {
|
||||
身份证: '身',
|
||||
驾驶证: '驾',
|
||||
从业资格证: '业'
|
||||
}
|
||||
|
||||
export type PersonnelCertBadgeStatus = 'missing' | 'valid' | 'expiring' | 'expired'
|
||||
|
||||
export interface PersonnelCertBadgeItem {
|
||||
requiredName: string
|
||||
shortLabel: string
|
||||
status: PersonnelCertBadgeStatus
|
||||
title: string
|
||||
}
|
||||
|
||||
function getPersonnelCertMissingFieldLabels(
|
||||
cert: Pick<CertRow, 'certName' | 'certNo' | 'expireDate' | 'attachmentUrls'> | undefined,
|
||||
requiredName: string
|
||||
): string[] {
|
||||
if (!cert || !matchRequiredCertName(cert.certName, requiredName)) {
|
||||
return ['证号', '有效期', '附件']
|
||||
}
|
||||
const missing: string[] = []
|
||||
if (!cert.certNo?.trim()) missing.push('证号')
|
||||
if (!cert.expireDate) missing.push('有效期')
|
||||
if (!cert.attachmentUrls?.trim()) missing.push('附件')
|
||||
return missing
|
||||
}
|
||||
|
||||
function formatPersonnelCertBadgeTooltip(
|
||||
requiredName: string,
|
||||
status: PersonnelCertBadgeStatus,
|
||||
cert?: Pick<CertRow, 'certName' | 'certNo' | 'expireDate' | 'attachmentUrls' | 'remindDays'>
|
||||
): string {
|
||||
if (status === 'missing') {
|
||||
if (!cert || !matchRequiredCertName(cert.certName, requiredName)) {
|
||||
return `${requiredName}:缺失(未登记该证书)`
|
||||
}
|
||||
const missing = getPersonnelCertMissingFieldLabels(cert, requiredName)
|
||||
return `${requiredName}:缺失(缺少${missing.join('、')})`
|
||||
}
|
||||
|
||||
const expireDate = cert?.expireDate || '—'
|
||||
const expDate = new Date(expireDate)
|
||||
const today = new Date()
|
||||
today.setHours(0, 0, 0, 0)
|
||||
expDate.setHours(0, 0, 0, 0)
|
||||
const diffDays = Math.ceil((expDate.getTime() - today.getTime()) / (1000 * 60 * 60 * 24))
|
||||
const certNo = cert?.certNo?.trim()
|
||||
const certNoText = certNo ? `,证号 ${certNo}` : ''
|
||||
|
||||
if (status === 'expired') {
|
||||
return `${requiredName}:已过期,有效期 ${expireDate},已过期 ${Math.abs(diffDays)} 天${certNoText}`
|
||||
}
|
||||
if (status === 'expiring') {
|
||||
return `${requiredName}:临期,有效期 ${expireDate},剩余 ${diffDays} 天${certNoText}`
|
||||
}
|
||||
return `${requiredName}:正常,有效期 ${expireDate}${certNoText}`
|
||||
}
|
||||
|
||||
export function getPersonnelCertBadgeStatus(
|
||||
cert: Pick<CertRow, 'certName' | 'certNo' | 'expireDate' | 'attachmentUrls' | 'remindDays'> | undefined,
|
||||
requiredName: string
|
||||
): PersonnelCertBadgeStatus {
|
||||
if (!isPersonnelCertStrictComplete(cert, requiredName)) {
|
||||
return 'missing'
|
||||
}
|
||||
const expireDate = cert?.expireDate
|
||||
if (!expireDate) return 'missing'
|
||||
|
||||
const remindDays = cert?.remindDays ?? 30
|
||||
const expDate = new Date(expireDate)
|
||||
const today = new Date()
|
||||
today.setHours(0, 0, 0, 0)
|
||||
expDate.setHours(0, 0, 0, 0)
|
||||
const diffDays = Math.ceil((expDate.getTime() - today.getTime()) / (1000 * 60 * 60 * 24))
|
||||
|
||||
if (diffDays <= 0) return 'expired'
|
||||
if (diffDays <= remindDays) return 'expiring'
|
||||
return 'valid'
|
||||
}
|
||||
|
||||
export function getPersonnelRequiredCertBadges(
|
||||
personnelType: string | null | undefined,
|
||||
certList: CertRow[] = []
|
||||
): PersonnelCertBadgeItem[] {
|
||||
return getRequiredPersonnelCertNamesByType(personnelType).map(requiredName => {
|
||||
const matched = certList.find(cert => matchRequiredCertName(cert.certName, requiredName))
|
||||
const status = getPersonnelCertBadgeStatus(matched, requiredName)
|
||||
const shortLabel = PL_PERSONNEL_CERT_SHORT_LABELS[requiredName] || requiredName.slice(0, 1)
|
||||
return {
|
||||
requiredName,
|
||||
shortLabel,
|
||||
status,
|
||||
title: formatPersonnelCertBadgeTooltip(requiredName, status, matched)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -235,3 +235,124 @@ export function validateVehicleCertNamesNotEmpty(
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
export const PL_VEHICLE_CERT_SHORT_LABELS: Record<string, string> = {
|
||||
行驶证: '行',
|
||||
营运证: '营',
|
||||
保险单: '保',
|
||||
罐检报告: '罐'
|
||||
}
|
||||
|
||||
export type VehicleCertBadgeStatus = 'missing' | 'valid' | 'expiring' | 'expired'
|
||||
|
||||
export interface VehicleCertBadgeItem {
|
||||
requiredName: string
|
||||
shortLabel: string
|
||||
status: VehicleCertBadgeStatus
|
||||
title: string
|
||||
}
|
||||
|
||||
function matchVehicleRequiredCertName(
|
||||
actualName: string | undefined,
|
||||
requiredName: string
|
||||
): boolean {
|
||||
return (actualName?.trim() || '') === requiredName
|
||||
}
|
||||
|
||||
function getVehicleCertMissingFieldLabels(
|
||||
cert: Pick<CertRow, 'certName' | 'certNo' | 'expireDate' | 'attachmentUrls'> | undefined,
|
||||
requiredName: string
|
||||
): string[] {
|
||||
if (!cert || !matchVehicleRequiredCertName(cert.certName, requiredName)) {
|
||||
return ['证号', '有效期', '附件']
|
||||
}
|
||||
const missing: string[] = []
|
||||
if (!cert.certNo?.trim()) missing.push('证号')
|
||||
if (!cert.expireDate) missing.push('有效期')
|
||||
if (!cert.attachmentUrls?.trim()) missing.push('附件')
|
||||
return missing
|
||||
}
|
||||
|
||||
function formatVehicleCertBadgeTooltip(
|
||||
partLabel: string,
|
||||
requiredName: string,
|
||||
status: VehicleCertBadgeStatus,
|
||||
cert?: Pick<CertRow, 'certName' | 'certNo' | 'expireDate' | 'attachmentUrls' | 'remindDays'>
|
||||
): string {
|
||||
const prefix = partLabel ? `${partLabel} · ` : ''
|
||||
if (status === 'missing') {
|
||||
if (!cert || !matchVehicleRequiredCertName(cert.certName, requiredName)) {
|
||||
return `${prefix}${requiredName}:缺失(未登记该证书)`
|
||||
}
|
||||
const missing = getVehicleCertMissingFieldLabels(cert, requiredName)
|
||||
return `${prefix}${requiredName}:缺失(缺少${missing.join('、')})`
|
||||
}
|
||||
|
||||
const expireDate = cert?.expireDate || '—'
|
||||
const expDate = new Date(expireDate)
|
||||
const today = new Date()
|
||||
today.setHours(0, 0, 0, 0)
|
||||
expDate.setHours(0, 0, 0, 0)
|
||||
const diffDays = Math.ceil((expDate.getTime() - today.getTime()) / (1000 * 60 * 60 * 24))
|
||||
const certNo = cert?.certNo?.trim()
|
||||
const certNoText = certNo ? `,证号 ${certNo}` : ''
|
||||
|
||||
if (status === 'expired') {
|
||||
return `${prefix}${requiredName}:已过期,有效期 ${expireDate},已过期 ${Math.abs(diffDays)} 天${certNoText}`
|
||||
}
|
||||
if (status === 'expiring') {
|
||||
return `${prefix}${requiredName}:临期,有效期 ${expireDate},剩余 ${diffDays} 天${certNoText}`
|
||||
}
|
||||
return `${prefix}${requiredName}:正常,有效期 ${expireDate}${certNoText}`
|
||||
}
|
||||
|
||||
export function getVehicleCertBadgeStatus(
|
||||
cert: Pick<CertRow, 'certName' | 'certNo' | 'expireDate' | 'attachmentUrls' | 'remindDays'> | undefined,
|
||||
requiredName: string
|
||||
): VehicleCertBadgeStatus {
|
||||
if (!isVehicleCertUploaded(cert) || !matchVehicleRequiredCertName(cert?.certName, requiredName)) {
|
||||
return 'missing'
|
||||
}
|
||||
const expireDate = cert?.expireDate
|
||||
if (!expireDate) return 'missing'
|
||||
|
||||
const remindDays = cert?.remindDays ?? 30
|
||||
const expDate = new Date(expireDate)
|
||||
const today = new Date()
|
||||
today.setHours(0, 0, 0, 0)
|
||||
expDate.setHours(0, 0, 0, 0)
|
||||
const diffDays = Math.ceil((expDate.getTime() - today.getTime()) / (1000 * 60 * 60 * 24))
|
||||
|
||||
if (diffDays <= 0) return 'expired'
|
||||
if (diffDays <= remindDays) return 'expiring'
|
||||
return 'valid'
|
||||
}
|
||||
|
||||
export function getVehiclePartRequiredCertBadges(options: {
|
||||
vehicleType: PlVehicleCertCheckType
|
||||
certList?: CertRow[]
|
||||
part: VehicleCertPart
|
||||
partLabel?: string
|
||||
}): VehicleCertBadgeItem[] {
|
||||
const { vehicleType, certList = [], part, partLabel = '' } = options
|
||||
const partCerts =
|
||||
part === PL_VEHICLE_CERT_PART_TRAILER
|
||||
? splitVehicleCertsByPart(certList).trailerCerts
|
||||
: splitVehicleCertsByPart(certList).headCerts
|
||||
const requiredNames =
|
||||
part === PL_VEHICLE_CERT_PART_TRAILER
|
||||
? getVehicleTrailerRequiredCertNames(vehicleType)
|
||||
: getVehicleHeadRequiredCertNames(vehicleType)
|
||||
|
||||
return requiredNames.map(requiredName => {
|
||||
const matched = partCerts.find(cert => matchVehicleRequiredCertName(cert.certName, requiredName))
|
||||
const status = getVehicleCertBadgeStatus(matched, requiredName)
|
||||
const shortLabel = PL_VEHICLE_CERT_SHORT_LABELS[requiredName] || requiredName.slice(0, 1)
|
||||
return {
|
||||
requiredName,
|
||||
shortLabel,
|
||||
status,
|
||||
title: formatVehicleCertBadgeTooltip(partLabel, requiredName, status, matched)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -182,7 +182,7 @@
|
||||
<el-tag v-else-if="row.qualificationComplete === false" type="warning" size="small">
|
||||
资质不全
|
||||
</el-tag>
|
||||
<span v-else>—</span>
|
||||
<el-tag v-else type="success" size="small">资质齐全</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
|
||||
@@ -114,12 +114,18 @@
|
||||
<el-table-column
|
||||
prop="personnelName"
|
||||
label="姓名"
|
||||
min-width="100"
|
||||
min-width="160"
|
||||
align="center"
|
||||
header-align="center"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<el-link type="primary" @click="handleView(row)">{{ row.personnelName }}</el-link>
|
||||
<div class="personnel-name-cell">
|
||||
<el-link type="primary" @click="handleView(row)">{{ row.personnelName }}</el-link>
|
||||
<PlPersonnelCertBadges
|
||||
:personnel-type="row.personnelType"
|
||||
:cert-list="row.certList"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
@@ -357,6 +363,7 @@ import { Check, Close, Delete, Edit, Plus, RefreshLeft, Search, User } from '@el
|
||||
import { personnelApi, type Personnel, type PersonnelDetail, type CertRow } from '@/api/pl'
|
||||
import PlCertFormList from '@/components/business/pl-cert-form-list/index.vue'
|
||||
import PlCertViewList from '@/components/business/pl-cert-view-list/index.vue'
|
||||
import PlPersonnelCertBadges from '@/components/business/pl-personnel-cert-badges/index.vue'
|
||||
import SystemViewDialog, {
|
||||
type ViewSection
|
||||
} from '@/components/business/system-view-dialog/index.vue'
|
||||
@@ -824,4 +831,12 @@ onMounted(() => {
|
||||
.sub-table {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.personnel-name-cell {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
}
|
||||
</style>
|
||||
@@ -113,14 +113,21 @@
|
||||
<el-table-column
|
||||
prop="licensePlate"
|
||||
label="车牌号"
|
||||
min-width="120"
|
||||
min-width="340"
|
||||
align="center"
|
||||
header-align="center"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<el-link type="primary" @click="handleView(row)">
|
||||
{{ formatPlVehiclePlateDisplay(row.licensePlate, row.trailerNo) }}
|
||||
</el-link>
|
||||
<div class="vehicle-plate-cell">
|
||||
<el-link type="primary" @click="handleView(row)">
|
||||
{{ formatPlVehiclePlateDisplay(row.licensePlate, row.trailerNo) }}
|
||||
</el-link>
|
||||
<PlVehicleCertBadges
|
||||
vehicle-type="self"
|
||||
:cert-list="row.certList"
|
||||
:trailer-no="row.trailerNo"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="车辆类型" min-width="90" align="center" header-align="center" v-if="isColumnVisible('vehicleType')">
|
||||
@@ -216,7 +223,7 @@
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="承运商" prop="carrierId">
|
||||
<el-select v-model="formData.carrierId" placeholder="请选择承运商(选填)" clearable filterable>
|
||||
<el-select v-model="formData.carrierId" placeholder="请选择承运商" filterable>
|
||||
<el-option
|
||||
v-for="c in carrierList"
|
||||
:key="c.id"
|
||||
@@ -390,6 +397,7 @@ import {
|
||||
} from '@/api/pl'
|
||||
import PlVehicleCertPartTabs from '@/components/business/pl-vehicle-cert-part-tabs/index.vue'
|
||||
import PlVehicleCertPersonnelTabs from '@/components/business/pl-vehicle-cert-personnel-tabs/index.vue'
|
||||
import PlVehicleCertBadges from '@/components/business/pl-vehicle-cert-badges/index.vue'
|
||||
import type { VehiclePersonnelViewRow } from '@/components/business/pl-vehicle-personnel-view-list/index.vue'
|
||||
import SystemViewDialog, {
|
||||
type ViewSection
|
||||
@@ -414,7 +422,11 @@ import {
|
||||
PL_VEHICLE_CERT_NAME_OPTIONS,
|
||||
getSelfVehicleCertMissingSuffix
|
||||
} from '@/utils/pl-vehicle-cert'
|
||||
import { validatePersonnelTypeRoleCompat, validatePersonnelAffiliationVehicleCompat } from '@/utils/pl-personnel-cert'
|
||||
import {
|
||||
mapPersonnelTypeToVehicleRole,
|
||||
validatePersonnelTypeRoleCompat,
|
||||
validatePersonnelAffiliationVehicleCompat
|
||||
} from '@/utils/pl-personnel-cert'
|
||||
import { canDeleteByCreator, filterDeletableByCreator, allRowsDeletableByCreator, CREATOR_DELETE_TIP } from '@/utils/creator-delete'
|
||||
|
||||
const VEHICLE_TYPE_SELF = 'self'
|
||||
@@ -487,7 +499,8 @@ const formData = reactive({
|
||||
|
||||
const formRules = {
|
||||
licensePlate: [{ required: true, message: '请输入车牌号', trigger: 'blur' }],
|
||||
vehicleStatus: [{ required: true, message: '请选择车辆状态', trigger: 'change' }]
|
||||
vehicleStatus: [{ required: true, message: '请选择车辆状态', trigger: 'change' }],
|
||||
carrierId: [{ required: true, message: '请选择承运商', trigger: 'change' }]
|
||||
}
|
||||
|
||||
function getStatusTagType(status: string) {
|
||||
@@ -605,6 +618,7 @@ function handlePersonnelSelect(row: VehiclePersonnelRow, personnelId?: string) {
|
||||
row.personnelName = ''
|
||||
row.phoneNo = ''
|
||||
row.age = null
|
||||
row.role = ''
|
||||
return
|
||||
}
|
||||
const person = personnelOptions.value.find(p => p.id === personnelId)
|
||||
@@ -613,6 +627,11 @@ function handlePersonnelSelect(row: VehiclePersonnelRow, personnelId?: string) {
|
||||
row.personnelName = person.personnelName
|
||||
row.phoneNo = person.phoneNo || ''
|
||||
row.age = person.age ?? null
|
||||
const mappedRole = mapPersonnelTypeToVehicleRole(person.personnelType)
|
||||
if (mappedRole) {
|
||||
row.role = mappedRole
|
||||
handleRoleChange(row, 0)
|
||||
}
|
||||
}
|
||||
|
||||
function resolvePersonnelRows(rows: VehiclePersonnelRow[]) {
|
||||
@@ -1002,4 +1021,13 @@ onMounted(() => {
|
||||
.sub-table {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.vehicle-plate-cell {
|
||||
display: inline-flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-wrap: nowrap;
|
||||
gap: 6px;
|
||||
}
|
||||
</style>
|
||||
@@ -121,14 +121,21 @@
|
||||
<el-table-column
|
||||
prop="licensePlate"
|
||||
label="车牌号"
|
||||
min-width="120"
|
||||
min-width="340"
|
||||
align="center"
|
||||
header-align="center"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<el-link type="primary" @click="handleView(row)">
|
||||
{{ formatPlVehiclePlateDisplay(row.licensePlate, row.trailerNo) }}
|
||||
</el-link>
|
||||
<div class="vehicle-plate-cell">
|
||||
<el-link type="primary" @click="handleView(row)">
|
||||
{{ formatPlVehiclePlateDisplay(row.licensePlate, row.trailerNo) }}
|
||||
</el-link>
|
||||
<PlVehicleCertBadges
|
||||
:vehicle-type="row.vehicleType === 'carrier' ? 'carrier' : 'self'"
|
||||
:cert-list="row.certList"
|
||||
:trailer-no="row.trailerNo"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="车辆类型" min-width="100" align="center" header-align="center" v-if="isColumnVisible('vehicleType')">
|
||||
@@ -233,7 +240,7 @@
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="承运商" prop="carrierId">
|
||||
<el-select v-model="formData.carrierId" placeholder="请选择承运商" clearable filterable>
|
||||
<el-select v-model="formData.carrierId" placeholder="请选择承运商" filterable>
|
||||
<el-option
|
||||
v-for="c in carrierList"
|
||||
:key="c.id"
|
||||
@@ -412,6 +419,7 @@ import {
|
||||
} from '@/api/pl'
|
||||
import PlVehicleCertPartTabs from '@/components/business/pl-vehicle-cert-part-tabs/index.vue'
|
||||
import PlVehicleCertPersonnelTabs from '@/components/business/pl-vehicle-cert-personnel-tabs/index.vue'
|
||||
import PlVehicleCertBadges from '@/components/business/pl-vehicle-cert-badges/index.vue'
|
||||
import type { VehiclePersonnelViewRow } from '@/components/business/pl-vehicle-personnel-view-list/index.vue'
|
||||
import SystemViewDialog, {
|
||||
type ViewSection
|
||||
@@ -432,7 +440,11 @@ import {
|
||||
getVehicleCertMissingSuffix,
|
||||
type PlVehicleCertCheckType
|
||||
} from '@/utils/pl-vehicle-cert'
|
||||
import { validatePersonnelTypeRoleCompat, validatePersonnelAffiliationVehicleCompat } from '@/utils/pl-personnel-cert'
|
||||
import {
|
||||
mapPersonnelTypeToVehicleRole,
|
||||
validatePersonnelTypeRoleCompat,
|
||||
validatePersonnelAffiliationVehicleCompat
|
||||
} from '@/utils/pl-personnel-cert'
|
||||
import { canDeleteByCreator, filterDeletableByCreator, allRowsDeletableByCreator, CREATOR_DELETE_TIP } from '@/utils/creator-delete'
|
||||
|
||||
type CertListItem = CertRow & { _key?: string }
|
||||
@@ -506,7 +518,8 @@ const formData = reactive({
|
||||
|
||||
const formRules = {
|
||||
licensePlate: [{ required: true, message: '请输入车牌号', trigger: 'blur' }],
|
||||
vehicleType: [{ required: true, message: '请选择车辆类型', trigger: 'change' }]
|
||||
vehicleType: [{ required: true, message: '请选择车辆类型', trigger: 'change' }],
|
||||
carrierId: [{ required: true, message: '请选择承运商', trigger: 'change' }]
|
||||
}
|
||||
|
||||
function getStatusTagType(status: string) {
|
||||
@@ -671,6 +684,7 @@ function handlePersonnelSelect(row: VehiclePersonnelRow, personnelId?: string) {
|
||||
row.personnelName = ''
|
||||
row.phoneNo = ''
|
||||
row.age = null
|
||||
row.role = ''
|
||||
return
|
||||
}
|
||||
const person = personnelOptions.value.find(p => p.id === personnelId)
|
||||
@@ -679,6 +693,11 @@ function handlePersonnelSelect(row: VehiclePersonnelRow, personnelId?: string) {
|
||||
row.personnelName = person.personnelName
|
||||
row.phoneNo = person.phoneNo || ''
|
||||
row.age = person.age ?? null
|
||||
const mappedRole = mapPersonnelTypeToVehicleRole(person.personnelType)
|
||||
if (mappedRole) {
|
||||
row.role = mappedRole
|
||||
handleRoleChange(row, 0)
|
||||
}
|
||||
}
|
||||
|
||||
function resolvePersonnelRows(rows: VehiclePersonnelRow[]) {
|
||||
@@ -1107,4 +1126,13 @@ onMounted(() => {
|
||||
.sub-table {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.vehicle-plate-cell {
|
||||
display: inline-flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-wrap: nowrap;
|
||||
gap: 6px;
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user