feat: 配送H5新模块 + 净菜三页物流改造 + 餐次历史内聚到统计页
- 新增 other-module/meal-delivery-h5/ 配送员端 H5 全套 9 页(登录/工作台/派单接听/抢单/订单详情/配送中/送达签收/历史/个人中心) - 净菜内供/外售/订单三页物流模型统一,支持自营派单/自营抢单/三方物流三种配送方式,新增收货码 + 配送进度时间轴 + 物流详情弹窗 - 删除结算设备 10-meal-center/13-meal-history 两页,餐次控制内聚到 02-standby,餐次历史作为 Tab3 合并进 07-statistics - 营养管理端新增 din-canteen-shift.html(场所排版设置),din-ingredient 详情页增加删除食材确认弹窗 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
a16500068c
commit
2346465c90
@@ -37,6 +37,7 @@
|
||||
background: #1a2b4a;
|
||||
padding: 0 20px;
|
||||
flex-shrink: 0;
|
||||
gap: 12px;
|
||||
}
|
||||
.back-btn {
|
||||
font-size: 13px;
|
||||
@@ -57,6 +58,36 @@
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
font-family: Menlo, Consolas, monospace;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.top-bar__right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
/* 顶部栏内的收银员信息(紧凑版) */
|
||||
.cashier-info--compact {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 4px 10px 4px 4px;
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
border-radius: 16px;
|
||||
}
|
||||
.cashier-info--compact .cashier-info__avatar {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
font-size: 10px;
|
||||
}
|
||||
.cashier-info--compact .cashier-info__text {
|
||||
font-size: 11px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
.logout-btn--compact {
|
||||
padding: 4px 10px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
/* 主内容 */
|
||||
@@ -132,6 +163,84 @@
|
||||
color: #ff6b6b;
|
||||
}
|
||||
|
||||
/* 餐次控制区 */
|
||||
.meal-ctrl {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
padding: 14px 18px;
|
||||
background: rgba(26, 43, 74, 0.4);
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
border-radius: 14px;
|
||||
min-width: 200px;
|
||||
}
|
||||
.meal-ctrl__status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.meal-ctrl__status-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.meal-ctrl__status-dot--live {
|
||||
background: #4ade80;
|
||||
box-shadow: 0 0 8px rgba(74, 222, 128, 0.5);
|
||||
animation: dotBlink2 1.4s infinite;
|
||||
}
|
||||
.meal-ctrl__status-dot--off {
|
||||
background: #94a3b8;
|
||||
}
|
||||
@keyframes dotBlink2 {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0.35; }
|
||||
}
|
||||
.meal-ctrl__status-text { color: #fff; }
|
||||
.meal-ctrl__status-text--live { color: #4ade80; }
|
||||
.meal-ctrl__status-text--off { color: rgba(255, 255, 255, 0.5); }
|
||||
.meal-ctrl__buttons {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
.meal-ctrl__btn {
|
||||
flex: 1;
|
||||
height: 38px;
|
||||
border-radius: 10px;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
border: 1px solid;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 5px;
|
||||
transition: all 0.2s;
|
||||
text-decoration: none;
|
||||
}
|
||||
.meal-ctrl__btn--start {
|
||||
background: linear-gradient(135deg, rgba(74, 222, 128, 0.18), rgba(34, 197, 94, 0.12));
|
||||
border-color: rgba(74, 222, 128, 0.4);
|
||||
color: #4ade80;
|
||||
}
|
||||
.meal-ctrl__btn--start:hover {
|
||||
background: linear-gradient(135deg, rgba(74, 222, 128, 0.28), rgba(34, 197, 94, 0.2));
|
||||
border-color: rgba(74, 222, 128, 0.6);
|
||||
box-shadow: 0 4px 14px rgba(74, 222, 128, 0.2);
|
||||
}
|
||||
.meal-ctrl__btn--stop {
|
||||
background: rgba(239, 68, 68, 0.1);
|
||||
border-color: rgba(239, 68, 68, 0.3);
|
||||
color: #f87171;
|
||||
}
|
||||
.meal-ctrl__btn--stop:hover {
|
||||
background: rgba(239, 68, 68, 0.2);
|
||||
border-color: rgba(239, 68, 68, 0.5);
|
||||
}
|
||||
|
||||
/* 中央:核心动作区 */
|
||||
.hero {
|
||||
flex: 1;
|
||||
@@ -466,6 +575,254 @@
|
||||
font-size: 11px;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
/* ============ 交接班弹窗 ============ */
|
||||
.shift-overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.72);
|
||||
backdrop-filter: blur(6px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 100;
|
||||
border-radius: 24px;
|
||||
}
|
||||
.shift-modal {
|
||||
width: 680px;
|
||||
max-height: 680px;
|
||||
background: linear-gradient(180deg, #1a2744 0%, #141e36 100%);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: 18px;
|
||||
padding: 28px 32px 24px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5), 0 0 120px rgba(74, 144, 217, 0.08);
|
||||
overflow: hidden;
|
||||
}
|
||||
.shift-modal__head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.shift-modal__title {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
}
|
||||
.shift-modal__close {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 14px;
|
||||
color: rgba(255, 255, 255, 0.55);
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.shift-modal__close:hover {
|
||||
background: rgba(245, 34, 45, 0.2);
|
||||
border-color: rgba(245, 34, 45, 0.4);
|
||||
color: #ff6b6b;
|
||||
}
|
||||
|
||||
/* 收银员信息条 */
|
||||
.shift-modal__cashier {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 14px 16px;
|
||||
background: rgba(0, 0, 0, 0.25);
|
||||
border: 1px solid rgba(255, 255, 255, 0.06);
|
||||
border-radius: 12px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.shift-modal__cashier-avatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(135deg, #4a90d9, #0AC4A8);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.shift-modal__cashier-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
.shift-modal__cashier-name {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
}
|
||||
.shift-modal__cashier-meta {
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
/* 统计指标网格 */
|
||||
.shift-modal__kpi-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 12px;
|
||||
}
|
||||
.shift-kpi {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border: 1px solid rgba(255, 255, 255, 0.05);
|
||||
border-radius: 10px;
|
||||
padding: 14px 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
.shift-kpi__label {
|
||||
font-size: 11px;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
.shift-kpi__value {
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 4px;
|
||||
}
|
||||
.shift-kpi__value--green { color: #4ade80; }
|
||||
.shift-kpi__value--gold { color: #fbbf24; }
|
||||
.shift-kpi__unit {
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: rgba(255, 255, 255, 0.55);
|
||||
}
|
||||
.shift-kpi__hint {
|
||||
font-size: 10px;
|
||||
color: rgba(255, 255, 255, 0.35);
|
||||
line-height: 1.4;
|
||||
}
|
||||
.shift-modal__kpi-grid--two {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
|
||||
/* 分区标题 */
|
||||
.shift-modal__section {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.shift-modal__section-title {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
/* 支付方式明细表 */
|
||||
.shift-pay-table {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border: 1px solid rgba(255, 255, 255, 0.06);
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.shift-pay-table__head {
|
||||
display: flex;
|
||||
padding: 8px 16px;
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
|
||||
}
|
||||
.shift-pay-table__th {
|
||||
font-size: 11px;
|
||||
color: rgba(255, 255, 255, 0.45);
|
||||
font-weight: 500;
|
||||
}
|
||||
.shift-pay-table__th--name { flex: 1; }
|
||||
.shift-pay-table__th--num { width: 80px; text-align: right; }
|
||||
.shift-pay-table__row {
|
||||
display: flex;
|
||||
padding: 9px 16px;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.04);
|
||||
transition: background 0.15s;
|
||||
}
|
||||
.shift-pay-table__row:last-child { border-bottom: none; }
|
||||
.shift-pay-table__row:hover { background: rgba(255, 255, 255, 0.03); }
|
||||
.shift-pay-table__row--total {
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
font-weight: 700;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
.shift-pay-table__td {
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
}
|
||||
.shift-pay-table__td--name { flex: 1; display: flex; align-items: center; gap: 8px; }
|
||||
.shift-pay-table__td--num { width: 80px; text-align: right; font-variant-numeric: tabular-nums; font-family: Menlo, Consolas, monospace; font-size: 12px; }
|
||||
.shift-pay-table__row--total .shift-pay-table__td { color: #fff; }
|
||||
|
||||
/* 支付方式色点 */
|
||||
.shift-pay-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.shift-pay-dot--online { background: #4ade80; box-shadow: 0 0 6px rgba(74, 222, 128, 0.5); }
|
||||
.shift-pay-dot--cash { background: #fb923c; box-shadow: 0 0 6px rgba(251, 146, 60, 0.5); }
|
||||
.shift-pay-dot--balance { background: #60a5fa; box-shadow: 0 0 6px rgba(96, 165, 250, 0.5); }
|
||||
|
||||
/* 分割线 */
|
||||
.shift-modal__divider {
|
||||
height: 1px;
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
/* 底部操作区 */
|
||||
.shift-modal__actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.shift-modal__btn {
|
||||
height: 40px;
|
||||
border-radius: 10px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
border: 1px solid;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 28px;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.shift-modal__btn--cancel {
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
border-color: rgba(255, 255, 255, 0.12);
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
.shift-modal__btn--cancel:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
color: #fff;
|
||||
}
|
||||
.shift-modal__btn--exit {
|
||||
background: linear-gradient(135deg, rgba(245, 34, 45, 0.18), rgba(239, 68, 68, 0.12));
|
||||
border-color: rgba(245, 34, 45, 0.4);
|
||||
color: #ff6b6b;
|
||||
}
|
||||
.shift-modal__btn--exit:hover {
|
||||
background: linear-gradient(135deg, rgba(245, 34, 45, 0.3), rgba(239, 68, 68, 0.22));
|
||||
border-color: rgba(245, 34, 45, 0.6);
|
||||
box-shadow: 0 4px 16px rgba(245, 34, 45, 0.2);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -477,6 +834,13 @@
|
||||
<a class="back-btn" href="index.html">◀ 返回主页</a>
|
||||
<span class="top-bar__title">结算台待机</span>
|
||||
<span class="top-bar__meta" id="topMeta">2026-08-06 周四</span>
|
||||
<div class="top-bar__right">
|
||||
<div class="cashier-info cashier-info--compact">
|
||||
<div class="cashier-info__avatar">张</div>
|
||||
<div class="cashier-info__text">CS001 · 张三</div>
|
||||
</div>
|
||||
<a class="logout-btn logout-btn--compact" href="javascript:void(0)" onclick="openShiftHandover()">交接班</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 主内容 -->
|
||||
@@ -491,11 +855,21 @@
|
||||
<div class="welcome__sub">数味餐厅 · 一楼 A 区 2 号餐线 · 等待顾客取餐</div>
|
||||
</div>
|
||||
<div class="welcome__right">
|
||||
<div class="cashier-info">
|
||||
<div class="cashier-info__avatar">张</div>
|
||||
<div class="cashier-info__text">CS001 · 张三</div>
|
||||
<!-- 餐次控制区 -->
|
||||
<div class="meal-ctrl">
|
||||
<div class="meal-ctrl__status" id="mealCtrlStatus">
|
||||
<span class="meal-ctrl__status-dot meal-ctrl__status-dot--live" id="mealCtrlDot"></span>
|
||||
<span class="meal-ctrl__status-text meal-ctrl__status-text--live" id="mealCtrlText">午餐开餐中</span>
|
||||
</div>
|
||||
<div class="meal-ctrl__buttons" id="mealCtrlBtns">
|
||||
<button class="meal-ctrl__btn meal-ctrl__btn--start" id="mealStartBtn" onclick="showMealStartConfirm()">
|
||||
🔊 开餐
|
||||
</button>
|
||||
<a class="meal-ctrl__btn meal-ctrl__btn--stop" id="mealStopBtn" href="11-meal-active.html?meal=lunch&action=collect">
|
||||
🥢 收餐
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<a class="logout-btn" href="01-login.html" onclick="return confirm('确定退出登录吗?');">退出登录</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -585,7 +959,7 @@
|
||||
<div class="entry-card__desc">今日数据可视化</div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="entry-card" href="10-meal-center.html">
|
||||
<a class="entry-card" id="mealMgmtLink" href="11-meal-active.html">
|
||||
<div class="entry-card__icon entry-card__icon--gold">🍽️</div>
|
||||
<div class="entry-card__text">
|
||||
<div class="entry-card__title">餐次管理</div>
|
||||
@@ -607,6 +981,7 @@
|
||||
|
||||
<script>
|
||||
/* ============ 实时时钟(只显示时分秒,年月日由 topMeta 展示) ============ */
|
||||
var lastMealHour = -1;
|
||||
function updateClock() {
|
||||
var now = new Date();
|
||||
var hh = String(now.getHours()).padStart(2, '0');
|
||||
@@ -645,10 +1020,105 @@
|
||||
mealTag.style.borderColor = '';
|
||||
mealTag.innerHTML = '🌟 欢迎光临';
|
||||
}
|
||||
|
||||
/* 餐次控制区随小时联动(仅在跨整点时更新) */
|
||||
if (hour !== lastMealHour) {
|
||||
lastMealHour = hour;
|
||||
updateMealCtrl(hour);
|
||||
}
|
||||
}
|
||||
updateClock();
|
||||
setInterval(updateClock, 1000);
|
||||
|
||||
/* ============ 餐次控制区状态联动(双按钮常驻演示) ============ */
|
||||
var mealCtrlState = 'live'; /* 'live' | 'collected' | 'off' */
|
||||
var currentMealKey = 'lunch';
|
||||
var currentMealName = '午餐';
|
||||
|
||||
function updateMealCtrl(hour) {
|
||||
var dot = document.getElementById('mealCtrlDot');
|
||||
var text = document.getElementById('mealCtrlText');
|
||||
|
||||
/* 根据时段判断当前餐次 */
|
||||
var isMealTime = false;
|
||||
if (hour >= 6 && hour < 10) {
|
||||
currentMealKey = 'breakfast'; currentMealName = '早餐'; isMealTime = true;
|
||||
} else if (hour >= 10 && hour < 14) {
|
||||
currentMealKey = 'lunch'; currentMealName = '午餐'; isMealTime = true;
|
||||
} else if (hour >= 16 && hour < 21) {
|
||||
currentMealKey = 'dinner'; currentMealName = '晚餐'; isMealTime = true;
|
||||
}
|
||||
|
||||
if (mealCtrlState === 'collected') {
|
||||
dot.className = 'meal-ctrl__status-dot meal-ctrl__status-dot--off';
|
||||
text.className = 'meal-ctrl__status-text meal-ctrl__status-text--off';
|
||||
text.textContent = '已收餐 · 员工餐时间';
|
||||
syncMealMgmtLink('collected');
|
||||
} else if (isMealTime) {
|
||||
mealCtrlState = 'live';
|
||||
dot.className = 'meal-ctrl__status-dot meal-ctrl__status-dot--live';
|
||||
text.className = 'meal-ctrl__status-text meal-ctrl__status-text--live';
|
||||
text.textContent = currentMealName + ' 开餐中';
|
||||
syncMealMgmtLink('live');
|
||||
} else {
|
||||
mealCtrlState = 'off';
|
||||
dot.className = 'meal-ctrl__status-dot meal-ctrl__status-dot--off';
|
||||
text.className = 'meal-ctrl__status-text meal-ctrl__status-text--off';
|
||||
text.textContent = '非餐时段';
|
||||
syncMealMgmtLink('off');
|
||||
}
|
||||
|
||||
/* 按钮动态链接随餐次更新 */
|
||||
var stopBtn = document.getElementById('mealStopBtn');
|
||||
if (stopBtn) stopBtn.href = '11-meal-active.html?meal=' + currentMealKey + '&action=collect';
|
||||
}
|
||||
|
||||
/* 同步底部"餐次管理"入口卡片的跳转链接 */
|
||||
function syncMealMgmtLink(state) {
|
||||
var link = document.getElementById('mealMgmtLink');
|
||||
if (!link) return;
|
||||
var desc = link.querySelector('.entry-card__desc');
|
||||
if (state === 'collected') {
|
||||
link.href = '11-meal-active.html?meal=' + currentMealKey + '&status=collected';
|
||||
if (desc) desc.textContent = '员工餐时间 · 余量处置';
|
||||
} else {
|
||||
link.href = '11-meal-active.html?meal=' + currentMealKey;
|
||||
if (desc) desc.textContent = '开餐/结束用餐/历史记录';
|
||||
}
|
||||
}
|
||||
|
||||
/* 开餐确认 */
|
||||
function showMealStartConfirm() {
|
||||
if (!confirm('确认开餐「' + currentMealName + '」?\n\n开启后将进入' + currentMealName + '餐次,系统开始记录取餐结算数据。')) return;
|
||||
mealCtrlState = 'live';
|
||||
document.getElementById('mealCtrlDot').className = 'meal-ctrl__status-dot meal-ctrl__status-dot--live';
|
||||
document.getElementById('mealCtrlText').className = 'meal-ctrl__status-text meal-ctrl__status-text--live';
|
||||
document.getElementById('mealCtrlText').textContent = currentMealName + ' 开餐中';
|
||||
syncMealMgmtLink('live');
|
||||
}
|
||||
|
||||
/* 收餐确认 */
|
||||
function showMealStopConfirm() {
|
||||
if (!confirm('确认收餐?\n\n收餐后进入员工餐时间,顾客无法继续取餐结算。\n稍后可在下方完成余量处置。')) return;
|
||||
mealCtrlState = 'collected';
|
||||
document.getElementById('mealCtrlDot').className = 'meal-ctrl__status-dot meal-ctrl__status-dot--off';
|
||||
document.getElementById('mealCtrlText').className = 'meal-ctrl__status-text meal-ctrl__status-text--off';
|
||||
document.getElementById('mealCtrlText').textContent = '已收餐 · 员工餐时间';
|
||||
syncMealMgmtLink('collected');
|
||||
}
|
||||
|
||||
/* 初始执行:检查 URL 参数是否包含 collected 状态 */
|
||||
(function () {
|
||||
var params = new URLSearchParams(window.location.search);
|
||||
if (params.get('status') === 'collected') {
|
||||
mealCtrlState = 'collected';
|
||||
var m = params.get('meal');
|
||||
if (m) { currentMealKey = m; currentMealName = {breakfast:'早餐',lunch:'午餐',dinner:'晚餐'}[m] || '午餐'; }
|
||||
history.replaceState(null, '', window.location.pathname);
|
||||
}
|
||||
})();
|
||||
updateMealCtrl(new Date().getHours());
|
||||
|
||||
/* ============ 副屏人脸识别状态三态轮播(演示) ============
|
||||
三态轮播用于在原型中展示收银员需要识别的三种提醒场景:
|
||||
success: 识别成功 - 显示用户信息,收银员可引导支付
|
||||
@@ -717,7 +1187,98 @@
|
||||
/* 初始展示第一态,4 秒后开始轮播 */
|
||||
rotateFaceState();
|
||||
setInterval(rotateFaceState, 4000);
|
||||
|
||||
/* ============ 交接班弹窗 ============ */
|
||||
function openShiftHandover() {
|
||||
document.getElementById('shiftOverlay').style.display = 'flex';
|
||||
}
|
||||
function closeShiftHandover() {
|
||||
document.getElementById('shiftOverlay').style.display = 'none';
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- 交接班弹窗 -->
|
||||
<div class="shift-overlay" id="shiftOverlay" style="display:none;">
|
||||
<div class="shift-modal">
|
||||
<div class="shift-modal__head">
|
||||
<div class="shift-modal__title">📋 交接班 · 当班营业汇总</div>
|
||||
<div class="shift-modal__close" onclick="closeShiftHandover()" title="关闭">✕</div>
|
||||
</div>
|
||||
<div class="shift-modal__cashier">
|
||||
<div class="shift-modal__cashier-avatar">张</div>
|
||||
<div class="shift-modal__cashier-info">
|
||||
<div class="shift-modal__cashier-name">张三 · CS001</div>
|
||||
<div class="shift-modal__cashier-meta">登录时间:2026-08-11 07:55 · 已值班 <span id="shiftDuration">4h 35m</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 汇总指标 -->
|
||||
<div class="shift-modal__kpi-grid">
|
||||
<div class="shift-kpi">
|
||||
<div class="shift-kpi__label">当班营业额</div>
|
||||
<div class="shift-kpi__value shift-kpi__value--green">¥5,428<span class="shift-kpi__unit">.50</span></div>
|
||||
<div class="shift-kpi__hint">含早餐 ¥1,926 + 午餐 ¥3,502.50</div>
|
||||
</div>
|
||||
<div class="shift-kpi">
|
||||
<div class="shift-kpi__label">当班订单数</div>
|
||||
<div class="shift-kpi__value">186<span class="shift-kpi__unit">单</span></div>
|
||||
<div class="shift-kpi__hint">早餐 71 单 + 午餐 115 单</div>
|
||||
</div>
|
||||
<div class="shift-kpi">
|
||||
<div class="shift-kpi__label">退款笔数 / 金额</div>
|
||||
<div class="shift-kpi__value">3<span class="shift-kpi__unit">笔</span></div>
|
||||
<div class="shift-kpi__hint">合计 ¥82.00 · 退款率 1.61%</div>
|
||||
</div>
|
||||
<div class="shift-kpi">
|
||||
<div class="shift-kpi__label">开餐 / 收餐操作</div>
|
||||
<div class="shift-kpi__value">2<span class="shift-kpi__unit">次开餐</span></div>
|
||||
<div class="shift-kpi__hint">早餐 07:32 开 · 午餐 10:58 开 · 暂未收餐</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 支付方式收款明细 -->
|
||||
<div class="shift-modal__section">
|
||||
<div class="shift-modal__section-title">💳 收款方式明细</div>
|
||||
<div class="shift-pay-table">
|
||||
<div class="shift-pay-table__head">
|
||||
<span class="shift-pay-table__th shift-pay-table__th--name">支付方式</span>
|
||||
<span class="shift-pay-table__th shift-pay-table__th--num">笔数</span>
|
||||
<span class="shift-pay-table__th shift-pay-table__th--num">金额</span>
|
||||
<span class="shift-pay-table__th shift-pay-table__th--num">占比</span>
|
||||
</div>
|
||||
<div class="shift-pay-table__row">
|
||||
<span class="shift-pay-table__td shift-pay-table__td--name"><span class="shift-pay-dot shift-pay-dot--online"></span>在线支付</span>
|
||||
<span class="shift-pay-table__td shift-pay-table__td--num">152</span>
|
||||
<span class="shift-pay-table__td shift-pay-table__td--num">¥4,426.50</span>
|
||||
<span class="shift-pay-table__td shift-pay-table__td--num">81.5%</span>
|
||||
</div>
|
||||
<div class="shift-pay-table__row">
|
||||
<span class="shift-pay-table__td shift-pay-table__td--name"><span class="shift-pay-dot shift-pay-dot--cash"></span>现金</span>
|
||||
<span class="shift-pay-table__td shift-pay-table__td--num">3</span>
|
||||
<span class="shift-pay-table__td shift-pay-table__td--num">¥82.00</span>
|
||||
<span class="shift-pay-table__td shift-pay-table__td--num">1.5%</span>
|
||||
</div>
|
||||
<div class="shift-pay-table__row">
|
||||
<span class="shift-pay-table__td shift-pay-table__td--name"><span class="shift-pay-dot shift-pay-dot--balance"></span>余额支付</span>
|
||||
<span class="shift-pay-table__td shift-pay-table__td--num">31</span>
|
||||
<span class="shift-pay-table__td shift-pay-table__td--num">¥920.00</span>
|
||||
<span class="shift-pay-table__td shift-pay-table__td--num">17.0%</span>
|
||||
</div>
|
||||
<div class="shift-pay-table__row shift-pay-table__row--total">
|
||||
<span class="shift-pay-table__td shift-pay-table__td--name">合计</span>
|
||||
<span class="shift-pay-table__td shift-pay-table__td--num">186</span>
|
||||
<span class="shift-pay-table__td shift-pay-table__td--num">¥5,428.50</span>
|
||||
<span class="shift-pay-table__td shift-pay-table__td--num">100%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="shift-modal__divider"></div>
|
||||
<div class="shift-modal__actions">
|
||||
<button class="shift-modal__btn shift-modal__btn--cancel" onclick="closeShiftHandover()">取消</button>
|
||||
<a class="shift-modal__btn shift-modal__btn--exit" href="01-login.html">确定交接班并退出</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,343 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=1280, initial-scale=1.0">
|
||||
<title>结算设备 - 餐次管理 | 蚁熊智能餐养平台</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
font-family: -apple-system, "Microsoft YaHei", "PingFang SC", sans-serif;
|
||||
background: #05080f;
|
||||
color: #fff;
|
||||
min-height: 100vh;
|
||||
min-width: 1280px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
}
|
||||
.device-frame {
|
||||
width: 1280px;
|
||||
height: 720px;
|
||||
background: #0e1326;
|
||||
border-radius: 24px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 24px 64px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(255, 255, 255, 0.04);
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* 顶部导航 */
|
||||
.top-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 44px;
|
||||
background: #1a2b4a;
|
||||
padding: 0 20px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.back-btn {
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
.back-btn:hover { color: #fff; }
|
||||
.top-bar__title {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
}
|
||||
.top-bar__meta {
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
font-family: Menlo, Consolas, monospace;
|
||||
}
|
||||
|
||||
/* 主内容区 */
|
||||
.main-area {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 28px 56px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 顶部餐次状态摘要 */
|
||||
.meal-summary {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding: 14px 20px;
|
||||
background: rgba(26, 43, 74, 0.5);
|
||||
border: 1px solid rgba(255, 255, 255, 0.06);
|
||||
border-radius: 12px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
.meal-summary__icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 10px;
|
||||
background: rgba(74, 144, 217, 0.18);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 18px;
|
||||
}
|
||||
.meal-summary__body { flex: 1; display: flex; flex-direction: column; gap: 4px; }
|
||||
.meal-summary__title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
}
|
||||
.meal-summary__sub {
|
||||
font-size: 11px;
|
||||
color: rgba(255, 255, 255, 0.55);
|
||||
}
|
||||
.meal-summary__time {
|
||||
font-size: 22px;
|
||||
font-weight: 600;
|
||||
font-family: Menlo, Consolas, monospace;
|
||||
color: #4ade80;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
/* 导航卡片容器 */
|
||||
.nav-cards {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 28px;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
/* 导航卡片 */
|
||||
.nav-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 260px;
|
||||
padding: 32px 24px 24px;
|
||||
border-radius: 16px;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
transition: all 0.25s;
|
||||
border: 1px solid;
|
||||
text-align: center;
|
||||
}
|
||||
.nav-card:hover {
|
||||
transform: translateY(-3px);
|
||||
}
|
||||
|
||||
/* 开餐开关卡(绿色主调) */
|
||||
.nav-card--active {
|
||||
background: linear-gradient(180deg, rgba(74, 222, 128, 0.12) 0%, rgba(26, 43, 74, 0.4) 100%);
|
||||
border-color: rgba(74, 222, 128, 0.35);
|
||||
}
|
||||
.nav-card--active:hover {
|
||||
background: linear-gradient(180deg, rgba(74, 222, 128, 0.2) 0%, rgba(26, 43, 74, 0.55) 100%);
|
||||
border-color: rgba(74, 222, 128, 0.55);
|
||||
box-shadow: 0 8px 24px rgba(74, 222, 128, 0.15);
|
||||
}
|
||||
|
||||
/* 历史记录卡(蓝色主调) */
|
||||
.nav-card--history {
|
||||
background: linear-gradient(180deg, rgba(74, 144, 217, 0.12) 0%, rgba(26, 43, 74, 0.4) 100%);
|
||||
border-color: rgba(74, 144, 217, 0.35);
|
||||
}
|
||||
.nav-card--history:hover {
|
||||
background: linear-gradient(180deg, rgba(74, 144, 217, 0.2) 0%, rgba(26, 43, 74, 0.55) 100%);
|
||||
border-color: rgba(74, 144, 217, 0.55);
|
||||
box-shadow: 0 8px 24px rgba(74, 144, 217, 0.15);
|
||||
}
|
||||
|
||||
.nav-card__icon {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border-radius: 14px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 28px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.nav-card--active .nav-card__icon {
|
||||
background: rgba(74, 222, 128, 0.2);
|
||||
}
|
||||
.nav-card--history .nav-card__icon {
|
||||
background: rgba(74, 144, 217, 0.2);
|
||||
}
|
||||
|
||||
.nav-card__title {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.nav-card__desc {
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.55);
|
||||
line-height: 1.6;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
/* 状态标签 */
|
||||
.nav-card__pill {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
padding: 4px 12px;
|
||||
border-radius: 10px;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.nav-card__pill--live {
|
||||
background: rgba(74, 222, 128, 0.18);
|
||||
color: #4ade80;
|
||||
border: 1px solid rgba(74, 222, 128, 0.35);
|
||||
}
|
||||
.nav-card__pill--count {
|
||||
background: rgba(74, 144, 217, 0.18);
|
||||
color: #60a5fa;
|
||||
border: 1px solid rgba(74, 144, 217, 0.35);
|
||||
}
|
||||
.nav-card__pill .dot {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: currentColor;
|
||||
animation: dotBlink 1.4s infinite;
|
||||
}
|
||||
@keyframes dotBlink {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0.35; }
|
||||
}
|
||||
|
||||
/* Toast 提示条 */
|
||||
.toast {
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%) translateY(-20px);
|
||||
padding: 10px 22px;
|
||||
background: rgba(74, 222, 128, 0.95);
|
||||
color: #0e1326;
|
||||
border-radius: 22px;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
box-shadow: 0 8px 24px rgba(74, 222, 128, 0.3);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: all 0.3s;
|
||||
z-index: 100;
|
||||
}
|
||||
.toast--show {
|
||||
opacity: 1;
|
||||
transform: translateX(-50%) translateY(0);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="device-frame">
|
||||
|
||||
<!-- 顶部导航 -->
|
||||
<div class="top-bar">
|
||||
<a class="back-btn" href="02-standby.html">◀ 返回待机</a>
|
||||
<span class="top-bar__title">餐次管理</span>
|
||||
<span class="top-bar__meta" id="topMeta">2026-08-10 周一</span>
|
||||
</div>
|
||||
|
||||
<!-- Toast 提示 -->
|
||||
<div class="toast" id="toast">余量处置已提交 ✓</div>
|
||||
|
||||
<!-- 主内容 -->
|
||||
<div class="main-area">
|
||||
|
||||
<!-- 当前餐次状态摘要 -->
|
||||
<div class="meal-summary">
|
||||
<div class="meal-summary__icon">🥪</div>
|
||||
<div class="meal-summary__body">
|
||||
<div class="meal-summary__title">当前餐次 · 午餐</div>
|
||||
<div class="meal-summary__sub">数味餐厅 · 一楼 | 共 3 条餐线 · 28 道菜</div>
|
||||
</div>
|
||||
<div class="meal-summary__time" id="liveClock">12:30:45</div>
|
||||
</div>
|
||||
|
||||
<!-- 导航卡片区 -->
|
||||
<div class="nav-cards">
|
||||
|
||||
<!-- 餐次开关 -->
|
||||
<a class="nav-card nav-card--active" href="11-meal-active.html?meal=lunch">
|
||||
<div class="nav-card__icon">🔊</div>
|
||||
<div class="nav-card__title">餐次开关</div>
|
||||
<div class="nav-card__desc">查看开餐信息 · 餐品余量<br>通知补餐 · 结束用餐</div>
|
||||
<span class="nav-card__pill nav-card__pill--live">
|
||||
<span class="dot"></span> 开餐中
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<!-- 历史记录 -->
|
||||
<a class="nav-card nav-card--history" href="13-meal-history.html">
|
||||
<div class="nav-card__icon">📜</div>
|
||||
<div class="nav-card__title">历史记录</div>
|
||||
<div class="nav-card__desc">查看餐次开餐/补餐<br>闭餐/余量处置流程 · 点击查看明细</div>
|
||||
<span class="nav-card__pill nav-card__pill--count">今日 2 餐次</span>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* ============ 实时时钟(只显示时分秒) ============ */
|
||||
function updateClock() {
|
||||
var now = new Date();
|
||||
var hh = String(now.getHours()).padStart(2, '0');
|
||||
var mm = String(now.getMinutes()).padStart(2, '0');
|
||||
var ss = String(now.getSeconds()).padStart(2, '0');
|
||||
document.getElementById('liveClock').textContent = hh + ':' + mm + ':' + ss;
|
||||
|
||||
/* 右上角元信息:年月日 + 周几 */
|
||||
var year = now.getFullYear();
|
||||
var month = String(now.getMonth() + 1).padStart(2, '0');
|
||||
var date = String(now.getDate()).padStart(2, '0');
|
||||
var weekDay = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'][now.getDay()];
|
||||
document.getElementById('topMeta').textContent = year + '-' + month + '-' + date + ' ' + weekDay;
|
||||
}
|
||||
updateClock();
|
||||
setInterval(updateClock, 1000);
|
||||
|
||||
/* ============ URL 参数驱动的 Toast 提示 ============
|
||||
场景:从 12-meal-end-surplus.html 提交余量处置后跳回本页时
|
||||
携带 ?toast=submitted 参数,本页解析后显示"余量处置已提交"提示
|
||||
*/
|
||||
(function () {
|
||||
var params = new URLSearchParams(window.location.search);
|
||||
var toastKey = params.get('toast');
|
||||
if (toastKey === 'submitted') {
|
||||
var toast = document.getElementById('toast');
|
||||
setTimeout(function () {
|
||||
toast.classList.add('toast--show');
|
||||
setTimeout(function () {
|
||||
toast.classList.remove('toast--show');
|
||||
}, 2400);
|
||||
}, 400);
|
||||
}
|
||||
/* 清除 URL 中的 toast 参数,避免刷新重复触发 */
|
||||
if (toastKey) {
|
||||
history.replaceState(null, '', window.location.pathname);
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -459,6 +459,140 @@
|
||||
opacity: 1;
|
||||
transform: translateX(-50%) translateY(0);
|
||||
}
|
||||
|
||||
/* 已收餐状态:信息条变琥珀色调 */
|
||||
.meal-info-bar--collected {
|
||||
background: linear-gradient(135deg, rgba(251, 191, 36, 0.12) 0%, rgba(26, 43, 74, 0.6) 100%);
|
||||
border-color: rgba(251, 191, 36, 0.3);
|
||||
}
|
||||
.meal-info-bar--collected .meal-info-bar__icon {
|
||||
background: rgba(251, 191, 36, 0.22);
|
||||
}
|
||||
.meal-info-bar__live--collected {
|
||||
background: rgba(251, 191, 36, 0.18);
|
||||
border-color: rgba(251, 191, 36, 0.4);
|
||||
color: #fbbf24;
|
||||
}
|
||||
.meal-info-bar__live--collected::before {
|
||||
background: #fbbf24;
|
||||
}
|
||||
|
||||
/* ===== 收餐弹窗:双卡片选项 ===== */
|
||||
.modal--wide { width: 500px; }
|
||||
.collect-cards {
|
||||
display: flex;
|
||||
gap: 14px;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
.collect-card {
|
||||
flex: 1;
|
||||
padding: 18px 16px 14px;
|
||||
border-radius: 12px;
|
||||
border: 1.5px solid;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
text-decoration: none;
|
||||
}
|
||||
.collect-card:hover {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
.collect-card--employee {
|
||||
background: linear-gradient(180deg, rgba(251, 191, 36, 0.12) 0%, rgba(26, 43, 74, 0.4) 100%);
|
||||
border-color: rgba(251, 191, 36, 0.4);
|
||||
}
|
||||
.collect-card--employee:hover {
|
||||
border-color: rgba(251, 191, 36, 0.65);
|
||||
box-shadow: 0 6px 20px rgba(251, 191, 36, 0.15);
|
||||
}
|
||||
.collect-card--dispose {
|
||||
background: linear-gradient(180deg, rgba(168, 85, 247, 0.12) 0%, rgba(26, 43, 74, 0.4) 100%);
|
||||
border-color: rgba(168, 85, 247, 0.4);
|
||||
}
|
||||
.collect-card--dispose:hover {
|
||||
border-color: rgba(168, 85, 247, 0.65);
|
||||
box-shadow: 0 6px 20px rgba(168, 85, 247, 0.15);
|
||||
}
|
||||
.collect-card__step {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 50%;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.collect-card--employee .collect-card__step {
|
||||
background: rgba(251, 191, 36, 0.25);
|
||||
color: #fbbf24;
|
||||
}
|
||||
.collect-card--dispose .collect-card__step {
|
||||
background: rgba(168, 85, 247, 0.25);
|
||||
color: #c084fc;
|
||||
}
|
||||
.collect-card__title {
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
}
|
||||
.collect-card__desc {
|
||||
font-size: 11px;
|
||||
color: rgba(255, 255, 255, 0.55);
|
||||
line-height: 1.5;
|
||||
flex: 1;
|
||||
}
|
||||
.collect-arrow {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 20px;
|
||||
color: rgba(255, 255, 255, 0.3);
|
||||
flex-shrink: 0;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
/* 余量处置按钮(已收餐状态下显示,琥珀渐变) */
|
||||
.footer-btn--warning {
|
||||
background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
|
||||
border-color: #f59e0b;
|
||||
color: #fff;
|
||||
box-shadow: 0 6px 18px rgba(245, 158, 11, 0.35);
|
||||
}
|
||||
.footer-btn--warning:hover {
|
||||
background: linear-gradient(135deg, #d97706 0%, #b45309 100%);
|
||||
box-shadow: 0 8px 22px rgba(245, 158, 11, 0.5);
|
||||
}
|
||||
|
||||
/* 已收餐提示横幅 */
|
||||
.collected-banner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 14px 18px;
|
||||
background: linear-gradient(135deg, rgba(251, 191, 36, 0.1) 0%, rgba(26, 43, 74, 0.4) 100%);
|
||||
border: 1px solid rgba(251, 191, 36, 0.25);
|
||||
border-radius: 12px;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
.collected-banner__icon {
|
||||
font-size: 24px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.collected-banner__text {
|
||||
flex: 1;
|
||||
font-size: 13px;
|
||||
color: #fbbf24;
|
||||
font-weight: 600;
|
||||
}
|
||||
.collected-banner__sub {
|
||||
font-size: 11px;
|
||||
color: rgba(255, 255, 255, 0.55);
|
||||
font-weight: 400;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -467,7 +601,7 @@
|
||||
|
||||
<!-- 顶部导航 -->
|
||||
<div class="top-bar">
|
||||
<a class="back-btn" href="10-meal-center.html">◀ 返回餐次管理</a>
|
||||
<a class="back-btn" href="02-standby.html">◀ 返回待机</a>
|
||||
<span class="top-bar__title">开餐中 · <span id="mealTitle">午餐</span></span>
|
||||
<span class="top-bar__meta" id="topMeta">2026-08-10 周一</span>
|
||||
</div>
|
||||
@@ -525,26 +659,40 @@
|
||||
</div>
|
||||
|
||||
<!-- 底部固定操作 -->
|
||||
<div class="footer-actions">
|
||||
<a class="footer-btn footer-btn--secondary" href="10-meal-center.html">◀ 返回</a>
|
||||
<button class="footer-btn footer-btn--danger" onclick="showEndModal()">
|
||||
⛔ 结束用餐
|
||||
<div class="footer-actions" id="footerActions">
|
||||
<a class="footer-btn footer-btn--secondary" href="02-standby.html">◀ 返回</a>
|
||||
<button class="footer-btn footer-btn--danger" id="footerActionBtn" onclick="showEndModal()">
|
||||
🥢 收餐
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 二次确认对话框 -->
|
||||
<!-- 收餐对话框 -->
|
||||
<div class="modal-overlay" id="endModal">
|
||||
<div class="modal">
|
||||
<div class="modal__title">⛔ 确认结束用餐?</div>
|
||||
<div class="modal modal--wide">
|
||||
<div class="modal__title">🥢 确认收餐</div>
|
||||
<div class="modal__desc">
|
||||
结束后顾客将<strong>无法继续取餐结算</strong>,本餐次进入收尾流程。<br>
|
||||
系统将引导你完成各餐线餐品的<strong>余量处置</strong>(员工福利/捐赠/废弃/加工再利用)。
|
||||
收餐后顾客将<strong>无法继续取餐结算</strong>。请选择收餐后的处理方式:
|
||||
</div>
|
||||
<div class="collect-cards">
|
||||
<!-- ① 员工餐时间 -->
|
||||
<a class="collect-card collect-card--employee" href="javascript:void(0)" onclick="goEmployeeMeal()">
|
||||
<span class="collect-card__step">①</span>
|
||||
<span class="collect-card__title">🍽️ 员工餐时间</span>
|
||||
<span class="collect-card__desc">先让员工用餐,暂不处置剩余餐品。餐次状态变更为已收餐,稍后再处理余量。</span>
|
||||
</a>
|
||||
<!-- 连接箭头 -->
|
||||
<span class="collect-arrow">➜</span>
|
||||
<!-- ② 余量处置 -->
|
||||
<a class="collect-card collect-card--dispose" href="javascript:void(0)" onclick="goSurplus()">
|
||||
<span class="collect-card__step">②</span>
|
||||
<span class="collect-card__title">♻️ 余量处置</span>
|
||||
<span class="collect-card__desc">直接进入余量处置流程。员工福利 / 捐赠 / 废弃 / 加工再利用。</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="modal__actions">
|
||||
<button class="modal__btn modal__btn--cancel" onclick="hideEndModal()">取消</button>
|
||||
<a class="modal__btn modal__btn--confirm" href="12-meal-end-surplus.html?meal=lunch" style="text-decoration:none;display:inline-flex;align-items:center;justify-content:center;">确认结束 · 去处置余量</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -679,6 +827,7 @@
|
||||
}
|
||||
|
||||
/* ============ 二次确认对话框 ============ */
|
||||
var currentMeal = 'lunch';
|
||||
function showEndModal() {
|
||||
document.getElementById('endModal').classList.add('is-show');
|
||||
}
|
||||
@@ -686,6 +835,16 @@
|
||||
document.getElementById('endModal').classList.remove('is-show');
|
||||
}
|
||||
|
||||
/* 员工餐时间:回到待机页面并传递已收餐状态 */
|
||||
function goEmployeeMeal() {
|
||||
window.location.href = '02-standby.html?status=collected&meal=' + currentMeal;
|
||||
}
|
||||
|
||||
/* 直接去余量处置 */
|
||||
function goSurplus() {
|
||||
window.location.href = '12-meal-end-surplus.html?meal=' + currentMeal;
|
||||
}
|
||||
|
||||
/* ============ 实时时钟 + 开餐时长 ============ */
|
||||
function updateClock() {
|
||||
var now = new Date();
|
||||
@@ -698,12 +857,43 @@
|
||||
updateClock();
|
||||
setInterval(updateClock, 30000);
|
||||
|
||||
/* ============ URL 参数解析(餐次) ============ */
|
||||
/* ============ URL 参数解析(餐次 + 收餐状态) ============ */
|
||||
(function () {
|
||||
var params = new URLSearchParams(window.location.search);
|
||||
var meal = params.get('meal') || 'lunch';
|
||||
currentMeal = meal;
|
||||
var status = params.get('status'); /* 'collected' 表示已收餐 */
|
||||
var mealMap = { breakfast: '早餐', lunch: '午餐', dinner: '晚餐' };
|
||||
document.getElementById('mealTitle').textContent = mealMap[meal] || '午餐';
|
||||
var mealName = mealMap[meal] || '午餐';
|
||||
|
||||
if (status === 'collected') {
|
||||
/* 已收餐状态:页面标题、信息条、底部按钮全部切换 */
|
||||
document.getElementById('mealTitle').textContent = mealName + ' · 已收餐';
|
||||
|
||||
/* 信息条变琥珀色 */
|
||||
var infoBar = document.querySelector('.meal-info-bar');
|
||||
infoBar.classList.add('meal-info-bar--collected');
|
||||
|
||||
/* 状态标签变为"员工餐时间" */
|
||||
var liveBadge = document.querySelector('.meal-info-bar__live');
|
||||
liveBadge.textContent = '员工餐时间';
|
||||
liveBadge.classList.add('meal-info-bar__live--collected');
|
||||
|
||||
/* 底部按钮变为"余量处置" */
|
||||
var btn = document.getElementById('footerActionBtn');
|
||||
btn.textContent = '♻ 余量处置';
|
||||
btn.className = 'footer-btn footer-btn--warning';
|
||||
btn.onclick = function () { window.location.href = '12-meal-end-surplus.html?meal=' + currentMeal; };
|
||||
} else {
|
||||
document.getElementById('mealTitle').textContent = mealName;
|
||||
}
|
||||
|
||||
/* 从待机页点"收餐"跳转过来时,自动弹出收餐弹窗 */
|
||||
if (params.get('action') === 'collect') {
|
||||
setTimeout(function () { showEndModal(); }, 300);
|
||||
/* 清理 URL 参数避免刷新重复触发 */
|
||||
history.replaceState(null, '', '11-meal-active.html?meal=' + currentMeal);
|
||||
}
|
||||
})();
|
||||
|
||||
/* ============ 初始渲染:A 区餐线 ============ */
|
||||
|
||||
@@ -128,21 +128,6 @@
|
||||
border-radius: 10px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.toolbar__select-all {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
user-select: none;
|
||||
}
|
||||
.toolbar__select-all input { cursor: pointer; accent-color: #4a90d9; }
|
||||
.toolbar__divider {
|
||||
width: 1px;
|
||||
height: 22px;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
.toolbar__label {
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
@@ -164,30 +149,11 @@
|
||||
min-width: 130px;
|
||||
}
|
||||
.toolbar__select:focus { border-color: #4a90d9; }
|
||||
.toolbar__btn {
|
||||
height: 28px;
|
||||
padding: 0 14px;
|
||||
background: linear-gradient(135deg, rgba(74, 144, 217, 0.4), rgba(74, 144, 217, 0.25));
|
||||
border: 1px solid rgba(74, 144, 217, 0.5);
|
||||
border-radius: 6px;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.toolbar__btn:hover {
|
||||
background: linear-gradient(135deg, rgba(74, 144, 217, 0.6), rgba(74, 144, 217, 0.4));
|
||||
}
|
||||
.toolbar__btn:disabled {
|
||||
opacity: 0.4;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.toolbar__spacer { flex: 1; }
|
||||
.toolbar__hint {
|
||||
font-size: 11px;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
.toolbar__spacer { flex: 1; }
|
||||
|
||||
/* 表格容器 */
|
||||
.table-wrap {
|
||||
@@ -231,7 +197,6 @@
|
||||
.surplus-table tbody tr:last-child td { border-bottom: none; }
|
||||
|
||||
/* 列宽 */
|
||||
.col-ck { width: 36px; text-align: center; }
|
||||
.col-name { width: 130px; }
|
||||
.col-line { width: 80px; }
|
||||
.col-num { width: 80px; text-align: right; }
|
||||
@@ -240,15 +205,6 @@
|
||||
.col-amount { width: 90px; }
|
||||
.col-note { width: auto; }
|
||||
|
||||
/* 复选框 */
|
||||
.row-ck {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
cursor: pointer;
|
||||
accent-color: #4a90d9;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* 餐线徽标 */
|
||||
.line-badge {
|
||||
display: inline-block;
|
||||
@@ -519,13 +475,8 @@
|
||||
|
||||
<!-- 工具栏 -->
|
||||
<div class="toolbar">
|
||||
<label class="toolbar__select-all">
|
||||
<input type="checkbox" id="selectAll" onchange="toggleAll(this)">
|
||||
全选
|
||||
</label>
|
||||
<div class="toolbar__divider"></div>
|
||||
<span class="toolbar__label">批量处置方式:</span>
|
||||
<select class="toolbar__select" id="batchMethod">
|
||||
<span class="toolbar__label">批量处置方式:</span>
|
||||
<select class="toolbar__select" id="batchMethod" onchange="onBatchMethodChange(this.value)">
|
||||
<option value="">请选择...</option>
|
||||
<option value="welfare">员工福利</option>
|
||||
<option value="donate">捐赠</option>
|
||||
@@ -533,16 +484,14 @@
|
||||
<option value="reprocess">加工再利用</option>
|
||||
<option value="locker">存入智能货柜</option>
|
||||
</select>
|
||||
<button class="toolbar__btn" onclick="applyBatch()">应用到选中项</button>
|
||||
<div class="toolbar__spacer"></div>
|
||||
<span class="toolbar__hint" id="selectCount">已选 0 项</span>
|
||||
<span class="toolbar__hint" id="totalCount">共 20 道菜</span>
|
||||
</div>
|
||||
|
||||
<!-- 余量处置表格 -->
|
||||
<div class="table-wrap">
|
||||
<table class="surplus-table">
|
||||
<colgroup>
|
||||
<col class="col-ck">
|
||||
<col class="col-name">
|
||||
<col class="col-line">
|
||||
<col class="col-num">
|
||||
@@ -555,7 +504,6 @@
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="col-ck"></th>
|
||||
<th>餐品名称</th>
|
||||
<th>餐线</th>
|
||||
<th style="text-align:right;">实际制作(kg)</th>
|
||||
@@ -672,7 +620,6 @@
|
||||
|
||||
html += ''
|
||||
+ '<tr data-id="' + item.id + '">'
|
||||
+ ' <td class="col-ck"><input type="checkbox" class="row-ck" onchange="updateSummary()" data-id="' + item.id + '"></td>'
|
||||
+ ' <td><span style="margin-right:4px;">' + item.emoji + '</span>' + item.name + '</td>'
|
||||
+ ' <td><span class="line-badge line-badge--' + item.line + '">' + item.line + ' 区</span></td>'
|
||||
+ ' <td style="text-align:right;" class="num-made">' + item.made.toFixed(1) + '</td>'
|
||||
@@ -689,18 +636,12 @@
|
||||
+ ' <option value="locker">存入智能货柜</option>'
|
||||
+ ' </select>'
|
||||
+ ' </td>'
|
||||
+ ' <td><input type="number" class="amount-input" step="0.1" min="0" max="' + surplus.toFixed(1) + '" value="' + surplus.toFixed(1) + '" data-id="' + item.id + '"></td>'
|
||||
+ ' <td><input type="number" class="amount-input" step="0.1" min="0" max="' + surplus.toFixed(1) + '" value="' + surplus.toFixed(1) + '" data-id="' + item.id + '" onchange="updateSummary()"></td>'
|
||||
+ ' <td><input type="text" class="note-input" placeholder="如:加班餐/捐赠予..." data-id="' + item.id + '"></td>'
|
||||
+ '</tr>';
|
||||
});
|
||||
document.getElementById('surplusTbody').innerHTML = html;
|
||||
updateSummary();
|
||||
}
|
||||
|
||||
/* ============ 全选/取消全选 ============ */
|
||||
function toggleAll(masterCk) {
|
||||
var cks = document.querySelectorAll('.row-ck');
|
||||
cks.forEach(function (ck) { ck.checked = masterCk.checked; });
|
||||
document.getElementById('totalCount').textContent = '共 ' + SURPLUS_DATA.length + ' 道菜';
|
||||
updateSummary();
|
||||
}
|
||||
|
||||
@@ -711,34 +652,24 @@
|
||||
updateSummary();
|
||||
}
|
||||
|
||||
/* ============ 批量应用处置方式 ============ */
|
||||
function applyBatch() {
|
||||
var batchVal = document.getElementById('batchMethod').value;
|
||||
if (!batchVal) {
|
||||
showToast('请先选择批量处置方式', true);
|
||||
return;
|
||||
}
|
||||
var checkedCks = document.querySelectorAll('.row-ck:checked');
|
||||
if (checkedCks.length === 0) {
|
||||
showToast('请先勾选要批量处置的餐品', true);
|
||||
return;
|
||||
}
|
||||
checkedCks.forEach(function (ck) {
|
||||
var id = ck.getAttribute('data-id');
|
||||
var sel = document.querySelector('.method-select[data-id="' + id + '"]');
|
||||
/* ============ 批量处置下拉自动应用到全部行 ============ */
|
||||
function onBatchMethodChange(batchVal) {
|
||||
if (!batchVal) return;
|
||||
var allSelects = document.querySelectorAll('.method-select');
|
||||
allSelects.forEach(function (sel) {
|
||||
sel.value = batchVal;
|
||||
sel.className = 'method-select ' + METHOD_MAP[batchVal].cls;
|
||||
});
|
||||
updateSummary();
|
||||
showToast('已应用到 ' + checkedCks.length + ' 项 ✓');
|
||||
showToast('已批量应用「' + METHOD_MAP[batchVal].label + '」到全部 ' + SURPLUS_DATA.length + ' 道菜 ✓');
|
||||
}
|
||||
|
||||
/* ============ 更新汇总栏 ============ */
|
||||
function updateSummary() {
|
||||
var totalSurplus = 0;
|
||||
var totalDisposed = 0;
|
||||
var disposedCount = 0;
|
||||
var methodCount = { welfare: 0, donate: 0, waste: 0, reprocess: 0, locker: 0 };
|
||||
var checkedCount = 0;
|
||||
|
||||
SURPLUS_DATA.forEach(function (item) {
|
||||
var surplus = +(item.made - item.sold).toFixed(1);
|
||||
@@ -746,11 +677,9 @@
|
||||
|
||||
var sel = document.querySelector('.method-select[data-id="' + item.id + '"]');
|
||||
var amountInput = document.querySelector('.amount-input[data-id="' + item.id + '"]');
|
||||
var ck = document.querySelector('.row-ck[data-id="' + item.id + '"]');
|
||||
|
||||
if (ck.checked) checkedCount++;
|
||||
|
||||
if (sel.value) {
|
||||
if (sel && sel.value) {
|
||||
disposedCount++;
|
||||
var amount = parseFloat(amountInput.value) || 0;
|
||||
totalDisposed += amount;
|
||||
if (methodCount.hasOwnProperty(sel.value)) {
|
||||
@@ -766,7 +695,6 @@
|
||||
document.getElementById('totalSurplus').textContent = totalSurplus.toFixed(1) + ' kg';
|
||||
document.getElementById('totalDisposed').textContent = totalDisposed.toFixed(1) + ' kg';
|
||||
document.getElementById('totalPending').textContent = pending.toFixed(1) + ' kg';
|
||||
document.getElementById('selectCount').textContent = '已选 ' + checkedCount + ' 项';
|
||||
|
||||
/* 处置方式分布 */
|
||||
var parts = [];
|
||||
@@ -776,6 +704,9 @@
|
||||
}
|
||||
});
|
||||
document.getElementById('methodDist').textContent = parts.length ? parts.join(' / ') : '—';
|
||||
|
||||
/* 工具栏提示 */
|
||||
document.getElementById('totalCount').textContent = '共 ' + SURPLUS_DATA.length + ' 道 · 已处置 ' + disposedCount + ' 道';
|
||||
}
|
||||
|
||||
/* ============ 提交二次确认 ============ */
|
||||
@@ -832,7 +763,7 @@
|
||||
/* ============ 提交跳转(模拟) ============ */
|
||||
function submitForm() {
|
||||
/* 实际场景:POST 数据到后端 → 成功后跳转 */
|
||||
window.location.href = '10-meal-center.html?toast=submitted';
|
||||
window.location.href = '02-standby.html';
|
||||
}
|
||||
|
||||
/* ============ Toast 提示 ============ */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -292,7 +292,7 @@
|
||||
<div class="card__icon">📊</div>
|
||||
<div class="card__body">
|
||||
<div class="card__title">运营数据统计</div>
|
||||
<div class="card__desc">营收 + 餐次 + Top + 时段</div>
|
||||
<div class="card__desc">营收 + 餐线 + 餐次历史</div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="card" href="08-reconcile.html">
|
||||
@@ -311,14 +311,6 @@
|
||||
<div class="card__desc">餐后小票预览与打印</div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="card" href="10-meal-center.html">
|
||||
<span class="card__status card__status--core">10 新</span>
|
||||
<div class="card__icon">🍽️</div>
|
||||
<div class="card__body">
|
||||
<div class="card__title">餐次管理</div>
|
||||
<div class="card__desc">开餐开关 / 历史记录入口</div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="card" href="11-meal-active.html?meal=lunch">
|
||||
<span class="card__status card__status--done">11</span>
|
||||
<div class="card__icon">🔊</div>
|
||||
@@ -335,14 +327,6 @@
|
||||
<div class="card__desc">结束用餐引导 · 批量处置</div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="card" href="13-meal-history.html">
|
||||
<span class="card__status card__status--done">13</span>
|
||||
<div class="card__icon">📜</div>
|
||||
<div class="card__body">
|
||||
<div class="card__title">餐次历史记录</div>
|
||||
<div class="card__desc">开餐/补餐/闭餐/余量处置 · 点击查看明细</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -0,0 +1,397 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>配送员登录 | 营养管理餐品配送</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
:root {
|
||||
--primary: #ff6d3a;
|
||||
--primary-dark: #e85a28;
|
||||
--primary-light: #fff0e8;
|
||||
--text-primary: #1f2937;
|
||||
--text-secondary: #6b7280;
|
||||
--text-tertiary: #9ca3af;
|
||||
--border: #e5e7eb;
|
||||
--white: #ffffff;
|
||||
--danger: #ef4444;
|
||||
--shadow-md: 0 10px 28px rgba(15, 23, 42, 0.10);
|
||||
}
|
||||
body {
|
||||
min-height: 100vh;
|
||||
padding: 24px 0 40px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
background: #2a2a2a;
|
||||
color: var(--text-primary);
|
||||
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", sans-serif;
|
||||
}
|
||||
.phone-shell {
|
||||
position: relative;
|
||||
width: 375px;
|
||||
height: 812px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--white);
|
||||
border-radius: 44px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3), inset 0 0 0 2px #e0e0e0;
|
||||
}
|
||||
.status-bar {
|
||||
height: 44px;
|
||||
padding: 0 24px;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
color: #111827;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.status-bar__time { font-size: 15px; font-weight: 700; }
|
||||
.status-bar__icons { display: flex; align-items: center; gap: 6px; }
|
||||
.status-bar__signal {
|
||||
width: 18px; height: 10px;
|
||||
background: #111827;
|
||||
clip-path: polygon(0 100%, 18% 64%, 18% 100%, 36% 42%, 36% 100%, 54% 24%, 54% 100%, 72% 8%, 72% 100%, 100% 0, 100% 100%);
|
||||
}
|
||||
.status-bar__wifi {
|
||||
width: 16px; height: 12px;
|
||||
background: #111827;
|
||||
clip-path: polygon(0 50%, 50% 0, 100% 50%, 86% 60%, 50% 22%, 14% 60%);
|
||||
}
|
||||
.status-bar__battery {
|
||||
width: 24px; height: 12px;
|
||||
border: 1.5px solid #111827;
|
||||
border-radius: 3px;
|
||||
position: relative;
|
||||
padding: 1.5px;
|
||||
}
|
||||
.status-bar__battery::after {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 70%; height: 100%;
|
||||
background: #111827;
|
||||
border-radius: 1px;
|
||||
}
|
||||
.status-bar__battery::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: -3px; top: 3px;
|
||||
width: 2px; height: 6px;
|
||||
background: #111827;
|
||||
border-radius: 0 1px 1px 0;
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: linear-gradient(180deg, var(--primary-light) 0%, var(--white) 30%);
|
||||
padding: 20px 28px 32px;
|
||||
}
|
||||
.hero {
|
||||
text-align: center;
|
||||
margin: 32px 0 40px;
|
||||
}
|
||||
.hero__logo {
|
||||
width: 88px; height: 88px;
|
||||
margin: 0 auto 16px;
|
||||
background: linear-gradient(135deg, var(--primary), var(--primary-dark));
|
||||
border-radius: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 44px;
|
||||
box-shadow: 0 12px 24px rgba(255, 109, 58, 0.35);
|
||||
}
|
||||
.hero__title {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.hero__subtitle {
|
||||
font-size: 13px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.form-group { margin-bottom: 16px; }
|
||||
.form-label {
|
||||
display: block;
|
||||
font-size: 13px;
|
||||
color: var(--text-secondary);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.input-wrap {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #f6f8fb;
|
||||
border: 1.5px solid transparent;
|
||||
border-radius: 12px;
|
||||
padding: 0 14px;
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
.input-wrap:focus-within {
|
||||
border-color: var(--primary);
|
||||
background: var(--white);
|
||||
}
|
||||
.input-icon { font-size: 18px; margin-right: 8px; }
|
||||
.input {
|
||||
flex: 1;
|
||||
height: 48px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
font-size: 15px;
|
||||
color: var(--text-primary);
|
||||
outline: none;
|
||||
}
|
||||
.input::placeholder { color: var(--text-tertiary); }
|
||||
.sms-btn {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: var(--primary);
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
padding: 0 4px;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.sms-btn:disabled { color: var(--text-tertiary); cursor: not-allowed; }
|
||||
.sms-divider {
|
||||
width: 1px;
|
||||
height: 18px;
|
||||
background: var(--border);
|
||||
margin: 0 8px;
|
||||
}
|
||||
|
||||
.agree-row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 8px;
|
||||
margin: 16px 0 24px;
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
line-height: 1.6;
|
||||
}
|
||||
.agree-checkbox {
|
||||
width: 16px; height: 16px;
|
||||
border: 1.5px solid var(--border);
|
||||
border-radius: 4px;
|
||||
flex-shrink: 0;
|
||||
margin-top: 2px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
.agree-checkbox.checked {
|
||||
background: var(--primary);
|
||||
border-color: var(--primary);
|
||||
}
|
||||
.agree-checkbox.checked::after {
|
||||
content: '✓';
|
||||
position: absolute;
|
||||
top: 50%; left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
color: white;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.agree-link { color: var(--primary); text-decoration: none; }
|
||||
|
||||
.primary-btn {
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
background: linear-gradient(135deg, var(--primary), var(--primary-dark));
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 14px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 8px 16px rgba(255, 109, 58, 0.3);
|
||||
transition: transform 0.1s;
|
||||
}
|
||||
.primary-btn:active { transform: scale(0.98); }
|
||||
.primary-btn:disabled {
|
||||
background: #d1d5db;
|
||||
box-shadow: none;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.wechat-btn {
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
background: var(--white);
|
||||
color: #07c160;
|
||||
border: 1.5px solid #07c160;
|
||||
border-radius: 14px;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
margin-top: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.wechat-btn:active { background: #f0fbf4; }
|
||||
|
||||
.divider {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin: 24px 0 16px;
|
||||
color: var(--text-tertiary);
|
||||
font-size: 12px;
|
||||
}
|
||||
.divider::before,
|
||||
.divider::after {
|
||||
content: '';
|
||||
flex: 1;
|
||||
height: 1px;
|
||||
background: var(--border);
|
||||
}
|
||||
|
||||
.switch-role {
|
||||
text-align: center;
|
||||
margin-top: auto;
|
||||
padding-top: 24px;
|
||||
font-size: 13px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
.switch-role a {
|
||||
color: var(--primary);
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.toast {
|
||||
position: absolute;
|
||||
top: 60px; left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
color: white;
|
||||
padding: 8px 16px;
|
||||
border-radius: 20px;
|
||||
font-size: 13px;
|
||||
z-index: 100;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
pointer-events: none;
|
||||
}
|
||||
.toast.show { opacity: 1; }
|
||||
|
||||
.home-indicator {
|
||||
height: 8px;
|
||||
width: 134px;
|
||||
background: #1f2937;
|
||||
border-radius: 4px;
|
||||
margin: 0 auto 8px;
|
||||
align-self: center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
<div class="status-bar">
|
||||
<span class="status-bar__time">9:41</span>
|
||||
<div class="status-bar__icons">
|
||||
<span class="status-bar__signal"></span>
|
||||
<span class="status-bar__wifi"></span>
|
||||
<span class="status-bar__battery"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div class="hero">
|
||||
<div class="hero__logo">🛵</div>
|
||||
<div class="hero__title">营养餐品配送</div>
|
||||
<div class="hero__subtitle">配送员端 · 接单抢单高效配送</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">手机号</label>
|
||||
<div class="input-wrap">
|
||||
<span class="input-icon">📱</span>
|
||||
<input class="input" type="tel" placeholder="请输入手机号" maxlength="11" value="138****6688">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">短信验证码</label>
|
||||
<div class="input-wrap">
|
||||
<span class="input-icon">🔑</span>
|
||||
<input class="input" type="text" placeholder="6位验证码" maxlength="6" value="••••••">
|
||||
<div class="sms-divider"></div>
|
||||
<button class="sms-btn" id="smsBtn">获取验证码</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="agree-row">
|
||||
<div class="agree-checkbox checked" id="agreeBox"></div>
|
||||
<div>
|
||||
我已阅读并同意
|
||||
<a href="javascript:void(0)" class="agree-link">《配送员服务协议》</a>
|
||||
与
|
||||
<a href="javascript:void(0)" class="agree-link">《隐私政策》</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="primary-btn" onclick="location.href='01-home.html'">登录 / 注册</button>
|
||||
|
||||
<div class="divider">其他登录方式</div>
|
||||
|
||||
<button class="wechat-btn" onclick="toast('微信授权中...')">
|
||||
<span>💬</span>
|
||||
微信一键登录
|
||||
</button>
|
||||
|
||||
<div class="switch-role">
|
||||
想要合作配送?
|
||||
<a href="javascript:void(0)" onclick="toast('请联系站点管理员')">申请入驻</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="home-indicator"></div>
|
||||
<div class="toast" id="toast"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function toast(msg) {
|
||||
const t = document.getElementById('toast');
|
||||
t.textContent = msg;
|
||||
t.classList.add('show');
|
||||
setTimeout(() => t.classList.remove('show'), 1800);
|
||||
}
|
||||
|
||||
let countdown = 0;
|
||||
const smsBtn = document.getElementById('smsBtn');
|
||||
smsBtn.addEventListener('click', () => {
|
||||
if (countdown > 0) return;
|
||||
countdown = 60;
|
||||
toast('验证码已发送');
|
||||
const tick = () => {
|
||||
if (countdown <= 0) {
|
||||
smsBtn.disabled = false;
|
||||
smsBtn.textContent = '获取验证码';
|
||||
return;
|
||||
}
|
||||
smsBtn.disabled = true;
|
||||
smsBtn.textContent = countdown + 's 后重发';
|
||||
countdown--;
|
||||
setTimeout(tick, 1000);
|
||||
};
|
||||
tick();
|
||||
});
|
||||
|
||||
document.getElementById('agreeBox').addEventListener('click', e => {
|
||||
e.target.classList.toggle('checked');
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,643 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>工作台首页 | 营养餐品配送</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
:root {
|
||||
--primary: #ff6d3a;
|
||||
--primary-dark: #e85a28;
|
||||
--primary-light: #fff0e8;
|
||||
--text-primary: #1f2937;
|
||||
--text-secondary: #6b7280;
|
||||
--text-tertiary: #9ca3af;
|
||||
--border: #e5e7eb;
|
||||
--background: #f6f8fb;
|
||||
--white: #ffffff;
|
||||
--shadow-sm: 0 2px 8px rgba(15, 23, 42, 0.06);
|
||||
--shadow-md: 0 10px 28px rgba(15, 23, 42, 0.10);
|
||||
--status-accepted: #3b82f6;
|
||||
--status-picking: #14b8a6;
|
||||
--status-delivering: #8b5cf6;
|
||||
--status-completed: #10b981;
|
||||
}
|
||||
body {
|
||||
min-height: 100vh;
|
||||
padding: 24px 0 40px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
background: #2a2a2a;
|
||||
color: var(--text-primary);
|
||||
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", sans-serif;
|
||||
}
|
||||
.phone-shell {
|
||||
position: relative;
|
||||
width: 375px;
|
||||
height: 812px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--background);
|
||||
border-radius: 44px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3), inset 0 0 0 2px #e0e0e0;
|
||||
}
|
||||
.status-bar {
|
||||
height: 44px;
|
||||
padding: 0 24px;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
background: linear-gradient(135deg, var(--primary), var(--primary-dark));
|
||||
}
|
||||
.status-bar__time { font-size: 15px; font-weight: 700; }
|
||||
.status-bar__icons { display: flex; align-items: center; gap: 6px; }
|
||||
.status-bar__signal {
|
||||
width: 18px; height: 10px; background: #fff;
|
||||
clip-path: polygon(0 100%, 18% 64%, 18% 100%, 36% 42%, 36% 100%, 54% 24%, 54% 100%, 72% 8%, 72% 100%, 100% 0, 100% 100%);
|
||||
}
|
||||
.status-bar__wifi {
|
||||
width: 16px; height: 12px; background: #fff;
|
||||
clip-path: polygon(0 50%, 50% 0, 100% 50%, 86% 60%, 50% 22%, 14% 60%);
|
||||
}
|
||||
.status-bar__battery {
|
||||
width: 24px; height: 12px;
|
||||
border: 1.5px solid #fff;
|
||||
border-radius: 3px;
|
||||
position: relative;
|
||||
padding: 1.5px;
|
||||
}
|
||||
.status-bar__battery::after {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 70%; height: 100%;
|
||||
background: #fff;
|
||||
border-radius: 1px;
|
||||
}
|
||||
.status-bar__battery::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: -3px; top: 3px;
|
||||
width: 2px; height: 6px;
|
||||
background: #fff;
|
||||
border-radius: 0 1px 1px 0;
|
||||
}
|
||||
|
||||
.scroll-area {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding-bottom: 80px;
|
||||
}
|
||||
.scroll-area::-webkit-scrollbar { display: none; }
|
||||
|
||||
/* 顶部配送员信息 + 在线开关 */
|
||||
.top-bar {
|
||||
background: linear-gradient(135deg, var(--primary), var(--primary-dark));
|
||||
padding: 0 20px 20px;
|
||||
color: white;
|
||||
}
|
||||
.rider-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 4px 0 16px;
|
||||
}
|
||||
.rider-avatar {
|
||||
width: 50px; height: 50px;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
border: 2px solid rgba(255, 255, 255, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 22px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.rider-info { flex: 1; }
|
||||
.rider-name {
|
||||
font-size: 17px;
|
||||
font-weight: 700;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.rider-meta {
|
||||
font-size: 12px;
|
||||
opacity: 0.9;
|
||||
}
|
||||
.rider-meta .level {
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
padding: 1px 6px;
|
||||
border-radius: 6px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
.online-switch {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
background: rgba(255, 255, 255, 0.18);
|
||||
border-radius: 24px;
|
||||
padding: 6px 12px 6px 6px;
|
||||
}
|
||||
.switch-track {
|
||||
width: 36px; height: 20px;
|
||||
background: #10b981;
|
||||
border-radius: 10px;
|
||||
position: relative;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
.switch-track::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 16px; height: 16px;
|
||||
background: white;
|
||||
border-radius: 50%;
|
||||
top: 2px; left: 18px;
|
||||
transition: left 0.3s;
|
||||
}
|
||||
.online-switch.off .switch-track { background: #9ca3af; }
|
||||
.online-switch.off .switch-track::after { left: 2px; }
|
||||
.online-text { font-size: 12px; font-weight: 600; }
|
||||
|
||||
/* 今日数据 */
|
||||
.stats-card {
|
||||
background: white;
|
||||
margin: -10px 16px 0;
|
||||
padding: 18px 12px;
|
||||
border-radius: 14px;
|
||||
box-shadow: var(--shadow-md);
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 4px;
|
||||
}
|
||||
.stat-item { text-align: center; }
|
||||
.stat-num {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: var(--primary);
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.stat-label {
|
||||
font-size: 11px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
/* 派单提醒横幅(模拟收到派单) */
|
||||
.dispatch-banner {
|
||||
margin: 14px 16px 0;
|
||||
background: linear-gradient(135deg, #fff5e6, #ffe5d4);
|
||||
border: 1.5px solid var(--primary);
|
||||
border-radius: 14px;
|
||||
padding: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
animation: bannerPulse 2s ease-in-out infinite;
|
||||
cursor: pointer;
|
||||
}
|
||||
@keyframes bannerPulse {
|
||||
0%, 100% { box-shadow: 0 0 0 0 rgba(255, 109, 58, 0.4); }
|
||||
50% { box-shadow: 0 0 0 8px rgba(255, 109, 58, 0); }
|
||||
}
|
||||
.dispatch-banner__icon {
|
||||
width: 40px; height: 40px;
|
||||
background: var(--primary);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 20px;
|
||||
flex-shrink: 0;
|
||||
animation: ringShake 1.5s ease-in-out infinite;
|
||||
}
|
||||
@keyframes ringShake {
|
||||
0%, 100% { transform: rotate(0); }
|
||||
20% { transform: rotate(-15deg); }
|
||||
40% { transform: rotate(15deg); }
|
||||
60% { transform: rotate(-10deg); }
|
||||
80% { transform: rotate(10deg); }
|
||||
}
|
||||
.dispatch-banner__text { flex: 1; }
|
||||
.dispatch-banner__title {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: var(--primary-dark);
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.dispatch-banner__desc {
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
.dispatch-banner__arrow {
|
||||
color: var(--primary);
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* 进行中订单 */
|
||||
.section {
|
||||
margin: 18px 16px 0;
|
||||
}
|
||||
.section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.section-title {
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
color: var(--text-primary);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
.section-title__dot {
|
||||
width: 4px; height: 14px;
|
||||
background: var(--primary);
|
||||
border-radius: 2px;
|
||||
}
|
||||
.section-more {
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.order-card {
|
||||
background: white;
|
||||
border-radius: 14px;
|
||||
padding: 14px;
|
||||
margin-bottom: 10px;
|
||||
box-shadow: var(--shadow-sm);
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
display: block;
|
||||
}
|
||||
.order-card__head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.order-num {
|
||||
font-size: 12px;
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
.status-pill {
|
||||
font-size: 11px;
|
||||
padding: 2px 8px;
|
||||
border-radius: 10px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.status-pill--delivering {
|
||||
background: #f3e8ff;
|
||||
color: var(--status-delivering);
|
||||
}
|
||||
.status-pill--picking {
|
||||
background: #ccfbf1;
|
||||
color: var(--status-picking);
|
||||
}
|
||||
.status-pill--accepted {
|
||||
background: #dbeafe;
|
||||
color: var(--status-accepted);
|
||||
}
|
||||
.order-type-tag {
|
||||
display: inline-block;
|
||||
font-size: 10px;
|
||||
padding: 1px 6px;
|
||||
border-radius: 4px;
|
||||
margin-left: 6px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.order-type-tag--store {
|
||||
background: #fef3c7;
|
||||
color: #92400e;
|
||||
}
|
||||
.order-type-tag--home {
|
||||
background: #dbeafe;
|
||||
color: #1e40af;
|
||||
}
|
||||
|
||||
.route-line {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
padding: 4px 0;
|
||||
}
|
||||
.route-point {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.route-icon {
|
||||
width: 22px; height: 22px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 11px;
|
||||
flex-shrink: 0;
|
||||
color: white;
|
||||
}
|
||||
.route-icon--start { background: var(--primary); }
|
||||
.route-icon--end { background: var(--status-completed); }
|
||||
.route-info { flex: 1; padding-top: 1px; }
|
||||
.route-name {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.route-addr {
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
line-height: 1.5;
|
||||
}
|
||||
.route-connector {
|
||||
width: 2px;
|
||||
height: 14px;
|
||||
background: var(--border);
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.order-meta {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
margin: 10px 0;
|
||||
padding: 8px 10px;
|
||||
background: var(--background);
|
||||
border-radius: 8px;
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
.order-meta-item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.order-meta-label { font-size: 11px; color: var(--text-tertiary); }
|
||||
.order-meta-value { font-size: 13px; color: var(--text-primary); font-weight: 600; }
|
||||
|
||||
.order-action {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
.btn {
|
||||
flex: 1;
|
||||
height: 36px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
}
|
||||
.btn--ghost {
|
||||
background: var(--background);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
.btn--primary {
|
||||
background: var(--primary);
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* 底部 Tab */
|
||||
.tabbar {
|
||||
position: absolute;
|
||||
bottom: 0; left: 0; right: 0;
|
||||
height: 70px;
|
||||
background: white;
|
||||
border-top: 1px solid var(--border);
|
||||
display: flex;
|
||||
padding: 8px 0 20px;
|
||||
}
|
||||
.tab {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 2px;
|
||||
text-decoration: none;
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
.tab.active { color: var(--primary); }
|
||||
.tab__icon { font-size: 22px; }
|
||||
.tab__label { font-size: 10px; font-weight: 600; }
|
||||
|
||||
.home-indicator {
|
||||
position: absolute;
|
||||
bottom: 8px; left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 134px; height: 5px;
|
||||
background: #1f2937;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.toast {
|
||||
position: absolute;
|
||||
top: 60px; left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
color: white;
|
||||
padding: 8px 16px;
|
||||
border-radius: 20px;
|
||||
font-size: 13px;
|
||||
z-index: 100;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
pointer-events: none;
|
||||
}
|
||||
.toast.show { opacity: 1; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
<div class="status-bar">
|
||||
<span class="status-bar__time">9:41</span>
|
||||
<div class="status-bar__icons">
|
||||
<span class="status-bar__signal"></span>
|
||||
<span class="status-bar__wifi"></span>
|
||||
<span class="status-bar__battery"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="scroll-area">
|
||||
<!-- 顶部配送员信息 -->
|
||||
<div class="top-bar">
|
||||
<div class="rider-row">
|
||||
<div class="rider-avatar">🧑🦱</div>
|
||||
<div class="rider-info">
|
||||
<div class="rider-name">陈师傅 <span style="font-size:12px;opacity:.85">(陕A·9F8K2)</span></div>
|
||||
<div class="rider-meta">
|
||||
今日已在线 3h 24min
|
||||
</div>
|
||||
</div>
|
||||
<div class="online-switch" id="onlineSwitch" onclick="toggleOnline()">
|
||||
<div class="switch-track"></div>
|
||||
<span class="online-text">在线</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 今日工作量统计 -->
|
||||
<div class="stats-card">
|
||||
<div class="stat-item">
|
||||
<div class="stat-num">8</div>
|
||||
<div class="stat-label">已完成</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-num">2</div>
|
||||
<div class="stat-label">进行中</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-num">32km</div>
|
||||
<div class="stat-label">总里程</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-num">3h24m</div>
|
||||
<div class="stat-label">在线时长</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 派单提醒横幅(模拟收到新派单) -->
|
||||
<div class="dispatch-banner" onclick="location.href='02-dispatch-incoming.html'">
|
||||
<div class="dispatch-banner__icon">📲</div>
|
||||
<div class="dispatch-banner__text">
|
||||
<div class="dispatch-banner__title">您有新的派单 · 倒计时 25s</div>
|
||||
<div class="dispatch-banner__desc">味之都食堂 → 高新区科技路 12 号 · 1.8km</div>
|
||||
</div>
|
||||
<div class="dispatch-banner__arrow">›</div>
|
||||
</div>
|
||||
|
||||
<!-- 进行中订单 -->
|
||||
<div class="section">
|
||||
<div class="section-header">
|
||||
<div class="section-title">
|
||||
<span class="section-title__dot"></span>
|
||||
进行中订单
|
||||
</div>
|
||||
<a href="07-history.html" class="section-more">查看全部 ›</a>
|
||||
</div>
|
||||
|
||||
<a href="05-delivering.html" class="order-card">
|
||||
<div class="order-card__head">
|
||||
<div class="order-num">#DP20260812-0832
|
||||
<span class="order-type-tag order-type-tag--home">到家</span>
|
||||
</div>
|
||||
<span class="status-pill status-pill--delivering">配送中</span>
|
||||
</div>
|
||||
<div class="route-line">
|
||||
<div class="route-point">
|
||||
<div class="route-icon route-icon--start">取</div>
|
||||
<div class="route-info">
|
||||
<div class="route-name">中央厨房·高新站</div>
|
||||
<div class="route-addr">科技三路 8 号 · 已取货 14:22</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="route-point">
|
||||
<div class="route-icon route-icon--end">达</div>
|
||||
<div class="route-info">
|
||||
<div class="route-name">万科城 5 号楼 1802</div>
|
||||
<div class="route-addr">张女士 · 138****6688 · 距离 2.3km</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="order-meta">
|
||||
<div class="order-meta-item">
|
||||
<span class="order-meta-label">餐品</span>
|
||||
<span class="order-meta-value">3 份</span>
|
||||
</div>
|
||||
<div class="order-meta-item">
|
||||
<span class="order-meta-label">配送距离</span>
|
||||
<span class="order-meta-value">2.3km</span>
|
||||
</div>
|
||||
<div class="order-meta-item">
|
||||
<span class="order-meta-label">要求送达</span>
|
||||
<span class="order-meta-value">15:30 前</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="order-action">
|
||||
<button class="btn btn--ghost" onclick="event.preventDefault();toast('已呼叫客户')">📞 联系客户</button>
|
||||
<button class="btn btn--primary" onclick="event.preventDefault();location.href='05-delivering.html'">查看路线</button>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="04-order-detail.html" class="order-card">
|
||||
<div class="order-card__head">
|
||||
<div class="order-num">#DP20260812-0905
|
||||
<span class="order-type-tag order-type-tag--store">到店</span>
|
||||
</div>
|
||||
<span class="status-pill status-pill--picking">取货中</span>
|
||||
</div>
|
||||
<div class="route-line">
|
||||
<div class="route-point">
|
||||
<div class="route-icon route-icon--start">取</div>
|
||||
<div class="route-info">
|
||||
<div class="route-name">净菜加工中心·长安站</div>
|
||||
<div class="route-addr">长安区西长安街 · 已到店 14:48</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="route-point">
|
||||
<div class="route-icon route-icon--end">达</div>
|
||||
<div class="route-info">
|
||||
<div class="route-name">家兴源食堂(科技路店)</div>
|
||||
<div class="route-addr">科技路 12 号 · 距离 5.6km</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="order-action">
|
||||
<button class="btn btn--ghost" onclick="event.preventDefault();toast('正在呼叫商家')">📞 联系客户</button>
|
||||
<button class="btn btn--primary" onclick="event.preventDefault();toast('已通知商家准备')">到店报到</button>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部 Tab -->
|
||||
<div class="tabbar">
|
||||
<a href="01-home.html" class="tab active">
|
||||
<span class="tab__icon">🏠</span>
|
||||
<span class="tab__label">首页</span>
|
||||
</a>
|
||||
<a href="03-grab-pool.html" class="tab">
|
||||
<span class="tab__icon">🔥</span>
|
||||
<span class="tab__label">抢单</span>
|
||||
</a>
|
||||
<a href="07-history.html" class="tab">
|
||||
<span class="tab__icon">📚</span>
|
||||
<span class="tab__label">历史</span>
|
||||
</a>
|
||||
<a href="08-profile.html" class="tab">
|
||||
<span class="tab__icon">👤</span>
|
||||
<span class="tab__label">我的</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="home-indicator"></div>
|
||||
<div class="toast" id="toast"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function toast(msg) {
|
||||
const t = document.getElementById('toast');
|
||||
t.textContent = msg;
|
||||
t.classList.add('show');
|
||||
setTimeout(() => t.classList.remove('show'), 1800);
|
||||
}
|
||||
|
||||
function toggleOnline() {
|
||||
const sw = document.getElementById('onlineSwitch');
|
||||
sw.classList.toggle('off');
|
||||
const isOnline = !sw.classList.contains('off');
|
||||
sw.querySelector('.online-text').textContent = isOnline ? '在线' : '离线';
|
||||
toast(isOnline ? '已上线·开始接单' : '已离线·暂停接单');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,683 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>派单接听 | 营养餐品配送</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
:root {
|
||||
--primary: #ff6d3a;
|
||||
--primary-dark: #e85a28;
|
||||
--text-primary: #1f2937;
|
||||
--text-secondary: #6b7280;
|
||||
--text-tertiary: #9ca3af;
|
||||
--border: #e5e7eb;
|
||||
--white: #ffffff;
|
||||
--danger: #ef4444;
|
||||
--success: #10b981;
|
||||
}
|
||||
body {
|
||||
min-height: 100vh;
|
||||
padding: 24px 0 40px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
background: #2a2a2a;
|
||||
color: var(--text-primary);
|
||||
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", sans-serif;
|
||||
}
|
||||
.phone-shell {
|
||||
position: relative;
|
||||
width: 375px;
|
||||
height: 812px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: radial-gradient(circle at 50% 20%, #fff0e8 0%, #ffe5d4 40%, var(--primary) 100%);
|
||||
border-radius: 44px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3), inset 0 0 0 2px #e0e0e0;
|
||||
}
|
||||
|
||||
.status-bar {
|
||||
height: 44px;
|
||||
padding: 0 24px;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.status-bar__time { font-size: 15px; font-weight: 700; }
|
||||
.status-bar__icons { display: flex; align-items: center; gap: 6px; }
|
||||
.status-bar__signal {
|
||||
width: 18px; height: 10px; background: #fff;
|
||||
clip-path: polygon(0 100%, 18% 64%, 18% 100%, 36% 42%, 36% 100%, 54% 24%, 54% 100%, 72% 8%, 72% 100%, 100% 0, 100% 100%);
|
||||
}
|
||||
.status-bar__wifi {
|
||||
width: 16px; height: 12px; background: #fff;
|
||||
clip-path: polygon(0 50%, 50% 0, 100% 50%, 86% 60%, 50% 22%, 14% 60%);
|
||||
}
|
||||
.status-bar__battery {
|
||||
width: 24px; height: 12px;
|
||||
border: 1.5px solid #fff;
|
||||
border-radius: 3px;
|
||||
position: relative;
|
||||
padding: 1.5px;
|
||||
}
|
||||
.status-bar__battery::after {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 70%; height: 100%;
|
||||
background: #fff;
|
||||
border-radius: 1px;
|
||||
}
|
||||
.status-bar__battery::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: -3px; top: 3px;
|
||||
width: 2px; height: 6px;
|
||||
background: #fff;
|
||||
border-radius: 0 1px 1px 0;
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 20px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 派单图标 + 响铃动效 */
|
||||
.ring-section {
|
||||
text-align: center;
|
||||
padding: 8px 0 16px;
|
||||
}
|
||||
.ring-icon-wrap {
|
||||
position: relative;
|
||||
width: 100px; height: 100px;
|
||||
margin: 0 auto 12px;
|
||||
}
|
||||
.ring-icon {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: white;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 50px;
|
||||
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.2);
|
||||
animation: ringShake 1s ease-in-out infinite;
|
||||
}
|
||||
@keyframes ringShake {
|
||||
0%, 100% { transform: rotate(0); }
|
||||
20% { transform: rotate(-15deg); }
|
||||
40% { transform: rotate(15deg); }
|
||||
60% { transform: rotate(-10deg); }
|
||||
80% { transform: rotate(10deg); }
|
||||
}
|
||||
.ring-pulse {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: 50%;
|
||||
border: 3px solid rgba(255, 255, 255, 0.6);
|
||||
animation: pulseRing 1.5s ease-out infinite;
|
||||
}
|
||||
.ring-pulse:nth-child(2) { animation-delay: 0.5s; }
|
||||
.ring-pulse:nth-child(3) { animation-delay: 1s; }
|
||||
@keyframes pulseRing {
|
||||
0% { transform: scale(1); opacity: 0.8; }
|
||||
100% { transform: scale(2.2); opacity: 0; }
|
||||
}
|
||||
|
||||
.ring-title {
|
||||
color: white;
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
margin-bottom: 4px;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
.ring-subtitle {
|
||||
color: rgba(255, 255, 255, 0.95);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* 倒计时圆环 */
|
||||
.countdown-section {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 8px 0 16px;
|
||||
}
|
||||
.countdown-ring {
|
||||
position: relative;
|
||||
width: 110px; height: 110px;
|
||||
}
|
||||
.countdown-ring svg {
|
||||
width: 100%; height: 100%;
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
.countdown-track {
|
||||
fill: none;
|
||||
stroke: rgba(255, 255, 255, 0.3);
|
||||
stroke-width: 8;
|
||||
}
|
||||
.countdown-progress {
|
||||
fill: none;
|
||||
stroke: white;
|
||||
stroke-width: 8;
|
||||
stroke-linecap: round;
|
||||
stroke-dasharray: 283;
|
||||
transition: stroke-dashoffset 1s linear;
|
||||
}
|
||||
.countdown-number {
|
||||
position: absolute;
|
||||
top: 50%; left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
color: white;
|
||||
text-align: center;
|
||||
}
|
||||
.countdown-number__val {
|
||||
font-size: 36px;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
.countdown-number__unit {
|
||||
font-size: 12px;
|
||||
margin-top: 2px;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
/* 订单卡片 */
|
||||
.order-card {
|
||||
background: white;
|
||||
border-radius: 16px;
|
||||
padding: 16px;
|
||||
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.15);
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
.order-card__head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px dashed var(--border);
|
||||
}
|
||||
.order-num { font-size: 12px; color: var(--text-tertiary); }
|
||||
.order-type-tag {
|
||||
display: inline-block;
|
||||
font-size: 10px;
|
||||
padding: 1px 6px;
|
||||
border-radius: 4px;
|
||||
margin-left: 6px;
|
||||
vertical-align: middle;
|
||||
font-weight: 600;
|
||||
}
|
||||
.order-type-tag--home {
|
||||
background: #dbeafe;
|
||||
color: #1e40af;
|
||||
}
|
||||
.order-type-tag--store {
|
||||
background: #fef3c7;
|
||||
color: #92400e;
|
||||
}
|
||||
.order-distance {
|
||||
font-size: 12px;
|
||||
color: var(--primary);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.route {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
padding: 4px 0;
|
||||
}
|
||||
.route-point {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.route-icon {
|
||||
width: 24px; height: 24px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 12px;
|
||||
flex-shrink: 0;
|
||||
color: white;
|
||||
font-weight: 700;
|
||||
}
|
||||
.route-icon--start { background: var(--primary); }
|
||||
.route-icon--end { background: var(--success); }
|
||||
.route-info { flex: 1; padding-top: 2px; }
|
||||
.route-name {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.route-addr {
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
.route-connector {
|
||||
width: 2px;
|
||||
height: 16px;
|
||||
background: var(--border);
|
||||
margin-left: 11px;
|
||||
border-left: 2px dashed var(--border);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.meta-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 8px;
|
||||
margin: 12px 0 0;
|
||||
padding: 10px;
|
||||
background: #f6f8fb;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.meta-cell { text-align: center; }
|
||||
.meta-label {
|
||||
font-size: 11px;
|
||||
color: var(--text-tertiary);
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.meta-value {
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
/* 操作按钮 */
|
||||
.action-bar {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-top: 8px;
|
||||
padding: 8px 0;
|
||||
}
|
||||
.btn {
|
||||
flex: 1;
|
||||
height: 56px;
|
||||
border: none;
|
||||
border-radius: 14px;
|
||||
font-size: 17px;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 2px;
|
||||
transition: transform 0.1s;
|
||||
}
|
||||
.btn:active { transform: scale(0.97); }
|
||||
.btn--reject {
|
||||
background: white;
|
||||
color: var(--danger);
|
||||
border: 2px solid var(--danger);
|
||||
}
|
||||
.btn--accept {
|
||||
background: linear-gradient(135deg, #10b981, #059669);
|
||||
color: white;
|
||||
box-shadow: 0 8px 16px rgba(16, 185, 129, 0.35);
|
||||
}
|
||||
.btn__small {
|
||||
font-size: 11px;
|
||||
opacity: 0.85;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 拒单理由弹窗 */
|
||||
.modal-mask {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 50;
|
||||
display: none;
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
}
|
||||
.modal-mask.show { display: flex; }
|
||||
.modal {
|
||||
width: 100%;
|
||||
background: white;
|
||||
border-radius: 20px 20px 0 0;
|
||||
padding: 20px;
|
||||
max-height: 80%;
|
||||
overflow-y: auto;
|
||||
animation: slideUp 0.3s;
|
||||
}
|
||||
@keyframes slideUp {
|
||||
from { transform: translateY(100%); }
|
||||
to { transform: translateY(0); }
|
||||
}
|
||||
.modal__head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
.modal__title {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.modal__close {
|
||||
background: var(--border);
|
||||
color: var(--text-secondary);
|
||||
border: none;
|
||||
width: 28px; height: 28px;
|
||||
border-radius: 50%;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.reason-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.reason-item {
|
||||
padding: 14px 16px;
|
||||
background: var(--background, #f6f8fb);
|
||||
border: 1.5px solid transparent;
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.reason-item:hover {
|
||||
background: #fff0e8;
|
||||
border-color: var(--primary);
|
||||
}
|
||||
.reason-item.selected {
|
||||
background: #fff0e8;
|
||||
border-color: var(--primary);
|
||||
}
|
||||
.reason-icon {
|
||||
width: 36px; height: 36px;
|
||||
background: white;
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 18px;
|
||||
}
|
||||
.reason-info { flex: 1; }
|
||||
.reason-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
.reason-desc {
|
||||
font-size: 11px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
.reason-check {
|
||||
width: 18px; height: 18px;
|
||||
border: 2px solid var(--border);
|
||||
border-radius: 50%;
|
||||
}
|
||||
.reason-item.selected .reason-check {
|
||||
border-color: var(--primary);
|
||||
background: var(--primary);
|
||||
position: relative;
|
||||
}
|
||||
.reason-item.selected .reason-check::after {
|
||||
content: '✓';
|
||||
position: absolute;
|
||||
top: 50%; left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
color: white;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.modal-tip {
|
||||
background: #fef3c7;
|
||||
color: #92400e;
|
||||
padding: 10px 12px;
|
||||
border-radius: 8px;
|
||||
font-size: 12px;
|
||||
margin-bottom: 14px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.home-indicator {
|
||||
position: absolute;
|
||||
bottom: 8px; left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 134px; height: 5px;
|
||||
background: white;
|
||||
border-radius: 3px;
|
||||
z-index: 10;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
<div class="status-bar">
|
||||
<span class="status-bar__time">9:41</span>
|
||||
<div class="status-bar__icons">
|
||||
<span class="status-bar__signal"></span>
|
||||
<span class="status-bar__wifi"></span>
|
||||
<span class="status-bar__battery"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<!-- 派单响铃 -->
|
||||
<div class="ring-section">
|
||||
<div class="ring-icon-wrap">
|
||||
<div class="ring-pulse"></div>
|
||||
<div class="ring-pulse"></div>
|
||||
<div class="ring-pulse"></div>
|
||||
<div class="ring-icon">🛵</div>
|
||||
</div>
|
||||
<div class="ring-title">您有新的派单</div>
|
||||
<div class="ring-subtitle">调度中心为您指派了新订单</div>
|
||||
</div>
|
||||
|
||||
<!-- 倒计时 -->
|
||||
<div class="countdown-section">
|
||||
<div class="countdown-ring">
|
||||
<svg viewBox="0 0 100 100">
|
||||
<circle cx="50" cy="50" r="45" class="countdown-track"/>
|
||||
<circle cx="50" cy="50" r="45" class="countdown-progress" id="progress"/>
|
||||
</svg>
|
||||
<div class="countdown-number">
|
||||
<div class="countdown-number__val" id="countdownVal">30</div>
|
||||
<div class="countdown-number__unit">秒后自动拒绝</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 订单摘要卡片 -->
|
||||
<div class="order-card">
|
||||
<div class="order-card__head">
|
||||
<div>
|
||||
<span class="order-num">#DP20260812-0928</span>
|
||||
<span class="order-type-tag order-type-tag--home">到家</span>
|
||||
</div>
|
||||
<span class="order-distance">📏 距您 1.8km</span>
|
||||
</div>
|
||||
|
||||
<div class="route">
|
||||
<div class="route-point">
|
||||
<div class="route-icon route-icon--start">取</div>
|
||||
<div class="route-info">
|
||||
<div class="route-name">味之都食堂·高新店</div>
|
||||
<div class="route-addr">科技三路 8 号 · 距您 0.8km</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="route-connector"></div>
|
||||
<div class="route-point">
|
||||
<div class="route-icon route-icon--end">达</div>
|
||||
<div class="route-info">
|
||||
<div class="route-name">万科城 5 号楼 1802</div>
|
||||
<div class="route-addr">高新区科技路 · 取货后 2.6km</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="meta-grid">
|
||||
<div class="meta-cell">
|
||||
<div class="meta-label">餐品数量</div>
|
||||
<div class="meta-value">4 份</div>
|
||||
</div>
|
||||
<div class="meta-cell">
|
||||
<div class="meta-label">配送距离</div>
|
||||
<div class="meta-value">2.6km</div>
|
||||
</div>
|
||||
<div class="meta-cell">
|
||||
<div class="meta-label">要求送达</div>
|
||||
<div class="meta-value">15:45 前</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<div class="action-bar">
|
||||
<button class="btn btn--reject" onclick="openReject()">
|
||||
<span>拒绝</span>
|
||||
<span class="btn__small">需选择理由</span>
|
||||
</button>
|
||||
<button class="btn btn--accept" onclick="acceptOrder()">
|
||||
<span>✓ 接受派单</span>
|
||||
<span class="btn__small">立即开始配送</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 拒单理由弹窗 -->
|
||||
<div class="modal-mask" id="rejectModal">
|
||||
<div class="modal">
|
||||
<div class="modal__head">
|
||||
<div class="modal__title">请选择拒单理由</div>
|
||||
<button class="modal__close" onclick="closeReject()">×</button>
|
||||
</div>
|
||||
<div class="modal-tip">
|
||||
⚠️ 拒单将影响您的接单评分,频繁拒单可能被暂停派单权限。请如实选择理由。
|
||||
</div>
|
||||
<div class="reason-list" id="reasonList">
|
||||
<div class="reason-item" data-reason="车辆故障">
|
||||
<div class="reason-icon">🛵</div>
|
||||
<div class="reason-info">
|
||||
<div class="reason-title">车辆故障</div>
|
||||
<div class="reason-desc">电动车辆故障,无法继续配送</div>
|
||||
</div>
|
||||
<div class="reason-check"></div>
|
||||
</div>
|
||||
<div class="reason-item" data-reason="个人原因">
|
||||
<div class="reason-icon">😣</div>
|
||||
<div class="reason-info">
|
||||
<div class="reason-title">个人原因</div>
|
||||
<div class="reason-desc">身体不适/突发事件等</div>
|
||||
</div>
|
||||
<div class="reason-check"></div>
|
||||
</div>
|
||||
<div class="reason-item" data-reason="距离过远">
|
||||
<div class="reason-icon">📍</div>
|
||||
<div class="reason-info">
|
||||
<div class="reason-title">距离过远</div>
|
||||
<div class="reason-desc">当前车辆电量/油量不足</div>
|
||||
</div>
|
||||
<div class="reason-check"></div>
|
||||
</div>
|
||||
<div class="reason-item" data-reason="已接其他单">
|
||||
<div class="reason-icon">📋</div>
|
||||
<div class="reason-info">
|
||||
<div class="reason-title">已接其他订单</div>
|
||||
<div class="reason-desc">已有配送中订单无法准时送达</div>
|
||||
</div>
|
||||
<div class="reason-check"></div>
|
||||
</div>
|
||||
<div class="reason-item" data-reason="其他">
|
||||
<div class="reason-icon">📝</div>
|
||||
<div class="reason-info">
|
||||
<div class="reason-title">其他</div>
|
||||
<div class="reason-desc">手动填写具体原因</div>
|
||||
</div>
|
||||
<div class="reason-check"></div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn--accept" style="height:48px;font-size:15px" onclick="confirmReject()">
|
||||
确认拒单
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="home-indicator"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 倒计时
|
||||
const TOTAL = 30;
|
||||
const CIRC = 2 * Math.PI * 45;
|
||||
let remaining = TOTAL;
|
||||
const progressEl = document.getElementById('progress');
|
||||
const valEl = document.getElementById('countdownVal');
|
||||
progressEl.style.strokeDasharray = CIRC;
|
||||
|
||||
function renderProgress() {
|
||||
const offset = CIRC * (1 - remaining / TOTAL);
|
||||
progressEl.style.strokeDashoffset = offset;
|
||||
valEl.textContent = remaining;
|
||||
}
|
||||
renderProgress();
|
||||
|
||||
const timer = setInterval(() => {
|
||||
remaining--;
|
||||
renderProgress();
|
||||
if (remaining <= 0) {
|
||||
clearInterval(timer);
|
||||
alert('已超时未响应,此单已自动转派');
|
||||
location.href = '01-home.html';
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
// 接受
|
||||
function acceptOrder() {
|
||||
clearInterval(timer);
|
||||
alert('✅ 已接单,请尽快到达取货地点');
|
||||
location.href = '04-order-detail.html?orderId=DP20260812-0928&state=accepted';
|
||||
}
|
||||
|
||||
// 拒单弹窗
|
||||
let selectedReason = '';
|
||||
function openReject() {
|
||||
document.getElementById('rejectModal').classList.add('show');
|
||||
}
|
||||
function closeReject() {
|
||||
document.getElementById('rejectModal').classList.remove('show');
|
||||
}
|
||||
document.querySelectorAll('.reason-item').forEach(item => {
|
||||
item.addEventListener('click', () => {
|
||||
document.querySelectorAll('.reason-item').forEach(i => i.classList.remove('selected'));
|
||||
item.classList.add('selected');
|
||||
selectedReason = item.dataset.reason;
|
||||
});
|
||||
});
|
||||
function confirmReject() {
|
||||
if (!selectedReason) {
|
||||
alert('请选择拒单理由');
|
||||
return;
|
||||
}
|
||||
clearInterval(timer);
|
||||
alert('已拒单 · 理由:' + selectedReason);
|
||||
location.href = '01-home.html';
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,734 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>抢单大厅 | 营养餐品配送</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
:root {
|
||||
--primary: #ff6d3a;
|
||||
--primary-dark: #e85a28;
|
||||
--primary-light: #fff0e8;
|
||||
--text-primary: #1f2937;
|
||||
--text-secondary: #6b7280;
|
||||
--text-tertiary: #9ca3af;
|
||||
--border: #e5e7eb;
|
||||
--background: #f6f8fb;
|
||||
--white: #ffffff;
|
||||
--success: #10b981;
|
||||
--shadow-sm: 0 2px 8px rgba(15, 23, 42, 0.06);
|
||||
--shadow-md: 0 10px 28px rgba(15, 23, 42, 0.10);
|
||||
}
|
||||
body {
|
||||
min-height: 100vh;
|
||||
padding: 24px 0 40px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
background: #2a2a2a;
|
||||
color: var(--text-primary);
|
||||
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", sans-serif;
|
||||
}
|
||||
.phone-shell {
|
||||
position: relative;
|
||||
width: 375px;
|
||||
height: 812px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--background);
|
||||
border-radius: 44px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3), inset 0 0 0 2px #e0e0e0;
|
||||
}
|
||||
.status-bar {
|
||||
height: 44px;
|
||||
padding: 0 24px;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
background: linear-gradient(135deg, var(--primary), var(--primary-dark));
|
||||
}
|
||||
.status-bar__time { font-size: 15px; font-weight: 700; }
|
||||
.status-bar__icons { display: flex; align-items: center; gap: 6px; }
|
||||
.status-bar__signal {
|
||||
width: 18px; height: 10px; background: #fff;
|
||||
clip-path: polygon(0 100%, 18% 64%, 18% 100%, 36% 42%, 36% 100%, 54% 24%, 54% 100%, 72% 8%, 72% 100%, 100% 0, 100% 100%);
|
||||
}
|
||||
.status-bar__wifi {
|
||||
width: 16px; height: 12px; background: #fff;
|
||||
clip-path: polygon(0 50%, 50% 0, 100% 50%, 86% 60%, 50% 22%, 14% 60%);
|
||||
}
|
||||
.status-bar__battery {
|
||||
width: 24px; height: 12px;
|
||||
border: 1.5px solid #fff;
|
||||
border-radius: 3px;
|
||||
position: relative;
|
||||
padding: 1.5px;
|
||||
}
|
||||
.status-bar__battery::after {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 70%; height: 100%;
|
||||
background: #fff;
|
||||
border-radius: 1px;
|
||||
}
|
||||
.status-bar__battery::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: -3px; top: 3px;
|
||||
width: 2px; height: 6px;
|
||||
background: #fff;
|
||||
border-radius: 0 1px 1px 0;
|
||||
}
|
||||
|
||||
.nav-bar {
|
||||
flex-shrink: 0;
|
||||
background: linear-gradient(135deg, var(--primary), var(--primary-dark));
|
||||
color: white;
|
||||
padding: 4px 20px 14px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
.nav-back {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
font-size: 22px;
|
||||
width: 32px;
|
||||
}
|
||||
.nav-title {
|
||||
flex: 1;
|
||||
font-size: 17px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.nav-count {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
padding: 4px 10px;
|
||||
border-radius: 12px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.filter-bar {
|
||||
flex-shrink: 0;
|
||||
background: white;
|
||||
padding: 10px 16px;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
overflow-x: auto;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
.filter-bar::-webkit-scrollbar { display: none; }
|
||||
.filter-pill {
|
||||
padding: 6px 14px;
|
||||
border-radius: 16px;
|
||||
background: var(--background);
|
||||
color: var(--text-secondary);
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
.filter-pill.active {
|
||||
background: var(--primary);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.sort-bar {
|
||||
flex-shrink: 0;
|
||||
padding: 8px 16px;
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: var(--background);
|
||||
}
|
||||
.sort-bar__left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
.sort-bar__count { color: var(--primary); font-weight: 700; }
|
||||
.sort-toggle {
|
||||
background: white;
|
||||
padding: 4px 10px;
|
||||
border-radius: 12px;
|
||||
color: var(--text-primary);
|
||||
font-size: 11px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.scroll-area {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 8px 16px 90px;
|
||||
}
|
||||
.scroll-area::-webkit-scrollbar { display: none; }
|
||||
|
||||
.order-card {
|
||||
background: white;
|
||||
border-radius: 14px;
|
||||
padding: 14px;
|
||||
margin-bottom: 12px;
|
||||
box-shadow: var(--shadow-sm);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.order-card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0; left: 0;
|
||||
width: 4px; height: 100%;
|
||||
background: var(--primary);
|
||||
}
|
||||
.order-card.is-store::before { background: #f59e0b; }
|
||||
|
||||
.order-head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.order-head__left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
.order-num { font-size: 12px; color: var(--text-tertiary); }
|
||||
.type-tag {
|
||||
display: inline-block;
|
||||
font-size: 10px;
|
||||
padding: 1px 6px;
|
||||
border-radius: 4px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.type-tag--home { background: #dbeafe; color: #1e40af; }
|
||||
.type-tag--store { background: #fef3c7; color: #92400e; }
|
||||
.hot-tag {
|
||||
background: #fee2e2;
|
||||
color: var(--primary-dark);
|
||||
padding: 2px 6px;
|
||||
border-radius: 8px;
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.route {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
padding: 4px 0;
|
||||
}
|
||||
.route-point {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.route-icon {
|
||||
width: 22px; height: 22px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 11px;
|
||||
flex-shrink: 0;
|
||||
color: white;
|
||||
font-weight: 700;
|
||||
}
|
||||
.route-icon--start { background: var(--primary); }
|
||||
.route-icon--end { background: var(--success); }
|
||||
.route-info { flex: 1; padding-top: 1px; }
|
||||
.route-name {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.route-addr {
|
||||
font-size: 11px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
.route-connector {
|
||||
width: 2px;
|
||||
height: 12px;
|
||||
border-left: 2px dashed var(--border);
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.meta-row {
|
||||
display: flex;
|
||||
gap: 14px;
|
||||
margin: 10px 0;
|
||||
padding: 8px 10px;
|
||||
background: #fff0e8;
|
||||
border-radius: 8px;
|
||||
}
|
||||
.meta-cell { flex: 1; }
|
||||
.meta-label {
|
||||
font-size: 10px;
|
||||
color: var(--text-tertiary);
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.meta-value {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
.order-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: 6px;
|
||||
}
|
||||
.distance-text {
|
||||
font-size: 11px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
.countdown-tag {
|
||||
background: #f3f4f6;
|
||||
color: var(--text-secondary);
|
||||
padding: 2px 8px;
|
||||
border-radius: 8px;
|
||||
font-size: 11px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
.grab-btn {
|
||||
background: linear-gradient(135deg, var(--primary), var(--primary-dark));
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 8px 22px;
|
||||
border-radius: 20px;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 4px 12px rgba(255, 109, 58, 0.3);
|
||||
}
|
||||
.grab-btn:active { transform: scale(0.96); }
|
||||
.grab-btn.grabbed {
|
||||
background: var(--border);
|
||||
color: var(--text-secondary);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.empty {
|
||||
text-align: center;
|
||||
padding: 60px 20px;
|
||||
color: var(--text-tertiary);
|
||||
font-size: 13px;
|
||||
}
|
||||
.empty__icon {
|
||||
font-size: 48px;
|
||||
margin-bottom: 8px;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
/* 底部 Tab */
|
||||
.tabbar {
|
||||
position: absolute;
|
||||
bottom: 0; left: 0; right: 0;
|
||||
height: 70px;
|
||||
background: white;
|
||||
border-top: 1px solid var(--border);
|
||||
display: flex;
|
||||
padding: 8px 0 20px;
|
||||
}
|
||||
.tab {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 2px;
|
||||
text-decoration: none;
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
.tab.active { color: var(--primary); }
|
||||
.tab__icon { font-size: 22px; }
|
||||
.tab__label { font-size: 10px; font-weight: 600; }
|
||||
|
||||
.home-indicator {
|
||||
position: absolute;
|
||||
bottom: 8px; left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 134px; height: 5px;
|
||||
background: #1f2937;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.float-btn {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
bottom: 86px;
|
||||
width: 52px; height: 52px;
|
||||
background: var(--primary);
|
||||
color: white;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 22px;
|
||||
box-shadow: 0 8px 16px rgba(255, 109, 58, 0.4);
|
||||
cursor: pointer;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.toast {
|
||||
position: absolute;
|
||||
top: 60px; left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
color: white;
|
||||
padding: 8px 16px;
|
||||
border-radius: 20px;
|
||||
font-size: 13px;
|
||||
z-index: 100;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
pointer-events: none;
|
||||
}
|
||||
.toast.show { opacity: 1; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
<div class="status-bar">
|
||||
<span class="status-bar__time">9:41</span>
|
||||
<div class="status-bar__icons">
|
||||
<span class="status-bar__signal"></span>
|
||||
<span class="status-bar__wifi"></span>
|
||||
<span class="status-bar__battery"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="nav-bar">
|
||||
<a href="01-home.html" class="nav-back">‹</a>
|
||||
<span class="nav-title">🔥 抢单大厅</span>
|
||||
<span class="nav-count">大厅 5 单</span>
|
||||
</div>
|
||||
|
||||
<div class="filter-bar">
|
||||
<div class="filter-pill active" data-filter="all">全部</div>
|
||||
<div class="filter-pill" data-filter="home">到家</div>
|
||||
<div class="filter-pill" data-filter="store">到店</div>
|
||||
<div class="filter-pill" data-filter="near">附近 3km</div>
|
||||
<div class="filter-pill" data-filter="high">长距离</div>
|
||||
</div>
|
||||
|
||||
<div class="sort-bar">
|
||||
<div class="sort-bar__left">
|
||||
📍 当前位置:科技三路 · 附近 <span class="sort-bar__count">5</span> 单
|
||||
</div>
|
||||
<div class="sort-toggle" onclick="toast('已切换为按距离排序')">
|
||||
按距离 ↑↓
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="scroll-area">
|
||||
|
||||
<!-- 订单 1 -->
|
||||
<div class="order-card" data-type="home">
|
||||
<div class="order-head">
|
||||
<div class="order-head__left">
|
||||
<span class="order-num">#QD20260812-1421</span>
|
||||
<span class="type-tag type-tag--home">到家</span>
|
||||
<span class="hot-tag">🔥 急</span>
|
||||
</div>
|
||||
<span class="distance-text">📏 0.8km</span>
|
||||
</div>
|
||||
<div class="route">
|
||||
<div class="route-point">
|
||||
<div class="route-icon route-icon--start">取</div>
|
||||
<div class="route-info">
|
||||
<div class="route-name">味之都食堂·高新店</div>
|
||||
<div class="route-addr">科技三路 8 号</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="route-connector"></div>
|
||||
<div class="route-point">
|
||||
<div class="route-icon route-icon--end">达</div>
|
||||
<div class="route-info">
|
||||
<div class="route-name">锦业一号楼 2503</div>
|
||||
<div class="route-addr">锦业路 · 0.8km</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="meta-row">
|
||||
<div class="meta-cell">
|
||||
<div class="meta-label">餐品</div>
|
||||
<div class="meta-value">3 份</div>
|
||||
</div>
|
||||
<div class="meta-cell">
|
||||
<div class="meta-label">配送距离</div>
|
||||
<div class="meta-value">0.8km</div>
|
||||
</div>
|
||||
<div class="meta-cell">
|
||||
<div class="meta-label">送达时限</div>
|
||||
<div class="meta-value">30min</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="order-footer">
|
||||
<span class="distance-text">⏱ 剩余抢单时间 <span class="countdown-tag">02:35</span></span>
|
||||
<button class="grab-btn" onclick="grabOrder(this)">立即抢</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 订单 2 -->
|
||||
<div class="order-card is-store" data-type="store">
|
||||
<div class="order-head">
|
||||
<div class="order-head__left">
|
||||
<span class="order-num">#QD20260812-1438</span>
|
||||
<span class="type-tag type-tag--store">到店</span>
|
||||
</div>
|
||||
<span class="distance-text">📏 1.2km</span>
|
||||
</div>
|
||||
<div class="route">
|
||||
<div class="route-point">
|
||||
<div class="route-icon route-icon--start">取</div>
|
||||
<div class="route-info">
|
||||
<div class="route-name">净菜加工中心</div>
|
||||
<div class="route-addr">科技二路 6 号</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="route-connector"></div>
|
||||
<div class="route-point">
|
||||
<div class="route-icon route-icon--end">达</div>
|
||||
<div class="route-info">
|
||||
<div class="route-name">家兴源食堂·科技路店</div>
|
||||
<div class="route-addr">科技路 12 号 · 5.6km</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="meta-row">
|
||||
<div class="meta-cell">
|
||||
<div class="meta-label">餐品</div>
|
||||
<div class="meta-value">12 箱</div>
|
||||
</div>
|
||||
<div class="meta-cell">
|
||||
<div class="meta-label">配送距离</div>
|
||||
<div class="meta-value">5.6km</div>
|
||||
</div>
|
||||
<div class="meta-cell">
|
||||
<div class="meta-label">送达时限</div>
|
||||
<div class="meta-value">60min</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="order-footer">
|
||||
<span class="distance-text">⏱ 剩余抢单时间 <span class="countdown-tag">05:18</span></span>
|
||||
<button class="grab-btn" onclick="grabOrder(this)">立即抢</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 订单 3 -->
|
||||
<div class="order-card" data-type="home">
|
||||
<div class="order-head">
|
||||
<div class="order-head__left">
|
||||
<span class="order-num">#QD20260812-1445</span>
|
||||
<span class="type-tag type-tag--home">到家</span>
|
||||
<span class="hot-tag">📦 大</span>
|
||||
</div>
|
||||
<span class="distance-text">📏 2.3km</span>
|
||||
</div>
|
||||
<div class="route">
|
||||
<div class="route-point">
|
||||
<div class="route-icon route-icon--start">取</div>
|
||||
<div class="route-info">
|
||||
<div class="route-name">中央厨房·高新站</div>
|
||||
<div class="route-addr">科技三路 8 号</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="route-connector"></div>
|
||||
<div class="route-point">
|
||||
<div class="route-icon route-icon--end">达</div>
|
||||
<div class="route-info">
|
||||
<div class="route-name">紫薇田园都市 12 号楼</div>
|
||||
<div class="route-addr">紫薇路 · 3.5km</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="meta-row">
|
||||
<div class="meta-cell">
|
||||
<div class="meta-label">餐品</div>
|
||||
<div class="meta-value">6 份</div>
|
||||
</div>
|
||||
<div class="meta-cell">
|
||||
<div class="meta-label">配送距离</div>
|
||||
<div class="meta-value">3.5km</div>
|
||||
</div>
|
||||
<div class="meta-cell">
|
||||
<div class="meta-label">送达时限</div>
|
||||
<div class="meta-value">45min</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="order-footer">
|
||||
<span class="distance-text">⏱ 剩余抢单时间 <span class="countdown-tag">08:42</span></span>
|
||||
<button class="grab-btn" onclick="grabOrder(this)">立即抢</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 订单 4 -->
|
||||
<div class="order-card is-store" data-type="store">
|
||||
<div class="order-head">
|
||||
<div class="order-head__left">
|
||||
<span class="order-num">#QD20260812-1502</span>
|
||||
<span class="type-tag type-tag--store">到店</span>
|
||||
</div>
|
||||
<span class="distance-text">📏 2.8km</span>
|
||||
</div>
|
||||
<div class="route">
|
||||
<div class="route-point">
|
||||
<div class="route-icon route-icon--start">取</div>
|
||||
<div class="route-info">
|
||||
<div class="route-name">食材配送中心</div>
|
||||
<div class="route-addr">高新区科技路</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="route-connector"></div>
|
||||
<div class="route-point">
|
||||
<div class="route-icon route-icon--end">达</div>
|
||||
<div class="route-info">
|
||||
<div class="route-name">味之滨餐厅</div>
|
||||
<div class="route-addr">长安区 · 4.8km</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="meta-row">
|
||||
<div class="meta-cell">
|
||||
<div class="meta-label">餐品</div>
|
||||
<div class="meta-value">8 箱</div>
|
||||
</div>
|
||||
<div class="meta-cell">
|
||||
<div class="meta-label">配送距离</div>
|
||||
<div class="meta-value">4.8km</div>
|
||||
</div>
|
||||
<div class="meta-cell">
|
||||
<div class="meta-label">送达时限</div>
|
||||
<div class="meta-value">50min</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="order-footer">
|
||||
<span class="distance-text">⏱ 剩余抢单时间 <span class="countdown-tag">12:15</span></span>
|
||||
<button class="grab-btn" onclick="grabOrder(this)">立即抢</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 订单 5 -->
|
||||
<div class="order-card" data-type="home">
|
||||
<div class="order-head">
|
||||
<div class="order-head__left">
|
||||
<span class="order-num">#QD20260812-1518</span>
|
||||
<span class="type-tag type-tag--home">到家</span>
|
||||
</div>
|
||||
<span class="distance-text">📏 3.0km</span>
|
||||
</div>
|
||||
<div class="route">
|
||||
<div class="route-point">
|
||||
<div class="route-icon route-icon--start">取</div>
|
||||
<div class="route-info">
|
||||
<div class="route-name">味之都食堂·高新店</div>
|
||||
<div class="route-addr">科技三路 8 号</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="route-connector"></div>
|
||||
<div class="route-point">
|
||||
<div class="route-icon route-icon--end">达</div>
|
||||
<div class="route-info">
|
||||
<div class="route-name">枫林绿洲 6 号楼 502</div>
|
||||
<div class="route-addr">高新四路 · 3.8km</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="meta-row">
|
||||
<div class="meta-cell">
|
||||
<div class="meta-label">餐品</div>
|
||||
<div class="meta-value">2 份</div>
|
||||
</div>
|
||||
<div class="meta-cell">
|
||||
<div class="meta-label">配送距离</div>
|
||||
<div class="meta-value">3.8km</div>
|
||||
</div>
|
||||
<div class="meta-cell">
|
||||
<div class="meta-label">送达时限</div>
|
||||
<div class="meta-value">35min</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="order-footer">
|
||||
<span class="distance-text">⏱ 剩余抢单时间 <span class="countdown-tag">15:30</span></span>
|
||||
<button class="grab-btn" onclick="grabOrder(this)">立即抢</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="text-align:center;padding:16px;color:var(--text-tertiary);font-size:12px">
|
||||
· 已加载全部 ·
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="float-btn" onclick="toast('已为您定位附近最近的订单')">🎯</div>
|
||||
|
||||
<!-- 底部 Tab -->
|
||||
<div class="tabbar">
|
||||
<a href="01-home.html" class="tab">
|
||||
<span class="tab__icon">🏠</span>
|
||||
<span class="tab__label">首页</span>
|
||||
</a>
|
||||
<a href="03-grab-pool.html" class="tab active">
|
||||
<span class="tab__icon">🔥</span>
|
||||
<span class="tab__label">抢单</span>
|
||||
</a>
|
||||
<a href="07-history.html" class="tab">
|
||||
<span class="tab__icon">📚</span>
|
||||
<span class="tab__label">历史</span>
|
||||
</a>
|
||||
<a href="08-profile.html" class="tab">
|
||||
<span class="tab__icon">👤</span>
|
||||
<span class="tab__label">我的</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="home-indicator"></div>
|
||||
<div class="toast" id="toast"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function toast(msg) {
|
||||
const t = document.getElementById('toast');
|
||||
t.textContent = msg;
|
||||
t.classList.add('show');
|
||||
setTimeout(() => t.classList.remove('show'), 1800);
|
||||
}
|
||||
|
||||
function grabOrder(btn) {
|
||||
if (btn.classList.contains('grabbed')) return;
|
||||
btn.classList.add('grabbed');
|
||||
btn.textContent = '✓ 已抢';
|
||||
toast('🎉 抢单成功!请尽快取货');
|
||||
setTimeout(() => {
|
||||
location.href = '04-order-detail.html?state=accepted';
|
||||
}, 1200);
|
||||
}
|
||||
|
||||
// 筛选
|
||||
document.querySelectorAll('.filter-pill').forEach(pill => {
|
||||
pill.addEventListener('click', () => {
|
||||
document.querySelectorAll('.filter-pill').forEach(p => p.classList.remove('active'));
|
||||
pill.classList.add('active');
|
||||
const filter = pill.dataset.filter;
|
||||
document.querySelectorAll('.order-card').forEach(card => {
|
||||
if (filter === 'all' || card.dataset.type === filter || filter === 'near' || filter === 'high') {
|
||||
card.style.display = 'block';
|
||||
} else {
|
||||
card.style.display = 'none';
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,613 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>订单详情 | 营养餐品配送</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
:root {
|
||||
--primary: #ff6d3a;
|
||||
--primary-dark: #e85a28;
|
||||
--primary-light: #fff0e8;
|
||||
--text-primary: #1f2937;
|
||||
--text-secondary: #6b7280;
|
||||
--text-tertiary: #9ca3af;
|
||||
--border: #e5e7eb;
|
||||
--background: #f6f8fb;
|
||||
--white: #ffffff;
|
||||
--success: #10b981;
|
||||
--info: #3b82f6;
|
||||
--warn: #f59e0b;
|
||||
--shadow-sm: 0 2px 8px rgba(15, 23, 42, 0.06);
|
||||
}
|
||||
body {
|
||||
min-height: 100vh;
|
||||
padding: 24px 0 40px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
background: #2a2a2a;
|
||||
color: var(--text-primary);
|
||||
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", sans-serif;
|
||||
}
|
||||
.phone-shell {
|
||||
position: relative;
|
||||
width: 375px;
|
||||
height: 812px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--background);
|
||||
border-radius: 44px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3), inset 0 0 0 2px #e0e0e0;
|
||||
}
|
||||
.status-bar {
|
||||
height: 44px;
|
||||
padding: 0 24px;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
background: linear-gradient(135deg, var(--primary), var(--primary-dark));
|
||||
}
|
||||
.status-bar__time { font-size: 15px; font-weight: 700; }
|
||||
.status-bar__icons { display: flex; align-items: center; gap: 6px; }
|
||||
.status-bar__signal { width:18px;height:10px;background:#fff;clip-path: polygon(0 100%, 18% 64%, 18% 100%, 36% 42%, 36% 100%, 54% 24%, 54% 100%, 72% 8%, 72% 100%, 100% 0, 100% 100%); }
|
||||
.status-bar__wifi { width:16px;height:12px;background:#fff;clip-path: polygon(0 50%, 50% 0, 100% 50%, 86% 60%, 50% 22%, 14% 60%); }
|
||||
.status-bar__battery { width:24px;height:12px;border:1.5px solid #fff;border-radius:3px;position:relative;padding:1.5px;}
|
||||
.status-bar__battery::after { content:'';display:block;width:70%;height:100%;background:#fff;border-radius:1px;}
|
||||
.status-bar__battery::before { content:'';position:absolute;right:-3px;top:3px;width:2px;height:6px;background:#fff;border-radius:0 1px 1px 0;}
|
||||
|
||||
.nav-bar {
|
||||
flex-shrink: 0;
|
||||
background: linear-gradient(135deg, var(--primary), var(--primary-dark));
|
||||
color: white;
|
||||
padding: 4px 16px 14px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
.nav-back { color: white; text-decoration: none; font-size: 22px; width: 32px; }
|
||||
.nav-title { flex: 1; font-size: 16px; font-weight: 700; }
|
||||
.nav-status {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
padding: 4px 10px;
|
||||
border-radius: 12px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.scroll-area {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 12px 16px 100px;
|
||||
}
|
||||
.scroll-area::-webkit-scrollbar { display: none; }
|
||||
|
||||
.card {
|
||||
background: white;
|
||||
border-radius: 14px;
|
||||
padding: 16px;
|
||||
margin-bottom: 12px;
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
.card__head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.card__title {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
.card__title::before {
|
||||
content: '';
|
||||
width: 4px; height: 14px;
|
||||
background: var(--primary);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
/* 进度条 */
|
||||
.progress-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 16px 0 20px;
|
||||
position: relative;
|
||||
}
|
||||
.progress-line {
|
||||
position: absolute;
|
||||
top: 28px; left: 30px; right: 30px;
|
||||
height: 3px;
|
||||
background: var(--border);
|
||||
z-index: 0;
|
||||
}
|
||||
.progress-line__filled {
|
||||
position: absolute;
|
||||
top: 28px; left: 30px;
|
||||
width: calc((100% - 60px) * 0.34);
|
||||
height: 3px;
|
||||
background: var(--primary);
|
||||
z-index: 1;
|
||||
transition: width 0.3s;
|
||||
}
|
||||
.step {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
.step__dot {
|
||||
width: 24px; height: 24px;
|
||||
border-radius: 50%;
|
||||
background: white;
|
||||
border: 3px solid var(--border);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 10px;
|
||||
color: var(--text-tertiary);
|
||||
font-weight: 700;
|
||||
}
|
||||
.step.done .step__dot {
|
||||
background: var(--primary);
|
||||
border-color: var(--primary);
|
||||
color: white;
|
||||
}
|
||||
.step.active .step__dot {
|
||||
background: white;
|
||||
border-color: var(--primary);
|
||||
color: var(--primary);
|
||||
box-shadow: 0 0 0 4px rgba(255, 109, 58, 0.2);
|
||||
}
|
||||
.step__label {
|
||||
font-size: 11px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
.step.done .step__label,
|
||||
.step.active .step__label {
|
||||
color: var(--text-primary);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 路线信息 */
|
||||
.route-card {
|
||||
background: white;
|
||||
border-radius: 14px;
|
||||
padding: 16px;
|
||||
margin-bottom: 12px;
|
||||
box-shadow: var(--shadow-sm);
|
||||
position: relative;
|
||||
}
|
||||
.route-row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.route-icons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding-top: 4px;
|
||||
}
|
||||
.route-dot {
|
||||
width: 28px; height: 28px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 14px;
|
||||
color: white;
|
||||
font-weight: 700;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.route-dot--start { background: var(--primary); }
|
||||
.route-dot--end { background: var(--success); }
|
||||
.route-line-vertical {
|
||||
width: 2px;
|
||||
flex: 1;
|
||||
min-height: 50px;
|
||||
border-left: 2px dashed var(--border);
|
||||
margin: 4px 0;
|
||||
}
|
||||
.route-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
padding: 0 0 8px 0;
|
||||
gap: 28px;
|
||||
}
|
||||
.route-block__name {
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.route-block__addr {
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
line-height: 1.5;
|
||||
}
|
||||
.route-block__contact {
|
||||
margin-top: 6px;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
.contact-tag {
|
||||
background: var(--primary-light);
|
||||
color: var(--primary-dark);
|
||||
padding: 4px 10px;
|
||||
border-radius: 12px;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
/* 餐品列表 */
|
||||
.goods-list {
|
||||
padding: 0;
|
||||
}
|
||||
.goods-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 10px 0;
|
||||
border-bottom: 1px dashed var(--border);
|
||||
}
|
||||
.goods-item:last-child { border-bottom: none; }
|
||||
.goods-img {
|
||||
width: 50px; height: 50px;
|
||||
background: linear-gradient(135deg, #fef3c7, #fed7aa);
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 22px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.goods-info { flex: 1; }
|
||||
.goods-name {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.goods-spec {
|
||||
font-size: 11px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
.goods-meta {
|
||||
text-align: right;
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
.goods-qty {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
/* 订单信息 */
|
||||
.info-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
.info-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 13px;
|
||||
}
|
||||
.info-label { color: var(--text-secondary); }
|
||||
.info-value { color: var(--text-primary); font-weight: 600; }
|
||||
.info-value--price { color: var(--primary); }
|
||||
.info-divider {
|
||||
border-top: 1px dashed var(--border);
|
||||
padding-top: 10px;
|
||||
}
|
||||
.info-row.total {
|
||||
padding-top: 10px;
|
||||
border-top: 1px solid var(--border);
|
||||
}
|
||||
.info-row.total .info-value {
|
||||
font-size: 18px;
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
/* 操作按钮 */
|
||||
.action-bar {
|
||||
position: absolute;
|
||||
bottom: 0; left: 0; right: 0;
|
||||
background: white;
|
||||
padding: 12px 16px 32px;
|
||||
box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.06);
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
z-index: 10;
|
||||
}
|
||||
.btn {
|
||||
flex: 1;
|
||||
height: 48px;
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
}
|
||||
.btn--ghost {
|
||||
background: var(--background);
|
||||
color: var(--text-primary);
|
||||
flex: 0 0 110px;
|
||||
}
|
||||
.btn--primary {
|
||||
background: linear-gradient(135deg, var(--primary), var(--primary-dark));
|
||||
color: white;
|
||||
box-shadow: 0 6px 12px rgba(255, 109, 58, 0.25);
|
||||
}
|
||||
|
||||
.tag-list {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 8px;
|
||||
}
|
||||
.info-tag {
|
||||
font-size: 10px;
|
||||
padding: 2px 8px;
|
||||
border-radius: 6px;
|
||||
background: #f3f4f6;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
.info-tag--warn {
|
||||
background: #fef3c7;
|
||||
color: #92400e;
|
||||
}
|
||||
|
||||
.home-indicator {
|
||||
position: absolute;
|
||||
bottom: 8px; left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 134px; height: 5px;
|
||||
background: #1f2937;
|
||||
border-radius: 3px;
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.toast {
|
||||
position: absolute;
|
||||
top: 60px; left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
color: white;
|
||||
padding: 8px 16px;
|
||||
border-radius: 20px;
|
||||
font-size: 13px;
|
||||
z-index: 100;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
pointer-events: none;
|
||||
}
|
||||
.toast.show { opacity: 1; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
<div class="status-bar">
|
||||
<span class="status-bar__time">9:41</span>
|
||||
<div class="status-bar__icons">
|
||||
<span class="status-bar__signal"></span>
|
||||
<span class="status-bar__wifi"></span>
|
||||
<span class="status-bar__battery"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="nav-bar">
|
||||
<a href="01-home.html" class="nav-back">‹</a>
|
||||
<span class="nav-title">订单详情</span>
|
||||
<span class="nav-status">已接单</span>
|
||||
</div>
|
||||
|
||||
<div class="scroll-area">
|
||||
|
||||
<!-- 进度条 -->
|
||||
<div class="card">
|
||||
<div class="progress-bar">
|
||||
<div class="progress-line"></div>
|
||||
<div class="progress-line__filled"></div>
|
||||
<div class="step done">
|
||||
<div class="step__dot">✓</div>
|
||||
<div class="step__label">接单</div>
|
||||
</div>
|
||||
<div class="step active">
|
||||
<div class="step__dot">2</div>
|
||||
<div class="step__label">取货</div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<div class="step__dot">3</div>
|
||||
<div class="step__label">配送</div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<div class="step__dot">4</div>
|
||||
<div class="step__label">送达</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="text-align:center;font-size:12px;color:var(--text-secondary);padding:8px 0 0">
|
||||
预计 <span style="color:var(--primary);font-weight:700">15:45</span> 前送达 · 剩余 38 分钟
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 路线 -->
|
||||
<div class="route-card">
|
||||
<div class="card__head">
|
||||
<div class="card__title">配送路线</div>
|
||||
<span style="font-size:12px;color:var(--primary);font-weight:600">全程 2.6km · 约 12 分钟</span>
|
||||
</div>
|
||||
|
||||
<div class="route-row">
|
||||
<div class="route-icons">
|
||||
<div class="route-dot route-dot--start">取</div>
|
||||
<div class="route-line-vertical"></div>
|
||||
<div class="route-dot route-dot--end">达</div>
|
||||
</div>
|
||||
<div class="route-content">
|
||||
<div>
|
||||
<div class="route-block__name">味之都食堂·高新店</div>
|
||||
<div class="route-block__addr">高新区科技三路 8 号 · 联系人:王经理</div>
|
||||
<div class="route-block__contact">
|
||||
<a href="javascript:void(0)" class="contact-tag" onclick="toast('正在呼叫商家')">📞 呼叫商家</a>
|
||||
<a href="javascript:void(0)" class="contact-tag" onclick="toast('已打开导航')">📍 导航</a>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="route-block__name">万科城 5 号楼 1802</div>
|
||||
<div class="route-block__addr">高新区科技路 · 联系人:张女士 138****6688</div>
|
||||
<div class="route-block__contact">
|
||||
<a href="javascript:void(0)" class="contact-tag" onclick="toast('正在呼叫客户')">📞 呼叫客户</a>
|
||||
<a href="javascript:void(0)" class="contact-tag" onclick="toast('已发送短信提醒')">💬 短信</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 餐品清单 -->
|
||||
<div class="card">
|
||||
<div class="card__head">
|
||||
<div class="card__title">餐品清单</div>
|
||||
<span style="font-size:12px;color:var(--text-secondary)">共 4 份</span>
|
||||
</div>
|
||||
<div class="goods-list">
|
||||
<div class="goods-item">
|
||||
<div class="goods-img">🍱</div>
|
||||
<div class="goods-info">
|
||||
<div class="goods-name">红烧牛肉套餐</div>
|
||||
<div class="goods-spec">主荤·标准份 · 含米饭/汤</div>
|
||||
</div>
|
||||
<div class="goods-meta">
|
||||
<div class="goods-qty">×2</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="goods-item">
|
||||
<div class="goods-img">🥗</div>
|
||||
<div class="goods-info">
|
||||
<div class="goods-name">清炒时蔬套餐</div>
|
||||
<div class="goods-spec">素菜·小份 · 含米饭</div>
|
||||
</div>
|
||||
<div class="goods-meta">
|
||||
<div class="goods-qty">×1</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="goods-item">
|
||||
<div class="goods-img">🍲</div>
|
||||
<div class="goods-info">
|
||||
<div class="goods-name">番茄鸡蛋汤</div>
|
||||
<div class="goods-spec">汤类·大份</div>
|
||||
</div>
|
||||
<div class="goods-meta">
|
||||
<div class="goods-qty">×1</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tag-list">
|
||||
<span class="info-tag info-tag--warn">⚠ 请核对溯源码</span>
|
||||
<span class="info-tag">📦 含冷链保温箱</span>
|
||||
<span class="info-tag">🥢 含餐具 4 份</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 订单信息 -->
|
||||
<div class="card">
|
||||
<div class="card__head">
|
||||
<div class="card__title">订单信息</div>
|
||||
</div>
|
||||
<div class="info-list">
|
||||
<div class="info-row">
|
||||
<span class="info-label">订单编号</span>
|
||||
<span class="info-value">DP20260812-0928</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">订单类型</span>
|
||||
<span class="info-value">到家配送</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">接单方式</span>
|
||||
<span class="info-value" style="color:var(--primary)">📌 派单</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">下单时间</span>
|
||||
<span class="info-value">14:08:25</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">接单时间</span>
|
||||
<span class="info-value">14:10:12</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">餐品份数</span>
|
||||
<span class="info-value">4 份</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">配送距离</span>
|
||||
<span class="info-value">2.6 km</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">预计时长</span>
|
||||
<span class="info-value">12 min</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">收货方式</span>
|
||||
<span class="info-value" style="color:var(--primary)">🔢 验证码收货</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 客户备注 -->
|
||||
<div class="card">
|
||||
<div class="card__head">
|
||||
<div class="card__title">客户备注</div>
|
||||
</div>
|
||||
<div style="font-size:13px;color:var(--text-primary);line-height:1.6">
|
||||
📝 麻烦放门口即可,不要按门铃,孩子正在午休。电话联系后放在 1802 门口鞋柜上,谢谢!
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="action-bar">
|
||||
<button class="btn btn--ghost" onclick="toast('异常上报页面开发中')">⚠ 异常</button>
|
||||
<button class="btn btn--primary" onclick="location.href='05-delivering.html'">🚀 到店报到</button>
|
||||
</div>
|
||||
|
||||
<div class="home-indicator"></div>
|
||||
<div class="toast" id="toast"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function toast(msg) {
|
||||
const t = document.getElementById('toast');
|
||||
t.textContent = msg;
|
||||
t.classList.add('show');
|
||||
setTimeout(() => t.classList.remove('show'), 1800);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,606 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>配送中 | 营养餐品配送</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
:root {
|
||||
--primary: #ff6d3a;
|
||||
--primary-dark: #e85a28;
|
||||
--primary-light: #fff0e8;
|
||||
--text-primary: #1f2937;
|
||||
--text-secondary: #6b7280;
|
||||
--text-tertiary: #9ca3af;
|
||||
--border: #e5e7eb;
|
||||
--background: #f6f8fb;
|
||||
--white: #ffffff;
|
||||
--success: #10b981;
|
||||
--info: #3b82f6;
|
||||
--shadow-sm: 0 2px 8px rgba(15, 23, 42, 0.06);
|
||||
--shadow-md: 0 10px 28px rgba(15, 23, 42, 0.10);
|
||||
}
|
||||
body {
|
||||
min-height: 100vh;
|
||||
padding: 24px 0 40px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
background: #2a2a2a;
|
||||
color: var(--text-primary);
|
||||
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", sans-serif;
|
||||
}
|
||||
.phone-shell {
|
||||
position: relative;
|
||||
width: 375px;
|
||||
height: 812px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--background);
|
||||
border-radius: 44px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3), inset 0 0 0 2px #e0e0e0;
|
||||
}
|
||||
.status-bar {
|
||||
height: 44px;
|
||||
padding: 0 24px;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
background: linear-gradient(135deg, #8b5cf6, #6d28d9);
|
||||
}
|
||||
.status-bar__time { font-size: 15px; font-weight: 700; }
|
||||
.status-bar__icons { display: flex; align-items: center; gap: 6px; }
|
||||
.status-bar__signal { width:18px;height:10px;background:#fff;clip-path: polygon(0 100%, 18% 64%, 18% 100%, 36% 42%, 36% 100%, 54% 24%, 54% 100%, 72% 8%, 72% 100%, 100% 0, 100% 100%); }
|
||||
.status-bar__wifi { width:16px;height:12px;background:#fff;clip-path: polygon(0 50%, 50% 0, 100% 50%, 86% 60%, 50% 22%, 14% 60%); }
|
||||
.status-bar__battery { width:24px;height:12px;border:1.5px solid #fff;border-radius:3px;position:relative;padding:1.5px;}
|
||||
.status-bar__battery::after { content:'';display:block;width:70%;height:100%;background:#fff;border-radius:1px;}
|
||||
.status-bar__battery::before { content:'';position:absolute;right:-3px;top:3px;width:2px;height:6px;background:#fff;border-radius:0 1px 1px 0;}
|
||||
|
||||
/* 顶部地图区域(模拟) */
|
||||
.map-area {
|
||||
height: 280px;
|
||||
flex-shrink: 0;
|
||||
background:
|
||||
radial-gradient(circle at 30% 40%, #e0e7ff 0%, transparent 60%),
|
||||
radial-gradient(circle at 70% 60%, #fef3c7 0%, transparent 60%),
|
||||
linear-gradient(135deg, #e0e7ff, #f0f9ff);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
/* 地图网格 */
|
||||
.map-area::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background-image:
|
||||
linear-gradient(rgba(99, 102, 241, 0.08) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(99, 102, 241, 0.08) 1px, transparent 1px);
|
||||
background-size: 40px 40px;
|
||||
}
|
||||
/* 模拟道路 */
|
||||
.map-area::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 200%;
|
||||
height: 30px;
|
||||
background: white;
|
||||
box-shadow: 0 0 0 1px #d1d5db;
|
||||
top: 60%;
|
||||
left: -50%;
|
||||
transform: rotate(-12deg);
|
||||
}
|
||||
.nav-bar {
|
||||
position: absolute;
|
||||
top: 44px; left: 0; right: 0;
|
||||
padding: 12px 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
z-index: 10;
|
||||
}
|
||||
.nav-back {
|
||||
width: 36px; height: 36px;
|
||||
background: white;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-decoration: none;
|
||||
color: var(--text-primary);
|
||||
font-size: 20px;
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
.nav-status {
|
||||
flex: 1;
|
||||
background: rgba(139, 92, 246, 0.95);
|
||||
color: white;
|
||||
padding: 8px 14px;
|
||||
border-radius: 20px;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
justify-content: center;
|
||||
}
|
||||
.nav-action {
|
||||
width: 36px; height: 36px;
|
||||
background: white;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
box-shadow: var(--shadow-sm);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* 地图标记 */
|
||||
.map-marker {
|
||||
position: absolute;
|
||||
transform: translate(-50%, -100%);
|
||||
z-index: 5;
|
||||
}
|
||||
.map-marker--start {
|
||||
top: 60%; left: 22%;
|
||||
}
|
||||
.map-marker--end {
|
||||
top: 30%; left: 78%;
|
||||
}
|
||||
.map-marker--rider {
|
||||
top: 45%; left: 50%;
|
||||
z-index: 6;
|
||||
}
|
||||
.marker-icon {
|
||||
width: 32px; height: 32px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
||||
border: 2px solid white;
|
||||
}
|
||||
.marker-icon--start { background: var(--primary); }
|
||||
.marker-icon--end { background: var(--success); }
|
||||
.marker-icon--rider {
|
||||
background: #8b5cf6;
|
||||
width: 40px; height: 40px;
|
||||
font-size: 20px;
|
||||
animation: riderPulse 2s ease-in-out infinite;
|
||||
}
|
||||
@keyframes riderPulse {
|
||||
0%, 100% { box-shadow: 0 0 0 0 rgba(139, 92, 246, 0.5), 0 4px 8px rgba(0,0,0,0.2); }
|
||||
50% { box-shadow: 0 0 0 12px rgba(139, 92, 246, 0), 0 4px 8px rgba(0,0,0,0.2); }
|
||||
}
|
||||
.map-route {
|
||||
position: absolute;
|
||||
top: 60%; left: 22%;
|
||||
width: 60%;
|
||||
height: 100px;
|
||||
transform: rotate(-25deg);
|
||||
transform-origin: 0 0;
|
||||
border-top: 4px dashed var(--primary);
|
||||
z-index: 2;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.map-float-info {
|
||||
position: absolute;
|
||||
top: 110px;
|
||||
left: 16px;
|
||||
background: white;
|
||||
padding: 10px 14px;
|
||||
border-radius: 12px;
|
||||
box-shadow: var(--shadow-md);
|
||||
z-index: 10;
|
||||
font-size: 12px;
|
||||
min-width: 140px;
|
||||
}
|
||||
.map-float-info__label {
|
||||
color: var(--text-secondary);
|
||||
font-size: 11px;
|
||||
}
|
||||
.map-float-info__value {
|
||||
color: var(--text-primary);
|
||||
font-size: 17px;
|
||||
font-weight: 700;
|
||||
margin-top: 2px;
|
||||
}
|
||||
.map-float-info__eta {
|
||||
color: var(--primary);
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.map-locate {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
bottom: 16px;
|
||||
width: 40px; height: 40px;
|
||||
background: white;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 18px;
|
||||
box-shadow: var(--shadow-md);
|
||||
cursor: pointer;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.content-area {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 16px;
|
||||
padding-bottom: 100px;
|
||||
}
|
||||
.content-area::-webkit-scrollbar { display: none; }
|
||||
|
||||
.card {
|
||||
background: white;
|
||||
border-radius: 14px;
|
||||
padding: 14px;
|
||||
margin-bottom: 12px;
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
/* 配送进度步骤 */
|
||||
.steps-card {
|
||||
margin-top: -30px;
|
||||
position: relative;
|
||||
z-index: 8;
|
||||
}
|
||||
.step-item {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
padding: 8px 0;
|
||||
}
|
||||
.step-item__icon {
|
||||
width: 28px; height: 28px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 13px;
|
||||
flex-shrink: 0;
|
||||
color: white;
|
||||
font-weight: 700;
|
||||
position: relative;
|
||||
}
|
||||
.step-item__icon--done { background: var(--success); }
|
||||
.step-item__icon--active {
|
||||
background: var(--primary);
|
||||
box-shadow: 0 0 0 4px rgba(255, 109, 58, 0.2);
|
||||
}
|
||||
.step-item__icon--pending {
|
||||
background: white;
|
||||
border: 2px dashed var(--border);
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
.step-item__icon:not(:last-child)::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 2px;
|
||||
height: 24px;
|
||||
background: var(--border);
|
||||
}
|
||||
.step-item:last-child .step-item__icon::after { display: none; }
|
||||
.step-item__icon--done::after { background: var(--success); }
|
||||
|
||||
.step-item__content { flex: 1; padding-top: 4px; }
|
||||
.step-item__title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.step-item__time {
|
||||
font-size: 11px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
.step-item__desc {
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
margin-top: 4px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.status-mini {
|
||||
font-size: 10px;
|
||||
padding: 2px 6px;
|
||||
border-radius: 6px;
|
||||
background: var(--primary-light);
|
||||
color: var(--primary-dark);
|
||||
font-weight: 600;
|
||||
}
|
||||
.status-mini--done {
|
||||
background: #d1fae5;
|
||||
color: #065f46;
|
||||
}
|
||||
|
||||
/* 客户信息 */
|
||||
.customer-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 14px;
|
||||
}
|
||||
.customer-avatar {
|
||||
width: 48px; height: 48px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(135deg, #fde68a, #fbbf24);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 22px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.customer-info { flex: 1; }
|
||||
.customer-name {
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.customer-addr {
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
line-height: 1.4;
|
||||
}
|
||||
.customer-actions {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
}
|
||||
.icon-btn {
|
||||
width: 38px; height: 38px;
|
||||
border-radius: 50%;
|
||||
border: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.icon-btn--call {
|
||||
background: var(--success);
|
||||
color: white;
|
||||
}
|
||||
.icon-btn--msg {
|
||||
background: var(--info);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.order-summary {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding: 12px 14px;
|
||||
}
|
||||
.summary-cell { text-align: center; }
|
||||
.summary-num {
|
||||
font-size: 17px;
|
||||
font-weight: 700;
|
||||
color: var(--primary);
|
||||
}
|
||||
.summary-label {
|
||||
font-size: 11px;
|
||||
color: var(--text-secondary);
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
/* 操作按钮 */
|
||||
.action-bar {
|
||||
position: absolute;
|
||||
bottom: 0; left: 0; right: 0;
|
||||
background: white;
|
||||
padding: 12px 16px 32px;
|
||||
box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.08);
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
z-index: 10;
|
||||
}
|
||||
.btn {
|
||||
flex: 1;
|
||||
height: 50px;
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
}
|
||||
.btn--ghost {
|
||||
background: var(--background);
|
||||
color: var(--text-primary);
|
||||
flex: 0 0 100px;
|
||||
}
|
||||
.btn--primary {
|
||||
background: linear-gradient(135deg, var(--success), #059669);
|
||||
color: white;
|
||||
box-shadow: 0 6px 12px rgba(16, 185, 129, 0.25);
|
||||
}
|
||||
|
||||
.home-indicator {
|
||||
position: absolute;
|
||||
bottom: 8px; left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 134px; height: 5px;
|
||||
background: #1f2937;
|
||||
border-radius: 3px;
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.toast {
|
||||
position: absolute;
|
||||
top: 60px; left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
color: white;
|
||||
padding: 8px 16px;
|
||||
border-radius: 20px;
|
||||
font-size: 13px;
|
||||
z-index: 100;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
pointer-events: none;
|
||||
}
|
||||
.toast.show { opacity: 1; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
<div class="status-bar">
|
||||
<span class="status-bar__time">15:08</span>
|
||||
<div class="status-bar__icons">
|
||||
<span class="status-bar__signal"></span>
|
||||
<span class="status-bar__wifi"></span>
|
||||
<span class="status-bar__battery"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 地图区 -->
|
||||
<div class="map-area">
|
||||
<div class="nav-bar">
|
||||
<a href="04-order-detail.html" class="nav-back">‹</a>
|
||||
<div class="nav-status">🛵 配送中 · 已骑行 6 分钟</div>
|
||||
<div class="nav-action" onclick="toast('已开启导航')">🧭</div>
|
||||
</div>
|
||||
|
||||
<div class="map-float-info">
|
||||
<div class="map-float-info__label">距离客户</div>
|
||||
<div class="map-float-info__value">1.8 km</div>
|
||||
<div class="map-float-info__eta">预计 15:25 送达</div>
|
||||
</div>
|
||||
|
||||
<div class="map-route"></div>
|
||||
<div class="map-marker map-marker--start">
|
||||
<div class="marker-icon marker-icon--start">取</div>
|
||||
</div>
|
||||
<div class="map-marker map-marker--rider">
|
||||
<div class="marker-icon marker-icon--rider">🛵</div>
|
||||
</div>
|
||||
<div class="map-marker map-marker--end">
|
||||
<div class="marker-icon marker-icon--end">达</div>
|
||||
</div>
|
||||
|
||||
<div class="map-locate" onclick="toast('已定位到当前位置')">📍</div>
|
||||
</div>
|
||||
|
||||
<div class="content-area">
|
||||
<!-- 配送步骤 -->
|
||||
<div class="card steps-card">
|
||||
<div class="step-item">
|
||||
<div class="step-item__icon step-item__icon--done">✓</div>
|
||||
<div class="step-item__content">
|
||||
<div class="step-item__title">
|
||||
已接单
|
||||
<span class="status-mini status-mini--done">完成</span>
|
||||
</div>
|
||||
<div class="step-item__time">14:10:12</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="step-item">
|
||||
<div class="step-item__icon step-item__icon--done">✓</div>
|
||||
<div class="step-item__content">
|
||||
<div class="step-item__title">
|
||||
已到店取货
|
||||
<span class="status-mini status-mini--done">完成</span>
|
||||
</div>
|
||||
<div class="step-item__time">14:22:08 · 味之都食堂·高新店</div>
|
||||
<div class="step-item__desc">餐品核对完成,共 4 份,溯源码已扫描 ✓</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="step-item">
|
||||
<div class="step-item__icon step-item__icon--active">🛵</div>
|
||||
<div class="step-item__content">
|
||||
<div class="step-item__title">
|
||||
配送中
|
||||
<span class="status-mini">当前</span>
|
||||
</div>
|
||||
<div class="step-item__time">15:02:30 开始配送</div>
|
||||
<div class="step-item__desc">距离客户 1.8km · 预计 15:25 送达</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="step-item">
|
||||
<div class="step-item__icon step-item__icon--pending">4</div>
|
||||
<div class="step-item__content">
|
||||
<div class="step-item__title" style="color:var(--text-secondary)">送达签收</div>
|
||||
<div class="step-item__time" style="color:var(--text-tertiary)">待完成</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 客户信息 -->
|
||||
<div class="card">
|
||||
<div class="customer-card">
|
||||
<div class="customer-avatar">👩</div>
|
||||
<div class="customer-info">
|
||||
<div class="customer-name">张女士</div>
|
||||
<div class="customer-addr">万科城 5 号楼 1802 · 138****6688</div>
|
||||
</div>
|
||||
<div class="customer-actions">
|
||||
<button class="icon-btn icon-btn--call" onclick="toast('正在呼叫张女士')">📞</button>
|
||||
<button class="icon-btn icon-btn--msg" onclick="toast('已发送到达提醒短信')">💬</button>
|
||||
</div>
|
||||
</div>
|
||||
<div style="padding:8px 14px 14px;font-size:12px;color:var(--text-secondary);line-height:1.6;border-top:1px dashed var(--border);margin-top:4px">
|
||||
💬 <strong style="color:var(--text-primary)">客户备注:</strong>
|
||||
麻烦放门口即可,不要按门铃,孩子正在午休。
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 订单概览 -->
|
||||
<div class="card">
|
||||
<div class="order-summary">
|
||||
<div class="summary-cell">
|
||||
<div class="summary-num">4 份</div>
|
||||
<div class="summary-label">餐品</div>
|
||||
</div>
|
||||
<div class="summary-cell">
|
||||
<div class="summary-num">2.6km</div>
|
||||
<div class="summary-label">配送距离</div>
|
||||
</div>
|
||||
<div class="summary-cell">
|
||||
<div class="summary-num">15:45</div>
|
||||
<div class="summary-label">要求送达</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="action-bar">
|
||||
<button class="btn btn--ghost" onclick="toast('异常上报页面开发中')">⚠ 异常</button>
|
||||
<button class="btn btn--primary" onclick="location.href='06-finish-sign.html'">📍 已到达 · 验证码签收</button>
|
||||
</div>
|
||||
|
||||
<div class="home-indicator"></div>
|
||||
<div class="toast" id="toast"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function toast(msg) {
|
||||
const t = document.getElementById('toast');
|
||||
t.textContent = msg;
|
||||
t.classList.add('show');
|
||||
setTimeout(() => t.classList.remove('show'), 1800);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,634 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>验证码签收 | 营养管理餐品配送</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
:root {
|
||||
--primary: #ff6d3a;
|
||||
--primary-dark: #e85a28;
|
||||
--primary-light: #fff0e8;
|
||||
--text-primary: #1f2937;
|
||||
--text-secondary: #6b7280;
|
||||
--text-tertiary: #9ca3af;
|
||||
--border: #e5e7eb;
|
||||
--background: #f6f8fb;
|
||||
--white: #ffffff;
|
||||
--success: #10b981;
|
||||
--shadow-sm: 0 2px 8px rgba(15, 23, 42, 0.06);
|
||||
}
|
||||
body {
|
||||
min-height: 100vh;
|
||||
padding: 24px 0 40px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
background: #2a2a2a;
|
||||
color: var(--text-primary);
|
||||
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", sans-serif;
|
||||
}
|
||||
.phone-shell {
|
||||
position: relative;
|
||||
width: 375px;
|
||||
height: 812px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--background);
|
||||
border-radius: 44px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3), inset 0 0 0 2px #e0e0e0;
|
||||
}
|
||||
.status-bar {
|
||||
height: 44px;
|
||||
padding: 0 24px;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
background: linear-gradient(135deg, #10b981, #059669);
|
||||
}
|
||||
.status-bar__time { font-size: 15px; font-weight: 700; }
|
||||
.status-bar__icons { display: flex; align-items: center; gap: 6px; }
|
||||
.status-bar__signal { width:18px;height:10px;background:#fff;clip-path: polygon(0 100%, 18% 64%, 18% 100%, 36% 42%, 36% 100%, 54% 24%, 54% 100%, 72% 8%, 72% 100%, 100% 0, 100% 100%); }
|
||||
.status-bar__wifi { width:16px;height:12px;background:#fff;clip-path: polygon(0 50%, 50% 0, 100% 50%, 86% 60%, 50% 22%, 14% 60%); }
|
||||
.status-bar__battery { width:24px;height:12px;border:1.5px solid #fff;border-radius:3px;position:relative;padding:1.5px;}
|
||||
.status-bar__battery::after { content:'';display:block;width:70%;height:100%;background:#fff;border-radius:1px;}
|
||||
.status-bar__battery::before { content:'';position:absolute;right:-3px;top:3px;width:2px;height:6px;background:#fff;border-radius:0 1px 1px 0;}
|
||||
|
||||
.nav-bar {
|
||||
flex-shrink: 0;
|
||||
background: linear-gradient(135deg, #10b981, #059669);
|
||||
color: white;
|
||||
padding: 4px 16px 14px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
.nav-back { color: white; text-decoration: none; font-size: 22px; width: 32px; }
|
||||
.nav-title { flex: 1; font-size: 17px; font-weight: 700; }
|
||||
|
||||
.scroll-area {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 16px;
|
||||
padding-bottom: 110px;
|
||||
}
|
||||
.scroll-area::-webkit-scrollbar { display: none; }
|
||||
|
||||
.head-banner {
|
||||
background: white;
|
||||
border-radius: 14px;
|
||||
padding: 16px;
|
||||
margin-bottom: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
.head-banner__icon {
|
||||
width: 52px; height: 52px;
|
||||
background: linear-gradient(135deg, #d1fae5, #6ee7b7);
|
||||
border-radius: 14px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 26px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.head-banner__title {
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.head-banner__desc {
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: white;
|
||||
border-radius: 14px;
|
||||
padding: 16px;
|
||||
margin-bottom: 12px;
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
.card__head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.card__title {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
.card__title::before {
|
||||
content: '';
|
||||
width: 4px; height: 14px;
|
||||
background: var(--primary);
|
||||
border-radius: 2px;
|
||||
}
|
||||
.card__required {
|
||||
color: var(--primary);
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.card__optional {
|
||||
color: var(--text-tertiary);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* 验证码输入 */
|
||||
.code-area {
|
||||
padding: 8px 0;
|
||||
}
|
||||
.code-tip {
|
||||
font-size: 13px;
|
||||
color: var(--text-secondary);
|
||||
text-align: center;
|
||||
margin-bottom: 14px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.code-tip strong {
|
||||
color: var(--text-primary);
|
||||
}
|
||||
.code-inputs {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
.code-box {
|
||||
width: 44px; height: 56px;
|
||||
border: 2px solid var(--border);
|
||||
border-radius: 10px;
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: var(--text-primary);
|
||||
text-align: center;
|
||||
outline: none;
|
||||
background: var(--background);
|
||||
transition: all 0.2s;
|
||||
font-family: monospace;
|
||||
}
|
||||
.code-box:focus {
|
||||
border-color: var(--primary);
|
||||
background: white;
|
||||
box-shadow: 0 0 0 3px rgba(255, 109, 58, 0.15);
|
||||
}
|
||||
.code-box.filled {
|
||||
border-color: var(--primary);
|
||||
background: var(--primary-light);
|
||||
color: var(--primary-dark);
|
||||
}
|
||||
|
||||
.code-actions {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 16px;
|
||||
padding-top: 4px;
|
||||
}
|
||||
.code-action {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: var(--primary);
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
padding: 6px 12px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
.code-action:disabled {
|
||||
color: var(--text-tertiary);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.code-notice {
|
||||
background: #fef3c7;
|
||||
color: #92400e;
|
||||
padding: 10px 12px;
|
||||
border-radius: 8px;
|
||||
font-size: 12px;
|
||||
line-height: 1.6;
|
||||
margin-top: 12px;
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
/* 拍照区 */
|
||||
.photo-area {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 8px;
|
||||
}
|
||||
.photo-slot {
|
||||
aspect-ratio: 1;
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 11px;
|
||||
color: var(--text-secondary);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.photo-slot--taken {
|
||||
background: linear-gradient(135deg, #fde68a, #fbbf24);
|
||||
color: #1f2937;
|
||||
}
|
||||
.photo-slot--taken::after {
|
||||
content: '📦';
|
||||
font-size: 32px;
|
||||
}
|
||||
.photo-slot--empty {
|
||||
background: var(--background);
|
||||
border: 1.5px dashed var(--border);
|
||||
}
|
||||
.photo-slot__icon {
|
||||
font-size: 24px;
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
.photo-slot--taken .photo-slot__label {
|
||||
position: absolute;
|
||||
bottom: 4px;
|
||||
background: rgba(0,0,0,0.6);
|
||||
color: white;
|
||||
padding: 1px 6px;
|
||||
border-radius: 4px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
/* 工作量记录 */
|
||||
.info-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 8px 0;
|
||||
font-size: 13px;
|
||||
border-bottom: 1px dashed var(--border);
|
||||
}
|
||||
.info-row:last-child { border-bottom: none; }
|
||||
.info-label { color: var(--text-secondary); }
|
||||
.info-value { font-weight: 600; color: var(--text-primary); }
|
||||
.info-row--highlight {
|
||||
padding-top: 12px;
|
||||
border-top: 2px solid var(--border);
|
||||
margin-top: 4px;
|
||||
}
|
||||
.info-row--highlight .info-value {
|
||||
font-size: 17px;
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
/* 操作按钮 */
|
||||
.action-bar {
|
||||
position: absolute;
|
||||
bottom: 0; left: 0; right: 0;
|
||||
background: white;
|
||||
padding: 12px 16px 32px;
|
||||
box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.08);
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
z-index: 10;
|
||||
}
|
||||
.btn {
|
||||
flex: 1;
|
||||
height: 52px;
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
}
|
||||
.btn--primary {
|
||||
background: linear-gradient(135deg, #10b981, #059669);
|
||||
color: white;
|
||||
box-shadow: 0 6px 12px rgba(16, 185, 129, 0.25);
|
||||
}
|
||||
.btn--primary:disabled {
|
||||
background: #d1d5db;
|
||||
box-shadow: none;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.home-indicator {
|
||||
position: absolute;
|
||||
bottom: 8px; left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 134px; height: 5px;
|
||||
background: #1f2937;
|
||||
border-radius: 3px;
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.toast {
|
||||
position: absolute;
|
||||
top: 60px; left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
color: white;
|
||||
padding: 8px 16px;
|
||||
border-radius: 20px;
|
||||
font-size: 13px;
|
||||
z-index: 100;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
pointer-events: none;
|
||||
}
|
||||
.toast.show { opacity: 1; }
|
||||
|
||||
/* 成功弹窗 */
|
||||
.success-modal {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
z-index: 200;
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.success-modal.show { display: flex; }
|
||||
.success-box {
|
||||
background: white;
|
||||
width: 280px;
|
||||
border-radius: 20px;
|
||||
padding: 28px 20px 20px;
|
||||
text-align: center;
|
||||
animation: popIn 0.3s;
|
||||
}
|
||||
@keyframes popIn {
|
||||
from { transform: scale(0.8); opacity: 0; }
|
||||
to { transform: scale(1); opacity: 1; }
|
||||
}
|
||||
.success-icon {
|
||||
width: 72px; height: 72px;
|
||||
background: linear-gradient(135deg, #10b981, #059669);
|
||||
border-radius: 50%;
|
||||
margin: 0 auto 14px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 36px;
|
||||
animation: checkPop 0.5s ease 0.2s both;
|
||||
}
|
||||
@keyframes checkPop {
|
||||
0% { transform: scale(0); }
|
||||
60% { transform: scale(1.2); }
|
||||
100% { transform: scale(1); }
|
||||
}
|
||||
.success-title {
|
||||
font-size: 19px;
|
||||
font-weight: 700;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.success-stats {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding: 12px 0 16px;
|
||||
border-top: 1px dashed var(--border);
|
||||
border-bottom: 1px dashed var(--border);
|
||||
margin: 12px 0;
|
||||
}
|
||||
.success-stat__num {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: var(--primary);
|
||||
}
|
||||
.success-stat__label {
|
||||
font-size: 11px;
|
||||
color: var(--text-secondary);
|
||||
margin-top: 2px;
|
||||
}
|
||||
.success-desc {
|
||||
font-size: 13px;
|
||||
color: var(--text-secondary);
|
||||
line-height: 1.6;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
.success-btn {
|
||||
width: 100%;
|
||||
height: 44px;
|
||||
background: linear-gradient(135deg, var(--primary), var(--primary-dark));
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
<div class="status-bar">
|
||||
<span class="status-bar__time">15:22</span>
|
||||
<div class="status-bar__icons">
|
||||
<span class="status-bar__signal"></span>
|
||||
<span class="status-bar__wifi"></span>
|
||||
<span class="status-bar__battery"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="nav-bar">
|
||||
<a href="05-delivering.html" class="nav-back">‹</a>
|
||||
<span class="nav-title">验证码签收</span>
|
||||
</div>
|
||||
|
||||
<div class="scroll-area">
|
||||
<div class="head-banner">
|
||||
<div class="head-banner__icon">📍</div>
|
||||
<div>
|
||||
<div class="head-banner__title">已到达目的地</div>
|
||||
<div class="head-banner__desc">万科城 5 号楼 1802 · 张女士 · 提前 23 分钟到达</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 验证码输入 -->
|
||||
<div class="card">
|
||||
<div class="card__head">
|
||||
<div class="card__title">验证码签收</div>
|
||||
<span class="card__required">*必填</span>
|
||||
</div>
|
||||
<div class="code-area">
|
||||
<div class="code-tip">
|
||||
请向客户索取 <strong>6 位数字验证码</strong><br>
|
||||
输入正确验证码后可确认送达
|
||||
</div>
|
||||
<div class="code-inputs">
|
||||
<input type="tel" class="code-box" maxlength="1" data-idx="0">
|
||||
<input type="tel" class="code-box" maxlength="1" data-idx="1">
|
||||
<input type="tel" class="code-box" maxlength="1" data-idx="2">
|
||||
<input type="tel" class="code-box" maxlength="1" data-idx="3">
|
||||
<input type="tel" class="code-box" maxlength="1" data-idx="4">
|
||||
<input type="tel" class="code-box" maxlength="1" data-idx="5">
|
||||
</div>
|
||||
<div class="code-actions">
|
||||
<button class="code-action" onclick="toast('已发送验证码到客户手机,请客户查收短信')">📲 发送验证码</button>
|
||||
<button class="code-action" onclick="toast('请拨打客户电话 138****6688 索取验证码')">📞 联系客户</button>
|
||||
</div>
|
||||
<div class="code-notice">
|
||||
<span>⚠️</span>
|
||||
<span>验证码由系统在下单时发送至客户手机,客户未收到可点击「发送验证码」重新获取。验证码 5 分钟内有效。</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 拍照留证 -->
|
||||
<div class="card">
|
||||
<div class="card__head">
|
||||
<div class="card__title">拍照留证</div>
|
||||
<span class="card__required">*至少 1 张</span>
|
||||
</div>
|
||||
<div class="photo-area">
|
||||
<div class="photo-slot photo-slot--taken">
|
||||
<span class="photo-slot__label">餐品放置</span>
|
||||
</div>
|
||||
<div class="photo-slot photo-slot--taken">
|
||||
<span class="photo-slot__label">门口环境</span>
|
||||
</div>
|
||||
<div class="photo-slot photo-slot--empty" onclick="toast('打开相机')">
|
||||
<span class="photo-slot__icon">+</span>
|
||||
<span>添加照片</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 工作量记录 -->
|
||||
<div class="card">
|
||||
<div class="card__head">
|
||||
<div class="card__title">本次工作量</div>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">餐品数量</span>
|
||||
<span class="info-value">4 份</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">配送距离</span>
|
||||
<span class="info-value">2.6 km</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">配送时长</span>
|
||||
<span class="info-value">20 分钟</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">送达时间</span>
|
||||
<span class="info-value">15:22 · 提前 23 分钟</span>
|
||||
</div>
|
||||
<div class="info-row info-row--highlight">
|
||||
<span class="info-label" style="font-weight:700">本次完成 1 单</span>
|
||||
<span class="info-value">已记录</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="action-bar">
|
||||
<button class="btn btn--primary" id="finishBtn" disabled onclick="confirmFinish()">✓ 输入验证码后确认送达</button>
|
||||
</div>
|
||||
|
||||
<div class="home-indicator"></div>
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<!-- 成功弹窗 -->
|
||||
<div class="success-modal" id="successModal">
|
||||
<div class="success-box">
|
||||
<div class="success-icon">✓</div>
|
||||
<div class="success-title">配送完成 🎉</div>
|
||||
<div class="success-stats">
|
||||
<div>
|
||||
<div class="success-stat__num">4 份</div>
|
||||
<div class="success-stat__label">餐品</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="success-stat__num">2.6km</div>
|
||||
<div class="success-stat__label">距离</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="success-stat__num">20min</div>
|
||||
<div class="success-stat__label">时长</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="success-desc">
|
||||
已记录本次配送工作量<br>
|
||||
<span style="color:#10b981;font-weight:600">提前 23 分钟送达 · 准时配送</span>
|
||||
</div>
|
||||
<button class="success-btn" onclick="location.href='01-home.html'">返回工作台</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function toast(msg) {
|
||||
const t = document.getElementById('toast');
|
||||
t.textContent = msg;
|
||||
t.classList.add('show');
|
||||
setTimeout(() => t.classList.remove('show'), 1800);
|
||||
}
|
||||
|
||||
// 验证码自动跳格
|
||||
const boxes = document.querySelectorAll('.code-box');
|
||||
const finishBtn = document.getElementById('finishBtn');
|
||||
|
||||
boxes.forEach((box, idx) => {
|
||||
box.addEventListener('input', e => {
|
||||
const v = e.target.value.replace(/\D/g, '');
|
||||
e.target.value = v.slice(0, 1);
|
||||
if (v && idx < boxes.length - 1) {
|
||||
boxes[idx + 1].focus();
|
||||
}
|
||||
e.target.classList.toggle('filled', !!v);
|
||||
checkComplete();
|
||||
});
|
||||
box.addEventListener('keydown', e => {
|
||||
if (e.key === 'Backspace' && !e.target.value && idx > 0) {
|
||||
boxes[idx - 1].focus();
|
||||
}
|
||||
});
|
||||
box.addEventListener('paste', e => {
|
||||
e.preventDefault();
|
||||
const text = (e.clipboardData || window.clipboardData).getData('text').replace(/\D/g, '').slice(0, 6);
|
||||
text.split('').forEach((ch, i) => {
|
||||
if (boxes[i]) {
|
||||
boxes[i].value = ch;
|
||||
boxes[i].classList.add('filled');
|
||||
}
|
||||
});
|
||||
boxes[Math.min(text.length, 5)].focus();
|
||||
checkComplete();
|
||||
});
|
||||
});
|
||||
|
||||
function checkComplete() {
|
||||
const allFilled = Array.from(boxes).every(b => b.value);
|
||||
finishBtn.disabled = !allFilled;
|
||||
if (allFilled) {
|
||||
finishBtn.textContent = '✓ 确认送达';
|
||||
} else {
|
||||
finishBtn.textContent = '✓ 输入验证码后确认送达';
|
||||
}
|
||||
}
|
||||
|
||||
function confirmFinish() {
|
||||
document.getElementById('successModal').classList.add('show');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,620 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>历史订单 | 营养餐品配送</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
:root {
|
||||
--primary: #ff6d3a;
|
||||
--primary-dark: #e85a28;
|
||||
--primary-light: #fff0e8;
|
||||
--text-primary: #1f2937;
|
||||
--text-secondary: #6b7280;
|
||||
--text-tertiary: #9ca3af;
|
||||
--border: #e5e7eb;
|
||||
--background: #f6f8fb;
|
||||
--white: #ffffff;
|
||||
--success: #10b981;
|
||||
--shadow-sm: 0 2px 8px rgba(15, 23, 42, 0.06);
|
||||
--shadow-md: 0 10px 28px rgba(15, 23, 42, 0.10);
|
||||
}
|
||||
body {
|
||||
min-height: 100vh;
|
||||
padding: 24px 0 40px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
background: #2a2a2a;
|
||||
color: var(--text-primary);
|
||||
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", sans-serif;
|
||||
}
|
||||
.phone-shell {
|
||||
position: relative;
|
||||
width: 375px;
|
||||
height: 812px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--background);
|
||||
border-radius: 44px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3), inset 0 0 0 2px #e0e0e0;
|
||||
}
|
||||
.status-bar {
|
||||
height: 44px;
|
||||
padding: 0 24px;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
background: linear-gradient(135deg, var(--primary), var(--primary-dark));
|
||||
}
|
||||
.status-bar__time { font-size: 15px; font-weight: 700; }
|
||||
.status-bar__icons { display: flex; align-items: center; gap: 6px; }
|
||||
.status-bar__signal { width:18px;height:10px;background:#fff;clip-path: polygon(0 100%, 18% 64%, 18% 100%, 36% 42%, 36% 100%, 54% 24%, 54% 100%, 72% 8%, 72% 100%, 100% 0, 100% 100%); }
|
||||
.status-bar__wifi { width:16px;height:12px;background:#fff;clip-path: polygon(0 50%, 50% 0, 100% 50%, 86% 60%, 50% 22%, 14% 60%); }
|
||||
.status-bar__battery { width:24px;height:12px;border:1.5px solid #fff;border-radius:3px;position:relative;padding:1.5px;}
|
||||
.status-bar__battery::after { content:'';display:block;width:70%;height:100%;background:#fff;border-radius:1px;}
|
||||
.status-bar__battery::before { content:'';position:absolute;right:-3px;top:3px;width:2px;height:6px;background:#fff;border-radius:0 1px 1px 0;}
|
||||
|
||||
/* 顶部收益统计 */
|
||||
.summary-bar {
|
||||
flex-shrink: 0;
|
||||
background: linear-gradient(135deg, var(--primary), var(--primary-dark));
|
||||
color: white;
|
||||
padding: 0 16px 20px;
|
||||
}
|
||||
.summary-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.summary-title {
|
||||
font-size: 17px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.summary-date {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
padding: 4px 10px;
|
||||
border-radius: 12px;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.summary-stats {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 4px;
|
||||
}
|
||||
.summary-item {
|
||||
text-align: center;
|
||||
}
|
||||
.summary-num {
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.summary-num--lg { font-size: 24px; }
|
||||
.summary-label {
|
||||
font-size: 11px;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
/* Tab */
|
||||
.tab-bar {
|
||||
flex-shrink: 0;
|
||||
background: white;
|
||||
display: flex;
|
||||
padding: 0 16px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
.tab-item {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
padding: 12px 0;
|
||||
font-size: 13px;
|
||||
color: var(--text-secondary);
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
font-weight: 500;
|
||||
}
|
||||
.tab-item.active {
|
||||
color: var(--primary);
|
||||
font-weight: 700;
|
||||
}
|
||||
.tab-item.active::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0; left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 24px; height: 3px;
|
||||
background: var(--primary);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.scroll-area {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 12px 16px 90px;
|
||||
}
|
||||
.scroll-area::-webkit-scrollbar { display: none; }
|
||||
|
||||
/* 日期分组 */
|
||||
.date-group {
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
.date-group__head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 6px 0;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.date-group__title {
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
.date-group__stat {
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
.date-group__stat strong {
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
.order-item {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
padding: 14px;
|
||||
margin-bottom: 8px;
|
||||
box-shadow: var(--shadow-sm);
|
||||
cursor: pointer;
|
||||
transition: transform 0.1s;
|
||||
}
|
||||
.order-item:active { transform: scale(0.98); }
|
||||
|
||||
.order-item__head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.order-item__num {
|
||||
font-size: 12px;
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
.type-tag {
|
||||
display: inline-block;
|
||||
font-size: 10px;
|
||||
padding: 1px 6px;
|
||||
border-radius: 4px;
|
||||
margin-left: 4px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.type-tag--home { background: #dbeafe; color: #1e40af; }
|
||||
.type-tag--store { background: #fef3c7; color: #92400e; }
|
||||
|
||||
.status-tag {
|
||||
font-size: 11px;
|
||||
padding: 2px 8px;
|
||||
border-radius: 10px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.status-tag--completed { background: #d1fae5; color: #065f46; }
|
||||
.status-tag--rejected { background: #f3f4f6; color: #6b7280; }
|
||||
.status-tag--timeout { background: #f3f4f6; color: #9ca3af; border: 1px dashed var(--text-tertiary); }
|
||||
|
||||
.order-route {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
padding: 6px 0;
|
||||
border-top: 1px dashed var(--border);
|
||||
border-bottom: 1px dashed var(--border);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.order-route__point {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.order-route__icon {
|
||||
width: 18px; height: 18px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
font-size: 10px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.order-route__icon--start { background: var(--primary); }
|
||||
.order-route__icon--end { background: var(--success); }
|
||||
.order-route__arrow {
|
||||
color: var(--text-tertiary);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.order-item__foot {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.order-time {
|
||||
font-size: 11px;
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
.order-income {
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
color: var(--primary);
|
||||
}
|
||||
.order-income--rejected {
|
||||
color: var(--text-tertiary);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.empty {
|
||||
text-align: center;
|
||||
padding: 60px 20px;
|
||||
color: var(--text-tertiary);
|
||||
font-size: 13px;
|
||||
}
|
||||
.empty__icon {
|
||||
font-size: 48px;
|
||||
margin-bottom: 8px;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
/* 底部 Tab */
|
||||
.tabbar {
|
||||
position: absolute;
|
||||
bottom: 0; left: 0; right: 0;
|
||||
height: 70px;
|
||||
background: white;
|
||||
border-top: 1px solid var(--border);
|
||||
display: flex;
|
||||
padding: 8px 0 20px;
|
||||
}
|
||||
.tab {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 2px;
|
||||
text-decoration: none;
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
.tab.active { color: var(--primary); }
|
||||
.tab__icon { font-size: 22px; }
|
||||
.tab__label { font-size: 10px; font-weight: 600; }
|
||||
|
||||
.home-indicator {
|
||||
position: absolute;
|
||||
bottom: 8px; left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 134px; height: 5px;
|
||||
background: #1f2937;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.toast {
|
||||
position: absolute;
|
||||
top: 60px; left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
color: white;
|
||||
padding: 8px 16px;
|
||||
border-radius: 20px;
|
||||
font-size: 13px;
|
||||
z-index: 100;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
pointer-events: none;
|
||||
}
|
||||
.toast.show { opacity: 1; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
<div class="status-bar">
|
||||
<span class="status-bar__time">9:41</span>
|
||||
<div class="status-bar__icons">
|
||||
<span class="status-bar__signal"></span>
|
||||
<span class="status-bar__wifi"></span>
|
||||
<span class="status-bar__battery"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 顶部收益 -->
|
||||
<div class="summary-bar">
|
||||
<div class="summary-head">
|
||||
<div class="summary-title">📚 历史订单</div>
|
||||
<div class="summary-date" onclick="toast('选择日期范围')">📅 本月 ›</div>
|
||||
</div>
|
||||
<div class="summary-stats">
|
||||
<div class="summary-item">
|
||||
<div class="summary-num summary-num--lg">186</div>
|
||||
<div class="summary-label">完成单数</div>
|
||||
</div>
|
||||
<div class="summary-item">
|
||||
<div class="summary-num summary-num--lg">486km</div>
|
||||
<div class="summary-label">总里程</div>
|
||||
</div>
|
||||
<div class="summary-item">
|
||||
<div class="summary-num">98%</div>
|
||||
<div class="summary-label">准时率</div>
|
||||
</div>
|
||||
<div class="summary-item">
|
||||
<div class="summary-num">4.9</div>
|
||||
<div class="summary-label">客户评分</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tab -->
|
||||
<div class="tab-bar">
|
||||
<div class="tab-item active">全部</div>
|
||||
<div class="tab-item">已完成</div>
|
||||
<div class="tab-item">已拒单</div>
|
||||
<div class="tab-item">超时</div>
|
||||
</div>
|
||||
|
||||
<div class="scroll-area">
|
||||
|
||||
<!-- 今日 -->
|
||||
<div class="date-group">
|
||||
<div class="date-group__head">
|
||||
<div class="date-group__title">📅 今天 (8月12日)</div>
|
||||
<div class="date-group__stat">完成 <strong>8</strong> 单 · 总里程 <strong>20.6km</strong></div>
|
||||
</div>
|
||||
|
||||
<div class="order-item" onclick="toast('打开订单详情')">
|
||||
<div class="order-item__head">
|
||||
<div>
|
||||
<span class="order-item__num">#DP20260812-0832</span>
|
||||
<span class="type-tag type-tag--home">到家</span>
|
||||
</div>
|
||||
<span class="status-tag status-tag--completed">✓ 已送达</span>
|
||||
</div>
|
||||
<div class="order-route">
|
||||
<div class="order-route__point">
|
||||
<span class="order-route__icon order-route__icon--start">取</span>
|
||||
<span>中央厨房·高新站</span>
|
||||
</div>
|
||||
<span class="order-route__arrow">→</span>
|
||||
<div class="order-route__point">
|
||||
<span class="order-route__icon order-route__icon--end">达</span>
|
||||
<span>万科城 5 号楼</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="order-item__foot">
|
||||
<span class="order-time">15:08 送达 · 提前 23 分钟</span>
|
||||
<span class="order-income">2.3km · 20min</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="order-item" onclick="toast('打开订单详情')">
|
||||
<div class="order-item__head">
|
||||
<div>
|
||||
<span class="order-item__num">#DP20260812-0728</span>
|
||||
<span class="type-tag type-tag--store">到店</span>
|
||||
</div>
|
||||
<span class="status-tag status-tag--completed">✓ 已送达</span>
|
||||
</div>
|
||||
<div class="order-route">
|
||||
<div class="order-route__point">
|
||||
<span class="order-route__icon order-route__icon--start">取</span>
|
||||
<span>净菜加工中心</span>
|
||||
</div>
|
||||
<span class="order-route__arrow">→</span>
|
||||
<div class="order-route__point">
|
||||
<span class="order-route__icon order-route__icon--end">达</span>
|
||||
<span>家兴源食堂</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="order-item__foot">
|
||||
<span class="order-time">13:42 送达 · 准时送达</span>
|
||||
<span class="order-income">5.6km · 38min</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="order-item" onclick="toast('打开订单详情')">
|
||||
<div class="order-item__head">
|
||||
<div>
|
||||
<span class="order-item__num">#DP20260812-0905</span>
|
||||
<span class="type-tag type-tag--store">到店</span>
|
||||
</div>
|
||||
<span class="status-tag status-tag--completed">✓ 已送达</span>
|
||||
</div>
|
||||
<div class="order-route">
|
||||
<div class="order-route__point">
|
||||
<span class="order-route__icon order-route__icon--start">取</span>
|
||||
<span>净菜加工·长安</span>
|
||||
</div>
|
||||
<span class="order-route__arrow">→</span>
|
||||
<div class="order-route__point">
|
||||
<span class="order-route__icon order-route__icon--end">达</span>
|
||||
<span>家兴源·科技路</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="order-item__foot">
|
||||
<span class="order-time">12:18 送达 · 准时</span>
|
||||
<span class="order-income">4.8km · 30min</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 昨日 -->
|
||||
<div class="date-group">
|
||||
<div class="date-group__head">
|
||||
<div class="date-group__title">📅 昨天 (8月11日)</div>
|
||||
<div class="date-group__stat">完成 <strong>11</strong> 单 · 总里程 <strong>32.4km</strong></div>
|
||||
</div>
|
||||
|
||||
<div class="order-item" onclick="toast('打开订单详情')">
|
||||
<div class="order-item__head">
|
||||
<div>
|
||||
<span class="order-item__num">#DP20260811-1922</span>
|
||||
<span class="type-tag type-tag--home">到家</span>
|
||||
</div>
|
||||
<span class="status-tag status-tag--completed">✓ 已送达</span>
|
||||
</div>
|
||||
<div class="order-route">
|
||||
<div class="order-route__point">
|
||||
<span class="order-route__icon order-route__icon--start">取</span>
|
||||
<span>味之都·高新店</span>
|
||||
</div>
|
||||
<span class="order-route__arrow">→</span>
|
||||
<div class="order-route__point">
|
||||
<span class="order-route__icon order-route__icon--end">达</span>
|
||||
<span>紫薇田园都市</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="order-item__foot">
|
||||
<span class="order-time">19:48 送达 · 准时送达</span>
|
||||
<span class="order-income">3.5km · 25min</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="order-item" onclick="toast('打开订单详情')">
|
||||
<div class="order-item__head">
|
||||
<div>
|
||||
<span class="order-item__num">#DP20260811-1438</span>
|
||||
<span class="type-tag type-tag--home">到家</span>
|
||||
</div>
|
||||
<span class="status-tag status-tag--rejected">已拒单</span>
|
||||
</div>
|
||||
<div class="order-route">
|
||||
<div class="order-route__point">
|
||||
<span class="order-route__icon order-route__icon--start">取</span>
|
||||
<span>味之都·高新店</span>
|
||||
</div>
|
||||
<span class="order-route__arrow">→</span>
|
||||
<div class="order-route__point">
|
||||
<span class="order-route__icon order-route__icon--end">达</span>
|
||||
<span>枫林绿洲 6 号楼</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="order-item__foot">
|
||||
<span class="order-time">14:38 拒单 · 理由:车辆故障</span>
|
||||
<span class="order-income order-income--rejected">未配送</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="order-item" onclick="toast('打开订单详情')">
|
||||
<div class="order-item__head">
|
||||
<div>
|
||||
<span class="order-item__num">#DP20260811-1126</span>
|
||||
<span class="type-tag type-tag--store">到店</span>
|
||||
</div>
|
||||
<span class="status-tag status-tag--timeout">超时未响应</span>
|
||||
</div>
|
||||
<div class="order-route">
|
||||
<div class="order-route__point">
|
||||
<span class="order-route__icon order-route__icon--start">取</span>
|
||||
<span>食材配送中心</span>
|
||||
</div>
|
||||
<span class="order-route__arrow">→</span>
|
||||
<div class="order-route__point">
|
||||
<span class="order-route__icon order-route__icon--end">达</span>
|
||||
<span>味之滨餐厅</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="order-item__foot">
|
||||
<span class="order-time">11:26 派单 · 超时 30s 未响应</span>
|
||||
<span class="order-income order-income--rejected">已转派</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 前天 -->
|
||||
<div class="date-group">
|
||||
<div class="date-group__head">
|
||||
<div class="date-group__title">📅 8月10日</div>
|
||||
<div class="date-group__stat">完成 <strong>9</strong> 单 · 总里程 <strong>28.2km</strong></div>
|
||||
</div>
|
||||
|
||||
<div class="order-item" onclick="toast('打开订单详情')">
|
||||
<div class="order-item__head">
|
||||
<div>
|
||||
<span class="order-item__num">#DP20260810-1812</span>
|
||||
<span class="type-tag type-tag--home">到家</span>
|
||||
</div>
|
||||
<span class="status-tag status-tag--completed">✓ 已送达</span>
|
||||
</div>
|
||||
<div class="order-route">
|
||||
<div class="order-route__point">
|
||||
<span class="order-route__icon order-route__icon--start">取</span>
|
||||
<span>中央厨房·高新站</span>
|
||||
</div>
|
||||
<span class="order-route__arrow">→</span>
|
||||
<div class="order-route__point">
|
||||
<span class="order-route__icon order-route__icon--end">达</span>
|
||||
<span>锦业一号楼</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="order-item__foot">
|
||||
<span class="order-time">18:48 送达 · 准时</span>
|
||||
<span class="order-income">0.8km · 8min</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="text-align:center;padding:16px;color:var(--text-tertiary);font-size:12px">
|
||||
· 上拉加载更多历史 ·
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部 Tab -->
|
||||
<div class="tabbar">
|
||||
<a href="01-home.html" class="tab">
|
||||
<span class="tab__icon">🏠</span>
|
||||
<span class="tab__label">首页</span>
|
||||
</a>
|
||||
<a href="03-grab-pool.html" class="tab">
|
||||
<span class="tab__icon">🔥</span>
|
||||
<span class="tab__label">抢单</span>
|
||||
</a>
|
||||
<a href="07-history.html" class="tab active">
|
||||
<span class="tab__icon">📚</span>
|
||||
<span class="tab__label">历史</span>
|
||||
</a>
|
||||
<a href="08-profile.html" class="tab">
|
||||
<span class="tab__icon">👤</span>
|
||||
<span class="tab__label">我的</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="home-indicator"></div>
|
||||
<div class="toast" id="toast"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function toast(msg) {
|
||||
const t = document.getElementById('toast');
|
||||
t.textContent = msg;
|
||||
t.classList.add('show');
|
||||
setTimeout(() => t.classList.remove('show'), 1800);
|
||||
}
|
||||
|
||||
document.querySelectorAll('.tab-item').forEach(t => {
|
||||
t.addEventListener('click', () => {
|
||||
document.querySelectorAll('.tab-item').forEach(i => i.classList.remove('active'));
|
||||
t.classList.add('active');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,539 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>个人中心 | 营养餐品配送</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
:root {
|
||||
--primary: #ff6d3a;
|
||||
--primary-dark: #e85a28;
|
||||
--primary-light: #fff0e8;
|
||||
--text-primary: #1f2937;
|
||||
--text-secondary: #6b7280;
|
||||
--text-tertiary: #9ca3af;
|
||||
--border: #e5e7eb;
|
||||
--background: #f6f8fb;
|
||||
--white: #ffffff;
|
||||
--success: #10b981;
|
||||
--info: #3b82f6;
|
||||
--warn: #f59e0b;
|
||||
--shadow-sm: 0 2px 8px rgba(15, 23, 42, 0.06);
|
||||
--shadow-md: 0 10px 28px rgba(15, 23, 42, 0.10);
|
||||
}
|
||||
body {
|
||||
min-height: 100vh;
|
||||
padding: 24px 0 40px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
background: #2a2a2a;
|
||||
color: var(--text-primary);
|
||||
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", sans-serif;
|
||||
}
|
||||
.phone-shell {
|
||||
position: relative;
|
||||
width: 375px;
|
||||
height: 812px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--background);
|
||||
border-radius: 44px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3), inset 0 0 0 2px #e0e0e0;
|
||||
}
|
||||
.status-bar {
|
||||
height: 44px;
|
||||
padding: 0 24px;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
background: linear-gradient(135deg, var(--primary), var(--primary-dark));
|
||||
}
|
||||
.status-bar__time { font-size: 15px; font-weight: 700; }
|
||||
.status-bar__icons { display: flex; align-items: center; gap: 6px; }
|
||||
.status-bar__signal { width:18px;height:10px;background:#fff;clip-path: polygon(0 100%, 18% 64%, 18% 100%, 36% 42%, 36% 100%, 54% 24%, 54% 100%, 72% 8%, 72% 100%, 100% 0, 100% 100%); }
|
||||
.status-bar__wifi { width:16px;height:12px;background:#fff;clip-path: polygon(0 50%, 50% 0, 100% 50%, 86% 60%, 50% 22%, 14% 60%); }
|
||||
.status-bar__battery { width:24px;height:12px;border:1.5px solid #fff;border-radius:3px;position:relative;padding:1.5px;}
|
||||
.status-bar__battery::after { content:'';display:block;width:70%;height:100%;background:#fff;border-radius:1px;}
|
||||
.status-bar__battery::before { content:'';position:absolute;right:-3px;top:3px;width:2px;height:6px;background:#fff;border-radius:0 1px 1px 0;}
|
||||
|
||||
.scroll-area {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding-bottom: 90px;
|
||||
}
|
||||
.scroll-area::-webkit-scrollbar { display: none; }
|
||||
|
||||
/* 用户信息卡 */
|
||||
.profile-card {
|
||||
background: linear-gradient(135deg, var(--primary), var(--primary-dark));
|
||||
color: white;
|
||||
padding: 12px 20px 30px;
|
||||
position: relative;
|
||||
}
|
||||
.profile-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
padding: 4px 0 18px;
|
||||
}
|
||||
.profile-avatar {
|
||||
width: 64px; height: 64px;
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
border: 3px solid rgba(255, 255, 255, 0.5);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 30px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.profile-info { flex: 1; }
|
||||
.profile-name {
|
||||
font-size: 19px;
|
||||
font-weight: 700;
|
||||
margin-bottom: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.profile-level {
|
||||
background: linear-gradient(135deg, #fbbf24, #f59e0b);
|
||||
color: #78350f;
|
||||
padding: 2px 8px;
|
||||
border-radius: 10px;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.profile-meta {
|
||||
font-size: 12px;
|
||||
opacity: 0.9;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.profile-meta-item {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.setting-entry {
|
||||
width: 36px; height: 36px;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 18px;
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* 收益统计 */
|
||||
.income-card {
|
||||
background: white;
|
||||
margin: -22px 16px 0;
|
||||
padding: 16px;
|
||||
border-radius: 14px;
|
||||
box-shadow: var(--shadow-md);
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
.income-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
.income-title {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
.income-detail {
|
||||
font-size: 12px;
|
||||
color: var(--primary);
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
}
|
||||
.income-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 4px;
|
||||
text-align: center;
|
||||
}
|
||||
.income-item__num {
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: var(--primary);
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.income-item__label {
|
||||
font-size: 11px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
/* 接单状态 */
|
||||
.work-status {
|
||||
background: white;
|
||||
margin: 12px 16px 0;
|
||||
border-radius: 14px;
|
||||
padding: 14px;
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
.work-status__head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.work-status__title {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.online-tag {
|
||||
font-size: 11px;
|
||||
padding: 2px 8px;
|
||||
border-radius: 10px;
|
||||
background: #d1fae5;
|
||||
color: #065f46;
|
||||
font-weight: 600;
|
||||
}
|
||||
.work-status__row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 6px 0;
|
||||
font-size: 13px;
|
||||
}
|
||||
.work-status__label { color: var(--text-secondary); }
|
||||
.work-status__value { font-weight: 600; }
|
||||
|
||||
/* 设置组 */
|
||||
.menu-group {
|
||||
background: white;
|
||||
margin: 12px 16px 0;
|
||||
border-radius: 14px;
|
||||
overflow: hidden;
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
.menu-group__title {
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
padding: 14px 16px 8px;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
.menu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 14px 16px;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
border-bottom: 1px solid var(--background);
|
||||
transition: background 0.2s;
|
||||
}
|
||||
.menu-item:last-child { border-bottom: none; }
|
||||
.menu-item:active { background: var(--background); }
|
||||
.menu-icon {
|
||||
width: 32px; height: 32px;
|
||||
border-radius: 8px;
|
||||
background: var(--primary-light);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
margin-right: 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.menu-icon--blue { background: #dbeafe; }
|
||||
.menu-icon--green { background: #d1fae5; }
|
||||
.menu-icon--yellow { background: #fef3c7; }
|
||||
.menu-icon--purple { background: #f3e8ff; }
|
||||
.menu-icon--gray { background: #f3f4f6; }
|
||||
|
||||
.menu-content {
|
||||
flex: 1;
|
||||
}
|
||||
.menu-label {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.menu-desc {
|
||||
font-size: 11px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
.menu-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
.menu-value {
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
.menu-arrow {
|
||||
color: var(--text-tertiary);
|
||||
font-size: 18px;
|
||||
}
|
||||
.menu-badge {
|
||||
background: var(--primary);
|
||||
color: white;
|
||||
padding: 1px 6px;
|
||||
border-radius: 8px;
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Switch */
|
||||
.switch {
|
||||
width: 44px; height: 24px;
|
||||
background: #d1d5db;
|
||||
border-radius: 12px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
.switch.on { background: var(--primary); }
|
||||
.switch::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 20px; height: 20px;
|
||||
background: white;
|
||||
border-radius: 50%;
|
||||
top: 2px; left: 2px;
|
||||
transition: left 0.3s;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
|
||||
}
|
||||
.switch.on::after { left: 22px; }
|
||||
|
||||
/* 底部 Tab */
|
||||
.tabbar {
|
||||
position: absolute;
|
||||
bottom: 0; left: 0; right: 0;
|
||||
height: 70px;
|
||||
background: white;
|
||||
border-top: 1px solid var(--border);
|
||||
display: flex;
|
||||
padding: 8px 0 20px;
|
||||
}
|
||||
.tab {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 2px;
|
||||
text-decoration: none;
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
.tab.active { color: var(--primary); }
|
||||
.tab__icon { font-size: 22px; }
|
||||
.tab__label { font-size: 10px; font-weight: 600; }
|
||||
|
||||
.home-indicator {
|
||||
position: absolute;
|
||||
bottom: 8px; left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 134px; height: 5px;
|
||||
background: #1f2937;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.toast {
|
||||
position: absolute;
|
||||
top: 60px; left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
color: white;
|
||||
padding: 8px 16px;
|
||||
border-radius: 20px;
|
||||
font-size: 13px;
|
||||
z-index: 100;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
pointer-events: none;
|
||||
}
|
||||
.toast.show { opacity: 1; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
<div class="status-bar">
|
||||
<span class="status-bar__time">9:41</span>
|
||||
<div class="status-bar__icons">
|
||||
<span class="status-bar__signal"></span>
|
||||
<span class="status-bar__wifi"></span>
|
||||
<span class="status-bar__battery"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="scroll-area">
|
||||
<!-- 用户信息 -->
|
||||
<div class="profile-card">
|
||||
<div class="profile-top">
|
||||
<div class="profile-avatar">🧑🦱</div>
|
||||
<div class="profile-info">
|
||||
<div class="profile-name">
|
||||
陈师傅
|
||||
</div>
|
||||
<div class="profile-meta">
|
||||
<span class="profile-meta-item">工号:RDR-2026</span>
|
||||
<span class="profile-meta-item">📱 138****6688</span><br>
|
||||
<span class="profile-meta-item">📍 高新站 · 接单评分 4.9</span>
|
||||
</div>
|
||||
</div>
|
||||
<a href="javascript:void(0)" class="setting-entry" onclick="toast('打开设置')">⚙️</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 工作量统计 -->
|
||||
<div class="income-card">
|
||||
<div class="income-head">
|
||||
<div class="income-title">📊 工作统计</div>
|
||||
<a href="07-history.html" class="income-detail" onclick="toast('查看配送明细')">查看明细 ›</a>
|
||||
</div>
|
||||
<div class="income-grid">
|
||||
<div>
|
||||
<div class="income-item__num">8</div>
|
||||
<div class="income-item__label">今日单数</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="income-item__num">186</div>
|
||||
<div class="income-item__label">本月单数</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="income-item__num">486km</div>
|
||||
<div class="income-item__label">本月里程</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 工作状态 -->
|
||||
<div class="work-status">
|
||||
<div class="work-status__head">
|
||||
<div class="work-status__title">🛵 接单状态</div>
|
||||
<span class="online-tag">● 在线中</span>
|
||||
</div>
|
||||
<div class="work-status__row">
|
||||
<span class="work-status__label">今日在线时长</span>
|
||||
<span class="work-status__value">3h 24min</span>
|
||||
</div>
|
||||
<div class="work-status__row">
|
||||
<span class="work-status__label">本周接单数</span>
|
||||
<span class="work-status__value">56 单 · 准时率 98%</span>
|
||||
</div>
|
||||
<div class="work-status__row">
|
||||
<span class="work-status__label">拒单次数(本周)</span>
|
||||
<span class="work-status__value" style="color:#ef4444">2 次</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 接单设置 -->
|
||||
<div class="menu-group">
|
||||
<div class="menu-group__title">接单设置</div>
|
||||
<a href="javascript:void(0)" class="menu-item" onclick="toast('打开派单偏好')">
|
||||
<div class="menu-icon">📌</div>
|
||||
<div class="menu-content">
|
||||
<div class="menu-label">派单偏好</div>
|
||||
<div class="menu-desc">自动接单距离 / 偏好订单类型</div>
|
||||
</div>
|
||||
<div class="menu-right">
|
||||
<span class="menu-value">3km 内</span>
|
||||
<span class="menu-arrow">›</span>
|
||||
</div>
|
||||
</a>
|
||||
<div class="menu-item">
|
||||
<div class="menu-icon menu-icon--yellow">🔔</div>
|
||||
<div class="menu-content">
|
||||
<div class="menu-label">派单声音提醒</div>
|
||||
<div class="menu-desc">派单到达时响铃 + 震动</div>
|
||||
</div>
|
||||
<div class="menu-right">
|
||||
<div class="switch on" onclick="toggleSwitch(this)"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 其他 -->
|
||||
<div class="menu-group">
|
||||
<div class="menu-group__title">其他</div>
|
||||
<a href="javascript:void(0)" class="menu-item" onclick="toast('打开车辆信息')">
|
||||
<div class="menu-icon">🛵</div>
|
||||
<div class="menu-content">
|
||||
<div class="menu-label">我的车辆</div>
|
||||
<div class="menu-desc">陕A·9F8K2 · 电动车 · 续航 80km</div>
|
||||
</div>
|
||||
<div class="menu-right">
|
||||
<span class="menu-arrow">›</span>
|
||||
</div>
|
||||
</a>
|
||||
<a href="javascript:void(0)" class="menu-item" onclick="toast('打开帮助中心')">
|
||||
<div class="menu-icon menu-icon--gray">❓</div>
|
||||
<div class="menu-content">
|
||||
<div class="menu-label">帮助中心</div>
|
||||
<div class="menu-desc">常见问题 · 配送指南</div>
|
||||
</div>
|
||||
<div class="menu-right">
|
||||
<span class="menu-arrow">›</span>
|
||||
</div>
|
||||
</a>
|
||||
<a href="00-login.html" class="menu-item">
|
||||
<div class="menu-icon menu-icon--gray">🚪</div>
|
||||
<div class="menu-content">
|
||||
<div class="menu-label">退出登录</div>
|
||||
<div class="menu-desc">切换账号或下线</div>
|
||||
</div>
|
||||
<div class="menu-right">
|
||||
<span class="menu-arrow">›</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div style="text-align:center;padding:20px;color:var(--text-tertiary);font-size:11px">
|
||||
营养管理餐品配送端 v1.0.0<br>
|
||||
© 2026 寰汐营养管理
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部 Tab -->
|
||||
<div class="tabbar">
|
||||
<a href="01-home.html" class="tab">
|
||||
<span class="tab__icon">🏠</span>
|
||||
<span class="tab__label">首页</span>
|
||||
</a>
|
||||
<a href="03-grab-pool.html" class="tab">
|
||||
<span class="tab__icon">🔥</span>
|
||||
<span class="tab__label">抢单</span>
|
||||
</a>
|
||||
<a href="07-history.html" class="tab">
|
||||
<span class="tab__icon">📚</span>
|
||||
<span class="tab__label">历史</span>
|
||||
</a>
|
||||
<a href="08-profile.html" class="tab active">
|
||||
<span class="tab__icon">👤</span>
|
||||
<span class="tab__label">我的</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="home-indicator"></div>
|
||||
<div class="toast" id="toast"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function toast(msg) {
|
||||
const t = document.getElementById('toast');
|
||||
t.textContent = msg;
|
||||
t.classList.add('show');
|
||||
setTimeout(() => t.classList.remove('show'), 1800);
|
||||
}
|
||||
function toggleSwitch(el) {
|
||||
el.classList.toggle('on');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,141 @@
|
||||
# 营养管理餐品配送 H5 模块变更日志
|
||||
|
||||
## 2026-08-12 · 工作台与个人中心简化(第四版)
|
||||
|
||||
### 优化
|
||||
- **`01-home.html` 取货中订单按钮简化**:移除"扫码取货"按钮(溯源码扫描暂不进入业务路径),保留两个核心操作:
|
||||
- 「📞 联系客户」(ghost 样式,呼叫商家/客户)
|
||||
- 「到店报到」(primary 样式,通知商家准备)
|
||||
- **`08-profile.html` 接单设置精简**:由 5 项裁剪为 2 项,仅保留:
|
||||
- 「派单偏好」(自动接单距离 / 偏好订单类型)
|
||||
- 「派单声音提醒」(响铃 + 震动开关)
|
||||
- 移除项:服务范围 / 配送类型 / 夜间免打扰
|
||||
- **`08-profile.html` 车辆与装备栏目整体去除**:移除「我的车辆 / 保温箱装备 / 工作服装备」整组菜单
|
||||
- **`08-profile.html` 其他栏目重组**:由 4 项裁剪为 3 项:
|
||||
- 「我的车辆」(从原"车辆与装备"栏目迁入,陕A·9F8K2 · 电动车 · 续航 80km)
|
||||
- 「帮助中心」(常见问题 · 配送指南)
|
||||
- 「退出登录」(切换账号或下线)
|
||||
- 移除项:配送员培训 / 联系客服
|
||||
|
||||
### 业务约定更新
|
||||
- 取货环节不再要求扫码溯源,改由商家在到店报到环节确认餐品交接
|
||||
- 个人中心聚焦核心配送设置,装备类信息后续如有需要再单独建模
|
||||
- 客服联系与培训入口暂不上线,引导至帮助中心自助解决
|
||||
|
||||
---
|
||||
|
||||
## 2026-08-12 · 配送员称谓统一与等级标签清理(第三版)
|
||||
|
||||
### 优化
|
||||
- **称谓统一**:由于后续可能采用机动车/汽车配送而非仅电动自行车,所有页面"骑手"统一改为"配送员",去除等级化标签
|
||||
- `00-login.html`:页面标题 "骑手登录" → "配送员登录";副标题 "骑手端" → "配送员端";协议名 "《骑手服务协议》" → "《配送员服务协议》"
|
||||
- `01-home.html`:删除 `rider-meta` 中的 `金牌骑手` 等级徽标,改为只显示在线时长;CSS 注释 "顶部骑手信息" → "顶部配送员信息"
|
||||
- `08-profile.html`:删除 `profile-level` 中的 `🏅 金牌骑手` 等级标签;菜单项 "骑手培训" → "配送员培训";页脚 "营养餐品配送骑手端" → "营养管理餐品配送端"
|
||||
- 根 `index.html` SITE_MAP:"骑手登录" → "配送员登录"
|
||||
- CHANGELOG 中所有 "骑手" 措辞同步改为 "配送员"
|
||||
|
||||
### 业务约定更新
|
||||
- 配送员可能使用电动自行车、机动车、汽车等多种配送工具,UI 不预设具体配送方式
|
||||
- 不再使用 "金牌骑手/银牌骑手" 等级化标签,避免等级体系与实际运营模式不符
|
||||
|
||||
---
|
||||
|
||||
## 2026-08-12 · 模块初始化与运营模式调整(第二版)
|
||||
|
||||
### 优化
|
||||
- **模块名称**:由"营养餐品配送"统一改为"营养管理餐品配送",对齐营养管理业务域
|
||||
- **入口直连**:删除二级导航页 `index.html`,从根导航卡片点击直接进入小程序主页 `01-home.html`,其余 8 个页面在小程序内串联跳转
|
||||
- **配送模式调整**:本模块为自营配送,配送员为内部员工,暂不使用计件工资,所有页面去除收益/余额/提现相关元素:
|
||||
- `01-home.html`:今日数据卡 "今日收益" 改为 "在线时长";快捷功能 "立即提现" 改为 "工作统计"
|
||||
- `02-dispatch-incoming.html`:订单摘要 "预估收益" 改为 "配送距离"
|
||||
- `03-grab-pool.html`:5 张订单 "预估收益" 全部改为 "配送距离";筛选标签 "高收益" 改为 "长距离";订单标记 "💰 高" 改为 "📦 大"
|
||||
- `04-order-detail.html`:餐品清单移除金额列;订单信息卡移除 "餐品总额 / 配送费 / 配送员收益" 三行,补充 "餐品份数 / 配送距离 / 预计时长 / 收货方式" 工作量字段
|
||||
- `05-delivering.html`:概览卡 "配送收益 ¥15.8" 改为 "配送距离 2.6km";底部按钮文案改为 "已到达 · 验证码签收"
|
||||
- `07-history.html`:顶部汇总 "本月收益" 改为 "总里程";三个日期分组头部 "收益 ¥xxx" 改为 "总里程 xxxkm";每单右侧 "+¥xx" 改为 "x.xkm · xmin" 工作量标签;拒单/超时单 "无收益" 改为 "未配送"
|
||||
- `08-profile.html`:钱包卡 "💰 我的钱包" 改为 "📊 工作统计";三项指标由 "今日收益 / 本月收益 / 可提现" 改为 "今日单数 / 本月单数 / 本月里程"
|
||||
|
||||
### 重构
|
||||
- **送达签收页 `06-finish-sign.html` 重构为验证码收货**:
|
||||
- 移除手写签名区与 SVG 签名组件
|
||||
- 新增 **6 位验证码输入框**:六宫格独立输入,支持自动跳格 / 退格回跳 / 粘贴整段填充
|
||||
- 验证码由系统在下单时发送至客户手机,配送员到达后向客户索取,可点击 "发送验证码" 重新获取或 "联系客户" 拨打电话索取
|
||||
- **送达按钮锁定**:6 位验证码全部填写前,"确认送达" 按钮置灰禁用,全部填写后按钮文案变为 "✓ 确认送达"
|
||||
- 验证码 5 分钟内有效,失效需重新发送
|
||||
- 收益结算卡移除,改为 "本次工作量" 列表:餐品数量 / 配送距离 / 配送时长 / 送达时间 + 本次完成 1 单
|
||||
- 成功弹窗去除金额,改为工作量统计(餐品 / 距离 / 时长)+ 准时提示
|
||||
|
||||
### 业务约定更新
|
||||
- **配送模式**:自营配送,内部员工,不涉及计件工资与收益结算
|
||||
- **工作量度量**:仅记录 单数 / 里程 / 时长 / 准时率 / 客户评分
|
||||
- **收货流程**:客户手机接收 6 位验证码 → 配送员到达后索取 → 输入验证码 → 系统校验通过 → 确认送达
|
||||
- **拒单仍保留五选项**:车辆故障/个人原因/距离过远/已接其他单/其他(影响派单评分,不影响工资)
|
||||
|
||||
---
|
||||
|
||||
## 2026-08-12 · 模块初始化(首版)
|
||||
|
||||
### 新增
|
||||
|
||||
|
||||
### 新增
|
||||
- 模块导航页 `index.html`:9 个页面入口 + 状态色编码图例
|
||||
- 配送员登录页 `00-login.html`:手机号 + 验证码 + 微信一键登录 + 协议勾选 + 60s 倒计时
|
||||
- 工作台首页 `01-home.html`:
|
||||
- 在线状态开关(可切换上线/下线)
|
||||
- 今日数据卡片(完成/收益/进行中/里程)
|
||||
- **派单提醒横幅**(脉冲动画 + 响铃图标,点击进入派单接听)
|
||||
- 进行中订单卡片(配送中 + 取货中两种状态)
|
||||
- 快捷功能入口(抢单大厅/历史/提现/设置)
|
||||
- **派单接听核心页 `02-dispatch-incoming.html`**(派单流程主线):
|
||||
- 全屏红色脉冲背景 + 响铃动效(三轮波纹)
|
||||
- **30s 倒计时圆环**(SVG 实现,超时自动拒接)
|
||||
- 订单摘要卡片(取货/配送路线 + 餐品/收益/时限)
|
||||
- 接受/拒绝双按钮
|
||||
- 拒单理由弹窗(车辆故障/个人原因/距离过远/已接其他单/其他)
|
||||
- 抢单大厅 `03-grab-pool.html`(辅线):
|
||||
- 5 条公共订单池(到家 + 到店两种类型)
|
||||
- 筛选 pill(全部/到家/到店/附近/高收益)
|
||||
- 一键抢单按钮 + 倒计时标签
|
||||
- 急单/高收益标记
|
||||
- 订单详情 `04-order-detail.html`:
|
||||
- 4 步进度条(接单/取货/配送/送达)
|
||||
- 完整路线(取货点 + 配送点 + 联系按钮)
|
||||
- 餐品清单(含溯源码校验提示)
|
||||
- 订单信息(派单方式/时间/收益)
|
||||
- 客户备注卡片
|
||||
- 配送中 `05-delivering.html`:
|
||||
- 模拟地图区(网格 + 道路 + 三点标记 + 路线虚线)
|
||||
- 浮窗信息(距离/ETA)
|
||||
- 4 步配送进度(已完成 2 步 + 进行中 + 待完成)
|
||||
- 客户联系(电话 + 短信)
|
||||
- 异常上报按钮
|
||||
- 送达签收 `06-finish-sign.html`:
|
||||
- 拍照留证(3 卡槽,已拍照占位)
|
||||
- 客户签名(SVG 路径模拟,支持清除 + 改用验证码)
|
||||
- 5 星评价 + 多选标签 + 文本备注
|
||||
- 收益结算明细(基础费 + 距离补贴 + 准时奖励)
|
||||
- 完成成功弹窗(收益 + 提前送达提示)
|
||||
- 历史订单 `07-history.html`:
|
||||
- 顶部本月汇总(单数/收益/准时率/评分)
|
||||
- 4 个 Tab(全部/已完成/已拒单/超时)
|
||||
- 按日期分组展示(今日/昨日/前天)
|
||||
- 订单卡片含路线缩略图 + 状态徽标 + 收益
|
||||
- 个人中心 `08-profile.html`:
|
||||
- 用户信息卡(头像/姓名/金牌骑手等级/工号/电话)
|
||||
- 钱包卡片(今日/本月/可提现)
|
||||
- 接单状态(在线时长/接单数/拒单数)
|
||||
- 接单设置(派单偏好/服务范围/配送类型/声音/夜间免打扰)
|
||||
- 车辆装备(车辆/保温箱/工作服)
|
||||
- 其他(培训/客服/帮助/退出)
|
||||
|
||||
### 设计令牌
|
||||
- 主色:`#ff6d3a`(配送橙红,区别于小程序绿色)
|
||||
- 状态色:已派单(橙)/已接受(蓝)/取货中(青)/配送中(紫)/已送达(绿)/已拒单(灰)/超时(虚灰)
|
||||
- 画布:375 × 812 iPhone 手机外壳(对齐 mini-program 设计)
|
||||
|
||||
### 业务约定
|
||||
- **派单流程为主线**:调度中心主动派单 → 骑手 30s 内响铃接听 → 接受/拒绝(拒绝需填理由) → 进入配送流程
|
||||
- **抢单流程为辅线**:用于派单被拒、临时增补运力场景,骑手在大厅主动挑选订单
|
||||
- **配送场景区分**:到家(C 端,蓝色标签) / 到店(B 端,黄色标签)
|
||||
- **状态徽标七态**:已派单/已接受/取货中/配送中/已送达/已拒单/超时未响应,跨页配色一致
|
||||
- **拒单理由五选项**:车辆故障/个人原因/距离过远/已接其他单/其他,数据沉淀用于评分
|
||||
Reference in New Issue
Block a user