Prechádzať zdrojové kódy

bug修复和功能优化

徐滕 2 týždňov pred
rodič
commit
caa2845358

+ 3 - 9
forge-admin-ui/src/views/hotel/qrcode.vue

@@ -43,7 +43,7 @@
     <NModal v-model:show="showBatchGenerate" preset="dialog" title="批量生成二维码" positive-text="生成" negative-text="取消" @positive-click="handleBatchGenerate">
       <NForm>
         <NFormItem label="生成数量">
-          <NSelect v-model:value="batchCount" :options="batchCountOptions" />
+          <NInputNumber v-model:value="batchCount" :min="1" :max="1000" :step="10" placeholder="请输入生成数量" style="width: 100%;" />
         </NFormItem>
       </NForm>
     </NModal>
@@ -111,7 +111,7 @@
 <script setup>
 import { computed, h, ref } from 'vue'
 import { Add, TrashOutline, DownloadOutline } from '@vicons/ionicons5'
-import { NButton, NDataTable, NForm, NFormItem, NIcon, NImage, NInput, NModal, NSelect, NTag } from 'naive-ui'
+import { NButton, NDataTable, NForm, NFormItem, NIcon, NImage, NInput, NInputNumber, NModal, NSelect, NTag } from 'naive-ui'
 import { AiCrudPage } from '@/components/ai-form'
 import DictTag from '@/components/DictTag.vue'
 import { useDict } from '@/composables/useDict'
