wansfa 1 year ago
parent
commit
5ccc907af6

+ 583 - 0
src/components/LemonUI/components/chatrecords/basic.vue

@@ -0,0 +1,583 @@
+<template>
+<div>
+
+    <el-dialog   :visible.sync="dialogVisible" width="70%">
+        <div class="app-container">  
+             <el-form ref="form" :model="form" :inline="true"  label-width="80px">
+                <el-row>
+                    <el-col :span="22">
+                        <el-form-item label="搜索内容" prop="content" style="width:100%" >
+                            <el-input @input="serchInput"  style="width:100%"  v-model="form.content"  placeholder="请输入搜索消息内容"  clearable />
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span="2">
+                        <el-form-item >
+                            <el-button type="primary" @click="handleQuery">搜索</el-button>
+                        </el-form-item>
+                    </el-col>
+                 </el-row>
+              </el-form>
+
+             <el-tabs v-model="activeName" @tab-click="handleTabClick">
+                <el-tab-pane label="全部" name="first">
+                    <SegRecords :qwUser="qwUser" :conversationId="conversationId" :conversationData="conversationData" :msgType=0  ref="sIMUI0" v-show="!showSearch"></SegRecords>
+                 
+                    <SegRecords :qwUser="qwUser" :conversationId="conversationId" :conversationData="conversationData" :msgType=0  ref="sIMUI"  @showContextBox="showContextBox"  v-show="showSearch"  ></SegRecords>
+                </el-tab-pane>
+
+                <el-tab-pane label="图片与视频" name="second">
+                     <SegRecords :qwUser="qwUser" :conversationId="conversationId" :conversationData="conversationData" :msgType=1   ref="sIMUI1"></SegRecords>
+                </el-tab-pane>
+
+                <el-tab-pane label="语音" name="third">
+                    <SegRecords :qwUser="qwUser" :conversationId="conversationId" :conversationData="conversationData"  :msgType=2  ref="sIMUI2"></SegRecords>
+                </el-tab-pane>
+
+                <el-tab-pane label="文件" name="fourth">
+                    <SegRecords :qwUser="qwUser" :conversationId="conversationId" :conversationData="conversationData" :msgType=3  ref="sIMUI3"></SegRecords>
+                </el-tab-pane>
+            </el-tabs>
+          
+        </div>
+    </el-dialog>
+
+     <el-dialog :visible.sync="dialogContextVisible" width="70%">
+            <SegRecords :qwUser="qwUser" :conversationId="conversationId" :conversationData="conversationData" :isContext=true :msgType=0  ref="sIMUI4"></SegRecords>
+      </el-dialog>
+
+
+</div>
+
+</template>
+
+<script>
+
+  import LemonMessageVoice from "@/components/LemonUI/components/message/voice";
+  import { getContactsByUser,getConversations,getMessageList,getConversation,sendTextMsg,sendImageMsg,getRoomInfo} from '@/api/qw/im';
+  import Conversations from "@/components/LemonUI/database/conversations";
+  import EmojiData from "@/components/LemonUI/database/emoji";
+  import '@/components/LemonUI/index.css';
+  import VideoPlayer from '@/components/VideoPlayer/VueAliplayer'
+  import SegRecords from './segrecords.vue'
+  let pages = {};
+  export default {
+       name: "ChatRecords",
+       components: {   
+          VideoPlayer,
+          SegRecords
+       },
+       props: {
+            qwUser: {
+                type: Object,
+                default: () => {
+                    return {
+                          //"userId":1688854331463712,"avatar":"https://wework.qpic.cn/wwpic/258414_QSUkkN5rTMGzwIc_1692169272/0","corpId":1970326754004217,"corpName":"重庆润方数字科技","nickName":"秦先觉","deviceId":"aeff5e72448d4d299e03d7291a21c2ea","phone":null,"account":"1261818888"
+                     };
+                },
+          },
+       },
+       data(){
+           return {
+                activeName: 'first',
+                dialogVisible:false,
+                dialogContextVisible:false,
+                theme: "default",
+                IMUI:null,
+                hideMenuAvatar: false,
+                hideMenu: false,
+                hideMessageName: false,
+                hideMessageTime: true,
+                showSearch:false,
+                UserData: {
+                    id: "1000",
+                    displayName: "June",
+                    avatar: "https://p.qqan.com/up/2018-4/15244505348390471.jpg",
+                },
+                contactData:null,
+                conversationId:null,
+                conversationData:null,
+                isFromLogin:false,
+                dialogImgVisible:false,
+                dialogImageUrl: '',
+                dialogVideoVisible:false, 
+                dialogVideoUrl:'',
+                dialogVideoCover:'',
+                imageArr:[],
+                pickUploadImgData:null,
+                aplayer: {
+                    vid: "bf9b7e4a36d84aea8cee769765fbc28b",
+                    pWidth:"1040px",
+                    width:"1000px",
+                    height:"900px",
+                    videoWidth:"1000px",
+                    videoHeight:"900px"
+                },
+                player: null,
+                roomMembers:[],
+                roomAdmins:[],
+                roomInfo:null,
+                windowWidth: document.documentElement.clientWidth*0.95,  //实时屏幕宽度
+                windowHeight: document.documentElement.clientHeight*0.7,   //实时屏幕高度
+                queryParams: {
+                    pageNum: 1,
+                    pageSize: 10,
+                    conversationId: null,
+                },
+                form: { content:"" },
+                // 表单校验
+                rules: {
+                    content: [
+                        { required: true, message: "请输入关键字", trigger: "blur" }
+                    ],
+                }
+           }
+       },
+       created(){
+           
+       },
+       mounted(){
+           
+       },
+       methods: {
+                handleTabClick(tab, event){
+                    console.log(tab,tab.index);
+                    const sIMUI = this.$refs["sIMUI"+tab.index];
+                    sIMUI.open();
+                },
+                serchInput(value){
+                   this.showSearch=value!="";
+                   if(value!=""){
+                        const sIMUI = this.$refs["sIMUI"];
+                        sIMUI.openSearch(value);
+                   }else{
+                   }
+                   console.log("qxj serchInput:"+JSON.stringify(value));
+                },
+                /** 搜索按钮操作 */
+                handleQuery() {
+                    if(this.form.content!=""){
+                         const sIMUI = this.$refs["sIMUI"];
+                         sIMUI.openSearch(this.form.content);
+                    }
+                },
+                showContextBox(message){
+                    this.dialogContextVisible=true;
+                    setTimeout(() => {
+                         const sIMUI = this.$refs["sIMUI4"];
+                         console.log("点击了上下文", sIMUI);
+                         sIMUI.openContextBox(message);
+                    }, 50);
+                },
+                init(){
+                     this.deviceId=this.qwUser.deviceId;
+                     this.UserData.id=this.qwUser.userId;
+                     this.UserData.displayName=this.qwUser.nickName;
+                     this.UserData.avatar=this.qwUser.avatar;
+                     const IMUI = this.$refs.IMUI;
+                    //IMUI.changeContact(this.queryParams.conversationId);
+                    //this.getContacts();  //获取联系人信息
+                    this.getConversation();   //获取会话信息
+                    ////IMUI.initEmoji(EmojiData); 
+                },
+                open(qwUser,conversationId,conversationData){
+                     this.dialogVisible=true;
+                     var converChanged=this.conversationId!=conversationId;
+                     this.qwUser=qwUser;
+                     this.conversationId=conversationId;
+                     this.conversationData=conversationData;
+                     this.queryParams.conversationId=conversationId;
+                     setTimeout(() => {
+                         const sIMUI = this.$refs.sIMUI0;
+                         sIMUI.open(converChanged);
+                    }, 50);
+
+                },
+                getRoomInfo(roomId){
+                    getRoomInfo(roomId).then(response => {
+                        this.roomMembers=response.members;
+                        this.admins=response.members;
+                        this.roomInfo=response.detail;
+                    });
+                },
+                getContacts(){  
+                    getContactsByUser(this.qwUser.userId).then(response => {
+                        this.contactData = response.data;
+                        this.$refs.IMUI.initContacts(this.contactData);
+                        
+                    });
+                },
+                getConversation(){
+                    let that=this;
+                    const IMUI = this.$refs.IMUI;
+                    //getConversations(this.qwUser.userId).then(response => {
+                    //this.conversationData = response.data;
+                        IMUI.initConversations(this.conversationData);
+                        var fstConversation=this.conversationData[0];
+                        if(fstConversation){
+                            IMUI.changeContact(fstConversation.conversationId);
+                        }
+                    //});
+                },
+                messageTimeFormat(time) {
+                   return this.friendlyDate(time);
+                },
+                changeTheme() {
+                  this.theme = this.theme == "default" ? "blue" : "default";
+                },
+                scrollToTop() {
+                  document.body.scrollIntoView();
+                },
+                openDrawer(position) {
+                        const IMUI = this.$refs.IMUI;
+                        const params = {
+                            position,
+                            render: contact => {
+                            return (
+                                <div style="padding:15px">
+                                <h5>{contact.displayName}</h5>
+                                <span style="cursor:pointer;" on-click={IMUI.closeDrawer}>关闭抽屉</span>
+                                </div>
+                            );
+                            },
+                };
+                if (position == "center") {
+                    params.width = "50%";
+                    params.height = "50%";
+                } else if (position == "rightInside") {
+                    params.height = "90%";
+                    params.offsetY = "10%";
+                }
+                this.IMUI.openDrawer(params);
+                },
+                handlePullMessages(contact, next,instance) {
+                    const { IMUI } = this.$refs;
+                    let isEnd = false;
+                    getMessageList(this.queryParams).then(response => {
+                        if(response.code==200){
+                            isEnd=response.data.isLastPage;
+                            next(response.data.list, isEnd);
+                            if(!isEnd){
+                                pages[contact.conversationId]++;
+                            }
+                        }
+                    });
+                },
+                handleChangeConversation(conversation, instance) {
+                    console.log("qxj ChangeConversation:"+JSON.stringify(conversation));
+                    if (!pages[conversation.conversationId]){
+                        pages[conversation.conversationId] =1;
+                    }
+                    this.queryParams.pageNum=pages[conversation.conversationId];
+                    this.queryParams.conversationId=conversation.conversationId;
+                    if(conversation.unread>0){
+                        conversation.unread=0;
+                        instance.updateContact(conversation);
+                    }
+                    instance.closeDrawer();
+                },
+                handleChangeContact(contact, instance) {
+
+                },
+                //收到消息后添加消息显示
+                appendMessageAction(msgData){
+                    if(msgData.type=="text" || msgData.type=="image" || msgData.type=="voice"){     //文本   text  image  video  voice 
+                        const message = {
+                                id: msgData.id,
+                                status: msgData.status,
+                                type: msgData.type,
+                                sendTime: msgData.sendTime,
+                                content: msgData.content,
+                                params1: "1",
+                                params2: "2",
+                                toContactId: msgData.toContactId,
+                                fromUser: msgData.fromUser,
+                        };
+                        this.appendRemoteMessage(message);
+                    }
+                    else if(msgData.type=="file"){
+                        const message = {
+                                id: msgData.id,
+                                status: msgData.status,
+                                type: msgData.type,
+                                sendTime: msgData.sendTime,
+                                content: msgData.content,
+                                toContactId: msgData.toContactId,
+                                fromUser: msgData.fromUser,
+                                fileName:msgData.fileName,
+                                fileSize:msgData.fileSize
+                        };
+                        this.appendRemoteMessage(message);
+                    }
+                    else{
+                        const message = {
+                                id: msgData.id,
+                                status: msgData.status,
+                                type: msgData.type,
+                                sendTime: msgData.sendTime,
+                                content: msgData.content,
+                                toContactId: msgData.toContactId,
+                                fromUser: msgData.fromUser,
+                        };
+                        this.appendRemoteMessage(message);
+                    }
+                },
+                handleMenuAvatarClick() {
+                console.log("Event:menu-avatar-click");
+                },
+                //聊天工具栏点击图片
+                handleImageClick() { 
+                
+                },
+                //选择图片框确定按钮回调
+                handlePickImageDone(data){
+                    console.log("handlePickImageDone:"+JSON.stringify(data));
+                    this.pickUploadImgData=data;
+                    const IMUI = this.$refs.IMUI;
+                    IMUI._handleRemoteImage(data.url);
+                },
+                tooglePlayVideo(data){
+                    this.dialogVideoVisible=true;
+                    this.dialogVideoUrl=data.content;
+                    this.dialogVideoCover=data.url;
+                    const player = this.$refs.player.instance
+                    player && player.play()
+                },
+                handleMessageClick(e, key, message, instance) {
+                    console.log("点击了消息", e, key, message);
+                    //console.log("qxj message:"+JSON.stringify(message));
+                    if(message.type=="image"){
+                        var url=!!message.url?message.url:message.content;
+                        this.handlePicturePreview(url);
+                    }
+                    else if(message.type=="video"){  
+                        this.tooglePlayVideo(message);
+                    }
+                    else if(message.type=="file"){  
+                        
+                    }
+                    if (key == "status") {
+                        instance.updateMessage({
+                        id: message.id,
+                        status: "going",
+                        content: "正在重新发送消息...",
+                        });
+                        setTimeout(() => {
+                        instance.updateMessage({
+                            id: message.id,
+                            status: "succeed",
+                            content: "发送成功",
+                        });
+                        }, 2000);
+                    }
+                },
+
+                changeMenuAvatarVisible() {
+                   this.hideMenuAvatar = !this.hideMenuAvatar;
+                },
+                changeMenuVisible() {
+                   this.hideMenu = !this.hideMenu;
+                },
+                changeMessageNameVisible() {
+                   this.hideMessageName = !this.hideMessageName;
+                },
+                changeMessageTimeVisible() {
+                   this.hideMessageTime = !this.hideMessageTime;
+                },
+                removeMessage() {
+                    const { IMUI } = this.$refs;
+                    const messages = IMUI.getCurrentMessages();
+                    const id = messages[messages.length - 1].id;
+                    if (messages.length > 0) {
+                        IMUI.removeMessage(id);
+                    }
+                },
+                updateMessage() {
+                    const { IMUI } = this.$refs;
+                    const messages = IMUI.getCurrentMessages();
+                    const message = messages[messages.length - 1];
+                    if (messages.length > 0) {
+                        const update = {
+                        id: message.id,
+                        status: "succeed",
+                        type: "file",
+                        fileName: "被修改成文件了.txt",
+                        fileSize: "4200000",
+                        };
+                        if (message.type == "event") {
+                        update.fromUser = this.user;
+                        }
+                        IMUI.updateMessage(update);
+                        IMUI.messageViewToBottom();
+                }
+                },
+                appendCustomMessage() {
+                    const { IMUI } = this.$refs;
+                    const message = {
+                        id: generateRandId(),
+                        status: "succeed",
+                        type: "voice",
+                        sendTime: getTime(),
+                        content: "语音消息",
+                        params1: "1",
+                        params2: "2",
+                        toContactId: "contact-1",
+                        fromUser: this.user,
+                    };
+                    IMUI.appendMessage(message, true);
+                },
+                appendMessage() {
+                    const { IMUI } = this.$refs;
+                    const contact = IMUI.currentContact;
+                    const message = generateMessage("contact-3");
+                    message.fromUser = {
+                        ...message.fromUser,
+                        ...this.user,
+                    };
+                    IMUI.appendMessage(message, true);
+                    console.log("🚀 ~ file: App.vue ~ line 1508 ~ appendMessage ~ message", message)
+                },
+                appendEventMessage() {
+                    const { IMUI } = this.$refs;
+                    const message = {
+                        id: generateRandId(),
+                        type: "event",
+                        content: (
+                        <span>
+                            邀请你加入群聊{" "}
+                            <span
+                            style="color:#333;cursor:pointer"
+                            on-click={() => alert("OK")}>
+                            接受
+                            </span>
+                        </span>
+                        ),
+                        toContactId: "contact-3",
+                        sendTime: getTime(),
+                    };
+                    IMUI.appendMessage(message, true);
+                },
+                appendRemoteMessage(message) {  //从服务端返回的消息
+                    const { IMUI } = this.$refs;
+                    IMUI.appendMessage(message, true);
+                },
+                updateContact() {
+                    this.$refs.IMUI.updateContact({
+                        id: "contact-3",
+                        unread: 10,
+                        displayName: generateRandWord(),
+                        lastSendTime: getTime(),
+                        lastContent: "修改昵称为随机字母",
+                     });
+                },
+                handleChangeMenu() {
+                     console.log("Event:change-menu");
+                },
+                openCustomContainer() {
+
+                },
+                handlePicturePreview(url) {
+                    this.dialogImageUrl = url;
+                    this.dialogImgVisible=true;
+                },
+       }
+  }
+
+</script>
+
+
+
+<style lang="scss" scoped>
+    .app-container{
+       padding-top:0;
+    }
+    .imui-center{
+        margin-bottom:"60px"; 
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        // height: 80vh;
+    }
+    .lemon-wrapper{
+        border:"1px solid #ddd";
+        height: "60%" !important;
+    }
+    .lemon-drawer{
+        border:"1px solid #ddd";
+        border-left:"0";
+    }
+    .more {
+        font-size: 12px;
+        line-height: 24px;
+        height: 24px;
+        position: absolute;
+        top: 14px;
+        right: 14px;
+        cursor: pointer;
+        -webkit-user-select: none;
+        -moz-user-select: none;
+        -ms-user-select: none;
+        user-select: none;
+        color: #f1f1f1;
+        display: inline-block;
+        border-radius: 4px;
+        background: #111;
+        padding: 0 8px;
+    }
+
+    /deep/.el-dialog__headerbtn{
+         top:10px;
+    }
+
+    /deep/.el-form--inline .el-form-item{
+        display: flex;
+    }
+    /deep/.el-form-item--medium .el-form-item__content{
+        flex: 1;
+        margin-right: 20px;
+    }
+
+    /deep/.el-dialog:not(.is-fullscreen) {
+        margin-top: 0 !important;
+    }
+
+    // /deep/.el-dialog__header{
+    //     padding-bottom: 0;
+    // }
+    
+</style>
+
+
+<style lang="stylus">
+   .lemon-container__title
+     padding-bottom:10px;
+   .slot-group
+      width:200px;
+      .slot-group-title
+        padding:0 0 10px 0;
+        .slot-group-notice
+           padding: 10px 10px;
+     
+      .slot-search
+           width:calc(100% - 20px) ;
+           margin:5px 10px;
+           padding:3px 0px;
+
+      .slot-group-member
+          display: flex;
+          padding: 5px 0;
+          flex:1;
+          font-size: 14px;
+          align-items: center;
+          .avatar
+              width: 30px;
+              height: 30px;
+              line-height: 30px;
+              margin-right:5px;
+              img 
+                vertical-align: middle;
+                border-style: none;
+                width: 100%;
+                height: 100%;
+                line-height: 30px;
+                border-radius: 50%;
+</style>

