zory před 2 týdny
rodič
revize
863060f9f2
3 změnil soubory, kde provedl 421 přidání a 8 odebrání
  1. 19 0
      src/api/model/chat.js
  2. 217 8
      src/components/imFloat/imFloat.vue
  3. 185 0
      src/utils/emoji.js

+ 19 - 0
src/api/model/chat.js

@@ -0,0 +1,19 @@
+import config from "@/config";
+import http from "@/utils/request";
+
+export default {
+    list: {
+        url: `${config.API_URL}/service/chat/list`,
+        name: "-",
+        get: async function (data = {}) {
+            return await http.get(this.url, data);
+        },
+    },
+    save: {
+        url: `${config.API_URL}/category/save`,
+        name: "-",
+        post: async function (data = {}) {
+            return await http.post(this.url, data);
+        },
+    },
+}

+ 217 - 8
src/components/imFloat/imFloat.vue

@@ -22,11 +22,26 @@
             </div>
             <el-main class="nopadding">
                 <el-container>
-                    <el-aside width="200px" v-loading="menuloading">
-                        
+                    <el-aside width="300px" v-loading="menuloading">
+                      <div class="chat-contact">
+                        <div :class="checkChat==index?'contact-item active':'contact-item'" v-for="(item,index) in chatContact" :key="index" @click="checkChatItem(index)">
+                          <div class="img"><el-image :src="item.avatar" fit="contain" style="width: 40px; height: 40px"></el-image></div>
+                          <div class="kefu-store">
+                            <div class="name">{{item.user.nickname}} <span v-if="item.last.num > 0">{{item.last.num}}</span></div>
+                            <div class="desc" v-if="item.last.type=='text'">{{item.last.content}}</div>
+                            <div class="desc" v-if="item.last.type=='order'">[订单消息]</div>
+                            <div class="desc" v-if="item.last.type=='image'">[图片消息]</div>
+                            <div class="desc" v-if="item.last.type=='video'">[视频消息]</div>
+                            <div class="desc" v-if="item.last.type=='pay'">[支付消息]</div>
+                          </div>
+                          <div class="time">
+                            {{item.last.create_at}}
+                          </div>
+                        </div>
+                      </div>
                     </el-aside>
-                    <el-container>
-                        <el-header><div class="msg-title">与xxx的对话</div></el-header>
+                    <el-container v-if="chatItem">
+                        <el-header><div class="msg-title">与{{ chatItem.user.nickname }}的对话</div></el-header>
                         <el-main class="nopadding" ref="main">
                             <div class="chat-container">
                                 <div class="message-list" ref="messageListRef">
@@ -36,9 +51,46 @@
                                         type="textarea"
                                         :rows="3"
                                         v-model="inputMessage"
-                                        placeholder="请输入消息..."
+                                        placeholder="请输入消息...按 Ctrl+Enter 换行"
+                                        @keyup.enter.native="handleKeyCode"
+                                        @keydown.native="handleKeyCode"
                                     ></el-input>
-                                    <el-button type="primary" style="margin-top: 10px;" @click="sendMessage">发送</el-button>
+                                    <div class="send-btn-group">
+                                        <div class="send-emoji">
+                                            <div class="emoji-item" @click="showEmoji">
+                                                <el-popover placement="top" :width="400" trigger="click">
+                                                    <template #reference>
+                                                        <el-image style="width:25px;height:25px;" src="https://jymini.oss-cn-guangzhou.aliyuncs.com/pc/face.svg"></el-image>
+                                                    </template>
+                                                    <div class="swiper-item-box">
+                                                        <div class="flex_r swiper-item-box-l" v-for="(im, ix) in emojiList" :key="ix">
+                                                            <div
+                                                                class="icon_ emoji-item"
+                                                                v-for="(item, index) in im"
+                                                                :key="index"
+                                                                :style="{ opacity: ix === opacityGroup && (index == 5 || index == 6 || index == 7) ? opacity : 1 }"
+                                                            >
+                                                                <el-image class="img" :src="emojiUrl + item.image" @click="chooseEmoji(item.text)"></el-image>
+                                                            </div>
+                                                        </div>
+                                                    </div>
+                                                </el-popover>
+                                            </div>
+                                            <div class="emoji-item" @click="showUpload">
+                                                <el-tooltip effect="dark" content="上传图片" placement="top-start">
+                                                    <el-image style="width:25px;height:25px;" src="https://jymini.oss-cn-guangzhou.aliyuncs.com/pc/more.svg"></el-image>
+                                                </el-tooltip>
+                                            </div>
+                                            <div class="emoji-item" @click="showQuick">
+                                                <el-tooltip effect="dark" content="快捷回复" placement="top-start">
+                                                    <el-image style="width:25px;height:25px;" src="https://jymini.oss-cn-guangzhou.aliyuncs.com/pc/order.svg"></el-image>
+                                                </el-tooltip>
+                                            </div>
+                                        </div>
+                                        <div class="send-btn-right">
+                                            <el-button type="primary" @click="sendMessage">发送</el-button>
+                                        </div>
+                                    </div>
                                 </div>
                             </div>
                         </el-main>
