<template>
  <view class="content">
    <!-- 聊天内容 -->
    <scroll-view
        class="chat"
        scroll-y="true"
        scroll-with-animation="true"
        :scroll-into-view="scrollToView"
        refresher-enabled="true"
        :refresher-triggered="triggered"
        :refresher-threshold="100"
        refresher-background="#f0f0f0"
        @refresherpulling="onPulling"
        @refresherrefresh="onRefresh"
        @refresherrestore="onRestore"
        @refresherabort="onAbort"
    >
      <view class="chat-main" :style="{ paddingBottom: inputh + 'px' }">
        <view
            class="chat-ls"
            v-for="(item, index) in messageList"
            :key="index"
            :id="'msg' + index"
        >
          <!-- 时间分隔 -->
          <view class="chat-time" v-if="item.fromtime != ''">
            {{ changeTime(item.fromtime) }}
          </view>

          <!-- 消息体：左侧（对方） -->
          <view class="msg-m msg-left" v-if="item.fromuser !== userId">
            <view class="user-img">
              <image
                  class="uimg"
                  :src="item.headimg"
                  @error="handleImageError($event, index)"
                  mode="aspectFill"
              />
              <text class="uname">{{ item.fromname }}</text>
            </view>

            <!-- 文本 -->
            <view class="message" v-if="item.type == 'txt'">
              <view class="msg-text"><text selectable>{{ item.content }}</text></view>
            </view>

            <!-- 图片 -->
            <view class="message" v-if="item.type == 'image'" @tap="previewImg(item.content)">
              <image :src="item.content" class="msg-img" mode="widthFix" />
            </view>

            <!-- 视频 -->
            <view class="messagevideo" v-if="item.type == 'video'">
              <myVideo :videoUrl="item.content" />
            </view>

            <!-- 音频 -->
            <view class="message" v-if="item.type == 'audio'" @click="playVoice(item.content, item.ifaudio, index)">
              <view class="msg-text voice" :style="{ width: item.time * 40 + 'rpx' }">
                <view class="voicel" v-if="item.ifaudio"><div class="bg voicePlay"></div></view>
                <image v-else src="../../static/icon/horn.png" class="voice-img" />
                {{ item.time }}″
              </view>
            </view>

            <!-- 商品/订单 -->
            <view class="message" v-if="item.type == 'product'">
              <view v-if="item.send" class="msg-product" @click="gotoDetail(item)">
                <view v-if="item.send.type == 3" class="zx">
                  <view class="zxname">订单咨询</view>
                  <view class="zxview">查看订单</view>
                </view>
                <view class="msg-con">
                  <image class="img" :src="item.send.pic" mode="aspectFit" />
                  <view class="info">
                    <view class="name">
                      <text class="ntxt">{{ item.send.name }}</text>
                      <text
                          v-if="item.send.spData"
                          v-for="(value, key) in item.send.spData"
                          :key="key"
                          class="txt"
                      >
                        {{ key }}: {{ value }}
                      </text>
                    </view>
                    <view class="xq">
                      <view class="list">
                        <view v-if="item.send.type == 3" class="ord">
                          购买金额:¥ <text style="font-size: 30rpx;">{{ item.send.price }}</text>
                          {{ item.send.unit ? '/' + item.send.unit : '' }}
                        </view>
                        <view v-else class="price">
                          ¥{{ item.send.price }}{{ item.send.unit ? '/' + item.send.unit : '' }}
                        </view>
                        <view v-if="item.send.quantity" class="qty">
                          共({{ item.send.quantity }}{{ item.send.unit ? item.send.unit : '件' }})
                        </view>
                      </view>
                      <button class="btn" type="primary" v-if="item.send.type == 1 || item.send.type == 2">
                        去购买
                      </button>
                    </view>
                  </view>
                </view>
              </view>
            </view>
          </view>

          <!-- 消息体：右侧（自己） -->
          <view class="msg-m msg-right" v-if="item.fromuser == userId">
            <view class="user-img">
              <image class="uimg" :src="item.headimg" @error="handleImageError($event, index)" mode="aspectFill" />
              <text class="uname">{{ item.fromname }}</text>
            </view>

            <!-- 群聊才显示已读/未读按钮 -->
            <template v-if="chatType === 'group'">
              <view v-if="item.type == 'txt' || item.type == 'image' || item.type == 'video' || item.type == 'audio' || item.type == 'product'" class="message" style="flex-direction: column; align-items: flex-end;">
                <view class="rcon">
                  <view class="read" @click="openRead(item)">已读{{ item.read ? item.read.length : 0 }}</view>
                  <view class="noread" @click="openNoRead(item)">未读{{ item.read ? 3 - item.read.length : 3 }}</view>
                </view>
                <!-- 内容显示与左侧类似，但文字颜色为白色，背景为绿色，故复用部分结构 -->
                <view v-if="item.type == 'txt'" class="msg-text" style="margin-right: 0;">
                  <text selectable>{{ item.content }}</text>
                </view>
                <image v-if="item.type == 'image'" :src="item.content" class="msg-img" mode="widthFix" style="margin-right: 0;" />
                <myVideo v-if="item.type == 'video'" :videoUrl="item.content" style="margin-right: 0;" />
                <view v-if="item.type == 'audio'" class="msg-text voice" :style="{ width: item.time * 40 + 'rpx' }">
                  {{ item.time }}″
                  <view class="voicel" v-if="item.ifaudio"><div class="bg voicePlay"></div></view>
                  <image v-else src="../../static/icon/hornrw.png" class="voice-img" />
                </view>
                <view v-if="item.type == 'product'" class="msg-product" style="margin-right: 0;">
                  <!-- 商品卡片复用左侧相同结构，但右侧需调整样式，因为父级flex方向不同，此处省略重复代码 -->
                  <!-- 实际开发中应抽离为组件，这里为简洁略 -->
                </view>
              </view>
            </template>

            <!-- 私聊显示已读/未读状态（仅文字和图片） -->
            <template v-else>
              <view v-if="item.type == 'txt'" class="message">
                <view v-if="item.ifread" class="read">已读</view>
                <view v-else class="noread">未读</view>
                <view class="msg-text"><text selectable>{{ item.content }}</text></view>
              </view>
              <view v-if="item.type == 'image'" @tap="previewImg(item.content)" class="message">
                <view v-if="item.ifread" class="read">已读</view>
                <view v-else class="noread">未读</view>
                <image :src="item.content" class="msg-img" mode="widthFix" />
              </view>
              <view v-if="item.type == 'video'" class="messagevideo">
                <view v-if="item.ifread" class="read">已读</view>
                <view v-else class="noread">未读</view>
                <myVideo :videoUrl="item.content" />
              </view>
              <view v-if="item.type == 'audio'" @click="playVoice(item.content, item.ifaudio, index)" class="message">
                <view v-if="item.ifread" class="read">已读</view>
                <view v-else class="noread">未读</view>
                <view class="msg-text voice" :style="{ width: item.time > 2 ? item.time * 40 + 'rpx' : 'auto' }">
                  {{ item.time }}″
                  <view class="voicel" v-if="item.ifaudio"><div class="bg voicePlay"></div></view>
                  <image v-else src="../../static/icon/hornrw.png" class="voice-img" />
                </view>
              </view>
              <view v-if="item.type == 'product'" class="message">
                <view v-if="item.ifread" class="read">已读</view>
                <view v-else class="noread">未读</view>
                <view v-if="item.send" class="msg-product" @click="gotoDetail(item)">
                  <!-- 商品卡片，略 -->
                </view>
              </view>
            </template>
          </view>
        </view>
      </view>
    </scroll-view>

    <!-- 商品/订单发送弹窗 -->
    <view class="popup" v-if="ifSend && sendInfo">
      <view class="tipcon">
        <image class="img" :src="sendInfo.pic" mode="aspectFit" />
        <view class="info">
          <view class="name">
            <text class="ntxt">{{ sendInfo.name }}</text>
            <text v-if="sendInfo.spData" v-for="(value, key) in sendInfo.spData" :key="key" class="txt">
              {{ key }}: {{ value }}
            </text>
          </view>
          <view class="xq">
            <view class="list">
              <view v-if="sendInfo.type == 3" class="ord">
                购买金额:¥ <text style="font-size: 30rpx;">{{ sendInfo.price }}</text>
                {{ sendInfo.unit ? '/' + sendInfo.unit : '' }}
              </view>
              <view v-else class="price">
                ¥{{ sendInfo.price }}{{ sendInfo.unit ? '/' + sendInfo.unit : '' }}
              </view>
              <view class="qty">
                {{ sendInfo.quantity ? '共(' + sendInfo.quantity + (sendInfo.unit ? sendInfo.unit : '件') + ')' : '' }}
              </view>
            </view>
            <button class="btn" type="primary" @click="sendServer">发送{{ sendInfo.type == 1 ? '商品' : sendInfo.type == 2 ? '课程' : '订单' }}</button>
          </view>
          <view class="close">
            <uni-icons type="closeempty" color="#bebdbd" size="16" @click="closeSendPopup" />
          </view>
        </view>
      </view>
    </view>

    <!-- 输入组件 -->
    <submit @inputs="inputs" @heights="heights" />

    <!-- 提示 Toast -->
    <u-toast ref="uToast" />

    <!-- 群公告弹窗（仅群聊） -->
    <uni-popup ref="popup" background-color="#fff" v-if="chatType === 'group'">
      <view class="popup-content">
        <view class="example">
          <view class="order">
            <view class="chatlist">
              <view class="chatcell" v-for="(person, key) in groupPersons" :key="key">
                <image class="user-img" :src="person.img" />
                <text class="user-name">{{ person.name }}</text>
              </view>
            </view>
            <view class="lcon">
              <view class="lhtxt">群聊名称</view>
              <view class="ltxt">{{ chatInfo.chatName || '未设置' }}</view>
            </view>
            <view class="lcon">
              <view class="lhtxt">群公告</view>
              <view class="ltxt">{{ chatInfo.notice || '未设置' }}</view>
            </view>
            <view class="lcon">
              <view class="lhtxt">备注</view>
              <view class="ltxt">{{ chatInfo.reason ? chatInfo.reason : '无' }}</view>
            </view>
            <view class="lcon">
              <view class="lhtxt">在本群昵称</view>
              <view class="ltxt">{{ userName || '' }}</view>
            </view>
          </view>
        </view>
      </view>
    </uni-popup>

    <!-- 已读/未读列表弹窗（仅群聊） -->
    <uni-popup ref="popupRead" background-color="#fff" v-if="chatType === 'group'">
      <view class="popup-content">
        <view class="example">
          <view class="order">
            <view class="qhbtn">
              <view :class="ifRead ? 'btn cur' : 'btn'" @click="switchReadTab(1)">已读({{ readInfo.read.length }})</view>
              <view :class="ifRead ? 'btn' : 'btn cur'" @click="switchReadTab(2)">未读({{ readInfo.noread.length }})</view>
            </view>
            <view class="readlist" v-if="ifRead">
              <view class="readcell" v-for="(item, idx) in readInfo.read" :key="idx">
                <text class="readname">{{ item.name }}</text>
                <text class="readtime">{{ item.time }}</text>
              </view>
            </view>
            <view class="readlist" v-else>
              <view class="readcell" v-for="(item, idx) in readInfo.noread" :key="idx">
                <text class="readname">{{ item.name }}</text>
              </view>
            </view>
          </view>
        </view>
      </view>
    </uni-popup>
  </view>
