Browse Source

多终端同时在线后端改造(开发中)

master
xsx 3 years ago
parent
commit
69dcd47d21
  1. 21
      im-uniapp/common/emotion.js
  2. 171
      im-uniapp/common/wssocket.js
  3. 134
      im-uniapp/components/chat-item/chat-item.vue
  4. 379
      im-uniapp/components/chat-message-item/chat-message-item.vue
  5. 45
      im-uniapp/components/chat-time/chat-time.vue
  6. 101
      im-uniapp/components/image-upload/image-upload.vue
  7. 49
      im-uniapp/components/loading/loading.vue
  8. 343
      im-uniapp/pages/chat/chat-box.vue
  9. BIN
      im-uniapp/static/audio/call.wav
  10. BIN
      im-uniapp/static/audio/tip.wav
  11. BIN
      im-uniapp/static/emoji/0.gif
  12. BIN
      im-uniapp/static/emoji/1.gif
  13. BIN
      im-uniapp/static/emoji/10.gif
  14. BIN
      im-uniapp/static/emoji/100.gif
  15. BIN
      im-uniapp/static/emoji/101.gif
  16. BIN
      im-uniapp/static/emoji/102.gif
  17. BIN
      im-uniapp/static/emoji/103.gif
  18. BIN
      im-uniapp/static/emoji/104.gif
  19. BIN
      im-uniapp/static/emoji/11.gif
  20. BIN
      im-uniapp/static/emoji/12.gif
  21. BIN
      im-uniapp/static/emoji/13.gif
  22. BIN
      im-uniapp/static/emoji/14.gif
  23. BIN
      im-uniapp/static/emoji/15.gif
  24. BIN
      im-uniapp/static/emoji/16.gif
  25. BIN
      im-uniapp/static/emoji/17.gif
  26. BIN
      im-uniapp/static/emoji/18.gif
  27. BIN
      im-uniapp/static/emoji/19.gif
  28. BIN
      im-uniapp/static/emoji/2.gif
  29. BIN
      im-uniapp/static/emoji/20.gif
  30. BIN
      im-uniapp/static/emoji/21.gif
  31. BIN
      im-uniapp/static/emoji/22.gif
  32. BIN
      im-uniapp/static/emoji/23.gif
  33. BIN
      im-uniapp/static/emoji/24.gif
  34. BIN
      im-uniapp/static/emoji/25.gif
  35. BIN
      im-uniapp/static/emoji/26.gif
  36. BIN
      im-uniapp/static/emoji/27.gif
  37. BIN
      im-uniapp/static/emoji/28.gif
  38. BIN
      im-uniapp/static/emoji/29.gif
  39. BIN
      im-uniapp/static/emoji/3.gif
  40. BIN
      im-uniapp/static/emoji/30.gif
  41. BIN
      im-uniapp/static/emoji/31.gif
  42. BIN
      im-uniapp/static/emoji/32.gif
  43. BIN
      im-uniapp/static/emoji/33.gif
  44. BIN
      im-uniapp/static/emoji/34.gif
  45. BIN
      im-uniapp/static/emoji/35.gif
  46. BIN
      im-uniapp/static/emoji/36.gif
  47. BIN
      im-uniapp/static/emoji/37.gif
  48. BIN
      im-uniapp/static/emoji/38.gif
  49. BIN
      im-uniapp/static/emoji/39.gif
  50. BIN
      im-uniapp/static/emoji/4.gif
  51. BIN
      im-uniapp/static/emoji/40.gif
  52. BIN
      im-uniapp/static/emoji/41.gif
  53. BIN
      im-uniapp/static/emoji/42.gif
  54. BIN
      im-uniapp/static/emoji/43.gif
  55. BIN
      im-uniapp/static/emoji/44.gif
  56. BIN
      im-uniapp/static/emoji/45.gif
  57. BIN
      im-uniapp/static/emoji/46.gif
  58. BIN
      im-uniapp/static/emoji/47.gif
  59. BIN
      im-uniapp/static/emoji/48.gif
  60. BIN
      im-uniapp/static/emoji/49.gif
  61. BIN
      im-uniapp/static/emoji/5.gif
  62. BIN
      im-uniapp/static/emoji/50.gif
  63. BIN
      im-uniapp/static/emoji/51.gif
  64. BIN
      im-uniapp/static/emoji/52.gif
  65. BIN
      im-uniapp/static/emoji/53.gif
  66. BIN
      im-uniapp/static/emoji/54.gif
  67. BIN
      im-uniapp/static/emoji/55.gif
  68. BIN
      im-uniapp/static/emoji/56.gif
  69. BIN
      im-uniapp/static/emoji/57.gif
  70. BIN
      im-uniapp/static/emoji/58.gif
  71. BIN
      im-uniapp/static/emoji/59.gif
  72. BIN
      im-uniapp/static/emoji/6.gif
  73. BIN
      im-uniapp/static/emoji/60.gif
  74. BIN
      im-uniapp/static/emoji/61.gif
  75. BIN
      im-uniapp/static/emoji/62.gif
  76. BIN
      im-uniapp/static/emoji/63.gif
  77. BIN
      im-uniapp/static/emoji/64.gif
  78. BIN
      im-uniapp/static/emoji/65.gif
  79. BIN
      im-uniapp/static/emoji/66.gif
  80. BIN
      im-uniapp/static/emoji/67.gif
  81. BIN
      im-uniapp/static/emoji/68.gif
  82. BIN
      im-uniapp/static/emoji/69.gif
  83. BIN
      im-uniapp/static/emoji/7.gif
  84. BIN
      im-uniapp/static/emoji/70.gif
  85. BIN
      im-uniapp/static/emoji/71.gif
  86. BIN
      im-uniapp/static/emoji/72.gif
  87. BIN
      im-uniapp/static/emoji/73.gif
  88. BIN
      im-uniapp/static/emoji/74.gif
  89. BIN
      im-uniapp/static/emoji/75.gif
  90. BIN
      im-uniapp/static/emoji/76.gif
  91. BIN
      im-uniapp/static/emoji/77.gif
  92. BIN
      im-uniapp/static/emoji/78.gif
  93. BIN
      im-uniapp/static/emoji/79.gif
  94. BIN
      im-uniapp/static/emoji/8.gif
  95. BIN
      im-uniapp/static/emoji/80.gif
  96. BIN
      im-uniapp/static/emoji/81.gif
  97. BIN
      im-uniapp/static/emoji/82.gif
  98. BIN
      im-uniapp/static/emoji/83.gif
  99. BIN
      im-uniapp/static/emoji/84.gif
  100. BIN
      im-uniapp/static/emoji/85.gif