@@ -56,11 +108,15 @@
 
 <script>
 import { Push } from "@/utils/push";
+import { emojiMap } from "@/utils/emoji";
 var pushObj = null;
+let height2 = null;
+const emojiUrl = 'https://imgcache.qq.com/open/qcloud/tim/assets/emoji/';
 export default {
     name: 'GlobalIM',
     data() {
         return {
+            emojiUrl,
             loading:false,
             visible: false,           // 聊天窗口可见性
             unreadCount: 0,          // 未读消息数量
@@ -69,11 +125,20 @@ export default {
             messages: [              // 消息列表
                 { id: 1, name: '系统助手', avatar: '', text: '欢迎使用 SCUI!', time: '10:00', self: false },
                 { id: 2, name: '我', avatar: '', text: '你好,这个全局IM功能不错', time: '10:01', self: true },
-            ]
+            ],
+            wsAuth:"http://127.0.0.1:9881/plugin/webman/push/auth",
+            wsUrl: 'ws://127.0.0.1:3131',
+            page:1,
+            size:10,
+            chatContact:[],
+            checkChat:0,
+            chatItem:null,
+            emojiList:[]
         }
     },
     mounted() {
         console.log("pushObj")
+        this.initEmoji()
         // this.simulateNewMessage()
     },
     beforeDestroy() {
@@ -82,13 +147,80 @@ export default {
         // }
     },
     methods: {
+        chooseEmoji(){
+
+        },
+        initEmoji() {
+			let newList = [];
+			let i = 1;
+			for (let key in emojiMap) {
+				let obj = {};
+				obj['index'] = i;
+				obj['text'] = key;
+				obj['image'] = emojiMap[key];
+				i++;
+				newList.push(obj);
+			}
+			var list = [];
+			let A = newList.filter((item, index) => {
+				return (index + 1) % 8 === 0;
+			});
+			A.unshift({ index: 0 });
+			A.push({ index: newList.length });
+			this.emojiList = A.map((item, index) => {
+				return newList.slice(A[index].index, A[index + 1]?.index || newList.length);
+			});
+            console.log(this.emojiList)
+			// this.scroll({ detail: { scrollTop: 10 } });
+		},
+        sendMessage(){
+            if (!this.inputMessage) return ;
+            this.inputMessage = ""
+        },
+        handleKeyCode(event){
+            console.log(event)
+            if (event.keyCode == 13) {
+                if (!event.ctrlKey) {
+                    event.preventDefault();
+                    this.sendMessage()
+                } else {
+                    this.inputMessage += "\n";
+                }
+            } else {
+                return ;
+            }
+        },
+        checkChatItem(index){
+            this.checkChat = index;
+            this.chatItem = this.chatContact[index]
+        },
+        initPush(){
+          var _this = this;
+          this.pushObj = new Push({
+            "url":this.wsUrl,
+            "app_key":"265c33b73d5c04f918978577df2c48d2",
+            "auth":this.wsAuth
+          });
+          var user_channel = this.pushObj.subscribe('service-' + this.myid);
+          user_channel.on('message', function (data) {
+            // console.log(data);
+            // _this.formatMsg(data);
+          })
+        },
         // 切换聊天窗口
-        toggleChat() {
+        async toggleChat() {
             this.visible = !this.visible
+            this.chatContact = [];
             if (this.visible) {
                 // 打开窗口时清除未读角标
                 this.unreadCount = 0
             }
+            var resp = await this.$API.chat.list.get({page:this.page,pageSize:this.size})
+            if (resp.code == 0) {
+              return this.$message.error(resp.msg)
+            }
+            this.chatContact = this.chatContact.concat(resp.data.rows)
+            this.chatItem = this.chatContact[0]
         }
     }
 }
@@ -96,6 +228,83 @@ export default {
 
 <style scoped lang="scss">
 .msg-title{font-size: 18px;font-weight: bold;}
+.contact-item{display: flex;align-items: center;background-color: #fff;padding: 10px;border-bottom: 1px solid #f8f8f8;cursor: pointer;}
+.contact-item.active{background-color: #f8f8f8;}
+.contact-item .kefu-store{margin-left: 10px;}
+.contact-item .kefu-store .name{font-size: 14px;color: #333;display: flex;align-items: center;}
+.contact-item .kefu-store .name text{background-color: #f00;color: #fff;width: 20px;height: 20px;display: flex;align-items: center;justify-content: center;border-radius: 20px;font-size: 12px;margin-left: 10px;}
+.contact-item .kefu-store .desc{font-size: 12px;color: #666;margin-top: 5px;}
+.contact-item .time{margin-left: auto;margin-right: 0;font-size: 12px;color: #666;}
+.send-btn-group{margin-top: 10px;display: flex;align-items: center;justify-content: space-between;}
+.send-btn-group .send-emoji{display: flex;align-items: center;gap: 15px;cursor: pointer;}
+
+.swiper-item-box {
+    position: relative;
+    z-index: 1;
+    box-sizing: border-box;
+    width: 100%;
+    height: 100%;
+    flex-wrap: wrap;
+    align-items: flex-start;
+
+    .swiper-item-box-l {
+        // width: calc(62.5vw);
+        width: calc(100%);
+        flex-wrap: wrap;
+        align-items: flex-start;
+    }
+    .swiper-item-box-r {
+        width: calc(37.5%);
+        flex-wrap: wrap;
+        align-items: flex-start;
+    }
+
+    .emoji-item {
+        width: calc(12.5%);
+        height: calc(12.5%);
+        flex-shrink: 0;
+        transition: all 0.1s;
+        .img {
+            width: 70%;
+            height: 70%;
+            cursor: pointer;
+        }
+    }
+}
+.flex_r {
+    display: flex;
+    flex-direction: row;
+}
+.swiper-item-box-b {
+    width: calc(38%);
+    position: absolute;
+    z-index: 99;
+    right: 0rpx;
+    bottom: 0px;
+    padding: 0 0 40rpx 0;
+    // background-color: #000;
+    background-image: linear-gradient(to top, #ececec, #ececec, #ececec, #ececec, #ececec, rgba(0, 0, 0, 0));
+}
+.swiper-item-box-delete {
+    width: 116rpx;
+    height: calc(12.5%);
+    border-radius: 10rpx;
+    margin-right: 20rpx;
+    background-color: #fff;
+    .img {
+        width: 45%;
+        height: 45%;
+        margin-right: 4rpx;
+    }
+}
+.swiper-item-box-button {
+    width: 116rpx;
+    height: calc(12.5vw);
+    border-radius: 10rpx;
+    margin-right: 10rpx;
+    background-color: #05c160;
+}
+
 .global-im {
   .im-trigger {
     position: fixed;

+ 185 - 0
src/utils/emoji.js

@@ -0,0 +1,185 @@
+let font_size = {
+	page_font_size: 0,
+	page_font_size_max: 2,
+	page_font_size_max_plus: 4,
+	page_font_size_max_plus_pro: 6
+};
+export class EmojiDecoder {
+	emojiMap = null;
+	url = "";
+	patterns = [];
+	metaChars = /[[\]{}()*+?.\\|^$\-,&#\s]/g;
+
+	constructor(url, emojiMap) {
+		this.url = url || '';
+		this.emojiMap = emojiMap || {};
+		for (let i in this.emojiMap) {
+			if (this.emojiMap.hasOwnProperty(i)) {
+				this.patterns.push('(' + i.replace(this.metaChars, "\\$&") + ')');
+			}
+		}
+	}
+
+	decode(text, size, top = '4px') {
+		if (!size) {
+			size = `22px`
+		}
+		return text.replace(new RegExp(this.patterns.join('|'), 'g'), (match) => {
+			return typeof this.emojiMap[match] != 'undefined' ?
+				`<img style="position: relative;top: ${top};" height="${size}" width="${size}" src="${this.url}${this.emojiMap[match]}" />` :
+				match;
+		}).replace(/\n/g, '<br/>');
+	}
+	// 无需换行
+	decodeNo(text, size = '22rpx', top = '4px') {
+		return text.replace(new RegExp(this.patterns.join('|'), 'g'), (match) => {
+			return typeof this.emojiMap[match] != 'undefined' ?
+				`<img style="position: relative;top: ${top};" height="${size}" width="${size}" src="${this.url}${this.emojiMap[match]}" />` :
+				match;
+		});
+	}
+};
+export const emojiMap = {
+	"[微笑]": "emoji_49@2x.png",
+	"[NO]": "emoji_0@2x.png",
+	"[OK]": "emoji_1@2x.png",
+	"[下雨]": "emoji_2@2x.png",
+	"[么么哒]": "emoji_3@2x.png",
+	"[乒乓]": "emoji_4@2x.png",
+	"[便便]": "emoji_5@2x.png",
+	"[信封]": "emoji_6@2x.png",
+	"[偷笑]": "emoji_7@2x.png",
+	"[傲慢]": "emoji_8@2x.png",
+	"[再见]": "emoji_9@2x.png",
+	"[冷汗]": "emoji_10@2x.png",
+	"[凋谢]": "emoji_11@2x.png",
+	"[刀]": "emoji_12@2x.png",
+	"[删除]": "emoji_13@2x.png",
+	"[勾引]": "emoji_14@2x.png",
+	"[发呆]": "emoji_15@2x.png",
+	"[发抖]": "emoji_16@2x.png",
+	"[可怜]": "emoji_17@2x.png",
+	"[可爱]": "emoji_18@2x.png",
+	"[右哼哼]": "emoji_19@2x.png",
+	"[右太极]": "emoji_20@2x.png",
+	"[右车头]": "emoji_21@2x.png",
+	"[吐]": "emoji_22@2x.png",
+	"[吓]": "emoji_23@2x.png",
+	"[咒骂]": "emoji_24@2x.png",
+	"[咖啡]": "emoji_25@2x.png",
+	"[啤酒]": "emoji_26@2x.png",
+	"[嘘]": "emoji_27@2x.png",
+	"[回头]": "emoji_28@2x.png",
+	"[困]": "emoji_29@2x.png",
+	"[坏笑]": "emoji_30@2x.png",
+	"[多云]": "emoji_31@2x.png",
+	"[大兵]": "emoji_32@2x.png",
+	"[大哭]": "emoji_33@2x.png",
+	"[太阳]": "emoji_34@2x.png",
+	"[奋斗]": "emoji_35@2x.png",
+	"[奶瓶]": "emoji_36@2x.png",
+	"[委屈]": "emoji_37@2x.png",
+	"[害羞]": "emoji_38@2x.png",
+	"[尴尬]": "emoji_39@2x.png",
+	"[左哼哼]": "emoji_40@2x.png",
+	"[左太极]": "emoji_41@2x.png",
+	"[左车头]": "emoji_42@2x.png",
+	"[差劲]": "emoji_43@2x.png",
+	"[弱]": "emoji_44@2x.png",
+	"[强]": "emoji_45@2x.png",
+	"[彩带]": "emoji_46@2x.png",
+	"[彩球]": "emoji_47@2x.png",
+	"[得意]": "emoji_48@2x.png",
+	"[心碎了]": "emoji_50@2x.png",
+	"[快哭了]": "emoji_51@2x.png",
+	"[怄火]": "emoji_52@2x.png",
+	"[怒]": "emoji_53@2x.png",
+	"[惊恐]": "emoji_54@2x.png",
+	"[惊讶]": "emoji_55@2x.png",
+	"[憨笑]": "emoji_56@2x.png",
+	"[手枪]": "emoji_57@2x.png",
+	"[打哈欠]": "emoji_58@2x.png",
+	"[抓狂]": "emoji_59@2x.png",
+	"[折磨]": "emoji_60@2x.png",
+	"[抠鼻]": "emoji_61@2x.png",
+	"[抱抱]": "emoji_62@2x.png",
+	"[抱拳]": "emoji_63@2x.png",
+	"[拳头]": "emoji_64@2x.png",
+	"[挥手]": "emoji_65@2x.png",
+	"[握手]": "emoji_66@2x.png",
+	"[撇嘴]": "emoji_67@2x.png",
+	"[擦汗]": "emoji_68@2x.png",
+	"[敲打]": "emoji_69@2x.png",
+	"[晕]": "emoji_70@2x.png",
+	"[月亮]": "emoji_71@2x.png",
+	"[棒棒糖]": "emoji_72@2x.png",
+	"[汽车]": "emoji_73@2x.png",
+	"[沙发]": "emoji_74@2x.png",
+	"[流汗]": "emoji_75@2x.png",
+	"[流泪]": "emoji_76@2x.png",
+	"[激动]": "emoji_77@2x.png",
+	"[灯泡]": "emoji_78@2x.png",
+	"[炸弹]": "emoji_79@2x.png",
+	"[熊猫]": "emoji_80@2x.png",
+	"[爆筋]": "emoji_81@2x.png",
+	"[爱你]": "emoji_82@2x.png",
+	"[爱心]": "emoji_83@2x.png",
+	"[爱情]": "emoji_84@2x.png",
+	"[猪头]": "emoji_85@2x.png",
+	"[猫咪]": "emoji_86@2x.png",
+	"[献吻]": "emoji_87@2x.png",
+	"[玫瑰]": "emoji_88@2x.png",
+	"[瓢虫]": "emoji_89@2x.png",
+	"[疑问]": "emoji_90@2x.png",
+	"[白眼]": "emoji_91@2x.png",
+	"[皮球]": "emoji_92@2x.png",
+	"[睡觉]": "emoji_93@2x.png",
+	"[磕头]": "emoji_94@2x.png",
+	"[示爱]": "emoji_95@2x.png",
+	"[礼品袋]": "emoji_96@2x.png",
+	"[礼物]": "emoji_97@2x.png",
+	"[篮球]": "emoji_98@2x.png",
+	"[米饭]": "emoji_99@2x.png",
+	"[糗大了]": "emoji_100@2x.png",
+	"[红双喜]": "emoji_101@2x.png",
+	"[红灯笼]": "emoji_102@2x.png",
+	"[纸巾]": "emoji_103@2x.png",
+	"[胜利]": "emoji_104@2x.png",
+	"[色]": "emoji_105@2x.png",
+	"[药]": "emoji_106@2x.png",
+	"[菜刀]": "emoji_107@2x.png",
+	"[蛋糕]": "emoji_108@2x.png",
+	"[蜡烛]": "emoji_109@2x.png",
+	"[街舞]": "emoji_110@2x.png",
+	"[衰]": "emoji_111@2x.png",
+	"[西瓜]": "emoji_112@2x.png",
+	"[调皮]": "emoji_113@2x.png",
+	"[象棋]": "emoji_114@2x.png",
+	"[跳绳]": "emoji_115@2x.png",
+	"[跳跳]": "emoji_116@2x.png",
+	"[车厢]": "emoji_117@2x.png",
+	"[转圈]": "emoji_118@2x.png",
+	"[鄙视]": "emoji_119@2x.png",
+	"[酷]": "emoji_120@2x.png",
+	"[钞票]": "emoji_121@2x.png",
+	"[钻戒]": "emoji_122@2x.png",
+	"[闪电]": "emoji_123@2x.png",
+	"[闭嘴]": "emoji_124@2x.png",
+	"[闹钟]": "emoji_125@2x.png",
+	"[阴险]": "emoji_126@2x.png",
+	"[难过]": "emoji_127@2x.png",
+	"[雨伞]": "emoji_128@2x.png",
+	"[青蛙]": "emoji_129@2x.png",
+	"[面条]": "emoji_130@2x.png",
+	"[鞭炮]": "emoji_131@2x.png",
+	"[风车]": "emoji_132@2x.png",
+	"[飞吻]": "emoji_133@2x.png",
+	"[飞机]": "emoji_134@2x.png",
+	"[饥饿]": "emoji_135@2x.png",
+	"[香蕉]": "emoji_136@2x.png",
+	"[骷髅]": "emoji_137@2x.png",
+	"[麦克风]": "emoji_138@2x.png",
+	"[麻将]": "emoji_139@2x.png",
+	"[鼓掌]": "emoji_140@2x.png",
+	"[龇牙]": "emoji_141@2x.png"
+}