feat(backend): add sample options for freight config dialog

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zlwuandCursor committed 2026-10-08 09:59:29 +08:00
1 parent 971af93132
commit f092b64a33
2 files changed
+196 -1

No files matched your search

+28
View File
@@ -100,6 +100,34 @@ async def list_sample_freights(
return error_response(400, str(e))
@router.get("/sample-freights/sample-options")
async def list_sample_freight_options(
page: int = Query(1, ge=1),
pageSize: int = Query(20, ge=1, le=100, alias="pageSize"),
keyword: Optional[str] = None,
sampleSource: Optional[str] = None,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
items, total = freight_svc.list_sample_options(
db,
tenant_no=tenant_no,
page=page,
page_size=pageSize,
keyword=keyword,
sample_source=sampleSource,
)
return success_response(
{"list": items, "total": total, "page": page, "pageSize": pageSize}
)
except PermissionError as e:
return error_response(403, str(e))
except ValueError as e:
return error_response(400, str(e))
@router.get("/sample-freights/{freight_id}")
async def get_sample_freight(
freight_id: str,
+168 -1
View File
@@ -455,10 +455,177 @@ def get_freight_detail(db: Session, freight_id: str, tenant_no: str) -> Dict[str
linked_sample_count=len(items),
transport_mode_label=labels.get(obj.transport_mode or "", obj.transport_mode or ""),
)
data["items"] = [_item_to_dict(i) for i in items]
protocol_no_map, type_name_map = _enrich_items_maps(db, items, tenant_no)
enriched = []
for i in items:
key = f"{i.sample_source}|{i.sample_id}"
enriched.append(
_item_to_dict_enriched(
i,
protocol_no=protocol_no_map.get(key, ""),
sample_type_name=type_name_map.get(key, ""),
)
)
data["items"] = enriched
return data
def list_sample_options(
db: Session,
*,
tenant_no: str,
page: int = 1,
page_size: int = 20,
keyword: Optional[str] = None,
sample_source: Optional[str] = None,
) -> Tuple[List[Dict[str, Any]], int]:
"""可选样本列表(配置运费弹窗),支持细胞存储 / 科研捐赠。"""
page = max(1, int(page or 1))
page_size = max(1, min(100, int(page_size or 20)))
src = (sample_source or "").strip() or None
if src and src not in (SAMPLE_SOURCE_CELL, SAMPLE_SOURCE_DONATION):
raise ValueError("sampleSource 无效")
kw = (keyword or "").strip()
like = f"%{kw}%" if kw else None
rows: List[Dict[str, Any]] = []
if src in (None, SAMPLE_SOURCE_CELL):
cq = (
db.query(
BizProtocolSample.id,
BizProtocolSample.sample_code,
BizProtocolSample.collection_protocol_id,
BizProtocolSample.create_time,
BizCollectionProtocol.protocol_no,
BizCellSampleType.type_name,
)
.outerjoin(
BizCollectionProtocol,
and_(
BizCollectionProtocol.id
== BizProtocolSample.collection_protocol_id,
BizCollectionProtocol.del_flag == 0,
),
)
.outerjoin(
BizCellSampleType,
and_(
BizCellSampleType.id == BizProtocolSample.sample_type_id,
BizCellSampleType.del_flag == 0,
),
)
.filter(
BizProtocolSample.tenant_no == tenant_no,
BizProtocolSample.del_flag == 0,
)
)
if like:
cq = cq.filter(
or_(
BizProtocolSample.sample_code.like(like),
BizCollectionProtocol.protocol_no.like(like),
)
)
for sid, scode, pid, ctime, pno, tname in cq.all():
rows.append(
{
"sampleSource": SAMPLE_SOURCE_CELL,
"sampleId": sid,
"sampleCode": scode or "",
"protocolId": pid or "",
"protocolNo": pno or "",
"sampleTypeName": tname or "",
"createTime": ctime,
"freightId": "",
}
)
if src in (None, SAMPLE_SOURCE_DONATION):
dq = (
db.query(
BizResearchDonationSample.id,
BizResearchDonationSample.sample_code,
BizResearchDonationSample.research_donation_id,
BizResearchDonationSample.create_time,
BizResearchDonation.donation_no,
BizCellSampleType.type_name,
)
.outerjoin(
BizResearchDonation,
and_(
BizResearchDonation.id
== BizResearchDonationSample.research_donation_id,
BizResearchDonation.del_flag == 0,
),
)
.outerjoin(
BizCellSampleType,
and_(
BizCellSampleType.id == BizResearchDonationSample.sample_type_id,
BizCellSampleType.del_flag == 0,
),
)
.filter(
BizResearchDonationSample.tenant_no == tenant_no,
BizResearchDonationSample.del_flag == 0,
)
)
if like:
dq = dq.filter(
or_(
BizResearchDonationSample.sample_code.like(like),
BizResearchDonation.donation_no.like(like),
)
)
for sid, scode, pid, ctime, dno, tname in dq.all():
rows.append(
{
"sampleSource": SAMPLE_SOURCE_DONATION,
"sampleId": sid,
"sampleCode": scode or "",
"protocolId": pid or "",
"protocolNo": dno or "",
"sampleTypeName": tname or "",
"createTime": ctime,
"freightId": "",
}
)
# 左连当前运费关联
if rows:
sample_ids = [r["sampleId"] for r in rows]
link_rows = (
db.query(
BizSampleFreightItem.sample_source,
BizSampleFreightItem.sample_id,
BizSampleFreightItem.freight_id,
)
.filter(
BizSampleFreightItem.tenant_no == tenant_no,
BizSampleFreightItem.del_flag == 0,
BizSampleFreightItem.sample_id.in_(sample_ids),
)
.all()
)
freight_map = {
f"{src_}|{sid}": fid for src_, sid, fid in link_rows if src_ and sid and fid
}
for r in rows:
r["freightId"] = freight_map.get(f"{r['sampleSource']}|{r['sampleId']}", "") or ""
rows.sort(
key=lambda r: (r["createTime"] or datetime.min, r["sampleId"]),
reverse=True,
)
total = len(rows)
start = (page - 1) * page_size
page_rows = rows[start : start + page_size]
for r in page_rows:
r["createTime"] = _fmt_dt(r.get("createTime"))
return page_rows, total
def _upsert_item(
db: Session,
*,