Pārlūkot izejas kodu

结算的时候选择优惠卷

sunshibo 1 mēnesi atpakaļ
vecāks
revīzija
079c1bdef3
3 mainītis faili ar 139 papildinājumiem un 152 dzēšanām
  1. 136 2
      pages/checkout/index.vue
  2. 0 13
      pages/orderInfo/orderDetail.vue
  3. 3 137
      pages/placeOrder/index.vue

+ 136 - 2
pages/checkout/index.vue

@@ -68,11 +68,12 @@
           <view class="info-item-label">餐具费</view>
           <view class="info-item-value">¥{{ formatPrice(orderInfo.utensilFee ?? 0) }}</view>
         </view>
-        <view class="info-item info-item--coupon">
+        <view class="info-item info-item--coupon info-item--clickable" @click="onCouponRowClick">
           <view class="info-item-label">优惠券</view>
           <view class="info-item-value coupon-value">
             <text v-if="(orderInfo.discountAmount ?? 0) > 0" class="coupon-amount">{{ couponDisplayText }}</text>
-            <text v-else class="coupon-placeholder">—</text>
+            <text v-else class="coupon-placeholder">请选择</text>
+            <text class="coupon-arrow">›</text>
           </view>
         </view>
         <view v-if="(orderInfo.discountAmount ?? 0) > 0" class="info-item info-item--coupon">
@@ -91,6 +92,18 @@
     <view class="bottom-button">
       <view class="bottom-button-text" hover-class="hover-active" @click="handleConfirmPay">确认支付 ¥{{ formatPrice(orderInfo.payAmount ?? 0) }}</view>
     </view>
+
+    <!-- 选择优惠券弹窗 -->
+    <view class="coupon-modal-wrapper">
+      <SelectCouponModal
+        v-model:open="couponModalOpen"
+        :coupon-list="couponList"
+        :selected-coupon-id="selectedCouponId"
+        :view-only="false"
+        @select="handleCouponSelect"
+        @close="couponModalOpen = false"
+      />
+    </view>
   </view>
 </template>
 
@@ -101,6 +114,7 @@ import { go } from '@/utils/utils.js';
 import { getFileUrl } from '@/utils/file.js';
 import { useUserStore } from '@/store/user.js';
 import * as diningApi from '@/api/dining.js';