+ 592 - 0
src/components/LemonUI/components/chatrecords/basic1.vue

@@ -0,0 +1,592 @@
+<template>
+<div>
+
+    <el-dialog   :visible.sync="dialogVisible" width="70%">
+        <div class="app-container">  
+             <el-form ref="form" :model="form" :inline="true"  label-width="80px">
+                <el-row>
+                    <el-col :span="22">
+                        <el-form-item label="搜索内容" prop="content" style="width:100%" >
+                            <el-input  style="width:100%"  v-model="form.content"  placeholder="请输入搜索消息内容" />
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span="2">
+                        <el-form-item >
+                            <el-button type="primary" @click="handleQuery">搜索</el-button>
+                        </el-form-item>
+                    </el-col>
+                 </el-row>
+              </el-form>
+
+            <div class="imui-center qq-lemon-imui">
+                <lemon-records  class="lemon-slot"  
+                    :width="windowWidth"
+                    :height="windowHeight"
+                    :user="UserData"
+                    ref="IMUI"  
+                    :theme="theme"
+                    :hide-menu="hideMenu"
+                    :hide-menu-avatar="hideMenuAvatar"
+                    :hide-message-name="hideMessageName"
+                    :hide-message-time="hideMessageTime"
+                    :messageTimeFormat="messageTimeFormat"
+                    @change-menu="handleChangeMenu"
+                    @pull-messages="handlePullMessages"
+                    @change-contact="handleChangeContact"
+                    @change-conversation="handleChangeConversation"
+                    @message-click="handleMessageClick"
+                    @menu-avatar-click="handleMenuAvatarClick"
+                    @pick-image="handleImageClick">
+
+                    <template #cover>
+                            <div class="cover">
+                                <!-- <i class="lemon-icon-message"></i>
+                                <p>
+                                    <b>自定义封面 Lemon</b>IMUI
+                                </p> -->
+                            </div>
+                    </template>
+
+                    <template #message-title="contact">
+                        <div>
+                            <div style="display:flex;justify-content:space-between">
+                                <span>{{contact.displayName}}</span>
+                                <span style="font-size:12px;">
+                                <!-- <span>打开抽屉:</span>
+                                <span style="cursor:pointer;"  @click="openDrawer('right')">
+                                    右侧  | 
+                                </span>
+                                <span style="cursor:pointer;" @click="openDrawer('rightInside')">
+                                    右侧内部  | 
+                                </span>
+                                <span style="cursor:pointer;" @click="openDrawer('center')">
+                                    居中
+                                </span> -->
+                                </span>
+                            </div>
+                            <!-- <div v-if="contact.isGroup" class="slot-group-menu">
+                                <span>聊天</span>
+                                <span>公告</span>
+                                <span>相册</span>
+                                <span>文件</span>
+                                <span>活动</span>
+                                <span>设置(左键弹出菜单)</span> 
+                            </div> -->
+                        </div>
+                    </template>
+                </lemon-records>
+
+            </div>
+
+            
+        </div>
+    </el-dialog>
+
+    <el-dialog :visible.sync="dialogImgVisible">
+        <img width="100%" :src="dialogImageUrl" alt="" />
+    </el-dialog>
+
+     <el-dialog :visible.sync="dialogVideoVisible"
+               :close-on-click-modal="false"
+               :destroy-on-close="true"
+               :width="aplayer.pWidth"
+               :height="aplayer.height" 
+               @close="dialogVideoVisible=false"
+               ref="player">
+              <videoPlayer  :width="aplayer.width" :height="aplayer.height"  :videoWidth="aplayer.videoWidth"  :videoHeight="aplayer.videoHeight"   :vid="aplayer.vid"  :autoplay="true" 
+                :source="dialogVideoUrl" :cover="dialogVideoCover" ref="player">
+              </videoPlayer>
+       </el-dialog>
+
+</div>
+
+</template>
+
+<script>
+
+  import LemonMessageVoice from "@/components/LemonUI/components/message/voice";
+  import { getContactsByUser,getConversations,getMessageList,getConversation,sendTextMsg,sendImageMsg,getRoomInfo} from '@/api/qw/im';
+  import Conversations from "@/components/LemonUI/database/conversations";
+  import EmojiData from "@/components/LemonUI/database/emoji";
+  import '@/components/LemonUI/index.css';
+  import VideoPlayer from '@/components/VideoPlayer/VueAliplayer'
+  let pages = {};
+  export default {
+       name: "ChatRecords",
+       components: {   
+          VideoPlayer,
+       },
+       data(){
+           return {
+                dialogVisible:false,
+                theme: "default",
+                IMUI:null,
+                hideMenuAvatar: false,
+                hideMenu: false,
+                hideMessageName: false,
+                hideMessageTime: true,
+                qwUser:{
+                    "userId":1688854331463712,"avatar":"https://wework.qpic.cn/wwpic/258414_QSUkkN5rTMGzwIc_1692169272/0","corpId":1970326754004217,"corpName":"重庆润方数字科技","nickName":"秦先觉","deviceId":"aeff5e72448d4d299e03d7291a21c2ea","phone":null,"account":"1261818888"
+                },
+                showQW:false,
+                UserData: {
+                    id: "1000",
+                    displayName: "June",
+                    avatar: "https://p.qqan.com/up/2018-4/15244505348390471.jpg",
+                },
+                contactData:null,
+                conversationData:null,
+                isFromLogin:false,
+                dialogImgVisible:false,
+                dialogImageUrl: '',
+                dialogVideoVisible:false, 
+                dialogVideoUrl:'',
+                dialogVideoCover:'',
+                imageArr:[],
+                pickUploadImgData:null,
+                aplayer: {
+                    vid: "bf9b7e4a36d84aea8cee769765fbc28b",
+                    pWidth:"1040px",
+                    width:"1000px",
+                    height:"900px",
+                    videoWidth:"1000px",
+                    videoHeight:"900px"
+                    
+                },
+                player: null,
+                roomMembers:[],
+                roomAdmins:[],
+                roomInfo:null,
+                windowWidth: document.documentElement.clientWidth*0.95,  //实时屏幕宽度
+                windowHeight: document.documentElement.clientHeight*0.7,   //实时屏幕高度
+                queryParams: {
+                    pageNum: 1,
+                    pageSize: 10,
+                    conversationId: null,
+                },
+                form: { content:"" },
+                // 表单校验
+                rules: {
+                    content: [
+                        { required: true, message: "请输入关键字", trigger: "blur" }
+                    ],
+                }
+           }
+       },
+        created(){
+           
+       },
+       mounted(){
+            this.deviceId=this.qwUser.deviceId;
+            this.UserData.id=this.qwUser.userId;
+            this.UserData.displayName=this.qwUser.nickName;
+            this.UserData.avatar=this.qwUser.avatar;
+       },
+       methods: {
+                /** 搜索按钮操作 */
+                handleQuery() {
+                   
+                },
+                init(){
+                    const IMUI = this.$refs.IMUI;
+                    //IMUI.changeContact(this.queryParams.conversationId);
+                    //this.getContacts();  //获取联系人信息
+                    this.getConversation();   //获取会话信息
+                    ////IMUI.initEmoji(EmojiData); 
+                },
+                open(conversationId,conversationData){
+                     this.conversationData=conversationData;
+                     this.queryParams.conversationId=conversationId;
+                     console.log("qxj conversationId:"+conversationId);
+                     this.dialogVisible=true;
+                      setTimeout(() => {
+                         const IMUI = this.$refs.IMUI;
+                         console.log("qxj records imui:"+IMUI);
+                         this.init();
+                    }, 500);
+                },
+                getRoomInfo(roomId){
+                    getRoomInfo(roomId).then(response => {
+                        this.roomMembers=response.members;
+                        this.admins=response.members;
+                        this.roomInfo=response.detail;
+                    });
+                },
+                getContacts(){  
+                    getContactsByUser(this.qwUser.userId).then(response => {
+                        this.contactData = response.data;
+                        this.$refs.IMUI.initContacts(this.contactData);
+                        
+                    });
+                },
+                getConversation(){
+                    let that=this;
+                    const IMUI = this.$refs.IMUI;
+                    //getConversations(this.qwUser.userId).then(response => {
+                    //    this.conversationData = response.data;
+                        IMUI.initConversations(this.conversationData);
+                        var fstConversation=this.conversationData[0];
+                        if(fstConversation){
+                            IMUI.changeContact(fstConversation.conversationId);
+                        }
+                    //});
+                },
+                messageTimeFormat(time) {
+                   return this.friendlyDate(time);
+                },
+                changeTheme() {
+                  this.theme = this.theme == "default" ? "blue" : "default";
+                },
+                scrollToTop() {
+                  document.body.scrollIntoView();
+                },
+                openDrawer(position) {
+                        const IMUI = this.$refs.IMUI;
+                        const params = {
+                            position,
+                            render: contact => {
+                            return (
+                                <div style="padding:15px">
+                                <h5>{contact.displayName}</h5>
+                                <span style="cursor:pointer;" on-click={IMUI.closeDrawer}>关闭抽屉</span>
+                                </div>
+                            );
+                            },
+                };
+                if (position == "center") {
+                    params.width = "50%";
+                    params.height = "50%";
+                } else if (position == "rightInside") {
+                    params.height = "90%";
+                    params.offsetY = "10%";
+                }
+                this.IMUI.openDrawer(params);
+                },
+                handlePullMessages(contact, next,instance) {
+                    const { IMUI } = this.$refs;
+                    let isEnd = false;
+                    getMessageList(this.queryParams).then(response => {
+                        if(response.code==200){
+                            isEnd=response.data.isLastPage;
+                            next(response.data.list, isEnd);
+                            if(!isEnd){
+                                pages[contact.conversationId]++;
+                            }
+                        }
+                    });
+                },
+                handleChangeConversation(conversation, instance) {
+                    console.log("qxj ChangeConversation:"+JSON.stringify(conversation));
+                    if (!pages[conversation.conversationId]){
+                        pages[conversation.conversationId] =1;
+                    }
+                    this.queryParams.pageNum=pages[conversation.conversationId];
+                    this.queryParams.conversationId=conversation.conversationId;
+                    if(conversation.unread>0){
+                        conversation.unread=0;
+                        instance.updateContact(conversation);
+                    }
+                    instance.closeDrawer();
+                },
+                handleChangeContact(contact, instance) {
+
+                },
+                //收到消息后添加消息显示
+                appendMessageAction(msgData){
+                    if(msgData.type=="text" || msgData.type=="image" || msgData.type=="voice"){     //文本   text  image  video  voice 
+                        const message = {
+                                id: msgData.id,
+                                status: msgData.status,
+                                type: msgData.type,
+                                sendTime: msgData.sendTime,
+                                content: msgData.content,
+                                params1: "1",
+                                params2: "2",
+                                toContactId: msgData.toContactId,
+                                fromUser: msgData.fromUser,
+                        };
+                        this.appendRemoteMessage(message);
+                    }
+                    else if(msgData.type=="file"){
+                        const message = {
+                                id: msgData.id,
+                                status: msgData.status,
+                                type: msgData.type,
+                                sendTime: msgData.sendTime,
+                                content: msgData.content,
+                                toContactId: msgData.toContactId,
+                                fromUser: msgData.fromUser,
+                                fileName:msgData.fileName,
+                                fileSize:msgData.fileSize
+                        };
+                        this.appendRemoteMessage(message);
+                    }
+                    else{
+                        const message = {
+                                id: msgData.id,
+                                status: msgData.status,
+                                type: msgData.type,
+                                sendTime: msgData.sendTime,
+                                content: msgData.content,
+                                toContactId: msgData.toContactId,
+                                fromUser: msgData.fromUser,
+                        };
+                        this.appendRemoteMessage(message);
+                    }
+                },
+                handleMenuAvatarClick() {
+                console.log("Event:menu-avatar-click");
+                },
+                //聊天工具栏点击图片
+                handleImageClick() { 
+                
+                },
+                //选择图片框确定按钮回调
+                handlePickImageDone(data){
+                    console.log("handlePickImageDone:"+JSON.stringify(data));
+                    this.pickUploadImgData=data;
+                    const IMUI = this.$refs.IMUI;
+                    IMUI._handleRemoteImage(data.url);
+                },
+                tooglePlayVideo(data){
+                    this.dialogVideoVisible=true;
+                    this.dialogVideoUrl=data.content;
+                    this.dialogVideoCover=data.url;
+                    const player = this.$refs.player.instance
+                    player && player.play()
+                },
+                handleMessageClick(e, key, message, instance) {
+                    console.log("点击了消息", e, key, message);
+                    //console.log("qxj message:"+JSON.stringify(message));
+                    if(message.type=="image"){
+                        var url=!!message.url?message.url:message.content;
+                        this.handlePicturePreview(url);
+                    }
+                    else if(message.type=="video"){  
+                        this.tooglePlayVideo(message);
+                    }
+                    else if(message.type=="file"){  
+                        
+                    }
+                    if (key == "status") {
+                        instance.updateMessage({
+                        id: message.id,
+                        status: "going",
+                        content: "正在重新发送消息...",
+                        });
+                        setTimeout(() => {
+                        instance.updateMessage({
+                            id: message.id,
+                            status: "succeed",
+                            content: "发送成功",
+                        });
+                        }, 2000);
+                    }
+                },
+
+                changeMenuAvatarVisible() {
+                   this.hideMenuAvatar = !this.hideMenuAvatar;
+                },
+                changeMenuVisible() {
+                   this.hideMenu = !this.hideMenu;
+                },
+                changeMessageNameVisible() {
+                   this.hideMessageName = !this.hideMessageName;
+                },
+                changeMessageTimeVisible() {
+                   this.hideMessageTime = !this.hideMessageTime;
+                },
+                removeMessage() {
+                    const { IMUI } = this.$refs;
+                    const messages = IMUI.getCurrentMessages();
+                    const id = messages[messages.length - 1].id;
+                    if (messages.length > 0) {
+                        IMUI.removeMessage(id);
+                    }
+                },
+                updateMessage() {
+                    const { IMUI } = this.$refs;
+                    const messages = IMUI.getCurrentMessages();
+                    const message = messages[messages.length - 1];
+                    if (messages.length > 0) {
+                        const update = {
+                        id: message.id,
+                        status: "succeed",
+                        type: "file",
+                        fileName: "被修改成文件了.txt",
+                        fileSize: "4200000",
+                        };
+                        if (message.type == "event") {
+                        update.fromUser = this.user;
+                        }
+                        IMUI.updateMessage(update);
+                        IMUI.messageViewToBottom();
+                }
+                },
+                appendCustomMessage() {
+                    const { IMUI } = this.$refs;
+                    const message = {
+                        id: generateRandId(),
+                        status: "succeed",
+                        type: "voice",
+                        sendTime: getTime(),
+                        content: "语音消息",
+                        params1: "1",
+                        params2: "2",
+                        toContactId: "contact-1",
+                        fromUser: this.user,
+                    };
+                    IMUI.appendMessage(message, true);
+                },
+                appendMessage() {
+                    const { IMUI } = this.$refs;
+                    const contact = IMUI.currentContact;
+                    const message = generateMessage("contact-3");
+                    message.fromUser = {
+                        ...message.fromUser,
+                        ...this.user,
+                    };
+                    IMUI.appendMessage(message, true);
+                    console.log("🚀 ~ file: App.vue ~ line 1508 ~ appendMessage ~ message", message)
+                },
+                appendEventMessage() {
+                    const { IMUI } = this.$refs;
+                    const message = {
+                        id: generateRandId(),
+                        type: "event",
+                        content: (
+                        <span>
+                            邀请你加入群聊{" "}
+                            <span
+                            style="color:#333;cursor:pointer"
+                            on-click={() => alert("OK")}>
+                            接受
+                            </span>
+                        </span>
+                        ),
+                        toContactId: "contact-3",
+                        sendTime: getTime(),
+                    };
+                    IMUI.appendMessage(message, true);
+                },
+                appendRemoteMessage(message) {  //从服务端返回的消息
+                    const { IMUI } = this.$refs;
+                    IMUI.appendMessage(message, true);
+                },
+                updateContact() {
+                    this.$refs.IMUI.updateContact({
+                        id: "contact-3",
+                        unread: 10,
+                        displayName: generateRandWord(),
+                        lastSendTime: getTime(),
+                        lastContent: "修改昵称为随机字母",
+                     });
+                },
+                handleChangeMenu() {
+                     console.log("Event:change-menu");
+                },
+                openCustomContainer() {
+
+                },
+                handlePicturePreview(url) {
+                    this.dialogImageUrl = url;
+                    this.dialogImgVisible=true;
+                },
+       }
+  }
+
+</script>
+
+
+
+<style lang="scss" scoped>
+    .app-container{
+       padding-top:0;
+    }
+    .imui-center{
+        margin-bottom:"60px"; 
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        // height: 80vh;
+    }
+    .lemon-wrapper{
+        border:"1px solid #ddd";
+        height: "60%" !important;
+    }
+    .lemon-drawer{
+        border:"1px solid #ddd";
+        border-left:"0";
+    }
+    .more {
+        font-size: 12px;
+        line-height: 24px;
+        height: 24px;
+        position: absolute;
+        top: 14px;
+        right: 14px;
+        cursor: pointer;
+        -webkit-user-select: none;
+        -moz-user-select: none;
+        -ms-user-select: none;
+        user-select: none;
+        color: #f1f1f1;
+        display: inline-block;
+        border-radius: 4px;
+        background: #111;
+        padding: 0 8px;
+    }
+
+    /deep/.el-dialog__headerbtn{
+         top:10px;
+    }
+
+    /deep/.el-form--inline .el-form-item{
+        display: flex;
+    }
+    /deep/.el-form-item--medium .el-form-item__content{
+        flex: 1;
+        margin-right: 20px;
+    }
+
+    // /deep/.el-dialog__header{
+    //     padding-bottom: 0;
+    // }
+    
+</style>
+
+
+<style lang="stylus">
+   .lemon-container__title
+     padding-bottom:10px;
+   .slot-group
+      width:200px;
+      .slot-group-title
+        padding:0 0 10px 0;
+        .slot-group-notice
+           padding: 10px 10px;
+     
+      .slot-search
+           width:calc(100% - 20px) ;
+           margin:5px 10px;
+           padding:3px 0px;
+
+      .slot-group-member
+          display: flex;
+          padding: 5px 0;
+          flex:1;
+          font-size: 14px;
+          align-items: center;
+          .avatar
+              width: 30px;
+              height: 30px;
+              line-height: 30px;
+              margin-right:5px;
+              img 
+                vertical-align: middle;
+                border-style: none;
+                width: 100%;
+                height: 100%;
+                line-height: 30px;
+                border-radius: 50%;
+</style>