</template>

<script>
import { myCache } from '../../utils/utils.js';
import dateTime from '@/common/dateTime.js';
import submit from '@/components/chat/submit.vue';
import myVideo from '@/components/myVideo.vue';

const innerAudioContext = uni.createInnerAudioContext();

export default {
  components: { submit, myVideo },
  data() {
    return {
      triggered: false,
      userName: '',
      userId: '',
      userHeadImg: '',
      chatInfo: {}, // 会话基本信息
      // 聊天类型：'private' 或 'group'
      chatType: 'private',
      // 消息列表
      messageList: [],
      // 图片预览用
      imgMsg: [],
      scrollToView: '',
      inputh: '90',
      ifaudio: false,
      // 商品/订单发送
      ifSend: false,
      sendInfo: null,
      // 群聊特有
      ifRead: true,
      readInfo: { read: [], noread: [] },
      // WebSocket相关（页面内独立管理，也可抽离为全局）
      isConnected: false,
      heartbeatInterval: null,
      heartbeatTimeout: 20000,
    };
  },
  onLoad(options) {
    // 从缓存获取用户信息
    const user = myCache('user');
    this.userName = user.nickName || '';
    this.userId = user.userid || '';
    this.userHeadImg = user.avatar || require('@/static/image/girl.png');

    if (options.data) {
      this.chatInfo = JSON.parse(decodeURIComponent(options.data));
      // 根据会话类型设置 chatType
      this.chatType = this.chatInfo.sort === 'groupchat' ? 'group' : 'private';
      // 设置标题
      uni.setNavigationBarTitle({ title: this.chatInfo.chatName || '聊天' });

      // 是否有待发送的商品/订单
      if (this.chatInfo.sendinfo) {
        this.ifSend = true;
        this.sendInfo = this.chatInfo.sendinfo;
      }
    }

    // 群聊时获取教练、客服等头像
    if (this.chatType === 'group') {
      this.getGroupMemberInfo();
    }
  },
  onShow() {
    this.getMessageList();
    // 重新连接WebSocket
    this.reconnect();
    // 滚动到底部
    setTimeout(() => this.scrollToBottom(), 300);
  },
  methods: {
    // ---------- 消息列表加载 ----------
    getMessageList() {
      const list = myCache(this.chatInfo.chatId) || [];
      if (list.length === 0) {
        // 首次会话显示欢迎语
        const welcome = `Hi，${this.userName}，欢迎您！这里是${this.chatInfo.chatName}，请问有什么可以帮助您的呢？`;
        this.messageList = [{
          fromname: this.chatInfo.chatName,
          fromuser: this.chatInfo.friendId || this.chatInfo.ownerId,
          headimg: this.chatInfo.chatAvatar,
          toname: this.userName,
          touser: this.userId,
          content: welcome,
          fromtime: new Date().toISOString(),
          type: 'txt',
        }];
        // 立即缓存
        myCache(this.chatInfo.chatId, this.messageList);
      } else {
        this.messageList = list;
        // 处理时间显示（已由缓存保存时处理好）
      }
      this.$forceUpdate();
      // 加载完成后滚动到底部
      this.$nextTick(() => this.scrollToBottom());
    },

    // ---------- WebSocket 连接（合并后统一管理） ----------
    socketInit() {
      const that = this;
      if (this.isConnected) return;
      uni.connectSocket({
        url: 'wss://www.sanduolantoyoga.com/yoga-imserver',
        header: { Authorization: uni.getStorageSync('token') },
        success: (res) => {
          console.log('socket连接成功', res);
          // 拉取离线消息
          this.getReadedId();
        },
        fail: (err) => console.log('socket连接失败', err),
      });
      uni.onSocketOpen(() => {
        that.isConnected = true;
        // 登录包
        uni.sendSocketMessage({
          data: JSON.stringify({ cmd: 0, data: { accessToken: uni.getStorageSync('token') } }),
          success: () => console.log('登录包发送成功'),
          fail: () => console.log('登录包发送失败'),
        });
        that.startHeartbeat();
      });
      uni.onSocketClose(() => {
        that.isConnected = false;
        that.reconnect();
      });
      uni.onSocketError(() => {
        that.isConnected = false;
        that.reconnect();
      });
      uni.onSocketMessage((res) => {
        if (!res.data) return;
        const data = JSON.parse(res.data);
        console.log('收到消息', data);
        // 根据 cmd 分发
        if (data.cmd === 3) {
          // 私聊
          this.handlePrivateMessage(data.data);
        } else if (data.cmd === 4) {
          // 群聊
          this.handleGroupMessage(data.data);
        }
      });
    },

    handlePrivateMessage(data) {
      // 仅处理发给自己的消息
      if (data.recvId != this.userId) return;
      if (!this.ifMsgExist(data.id)) {
        this.appendMessage(data);
        // 已读上报
        this.readedPrivate(data.id);
        // 更新会话列表
        this.updateChatList(data);
      }
    },

    handleGroupMessage(data) {
      if (data.groupId != this.chatInfo.groupId) return;
      if (!this.ifMsgExist(data.id)) {
        this.appendMessage(data);
        this.readedGroup();
        this.updateChatList(data);
      }
    },

    ifMsgExist(id) {
      return this.messageList.some(item => item.id === id);
    },

    appendMessage(data) {
      // 将消息转换为显示格式
      const msg = {
        fromname: data.sendNickName || '匿名',
        fromuser: data.sendId,
        headimg: data.headImage || require('@/static/image/girl.png'),
        toname: this.userName,
        touser: this.userId,
        content: data.type === 0 ? decodeURIComponent(data.content) : data.content,
        fromtime: data.sendTime,
        type: this.mapMsgType(data.type),
        id: data.id,
        sendId: data.sendId,
        recvId: data.recvId,
        time: data.type === 3 ? 5 : 0,
        ifaudio: false,
        read: data.readedCount ? [] : undefined, // 群聊使用
        ifread: false, // 私聊使用
        send: data.type === 6 ?  this.getProduct(data.content) : (data.type === 5 ?  this.getOrder(data.content) : null),
      };
      this.messageList.push(msg);
      this.$forceUpdate();
      // 缓存
      myCache(this.chatInfo.chatId, this.messageList);
      this.scrollToBottom();
    },

    mapMsgType(type) {
      const map = {
        0: 'txt',
        1: 'image',
        3: 'audio',
        4: 'video',
        5: 'product',
        6: 'product',
      };
      return map[type] || 'txt';
    },

    // ---------- 读写已读状态 ----------
    async readedPrivate() {
      await uni.$http.put(`/api/message/private/readed?friendId=${this.chatInfo.friendId}`);
    },
    async readedGroup() {
      await uni.$http.put(`/api/message/group/readed?groupId=${this.chatInfo.groupId}`);
    },

    // ---------- 拉取离线消息 ----------
    async getReadedId() {
      let url, param;
      if (this.chatType === 'private') {
        url = '/api/message/private/maxReadedId';
        param = { friendId: this.chatInfo.friendId };
      } else {
        url = '/api/message/group/maxReadedId';
        param = { groupId: this.chatInfo.groupId };
      }
      const { data: res } = await uni.$http.get(url, param);
      if (res.data) {
        this.chatInfo.minId = res.data;
        this.pullOfflineMessages();
      }
    },

    async pullOfflineMessages() {
      let url, param;
      if (this.chatType === 'private') {
        url = '/api/message/private/pullOfflineMessage';
        param = { minId: this.chatInfo.minId };
      } else {
        url = '/api/message/group/pullOfflineMessage';
        param = { minId: this.chatInfo.minId };
      }
      const { data: res } = await uni.$http.get(url, param);
      if (res.data && res.data.length) {
        // 倒序插入（因为消息按时间升序）
        res.data.forEach(item => {
          if (!this.ifMsgExist(item.id)) {
            const msg = this.convertMsg(item);
            this.messageList.push(msg);
          }
        });
        this.messageList.sort((a, b) => a.fromtime - b.fromtime);
        myCache(this.chatInfo.chatId, this.messageList);
        this.$forceUpdate();
        this.scrollToBottom();
      }
    },

    // ---------- 发送消息 ----------
    async inputs(e) {
      const data = {
        fromname: this.userName,
        fromuser: this.userId,
        headimg: this.userHeadImg,
        toname: this.chatInfo.chatName,
        touser: this.chatInfo.friendId || this.chatInfo.groupId,
        content: e.type === 'audio' ? e.message.voice : e.message,
        time: e.type === 'audio' ? e.message.time : 0,
        ifaudio: false,
        fromtime: new Date(),
        type: e.type,
      };
      if (e.type !== 'video') {
        this.messageList.push(data);
        this.scrollToBottom();
        myCache(this.chatInfo.chatId, this.messageList);
      }
      // 根据类型上传文件并发送
      if (['txt', 'audio', 'image', 'video'].includes(e.type)) {
        let content = data.content;
        if (e.type !== 'txt') {
          // 上传文件
          const url = await this.uploadFile(e.message, e.type);
          content = url;
        }
        // 发送消息
        await this.sendMsg(content, e.type);
      }
    },

    async uploadFile(filePath, type) {
      let url = '';
      const token = uni.getStorageSync('token');
      const uploadUrl = uni.$http.baseUrl + (type === 'image' ? '/api/image/upload' : '/api/file/upload');
      uni.showLoading({ title: '上传中...' });
      try {
        const res = await new Promise((resolve, reject) => {
          uni.uploadFile({
            url: uploadUrl,
            filePath,
            name: 'file',
            header: { Authorization: token },
            success: (res) => {
              const data = JSON.parse(res.data);
              if (data.data) resolve(data.data.originUrl || data.data);
              else reject(data.msg);
            },
            fail: reject,
          });
        });
        uni.hideLoading();
        return res;
      } catch (err) {
        uni.hideLoading();
        this.$refs.uToast.show({ title: err || '上传失败', type: 'error' });
        throw err;
      }
    },

    async sendMsg(content, type) {
      const mtypeMap = { txt: '0', image: '1', audio: '3', video: '4' };
      const mtype = mtypeMap[type] || '0';
      let param = { content };
      if (this.chatType === 'private') {
        param.recvId = this.chatInfo.friendId;
      } else {
        param.groupId = this.chatInfo.groupId;
        param.atUserIds = [this.chatInfo.friendId, this.chatInfo.teacherId].filter(Boolean);
      }
      param.type = mtype;
      const url = this.chatType === 'private' ? '/api/message/private/send' : '/api/message/group/send';
      try {
        const res = await uni.$http.post(url, param);
        if (res.data) {
          const msg = res.data;
          // 更新已发送的消息
          const last = this.messageList[this.messageList.length - 1];
          if (last && last.content === param.content) {
            last.id = msg.id;
            last.fromtime = msg.sendTime;
            last.sendId = msg.sendId;
            last.recvId = msg.recvId;
            last.ifread = false;
            myCache(this.chatInfo.chatId, this.messageList);
          }
        }
      } catch (err) {
        this.messageList.pop();
        uni.showToast({ title: err.msg || '发送失败', icon: 'none' });
      }
    },

    // ---------- 聊天列表更新（缓存） ----------
    updateChatList(data) {
      const list = myCache('chatlist-' + this.userId) || [];
      const idx = list.findIndex(item => item.id === this.chatInfo.chatId);
      const entry = {
        id: this.chatInfo.chatId,
        content: data.content || '',
        type: data.type,
        minId: data.id,
        datetime: data.sendTime,
        name: this.chatInfo.chatName,
        userid: this.userId,
        fromuser: data.sendId,
        img: this.chatInfo.chatAvatar,
        sort: this.chatType === 'private' ? 'privatechat' : 'groupchat',
        groupId: this.chatInfo.groupId,
        friendId: this.chatInfo.friendId,
        teacherId: this.chatInfo.teacherId,
      };
      if (idx >= 0) {
        list[idx] = entry;
      } else {
        list.unshift(entry);
      }
      myCache('chatlist-' + this.userId, list);
    },

    // ---------- 工具方法 ----------
    changeTime(date) {
      return dateTime.dateTime1(date);
    },

    previewImg(url) {
      const idx = this.imgMsg.indexOf(url);
      uni.previewImage({
        current: idx >= 0 ? idx : 0,
        urls: this.imgMsg,
      });
    },

    playVoice(url, ifplay, index) {
      innerAudioContext.stop();
      this.messageList.forEach((item, i) => (item.ifaudio = false));
      ifplay = !ifplay;
      this.messageList[index].ifaudio = ifplay;
      this.$forceUpdate();
      if (ifplay) {
        innerAudioContext.src = url;
        innerAudioContext.play();
        innerAudioContext.onEnded(() => {
          this.messageList[index].ifaudio = false;
          this.$forceUpdate();
        });
      }
    },

    handleImageError(e, index) {
      this.messageList[index].headimg = require('@/static/image/girl.png');
    },

    scrollToBottom() {
      const len = this.messageList.length;
      if (len) {
        this.scrollToView = '';
        this.$nextTick(() => {
          this.scrollToView = 'msg' + (len - 1);
        });
      }
    },

    // 下拉刷新
    onPulling() {
      this.triggered = true;
      setTimeout(() => (this.triggered = false), 2000);
    },
    onRefresh() {
      this.pullOfflineMessages();
    },
    onRestore() { this.triggered = false; },
    onAbort() { this.triggered = false; },

    // 输入框高度
    heights(h) {
      this.inputh = h;
      this.scrollToBottom();
    },

    // 商品/订单弹窗
    closeSendPopup() {
      this.ifSend = false;
      this.sendInfo = null;
    },
    sendServer() {
      // 触发发送商品/订单消息，实际调用 inputs 或直接 sendMsg
      const data = {
        type: 'product',
        message: this.sendInfo.id,
      };
      this.inputs(data);
    },

    // 跳转详情
    gotoDetail(item) {
      const send = item.send;
      if (!send) return;
      let url = '';
      if (send.type === 1) url = `/pages/product/detail?id=${send.id}`;
      else if (send.type === 2) url = `/pages/product/cdetail?id=${send.id}`;
      else if (send.type === 3) url = `/pages/order/orderinfo?id=${send.orderId}`;
      if (url) uni.navigateTo({ url });
    },

    // 群聊成员信息（客服、教练、咨询用户）
    async getGroupMemberInfo() {
      const ids = [this.chatInfo.customerService, this.chatInfo.instructor, this.chatInfo.ownerId];
      // 实际项目中可批量请求，此处简化，只取当前用户信息
      // 为了演示，直接设置占位
      this.groupPersons = [
        { name: this.chatInfo.customername || '客服', img: this.chatInfo.customerimg || '/static/image/kfr.png' },
        { name: this.chatInfo.instructorname || '教练', img: this.chatInfo.instructorimg || '/static/image/jltx.png' },
        { name: this.chatInfo.ownername || '咨询用户', img: this.chatInfo.ownerimg || '/static/image/mr.png' },
      ];
    },

    // 群聊已读未读弹窗
    openRead(item) {
      this.ifRead = true;
      this.buildReadInfo(item);
      this.$refs.popupRead.open('right');
    },
    openNoRead(item) {
      this.ifRead = false;
      this.buildReadInfo(item);
      this.$refs.popupRead.open('right');
    },
    buildReadInfo(item) {
      // 假设 item.read 存储已读用户id列表，此处仅为示例
      // 实际需从服务器获取或本地维护，此处仅演示界面
      const readList = item.read || [];
      const allUsers = [
        { id: this.chatInfo.customerService, name: this.chatInfo.customername || '客服' },
        { id: this.chatInfo.instructor, name: this.chatInfo.instructorname || '教练' },
        { id: this.chatInfo.ownerId, name: this.chatInfo.ownername || '咨询用户' },
      ];
      this.readInfo.read = allUsers.filter(u => readList.includes(u.id)).map(u => ({ ...u, time: new Date() }));
      this.readInfo.noread = allUsers.filter(u => !readList.includes(u.id));
    },
    switchReadTab(type) {
      this.ifRead = type === 1;
    },

    // WebSocket 心跳/重连（合并，与上述 socketInit 配合）
    startHeartbeat() {
      clearInterval(this.heartbeatInterval);
      this.heartbeatInterval = setInterval(() => {
        if (this.isConnected) {
          uni.sendSocketMessage({
            data: JSON.stringify({ cmd: 1, data: { accessToken: uni.getStorageSync('token') } }),
            fail: () => this.reconnect(),
          });
        }
      }, this.heartbeatTimeout);
    },
    reconnect() {
      if (!this.isConnected) {
        clearTimeout(this.heartbeatInterval);
        this.heartbeatInterval = setTimeout(() => this.socketInit(), this.heartbeatTimeout);
      }
    },

    // 获取商品/订单详情（略，实际调用接口）
    async getProduct(id) {
      // 模拟
      return { type: 1, id, name: '商品名', pic: '/static/image/nopic.png', price: 100, unit: '元' };
    },
    async getOrder(id) {
      return { type: 3, id, orderId: '123', name: '订单', pic: '/static/image/nopic.png', price: 200, quantity: 1 };
    },
  },
};
</script>

