企微跳转改为账号密码登录,报价卡上的费用按原金额改回;航线按单价数量金额报价时不再记成海运费。 Co-authored-by: Cursor <cursoragent@cursor.com>
113 lines
4.1 KiB
Python
113 lines
4.1 KiB
Python
"""
|
|
陆运选线路 H5 页。
|
|
|
|
本文件职责:按完整线路列出各段成本与合计,提交所选下标。
|
|
样式对齐空运选线路页。禁止 URL userid;禁止本页查 TMS。
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import html
|
|
from typing import Any
|
|
|
|
from agent.channel.h5.air_route_page import _PAGE_CSS, _wrap
|
|
from agent.schema.land_route_options import (
|
|
_money,
|
|
group_land_routes,
|
|
land_leg_fee_blocks_for_route,
|
|
option_eta_bits,
|
|
option_total,
|
|
route_line,
|
|
)
|
|
|
|
|
|
def expired_land_route_page() -> str:
|
|
"""token 过期页。"""
|
|
return _wrap(
|
|
"已过期",
|
|
"<div class='msg'><h1>链接已过期</h1><p>请回企微重新打开选线路卡片。</p></div>",
|
|
)
|
|
|
|
|
|
def render_land_route_page(payload: dict[str, Any]) -> str:
|
|
"""渲染选线路页。payload 来自 token。"""
|
|
quote = dict(payload.get("quote") or {})
|
|
wo = html.escape(str(payload.get("work_order_no") or ""))
|
|
routes = group_land_routes(quote)
|
|
rows = [_route_card(i, route, quote) for i, route in enumerate(routes)]
|
|
body = (
|
|
"<div class='wrap'>"
|
|
"<header class='hero'>"
|
|
f"<p class='wo'>{wo}</p>"
|
|
"<h1>选择线路</h1>"
|
|
f"<p class='lead'>共 {len(routes)} 条线路,每条按段报价。点选一条后确定。</p>"
|
|
"</header>"
|
|
"<form method='post'>"
|
|
+ "".join(rows)
|
|
+ "<div class='bar'><div class='bar-inner'>"
|
|
"<button type='submit'>选定这条</button>"
|
|
"</div></div></form></div>"
|
|
"<script>(function(){var f=document.querySelector('form');if(!f)return;"
|
|
"function sync(){f.querySelectorAll('.opt').forEach(function(el){"
|
|
"el.classList.toggle('is-on',!!(el.querySelector('input')||{}).checked);});}"
|
|
"f.addEventListener('change',sync);})();</script>"
|
|
)
|
|
return _wrap("选择线路", body)
|
|
|
|
|
|
def render_land_route_ok() -> str:
|
|
"""选定成功:短暂展示后关企微 H5。"""
|
|
return _wrap(
|
|
"已选定",
|
|
"<div class='msg'><h1>已选定</h1><p>正在返回企微,请查看价格明细。</p></div>",
|
|
auto_close=True,
|
|
)
|
|
|
|
|
|
def _route_card(index: int, route: dict[str, Any], quote: dict[str, Any] | None = None) -> str:
|
|
"""一张线路:航线、各段路段+TMS 费目、合计。"""
|
|
line = html.escape(route_line(route))
|
|
blocks = land_leg_fee_blocks_for_route(quote, route)
|
|
etas = {i: d for i, (_, d) in enumerate(option_eta_bits(route), 1)}
|
|
fee_bits: list[str] = []
|
|
items = ""
|
|
if blocks:
|
|
for i, (title, fees, eta) in enumerate(blocks, 1):
|
|
items += (
|
|
f"<li class='leg'><span class='n'>{html.escape(title)}</span>"
|
|
"<span></span></li>"
|
|
)
|
|
for fee in fees:
|
|
amount = _money(fee.get("amount"), str(fee.get("currency") or "").strip())
|
|
name = str(fee.get("name") or "").strip()
|
|
if not name or not amount:
|
|
continue
|
|
items += (
|
|
f"<li><span class='n'>{html.escape(name)}</span>"
|
|
f"<span class='a'>{html.escape(amount)}</span></li>"
|
|
)
|
|
days = eta or etas.get(i) or ""
|
|
if days:
|
|
items += (
|
|
f"<li><span class='n'>时效 {html.escape(days)}</span>"
|
|
"<span></span></li>"
|
|
)
|
|
if items:
|
|
fee_bits.append(f"<ul class='fees'>{items}</ul>")
|
|
else:
|
|
fee_bits.append("<p class='empty'>本线路未返回分段成本</p>")
|
|
total = html.escape(option_total(route))
|
|
legs = list(route.get("legs") or [])
|
|
tag = "中转" if len(legs) > 1 else "直达"
|
|
tag_cls = "pill via" if len(legs) > 1 else "pill"
|
|
return (
|
|
"<label class='opt'>"
|
|
f"<input type='radio' name='index' value='{index}' required />"
|
|
"<div class='head'><span class='tick' aria-hidden='true'></span>"
|
|
f"<div class='route'><strong>{line}</strong>"
|
|
f"<div class='meta'><span class='{tag_cls}'>{tag}</span></div></div></div>"
|
|
+ "".join(fee_bits)
|
|
+ f"<p class='total'><span>成本价合计</span><b>{total}</b></p>"
|
|
"</label>"
|
|
)
|