From e47a3958fbfa863d16624bafe61ba1053326dfbe Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 27 Jul 2026 13:34:30 +0800 Subject: [PATCH] =?UTF-8?q?feat(orders):=20redesign=20detail=20modal=20?= =?UTF-8?q?=E2=80=94=20hero=20pill,=20no=20duplicate=20close?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove bottom "关闭" button so the top-right ✕ is the single dismiss. - Drop redundant 订单类型 row from modal body (already shown as card chip). - Add hero strip with status pill + amount; unify dt/dd rows into a bordered card; tighten items list and add timeline rail. - Refresh modal styling: rounded dialog, gradient header, hover-lift buttons, mobile-friendly rows. --- assets/css/routes/orders.css | 279 ++++++++++++++++++++++++++++++++--- assets/js/order-center.js | 46 ++++-- 2 files changed, 287 insertions(+), 38 deletions(-) diff --git a/assets/css/routes/orders.css b/assets/css/routes/orders.css index 97fe8533..52157e87 100644 --- a/assets/css/routes/orders.css +++ b/assets/css/routes/orders.css @@ -524,20 +524,135 @@ /* Order detail modal content */ .aksrt-order-detail-dialog { width: min(560px, 100%); + border-radius: 18px; + overflow: hidden; + background: + linear-gradient(180deg, color-mix(in srgb, var(--color-primary, #3b82f6) 6%, var(--surface-1, #fff)) 0%, var(--surface-1, #fff) 64px); +} + +.aksrt-order-detail-dialog .aksrt-modal__header { + background: transparent; + border-bottom: none; + padding: 18px 20px 12px; +} + +.aksrt-order-detail-dialog .aksrt-modal__header h3 { + font-size: 17px; + letter-spacing: 0.01em; +} + +.aksrt-order-detail-dialog .aksrt-modal__close { + background: color-mix(in srgb, var(--surface-2, #f3f4f6) 70%, transparent); +} + +.aksrt-order-detail-dialog .aksrt-modal__body { + padding: 0 20px 18px; + gap: 18px; +} + +.aksrt-order-detail__hero { + position: relative; + margin: 0 -20px 0; + padding: 14px 20px 18px; + background: + radial-gradient(circle at 100% 0%, color-mix(in srgb, var(--color-primary, #3b82f6) 12%, transparent) 0%, transparent 60%), + linear-gradient(180deg, color-mix(in srgb, var(--color-primary, #3b82f6) 8%, var(--surface-1, #fff)) 0%, transparent 100%); + border-bottom: 1px solid color-mix(in srgb, var(--color-line, #e5e7eb) 70%, transparent); +} + +.aksrt-order-detail__hero-main { + display: grid; + grid-template-columns: auto 1fr; + grid-template-rows: auto auto; + column-gap: 12px; + row-gap: 2px; + align-items: center; +} + +.aksrt-order-detail__status-pill { + grid-column: 1; + grid-row: 1; + justify-self: start; + display: inline-flex; + align-items: center; + padding: 4px 12px; + border-radius: 999px; + font-size: 12px; + font-weight: 700; + letter-spacing: 0.02em; + background: color-mix(in srgb, var(--color-primary, #3b82f6) 14%, transparent); + color: var(--color-primary, #3b82f6); +} + +.aksrt-order-detail__status-pill.is-pending, +.aksrt-order-detail__status-pill.is-created { + background: color-mix(in srgb, var(--color-warning, #d97706) 14%, transparent); + color: var(--color-warning, #d97706); +} + +.aksrt-order-detail__status-pill.is-paid, +.aksrt-order-detail__status-pill.is-delivered, +.aksrt-order-detail__status-pill.is-completed { + background: color-mix(in srgb, var(--color-success, #16a34a) 14%, transparent); + color: var(--color-success, #16a34a); +} + +.aksrt-order-detail__status-pill.is-cancelled, +.aksrt-order-detail__status-pill.is-expired, +.aksrt-order-detail__status-pill.is-refunded, +.aksrt-order-detail__status-pill.is-refunding { + background: color-mix(in srgb, var(--color-ink-3, #8b8f97) 14%, transparent); + color: var(--color-ink-3, #8b8f97); +} + +.aksrt-order-detail__status-pill.is-pending-review { + background: color-mix(in srgb, var(--color-warning, #d97706) 14%, transparent); + color: var(--color-warning, #d97706); +} + +.aksrt-order-detail__hero-amount { + grid-column: 2; + grid-row: 1; + text-align: right; + font-size: 22px; + font-weight: 800; + color: var(--color-error, #ef4444); + font-variant-numeric: tabular-nums; + letter-spacing: -0.01em; +} + +.aksrt-order-detail__hero-label { + grid-column: 1 / -1; + grid-row: 2; + font-size: 12px; + color: var(--color-ink-3, #8b8f97); + margin-top: 8px; + letter-spacing: 0.02em; } .aksrt-order-detail__list { margin: 0; + padding: 4px 0 0; display: grid; - gap: 10px; + gap: 0; + border-radius: 12px; + background: var(--surface-1, #fff); + border: 1px solid color-mix(in srgb, var(--color-line, #e5e7eb) 88%, transparent); + overflow: hidden; } .aksrt-order-detail__row { display: grid; grid-template-columns: 96px minmax(0, 1fr); gap: 10px 14px; - align-items: start; + align-items: center; + padding: 12px 14px; font-size: 13.5px; + border-bottom: 1px solid color-mix(in srgb, var(--color-line, #e5e7eb) 70%, transparent); +} + +.aksrt-order-detail__row:last-child { + border-bottom: none; } .aksrt-order-detail__row dt { @@ -552,21 +667,35 @@ font-weight: 600; word-break: break-all; font-variant-numeric: tabular-nums; + text-align: right; } .aksrt-order-detail__items, .aksrt-order-detail__timeline { - margin-top: 16px; - padding-top: 14px; - border-top: 1px dashed color-mix(in srgb, var(--color-line, #e5e7eb) 85%, transparent); + margin: 0; + padding: 0; + border: none; } .aksrt-order-detail__items h4, .aksrt-order-detail__timeline h4 { margin: 0 0 10px; - font-size: 13.5px; + font-size: 13px; font-weight: 700; color: var(--color-ink, #1f2329); + display: flex; + align-items: center; + gap: 6px; +} + +.aksrt-order-detail__items h4::before, +.aksrt-order-detail__timeline h4::before { + content: ""; + width: 3px; + height: 14px; + border-radius: 2px; + background: var(--color-primary, #3b82f6); + display: inline-block; } .aksrt-order-detail__items ul, @@ -578,37 +707,110 @@ gap: 8px; } +.aksrt-order-detail__items ul { + border-radius: 12px; + background: var(--surface-1, #fff); + border: 1px solid color-mix(in srgb, var(--color-line, #e5e7eb) 88%, transparent); + overflow: hidden; +} + .aksrt-order-detail__items li { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; gap: 10px; align-items: center; + padding: 10px 14px; font-size: 13px; color: var(--color-ink-2, #4b5563); + border-bottom: 1px solid color-mix(in srgb, var(--color-line, #e5e7eb) 70%, transparent); } -.aksrt-order-detail__items li em { +.aksrt-order-detail__items li:last-child { + border-bottom: none; +} + +.aksrt-order-detail__item-title { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.aksrt-order-detail__item-qty { font-style: normal; color: var(--color-ink-3, #8b8f97); -} - -.aksrt-order-detail__items li strong { - font-weight: 700; - color: var(--color-ink, #1f2329); font-variant-numeric: tabular-nums; } +.aksrt-order-detail__item-price { + font-weight: 700; + color: var(--color-ink, #1f2329); + font-variant-numeric: tabular-nums; + min-width: 72px; + text-align: right; +} + +.aksrt-order-detail__timeline ol { + position: relative; + padding-left: 16px; + gap: 10px; +} + +.aksrt-order-detail__timeline ol::before { + content: ""; + position: absolute; + left: 5px; + top: 6px; + bottom: 6px; + width: 2px; + border-radius: 2px; + background: color-mix(in srgb, var(--color-line, #e5e7eb) 90%, transparent); +} + .aksrt-order-detail__timeline li { + position: relative; + display: grid; + grid-template-columns: 1fr; + gap: 2px; + font-size: 13px; + color: var(--color-ink-2, #4b5563); + padding: 2px 0; +} + +.aksrt-order-detail__timeline-dot { + position: absolute; + left: -16px; + top: 7px; + width: 10px; + height: 10px; + border-radius: 50%; + background: var(--color-primary, #3b82f6); + box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-primary, #3b82f6) 14%, transparent); +} + +.aksrt-order-detail__timeline li:first-child .aksrt-order-detail__timeline-dot { + background: var(--color-success, #16a34a); + box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-success, #16a34a) 14%, transparent); +} + +.aksrt-order-detail__timeline-body { display: grid; grid-template-columns: 140px minmax(0, 1fr); gap: 10px; - font-size: 12.5px; - color: var(--color-ink-2, #4b5563); + align-items: baseline; } .aksrt-order-detail__timeline time { color: var(--color-ink-3, #8b8f97); font-variant-numeric: tabular-nums; + font-size: 12.5px; +} + +.aksrt-order-detail-dialog .aksrt-modal__footer { + padding: 16px 20px 18px; + background: color-mix(in srgb, var(--surface-2, #f6f7f9) 65%, transparent); + border-top: 1px solid color-mix(in srgb, var(--color-line, #e5e7eb) 70%, transparent); + gap: 8px; } .aksrt-modal__footer .btn-primary, @@ -616,27 +818,35 @@ .aksrt-modal__footer .btn-ghost, .aksrt-modal__footer a.btn-ghost, .aksrt-modal__footer a.btn-outline { - min-height: 34px; - padding: 0 14px; - border-radius: 999px; - font-size: 13px; + min-height: 36px; + padding: 0 18px; + border-radius: 10px; + font-size: 13.5px; font-weight: 600; - line-height: 32px; + line-height: 34px; display: inline-flex; align-items: center; justify-content: center; text-decoration: none; cursor: pointer; + transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease; } .aksrt-modal__footer .btn-primary { border: 1px solid transparent; background: var(--color-primary, #3b82f6); color: var(--color-on-primary, #fff); + box-shadow: 0 6px 16px color-mix(in srgb, var(--color-primary, #3b82f6) 30%, transparent); +} + +.aksrt-modal__footer .btn-primary:hover { + filter: brightness(1.05); + transform: translateY(-1px); } .aksrt-modal__footer .btn-primary.c-green { background: var(--color-success, #16a34a); + box-shadow: 0 6px 16px color-mix(in srgb, var(--color-success, #16a34a) 30%, transparent); } .aksrt-modal__footer .btn-outline { @@ -645,19 +855,39 @@ color: var(--color-ink-2, #4b5563); } +.aksrt-modal__footer .btn-outline:hover { + border-color: var(--color-primary, #3b82f6); + color: var(--color-primary, #3b82f6); + transform: translateY(-1px); +} + .aksrt-modal__footer .btn-ghost { border: 1px solid transparent; background: transparent; color: var(--color-ink-3, #8b8f97); } +.aksrt-modal__footer .btn-ghost:hover { + color: var(--color-ink, #1f2329); + background: color-mix(in srgb, var(--surface-2, #f3f4f6) 80%, transparent); +} + @media (max-width: 767px) { - .aksrt-order-detail__row { - grid-template-columns: 1fr; - gap: 2px; + .aksrt-order-detail-dialog { + border-radius: 16px 16px 0 0; + margin-top: auto; } - .aksrt-order-detail__timeline li { + .aksrt-order-detail__row { + grid-template-columns: 1fr 1fr; + gap: 2px 12px; + } + + .aksrt-order-detail__row dt { + text-align: left; + } + + .aksrt-order-detail__timeline-body { grid-template-columns: 1fr; gap: 2px; } @@ -670,7 +900,8 @@ .aksrt-modal__footer .btn-outline, .aksrt-modal__footer .btn-ghost, .aksrt-modal__footer a { - flex: 1 1 auto; + flex: 1 1 calc(50% - 8px); + min-width: 0; } } diff --git a/assets/js/order-center.js b/assets/js/order-center.js index 24cb862b..a8dc6bba 100644 --- a/assets/js/order-center.js +++ b/assets/js/order-center.js @@ -511,10 +511,12 @@ } if (!qty || qty < 1) qty = 1; + var status = order.status || ""; + var statusLabel = order.status_label || status || "—"; + var statusClass = "is-" + String(status).replace(/[^a-z0-9_-]/gi, "-"); + var rows = [ - ["订单状态", order.status_label || order.status || "—"], ["订单名称", order.product_name || (order.product && order.product.title) || "—"], - ["订单类型", order.product_type_label || order.product_type || "—"], ["订单数量", String(qty)], ["应付金额", formatMoneyText(order)], ["订单编号", order.order_number || "—"], @@ -533,11 +535,19 @@ rows.push(["备注", order.customer_note]); } - var html = '
'; + var html = ""; + html += '
'; + html += '
'; + html += ' ' + escapeHtml(statusLabel) + ""; + html += ' ' + escapeHtml(formatMoneyText(order)) + ""; + html += ' 应付金额'; + html += "
"; + html += "
"; + + html += '
'; rows.forEach(function (row) { html += '
'; html += '
' + escapeHtml(row[0]) + '
'; - // Money strings already composed; still escape all cells for safety. html += '
' + escapeHtml(row[1]) + '
'; html += '
'; }); @@ -549,12 +559,13 @@ var title = item.product_title || item.title || order.product_name || "商品"; var itemQty = item.quantity || item.qty || 1; var price = item.pay_price != null ? item.pay_price : (item.unit_price || 0); - html += '
  • ' + escapeHtml(title) + ''; - html += '×' + escapeHtml(String(itemQty)) + ''; + html += '
  • '; + html += ' ' + escapeHtml(title) + ""; + html += ' ×' + escapeHtml(String(itemQty)) + ''; if (order.is_points) { - html += '' + escapeHtml(order.currency_symbol || "积分") + " " + Math.round(Number(price || 0)) + ""; + html += '' + escapeHtml(order.currency_symbol || "积分") + " " + Math.round(Number(price || 0)) + ""; } else { - html += '¥' + Number(price || 0).toFixed(2) + ""; + html += '¥' + Number(price || 0).toFixed(2) + ""; } html += "
  • "; }); @@ -564,7 +575,11 @@ if (order.timeline && order.timeline.length) { html += '

    订单进度

      '; order.timeline.forEach(function (tl) { - html += '
    1. " + escapeHtml(tl.label || "") + "
    2. "; + html += '
    3. '; + html += '
      '; + html += '"; + html += "" + escapeHtml(tl.label || "") + ""; + html += "
    4. "; }); html += "
    "; } @@ -572,19 +587,20 @@ detailBody.innerHTML = html; var footer = ""; - // Status-aware footer actions. + // Status-aware footer actions. The modal's own ✕ button (top-right) is the only + // dismiss control, so do not add a duplicate "关闭" button here. if (actions.can_cancel) { footer += ''; } - if (actions.can_pay) { - footer += ''; - } if (actions.can_receipt) { footer += ''; } if (actions.can_review) { footer += ''; } + if (actions.can_pay) { + footer += ''; + } if (actions.can_after_sale) { footer += ''; } @@ -597,7 +613,9 @@ if (order.secondary_url && order.secondary_label) { footer += '' + escapeHtml(order.secondary_label) + ""; } - footer += ''; + if (footer === "") { + footer = ''; + } detailFooter.innerHTML = footer; }