<style lang="scss">
page {
  height: 100%;
}

.content {
  height: 100%;
  background-color: rgba(244, 244, 244, 1);
  position: relative;
}
::v-deep .uni-noticebar{
  margin-bottom: 0 !important;
  padding: 10rpx 12rpx !important;
  border-radius: 10rpx;
}

.chat {
  height: 100%;

  .chat-main {
    padding-left: 20rpx;
    padding-right: 20rpx;
    padding-top: 20rpx;
    // padding-bottom: 120rpx;  //获取动态高度
    display: flex;
    flex-direction: column;
  }

  .chat-ls {
    .chat-time {
      font-size: 24rpx;
      color: rgba(39, 40, 50, 0.3);
      line-height: 34rpx;
      padding: 10rpx 0rpx;
      text-align: center;
    }

    .msg-m {
      display: flex;
      padding: 20rpx 0;

      .user-img {
        flex: none;
        width: 92rpx;
        height: 90rpx;
        border-radius: 20rpx;
        text-align: center;
        .uimg{
          width: 70rpx;
          height: 70rpx;
          margin: 0 auto;
          border-radius: 35rpx;
        }
        .uname{
          height: 30rpx;
          display: block;
          margin: 0 auto;
          line-height: 30rpx;
          color: rgba(39, 40, 50, 0.5);
          font-size: 24rpx;
        }
      }
      .message {
        flex: none;
        max-width: 540rpx;
        display: flex;
        flex-direction: row;
      }
      .messagevideo {
        max-width: 540rpx;
        height: 300rpx;
        display: flex;
        flex-direction: row;
      }
      .msg-text {
        font-size: 32rpx;
        color: rgba(39, 40, 50, 1);
        line-height: 44rpx;
        padding: 18rpx 24rpx;
      }

      .msg-img {
        max-width: 400rpx;
        border-radius: 20rpx;
      }
      .msg-video{
        width: 400rpx;
        height: 300rpx;
        border-radius: 20rpx;
      }
      .msg-map {
        background: #fff;
        width: 464rpx;
        height: 284rpx;
        overflow: hidden;
        margin: 0 20rpx;
        .map-name {
          font-size: 32rpx;
          color: rgba(39, 40, 50, 1);
          line-height: 44rpx;
          padding: 18rpx 24rpx 0 24rpx;
          //下面四行是单行文字的样式
          display: -webkit-box;
          -webkit-box-orient: vertical;
          -webkit-line-clamp: 1;
          overflow: hidden;
        }
        .map-address {
          font-size: 24rpx;
          color: rgba(39, 40, 50, 0.4);
          padding: 0 24rpx;
          //下面四行是单行文字的样式
          display: -webkit-box;
          -webkit-box-orient: vertical;
          -webkit-line-clamp: 1;
          overflow: hidden;
        }

        .map {
          padding-top: 8rpx;
          width: 464rpx;
          height: 190rpx;
        }
      }
      .voice {
        // width: 200rpx;
        min-width: 100rpx;
        max-width: 400rpx;
      }
      .voice-img {
        width: 36rpx;
        height: 36rpx;
      }
    }

    .msg-left {
      flex-direction: row;
      .feed-imgy{
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-self: center;
        margin-right: 0rpx;
        width: 95rpx;
        height: 75rpx;
      }
      .feed-img{
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-self: center;
        margin-right: 0rpx;
        width: 75rpx;
        height: 75rpx;
      }
      .msg-text {
        margin-left: 16rpx;
        background-color: #fff;
        border-radius: 0rpx 20rpx 20rpx 20rpx;
      }

      .ms-img {
        margin-left: 16rpx;
      }
      .msg-video{
        margin-left: 16rpx;
      }
      .msh-map {
        margin-left: 16rpx;
        border-radius: 0rpx 20rpx 20rpx 20rpx;
      }

      .msg-img {
        margin: 0 0 0 20rpx;
      }

      .voice {
        text-align: left;
        display: flex;
      }
      .voice-img {
        transform: rotate(180deg);
        width: 36rpx;
        height: 36rpx;
        padding-bottom: 4rpx;
        margin-right: 10rpx;
      }
      .voicel{
        height: 32rpx;
        width: 32rpx;
      }
      .bg {
        background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAAAYCAYAAAAF6fiUAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MEM0NzgwODc1MDY0MTFFRjk1QjhFRUUxQjYyOUQ5NDQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MEM0NzgwODg1MDY0MTFFRjk1QjhFRUUxQjYyOUQ5NDQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDowQzQ3ODA4NTUwNjQxMUVGOTVCOEVFRTFCNjI5RDk0NCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDowQzQ3ODA4NjUwNjQxMUVGOTVCOEVFRTFCNjI5RDk0NCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PqxjhsEAAANzSURBVHjazJlLaNRQFIaTVIcRQUELoggVKYIgQvGFr40giLMRBAtjXblwUSmIK1vBTQUREUFB8NGdGwUXgoIVFwq6EGSkOAguXKiUQQq6kKK0Gv+LJ+HkTpLJfYUc+DnJ3M436Tn3eeKHYeiZ2NDQkGfZfCj03Nka6DzUgqZMYa1WS45HzIf15C/xqmeuE7ATOs3up1zxRefslYSgggn465j/GLpJ13ehfS75SEIu36/AFCQ6wQHoBbTgIOBZfBGow9AvaIXBb8d89PYFFpcEn7e5GAG+wXfPQc+g91DNQQKy+A3oB1SnkWDMR9BrbG0oxLeVgNAgCeLhF6FN0CuLiS3CP07+BDTgko/kbHC9BugG6w20ja63QxNSYk0tj/8EatP1uOYuKMFHoCdYW09+kDKnT0Kz0KjGKChik9AsxPkz0FnWvtIgsar8y2wUBDp8BDrBR+zS+CP4PCgyApZDa6Eb+ELDQQJiPs3DkV2FOnQ9atDjVfkPyS+DduvykQQtfpAypM7A3aPbB0iC7bNCgi+dRW6RP2owDanyf0Lv6HqPKl+KTxcf8czlBxnz2gjcPGXtiIOdSRb/Ofmt1KY7DanyZ8gP2uIjMYX4eXPeNPm9jg5Eafwv7IS+rkT+N/Kry+bnJeA3+T5HCUjjhxa3oCr8UOM3rfDzEnCQ/Fu2Q7K5be3i0+IWWadEfj/572Xzg4zywhW4VWwhs128y+LvJ9+mxbEs/mbyn2zxafHtyU87B4yzPe1JgOZZ8x8LwU/waTGL7BT5RwZTkSq/Rge06NCmxJfi08Wn8kQmP20ErKc56xIvpQJUx72NBMR8L1kKbkIb6fq6FKDQIb9BI1v8by91+YiPFj+1GgpYP4I9x+593IcZ05VOEsScOMfuxUuMr/Sg4uHHWNtSjUqlCv81HZDuQ8OqfPFChl7CxHx8NsbiE/Px+XChBKiYhXL0IPUMsYB9lopiddpthI74O9i0sIXVbbT5CPIAi02Cj7a2y2KcrjXp4UXpdpfUtmihIJfHjxbQp5rBL8xPC77NXY2JXaOeOS1t3fooAa74t9loaNrgI8gd1vsL8f0KvpSPdj4u3wuLncxFuj4mbSWVTH4pz3aSMR9/k8mv4jthz3HwD7HgXDAJfkaHTPDzgl+VKahs+wjdgT54/0vUzvhUos61fwIMANiWariLn8/jAAAAAElFTkSuQmCC);
        width: 32rpx;
        height: 32rpx;
        background-size: 400%;
      }

      .msg-product{
        display: flex;
        flex-direction: column;
        width: 100%;
        background-color: #FFFFFF;
        padding: 10rpx;
        border-radius: 16rpx;
        width: 480rpx;
        margin-left: 12rpx;
        .zx{
          display: flex;
          justify-content: space-between;
          width: 100%;
          font-size: 28rpx;
          margin: 10rpx;
          .zxview{
            color: darkgrey;
            font-size: 26rpx;
            margin-right: 20rpx;
          }
        }
        .msg-con{
          display: flex;
          justify-content: space-between;
          width: 100%;
          padding: 10rpx;
          border-radius: 16rpx;
        }
        .img{
          width: 120rpx;
          height: 120rpx;
        }
        .info{
          display: flex;
          flex-direction: column;
          flex: 1;
          padding: 6rpx 8rpx;
          position: relative;
          margin-left: 10rpx;
          background-color: #f4f4f4;
          border-radius: 0 10rpx 10rpx 0;
          .name{
            width: 330rpx;
            // white-space: nowrap; /* 防止文本换行 */
            // overflow: hidden; /* 隐藏溢出的内容 */
            // text-overflow: ellipsis; /* 溢出部分显示省略号 */
            .txt{
              font-size: 26rpx;
              color: darkgrey;
              margin-left: 6rpx;
            }
            .ntxt{
              font-size: 28rpx;
              color: #000;
            }
          }
          .sku{
            display: flex;
            flex-direction: row;
            .txt{
              font-size: 26rpx;
              color: darkgrey;
              margin-right: 6rpx;
            }
          }
          .xq{
            width: 100%;
            display: flex;
            flex-direction: row;
            .list{
              display: flex;
              flex: 1;
            }
            .price{
              display: flex;
              align-items: center;
              font-size: 28rpx;
              color: #ff007f;
            }
            .ord{
              display: flex;
              align-items: center;
              font-size: 26rpx;
              color: #232323;
            }
            .qty{
              display: flex;
              align-items: center;
              font-size: 26rpx;
              color: darkgrey;
              margin-left: 8rpx;
            }
            .btn{
              font-size: 26rpx;
              font-family: PingFang SC-Medium, PingFang SC;
              font-weight: 500;
              color: #FCFCFD;
              width: 110rpx;
              height: 50rpx;
              line-height: 50rpx;
              background: #ff007f;
              box-shadow: 0rpx 10rpx 30rpx 2rpx rgba(255,0,127,0.2);
              border-radius: 60rpx;
              opacity: 1;
              margin-right: 10rpx;
              margin-top: 10rpx;
              margin-bottom: 10rpx;
              padding-left:0 !important;
              padding-right:0 !important;
              &::after{
                border:none;
              }
            }
          }
        }

      }
    }

    .msg-right {
      flex-direction: row-reverse;
      .rcon{
        display: flex;
        flex-direction: column;
        justify-content: flex-end;
        align-items: flex-end;
      }
      .read{
        font-size: 24rpx;
        color: #888;
        margin-right: 10rpx;
        display: flex;
        justify-content: flex-end;
        align-items: flex-end;
      }
      .noread{
        font-size: 24rpx;
        color: #00a89b;
        margin-right: 10rpx;
        display: flex;
        justify-content: flex-end;
        align-items: flex-end;
      }

      .feed-imgy{
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-self: center;
        margin-right: 0rpx;
        width: 95rpx;
        height: 75rpx;
      }
      .feed-img{
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-self: center;
        margin-right: 0rpx;
        width: 75rpx;
        height: 75rpx;
      }
      .msg-text {
        margin-right: 16rpx;
        background-color: #00a89b;
        font-family: PingFang SC, PingFang SC;
        font-weight: 400;
        font-size: 32rpx;
        color: #FFFFFF;
        line-height: 48rpx;
        border-radius: 20rpx 0rpx 20rpx 20rpx;
      }

      .ms-img {
        margin-right: 16rpx;
      }

      .msg-img {
        margin: 0 20rpx 0 0;
      }
      .msg-video{
        margin: 0 20rpx 0 0;
      }
      .msh-map {
        margin-left: 16rpx;
        border-radius: 20rpx 0rpx 20rpx 20rpx;
      }

      .voice {
        display: flex;
        flex-direction: row;
        align-items: center;
        justify-content: flex-end;
      }

      .voice-img {
        display: block;
        width: 36rpx;
        height: 36rpx;
        margin-left: 10rpx;
      }
      .voicel{
        height: 32rpx;
        width: 32rpx;
      }
      .bg {
        background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAAAYCAYAAAAF6fiUAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6REJBQzQ1RjQ1MDYzMTFFRjk5QjZEQkI5MDlENzE3RTQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6REJBQzQ1RjU1MDYzMTFFRjk5QjZEQkI5MDlENzE3RTQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpEQkFDNDVGMjUwNjMxMUVGOTlCNkRCQjkwOUQ3MTdFNCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpEQkFDNDVGMzUwNjMxMUVGOTlCNkRCQjkwOUQ3MTdFNCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pm5p+OoAAAKmSURBVHja1Jk/SBxBFMbdy6mHSEARNYIkhU0ICCEkEEynEYmkUEiTxmBtZZHCgGVsAgEhQozYaAo7G0GwjgemC1ZBgzbaKKnEIsb1HbwjH8PM7szdfEQffMzyzexvhn2zM/snSdO0wSOmRfdFc6JfDfGDzb++UUlAjmbTfzHi0T5UbP61Vl6DV3BxZggDYPNRyU1LQDtcnC9GXY/ojeh2HZ2z+ahbZD4lAZt6cQ4Mv1v0W+tm6+icza+qSOZTEvAAZudjo+5Q/SNRX40ds/m47JSIfFoC1nSQ24Y/r/4fUZdR1xHQMZtfVSOZH7LndPgmoEl0oQMdA/8OzNrXxjlzokvRgsfA2HxUM5nvUsmXbzt5CGZJE/jv1d832k8GPsmw+TgDEyLfd8PP5NsAM9q4bPi76r8FrwXgHzwHyOa7loDY/Kw73JtvAyzpCcvgtQLoKfgT6p0GDJDNtyWAwXepEMIvWF6O27Q8Aa8bjo/h+JGWWwEv32y+Ldh8jMsQvi0B1Y9DicUz/b9aNod8/SDzs/pk8V2Ry7cl4FTLTvCORBd63Av+Ny2HAwbF5tuCzXdFLt+WgD0t+8E7F/3Q40Hw17WuRbTqOSg23zbrGXyfyOdbNoYB2LBaLU8vx0b7UWj/0WOTYvNdGzGD76NMvu0OKGvWKjEO/ifY0KbB3xBN6eZ25jEr2HxXxOQnAf1m8x1ZW9SM7Rr+O8hmfx2z4jOZ71IsfoH9LegeDPSFUfcd3mSf1NjxXTI/64UsBj/av4WC47Y5EK3o8VejbkD0U1QUPa9xOTgk812bcSx+GrgM1fRLsvIl8Vxny4albqjOW5HNz+ubyY/2S/IZLBULhAGz+Tf+n7D5Ne8lYRBsPmXzjKWixyq1rOVD0Q7hZYXNz9oP/ntcCTAAHScbp0OSlTgAAAAASUVORK5CYII=);
        width: 32rpx;
        height: 32rpx;
        background-size: 400%;
      }

      .msg-product{
        display: flex;
        flex-direction: column;
        width: 100%;
        background-color: #FFFFFF;
        padding: 10rpx;
        border-radius: 16rpx;
        width: 480rpx;
        margin-right: 12rpx;
        .zx{
          display: flex;
          justify-content: space-between;
          width: 100%;
          font-size: 28rpx;
          margin: 10rpx;
          .zxview{
            color: darkgrey;
            font-size: 26rpx;
            margin-right: 20rpx;
          }
        }
        .msg-con{
          display: flex;
          justify-content: space-between;
          width: 100%;
          padding: 10rpx;
          border-radius: 16rpx;
        }
        .img{
          width: 120rpx;
          height: 120rpx;
        }
        .info{
          display: flex;
          flex-direction: column;
          flex: 1;
          padding: 6rpx 8rpx;
          position: relative;
          margin-left: 10rpx;
          background-color: #f4f4f4;
          border-radius: 0 10rpx 10rpx 0;
          .name{
            width: 330rpx;
            // white-space: nowrap; /* 防止文本换行 */
            // overflow: hidden; /* 隐藏溢出的内容 */
            // text-overflow: ellipsis; /* 溢出部分显示省略号 */
            .txt{
              font-size: 26rpx;
              color: darkgrey;
              margin-left: 6rpx;
            }
            .ntxt{
              font-size: 28rpx;
              color: #000;
            }
          }
          .sku{
            display: flex;
            flex-direction: row;
            .txt{
              font-size: 26rpx;
              color: darkgrey;
              margin-right: 6rpx;
            }
          }
          .xq{
            width: 100%;
            display: flex;
            flex-direction: row;
            .list{
              display: flex;
              flex: 1;
            }
            .price{
              display: flex;
              align-items: center;
              font-size: 28rpx;
              color: #ff007f;
            }
            .ord{
              display: flex;
              align-items: center;
              font-size: 26rpx;
              color: #232323;
            }
            .qty{
              display: flex;
              align-items: center;
              font-size: 26rpx;
              color: darkgrey;
              margin-left: 8rpx;
            }
            .btn{
              font-size: 26rpx;
              font-family: PingFang SC-Medium, PingFang SC;
              font-weight: 500;
              color: #FCFCFD;
              width: 110rpx;
              height: 50rpx;
              line-height: 50rpx;
              background: #ff007f;
              box-shadow: 0rpx 10rpx 30rpx 2rpx rgba(255,0,127,0.2);
              border-radius: 60rpx;
              opacity: 1;
              margin-right: 10rpx;
              margin-top: 10rpx;
              margin-bottom: 10rpx;
              padding-left:0 !important;
              padding-right:0 !important;
              &::after{
                border:none;
              }
            }
          }
        }

      }

    }
  }
}