+ 499 - 0
src/components/LemonUI/components/chatrecords/segrecords.vue

@@ -0,0 +1,499 @@
+<template>
+<div>
+
+    <div class="imui-center qq-lemon-imui">
+        <lemon-records  class="lemon-slot"  
+            :width="windowWidth"
+            :height="windowHeight"
+            :user="UserData"
+            ref="IMUI"  
+            :sendText="sendText"
+            :theme="theme"
+            :show-context="showContext"
+            :hide-menu="hideMenu"
+            :hide-menu-avatar="hideMenuAvatar"
+            :hide-message-name="hideMessageName"
+            :hide-message-time="hideMessageTime"
+            :messageTimeFormat="messageTimeFormat"
+            @change-menu="handleChangeMenu"
+            @pull-messages="handlePullMessages"
+            @pull-up-messages="handleMoreMessages"
+            @change-contact="handleChangeContact"
+            @change-conversation="handleChangeConversation"
+            @message-click="handleMessageClick"
+            @context-click="handleContextClick"
+            @menu-avatar-click="handleMenuAvatarClick"
+            >
+
+            <template #cover>
+                    <div class="cover">
+                        <!-- <i class="lemon-icon-message"></i>
+                        <p>
+                            <b>自定义封面 Lemon</b>IMUI
+                        </p> -->
+                    </div>
+            </template>
+
+            <template #message-title="contact">
+                <div>
+                    <div style="display:flex;justify-content:space-between">
+                        <span>{{contact.displayName}}</span>
+                        <span style="font-size:12px;">
+                        <!-- <span>打开抽屉:</span>
+                        <span style="cursor:pointer;"  @click="openDrawer('right')">
+                            右侧  | 
+                        </span>
+                        <span style="cursor:pointer;" @click="openDrawer('rightInside')">
+                            右侧内部  | 
+                        </span>
+                        <span style="cursor:pointer;" @click="openDrawer('center')">
+                            居中
+                        </span> -->
+                        </span>
+                    </div>
+                    <!-- <div v-if="contact.isGroup" class="slot-group-menu">
+                        <span>聊天</span>
+                        <span>公告</span>
+                        <span>相册</span>
+                        <span>文件</span>
+                        <span>活动</span>
+                        <span>设置(左键弹出菜单)</span> 
+                    </div> -->
+                </div>
+            </template>
+        </lemon-records>
+
+    </div>
+
+    <el-dialog :visible.sync="dialogImgVisible" append-to-body width="35%">
+        <img style="width:100%;height:auto" :src="dialogImageUrl" alt="" />
+    </el-dialog>
+
+     <el-dialog :visible.sync="dialogVideoVisible" 
+                append-to-body 
+               :close-on-click-modal="false"
+               :destroy-on-close="true"
+               :width="aplayer.pWidth"
+               :height="aplayer.height" 
+               @close="dialogVideoVisible=false"
+               ref="player">
+              <videoPlayer  :width="aplayer.width" :height="aplayer.height"  :videoWidth="aplayer.videoWidth"  
+                :videoHeight="aplayer.videoHeight"   :vid="aplayer.vid"  :autoplay="true" 
+                :source="dialogVideoUrl" :cover="dialogVideoCover" ref="player">
+              </videoPlayer>
+       </el-dialog>
+</div>
+
+</template>
+
+<script>
+
+  import LemonMessageVoice from "@/components/LemonUI/components/message/voice";
+  import { getContactsByUser,getConversations,getMessageList} from '@/api/qw/im';
+  import Conversations from "@/components/LemonUI/database/conversations";
+  import EmojiData from "@/components/LemonUI/database/emoji";
+  import '@/components/LemonUI/index.css';
+  import VideoPlayer from '@/components/VideoPlayer/VueAliplayer'
+  let pages = {};
+  export default {
+       name: "SegRecords",
+       components: {   
+          VideoPlayer,
+       },
+       props: {
+          qwUser: {
+                type: Object,
+                default: () => {
+                    return { };
+                },
+          },
+          conversationId: {
+                type: String,
+                default: "default",
+          },
+          conversationData: {
+                type: Array,
+                default: () => {
+                    return [];
+                },
+          },
+          msgType: {
+                type: Number,
+                default: 0,
+          },
+          isContext: {
+                type: Boolean,
+                default: false,
+          },
+
+      },
+       data(){
+           return {
+                theme: "default",
+                IMUI:null,
+                hideMenuAvatar: false,
+                hideMenu: false,
+                hideMessageName: false,
+                hideMessageTime: true,
+                showContext:false,
+                showQW:false,
+                messageId:null,
+                UserData: {
+                    id: "1000",
+                    displayName: "June",
+                    avatar: "https://p.qqan.com/up/2018-4/15244505348390471.jpg",
+                },
+                dialogImgVisible:false,
+                dialogImageUrl: '',
+                dialogVideoVisible:false, 
+                dialogVideoUrl:'',
+                dialogVideoCover:'',
+                imageArr:[],
+                pickUploadImgData:null,
+                aplayer: {
+                    vid: "bf9b7e4a36d84aea8cee769765fbc28b",
+                    pWidth:"1040px",
+                    width:"1000px",
+                    height:"900px",
+                    videoWidth:"1000px",
+                    videoHeight:"900px"
+
+                },
+                player: null,
+                roomMembers:[],
+                roomAdmins:[],
+                roomInfo:null,
+                windowWidth: document.documentElement.clientWidth*0.95,  //实时屏幕宽度
+                windowHeight: document.documentElement.clientHeight*0.7,   //实时屏幕高度
+                queryParams: {
+                    pageNum: 1,
+                    pageSize: 10,
+                    conversationId: null,
+                },
+                isLoaded:false,
+                sendText:"",
+               
+           }
+       },
+       created(){
+            
+       },
+       mounted(){
+            //this.deviceId=this.qwUser.deviceId;
+            this.UserData.id=this.qwUser.userId;
+            this.UserData.displayName=this.qwUser.nickName;
+            this.UserData.avatar=this.qwUser.avatar;
+            this.queryParams.msgType=this.msgType;
+            //this.open();
+           
+       },
+       methods: {
+                /** 搜索按钮操作 */
+                handleQuery() {
+                   
+                },
+                handleClose(){
+                   
+                }, 
+                init(){
+                    const IMUI = this.$refs.IMUI;
+                    this.getConversation();   //获取会话信息
+                    ////IMUI.initEmoji(EmojiData); 
+                },
+                open(converChanged){
+                      if(this.isLoaded && !converChanged){
+                          return;
+                      }
+                      pages=[];
+                      setTimeout(() => {
+                          const IMUI = this.$refs.IMUI;
+                          this.init();
+                          this.isLoaded=true;
+                    }, 0);
+                },
+                //消息关键字搜索
+                openSearch(searchVal){
+                      pages=[];
+                      this.queryParams.searchVal=searchVal;
+                      this.showContext=true;
+                      setTimeout(() => {
+                          const IMUI = this.$refs.IMUI;
+                          this.init();
+                    }, 100);
+                },
+                //查看上下文
+                openContextBox(message){ 
+                      pages=[];
+                      this.queryParams.messageId=message.id;
+                      this.queryParams.pullAct=0;//下拉刷新
+                      setTimeout(() => {
+                          const IMUI = this.$refs.IMUI;
+                          this.init();
+                    }, 100);
+                },
+                getConversation(){
+                      const IMUI = this.$refs.IMUI;
+                      if(this.conversationData.length==0){
+                          getConversations(this.qwUser.userId).then(response => {
+                                const conversationData = response.data;
+                                IMUI.initConversations(conversationData);
+                                IMUI.clearMessages(this.conversationId);
+                                IMUI.currentContactId="";
+                                IMUI.changeContact(this.conversationId);
+                          });
+                       }else{
+                                IMUI.initConversations(this.conversationData);
+                                IMUI.clearMessages(this.conversationId);
+                                IMUI.currentContactId="";
+                                IMUI.changeContact(this.conversationId);
+                        }
+                },
+                messageTimeFormat(time) {
+                   return this.friendlyDate(time);
+                },
+                changeTheme() {
+                  this.theme = this.theme == "default" ? "blue" : "default";
+                },
+                scrollToTop() {
+                  document.body.scrollIntoView();
+                },
+                handlePullMessages(contact, next,instance) {
+                    const { IMUI } = this.$refs;
+                    let isEnd = false;
+                    if(this.isContext){
+                         this.queryParams.pullAct=0;//下拉刷新
+                    }
+                    console.log("qxj handlePullMessages:"+JSON.stringify(this.queryParams));
+                    getMessageList(this.queryParams).then(response => {
+                        if(response.code==200){
+                            isEnd=response.data.isLastPage;
+                            next(response.data.list, isEnd);
+                            if(!isEnd){
+                                if(this.isContext){
+                                    pages[contact.conversationId+this.queryParams.pullAct]++;
+                                    this.queryParams.pageNum=pages[contact.conversationId+this.queryParams.pullAct];
+                                }else{
+                                    pages[contact.conversationId]++;
+                                    this.queryParams.pageNum=pages[contact.conversationId];
+                                }
+                            }
+                        }
+                    });
+                },
+                handleMoreMessages(contact, next,instance) {
+                    const { IMUI } = this.$refs;
+                    let isEnd = false;
+                    console.log("qxj handleMoreMessages:"+JSON.stringify(this.queryParams));
+                     if(this.isContext){
+                         this.queryParams.pullAct=1;//上拉加载更多
+                    }
+                    getMessageList(this.queryParams).then(response => {
+                        if(response.code==200){
+                            isEnd=response.data.isLastPage;
+                            next(response.data.list, isEnd);
+                            if(this.isContext){
+                                pages[conversation.conversationId+this.queryParams.pullAct]++;
+                            }else{
+                                pages[contact.conversationId]++;
+                            }
+                        }
+                    });
+                },
+
+                handleChangeConversation(conversation, instance) {
+                    console.log("qxj ChangeConversation:"+JSON.stringify(conversation));
+                    if(this.isContext){
+                        if (!pages[conversation.conversationId+this.queryParams.pullAct]){
+                              pages[conversation.conversationId+this.queryParams.pullAct] =1;
+                        }
+                        this.queryParams.pageNum=pages[conversation.conversationId+this.queryParams.pullAct];
+                    }
+                    else{
+                        if (!pages[conversation.conversationId]){
+                              pages[conversation.conversationId] =1;
+                        }
+                        this.queryParams.pageNum=pages[conversation.conversationId];
+                    }
+                    this.queryParams.conversationId=conversation.conversationId;
+                    if(conversation.unread>0){
+                        conversation.unread=0;
+                        instance.updateContact(conversation);
+                    }
+                    instance.closeDrawer();
+                },
+                handleChangeContact(contact, instance) {
+
+                },
+            
+                handleMenuAvatarClick() {
+                   console.log("Event:menu-avatar-click");
+                },
+                tooglePlayVideo(data){
+                    this.dialogVideoVisible=true;
+                    this.dialogVideoUrl=data.content;
+                    this.dialogVideoCover=data.url;
+                    const player = this.$refs.player.instance 
+                    player && player.play()
+                },
+                handleMessageClick(e, key, message, instance) {
+                    console.log("点击了消息", e, key, message);
+                    //console.log("qxj message:"+JSON.stringify(message));
+                    if(message.type=="image"){
+                        var url=!!message.url?message.url:message.content;
+                        this.handlePicturePreview(url);
+                    }
+                    else if(message.type=="video"){  
+                        this.tooglePlayVideo(message);
+                    }
+                    else if(message.type=="file"){  
+                        
+                    }
+                    if (key == "status") {
+                        instance.updateMessage({
+                        id: message.id,
+                        status: "going",
+                        content: "正在重新发送消息...",
+                        });
+                        setTimeout(() => {
+                        instance.updateMessage({
+                            id: message.id,
+                            status: "succeed",
+                            content: "发送成功",
+                        });
+                        }, 2000);
+                    }
+                },
+                handleContextClick(e, key, message, instance){
+                    this.$emit("showContextBox",message);
+                },
+                changeMenuAvatarVisible() {
+                   this.hideMenuAvatar = !this.hideMenuAvatar;
+                },
+                changeMenuVisible() {
+                   this.hideMenu = !this.hideMenu;
+                },
+                changeMessageNameVisible() {
+                   this.hideMessageName = !this.hideMessageName;
+                },
+                changeMessageTimeVisible() {
+                   this.hideMessageTime = !this.hideMessageTime;
+                },
+    
+                updateContact() {
+                    this.$refs.IMUI.updateContact({
+                        id: "contact-3",
+                        unread: 10,
+                        displayName: generateRandWord(),
+                        lastSendTime: getTime(),
+                        lastContent: "修改昵称为随机字母",
+                     });
+                },
+                handleChangeMenu() {
+                     console.log("Event:change-menu");
+                },
+                handlePicturePreview(url) {
+                    this.dialogImageUrl = url;
+                    this.dialogImgVisible=true;
+                },
+       }
+  }
+
+</script>
+
+
+
+<style lang="scss" scoped>
+    .app-container{
+       padding-top:0;
+    }
+    .imui-center{
+        margin-bottom:"60px"; 
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        // height: 80vh;
+    }
+    .lemon-wrapper{
+        border:"1px solid #ddd";
+        height: "60%" !important;
+    }
+    .lemon-drawer{
+        border:"1px solid #ddd";
+        border-left:"0";
+    }
+    .more {
+        font-size: 12px;
+        line-height: 24px;
+        height: 24px;
+        position: absolute;
+        top: 14px;
+        right: 14px;
+        cursor: pointer;
+        -webkit-user-select: none;
+        -moz-user-select: none;
+        -ms-user-select: none;
+        user-select: none;
+        color: #f1f1f1;
+        display: inline-block;
+        border-radius: 4px;
+        background: #111;
+        padding: 0 8px;
+    }
+
+    /deep/.el-dialog__headerbtn{
+         top:10px;
+    }
+
+    /deep/.el-form--inline .el-form-item{
+        display: flex;
+    }
+    /deep/.el-form-item--medium .el-form-item__content{
+        flex: 1;
+        margin-right: 20px;
+    }
+
+    /deep/.el-dialog:not(.is-fullscreen) {
+        margin-top: 0 !important;
+    }
+
+    // /deep/.el-dialog__header{
+    //     padding-bottom: 0;
+    // }
+    
+</style>
+
+
+<style lang="stylus">
+   .lemon-container__title
+     padding-bottom:10px;
+   .slot-group
+      width:200px;
+      .slot-group-title
+        padding:0 0 10px 0;
+        .slot-group-notice
+           padding: 10px 10px;
+     
+      .slot-search
+           width:calc(100% - 20px) ;
+           margin:5px 10px;
+           padding:3px 0px;
+
+      .slot-group-member
+          display: flex;
+          padding: 5px 0;
+          flex:1;
+          font-size: 14px;
+          align-items: center;
+          .avatar
+              width: 30px;
+              height: 30px;
+              line-height: 30px;
+              margin-right:5px;
+              img 
+                vertical-align: middle;
+                border-style: none;
+                width: 100%;
+                height: 100%;
+                line-height: 30px;
+                border-radius: 50%;
+</style>

