This commit is contained in:
唐明明
2022-02-18 10:52:29 +08:00
43 changed files with 1388 additions and 872 deletions

View File

@@ -0,0 +1,67 @@
<template>
<u-alert type="warning" v-if="connection != 0" :description="description" show-icon />
</template>
<script>
export default {
props: {
connection: {
type: Number,
default: 0
}
},
computed: {
description() {
return this.connectionStatusMap.filter(item => item.index == this.connection)[0].text
}
},
data() {
return {
connectionStatusMap: [{
index: -1,
text: '网络不可用'
},
{
index: 0,
text: '连接成功'
},
{
index: 1,
text: '连接中'
},
{
index: 2,
text: '未连接'
},
{
index: 3,
text: '用户账号在其它设备登录'
},
{
index: 4,
text: 'TOKEN过期'
},
{
index: 6,
text: '用户被禁用'
},
{
index: 12,
text: '退出登录'
},
{
index: 13,
text: '连接暂时被挂起'
},
{
index: 14,
text: '连接超时'
},
],
}
}
}
</script>
<style>
</style>

View File

@@ -46,6 +46,16 @@
}
},
created() {
uni.getSystemInfo({
success: (e) => {
this.winSize = {
width: e.windowWidth,
height: e.windowHeight
}
}
})
},
methods: {
// 隐藏功能菜单
hidePop() {
@@ -79,12 +89,15 @@
} else {
style = `top:${touches.clientY}px;`
}
if (touches.clientX > (this.winSize.witdh / 2)) {
style += `right:${this.winSize.witdh-touches.clientX}px`
if (touches.clientX > (this.winSize.width / 2)) {
style += `right:${this.winSize.width-touches.clientX}px`
} else {
style += `left:${touches.clientX}px`
}
this.popButton[0] = item.isTop ? '取消置顶' : '置顶聊天'
this.popStyle = style
this.pickedItem = item

View File

@@ -1,20 +1,15 @@
<template>
<view class="apply--cell u-border-bottom">
<view class="apply--cell">
<view class="avatar">
<u-avatar :src="user.portraitUrl" shape="square" size="46" />
<u-avatar :src="user.portraitUrl || require('@/static/user/cover.png')" shape="square" size="46" />
</view>
<view class="info">
<view class="name">
{{ user.name }}
</view>
<view class="message">
{{ message.message }}
</view>
<view class="name"> {{ user.name }}</view>
<view class="message"> {{ message.message!=='null' ? message.message : '听说你很优秀,想认识下你~' }} </view>
</view>
<view class="action">
<u-button type="success" size="mini" @click="resolve">通过</u-button>
<u-button type="warning" size="mini" @click="reject">拒绝</u-button>
<u-button class="u-button" size="default" type="success" @click="resolve">通过</u-button>
<u-button class="u-button" size="default" type="warning" @click="reject">拒绝</u-button>
</view>
</view>
</template>
@@ -41,15 +36,16 @@
methods: {
resolve() {
resolveFriend(this.message.sourceUserId).then(res => {
this.clearMessages()
uni.showToast({
icon: 'none',
title: '通过好友申请'
this.clearMessages()
uni.showToast({
icon: 'none',
title: '通过好友申请'
})
}).catch(err => {
uni.showToast({
icon: 'none',
title: err.message
uni.navigateBack({})
}).catch(err => {
uni.showToast({
icon: 'none',
title: err.message
})
})
},
@@ -73,7 +69,7 @@
// 不管是通过还是拒绝,都要把相关的信息清理
clearMessages() {
RongIMLib.deleteMessages(RongIMLib.ConversationType.SYSTEM, this.message.sourceUserId)
this.$emit('success')
this.$emit('success')
uni.$emit('onContactNotification')
}
}
@@ -85,6 +81,7 @@
display: flex;
padding: $padding;
align-items: center;
border-bottom: solid 1rpx #f9f9f9;
.info {
flex: 1;
@@ -103,9 +100,19 @@
.action {
justify-content: space-between;
display: flex;
flex-direction: row;
align-items: center;
box-sizing: border-box;
.u-button {
padding: 10rpx 20rpx !important;
font-size: $title-size-m;
height: 60rpx !important;
}
.u-button+.u-button {
margin-top: 10rpx;
margin-left: 10rpx;
}
}
}

View File

@@ -8,7 +8,7 @@
<view class="right">
<view class="title">
<view class="name">{{ item.name }}</view>
<view class="des">{{ item.latestMessage.message }}</view>
<view class="des">{{ item.latestMessage.message || '--' }}</view>
</view>
<view class="agress-btn">
<span v-if="isAgree" @click="action('agree', item)">通过</span>
@@ -105,6 +105,7 @@ export default {
.agress-btn {
display: flex;
color: #fff;
font-size: $title-size-m;
span {
display: inline-block;
padding: 6rpx 14rpx;

View File

@@ -0,0 +1,139 @@
<template>
<view class="friend-apply">
<block v-for="(item, index) in lists" v-if="lists.length > 0" :key="index">
<view class="lists">
<view class="" style="width: 100rpx;height: 100rpx;">
<u-avatar :src="item.portraitUrl || require('@/static/user/cover.png')" shape="square" size="44" />
</view>
<view class="right">
<view class="title">
<view class="name">{{ item.name }}</view>
<view class="des">{{ item.address }}</view>
</view>
<view class="agress-btn">
<span v-if="isApply && item.friendship !=='accepted'" @click="action('apply', item)">查看</span>
<span class="isFri" v-if="isApply && item.friendship ==='accepted'" @click="action('isFriend', item)">已是好友</span>
</view>
</view>
</view>
</block>
</view>
</template>
<script>
export default {
name: 'friend-apply-reject-agree',
props: {
lists: {
type: Array,
default: []
},
isAgree: {
type: Boolean,
default: false
},
isReject: {
type: Boolean,
default: false
},
isApply: {
type: Boolean,
default: false
}
},
created() {
console.log(this.lists);
},
methods: {
action(type, item) {
if (type === 'isFriend') {
// ,后期可以跳转到信息介绍页面,先留在这里
// return uni.showToast({
// title: '已是好友,无需重复添加',
// icon: 'none',
// duration: 2000
// });
}
this.$emit('action', {
type,
item
});
}
}
};
</script>
<style lang="scss" scoped>
.lists {
padding: 0 $padding;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
box-sizing: border-box;
font-size: $title-size;
color: $text-gray;
.cover {
background-color: #ffffff;
}
.right {
width: 570rpx;
margin-left: $margin - 10;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: $padding 0;
border-bottom: solid 1rpx #f9f9f9;
.title {
width: 370rpx;
.name {
width: 100%;
color: $text-color;
font-size: $title-size;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.des {
width: 100%;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: $title-size-m - 2;
margin-top: $margin - 10;
color: $text-gray-m;
}
}
.agress-btn {
display: flex;
color: #fff;
font-size: $title-size-m;
span {
display: inline-block;
padding: 6rpx 14rpx;
background-color: $text-price;
border-radius: 10rpx;
}
span:nth-child(1) {
background-color: $main-color;
margin-right: 10rpx;
}
.isFri {
background-color: #f9f9f9 !important;
color: #666;
}
}
}
}
</style>

View File

@@ -0,0 +1,331 @@
<template>
<view class="member--list">
<view class="users">
<view :class="['user', {'active': item.targetId === currentUser.targetId}]" @longpress="showAction(item)"
v-for="(item, index) in users" :key="index" @click="toUser(item)">
<view class="avatar">
<u-avatar :size="avatarSize" shape="square" :src="contact(item.targetId).portraitUrl" />
<view class="admin" v-if="item.is_admin === 1">管理</view>
<view class="owner" v-if="item.is_admin === 2">群主</view>
</view>
<view class="name">{{ item.name }}</view>
</view>
<view class="user" v-if="isAdmin">
<u-avatar @click="inviteUser" :size="avatarSize" shape="square" icon="plus" bgColor="#f9f9f9" color="#c7c7c7" />
<view class="name">邀请好友</view>
</view>
</view>
<view class="loadmore">
<u-icon name="arrow-right" @click="loadMore" v-if="members > users.length" color="#999" labelColor="#999"
label="查看更多群成员" labelPos="left" :labelSize="labelSize" :size="iconSize" />
</view>
<u-action-sheet :actions="actionMap" :title="actionTitle" cancelText="取消" @close="hideAction"
@select="handleAction" :show="actionShow" />
</view>
</template>
<script>
import {
getGroupUsers,
getGroupBase,
removeGroupUser,
setGroupAdmin,
removeGroupAdmin,
transferGroupOwner
} from '@/apis/interfaces/im.js'
import utils from '@/utils/index.js'
export default {
props: {
targetId: {
type: String,
default: ''
},
count: {
type: Number,
default: 0
}
},
data() {
return {
users: [],
isOwner: false,
isAdmin: false,
adminUid: 0,
members: 0,
actionShow: false,
actionMap: [],
actionTitle: '',
currentUser: {},
avatarSize: 45,
labelSize: 14,
iconSize: 14
}
},
computed: {
contact() {
return function(targetId) {
return this.$store.getters.contactInfo(targetId)
}
}
},
created() {
this.avatarSize = utils.rpx2px(90)
this.labelSize = utils.rpx2px(24)
this.iconSize = utils.rpx2px(26)
},
mounted() {
this.initGroupInfo()
getGroupUsers(this.targetId, this.count).then(res => {
this.users = res
res.map(item => {
this.$store.dispatch('updateContact', item)
})
})
},
methods: {
initGroupInfo() {
getGroupBase(this.targetId).then(res => {
this.isOwner = res.is_owner
this.isAdmin = res.is_admin
this.adminUid = res.user_id
this.members = res.members
})
},
initUsers() {
getGroupUsers(this.targetId, this.count).then(res => {
this.users = res
})
},
hideAction(item) {
this.actionShow = false
},
showAction(item) {
this.currentUser = item
this.actionTitle = item.name
// 只有管理员以上才会弹窗
if (this.isAdmin) {
if (this.isOwner) {
if (!item.is_admin) {
this.actionMap = [{
key: 0,
name: '移除成员',
disabled: false
}, {
key: 1,
name: '设置管理',
disabled: false
}, {
key: 2,
name: '转移群主',
disabled: false
}]
} else {
this.actionMap = [{
key: 0,
name: '移除成员',
disabled: false
}, {
key: 4,
name: '取消管理',
disabled: false
}, {
key: 2,
name: '转移群主',
disabled: false
}]
}
} else {
this.actionMap = [{
key: 0,
name: '移除成员',
disabled: false
}]
}
this.actionShow = true
}
},
handleAction(e) {
switch (e.key) {
case 0:
removeGroupUser(this.targetId, this.currentUser.targetId).then(res => {
uni.showToast({
icon: 'none',
title: '成员移除成功'
})
}).catch(err => {
uni.showToast({
icon: 'none',
title: err.message
})
}).finally(() => {
this.initUsers()
})
break;
case 1:
setGroupAdmin(this.targetId, this.currentUser.targetId).then(res => {
uni.showToast({
icon: 'none',
title: '设置管理成功'
})
}).catch(err => {
uni.showToast({
icon: 'none',
title: err.message
})
}).finally(() => {
this.initUsers()
})
break;
case 4:
removeGroupAdmin(this.targetId, this.currentUser.targetId).then(res => {
uni.showToast({
icon: 'none',
title: '取消管理员成功'
})
}).catch(err => {
uni.showToast({
icon: 'none',
title: err.message
})
}).finally(() => {
this.initUsers()
})
break;
case 2:
uni.showModal({
title: '转让群主',
content: '这个操作不可逆转,确定要转让群主身份么?',
success: (res) => {
if (res.confirm) {
console.log(this.targetId, this.currentUser.targetId);
transferGroupOwner(this.targetId, this.currentUser.targetId).then(
res => {
uni.showToast({
icon: 'none',
title: '群主转让成功'
})
}).catch(err => {
uni.showToast({
icon: 'none',
title: err.message
})
}).finally(() => {
this.initUsers()
this.initGroupInfo()
})
}
}
})
break;
}
},
inviteUser() {
uni.navigateTo({
url: '/pages/im/group/invite?targetId=' + this.targetId
})
},
loadMore() {
uni.navigateTo({
url: '/pages/im/group/users?targetId=' + this.targetId
})
},
toUser(item) {
if (item.targetId == this.$store.getters.sender.userId) {
uni.navigateTo({
url: '/pages/im/friends/mine?targetId=' + item.targetId
})
} else {
uni.navigateTo({
url: '/pages/im/friends/info?targetId=' + item.targetId
})
}
}
}
}
</script>
<style lang="scss" scoped>
.users {
flex-direction: row;
flex-wrap: wrap;
display: flex;
padding: 20rpx 0;
.user {
width: 126rpx;
margin-left: 20rpx;
margin-bottom: 20rpx;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
&.active {
background-color: $window-color;
}
.avatar {
border-radius: 0 8rpx 0 0;
position: relative;
width: 90rpx;
height: 90rpx;
overflow: hidden;
.admin {
position: absolute;
background-color: $main-color;
transform: rotate(45deg);
color: #ffffff;
font-size: 16rpx;
width: 100rpx;
padding-top: 30rpx;
text-align: center;
right: -45rpx;
top: -20rpx;
}
.owner {
position: absolute;
background-color: $text-price;
transform: rotate(45deg);
color: #ffffff;
font-size: 16rpx;
width: 100rpx;
padding-top: 30rpx;
text-align: center;
right: -45rpx;
top: -20rpx;
}
}
.name {
color: 20rpx;
width: 126rpx;
padding-top: 6rpx;
text-align: center;
font-size: 22rpx !important;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
word-break: break-word;
color: $text-gray-m !important;
}
}
}
.loadmore {
font-size: 26rpx;
color: $text-gray-m;
text-align: center;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
box-sizing: border-box;
}
</style>

View File

@@ -6,8 +6,7 @@
</view>
<view class="content">
<view class="header">
<view class="name">{{ contact(item.targetId).name }} <text v-if="item.conversationType === 3"
class='qun'>[]</text></view>
<view class="name">{{ contact(item.targetId).name }} <text v-if="item.conversationType === 3" class='qun'>[]</text></view>
<view class="time">{{ item.sentTime|timeCustomCN }}</view>
</view>
<message-preview class="preview" :msg="item.latestMessage" :conversationType="item.conversationType"
@@ -44,7 +43,7 @@
<style lang="scss" scoped>
.message--cell {
display: flex;
padding: 20rpx 0 0 20rpx;
padding: 20rpx 10rpx 0 30rpx;
.avatar {
position: relative;
@@ -59,9 +58,10 @@
box-sizing: border-box;
position: relative;
flex: 1;
border-bottom-width: 0.5px !important;
border-color: $u-border-color !important;
border-color: #f9f9f9 !important;
border-bottom-style: solid;
.header {
@@ -70,22 +70,26 @@
.name {
font-size: $title-size + 2;
color: #454545;
display: flex;
align-items: center;
color: #454545;
display: flex;
align-items: center;
.qun {
color: $main-color;
font-size: $title-size-m;
font-size: $title-size-m - 4;
margin-left: 4px;
position: relative;
top: -4rpx;
}
}
.time {
font-size: $title-size-sm;
font-size: $title-size-sm - 3;
color: $text-gray-m;
position: absolute;
right: 30rpx;
padding-top: 4rpx;
font-weight: normal;
}
}
}

View File

@@ -1,28 +1,31 @@
<template>
<view>
<view class="preview" v-if="msg.objectName=='RC:TxtMsg'">
<text v-if="conversationType == 3">{{ user.name }}: </text>{{ msg.content || '' }}
<text v-if="conversationType == 3">{{ user.name }}</text>{{ msg.content || '' }}
</view>
<view class="preview" v-if="msg.objectName=='RC:HQVCMsg'">
<text v-if="conversationType == 3">{{ user.name }}: </text>[语音]
<text v-if="conversationType == 3">{{ user.name }}</text>[语音]
</view>
<view class="preview" v-if="msg.objectName=='RC:ImgMsg'">
<text v-if="conversationType == 3">{{ user.name }}: </text>[图片]
<text v-if="conversationType == 3">{{ user.name }}</text>[图片]
</view>
<view class="preview" v-if="msg.objectName=='RC:GIFMsg'">
<text v-if="conversationType == 3">{{ user.name }}: </text>[表情]
<text v-if="conversationType == 3">{{ user.name }}</text>[表情]
</view>
<view class="preview" v-if="msg.objectName=='RC:FileMsg'">
<text v-if="conversationType == 3">{{ user.name }}: </text>[文件]
<text v-if="conversationType == 3">{{ user.name }}</text>[文件]
</view>
<view class="preview" v-if="msg.objectName=='RC:LBSMsg'">
<text v-if="conversationType == 3">{{ user.name }}: </text>[位置]
<text v-if="conversationType == 3">{{ user.name }}</text>[位置]
</view>
<view class="preview" v-if="msg.objectName=='RC:AudioMsg'">
<text v-if="conversationType == 3">{{ user.name }}: </text>[语音通话]
<text v-if="conversationType == 3">{{ user.name }}</text>[语音通话]
</view>
<view class="preview" v-if="msg.objectName=='RC:VideoMsg'">
<text v-if="conversationType == 3">{{ user.name }}: </text>[视频通话]
<text v-if="conversationType == 3">{{ user.name }}</text>[视频通话]
</view>
<view class="preview" v-if="msg.objectName=='RC:GrpNtf'">
[{{ msg.message }}]
</view>
</view>
</template>
@@ -54,9 +57,9 @@
.preview {
word-break: break-all;
color: $text-gray-m;
padding-top: $padding - 20;
padding-top: 6rpx;
padding-bottom: $padding;
font-size: $title-size-m;
font-size: $title-size-m - 2;
height: 32rpx;
line-height: 32rpx;
width: 520rpx;

View File

@@ -3,22 +3,15 @@
<!-- footer -->
<view class="footer">
<view class="msg-type" @click="changeMessageType">
<image class="icon" src="@/static/icon/key-icon.png" v-if="chatType === 0" mode="widthFix">
</image>
<image class="icon" src="@/static/icon/msg-icon.png" v-if="chatType === 1" mode="widthFix">
</image>
</view>
<sent-voice v-if="chatType === 0" :conversationType="conversationType" :targetId="targetId"
@success="onSuccess" />
<sent-text v-if="chatType === 1" :conversationType="conversationType" :targetId="targetId"
@success="onSuccess" @focus="onHidePopus" />
<view class="msg-type msg-popups" @click="() => { showPopups = !showPopups, onHidePopus }">
<image class="icon" src="@/static/icon/popups-icon.png"></image>
<image class="icon" src="@/static/icon/key-icon.png" v-if="chatType === 0" mode="widthFix" />
<image class="icon" src="@/static/icon/msg-icon.png" v-if="chatType === 1" mode="widthFix" />
</view>
<sent-voice v-if="chatType === 0" :conversationType="conversationType" :targetId="targetId" @success="onSuccess" />
<sent-text v-if="chatType === 1" :conversationType="conversationType" :targetId="targetId" @success="onSuccess" />
<view class="msg-type msg-popups" @click="showPopups = !showPopups"> <image class="icon" src="@/static/icon/popups-icon.png" /> </view>
</view>
<!-- 弹出层 -->
<sent-popups :show="showPopups" :conversationType="conversationType" :targetId="targetId"
@success="() => {showPopups = false, onSuccess()}"></sent-popups>
<sent-popups :show="showPopups" :conversationType="conversationType" :targetId="targetId" @success="() => {showPopups = false, onSuccess()}" />
</view>
</template>

View File

@@ -8,7 +8,7 @@
<image class="icon" src="@/static/icon/popups-icon-01.png" mode="widthFix"></image>
<text class="text">拍摄</text>
</view>
<view class="item" @click="onPopupsItem('video')">
<view class="item" @click="onPopupsItem('video')" v-if="conversationType == 1">
<image class="icon" src="@/static/icon/popups-icon-02.png" mode="widthFix"></image>
<text class="text">视频通话</text>
</view>
@@ -33,6 +33,7 @@
<script>
import im from '@/utils/im/index.js'
import * as CallLib from '@/uni_modules/RongCloud-CallWrapper/lib/index'
export default {
data() {
@@ -64,20 +65,15 @@
}
},
computed: {
user() {
sender() {
return this.$store.getters.sender
}
},
methods: {
singleCall(e) {
uni.showToast({
icon: 'none',
title: '功能正在开发中'
uni.navigateTo({
url: '/pages/im/private/call?targetId=' + this.targetId + '&mediaType=' + e.type
})
// CallLib.startSingleCall(this.targetId, e.type, '');
// uni.redirectTo({
// url: '/pages/im/private/call?targetId=' + this.targetId + '&mediaType=' + e.type
// })
},
onPopupsItem(type) {
switch (type) {
@@ -87,8 +83,7 @@
sourceType: ['album'],
success: res => {
im.sentImage(this.conversationType, this.targetId, res.tempFilePaths[0],
this.user, (
res) => {
this.sender, (res) => {
this.success()
})
}
@@ -99,8 +94,7 @@
sourceType: ['camera'],
success: res => {
im.sentImage(this.conversationType, this.targetId, res.tempFilePaths[0],
this.user, (
res) => {
this.sender, (res) => {
this.success()
})
}

View File

@@ -29,7 +29,7 @@
disabled() {
return this.inputTxt.length === 0
},
user() {
sender() {
return this.$store.getters.sender
}
},
@@ -55,7 +55,7 @@
sent() {
if (!this.disabled) {
RongIMLib.clearTextMessageDraft(this.conversationType, this.targetId)
im.sentText(this.conversationType, this.targetId, this.inputTxt, this.user, () => {
im.sentText(this.conversationType, this.targetId, this.inputTxt, this.sender, () => {
this.$emit('success')
this.inputTxt = ''
})

View File

@@ -36,7 +36,7 @@
}
},
computed: {
user() {
sender() {
return this.$store.getters.sender
}
},
@@ -85,8 +85,7 @@
//
this.recorderManager.onStop(res => {
im.sentVoice(this.conversationType, this.targetId, res.tempFilePath, (this.maxRecordTime -
this
.recordTime), this.user, () => {
this.recordTime), this.sender, () => {
setTimeout(() => {
this.$emit('success')
}, 500)