21
im-uniapp/common/emotion.js

@ -0,0 +1,21 @@
const emoTextList = ['微笑', '撇嘴', '色', '发呆', '得意', '流泪', '害羞', '闭嘴', '睡', '大哭', '尴尬', '发怒', '调皮', '呲牙', '惊讶', '难过', '酷', '冷汗', '抓狂', '吐', '偷笑', '可爱', '白眼', '傲慢', '饥饿', '困', '惊恐', '流汗', '憨笑', '大兵', '奋斗', '咒骂', '疑问', '嘘', '晕', '折磨', '衰', '骷髅', '敲打', '再见', '擦汗', '抠鼻', '鼓掌', '糗大了', '坏笑', '左哼哼', '右哼哼', '哈欠', '鄙视', '委屈', '快哭了', '阴险', '亲亲', '吓', '可怜', '菜刀', '西瓜', '啤酒', '篮球', '乒乓', '咖啡', '饭', '猪头', '玫瑰', '凋谢', '示爱', '爱心', '心碎', '蛋糕', '闪电', '炸弹', '刀', '足球', '瓢虫', '便便', '月亮', '太阳', '礼物', '拥抱', '强', '弱', '握手', '胜利', '抱拳', '勾引', '拳头', '差劲', '爱你', 'NO', 'OK', '爱情', '飞吻', '跳跳', '发抖', '怄火', '转圈', '磕头', '回头', '跳绳', '挥手', '激动', '街舞', '献吻', '左太极', '右太极'];
let transform = (content) => {
return content.replace(/\#[\u4E00-\u9FA5]{1,3}\;/gi, textToImg);
}
// 将匹配结果替换表情图片
let textToImg = (emoText) => {
let word = emoText.replace(/\#|\;/gi, '');
let idx = emoTextList.indexOf(word);
let url = `/static/emoji/${idx}.gif`;
return `<img src="${url}" style="vertical-align:bottom;"/>`
}
export default {
emoTextList,
transform,
textToImg
}

171
im-uniapp/common/wssocket.js

@ -0,0 +1,171 @@
let wsurl = "";
let accessToken = "";
let messageCallBack = null;
let openCallBack = null;
let isConnect = false; //连接标识 避免重复连接
let hasLogin = false;
let createWebSocket = (url, token) => {
wsurl = url;
accessToken = token;
closeWebSocket().then(() => {
initWebSocket();
});
};
let initWebSocket = () => {
console.log("初始化WebSocket");
uni.connectSocket({
url: wsurl,
success: (res) => {
console.log("websocket连接成功");
},
fail: (err) => {
console.log(e);
console.log("websocket连接失败");
reConnect(); //如果无法连接上webSocket 那么重新连接!可能会因为服务器重新部署,或者短暂断网等导致无法创建连接
}
});
uni.onSocketOpen((res) => {
console.log("WebSocket连接已打开");
isConnect = true;
// 发送登录命令
let loginInfo = {
cmd: 0,
data: {
accessToken: accessToken
}
};
uni.sendSocketMessage({
data: JSON.stringify(loginInfo)
});
})
uni.onSocketMessage((res) => {
let sendInfo = JSON.parse(res.data)
if (sendInfo.cmd == 0) {
hasLogin = true;
heartCheck.start()
console.log('WebSocket登录成功')
// 登录成功才算连接完成
openCallBack && openCallBack();
} else if (sendInfo.cmd == 1) {
// 重新开启心跳定时
heartCheck.reset();
} else {
// 其他消息转发出去
console.log("接收到消息",sendInfo);
messageCallBack && messageCallBack(sendInfo.cmd, sendInfo.data)
}
})
uni.onSocketClose((res) => {
console.log(res)
console.log('WebSocket连接关闭')
isConnect = false; //断开后修改标识
//reConnect();
})
uni.onSocketError((err) => {
console.log(err)
isConnect = false; //连接断开修改标识
uni.showModal({
content: '连接失败,可能是websocket服务不可用,请稍后再试',
showCancel: false,
})
})
};
//定义重连函数
let reConnect = () => {
console.log("尝试重新连接");
if (isConnect) return; //如果已经连上就不在重连了
rec && clearTimeout(rec);
rec = setTimeout(function() { // 延迟5秒重连 避免过多次过频繁请求重连
initWebSocket();
}, 5000);
};
//设置关闭连接
let closeWebSocket = () => {
return new Promise((resolve, reject) => {
if (!isConnect) {
resolve();
return;
}
console.log("关闭websocket连接");
uni.closeSocket({
code: 1000,
complete: (res) => {
hasLogin = false;
isConnect = false;
resolve();
}
})
})
};
//心跳设置
var heartCheck = {
timeout: 10000, //每段时间发送一次心跳包 这里设置为30s
timeoutObj: null, //延时发送消息对象(启动心跳新建这个对象,收到消息后重置对象)
start: function() {
if (isConnect) {
console.log('发送WebSocket心跳')
let heartBeat = {
cmd: 1,
data: {}
};
uni.sendSocketMessage({
data: JSON.stringify(heartBeat),
fail(res) {
console.log(res);
}
})
}
},
reset: function() {
clearTimeout(this.timeoutObj);
this.timeoutObj = setTimeout(function() {
heartCheck.start();
}, this.timeout);
}
}
// 实际调用的方法
function sendMessage(agentData) {
uni.sendSocketMessage({
data: agentData
})
}
function onmessage(callback) {
messageCallBack = callback;
}
function onopen(callback) {
openCallBack = callback;
if (hasLogin) {
openCallBack();
}
}
// 将方法暴露出去
export {
createWebSocket,
closeWebSocket,
sendMessage,
onmessage,
onopen
}

134
im-uniapp/components/chat-item/chat-item.vue

@ -0,0 +1,134 @@
<template>
<view class="chat-item" @click="showChatBox()">
<view class="left">
<image class="head-image" :src="chat.headImage" mode="aspectFill" lazy-load="true" ></image>
<view v-show="chat.unreadCount>0" class="unread-text">{{chat.unreadCount}}</view>
</view>
<view class="mid">
<view class="show-name">{{ chat.showName}}</view>
<view class="msg-text" v-html="$emo.transform(chat.lastContent)"></view>
</view>
<view class="right ">
<view class="msg-time">
<chat-time :time="chat.lastSendTime"></chat-time>
</view>
<view></view>
</view>
</view>
</template>
<script>
export default {
name: "chatItem",
data() {
return {}
},
props: {
chat: {
type: Object
},
index: {
type: Number
}
},
methods: {
showChatBox(){
uni.navigateTo({
url: "/pages/chat/chat-box?chatIdx="+this.index
})
}
}
}
</script>
<style lang="scss" scode>
.chat-item {
height: 120rpx;
display: flex;
margin-bottom: 1rpx;
position: relative;
padding-left: 30rpx;
align-items: center;
padding-right: 10rpx;
background-color: #fafafa;
white-space: nowrap;
&:hover {
background-color: #eeeeee;
}
.left {
position: relative;
display: flex;
justify-content: center;
align-items: center;
width: 100rpx;
height: 100rpx;
.head-image{
width: 100%;
height: 100%;
border-radius: 10%;
}
.unread-text {
position: absolute;
background-color: red;
right: -12rpx;
top: -12rpx;
color: white;
border-radius: 30rpx;
padding: 5rpx 6rpx;
font-size: 10px;
text-align: center;
white-space: nowrap;
}
}
.mid {
margin-left: 20rpx;
flex: 2;
display: flex;
flex-direction: column;
height: 100%;
flex-shrink: 0;
overflow: hidden;
.show-name {
display: flex;
justify-content: flex-start;
align-items: center;
font-size: 36rpx;
flex: 3;
}
.msg-text {
flex: 2;
font-size: 28rpx;
color: #888888;
white-space: nowrap;
}
}
.right {
flex: 1;
display: flex;
flex-direction: column;
align-items: flex-end;
height: 80rpx;
flex-shrink: 0;
overflow: hidden;
.msg-time {
display: flex;
justify-content: flex-start;
align-items: center;
font-size: 14px;
color: #888888;
white-space: nowrap;
}
}
}
</style>

379
im-uniapp/components/chat-message-item/chat-message-item.vue

@ -0,0 +1,379 @@
<template>
<view class="chat-msg-item">
<view class="chat-msg-tip" v-show="msgInfo.type==$enums.MESSAGE_TYPE.RECALL">{{msgInfo.content}}</view>
<view class="chat-msg-normal" v-show="msgInfo.type!=$enums.MESSAGE_TYPE.RECALL" :class="{'chat-msg-mine':msgInfo.selfSend}">
<view class="avatar">
<image class="head-image" :src="headImage"></image>
</view>
<view class="chat-msg-content">
<view class="chat-msg-top">
<text>{{showName}}</text>
<chat-time :time="msgInfo.sendTime"></chat-time>
</view>
<view class="chat-msg-bottom">
<rich-text class="chat-msg-text" v-if="msgInfo.type==$enums.MESSAGE_TYPE.TEXT" :nodes="$emo.transform(msgInfo.content)"></rich-text>
<view class="chat-msg-image" v-if="msgInfo.type==$enums.MESSAGE_TYPE.FILE">
<view class="img-load-box" >
<image class="send-image" :src="JSON.parse(msgInfo.content).thumbUrl" lazy-load="true" ></image>
<loading v-show="loading"></loading>
</view>
<text title="发送失败" v-show="loadFail" class="send-fail iconfont icon-warning-circle-fill"></text>
</view>
<!--
<view class="chat-msg-file" v-if="msgInfo.type==$enums.MESSAGE_TYPE.IMAGE">
<view class="chat-file-box" v-loading="loading">
<view class="chat-file-info">
<el-link class="chat-file-name" :underline="true" target="_blank" type="primary" :href="data.url">{{data.name}}</el-link>
<view class="chat-file-size">{{fileSize}}</view>
</view>
<view class="chat-file-icon">
<text type="primary" class="el-icon-document"></text>
</view>
</view>
<text title="发送失败" v-show="loadFail" @click="handleSendFail" class="send-fail el-icon-warning"></text>
</view>
<view class="chat-msg-voice" v-if="msgInfo.type==$enums.MESSAGE_TYPE.AUDIO" @click="handlePlayVoice()">
<audio controls :src="JSON.parse(msgInfo.content).url"></audio>
</view>
-->
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: "chat-message-item",
props: {
headImage: {
type: String,
required: true
},
showName: {
type: String,
required: true
},
msgInfo: {
type: Object,
required: true
},
menu:{
type: Boolean,
default: true
}
},
data() {
return {
audioPlayState: 'STOP',
rightMenu: {
show: false,
pos: {
x: 0,
y: 0
}
}
}
},
methods: {
handleSendFail() {
this.$message.error("该文件已发送失败,目前不支持自动重新发送,建议手动重新发送")
},
showFullImageBox() {
let imageUrl = JSON.parse(this.msgInfo.content).originUrl;
if (imageUrl) {
this.$store.commit('showFullImageBox', imageUrl);
}
},
handlePlayVoice() {
if (!this.audio) {
this.audio = new Audio();
}
this.audio.src = JSON.parse(this.msgInfo.content).url;
this.audio.play();
this.handlePlayVoice = 'RUNNING';
},
showRightMenu(e) {
this.rightMenu.pos = {
x: e.x,
y: e.y
};
this.rightMenu.show = "true";
},
handleSelectMenu(item) {
this.$emit(item.key.toLowerCase(), this.msgInfo);
}
},
computed: {
loading() {
return !this.isTimeout && this.msgInfo.loadStatus && this.msgInfo.loadStatus === "loading";
},
loadFail() {
return this.msgInfo.loadStatus && (this.isTimeout || this.msgInfo.loadStatus === "fail");
},
isTimeout(){
return (new Date().getTime() - new Date(this.msgInfo.sendTime).getTime()) > 30*1000;
},
data() {
return JSON.parse(this.msgInfo.content)
},
fileSize() {
let size = this.data.size;
if (size > 1024 * 1024) {
return Math.round(size / 1024 / 1024) + "M";
}
if (size > 1024) {
return Math.round(size / 1024) + "KB";
}
return size + "B";
},
menuItems() {
let items = [];
items.push({
key: 'DELETE',
name: '删除',
icon: 'el-icon-delete'
});
if (this.msgInfo.selfSend && this.msgInfo.id > 0) {
items.push({
key: 'RECALL',
name: '撤回',
icon: 'el-icon-refresh-left'
});
}
return items;
}
},
mounted() {
//console.log(this.msgInfo);
}
}
</script>
<style lang="scss">
.chat-msg-item {
padding: 20rpx;
.chat-msg-tip {
line-height: 50px;
}
.chat-msg-normal {
position: relative;
font-size: 0;
margin-bottom: 15rpx;
padding-left: 120rpx;
min-height: 120rpx;
.avatar {
position: absolute;
display: flex;
justify-content: center;
align-items: center;
width: 100rpx;
height: 100rpx;
top: 0;
left: 0;
.head-image{
width: 100%;
height: 100%;
border-radius: 5%;
}
}
.chat-msg-content {
display: flex;
flex-direction: column;
.chat-msg-top {
display: flex;
flex-wrap: nowrap;
color: #333;
font-size: 14px;
line-height: 20px;
text {
margin-right: 12px;
}
}
.chat-msg-bottom {
text-align: left;
.chat-msg-text {
position: relative;
line-height: 22px;
margin-top: 10px;
padding: 10px;
background-color: #eeeeee;
border-radius: 3px;
color: #333;
display: inline-block;
font-size: 14px;
word-break: break-all;
white-space: pre-line;
&:after {
content: "";
position: absolute;
left: -10px;
top: 13px;
width: 0;
height: 0;
border-style: solid dashed dashed;
border-color: #eeeeee transparent transparent;
overflow: hidden;
border-width: 10px;
}
}
.chat-msg-image {
display: flex;
flex-wrap: nowrap;
flex-direction: row;
align-items: center;
.img-load-box{
position: relative;
.send-image {
min-width: 200rpx;
min-height: 150rpx;
max-width: 400rpx;
max-height: 300rpx;
border: #dddddd solid 1px;
cursor: pointer;
}
}
.send-fail {
color: #e60c0c;
font-size: 30px;
cursor: pointer;
margin: 0 20px;
}
}
.chat-msg-file {
display: flex;
flex-wrap: nowrap;
flex-direction: row;
align-items: center;
cursor: pointer;
.chat-file-box {
display: flex;
flex-wrap: nowrap;
align-items: center;
width: 20%;
min-height: 80px;
border: #dddddd solid 1px;
border-radius: 3px;
background-color: #eeeeee;
padding: 10px 15px;
.chat-file-info {
flex: 1;
height: 100%;
text-align: left;
font-size: 14px;
.chat-file-name {
font-size: 16px;
font-weight: 600;
margin-bottom: 15px;
}
}
.chat-file-icon {
font-size: 50px;
color: #d42e07;
}
}
.send-fail {
color: #e60c0c;
font-size: 30px;
cursor: pointer;
margin: 0 20px;
}
}
.chat-msg-voice {
font-size: 14px;
cursor: pointer;
audio {
height: 45px;
padding: 5px 0;
}
}
}
}
&.chat-msg-mine {
text-align: right;
padding-left: 0;
padding-right: 120rpx;
.avatar {
left: auto;
right: 0;
}
.chat-msg-content {
.chat-msg-top {
flex-direction: row-reverse;
text {
margin-left: 12px;
margin-right: 0;
}
}
.chat-msg-bottom {
text-align: right;
.chat-msg-text {
margin-left: 10px;
background-color: #5fb878;
color: #fff;
display: inline-block;
vertical-align: top;
font-size: 14px;
&:after {
left: auto;
right: -10px;
border-top-color: #5fb878;
}
}
.chat-msg-image {
flex-direction: row-reverse;
}
.chat-msg-file {
flex-direction: row-reverse;
}
}
}
}
}
}
</style>

45
im-uniapp/components/chat-time/chat-time.vue

@ -0,0 +1,45 @@
<template>
<view>
<text>{{formatDate}}</text>
</view>
</template>
<script>
export default {
name: "chat-time",
data() {
return {}
},
props: {
time: {
type: Number
}
},
computed: {
formatDate() {
let time = new Date(this.time);
let strtime = "";
let todayTime = new Date();
todayTime.setHours(0, 0, 0, 0)
let dayDiff = Math.floor((todayTime.getTime() - time.getTime()) / (24 * 3600 * 1000));
if (time.getTime() > todayTime.getTime()) {
strtime = time.getHours() <= 9 ? "0" + time.getHours() : time.getHours();
strtime += ":"
strtime += time.getMinutes() <= 9 ? "0" + time.getMinutes() : time.getMinutes();
} else if (dayDiff < 1) {
strtime = "昨天";
} else if (dayDiff < 7) {
strtime = `${dayDiff+1}天前`;
} else {
strtime = time.getMonth() + 1 + "月" + time.getDate() + "日";
}
return strtime;
}
}
}
</script>
<style>
</style>

101
im-uniapp/components/image-upload/image-upload.vue

@ -0,0 +1,101 @@
<template>
<view @click="selectAndUpload()">
<slot></slot>
</view>
</template>
<script>
export default {
name: "image-upload",
data() {
return {
uploadHeaders: {
"accessToken": uni.getStorageSync('loginInfo').accessToken
}
}
},
props: {
maxSize: {
type: Number,
default: null
},
onBefore: {
type: Function,
default: null
},
onSuccess: {
type: Function,
default: null
},
onError: {
type: Function,
default: null
}
},
methods: {
selectAndUpload() {
console.log("selectAndUpload");
uni.chooseImage({
count: 9, //9
sourceType: ['album'], //album camera 使使
sizeType: ['original'], //original compressed
success: (res) => {
res.tempFiles.forEach((file) => {
console.log("选择文件");
//
if (this.maxSize && file.size > this.maxSize) {
this.$message.error(`文件大小不能超过 ${this.fileSizeStr}!`);
this.$emit("fail", file);
return;
}
if (!this.onBefore || this.onBefore(file)) {
//
this.uploadImage(file);
}
})
}
})
},
uploadImage(file) {
console.log("上传文件")
uni.uploadFile({
url: process.env.BASE_URL + '/image/upload',
header: {
accessToken: uni.getStorageSync("loginInfo").accessToken
},
filePath: file.path, //
name: 'file',
success: (res) => {
let data = JSON.parse(res.data);
if(data.code != 200){
this.onError && this.onError(file, data);
}else{
console.log("上传成功")
this.onSuccess && this.onSuccess(file, data);
}
},
fail: (err) => {
console.log("上传失败")
console.log(this.onError)
this.onError && this.onError(file, err);
}
})
}
},
computed: {
fileSizeStr() {
if (this.maxSize > 1024 * 1024) {
return Math.round(this.maxSize / 1024 / 1024) + "M";
}
if (this.maxSize > 1024) {
return Math.round(this.maxSize / 1024) + "KB";
}
return this.maxSize + "B";
}
}
}
</script>
<style>
</style>

49
im-uniapp/components/loading/loading.vue

@ -0,0 +1,49 @@
<template>
<view class="loading-box">
<view class="rotate iconfont icon-loading" ></view>
</view>
</template>
<script>
export default {
data() {
return {};
},
methods: {
},
computed: {
}
};
</script>
<style>
.loading-box {
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.4);
position: absolute;
left: 0;
top: 0;
z-index: 10000;
display: flex;
justify-content: center;
align-items: center;
}
.rotate {
animation: rotate 2s ease-in-out infinite;
font-size: 100rpx;
}
@keyframes rotate {
from {
transform: rotate(0deg)
}
to {
transform: rotate(360deg)
}
}
</style>

