|
@@ -22,16 +22,17 @@
|
|
|
</scroll-view>
|
|
</scroll-view>
|
|
|
</view>
|
|
</view>
|
|
|
|
|
|
|
|
- <!-- 底部下单 -->
|
|
|
|
|
- <BottomActionBar :cart-list="cartList" @coupon-click="handleCouponClick" @cart-click="handleCartClick"
|
|
|
|
|
|
|
+ <!-- 底部下单:按接口格式展示 totalQuantity / totalAmount -->
|
|
|
|
|
+ <BottomActionBar :cart-list="displayCartList" :total-quantity="displayTotalQuantity"
|
|
|
|
|
+ :total-amount="displayTotalAmount" @coupon-click="handleCouponClick" @cart-click="handleCartClick"
|
|
|
@order-click="handleOrderClick" />
|
|
@order-click="handleOrderClick" />
|
|
|
|
|
|
|
|
<!-- 领取优惠券弹窗 -->
|
|
<!-- 领取优惠券弹窗 -->
|
|
|
<CouponModal v-model:open="couponModalOpen" :coupon-list="couponList" @receive="handleCouponReceive"
|
|
<CouponModal v-model:open="couponModalOpen" :coupon-list="couponList" @receive="handleCouponReceive"
|
|
|
@close="handleCouponClose" />
|
|
@close="handleCouponClose" />
|
|
|
|
|
|
|
|
- <!-- 购物车弹窗 -->
|
|
|
|
|
- <CartModal v-model:open="cartModalOpen" :cart-list="cartList" :discount-amount="discountAmount"
|
|
|
|
|
|
|
+ <!-- 购物车弹窗:按接口格式展示 items(cuisineName/cuisineImage/quantity/unitPrice/subtotalAmount/remark) -->
|
|
|
|
|
+ <CartModal v-model:open="cartModalOpen" :cart-list="displayCartList" :discount-amount="discountAmount"
|
|
|
@increase="handleIncrease" @decrease="handleDecrease" @clear="handleCartClear"
|
|
@increase="handleIncrease" @decrease="handleDecrease" @clear="handleCartClear"
|
|
|
@coupon-click="handleSelectCouponClick" @order-click="handleOrderClick" @close="handleCartClose" />
|
|
@coupon-click="handleSelectCouponClick" @order-click="handleOrderClick" @close="handleCartClose" />
|
|
|
|
|
|
|
@@ -42,7 +43,7 @@
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup>
|
|
<script setup>
|
|
|
-import { onLoad } from "@dcloudio/uni-app";
|
|
|
|
|
|
|
+import { onLoad, onUnload } from "@dcloudio/uni-app";
|
|
|
import { ref, computed } from "vue";
|
|
import { ref, computed } from "vue";
|
|
|
import FoodCard from "./components/FoodCard.vue";
|
|
import FoodCard from "./components/FoodCard.vue";
|
|
|
import BottomActionBar from "./components/BottomActionBar.vue";
|
|
import BottomActionBar from "./components/BottomActionBar.vue";
|
|
@@ -50,10 +51,11 @@ import CouponModal from "./components/CouponModal.vue";
|
|
|
import CartModal from "./components/CartModal.vue";
|
|
import CartModal from "./components/CartModal.vue";
|
|
|
import SelectCouponModal from "./components/SelectCouponModal.vue";
|
|
import SelectCouponModal from "./components/SelectCouponModal.vue";
|
|
|
import { go } from "@/utils/utils.js";
|
|
import { go } from "@/utils/utils.js";
|
|
|
-import { DiningOrderFood, GetStoreCategories, GetStoreCuisines } from "@/api/dining.js";
|
|
|
|
|
|
|
+import { DiningOrderFood, GetStoreCategories, GetStoreCuisines, createOrderSseConnection, GetOrderCart, PostOrderCartAdd, PostOrderCartUpdate } from "@/api/dining.js";
|
|
|
|
|
|
|
|
const tableId = ref(''); // 桌号,来自上一页 url 参数 tableid
|
|
const tableId = ref(''); // 桌号,来自上一页 url 参数 tableid
|
|
|
const currentDiners = ref(uni.getStorageSync('currentDiners') || '');
|
|
const currentDiners = ref(uni.getStorageSync('currentDiners') || '');
|
|
|
|
|
+let sseRequestTask = null; // 订单 SSE 连接,页面卸载时需 abort
|
|
|
const currentCategoryIndex = ref(0);
|
|
const currentCategoryIndex = ref(0);
|
|
|
const couponModalOpen = ref(false);
|
|
const couponModalOpen = ref(false);
|
|
|
const cartModalOpen = ref(false);
|
|
const cartModalOpen = ref(false);
|
|
@@ -66,6 +68,10 @@ const categories = ref([]);
|
|
|
|
|
|
|
|
// 菜品列表(由接口 /store/info/cuisines 按分类拉取并合并,每项含 quantity、categoryId)
|
|
// 菜品列表(由接口 /store/info/cuisines 按分类拉取并合并,每项含 quantity、categoryId)
|
|
|
const foodList = ref([]);
|
|
const foodList = ref([]);
|
|
|
|
|
+// SSE 连接建立后拉取的购物车数据,在 foodList 就绪后合并
|
|
|
|
|
+let pendingCartData = null;
|
|
|
|
|
+// 购物车接口返回的完整数据:{ items, totalAmount, totalQuantity },用于按接口格式展示
|
|
|
|
|
+const cartData = ref({ items: [], totalAmount: 0, totalQuantity: 0 });
|
|
|
|
|
|
|
|
// 当前分类的菜品列表(按当前选中的分类 id 过滤)
|
|
// 当前分类的菜品列表(按当前选中的分类 id 过滤)
|
|
|
const currentFoodList = computed(() => {
|
|
const currentFoodList = computed(() => {
|
|
@@ -87,6 +93,35 @@ const cartList = computed(() => {
|
|
|
});
|
|
});
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
|
|
+// 用于展示的购物车列表:优先使用接口返回的 items(含 cuisineName/cuisineImage/unitPrice/subtotalAmount/remark),只展示数量>0
|
|
|
|
|
+const displayCartList = computed(() => {
|
|
|
|
|
+ const apiItems = cartData.value?.items;
|
|
|
|
|
+ if (Array.isArray(apiItems) && apiItems.length > 0) {
|
|
|
|
|
+ return apiItems.filter((it) => (Number(it?.quantity) || 0) > 0);
|
|
|
|
|
+ }
|
|
|
|
|
+ return cartList.value;
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+// 展示用总数量:优先接口 totalQuantity,否则从列表计算
|
|
|
|
|
+const displayTotalQuantity = computed(() => {
|
|
|
|
|
+ if (Array.isArray(cartData.value?.items) && cartData.value.items.length > 0 && cartData.value.totalQuantity != null) {
|
|
|
|
|
+ return cartData.value.totalQuantity;
|
|
|
|
|
+ }
|
|
|
|
|
+ return displayCartList.value.reduce((sum, item) => sum + (Number(item?.quantity) || 0), 0);
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+// 展示用总金额:优先接口 totalAmount,否则从列表计算
|
|
|
|
|
+const displayTotalAmount = computed(() => {
|
|
|
|
|
+ if (Array.isArray(cartData.value?.items) && cartData.value.items.length > 0 && cartData.value.totalAmount != null) {
|
|
|
|
|
+ return cartData.value.totalAmount;
|
|
|
|
|
+ }
|
|
|
|
|
+ return displayCartList.value.reduce((sum, item) => {
|
|
|
|
|
+ const qty = Number(item?.quantity) || 0;
|
|
|
|
|
+ const price = Number(item?.subtotalAmount ?? item?.unitPrice ?? item?.price ?? item?.totalPrice ?? 0) || 0;
|
|
|
|
|
+ return sum + (item?.subtotalAmount != null ? Number(item.subtotalAmount) : qty * price);
|
|
|
|
|
+ }, 0);
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
// 优惠券列表(示例数据)
|
|
// 优惠券列表(示例数据)
|
|
|
const couponList = ref([
|
|
const couponList = ref([
|
|
|
{
|
|
{
|
|
@@ -131,6 +166,76 @@ const availableCoupons = computed(() => {
|
|
|
// 分类 id 统一转字符串,避免 number/string 比较导致误判
|
|
// 分类 id 统一转字符串,避免 number/string 比较导致误判
|
|
|
const sameCategory = (a, b) => String(a ?? '') === String(b ?? '');
|
|
const sameCategory = (a, b) => String(a ?? '') === String(b ?? '');
|
|
|
|
|
|
|
|
|
|
+// 将购物车数量同步到菜品列表:用购物车接口的 items 按 cuisineId 匹配 foodList 中的菜品并更新 quantity
|
|
|
|
|
+const mergeCartIntoFoodList = () => {
|
|
|
|
|
+ const cartItems = pendingCartData ?? cartData.value?.items ?? [];
|
|
|
|
|
+ if (!Array.isArray(cartItems) || cartItems.length === 0) return;
|
|
|
|
|
+ if (!foodList.value.length) {
|
|
|
|
|
+ console.log('购物车已缓存,等 foodList 加载后再同步到菜品列表');
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ foodList.value = foodList.value.map((item) => {
|
|
|
|
|
+ const itemId = String(item?.id ?? item?.cuisineId ?? '');
|
|
|
|
|
+ const cartItem = cartItems.find((c) => {
|
|
|
|
|
+ const cId = String(c?.id ?? c?.cuisineId ?? c?.foodId ?? c?.dishId ?? '');
|
|
|
|
|
+ return cId && cId === itemId;
|
|
|
|
|
+ });
|
|
|
|
|
+ const qty = cartItem
|
|
|
|
|
+ ? Number(cartItem.quantity ?? cartItem.num ?? cartItem.count ?? 0) || 0
|
|
|
|
|
+ : (item.quantity ?? 0);
|
|
|
|
|
+ return { ...item, quantity: qty };
|
|
|
|
|
+ });
|
|
|
|
|
+ pendingCartData = null;
|
|
|
|
|
+ console.log('购物车数量已同步到菜品列表');
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// 从接口返回的 data 层中解析出购物车数组(/store/order/cart/{id} 返回在 items 下)
|
|
|
|
|
+function parseCartListFromResponse(cartRes) {
|
|
|
|
|
+ if (cartRes == null) return [];
|
|
|
|
|
+ if (Array.isArray(cartRes.items)) return cartRes.items;
|
|
|
|
|
+ // 优先 items(当前接口约定),再兼容 list / data / records 等
|
|
|
|
|
+ const firstLevel =
|
|
|
|
|
+ cartRes.items ??
|
|
|
|
|
+ cartRes.list ??
|
|
|
|
|
+ cartRes.data ??
|
|
|
|
|
+ cartRes.records ??
|
|
|
|
|
+ cartRes.cartList ??
|
|
|
|
|
+ cartRes.cartItems ??
|
|
|
|
|
+ cartRes.cart?.list ??
|
|
|
|
|
+ cartRes.cart?.items ??
|
|
|
|
|
+ cartRes.result?.list ??
|
|
|
|
|
+ cartRes.result?.data ??
|
|
|
|
|
+ cartRes.result?.items;
|
|
|
|
|
+ if (Array.isArray(firstLevel)) return firstLevel;
|
|
|
|
|
+ if (typeof cartRes === 'object') {
|
|
|
|
|
+ const arr = Object.values(cartRes).find((v) => Array.isArray(v));
|
|
|
|
|
+ if (arr) return arr;
|
|
|
|
|
+ }
|
|
|
|
|
+ return [];
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 调获取购物车接口并合并到 foodList(需在 foodList 有数据后调用才能返显到购物车)
|
|
|
|
|
+// 注意:request 层在 code=200 时只返回 res.data.data,故 cartRes 已是后端 data 层
|
|
|
|
|
+const fetchAndMergeCart = async (tableid) => {
|
|
|
|
|
+ if (!tableid) return;
|
|
|
|
|
+ try {
|
|
|
|
|
+ const cartRes = await GetOrderCart(tableid);
|
|
|
|
|
+ const list = parseCartListFromResponse(cartRes);
|
|
|
|
|
+ pendingCartData = list;
|
|
|
|
|
+ // 按接口格式绑定:data.items / totalAmount / totalQuantity
|
|
|
|
|
+ cartData.value = {
|
|
|
|
|
+ items: list,
|
|
|
|
|
+ totalAmount: Number(cartRes?.totalAmount) || 0,
|
|
|
|
|
+ totalQuantity: Number(cartRes?.totalQuantity) || 0
|
|
|
|
|
+ };
|
|
|
|
|
+ mergeCartIntoFoodList();
|
|
|
|
|
+ console.log('购物车接口返回(data 层):', cartRes, '解析条数:', list.length);
|
|
|
|
|
+ } catch (err) {
|
|
|
|
|
+ console.error('获取购物车失败:', err);
|
|
|
|
|
+ throw err;
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
// 根据分类 id 拉取菜品并合并到 foodList,切换分类时保留其他分类已选菜品及本分类已选数量
|
|
// 根据分类 id 拉取菜品并合并到 foodList,切换分类时保留其他分类已选菜品及本分类已选数量
|
|
|
const fetchCuisinesByCategoryId = async (categoryId) => {
|
|
const fetchCuisinesByCategoryId = async (categoryId) => {
|
|
|
if (!categoryId) return;
|
|
if (!categoryId) return;
|
|
@@ -147,12 +252,14 @@ const fetchCuisinesByCategoryId = async (categoryId) => {
|
|
|
// 本分类:按菜品 id 从整份列表里取已选数量,id 一致则自动带上数量
|
|
// 本分类:按菜品 id 从整份列表里取已选数量,id 一致则自动带上数量
|
|
|
const merged = normalized.map((newItem) => {
|
|
const merged = normalized.map((newItem) => {
|
|
|
const existing = foodList.value.find(
|
|
const existing = foodList.value.find(
|
|
|
- (e) => String(e?.id ?? '') === String(newItem?.id ?? '')
|
|
|
|
|
|
|
+ (e) => String(e?.id ?? e?.cuisineId ?? '') === String(newItem?.id ?? newItem?.cuisineId ?? '')
|
|
|
);
|
|
);
|
|
|
const quantity = existing ? existing.quantity : (newItem.quantity ?? 0);
|
|
const quantity = existing ? existing.quantity : (newItem.quantity ?? 0);
|
|
|
return { ...newItem, quantity };
|
|
return { ...newItem, quantity };
|
|
|
});
|
|
});
|
|
|
foodList.value = [...rest, ...merged];
|
|
foodList.value = [...rest, ...merged];
|
|
|
|
|
+ // 切换分类后,把购物车数量再同步到当前分类的菜品列表
|
|
|
|
|
+ mergeCartIntoFoodList();
|
|
|
} catch (err) {
|
|
} catch (err) {
|
|
|
console.error('获取菜品失败:', err);
|
|
console.error('获取菜品失败:', err);
|
|
|
}
|
|
}
|
|
@@ -167,26 +274,89 @@ const selectCategory = async (index) => {
|
|
|
await fetchCuisinesByCategoryId(categoryId);
|
|
await fetchCuisinesByCategoryId(categoryId);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-// 更新菜品数量:菜品 id 一致则全部同步为同一数量,触发响应式使底部金额重新计算
|
|
|
|
|
|
|
+// 根据展示项(可能来自接口 cuisineId 或 foodList 的 id)找到 foodList 中的菜品
|
|
|
|
|
+const findFoodByCartItem = (item) => {
|
|
|
|
|
+ const id = item?.id ?? item?.cuisineId;
|
|
|
|
|
+ if (id == null) return null;
|
|
|
|
|
+ return foodList.value.find((f) => String(f?.id ?? f?.cuisineId ?? '') === String(id));
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// 同步 cartData:根据 cuisineId 更新 items 中对应项的 quantity、subtotalAmount,并重算 totalAmount、totalQuantity
|
|
|
|
|
+const syncCartDataFromFoodList = () => {
|
|
|
|
|
+ const items = cartData.value?.items ?? [];
|
|
|
|
|
+ if (!items.length) return;
|
|
|
|
|
+ let totalAmount = 0;
|
|
|
|
|
+ let totalQuantity = 0;
|
|
|
|
|
+ const nextItems = items.map((it) => {
|
|
|
|
|
+ const food = findFoodByCartItem(it);
|
|
|
|
|
+ const qty = food != null ? (food.quantity || 0) : (it.quantity || 0);
|
|
|
|
|
+ const unitPrice = Number(it?.unitPrice ?? it?.price ?? 0) || 0;
|
|
|
|
|
+ const subtotalAmount = qty * unitPrice;
|
|
|
|
|
+ totalAmount += subtotalAmount;
|
|
|
|
|
+ totalQuantity += qty;
|
|
|
|
|
+ return { ...it, quantity: qty, subtotalAmount };
|
|
|
|
|
+ });
|
|
|
|
|
+ cartData.value = { ...cartData.value, items: nextItems, totalAmount, totalQuantity };
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// 更新菜品数量:菜品 id 一致则全部同步为同一数量,触发响应式;新增加入购物车时调接口;并同步 cartData
|
|
|
const updateFoodQuantity = (food, delta) => {
|
|
const updateFoodQuantity = (food, delta) => {
|
|
|
if (!food) return;
|
|
if (!food) return;
|
|
|
- const id = food.id;
|
|
|
|
|
|
|
+ const id = food.id ?? food.cuisineId;
|
|
|
const nextQty = Math.max(0, (food.quantity || 0) + delta);
|
|
const nextQty = Math.max(0, (food.quantity || 0) + delta);
|
|
|
const sameId = (item) =>
|
|
const sameId = (item) =>
|
|
|
- String(item?.id ?? '') === String(id ?? '');
|
|
|
|
|
|
|
+ String(item?.id ?? item?.cuisineId ?? '') === String(id ?? '');
|
|
|
foodList.value = foodList.value.map((item) =>
|
|
foodList.value = foodList.value.map((item) =>
|
|
|
sameId(item) ? { ...item, quantity: nextQty } : item
|
|
sameId(item) ? { ...item, quantity: nextQty } : item
|
|
|
);
|
|
);
|
|
|
|
|
+ // 同步接口格式购物车:若 cartData 中有该项则更新,否则追加(来自菜品列表新加)
|
|
|
|
|
+ const items = cartData.value?.items ?? [];
|
|
|
|
|
+ const idx = items.findIndex((it) => String(it?.cuisineId ?? it?.id ?? '') === String(id));
|
|
|
|
|
+ if (idx >= 0) {
|
|
|
|
|
+ const it = items[idx];
|
|
|
|
|
+ const unitPrice = Number(it?.unitPrice ?? it?.price ?? 0) || 0;
|
|
|
|
|
+ const nextItems = items.slice();
|
|
|
|
|
+ nextItems[idx] = { ...it, quantity: nextQty, subtotalAmount: nextQty * unitPrice };
|
|
|
|
|
+ const totalAmount = nextItems.reduce((s, i) => s + (Number(i.subtotalAmount) || 0), 0);
|
|
|
|
|
+ const totalQuantity = nextItems.reduce((s, i) => s + (Number(i.quantity) || 0), 0);
|
|
|
|
|
+ cartData.value = { ...cartData.value, items: nextItems, totalAmount, totalQuantity };
|
|
|
|
|
+ } else if (delta > 0) {
|
|
|
|
|
+ // 来自菜品列表新加:按接口格式追加到 cartData.items
|
|
|
|
|
+ const unitPrice = Number(food?.price ?? food?.unitPrice ?? food?.salePrice ?? 0) || 0;
|
|
|
|
|
+ const newItem = {
|
|
|
|
|
+ cuisineId: id,
|
|
|
|
|
+ cuisineName: food?.name ?? food?.cuisineName ?? '',
|
|
|
|
|
+ cuisineImage: food?.image ?? food?.cuisineImage ?? food?.imageUrl ?? '',
|
|
|
|
|
+ quantity: nextQty,
|
|
|
|
|
+ unitPrice,
|
|
|
|
|
+ subtotalAmount: nextQty * unitPrice
|
|
|
|
|
+ };
|
|
|
|
|
+ const nextItems = [...items, newItem];
|
|
|
|
|
+ const totalAmount = nextItems.reduce((s, i) => s + (Number(i.subtotalAmount) || 0), 0);
|
|
|
|
|
+ const totalQuantity = nextItems.reduce((s, i) => s + (Number(i.quantity) || 0), 0);
|
|
|
|
|
+ cartData.value = { ...cartData.value, items: nextItems, totalAmount, totalQuantity };
|
|
|
|
|
+ }
|
|
|
|
|
+ // 增加数量且商品数量 >= 1 时调用 /store/order/cart/update
|
|
|
|
|
+ if (delta > 0 && nextQty >= 1 && tableId.value) {
|
|
|
|
|
+ const params = {
|
|
|
|
|
+ cuisineId: id,
|
|
|
|
|
+ quantity: nextQty,
|
|
|
|
|
+ tableId: tableId.value
|
|
|
|
|
+ }
|
|
|
|
|
+ PostOrderCartUpdate(params).catch((err) => console.error('更新购物车失败:', err));
|
|
|
|
|
+ }
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-// 增加数量
|
|
|
|
|
-const handleIncrease = (food) => {
|
|
|
|
|
|
|
+// 增加数量:支持传入接口项(cuisineId)或菜品项(id),先解析为 foodList 中的 food
|
|
|
|
|
+const handleIncrease = (item) => {
|
|
|
|
|
+ const food = item?.id != null && item?.cuisineId == null ? item : findFoodByCartItem(item) ?? item;
|
|
|
updateFoodQuantity(food, 1);
|
|
updateFoodQuantity(food, 1);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
// 减少数量
|
|
// 减少数量
|
|
|
-const handleDecrease = (food) => {
|
|
|
|
|
- updateFoodQuantity(food, -1);
|
|
|
|
|
|
|
+const handleDecrease = (item) => {
|
|
|
|
|
+ const food = item?.id != null && item?.cuisineId == null ? item : findFoodByCartItem(item) ?? item;
|
|
|
|
|
+ if (food && (food.quantity || 0) > 0) updateFoodQuantity(food, -1);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
// 优惠券点击(领取优惠券弹窗)
|
|
// 优惠券点击(领取优惠券弹窗)
|
|
@@ -255,7 +425,7 @@ const handleCouponClose = () => {
|
|
|
|
|
|
|
|
// 购物车点击
|
|
// 购物车点击
|
|
|
const handleCartClick = () => {
|
|
const handleCartClick = () => {
|
|
|
- if (cartList.value.length === 0) {
|
|
|
|
|
|
|
+ if (displayCartList.value.length === 0) {
|
|
|
uni.showToast({
|
|
uni.showToast({
|
|
|
title: '购物车为空',
|
|
title: '购物车为空',
|
|
|
icon: 'none'
|
|
icon: 'none'
|
|
@@ -279,9 +449,8 @@ const handleCartClose = () => {
|
|
|
|
|
|
|
|
// 清空购物车
|
|
// 清空购物车
|
|
|
const handleCartClear = () => {
|
|
const handleCartClear = () => {
|
|
|
- foodList.value.forEach(food => {
|
|
|
|
|
- food.quantity = 0;
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ foodList.value = foodList.value.map((f) => ({ ...f, quantity: 0 }));
|
|
|
|
|
+ cartData.value = { items: [], totalAmount: 0, totalQuantity: 0 };
|
|
|
cartModalOpen.value = false;
|
|
cartModalOpen.value = false;
|
|
|
uni.showToast({
|
|
uni.showToast({
|
|
|
title: '已清空购物车',
|
|
title: '已清空购物车',
|
|
@@ -302,6 +471,38 @@ onLoad(async (options) => {
|
|
|
currentDiners.value = diners;
|
|
currentDiners.value = diners;
|
|
|
console.log('点餐页接收参数 - 桌号(tableid):', tableid, '就餐人数(diners):', diners);
|
|
console.log('点餐页接收参数 - 桌号(tableid):', tableid, '就餐人数(diners):', diners);
|
|
|
|
|
|
|
|
|
|
+ // 先拉取购物车并缓存,再加载菜品,保证合并时 pendingCartData 已就绪,避免不返显
|
|
|
|
|
+ if (tableid) {
|
|
|
|
|
+ await fetchAndMergeCart(tableid).catch((err) => console.error('获取购物车失败:', err));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 页面加载时创建订单 SSE 连接(GET /store/order/sse/{tableId})
|
|
|
|
|
+ if (tableid) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ sseRequestTask = createOrderSseConnection(tableid);
|
|
|
|
|
+ if (sseRequestTask && typeof sseRequestTask.onChunkReceived === 'function') {
|
|
|
|
|
+ sseRequestTask.onChunkReceived((res) => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const uint8 = new Uint8Array(res.data);
|
|
|
|
|
+ const text = String.fromCharCode.apply(null, uint8);
|
|
|
|
|
+ console.log('SSE 收到:', text);
|
|
|
|
|
+ // 可在此解析 SSE 事件并更新页面
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ console.error('SSE 数据解析:', e);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ if (sseRequestTask && typeof sseRequestTask.onHeadersReceived === 'function') {
|
|
|
|
|
+ sseRequestTask.onHeadersReceived(async () => {
|
|
|
|
|
+ console.log('SSE 连接已建立');
|
|
|
|
|
+ await fetchAndMergeCart(tableid).catch(() => {});
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ console.error('SSE 连接失败:', e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// 调用点餐页接口,入参 dinerCount、tableId
|
|
// 调用点餐页接口,入参 dinerCount、tableId
|
|
|
if (tableid || diners) {
|
|
if (tableid || diners) {
|
|
|
try {
|
|
try {
|
|
@@ -331,6 +532,7 @@ onLoad(async (options) => {
|
|
|
categoryId: item.categoryId ?? firstCategoryId
|
|
categoryId: item.categoryId ?? firstCategoryId
|
|
|
}));
|
|
}));
|
|
|
console.log('默认分类菜品:', cuisinesRes);
|
|
console.log('默认分类菜品:', cuisinesRes);
|
|
|
|
|
+ mergeCartIntoFoodList();
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
console.log('菜品种类:', categoriesRes);
|
|
console.log('菜品种类:', categoriesRes);
|
|
@@ -343,6 +545,13 @@ onLoad(async (options) => {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
|
|
+
|
|
|
|
|
+onUnload(() => {
|
|
|
|
|
+ if (sseRequestTask && typeof sseRequestTask.abort === 'function') {
|
|
|
|
|
+ sseRequestTask.abort();
|
|
|
|
|
+ sseRequestTask = null;
|
|
|
|
|
+ }
|
|
|
|
|
+});
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
<style lang="scss" scoped>
|