.voicePlay {
  animation-name: voicePlay;
  animation-duration: 1s;
  animation-direction: normal;
  animation-iteration-count: infinite;
  animation-timing-function: steps(3);
}

@keyframes voicePlay {
  0% {
    background-position: 0;
  }
  100% {
    background-position: 100%;
  }
}

.popup{
  position: fixed;
  bottom: 180rpx;
  /* #ifdef H5 */
  bottom: 100rpx;
  /* #endif */
  left: 0;
  width: 100%;
  padding: 18rpx;
  border-radius: 16rpx;
  .tipcon{
    display: flex;
    justify-content: space-between;
    width: 100%;
    background-color: #FFFFFF;
    padding: 16rpx;
    border-radius: 16rpx;
    .img{
      width: 100rpx;
      height: 100rpx;
    }
    .info{
      display: flex;
      flex-direction: column;
      flex: 1;
      margin-left: 16rpx;
      position: relative;
      .name{
        width: 550rpx;
        // white-space: nowrap; /* 防止文本换行 */
        // overflow: hidden; /* 隐藏溢出的内容 */
        // text-overflow: ellipsis; /* 溢出部分显示省略号 */
        margin-right: 50rpx;
        .txt{
          font-size: 26rpx;
          color: darkgrey;
          margin-left: 6rpx;
        }
        .ntxt{
          font-size: 28rpx;
          color: #000;
        }
      }
      .sku{
        display: flex;
        flex-direction: row;
        .txt{
          font-size: 26rpx;
          color: darkgrey;
          margin-right: 6rpx;
        }
      }
      .xq{
        width: 100%;
        display: flex;
        flex-direction: row;
        .list{
          display: flex;
          flex: 1;
          align-items: flex-end;
        }
        .price{
          font-size: 28rpx;
          color: #ff007f;
        }
        .ord{
          display: flex;
          align-items: center;
          font-size: 26rpx;
          color: #232323;
        }
        .qty{
          font-size: 26rpx;
          color: darkgrey;
          margin-left: 6rpx;
        }
        .btn{
          font-size: 26rpx;
          font-family: PingFang SC-Medium, PingFang SC;
          font-weight: 500;
          color: #FCFCFD;
          width: 150rpx;
          height: 50rpx;
          line-height: 50rpx;
          background: #ff007f;
          box-shadow: 0rpx 10rpx 30rpx 2rpx rgba(255,0,127,0.2);
          border-radius: 10rpx;
          opacity: 1;
          margin-right: 10rpx;
          padding-left:0 !important;
          padding-right:0 !important;
          &::after{
            border:none;
          }
        }
      }
      .close{
        position: absolute;
        top: 0;
        right: 6rpx;
      }
    }
  }
}