343
im-uniapp/pages/chat/chat-box.vue

@ -0,0 +1,343 @@
<template>
<view class="chat-box">
<view class="header">
<text class="title">{{title}}</text>
<uni-icons class="btn-side" type="more-filled" size="30"></uni-icons>
</view>
<view class="chat-msg" @click="showToolBox(false)">
<scroll-view class="scroll-box" scroll-y="true" :scroll-into-view="'chat-item-'+scrollMsgIdx">
<view v-for="(msgInfo,idx) in chat.messages" :key="idx">
<chat-message-item :headImage="headImage(msgInfo)" :showName="showName(msgInfo)"
:id="'chat-item-'+idx" :msgInfo="msgInfo">
</chat-message-item>
</view>
</scroll-view>
</view>
<view class="send-bar">
<view class="iconfont icon-voice-circle"></view>
<view class="send-text">
<textarea class="send-text-area" v-model="sendText" ref="sendBox" auto-height :show-confirm-bar="false"
cursor-spacing="10" @keydown.enter="sendTextMessage()" @click="showToolBox(false)"></textarea>
</view>
<view class="iconfont icon-icon_emoji"></view>
<view v-show="sendText==''" class="iconfont icon-add-circle" @click="showToolBox(true)" ></view>
<button v-show="sendText!=''" class="btn-send" type="primary" @click="sendTextMessage()" size="mini">发送</button>
</view>
<view v-show="showTools" class="chat-tools" >
<view class="chat-tools-item">
<image-upload :onBefore="onUploadImageBefore" :onSuccess="onUploadImageSuccess"
:onError="onUploadImageFail">
<view class="tool-icon iconfont icon-picture"></view>
</image-upload>
<view class="tool-name">相册</view>
</view>
<view class="chat-tools-item" v-for="(tool, idx) in tools" @click="onClickTool(tool)">
<view class="tool-icon iconfont" :class="tool.icon"></view>
<view class="tool-name">{{ tool.name }}</view>
</view>
</view>
<!--
<emotion v-show="showEmotion" :pos="emoBoxPos" @emotion="handleEmotion"></Emotion>
<chat-voice :visible="showVoice" @close="closeVoiceBox" @send="handleSendVoice"></chat-voice>
<chat-history :visible="showHistory" :chat="chat" :friend="friend" :group="group" :groupMembers="groupMembers" @close="closeHistoryBox"></chat-history>
-->
</view>
</template>
<script>
export default {
data() {
return {
chat: {},
friend: {},
group: {},
groupMembers: [],
sendText: "",
showVoice: false, //
showSide: false, //
showEmotion: false, // emoji
showHistory: false, //
scrollMsgIdx: 0, //
showTools: false,
tools: [{
name: "拍摄",
icon: "icon-camera"
},
{
name: "语音输入",
icon: "icon-microphone"
},
{
name: "文件",
icon: "icon-folder"
},
{
name: "呼叫",
icon: "icon-call"
}
]
}
},
methods: {
headImage(msgInfo) {
if (this.chat.type == 'GROUP') {
let member = this.groupMembers.find((m) => m.userId == msgInfo.sendId);
return member ? member.headImage : "";
} else {
return msgInfo.selfSend ? this.mine.headImageThumb : this.chat.headImage
}
},
showName(msgInfo) {
if (this.chat.type == 'GROUP') {
let member = this.groupMembers.find((m) => m.userId == msgInfo.sendId);
return member ? member.aliasName : "";
} else {
return msgInfo.selfSend ? this.mine.nickName : this.chat.showName
}
},
sendTextMessage() {
if (!this.sendText.trim()) {
return uni.showToast({
title: "不能发送空白信息",
icon: "none"
});
}
let msgInfo = {
content: this.sendText,
type: 0
}
// id
this.fillTargetId(msgInfo, this.chat.targetId);
this.sendText = "";
this.$http({
url: this.messageAction,
method: 'POST',
data: msgInfo
}).then((id) => {
msgInfo.id = id;
msgInfo.sendTime = new Date().getTime();
msgInfo.sendId = this.$store.state.userStore.userInfo.id;
msgInfo.selfSend = true;
this.$store.commit("insertMessage", msgInfo);
uni.showToast({
title: "发送成功",
icon: "none"
})
}).finally(() => {
//
this.scrollToBottom();
});
},
fillTargetId(msgInfo, targetId) {
if (this.chat.type == "GROUP") {
msgInfo.groupId = targetId;
} else {
msgInfo.recvId = targetId;
}
},
scrollToBottom() {
this.$nextTick(() => {
this.scrollMsgIdx = this.chat.messages.length - 1;
})
},
showToolBox(v){
this.showTools = v;
},
onUploadImageBefore(file) {
let data = {
originUrl: file.path,
thumbUrl: file.path
}
let msgInfo = {
id: 0,
fileId: file.uid,
sendId: this.mine.id,
content: JSON.stringify(data),
sendTime: new Date().getTime(),
selfSend: true,
type: 1,
loadStatus: "loading"
}
// id
this.fillTargetId(msgInfo, this.chat.targetId);
//
this.$store.commit("insertMessage", msgInfo);
// file
file.msgInfo = msgInfo;
//
this.scrollToBottom();
return true;
},
onUploadImageSuccess(file, res) {
console.log("onUploadImageSuccess")
let msgInfo = JSON.parse(JSON.stringify(file.msgInfo));
msgInfo.content = JSON.stringify(res.data);
this.$http({
url: this.messageAction,
method: 'POST',
data: msgInfo
}).then((id) => {
msgInfo.loadStatus = 'ok';
msgInfo.id = id;
this.$store.commit("insertMessage", msgInfo);
})
},
onUploadImageFail(file, err) {
let msgInfo = JSON.parse(JSON.stringify(file.msgInfo));
msgInfo.loadStatus = 'fail';
this.$store.commit("insertMessage", msgInfo);
},
onClickTool(tool) {
switch (tool.name) {
case "相册":
break;
}
console.log(tool);
}
},
computed: {
mine() {
return this.$store.state.userStore.userInfo;
},
title() {
if (!this.chat) {
return "";
}
let title = this.chat.showName;
if (this.chat.type == "GROUP") {
let size = this.groupMembers.filter(m => !m.quit).length;
title += `(${size})`;
}
return title;
},
messageAction() {
return `/message/${this.chat.type.toLowerCase()}/send`;
}
},
onLoad(options) {
console.log("onLoad")
let chatIdx = options.chatIdx;
this.chat = this.$store.state.chatStore.chats[chatIdx];
this.scrollToBottom();
}
}
</script>
<style lang="scss" scoped>
.chat-box {
position: relative;
background: white;
border: #dddddd solid 1px;
display: flex;
flex-direction: column;
height: calc(100vh - 44px);
.header {
display: flex;
justify-content: center;
align-items: center;
height: 60rpx;
padding: 5px;
background-color: white;
line-height: 50px;
font-size: 40rpx;
font-weight: 600;
border: #dddddd solid 1px;
.btn-side {
position: absolute;
right: 30rpx;
line-height: 60rpx;
font-size: 28rpx;
cursor: pointer;
}
}
.chat-msg {
flex: 1;
padding: 0;
border: #dddddd solid 1px;
overflow: hidden;
position: relative;
.scroll-box {
height: 100%;
}
}
.send-bar {
display: flex;
align-items: center;
padding: 3rpx;
border: #dddddd solid 1px;
background-color: #eeeeee;
.iconfont{
font-size: 50rpx;
}
.send-text {
flex: 1;
background-color: #f8f8f8 !important;
overflow: auto;
margin: 0rpx 12rpx;
padding: 12rpx;
background-color: #fff;
border-radius: 10rpx;
max-height: 225rpx;
min-height: 65rpx;
box-sizing: border-box;
.send-text-area {
width: 100%;
}
}
.btn-send {
text-align: right;
}
}
.chat-tools {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
background-color: whitesmoke;
.chat-tools-item {
width: 140rpx;
padding: 20rpx;
display: flex;
flex-direction: column;
align-items: center;
.tool-icon {
padding: 15rpx;
font-size: 60rpx;
background-color: white;
border-radius: 13%;
}
.tool-name {
height: 50rpx;
line-height: 50rpx;
font-size: 25rpx;
flex: 3;
}
}
}
}
</style>

