Ver Fonte

修改bug返回主页、列表展示bug

sunshibo há 1 mês atrás
pai
commit
cc753e7b50

+ 4 - 4
components/NavBar/StatusBar.vue

@@ -8,8 +8,10 @@
 export default {
 	name: 'UniStatusBar',
 	data() {
+		const info = uni.getWindowInfo();
+		const h = info.statusBarHeight ?? 20;
 		return {
-			statusBarHeight: uni.getWindowInfo().statusBarHeight + 14 + 'rpx'
+			statusBarHeight: h + 'px'
 		};
 	}
 };
@@ -17,8 +19,6 @@ export default {
 
 <style lang="scss">
 .uni-status-bar {
-	// width: 750rpx;
-	height: 20px;
-	// height: var(--status-bar-height);
+	background: #ffffff;
 }
 </style>

+ 19 - 13
components/NavBar/index.vue

@@ -63,28 +63,34 @@
 	// 是否显示右侧按钮
 	const ifShowRight = computed(() => slots.right || props.warn)
 	// 
-	const statusBarHeight = computed(() => systemInfo.statusBarHeight) // 状态栏高度
+	const statusBarHeight = computed(() => systemInfo.statusBarHeight ?? 0)
+	const statusH = unref(statusBarHeight)
+	const menuTop = menuButtonInfo.top ?? statusH
+	const menuRight = menuButtonInfo.right ?? ((systemInfo.windowWidth ?? 375) - 87)
+	const menuHeight = menuButtonInfo.height ?? 32
+	const menuWidth = menuButtonInfo.width ?? 87
+	const gap = menuButtonInfo.top != null ? Math.max(0, menuTop - statusH) : 4
 	const getNavWrapStyle = computed(() => {
-		const { windowWidth } = systemInfo
-		const { top, right, height } = menuButtonInfo
+		const w = systemInfo.windowWidth ?? 375
+		const padRight = Math.max(0, w - menuRight)
 		return {
-			padding: `${top - unref(statusBarHeight)}px ${windowWidth - right}px`,
-			height: `${height + (top - unref(statusBarHeight)) * 2}px`
+			padding: `${gap}px ${padRight}px`,
+			height: `${menuHeight + gap * 2}px`
 		}
 	})
 	
 	const getNavBarContent = computed(() => {
-		const { width } = menuButtonInfo
 		const style = {}
 		if(unref(ifShowRight)){
-			style.paddingRight = width + 'px'
+			style.paddingRight = menuWidth + 'px'
 		}else{
 			style.position = 'absolute'
 			style.width = '100%'
 			style.top = '0'
 			style.bottom = '0'
-			style.zIndex = '-1'
-			style.padding = `0 ${width + 10}px`
+			style.left = '0'
+			style.zIndex = '0'
+			style.padding = `0 ${menuWidth + 10}px`
 		}
 		return style
 	})
@@ -113,16 +119,17 @@
 	.wrap{
 		position: sticky;
 		z-index: 101;
+		background: #ffffff;
 		&-shadow{
 			box-shadow: 0 1rpx 0 2rpx #F4F6FA;
 		}
 		.nav-bar-wrap{
-			padding:4px 8px;
-			height:40px;
 			.nav-bar{
 				height: 100%;
 				position: relative;
 				&_left{
+					position: relative;
+					z-index: 10;
 					margin-right: 30rpx;
 					flex: none;
 					.left-btns{
@@ -192,8 +199,7 @@
 					&_title{
 						text-align: center;
 						font-size: 36rpx;
-						color: #fff;
-						// background: red;
+						color: #333333;
 					}
 					&_right{
 						flex: none;

+ 48 - 31
pages/foodDetail/index.vue

@@ -1,15 +1,6 @@
 <template>
-  <!-- 菜品详情 -->
+  <!-- 菜品详情:图片从状态栏开始,返回按钮悬浮其上 -->
   <view class="content">
-    <!-- 自定义返回栏,避免引用 NavBar 组件导致的 mp 依赖分析报错 -->
-    <view class="back-bar">
-      <view class="back-bar-inner">
-        <view class="back-btn" hover-class="hover-active" @click="onBack">
-          <text class="back-arrow">‹</text>
-        </view>
-        <text class="back-title">菜品详情</text>
-      </view>
-    </view>
     <swiper class="swiper" :circular="true" :autoplay="true" :interval="3000" v-if="swiperImages.length">
       <swiper-item v-for="(img, i) in swiperImages" :key="i">
         <image :src="getFileUrl(img)" mode="aspectFill" class="food-image"></image>
@@ -18,6 +9,15 @@
     <view class="swiper swiper-placeholder" v-else>
       <image :src="placeholderImage" mode="aspectFill" class="food-image"></image>
     </view>
+    <!-- 返回按钮悬浮在图片上方 -->
+    <view class="back-bar">
+      <view class="back-bar-status" :style="{ height: statusBarHeight + 'px' }"></view>
+      <view class="back-bar-inner" :style="backBarInnerStyle">
+        <view class="back-btn" hover-class="hover-active" @click="onBack">
+          <text class="back-arrow">‹</text>
+        </view>
+      </view>
+    </view>
     <view class="food-info">
       <view class="food-price">
         <text class="price-symbol">¥</text>
@@ -76,6 +76,30 @@ import { onLoad } from "@dcloudio/uni-app";
 import { getFileUrl } from "@/utils/file.js";
 import { GetCuisineDetail, GetOrderCart, PostOrderCartAdd, PostOrderCartUpdate } from "@/api/dining.js";
 
+// 胶囊信息:返回按钮与小程序胶囊同一行
+let menuButtonInfo = {};
+// #ifdef MP-WEIXIN
+try {
+  menuButtonInfo = uni.getMenuButtonBoundingClientRect() || {};
+} catch (_) {}
+// #endif
+const systemInfo = uni.getWindowInfo();
+const statusBarHeight = systemInfo.statusBarHeight ?? 20;
+const menuTop = menuButtonInfo.top ?? statusBarHeight;
+const menuRight = menuButtonInfo.right ?? (systemInfo.windowWidth ?? 375) - 87;
+const menuHeight = menuButtonInfo.height ?? 32;
+const gap = menuButtonInfo.top != null ? Math.max(0, menuTop - statusBarHeight) : 4;
+const padRight = Math.max(0, (systemInfo.windowWidth ?? 375) - menuRight);
+
+const backBarInnerStyle = computed(() => ({
+  height: menuHeight + gap * 2 + 'px',
+  paddingRight: padRight + 'px'
+}));
+
+const onBack = () => {
+  uni.navigateBack();
+};
+
 const quantity = ref(1);
 const loading = ref(false);
 const cuisineId = ref('');
@@ -138,10 +162,6 @@ const detailTags = computed(() => {
   return [];
 });
 
-const onBack = () => {
-  uni.navigateBack();
-};
-
 // 加减号只改本地数量,不调接口;只有点击「加入购物车」才调接口
 const handleIncrease = () => {
   if (quantity.value >= 99) return;
@@ -236,45 +256,42 @@ onLoad(async (options) => {
 </script>
 
 <style lang="scss" scoped>
+.content {
+  position: relative;
+}
 .back-bar {
-  position: sticky;
+  position: absolute;
   top: 0;
+  left: 0;
+  right: 0;
   z-index: 101;
-  padding-top: constant(safe-area-inset-top);
-  padding-top: env(safe-area-inset-top);
-  background: rgba(0, 0, 0, 0.3);
+}
+.back-bar-status {
+  width: 100%;
 }
 .back-bar-inner {
-  height: 88rpx;
   padding: 0 24rpx;
   display: flex;
   align-items: center;
+  box-sizing: border-box;
 }
 .back-btn {
-  width: 64rpx;
-  height: 64rpx;
-  border-radius: 50%;
-  background: rgba(255, 255, 255, 0.5);
+  width: 100rpx;
+  height: 100rpx;
   display: flex;
   align-items: center;
   justify-content: center;
-  margin-right: 16rpx;
   &.hover-active {
     opacity: 0.8;
   }
 }
 .back-arrow {
-  font-size: 48rpx;
-  color: #fff;
+  font-size: 80rpx;
+  color: #000000;
   font-weight: 300;
   line-height: 1;
   margin-left: -4rpx;
 }
-.back-title {
-  font-size: 32rpx;
-  color: #fff;
-  font-weight: 500;
-}
 
 .swiper {
   width: 100%;

+ 4 - 3
pages/orderFood/components/CartModal.vue

@@ -170,16 +170,17 @@ const handleClear = () => {
 <style scoped lang="scss">
 .cart-modal {
     width: 100%;
+    max-height: 70vh;
     background: #FFFFFF;
     border-radius: 24rpx 24rpx 0 0;
     padding: 0;
     box-sizing: border-box;
-    max-height: 80vh;
     display: flex;
     flex-direction: column;
     overflow: hidden;
 
     &__header {
+        flex-shrink: 0;
         position: relative;
         display: flex;
         align-items: center;
@@ -217,11 +218,11 @@ const handleClear = () => {
 
     &__list {
         flex: 1;
+        min-height: 0;
+        height: 0;
         padding: 24rpx 30rpx;
         padding-bottom: calc(140rpx + env(safe-area-inset-bottom));
         box-sizing: border-box;
-        overflow-y: auto;
-        min-height: 0;
     }
 }
 

+ 88 - 28
pages/orderFood/index.vue

@@ -1,27 +1,31 @@
 <template>
-  <!-- 点餐页:左上角永远返回主页 -->
+  <!-- 点餐页:左上角永远返回主页,顶部固定 -->
   <view class="page-wrap">
-    <NavBar title="点餐" only-home />
+    <view class="top-fixed">
+      <NavBar :title="navTitle" only-home />
+      <view class="top-info">桌号:{{ displayTableNumber }} &nbsp;&nbsp;就餐人数:{{ currentDiners }}人</view>
+      <input type="text" placeholder="请输入菜品名称" class="search-input" />
+    </view>
     <view class="content">
-    <view class="top-info">桌号:{{ displayTableNumber }} &nbsp;&nbsp;就餐人数:{{ currentDiners }}人</view>
-    <!-- 搜索 -->
-    <input type="text" placeholder="请输入菜品名称" class="search-input" />
-
     <!-- 内容 -->
     <view class="content-box">
       <!-- 左侧分类列表 -->
-      <scroll-view class="category-list" scroll-y>
-        <view v-for="(category, index) in categories" :key="index" class="category-item"
-          :class="{ active: currentCategoryIndex === index }" @click="selectCategory(index)">
-          {{ category.categoryName }}
-        </view>
-      </scroll-view>
+      <view class="category-list-wrap">
+        <scroll-view class="category-list" scroll-y>
+          <view v-for="(category, index) in categories" :key="index" class="category-item"
+            :class="{ active: currentCategoryIndex === index }" @click="selectCategory(index)">
+            {{ category.categoryName }}
+          </view>
+        </scroll-view>
+      </view>
 
       <!-- 右侧菜品列表 -->
-      <scroll-view class="food-list" scroll-y>
-        <FoodCard v-for="(food, index) in currentFoodList" :key="food.id || food.cuisineId || index" :food="food"
-          :table-id="tableId" @increase="handleIncrease" @decrease="handleDecrease"/>
-      </scroll-view>
+      <view class="food-list-wrap">
+        <scroll-view class="food-list" scroll-y>
+          <FoodCard v-for="(food, index) in currentFoodList" :key="food.id || food.cuisineId || index" :food="food"
+            :table-id="tableId" @increase="handleIncrease" @decrease="handleDecrease"/>
+        </scroll-view>
+      </view>
     </view>
 
     <!-- 底部下单:按接口格式展示 totalQuantity / totalAmount -->
@@ -54,14 +58,17 @@ import CouponModal from "./components/CouponModal.vue";
 import CartModal from "./components/CartModal.vue";
 import SelectCouponModal from "./components/SelectCouponModal.vue";
 import { go } from "@/utils/utils.js";
-import { DiningOrderFood, GetStoreCategories, GetStoreCuisines, getOrderSseConfig, GetOrderCart, PostOrderCartAdd, PostOrderCartUpdate, PostOrderCartClear, PutOrderCartUpdateTableware, GetUserOwnedCouponList } from "@/api/dining.js";
+import { DiningOrderFood, GetStoreCategories, GetStoreCuisines, GetStoreDetail, getOrderSseConfig, GetOrderCart, PostOrderCartAdd, PostOrderCartUpdate, PostOrderCartClear, PutOrderCartUpdateTableware, GetUserOwnedCouponList } from "@/api/dining.js";
 import { createSSEConnection } from "@/utils/sse.js";
 
+const storeName = ref(''); // 店铺名称,用于导航栏标题
 const tableId = ref(''); // 桌号ID,来自上一页 url 参数 tableid,用于接口入参
 const tableNumber = ref(''); // 桌号展示,来自 dining/page-info 接口返回的 tableNumber
 const tableNumberFetched = ref(false); // 是否已请求过桌号(避免未返回前用 tableId 展示导致闪一下 43)
 const currentDiners = ref(uni.getStorageSync('currentDiners') || '');
 
+const navTitle = computed(() => storeName.value || '点餐');
+
 // 桌号展示:优先用接口返回的 tableNumber,未请求完前不显示 tableId,避免闪 43 再变 2
 const displayTableNumber = computed(() => {
   if (tableNumber.value) return tableNumber.value;
@@ -70,6 +77,7 @@ const displayTableNumber = computed(() => {
 });
 let sseRequestTask = null; // 订单 SSE 连接(封装后兼容小程序),页面卸载时需 abort()
 const currentCategoryIndex = ref(0);
+const foodListScrollTop = ref(0);
 const couponModalOpen = ref(false);
 const cartModalOpen = ref(false);
 const selectCouponModalOpen = ref(false);
@@ -636,6 +644,7 @@ onLoad(async (options) => {
       const data = res?.data ?? res ?? {};
       tableNumber.value = data?.tableNumber ?? data?.tableNo ?? '';
       tableNumberFetched.value = true;
+      storeName.value = data?.storeName ?? data?.storeInfo?.storeName ?? '';
       // 餐具费:点餐页接口可能返回,若购物车未带则用此处兜底
       const fee = Number(data?.tablewareFee ?? data?.tablewareAmount ?? 0) || 0;
       if (fee > 0) cartData.value = { ...cartData.value, tablewareFee: fee };
@@ -643,6 +652,13 @@ onLoad(async (options) => {
       // 成功后调接口获取菜品种类(storeId 取自点餐页接口返回,若无则需从别处获取)
       const storeId = res?.storeId ?? data?.storeId ?? '';
       if (storeId) uni.setStorageSync('currentStoreId', storeId);
+      if (storeId && !storeName.value) {
+        try {
+          const storeRes = await GetStoreDetail(storeId);
+          const storeData = storeRes?.data ?? storeRes;
+          storeName.value = storeData?.storeInfo?.storeName ?? storeData?.storeName ?? '';
+        } catch (_) {}
+      }
       if (storeId) {
         try {
           const categoriesRes = await GetStoreCategories({ storeId });
@@ -675,6 +691,14 @@ onLoad(async (options) => {
     }
   } else {
     tableNumberFetched.value = true;
+    const storeId = uni.getStorageSync('currentStoreId') || '';
+    if (storeId && !storeName.value) {
+      try {
+        const storeRes = await GetStoreDetail(storeId);
+        const storeData = storeRes?.data ?? storeRes;
+        storeName.value = storeData?.storeInfo?.storeName ?? storeData?.storeName ?? '';
+      } catch (_) {}
+    }
   }
 });
 
@@ -695,12 +719,28 @@ onUnload(() => {
 </script>
 
 <style lang="scss" scoped>
-.content {
+.page-wrap {
+  height: 100vh;
+  overflow: hidden;
   display: flex;
   flex-direction: column;
-  height: 100vh;
   background-color: #f7f9fa;
-  padding-bottom: 100rpx;
+}
+.top-fixed {
+  flex-shrink: 0;
+  z-index: 100;
+  background-color: #fff;
+  padding-bottom: 20rpx;
+}
+.content {
+  flex: 1;
+  min-height: 0;
+  overflow: hidden;
+  display: flex;
+  flex-direction: column;
+  /* 底部预留:BottomActionBar 高度(100rpx) + 内边距(20rpx) + 安全区 */
+  padding-bottom: calc(120rpx + constant(safe-area-inset-bottom));
+  padding-bottom: calc(120rpx + env(safe-area-inset-bottom));
   box-sizing: border-box;
 }
 
@@ -727,17 +767,29 @@ onUnload(() => {
 }
 
 .content-box {
-  display: flex;
   flex: 1;
+  min-height: 0;
   overflow: hidden;
+  display: flex;
   margin-top: 20rpx;
 }
 
-// 左侧分类列表
-.category-list {
+// 左侧分类列表容器(给 scroll-view 提供固定高度)
+.category-list-wrap {
   width: 180rpx;
-  background-color: #fff;
+  flex-shrink: 0;
+  min-height: 0;
+  display: flex;
+  flex-direction: column;
+  overflow: hidden;
+  align-self: stretch;
+}
+.category-list {
+  flex: 1;
+  min-height: 0;
   height: 100%;
+  background-color: #fff;
+  box-sizing: border-box;
 }
 
 .category-item {
@@ -757,11 +809,19 @@ onUnload(() => {
   }
 }
 
-// 右侧菜品列表
-.food-list {
+// 右侧菜品列表容器(给 scroll-view 提供固定高度)
+.food-list-wrap {
   flex: 1;
-  // background-color: #fff;
-  // padding: 0 20rpx;
+  min-width: 0;
+  min-height: 0;
+  display: flex;
+  flex-direction: column;
+  overflow: hidden;
   margin: 0 20rpx;
 }
+.food-list {
+  flex: 1;
+  min-height: 0;
+  height: 100%;
+}
 </style>