+ 1384 - 0
src/components/LemonUI/components/records.vue

@@ -0,0 +1,1384 @@
+<script>
+import {
+  useScopedSlot,
+  funCall,
+  generateUUID,
+  clearHtmlExcludeImg,
+} from "../utils";
+import { isFunction, isString, isEmpty } from "../utils/validate";
+import contextmenu from "../directives/contextmenu";
+import {
+  DEFAULT_MENUS,
+  DEFAULT_MENU_LASTMESSAGES,
+  DEFAULT_MENU_CONTACTS,
+} from "../utils/constant";
+import lastContentRender from "../lastContentRender";
+
+import MemoryCache from "../utils/cache/memory";
+
+let allMessages = {};
+const emojiMap = {};
+const toPx = val => {
+  return isString(val) ? val : `${val}px`;
+};
+const toPoint = str => {
+  return str.replace("%", "") / 100;
+};
+
+let renderDrawerContent = () => {};
+
+export default {
+  name: "LemonRecords",
+  provide() {
+    return {
+      IMUI: this,
+    };
+  },
+  props: {
+    width: {
+      type: [String, Number],
+      default: 850,
+    },
+    height: {
+      type: [String, Number],
+      default: 580,
+    },
+    theme: {
+      type: String,
+      default: "default",
+    },
+    simple: {
+      type: Boolean,
+      default: false,
+    },
+    loadingText: [String, Function],
+    loadendText: [String, Function],
+    /**
+     * 消息时间格式化规则
+     */
+    messageTimeFormat: Function,
+    /**
+     * 联系人最新消息时间格式化规则
+     */
+    contactTimeFormat: Function,
+    /**
+     * 初始化时是否隐藏抽屉
+     */
+    hideDrawer: {
+      type: Boolean,
+      default: true,
+    },
+    /**
+     * 是否隐藏导航按钮上的头像
+     */
+    hideMenuAvatar: Boolean,
+    hideMenu: Boolean,
+    /**
+     * 是否隐藏消息列表内的联系人名字
+     */
+    hideMessageName: Boolean,
+    /**
+     * 是否隐藏消息列表内的发送时间
+     */
+    hideMessageTime: Boolean,
+    showContext:Boolean,
+    sendKey: Function,
+    wrapKey: Function,
+    sendText: String,
+    contextmenu: Array,
+    contactContextmenu: Array,
+    avatarCricle: Boolean,
+    user: {
+      type: Object,
+      default: () => {
+        return {};
+      },
+    },
+  },
+  data() {
+    this.CacheContactContainer = new MemoryCache();
+    this.CacheMenuContainer = new MemoryCache();
+    this.CacheMessageLoaded = new MemoryCache();
+    this.CacheDraft = new MemoryCache();
+    return {
+      drawerVisible: !this.hideDrawer,
+      currentContactId: null,
+      currentNewContactId: null,
+      currentMessages: [],
+      activeSidebar: DEFAULT_MENU_LASTMESSAGES,
+      contacts: [],
+      conversations:[],
+      menus: [],
+      editorTools: [
+        { name: "emoji" },
+        { name: "uploadFile" },
+        { name: "uploadImage" },
+      ],
+    };
+  },
+
+  render() {
+    return this._renderWrapper([
+      //this._renderMenu(),
+      //this._renderSidebarMessage(),//加载会话数据
+      //this._renderSidebarContact(),//加载联系人
+      this._renderContainer(),
+      //this._renderDrawer(),
+    ]);
+  },
+  created() {
+    this.initMenus();
+  },
+  async mounted() {
+    await this.$nextTick();
+  },
+  computed: {
+    currentContact() {
+       return this.conversations.find(item =>  item.conversationId == this.currentContactId) || {};
+    },
+    //获取当前联系人
+    currentNewContact() {
+       return this.contacts.find(item =>  item.id == this.currentNewContactId) || {};
+    },
+    currentMenu() {
+      return this.menus.find(item => item.name == this.activeSidebar) || {};
+    },
+    currentIsDefSidebar() {
+      return DEFAULT_MENUS.includes(this.activeSidebar);
+    },
+    lastMessages() {
+      // var data = this.contacts.filter(item => !isEmpty(item.lastContent));
+      // data.sort((a1, a2) => {
+      //   return a2.lastSendTime - a1.lastSendTime;
+      // });
+      var data=null;
+      if(!!this.conversations){
+          data=this.conversations;
+      }
+      return data;
+    },
+  },
+  watch: {
+    activeSidebar() {},
+  },
+  methods: {
+    _menuIsContacts() {
+      return this.activeSidebar == DEFAULT_MENU_CONTACTS;
+    },
+    _menuIsMessages() {
+      return this.activeSidebar == DEFAULT_MENU_LASTMESSAGES;
+    },
+    _createMessage(message) {
+      return {
+        ...{
+          id: generateUUID(),
+          type: "text",
+          status: "going",
+          sendTime: new Date().getTime(),
+          toContactId: this.currentContactId,
+          fromUser: {
+            ...this.user,
+          },
+        },
+        ...message,
+      };
+    },
+    /**
+     * 新增一条消息
+     */
+    appendMessage(message, scrollToBottom = false) {
+        let messageList = allMessages[message.toContactId];
+        // 如果是自己的消息需要push,发送的消息不再增加未读条数
+        let conversation=this.findConversation(message.toContactId);
+        let unread=conversation.unread!=undefined && conversation.unread>0?(conversation.unread+1):1;
+        if (message.type == 'event'){
+            // if(this.user.id == message.fromUser.id){}
+            unread = 0;
+        } 
+        if (messageList === undefined) {
+          //console.log("qxj appendMessage messageList:"+messageList+",message"+JSON.stringify(message));
+          conversation.id=message.toContactId;
+          conversation.unread = unread;
+          conversation.lastSendTime=message.sendTime;
+          conversation.lastContent=this.lastContentRender(message);
+          this.updateContact(conversation);
+      } else {
+          // 如果消息存在则不再添加
+          let hasMsg = messageList.some(({id})=>id == message.id);
+          if (hasMsg) return;
+          this._addMessage(message, message.toContactId, 1);
+          
+          conversation.lastContent=this.lastContentRender(message);
+          conversation.lastSendTime=message.sendTime;
+          if (message.toContactId == this.currentContactId) {
+            conversation.unread=0;
+            if (scrollToBottom == true) {
+              this.messageViewToBottom();
+            }
+            this.CacheDraft.remove(message.toContactId);
+          } else {
+            conversation.unread = unread;
+          }
+          this.updateContact(conversation);
+      }
+    },
+    _emitSend(message, next, file) {
+      this.$emit(
+        "send",
+        message,
+        (replaceMessage = { status: "succeed" }) => {
+          next();
+          this.updateMessage(Object.assign(message, replaceMessage));
+        },
+        file,
+      );
+    },
+    _handleSend(text) {
+      const message = this._createMessage({ content: text });
+      this.appendMessage(message, true);
+      this._emitSend(message, () => {
+        this.updateContact({
+          id: message.toContactId,
+          lastContent: this.lastContentRender(message),
+          lastSendTime: message.sendTime,
+        });
+        this.CacheDraft.remove(message.toContactId);
+      });
+    },
+    _handleUpload(file) {
+      const imageTypes = ["image/gif", "image/jpeg", "image/png"];
+      let joinMessage;
+      if (imageTypes.includes(file.type)) {
+        joinMessage = {
+          type: "image",
+          content: URL.createObjectURL(file),
+        };
+      } else {
+        joinMessage = {
+          type: "file",
+          fileSize: file.size,
+          fileName: file.name,
+          content: "",
+        };
+      }
+      const message = this._createMessage(joinMessage);
+      this.appendMessage(message, true);
+      this._emitSend(
+        message,
+        () => {
+          this.updateContact({
+            id: message.toContactId,
+            lastContent: this.lastContentRender(message),
+            lastSendTime: message.sendTime,
+          });
+        },
+        file,
+      );
+    },
+    _handleRemoteImage(url) {
+        let joinMessage = {
+            type: "image",
+            content: url,
+          };
+        const message = this._createMessage(joinMessage);
+        this.appendMessage(message, true);
+        this._emitSend(
+          message,
+          () => {
+            this.updateContact({
+              id: message.toContactId,
+              lastContent: this.lastContentRender(message),
+              lastSendTime: message.sendTime,
+            });
+          },
+          null,
+        );
+    },
+    _pickImg(){
+        this.$emit("pick-image");
+    },
+    _emitPullMessages(next) {
+      //console.log("qxj currentContact:"+JSON.stringify(this.currentContact));
+      this._changeContactLock = true;
+      this.$emit("pull-messages",
+      this.currentContact,
+        (messages = [], isEnd = false) => {
+          this._addMessage(messages, this.currentContactId, 0);
+          this.CacheMessageLoaded.set(this.currentContactId, isEnd);
+          if (isEnd == true) this.$refs.messages.loaded();
+          this.updateCurrentMessages();
+          this._changeContactLock = false;
+          next(isEnd);
+        },
+        this,
+      );
+    },
+     _emitPullUpMessages(next) {
+        this._changeContactLock = true;
+        this.$emit("pull-up-messages",
+        this.currentContact,
+          (messages = [], isEnd = false) => {
+            this._addMessage(messages, this.currentContactId, 1);
+            this.CacheMessageLoaded.set(this.currentContactId, isEnd);
+            if (isEnd == true) this.$refs.messages.loaded();
+            this.updateCurrentMessages();
+            this._changeContactLock = false;
+            next(isEnd);
+          },
+          this,
+        );
+    },
+    clearCacheContainer(name) {
+      this.CacheContactContainer.remove(name);
+      this.CacheMenuContainer.remove(name);
+    },
+    _renderWrapper(children) {
+      return (
+        <div
+          style={{
+            width: toPx(this.width),
+            height: toPx(this.height),
+          }}
+          ref="wrapper"
+          class={[
+            "lemon-wrapper",
+            `lemon-wrapper--theme-${this.theme}`,
+            { "lemon-wrapper--simple": this.simple },
+            this.drawerVisible && "lemon-wrapper--drawer-show",
+          ]}
+        >
+          {children}
+        </div>
+      );
+    },
+    _renderMenu() {
+      const menuItem = this._renderMenuItem();
+      return (
+        <div class="lemon-menu" v-show={!this.hideMenu}>
+          {
+            <lemon-avatar
+              v-show={!this.hideMenuAvatar}
+              on-click={e => {
+                this.$emit("menu-avatar-click", e);
+              }}
+              class="lemon-menu__avatar"
+              src={this.user.avatar}
+            />
+          }
+          {menuItem.top}
+          {this.$slots.menu}
+          <div class="lemon-menu__bottom">
+            {this.$slots["menu-bottom"]}
+            {menuItem.bottom}
+          </div>
+        </div>
+      );
+    },
+    _renderMenuAvatar() {
+      return;
+    },
+    _renderMenuItem() {
+      const top = [];
+      const bottom = [];
+      this.menus.forEach(item => {
+        const { name, title, unread, render, click } = item;
+        const node = (
+          <div
+            class={[
+              "lemon-menu__item",
+              { "lemon-menu__item--active": this.activeSidebar == name },
+            ]}
+            on-click={() => {
+              funCall(click, () => {
+                if (name) this.changeMenu(name);
+              });
+            }}
+            title={title}
+          >
+            <lemon-badge count={unread}>{render(item)}</lemon-badge>
+          </div>
+        );
+        item.isBottom === true ? bottom.push(node) : top.push(node);
+      });
+      return {
+        top,
+        bottom,
+      };
+    },
+    _renderSidebarMessage() {
+      return this._renderSidebar(
+        [
+          useScopedSlot(this.$scopedSlots["sidebar-message-top"], null, this),
+          this.lastMessages.map(contact => {
+            return this._renderContact(
+              {
+                contact,
+                timeFormat: this.contactTimeFormat,
+              },
+              () => this.changeContact(contact.conversationId),
+              this.$scopedSlots["sidebar-message"],
+            );
+          }),
+        ],
+        DEFAULT_MENU_LASTMESSAGES,
+        useScopedSlot(
+          this.$scopedSlots["sidebar-message-fixedtop"],
+          null,
+          this,
+        ),
+      );
+    },
+    _renderContact(props, onClick, slot) {
+      const {
+        click: customClick,
+        renderContainer,
+        id: contactId,
+      } = props.contact;
+      const click = () => {
+        funCall(customClick, () => {
+          onClick();
+          this._customContainerReady(
+            renderContainer,
+            this.CacheContactContainer,
+            contactId,
+          );
+        });
+      };
+      return (
+        <lemon-contact
+          class={{
+            "lemon-contact--active":this._menuIsMessages()?this.currentContactId == props.contact.conversationId:(this._menuIsContacts()?this.currentNewContactId == props.contact.id:false)
+          }}
+          v-lemon-contextmenu_contact={this.contactContextmenu}
+          props={props}
+          on-click={click}
+          scopedSlots={{ default: slot }}
+        />
+      );
+    },
+    _renderSidebarContact() {
+      let prevIndex;
+      return this._renderSidebar(
+        [
+          useScopedSlot(this.$scopedSlots["sidebar-contact-top"], null, this),
+          this.contacts.map(contact => {
+            if (!contact.index) return;
+            contact.index = contact.index.replace(/\[[0-9]*\]/, "");
+            const node = [
+              contact.index !== prevIndex && (
+                <p class="lemon-sidebar__label">{contact.index}</p>
+              ),
+              this._renderContact(
+                {
+                  contact: contact,
+                  simple: true,
+                },
+                () => {
+                  console.log("qxj contact click");
+                  this.currentNewContactId=contact.id;
+                  //this.changeContact(contact.id);
+                },
+                this.$scopedSlots["sidebar-contact"],
+              ),
+            ];
+            prevIndex = contact.index;
+            return node;
+          }),
+        ],
+        DEFAULT_MENU_CONTACTS,
+        useScopedSlot(
+          this.$scopedSlots["sidebar-contact-fixedtop"],
+          null,
+          this,
+        ),
+      );
+    },
+    _renderSidebar(children, name, fixedtop) {
+      return (
+        <div
+          class="lemon-sidebar"
+          v-show={this.activeSidebar == name}
+          on-scroll={this._handleSidebarScroll}
+        >
+          <div class="lemon-sidebar__fixed-top">{fixedtop}</div>
+          <div class="lemon-sidebar__scroll">{children}</div>
+        </div>
+      );
+    },
+    _renderDrawer() {
+      return this._menuIsMessages() && this.currentContactId ? (
+        <div class="lemon-drawer" ref="drawer">
+          {renderDrawerContent(this.currentContact)}
+          {useScopedSlot(this.$scopedSlots.drawer, "", this.currentContact)}
+        </div>
+      ) : (
+        ""
+      );
+    },
+    _isContactContainerCache(name) {
+      return name.startsWith("contact#");
+    },
+    _renderContainer() {
+      const nodes = [];
+      const cls = "lemon-container";
+      const curact = this.currentContact;
+      const curactNew = this.currentNewContact;
+      let defIsShow = true;
+      for (const name in this.CacheContactContainer.get()) {
+        const show = curactNew.id == name && this.currentIsDefSidebar;
+        if(show)defIsShow = !show;
+        nodes.push(
+          <div class={cls} v-show={show}>
+            {this.CacheContactContainer.get(name)}
+          </div>,
+        );
+      }
+      for (const name in this.CacheMenuContainer.get()) {
+          nodes.push(
+            <div
+              class={cls}
+              v-show={this.activeSidebar == name && !this.currentIsDefSidebar}
+            >
+              {this.CacheMenuContainer.get(name)}
+            </div>,
+          );
+      }
+      
+      //聊天消息View
+      nodes.push(
+        <div
+          class={cls}
+          v-show={this._menuIsMessages() && defIsShow && curact.id}
+        >
+          <div class="lemon-container__title">
+            {useScopedSlot(
+              this.$scopedSlots["message-title"],
+              <div class="lemon-container__displayname">
+                {curact.displayName}
+              </div>,
+              curact,
+            )}
+          </div>
+          <div class="lemon-vessel">
+            <div class="lemon-vessel__left">
+              <lemon-messages
+                ref="messages"
+                loading-text={this.loadingText}
+                loadend-text={this.loadendText}
+                hide-time={this.hideMessageTime}
+                hide-name={this.hideMessageName}
+                show-context={this.showContext}
+                time-format={this.messageTimeFormat}
+                reverse-user-id={this.user.id}
+                on-reach-top={this._emitPullMessages}
+                on-reach-bottom={this._emitPullUpMessages}
+                messages={this.currentMessages}
+              />
+          
+            </div>
+           
+          </div>
+        </div>,
+      );
+      nodes.push(
+        <div class={cls} v-show={!curact.id && this.currentIsDefSidebar}>
+          {this.$slots.cover}
+        </div>,
+      );
+
+      //联系人View
+      nodes.push(
+        <div
+          class={cls}
+          v-show={this._menuIsContacts() && defIsShow && curactNew.id}>
+          {useScopedSlot(
+            this.$scopedSlots["contact-info"],
+            <div class="lemon-contact-info">
+              <lemon-avatar src={curactNew.avatar} size={90} />
+              <h4>{curactNew.displayName}</h4>
+              <lemon-button
+                on-click={() => {
+                  if (isEmpty(curactNew.lastContent)) {
+                    this.updateContact({
+                      id: curactNew.id,
+                      lastContent: " ",
+                    });
+                  }
+                  this.changeContact(curactNew.conversationId, DEFAULT_MENU_LASTMESSAGES);
+                }}
+              >
+                发送消息
+              </lemon-button>
+            </div>,
+            curactNew,
+          )}
+        </div>,
+      );
+      return nodes;
+    },
+    _handleSidebarScroll() {
+      contextmenu.hide();
+    },
+    _addContact(data, t) {
+      const type = {
+        0: "unshift",
+        1: "push",
+      }[t];
+      this.contacts[type](data);
+    },
+    _addMessage(data, contactId, t) {
+      const type = {
+        0: "unshift",
+        1: "push",
+      }[t];
+      if (!Array.isArray(data)) data = [data];
+      allMessages[contactId] = allMessages[contactId] || [];
+      allMessages[contactId][type](...data);
+    },
+    /**
+     * 设置最新消息DOM
+     * @param {String} messageType 消息类型
+     * @param {Function} render 返回消息 vnode
+     */
+    setLastContentRender(messageType, render) {
+      lastContentRender[messageType] = render;
+    },
+    lastContentRender(message) {
+      if (!isFunction(lastContentRender[message.type])) {
+        console.error(
+          `not found '${
+            message.type
+          }' of the latest message renderer,try to use ‘setLastContentRender()’`,
+        );
+        return "";
+      }
+      return lastContentRender[message.type].call(this, message);
+    },
+    /**
+     * 将字符串内的 EmojiItem.name 替换为 img
+     * @param {String} str 被替换的字符串
+     * @return {String} 替换后的字符串
+     */
+    emojiNameToImage(str) {
+      return str.replace(/\[!(\w+)\]/gi, (str, match) => {
+        const file = match;
+        return emojiMap[file]
+          ? `<img emoji-name="${match}" src="${emojiMap[file]}" />`
+          : `[!${match}]`;
+      });
+    },
+    emojiImageToName(str) {
+      return str.replace(/<img emoji-name=\"([^\"]*?)\" [^>]*>/gi, "[!$1]");
+    },
+    updateCurrentMessages() {
+      if (!allMessages[this.currentContactId]){
+          allMessages[this.currentContactId] = [];
+      }
+      //console.log("qxj allMessages:"+JSON.stringify(allMessages));
+      this.currentMessages = allMessages[this.currentContactId];
+    },
+    /**
+     * 将当前聊天窗口滚动到底部
+     */
+    messageViewToBottom() {
+      this.$refs.messages.scrollToBottom();
+    },
+    /**
+     * 设置联系人的草稿信息
+     */
+    setDraft(cid, editorValue) {
+      if (isEmpty(cid) || isEmpty(editorValue)) return false;
+      const conversation = this.findConversation(cid);
+      let lastContent = conversation.lastContent;
+      if (isEmpty(conversation)) return false;
+      if (this.CacheDraft.has(cid)) {
+        lastContent = this.CacheDraft.get(cid).lastContent;
+      }
+      this.CacheDraft.set(cid, {
+        editorValue,
+        lastContent,
+      });
+      
+      var tempDraft=this.CacheDraft.get(cid);
+      //console.log("qxj editorValue:"+editorValue+",tempDraft:"+JSON.stringify(tempDraft)+"lastContent:"+lastContent);
+
+      this.updateContact({
+        id: cid,
+        lastContent: `<span style="color:red;">[草稿]</span><span>${this.lastContentRender(
+          { type: "text", content: editorValue },
+        )}</span>`,
+      });
+    },
+    /**
+     * 清空联系人草稿信息
+     */
+    clearDraft(contactId) {
+      const draft = this.CacheDraft.get(contactId);
+      if (draft) {
+        const currentContent = this.findConversation(contactId).lastContent;
+        console.log("qxj currentContent:"+currentContent+",lastContent:"+JSON.stringify(draft));
+        //if (currentContent.indexOf('<span style="color:red;">[草稿]</span>') === 0) {
+          this.updateContact({
+            id: contactId,
+            lastContent: draft.lastContent
+          });
+        //}
+        this.CacheDraft.remove(contactId);
+      }
+    },
+    /**
+     * 改变聊天对象
+     * @param contactId 联系人 id
+     */
+    async changeContact(contactId, menuName) {
+      if (menuName) {
+           this.changeMenu(menuName);
+      } else {
+        if (this._changeContactLock || this.currentContactId == contactId){
+           console.log("qxj _changeContactLock currentContactId:"+this.currentContactId+" contactId:"+contactId);
+           return false;
+        }
+      }
+      //保存上个聊天目标的草稿
+      if (this.currentContactId) {
+        const editorValue = clearHtmlExcludeImg(this.getEditorValue()).trim();
+        if (editorValue) {
+          this.setDraft(this.currentContactId, editorValue);
+          this.setEditorValue();
+        } else {
+          this.clearDraft(this.currentContactId);
+        }
+      }
+
+      this.currentContactId = contactId;
+      if (!this.currentContactId) return false;
+      this.$emit("change-conversation", this.currentContact, this);
+      if (isFunction(this.currentContact.renderContainer) || this.activeSidebar == DEFAULT_MENU_CONTACTS) {
+          return;
+      }
+      //填充草稿内容
+      const draft = this.CacheDraft.get(contactId);
+      if (draft) this.setEditorValue(draft.editorValue);
+
+      if (this.CacheMessageLoaded.has(contactId)) {
+        this.$refs.messages.loaded();
+      } else {
+        this.$refs.messages.resetLoadState();
+      }
+      if (!allMessages[contactId]) {
+          this.updateCurrentMessages();
+          this._emitPullMessages(isEnd => {
+              this.messageViewToBottom();
+          });
+      } else {
+          setTimeout(() => {
+              this.updateCurrentMessages();
+              this.messageViewToBottom();
+          }, 0);
+      }
+    },
+    /**
+     * 删除一条聊天消息
+     * @param messageId 消息 id
+     * @param contactId 联系人 id
+     */
+    removeMessage(messageId) {
+      const message = this.findMessage(messageId);
+      if (!message) return false;
+      const index = allMessages[message.toContactId].findIndex(
+        ({ id }) => id == messageId,
+      );
+      allMessages[message.toContactId].splice(index, 1);
+      return true;
+    },
+    /**
+     * 修改聊天一条聊天消息
+     * @param {Message} data 根据 data.id 查找聊天消息并覆盖传入的值
+     * @param contactId 联系人 id
+     */
+    updateMessage(message) {
+      if (!message.id) return false;
+      let historyMessage = this.findMessage(message.id);
+      if (!historyMessage) return false;
+      historyMessage = Object.assign(historyMessage, message, {
+        toContactId: historyMessage.toContactId,
+      });
+      return true;
+    },
+    /**
+     * 手动更新对话消息
+     * @param {String} messageId 消息ID,如果为空则更新当前聊天窗口的所有消息
+     */
+    forceUpdateMessage(messageId) {
+      if (!messageId) {
+        this.$refs.messages.$forceUpdate();
+      } else {
+        const components = this.$refs.messages.$refs.message;
+        if (components) {
+          const messageComponent = components.find(
+            com => com.$attrs.message.id == messageId,
+          );
+          if (messageComponent) messageComponent.$forceUpdate();
+        }
+      }
+    },
+    _customContainerReady(render, cacheDrive, key) {
+      if (isFunction(render) && !cacheDrive.has(key)) {
+        cacheDrive.set(key, render.call(this));
+      }
+    },
+    /**
+     * 切换左侧按钮
+     * @param {String} name 按钮 name
+     */
+    changeMenu(name) {
+      this.$emit("change-menu", name);
+      this.activeSidebar = name;
+    },
+    /**
+     * 初始化编辑框的 Emoji 表情列表,是 Lemon-editor.initEmoji 的代理方法
+     * @param {Array<Emoji,EmojiItem>} data emoji 数据
+     * Emoji = {label: 表情,children: [{name: wx,title: 微笑,src: url}]} 分组
+     * EmojiItem = {name: wx,title: 微笑,src: url} 无分组
+     */
+    initEmoji(data) {
+      let flatData = [];
+      this.$refs.editor.initEmoji(data);
+      if (data[0].label) {
+        data.forEach(item => {
+          flatData.push(...item.children);
+        });
+      } else {
+        flatData = data;
+      }
+      flatData.forEach(({ name, src }) => (emojiMap[name] = src));
+    },
+    initEditorTools(data) {
+      //this.editorTools = data;
+      this.editorTools = data;
+      //this.$refs.editor.initTools(data);
+    },
+    /**
+     * 初始化左侧按钮
+     * @param {Array<Menu>} data 按钮数据
+     */
+    initMenus(data) {
+      const defaultMenus = [
+        {
+          name: DEFAULT_MENU_LASTMESSAGES,
+          title: "聊天",
+          unread: 0,
+          click: null,
+          render: menu => {
+            return <i class="lemon-icon-message" />;
+          },
+          isBottom: false,
+        },
+        {
+          name: DEFAULT_MENU_CONTACTS,
+          title: "通讯录",
+          unread: 0,
+          click: null,
+          render: menu => {
+            return <i class="lemon-icon-addressbook" />;
+          },
+          isBottom: false,
+        },
+      ];
+      let menus = [];
+      if (Array.isArray(data)) {
+        const indexMap = {
+          messages: 0,
+          contacts: 1,
+        };
+        const indexKeys = Object.keys(indexMap);
+        menus = data.map(item => {
+          if (indexKeys.includes(item.name)) {
+            return {
+              ...defaultMenus[indexMap[item.name]],
+              ...item,
+              ...{ renderContainer: null },
+            };
+          }
+          if (item.renderContainer) {
+            this._customContainerReady(
+              item.renderContainer,
+              this.CacheMenuContainer,
+              item.name,
+            );
+          }
+          return item;
+        });
+      } else {
+        menus = defaultMenus;
+      }
+      this.menus = menus;
+    },
+    /**
+     * 初始化联系人数据
+     * @param {Array<Contact>} data 联系人列表
+     */
+    initContacts(data) {
+      this.contacts = data;
+      this.sortContacts();
+      if(!!this.contacts>0){
+          this.currentNewContactId=(this.contacts[0]).id;
+      }
+    },
+      /**
+     * 初始化会话数据
+     * @param {Array<Contact>} data 会话列表
+     */
+    initConversations(data) {
+      this.conversations = data;
+      this.sortConversations();
+      
+    },
+
+    /**
+     * 使用 联系人的 index 值进行排序
+     */
+    sortContacts() {
+      this.contacts.sort((a, b) => {
+        if (!a.index) return;
+        return a.index.localeCompare(b.index);
+      });
+    },
+    sortConversations() {
+      this.conversations.sort((a, b) => {
+        if (!a.index) return;
+        return a.index.localeCompare(b.index);
+      });
+    },
+    appendContact(contact) {
+      if (isEmpty(contact.id) || isEmpty(contact.displayName)) {
+        console.error("id | displayName cant be empty");
+        return false;
+      }
+      if (this.hasContact(contact.id)) return true;
+      this.contacts.push(
+        Object.assign(
+          {
+            id: "",
+            displayName: "",
+            avatar: "",
+            index: "",
+            unread: 0,
+            lastSendTime: "",
+            lastContent: "",
+          },
+          contact,
+        ),
+      );
+      return true;
+    },
+
+     appendConversation(conversation) {
+      if (isEmpty(conversation.conversationId) || isEmpty(conversation.displayName)) {
+        console.error("id | displayName cant be empty");
+        return false;
+      }
+      if (this.hasConversation(conversation.conversationId)) return true;
+      let insConversation=Object.assign({
+            conversationId: "",
+            displayName: "",
+            avatar: "",
+            index: "",
+            unread: 1,
+            lastSendTime: "",
+            lastContent: "",
+          },conversation
+        );
+       console.log("qxj insConversation:"+JSON.stringify(insConversation));
+       this.conversations.unshift(insConversation);
+      //  this.updateContact(insConversation);
+       //this.conversations.push(insConversation);
+      return true;
+    },
+    removeContact(id) {
+      const index = this.findContactIndexById(id);
+      if (index === -1) return false;
+      this.contacts.splice(index, 1);
+      this.CacheDraft.remove(id);
+      this.CacheMessageLoaded.remove(id);
+      return true;
+    },
+    removeConversations(conversationId) {
+      const index = this.findConversationIndexById(conversationId);
+      if (index === -1) return false;
+      this.conversations.splice(index, 1);
+      // this.CacheDraft.remove(id);
+      // this.CacheMessageLoaded.remove(id);
+      return true;
+    },
+    topPopConversations(conversation,isNotDel) {  //置顶
+      if(!isNotDel){
+          this.removeConversations(conversation.conversationId);
+      }
+      this.conversations.unshift(conversation);
+    },
+    /**
+     * 修改会话数据
+     * @param {Contact} data 修改的数据,根据 Contact.id 查找联系人并覆盖传入的值
+     */
+    updateContact(data) {
+      const conversationId = data.conversationId;
+      const index = this.findConversationIndexById(conversationId);  
+      if (index !== -1) {
+        // if(isString(data.unread)) {
+        //     if (unread.indexOf("+") === 0 || unread.indexOf("-") === 0) {
+        //       data.unread =parseInt(unread) + parseInt(this.conversations[index].unread);
+        //     }
+        // }
+        this.$set(this.conversations, index, {
+          ...this.conversations[index],
+          ...data,
+        });
+      }
+    },
+    updateContact1(data) {
+      const contactId = data.id;
+      delete data.id;
+      const index = this.findContactIndexById(contactId);  
+      if (index !== -1) {
+        const { unread } = data;
+        if (isString(unread)) {
+          if (unread.indexOf("+") === 0 || unread.indexOf("-") === 0) {
+            data.unread =parseInt(unread) + parseInt(this.contacts[index].unread);
+          }
+        }
+        this.$set(this.contacts, index, {
+          ...this.contacts[index],
+          ...data,
+        });
+      }
+    },
+    /**
+     * 根据 id 查找联系人的索引
+     * @param contactId 联系人 id
+     * @return {Number} 联系人索引,未找到返回 -1
+     */
+    findContactIndexById(contactId) {
+      return this.contacts.findIndex(item => item.id == contactId);
+    },
+    findConversationIndexById(conversationId) {
+      return this.conversations.findIndex(item => item.conversationId == conversationId);
+    },
+    /**
+     * 根据 id 查找判断是否存在联系人
+     * @param contactId 联系人 id
+     * @return {Boolean}
+     */
+    hasContact(contactId) {
+      return this.findContactIndexById(contactId) !== -1;
+    },
+    hasConversation(conversationId) {
+      return this.findConversationIndexById(conversationId) !== -1;
+    },
+    findMessage(messageId) {
+      for (const key in allMessages) {
+        const message = allMessages[key].find(({ id }) => id == messageId);
+        if (message) return message;
+      }
+    },
+    findContact(contactId) {
+      return this.getContacts().find(({ id }) => id == contactId);
+    },
+    findConversation(currentContactId) {
+       return this.conversations.find(item =>  item.conversationId == currentContactId) || {};
+    },
+    /**
+     * 返回所有联系人
+     * @return {Array<Contact>}
+     */
+    getContacts() {
+      return this.contacts;
+    },
+      /**
+     * 返回所有会话
+     * @return {Array<Contact>}
+     */
+    getConversations() {
+      return this.conversations;
+    },
+    //返回当前聊天窗口联系人信息
+    getCurrentContact() {
+      return this.currentContact;
+    },
+    getCurrentMessages() {
+      return this.currentMessages;
+    },
+    setEditorValue(val = "") {
+      if (!isString(val)) return false;
+      this.$refs.editor.setValue(this.emojiNameToImage(val));
+    },
+    getEditorValue() {
+      return this.$refs.editor.getFormatValue();
+    },
+    /**
+     * 清空某个联系人的消息,切换到该联系人时会重新触发pull-messages事件
+     */
+    clearMessages(contactId) {
+      if (contactId) {
+        delete allMessages[contactId];
+        this.CacheMessageLoaded.remove(contactId);
+        this.CacheDraft.remove(contactId);
+      } else {
+        allMessages = {};
+        this.CacheMessageLoaded.remove();
+        this.CacheDraft.remove();
+      }
+      return true;
+    },
+    /**
+     * 返回所有消息
+     * @return {Object<Contact.id,Message>}
+     */
+    getMessages(contactId) {
+      return (contactId ? allMessages[contactId] : allMessages) || [];
+    },
+    changeDrawer(params) {
+      this.drawerVisible = !this.drawerVisible;
+      if (this.drawerVisible == true) this.openDrawer(params);
+    },
+    // openDrawer(data) {
+    //   renderDrawerContent = data || new Function();
+    //   this.drawerVisible = true;
+    // },
+    openDrawer(params) {
+      renderDrawerContent = isFunction(params)
+        ? params
+        : params.render || new Function();
+      const wrapperWidth = this.$refs.wrapper.clientWidth;
+      const wrapperHeight = this.$refs.wrapper.clientHeight;
+      let width = params.width || 200;
+      let height = params.height || wrapperHeight;
+      let offsetX = params.offsetX || 0;
+      let offsetY = params.offsetY || 0;
+      const position = params.position || "right";
+      if (isString(width)) width = wrapperWidth * toPoint(width);
+      if (isString(height)) height = wrapperHeight * toPoint(height);
+      if (isString(offsetX)) offsetX = wrapperWidth * toPoint(offsetX);
+      if (isString(offsetY)) offsetY = wrapperHeight * toPoint(offsetY);
+
+      this.$refs.drawer.style.width = `${width}px`;
+      this.$refs.drawer.style.height = `${height}px`;
+
+      let left = 0;
+      let top = 0;
+      let shadow = "";
+      if (position == "right") {
+        left = wrapperWidth;
+      } else if (position == "rightInside") {
+        left = wrapperWidth - width;
+        shadow = `-15px 0 16px -14px rgba(0,0,0,0.08)`;
+      } else if (position == "center") {
+        left = wrapperWidth / 2 - width / 2;
+        top = wrapperHeight / 2 - height / 2;
+        shadow = `0 0 20px rgba(0,0,0,0.08)`;
+      }
+      left += offsetX;
+      top += offsetY + -1;
+      this.$refs.drawer.style.top = `${top}px`;
+      this.$refs.drawer.style.left = `${left}px`;
+      this.$refs.drawer.style.boxShadow = shadow;
+
+      this.drawerVisible = true;
+    },
+    closeDrawer() {
+      this.drawerVisible = false;
+    },
+  },
+};
+
+
+
+</script>
+<style lang="stylus">
+bezier = cubic-bezier(0.645, 0.045, 0.355, 1)
+@import '../styles/utils/index'
+
++b(lemon-wrapper)
+  display flex
+  font-size 14px
+  font-family "Microsoft YaHei"
+  //mask-image radial-gradient(circle, white 100%, black 100%)
+  background #efefef
+  transition all .4s bezier
+  position relative
+  p
+    margin 0
+  img
+    vertical-align middle
+    border-style none
++b(lemon-menu)
+  flex-column()
+  align-items center
+  width 60px
+  background #1d232a
+  padding 15px 0
+  position relative
+  user-select none
+  +e(bottom)
+    flex-column()
+    position absolute
+    bottom 0
+  +e(avatar)
+    margin-bottom 20px
+    cursor pointer
+  +e(item)
+    color #999
+    cursor pointer
+    padding 14px 10px
+    max-width 100%
+    +m(active)
+      color #0fd547
+    &:hover:not(.lemon-menu__item--active)
+      color #eee
+    word-break()
+    > *
+      font-size 24px
+    .ant-badge-count
+      display inline-block
+      padding 0 4px
+      height 18px
+      line-height 16px
+      min-width 18px
+    .ant-badge-count
+    .ant-badge-dot
+      box-shadow 0 0 0 1px #1d232a
++b(lemon-sidebar)
+  width 250px
+  background #efefef
+  display flex
+  flex-direction column
+  +e(scroll)
+    overflow-y auto
+    scrollbar-light()
+  +e(label)
+    padding 6px 14px 6px 14px
+    color #666
+    font-size 12px
+    margin 0
+    text-align left
+  +b(lemon-contact--active)
+    background #d9d9d9
++b(lemon-container)
+  flex 1
+  flex-column()
+  background #f4f4f4
+  word-break()
+  position relative
+  z-index 10
+  +e(title)
+    padding 15px 15px
+  +e(displayname)
+    font-size 16px
++b(lemon-vessel)
+  display flex
+  flex 1
+  min-height 100px
+  +e(left)
+    display flex
+    flex-direction column
+    flex 1
+  +e(right)
+    flex none
++b(lemon-messages)
+  flex 1
+  height auto
++b(lemon-drawer)
+  position absolute
+  top 0
+  overflow hidden
+  background #f6f6f6
+  z-index 11
+  display none
++b(lemon-wrapper)
+  +m(drawer-show)
+    +b(lemon-drawer)
+      display block
++b(lemon-contact-info)
+  flex-column()
+  justify-content center
+  align-items center
+  height 100%
+  h4
+    font-size 16px
+    font-weight normal
+    margin 10px 0 20px 0
+    user-select none
+.lemon-wrapper--theme-blue
+  .lemon-message__content
+    background #f3f3f3
+    &::before
+      border-right-color #f3f3f3
+  .lemon-message--reverse .lemon-message__content
+    background #e6eeff
+    &::before
+      border-left-color #e6eeff
+  .lemon-container
+    background #fff
+  .lemon-sidebar
+    background #f9f9f9
+    .lemon-contact
+      background #f9f9f9
+      &:hover:not(.lemon-contact--active)
+        background #f1f1f1
+      &--active
+        background #e9e9e9
+  .lemon-menu
+    background #096bff
+  .lemon-menu__item
+    color rgba(255,255,255,0.4)
+    &:hover:not(.lemon-menu__item--active)
+      color rgba(255,255,255,0.6)
+    &--active
+      color #fff
+      text-shadow 0 0 10px rgba(2,48,118,0.4)
+.lemon-wrapper--simple
+  .lemon-menu
+  .lemon-sidebar
+    display none
+.lemon-wrapper--simple
+  .lemon-menu
+  .lemon-sidebar
+    display none
++b(lemon-contextmenu)
+  border-radius 4px
+  font-size 14px
+  font-variant tabular-nums
+  line-height 1.5
+  color rgba(0, 0, 0, 0.65)
+  z-index 9999
+  background-color #fff
+  border-radius 6px
+  box-shadow 0 2px 8px rgba(0, 0, 0, 0.06)
+  position absolute
+  transform-origin 50% 150%
+  box-sizing border-box
+  user-select none
+  overflow hidden
+  min-width 120px
+  +e(item)
+    font-size 14px
+    line-height 16px
+    padding 10px 15px
+    cursor pointer
+    display flex
+    align-items center
+    color #333
+    > span
+      display inline-block
+      flex none
+      //max-width 100px
+      ellipsis()
+    &:hover
+      background #f3f3f3
+      color #000
+    &:active
+      background #e9e9e9
+  +e(icon)
+    font-size 16px
+    margin-right 4px
+</style>

+ 3 - 1
src/components/LemonUI/index.js

@@ -17,6 +17,7 @@ import LemonMessageVideo from "./components/message/video";
 
 
 import LemonIMUI from "./components/index";
+import LemonRecords from "./components/records";
 import "./styles/common/index.styl";
 const version = "1.4.2";
 const components = [
@@ -35,7 +36,8 @@ const components = [
   lemonMessageFile,
   lemonMessageEvent,
   LemonMessageVoice,
-  LemonMessageVideo
+  LemonMessageVideo,
+  LemonRecords
 ];
 const install = (Vue) => {
   Vue.directive("LemonContextmenu", Contextmenu);

+ 0 - 1
src/layout/index.vue

@@ -100,7 +100,6 @@ export default {
       
   },
   mounted () {
-       console.log("qxj mounted companyUser:"+JSON.stringify(this.companyUser));
        if(this.companyUser.userType=="00"){
           this.initSocket(this.companyUser.userId);
        }

+ 1 - 2
src/utils/WebsocketHeartbeat.js

@@ -3,7 +3,7 @@
  *
  * @param {Object} opts
  * {
- *  url                  websocket链接地址
+ *  url websocket链接地址
  *  pingTimeout 未收到消息多少秒之后发送ping请求,默认15000毫秒
     pongTimeout  发送ping之后,未收到消息超时时间,默认10000毫秒
     reconnectTimeout
@@ -28,7 +28,6 @@
             pingMsg: pingMsg
         };
         this.ws = null;//websocket实例
-    
         //override hook function
         this.onclose = () => {};
         this.onerror = () => {};

+ 35 - 4
src/views/qw/forbiddenMessage/index.vue

@@ -72,6 +72,7 @@
       <el-table-column type="selection" width="40" align="center" />
       <el-table-column label="公司" width="200" align="center" prop="companyName" />
       <el-table-column label="员工" width="100" align="center" prop="companyUserName" />
+      <el-table-column label="企微账号" width="100" align="center" prop="account" />
       <el-table-column label="发送时间" width="200" align="center" prop="sendTime">
         <template slot-scope="scope">
           {{ convertTimestampToTime(scope.row.sendTime) }}
@@ -79,7 +80,7 @@
       </el-table-column>
       <el-table-column label="提示" align="center" prop="forbiddenMessage">
         <template slot-scope="scope">
-          <div style="font-size: 16px; color: red;">
+          <div style="font-size: 14px; color: #ff0000">
             {{ scope.row.forbiddenMessage }}
           </div>
         </template>
@@ -89,7 +90,7 @@
           <el-button
             size="mini"
             type="text"
-            @click="handleUpdate(scope.row)"
+            @click="handleLookMsg(scope.row)"
             v-hasPermi="['qw:forbiddenMessage:edit']"
           >查看</el-button>
         </template>
@@ -128,16 +129,22 @@
         <el-button @click="cancel">取 消</el-button>
       </div>
     </el-dialog>
+
+
+     <el-dialog :visible.sync="dialogContextVisible" width="70%">
+        <SegRecords :qwUser="qwUser" :conversationId="conversationId"  :isContext=true :msgType=0  ref="sIMUI4"></SegRecords>
+    </el-dialog>
   </div>
 </template>
 
 <script>
 import { listForbiddenMessage, getForbiddenMessage, delForbiddenMessage, addForbiddenMessage, updateForbiddenMessage, exportForbiddenMessage } from "@/api/qw/forbiddenMessage";
 import Editor from '@/components/Editor';
+import SegRecords from '@/components/LemonUI/components/chatrecords/segrecords.vue'
 
 export default {
   name: "ForbiddenMessage",
-  components: { Editor },
+  components: { Editor, SegRecords },
   data() {
     return {
       // 遮罩层
@@ -160,6 +167,9 @@ export default {
       title: "",
       // 是否显示弹出层
       open: false,
+      qwUser:{},
+      conversationId:null,
+      dialogContextVisible:false,
       // 查询参数
       queryParams: {
         pageNum: 1,
@@ -260,6 +270,20 @@ export default {
         this.title = "修改企微违禁消息";
       });
     },
+    handleLookMsg(row){
+          console.log("qxj row:"+JSON.stringify(row));
+          this.qwUser.userId=row.qwUserId;
+          this.qwUser.nickName=row.nickName;
+          this.qwUser.avatar=row.avatar;
+          this.conversationId=row.conversationId;
+          this.dialogContextVisible=true;
+          setTimeout(() => {
+                const sIMUI = this.$refs["sIMUI4"];
+                console.log("点击了上下文", sIMUI);
+                let message={id:row.messageId};
+                sIMUI.openContextBox(message);
+          }, 50);
+    },
     /** 提交按钮 */
     submitForm() {
       this.$refs["form"].validate(valid => {
@@ -313,4 +337,11 @@ export default {
     }
   }
 };
-</script>
+</script>
+
+
+<style lang="scss" scoped>
+    /deep/.el-dialog__headerbtn{
+         top:10px;
+    }
+</style>