BIN
im-uniapp/static/audio/call.wav

Binary file not shown.

BIN
im-uniapp/static/audio/tip.wav

Binary file not shown.

BIN
im-uniapp/static/emoji/0.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
im-uniapp/static/emoji/1.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
im-uniapp/static/emoji/10.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
im-uniapp/static/emoji/100.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
im-uniapp/static/emoji/101.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
im-uniapp/static/emoji/102.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
im-uniapp/static/emoji/103.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
im-uniapp/static/emoji/104.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
im-uniapp/static/emoji/11.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

BIN
im-uniapp/static/emoji/12.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
im-uniapp/static/emoji/13.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
im-uniapp/static/emoji/14.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
im-uniapp/static/emoji/15.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
im-uniapp/static/emoji/16.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
im-uniapp/static/emoji/17.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
im-uniapp/static/emoji/18.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

BIN
im-uniapp/static/emoji/19.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

BIN
im-uniapp/static/emoji/2.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
im-uniapp/static/emoji/20.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
im-uniapp/static/emoji/21.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
im-uniapp/static/emoji/22.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
im-uniapp/static/emoji/23.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
im-uniapp/static/emoji/24.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
im-uniapp/static/emoji/25.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
im-uniapp/static/emoji/26.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
im-uniapp/static/emoji/27.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
im-uniapp/static/emoji/28.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
im-uniapp/static/emoji/29.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