@@ -234,19 +234,13 @@ function handleLoadSuccess() {
 // ==================== 选中管理 ====================
 const selectedIds = ref([])
 
-function handleSelectionChange(rows) {
+function handleSelectionChange({ rows }) {
   selectedIds.value = (rows || []).map(r => r.id)
 }
 
 // ==================== 批量生成 ====================
 const showBatchGenerate = ref(false)
 const batchCount = ref(10)
-const batchCountOptions = [
-  { label: '10个', value: 10 },
-  { label: '50个', value: 50 },
-  { label: '100个', value: 100 },
-  { label: '200个', value: 200 },
-]
 
 async function handleBatchGenerate() {
   try {

+ 12 - 2
forge-h5-ui/src/pages/hotel/customer/dish-detail.vue

@@ -254,9 +254,19 @@ function previewImage(index) {
   })
 }
 
-/** 选择规格 */
+/** 选择规格(必选组不可取消,可选组点击已选项可取消) */
 function selectSpec(group, opt) {
-  selectedSpecs[group.id] = opt.id
+  if (group.required) {
+    // 必选组:直接选中
+    selectedSpecs[group.id] = opt.id
+  } else {
+    // 可选组:点击已选项则取消,否则选中
+    if (selectedSpecs[group.id] === opt.id) {
+      delete selectedSpecs[group.id]
+    } else {
+      selectedSpecs[group.id] = opt.id
+    }
+  }
 }
 
 /** 切换加料 */

+ 21 - 0
forge-h5-ui/src/pages/hotel/customer/order-confirm.vue

@@ -167,6 +167,7 @@ function onCustomTimeChange(e) {
 
 onMounted(() => {
   loadPauseStatus()
+  loadGuestInfo()
 })
 
 /** 加载暂停接单状态 */
@@ -181,6 +182,26 @@ async function loadPauseStatus() {
   }
 }
 
+/** 从后端获取最新住客信息填充联系人(二次下单时 store 可能为空) */
+async function loadGuestInfo() {
+  // store 已有联系人则跳过,保留用户手动填写的值
+  if (orderStore.contactName && orderStore.contactPhone) return
+  const params = orderStore.scanParams
+  if (!params || !params.shortCode || !params.sign) return
+  try {
+    var res = await api.hotelCustomerScan({ shortCode: params.shortCode, sign: params.sign })
+    var data = res?.data || res
+    if (data?.room?.guestName || data?.room?.guestPhone) {
+      orderStore.setContactInfo(data.room.guestName, data.room.guestPhone)
+      // 同步更新本地 ref,确保页面立即显示
+      if (data.room.guestName) contactName.value = data.room.guestName
+      if (data.room.guestPhone) contactPhone.value = data.room.guestPhone
+    }
+  } catch (e) {
+    console.log('住客信息获取失败:', e?.message || e)
+  }
+}
+
 async function submitOrder() {
   if (!contactName.value.trim()) {
     uni.showToast({ title: '请输入联系人姓名', icon: 'none' })

+ 18 - 9
forge-h5-ui/src/pages/hotel/customer/room-confirm.vue

@@ -266,9 +266,15 @@ async function loadRoomInfo() {
       stayId: data.room?.stayId || null,
     }
 
+    // 在更新 Store 之前捕获旧 stayId,用于判断是否为同一客人重新扫码
+    const prevStayId = orderStore.roomInfo?.stayId || null
+    const newStayId = data.room?.stayId || null
+    const stayChanged = prevStayId !== null && newStayId !== null && prevStayId !== newStayId
+
     // 存入 Store
     orderStore.setTenantId(data.tenantId)
     orderStore.setRoomInfo(roomInfo.value)
+    orderStore.setScanParams(shortCode, sign)
 
     // 校验营业状态(非营业时段整页拦截,不给进菜单)
     const hoursState = await loadBusinessHours(data.tenantId)
@@ -289,12 +295,15 @@ async function loadRoomInfo() {
       return
     }
 
-    // 入住时前台已录入客人信息,自动回填到联系人(优先级高于支付宝授权)
+    // 联系人信息同步策略:
+    // 1. 房间有住客数据 → 以房间数据为准更新对应字段(前台录入/首单回写,是权威来源)
+    //    只更新有值的字段,缺失字段保留 store 旧值
+    // 2. 房间无住客数据 + stayId 变化 → 新客人,清空旧缓存防止串数据
+    // 3. 房间无住客数据 + stayId 不变 → 同一客人,保留已填写的联系人
     if (data.room?.guestName || data.room?.guestPhone) {
-      orderStore.setContactInfo(
-        data.room.guestName || orderStore.contactName,
-        data.room.guestPhone || orderStore.contactPhone,
-      )
+      orderStore.setContactInfo(data.room.guestName, data.room.guestPhone)
+    } else if (stayChanged || !prevStayId) {
+      orderStore.clearContactInfo()
     }
 
     // 加载酒店配置(暂时使用默认值,后续可扩展接口)
@@ -394,8 +403,8 @@ async function autoFetchUserName() {
       var data = res?.data || res
       if (data && data.userName) {
         authName.value = data.userName
-        // 存入 Store,下单时自动填入
-        orderStore.setContactInfo(data.userName, orderStore.contactPhone || '')
+        // 存入 Store,下单时自动填入(只更新姓名,不碰电话)
+        orderStore.setContactInfo(data.userName)
       }
     }
     // #endif
@@ -433,8 +442,8 @@ async function doGetPhone() {
 
     if (data && data.phone) {
       authPhone.value = data.phone
-      // 存入 Store,下单时自动填入
-      orderStore.setContactInfo(authName.value || orderStore.contactName, data.phone)
+      // 存入 Store,下单时自动填入(只更新电话,不碰姓名)
+      orderStore.setContactInfo(undefined, data.phone)
       uni.showToast({ title: '授权成功', icon: 'success' })
     }
     // #endif

+ 20 - 6
forge-h5-ui/src/store/modules/hotel-order.js

@@ -6,12 +6,15 @@ import { defineStore } from 'pinia'
  */
 export const useHotelOrderStore = defineStore('hotel-order', {
   state: () => ({
-    /** 租户ID(扫码验证后存入,供后续顾客端接口使用) */
+    /** 租户 ID(扫码验证后存入,供后续顾客端接口使用) */
     tenantId: null,
-
+  
     /** 房间信息(扫码验证后存入,含在住会话用于隔离不同住客) */
     roomInfo: null, // { roomId, roomNo, roomTypeName, roomStatus, stayId }
-
+  
+    /** 扫码参数(短码和签名,用于二次下单时重新获取住客信息) */
+    scanParams: null, // { shortCode, sign }
+  
     /** 酒店配置 */
     hotelConfig: {
       deliveryFee: 0,
@@ -91,10 +94,15 @@ export const useHotelOrderStore = defineStore('hotel-order', {
   },
 
   actions: {
-    /** 设置租户ID */
+    /** 设置租户 ID */
     setTenantId(id) {
       this.tenantId = id
     },
+    
+    /** 设置扫码参数(用于后续订单确认页刷新住客信息) */
+    setScanParams(shortCode, sign) {
+      this.scanParams = { shortCode, sign }
+    },
 
     /**
      * 设置房间信息。
@@ -157,12 +165,18 @@ export const useHotelOrderStore = defineStore('hotel-order', {
       this.orderNote = note
     },
 
-    /** 设置授权联系人信息 */
+    /** 更新联系人信息(仅更新有值的字段,null/undefined/空字符串均保留旧值) */
     setContactInfo(name, phone) {
       if (name) this.contactName = name
       if (phone) this.contactPhone = phone
     },
 
+    /** 清空联系人信息(换住客时清除旧缓存) */
+    clearContactInfo() {
+      this.contactName = ''
+      this.contactPhone = ''
+    },
+
     /** 设置营业状态(存后端 VO 原样) */
     setBusinessHours(v) {
       this.businessHours = v
@@ -184,6 +198,6 @@ export const useHotelOrderStore = defineStore('hotel-order', {
 
   persist: {
     key: 'hotel-order',
-    pick: ['tenantId', 'roomInfo', 'hotelConfig', 'cartItems', 'orderNote', 'contactName', 'contactPhone'],
+    pick: ['tenantId', 'roomInfo', 'scanParams', 'hotelConfig', 'cartItems', 'orderNote', 'contactName', 'contactPhone'],
   },
 })

+ 1 - 1
forge-server/forge-admin-server/src/main/resources/application-dev.yml

@@ -113,6 +113,6 @@ hotel:
     # 沙箱网关地址
     gateway-url: https://openapi-sandbox.dl.alipaydev.com/gateway.do
     # 异步回调地址(内网穿透映射到本地8580端口)
-    notify-url: http://qbaa6e66.natappfree.cc/hotel/open/pay/notify
+    notify-url: http://ka6caff8.natappfree.cc/hotel/open/pay/notify
     # 是否沙箱环境
     sandbox: true

+ 1 - 1
forge-server/forge-app-server/src/main/resources/application-dev.yml

@@ -92,7 +92,7 @@ hotel:
     # 沙箱网关地址
     gateway-url: https://openapi-sandbox.dl.alipaydev.com/gateway.do
     # 异步回调地址(内网穿透映射到本地8583端口)
-    notify-url: http://qbaa6e66.natappfree.cc/hotel/open/pay/notify
+    notify-url: http://ka6caff8.natappfree.cc/hotel/open/pay/notify
     # 支付完成后跳转回 H5 页面(支付页会自动检测已支付状态并跳转订单详情页)
     return-url: http://192.168.10.7:3001/#/pages/hotel/customer/pay
     # 是否沙箱环境