.example {
  width: 550rpx;
  opacity: 1;
  padding: 0;
  box-sizing: border-box;
  .order {
    position: relative;
    overflow: hidden;
    display: block;
    background-color: #ffffff;
    margin: 0 0 10rpx;
    box-sizing: border-box;
    padding: 0rpx 20rpx;
  }
  .qhbtn{
    width: 100%;
    display: flex;
    flex-direction: row;
    .btn{
      width: 120rpx;
      height: 60rpx;
      border-radius: 20rpx;
      background-color: #eee;
      color: #000;
      font-size: 26rpx;
      display: flex;
      align-items: center;
      justify-content: center;
      margin-right: 16rpx;
      margin-top: 16rpx;
    }
    .cur{
      background-color: #00a89b;
      color: #fff;
    }
  }
  .readlist{
    display: flex;
    flex-wrap: wrap;
    padding: 20rpx 0 0 10rpx ;
  }
  .readcell{
    display: flex;
    justify-content: space-between;
    width: 100%;
    padding: 16rpx 0;
    border-bottom: 1rpx solid #eee;
    .readtime{
      font-size: 24rpx;
      color: #888;
    }
    .readname{
      font-size: 26rpx;
      color: #33383c;
      display: flex;
      flex: 1;
    }
  }

  .chatlist{
    display: flex;
    flex-wrap: wrap;
    padding: 20rpx 0 0 10rpx ;
  }
  .chatcell{
    display: flex;
    flex-direction: column;
    min-width: 90rpx;
    height: 150rpx;
    align-items: center;
    justify-content: center;
    margin-right: 30rpx;
    .user-img{
      width: 90rpx;
      height: 90rpx;
      border-radius: 5rpx;
    }
    .user-name{
      font-size: 26rpx;
      color: #33383c;
      margin-top: 16rpx;
    }
  }
  .lcon{
    padding: 20rpx 10rpx;
    display: flex;
    flex-direction: column;
    border-bottom: 1rpx solid #eee;
    .lhtxt{
      font-size: 30rpx;
      color: #33383c;
      line-height: 40rpx;
    }
    .ltxt{
      margin-top: 16rpx;
      font-size: 28rpx;
      color: #888;
      line-height: 30rpx;
    }
  }
}


</style>