BIN
im-uniapp/static/emoji/3.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
im-uniapp/static/emoji/30.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
im-uniapp/static/emoji/31.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

BIN
im-uniapp/static/emoji/32.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

BIN
im-uniapp/static/emoji/33.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
im-uniapp/static/emoji/34.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
im-uniapp/static/emoji/35.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
im-uniapp/static/emoji/36.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
im-uniapp/static/emoji/37.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
im-uniapp/static/emoji/38.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
im-uniapp/static/emoji/39.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
im-uniapp/static/emoji/4.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
im-uniapp/static/emoji/40.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

BIN
im-uniapp/static/emoji/41.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
im-uniapp/static/emoji/42.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
im-uniapp/static/emoji/43.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
im-uniapp/static/emoji/44.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
im-uniapp/static/emoji/45.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
im-uniapp/static/emoji/46.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
im-uniapp/static/emoji/47.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
im-uniapp/static/emoji/48.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
im-uniapp/static/emoji/49.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

BIN
im-uniapp/static/emoji/5.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
im-uniapp/static/emoji/50.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

BIN
im-uniapp/static/emoji/51.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
im-uniapp/static/emoji/52.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
im-uniapp/static/emoji/53.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
im-uniapp/static/emoji/54.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
im-uniapp/static/emoji/55.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
im-uniapp/static/emoji/56.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
im-uniapp/static/emoji/57.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
im-uniapp/static/emoji/58.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
im-uniapp/static/emoji/59.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
im-uniapp/static/emoji/6.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

BIN
im-uniapp/static/emoji/60.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
im-uniapp/static/emoji/61.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
im-uniapp/static/emoji/62.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
im-uniapp/static/emoji/63.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 971 B

BIN
im-uniapp/static/emoji/64.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 B

BIN
im-uniapp/static/emoji/65.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
im-uniapp/static/emoji/66.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
im-uniapp/static/emoji/67.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
im-uniapp/static/emoji/68.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
im-uniapp/static/emoji/69.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1015 B

BIN
im-uniapp/static/emoji/7.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
im-uniapp/static/emoji/70.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
im-uniapp/static/emoji/71.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 824 B

BIN
im-uniapp/static/emoji/72.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
im-uniapp/static/emoji/73.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
im-uniapp/static/emoji/74.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
im-uniapp/static/emoji/75.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
im-uniapp/static/emoji/76.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
im-uniapp/static/emoji/77.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
im-uniapp/static/emoji/78.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
im-uniapp/static/emoji/79.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
im-uniapp/static/emoji/8.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
im-uniapp/static/emoji/80.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
im-uniapp/static/emoji/81.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
im-uniapp/static/emoji/82.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
im-uniapp/static/emoji/83.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
im-uniapp/static/emoji/84.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
im-uniapp/static/emoji/85.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save