Browse Source

!131 合并

Merge pull request !131 from blue/v_3.0.0
master
blue 1 year ago
committed by Gitee
parent
commit
bf44713971
No known key found for this signature in database GPG Key ID: 173E9B9CA92EEF8F
  1. 6
      im-uniapp/common/emotion.js
  2. 15
      im-uniapp/common/url.js
  3. 32
      im-uniapp/components/bar/arrow-bar.vue
  4. 17
      im-uniapp/components/chat-message-item/chat-message-item.vue
  5. 18
      im-uniapp/im.scss
  6. 2
      im-uniapp/main.js
  7. 7
      im-uniapp/pages/chat/chat-box.vue
  8. 2
      im-uniapp/pages/mine/mine.vue
  9. 30
      im-uniapp/static/icon/iconfont.css
  10. BIN
      im-uniapp/static/icon/iconfont.ttf
  11. 15
      im-web/src/api/url.js
  12. 17
      im-web/src/components/chat/ChatMessageItem.vue
  13. 2
      im-web/src/main.js

6
im-uniapp/common/emotion.js

@ -26,7 +26,11 @@ let transform = (content, extClass) => {
let textToPath = (emoText) => { let textToPath = (emoText) => {
let word = emoText.replace(/\#|\;/gi, ''); let word = emoText.replace(/\#|\;/gi, '');
let idx = emoTextList.indexOf(word); let idx = emoTextList.indexOf(word);
return `/static/emoji/${idx}.gif`; let baseUrl = "/"
// #ifdef H5
baseUrl = window.location.pathname;
// #endif
return `${baseUrl}static/emoji/${idx}.gif`;
} }

15
im-uniapp/common/url.js

@ -0,0 +1,15 @@
let replaceURLWithHTMLLinks = (content, color) => {
// 使用正则表达式匹配更广泛的URL格式(此正则由deepseek生成)
const urlRegex = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|]|\bwww\.[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
return content.replace(urlRegex, (url) => {
// 如果URL不以http(s)://开头,则添加http://前缀
if (!url.startsWith("http")) {
url = "http://" + url;
}
return `<a href="${url}" target="_blank" style="color: ${color};text-decoration: underline;">${url}</a>`;
});
}
export default {
replaceURLWithHTMLLinks
}

32
im-uniapp/components/bar/arrow-bar.vue

@ -1,5 +1,6 @@
<template> <template>
<view class="arrow-bar"> <view class="arrow-bar">
<text class="icon iconfont" :class="icon" :style="{color: textColor}"></text>
<text class="title">{{ title }}</text> <text class="title">{{ title }}</text>
<uni-icons class="arrow" type="right" size="16"></uni-icons> <uni-icons class="arrow" type="right" size="16"></uni-icons>
</view> </view>
@ -12,8 +13,27 @@ export default {
title: { title: {
type: String, type: String,
required: true required: true
},
icon: {
type: String,
default: ''
}
},
data() {
return {
colors: ["#5daa31", "#c7515a", "#e03697", "#85029b",
"#c9b455", "#326eb6"]
} }
}, },
computed:{
textColor() {
let hash = 0;
for (var i = 0; i < this.title.length; i++) {
hash += this.title.charCodeAt(i);
}
return this.colors[hash % this.colors.length];
}
}
} }
</script> </script>
@ -21,16 +41,20 @@ export default {
.arrow-bar { .arrow-bar {
width: 100%; width: 100%;
height: 90rpx; height: 90rpx;
font-size: 30rpx; font-size: $im-font-size;
color: black; color: $im-text-color;
margin-top: 5rpx; margin-top: 5rpx;
background-color: white; background-color: white;
line-height: 90rpx; line-height: 90rpx;
display: flex; display: flex;
.icon {
margin-left: 40rpx;
}
.title { .title {
flex: 1; flex: 1;
margin-left: 40rpx; margin-left: 10rpx;
} }
.arrow { .arrow {

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

@ -17,7 +17,8 @@
<view class="chat-msg-bottom"> <view class="chat-msg-bottom">
<view v-if="msgInfo.type == $enums.MESSAGE_TYPE.TEXT"> <view v-if="msgInfo.type == $enums.MESSAGE_TYPE.TEXT">
<long-press-menu :items="menuItems" @select="onSelectMenu"> <long-press-menu :items="menuItems" @select="onSelectMenu">
<rich-text class="chat-msg-text" :nodes="$emo.transform(msgInfo.content,'emoji-normal')"></rich-text> <up-parse class="chat-msg-text" :showImgMenu="false" :content="nodesText"></up-parse>
<!-- <rich-text class="chat-msg-text" :nodes="nodesText"></rich-text> -->
</long-press-menu> </long-press-menu>
</view> </view>
<view class="chat-msg-image" v-if="msgInfo.type == $enums.MESSAGE_TYPE.IMAGE"> <view class="chat-msg-image" v-if="msgInfo.type == $enums.MESSAGE_TYPE.IMAGE">
@ -47,7 +48,8 @@
<text title="发送失败" v-if="loadFail" @click="onSendFail" <text title="发送失败" v-if="loadFail" @click="onSendFail"
class="send-fail iconfont icon-warning-circle-fill"></text> class="send-fail iconfont icon-warning-circle-fill"></text>
</view> </view>
<long-press-menu v-if="msgInfo.type == $enums.MESSAGE_TYPE.AUDIO" :items="menuItems" @select="onSelectMenu"> <long-press-menu v-if="msgInfo.type == $enums.MESSAGE_TYPE.AUDIO" :items="menuItems"
@select="onSelectMenu">
<view class="chat-msg-audio chat-msg-text" @click="onPlayAudio()"> <view class="chat-msg-audio chat-msg-text" @click="onPlayAudio()">
<text class="iconfont icon-voice-play"></text> <text class="iconfont icon-voice-play"></text>
<text class="chat-audio-text">{{ JSON.parse(msgInfo.content).duration + '"' }}</text> <text class="chat-audio-text">{{ JSON.parse(msgInfo.content).duration + '"' }}</text>
@ -162,10 +164,10 @@ export default {
onShowReadedBox() { onShowReadedBox() {
this.$refs.chatGroupReaded.open(); this.$refs.chatGroupReaded.open();
}, },
emit(){ emit() {
this.$emit("audioStateChange",this.audioPlayState,this.msgInfo); this.$emit("audioStateChange", this.audioPlayState, this.msgInfo);
}, },
stopPlayAudio(){ stopPlayAudio() {
if (this.innerAudioContext) { if (this.innerAudioContext) {
this.innerAudioContext.stop(); this.innerAudioContext.stop();
this.innerAudioContext = null; this.innerAudioContext = null;
@ -230,6 +232,11 @@ export default {
isNormal() { isNormal() {
const type = this.msgInfo.type; const type = this.msgInfo.type;
return this.$msgType.isNormal(type) || this.$msgType.isAction(type) return this.$msgType.isNormal(type) || this.$msgType.isAction(type)
},
nodesText() {
let color = this.msgInfo.selfSend ? 'white' : '';
let text = this.$url.replaceURLWithHTMLLinks(this.msgInfo.content, color)
return this.$emo.transform(text, 'emoji-normal')
} }
} }

18
im-uniapp/im.scss

@ -174,19 +174,19 @@ button[size='mini'] {
} }
.emoji-large { .emoji-large {
width: 64rpx; width: 64rpx !important;
height: 64rpx; height: 64rpx !important;
vertical-align: bottom; vertical-align: bottom !important;
} }
.emoji-normal { .emoji-normal {
width: 54rpx; width: 54rpx !important;
height: 54rpx; height: 54rpx !important;
vertical-align: bottom; vertical-align: bottom !important;
} }
.emoji-small { .emoji-small {
width: 36rpx; width: 36rpx !important;
height: 36rpx; height: 36rpx !important;
vertical-align: bottom; vertical-align: bottom !important;
} }

2
im-uniapp/main.js

@ -1,6 +1,7 @@
import App from './App' import App from './App'
import request from './common/request'; import request from './common/request';
import emotion from './common/emotion.js'; import emotion from './common/emotion.js';
import url from './common/url.js';
import * as enums from './common/enums.js'; import * as enums from './common/enums.js';
import * as date from './common/date'; import * as date from './common/date';
import * as socketApi from './common/wssocket'; import * as socketApi from './common/wssocket';
@ -39,6 +40,7 @@ export function createApp() {
app.config.globalProperties.$wsApi = socketApi; app.config.globalProperties.$wsApi = socketApi;
app.config.globalProperties.$msgType = messageType; app.config.globalProperties.$msgType = messageType;
app.config.globalProperties.$emo = emotion; app.config.globalProperties.$emo = emotion;
app.config.globalProperties.$url = url;
app.config.globalProperties.$enums = enums; app.config.globalProperties.$enums = enums;
app.config.globalProperties.$date = date; app.config.globalProperties.$date = date;
app.config.globalProperties.$rc = recorder; app.config.globalProperties.$rc = recorder;

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

@ -264,14 +264,12 @@ export default {
success: (e) => { success: (e) => {
// //
this.editorCtx.clear(); this.editorCtx.clear();
this.atUserIds = [];
this.isReceipt = false;
// //
if (this.isBanned) { if (this.isBanned) {
this.showBannedTip(); this.showBannedTip();
return; return;
} }
let sendText = this.isReceipt ? "【回执消息】" : ""; let sendText = "";
e.delta.ops.forEach((op) => { e.delta.ops.forEach((op) => {
if (op.insert.image) { if (op.insert.image) {
// emo // emo
@ -295,6 +293,9 @@ export default {
receipt: this.isReceipt, receipt: this.isReceipt,
type: 0 type: 0
} }
// @
this.atUserIds = [];
this.isReceipt = false;
// id // id
this.fillTargetId(msgInfo, this.chat.targetId); this.fillTargetId(msgInfo, this.chat.targetId);
this.sendMessageRequest(msgInfo).then((m) => { this.sendMessageRequest(msgInfo).then((m) => {

2
im-uniapp/pages/mine/mine.vue

@ -34,7 +34,7 @@
</view> </view>
</uni-card> </uni-card>
<bar-group> <bar-group>
<arrow-bar title="修改密码" @tap="onModifyPassword()"></arrow-bar> <arrow-bar title="修改密码" icon="icon-modify-pwd" @tap="onModifyPassword()"></arrow-bar>
</bar-group> </bar-group>
<bar-group> <bar-group>
<btn-bar title="退出登录" type="danger" @tap="onQuit()"></btn-bar> <btn-bar title="退出登录" type="danger" @tap="onQuit()"></btn-bar>

30
im-uniapp/static/icon/iconfont.css

@ -1,6 +1,6 @@
@font-face { @font-face {
font-family: "iconfont"; /* Project id 4272106 */ font-family: "iconfont"; /* Project id 4272106 */
src: url('iconfont.ttf?t=1719727774055') format('truetype'); src: url('iconfont.ttf?t=1739084401359') format('truetype');
} }
.iconfont { .iconfont {
@ -11,6 +11,34 @@
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
.icon-privacy-protocol:before {
content: "\e70a";
}
.icon-un-register:before {
content: "\e656";
}
.icon-modify-pwd:before {
content: "\e63c";
}
.icon-user-protocol:before {
content: "\e61a";
}
.icon-film:before {
content: "\e66b";
}
.icon-chat:before {
content: "\e624";
}
.icon-delete:before {
content: "\e605";
}
.icon-receipt:before { .icon-receipt:before {
content: "\e601"; content: "\e601";
} }

BIN
im-uniapp/static/icon/iconfont.ttf

Binary file not shown.

15
im-web/src/api/url.js

@ -0,0 +1,15 @@
let replaceURLWithHTMLLinks = (content, color) => {
// 使用正则表达式匹配更广泛的URL格式(此正则由deepseek生成)
const urlRegex = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|]|\bwww\.[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
return content.replace(urlRegex, (url) => {
// 如果URL不以http(s)://开头,则添加http://前缀
if (!url.startsWith("http")) {
url = "http://" + url;
}
return `<a href="${url}" target="_blank" style="color: ${color};text-decoration: underline;">${url}</a>`;
});
}
export default {
replaceURLWithHTMLLinks
}

17
im-web/src/components/chat/ChatMessageItem.vue

@ -22,7 +22,7 @@
<div class="chat-msg-bottom" @contextmenu.prevent="showRightMenu($event)"> <div class="chat-msg-bottom" @contextmenu.prevent="showRightMenu($event)">
<div ref="chatMsgBox"> <div ref="chatMsgBox">
<span class="chat-msg-text" v-if="msgInfo.type == $enums.MESSAGE_TYPE.TEXT" <span class="chat-msg-text" v-if="msgInfo.type == $enums.MESSAGE_TYPE.TEXT"
v-html="$emo.transform(msgInfo.content)"></span> v-html="htmlText"></span>
<div class="chat-msg-image" v-if="msgInfo.type == $enums.MESSAGE_TYPE.IMAGE"> <div class="chat-msg-image" v-if="msgInfo.type == $enums.MESSAGE_TYPE.IMAGE">
<div class="img-load-box" v-loading="loading" element-loading-text="上传中.." <div class="img-load-box" v-loading="loading" element-loading-text="上传中.."
element-loading-background="rgba(0, 0, 0, 0.4)"> element-loading-background="rgba(0, 0, 0, 0.4)">
@ -51,10 +51,10 @@
<audio controls :src="JSON.parse(msgInfo.content).url"></audio> <audio controls :src="JSON.parse(msgInfo.content).url"></audio>
</div> </div>
<div class="chat-action chat-msg-text" v-if="isAction"> <div class="chat-action chat-msg-text" v-if="isAction">
<span v-if="msgInfo.type == $enums.MESSAGE_TYPE.ACT_RT_VOICE" title="重新呼叫" @click="$emit('call')" <span v-if="msgInfo.type == $enums.MESSAGE_TYPE.ACT_RT_VOICE" title="重新呼叫"
class="iconfont icon-chat-voice"></span> @click="$emit('call')" class="iconfont icon-chat-voice"></span>
<span v-if="msgInfo.type == $enums.MESSAGE_TYPE.ACT_RT_VIDEO" title="重新呼叫" @click="$emit('call')" <span v-if="msgInfo.type == $enums.MESSAGE_TYPE.ACT_RT_VIDEO" title="重新呼叫"
class="iconfont icon-chat-video"></span> @click="$emit('call')" class="iconfont icon-chat-video"></span>
<span>{{ msgInfo.content }}</span> <span>{{ msgInfo.content }}</span>
</div> </div>
<div class="chat-msg-status" v-if="!isAction"> <div class="chat-msg-status" v-if="!isAction">
@ -203,6 +203,11 @@ export default {
isNormal() { isNormal() {
const type = this.msgInfo.type; const type = this.msgInfo.type;
return this.$msgType.isNormal(type) || this.$msgType.isAction(type) return this.$msgType.isNormal(type) || this.$msgType.isAction(type)
},
htmlText() {
let color = this.msgInfo.selfSend ? 'white' : '';
let text = this.$url.replaceURLWithHTMLLinks(this.msgInfo.content, color)
return this.$emo.transform(text)
} }
} }
} }
@ -472,4 +477,4 @@ export default {
} }
} }
</style> </style>

2
im-web/src/main.js

@ -9,6 +9,7 @@ import httpRequest from './api/httpRequest';
import * as socketApi from './api/wssocket'; import * as socketApi from './api/wssocket';
import * as messageType from './api/messageType'; import * as messageType from './api/messageType';
import emotion from './api/emotion.js'; import emotion from './api/emotion.js';
import url from './api/url.js';
import element from './api/element.js'; import element from './api/element.js';
import store from './store'; import store from './store';
import * as enums from './api/enums.js'; import * as enums from './api/enums.js';
@ -22,6 +23,7 @@ Vue.prototype.$msgType = messageType
Vue.prototype.$date = date; Vue.prototype.$date = date;
Vue.prototype.$http = httpRequest // http请求方法 Vue.prototype.$http = httpRequest // http请求方法
Vue.prototype.$emo = emotion; // emo表情 Vue.prototype.$emo = emotion; // emo表情
Vue.prototype.$url = url; // url转换
Vue.prototype.$elm = element; // 元素操作 Vue.prototype.$elm = element; // 元素操作
Vue.prototype.$enums = enums; // 枚举 Vue.prototype.$enums = enums; // 枚举
Vue.prototype.$eventBus = new Vue(); // 全局事件 Vue.prototype.$eventBus = new Vue(); // 全局事件

Loading…
Cancel
Save