Bläddra i källkod

Merge branch 'master' of http://1.14.104.71:10880/root/ylrz_scrm_companyUI

ct 2 dagar sedan
förälder
incheckning
b8548d323a

BIN
src/assets/image/qw-im.png


BIN
src/assets/voice/new-notification.mp3


+ 28 - 2
src/components/LemonUI/components/contact.vue

@@ -21,7 +21,7 @@ export default {
     timeFormat: {
       type: Function,
       default(val) {
-        return timeFormat(val, isToday(val) ? "h:i" : "y/m/d");
+        return timeFormat(val, isToday(val) ? "h:i" : "m/d");
       },
     },
   },
@@ -56,7 +56,11 @@ export default {
         </lemon-badge>,
         <div class="lemon-contact__inner">
           <p class="lemon-contact__label">
-            <span class="lemon-contact__name">{contact.displayName}</span>
+            <span class="lemon-contact__name">
+              {contact.displayName}
+              {true && <span class="lemon-contact__chong">重</span>}
+              {true && <span class="lemon-contact__hei">黑</span>}
+            </span>
             {!this.simple && (
               <span class="lemon-contact__time">
                 {this.timeFormat(contact.lastSendTime)}
@@ -142,4 +146,26 @@ export default {
     +e(label)
       padding-bottom 0
       line-height 38px
+  +e(chong)
+    display inline-flex
+    align-items center
+    justify-content center
+    width 20px
+    height 20px
+    font-size 12px
+    border-radius 5px
+    background-image: linear-gradient(-225deg, #231557 0%, #44107A 29%, #FF1361 67%, #FFF800 100%);
+    color white
+    margin-left 5px
+  +e(hei)
+    display inline-flex
+    align-items center
+    justify-content center
+    width 20px
+    height 20px
+    font-size 12px
+    border-radius 5px
+    background-image: linear-gradient(-20deg, #2b5876 0%, #4e4376 100%);
+    color white
+    margin-left 5px
 </style>

+ 12 - 0
src/components/LemonUI/components/index.vue

@@ -577,6 +577,18 @@ export default {
           </div>
         </div>,
       );
+
+      // 拓展
+      nodes.push(
+        <div
+          class={cls}
+          style="flex: 1 1 0;width: 0;"
+          v-show={this._menuIsMessages() && defIsShow && curact.id}
+        >
+          {useScopedSlot(this.$scopedSlots["message-extend"], null, curact)}
+        </div>,
+      );
+
       nodes.push(
         <div class={cls} v-show={!curact.id && this.currentIsDefSidebar}>
           {this.$slots.cover}

+ 37 - 14
src/layout/index.vue

@@ -46,7 +46,9 @@
       </div>
 
       <div class="qw-im">
-        <img alt="" class="qw-im-img" @click="() => {this.qw.open = !this.qw.open}" src="../assets/image/qw-im.png"/>
+        <el-badge :value="totalUnreadCount" :max="99" :hidden="totalUnreadCount < 1">
+          <img alt="" class="qw-im-img" @click="() => {this.qw.open = !this.qw.open}" src="../assets/image/qw-im.png"/>
+        </el-badge>
       </div>
     </div>
 
@@ -55,18 +57,20 @@
                custom-class="im-dialog"
                :fullscreen="qw.isMaximized"
                :visible.sync="qw.open"
+               :modal="false"
+               :style="{visibility: !qw.initLoad ? 'hidden' : 'unset'}"
                :title="qw.title">
-      <template #title>
-        <span>{{ qw.title }}</span>
-        <span style="float:right;">
-          <i class="el-icon-full-screen"
-            @click.stop="toggleMaximize"
-            style="margin-right: 50px;cursor: pointer;color: #93969b"
-          />
-        </span>
-      </template>
+<!--      <template #title>-->
+<!--        <span>{{ qw.title }}</span>-->
+<!--        <span style="float:right;">-->
+<!--          <i class="el-icon-full-screen"-->
+<!--            @click.stop="toggleMaximize"-->
+<!--            style="margin-right: 50px;cursor: pointer;color: #93969b"-->
+<!--          />-->
+<!--        </span>-->
+<!--      </template>-->
       <div class="qw-im-content">
-        <QwIM :showQw="qw.open" :isMaximized="qw.isMaximized"/>
+        <QwIM :showQw="qw.open" :isMaximized="qw.isMaximized" @close="() => qw.open = false"/>
       </div>
     </el-dialog>
   </div>
@@ -100,7 +104,8 @@ export default {
       needTagsView: state => state.settings.tagsView,
       fixedHeader: state => state.settings.fixedHeader,
       isCall:state => state.user.isCall,
-      companyUser:state => state.user.user
+      companyUser:state => state.user.user,
+      totalUnreadCount: state => state.qwIm.totalUnreadCount
     }),
     classObj() {
       return {
@@ -122,7 +127,8 @@ export default {
       qw: {
         open: false,
         title: '',
-        isMaximized: false
+        isMaximized: false,
+        initLoad: false
       }
     }
   },
@@ -133,6 +139,15 @@ export default {
        // if(this.companyUser.userType=="00"){
        //    this.initSocket(this.companyUser.userId);
        // }
+    if (!this.qw.initLoad) {
+      this.qw.open = true
+      this.$nextTick(() => {
+        this.qw.open = false
+        setTimeout(() => {
+          this.qw.initLoad = true
+        },  50)
+      })
+    }
   },
   methods: {
     callPhone(){
@@ -335,7 +350,8 @@ export default {
 
 }
 
-.qw-im {
+::v-deep .qw-im {
+  background-color: #fff;
   z-index: 2000;
   position: fixed;
   right: 30px;
@@ -346,11 +362,18 @@ export default {
     border-radius: 30px;
     width: 100%;
   }
+  .el-badge__content {
+    border: unset;
+  }
 }
 
 ::v-deep .im-dialog {
+  margin-top: unset !important;
   max-width: 100vw;
   max-height: 100vh;
+  .el-dialog__header {
+    display: none;
+  }
   .el-dialog__body {
     padding: 0 !important;
   }

+ 7 - 0
src/store/modules/qwIm.js

@@ -1,16 +1,23 @@
 const state = {
   shareCourse: null,
+  totalUnreadCount: 0
 }
 
 const mutations = {
   SHARE_COURSE: (state, data) => {
     state.shareCourse = data
+  },
+  TOTAL_UNREAD_COUNT: (state, data) => {
+    state.totalUnreadCount = data
   }
 }
 
 const actions = {
   shareCourse({ commit }, data) {
     commit('SHARE_COURSE', data)
+  },
+  totalUnreadCount({ commit }, data) {
+    commit('TOTAL_UNREAD_COUNT', data)
   }
 }
 

+ 403 - 47
src/views/qw/qwChat/qq.vue

@@ -5,10 +5,22 @@
       <el-tab-pane
         v-for="item in qwUserList"
         :key="item.id"
-        :label="item.qwUserId"
-        :name="item.appKey"/>
+        :name="item.appKey">
+        <span slot="label">
+          <el-badge :value="getUnreadCount(item.appKey)"
+                    :max="99"
+                    v-if="getUnreadCount(item.appKey) > 0">
+            {{ item.qwUserName }}
+          </el-badge>
+          <template v-else>
+            {{ item.qwUserName }}
+          </template>
+        </span>
+      </el-tab-pane>
     </el-tabs>
 
+    <i class="el-icon-close" @click="handleClose" style="font-size: 22px;position: absolute;top: 8px;right: 8px;cursor: pointer;"/>
+
     <div class="imui-center qq-lemon-imui" v-show="showQW">
       <lemon-imui  class="lemon-slot"
                    :width="isMaximized ? '100vw' : windowWidth"
@@ -31,7 +43,7 @@
                    @pick-image="handleImageClick"
                    @send="handleSend">
         <template #sidebar-message-top>
-          <div style="padding: 8px;">
+          <div style="padding: 8px; display: flex; align-items: center;">
             <el-input
               v-model="searchKeyword"
               prefix-icon="el-icon-search"
@@ -39,21 +51,50 @@
               size="small"
               clearable
               @input="handleSearch"
-              style="width: 100%;"
+              style="flex: 1;height: 32px;"
             />
+            <el-popover
+              placement="bottom-end"
+              width="200"
+              v-model="filterPopoverVisible"
+              trigger="click"
+            >
+              <!-- 这里放你的过滤选项内容 -->
+              <div>
+                <el-checkbox-group v-model="selectedFilters">
+                  <el-checkbox label="1">去掉重粉</el-checkbox>
+                  <el-checkbox label="2">去掉小黑屋</el-checkbox>
+                </el-checkbox-group>
+                <div style="margin-top: 10px; text-align: right;">
+                  <el-button size="mini" type="primary" @click="applyFilter">确定</el-button>
+                </div>
+              </div>
+              <el-button
+                slot="reference"
+                icon="el-icon-setting"
+                style="padding: 8px;height: 32px;"
+                size="small"
+                :type="selectedFilters.length > 0 ? 'primary' : 'default'"
+              ></el-button>
+            </el-popover>
           </div>
         </template>
         <template #message-title="contact">
 <!--          <div @click="openDrawer('right')" style="position: absolute;right: 14px;top: 10px;">-->
 <!--            <i class="el-icon-more" style="cursor: pointer"/>-->
 <!--          </div>-->
-          <div>
-            <el-button
-              type="primary"
-              size="small"
-              style="position: absolute;right: 14px;top: 10px;z-index: 1000"
-              @click="showDetail(contact.extId)"
-            >详情</el-button>
+<!--          <div>-->
+<!--            <el-button-->
+<!--              type="primary"-->
+<!--              size="small"-->
+<!--              style="position: absolute;right: 14px;top: 10px;z-index: 1000"-->
+<!--              @click="showDetail(contact.extId)"-->
+<!--            >详情</el-button>-->
+<!--          </div>-->
+        </template>
+        <template #message-extend="contact">
+          <div v-if="contact.extId" style="width: 100%;height: 100%;overflow: auto">
+            <userDetail :ext-id="contact.extId" :extend="true" ref="userDetail" />
           </div>
         </template>
       </lemon-imui>
@@ -100,8 +141,9 @@ import {getToken} from '@/utils/auth'
 import {uploadOss} from "@/api/common";
 import {mapState} from "vuex";
 import {generateUUID} from "@/components/LemonUI/utils";
+import {getTime} from "@/utils";
+import notificationMp3 from '@/assets/voice/new-notification.mp3'
 
-let pages = {};
 export default {
   name: "qqChat",
   components: {
@@ -150,8 +192,8 @@ export default {
       roomMembers:[],
       roomAdmins:[],
       roomInfo:null,
-      windowWidth: document.documentElement.clientWidth*0.6,  //实时屏幕宽度
-      windowHeight: document.documentElement.clientHeight*0.7,   //实时屏幕高度
+      windowWidth: document.documentElement.clientWidth * 0.8,  //实时屏幕宽度
+      windowHeight: document.documentElement.clientHeight * 0.85,   //实时屏幕高度
       queryParams: {
         pageNum: 1,
         pageSize: 10,
@@ -165,29 +207,53 @@ export default {
       imSocket: null,
       imUrl: process.env.VUE_APP_IM_WS_URL,
       searchKeyword: '',
+      filterPopoverVisible: false,
+      selectedFilters: [],
+      // 存储每个企微账号的会话记录和状态
+      qwUserSessions: {},
+      // 存储每个企微账号的分页信息
+      qwUserPages: {},
+      // 公司ID,用于WebSocket连接
+      companyId: null,
+      // 存储每个企微账号的未读消息数
+      qwUserUnreadCount: [],
     };
   },
   created(){
+    // 初始化企微账号会话页码对象
+    this.qwUserPages = {};
+
     //获取企微列表
     getQwUserList().then(response => {
       this.qwUserList = response.data;
       if (this.qwUserList.length>0){
         this.qwUser = this.qwUserList[0];
         this.appKey = this.qwUser.appKey;
+        this.companyId = this.qwUser.companyId; // 保存公司ID用于WebSocket连接
         this.setQwUserInfo();
         this.getConversation();
-        this.initImSocket(this.qwUser.companyId)
+
+        // 初始化单个WebSocket连接
+        this.initImSocket();
+
+        // 初始化未读消息数
+        this.initUnreadCount();
       }else {
         this.qwUser={};
       }
     });
   },
   computed: {
-    ...mapState('qwIm', ['shareCourse'])
+    ...mapState('qwIm', ['shareCourse']),
+    // 计算所有企微账号的未读消息总数
+    totalUnreadCount() {
+      return this.qwUserUnreadCount.reduce((sum, item) => sum + item.unreadCount, 0);
+    },
   },
   watch: {
     showQw(nv, ov) {
       if (nv) {
+        this.clearUnreadCount(this.appKey)
         this.$nextTick(() => {
           this.$refs.IMUI.messageViewToBottom();
         });
@@ -221,6 +287,13 @@ export default {
           null
         );
       }
+    },
+    // 监听未读消息数变化
+    qwUserUnreadCount: {
+      handler() {
+        this.$store.dispatch('qwIm/totalUnreadCount', this.totalUnreadCount)
+      },
+      deep: true // 深度监听对象内部变化
     }
   },
   mounted() {
@@ -244,49 +317,197 @@ export default {
     ])
   },
   beforeDestroy() {
+    // 关闭WebSocket连接
     if (this.imSocket) {
       this.imSocket.close();
+      this.imSocket = null;
     }
+    this.clearSessionCache()
   },
   methods: {
-    initImSocket(companyId) {
-      this.imSocket = new ImSocket(`${this.imUrl}/${companyId}?token=${getToken()}`);
+    getUnreadCount(appKey) {
+      const index = this.qwUserUnreadCount.findIndex(entry => entry.appKey === appKey);
+      return index !== -1 ? this.qwUserUnreadCount[index].unreadCount : 0;
+    },
+    // 清除会话缓存
+    clearSessionCache() {
+      this.qwUserSessions = {};
+      this.qwUserPages = {};
+    },
+
+    // 初始化WebSocket连接
+    initImSocket() {
+      // 如果已经有连接,先关闭
+      if (this.imSocket) {
+        this.imSocket.close();
+      }
+
+      // 创建新的WebSocket连接,使用公司ID
+      this.imSocket = new ImSocket(`${this.imUrl}/${this.companyId}?token=${getToken()}`);
+
+      // 处理接收到的消息
       this.imSocket.onMessage(data => {
         const { IMUI } = this.$refs;
-        let message = JSON.parse(data);
-        this.appendRemoteMessage(message)
-
-        let conversation = IMUI.findConversation(message.toContactId);
-        if (conversation.msgId) {
-          conversation.lastSendTime = message.sendTime;
-          conversation.lastContent = IMUI.lastContentRender(message)//message.content;
-          IMUI.topPopConversations(conversation);
+        try {
+          let message = JSON.parse(data);
+          this.appendRemoteMessage(message);
+
+          // 播放声音
+          const audio = new Audio(notificationMp3);
+          audio.play().catch(err => {
+            console.warn("播放声音失败", err);
+          });
+
+          // 确定消息所属的企微账号
+          const messageAppKey = message.appKey;
+
+          // 检查消息是否属于当前企微账号
+          if (messageAppKey === this.appKey) {
+
+            if (!this.showQw) {
+              this.incrementUnreadCount(messageAppKey);
+            }
+
+            let conversation = IMUI.findConversation(message.toContactId);
+            if (conversation) {
+              conversation.lastSendTime = message.sendTime;
+              conversation.lastContent = IMUI.lastContentRender(message);
+              IMUI.topPopConversations(conversation);
+
+              // 更新缓存中的会话记录
+              this.updateSessionConversation(conversation);
+            } else {
+              // 如果找不到会话,可能需要刷新会话列表
+              this.refreshCurrentSession();
+            }
+          } else if (messageAppKey) {
+            // 如果不是当前账号的消息,增加对应账号的未读消息数
+            this.incrementUnreadCount(messageAppKey);
+
+            if (this.qwUserSessions[messageAppKey]) {
+              const index = this.qwUserSessions[messageAppKey].findIndex(
+                item => item.conversationId === message.toContactId
+              );
+
+              if (index !== -1) {
+                let conversation = this.qwUserSessions[messageAppKey][index]
+                conversation.lastSendTime = message.sendTime;
+                conversation.lastContent = IMUI.lastContentRender(message);
+                conversation.unread = conversation.unread + 1;
+                this.qwUserSessions[messageAppKey][index] = {...conversation};
+              }
+            }
+          }
+        } catch (error) {
+          console.error("处理WebSocket消息时出错:", error);
+        }
+      });
+    },
+    // 初始化未读消息数
+    initUnreadCount() {
+      // 为每个企微账号初始化未读消息数为0
+      this.qwUserUnreadCount = []; // 先清空
+
+      this.qwUserList.forEach(user => {
+        this.qwUserUnreadCount.push({
+          appKey: user.appKey,
+          qwUserId: user.qwUserId,
+          unreadCount: 0
+        });
+      });
+    },
+
+    // 增加指定企微账号的未读消息数
+    incrementUnreadCount(appKey) {
+      if (!appKey) {
+        console.error("incrementUnreadCount: appKey不能为空");
+        return;
+      }
+
+      // 查找对应的企微账号记录
+      const index = this.qwUserUnreadCount.findIndex(item => item.appKey === appKey);
+
+      if (index !== -1) {
+        // 如果找到,则增加未读消息数
+        const newCount = this.qwUserUnreadCount[index].unreadCount + 1;
+        this.$set(this.qwUserUnreadCount[index], 'unreadCount', newCount);
+      } else {
+        // 如果没找到,则添加新记录
+        const user = this.qwUserList.find(u => u.appKey === appKey);
+        if (user) {
+          this.qwUserUnreadCount.push({
+            appKey: appKey,
+            qwUserId: user.qwUserId,
+            unreadCount: 1
+          });
         }
-      })
+      }
     },
+
+    // 清除指定企微账号的未读消息数
+    clearUnreadCount(appKey) {
+      // 查找对应的企微账号记录
+      const index = this.qwUserUnreadCount.findIndex(item => item.appKey === appKey);
+
+      if (index !== -1) {
+        // 如果找到,则清除未读消息数
+        this.$set(this.qwUserUnreadCount[index], 'unreadCount', 0);
+      }
+    },
+
     // 切换企微账号
     qwUserChange(tab, event){
       this.appKey = tab.name;
       let index= this.qwUserList.findIndex(item => item.appKey === tab.name);
       this.qwUser=this.qwUserList[index];
-      this.getConversation();   //获取会话信息
+
+      // 清除当前账号的未读消息数
+      this.clearUnreadCount(this.appKey);
+
+      // 不需要重新创建WebSocket连接,只需更新当前账号信息
       this.setQwUserInfo();
+      this.getConversation();   //获取会话信息
     },
     setQwUserInfo(){
       this.userData.id=this.qwUser.id;
       this.userData.displayName=this.qwUser.qwUserName;
-      this.userData.avatar="https://cos.his.cdwjyyh.com/fs/20241231/22a765a96da247d1b83ea94fef438a41.png";
+      this.userData.avatar=this.qwUser.avatar;
     },
     getConversation(){
       const IMUI = this.$refs.IMUI;
-      getConversations(this.qwUser.id).then(response => {
-        this.conversationData = response.data;
-        IMUI.initConversations(response.data);
-        const fstConversation = this.conversationData[0];
-        if(fstConversation) {
-          IMUI.changeContact(fstConversation.conversationId);
+
+      // 检查是否已有该企微账号的会话记录缓存
+      if (this.qwUserSessions[this.appKey]) {
+        // 如果有,直接使用缓存的会话记录
+        this.conversationData = this.qwUserSessions[this.appKey];
+        IMUI.initConversations(this.conversationData);
+
+        // 恢复上次选中的会话
+        const lastSelectedConversation = this.qwUserSessions[`${this.appKey}_selected`];
+        if (lastSelectedConversation) {
+          IMUI.changeContact(lastSelectedConversation);
+        } else {
+          // 如果没有上次选中的会话,选择第一个会话
+          const fstConversation = this.conversationData[0];
+          if(fstConversation) {
+            IMUI.changeContact(fstConversation.conversationId);
+          }
         }
-      });
+      } else {
+        // 如果没有缓存,则从服务器获取会话记录
+        getConversations(this.qwUser.id).then(response => {
+          this.conversationData = response.data;
+
+          // 缓存会话记录
+          this.qwUserSessions[this.appKey] = response.data;
+
+          IMUI.initConversations(response.data);
+          const fstConversation = this.conversationData[0];
+          if(fstConversation) {
+            IMUI.changeContact(fstConversation.conversationId);
+          }
+        });
+      }
     },
     messageTimeFormat(time) {
       return this.friendlyDate(time);
@@ -314,23 +535,44 @@ export default {
           isEnd=response.data.isLastPage;
           next(response.data.list, isEnd);
           if(!isEnd){
-            pages[contact.conversationId]++;
-            this.queryParams.pageNum=pages[contact.conversationId];
+            this.qwUserPages[contact.conversationId]++;
+            this.queryParams.pageNum=this.qwUserPages[contact.conversationId];
             this.queryParams.userId = this.qwUser.id
           }
         }
       });
     },
     handleChangeConversation(conversation, instance) {
-      if (!pages[conversation.conversationId]){
-        pages[conversation.conversationId] =1;
+      // 保存当前选中的会话ID
+      this.qwUserSessions[`${this.appKey}_selected`] = conversation.conversationId;
+
+      // 检查是否已有该会话的分页信息
+      if (!this.qwUserPages[conversation.conversationId]){
+        this.qwUserPages[conversation.conversationId] =1;
       }
-      this.queryParams.pageNum=pages[conversation.conversationId];
+
+      this.queryParams.pageNum=this.qwUserPages[conversation.conversationId];
       this.queryParams.conversationId=conversation.conversationId;
       this.queryParams.userId = this.qwUser.id
+
       if(conversation.unread>0){
         conversation.unread=0;
         instance.updateContact(conversation);
+
+        // 更新缓存中的会话记录
+        this.updateSessionConversation(conversation);
+      }
+    },
+
+    // 更新缓存中的会话记录
+    updateSessionConversation(conversation) {
+      if (this.qwUserSessions[this.appKey]) {
+        const index = this.qwUserSessions[this.appKey].findIndex(
+          item => item.conversationId === conversation.conversationId
+        );
+        if (index !== -1) {
+          this.qwUserSessions[this.appKey][index] = {...conversation};
+        }
       }
     },
     handleChangeContact(contact, instance) {
@@ -394,6 +636,10 @@ export default {
             conversation.lastSendTime = message.sendTime;
             conversation.lastContent = IMUI.lastContentRender(message)
             IMUI.topPopConversations(conversation);
+
+            // 更新缓存中的会话记录
+            this.updateSessionConversation(conversation);
+
             next();
           } else {
             next({status:'failed'})
@@ -415,6 +661,10 @@ export default {
                 conversation.lastSendTime = message.sendTime;
                 conversation.lastContent = IMUI.lastContentRender(message)
                 IMUI.topPopConversations(conversation);
+
+                // 更新缓存中的会话记录
+                this.updateSessionConversation(conversation);
+
                 next();
               } else {
                 next({status:'failed'})
@@ -440,6 +690,9 @@ export default {
             conversation.lastSendTime = message.sendTime;
             conversation.lastContent = IMUI.lastContentRender(message)
             IMUI.topPopConversations(conversation);
+
+            // 更新缓存中的会话记录
+            this.updateSessionConversation(conversation);
           }
         });
       }
@@ -543,7 +796,7 @@ export default {
     appendCustomMessage() {
       const { IMUI } = this.$refs;
       const message = {
-        id: generateRandId(),
+        id: generateUUID(),
         status: "succeed",
         type: "voice",
         sendTime: getTime(),
@@ -568,7 +821,79 @@ export default {
     },
     appendRemoteMessage(message) {  //从服务端返回的消息
       const { IMUI } = this.$refs;
-      IMUI.appendMessage(message, true);
+      if (!IMUI) {
+        console.error("IMUI引用不存在,无法添加消息");
+        return;
+      }
+
+      try {
+        // 确保消息对象包含必要的字段
+        if (!message.id) {
+          message.id = generateUUID(); // 使用UUID生成唯一ID
+        }
+
+        if (!message.status) {
+          message.status = "succeed";
+        }
+
+        if (!message.sendTime) {
+          message.sendTime = new Date().getTime();
+        }
+
+        // 根据消息类型处理
+        switch (message.type) {
+          case "text":
+            // 文本消息不需要特殊处理
+            break;
+          case "image":
+            // 确保图片消息有content或url字段
+            if (!message.content && message.url) {
+              message.content = message.url;
+            }
+            break;
+          case "voice":
+            // 确保语音消息有content字段
+            if (!message.content) {
+              message.content = "语音消息";
+            }
+            // 添加语音时长
+            if (message.duration) {
+              message.params1 = message.duration.toString();
+            }
+            break;
+          case "file":
+            // 确保文件消息有fileName和fileSize字段
+            if (!message.fileName) {
+              message.fileName = "未命名文件";
+            }
+            if (!message.fileSize && message.fileSize !== 0) {
+              message.fileSize = 0;
+            }
+            break;
+          case "miniprogram":
+            // 小程序消息处理
+            if (!message.content) {
+              message.content = "小程序卡片";
+            }
+            break;
+          default:
+            console.warn("未知消息类型:", message.type);
+            break;
+        }
+
+        // 添加消息到UI
+        IMUI.appendMessage(message, true);
+
+        // 更新缓存中的会话记录
+        if (message.toContactId && IMUI.conversations) {
+          const conversation = IMUI.findConversation(message.toContactId);
+          if (conversation) {
+            this.updateSessionConversation(conversation);
+          }
+        }
+      } catch (error) {
+        console.error("添加远程消息时出错:", error);
+      }
     },
     handleChangeMenu() {
       console.log("Event:change-menu");
@@ -602,6 +927,30 @@ export default {
       });
       this.$refs.IMUI.initConversations(filtered);
     },
+    applyFilter() {
+      this.filterPopoverVisible = false;
+      // 这里可以根据 selectedFilters 做过滤
+      this.handleSearch();
+    },
+    // 手动刷新当前企微账号的会话列表
+    refreshCurrentSession() {
+      // 删除当前企微账号的会话缓存
+      if (this.appKey) {
+        delete this.qwUserSessions[this.appKey];
+        delete this.qwUserSessions[`${this.appKey}_selected`];
+
+        // 重新获取会话列表
+        this.getConversation();
+
+        this.$message({
+          message: '会话列表已刷新',
+          type: 'success'
+        });
+      }
+    },
+    handleClose() {
+      this.$emit('close')
+    }
   },
 };
 </script>
@@ -611,10 +960,6 @@ export default {
   align-items: center;
   justify-content: center;
 }
-.lemon-wrapper{
-  border:1px solid #ddd;
-  //height: !important;
-}
 .lemon-drawer{
   border:1px solid #ddd;
   border-left:0;
@@ -647,12 +992,23 @@ export default {
 }
 
 ::v-deep .im-tabs {
+  width: 97%;
   .el-tabs__header {
     margin: 0 !important;
     .el-tabs__item {
       border-bottom: 0 !important;
     }
   }
+
+  /* 未读消息徽标样式 */
+  .el-badge__content {
+    border: none;
+    font-size: 12px;
+    font-weight: bold;
+    background-color: #F56C6C;
+    transform: translateY(-2px);
+    right: unset
+  }
 }
 
 </style>

+ 22 - 10
src/views/qw/qwChat/userDetail/courseManage.vue

@@ -43,7 +43,7 @@
     </div>
 
     <!-- 列表 -->
-    <div class="infinite-list-wrapper" style="overflow:auto">
+    <div :class="extend ? 'infinite-list-wrapper-extend' : 'infinite-list-wrapper'" style="overflow:auto">
       <ul class="video-list" v-infinite-scroll="loadMoreVideo">
         <li v-for="item in videoList" :key="item.videoId" class="video-item">
           <div class="video-thumbnail">
@@ -58,12 +58,12 @@
             </div>
           </div>
           <div class="video-actions">
-            <el-button 
-              type="primary" 
-              size="mini" 
-              round 
-              :loading="sharingVideoId === item.videoId" 
-              :disabled="sharingVideoId === item.videoId" 
+            <el-button
+              type="primary"
+              size="mini"
+              round
+              :loading="sharingVideoId === item.videoId"
+              :disabled="sharingVideoId === item.videoId"
               @click="handleShare(item)">分享课程</el-button>
           </div>
         </li>
@@ -92,6 +92,10 @@ export default {
     userId: {
       type: Number,
       default: () => null
+    },
+    extend: {
+      type: Boolean,
+      default: false
     }
   },
   data() {
@@ -239,11 +243,12 @@ export default {
       }
       this.sharingVideoId = item.videoId;
       createMiniLink(params).then(response => {
-        if (response.code === 200) {
-          this.$store.dispatch('qwIm/shareCourse', response.data)
+        const {code, data} = response;
+        if (code === 200) {
+          this.$store.dispatch('qwIm/shareCourse', data)
         }
         this.sharingVideoId = null;
-      }).catch(error => {
+      }).catch(() => {
         this.$message.error('分享课程失败');
         this.sharingVideoId = null;
       })
@@ -290,6 +295,13 @@ export default {
   padding: 0 10px;
   background-color: #f5f7fa;
 }
+.infinite-list-wrapper-extend {
+  height: calc(100vh - 330px);
+  overflow-y: auto;
+  padding: 0 10px;
+  background-color: #f5f7fa;
+}
+
 
 .video-list {
   list-style: none;

+ 85 - 113
src/views/qw/qwChat/userDetail/index.vue

@@ -1,89 +1,32 @@
 <template>
-  <div style="background-color: #f0f2f5; padding-bottom: 20px; min-height: 100%;">
+  <div :style="{backgroundColor: '#f0f2f5', paddingBottom: !extend && '20px', minHeight: '100%'}">
     <!-- 客户详情 -->
     <div v-if="showDetail">
-      <div style="padding: 20px; background-color: #fff;">
+      <div v-if="!extend" style="padding: 20px; background-color: #fff;">
         客户详情
       </div>
-
-      <!-- 用户头像 -->
-      <div style="padding: 20px 10px 0 10px;background-image: linear-gradient(to right, #e0edff, #dfe0fe)">
-        <div style="padding: 20px 10px 0 10px;background-image: linear-gradient(to right, #edf5ff, #ecedff);display: flex;border-radius: 8px;">
-          <div style="padding: 10px">
-            <el-avatar :size="50" :src="qwUserInfo.avatar"/>
-          </div>
-          <div style="padding: 10px;display: flex;flex-direction: column;align-items: flex-start;justify-content: center;">
-            <div>
-              <span style="font-size: 16px;">{{qwUserInfo.name}}</span>
-            </div>
-            <div>
-              <span style="font-size: 14px;color: #8c939d">备注:{{qwUserInfo.remark}}</span>
-            </div>
-          </div>
-        </div>
-      </div>
-
       <!--  基本信息 -->
-      <div>
-        <div style="display: flex;justify-content: space-between;align-items: center;flex-direction: row;background: #FFF;padding: 10px">
-          <div>
-            基本信息
-          </div>
-          <div>
-            <el-button size="mini" round @click="updateQwDetail">修改用户信息</el-button>
-          </div>
-        </div>
-        <div style="background: #FFF; padding: 0 10px 10px 20px;color: #8c939d">
-          <el-row>
-            <span style="font-size: 14px;">性别:</span>
-            <span style="font-size: 14px;margin-left: 10px">{{qwUserDetail.sex || '未知'}}</span>
-          </el-row>
-          <el-row style="margin-top: 10px">
-            <span style="font-size: 14px;">年龄:</span>
-            <span style="font-size: 14px;margin-left: 10px">{{qwUserDetail.age || '未知'}}</span>
-          </el-row>
-          <el-row style="margin-top: 10px">
-            <span style="font-size: 14px;">行为习惯:</span>
-            <span style="font-size: 14px;margin-left: 10px">{{qwUserDetail.habits || '无'}}</span>
-          </el-row>
-          <el-row style="margin-top: 10px">
-            <span style="font-size: 14px;">患病时间:</span>
-            <span style="font-size: 14px;margin-left: 10px">{{qwUserDetail.illnessTime || '无'}}</span>
-          </el-row>
-          <el-row style="margin-top: 10px">
-            <span style="font-size: 14px;">疾病:</span>
-            <span style="font-size: 14px;margin-left: 10px">{{qwUserDetail.disease || '无'}}</span>
-          </el-row>
-          <el-row style="margin-top: 10px">
-            <span style="font-size: 14px;">家人的疾病:</span>
-            <span style="font-size: 14px;margin-left: 10px">{{qwUserDetail.familyDisease || '无'}}</span>
-          </el-row>
-          <el-row style="margin-top: 10px">
-            <span style="font-size: 14px;">是否线下就诊:</span>
-            <span style="font-size: 14px;margin-left: 10px">{{qwUserDetail.isLine || '无'}}</span>
-          </el-row>
-          <el-row style="margin-top: 10px">
-            <span style="font-size: 14px;">体质:</span>
-            <span style="font-size: 14px;margin-left: 10px">{{qwUserDetail.constitution || '无'}}</span>
-          </el-row>
-          <el-row style="margin-top: 10px">
-            <span style="font-size: 14px;">使用药品:</span>
-            <span style="font-size: 14px;margin-left: 10px">{{qwUserDetail.medicine || '无'}}</span>
-          </el-row>
-          <el-row style="margin-top: 10px">
-            <span style="font-size: 14px;">咨询产品:</span>
-            <span style="font-size: 14px;margin-left: 10px">{{qwUserDetail.consultProduct || '无'}}</span>
-          </el-row>
-          <el-row style="margin-top: 10px">
-            <span style="font-size: 14px;">是否已经购买产品:</span>
-            <span style="font-size: 14px;margin-left: 10px">{{qwUserDetail.isBuy || '无'}}</span>
-          </el-row>
-        </div>
-      </div>
+      <el-descriptions :class="extend ? 'detail-description-extend' : 'detail-description'" title="基本信息" :column="extend ? 2 : 3" size="medium" border>
+        <template slot="extra">
+          <el-button size="mini" round @click="updateQwDetail">修改用户信息</el-button>
+        </template>
+        <el-descriptions-item label="姓名">{{qwUserInfo.name || '未知'}}</el-descriptions-item>
+        <el-descriptions-item label="性别">{{qwUserDetail.sex || '未知'}}</el-descriptions-item>
+        <el-descriptions-item label="年龄">{{qwUserDetail.age || '未知'}}</el-descriptions-item>
+        <el-descriptions-item label="行为习惯">{{qwUserDetail.habits || '无'}}</el-descriptions-item>
+        <el-descriptions-item label="患病时间">{{qwUserDetail.illnessTime || '无'}}</el-descriptions-item>
+        <el-descriptions-item label="疾病">{{qwUserDetail.disease || '无'}}</el-descriptions-item>
+        <el-descriptions-item label="家人的疾病">{{qwUserDetail.familyDisease || '无'}}</el-descriptions-item>
+        <el-descriptions-item label="是否线下就诊">{{qwUserDetail.isLine || '无'}}</el-descriptions-item>
+        <el-descriptions-item label="体质">{{qwUserDetail.constitution || '无'}}</el-descriptions-item>
+        <el-descriptions-item label="使用药品">{{qwUserDetail.medicine || '无'}}</el-descriptions-item>
+        <el-descriptions-item label="咨询产品">{{qwUserDetail.consultProduct || '无'}}</el-descriptions-item>
+        <el-descriptions-item label="是否已购产品">{{qwUserDetail.isBuy || '无'}}</el-descriptions-item>
+      </el-descriptions>
 
       <!-- 看课记录 -->
-      <div style="background-color: #FFF">
-        <div style="padding: 10px;">
+      <div :style="{backgroundColor: '#FFF',margin: !extend ? '10px' : '5px 0'}">
+        <div style="padding: 10px;font-weight: bold">
           看课记录
         </div>
         <!-- 状态 -->
@@ -102,7 +45,7 @@
         </div>
         <!-- 近七天看课记录 -->
         <div>
-          <div style="display: flex;justify-content: space-between;align-items: center;flex-direction: row;background: #FFF;padding: 10px 0 20px 0">
+          <div style="display: flex;justify-content: space-between;align-items: center;flex-direction: row;background: #FFF;padding: 10px 10px 20px">
             <div class="section-title">
               近七天看课记录
             </div>
@@ -128,6 +71,22 @@
         </div>
       </div>
 
+      <!-- 购买记录 -->
+      <div :style="{backgroundColor: '#FFF',margin: !extend ? '10px' : '5px 0'}" v-if="qwUserInfo.fsUserId">
+        <div style="padding: 10px;font-weight: bold">
+          用户订单
+        </div>
+        <userStorerDetails  ref="userDetails" />
+      </div>
+
+      <!-- 已看过课程 -->
+      <div :style="{backgroundColor: '#FFF',margin: extend ? '5px 0' : '10px'}" v-if="qwUserInfo.fsUserId">
+        <div style="padding: 10px;font-weight: bold">
+          用户看课记录
+        </div>
+        <userCourseWatchLog  ref="userWatchLog" />
+      </div>
+
     </div>
 
     <!-- 修改用户信息 -->
@@ -141,29 +100,10 @@
     <!-- 课程管理 -->
     <course-manage
       v-if="showCourseManage"
+      :extend="extend"
       :userId="qwUserInfo.id"
       @back="handleBack"
     />
-    <!-- 催课管理 -->
-    <remind-course-manage
-      v-if="showRemindCourseManage"
-      :user-id="qwUserDetail.id"
-      @back="handleBack"
-    />
-
-<!--    <div class="contentx" v-if="item.userId != null" >-->
-<!--      <div class="desct">-->
-<!--        用户订单-->
-<!--      </div>-->
-<!--      <userStorerDetails  ref="userDetails" />-->
-<!--    </div>-->
-
-<!--    <div class="contentx" v-if="item.userId != null" >-->
-<!--      <div class="desct">-->
-<!--        用户看客记录-->
-<!--      </div>-->
-<!--      <userCourseWatchLog  ref="userWatchLog" />-->
-<!--    </div>-->
   </div>
 </template>
 
@@ -172,17 +112,25 @@ import userStorerDetails from "@/views/qw/qwChat/userDetail/userStorerDetails.vu
 import userCourseWatchLog from "@/views/qw/qwChat/userDetail/userCourseWatchLog.vue";
 import userInfoEdit from "@/views/qw/qwChat/userDetail/userInfoEdit.vue";
 import courseManage from "@/views/qw/qwChat/userDetail/courseManage.vue";
-import remindCourseManage from "@/views/qw/qwChat/userDetail/remindCourseManage.vue";
 import {getQwExternalContactDetails, getQwUserInfo, queryCourseWatchStatistics} from "@/api/qw/im";
 
 export default {
   name: "userDetail",
+  props: {
+    extId: {
+      type: String,
+      default: null
+    },
+    extend: {
+      type: Boolean,
+      default: false
+    }
+  },
   components: {
     userStorerDetails,
     userCourseWatchLog,
     userInfoEdit,
     courseManage,
-    remindCourseManage
   },
   data() {
     // 定义颜色常量
@@ -195,7 +143,7 @@ export default {
     };
 
     return {
-      extId: null,
+      localExtId: this.extId,
       qwUserInfo: {},
       qwUserDetail: {},
       showDetail: true,
@@ -211,12 +159,23 @@ export default {
         { type: 4, text: '看课中断', color: logTypeColors.interrupted }
       ],
       showCourseManage: false,
-      showRemindCourseManage: false
+    }
+  },
+  created() {
+    if (this.extId) {
+      this.getDetail(this.extId)
+    }
+  },
+  watch: {
+    extId(newVal) {
+      if (newVal) {
+        this.getDetail(newVal);
+      }
     }
   },
   methods: {
     getDetail(extId) {
-      this.extId = extId
+      this.localExtId = extId
       this.getQwExternalContactDetails()
       this.getQwUserInfo()
       this.queryCourseWatchStatistics()
@@ -224,7 +183,7 @@ export default {
     queryCourseWatchStatistics() {
       const data = {
         type: 0,
-        qwExternalContactId: this.extId
+        qwExternalContactId: this.localExtId
       }
       queryCourseWatchStatistics(data).then(response => {
         this.courseWatch7day = response.data.data
@@ -232,15 +191,21 @@ export default {
     },
     getQwExternalContactDetails() {
       const query = {
-        qwExternalContactId: this.extId
+        qwExternalContactId: this.localExtId
       }
       getQwExternalContactDetails(query).then(response => {
         this.qwUserInfo = response.data
+        if (this.qwUserInfo.fsUserId) {
+          this.$nextTick(() => {
+            this.$refs.userDetails.getUserDetails(this.qwUserInfo.fsUserId)
+            this.$refs.userWatchLog.getUserWatchLog(this.qwUserInfo.fsUserId)
+          })
+        }
       })
     },
     getQwUserInfo() {
       const query = {
-        qwExternalContactId: this.extId
+        qwExternalContactId: this.localExtId
       }
       getQwUserInfo(query).then(response => {
         this.qwUserDetail = response.moreInfo
@@ -251,11 +216,10 @@ export default {
       this.showUpdate = true
     },
     handleBack() {
-      this.getQwUserInfo()
+      this.getDetail(this.localExtId)
       this.showDetail = true
       this.showUpdate = false
       this.showCourseManage = false
-      this.showRemindCourseManage = false
     },
     handleSaveSuccess() {
       this.handleBack()
@@ -288,10 +252,6 @@ export default {
       this.showDetail = false
       this.showCourseManage = true
     },
-    remindCourseManage() {
-      this.showDetail  = false
-      this.showRemindCourseManage = true
-    }
   }
 }
 </script>
@@ -360,4 +320,16 @@ export default {
   color: #909399;
   font-size: 14px;
 }
+.detail-description {
+  margin: 10px;
+  padding: 10px;
+  background-color: #FFF;
+}
+.detail-description-extend {
+  padding: 10px;
+  background-color: #FFF;
+}
+::v-deep .detail-description-extend .el-descriptions__title {
+  font-size: 14px;
+}
 </style>

+ 0 - 28
src/views/qw/qwChat/userDetail/remindCourseManage.vue

@@ -1,28 +0,0 @@
-<template>
-  <div>
-    <!-- 顶部标题栏 -->
-    <div>
-      <div style="position: relative; display: flex; align-items: center; justify-content: center; height: 48px; background: #fff; border-bottom: 1px solid #eee;">
-        <span style="position: absolute; left: 16px; cursor: pointer;" @click="handleBack">
-          <i class="el-icon-arrow-left" style="font-size: 20px; color: #333;"></i>
-        </span>
-        <span style="font-weight: bold; font-size: 16px;">催课面板</span>
-      </div>
-    </div>
-  </div>
-</template>
-
-<script>
-export default {
-  name: "remindCourseManage",
-  methods: {
-    handleBack() {
-      this.$emit("back");
-    }
-  }
-};
-</script>
-
-<style scoped>
-
-</style>

+ 17 - 238
src/views/qw/qwChat/userDetail/userCourseWatchLog.vue

@@ -1,15 +1,8 @@
 <template>
   <div class="apcontainer">
-
-    <el-tabs type="card" v-model="activeName" @tab-click="handleClickX">
-      <el-tab-pane label="全部" name="00"></el-tab-pane>
-      <el-tab-pane v-for="(item,index) in logTypeOptions" :label="item.dictLabel" :name="item.dictValue"></el-tab-pane>
-    </el-tabs>
-    <el-table border v-loading="loading" :data="courseWatchLogList" @selection-change="handleSelectionChange">
-      <el-table-column type="selection" width="55" align="center" />
+    <el-table border v-loading="loading" :data="courseWatchLogList">
       <el-table-column label="记录编号" align="center" prop="logId" />
       <el-table-column label="用户账号" align="center" prop="userName" />
-      <el-table-column label="企微客户" align="center" prop="externalUserName" v-if="queryParams.sourceType == 2"/>
       <el-table-column label="会员昵称" align="center" prop="fsNickName">
         <template slot-scope="scope">
           <div style="display: flex;white-space: nowrap">
@@ -29,17 +22,12 @@
       <el-table-column label="项目" align="center" prop="projectName" />
       <el-table-column label="课程名称" align="center" prop="courseName" />
       <el-table-column label="小节名称" align="center" prop="videoName" />
-      <el-table-column label="企微员工名称" align="center" prop="qwUserName" v-if="queryParams.sourceType == 2"/>
       <el-table-column label="记录类型" align="center" prop="logType">
         <template slot-scope="scope">
           <dict-tag :options="logTypeOptions" :value="scope.row.logType"/>
         </template>
       </el-table-column>
       <el-table-column label="播放时长" align="center" prop="duration" />
-      <el-table-column label="所属销售" align="center" prop="companyUserName" />
-      <!--      <el-table-column label="所属公司" align="center" prop="companyName" />-->
-      <!--      <el-table-column label="企微员工名称" align="center" prop="qwUserName" />-->
-      <el-table-column label="所属发送方式" align="center" prop="sendType" />
       <el-table-column label="创建时间" align="center" prop="createTime" />
       <el-table-column label="更新时间" align="center" prop="updateTime" />
       <el-table-column label="完课时间" align="center" prop="finishTime" />
@@ -58,135 +46,46 @@
 </template>
 
 <script>
-import { listCourseWatchLog, getCourseWatchLog, delCourseWatchLog, addCourseWatchLog, updateCourseWatchLog, exportCourseWatchLog } from "@/api/course/courseWatchLog";
-import {allList}from "@/api/company/company";
-import { courseList,videoList } from '@/api/course/courseRedPacketLog'
-import {getUserList} from "@/api/company/companyUser";
-import {getFsUserList} from "@/api/users/user";
+import { listCourseWatchLog } from "@/api/course/courseWatchLog";
+import {mapState} from "vuex";
 export default {
   name: "CourseWatchLog",
   data() {
     return {
-      userSourceTypeOptions: [],
       activeName:"00",
-      createTime:null,
-      updateTime:null,
-      courseLists:[],
-      videoList:[],
       logTypeOptions:[],
-      queryUserLoading: false,
       // 遮罩层
       loading: true,
-      // 导出遮罩层
-      exportLoading: false,
-      // 选中数组
-      ids: [],
-      // 非单个禁用
-      single: true,
-      // 非多个禁用
-      multiple: true,
-      // 显示搜索条件
-      showSearch: true,
       // 总条数
       total: 0,
-      companyUserList: [],
       // 短链课程看课记录表格数据
       courseWatchLogList: [],
-      fsUserList: [],
-      // 弹出层标题
-      title: "",
-      // 是否显示弹出层
-      open: false,
-
       // 查询参数
       queryParams: {
         pageNum: 1,
         pageSize: 10,
+        companyUserId: null,
         userId: null,
-        nickName: null,
-        videoId: null,
         logType: null,
-        qwExternalContactId: null,
-        externalUserName:null,
-        duration: null,
-        qwUserId: null,
-        companyUserId: null,
-        companyId: null,
-        courseId: null,
-        sTime:null,
-        eTime:null,
-        upSTime:null,
-        upETime:null,
-        scheduleStartTime: null,
-        scheduleEndTime: null,
-      },
-      // 表单参数
-      form: {},
-      // 表单校验
-      rules: {
       },
-      scheduleTime: null,
     };
   },
+  computed: {
+    ...mapState({
+      companyUserId: state => state.user.user.userId,
+    })
+  },
   created() {
-    courseList().then(response => {
-      this.courseLists = response.list;
-    });
-    this.getList();
     this.getDicts("sys_course_watch_log_type").then(response => {
       this.logTypeOptions = response.data;
     });
-    getUserList().then(res=>{
-      if(res.code === 200) {
-        this.companyUserList = res.data
-      }
-    })
-
-    getFsUserList({}).then(res=>{
-      if(res.code === 200) {
-        this.fsUserList = res.data
-      }
-    })
-
-    this.getDicts('user_source_type').then(response => {
-      this.userSourceTypeOptions = response.data;
-    })
-
-  },
-  computed: {
-    sourceTypeModel: {
-      get() {
-        return this.queryParams.sourceType !== null && this.queryParams.sourceType !== undefined ? this.queryParams.sourceType.toString() : null;
-      },
-      set(newVal) {
-        this.queryParams.sourceType = newVal;
-      }
-    }
+    this.queryParams.companyUserId = this.companyUserId
   },
   methods: {
     getUserWatchLog(id) {
       this.queryParams.userId = id
       this.getList()
     },
-    courseChange(row){
-      this.queryParams.videoId=null;
-      if(row === ''){
-        this.videoList=[];
-        return
-      }
-      videoList(row).then(response => {
-        this.videoList=response.list
-      });
-    },
-    handleClickX(tab,event){
-      this.activeName=tab.name;
-      if(tab.name=="00"){
-        this.queryParams.logType=null;
-      }else{
-        this.queryParams.logType=tab.name;
-      }
-      this.getList()
-    },
     /** 查询短链课程看课记录列表 */
     getList() {
       this.loading = true;
@@ -200,133 +99,13 @@ export default {
         this.loading = false;
       });
     },
-    // 取消按钮
-    cancel() {
-      this.open = false;
-      this.reset();
-    },
-    // 表单重置
-    reset() {
-      this.form = {
-        logId: null,
-        userId: null,
-        videoId: null,
-        logType: null,
-        createTime: null,
-        updateTime: null,
-        qwExternalContactId: null,
-        externalUserName:null,
-        duration: null,
-        qwUserId: null,
-        companyUserId: null,
-        companyId: null,
-        courseId: null,
-        scheduleStartTime: null,
-        scheduleEndTime: null,
-      };
-      this.scheduleTime=null;
-      this.resetForm("form");
-    },
-    /** 搜索按钮操作 */
-    handleQuery() {
-      this.queryParams.pageNum = 1;
-      this.getList();
-    },
-    /** 重置按钮操作 */
-    resetQuery() {
-      this.resetForm("queryForm");
-      this.createTime = null;
-      this.scheduleTime = null;
-      this.queryParams.sTime = null;
-      this.queryParams.eTime = null;
-      this.queryParams.upSTime = null;
-      this.queryParams.upETime = null;
-      this.queryParams.scheduleStartTime = null;
-      this.queryParams.scheduleEndTime = null;
-      this.scheduleTime=null;
-      this.updateTime=null;
-      this.handleQuery();
-    },
-    // 多选框选中数据
-    handleSelectionChange(selection) {
-      this.ids = selection.map(item => item.logId)
-      this.single = selection.length!==1
-      this.multiple = !selection.length
-    },
-    /** 新增按钮操作 */
-    handleAdd() {
-      this.reset();
-      this.open = true;
-      this.title = "添加短链课程看课记录";
-    },
-    /** 修改按钮操作 */
-    handleUpdate(row) {
-      this.reset();
-      const logId = row.logId || this.ids
-      getCourseWatchLog(logId).then(response => {
-        this.form = response.data;
-        this.open = true;
-        this.title = "修改短链课程看课记录";
-      });
-    },
-    /** 提交按钮 */
-    submitForm() {
-      this.$refs["form"].validate(valid => {
-        if (valid) {
-          if (this.form.logId != null) {
-            updateCourseWatchLog(this.form).then(response => {
-              this.msgSuccess("修改成功");
-              this.open = false;
-              this.getList();
-            });
-          } else {
-            addCourseWatchLog(this.form).then(response => {
-              this.msgSuccess("新增成功");
-              this.open = false;
-              this.getList();
-            });
-          }
-        }
-      });
-    },
-    /** 删除按钮操作 */
-    handleDelete(row) {
-      const logIds = row.logId || this.ids;
-      this.$confirm('是否确认删除短链课程看课记录编号为"' + logIds + '"的数据项?', "警告", {
-        confirmButtonText: "确定",
-        cancelButtonText: "取消",
-        type: "warning"
-      }).then(function() {
-        return delCourseWatchLog(logIds);
-      }).then(() => {
-        this.getList();
-        this.msgSuccess("删除成功");
-      }).catch(() => {});
-    },
-    /** 导出按钮操作 */
-    handleExport() {
-      const queryParams = this.queryParams;
-      this.$confirm('是否确认导出所有短链课程看课记录数据项?', "警告", {
-        confirmButtonText: "确定",
-        cancelButtonText: "取消",
-        type: "warning"
-      }).then(() => {
-        this.exportLoading = true;
-        return exportCourseWatchLog(queryParams);
-      }).then(response => {
-        this.download(response.msg);
-        this.exportLoading = false;
-      }).catch(() => {});
-    },
-    handleScheduleTimeChange(val) {
-      if (val) {
-        this.queryParams.scheduleStartTime = val[0];
-        this.queryParams.scheduleEndTime = val[1];
-      } else {
-        this.queryParams.scheduleStartTime = null;
-        this.queryParams.scheduleEndTime = null;
-      }
-    },
   }
 };
 </script>
+
+<style scoped>
+.apcontainer {
+  padding: 10px;
+  font-size: 12px;
+}
+</style>

+ 2 - 7
src/views/qw/qwChat/userDetail/userInfoEdit.vue

@@ -11,11 +11,6 @@
     </div>
     <!-- 表单内容 -->
     <div class="user-form">
-      <div class="form-row">
-        <div class="form-label">姓名</div>
-        <div class="form-input">
-        </div>
-      </div>
       <div class="form-row">
         <div class="form-label">性别</div>
         <div class="form-input">
@@ -127,11 +122,11 @@
         </div>
       </div>
       <div class="form-row">
-        <div class="form-label">是否已产品</div>
+        <div class="form-label">是否已购产品</div>
         <div class="form-input">
           <input
             v-model="formData.isBuy"
-            placeholder="请输入是否已产品"
+            placeholder="请输入是否已购产品"
             class="input"
             type="text"
           />

+ 47 - 269
src/views/qw/qwChat/userDetail/userStorerDetails.vue

@@ -1,13 +1,7 @@
 <template>
   <div class="aacontainer">
-
-    <el-tabs type="card" v-model="actName" @tab-click="handleClickX">
-      <el-tab-pane label="全部订单" name="10"></el-tab-pane>
-      <el-tab-pane v-for="(item,index) in orderOptions" :label="item.dictLabel" :name="item.dictValue"></el-tab-pane>
-    </el-tabs>
     <el-table v-loading="loading" :data="orderList" border>
       <el-table-column label="订单号" align="center" prop="orderCode" width="180px"/>
-      <el-table-column label="所属店铺" align="center" prop="storeName" width="180px"/>
       <el-table-column label="用户昵称" align="center" prop="nickName" show-overflow-tooltip width="100px"/>
       <el-table-column label="收货人" align="center" prop="userName" />
       <el-table-column label="医生姓名" align="center" prop="doctorName" />
@@ -50,14 +44,18 @@
       </el-table-column>
       <el-table-column label="处方编号" align="center" prop="prescribeCode" width="170px"/>
       <el-table-column label="发货时间" align="center" prop="deliveryTime" />
-      <el-table-column label="推广佣金" align="center" prop="tuiMoney" />
-      <el-table-column label="推广佣金状态" align="center" prop="tuiMoneyStatus" >
-        <template slot-scope="scope">
-              <dict-tag :options="tuiOptions" :value="scope.row.tuiMoneyStatus"/>
-         </template>
-      </el-table-column>
       <el-table-column label="创建时间" align="center" prop="createTime"  width="150px"/>
       <el-table-column label="修改时间" align="center" prop="updateTime"  width="150px"/>
+      <el-table-column label="操作" fixed="right" width="100px" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            @click="handleDetails(scope.row)"
+            v-hasPermi="['store:storeOrder:query']"
+          >查看</el-button>
+        </template>
+      </el-table-column>
     </el-table>
 
     <pagination
@@ -68,116 +66,58 @@
       @pagination="getList"
     />
 
-
-
+    <el-drawer
+      size="75%"
+      :title="show.title" :visible.sync="show.open"
+      :modal="false"
+    >
+      <product-order  ref="order" />
+    </el-drawer>
   </div>
 </template>
 
 <script>
-import {
-  listStoreOrder,
-  getStoreOrder,
-  delStoreOrder,
-  addStoreOrder,
-  updateStoreOrder,
-  exportStoreOrder,
-} from "@/api/store/storeOrder";
+import {listStoreOrder} from "@/api/store/storeOrder";
+import productOrder from "@/views/store/components/productOrder.vue";
+import {mapState} from "vuex";
 export default {
   name: "userInquir",
+  components: {productOrder},
   props:["data"],
   data() {
     return {
       actName:"10",
-      show:{
-              title:"订单详情",
-              open:false,
-            },
       // 遮罩层
       loading: true,
-      // 导出遮罩层
-      exportLoading: false,
-      // 选中数组
-      ids: [],
-      // 非单个禁用
-      single: true,
-      // 非多个禁用
-      multiple: true,
-      // 显示搜索条件
-      showSearch: true,
       // 总条数
       total: 0,
       // 订单表格数据
       orderList: [],
-      // 弹出层标题
-      title: "",
-      createTime:null,
-      payTime:null,
-      // 是否显示弹出层
-      open: false,
       // 查询参数
       queryParams: {
         pageNum: 1,
         pageSize: 10,
-        storeId: null,
-        orderCode: null,
+        companyUserId: null,
         userId: null,
-        userName: null,
-        userPhone: null,
-        userAddress: null,
-        cartId: null,
-        totalNum: null,
-        totalPrice: null,
-        payPrice: null,
-        payMoney: null,
-        isPay: null,
-        payTime: null,
-        payType: null,
         status: null,
-        refundStatus: null,
-        refundImg: null,
-        refundExplain: null,
-        refundTime: null,
-        refundReason: null,
-        refundMoney: null,
-        deliveryCode: null,
-        deliveryName: null,
-        deliverySn: null,
-        isDel: null,
-        costPrice: null,
-        verifyCode: null,
-        shippingType: null,
-        isChannel: null,
-        isPrescribe: null,
-        prescribeId: null,
-        finishTime: null,
-        patientName: null,
-        doctorName: null,
-        sTime:null,
-        eTime:null,
-        paysTime:null,
-        payeTime:null,
-        deliveryTime: null,
-        tuiMoney: null,
-        tuiMoneyStatus: null,
-        tuiUserId: null,
-        orderCreateType: null
-      },
-      // 表单参数
-      form: {},
-      // 表单校验
-      rules: {
       },
        PayOptions:[],
        orderOptions:[],
        payStatusOptions:[],
        refundOptions:[],
-       channelOptions:[],
        orderTypeOptions:[],
-       tuiOptions:[],
        orOptions:[],
-       storeOPtions:[],
+      show: {
+        title: "订单详情",
+        open: false
+      }
     };
   },
+  computed: {
+    ...mapState({
+      companyUserId: state => state.user.user.userId,
+    })
+  },
   created() {
     this.getDicts("sys_inquiry_pay").then(response => {
         this.PayOptions = response.data;
@@ -194,23 +134,16 @@ export default {
     this.getDicts("sys_refund_status").then(response => {
         this.refundOptions = response.data;
       });
-    this.getDicts("sys_channel").then(response => {
-        this.channelOptions = response.data;
-      });
-    this.getDicts("sys_tui_money_status").then(response => {
-          this.tuiOptions = response.data;
-        });
     this.getDicts("sys_company_or").then(response => {
           this.orOptions = response.data;
         });
+    this.queryParams.companyUserId = this.companyUserId
   },
   methods: {
-    getUserDetails(id){
-      this.queryParams.userId=id
+    getUserDetails(id) {
+      this.queryParams.userId = id
       this.getList();
     },
-
-
     /** 查询订单列表 */
     getList() {
       this.loading = true;
@@ -221,175 +154,20 @@ export default {
       });
 
     },
-    // 取消按钮
-    cancel() {
-      this.open = false;
-      this.reset();
-    },
-    // 表单重置
-    reset() {
-      this.form = {
-        orderId: null,
-        storeId: null,
-        orderCode: null,
-        userId: null,
-        userName: null,
-        userPhone: null,
-        userAddress: null,
-        cartId: null,
-        totalNum: null,
-        totalPrice: null,
-        payPrice: null,
-        payMoney: null,
-        isPay: null,
-        payTime: null,
-        payType: null,
-        createTime: null,
-        updateTime: null,
-        status: null,
-        refundStatus: "0",
-        refundImg: null,
-        refundExplain: null,
-        refundTime: null,
-        refundReason: null,
-        refundMoney: null,
-        deliveryCode: null,
-        deliveryName: null,
-        deliverySn: null,
-        remark: null,
-        isDel: null,
-        costPrice: null,
-        verifyCode: null,
-        shippingType: null,
-        isChannel: null,
-        isPrescribe: null,
-        prescribeId: null,
-        finishTime: null,
-        deliveryTime: null,
-        tuiMoney: null,
-        tuiMoneyStatus: 0,
-        tuiUserId: null,
-        orderCreateType: null
-      };
-      this.resetForm("form");
-    },
-    /** 搜索按钮操作 */
-    handleQuery() {
-      this.queryParams.pageNum = 1;
-      this.getList();
-    },
-   handleClickX(tab, event) {
-    if(tab.name=="10"){
-      this.queryParams.status=null;
-    }else{
-      this.queryParams.status=tab.name;
-    }
-     this.handleQuery();
-   },
-  changeTime(){
-        if(this.createTime!=null){
-          this.queryParams.sTime=this.createTime[0];
-          this.queryParams.eTime=this.createTime[1];
-        }else{
-          this.queryParams.sTime=null;
-          this.queryParams.eTime=null;
-        }
-
-      },
-  changePayTime(){
-      if(this.payTime!=null){
-        this.queryParams.sTime=this.payTime[0];
-        this.queryParams.eTime=this.payTime[1];
-      }else{
-        this.queryParams.paysTime=null;
-        this.queryParams.payeTime=null;
-      }
-
-    },
-
-
-    /** 重置按钮操作 */
-    resetQuery() {
-      this.resetForm("queryForm");
-       this.createTime=null;
-      this.queryParams.sTime=null;
-      this.queryParams.eTime=null;
-       this.payTime=null;
-      this.queryParams.paysTime=null;
-      this.queryParams.payeTime=null;
-      this.handleQuery();
-    },
-    // 多选框选中数据
-    handleSelectionChange(selection) {
-      this.ids = selection.map(item => item.orderId)
-      this.single = selection.length!==1
-      this.multiple = !selection.length
-    },
-    /** 新增按钮操作 */
-    handleAdd() {
-      this.reset();
-      this.open = true;
-      this.title = "添加订单";
-    },
-    /** 修改按钮操作 */
-    handleUpdate(row) {
-      this.reset();
-      const orderId = row.orderId || this.ids
-      getStoreOrder(orderId).then(response => {
-        this.form = response.data;
-        this.open = true;
-        this.title = "修改订单";
-      });
+    handleDetails(row){
+      this.show.open=true;
+      const orderId = row.id ;
+      setTimeout(() => {
+        this.$refs.order.getOrder(orderId);
+      }, 500);
     },
-    /** 提交按钮 */
-    submitForm() {
-      this.$refs["form"].validate(valid => {
-        if (valid) {
-          if (this.form.orderId != null) {
-            updateStoreOrder(this.form).then(response => {
-              this.msgSuccess("修改成功");
-              this.open = false;
-              this.getList();
-            });
-          } else {
-            addStoreOrder(this.form).then(response => {
-              this.msgSuccess("新增成功");
-              this.open = false;
-              this.getList();
-            });
-          }
-        }
-      });
-    },
-    /** 删除按钮操作 */
-    handleDelete(row) {
-      const orderIds = row.orderId || this.ids;
-      this.$confirm('是否确认删除订单编号为"' + orderIds + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return delStoreOrder(orderIds);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(() => {});
-    },
-    /** 导出按钮操作 */
-    handleExport() {
-      const queryParams = this.queryParams;
-      this.$confirm('是否确认导出所有订单数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportStoreOrder(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
-    }
   }
 };
 </script>
+
+<style scoped>
+.aacontainer {
+  padding: 10px;
+  font-size: 12px;
+}
+</style>

+ 1 - 1
src/views/qw/sop/addSop.vue

@@ -774,7 +774,7 @@ export default {
     //查询模板
     selectListSopTemp(type) {
       if(this.form.filterMode == 2){
-        type = 5;
+        type = 11;
       }
       this.tempOpen = true;
       setTimeout(() => {

+ 2 - 2
src/views/qw/user/index.vue

@@ -355,9 +355,9 @@
       :visible.sync="qwCode.open"
       width="600px"
       append-to-body>
-      <el-form  :model="qwCode"  label-width="80px" @submit.native.prevent="handleSubmit">
+      <el-form  :model="qwCode"  label-width="80px" @submit.native.prevent="submitCodeForm">
         <el-form-item label="验证码" prop="companyName">
-          <el-input v-model="qwCode.code" placeholder="输入企微6位验证码" />
+          <el-input v-model="qwCode.code" @input="validateCode" placeholder="输入企微6位验证码" />
         </el-form-item>
       </el-form>
 

+ 17 - 20
src/views/store/components/addUserAddress.vue

@@ -95,44 +95,41 @@ export default {
   },
   methods: {
     districtChange(val){
-      var item=this.citys.find((item)=>{
-        return item.cityId==val;
-      })
-      console.log(item)
+      const item = this.district.find(i => i.cityId === val)
       this.form.district=item.name;
-
     },
     cityChange(val){
-      this.district=this.citys.filter(item => item.parentId===val )
+      const item = this.city.find(i => i.cityId === val)
+      this.district = item.children
       this.form.district=null;
-      var item=this.citys.find((item)=>{
-        return item.cityId==val;
-      })
-      console.log(item)
       this.form.city=item.name;
       this.form.cityId=val;
-
     },
     provinceChange(val){
-      console.log(val)
-      this.city=this.citys.filter(item => item.parentId===val )
+      const item = this.citys.find(i => i.cityId === val)
+      this.city = item.children
       this.district=[];
       this.form.city=null;
       this.form.district=null;
-      var item=this.citys.find((item)=>{
-        return item.cityId==val;
-      })
-      console.log(item)
       this.form.province=item.name;
     },
     getCityList(){
       getCitys().then(res => {
           this.loading = false;
-          this.citys=res.data;
-          console.log("this.citys",this.citys)
-          this.province=res.data.filter(item => item.level===0 )
+          this.citys = this.convertCityData(res.data)
+          this.province=this.citys.filter(item => item.parentId===0 )
         })
     },
+    convertCityData(array) {
+      return array.map(item => {
+        return {
+          'cityId': item.value,
+          'name': item.label,
+          'parentId':  item.pid,
+          'children': item.children && this.convertCityData(item.children)
+        }
+      });
+    },
     init(userId){
       this.form.userId=userId;
     },