diff --git a/src/mobile/views/cashier/CashierEnvPage.vue b/src/mobile/views/cashier/CashierEnvPage.vue index c1e7c42..8f2ea67 100644 --- a/src/mobile/views/cashier/CashierEnvPage.vue +++ b/src/mobile/views/cashier/CashierEnvPage.vue @@ -482,7 +482,8 @@ onUnmounted(() => { @click="selectId = item.id" >
- + +
{{ methodName(item) }} {{ t('cashier.recommend') }} @@ -518,11 +519,16 @@ onUnmounted(() => { @border: #eee; .cashier { - min-height: 100vh; + // 三区布局: header 固定 / 中间滚动 / footer 贴底,矮屏不压按钮 + height: 100vh; + height: 100dvh; + max-height: 100vh; + max-height: 100dvh; background: @bg; display: flex; flex-direction: column; - padding-bottom: 80px; + overflow: hidden; + box-sizing: border-box; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; &__error { @@ -541,12 +547,15 @@ onUnmounted(() => { &__result { flex: 1; + min-height: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; - padding: 32px 24px; + padding: 32px 24px calc(24px + env(safe-area-inset-bottom, 0px)); text-align: center; + overflow-y: auto; + -webkit-overflow-scrolling: touch; animation: cashier-result-up 0.5s ease-out; } @@ -608,16 +617,17 @@ onUnmounted(() => { } } + // 金额红:与 PC 一致,比品牌蓝更醒目 &__result-amount { - color: @primary; + color: @danger; font-weight: 600; } &__result-btn { - position: fixed; - bottom: 20px; - left: 20px; - right: 20px; + // 流式底栏,不再 fixed,避免被内容遮挡 + margin-top: 32px; + width: 100%; + max-width: 320px; height: 48px; background: linear-gradient(135deg, @primary 0%, @primary-dark 100%); color: #fff; @@ -626,6 +636,7 @@ onUnmounted(() => { font-size: 16px; font-weight: 600; box-shadow: 0 4px 12px rgba(93, 157, 254, 0.3); + flex-shrink: 0; &:active { opacity: 0.9; @@ -634,6 +645,7 @@ onUnmounted(() => { } &__header { + flex-shrink: 0; background: linear-gradient(180deg, #f0f6ff 0%, #ffffff 100%); padding: 24px 20px 16px; display: flex; @@ -642,10 +654,11 @@ onUnmounted(() => { box-shadow: 0 2px 10px rgb(0 0 0 / 5%); } + // 应付金额用红色,主按钮保持品牌蓝,信息层级更清晰 &__price { display: flex; align-items: baseline; - color: @primary; + color: @danger; margin-bottom: 8px; } @@ -658,15 +671,16 @@ onUnmounted(() => { font-size: 44px; font-weight: 800; letter-spacing: -1px; - text-shadow: 0 2px 8px rgba(93, 157, 254, 0.2); + text-shadow: 0 2px 8px rgba(255, 77, 79, 0.15); } + // 倒计时用橙:与金额红区分(红=应付 / 橙=时限 / 蓝=操作) &__countdown { display: flex; align-items: center; gap: 8px; margin-bottom: 20px; - background: #fff1f0; + background: #fff7e6; padding: 6px 16px; border-radius: 100px; @@ -677,11 +691,11 @@ onUnmounted(() => { &__countdown-label { font-size: 12px; - color: @danger; + color: #fa8c16; } &__countdown-time { - color: @danger; + color: #fa8c16; font-weight: 700; font-size: 14px; } @@ -707,8 +721,13 @@ onUnmounted(() => { } } + // 中间唯一滚动区:支付项再多也不压底栏 &__body { - padding: 24px 20px; + flex: 1; + min-height: 0; + overflow-y: auto; + -webkit-overflow-scrolling: touch; + padding: 20px 20px 16px; } &__section-title { @@ -769,6 +788,7 @@ onUnmounted(() => { border: 2px solid #d9d9d9; border-radius: 50%; transition: all 0.2s; + flex-shrink: 0; &--checked { border-color: @primary; @@ -794,12 +814,11 @@ onUnmounted(() => { text-align: center; } + // 文档流底栏,不再 fixed,天然不被列表遮挡 &__footer { - position: fixed; - bottom: 0; - left: 0; - right: 0; - padding: 12px 20px 20px; + flex-shrink: 0; + z-index: 10; + padding: 12px 20px calc(16px + env(safe-area-inset-bottom, 0px)); background: @card; box-shadow: 0 -2px 10px rgb(0 0 0 / 5%); } diff --git a/src/pc/views/cashier/Index.vue b/src/pc/views/cashier/Index.vue index e9c96d8..ddd196a 100644 --- a/src/pc/views/cashier/Index.vue +++ b/src/pc/views/cashier/Index.vue @@ -252,8 +252,10 @@ onUnmounted(() => {
@@ -418,99 +432,142 @@ onUnmounted(() => { } .pc-cashier__box { - width: 1000px; + width: 1100px; max-width: 100%; background: #fff; - border-radius: 12px; - box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08); + border-radius: 16px; + box-shadow: 0 12px 40px rgba(15, 23, 42, 0.08); overflow: hidden; - position: relative; display: flex; flex-direction: column; - min-height: 420px; + min-height: 520px; +} + +.pc-cashier__loading { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 16px; + min-height: 320px; + color: #64748b; + font-size: 15px; +} + +.pc-cashier__spinner { + width: 36px; + height: 36px; + border: 3px solid #e2e8f0; + border-top-color: #5d9dfe; + border-radius: 50%; + animation: pc-cashier-spin 0.8s linear infinite; } .pc-cashier__header { background: linear-gradient(135deg, #eaf2fe 0%, #f5f9ff 100%); - padding: 30px 40px; + padding: 28px 40px 24px; border-bottom: 1px solid #edf2f7; position: relative; } .pc-cashier__countdown { position: absolute; - right: 30px; - top: 30px; + right: 32px; + top: 28px; display: flex; align-items: center; gap: 8px; - background: rgba(255, 255, 255, 0.8); - padding: 6px 12px; + background: rgba(255, 255, 255, 0.9); + padding: 6px 14px; border-radius: 20px; border: 1px solid rgba(0, 0, 0, 0.05); + box-shadow: 0 2px 8px rgba(15, 23, 42, 0.04); } .pc-cashier__countdown-label { - font-size: 14px; + font-size: 13px; color: #64748b; } .pc-cashier__countdown-time { - font-size: 16px; + font-size: 15px; font-weight: 600; color: #ff4d4f; font-family: 'Monaco', 'Menlo', 'Consolas', monospace; } .pc-cashier__title { - font-size: 18px; + font-size: 17px; font-weight: 600; color: #1e293b; + padding-right: 180px; + line-height: 1.4; } .pc-cashier__price { - margin-top: 32px; - margin-bottom: 16px; + margin-top: 20px; + margin-bottom: 12px; } .pc-cashier__price-label { - font-size: 16px; + font-size: 14px; color: #64748b; } .pc-cashier__price p { - font-size: 48px; + font-size: 44px; color: #ff4d4f; font-weight: 800; line-height: 1; - margin: 8px 0 0; + margin: 6px 0 0; + letter-spacing: -1px; } .pc-cashier__price p span { - font-size: 24px; - margin-right: 4px; + font-size: 22px; + margin-right: 2px; } .pc-cashier__order-no { - font-size: 14px; + font-size: 13px; color: #94a3b8; } .pc-cashier__content { flex: 1; background: #fff; - padding: 40px; + padding: 28px 40px 20px; display: flex; flex-direction: column; - align-items: center; - justify-content: center; - min-height: 240px; + min-height: 200px; + box-sizing: border-box; +} + +.pc-cashier__methods { + width: 100%; +} + +.pc-cashier__section-title { + font-size: 15px; + font-weight: 600; + color: #1e293b; + margin-bottom: 16px; +} + +.pc-cashier__paid { + font-size: 18px; + font-weight: 600; + color: #07c160; + text-align: center; + padding: 40px 0; } .pc-cashier__error { color: #ff4d4f; font-size: 14px; text-align: center; + padding: 24px 0; } .pc-cashier__result { @@ -613,17 +670,18 @@ onUnmounted(() => { } .pc-cashier__empty { - grid-column: 1 / -1; color: #94a3b8; text-align: center; - padding: 24px; + padding: 32px 16px; + font-size: 14px; } +/* 4 列横向卡片(与原布局一致) */ .pc-cashier__grid { width: 100%; display: grid; grid-template-columns: repeat(4, 1fr); - gap: 20px; + gap: 16px; } .pc-cashier__method { @@ -654,26 +712,34 @@ onUnmounted(() => { } .pc-cashier__method-name { - font-size: 16px; + font-size: 15px; font-weight: 500; color: #1e293b; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + min-width: 0; } .pc-cashier__recommend { + margin-left: auto; font-size: 12px; color: #f59e0b; background: #fffbeb; border: 1px solid #fef3c7; padding: 2px 8px; border-radius: 4px; - margin-left: auto; white-space: nowrap; + flex-shrink: 0; } .pc-cashier__qrcode { display: flex; align-items: center; + justify-content: center; gap: 40px; + padding: 16px 0 24px; + width: 100%; } .pc-cashier__qrcode-box { @@ -742,35 +808,91 @@ onUnmounted(() => { margin: 0; } +/* 底部操作栏:流式布局,不压支付项 */ +.pc-cashier__footer { + display: flex; + align-items: center; + justify-content: flex-end; + gap: 24px; + padding: 16px 40px 28px; + border-top: 1px solid #f1f5f9; + background: #fff; +} + +.pc-cashier__footer-amount { + display: flex; + align-items: baseline; + gap: 8px; +} + +.pc-cashier__footer-label { + font-size: 13px; + color: #94a3b8; +} + +.pc-cashier__footer-value { + font-size: 28px; + font-weight: 800; + color: #ff4d4f; + line-height: 1; +} + +.pc-cashier__footer-value em { + font-style: normal; + font-size: 16px; + font-weight: 700; + margin-right: 1px; +} + .pc-cashier__pay-btn { - position: absolute; - right: 40px; - bottom: 40px; width: 200px; - height: 54px; - font-size: 18px; + height: 48px; + font-size: 16px; font-weight: 600; color: #fff; - background: #5d9dfe; + background: linear-gradient(135deg, #5d9dfe 0%, #4a87e0 100%); border: none; - border-radius: 8px; + border-radius: 10px; cursor: pointer; transition: all 0.2s; - box-shadow: 0 4px 12px rgba(93, 157, 254, 0.3); + box-shadow: 0 4px 14px rgba(93, 157, 254, 0.32); + flex-shrink: 0; } .pc-cashier__pay-btn:hover:not(:disabled) { - background: #4a87e0; transform: translateY(-1px); - box-shadow: 0 6px 16px rgba(93, 157, 254, 0.4); + box-shadow: 0 6px 18px rgba(93, 157, 254, 0.4); } .pc-cashier__pay-btn:disabled { - opacity: 0.6; + opacity: 0.55; cursor: not-allowed; + box-shadow: none; } @media (max-width: 768px) { + .pc-cashier__box { + border-radius: 12px; + } + + .pc-cashier__header, + .pc-cashier__content, + .pc-cashier__footer { + padding-left: 20px; + padding-right: 20px; + } + + .pc-cashier__title { + padding-right: 0; + margin-bottom: 8px; + } + + .pc-cashier__countdown { + position: static; + margin-bottom: 12px; + width: fit-content; + } + .pc-cashier__grid { grid-template-columns: repeat(2, 1fr); } @@ -780,10 +902,24 @@ onUnmounted(() => { gap: 20px; } + .pc-cashier__footer { + flex-direction: column; + align-items: stretch; + gap: 16px; + } + + .pc-cashier__footer-amount { + justify-content: space-between; + } + .pc-cashier__pay-btn { - position: static; width: 100%; - margin: 20px 0 0; + } +} + +@keyframes pc-cashier-spin { + to { + transform: rotate(360deg); } } diff --git a/src/shared/assets/icons/channel/aggregate_pay.svg b/src/shared/assets/icons/channel/aggregate_pay.svg new file mode 100644 index 0000000..56ee217 --- /dev/null +++ b/src/shared/assets/icons/channel/aggregate_pay.svg @@ -0,0 +1 @@ + diff --git a/src/shared/assets/icons/channel/mastercard.svg b/src/shared/assets/icons/channel/mastercard.svg new file mode 100644 index 0000000..890e809 --- /dev/null +++ b/src/shared/assets/icons/channel/mastercard.svg @@ -0,0 +1 @@ + diff --git a/src/shared/assets/icons/channel/other.svg b/src/shared/assets/icons/channel/other.svg new file mode 100644 index 0000000..5f3ed1c --- /dev/null +++ b/src/shared/assets/icons/channel/other.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/shared/assets/icons/channel/union_pay.svg b/src/shared/assets/icons/channel/union_pay.svg new file mode 100644 index 0000000..82ceccf --- /dev/null +++ b/src/shared/assets/icons/channel/union_pay.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/shared/assets/icons/channel/visa.svg b/src/shared/assets/icons/channel/visa.svg new file mode 100644 index 0000000..28abe45 --- /dev/null +++ b/src/shared/assets/icons/channel/visa.svg @@ -0,0 +1 @@ + diff --git a/src/shared/components/pay/PayMethodIcon.vue b/src/shared/components/pay/PayMethodIcon.vue new file mode 100644 index 0000000..772623f --- /dev/null +++ b/src/shared/components/pay/PayMethodIcon.vue @@ -0,0 +1,85 @@ + + + + + diff --git a/src/shared/components/pay/QrCodeDisplay.vue b/src/shared/components/pay/QrCodeDisplay.vue new file mode 100644 index 0000000..d592bf8 --- /dev/null +++ b/src/shared/components/pay/QrCodeDisplay.vue @@ -0,0 +1,90 @@ + + + + +