Просмотр исходного кода

Merge branch 'master' into dev

shish 1 год назад
Родитель
Сommit
b447187eaf

+ 2 - 2
ghsApp/src/manifest.json

@@ -2,8 +2,8 @@
     "name" : "销花宝",
     "appid" : "__UNI__BD781B0",
     "description" : "鲜花批发销售管理系统",
-    "versionName" : "1.2.37",
-    "versionCode" : 1237,
+    "versionName" : "1.2.38",
+    "versionCode" : 1238,
     "transformPx" : true,
     /* 5+App特有相关 */
     "app-plus" : {

+ 246 - 169
hdApp/src/admin/chat/chatPage.vue

@@ -2,7 +2,7 @@
   <view class="chat-container">
     <!-- 连接状态指示器 -->
     <view class="connection-status" v-if="!isConnected && !isManualDisconnect">
-      <text class="status-text">{{ '连接中...' }}</text>
+      <text class="status-text">连接已断开,请退出重新进入</text>
     </view>
 
     <!-- 聊天消息列表 -->
@@ -18,19 +18,14 @@
       <view class="load-more" v-if="showLoadMore" @click="loadMoreMessages">
         <text class="load-more-text">加载更多</text>
       </view>
-      <view
-        class="message-item"
-        v-for="(message, index) in messageList"
-        :key="index"
-        :id="'message-' + message.id"
-      >
-        <!-- 左侧消息(商家/其他用户) -->
-        <view class="message-left" v-if="!message.isMine && !message.shopId">
+      <view class="message-item" v-for="(message, index) in messageList" :key="index" :id="'message-' + message.id">
+        <!-- 左侧消息(客户) -->
+        <view class="message-left" v-if="!message.isMine">
           <view class="avatar-wrapper">
             <image class="avatar" :src="message.avatar" mode="aspectFill" />
           </view>
 
-          <view v-if="message.messageType == 'text'|| message.messageType != 'goods'" class="message-content-wrapper">
+          <view v-if="message.messageType == 'text' || message.messageType != 'goods'" class="message-content-wrapper">
             <view class="username" v-if="isMultiUser">{{ message.username }}</view>
             <view class="message-bubble left-bubble">
               <text class="message-text">{{ message.message }}</text>
@@ -38,28 +33,34 @@
             <view class="message-time">{{ message.time }}</view>
           </view>
 
-          <view v-if="message.messageType == 'goods'" class="message-content-wrapper">
-            <view class="username align-right" v-if="isMultiUser">{{
-              message.username
-            }}</view>
+          <view v-if="message.messageType == 'goods'" class="goods-content-wrapper">
+            <view class="username align-right" v-if="isMultiUser">{{ message.username }}</view>
             <view class="goods-info left-bubble">
-              <view class="goods-main">
+              <view class="goods-main" @click="toGoodsDetail(message.goodsInfo)">
                 <image class="goods-image" :src="message.goodsInfo.goodsImg" mode="aspectFill"></image>
                 <view class="goods-details">
                   <view class="goods-name-wrapper">
-                    <text class="goods-name">{{message.goodsInfo.goodsName}}</text>
+                    <text class="goods-name">{{ message.goodsInfo.goodsName }}</text>
                   </view>
                   <!-- <view class="sales-info">
                     <text class="delivery-time">48小时发</text>
                   </view> -->
-                  <text v-if="message.goodsInfo.goodsPriceType == 1" class="goods-price">¥{{ message.goodsInfo.goodsPrice }}</text>
+                  <text v-if="message.goodsInfo.goodsPriceType == 1 || message.goodsInfo.goodsPriceType == 2" class="goods-price"
+                    >¥{{ parseFloat(message.goodsInfo.goodsPrice).toFixed(2) }}</text
+                  >
                 </view>
               </view>
-              <view class="goods-footer">
-              </view>
+              <view class="goods-footer" v-if="message.goodsInfo.goodsPriceType != 1"> </view>
               <view v-if="message.goodsInfo.goodsPriceType == 0 && isExpired(message.timestamp)" class="action-buttons">
                 <form @submit.prevent="createQrotedPrice(message)">
-                  <input class="price-input" type="number" v-model="message.quotedPrice" placeholder="输入价格" />
+                  <input 
+                    class="price-input"
+                    type="number" 
+                    v-model="message.quotedPrice"
+                    placeholder="输入价格"
+                    @focus="hideKeyboard"
+                    @blur="showKeyboard"
+                  />
                   <button class="action-btn buy-btn" form-type="submit">报价</button>
                 </form>
               </view>
@@ -69,8 +70,17 @@
               <!-- 报价类型显示重新报价 -->
               <view v-if="message.goodsInfo.goodsPriceType == 2 && isExpired(message.timestamp)" class="action-buttons">
                 <form @submit.prevent="createQrotedPrice(message)">
-                  <text class="goods-price" v-if="message.goodsInfo.lastPrice || message.goodsInfo.goodsPrice">¥{{message.goodsInfo.lastPrice || message.goodsInfo.goodsPrice}}</text>
-                  <input class="price-input" type="number" v-model="message.quotedPrice" placeholder="输入价格" />
+                  <text class="goods-price" v-if="message.goodsInfo.lastPrice || message.goodsInfo.goodsPrice"
+                    >¥{{ parseFloat(message.goodsInfo.lastPrice || message.goodsInfo.goodsPrice).toFixed(2) }}</text
+                  >
+                  <input
+                    class="price-input"
+                    type="number"
+                    v-model="message.quotedPrice"
+                    placeholder="输入价格"
+                    @focus="hideKeyboard"
+                    @blur="showKeyboard"
+                  />
                   <button class="action-btn buy-btn" form-type="submit">重新报价</button>
                 </form>
               </view>
@@ -80,9 +90,8 @@
         </view>
 
         <!-- 右侧消息(我的) -->
-        <view class="message-right" v-if="message.isMine || message.shopId">
-          
-          <view v-if="message.messageType == 'text'|| message.messageType != 'goods'" class="message-content-wrapper">
+        <view class="message-right" v-if="message.isMine">
+          <view v-if="message.messageType == 'text' || message.messageType != 'goods'" class="message-content-wrapper">
             <view class="username align-right" v-if="isMultiUser">{{ message.username }}</view>
             <view class="message-bubble right-bubble">
               <text class="message-text">{{ message.message }}</text>
@@ -90,37 +99,36 @@
             <view class="message-time align-right">{{ message.time }}</view>
           </view>
 
-          <view v-if="message.messageType == 'goods'" class="message-content-wrapper">
-            <view class="username align-right" v-if="isMultiUser">{{
-              message.username
-            }}</view>
+          <view v-if="message.messageType == 'goods'" class="goods-content-wrapper">
+            <view class="username align-right" v-if="isMultiUser">{{ message.username }}</view>
             <view class="goods-info right-bubble">
-              <view class="goods-main">
-                <image
-                  class="goods-image"
-                  :src="message.goodsInfo.goodsImg"
-                  mode="aspectFill"
-                />
+              <view class="goods-main" @click="toGoodsDetail(message.goodsInfo)">
+                <image class="goods-image" :src="message.goodsInfo.goodsImg" mode="aspectFill" />
                 <view class="goods-details">
                   <view class="goods-name-wrapper">
                     <text class="goods-name">{{ message.goodsInfo.goodsName }}</text>
                   </view>
+                  <text v-if="message.goodsInfo.goodsPriceType == 1 || message.goodsInfo.goodsPriceType == 2" class="goods-price"
+                    >¥{{ parseFloat(message.goodsInfo.goodsPrice).toFixed(2) }}</text
+                  >
                   <view class="sales-info">
                     <!-- <text class="delivery-time">48小时发</text> -->
                   </view>
-                  <text v-if="message.goodsInfo.goodsPriceType == 1" class="goods-price">¥{{ message.goodsInfo.goodsPrice }}</text>
+                  <text v-if="message.goodsInfo.goodsPriceType == 1" class="goods-price"
+                    >¥{{ parseFloat(message.goodsInfo.goodsPrice).toFixed(2) }}</text
+                  >
                 </view>
               </view>
-              <view class="goods-footer">
-                <!-- <text class="footer-text">破损包退·极速退款·7天无理由退货</text>
-                <text class="arrow">></text> -->
-              </view>
-              <view class="action-buttons">
+              <!-- <view class="goods-footer">
+                <text class="footer-text">破损包退·极速退款·7天无理由退货</text>
+                <text class="arrow">></text>
+              </view> -->
+              <!--<view class="action-buttons">
                 <button class="action-btn spec-btn" @click="toGoodsDetail(message.goodsInfo)">查看商品</button>
-                <!-- <button v-if="message.goodsInfo.goodsPriceType == 1" class="action-btn buy-btn" @click="toBuy">去购买</button> -->
-                <!-- 报价类型显示去购买 -->
-                <!-- <button v-if="message.goodsInfo.goodsPriceType == 2" class="action-btn buy-btn" @click="toBuy">去购买</button> -->
-              </view>
+                <button v-if="message.goodsInfo.goodsPriceType == 1" class="action-btn buy-btn" @click="toBuy">去购买</button>
+                //报价类型显示去购买
+                <button v-if="message.goodsInfo.goodsPriceType == 2" class="action-btn buy-btn" @click="toBuy">去购买</button>
+              </view> -->
             </view>
             <view class="message-time align-right">{{ message.time }}</view>
           </view>
@@ -137,7 +145,7 @@
     </scroll-view>
 
     <!-- 输入区域 -->
-    <view class="input-area" :style="{ 'padding-bottom': keyboardHeight > 0 ? keyboardHeight + 'px' : 'calc(20upx + env(safe-area-inset-bottom))' }">
+    <view v-show="msgInputShow" class="input-area" :style="{ 'padding-bottom': keyboardHeight > 0 ? keyboardHeight + 'px' : 'calc(20upx + env(safe-area-inset-bottom))' }">
       <view class="input-wrapper">
         <textarea
           class="message-input"
@@ -153,13 +161,9 @@
           :maxlength="500"
           :show-confirm-bar="false"
           :focus="inputFocus"
-          /><!-- @blur="onInputBlur" -->
-        <button
-          class="send-button"
-          :class="{ 'send-active': inputText.trim() }"
-          @click="sendMessage"
-          :disabled="!inputText.trim()"
-        > <!-- @touchstart.prevent="sendMessage" -->
+        /><!-- @blur="onInputBlur" -->
+        <button class="send-button" :class="{ 'send-active': inputText.trim() }" @click="sendMessage" :disabled="!inputText.trim()">
+          <!-- @touchstart.prevent="sendMessage" -->
           发送
         </button>
       </view>
@@ -168,7 +172,7 @@
 </template>
 
 <script>
-import { getChatHistory, createQuotedPrice } from '@/api/chat';
+import { getChatHistory, createQuotedPrice, getQuotedPrice } from '@/api/chat';
 import { WSSHOST } from '@/config.js';
 export default {
   data() {
@@ -186,7 +190,7 @@ export default {
         customId: 0, //客户id
         shopId: 0, //门店id
         username: '', //门店名称
-        avatar: ''
+        avatar: ''  //门店头像
       },
       // 聊天消息列表
       messageList: [],
@@ -201,14 +205,15 @@ export default {
       // 分页加载
       allMessages: [], // 存储所有从API获取的消息
       initialLoadSize: 50, // 首次加载数量
-      loadMoreSize: 100, // 每次加载更多的数量
+      loadMoreSize: 50, // 每次加载更多的数量
       showLoadMore: false, // 是否显示“加载更多”
       // 键盘相关
       keyboardHeight: 0, // 键盘高度
       isKeyboardShow: false, // 键盘是否显示
       inputFocus: false, // 输入框焦点
       isInputFocused: false, // 标记输入框是否聚焦
-      expireTime: 12 * 60 * 60, // 商品报价有效窗口时长 -- 12小时
+      expireTime: 23 * 60 * 60, // 商品报价有效窗口时长 -- 23小时
+      msgInputShow: true, // 消息输入框是否显示
     };
   },
   onLoad(options) {
@@ -217,7 +222,7 @@ export default {
       // 设置聊天人名称
       uni.setNavigationBarTitle({
         title: options.chatPerson
-      })
+      });
     }
 
     // 根据传入参数判断是否多人聊天
@@ -226,19 +231,28 @@ export default {
     }
 
     if (options.userId) {
-      this.currentUser.userId = options.userId;
+      this.currentUser.userId = parseInt(options.userId);
+      if(this.currentUser.userId == 0) {
+        console.error('userId 出错 ---------- this.currentUser.userId: ', this.currentUser.userId);
+      }
     }
     if (options.customId) {
-      this.currentUser.customId = options.customId;
+      this.currentUser.customId = parseInt(options.customId);
+      if(this.currentUser.customId == 0) {
+        console.error('customId 出错 ---------- this.currentUser.customId: ', this.currentUser.customId);
+      }
     }
     if (options.shopId) {
-      this.currentUser.shopId = options.shopId;
+      this.currentUser.shopId = parseInt(options.shopId);
+      if(this.currentUser.shopId == 0) {
+        console.error('shopId 出错 ---------- this.currentUser.shopId: ', this.currentUser.shopId);
+      }
     }
     if (options.name) {
       this.currentUser.username = options.name;
     }
     if (options.staffId) {
-      this.currentUser.staffId = options.staffId;
+      this.currentUser.staffId = parseInt(options.staffId);
     }
     if (options.avatar) {
       this.currentUser.avatar = options.avatar;
@@ -250,8 +264,9 @@ export default {
     } else {
       // 如果没有传入房间号,使用默认值或生成一个
       this.room = 'default_room';
+      console.error('房间号为默认房间 ---------- this.room: ', this.room);
     }
-    console.log('---------- this.room: ', this.room);
+    // console.log('---------- this.room: ', this.room);
 
     // 加载聊天记录
     this.loadChatHistory();
@@ -263,12 +278,12 @@ export default {
     this.$nextTick(() => {
       this.scrollToBottom();
     });
-     
+
     // 监听键盘弹起事件
     uni.onKeyboardHeightChange((res) => {
       this.keyboardHeight = res.height;
       this.isKeyboardShow = res.height > 0;
-      
+
       // 键盘弹起时,延迟滚动到底部
       if (this.isKeyboardShow) {
         this.$nextTick(() => {
@@ -280,13 +295,12 @@ export default {
     });
   },
   onUnload() {
-    // 页面卸载时关闭WebSocket连接
-    this.isManualDisconnect = true; // 标记为主动断开
+    // 页面卸载时关闭 WebSocket连接
     this.disconnectWebSocket();
   },
   onHide() {
-    // 页面隐藏时可以选择性地关闭连接(根据业务需求)
-    this.disconnectWebSocket()
+    // 页面隐藏时关闭 WebSocket连接(根据业务需求)
+    this.disconnectWebSocket();
   },
   onShow() {
     // 页面显示时重新连接(如果之前断开了)
@@ -299,26 +313,29 @@ export default {
     // 加载聊天历史记录
     loadChatHistory() {
       getChatHistory({
-        roomName: this.room,
-        userId: this.currentUser.id
+        roomName: this.room
       }).then((res) => {
         if (res.code == 1 && res.data) {
           this.allMessages = res.data.map((item, index) => {
+            // 判断是否是我(本店)发送的消息
+            const isMine = item.shopId ? parseInt(item.shopId) == this.currentUser.shopId : false;
+            //console.log("---isMine---: ", isMine);
+
             const newItem = {
               ...item,
-              id: `message-${index}`, // 为每条消息添加唯一ID
+              id: `message-${index}` // 为每条消息添加唯一ID // 'msg_local_' + timestamp + '_' + Math.floor(Math.random() * 100000) + 1,
             };
             //如果消息类型为 'goods',就调用 parseGoodsMessage 并将结果存入新属性 goodsInfo
             if (newItem.messageType === 'goods') {
               newItem.goodsInfo = this.parseGoodsMessage(newItem.message);
             }
+            newItem.isMine = isMine;
+
             return newItem;
           });
 
           if (this.allMessages.length > this.initialLoadSize) {
-            this.messageList = this.allMessages.slice(
-              this.allMessages.length - this.initialLoadSize
-            );
+            this.messageList = this.allMessages.slice(this.allMessages.length - this.initialLoadSize);
             this.showLoadMore = true;
           } else {
             this.messageList = this.allMessages;
@@ -343,10 +360,7 @@ export default {
         return;
       }
       const countToLoad = Math.min(this.loadMoreSize, remainingMessagesCount);
-      const moreMessages = this.allMessages.slice(
-        remainingMessagesCount - countToLoad,
-        remainingMessagesCount
-      );
+      const moreMessages = this.allMessages.slice(remainingMessagesCount - countToLoad, remainingMessagesCount);
       const oldTopMessageId = this.messageList.length > 0 ? this.messageList[0].id : null;
       this.messageList = [...moreMessages, ...this.messageList];
       if (this.allMessages.length - (currentLoadedCount + countToLoad) <= 0) {
@@ -355,7 +369,7 @@ export default {
       if (oldTopMessageId) {
         this.$nextTick(() => {
           this.scrollWithAnimation = false; // 加载更多时不使用动画
-          this.scrollIntoView = "message-" + oldTopMessageId;
+          this.scrollIntoView = 'message-' + oldTopMessageId;
         });
       }
     },
@@ -421,10 +435,12 @@ export default {
           // 只有在非主动断开的情况下才尝试重连
           if (!this.isManualDisconnect && this.reconnectCount < this.maxReconnectCount) {
             setTimeout(() => {
-              this.reconnectWebSocket();
+              if (!this.isManualDisconnect) {
+                this.reconnectWebSocket();
+              }
             }, 3000);
           }
-          
+
           // 尝试重新连接超过 maxReconnectCount 次才标记为未连接状态
           if (!this.isManualDisconnect && this.reconnectCount >= this.maxReconnectCount) {
             this.isConnected = false;
@@ -446,39 +462,42 @@ export default {
     // 构建WebSocket子协议参数(模拟POST body传输)
     buildWebSocketProtocols() {
       try {
-        const userId = parseInt(this.currentUser.userId); //客户登录帐户的id(不是 customId,是customer登录帐户的userId)
+        const userId = this.currentUser.userId; //客户登录帐户的id(不是 customId,是customer登录帐户的userId)
         if (isNaN(userId) || userId <= 0) {
-          this.$msg("当前用户的id出错");
+          this.$msg('当前用户的id出错');
           return;
         }
-        
-        const customId = parseInt(this.currentUser.customId);
+
+        const customId = this.currentUser.customId;
         if (isNaN(customId) || customId <= 0) {
-          this.$msg("当前用户的customId出错");
+          this.$msg('当前用户的customId出错');
           return;
         }
-        
-        const shopId = parseInt(this.currentUser.shopId);
+
+        const shopId = this.currentUser.shopId;
         if (isNaN(shopId) || shopId <= 0) {
-          this.$msg("当前用户的shopId出错");
+          this.$msg('当前用户的shopId出错');
           return;
         }
 
-        const staffId = parseInt(this.currentUser.staffId);
+        const staffId = this.currentUser.staffId;
         if (isNaN(staffId) || staffId <= 0) {
-          this.$msg("当前用户的staffId出错");
+          this.$msg('当前用户的staffId出错');
           return;
         }
 
         // 创建房间参数对象
         const roomParams = {
           u_id: userId, //不是 customId,是customer的: userId
-          c_id: parseInt(this.currentUser.customId),
-          s_id: parseInt(this.currentUser.shopId),
-          u_name: this.currentUser.username && this.currentUser.username.length > 30 ? this.currentUser.username.substring(0, 30) : this.currentUser.username,
+          c_id: this.currentUser.customId,
+          s_id: this.currentUser.shopId,
+          u_name:
+            this.currentUser.username && this.currentUser.username.length > 30
+              ? this.currentUser.username.substring(0, 30)
+              : this.currentUser.username,
           platform: this.getPlatformInfo(),
           type: 'shop', // 客户端类型:shop:门店端, customer:客户端
-          staff_id: staffId, //门店员工id
+          staff_id: staffId //门店员工id
         };
 
         // 分段传输(如果参数过长)
@@ -609,8 +628,8 @@ export default {
 
       // 增加一个保护
       if (typeof base64 !== 'string') {
-          console.error('Base64编码失败,返回非字符串值:', base64);
-          return ''; // 返回一个空字符串或其他默认值
+        console.error('Base64编码失败,返回非字符串值:', base64);
+        return ''; // 返回一个空字符串或其他默认值
       }
 
       // 转换为URL安全格式:替换 +/= 字符
@@ -669,7 +688,7 @@ export default {
           console.error('协议长度超限:', protocol.length);
           return false;
         }
-        console.log('protocal -- ', protocol, protocol.length)
+        // console.log('protocal -- ', protocol, protocol.length)
       }
 
       return true;
@@ -703,7 +722,7 @@ export default {
 
     // 处理 WebSocket 消息
     handleWebSocketMessage(data) {
-      console.log('---------- data: ', data);
+      // console.log('---------- data: ', data);
       try {
         // 尝试解析JSON,如果失败则认为是纯文本消息
         let messageData;
@@ -730,26 +749,27 @@ export default {
           isMine = true;
         }
 
-        const messageType = messageData.messageType || "text";
-        console.log('messageType -- ', messageType);
+        const messageType = messageData.messageType || 'text';
+        // console.log('messageType -- ', messageType);
 
         // 创建消息对象
         const newMessage = {
           id: 'msg_receive_' + Math.floor(Date.now() / 1000) + '_' + Math.floor(Math.random() * 100000) + 1,
           isMine: isMine, // 标记是否是本店发送的消息
+          //--------------------------------
           message: messageData.message || messageData || '',
           username: messageData.name || messageData.username || '未知用户',
           avatar: messageData.avatar || this.$constant.imgUrl + '/retail/default-img.png',
           time: this.getCurrentTime(), // 收到消息时间点
           timestamp: messageData.timestamp, // 消息发送时间点
-          messageType: messageType,
+          messageType: messageType
         };
 
         if (newMessage.messageType === 'goods') {
           newMessage.goodsInfo = this.parseGoodsMessage(newMessage.message);
         }
 
-        console.log('收到 ---------- newMessage: ', newMessage);
+        // console.log('收到 ---------- newMessage: ', newMessage);
         // 添加到消息列表
         this.messageList.push(newMessage);
 
@@ -788,12 +808,13 @@ export default {
         const myMessage = {
           id: 'msg_local_' + timestamp + '_' + Math.floor(Math.random() * 100000) + 1,
           isMine: true,
+          //--------------------------------
           message: messageContent,
           username: this.currentUser.username,
           avatar: avatar,
           time: this.getCurrentTime(timestamp), // 收到消息时间点
           timestamp: timestamp, // 消息发送时间点
-          messageType: "text",
+          messageType: 'text'
         };
 
         // 添加到消息列表
@@ -817,16 +838,16 @@ export default {
           avatar: avatar,
           shopId: this.currentUser.shopId, // 发送者:门店使用shopId,客户使用customId
           timestamp: timestamp,
-          messageType: "text",
+          messageType: 'text'
         };
 
         const json = JSON.stringify(messageData);
-        console.log('send ---------- json: ', json);
+        // console.log('send ---------- json: ', json);
         // 发送到WebSocket服务器
         this.socket.send({
           data: json,
           success: () => {
-            console.log('消息发送成功');
+            // console.log('消息发送成功');
           },
           fail: (error) => {
             console.error('消息发送失败:', error);
@@ -868,44 +889,44 @@ export default {
     scrollToBottom(enableAnimation = true) {
       this.scrollWithAnimation = enableAnimation;
       if (this.messageList.length > 0) {
-        this.scrollIntoView = "message-" + this.messageList[this.messageList.length - 1].id;
+        this.scrollIntoView = 'message-' + this.messageList[this.messageList.length - 1].id;
       }
     },
 
     // 获取当前时间
-    getCurrentTime(timestamp=null) {
+    getCurrentTime(timestamp = null) {
       let now;
       if (timestamp) {
         now = new Date(timestamp * 1000);
       } else {
         now = new Date();
       }
-      const hours = String(now.getHours()).padStart(2, "0");
-      const minutes = String(now.getMinutes()).padStart(2, "0");
+      const hours = String(now.getHours()).padStart(2, '0');
+      const minutes = String(now.getMinutes()).padStart(2, '0');
       return `${hours}:${minutes}`;
     },
     // 输入框聚焦事件
     onInputFocus() {
-      console.log('输入框聚焦');
+      // console.log('输入框聚焦');
       // 微信小程序中,聚焦时延迟滚动到底部
       setTimeout(() => {
         this.scrollToBottom();
       }, 450);
-      this.isInputFocused = true
-      this.inputFocus = true
+      this.isInputFocused = true;
+      this.inputFocus = true;
       //this.hideExtraPanels() // 聚焦时隐藏表情和更多面板
     },
 
     // 输入框失焦事件
     onInputBlur() {
-      console.log('输入框失焦');
-      this.isInputFocused = false
+      // console.log('输入框失焦');
+      this.isInputFocused = false;
       // this.inputFocus = false
     },
 
     // 输入内容变化事件
     onInputChange(event) {
-      this.inputText = event.detail.value
+      this.inputText = event.detail.value;
       // 可以在这里处理输入内容的变化,比如限制行数等
       const value = event.detail.value;
       // 限制最大行数为5行,避免输入框过高
@@ -919,23 +940,60 @@ export default {
     parseGoodsMessage(messageStr) {
       try {
         // 首先检查 messageStr 是否已经是对象
-        if (typeof messageStr === "object" && messageStr !== null) {
+        if (typeof messageStr === 'object' && messageStr !== null) {
           return messageStr;
         }
         // 如果是字符串,则尝试解析
-        if (typeof messageStr === "string") {
-          const parsed = JSON.parse(messageStr);
+        if (typeof messageStr === 'string') {
+          let parsed = JSON.parse(messageStr);
+          if(parsed.goodsPriceType == 0) { // 无价格类型,则要请求后端获取报价,再根据结果展示
+            // 如果没有过期,请求后端获取报价
+            const now = Math.floor(Date.now()/1000);
+            const timeDiff = now - parsed.timestamp;
+            const expireTime = 24 * 60 * 60;
+            if (timeDiff > expireTime) {
+              // console.log("parsed 过期:", parsed);
+            } else {
+              // console.log("parsed 无价格:", parsed);
+              const key = parsed.key || '';
+
+              if (key != '') {
+                getQuotedPrice({
+                  key: key,
+                }).then(res => {
+                  console.log("res", res)
+                  if (res.code == 1) {
+                    if (res.data.price != -1) {
+                      parsed.goodsPriceType = 2; // 报价类型
+                      parsed.goodsPrice = parseFloat(res.data.price).toFixed(2);
+                    }
+                  }
+                }).catch(err => {
+                  console.log("getQuotedPrice error: ", key, err)
+                })
+              }
+            }
+          } else if(parsed.goodsPriceType == 1) {
+            // console.log("parsed 有价格:", parsed);
+          } else if(parsed.goodsPriceType == 2) {
+            // console.log("parsed 重新报价:", parsed);
+          } else {
+            console.error("parsed 其他类型:", parsed);
+            return {};
+          }
           return parsed;
         }
+
+        console.error("解析商品消息失败:", messageStr);
         // 如果两者都不是,返回空对象
         return {};
       } catch (error) {
-        // console.error("解析商品消息失败:", error, messageStr);
+        console.error("解析商品消息失败:", error, messageStr);
         // 在解析失败时返回一个包含默认值的对象,以避免模板渲染错误
         return {
-          goodsImg: "",
-          goodsName: "商品信息解析失败",
-          goodsPrice: "0.00",
+          goodsImg: '',
+          goodsName: '商品信息解析失败',
+          goodsPrice: '0.00'
         };
       }
     },
@@ -944,32 +1002,32 @@ export default {
     sendMessageOfGoodsPrice(currentGoodsInfo) {
       if (!this.isConnected) {
         uni.showToast({
-          title: "WebSocket未连接",
-          icon: "none",
+          title: 'WebSocket未连接',
+          icon: 'none'
         });
         return;
       }
-      const avatar = this.currentUser.avatar || this.$constant.imgUrl + "/retail/default-img.png";
+      const avatar = this.currentUser.avatar || this.$constant.imgUrl + '/retail/default-img.png';
       const timestamp = Math.floor(Date.now() / 1000);
 
       // 构建商品信息消息体 -------------------------------- 所看到的消息体 -------------------------------
       const goodsMessage = {
-        ...currentGoodsInfo,
+        ...currentGoodsInfo
       };
       const messageContent = JSON.stringify(goodsMessage); // 所看到的消息体
 
       try {
         // 立即在本地显示发送的消息(右侧)
         const myMessage = {
-          id: "msg_local_" + timestamp + "_" + (Math.floor(Math.random() * 100000) + 1),
+          id: 'msg_local_' + timestamp + '_' + (Math.floor(Math.random() * 100000) + 1),
           isMine: true,
           // message: `[商品] ${this.goodsInfo.goodsName}`, // 显示简化信息
           message: messageContent,
           username: this.currentUser.username,
           avatar: avatar,
           time: this.getCurrentTime(timestamp),
-          messageType: "goods", // 附加一个字段,用于渲染时区分商品消息
-          goodsInfo: goodsMessage,
+          messageType: 'goods', // 附加一个字段,用于渲染时区分商品消息
+          goodsInfo: goodsMessage
         };
 
         // 添加到消息列表
@@ -990,7 +1048,7 @@ export default {
           avatar: avatar,
           shopId: this.currentUser.shopId, // 发送者:门店使用shopId,客户使用customId
           timestamp: timestamp,
-          messageType: "goods",
+          messageType: 'goods'
         };
 
         const json = JSON.stringify(messageData);
@@ -998,48 +1056,50 @@ export default {
         this.socket.send({
           data: json,
           success: () => {
-            console.log("商品消息发送成功");
+            // console.log("商品消息发送成功");
           },
           fail: (error) => {
-            console.error("商品消息发送失败:", error);
+            console.error('商品消息发送失败:', error);
             uni.showToast({
-              title: "发送失败",
-              icon: "none",
+              title: '发送失败',
+              icon: 'none'
             });
-          },
+          }
         });
       } catch (error) {
-        console.error("发送商品消息异常:", error);
+        console.error('发送商品消息异常:', error);
         uni.showToast({
-          title: "发送异常",
-          icon: "none",
+          title: '发送异常',
+          icon: 'none'
         });
       }
     },
     createQrotedPrice(message) {
-      console.log("createPrice", message)
+      // console.log("createPrice", message)
       createQuotedPrice({
         key: message.goodsInfo.key,
-        price: message.quotedPrice,
-      }).then(res => {
-        console.log("createQuotedPrice", res)
-        if (res.code == 1) {
-          this.$msg("报价成功")
-          message.goodsInfo.goodsPriceType = 2;
-          message.goodsInfo.goodsPrice = message.quotedPrice;
-          message.goodsInfo.lastPrice = message.quotedPrice;
-          message.quotedPrice = '';
-          this.sendMessageOfGoodsPrice(message.goodsInfo)
-        }
-      }).catch(err => {
-        console.log("createQuotedPrice error", err)
+        price: parseFloat(message.quotedPrice).toFixed(2)
       })
+        .then((res) => {
+          // console.log("createQuotedPrice", res)
+          if (res.code == 1) {
+            this.$msg('报价成功');
+            message.goodsInfo.goodsPriceType = 2;
+            message.goodsInfo.goodsPrice = parseFloat(message.quotedPrice).toFixed(2);
+            message.goodsInfo.lastPrice = parseFloat(message.quotedPrice).toFixed(2);
+            message.quotedPrice = '';
+            this.sendMessageOfGoodsPrice(message.goodsInfo);
+          }
+        })
+        .catch((err) => {
+          console.log('createQuotedPrice error', err);
+        });
     },
     isExpired(timestamp) {
       if (isNaN(timestamp)) {
         return false;
       }
-      const now = Math.floor(Date.now()/1000);
+      const now = Math.floor(Date.now() / 1000);
       const timeDiff = now - timestamp;
       return timeDiff < this.expireTime;
     },
@@ -1051,25 +1111,33 @@ export default {
       const hdId = parseInt(goodsInfo.hdId);
       const account = parseInt(goodsInfo.account);
       if (isNaN(goodsId) || isNaN(categoryId) || isNaN(hdId) || isNaN(account)) {
-        this.$msg("商品数据异常");
+        this.$msg('商品数据异常');
         return;
       }
 
       this.$util.pageTo({
-        url: "/admin/goods/detail",
-        query: { // id=2020&categoryId=1402&hdId=229&account=36548&shopId=36548&name=花仙子&avatar=https://img.theflorist.cn/hhb_small.png
+        url: '/admin/goods/detail',
+        query: {
+          // id=2020&categoryId=1402&hdId=229&account=36548&shopId=36548&name=花仙子&avatar=https://img.theflorist.cn/hhb_small.png
           id: goodsId,
           account: goodsInfo.account,
           hdId: goodsInfo.hdId,
           categoryId: categoryId,
           shopId: goodsInfo.shopId,
           name: goodsInfo.name,
-          avatar: goodsInfo.avatar,
-        },
+          avatar: goodsInfo.avatar
+        }
       });
       this.disconnectWebSocket();
+    },
+    hideKeyboard() {
+      this.keyboardHeight = 0;
+      this.msgInputShow = false;
+    },
+    showKeyboard() {
+      this.msgInputShow = true;
     }
-  },
+  }
 };
 </script>
 
@@ -1146,6 +1214,10 @@ export default {
   min-width: 100upx;
 }
 
+.goods-content-wrapper {
+  width: 72%;
+}
+
 .username {
   font-size: 24upx;
   color: $fontColor3;
@@ -1245,7 +1317,7 @@ export default {
       height: 80rpx;
     }
     .goods-name {
-      font-size: 28rpx;
+      font-size: 30rpx;
       color: #333;
       font-weight: bold;
       // 多行省略
@@ -1270,10 +1342,10 @@ export default {
       border-radius: 4rpx;
     }
     .goods-price {
-      font-size: 36rpx;
+      font-size: 28rpx;
       color: #ff5050;
       font-weight: bold;
-      margin-top: 10rpx;
+      margin-top: 40rpx;
     }
   }
 
@@ -1305,6 +1377,11 @@ export default {
       padding: 0 15rpx;
       font-size: 28rpx;
       text-align: center;
+      color: #666666;
+    }
+
+    .price-input::placeholder {
+      color: #aaaaaa;
     }
     .action-btn {
       display: inline-block;
@@ -1328,10 +1405,10 @@ export default {
       color: white;
     }
     .goods-price {
-      font-size: 26rpx;
-      color: #ff5050;
+      font-size: 28rpx;
+      color: green;
       font-weight: bold;
-      margin-right: 10rpx;
+      margin-right: 12rpx;
     }
   }
 }
@@ -1396,7 +1473,7 @@ export default {
   resize: none;
 
   &::placeholder {
-    color: #ccc;
+    color: #cccccc;
   }
 }
 

+ 1 - 5
hdApp/src/admin/chat/list.vue

@@ -29,8 +29,6 @@
         <app-wrapper-empty :is-empty="true" />
       </block>
     </view>
-
-    <NotLogin></NotLogin>
   </view>
 </template>
 <script>
@@ -38,14 +36,12 @@ import TuiListCell from "@/components/plugin/list-cell";
 import AppWrapperEmpty from "@/components/app-wrapper-empty";
 import { list } from "@/mixins";
 import { getLatestUsers } from "@/api/chat";
-import NotLogin from "@/components/not-login";
 import {mapGetters } from "vuex";
 export default {
   name: "member",
   components: {
     TuiListCell,
-    AppWrapperEmpty,
-    NotLogin
+    AppWrapperEmpty
   },
   mixins: [list],
   data() {

+ 1 - 1
hdApp/src/admin/goods/add.vue

@@ -93,7 +93,7 @@
         </tui-list-cell>
 
         <tui-list-cell class="line-cell" :hover="false">
-          <view class="tui-title">重量(公斤)</view>
+          <view class="tui-title required">重量(公斤)</view>
           <input v-model="form.weight" placeholder-class="phcolor" @focus="onWeightFocus" @blur="onWeightBlur" class="tui-input" name="weight" placeholder="公斤,可输入小数" maxlength="10" type="digit" />
         </tui-list-cell>
 

+ 4 - 1
hdApp/src/api/chat/index.js

@@ -7,4 +7,7 @@ export const getChatHistory = param => https.post('/chat/chat-history', param)
 export const unReadMsgCount = param => https.post('/chat/un-read-msg-count', param)
 
 // 报价
-export const createQuotedPrice = param => https.post('/chat/create-quoted-price', param)
+export const createQuotedPrice = param => https.post('/chat/create-quoted-price', param)
+
+// 获取商品报价
+export const getQuotedPrice = param => https.post('/chat/get-quoted-price', param)

+ 28 - 1
hdApp/src/utils/format.js

@@ -36,6 +36,7 @@ function formatLocation(longitude, latitude) {
 		latitude: latitude.toString().split('.')
 	}
 }
+
 var dateUtils = {
 	UNITS: {
 		'年': 31557600000,
@@ -73,8 +74,34 @@ var dateUtils = {
 	}
 }
 
+/**
+ * 格式化价格为两位小数
+ * @param {number|string} price - 需要格式化的价格
+ * @param {number} decimals - 小数位数,默认为2
+ * @returns {string} 格式化后的价格字符串
+ */
+function formatPrice(price, decimals = 2) {
+	// 输入验证
+	if (price === null || price === undefined || price === '') {
+		return '0.00';
+	}
+
+	// 转换为数字
+	const numPrice = typeof price === 'string' ? parseFloat(price) : price;
+
+	// 检查是否为有效数字
+	if (isNaN(numPrice)) {
+		console.warn('formatPrice: Invalid price value:', price);
+		return '0.00';
+	}
+
+	// 格式化为指定小数位数
+	return numPrice.toFixed(decimals);
+}
+
 module.exports = {
 	formatTime: formatTime,
 	formatLocation: formatLocation,
-	dateUtils: dateUtils
+	dateUtils: dateUtils,
+	formatPrice: formatPrice
 }

+ 3 - 1
hdApp/src/utils/util.js

@@ -337,8 +337,9 @@ export const hitRemind = () =>{
 //#ifdef APP-PLUS
 const CLDialog=uni.requireNativePlugin("CL-Dialog")
 //#endif
-export const confirmModal = (item,okCallback=null,cancelCallback=null) => {
 
+// 确认弹框
+export const confirmModal = (item,okCallback=null,cancelCallback=null) => {
 	let title = item.title || '提示'
 	let content = item.content || '确认操作?'
 	let okText = item.okText || '确认'
@@ -418,6 +419,7 @@ export const confirmModal = (item,okCallback=null,cancelCallback=null) => {
 	})
 	//#endif
 }
+
 //判断是否有扫码的条件
 export const isScanEnv = () =>{
 	let isScanEnv = false

+ 0 - 9
mallApp/src/api/category/index.js

@@ -14,15 +14,6 @@ export const getList = data => {
 	return https.get('/category/goods-list', data)
 }
 
-/**
- * 获取无价格分类的商品
- */
-export const getNonPriceList = data => {
-	return https.get('/category/non-price-goods-list', data)
-}
-
-// =====================  B 端 ========================
-
 /** *
  * 商品分类-列表(全部分类无分页) b
  */

+ 1 - 2
mallApp/src/pages.json

@@ -55,8 +55,7 @@
         {
             "root": "pages/goods",
             "pages": [
-                { "path": "detail", "style": { "navigationBarTitleText": "详情" } },
-                { "path": "picGoods", "style": { "navigationBarTitleText": "图集" } }
+                { "path": "detail", "style": { "navigationBarTitleText": "详情" } }
             ]
         },
         {

+ 90 - 73
mallApp/src/pages/chat/chatPage.vue

@@ -2,7 +2,7 @@
   <view class="chat-container">
     <!-- 连接状态指示器 -->
     <view class="connection-status" v-if="!isConnected && !isManualDisconnect">
-      <text class="status-text">"连接中...</text>
+      <text class="status-text">连接已断开,请退出重新进入</text>
     </view>
 
     <!-- 聊天消息列表 -->
@@ -25,7 +25,7 @@
         :id="'message-' + message.id"
       >
         <!-- 左侧消息(商家/其他用户) -->
-        <view class="message-left" v-if="!message.isMine && !message.customId">
+        <view class="message-left" v-if="!message.isMine">
           <view class="avatar-wrapper">
             <image class="avatar" :src="message.avatar" mode="aspectFill" />
           </view>
@@ -38,33 +38,37 @@
             <view class="message-time">{{ message.time }}</view>
           </view>
 
-          <view v-if="message.messageType == 'goods'" class="message-content-wrapper">
+          <view v-if="message.messageType == 'goods'" class="goods-content-wrapper">
             <view class="username align-right" v-if="isMultiUser">{{
               message.username
             }}</view>
             <view class="goods-info left-bubble">
-              <view class="goods-main">
+              <view class="goods-main" @click="toGoodsDetail(message.goodsInfo)">
                 <image class="goods-image" :src="message.goodsInfo.goodsImg" mode="aspectFill"></image>
                 <view class="goods-details">
                   <view class="goods-name-wrapper">
                     <text class="goods-name">{{message.goodsInfo.goodsName}}</text>
                   </view>
-                  <!-- <view class="sales-info">
-                    <text class="delivery-time">48小时发</text>
-                  </view> -->
-                <!-- 2 是报价类型,专门为报价类型使用 -->
-                  <text v-if="message.goodsInfo.goodsPriceType == 2" class="goods-price">¥{{ message.goodsInfo.goodsPrice }}</text>
+                  <view class="sales-info" v-if="message.goodsInfo.goodsPriceType == 2">
+                    <text class="delivery-time">商家标价</text>
+                  </view>
+                  <view class="sales-info" v-if="message.goodsInfo.notExpired === false">
+                    <text class="delivery-time">报价窗口过期</text>
+                  </view>
+                  <text v-if="message.goodsInfo.goodsPriceType != 0" class="goods-price">¥{{ parseFloat(message.goodsInfo.goodsPrice).toFixed(2) }}</text>
                 </view>
               </view>
-              <view class="goods-footer">
+
+              <view class="goods-footer" v-if="message.goodsInfo.goodsPriceType == 1 || message.goodsInfo.goodsPriceType == 2">
               </view>
+              
               <view v-if="message.goodsInfo.goodsPriceType == 2" class="action-buttons">
                 <button class="action-btn spec-btn" @click="toBuy(message.goodsInfo)">查看商品</button>
                 <button class="action-btn buy-btn" @click="toBuy(message.goodsInfo)">去购买</button>
               </view>
-              <view v-else>
+              <view v-if="message.goodsInfo.goodsPriceType == 1" class="action-buttons">
                 <button class="action-btn spec-btn" @click="toGoodsDetail(message.goodsInfo)">查看商品</button>
-                <text>报价 {{ message.goodsInfo.goodsInfo.price }}</text>
+                <button  class="action-btn buy-btn" @click="toBuy(message.goodsInfo)">去购买</button>
               </view>
             </view>
             <view class="message-time align-right">{{ message.time }}</view>
@@ -72,46 +76,44 @@
         </view>
 
         <!-- 右侧消息(我的) -->
-        <view class="message-right" v-if="message.isMine || message.customId">
+        <view class="message-right" v-if="message.isMine">
           <view v-if="message.messageType == 'text'|| message.messageType != 'goods'" class="message-content-wrapper">
-            <view class="username align-right" v-if="isMultiUser">{{
-              message.username
-            }}</view>
+            <view class="username align-right" v-if="isMultiUser">{{ message.username}}</view>
             <view class="message-bubble right-bubble">
               <text class="message-text">{{ message.message }}</text>
             </view>
             <view class="message-time align-right">{{ message.time }}</view>
           </view>
-          <view v-if="message.messageType == 'goods'" class="message-content-wrapper">
-            <view class="username align-right" v-if="isMultiUser">{{
-              message.username
-            }}</view>
+          <view v-if="message.messageType == 'goods'" class="goods-content-wrapper">
+            <view class="username align-right" v-if="isMultiUser">
+              {{ message.username }}
+            </view>
             <view class="goods-info right-bubble">
-              <view class="goods-main">
-                <image
-                  class="goods-image"
-                  :src="message.goodsInfo.goodsImg"
-                  mode="aspectFill"
-                />
+              <view class="goods-main" @click="toGoodsDetail(message.goodsInfo)">
+                <image class="goods-image" :src="message.goodsInfo.goodsImg" mode="aspectFill"/>
                 <view class="goods-details">
                   <view class="goods-name-wrapper">
                     <text class="goods-name">{{ message.goodsInfo.goodsName }}</text>
                   </view>
-                  <view class="sales-info">
-                    <!-- <text class="delivery-time">48小时发</text> -->
+                  <view class="sales-info" v-if="message.goodsInfo.goodsPriceType == 2">
+                    <text class="delivery-time">商家标价</text>
+                  </view>
+                  <view class="sales-info" v-if="(message.goodsInfo.goodsPriceType == 0 && message.goodsInfo.notExpired === true)">
+                    <text class="delivery-time">等待商家标价</text>
                   </view>
-                  <text v-if="message.goodsInfo.goodsPriceType == 1" class="goods-price">¥{{ message.goodsInfo.goodsPrice }}</text>
+                  <view class="sales-info" v-if="message.goodsInfo.notExpired === false">
+                    <text class="delivery-time">报价窗口过期</text>
+                  </view>
+                  <text v-if="message.goodsInfo.goodsPriceType != 0" class="goods-price">¥{{ parseFloat(message.goodsInfo.goodsPrice).toFixed(2) }}</text>
                 </view>
               </view>
-              <view class="goods-footer">
+              <view class="goods-footer" v-if="message.goodsInfo.goodsPriceType != 0">
                 <!-- <text class="footer-text">破损包退·极速退款·7天无理由退货</text>
                 <text class="arrow">></text> -->
               </view>
-              <view class="action-buttons">
-                <button class="action-btn spec-btn" @click="toBuy(message.goodsInfo)">查看商品</button>
-                <button v-if="message.goodsInfo.goodsPriceType == 1" class="action-btn buy-btn" @click="toGoodsDetail(message.goodsInfo)">去购买</button>
-                <!-- 报价类型显示去购买 -->
-                <button v-if="message.goodsInfo.goodsPriceType == 2" class="action-btn buy-btn" @click="toBuy(message.goodsInfo)">去购买</button>
+              <view class="action-buttons" v-if="message.goodsInfo.goodsPriceType != 0">
+                <button class="action-btn spec-btn" @click="toGoodsDetail(message.goodsInfo)">查看商品</button>
+                <button class="action-btn buy-btn" @click="toBuy(message.goodsInfo)">去购买</button>
               </view>
             </view>
             <view class="message-time align-right">{{ message.time }}</view>
@@ -134,7 +136,7 @@
         <image class="goods-image" :src="currentGoodsInfo.goodsImg" mode="aspectFill" />
         <view class="goods-details">
           <text class="goods-name">{{ currentGoodsInfo.goodsName }}</text>
-          <text v-if="currentGoodsInfo.goodsPriceType == 1" class="goods-price">¥{{ currentGoodsInfo.goodsPrice }}</text>
+          <text v-if="currentGoodsInfo.goodsPriceType == 1" class="goods-price">¥{{ parseFloat(currentGoodsInfo.goodsPrice).toFixed(2) }}</text>
         </view>
         <view class="goods-actions">
           <view class="close-icon" @click="closeGoodsCard">
@@ -220,7 +222,7 @@ export default {
       // 分页加载
       allMessages: [], // 存储所有从API获取的消息
       initialLoadSize: 50, // 首次加载数量
-      loadMoreSize: 100, // 每次加载更多的数量
+      loadMoreSize: 50, // 每次加载更多的数量
       showLoadMore: false, // 是否显示“加载更多”
       // 键盘相关
       keyboardHeight: 0, // 键盘高度
@@ -229,8 +231,7 @@ export default {
     };
   },
   onLoad(options) {
-    console.log("---------- options: ", options);
-
+    // console.log("---------- options: ", options);
     if (options.goodsId) {
       this.currentGoodsInfo = {
         ...options
@@ -250,13 +251,22 @@ export default {
     }
 
     if (this.loginInfo.id) {
-      this.currentUser.userId = this.loginInfo.id;
+      this.currentUser.userId = parseInt(this.loginInfo.id);
+      if(this.currentUser.userId == 0) {
+        console.error('userId 出错 ---------- this.currentUser.userId: ', this.currentUser.userId);
+      }
     }
     if (options.customId) {
-      this.currentUser.customId = options.customId;
+      this.currentUser.customId = parseInt(options.customId);
+      if(this.currentUser.customId == 0) {
+        console.error('customId 出错 ---------- this.currentUser.customId: ', this.currentUser.customId);
+      }
     }
     if (options.shopId) {
-      this.currentUser.shopId = options.shopId;
+      this.currentUser.shopId = parseInt(options.shopId);
+      if(this.currentUser.shopId == 0) {
+        console.error('shopId 出错 ---------- this.currentUser.shopId: ', this.currentUser.shopId);
+      }
     }
     if (options.name) {
       this.currentUser.username = options.name;
@@ -267,18 +277,12 @@ export default {
 
     // 获取房间号
     if (this.currentUser.customId && this.currentUser.shopId) {
-      this.room =
-        "custom_id-" +
-        this.currentUser.customId +
-        "AND" +
-        "shop_id-" +
-        this.currentUser.shopId;
+      this.room = "custom_id-" + this.currentUser.customId + "AND" + "shop_id-" + this.currentUser.shopId;
     } else {
       // 如果没有传入房间号,使用默认值或生成一个
       this.room = "default_room";
     }
-    
-    console.log("---------- this.room: ", this.room);
+    // console.log("---------- this.room: ", this.room);
 
     // 加载聊天记录
     this.loadChatHistory();
@@ -308,7 +312,6 @@ export default {
   },
   onUnload() {
     // 页面卸载时关闭WebSocket连接
-    this.isManualDisconnect = true; // 标记为主动断开
     this.disconnectWebSocket();
   },
   onHide() {
@@ -325,7 +328,7 @@ export default {
     init() {},
     // 加载聊天历史记录
     loadChatHistory() {
-      const userId = parseInt(this.currentUser.userId);
+      const userId = this.currentUser.userId;
       if (isNaN(userId) || userId <= 0) {
         this.$msg("当前用户的id出错");
         return;
@@ -336,6 +339,10 @@ export default {
       }).then((res) => {
         if (res.code == 1 && res.data) {
           this.allMessages = res.data.map((item, index) => {
+            // 判断是否是我(本客户)发送的消息
+            const isMine = item.customId ? parseInt(item.customId) == this.currentUser.customId : false;
+            //console.log("---isMine---: ", isMine);
+
             const newItem = {
               ...item,
               id: `message-${index}`, // 为每条消息添加唯一ID
@@ -345,6 +352,8 @@ export default {
             if (newItem.messageType === 'goods') {
               newItem.goodsInfo = this.parseGoodsMessage(newItem.message, newItem.timestamp);
             }
+            newItem.isMine = isMine;
+
             return newItem;
           });
 
@@ -473,7 +482,9 @@ export default {
           // 只有在非主动断开的情况下才尝试重连
           if (!this.isManualDisconnect && this.reconnectCount < this.maxReconnectCount) {
             setTimeout(() => {
-              this.reconnectWebSocket();
+              if (!this.isManualDisconnect) {
+                this.reconnectWebSocket();
+              }
             }, 3000);
           }
 
@@ -498,19 +509,19 @@ export default {
     // 构建WebSocket子协议参数(模拟POST body传输)
     buildWebSocketProtocols() {
       try {
-        const userId = parseInt(this.loginInfo.id); //当前用户的id(不是 customId,是customer登录帐户的userId)
+        const userId = this.currentUser.userId; //当前用户的id(不是 customId,是customer登录帐户的userId)
         if (isNaN(userId) || userId <= 0) {
           this.$msg("当前用户的id出错");
           return;
         }
         
-        const customId = parseInt(this.currentUser.customId);
+        const customId = this.currentUser.customId;
         if (isNaN(customId) || customId <= 0) {
           this.$msg("当前用户的customId出错");
           return;
         }
         
-        const shopId = parseInt(this.currentUser.shopId);
+        const shopId = this.currentUser.shopId;
         if (isNaN(shopId) || shopId <= 0) {
           this.$msg("当前用户的shopId出错");
           return;
@@ -523,7 +534,7 @@ export default {
           s_id: shopId,
           u_name: this.currentUser.username && this.currentUser.username.length > 30 ? this.currentUser.username.substring(0, 30) : this.currentUser.username,
           platform: this.getPlatformInfo(),
-          type: "customer", // 客户端类型:shop:门店端, customer:客户端
+          type: "customer", // 客户端类型:shop(门店端), customer(客户端)
           staff_id: parseInt(0),
         };
 
@@ -542,7 +553,6 @@ export default {
 
         // 验证协议字符串的合法性
         const isValid = this.validateProtocols(protocols);
-        console.log("协议验证结果:", isValid);
         if (!isValid) {
           this.$msg("协议验证失败");
           return;
@@ -575,7 +585,7 @@ export default {
           console.error("协议长度超限:", protocol.length);
           return false;
         }
-        console.log('protocal -- ', protocol, protocol.length)
+        // console.log('protocal -- ', protocol, protocol.length)
       }
 
       return true;
@@ -756,7 +766,7 @@ export default {
 
     // 处理WebSocket消息
     handleWebSocketMessage(data) {
-      console.log("---------- data: ", data);
+      // console.log("---------- data: ", data);
       try {
         // 尝试解析JSON,如果失败则认为是纯文本消息
         let messageData;
@@ -800,7 +810,7 @@ export default {
           newMessage.goodsInfo = this.parseGoodsMessage(messageData.message, messageData.timestamp);
         }
 
-        console.log("收到 ---------- newMessage: ", newMessage);
+        // console.log("收到 ---------- newMessage: ", newMessage);
         // 添加到消息列表
         this.messageList.push(newMessage);
 
@@ -871,7 +881,7 @@ export default {
         };
 
         const json = JSON.stringify(messageData);
-        console.log("send ---------- json: ", json);
+        // console.log("send ---------- json: ", json);
         // 发送到WebSocket服务器
         this.socket.send({
           data: json,
@@ -930,7 +940,7 @@ export default {
 
     // 输入框聚焦事件
     onInputFocus() {
-      console.log('输入框聚焦');
+      // console.log('输入框聚焦');
       // 微信小程序中,聚焦时延迟滚动到底部
       setTimeout(() => {
         this.scrollToBottom();
@@ -939,7 +949,7 @@ export default {
 
     // 输入框失焦事件
     onInputBlur() {
-      console.log('输入框失焦');
+      // console.log('输入框失焦');
     },
 
     // 输入内容变化事件
@@ -1025,7 +1035,7 @@ export default {
         this.socket.send({
           data: json,
           success: () => {
-            console.log("商品消息发送成功");
+            // console.log("商品消息发送成功");
           },
           fail: (error) => {
             console.error("商品消息发送失败:", error);
@@ -1054,6 +1064,7 @@ export default {
         // 如果是字符串,则尝试解析
         if (typeof messageStr === "string") {
           const parsed = JSON.parse(messageStr);
+
           if(parsed.goodsPriceType == 0) {
             const key = parsed.key || '';
             if (key == '') {
@@ -1081,8 +1092,10 @@ export default {
             const now = Math.floor(Date.now()/1000);
             const timeDiff = now - timestamp;
             const expireTime = 24 * 60 * 60;
+            parsed.notExpired = true; // 默认未过期
             if (timeDiff > expireTime) {
               //console.log("timeDiff > expireTime", timeDiff, expireTime)
+              parsed.notExpired = false;
               return parsed;
             }
 
@@ -1093,7 +1106,7 @@ export default {
               if (res.code == 1) {
                 if (res.data.price != -1) {
                   parsed.goodsPriceType = 2; // 报价类型
-                  parsed.goodsPrice = res.data.price;
+                  parsed.goodsPrice = parseFloat(res.data.price).toFixed(2);
                 }
               }
             }).catch(err => {
@@ -1117,7 +1130,7 @@ export default {
     // 查看商品
     toGoodsDetail(goodsInfo) {
       this.disconnectWebSocket();
-      console.log("---------- goodsInfo: ", goodsInfo);
+      // console.log("---------- goodsInfo: ", goodsInfo);
       const goodsId = parseInt(goodsInfo.goodsId);
       const categoryId = parseInt(goodsInfo.categoryId);
       const hdId = parseInt(goodsInfo.hdId);
@@ -1143,12 +1156,12 @@ export default {
     // 去购买
     toBuy(goodsInfo) {
       this.disconnectWebSocket();
-      console.log("---------- goodsInfo: ", goodsInfo);
+      // console.log("---------- goodsInfo: ", goodsInfo);
       const goodsId = parseInt(goodsInfo.goodsId);
       const categoryId = parseInt(goodsInfo.categoryId);
       const hdId = parseInt(goodsInfo.hdId);
       const account = parseInt(goodsInfo.account);
-      const price = parseFloat(goodsInfo.goodsPrice);
+      const price = parseFloat(goodsInfo.goodsPrice).toFixed(2);
       const priceType = goodsInfo.goodsPriceType;
       if (isNaN(goodsId) || isNaN(categoryId) || isNaN(hdId) || isNaN(account) || isNaN(price)) {
         this.$msg("商品数据异常");
@@ -1225,7 +1238,7 @@ export default {
     }
 
     .goods-price {
-      font-size: 30upx;
+      font-size: 28upx;
       font-weight: bold;
       color: #ff5050;
       margin-top: 4upx;
@@ -1326,6 +1339,10 @@ export default {
   min-width: 100upx;
 }
 
+.goods-content-wrapper {
+  width: 72%;
+}
+
 .username {
   font-size: 24upx;
   color: $fontColor3;
@@ -1425,7 +1442,7 @@ export default {
       height: 80rpx;
     }
     .goods-name {
-      font-size: 28rpx;
+      font-size: 32rpx;
       color: #333;
       font-weight: bold;
       // 多行省略
@@ -1450,10 +1467,10 @@ export default {
       border-radius: 4rpx;
     }
     .goods-price {
-      font-size: 36rpx;
+      font-size: 28rpx;
       color: #ff5050;
       font-weight: bold;
-      margin-top: 12rpx;
+      margin-top: 2rpx;
     }
   }
 

+ 80 - 70
mallApp/src/pages/goods/components/sel-popup.vue

@@ -8,22 +8,25 @@
             <div class="tui-number-box tui-bold tui-attr-title">
               <div class="tui-attr-title">数量</div>
               <div class="number-box-wrapper">
-                <number-box 
-                  :max="maxStock" 
-                  :min="1" 
-                  :value="buyNum" 
-                  :iconSize="36" 
-                  :height="60" 
-                  :width="120" 
+                <number-box
+                  :max="maxStock"
+                  :min="1"
+                  :value="buyNum"
+                  :iconSize="36"
+                  :height="60"
+                  :width="120"
                   :size="32"
-                  @change="change">
+                  @change="change"
+                >
                 </number-box>
               </div>
             </div>
           </div>
         </scroll-view>
         <div class="tui-popup-btn">
-          <button class="button-com red enhanced-btn" @click="nextFn">下一步</button>
+          <button class="button-com red enhanced-btn" @click="nextFn">
+            下一步
+          </button>
         </div>
       </div>
     </bottom-popup>
@@ -38,41 +41,41 @@ export default {
   components: {
     BottomPopup,
     NumberBox,
-    AppClose
+    AppClose,
   },
   props: {
     info: {
       type: Object,
       default: () => {
         return {};
-      }
+      },
     },
     buyNum: {
       type: Number,
-      default: 1
+      default: 1,
     },
     hdId: {
       type: Number,
-      default: 0
+      default: 0,
     },
-    account:{
-      type:Number,
-      default:0
+    account: {
+      type: Number,
+      default: 0,
     },
     show: {
       type: Boolean,
-      default: true
-    }
+      default: true,
+    },
   },
   data() {
     return {
-      selIndex: 0
+      selIndex: 0,
     };
   },
   computed: {
     maxStock() {
-      return 9999
-    }
+      return 9999;
+    },
   },
   methods: {
     change(e) {
@@ -82,58 +85,68 @@ export default {
       this.$emit("close");
     },
     nextFn() {
-      if(Number(this.info.price) <= 0){
-        this.$msg('商品还没有价格哦')
-        return false
+      if (Number(this.info.price) <= 0) {
+        this.$msg("商品还没有价格哦");
+        return false;
       }
-      uni.setStorageSync("buyGoodsDetil", this.info)
-      this.$util.pageTo({url:"/pages/order/buy?hdId="+this.hdId+'&goodsId='+this.info.id+'&goodsNum='+this.buyNum+'&selIndex='+this.selIndex+'&account='+this.account,type:2})
-    }
-  }
+      uni.setStorageSync("buyGoodsDetil", this.info);
+      this.$util.pageTo({
+        url: "/pages/order/buy",
+        query: {
+          hdId: this.hdId,
+          goodsId: this.info.id,
+          goodsNum: this.buyNum,
+          selIndex: this.selIndex,
+          account: this.account,
+        },
+        type: 2,
+      });
+    },
+  },
 };
 </script>
 
 <style lang="scss" scoped>
 ::v-deep.popup-wrap {
   .tui-popup-class {
-    border-top-left-radius: 24upx;
-    border-top-right-radius: 24upx;
+    border-top-left-radius: 24rpx;
+    border-top-right-radius: 24rpx;
     // 适配iphoneX
     padding-bottom: env(safe-area-inset-bottom);
   }
 
   .tui-popup-box {
     position: relative;
-    padding: 60upx 30upx 140upx;
+    padding: 60rpx 30rpx 140rpx;
     background: #fff;
-    min-height: 300upx;
+    min-height: 300rpx;
   }
 
   .tui-popup-btn {
     width: 100%;
     position: absolute;
     left: 0;
-    bottom: 0;
-    padding: 20upx 30upx 40upx 30upx;
-    padding-bottom: calc(40upx + env(safe-area-inset-bottom));
+    top: 250rpx;
+    padding: 20rpx 30rpx 20rpx 30rpx;
+    padding-bottom: calc(40rpx + env(safe-area-inset-bottom));
     @include disFlex(center, center);
-    border-top: 1upx solid $borderColor;
+    border-top: 1rpx solid $borderColor;
     background: #fff;
-    
+
     .button-com {
       width: 100%;
-      font-size: 36upx;
-      height: 110upx;
-      border-radius: 55upx;
+      font-size: 36rpx;
+      height: 110rpx;
+      border-radius: 55rpx;
       font-weight: 600;
-      letter-spacing: 2upx;
-      box-shadow: 0 8upx 24upx rgba(228, 31, 25, 0.3);
+      letter-spacing: 2rpx;
+      box-shadow: 0 8rpx 24rpx rgba(228, 31, 25, 0.3);
       display: flex;
       align-items: center;
       justify-content: center;
       line-height: 1;
       padding: 0;
-      
+
       &.enhanced-btn {
         background: linear-gradient(135deg, #ff4757 0%, #e41f19 100%);
         border: none;
@@ -142,36 +155,33 @@ export default {
     }
   }
 
-
   .tui-popup-scroll {
-    max-height: 400upx;
-    font-size: 28upx;
+    max-height: 400rpx;
+    font-size: 28rpx;
   }
 
   .tui-scrolldiv-box {
-    padding: 10upx 0;
+    padding: 10rpx 0;
   }
 
-
   .tui-attr-title {
-    padding: 0 0 20upx 0;
+    padding: 0 0 20rpx 0;
     color: #333;
-    font-size: 32upx;
+    font-size: 32rpx;
     font-weight: 600;
     text-align: left;
   }
 
-
   .tui-number-box {
     display: flex;
     align-items: center;
     justify-content: space-between;
-    padding: 30upx 0 40upx 0;
+    padding: 30rpx 0 40rpx 0;
     box-sizing: border-box;
     background: #fafafa;
-    border-radius: 16upx;
-    margin: 20upx 0;
-    padding: 40upx 30upx;
+    border-radius: 16rpx;
+    margin: 20rpx 0;
+    padding: 40rpx 30rpx;
   }
 
   .number-box-wrapper {
@@ -183,41 +193,41 @@ export default {
   // 覆盖 number-box 组件的样式
   ::v-deep .tui-numberbox {
     .tui-numbox-icon {
-      width: 60upx;
-      height: 60upx;
+      width: 60rpx;
+      height: 60rpx;
       border-radius: 50%;
       background: #fff;
       display: flex;
       align-items: center;
       justify-content: center;
-      box-shadow: 0 2upx 8upx rgba(0, 0, 0, 0.1);
+      box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
       padding: 0;
-      
+
       &:before {
-        font-size: 36upx !important;
+        font-size: 36rpx !important;
         font-weight: bold;
       }
-      
+
       &.tui-disabled {
         background: #f0f0f0;
         box-shadow: none;
-        
+
         &:before {
           color: #ccc !important;
         }
       }
     }
-    
+
     .tui-num-input {
-      width: 120upx !important;
-      height: 60upx !important;
-      margin: 0 20upx !important;
+      width: 120rpx !important;
+      height: 60rpx !important;
+      margin: 0 20rpx !important;
       background: #fff !important;
-      border-radius: 12upx !important;
-      border: 2upx solid #e8e8e8 !important;
-      font-size: 32upx !important;
+      border-radius: 12rpx !important;
+      border: 2rpx solid #e8e8e8 !important;
+      font-size: 32rpx !important;
       font-weight: 600 !important;
-      box-shadow: 0 2upx 8upx rgba(0, 0, 0, 0.08);
+      box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08);
     }
   }
 }

+ 1 - 0
mallApp/src/pages/goods/detail.vue

@@ -12,6 +12,7 @@
           {{ data.price ? parseFloat(data.price).toFixed(2) : 0}}
         </text>
       </view>
+      <!--报价类型-->
       <view class="app-price app-bold" v-if="data.priceType == 2">
         <text>¥</text>
         <text class="app-size-34">

+ 0 - 646
mallApp/src/pages/goods/picGoods.vue

@@ -1,646 +0,0 @@
-<template>
-    <view class="app-main app-content">
-  
-          <view class="c_header" :class="myClass">
-              <view class="header_inside">
-                  <image :src="shopImg"></image>
-                  <view class="shop_info">
-                      <view class="shop_title">{{shopName}}</view>
-                  </view>
-              </view>
-          </view>
-  
-          <!-- 搜索框和花材绿植按钮区域 -->
-          <view class="search-wrap">
-              <view class="search-bar">
-                  <app-search-module 
-                      v-model="searchText" 
-                      :placeholder="isSearching ? '正在搜索...' : '搜索商品名称'" 
-                      @input="searchFn" 
-                      :height="66"
-                      :fontSize="28"
-                  />
-              </view>
-              <view class="buy-material-container">
-                  <button class="buy-material-btn" @click="buyProduct()">
-                      <view class="btn-content">
-                          <text class="btn-text">花材绿植</text>
-                      </view>
-                  </button>
-              </view>
-          </view>
-          <!-- 搜索状态提示 -->
-          <view v-if="isSearching" class="search-loading">
-              <text class="loading-text">正在搜索...</text>
-          </view>
-  
-      <scroll-view scroll-y scroll-with-animation class="tab-view" :scroll-top="scrollTop">
-        <view v-for="(item,index) in tabbar" :key="index" class="tab-bar-item" :class="[!isSearchMode && currentTab==index ? 'active' : '']" :data-current="index" @tap.stop="swichNav($event ,item)" >
-          <text>{{item.categoryName}}</text>
-        </view>
-        <view style="height:150upx"></view>
-      </scroll-view>
-      
-      <!-- 搜索结果展示区域 -->
-      <scroll-view v-if="isSearchMode" scroll-y class="right-box" @scrolltolower="reachBottom">
-        <view class="page-view" v-if="!$util.isEmpty(list.data)" >
-          <view class="goods-list" v-for="(items) in list.data" :key="items.id" @click="toBuy(items)" >
-            <view class="img-blo">
-              <image :src="items.smallCover" mode="aspectFill" ></image>
-            </view>
-            <view class="goods-det">
-              <view class="goods-det-top">
-                <view class="goods-name">{{ items.name }}</view>
-                <view class="goods-sales"></view>
-              </view>
-              <view class="goods-price">已售 {{ items.actualSold?parseInt(items.actualSold):0 }}</view>
-              <view class="buy-btn">查看</view>
-            </view>
-          </view>
-        </view>
-        <block v-else>
-          <app-wrapper-empty 
-            :title="getEmptyTitle()" 
-            :is-empty="$util.isEmpty(list.data)" 
-          />
-        </block>
-      </scroll-view>
-  
-      <!-- 分类商品展示区域 -->
-      <block v-for="(item,index) in tabbar" :key="index" >
-        <scroll-view scroll-y class="right-box" @scrolltolower="reachBottom" v-if="!isSearchMode && currentTab==index" >
-          <view class="page-view" v-if="!$util.isEmpty(list.data)" >
-            <view class="goods-list" v-for="(items) in list.data" :key="items.id" @click="toBuy(items)" >
-              <view class="img-blo">
-                <image :src="items.smallCover" mode="aspectFill" ></image>
-              </view>
-              <view class="goods-det">
-                <view class="goods-det-top">
-                  <view class="goods-name">{{ items.name }}</view>
-                  <view class="goods-sales"></view>
-                </view>
-                <view class="goods-price">已售 {{ items.actualSold?parseInt(items.actualSold):0 }}</view>
-                <view class="buy-btn">查看</view>
-              </view>
-            </view>
-          </view>
-          <block v-else>
-            <app-wrapper-empty 
-              :title="getEmptyTitle()" 
-              :is-empty="$util.isEmpty(list.data)" 
-            />
-          </block>
-        </scroll-view>
-      </block>
-  
-      <wangCg :loginStyle.sync="globalLoginStyle" @goToLogin="loginTo()"></wangCg>
-    </view>
-  </template>
-  <script>
-  import { mapGetters } from 'vuex'
-  import AppImg from '@/components/app-img'
-  import wangCg from "@/components/wangCg"
-  import AppWrapperEmpty from '@/components/app-wrapper-empty'
-  import AppSearchModule from '@/components/item/module/app-search'
-  import { getClass, getNonPriceList } from '@/api/category'
-  import { list,share } from '@/mixins'
-  import { getInfo } from "@/api/shop"
-  export default {
-    name: 'category',
-    components: {
-      AppWrapperEmpty,
-      AppImg,
-      wangCg,
-      AppSearchModule
-    },
-    mixins: [list, share],
-    data () {
-      return {
-        tabbar: [],
-        height: 0,
-        currentTab: 0,
-        scrollTop: 0,
-        form: {
-          categoryId: ''
-        },
-        currentTabIndex: 1,
-        myClass: 'fadeIn',
-              shopName:'',
-              shopImg:'',
-        hdId:0,
-        searchText: '', // 搜索文本
-        searchTimer: null, // 搜索防抖定时器
-        isSearchMode: false, // 是否为搜索模式
-        isSearching: false, // 是否正在搜索
-        lastSearchText: '' // 上次搜索的文本,用于优化
-      }
-    },
-      computed: {
-      ...mapGetters({ loginInfo:"getLoginInfo" })
-      },
-    onShareAppMessage(res) {
-          return {
-              title: '花束花礼',
-              desc: "",
-              path: "pages/home/category?account="+this.option.account,
-          }
-      },
-      onShow(){
-          if(!this.$util.isEmpty(this.loginInfo)){
-              this.globalLoginStyle = 1
-          }else{
-              this.globalLoginStyle = 0
-          }
-    },
-    onUnload() {
-      // 清理搜索定时器
-      if (this.searchTimer) {
-        clearTimeout(this.searchTimer);
-        this.searchTimer = null;
-      }
-    },
-  
-      watch: {
-          loginInfo: {
-              deep: true,
-              handler: function(newVal) {
-                  if(!this.$util.isEmpty(newVal)){
-                      this.globalLoginStyle = 1
-                  }else{
-                      this.globalLoginStyle = 0
-                  }
-              },
-              immediate:true
-          }
-      },
-    methods: {
-      toBuy(item){
-        let account = this.option.account?this.option.account:0
-        this.$util.pageTo({url:"/pages/goods/detail?id="+item.id+'&hdId='+this.hdId+'&categoryId='+this.form.categoryId+'&account='+account})
-      },
-      buyProduct(){
-        let account = this.option.account?this.option.account:0
-        this.$util.pageTo({url:"/pages/item/item?account="+account+'&hdId='+this.hdId,type:2})
-      },
-      loginTo() {
-        let account = this.option.account?this.option.account:0
-        this.$util.pageTo({url:"/pages/login/index?needBack=1&account="+account})
-      },
-      init(){
-        this.hdId = this.option.hdId ? this.option.hdId : 0
-        this.classInit()
-              getInfo({hdId:this.hdId}).then(res=>{
-                  if(res.code == 1){
-                      if(res.data.info && res.data.info.merchantName){
-                          let sjName = res.data.info.merchantName
-                          let shopName = res.data.info.shopName ? res.data.info.shopName : '首店'
-                          let name = shopName == '首店' ? sjName : sjName+' '+shopName
-                          this.shopName = name
-                          this.shopImg = res.data.info.avatar
-                      }
-  
-                      if(res.data.hd && Number(res.data.hd.id) > 0){
-                          if(Number(this.hdId) == 0){
-                              this.hdId = res.data.hd.id
-                          }
-                      }
-  
-                  }
-              })
-      },
-      // 搜索输入处理(防抖)
-      searchFn() {
-        console.log('searchFn----------', this.searchText, 'lastSearchText:', this.lastSearchText)
-        
-        // 清除之前的定时器
-        if (this.searchTimer) {
-          clearTimeout(this.searchTimer)
-          this.searchTimer = null
-        }
-        
-        // 如果搜索文本为空
-        if (this.$util.isEmpty(this.searchText)) {
-          // 如果之前也是空文本(首次点击或焦点清空),跳过搜索
-          if (this.$util.isEmpty(this.lastSearchText)) {
-            console.log('搜索文本为空且之前也为空,跳过搜索')
-            return
-          }
-          // 如果之前有搜索文本,现在清空了,则恢复分类筛选
-          this.clearSearch()
-          return
-        }
-        
-        // 如果搜索文本与上次相同,不重复搜索
-        if (this.searchText === this.lastSearchText) {
-          console.log('搜索文本未变化,跳过搜索')
-          return
-        }
-        
-        // 设置防抖定时器,1秒后执行搜索
-        this.searchTimer = setTimeout(() => {
-          this.performSearch()
-        }, 1000)
-      },
-      
-      // 执行搜索
-      performSearch() {
-        if (this.$util.isEmpty(this.searchText)) {
-          return
-        }
-        
-        console.log('执行搜索:', this.searchText)
-        
-        this.isSearchMode = true
-        this.isSearching = true
-        this.lastSearchText = this.searchText
-        this.resetList()
-        this.searchGoods()
-      },
-      
-      // 清空搜索,恢复分类筛选
-      clearSearch() {
-        console.log('清空搜索,恢复分类筛选')
-        this.isSearchMode = false
-        this.isSearching = false
-        this.lastSearchText = ''
-        
-        // 确保搜索框内容被清空
-        this.$nextTick(() => {
-          this.searchText = ''
-        })
-        
-        this.resetList()
-        this.getGoodList()
-      },
-      
-      // 搜索商品
-      searchGoods() {
-        return getNonPriceList({ 
-          searchText: this.searchText, 
-          page: this.list.page, 
-          pageSize: 10 
-        }).then(res => {
-          this.isSearching = false
-          this.completes(res)
-          console.log('搜索成功,数据已加载')
-        }).catch(err => {
-          this.isSearching = false
-          console.error('搜索失败:', err)
-          this.$msg('搜索失败,请重试')
-        })
-      },
-      reachBottom () {
-        console.log('reachBottom----------', this.list.finished)
-        if (this.list.finished == false && !this.isSearching) {
-          // 根据是否为搜索模式决定调用哪个方法
-          if (this.isSearchMode) {
-            this.searchGoods().then(res => {
-              uni.stopPullDownRefresh()
-            });
-          } else {
-            this.getGoodList().then(res => {
-              uni.stopPullDownRefresh()
-            });
-          }
-        } else {
-          uni.stopPullDownRefresh()
-        }
-      },
-      async classInit () {
-        this.getMyClass() .then(res => {
-          this.getGoodList()
-        })
-      },
-      // 分类
-      getMyClass () {
-        return getClass().then(res => {
-          if(res.code && res.code == 1){
-            this.form.categoryId = res.data[0].id
-            this.tabbar = res.data
-          }
-        })
-      },
-      // 列表
-      getGoodList () {
-        return getNonPriceList({ ...this.form, page: this.list.page,pageSize:10 }) .then(res => {
-            // 处理商品列表数据,completes方法来自list混入
-            // 该方法会处理分页数据,更新list对象的data、page、finished等属性
-            // res包含接口返回的商品列表数据,completes方法会将数据添加到this.list.data中
-            this.completes(res)
-        })
-      },
-      // 点击标题切换当前页时改变样式
-      swichNav (e, item) {
-        let cur = e.currentTarget.dataset.current
-        if (this.currentTab == cur && !this.isSearchMode) {
-          return false
-        } else {
-          this.currentTab = cur
-          this.form.categoryId = item.id
-          
-          // 切换分类时清空搜索状态
-          this.clearSearchState()
-          this.resetList()
-          this.getGoodList()
-        }
-      },
-      // 判断当前滚动超过一屏时,设置tab标题滚动条。
-      checkCor () {
-        let that = this
-        // 这里计算按照实际情况进行修改,动态数据要进行动态分析
-        // 思路:窗体高度/单个分类高度 200upx 转px计算 =>得到一屏幕所显示的个数,结合后台传回分类总数进行计算
-        // 数据很多可以多次if判断然后进行滚动距离计算即可
-        if (that.currentTab > 7) {
-          that.scrollTop = 500
-        } else {
-          that.scrollTop = 0
-        }
-      },
-      tabClick (index) {
-        this.currentTabIndex = index
-      },
-      
-      // 清空搜索状态(不触发数据重新加载)
-      clearSearchState() {
-        // 清除定时器
-        if (this.searchTimer) {
-          clearTimeout(this.searchTimer)
-          this.searchTimer = null
-        }
-        
-        // 重置搜索相关状态
-        this.searchText = ''
-        this.isSearchMode = false
-        this.isSearching = false
-        this.lastSearchText = ''
-        
-        // 确保搜索框内容被清空(强制更新)
-        // this.$nextTick(() => {
-        //   this.searchText = ''
-        // })
-      },
-      
-      // 获取空状态提示文字
-      getEmptyTitle() {
-        if (this.isSearchMode && this.searchText) {
-          return `未找到"${this.searchText}"相关商品`
-        }
-        return '暂无商品'
-      }
-    },
-    
-    // 组件销毁时清理定时器
-    beforeDestroy() {
-      if (this.searchTimer) {
-        clearTimeout(this.searchTimer)
-        this.searchTimer = null
-      }
-    }
-  }
-  </script>
-  
-  <style lang="scss" scoped>
-  .app-content {
-    background-color: #fff;
-  
-  .c_header{
-      width: 100vw;
-      padding: 0 15upx;
-      box-sizing: border-box;
-      background: linear-gradient(to bottom,#3385FF, #fff);
-      &>.header_inside{
-        position: relative;
-        height: 124upx;
-        margin-top: 15upx;
-        background: #fff;
-        box-shadow: 0upx 1px 21px 0upx rgba(161, 166, 173, 0.4);
-        border-radius: 20upx;
-        padding: 35upx 30upx 30upx 30upx;
-        box-sizing: border-box;
-        &>image{
-          height: 60upx;
-          width: 60upx;
-          display: inline-block;
-          border-radius: 10upx;
-          background-color: #eee;
-          vertical-align: top;
-        }
-        &>.shop_info{
-          vertical-align: top;
-          display: inline-block;
-          height: 100%;
-          margin-left: 20upx;
-          &>.shop_title{
-            margin-top:0upx;
-            font-size:40upx;
-            font-weight: 600;
-            color: #060606;
-            width: 580upx;
-            overflow: hidden;
-            white-space: nowrap;
-          }
-        }
-      }
-    }
-  
-    .fadeIn{
-      height:180upx;
-      overflow: hidden;
-      animation-name: fadeInFrames;
-      animation-duration:.3s;
-    }
-  
-  }
-  
-  page {
-    background: #fff;
-  }
-  
-  ::-webkit-scrollbar {
-    width: 0;
-    height: 0;
-    color: transparent;
-  }
-  
-  .tab-view {
-    ::-webkit-scrollbar {
-      width: 0;
-      height: 0;
-      color: transparent;
-    }
-    width: 200upx;
-    position: fixed;
-    left: 0;
-    z-index: 10;
-    height: calc(100vh - 160upx); /* 调整高度以适应搜索框 */
-    background-color: #f0f2f6;
-    .tab-bar-item {
-      width: 200upx;
-      height: 110upx;
-      box-sizing: border-box;
-      display: flex;
-      align-items: center;
-      justify-content: center;
-      font-size: 28upx;
-      color: #444;
-      font-weight: 400;
-    }
-    .active {
-      position: relative;
-      color: $mainColor;
-      font-size: 26upx;
-      background: #fff;
-    }
-  
-    .active::before {
-      content: "";
-      position: absolute;
-      border-left: 8upx solid $mainColor;
-      height: 100%;
-      left: 0;
-    }
-  }
-  .right-box {
-    width: 100%;
-    overflow: auto;
-    height: calc(100vh - 280upx); /* 调整高度以适应搜索框 */
-    padding-left: 220upx;
-    box-sizing: border-box;
-    .page-view {
-      width: 100%;
-      overflow: hidden;
-      box-sizing: border-box;
-      margin-bottom:60upx;
-      .goods-list {
-        @include disFlex(flex-start, flex-start);
-        margin: 40upx 0;
-        .img-blo {
-          width: 200upx;
-          height: 200upx;
-          margin-right: 20upx;
-          image{
-            width: 200upx;
-            height: 200upx;
-          }
-        }
-        .goods-det {
-          padding-top: 18upx;
-          font-size: 28upx;
-          position: relative;
-          width: calc(100% - 240upx);
-          .goods-det-top {
-            .goods-name {
-              font-size: 32upx;
-              margin-bottom: 10upx;
-              overflow: hidden;
-              text-overflow: ellipsis;
-              display: -webkit-box;
-              -webkit-line-clamp: 2;
-              line-clamp: 2;
-              -webkit-box-orient: vertical;
-              word-break: break-all;
-            }
-          }
-          .goods-price {
-            font-size: 22upx;
-            margin-top: 110upx;
-            color: #676767;
-          }
-        }
-      }
-    }
-  }
-  
-  /* 搜索框样式 */
-  .search-wrap {
-      padding: 15upx 30upx 25upx 30upx;
-      background: linear-gradient(to bottom, #3385FF, #fff);
-      display: flex;
-      align-items: center;
-      gap: 20upx;
-  }
-  
-  .search-bar {
-      flex: 1;
-      background-color: #fff;
-      border-radius: 30upx;
-      padding: 2upx;
-      box-shadow: 0upx 2px 8px 0upx rgba(0, 0, 0, 0.1);
-      position: relative;
-  }
-  
-  .search-loading {
-      padding: 10upx 30upx;
-      text-align: center;
-      background-color: #f5f5f5;
-      
-      .loading-text {
-          font-size: 24upx;
-          color: #666;
-      }
-  }
-  
-  .buy-material-container {
-      flex-shrink: 0;
-  }
-  
-  .buy-material-btn {
-      position: relative;
-      background: linear-gradient(135deg, #4caf50, #66bb6a, #81c784);
-      border: none;
-      border-radius: 50upx;
-      padding: 0;
-      height: 80upx;
-      min-width: 160upx;
-      box-shadow: 0 8upx 20upx rgba(76, 175, 80, 0.3);
-      overflow: hidden;
-  
-  
-      &:active {
-          box-shadow: 0 4upx 10upx rgba(76, 175, 80, 0.4);
-      }
-  
-      .btn-content {
-          display: flex;
-          align-items: center;
-          justify-content: center;
-          height: 100%;
-          position: relative;
-          z-index: 1;
-      }
-  
-      .btn-text {
-          color: white;
-          font-size: 28upx;
-          font-weight: bold;
-          text-shadow: 0 2upx 4upx rgba(0, 0, 0, 0.2);
-          margin: 0 8upx;
-      }
-  }
-  
-  @keyframes fadeInFrames {
-      0% {
-          opacity: 0;
-          transform: translateY(0);
-          height: 0;
-      }
-      100% {
-          opacity: 1;
-          height: 180upx;
-      }
-  }
-  
-  .buy-btn {
-    color: red;
-    border: 1upx solid red;
-    border-radius: 10upx;
-    width: 100upx;
-    text-align: center;
-    padding: 5upx 0;
-    font-size: 25upx;
-    position: absolute;
-    right: 30upx;
-    top: 150upx;
-  }
-  </style>
-  

+ 1 - 89
mallApp/src/pages/home/index.vue

@@ -1,92 +1,4 @@
 <template>
   <view class="app-main app-content">
-    <app-swiper v-if="!$util.isEmpty(ad)" :list="ad" />
-    <view style="margin-bottom:100upx;" v-if="!$util.isEmpty(category)">
-      <view class="goods-module" v-for="(item, index) in category" :key="index" >
-        <goods-list-big v-if="item.showRow == 1" :info="item" />
-        <goods-list-small v-if="item.showRow == 2" :info="item" />
-      </view>
-    </view>
-    <block v-else>
-      <app-wrapper-empty title="暂无商品" is-empty="true" />
-    </block>
   </view>
-</template>
-<script>
-import { mapGetters } from "vuex";
-import AppSwiper from "@/components/app-swiper";
-import AppTrademark from "@/components/module/app-trademark";
-import goodsListBig from "@/pages/home/components/goods-list-big";
-import goodsListMiddle from "@/pages/home/components/goods-list-middle";
-import goodsListSmall from "@/pages/home/components/goods-list-small";
-import { getMainIndex } from "@/api/home";
-import { getOrderShop } from "@/utils/config"
-import { share } from "@/mixins"
-import AppWrapperEmpty from '@/components/app-wrapper-empty'
-export default {
-  name: "home",
-  components: {
-    AppSwiper,
-    AppTrademark,
-    goodsListBig,
-    goodsListMiddle,
-    goodsListSmall,
-    AppWrapperEmpty
-  },
-  mixins: [share],
-  data () {
-    return {
-      data: {},
-      ad: [],
-      category: [],
-      columnStyle: null,
-      currentTabIndex: 0,
-      account: '',
-      pageTitle: ''
-    };
-  },
-  computed: {
-    ...mapGetters({ orderShop: "getOrderShop" })
-  },
-  onLoad(){
-    uni.hideTabBar()
-  },
-  onShow () {
-    uni.hideTabBar()
-  },
-  methods: {
-    init () {
-      getOrderShop()
-      this.getDetail()
-    },
-    getDetail() {
-      return getMainIndex().then(res => {
-        this.data = res.data;
-        if (this.$util.isEmpty(res.data)){
-          return false;
-        }
-        this.ad = res.data.ad.map(e => {
-          e.img = e.adImg;
-          return e;
-        });
-        this.pageTitle = res.data.sj.name
-        uni.setNavigationBarTitle({ title: this.pageTitle })
-        console.log('this.category',this.category)
-        this.category = res.data.category;
-        this.columnStyle = res.data.columnStyle;
-      });
-    }
-  }
-};
-</script>
-<style lang="scss" scoped>
-.goods-module {
-  padding: 0 20upx;
-  margin-top: 40upx;
-  ::v-deep.buy-com-btn {
-    font-size: 24upx;
-    padding: 10upx 20upx 12upx;
-    box-shadow: 8upx 8upx 20upx #eee;
-  }
-}
-</style>
+</template>

+ 1 - 2
mallApp/src/pages/home/recent.vue

@@ -325,8 +325,7 @@ export default {
     tj(item) {
       this.pageTo({
         url: "/pages/home/mall?id=" + item.id + "&account=" + item.shopId,
-      });
-      //this.pageTo({ url:'/pages/goods/picGoods?id='+item.id+'&account='+item.shopId})
+      })
     },
     setAddress() {
       this.pageTo({ url: "/pages/user/address" });

+ 3 - 4
mallApp/src/pages/order/buy.vue

@@ -54,7 +54,7 @@
 import TuiListCell from "@/components/plugin/list-cell";
 import AppDeliveryModule from "@/components/app-delivery";
 import AppListModule from "./components/app-order-list2";
-import { getShopUser } from "@/utils/auth";
+//import { getShopUser } from "@/utils/auth";
 import { getOrderShop } from "@/utils/config";
 import { createOrder,newFreight } from "@/api/order";
 import { getHasMap } from "@/api/express";
@@ -90,7 +90,7 @@ export default {
   },
   onLoad(option) {
     this.option = option || {};
-    this.init();
+    //this.init();
   },
   computed: {
     mayPayAmount(){
@@ -108,7 +108,7 @@ export default {
       this.isFreight = goodsInfo.freightType == '0'
 
       getOrderShop()
-      getShopUser();
+      //getShopUser();
 
       const goodsNum = Number(this.option.goodsNum || goodsInfo.buyNum || 0)
       goodsInfo.buyNum = goodsNum
@@ -123,7 +123,6 @@ export default {
       getHasMap().then(res => {
         this.hasMap = (res.data && res.data.hasMap) ? res.data.hasMap : 0
       })
-
     },
 		changeSendType(num){
 			this.form.sendType = num

+ 2 - 2
mallApp/src/pages/order/components/app-order-list2.vue

@@ -6,11 +6,11 @@
 					<image :src="info.cover" mode="aspectFill" style="width:130upx;height:130upx;"></image>
 				</div>
 				<div class="list-msg">
-					<div class="title">{{ info.name}}</div>
+					<div class="title">{{ info.name }}</div>
 				</div>
 			</div>
 			<div class="list-right">
-				<div class="price">¥{{info.price?parseFloat(Number((info.price).toFixed(2))):0}}</div>
+				<div class="price">¥{{info.price ? parseFloat(info.price).toFixed(2) : 0}}</div>
 				<div class="num">X{{info.buyNum}}</div>
 			</div>
 		</block>

+ 2 - 2
开发http/ghsApp/src/manifest.json

@@ -2,8 +2,8 @@
     "name" : "销花宝",
     "appid" : "__UNI__BD781B0",
     "description" : "鲜花批发销售管理系统",
-    "versionName" : "1.2.37",
-    "versionCode" : 1237,
+    "versionName" : "1.2.38",
+    "versionCode" : 1238,
     "transformPx" : true,
     /* 5+App特有相关 */
     "app-plus" : {

+ 2 - 2
开发https/ghsApp/src/manifest.json

@@ -2,8 +2,8 @@
     "name" : "销花宝",
     "appid" : "__UNI__BD781B0",
     "description" : "鲜花批发销售管理系统",
-    "versionName" : "1.2.37",
-    "versionCode" : 1237,
+    "versionName" : "1.2.38",
+    "versionCode" : 1238,
     "transformPx" : true,
     /* 5+App特有相关 */
     "app-plus" : {

+ 2 - 2
线上/ghsApp/src/manifest.json

@@ -2,8 +2,8 @@
     "name" : "销花宝",
     "appid" : "__UNI__BD781B0",
     "description" : "鲜花批发销售管理系统",
-    "versionName" : "1.2.37",
-    "versionCode" : 1237,
+    "versionName" : "1.2.38",
+    "versionCode" : 1238,
     "transformPx" : true,
     /* 5+App特有相关 */
     "app-plus" : {