Browse Source

fix: R5修复 — 导航栏/box-sizing/双重跳转/拒单/未读计数/ProductCard高度

dev
mac 1 day ago
parent
commit
67eb3312b2
9 changed files with 58 additions and 41 deletions
  1. +4
    -4
      components/ProductCard.vue
  2. +10
    -9
      pages.json
  3. +7
    -8
      pages/chat/chat.vue
  4. +17
    -15
      pages/index/index.vue
  5. +4
    -1
      pages/staff/board.vue
  6. +4
    -2
      pages/staff/chat.vue
  7. +5
    -1
      stores/card.js
  8. +5
    -1
      stores/staff.js
  9. +2
    -0
      uni.scss

+ 4
- 4
components/ProductCard.vue View File

@ -22,12 +22,12 @@ export default {
</script> </script>
<style scoped> <style scoped>
.product-card{width:calc(50% - 12rpx);background:var(--bg-card);border-radius:var(--radius);overflow:hidden;margin-bottom:20rpx;border:1px solid var(--border);position:relative}
.product-card{width:calc(50% - 12rpx);background:var(--bg-card);border-radius:var(--radius);overflow:hidden;margin-bottom:20rpx;border:1px solid var(--border);position:relative;min-height:420rpx}
.card-img{width:100%;height:220rpx;display:flex;align-items:center;justify-content:center;font-size:88rpx;position:relative;background:rgba(245,166,35,.04)} .card-img{width:100%;height:220rpx;display:flex;align-items:center;justify-content:center;font-size:88rpx;position:relative;background:rgba(245,166,35,.04)}
.alc-tag{position:absolute;top:16rpx;right:16rpx;background:rgba(0,0,0,.6);color:var(--gold-light);font-size:20rpx;padding:6rpx 16rpx;border-radius:20rpx;font-weight:700} .alc-tag{position:absolute;top:16rpx;right:16rpx;background:rgba(0,0,0,.6);color:var(--gold-light);font-size:20rpx;padding:6rpx 16rpx;border-radius:20rpx;font-weight:700}
.card-body{padding:16rpx 20rpx 24rpx;position:relative} .card-body{padding:16rpx 20rpx 24rpx;position:relative}
.card-name{font-size:28rpx;font-weight:700;color:var(--text);display:block;margin-bottom:4rpx}
.card-en{font-size:20rpx;color:var(--text-muted);display:block;margin-bottom:6rpx}
.card-desc{font-size:22rpx;color:var(--text-dim);line-height:1.3;display:block;margin-bottom:4rpx}
.card-name{font-size:28rpx;font-weight:700;color:var(--text);display:block;margin-bottom:4rpx;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.card-en{font-size:20rpx;color:var(--text-muted);display:block;margin-bottom:6rpx;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.card-desc{font-size:22rpx;color:var(--text-dim);line-height:1.3;display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.card-add{position:absolute;bottom:16rpx;right:16rpx;width:56rpx;height:56rpx;border-radius:50%;background:var(--orange);color:#fff;font-size:32rpx;display:flex;align-items:center;justify-content:center;box-shadow:0 4rpx 20rpx rgba(255,107,53,.4)} .card-add{position:absolute;bottom:16rpx;right:16rpx;width:56rpx;height:56rpx;border-radius:50%;background:var(--orange);color:#fff;font-size:32rpx;display:flex;align-items:center;justify-content:center;box-shadow:0 4rpx 20rpx rgba(255,107,53,.4)}
</style> </style>

+ 10
- 9
pages.json View File

@ -1,16 +1,17 @@
{ {
"pages": [ "pages": [
{ "path": "pages/index/index", "style": { "navigationBarTitleText": "纯瘾大" } },
{ "path": "pages/menu/menu", "style": { "navigationBarTitleText": "酒水单" } },
{ "path": "pages/confirm/confirm", "style": { "navigationBarTitleText": "确认下单" } },
{ "path": "pages/orders/orders", "style": { "navigationBarTitleText": "我的订单" } },
{ "path": "pages/chat/chat", "style": { "navigationBarTitleText": "对话" } },
{ "path": "pages/staff/login", "style": { "navigationBarTitleText": "调酒师登录" } },
{ "path": "pages/staff/board", "style": { "navigationBarTitleText": "订单看板" } },
{ "path": "pages/staff/detail", "style": { "navigationBarTitleText": "订单详情" } },
{ "path": "pages/staff/chat", "style": { "navigationBarTitleText": "客人对话" } }
{ "path": "pages/index/index", "style": { "navigationStyle": "custom" } },
{ "path": "pages/menu/menu", "style": { "navigationStyle": "custom" } },
{ "path": "pages/confirm/confirm", "style": { "navigationStyle": "custom" } },
{ "path": "pages/orders/orders", "style": { "navigationStyle": "custom" } },
{ "path": "pages/chat/chat", "style": { "navigationStyle": "custom" } },
{ "path": "pages/staff/login", "style": { "navigationStyle": "custom" } },
{ "path": "pages/staff/board", "style": { "navigationStyle": "custom" } },
{ "path": "pages/staff/detail", "style": { "navigationStyle": "custom" } },
{ "path": "pages/staff/chat", "style": { "navigationStyle": "custom" } }
], ],
"globalStyle": { "globalStyle": {
"navigationStyle": "custom",
"navigationBarTextStyle": "white", "navigationBarTextStyle": "white",
"navigationBarTitleText": "纯瘾大", "navigationBarTitleText": "纯瘾大",
"navigationBarBackgroundColor": "#0D0D0D", "navigationBarBackgroundColor": "#0D0D0D",


+ 7
- 8
pages/chat/chat.vue View File

@ -19,7 +19,7 @@
</template> </template>
<script> <script>
import { ref, onMounted, onUnmounted, nextTick } from 'vue'
import { ref, onMounted, onUnmounted } from 'vue'
import { useCardStore } from '@/stores/card' import { useCardStore } from '@/stores/card'
import { get, post } from '@/utils/request' import { get, post } from '@/utils/request'
import { API } from '@/utils/constants' import { API } from '@/utils/constants'
@ -39,6 +39,8 @@ export default {
try { try {
const res = await get(API.MESSAGE_LIST, { card_no: card.cardNo, since: lastId }) const res = await get(API.MESSAGE_LIST, { card_no: card.cardNo, since: lastId })
if (Array.isArray(res) && res.length > 0) { if (Array.isArray(res) && res.length > 0) {
const newMsgs = res.filter(m => m.senderType === 'staff')
if (newMsgs.length > 0) card.incrementUnread(newMsgs.length)
messages.value = [...messages.value, ...res] messages.value = [...messages.value, ...res]
lastId = res[res.length - 1].id lastId = res[res.length - 1].id
scrollToId.value = 'chat-bottom' scrollToId.value = 'chat-bottom'
@ -56,12 +58,9 @@ export default {
} catch (e) {} } catch (e) {}
} }
function goBack() { uni.navigateBack() }
function goBack() { card.clearUnread(); uni.navigateBack() }
onMounted(() => {
loadMessages()
startPoll('chat', loadMessages, 5000)
})
onMounted(() => { card.clearUnread(); loadMessages(); startPoll('chat', loadMessages, 5000) })
onUnmounted(() => stopPoll('chat')) onUnmounted(() => stopPoll('chat'))
return { messages, inputText, scrollToId, sendMsg, goBack } return { messages, inputText, scrollToId, sendMsg, goBack }
@ -70,8 +69,8 @@ export default {
</script> </script>
<style scoped> <style scoped>
.page-chat{min-height:100vh;display:flex;flex-direction:column;background:var(--bg)}
.nav-bar{height:100rpx;display:flex;align-items:center;justify-content:space-between;padding:0 28rpx;border-bottom:1px solid var(--border)}
.page-chat{min-height:100vh;display:flex;flex-direction:column;background:var(--bg);width:100%}
.nav-bar{height:100rpx;display:flex;align-items:center;justify-content:space-between;padding:0 28rpx;border-bottom:1px solid var(--border);flex-shrink:0}
.nav-back{font-size:36rpx;color:var(--text-dim)} .nav-back{font-size:36rpx;color:var(--text-dim)}
.nav-title{font-size:32rpx;font-weight:800;color:var(--gold)} .nav-title{font-size:32rpx;font-weight:800;color:var(--gold)}
.chat-list{flex:1;padding:16rpx 0} .chat-list{flex:1;padding:16rpx 0}


+ 17
- 15
pages/index/index.vue View File

@ -76,6 +76,13 @@ export default {
const generated = ref(false) const generated = ref(false)
const inputNo = ref('') const inputNo = ref('')
const cardNo = ref('') const cardNo = ref('')
let navTimer = null
function goMenu() {
showModal.value = false
generated.value = false
uni.navigateTo({ url: '/pages/menu/menu' })
}
async function onGenerate() { async function onGenerate() {
try { try {
@ -83,11 +90,7 @@ export default {
cardNo.value = res.cardNo cardNo.value = res.cardNo
card.setCardNo(res.cardNo) card.setCardNo(res.cardNo)
generated.value = true generated.value = true
setTimeout(() => {
showModal.value = false
generated.value = false
uni.navigateTo({ url: '/pages/menu/menu' })
}, 3000)
navTimer = setTimeout(() => { goMenu() }, 3000)
} catch (e) {} } catch (e) {}
} }
@ -110,9 +113,8 @@ export default {
function onMaskTap() { function onMaskTap() {
if (generated.value) { if (generated.value) {
showModal.value = false
generated.value = false
uni.navigateTo({ url: '/pages/menu/menu' })
if (navTimer) { clearTimeout(navTimer); navTimer = null }
goMenu()
} }
} }
@ -143,22 +145,22 @@ export default {
.staff-link{padding:20rpx;text-align:center;flex-shrink:0} .staff-link{padding:20rpx;text-align:center;flex-shrink:0}
.staff-link text{color:var(--text-muted);font-size:22rpx;letter-spacing:2rpx} .staff-link text{color:var(--text-muted);font-size:22rpx;letter-spacing:2rpx}
/* 号码牌弹窗 (严格对齐UI CSS) */
/* 号码牌弹窗 */
.modal-mask{display:none;position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,.75);z-index:300;align-items:center;justify-content:center} .modal-mask{display:none;position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,.75);z-index:300;align-items:center;justify-content:center}
.modal-mask.show{display:flex} .modal-mask.show{display:flex}
.card-modal{width:580rpx;background:var(--bg-card);border-radius:40rpx;border:2px solid var(--border);overflow:hidden;animation:bounce-in .5s ease} .card-modal{width:580rpx;background:var(--bg-card);border-radius:40rpx;border:2px solid var(--border);overflow:hidden;animation:bounce-in .5s ease}
.modal-header{padding:56rpx 48rpx 32rpx;text-align:center}
.modal-header{padding:48rpx 36rpx 28rpx;text-align:center}
.modal-icon{font-size:104rpx;animation:float 2s ease-in-out infinite} .modal-icon{font-size:104rpx;animation:float 2s ease-in-out infinite}
.modal-title{font-size:36rpx;font-weight:800;color:var(--gold);margin-top:16rpx}
.modal-desc{font-size:26rpx;color:var(--text-dim);margin-top:8rpx;line-height:1.6}
.card-generated{text-align:center;padding:24rpx 48rpx 40rpx}
.modal-title{font-size:36rpx;font-weight:800;color:var(--gold);margin-top:16rpx;white-space:nowrap}
.modal-desc{font-size:26rpx;color:var(--text-dim);margin-top:8rpx;line-height:1.6;white-space:nowrap}
.card-generated{text-align:center;padding:24rpx 36rpx 40rpx}
.card-number-big{padding:32rpx;background:linear-gradient(135deg,rgba(245,166,35,.1),rgba(245,166,35,.05));border-radius:28rpx;border:2rpx dashed rgba(245,166,35,.3)} .card-number-big{padding:32rpx;background:linear-gradient(135deg,rgba(245,166,35,.1),rgba(245,166,35,.05));border-radius:28rpx;border:2rpx dashed rgba(245,166,35,.3)}
.card-number-big text{font-size:84rpx;font-weight:900;letter-spacing:20rpx;color:var(--gold)} .card-number-big text{font-size:84rpx;font-weight:900;letter-spacing:20rpx;color:var(--gold)}
.card-remember{font-size:26rpx;color:var(--red);margin-top:20rpx;font-weight:600;display:block} .card-remember{font-size:26rpx;color:var(--red);margin-top:20rpx;font-weight:600;display:block}
.modal-body{padding:0 48rpx 40rpx}
.modal-body{padding:0 36rpx 36rpx}
.card-input-group{display:flex;align-items:stretch;margin-bottom:24rpx;border:4rpx solid var(--border);border-radius:20rpx;overflow:hidden;background:var(--bg)} .card-input-group{display:flex;align-items:stretch;margin-bottom:24rpx;border:4rpx solid var(--border);border-radius:20rpx;overflow:hidden;background:var(--bg)}
.card-input{flex:1;min-width:0;height:92rpx;background:transparent;border:none;outline:none;padding:0 28rpx;font-size:36rpx;font-weight:700;text-align:center;letter-spacing:8rpx;color:var(--gold)} .card-input{flex:1;min-width:0;height:92rpx;background:transparent;border:none;outline:none;padding:0 28rpx;font-size:36rpx;font-weight:700;text-align:center;letter-spacing:8rpx;color:var(--gold)}
.card-confirm-btn{flex-shrink:0;width:128rpx;border:none;background:linear-gradient(135deg,var(--gold-dark),var(--gold));color:#1A1A1A;font-size:28rpx;font-weight:700;display:flex;align-items:center;justify-content:center} .card-confirm-btn{flex-shrink:0;width:128rpx;border:none;background:linear-gradient(135deg,var(--gold-dark),var(--gold));color:#1A1A1A;font-size:28rpx;font-weight:700;display:flex;align-items:center;justify-content:center}
.card-divider{text-align:center;color:var(--text-muted);font-size:24rpx;margin:20rpx 0;position:relative} .card-divider{text-align:center;color:var(--text-muted);font-size:24rpx;margin:20rpx 0;position:relative}
.modal-footer{padding:0 48rpx 48rpx}
.modal-footer{padding:0 36rpx 40rpx}
</style> </style>

+ 4
- 1
pages/staff/board.vue View File

@ -26,6 +26,7 @@
<button class="ba-btn ba-gold" @tap="onDetail(o)">📖 配方</button> <button class="ba-btn ba-gold" @tap="onDetail(o)">📖 配方</button>
<button class="ba-btn ba-blue" @tap="onChat(o)">💬 聊天</button> <button class="ba-btn ba-blue" @tap="onChat(o)">💬 聊天</button>
<button v-if="o.status===0" class="ba-btn ba-gold" @tap="onConfirm(o.id)"> 接单</button> <button v-if="o.status===0" class="ba-btn ba-gold" @tap="onConfirm(o.id)"> 接单</button>
<button v-if="o.status===0" class="ba-btn ba-red" @tap="onCancel(o.id)"> 拒单</button>
<button v-if="o.status===1" class="ba-btn ba-gold" @tap="onDone(o.id)"> 结单</button> <button v-if="o.status===1" class="ba-btn ba-gold" @tap="onDone(o.id)"> 结单</button>
</view> </view>
</template> </template>
@ -70,6 +71,7 @@ export default {
} }
function switchTab(s) { activeTab.value = s; loadOrders() } function switchTab(s) { activeTab.value = s; loadOrders() }
async function onConfirm(id) { try { await post(API.STAFF_CONFIRM, { id }); uni.showToast({ title: '已接单 ✅', icon: 'none' }); loadOrders(); loadCounts() } catch (e) {} } async function onConfirm(id) { try { await post(API.STAFF_CONFIRM, { id }); uni.showToast({ title: '已接单 ✅', icon: 'none' }); loadOrders(); loadCounts() } catch (e) {} }
async function onCancel(id) { try { await post(API.STAFF_CANCEL, { id }); uni.showToast({ title: '已拒单 ❌', icon: 'none' }); loadOrders(); loadCounts() } catch (e) {} }
async function onDone(id) { try { const res = await post(API.STAFF_DONE, { id }); uni.showToast({ title: res && res.released ? '已结单 ✔ 号码已释放' : '已结单 ✔', icon: 'none' }); loadOrders(); loadCounts() } catch (e) {} } async function onDone(id) { try { const res = await post(API.STAFF_DONE, { id }); uni.showToast({ title: res && res.released ? '已结单 ✔ 号码已释放' : '已结单 ✔', icon: 'none' }); loadOrders(); loadCounts() } catch (e) {} }
function onDetail(order) { uni.navigateTo({ url: '/pages/staff/detail?id=' + order.id }) } function onDetail(order) { uni.navigateTo({ url: '/pages/staff/detail?id=' + order.id }) }
function onRecipe(order) { recipeCardNo.value = order.cardNo; recipeItems.value = order.items; recipeVisible.value = true } function onRecipe(order) { recipeCardNo.value = order.cardNo; recipeItems.value = order.items; recipeVisible.value = true }
@ -79,7 +81,7 @@ export default {
onMounted(() => { loadOrders(); loadCounts(); startPoll('board', () => { loadOrders(); loadCounts() }, 10000) }) onMounted(() => { loadOrders(); loadCounts(); startPoll('board', () => { loadOrders(); loadCounts() }, 10000) })
onUnmounted(() => stopPoll('board')) onUnmounted(() => stopPoll('board'))
return { staff, tabs, activeTab, orders, counts, recipeVisible, recipeCardNo, recipeItems, switchTab, onConfirm, onDone, onDetail, onRecipe, onChat, onLogout }
return { staff, tabs, activeTab, orders, counts, recipeVisible, recipeCardNo, recipeItems, switchTab, onConfirm, onCancel, onDone, onDetail, onRecipe, onChat, onLogout }
} }
} }
</script> </script>
@ -101,6 +103,7 @@ export default {
.ba-btn{padding:12rpx 24rpx;border-radius:24rpx;font-size:24rpx;font-weight:600;border:none} .ba-btn{padding:12rpx 24rpx;border-radius:24rpx;font-size:24rpx;font-weight:600;border:none}
.ba-gold{background:rgba(245,166,35,.15);color:var(--gold)} .ba-gold{background:rgba(245,166,35,.15);color:var(--gold)}
.ba-blue{background:rgba(74,144,217,.15);color:var(--blue)} .ba-blue{background:rgba(74,144,217,.15);color:var(--blue)}
.ba-red{background:rgba(255,59,59,.15);color:var(--red)}
.empty-state{flex:1;display:flex;align-items:center;justify-content:center;flex-direction:column} .empty-state{flex:1;display:flex;align-items:center;justify-content:center;flex-direction:column}
.empty-icon{font-size:112rpx;opacity:.3} .empty-icon{font-size:112rpx;opacity:.3}
.empty-text{font-size:28rpx;color:var(--text-muted);margin-top:16rpx} .empty-text{font-size:28rpx;color:var(--text-muted);margin-top:16rpx}


+ 4
- 2
pages/staff/chat.vue View File

@ -40,6 +40,8 @@ export default {
try { try {
const res = await get(API.MESSAGE_LIST, { card_no: cardNo.value, since: lastId }) const res = await get(API.MESSAGE_LIST, { card_no: cardNo.value, since: lastId })
if (Array.isArray(res) && res.length > 0) { if (Array.isArray(res) && res.length > 0) {
const newMsgs = res.filter(m => m.senderType === 'customer')
if (newMsgs.length > 0) staff.incrementUnread(newMsgs.length)
messages.value = [...messages.value, ...res] messages.value = [...messages.value, ...res]
lastId = res[res.length - 1].id lastId = res[res.length - 1].id
scrollToId.value = 'chat-bottom' scrollToId.value = 'chat-bottom'
@ -57,9 +59,9 @@ export default {
} catch (e) {} } catch (e) {}
} }
function goBack() { uni.navigateBack() }
function goBack() { staff.clearUnread(); uni.navigateBack() }
onMounted(() => { loadMessages(); startPoll('staffChat', loadMessages, 5000) })
onMounted(() => { staff.clearUnread(); loadMessages(); startPoll('staffChat', loadMessages, 5000) })
onUnmounted(() => stopPoll('staffChat')) onUnmounted(() => stopPoll('staffChat'))
return { cardNo, messages, inputText, scrollToId, sendMsg, goBack } return { cardNo, messages, inputText, scrollToId, sendMsg, goBack }


+ 5
- 1
stores/card.js View File

@ -4,6 +4,7 @@ import { ref } from 'vue'
export const useCardStore = defineStore('card', () => { export const useCardStore = defineStore('card', () => {
const cardNo = ref(uni.getStorageSync('cardNo') || '') const cardNo = ref(uni.getStorageSync('cardNo') || '')
const dismissed = ref(false) const dismissed = ref(false)
const unread = ref(0)
function setCardNo(no) { function setCardNo(no) {
cardNo.value = no cardNo.value = no
@ -15,5 +16,8 @@ export const useCardStore = defineStore('card', () => {
uni.removeStorageSync('cardNo') uni.removeStorageSync('cardNo')
} }
return { cardNo, dismissed, setCardNo, clearCard }
function incrementUnread(n = 1) { unread.value += n }
function clearUnread() { unread.value = 0 }
return { cardNo, dismissed, unread, setCardNo, clearCard, incrementUnread, clearUnread }
}) })

+ 5
- 1
stores/staff.js View File

@ -22,10 +22,14 @@ export const useStaffStore = defineStore('staff', () => {
token.value = '' token.value = ''
nickname.value = '' nickname.value = ''
staffId.value = '' staffId.value = ''
unread.value = 0
uni.removeStorageSync('staffToken') uni.removeStorageSync('staffToken')
uni.removeStorageSync('staffNickname') uni.removeStorageSync('staffNickname')
uni.removeStorageSync('staffId') uni.removeStorageSync('staffId')
} }
return { token, nickname, staffId, unread, isLoggedIn, login, logout }
function incrementUnread(n = 1) { unread.value += n }
function clearUnread() { unread.value = 0 }
return { token, nickname, staffId, unread, isLoggedIn, login, logout, incrementUnread, clearUnread }
}) })

+ 2
- 0
uni.scss View File

@ -1,4 +1,6 @@
// 纯瘾大 全局样式 (严格对齐 UI/css/miniapp.css) // 纯瘾大 全局样式 (严格对齐 UI/css/miniapp.css)
*,*::before,*::after{box-sizing:border-box}
page { page {
--bg: #0D0D0D; --bg: #0D0D0D;
--bg-card: #1A1A1A; --bg-card: #1A1A1A;


Loading…
Cancel
Save