+import SelectCouponModal from '@/pages/orderFood/components/SelectCouponModal.vue';
 
 const orderId = ref('');
 const orderInfo = ref({
@@ -125,6 +139,11 @@ const orderInfo = ref({
 
 const foodList = ref([]);
 
+// 优惠券选择(结算页)
+const couponModalOpen = ref(false);
+const couponList = ref([]);
+const selectedCouponId = ref(null);
+
 // 菜品清单展示:包含所有项(含餐具 id/cuisineId === -1)
 const displayFoodList = computed(() => foodList.value ?? []);
 
@@ -150,6 +169,92 @@ const couponDisplayText = computed(() => {
   return o.couponName || '已使用优惠券';
 });
 
+// 规范化优惠券项(供 SelectCouponModal 使用)
+function normalizeCouponItem(item) {
+  if (!item || typeof item !== 'object') return null;
+  const raw = item;
+  const couponType = Number(raw.couponType) || 0;
+  const nominalValue = Number(raw.nominalValue ?? raw.amount ?? 0) || 0;
+  const discountRate = ((Number(raw.discountRate) || 0) / 10) || 0;
+  const minAmount = Number(raw.minimumSpendingAmount ?? raw.minAmount ?? 0) || 0;
+  let amountDisplay = nominalValue + '元';
+  if (couponType === 1) amountDisplay = nominalValue + '元';
+  else if (couponType === 2 && discountRate > 0) amountDisplay = (discountRate % 1 === 0 ? discountRate : discountRate.toFixed(1)) + '折';
+  return {
+    id: raw.userCouponId ?? raw.id ?? raw.couponId ?? '',
+    couponId: raw.couponId ?? raw.id ?? raw.userCouponId ?? '',
+    amount: nominalValue,
+    minAmount,
+    name: raw.name ?? raw.title ?? raw.couponName ?? '',
+    expireDate: raw.expirationTime ?? raw.endGetDate ?? raw.expireDate ?? '',
+    couponType,
+    discountRate,
+    amountDisplay
+  };
+}
+
+// 点击优惠券行:打开选择弹窗
+const onCouponRowClick = () => {
+  openCouponModal();
+};
+
+// 打开优惠券弹窗并拉取用户可用券
+const openCouponModal = async () => {
+  const storeId = orderInfo.value.storeId || uni.getStorageSync('currentStoreId') || '';
+  couponModalOpen.value = false;
+  if (!storeId) {
+    uni.showToast({ title: '暂无门店信息', icon: 'none' });
+    return;
+  }
+  try {
+    const res = await diningApi.GetUserOwnedCouponList({ storeId });
+    const list = Array.isArray(res) ? res : (res?.data ?? res?.records ?? res?.list ?? []);
+    const normalized = (Array.isArray(list) ? list : []).map(normalizeCouponItem).filter(Boolean);
+    couponList.value = normalized;
+    couponModalOpen.value = true;
+  } catch (err) {
+    console.error('获取优惠券失败:', err);
+    uni.showToast({ title: '获取优惠券失败', icon: 'none' });
+  }
+};
+
+// 选择优惠券后更新订单优惠与应付金额
+const handleCouponSelect = ({ coupon, selectedId }) => {
+  const hasSelected = selectedId != null && selectedId !== '';
+  selectedCouponId.value = hasSelected ? String(selectedId) : null;
+  orderInfo.value.couponId = hasSelected ? (coupon?.couponId ?? coupon?.id ?? selectedCouponId.value) : null;
+  if (!hasSelected) {
+    orderInfo.value.discountAmount = 0;
+    orderInfo.value.couponName = '';
+    orderInfo.value.couponType = null;
+    orderInfo.value.discountRate = null;
+    orderInfo.value.nominalValue = null;
+  } else if (coupon) {
+    orderInfo.value.couponName = coupon.name ?? '';
+    orderInfo.value.couponType = Number(coupon.couponType) ?? null;
+    orderInfo.value.discountRate = coupon.discountRate != null ? coupon.discountRate : null;
+    orderInfo.value.nominalValue = coupon.amount != null ? coupon.amount : null;
+    const total = Number(orderInfo.value.totalAmount) || 0;
+    const couponType = Number(coupon.couponType) || 0;
+    if (couponType === 2 && coupon.discountRate != null && total > 0) {
+      const rate = Number(coupon.discountRate) || 0;
+      orderInfo.value.discountAmount = Math.round(total * (1 - rate / 10) * 100) / 100;
+    } else {
+      orderInfo.value.discountAmount = Number(coupon.amount) || 0;
+    }
+  }
+  updateCheckoutPayAmount();
+  couponModalOpen.value = false;
+};
+
+// 根据菜品总价、餐具费、优惠额计算应付金额
+const updateCheckoutPayAmount = () => {
+  const total = Number(orderInfo.value.totalAmount) || 0;
+  const utensil = Number(orderInfo.value.utensilFee) || 0;
+  const discount = Number(orderInfo.value.discountAmount) || 0;
+  orderInfo.value.payAmount = Math.max(0, total + utensil - discount);
+};
+
 function formatPrice(price) {
   const num = Number(price);
   return Number.isNaN(num) ? '0.00' : num.toFixed(2);
@@ -221,6 +326,7 @@ const fetchOrderDetail = async () => {
     orderInfo.value.payAmount = Number(raw?.payAmount ?? raw?.totalAmount ?? raw?.totalPrice ?? 0) || 0;
     const list = raw?.orderItemList ?? raw?.orderItems ?? raw?.items ?? raw?.detailList ?? [];
     foodList.value = (Array.isArray(list) ? list : []).map(normalizeOrderItem);
+    selectedCouponId.value = orderInfo.value.couponId != null && orderInfo.value.couponId !== '' ? String(orderInfo.value.couponId) : null;
   } catch (err) {
     console.error('获取订单详情失败:', err);
     uni.showToast({ title: '加载失败', icon: 'none' });
@@ -395,6 +501,13 @@ onUnload(() => {
     .coupon-placeholder {
       color: #999999;
     }
+    .coupon-arrow {
+      color: #999;
+      margin-left: 4rpx;
+    }
+    &--clickable {
+      cursor: pointer;
+    }
   }
 
   .price-line {
@@ -508,4 +621,25 @@ onUnload(() => {
     opacity: 0.9;
   }
 }
+
+.coupon-modal-wrapper {
+  position: relative;
+  z-index: 99999;
+  :deep(.uni-popup) {
+    z-index: 99999 !important;
+    top: 0 !important;
+    left: 0 !important;
+    right: 0 !important;
+    bottom: 0 !important;
+  }
+  :deep(.uni-popup__wrapper) {
+    z-index: 99999 !important;
+  }
+  :deep(.select-coupon-modal__list) {
+    padding-bottom: calc(60rpx + env(safe-area-inset-bottom));
+  }
+  :deep(.select-coupon-modal__empty) {
+    margin-bottom: 60rpx;
+  }
+}
 </style>

+ 0 - 13
pages/orderInfo/orderDetail.vue

@@ -50,19 +50,6 @@
           <view class="info-item-label">餐具费</view>
           <view class="info-item-value">¥{{ priceDetail.tablewareFee }}</view>
         </view>
-        <view class="info-item info-item--coupon">
-          <view class="info-item-label">优惠券</view>
-          <view class="info-item-value coupon-value">
-            <text v-if="couponDisplayText !== '—'" class="coupon-amount">{{ couponDisplayText }}</text>
-            <text v-else class="coupon-placeholder">—</text>
-          </view>
-        </view>
-        <view v-if="(priceDetail.discountAmount ?? 0) > 0" class="info-item info-item--coupon">
-          <view class="info-item-label">优惠金额</view>
-          <view class="info-item-value coupon-value">
-            <text class="coupon-amount">-¥{{ formatPrice(priceDetail.discountAmount) }}</text>
-          </view>
-        </view>
         <view class="price-line">
           <view class="price-line-label">合计</view>
           <view class="price-line-value">¥{{ priceDetail.total }}</view>

+ 3 - 137
pages/placeOrder/index.vue

@@ -82,20 +82,7 @@
           <view class="info-item-label">餐具费</view>
           <view class="info-item-value">¥{{ formatPrice(orderInfo.utensilFee ?? 0) }}</view>
         </view>
-        <view class="info-item info-item--coupon info-item--clickable" @click="onCouponRowClick">
-          <view class="info-item-label">优惠券</view>
-          <view class="info-item-value coupon-value">
-            <text v-if="selectedCouponDisplay" class="coupon-amount">{{ selectedCouponDisplay }}</text>
-            <text v-else class="coupon-placeholder">请选择</text>
-            <text class="coupon-arrow">›</text>
-          </view>
-        </view>
-        <view v-if="(orderInfo.discountAmount ?? 0) > 0" class="info-item info-item--coupon">
-          <view class="info-item-label">优惠金额</view>
-          <view class="info-item-value coupon-value">
-            <text class="coupon-amount">-¥{{ formatPrice(orderInfo.discountAmount) }}</text>
-          </view>
-        </view>
+
         <view class="price-line">
           <view class="price-line-label">应付金额</view>
           <view class="price-line-value">¥{{ formatPrice(orderInfo.payAmount ?? orderInfo.totalAmount) }}</view>
@@ -108,17 +95,6 @@
       <view class="bottom-button-text" hover-class="hover-active" @click="handleConfirmOrder">确认下单</view>
     </view>
 
-    <!-- 选择优惠券弹窗(需盖住底部确认订单按钮) -->
-    <view class="coupon-modal-wrapper">
-      <SelectCouponModal
-        v-model:open="couponModalOpen"
-        :coupon-list="couponList"
-        :selected-coupon-id="selectedCouponId"
-        :view-only="false"
-        @select="handleCouponSelect"
-        @close="couponModalOpen = false"
-      />
-    </view>
   </view>
 </template>
 
@@ -129,7 +105,6 @@ import { go } from "@/utils/utils.js";
 import { getFileUrl } from "@/utils/file.js";
 import { useUserStore } from "@/store/user.js";
 import * as diningApi from "@/api/dining.js";
-import SelectCouponModal from "@/pages/orderFood/components/SelectCouponModal.vue";
 
 // 订单信息(从购物车带过来或 URL 参数)
 const orderInfo = ref({
@@ -147,13 +122,6 @@ const orderInfo = ref({
   couponId: null
 });
 
-// 优惠券选择
-const couponModalOpen = ref(false);
-const selectedCouponId = ref(null);
-const couponList = ref([]);
-/** 选中券的展示文案(如 "5.5折"、"10元"),用于价格明细展示 */
-const selectedCouponDisplay = ref('');
-
 // 菜品列表(从购物车带过来)
 const foodList = ref([]);
 
@@ -193,81 +161,11 @@ function formatPrice(price) {
   return Number.isNaN(num) ? '0.00' : num.toFixed(2);
 }
 
-// 规范化优惠券项(与 orderFood 的 normalizeCouponItem 一致,供 SelectCouponModal 使用)
-function normalizeCouponItem(item) {
-  if (!item || typeof item !== 'object') return null;
-  const raw = item;
-  const couponType = Number(raw.couponType) || 0;
-  const nominalValue = Number(raw.nominalValue ?? raw.amount ?? 0) || 0;
-  const discountRate = ((Number(raw.discountRate) || 0) / 10) || 0;
-  const minAmount = Number(raw.minimumSpendingAmount ?? raw.minAmount ?? 0) || 0;
-  let amountDisplay = nominalValue + '元';
-  if (couponType === 1) amountDisplay = nominalValue + '元';
-  else if (couponType === 2 && discountRate > 0) amountDisplay = (discountRate % 1 === 0 ? discountRate : discountRate.toFixed(1)) + '折';
-  return {
-    id: raw.userCouponId ?? raw.id ?? raw.couponId ?? '',
-    couponId: raw.couponId ?? raw.id ?? raw.userCouponId ?? '',
-    amount: nominalValue,
-    minAmount,
-    name: raw.name ?? raw.title ?? raw.couponName ?? '',
-    expireDate: raw.expirationTime ?? raw.endGetDate ?? raw.expireDate ?? '',
-    couponType,
-    discountRate,
-    amountDisplay
-  };
-}
-
-// 点击优惠券行:打开选择弹窗
-const onCouponRowClick = () => {
-  openCouponModal();
-};
-
-// 打开优惠券弹窗并拉取用户可用券
-const openCouponModal = async () => {
-  const storeId = uni.getStorageSync('currentStoreId') || '';
-  couponModalOpen.value = false;
-  try {
-    const res = await diningApi.GetUserOwnedCouponList({ storeId });
-    const list = Array.isArray(res) ? res : (res?.data ?? res?.records ?? res?.list ?? []);
-    const normalized = (Array.isArray(list) ? list : []).map(normalizeCouponItem).filter(Boolean);
-    couponList.value = normalized;
-    couponModalOpen.value = true;
-  } catch (err) {
-    console.error('获取优惠券失败:', err);
-    uni.showToast({ title: '获取优惠券失败', icon: 'none' });
-  }
-};
-
-// 选择优惠券后更新订单优惠与应付金额(折扣券按折扣率计算优惠金额);取消选中时 selectedId 为空,需清空展示
-const handleCouponSelect = ({ coupon, selectedId }) => {
-  const hasSelected = selectedId != null && selectedId !== '';
-  selectedCouponId.value = hasSelected ? String(selectedId) : null;
-  orderInfo.value.couponId = hasSelected ? (coupon?.couponId ?? coupon?.id ?? selectedCouponId.value) : null;
-  if (!hasSelected) {
-    selectedCouponDisplay.value = '';
-    orderInfo.value.discountAmount = 0;
-  } else if (coupon) {
-    selectedCouponDisplay.value = coupon.amountDisplay || (coupon.amount ? coupon.amount + '元' : '');
-    const total = dishTotal.value;
-    const couponType = Number(coupon.couponType) || 0;
-    if (couponType === 2 && coupon.discountRate != null && total > 0) {
-      // 折扣券:优惠金额 = 菜品总价 × (1 - 折数/10),如 5.5折 即 优惠 = 总价 × 0.45
-      const rate = Number(coupon.discountRate) || 0;
-      orderInfo.value.discountAmount = Math.round(total * (1 - rate / 10) * 100) / 100;
-    } else {
-      orderInfo.value.discountAmount = Number(coupon.amount) || 0;
-    }
-  }
-  updatePayAmount();
-  couponModalOpen.value = false;
-};
-
-// 根据菜品总价(不含餐具)、餐具费、优惠额计算应付金额
+// 根据菜品总价(不含餐具)、餐具费计算应付金额(优惠券在结算页选择,确认订单页不选券)
 const updatePayAmount = () => {
   const dish = dishTotal.value;
   const utensil = Number(orderInfo.value.utensilFee) || 0;
-  const discount = Number(orderInfo.value.discountAmount) || 0;
-  orderInfo.value.payAmount = Math.max(0, dish + utensil - discount);
+  orderInfo.value.payAmount = Math.max(0, dish + utensil);
 };
 
 // 将 tags 统一为 [{ text, type }] 格式
@@ -325,15 +223,10 @@ const handleConfirmOrder = async () => {
     const tablewareFee = Number(orderInfo.value.utensilFee) || 0;
     const payAmount = Number((Number(orderInfo.value.payAmount) ?? 0).toFixed(2));
     const totalAmount = Number((Number(dishTotal.value) ?? 0).toFixed(2));
-    const couponIdVal = orderInfo.value.couponId ?? selectedCouponId.value;
-    const couponIdToSend = (couponIdVal != null && couponIdVal !== '') ? String(couponIdVal) : null;
     const createParams = {
       tableId,
       contactPhone,
       totalAmount,
-      couponId: couponIdToSend,
-      userCouponId: couponIdToSend,
-      discountAmount: orderInfo.value.discountAmount ?? 0,
       tablewareFee,
       payAmount,
       dinerCount: dinerCount || undefined,
@@ -390,11 +283,6 @@ onLoad((options) => {
       if (data.dishTotal != null && data.dishTotal !== '') orderInfo.value.dishTotal = Number(data.dishTotal) || 0;
       const fee = data.utensilFee ?? data.tablewareFee;
       if (fee != null && fee !== '') orderInfo.value.utensilFee = Number(fee) || 0;
-      if (data.discountAmount != null) orderInfo.value.discountAmount = data.discountAmount;
-      if (data.couponId != null) {
-        selectedCouponId.value = data.couponId;
-        orderInfo.value.couponId = data.couponId;
-      }
       updatePayAmount();
     } catch (e) {
       console.error('解析购物车数据失败:', e);
@@ -606,28 +494,6 @@ onUnload(() => {
   }
 }
 
-/* 优惠券弹窗层级:需盖住底部确认订单按钮(z-index:999);确认订单页减小底部留白 */
-.coupon-modal-wrapper {
-  position: relative;
-  z-index: 99999;
-  :deep(.uni-popup) {
-    z-index: 99999 !important;
-    top: 0 !important;
-    left: 0 !important;
-    right: 0 !important;
-    bottom: 0 !important;
-  }
-  :deep(.uni-popup__wrapper) {
-    z-index: 99999 !important;
-  }
-  :deep(.select-coupon-modal__list) {
-    padding-bottom: calc( env(safe-area-inset-bottom));
-  }
-  :deep(.select-coupon-modal__empty) {
-    margin-bottom: 60rpx;
-  }
-}
-
 .bottom-button {
   width: 100%;
   background-color: #fff;