+
@@ -57,7 +63,12 @@ export function MobileLayout() {
safeArea
>
{tabs.map(tab => (
-
+
))}
diff --git a/frontend/src/shared/utils/format.ts b/frontend/src/shared/utils/format.ts
index ece36ea..9ee2820 100644
--- a/frontend/src/shared/utils/format.ts
+++ b/frontend/src/shared/utils/format.ts
@@ -21,6 +21,16 @@ export function formatDate(value?: string | null) {
return dayjs(value).format('YYYY-MM-DD')
}
+export function formatRelativeTime(value?: string | null) {
+ if (!value) return EMPTY
+ const target = dayjs(value)
+ const now = dayjs()
+ if (target.isSame(now, 'day')) return target.format('HH:mm')
+ if (target.isSame(now.subtract(1, 'day'), 'day')) return '昨天'
+ if (target.isSame(now, 'year')) return target.format('MM-DD HH:mm')
+ return target.format('YYYY-MM-DD')
+}
+
export function formatNumber(value?: number | null) {
if (value == null || Number.isNaN(value)) return EMPTY
return value.toLocaleString('zh-CN')
diff --git a/frontend/src/styles/global.css b/frontend/src/styles/global.css
index 3bf825b..6132960 100644
--- a/frontend/src/styles/global.css
+++ b/frontend/src/styles/global.css
@@ -1567,6 +1567,10 @@ a {
color: var(--ink);
}
+.mobile-shell--no-tabbar {
+ padding-bottom: 0;
+}
+
.mobile-header {
position: sticky;
top: 0;
@@ -2182,6 +2186,684 @@ a {
margin-top: 18px;
}
+.mobile-orders {
+ padding: 20px 16px 32px;
+}
+
+.mobile-orders__eyebrow {
+ color: var(--brand-seal);
+ font-size: 10px;
+ letter-spacing: 0.18em;
+}
+
+.mobile-orders__head {
+ margin-bottom: 16px;
+}
+
+.mobile-orders__head h1 {
+ margin: 6px 0;
+ color: var(--brand-ink);
+ font-family: 'Noto Serif SC', 'Songti SC', serif;
+ font-size: 28px;
+ letter-spacing: 0.04em;
+}
+
+.mobile-orders__head p {
+ margin: 0;
+ color: var(--ink-muted);
+ font-size: 12px;
+}
+
+.mobile-orders__login {
+ padding: 26px 20px;
+ border: 1px solid var(--line);
+ border-radius: 10px;
+ background: var(--paper-warm);
+ text-align: center;
+}
+
+.mobile-orders__login h2 {
+ margin: 14px 0 6px;
+ color: var(--brand-ink);
+ font-size: 18px;
+}
+
+.mobile-orders__login p {
+ margin: 0 0 18px;
+ color: var(--ink-secondary);
+ font-size: 12px;
+}
+
+.mobile-orders__list {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+ padding-top: 4px;
+}
+
+.mobile-orders__skeleton {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+}
+
+.mobile-orders__empty {
+ padding: 36px 0 10px;
+ text-align: center;
+}
+
+.mobile-orders__empty-link {
+ display: inline-flex;
+ align-items: center;
+ gap: 4px;
+ margin-top: 8px;
+ color: var(--brand-ink);
+ font-size: 12px;
+}
+
+.mobile-orders__more {
+ padding: 6px 0 10px;
+ color: var(--ink-muted);
+ font-size: 11px;
+ text-align: center;
+}
+
+.mobile-order-card {
+ display: block;
+ width: 100%;
+ padding: 16px 16px 14px;
+ border: 1px solid var(--line);
+ border-radius: 10px;
+ background: var(--paper-warm);
+ box-shadow: 0 6px 18px rgba(30, 77, 66, 0.04);
+ text-align: left;
+ transition:
+ transform 0.18s ease,
+ box-shadow 0.18s ease;
+}
+
+.mobile-order-card:active {
+ transform: scale(0.995);
+}
+
+.mobile-order-card--skeleton {
+ cursor: default;
+}
+
+.mobile-order-card__top {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 10px;
+}
+
+.mobile-order-card__no {
+ color: var(--ink-muted);
+ font-family: 'Inter', monospace;
+ font-size: 11px;
+ letter-spacing: 0.04em;
+}
+
+.mobile-order-card__title {
+ margin: 10px 0 8px;
+ color: var(--brand-ink);
+ font-size: 16px;
+ font-weight: 600;
+ line-height: 1.4;
+}
+
+.mobile-order-card__meta {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 6px;
+}
+
+.mobile-order-card__meta span {
+ padding: 2px 8px;
+ border: 1px solid var(--line);
+ border-radius: 999px;
+ color: var(--ink-secondary);
+ font-size: 10px;
+}
+
+.mobile-order-card__bottom {
+ display: flex;
+ align-items: flex-end;
+ justify-content: space-between;
+ margin-top: 12px;
+ padding-top: 10px;
+ border-top: 1px dashed var(--line);
+}
+
+.mobile-order-card__bottom strong {
+ display: block;
+ color: var(--brand-seal);
+ font-family: 'Inter', monospace;
+ font-size: 17px;
+}
+
+.mobile-order-card__bottom small {
+ color: var(--ink-muted);
+ font-size: 10px;
+}
+
+.mobile-order-card__date {
+ display: inline-flex;
+ align-items: center;
+ gap: 4px;
+ color: var(--ink-muted);
+ font-size: 10px;
+}
+
+.mobile-order-detail {
+ padding: 16px 16px 36px;
+}
+
+.mobile-order-detail__back button {
+ display: inline-flex;
+ align-items: center;
+ gap: 4px;
+ padding: 6px 0;
+ border: 0;
+ background: none;
+ color: var(--ink-secondary);
+ font-size: 12px;
+}
+
+.mobile-order-detail__hero {
+ margin-top: 10px;
+ padding: 18px;
+ border-radius: 10px;
+ background: var(--brand-ink);
+ color: #f0f4f2;
+}
+
+.mobile-order-detail__hero-top {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+
+.mobile-order-detail__no {
+ color: #b9cbc3;
+ font-family: 'Inter', monospace;
+ font-size: 11px;
+ letter-spacing: 0.04em;
+}
+
+.mobile-order-detail__hero h1 {
+ margin: 10px 0 12px;
+ color: #f6f2e8;
+ font-size: 20px;
+ line-height: 1.4;
+}
+
+.mobile-order-detail__status {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 14px;
+}
+
+.mobile-order-detail__status-line {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ color: #b9cbc3;
+ font-size: 10px;
+}
+
+.mobile-order-detail__hero-amount {
+ display: flex;
+ align-items: baseline;
+ gap: 10px;
+ margin-top: 16px;
+ padding-top: 12px;
+ border-top: 1px solid rgba(240, 244, 242, 0.16);
+}
+
+.mobile-order-detail__hero-amount strong {
+ color: #e8c9a6;
+ font-family: 'Inter', monospace;
+ font-size: 24px;
+}
+
+.mobile-order-detail__hero-amount span {
+ color: #b9cbc3;
+ font-size: 11px;
+}
+
+.mobile-order-detail__list {
+ margin-top: 12px;
+ overflow: hidden;
+ border: 1px solid var(--line);
+ border-radius: 10px;
+ background: var(--paper-warm);
+ --border-inner: 1px solid var(--line);
+}
+
+.mobile-order-detail__list .adm-list-header {
+ margin: 0;
+ padding: 12px 14px 8px;
+ border-bottom: 1px solid var(--line);
+ background: #faf6ec;
+ color: var(--brand-ink);
+ font-size: 11px;
+ letter-spacing: 0.12em;
+}
+
+.mobile-order-detail__list .adm-list-body {
+ border: 0;
+}
+
+.mobile-order-detail__checkout-content {
+ padding: 6px 0;
+ color: var(--ink-secondary);
+ font-size: 12px;
+ line-height: 1.7;
+ white-space: pre-wrap;
+ word-break: break-word;
+}
+
+.mobile-order-detail__actions {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+ margin-top: 18px;
+}
+
+.mobile-order-detail__back-link {
+ color: var(--ink-muted);
+ font-size: 12px;
+ text-align: center;
+}
+
+.mobile-messages {
+ padding: 20px 16px 32px;
+}
+
+.mobile-messages__eyebrow {
+ color: var(--brand-seal);
+ font-size: 10px;
+ letter-spacing: 0.18em;
+}
+
+.mobile-messages__head {
+ margin-bottom: 12px;
+}
+
+.mobile-messages__head h1 {
+ margin: 6px 0;
+ color: var(--brand-ink);
+ font-family: 'Noto Serif SC', 'Songti SC', serif;
+ font-size: 28px;
+ letter-spacing: 0.04em;
+}
+
+.mobile-messages__head p {
+ margin: 0;
+ color: var(--ink-muted);
+ font-size: 12px;
+}
+
+.mobile-messages__tabs {
+ --title-font-size: 13px;
+ margin-bottom: 10px;
+}
+
+.mobile-messages__panel-actions {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 10px;
+ margin-bottom: 10px;
+}
+
+.mobile-message-list {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+}
+
+.mobile-chat-row {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ width: 100%;
+ padding: 12px 14px;
+ border: 1px solid var(--line);
+ border-radius: 10px;
+ background: var(--paper-warm);
+ text-align: left;
+}
+
+.mobile-chat-row__avatar {
+ display: flex;
+ flex-shrink: 0;
+ align-items: center;
+ justify-content: center;
+ width: 40px;
+ height: 40px;
+ border: 1px solid var(--brand-seal-line);
+ border-radius: 10px;
+ background: #fbf6ec;
+ color: var(--brand-seal);
+ font-family: 'Noto Serif SC', 'Songti SC', serif;
+ font-size: 12px;
+}
+
+.mobile-chat-row__body {
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+ gap: 4px;
+ min-width: 0;
+}
+
+.mobile-chat-row__top {
+ display: flex;
+ justify-content: space-between;
+ gap: 8px;
+}
+
+.mobile-chat-row__top strong {
+ overflow: hidden;
+ color: var(--brand-ink);
+ font-size: 13px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.mobile-chat-row__top small {
+ flex-shrink: 0;
+ color: var(--ink-muted);
+ font-size: 10px;
+}
+
+.mobile-chat-row__preview {
+ overflow: hidden;
+ color: var(--ink-secondary);
+ font-size: 11px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.mobile-chat-row__tail {
+ flex-shrink: 0;
+ color: var(--ink-muted);
+}
+
+.mobile-notice-row {
+ display: flex;
+ gap: 10px;
+ width: 100%;
+ padding: 12px 14px;
+ border: 1px solid var(--line);
+ border-radius: 10px;
+ background: var(--paper-warm);
+ text-align: left;
+}
+
+.mobile-notice-row--unread {
+ border-color: var(--brand-seal-line);
+ background: #fffaf2;
+}
+
+.mobile-notice-row__dot {
+ flex-shrink: 0;
+ width: 6px;
+ height: 6px;
+ margin-top: 6px;
+ border-radius: 50%;
+ background: transparent;
+}
+
+.mobile-notice-row--unread .mobile-notice-row__dot {
+ background: var(--brand-seal);
+}
+
+.mobile-notice-row__body {
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+ gap: 4px;
+ min-width: 0;
+}
+
+.mobile-notice-row__top {
+ display: flex;
+ justify-content: space-between;
+ gap: 8px;
+}
+
+.mobile-notice-row__top strong {
+ color: var(--brand-ink);
+ font-size: 13px;
+}
+
+.mobile-notice-row__top small {
+ flex-shrink: 0;
+ color: var(--ink-muted);
+ font-size: 10px;
+}
+
+.mobile-notice-row__content {
+ display: -webkit-box;
+ overflow: hidden;
+ color: var(--ink-secondary);
+ font-size: 11px;
+ line-height: 1.6;
+ -webkit-box-orient: vertical;
+ -webkit-line-clamp: 2;
+}
+
+.mobile-messages__empty {
+ padding: 30px 10px;
+ text-align: center;
+}
+
+.mobile-messages__empty span {
+ display: block;
+ margin-top: 6px;
+ color: var(--ink-muted);
+ font-size: 11px;
+}
+
+.mobile-chat {
+ display: flex;
+ flex-direction: column;
+ height: calc(100vh - 58px);
+ height: calc(100dvh - 58px);
+}
+
+.mobile-chat__head {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ padding: 10px 12px;
+ border-bottom: 1px solid var(--line);
+ background: var(--paper-warm);
+}
+
+.mobile-chat__back {
+ border: 0;
+ background: none;
+ color: var(--brand-ink);
+ font-size: 16px;
+}
+
+.mobile-chat__title {
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+ gap: 2px;
+ min-width: 0;
+}
+
+.mobile-chat__title strong {
+ overflow: hidden;
+ color: var(--brand-ink);
+ font-size: 14px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.mobile-chat__title span {
+ color: var(--ink-muted);
+ font-size: 10px;
+}
+
+.mobile-chat__head-space {
+ width: 20px;
+}
+
+.mobile-chat__body {
+ flex: 1;
+ padding: 14px 14px 18px;
+ overflow-y: auto;
+ background: var(--paper);
+}
+
+.mobile-chat__earlier {
+ margin-bottom: 10px;
+ text-align: center;
+}
+
+.mobile-chat__empty {
+ padding: 40px 0;
+ color: var(--ink-muted);
+ font-size: 12px;
+ text-align: center;
+}
+
+.mobile-chat__date {
+ width: fit-content;
+ margin: 8px auto 12px;
+ padding: 2px 10px;
+ border-radius: 999px;
+ background: #ece7dc;
+ color: var(--ink-muted);
+ font-size: 10px;
+}
+
+.mobile-chat__system {
+ display: flex;
+ justify-content: center;
+ margin-bottom: 12px;
+}
+
+.mobile-chat__system span {
+ max-width: 85%;
+ padding: 5px 10px;
+ border-radius: 4px;
+ background: #ece7dc;
+ color: var(--ink-secondary);
+ font-size: 10px;
+ line-height: 1.6;
+}
+
+.mobile-chat__message {
+ display: flex;
+ align-items: flex-start;
+ gap: 8px;
+ margin-bottom: 12px;
+}
+
+.mobile-chat__message--self {
+ flex-direction: row-reverse;
+}
+
+.mobile-chat__avatar {
+ display: flex;
+ flex-shrink: 0;
+ align-items: center;
+ justify-content: center;
+ width: 30px;
+ height: 30px;
+ border-radius: 50%;
+ background: var(--brand-ink);
+ color: #f6f2e8;
+ font-size: 11px;
+}
+
+.mobile-chat__bubble-wrap {
+ display: flex;
+ flex-direction: column;
+ gap: 3px;
+ max-width: 76%;
+}
+
+.mobile-chat__message--self .mobile-chat__bubble-wrap {
+ align-items: flex-end;
+}
+
+.mobile-chat__sender {
+ color: var(--ink-muted);
+ font-size: 10px;
+}
+
+.mobile-chat__bubble {
+ padding: 9px 12px;
+ border: 1px solid var(--line);
+ border-radius: 12px;
+ border-top-left-radius: 3px;
+ background: var(--paper-warm);
+ color: var(--ink);
+ font-size: 13px;
+ line-height: 1.55;
+ word-break: break-word;
+}
+
+.mobile-chat__bubble p {
+ margin: 0;
+ white-space: pre-wrap;
+}
+
+.mobile-chat__message--self .mobile-chat__bubble {
+ border-color: var(--brand-ink);
+ border-top-left-radius: 12px;
+ border-top-right-radius: 3px;
+ background: var(--brand-ink);
+ color: #f4f7f5;
+}
+
+.mobile-chat__time {
+ color: var(--ink-muted);
+ font-size: 9px;
+}
+
+.mobile-chat__images {
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+ margin-bottom: 6px;
+}
+
+.mobile-chat__images img {
+ max-width: 180px;
+ border-radius: 6px;
+}
+
+.mobile-chat__composer {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 10px 12px calc(10px + env(safe-area-inset-bottom));
+ border-top: 1px solid var(--line);
+ background: var(--paper-warm);
+}
+
+.mobile-chat__composer .adm-input {
+ flex: 1;
+ padding: 8px 12px;
+ border: 1px solid var(--line);
+ border-radius: 999px;
+ background: var(--paper);
+}
+
+.mobile-chat__composer .adm-button {
+ min-width: 56px;
+}
+
@media (min-width: 640px) {
.mobile-shell {
border-right: 1px solid var(--line);