Compare commits

71 Commits

Author SHA1 Message Date
013c030963 群重复邀请处理 2022-02-25 14:45:38 +08:00
7b204e4a50 merge 2022-02-25 13:56:55 +08:00
3a28e34c3d tongbug 2022-02-25 13:56:17 +08:00
ab3d5933a8 用户的本地备注信息,暂时不链接网络 2022-02-25 12:05:48 +08:00
2a1590172e uni-modules组件升级,u-icon组件替换uni-icons,前面的那个网络不好的时候加载不出来 2022-02-25 11:17:16 +08:00
9bba6e4ef4 测试开启定位,正式打包是否可用 2022-02-25 10:05:08 +08:00
9d9c0cdaf8 登录成功后,刷新会话列表 2022-02-24 17:59:44 +08:00
e0185e589d SQLITE 数据库优化,创建时机调整 2022-02-24 17:51:59 +08:00
90584f1101 撤回消息优化 2022-02-24 16:01:51 +08:00
唐明明
31846e54a7 微调 2022-02-24 15:44:43 +08:00
唐明明
75d73e9c87 新增发送语音消息成功提示音 2022-02-24 15:40:59 +08:00
唐明明
81543cdcdc merge 2022-02-24 15:21:44 +08:00
唐明明
3ea3a2decd 新增语音时长0秒提示信息,调整取消后仍然调用发送语音的bug 2022-02-24 15:21:20 +08:00
eae895f181 最低一秒钟的消息 2022-02-24 15:11:10 +08:00
3cd11c5863 Merge branch 'master' of https://git.yuzhankeji.cn/TmOct5/ZhHealth 2022-02-24 15:04:39 +08:00
f5da4e7a2c 消息操作弹窗,删除、撤回、 2022-02-24 15:04:30 +08:00
唐明明
da6b60131d merge 2022-02-24 14:19:39 +08:00
唐明明
ae0fa1bde3 删除 'pages/im/.DS_Store' 2022-02-24 14:19:22 +08:00
唐明明
8b888e250f 优化语音录制取消功能 2022-02-24 14:15:59 +08:00
4888cf2ad1 消息撤回修复 2022-02-24 13:19:59 +08:00
0eb6be37be 好友关系解除,从会话页返回主页 2022-02-24 13:03:41 +08:00
831776f7dd 删除好友的时候,对方也删除会话 2022-02-24 12:10:06 +08:00
519caab9e5 ... 2022-02-24 11:55:00 +08:00
aead0f5ed1 .. 2022-02-24 11:53:19 +08:00
fb6f5697c7 进入到群会话的时候,更新群信息 2022-02-24 11:52:24 +08:00
4760adc504 个人中信头像可预览 2022-02-24 11:50:33 +08:00
b8291a4222 长按群主,不展示菜单 2022-02-24 11:34:28 +08:00
唐明明
33eacb2a5b merge 2022-02-24 11:28:37 +08:00
唐明明
5c5445d630 merge 2022-02-24 11:27:20 +08:00
056224881e 移除成员 2022-02-24 11:27:06 +08:00
唐明明
f77a91eafe 删除 'pages/im/.DS_Store' 2022-02-24 11:26:14 +08:00
唐明明
54cf21f211 语音播放组件新增取消发送,试听 2022-02-24 11:21:00 +08:00
唐明明
da78a3ac11 merge 2022-02-24 11:19:02 +08:00
7c4874a5e1 marge 2022-02-24 11:12:13 +08:00
6f508d906d marge 2022-02-24 11:11:38 +08:00
08ffc0fa53 修复会话列表弹出层,隐藏的问题 2022-02-24 11:06:11 +08:00
e72d6b3a91 删除公告,消息撤回优化 2022-02-24 10:56:16 +08:00
8b7a259c00 merge 2022-02-24 10:18:11 +08:00
4a31ba32f7 查看消息调准 2022-02-24 10:17:54 +08:00
32e3e0ef30 组件整理 2022-02-24 10:06:33 +08:00
a7dccde63a 组件合并,群公告指向修复 2022-02-24 10:01:22 +08:00
9c7a8c8ee1 聊天样式调整 2022-02-24 09:48:57 +08:00
18173995ab merge 2022-02-24 09:43:32 +08:00
07f707f94a voice-bug 2022-02-24 09:38:11 +08:00
d1f5f75355 ... 2022-02-24 09:36:18 +08:00
2d97294c9d 优化搜索 2022-02-24 09:35:37 +08:00
78d4611fb2 mixins优化 2022-02-24 09:28:59 +08:00
358372cdba 调整目录结构 2022-02-24 09:25:35 +08:00
ef785ab05f ... 2022-02-24 09:15:24 +08:00
8f3c741ad1 同步数据 2022-02-24 09:14:30 +08:00
f4e44de777 im-MIXINS 2022-02-23 17:28:42 +08:00
853c4611ef ... 2022-02-23 17:09:26 +08:00
1d648f2dc1 ... 2022-02-23 17:08:28 +08:00
d9748d0827 图片预览优化 2022-02-23 17:07:14 +08:00
103679c372 好友申请通知优化 2022-02-23 17:01:26 +08:00
唐明明
8c32758e37 merge 2022-02-23 16:50:38 +08:00
唐明明
29757fadeb merge 2022-02-23 16:50:26 +08:00
8a8e55600f uview新版本,search高度修复 2022-02-23 16:49:15 +08:00
768edb8e87 format 2022-02-23 16:38:14 +08:00
2ce4bb827f 消息免打扰消息同步 2022-02-23 16:35:33 +08:00
f68e5fa1fd 同步 2022-02-23 16:31:14 +08:00
8bb646a520 我的群聊+人数+默认头像四个小人 2022-02-23 16:30:35 +08:00
20317cc1df 群公告的群内提醒,链接跳转 2022-02-23 16:29:06 +08:00
a5bd5a898c 资料修改的事件通知 2022-02-23 16:06:41 +08:00
唐明明
00836ac209 合并 2022-02-23 15:54:27 +08:00
c840e9ee6b 限制群名称长度14 2022-02-23 15:46:02 +08:00
18f0ee457c 同步 2022-02-23 15:32:31 +08:00
a12d8a2c40 申请加好友认证信息优化,好友列表无好友状态处理 2022-02-23 15:30:09 +08:00
1407d677de 群解散时,无论在群组中的哪个页面,都退回到会话列表页面 2022-02-23 14:13:38 +08:00
8b10fd95fe Merge branch 'master' of https://git.yuzhankeji.cn/TmOct5/ZhHealth 2022-02-23 11:36:23 +08:00
3b3dda18ca 图片预览,版本更新的版本号调整 2022-02-23 11:36:18 +08:00
81 changed files with 2474 additions and 1625 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -7,12 +7,12 @@
export default {
onLaunch: function() {
im.initIm('lmxuhwaglu76d')
return
// return
//#ifdef APP-PLUS
// 获取系统版本号
getVersions({
platform: plus.os.name,
version: plus.runtime.versionCode
version: plus.runtime.version
}).then(res => {
if (res.update) {
uni.showModal({

View File

@@ -1,3 +1,6 @@
# ZhHealth
ZH健康
## uni-icons图标组件
[图标组件](https://hellouniapp.dcloud.net.cn/pages/extUI/icons/icons)

View File

@@ -323,6 +323,7 @@ export {
dismissGroup,
inviteGroupUser,
removeGroupUser,
transferGroupOwner,
setGroupAdmin,
removeGroupAdmin,
groupMakeSure, // 通过审核

29
main.js
View File

@@ -10,15 +10,16 @@ import Vue from 'vue'
import store from './store'
import uView from 'uview-ui'
import filters from './utils/filters.js'
import {
usqlite
} from '@/uni_modules/onemue-USQLite/js_sdk/usqlite.js'
import model from '@/utils/im/models.js'
import {
router,
RouterMount
} from 'router'
import {
usqlite
} from '@/uni_modules/onemue-USQLite/js_sdk/usqlite.js'
import {
contactModel
} from '@/utils/im/models.js'
Object.keys(filters).forEach(key => {
Vue.filter(key, filters[key])
@@ -29,12 +30,20 @@ Vue.use(router)
Vue.config.productionTip = false
Vue.prototype.$store = store
uni.$sql = usqlite
uni.model = model
uni.$sql.connect({
name: 'zh-health',// 数据库名称
path:'_doc/health.db', // 路径
usqlite.connect({
name: 'zh-health', // 数据库名称
path: '_doc/health.db', // 路径
}, (err, res) => {
uni.getStorage({
key: 'FIRST_RUN',
fail: () => {
contactModel.create((err, res) => {
console.error('SQLITE 创建表格', err, res)
uni.setStorageSync('FIRST_RUN', 'X')
})
}
})
})
App.mpType = 'app'

View File

@@ -2,8 +2,8 @@
"name" : "ZH-HEALTH",
"appid" : "__UNI__C29473D",
"description" : "ZH-HEALTH您手上的健康管理专家",
"versionName" : "1.0.13",
"versionCode" : 113,
"versionName" : "1.0.20",
"versionCode" : 100,
"transformPx" : false,
/* 5+App */
"app-plus" : {
@@ -89,7 +89,7 @@
"amap" : {
"__platform__" : [ "android" ],
"appkey_ios" : "",
"appkey_android" : "05b7f32ca9c897c8b63c505d92cd654b"
"appkey_android" : "1dfbe526a37dcb1f13263e0b5871ca4d"
},
"system" : {
"__platform__" : [ "android" ]
@@ -98,41 +98,44 @@
"maps" : {
"amap" : {
"appkey_ios" : "",
"appkey_android" : "05b7f32ca9c897c8b63c505d92cd654b"
"appkey_android" : "1dfbe526a37dcb1f13263e0b5871ca4d"
}
}
},
"icons" : {
"android" : {
"hdpi" : "unpackage/res/icons/72x72.png",
"xhdpi" : "unpackage/res/icons/96x96.png",
"xxhdpi" : "unpackage/res/icons/144x144.png",
"xxxhdpi" : "unpackage/res/icons/192x192.png"
"hdpi" : "",
"xhdpi" : "",
"xxhdpi" : "",
"xxxhdpi" : ""
},
"ios" : {
"appstore" : "unpackage/res/icons/1024x1024.png",
"appstore" : "",
"ipad" : {
"app" : "unpackage/res/icons/76x76.png",
"app@2x" : "unpackage/res/icons/152x152.png",
"notification" : "unpackage/res/icons/20x20.png",
"notification@2x" : "unpackage/res/icons/40x40.png",
"proapp@2x" : "unpackage/res/icons/167x167.png",
"settings" : "unpackage/res/icons/29x29.png",
"settings@2x" : "unpackage/res/icons/58x58.png",
"spotlight" : "unpackage/res/icons/40x40.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png"
"app" : "",
"app@2x" : "",
"notification" : "",
"notification@2x" : "",
"proapp@2x" : "",
"settings" : "",
"settings@2x" : "",
"spotlight" : "",
"spotlight@2x" : ""
},
"iphone" : {
"app@2x" : "unpackage/res/icons/120x120.png",
"app@3x" : "unpackage/res/icons/180x180.png",
"notification@2x" : "unpackage/res/icons/40x40.png",
"notification@3x" : "unpackage/res/icons/60x60.png",
"settings@2x" : "unpackage/res/icons/58x58.png",
"settings@3x" : "unpackage/res/icons/87x87.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png",
"spotlight@3x" : "unpackage/res/icons/120x120.png"
"app@2x" : "",
"app@3x" : "",
"notification@2x" : "",
"notification@3x" : "",
"settings@2x" : "",
"settings@3x" : "",
"spotlight@2x" : "",
"spotlight@3x" : ""
}
}
},
"splashscreen" : {
"androidStyle" : "common"
}
},
"nativePlugins" : {

BIN
pages/.DS_Store vendored

Binary file not shown.

View File

@@ -6,8 +6,10 @@
</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='group'>[]</text>
</view>
<view class="time">{{ item.sentTime|timeCustomCN }}</view>
</view>
<message-preview class="preview" :msg="item.latestMessage" :draft="item.draft"
@@ -19,8 +21,12 @@
<script>
import messagePreview from './messagePreview'
import utils from '@/utils/index.js'
import imBase from '../../mixins/imBase.js'
export default {
mixins: [
imBase
],
props: {
item: {
type: Object,
@@ -29,21 +35,6 @@
}
}
},
data() {
return {
avatarRpx: 84
}
},
computed: {
avatarSize() {
return utils.rpx2px(this.avatarRpx)
},
contact() {
return function(targetId) {
return this.$store.getters.contactInfo(targetId)
}
}
},
components: {
messagePreview
}
@@ -80,10 +71,8 @@
.name {
font-size: $title-size + 2;
color: #454545;
display: flex;
align-items: center;
.qun {
.group {
color: $main-color;
font-size: $title-size-m - 4;
margin-left: 4px;

View File

@@ -1,23 +1,24 @@
<template>
<view>
<view v-for="(item, index) in conversations" :key="index" :class="['message', { 'is-top': item.isTop, 'is-active': pickedItem.targetId == item.targetId }]"
:data-item="item" @longpress="onLongPress" @click="toDetail(item)">
<message-cell :item="item" />
</view>
<view class="shade" @click="hidePop" v-show="showPop">
<view class="shade" @click="hidePop" @touchmove="hidePop" v-show="showPop">
<view class="pop" :style="popStyle" :class="{'show':showPop}">
<view v-for="(item, index) in popButton" :key="index" @click="pickerMenu" :data-index="index">
{{item}}
<view v-for="(item, index) in popButton" :key="index" @click="pickerMenu(index)">
{{ item }}
</view>
</view>
</view>
<view v-for="(item, index) in conversations" :key="index"
:class="['message', { 'is-top': item.isTop, 'is-active': pickedItem.targetId == item.targetId }]"
:data-item="item" @longpress="onLongPress" @click="toDetail(item)">
<message-cell :item="item" />
</view>
</view>
</template>
<script>
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
import im from '@/utils/im/index.js'
import messageCell from './messageCell'
import messageCell from './conversation/messageCell'
export default {
props: {
@@ -65,9 +66,7 @@
}, 250)
},
// 点击会话功能菜单
pickerMenu(e) {
const index = Number(e.currentTarget.dataset.index)
pickerMenu(index) {
if (index == 0) {
RongIMLib.setConversationToTop(this.pickedItem.conversationType, this.pickedItem.targetId, !this
.pickedItem.isTop)
@@ -142,8 +141,10 @@
position: fixed;
width: 100%;
height: 100%;
z-index: 999;
.pop {
border-radius: 10rpx;
position: fixed;
z-index: 101;
width: 200rpx;

View File

@@ -1,7 +1,7 @@
<template>
<view class="apply--cell">
<view class="avatar">
<u-avatar :src="user.portraitUrl || require('@/static/user/cover.png')" shape="square" size="46" />
<u-avatar :src="user.portraitUrl || require('@/static/user/cover.png')" shape="square" :size="avatarSize" />
</view>
<view class="info">
<view class="name"> {{ user.name }}</view>
@@ -20,8 +20,12 @@
resolveFriend,
rejectFriend
} from '@/apis/interfaces/im.js'
import imBase from '../mixins/imBase.js'
export default {
mixins: [
imBase
],
props: {
message: {
type: Object,
@@ -36,7 +40,6 @@
methods: {
resolve() {
resolveFriend(this.message.sourceUserId).then(res => {
this.clearMessages()
uni.showToast({
icon: 'none',
title: '通过好友申请'
@@ -47,6 +50,8 @@
icon: 'none',
title: err.message
})
}).finally(() => {
this.clearMessages()
})
},
reject() {
@@ -70,7 +75,9 @@
clearMessages() {
RongIMLib.deleteMessages(RongIMLib.ConversationType.SYSTEM, this.message.sourceUserId)
this.$emit('success')
uni.$emit('onContactNotification')
uni.$emit('onNewContactConversation')
uni.$emit('onNewContactFriends')
uni.$emit('onNewContactPendings')
}
}
}

View File

@@ -3,7 +3,7 @@
<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="JSON.parse(item.latestMessage.extra).portraitUrl" shape="square" size="44" />
<u-avatar :src="JSON.parse(item.latestMessage.extra).portraitUrl" shape="square" :size="avatarSize" />
</view>
<view class="right">
<view class="title">
@@ -14,7 +14,8 @@
<span v-if="isAgree" @click="action('agree', item)">通过</span>
<span v-if="isAgree" @click="action('reject', item)">拒绝</span>
<span v-if="isApply && !item.is_friend" @click="action('apply', item)">查看</span>
<span class="isFri" v-if="isApply && item.is_friend" @click="action('isFriend', item)">已是好友</span>
<span class="isFri" v-if="isApply && item.is_friend"
@click="action('isFriend', item)">已是好友</span>
</view>
</view>
</view>
@@ -23,104 +24,124 @@
</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});
import imBase from '../mixins/imBase.js'
export default {
mixins:[
imBase
],
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
});
}
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;
.lists {
padding: 0 $padding;
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 + 2;
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;
margin-top: $margin - 10;
color: $text-gray-m;
}
justify-content: flex-start;
box-sizing: border-box;
font-size: $title-size;
color: $text-gray;
.cover {
background-color: #ffffff;
}
.agress-btn {
.right {
width: 570rpx;
margin-left: $margin - 10;
display: flex;
color: #fff;
font-size: $title-size-m;
span {
display: inline-block;
padding: 6rpx 14rpx;
background-color: $text-price;
border-radius: 10rpx;
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 + 2;
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;
margin-top: $margin - 10;
color: $text-gray-m;
}
}
span:nth-child(1) {
background-color: $main-color;
margin-right: 10rpx;
}
.isFri {
background-color: #f9f9f9 !important;
color: #666;
.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

@@ -3,7 +3,7 @@
<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" />
<u-avatar :src="item.portraitUrl || require('@/static/user/cover.png')" shape="square" :size="avatarSize" />
</view>
<view class="right">
<view class="title">
@@ -21,7 +21,12 @@
</template>
<script>
import imBase from '../mixins/imBase.js'
export default {
mixins: [
imBase
],
name: 'friend-apply-reject-agree',
props: {
lists: {

View File

@@ -18,9 +18,8 @@
</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 class="loadmore" @click="loadMore" v-if="members > users.length">
查看更多群成员 <uni-icons size="30rpx" type="right"></uni-icons>
</view>
<u-action-sheet :actions="actionMap" :title="actionTitle" cancelText="取消" @close="hideAction"
@@ -38,8 +37,12 @@
transferGroupOwner
} from '@/apis/interfaces/im.js'
import utils from '@/utils/index.js'
import imBase from '../mixins/imBase.js'
export default {
mixins: [
imBase
],
props: {
targetId: {
type: String,
@@ -55,35 +58,23 @@
users: [],
isOwner: false,
isAdmin: false,
canInvite:false,// 是否可以开启邀请
canInvite: 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 => {
console.log("res..",res)
this.users = res
res.map(item => {
this.$store.dispatch('updateContact', item)
@@ -110,6 +101,9 @@
this.actionShow = false
},
showAction(item) {
if (item.is_admin == 2) {
return
}
this.currentUser = item
this.actionTitle = item.name
// 只有管理员以上才会弹窗
@@ -278,7 +272,6 @@
border-radius: 0 8rpx 0 0;
position: relative;
width: 84rpx;
height: 84rpx;
overflow: hidden;
.admin {
@@ -327,12 +320,16 @@
.loadmore {
font-size: 26rpx;
color: $text-gray-m;
color: $text-gray-m !important;
text-align: center;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
box-sizing: border-box;
.uni-icons {
color: $text-gray-m !important;
}
}
</style>

View File

@@ -33,9 +33,12 @@
<script>
import im from '@/utils/im/index.js'
import * as CallLib from '@/uni_modules/RongCloud-CallWrapper/lib/index'
import imBase from '../../mixins/imBase.js'
export default {
mixins: [
imBase
],
data() {
return {
callActions: [{
@@ -64,15 +67,11 @@
default: ''
}
},
computed: {
sender() {
return this.$store.getters.sender
}
},
methods: {
singleCall(e) {
uni.navigateTo({
url: '/pages/im/private/call?targetId=' + this.targetId + '&mediaType=' + e.type + '&isCall=true'
url: '/pages/im/private/call?targetId=' + this.targetId + '&mediaType=' + e.type +
'&isCall=true'
})
},
onPopupsItem(type) {
@@ -104,16 +103,11 @@
this.callShow = true
break;
case 'location':
// uni.showToast({
// icon: 'none',
// title: ''
// })
// uni.chooseLocation({
// success: res => {
// console.log(res);
// // this.success()
// }
// })
uni.chooseLocation({
success: (c) => {
console.log(c);
}
})
break;
case 'redpacket':
uni.showToast({
@@ -144,6 +138,7 @@
display: flex;
flex-wrap: wrap;
flex-direction: row;
.item {
width: 150rpx;
margin: 15rpx;

View File

@@ -8,8 +8,12 @@
<script>
import im from '@/utils/im/index.js'
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
import imBase from '../../mixins/imBase.js'
export default {
mixins: [
imBase
],
props: {
conversationType: {
type: Number,
@@ -23,9 +27,6 @@
computed: {
disabled() {
return this.inputTxt.length === 0
},
sender() {
return this.$store.getters.sender
}
},
mounted() {
@@ -71,11 +72,10 @@
display: flex;
flex-direction: row;
justify-content: space-between;
.input {
background: #F3F6FB;
height: 70rpx;
width: 500rpx;
width: 460rpx;
border-radius: 10rpx;
margin-right: 15rpx;
padding: 0 20rpx;

View File

@@ -0,0 +1,300 @@
<template>
<view class="send--voice">
<view class="voice" hover-class="chat-hover" @touchstart="startRecord" @touchend="stopRecord" @touchmove="touchmove">
<text class="button">按住说话</text>
</view>
<!-- 录音层 -->
<view class="lay" v-if="showRecordTip">
<view class="lay-header">
<view class="modal">
<image class="icon" src="@/static/icon/record-icon.png" mode="widthFix"></image>
<text class="text">录音中 {{recordTime}} s</text>
</view>
</view>
<view class="lay-toast">上滑取消</view>
<view class="lay-footer">
<image class="lay-footer-icon videoFlicker" src="@/static/icon/audio_green.png" mode="widthFix"></image>
<view class="lay-footer-text">松开发送</view>
</view>
</view>
</view>
</template>
<script>
import im from '@/utils/im/index.js'
import permision from '@/utils/permission.js'
import imBase from '../../mixins/imBase.js'
export default {
mixins: [
imBase
],
props: {
conversationType: {
type: Number,
default: 0
},
targetId: {
type: String,
default: ''
}
},
data() {
return {
showRecordTip: false,
recordTime: 60,
interval: 0,
maxRecordTime: 60,
recorderManager: null,
mp3AudioSrc: null,
isMoveCancel: false,
isBetaPlay: false, // 暂时无用
startOffsetTop: 0
}
},
computed: {
sender() {
return this.$store.getters.sender
}
},
created() {
this.recorderManager = uni.getRecorderManager()
},
methods: {
// 检查安卓录制权限
async getAndroidPermission() {
return await permision.requestAndroidPermission('android.permission.RECORD_AUDIO')
},
// 录制语音消息
startRecord(e) {
this.getAndroidPermission().then(code => {
switch (code) {
case 1:
this.startOffsetTop = e.target.offsetTop
this.showRecordTip = true
this.recorderManager.start()
this.interval = setInterval(() => {
this.recordTime -= 1
if (this.recordTime === 0) {
this.stopRecord()
}
}, 1000)
break;
case 0:
uni.showToast({
title: '暂无麦克风权限,请前往应用设置开启麦克风',
icon: 'none'
})
break;
case -1:
uni.showToast({
title: '应用权限错误',
icon: 'none'
})
break;
}
})
},
// 结束录音
stopRecord(e) {
if (!this.showRecordTip) return
// 延迟500毫秒结束录音
setTimeout(()=> {
this.recorderManager.stop()
clearInterval(this.interval)
// 监听录音结束
this.recorderManager.onStop(res => {
if(this.isMoveCancel) {
this.isMoveCancel = false
return
}
if((this.maxRecordTime - this.recordTime) <= 0){
uni.showToast({
title: '说话时间太短',
icon : 'none',
})
this.showRecordTip = false
return
}
this.mp3AudioSrc = res.tempFilePath
this.showRecordTip = false
this.senVoice()
})
},500)
},
// 发送语音消息
senVoice(){
if(this.mp3AudioSrc === null) {
uni.showToast({
title: '发送失败, 暂无音频信息',
icon : 'none'
})
return
}
im.sentVoice(this.conversationType, this.targetId, this.mp3AudioSrc, (this.maxRecordTime -
this.recordTime), this.sender, () => {
this.recordTime = this.maxRecordTime
this.mp3AudioSrc = null
setTimeout(() => {
this.$emit('success')
this.toastAudiMp3()
}, 500)
})
},
// 移动按钮
touchmove(e){
if(this.startOffsetTop - e.changedTouches[0].pageY > 100){
if(this.showRecordTip){
this.isMoveCancel = true
this.showRecordTip = false
this.recorderManager.stop()
clearInterval(this.interval)
this.recordTime = this.maxRecordTime
this.mp3AudioSrc = null
return
}
}
},
// 试听语音
startPlay() {
let betaAudio = uni.createInnerAudioContext()
betaAudio.src = this.mp3AudioSrc;
// 在播放中
if(this.isBetaPlay){
betaAudio.stop()
betaAudio.onStop(() => {
this.isBetaPlay = false;
betaAudio.destroy()
})
return
}
// 监听音频播放中
betaAudio.play()
betaAudio.onPlay(() => {
this.isBetaPlay = true;
})
// 监听音频结束
betaAudio.onEnded(() => {
this.isBetaPlay = false;
betaAudio.destroy()
})
},
// 播放提示音乐
toastAudiMp3(){
let toastAudio = uni.createInnerAudioContext()
toastAudio.src = require('@/static/im/toast/sentVoice.mp3')
toastAudio.autoplay = true
toastAudio.volume = .1
toastAudio.onEnded(() => {
toastAudio.destroy()
})
}
}
}
</script>
<style>
@keyframes playFlicker {
0% {
opacity: 1;
}
50% {
opacity: .5;
}
100% {
opacity: 1;
}
}
.videoFlicker {
animation: playFlicker 1s infinite;
}
</style>
<style scoped lang="scss">
.send--voice {
.voice {
display: flex;
background: $window-color;
height: 70rpx;
line-height: 70rpx;
justify-content: center;
align-items: center;
width: 500rpx;
border-radius: 10rpx;
margin-right: 15rpx;
.button {
font-size: 30rpx;
color: #333;
}
}
.lay{
position: absolute;
left: 0;
top: 0;
z-index: 9;
background: rgba($color: #000000, $alpha: .5);
height: 100vh;
width: 100vw;
box-sizing: border-box;
.lay-header{
height: calc(100vh - 140px);
display: flex;
justify-content: center;
align-items: center;
.modal {
display: flex;
background: rgba(0, 0, 0, .6);
position: fixed;
height: 200rpx;
width: 300rpx;
border-radius: 10rpx;
z-index: 99;
flex-direction: column;
align-items: center;
justify-content: center;
.icon {
width: 88rpx;
height: 88rpx;
}
.text {
font-size: 28rpx;
color: #FFFFFF;
}
}
}
.lay-toast{
text-align: center;
color: rgba($color: #fff, $alpha: .8);
font-size: 28rpx;
}
.lay-footer{
background-color: white;
height: 100px;
border-radius: 50% 50% 0 0;
position: absolute;
bottom: 0;
left: 0;
right: 0;
text-align: center;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
.lay-footer-icon{
width: 58rpx;
height: 58rpx;
}
.lay-footer-text{
line-height: 40rpx;
color: gray;
font-size: 28rpx;
}
}
}
}
</style>

View File

@@ -16,9 +16,9 @@
</template>
<script>
import sentText from './sentText'
import sentVoice from './sentVoice'
import sentPopups from './sentPopups'
import sentText from './sent/sentText'
import sentVoice from './sent/sentVoice'
import sentPopups from './sent/sentPopups'
export default {
props: {

View File

@@ -1,143 +0,0 @@
<template>
<view class="send--voice">
<view class="voice" hover-class="chat-hover" @touchstart="startRecord" @touchend="stopRecord">
<text class="button">按住说话</text>
</view>
<!-- 录音中提示 -->
<view class="modal" v-if="showRecordTip">
<image class="icon" src="@/static/icon/record-icon.png" mode="widthFix"></image>
<text class="text">录音中 {{recordTime}} s</text>
</view>
</view>
</template>
<script>
import im from '@/utils/im/index.js'
import permision from '@/utils/permission.js'
export default {
props: {
conversationType: {
type: Number,
default: 0
},
targetId: {
type: String,
default: ''
}
},
data() {
return {
showRecordTip: false,
recordTime: 60,
interval: 0,
maxRecordTime: 60,
recorderManager: null
}
},
computed: {
sender() {
return this.$store.getters.sender
}
},
created() {
this.recorderManager = uni.getRecorderManager()
},
methods: {
// 检查安卓录制权限
async getAndroidPermission() {
return await permision.requestAndroidPermission('android.permission.RECORD_AUDIO')
},
// 录制语音消息
startRecord() {
this.getAndroidPermission().then(code => {
switch (code) {
case 1:
this.showRecordTip = true
this.recorderManager.start()
this.interval = setInterval(() => {
this.recordTime -= 1
if (this.recordTime === 0) {
this.stopRecord()
}
}, 1000)
break;
case 0:
uni.showToast({
title: '暂无麦克风权限,请前往应用设置开启麦克风',
icon: 'none'
})
break;
case -1:
uni.showToast({
title: '应用权限错误',
icon: 'none'
})
break;
}
})
},
// 结束录音
stopRecord(e) {
if (!this.showRecordTip) return
this.recorderManager.stop()
clearInterval(this.interval)
// 监听录音结束
this.recorderManager.onStop(res => {
im.sentVoice(this.conversationType, this.targetId, res.tempFilePath, (this.maxRecordTime -
this.recordTime), this.sender, () => {
setTimeout(() => {
this.$emit('success')
}, 500)
})
this.recordTime = this.maxRecordTime
this.showRecordTip = false
})
},
}
}
</script>
<style scoped lang="scss">
.send--voice {
.voice {
display: flex;
background: $window-color;
height: 70rpx;
line-height: 70rpx;
justify-content: center;
align-items: center;
width: 500rpx;
border-radius: 10rpx;
margin-right: 15rpx;
.button {
font-size: 30rpx;
color: #333;
}
}
.modal {
display: flex;
background: rgba(0, 0, 0, .6);
position: fixed;
height: 200rpx;
width: 300rpx;
border-radius: 10rpx;
z-index: 99;
top: 550rpx;
left: 225rpx;
flex-direction: column;
align-items: center;
justify-content: center;
.icon {
width: 88rpx;
height: 88rpx;
}
.text {
font-size: 28rpx;
color: #FFFFFF;
}
}
}
</style>

View File

@@ -2,18 +2,12 @@
<view v-if="!isRemote">
<view class="state" v-if="isGroup">
<!-- 已发送 -->
<u-icon name="checkbox-mark" :size="iconSize" class="sent"
:color="message.sentStatus >= 30 ? '#34CE98' : '#999999' " />
<!-- 已阅读 -->
<uni-icons class="sent" type="checkmarkempty" size="28rpx" :color="message.sentStatus >= 30 ? '#34CE98' : '#999999'" />
<text class="readers">{{ readers }}</text>
</view>
<view class="state" v-else>
<!-- 已发送 -->
<u-icon name="checkbox-mark" :size="iconSize" class="sent"
:color="message.sentStatus >= 30 ? '#34CE98' : '#999999' " />
<!-- 已阅读 -->
<u-icon name="checkbox-mark" :size="iconSize" class="receive"
:color="message.sentStatus >= 50 ? '#34CE98' : '#999999' " />
<uni-icons class="sent" type="checkmarkempty" size="28rpx" :color="message.sentStatus >= 30 ? '#34CE98' : '#999999'" />
<uni-icons class="receive" type="checkmarkempty" size="28rpx" :color="message.sentStatus >= 50 ? '#34CE98' : '#999999'" />
</view>
</view>
</template>

View File

@@ -2,8 +2,9 @@
<view class="msg--call">
<view class="name" v-if="isGroup && isRemote">{{ contact(message.senderUserId).name }}</view>
<view class="im--text" :class="isRemote ? 'left': 'right'">
<u-icon name="camera" size="22" v-if="msg.mediaType == 1" :label="label" />
<u-icon name="phone" size="22" v-else :label="label" />
<uni-icons type="videocam" size="44rpx" v-if="msg.mediaType == 1" />
<uni-icons type="phone" size="40rpx" v-else />
{{ label }}
</view>
</view>
</template>
@@ -11,8 +12,12 @@
<script>
import utils from '@/utils/index.js'
import moment from 'moment'
import imBase from '../../mixins/imBase.js'
export default {
mixins: [
imBase
],
name: 'showText',
props: {
message: {
@@ -38,11 +43,6 @@
isRemote() {
return this.message.messageDirection == 2
},
contact() {
return function(targetId) {
return this.$store.getters.contactInfo(targetId)
}
},
duration() {
if (this.message.duration > 3600) {
return moment.utc(this.message.duration * 1000).format('HH:mm:ss')
@@ -70,6 +70,7 @@
color: $text-color;
display: flex;
flex-direction: row;
align-items: center;
&.left {
border-radius: 0 20rpx 20rpx 20rpx;
@@ -81,8 +82,8 @@
background: $main-color;
color: white;
.u-icon {
color: white;
.uni-icons {
color: white !important;
}
}
}

View File

@@ -14,8 +14,12 @@
<script>
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
import messageState from './messageState'
import imBase from '../../mixins/imBase.js'
export default {
mixins: [
imBase
],
name: 'showImage',
props: {
message: {
@@ -38,51 +42,30 @@
},
content() {
return this.message.content
},
contact() {
return function(targetId) {
return this.$store.getters.contactInfo(targetId)
}
}
},
methods: {
showImage(path) {
uni.previewImage({
urls: [
path
]
})
},
previewImage() {
if (this.content.local) {
uni.previewImage({
urls: [
this.content.local
],
success: (e) => {
console.log(e);
},
fail: (er) => {
console.log(er);
}
})
if (this.content.local && this.content.local.indexOf('///data/user/') < 0) {
this.showImage(this.content.local)
} else {
RongIMLib.downloadMediaMessage(this.messageId, {
this.showImage(this.content.remote)
RongIMLib.downloadMediaMessage(this.message.messageId, {
success: (path) => {
this.content.local = path
uni.previewImage({
urls: [
path
],
success: (e) => {
console.log(e);
},
fail: (er) => {
console.log(er);
}
})
},
progress: (progress, messageId) => {
console.log('progress', progress);
},
cancel: (messageId) => {
console.log('cancel', messageId);
},
error: (errorCode, messageId) => {
console.log('errorCode', errorCode);
uni.showToast({
icon: 'none',
title: errorCode
})
}
})
}

View File

@@ -11,9 +11,13 @@
<script>
import messageState from './messageState'
import imBase from '../../mixins/imBase.js'
export default {
name: 'showText',
mixins: [
imBase,
],
props: {
message: {
type: Object,
@@ -35,11 +39,6 @@
},
content() {
return this.message.content.content
},
contact() {
return function(targetId) {
return this.$store.getters.contactInfo(targetId)
}
}
}
}
@@ -58,7 +57,7 @@
.text {
box-sizing: border-box;
max-width: 502rpx;
padding: 20rpx;
padding: 20rpx 24rpx;
line-height: 46rpx;
font-size: 32rpx;
color: $text-color;

View File

@@ -23,8 +23,12 @@
<script>
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
import messageState from './messageState'
import imBase from '../../mixins/imBase.js'
export default {
mixins: [
imBase
],
props: {
message: {
type: Object,
@@ -54,11 +58,6 @@
isRemote() {
return this.message.messageDirection == 2
},
contact() {
return function(targetId) {
return this.$store.getters.contactInfo(targetId)
}
},
width() {
if (this.duration > 3) {
return (this.duration * 5) + 150
@@ -75,11 +74,6 @@
}
})
},
created() {
console.log(this.message.messageId)
},
methods: {
// 播放语音消息
startPlay() {

View File

@@ -1,13 +1,17 @@
<template>
<view class="">
<view class="notify" v-if="message.objectName === 'RC:GrpNtf'">{{ message.content.message }}</view>
<view class="notify" v-if="message.objectName === 'RC:GrpNtf'">
{{ message.content.message }}
<text class="link" @click="toAnnounce(message)" v-if="message.content.operation == 'ANNOUNCEMENT'">点击查看
</text>
</view>
<view class="notify" v-else-if="message.objectName === 'RC:RcNtf'">
{{ contact(message.senderUserId).name }} 撤回了一条消息
</view>
<view v-else :class="['cell-item', message.messageDirection == 1 ? 'right' : 'left']">
<u-avatar class="avatar" @click="toUser(message)" :size="avatarSize" shape="square"
:src="contact(message.senderUserId).portraitUrl" />
<view class="msg" @longpress="backMessage">
<view class="msg" @longpress="messageAction($event, message)">
<show-text v-if="message.objectName === 'RC:TxtMsg'" :message="message" :isGroup="isGroup" />
<show-voice v-else-if="message.objectName === 'RC:HQVCMsg'" :message="message" :isGroup="isGroup" />
<show-image v-else-if="message.objectName === 'RC:ImgMsg'" :message="message" :isGroup="isGroup" />
@@ -22,14 +26,21 @@
</template>
<script>
import {
getGroupAnnouncement
} from '@/apis/interfaces/im.js'
import * as IMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
import showVoice from './show/showVoice'
import showImage from './show/showImage'
import showText from './show/showText'
import showCall from './show/showCall'
import utils from '@/utils/index.js'
import imBase from '../mixins/imBase.js'
export default {
mixins: [
imBase
],
components: {
showCall,
showVoice,
@@ -48,22 +59,13 @@
default: false
}
},
data() {
return {
avatarRpx: 84
}
},
computed: {
avatarSize() {
return utils.rpx2px(this.avatarRpx)
},
contact() {
return function(targetId) {
return this.$store.getters.contactInfo(targetId)
}
}
},
methods: {
messageAction(event, message) {
this.$emit('messageAction', {
event,
message
})
},
toUser(item) {
if (item.messageDirection == 1) {
uni.navigateTo({
@@ -75,39 +77,33 @@
})
}
},
// 撤回消息测试
backMessage() {
if (this.$store.getters.sender.userId != this.message.senderUserId) {
// 跳转群公告
toAnnounce(message) {
if (message.content.extra) {
getGroupAnnouncement(message.targetId, message.content.extra).then(res => {
uni.navigateTo({
url: '/pages/im/group/announceCreate?type=check&targetId=' + message
.targetId + '&aId=' + message.content.extra
})
}).catch(err => {
IMLib.deleteMessagesByIds([message.messageId], ({
code
}) => {
if (code === 0) {
uni.$emit('remove_message_' + message.targetId, message.messageId)
}
})
uni.showToast({
title: '公告不存在或已删除',
icon: 'none',
})
})
} else {
uni.showToast({
icon: 'none',
title: '不能撤回别人的消息'
title: '旧版本,无链接'
})
return
}
// 判断时间超过了多久 就不能撤回 TODO
// this.message.sentTime
const pushContent = this.$store.getters.sender.name + '撤回了一条消息'
IMLib.recallMessage(this.message.messageId, pushContent,
({
code,
message
}) => {
if (code === 0) {
uni.showToast({
icon: 'none',
title: '消息撤回成功'
})
IMLib.getMessage(this.message.messageId, res => {
uni.$emit('onRecallMessage', res.message)
})
} else {
uni.showToast({
icon: 'none',
title: '撤回失败' + code
})
}
}
)
}
}
}
@@ -118,6 +114,11 @@
text-align: center;
font-size: 24rpx;
color: #666;
.link {
color: $main-color;
margin-left: 10rpx;
}
}
.cell-item {

View File

@@ -2,12 +2,12 @@
<view>
<u-index-list :index-list="indexs" inactiveColor="#666" activeColor="#34CE98">
<view class="friend-flex" @click="toPending">
<u-avatar class="cover" size="40" shape="square" :src="require('@/static/im/im_01.png')"></u-avatar>
<u-avatar class="cover" size="40" shape="square" :src="require('@/static/im/im_01.png')" />
<u-badge max="99" absolute :offset="[23, 20]" :value="pendingCount" />
<view class="info">新的朋友</view>
</view>
<view class="friend-flex" @click="toGroup">
<u-avatar class="cover" size="40" shape="square" :src="require('@/static/im/im_00.png')"></u-avatar>
<u-avatar class="cover" size="40" shape="square" :src="require('@/static/im/im_00.png')" />
<view class="info">我的群聊</view>
</view>
<block v-if="friends.length > 0">
@@ -20,14 +20,15 @@
:src="contact(friendItem.targetId).portraitUrl" />
<view class="info">
<view class="name">{{ contact(friendItem.targetId).name }}</view>
<!-- <view class="address">地址:{{ friendItem.address }}</view> -->
</view>
</view>
</u-index-item>
</block>
<block v-else>
<u-empty class="pages-null" mode="data" text="暂无好友" />
</block>
<view class="no-lists" v-else>
<u-image class="cover" radius="4" width="400rpx" height="400rpx"
:src=" require('@/static/imgs/no-friend.png')" :lazy-load="true" />
<span>暂无好友列表~</span>
</view>
</u-index-list>
</view>
</template>
@@ -38,8 +39,12 @@
} from '@/apis/interfaces/im';
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
import im from '@/utils/im/index.js'
import imBase from '../mixins/imBase.js'
export default {
mixins: [
imBase
],
data() {
return {
indexs: [],
@@ -55,9 +60,14 @@
}
},
onLoad() {
uni.$on('onNewContactFriends', this.checkNewFriendPending)
},
onShow() {
this.getFriendList()
this.checkNewFriendPending()
uni.$on('onContactNotification', this.checkNewFriendPending)
},
onUnload() {
uni.$off("onNewContactFriends")
},
methods: {
getFriendList() {
@@ -73,10 +83,7 @@
},
toGroup() {
uni.navigateTo({
url: '/pages/im/group/index',
fail(err) {
console.log(err);
}
url: '/pages/im/group/index'
})
},
toFriend(targetId) {
@@ -86,24 +93,15 @@
},
// 新朋友
toPending() {
// if (this.pendingCount > 0) {
uni.navigateTo({
url: '/pages/im/friends/pending'
});
// } else {
// uni.showToast({
// title: ` 暂无好友申请 ~ `,
// icon: "none",
// mask: true,
// duration: 3000
// })
// }
})
}
},
onNavigationBarButtonTap(e) {
uni.navigateTo({
url: '/pages/im/friends/search'
});
})
}
};
</script>
@@ -172,4 +170,19 @@
line-height: 24px;
background-color: #fff;
}
.no-lists {
padding-top: $padding * 3;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
font-size: $title-size-m;
color: $text-gray-m;
span {
padding-top: $padding;
}
}
</style>

View File

@@ -2,10 +2,10 @@
<view class="content">
<!-- 用户信息 -->
<view class="info-flex">
<u-avatar :src="userInfo.portraitUrl || require('@/static/user/cover.png')" shape="square" size="50"
bg-color="#fff"></u-avatar>
<u-avatar :src="userInfo.portraitUrl || require('@/static/user/cover.png')" shape="square"
:size="rpx2px(100)" bg-color="#fff"></u-avatar>
<view class="info-text">
<view class="nickname">{{ userInfo.name }}</view>
<view class="nickname">{{ contact(targetId).name }} ({{ userInfo.name }})</view>
<view class="address" @longpress="copyAddress">地址{{ userInfo.address }}</view>
</view>
</view>
@@ -14,23 +14,19 @@
<view class="item">
<label>性别</label>
<view class="text" v-if="userInfo.gender === 0">保密</view>
<view class="text" v-if="userInfo.gender === 1"></view>
<view class="text" v-if="userInfo.gender === 2"></view>
<view class="text" v-else-if="userInfo.gender === 1"></view>
<view class="text" v-else></view>
</view>
</view>
<!-- 如果是好友 -->
<block v-if="userInfo.friendship ==='accepted'">
<view class="info-btns">
<view class="item u-border-bottom" @click="setRemark">
<label>设置备注</label>
<u-icon name="arrow-right" color="#eee" size="16" />
</view>
<view class="item u-border-bottom" @click="setRemark">
<label>设置标签</label>
<u-icon name="arrow-right" color="#eee" size="16" />
<uni-icons type="right" size="32rpx" />
</view>
<view class="item u-border-bottom">
<label>聊天免打扰</label>
<label>消息免打扰</label>
<u-switch size="22" v-model="status" activeColor="#34CE98" @change="setStatus"></u-switch>
</view>
<view class="item">
@@ -69,6 +65,14 @@
</view>
</view>
</block>
<u-modal negativeTop="300" :show="modalShow" title="修改备注" showCancelButton @cancel="onHideModal"
@confirm="onChangeRemark">
<view class="slot-content">
<u--input placeholder="好友备注" border="surround" focus v-model="contactRemark" maxlength="12" />
</view>
</u-modal>
<u-action-sheet :actions="callActions" cancelText="取消" @close="callShow = false" @select="singleCall"
:show="callShow">
</u-action-sheet>
@@ -83,12 +87,17 @@
} from '@/apis/interfaces/im.js'
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
import * as CallLib from '@/uni_modules/RongCloud-CallWrapper/lib/index'
import imBase from '../mixins/imBase.js'
// friendship: '' 没有好友关系
// accepted 好友
// pending 申请中
// denied 拒绝
// blocked 黑名单
export default {
mixins: [
imBase
],
data() {
return {
targetId: '',
@@ -107,13 +116,14 @@
}
],
callShow: false,
hasPeding: false
hasPeding: false,
modalShow: false,
contactRemark: ''
}
},
onLoad(e) {
this.targetId = e.targetId
getFriendInfo(e.targetId).then(res => {
console.log(res, "获取朋友的信息")
this.userInfo = res
// 获取到用户信息之后,去检查一下要不要更新
this.$store.dispatch('updateContact', res)
@@ -148,11 +158,30 @@
})
},
toPrivate() {
uni.redirectTo({
uni.navigateTo({
url: '/pages/im/private/chat?targetId=' + this.targetId
});
},
// 设置好友备注操作
setRemark() {
this.modalShow = true
this.contactRemark = this.$store.getters.contactInfo(this.targetId).name
},
onHideModal() {
this.modalShow = false
},
onChangeRemark() {
this.$store.dispatch('setContactRemark', {
targetId: this.targetId,
remark: this.contactRemark
})
uni.showToast({
icon: 'none',
title: '备注设置成功'
})
this.onHideModal()
},
setTag() {
uni.showToast({
title: '开发中',
icon: 'none'
@@ -209,7 +238,7 @@
})
return
}
pedingFriend(this.targetId, 'message').then(res => {
pedingFriend(this.targetId, '').then(res => {
uni.showToast({
title: ` 申请成功,等待审核 `,
icon: 'none',
@@ -228,8 +257,9 @@
})
},
singleCall(e) {
uni.redirectTo({
url: '/pages/im/private/call?targetId=' + this.targetId + '&mediaType=' + e.type + '&isCall=true'
uni.navigateTo({
url: '/pages/im/private/call?targetId=' + this.targetId + '&mediaType=' + e.type +
'&isCall=true'
})
}
}
@@ -344,6 +374,10 @@
width: 200rpx;
}
.uni-icons {
color: $text-gray-m !important;
}
.text {
width: calc(100% - 200rpx);
color: $text-gray-m;

View File

@@ -4,7 +4,7 @@
<!-- 用户信息 -->
<view class="info-flex">
<view class="info-flex-item">
<u-avatar :src="infoObj.portraitUrl" shape="square" size="210rpx" bg-color="#fff" class="avatar" />
<u-avatar :src="infoObj.portraitUrl" @click='previewImg(infoObj.portraitUrl)' shape="square" size="210rpx" bg-color="#fff" class="avatar" />
<view class="nickname">{{infoObj.name}}</view>
<view class="address">{{infoObj.address}}</view>
<view class="info-code">
@@ -23,7 +23,8 @@
<script>
import {
getUserInfo
} from '@/apis/interfaces/im'
} from '@/apis/interfaces/im.js'
export default {
data() {
return {
@@ -47,6 +48,12 @@
})
},
methods: {
previewImg(item){
console.log(item)
uni.previewImage({
urls:[item]
})
},
copy() {
uni.setClipboardData({
data: this.downUrl,
@@ -99,7 +106,7 @@
.avatar {
// padding: 14rpx;
border-radius: 10rpx;
border-radius: 20rpx;
background-color: #fff;
border: solid 14rpx rgba($color: #fff, $alpha:1);
}

View File

@@ -2,7 +2,7 @@
<view class="pending">
<u-sticky>
<view class="header-search" @click="$Router.push({ name: 'SearchFriend' })">
<u-search placeholder="输入手机号码搜索" height="74" searchIcon="search" inputAlign="center" bgColor="white"
<u-search placeholder="输入手机号码搜索" searchIcon="search" inputAlign="center" bgColor="white"
:disabled="true" :show-action="false" />
</view>
</u-sticky>
@@ -33,13 +33,17 @@
bg: '#fff'
}
},
onLoad() {
onShow() {
this.getPendingList()
uni.$on('onContactNotification', this.getPendingList)
uni.$on('onNewContactPendings', this.getPendingList)
},
onUnload() {
uni.$off('onNewContactPendings')
},
methods: {
getPendingList() {
im.getPendingList((pendings) => {
console.log(pendings, 'res......')
if (pendings.length > 0) {
this.bg = '#f9f9f9'
} else {

View File

@@ -8,17 +8,19 @@
<template>
<view class="search">
<!-- 搜索 -->
<!-- 搜索 -->
<u-sticky>
<view class="header-search">
<u-search placeholder="输入用户账号、手机号" height="74" searchIcon="search" @custom="search" v-model="searchValue" @search="search" bgColor="#f9f9f9" :focus="focused" />
<u-search placeholder="输入用户账号、手机号" searchIcon="search" @custom="search" v-model="searchValue"
@search="search" bgColor="#F3F6FB" :focus="focused" />
</view>
</u-sticky>
<block v-if="searchResult.length > 0">
<applyFriend :lists="searchResult" :isApply="true" @action="action" />
</block>
<view class="no-lists" v-else>
<u-image class="cover" radius="4" width="400rpx" height="400rpx" :src="require('@/static/imgs/no-search.png')" :lazy-load="true" />
<view class="no-lists" v-if="searchResult.length === 0 && searchValue.length > 1">
<u-image class="cover" radius="4" width="400rpx" height="400rpx"
:src="require('@/static/imgs/no-search.png')" :lazy-load="true" />
<span>暂无匹配内容~</span>
</view>
</view>
@@ -30,6 +32,7 @@
pedingFriend
} from '@/apis/interfaces/im.js';
import applyFriend from '../components/friendSearchList.vue';
export default {
components: {
applyFriend
@@ -41,13 +44,27 @@
focused: true
};
},
watch: {
searchValue(value) {
console.log(value.length, 'length...')
if (value.length > 1) {
this.searchResult = []
this.search()
return
}
if(value.length === 0){
this.searchResult = []
return
}
}
},
methods: {
search() {
// friendship: '' 没有好友关系
// accepted 好友
// pending 申请中
// denied 拒绝
// blocked 黑名单
// friendship: '' 没有好友关系
// accepted 好友
// pending 申请中
// denied 拒绝
// blocked 黑名单
searchFriend(this.searchValue)
.then(res => {
this.searchResult = res;

View File

@@ -1,13 +1,15 @@
<template>
<view class="create">
<view class="create-title">公告内容</view>
<block v-if="type !== 'cheack'">
<block v-if="type === 'check'">
<view class="content"> {{content}} </view>
</block>
<block v-else>
<u--textarea v-model="content" count height="240" maxlength="240" placeholder="请输入公告内容" />
<u-button type="primary" text="发布" :disabled="disabled" @click="onCreate" color="#34CE98" />
</block>
<block v-if="type === 'cheack'">
<view class="content-a"> {{content}} </view>
</block>
</view>
</template>
@@ -16,32 +18,42 @@
createGroupAnnouncement,
getGroupAnnouncement
} from '@/apis/interfaces/im.js'
import onGroupDismiss from '../mixins/onGroupDismiss.js'
export default {
mixins: [
onGroupDismiss
],
data() {
return {
targetId: '',
content: '',
aId: '',
type: '' // check ' 查看详情'
type: '' // cheack ' 查看详情'
}
},
onLoad(e) {
this.targetId = e.targetId
if (e.type) {
this.type = e.type
}
if (e.aId) {
this.type = e.type
uni.setNavigationBarTitle({
title: '群公告'
})
this.aId = e.aId
getGroupAnnouncement(this.targetId, this.aId).then(res => {
console.log(res.content)
this.content = res.content
}).catch(err => {
uni.showToast({
title: err.message,
icon: 'none',
mask: true
})
if (err.status_code == 404) {
this.$nextTick(() => {
uni.navigateBack()
})
} else {
uni.showToast({
title: err.message,
icon: 'none',
mask: true
})
}
})
}
},
@@ -95,7 +107,7 @@
}
}
.content-a {
.content {
color: $text-color;
font-size: $title-size;
line-height: 1.7;

View File

@@ -35,8 +35,14 @@
deleteGroupAnnouncement,
topGroupAnnouncement
} from '@/apis/interfaces/im.js'
import onGroupDismiss from '../mixins/onGroupDismiss.js'
import imBase from '../mixins/imBase.js'
export default {
mixins: [
imBase,
onGroupDismiss
],
data() {
return {
targetId: '',
@@ -55,7 +61,7 @@
disabled: false
}],
actionTitle: '请选择操作',
bg:'#fff'
bg: '#fff'
}
},
onLoad(e) {
@@ -85,9 +91,9 @@
// 获取公告信息
initData() {
getGroupAnnouncements(this.targetId).then(res => {
if(res.length>0){
if (res.length > 0) {
this.bg = '#f9f9f9'
}else{
} else {
this.bg = '#fff'
}
this.announcements = res
@@ -115,7 +121,7 @@
},
tabA(id) {
uni.navigateTo({
url: '/pages/im/group/announceCreate?type=cheack&targetId=' + this.targetId + '&aId=' + id
url: '/pages/im/group/announceCreate?type=check&targetId=' + this.targetId + '&aId=' + id
})
},
onTop(aId) {
@@ -128,14 +134,6 @@
uni.$emit('updateAnnouncement')
this.initData()
})
// uni.showModal({
// title: ' 置顶该公告',
// success: (res) => {
// if (res.confirm) {
// }
// }
// })
},
// 删除公告
onDelete(aId) {
@@ -148,14 +146,6 @@
uni.$emit('updateAnnouncement')
this.initData()
})
// uni.showModal({
// title: '删除该公告',
// success: (res) => {
// if (res.confirm) {
// }
// }
// })
}
}
}
@@ -194,7 +184,8 @@
box-sizing: border-box;
font-size: $title-size-m;
color: $text-gray-m;
padding: 10rpx;
padding: 20rpx 10rpx 10rpx 10rpx;
border-top: solid 1rpx #F9F9F9;
.name {
padding-left: 10rpx;
@@ -215,8 +206,6 @@
-webkit-line-clamp: 3;
overflow: hidden;
line-height: 1.5;
border-bottom: solid 1rpx #F9F9F9;
padding-bottom: 20rpx;
span {
color: #fff;

View File

@@ -20,8 +20,14 @@
joinGroupPre,
joinGroup
} from '@/apis/interfaces/im.js'
import onGroupDismiss from '../mixins/onGroupDismiss.js'
import imBase from '../mixins/imBase.js'
export default {
mixins: [
imBase,
onGroupDismiss
],
data() {
return {
targetId: '',

View File

@@ -2,10 +2,18 @@
<view class="chat">
<sent-message-bar :conversationType="conversationType" :targetId="targetId" @onSuccess="getNewMessage()" />
<view class="shade" @click="hidePop" v-show="showPop">
<view class="pop" :style="popStyle" :class="{'show':showPop}">
<view v-for="(item, index) in popButton" :key="index" @click="pickerMenu(item)">
{{ item }}
</view>
</view>
</view>
<view class="body">
<view class="scroll">
<view class="cell" v-for="(message, index) in messages" :key="index">
<show-message-cell :message="message" isGroup />
<show-message-cell :message="message" isGroup @messageAction="messageAction" />
</view>
</view>
</view>
@@ -21,8 +29,16 @@
import sentMessageBar from '../components/sentMessageBar'
import showMessageCell from '../components/showMessageCell'
import utils from '@/utils/index.js'
import onGroupDismiss from '../mixins/onGroupDismiss.js'
import imBase from '../mixins/imBase.js'
import messageActions from '../mixins/messageActions.js'
export default {
mixins: [
imBase,
onGroupDismiss,
messageActions
],
components: {
sentMessageBar,
showMessageCell
@@ -49,21 +65,16 @@
}
}
},
onShow() {
this.initGroupInfo()
},
onLoad(e) {
this.targetId = e.targetId
// 获取群成员数量
getGroupBase(this.targetId).then(res => {
uni.setNavigationBarTitle({
title: res.name + `(${res.members})`
})
})
// 获取历史消息列表
this.getMessageList()
// 监听收到本群的消息,追加消息
uni.$on('onReceiveMessage', (msg) => {
if (msg.targetId == this.targetId) {
this.getNewMessage()
}
// 监听消息
uni.$on('onReceiveMessage_' + this.targetId, (message) => {
this.getNewMessage()
})
uni.$on('onReceiptRequest', (msg) => {
if (msg.targetId == this.targetId) {
@@ -88,20 +99,24 @@
})
// 清理聊天记录
uni.$once('cleanGroupMessage', this.getMessageList)
uni.$on('onRecallMessage', (res) => {
if (res.targetId == this.targetId) {
this.messages = this.messages.map(item => {
if (res.messageId == item.messageId) {
return res
} else {
return item
}
})
}
uni.$on('onRecallMessage_' + this.targetId, (message) => {
this.messages = this.messages.map(item => {
if (message.messageId == item.messageId) {
return message
} else {
return item
}
})
})
uni.$on('onRemoveMessage_' + this.targetId, (messageId) => {
this.messages = this.messages.filter(item => item.messageId != messageId)
})
},
onUnload() {
uni.$off('onRecallMessage')
uni.$off('onRemoveMessage_' + this.targetId)
uni.$off('onReceiveMessage_' + this.targetId)
uni.$off('onUpdateProfile_' + this.targetId)
uni.$off('onRecallMessage_' + this.targetId)
uni.$off('onReceiptRequest')
uni.$off('onReceiptResponse')
},
@@ -111,6 +126,14 @@
})
},
methods: {
initGroupInfo() {
// 获取群信息,成员数量,设置标题
getGroupBase(this.targetId).then(res => {
uni.setNavigationBarTitle({
title: res.name + `(${res.members})`
})
})
},
onScroll(e) {
this.$refs.messageBar.onHidePopus()
},
@@ -164,7 +187,7 @@
},
onHide() {
// console.log(JSON.stringify(this.$refs))
this.$refs.voice.stopPlay()
// this.$refs.voice.stopPlay()
}
}
</script>
@@ -197,4 +220,47 @@
}
}
}
/* 遮罩 */
.shade {
position: fixed;
width: 100%;
height: 100%;
z-index: 999;
.pop {
border-radius: 10rpx;
position: fixed;
z-index: 101;
width: 200rpx;
box-sizing: border-box;
font-size: 28rpx;
text-align: left;
color: #333;
background-color: #fff;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
line-height: 80rpx;
transition: transform 0.15s ease-in-out 0s;
user-select: none;
-webkit-touch-callout: none;
transform: scale(0, 0);
&.show {
transform: scale(1, 1);
}
&>view {
padding: 0 20rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
user-select: none;
-webkit-touch-callout: none;
&:active {
background-color: #f3f3f3;
}
}
}
}
</style>

View File

@@ -3,16 +3,15 @@
<block v-if="groups.length > 0">
<view class="title"> 群聊 </view>
<view v-for="(item, index) in groups" :key="index" class="friend-flex" @click="toGroup(item.targetId)">
<u-avatar size="38" shape="square" :src="contact(item.targetId).portraitUrl" />
<u-avatar size="36" shape="square" :src="contact(item.targetId).portraitUrl" />
<view class="info">
<view class="name">{{ item.name }}</view>
<view class="name">{{ item.name }} <span class="total">{{ item.members }} 成员</span></view>
</view>
</view>
<view class="group-count"> {{groups.length}}个群聊 </view>
<view class="group-count"> {{ groups.length }}个群聊 </view>
</block>
<view class="no-lists" v-else>
<u-image class="cover" radius="4" width="400rpx" height="400rpx"
:src="require('@/static/imgs/no-friend.png')" :lazy-load="true" />
<u-image class="cover" radius="4" width="400rpx" height="400rpx" :src="require('@/static/imgs/no-friend.png')" :lazy-load="true" />
<span>空空如也~</span>
</view>
<u-modal negativeTop="300" :show="createModal" title="创建群聊" showCancelButton @cancel="onHideModal"
@@ -49,13 +48,14 @@
onNavigationBarButtonTap() {
this.createModal = true
},
onLoad() {
onShow() {
this.initData()
uni.$on('onGroupDismiss', this.initData)
},
methods: {
initData() {
getMyGroups().then((res) => {
console.log(res,'res...')
if (res.length > 0) {
this.bg = '#f9f9f9'
} else {
@@ -138,6 +138,11 @@
font-size: $title-size + 1;
color: #454545 !important;
}
.total{
color: $text-gray-m;
font-size: $title-size-m - 5;
padding-left: 10rpx;
}
.address {
color: $text-gray-m;

View File

@@ -9,12 +9,11 @@
<view slot="label" class="announcement-label "> {{announcement}} </view>
</u-cell>
<u-cell :border="false" class="u-border-bottom" isLink title="二维码" @click="showGroupQrCode" />
<u-cell :border="false" class="u-border-bottom" v-if="group.can_makesure" isLink title="群聊邀请确认"
@click="showGroupsSure" />
<u-cell :border="false" class="u-border-bottom" v-if="group.can_makesure" isLink title="群聊邀请确认" @click="showGroupsSure" />
<u-cell :border="false" class="u-border-bottom" title="聊天置顶">
<u-switch slot="value" size="20" v-model="isTop" activeColor="#34CE98" @change="setTop" />
</u-cell>
<u-cell class="u-border-bottom" :border="false" title="免打扰">
<u-cell class="u-border-bottom" :border="false" title="消息免打扰">
<u-switch slot="value" size="20" v-model="status" activeColor="#34CE98" @change="setStatus" />
</u-cell>
</u-cell-group>
@@ -22,11 +21,10 @@
<u-cell-group class="cells" v-if="group.is_admin" :border="false">
<u-cell :border="false" class="u-border-bottom" isLink title="修改群聊名称" :value="groupName"
@click="onGroupName" />
<u-cell :border="false" class="u-border-bottom" isLink title="修改群头像" @click="onGroupAvatar">
<!-- <u-cell :border="false" class="u-border-bottom" isLink title="修改群头像" @click="onGroupAvatar">
<u-avatar slot="value" size="25" shape="square" :src="group.cover" />
</u-cell>
<u-cell :border="false" class="u-border-bottom" isLink v-if="group.is_owner" title="准入方式" :value="joinType"
@click="onChangeJoinType" />
</u-cell> -->
<u-cell :border="false" class="u-border-bottom" isLink v-if="group.is_owner" title="准入方式" :value="joinType" @click="onChangeJoinType" />
</u-cell-group>
<view class="cells actions" v-if="loaded">
@@ -35,21 +33,15 @@
<view class="action u-border-bottom" v-else @click="onQuite">删除并退出</view>
</view>
<u-modal negativeTop="300" :show="modalShow" title="修改群名称" showCancelButton @cancel="onHideModal"
@confirm="onChangeGroupName">
<view class="slot-content">
<u--input placeholder="群名称" border="surround" focus v-model="groupName" />
</view>
<u-modal negativeTop="300" :show="modalShow" title="修改群名称" showCancelButton @cancel="onHideModal" @confirm="onChangeGroupName">
<view class="slot-content"> <u--input placeholder="群名称" border="surround" focus v-model="groupName" maxlength="12" /> </view>
</u-modal>
<u-modal :show="qrCodeShow" :title="group.name" @confirm="qrCodeShow = false">
<view class="slot-content">
<uqrcode class="info-code-src" :size="198" :text="qrContent" />
</view>
<view class="slot-content"> <uqrcode class="info-code-src" :size="198" :text="qrContent" /> </view>
</u-modal>
<u-action-sheet @select="doAction" :actions="joinTypeMap" cancelText="取消" :show="showActions"
@close="showActions=false" />
<u-action-sheet @select="doAction" :actions="joinTypeMap" cancelText="取消" :show="showActions" @close="showActions=false" />
</view>
</template>
@@ -65,11 +57,17 @@
} from '@/apis/interfaces/uploading'
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
import groupUserList from '../components/groupUserList'
import onGroupDismiss from '../mixins/onGroupDismiss.js'
import imBase from '../mixins/imBase.js'
export default {
components: {
groupUserList
},
mixins: [
imBase,
onGroupDismiss
],
data() {
return {
targetId: '',
@@ -133,7 +131,6 @@
return item.key == res.join_type
})[0].name
}).catch(err => {
console.log('getGroupInfo ERR', err);
uni.showToast({
icon: 'none',
title: '群不存在'

View File

@@ -8,8 +8,9 @@
<u-index-list :index-list="indexs" inactiveColor="#666" activeColor="#34CE98">
<u-checkbox-group v-if="friends.length > 0" v-model="checkboxValue" placement="column">
<u-index-item v-for="(item, fkey) in friends" :key="fkey">
<u-index-anchor :text="indexs[fkey]" v-if="indexs[fkey]" bgColor="#f9f9f9f" height="20" size="12"
color="#666" style="border:none !important;padding: 10rpx 30rpx;background-color: #f9f9f9 !important;" />
<u-index-anchor :text="indexs[fkey]" v-if="indexs[fkey]" bgColor="#f9f9f9f" height="20"
size="12" color="#666"
style="border:none !important;padding: 10rpx 30rpx;background-color: #f9f9f9 !important;" />
<view v-for="(friendItem, index) in item" :key="index" class="friend-flex"
@click="addContact(friendItem.targetId)">
<u-checkbox :name="friendItem.targetId" shape="circle" activeColor="#34ce98"
@@ -25,7 +26,8 @@
</u-checkbox-group>
</u-index-list>
<view class="bottom">
<span class="onInvite" @click="onInvite">完成<span>{{`(${checkboxValue.length})` || ''}}</span></span>
<span class="onInvite" v-if="canInvite"> 添加中<span>{{`(${checkboxValue.length})` || ''}}</span></span>
<span class="onInvite" v-else @click="onInvite">完成<span>{{`(${checkboxValue.length})` || ''}}</span></span>
</view>
</block>
<view class="no-lists" v-else>
@@ -44,10 +46,15 @@
getGroupUsers
} from '@/apis/interfaces/im';
import utils from '@/utils/index.js'
import onGroupDismiss from '../mixins/onGroupDismiss.js'
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
import imBase from '../mixins/imBase.js'
export default {
mixins: [
imBase,
onGroupDismiss
],
data() {
return {
searchTxt: '',
@@ -57,16 +64,10 @@
friends: [],
orignalFriends: [],
checkboxValue: [],
selectValue: []
selectValue: [],
canInvite:false
};
},
computed: {
contact() {
return function(targetId) {
return this.$store.getters.contactInfo(targetId)
}
}
},
onLoad(e) {
this.targetId = e.targetId
this.getFriendList()
@@ -123,23 +124,26 @@
},
onInvite() {
console.log(this.checkboxValue,'userIds.....')
console.log(this.selectValue,'userIds.....')
console.log(this.checkboxValue, 'userIds.....')
console.log(this.selectValue, 'userIds.....')
this.canInvite = true
let userIds = []
this.checkboxValue.filter(item=>{
if(!utils.inArray(item, this.selectValue)){
this.checkboxValue.filter(item => {
if (!utils.inArray(item, this.selectValue)) {
userIds.push(item)
}
})
// console.log(userIds)
inviteGroupUser(this.targetId, this.checkboxValue,userIds).then(res => {
inviteGroupUser(this.targetId, this.checkboxValue, userIds).then(res => {
uni.navigateBack({
delta: 1,
animationType: 'pop-out',
animationDuration: 200
});
this.canInvite = false
uni.$emit('groupInvitedUser')
}).catch(err => {
this.canInvite = false
uni.showToast({
icon: 'none',
title: err.message

View File

@@ -3,7 +3,7 @@
<view class="reviewed">
<block v-if="pendings.length > 0">
<view class="reviewed-item" v-for="(item, index) in pendings" :key="index">
<u-avatar class="avatar"
<u-avatar class="avatar"
:src="JSON.parse(item.content.extra).portraitUrl || require('@/static/user/cover.png')"
shape="square" size="46" />
<view style="flex:1;" v-if="item.content.operation == 'GroupPending'">
@@ -22,7 +22,7 @@
<view class="no-lists" v-else>
<u-image class="cover" radius="4" width="400rpx" height="400rpx"
:src="require('@/static/imgs/no-friend.png')" :lazy-load="true" />
<span> 暂无群聊申请数据~</span>
<span>暂无群聊申请数据</span>
</view>
</view>
</template>
@@ -34,9 +34,14 @@
} from "@/apis/interfaces/im.js"
import im from '@/utils/im/message.js'
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
import onGroupDismiss from '../mixins/onGroupDismiss.js'
import imBase from '../mixins/imBase.js'
export default {
mixins: [
imBase,
onGroupDismiss
],
data() {
return {
targetId: '',
@@ -79,7 +84,6 @@
uni.$emit('groupInvitedUser')
}
})
}).catch(err => {
// uni.showToast({
// title: err.message,
@@ -93,7 +97,7 @@
console.log('code', code)
if (code == 0) {
uni.showToast({
title:err.message,
title: err.message,
icon: 'none',
mask: true,
duration: 2000
@@ -153,6 +157,7 @@
}
}
.no-lists {
padding-top: $padding * 5;
display: flex;

View File

@@ -4,7 +4,12 @@
<script>
import groupUserList from '../components/groupUserList'
import onGroupDismiss from '../mixins/onGroupDismiss.js'
export default {
mixins: [
onGroupDismiss
],
components: {
groupUserList
},

View File

@@ -46,7 +46,8 @@
return {
conversations: [], // 会话列表
connection: 0,
hasNewFriends: 0
hasNewFriends: 0,
perPage: 200
}
},
components: {
@@ -54,27 +55,35 @@
connectionStatus
},
onLoad() {
// 好友申请数量
this.checkNewFriendPending()
// 监听新的好友申请
uni.$on('onContactNotification', () => {
uni.$on('onNewContactConversation', () => {
console.log('更新好友申请数量');
// 更新好友申请数量
this.checkNewFriendPending()
})
},
onShow() {
// 好友申请数量
this.checkNewFriendPending()
if (this.$store.state.token !== '') {
this.getConversationList()
}
uni.$on('onConnectionStatusChange', (status) => {
this.connection = status
})
// 监听新消息
uni.$on('onReceiveMessage', (msg) => {
this.getConversationList()
})
// 监听网络状态变化
uni.$on('onConnectionStatusChange', (status) => {
this.connection = status
if (status == 0) {
this.getConversationList()
}
})
},
onHide() {
uni.$off('onReceiveMessage')
uni.$off('onConnectionStatusChange')
},
methods: {
checkNewFriendPending() {
@@ -91,15 +100,14 @@
}
return true
},
// 获取私聊的会话列表
// 获取会话列表,最新的一千条
getConversationList() {
const count = 1000
const timestamp = 0
RongIMLib.getConversationList([1, 3], count, timestamp, ({
RongIMLib.getConversationList([1, 3], this.perPage, 0, ({
code,
conversations
}) => {
if (code === 0) {
console.log(conversations,',,,,,')
this.conversations = conversations
}
})

22
pages/im/mixins/imBase.js Normal file
View File

@@ -0,0 +1,22 @@
import utils from '@/utils/index.js'
export default {
computed: {
contact() {
return function(targetId) {
return this.$store.getters.contactInfo(targetId)
}
},
avatarSize() {
return utils.rpx2px(84)
},
sender() {
return this.$store.getters.sender
}
},
methods: {
rpx2px(size) {
return utils.rpx2px(size)
}
}
}

View File

@@ -0,0 +1,133 @@
import * as IMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
export default {
data() {
return {
winSize: {},
showPop: false,
/* 弹窗按钮列表 */
popButton: ['复制', '删除', '撤回'],
/* 弹窗定位样式 */
popStyle: "",
pickedItem: {}
}
},
onLoad() {
uni.getSystemInfo({
success: (e) => {
this.winSize = {
width: e.windowWidth,
height: e.windowHeight
}
}
})
},
methods: {
// 隐藏功能菜单
hidePop() {
this.showPop = false
this.pickedItem = {}
setTimeout(() => {
this.showShade = false
}, 250)
},
// 点击会话功能菜单
pickerMenu(e) {
const msg = this.pickedItem
console.log(msg);
switch (e) {
case '复制':
uni.setClipboardData({
data: msg.content.content
})
uni.showToast({
icon: 'none',
title: '复制成功'
})
break;
case '删除':
IMLib.deleteMessagesByIds([msg.messageId], ({
code
}) => {
if (code === 0) {
uni.$emit('onRemoveMessage_' + msg.targetId, msg.messageId)
uni.showToast({
title: '消息删除成功',
icon: 'none',
})
}
})
break;
case '撤回':
const pushContent = this.$store.getters.sender.name + '撤回了一条消息'
IMLib.recallMessage(msg.messageId, pushContent,
({
code,
message
}) => {
if (code === 0) {
uni.showToast({
icon: 'none',
title: '消息撤回成功'
})
msg.objectName = 'RC:RcNtf'
uni.$emit('onRecallMessage_' + msg.targetId, msg)
} else {
uni.showToast({
icon: 'none',
title: '撤回失败' + code
})
}
}
)
break;
}
this.hidePop()
},
messageAction(e) {
let [touches, style, item] = [e.event.touches[0], "", e.message]
if (touches.clientY > (this.winSize.height / 2)) {
style = `bottom:${this.winSize.height-touches.clientY}px;`
} else {
style = `top:${touches.clientY}px;`
}
if (touches.clientX > (this.winSize.width / 2)) {
style += `right:${this.winSize.width-touches.clientX}px`
} else {
style += `left:${touches.clientX}px`
}
if (item.messageDirection == 2) {
if (item.objectName == 'RC:TxtMsg') {
this.popButton = ['复制', '删除']
} else {
this.popButton = ['删除']
}
} else {
if ((new Date()).getTime() - item.sentTime > 120 * 1000) {
if (item.objectName == 'RC:TxtMsg') {
this.popButton = ['复制', '删除']
} else {
this.popButton = ['删除']
}
} else {
if (item.objectName == 'RC:TxtMsg') {
this.popButton = ['复制', '撤回']
} else {
this.popButton = ['删除']
}
}
}
this.popStyle = style
this.pickedItem = item
this.$nextTick(() => {
setTimeout(() => {
this.showPop = true;
}, 10)
})
},
}
}

View File

@@ -0,0 +1,34 @@
// 监听群解散的消息,直接跳转到会话列表页面
export default {
data() {
return {
currentTargetId: ''
}
},
onLoad(e) {
this.currentTargetId = e.targetId
uni.$once('onGroupDismiss_' + e.targetId, () => {
uni.showToast({
icon: 'none',
title: '当前群已解散'
})
uni.switchTab({
url: '/pages/im/index'
})
})
uni.$once('onGroupRemoveYou_' + e.targetId, () => {
uni.showToast({
icon: 'none',
title: '您已被移出群聊'
})
uni.switchTab({
url: '/pages/im/index'
})
})
},
onUnload() {
uni.$off('onGroupDismiss_' + this.currentTargetId)
uni.$off('onGroupRemoveYou_' + this.currentTargetId)
}
}

View File

@@ -150,7 +150,7 @@
} else {
IMLib.insertIncomingMessage(1, targetId, targetId, sentStatus, messageContent, sentTime)
}
uni.$emit('onReceiveMessage', {
uni.$emit('onReceiveMessage_' + this.targetId, {
targetId: this.targetId
})
},

View File

@@ -1,11 +1,20 @@
<template>
<view class="chat">
<sent-message-bar :conversationType="conversationType" :targetId="targetId" @onSuccess="getNewMessage()" />
<view class="shade" @click="hidePop" v-show="showPop">
<view class="pop" :style="popStyle" :class="{'show':showPop}">
<view v-for="(item, index) in popButton" :key="index" @click="pickerMenu(item)">
{{ item }}
</view>
</view>
</view>
<!-- chat -->
<view class="body">
<view class="scroll">
<view class="cell" v-for="(message, index) in messages" :key="index">
<show-message-cell :message="message" />
<show-message-cell :message="message" @messageAction="messageAction" />
</view>
</view>
</view>
@@ -18,8 +27,14 @@
import sentMessageBar from '../components/sentMessageBar'
import showMessageCell from '../components/showMessageCell'
import utils from '@/utils/index.js'
import imBase from '../mixins/imBase.js'
import messageActions from '../mixins/messageActions.js'
export default {
mixins: [
imBase,
messageActions
],
components: {
sentMessageBar,
showMessageCell
@@ -45,11 +60,6 @@
sentTime: 0
}
}
},
contact() {
return function(targetId) {
return this.$store.getters.contactInfo(targetId)
}
}
},
onLoad(e) {
@@ -60,6 +70,10 @@
})
// 获取消息列表
this.getMessageList()
// 监听新消息
uni.$on('onReceiveMessage_' + this.targetId, (message) => {
this.getNewMessage()
})
// 监听消息已读状态
uni.$on('onReadReceiptReceived', (data) => {
if (data.targetId == this.targetId) {
@@ -72,25 +86,29 @@
})
}
})
// 监听收到新消息,判断是否是当前会话,更新会话内容
uni.$on('onReceiveMessage', (msg) => {
if (msg.targetId == this.targetId) {
this.getNewMessage()
}
uni.$on('onRecallMessage_' + this.targetId, (message) => {
this.messages = this.messages.map(item => {
if (message.messageId == item.messageId) {
return message
} else {
return item
}
})
})
uni.$on('onRecallMessage', (res) => {
if (res.targetId == this.targetId) {
this.messages = this.messages.map(item => {
if (res.messageId == item.messageId) {
return res
} else {
return item
}
})
}
uni.$once('onUserDelete_' + this.targetId, () => {
uni.showToast({
icon: 'none',
title: '好友关系已解除'
})
uni.switchTab({
url: '/pages/im/index'
})
})
},
onUnload() {
uni.$off('onUserDelete_' + this.targetId)
uni.$off('onReceiveMessage_' + this.targetId)
uni.$off('onRecallMessage_' + this.targetId)
uni.$off('onRecallMessage')
uni.$off('onReadReceiptReceived')
},
@@ -195,4 +213,47 @@
}
}
}
/* 遮罩 */
.shade {
position: fixed;
width: 100%;
height: 100%;
z-index: 999;
.pop {
border-radius: 10rpx;
position: fixed;
z-index: 101;
width: 200rpx;
box-sizing: border-box;
font-size: 28rpx;
text-align: left;
color: #333;
background-color: #fff;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
line-height: 80rpx;
transition: transform 0.15s ease-in-out 0s;
user-select: none;
-webkit-touch-callout: none;
transform: scale(0, 0);
&.show {
transform: scale(1, 1);
}
&>view {
padding: 0 20rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
user-select: none;
-webkit-touch-callout: none;
&:active {
background-color: #f3f3f3;
}
}
}
}
</style>

BIN
static/.DS_Store vendored

Binary file not shown.

BIN
static/im/toast/sentVoice.mp3 Executable file

Binary file not shown.

BIN
static/user/cover-s.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -1,4 +1,7 @@
import im from "@/utils/im/index.js"
import {
contactModel
} from '@/utils/im/models.js'
export default {
state: {
@@ -14,7 +17,7 @@ export default {
const info = state.contacts[targetId]
return {
name: info.name,
name: info.remark ? info.remark : info.name,
hash: info.hash,
portraitUrl: info.localAvatar ? info.localAvatar : require('@/static/user/cover.png')
}
@@ -44,9 +47,27 @@ export default {
name: contactInfo.name,
portraitUrl: contactInfo.portraitUrl
}
},
setContactRemark(state, contactInfo) {
Vue.set(state.contacts, contactInfo.targetId, contactInfo)
}
},
actions: {
setContactRemark({
commit
}, {
targetId,
remark
}) {
contactModel.find('targetId="' + targetId + '"', (err, result) => {
if (!err && result.length > 0) {
result[0].remark = remark
contactModel.update('targetId="' + targetId + '"', result[0], (err, res) => {
commit('setContactRemark', result[0])
})
}
})
},
setSenderInfo({
commit
}, contactInfo) {
@@ -63,8 +84,7 @@ export default {
commit,
dispatch
}, contactInfo) {
const model = uni.model.contactModel
model.find('targetId="' + contactInfo.targetId + '"', (err, result) => {
contactModel.find('targetId="' + contactInfo.targetId + '"', (err, result) => {
if (result.length == 0) {
// 没有数据,直接新增一条
dispatch('initContact', contactInfo)
@@ -75,12 +95,13 @@ export default {
targetId: contactInfo.targetId,
name: contactInfo.name,
hash: contactInfo.hash,
type: contactInfo.type,
portraitUrl: contactInfo.portraitUrl,
localAvatar: savedFilePath
}
model.update('targetId="' + contactInfo.targetId + '"', info, (err,
contactModel.update('targetId="' + contactInfo.targetId + '"', info, (err,
res) => {
console.log('UPDATE AVATAR, ERR', err, info);
console.log('UPDATE AVATAR, ERR', err, info)
})
commit('updateContactInfo', info)
})
@@ -89,16 +110,17 @@ export default {
targetId: contactInfo.targetId,
name: contactInfo.name,
hash: contactInfo.hash,
type: contactInfo.type,
portraitUrl: contactInfo.portraitUrl,
localAvatar: result[0].localAvatar
}
model.update('targetId="' + contactInfo.targetId + '"', info, (err, res) => {
contactModel.update('targetId="' + contactInfo.targetId + '"', info, (err, res) => {
console.log('UPDATE NAME, ERR', err, info);
})
commit('updateContactInfo', info)
}
} else {
console.log('updateContact, 无操作');
console.log('updateContact, 无操作')
}
})
},
@@ -108,7 +130,6 @@ export default {
}, contactInfo) {
// 将好友信息保存到vuex的内存中方便立即使用
commit('updateContactInfo', contactInfo)
const model = uni.model.contactModel
// 用户头像,是否需要下载到本地
if (contactInfo.portraitUrl) {
saveAvatar(contactInfo, (savedFilePath) => {
@@ -116,10 +137,13 @@ export default {
targetId: contactInfo.targetId,
name: contactInfo.name,
hash: contactInfo.hash,
type: contactInfo.type,
portraitUrl: contactInfo.portraitUrl,
localAvatar: savedFilePath
}
model.insert(info, (err, res) => {})
contactModel.insert(info, (err, res) => {
console.error('保存头像', err, res)
})
// 保存头像后,更新信息
commit('updateContactInfo', info)
})
@@ -129,10 +153,13 @@ export default {
targetId: contactInfo.targetId,
name: contactInfo.name,
hash: contactInfo.hash,
type: contactInfo.type,
portraitUrl: contactInfo.portraitUrl,
localAvatar: ''
}
model.insert(info, (err, res) => {})
contactModel.insert(info, (err, res) => {
console.error('没保存头像', err, res)
})
}
}
}

BIN
uni_modules/onemue-USQLite/.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -1,7 +1,10 @@
## 2.1.02022-01-14
1. 新增了添加多个数据的事件选项options, index感谢`@风扬`
## 2.1.22022-01-14
1. 新增了添加多个数据的事件选项options, index感谢`@风扬`
## 2.2.22022-02-18
1. 解决了自增约束的部分bug
2. 解决了处理类型的问题
## 2.2.02022-02-16
1. 重新处理了判断类型的方法
2. 解决了`no connect`的问题
3. 新增了自增约束,需要为数字类型
## 2.1.02022-01-14
1. 新增了添加多个数据的事件选项options, index感谢`@风扬`
## 2.0.22022-01-05

View File

@@ -37,10 +37,13 @@ class Utils {
}
}
}
Utils.log(primaryKeyArr.length);
if (primaryKeyArr.length>=1) {
sql = `CREATE TABLE '${name}' (${sqlArr.join(', ')}, PRIMARY KEY (${primaryKeyArr.join()}))`;
}else{
if (primaryKeyArr.length>1) {
sql = `CREATE TABLE '${name}' (${sqlArr.join(', ').replaceAll(' PRIMARY KEY','')}, PRIMARY KEY (${primaryKeyArr.join()}))`;
}
else{
sql = `CREATE TABLE '${name}' (${sqlArr.join(', ')})`;
}
Utils.log(`modelSql :${sql}`);
@@ -59,6 +62,22 @@ class Utils {
}
restrainArray.push(Utils.toType(options.type));
// 主键
if (options.primaryKey == true) {
if(options.autoIncrement != true){
restrainArray.push('PRIMARY KEY');
}
}
// 自增
if (Utils.isNumber(options.type)&&options.autoIncrement == true) {
restrainArray.pop();
restrainArray.push('INTEGER');
restrainArray.push('PRIMARY KEY');
restrainArray.push('AUTOINCREMENT');
}
// 非空
if (options.notNull == true) {
restrainArray.push('NOT NULL');
@@ -74,10 +93,6 @@ class Utils {
restrainArray.push('UNIQUE');
}
// 主键
// if (options.primaryKey === true) {
// restrainArray.push('PRIMARY KEY');
// }
// 检查
if (options.check) {
@@ -87,27 +102,44 @@ class Utils {
return restrainArray.join(' ');
}
// 联合主键
static getUnionPrimaryKey() {
}
static toType(jsType) {
let sqliteType = '';
if (jsType == Number) {
if (Utils.isNumber(jsType)) {
sqliteType = 'numeric';
} else if (jsType == Date) {
} else if (Utils.isDate(jsType)) {
sqliteType = 'timestamp';
} else {
sqliteType = 'varchar';
}
return sqliteType;
}
static log() {
if (config.deBug) {
console.log.apply(null, arguments);
}
}
static warn() {
if (config.deBug) {
console.warn.apply(null, arguments);
}
}
static error() {
console.error.apply(null, arguments);
}
static isArray(value){ return Object.prototype.toString.call(value) === '[object Array]'}
static isObject(value){ return Object.prototype.toString.call(value) === '[object Object]'}
static isString(value){ return Object.prototype.toString.call(value) === '[object String]'}
static isFunction(value){ return (value === Function || Object.prototype.toString.call(value) === '[object Function]')}
static isNumber(value){ return (value === Number || Object.prototype.toString.call(value) === '[object Number]')}
static isNaN(value){ return (Object.prototype.toString.call(value) === '[object Number]' && isNaN(value))}
static isBoolean(value){ return Object.prototype.toString.call(value) === '[object Boolean]'}
static isUndefined(value){ return Object.prototype.toString.call(value) === '[object Undefined]'}
static isModel(value){ return Object.prototype.toString.call(value) === '[object Model]'}
static isDate(value){ return (value === Date||Object.prototype.toString.call(value) === '[object Date]')}
}
@@ -118,7 +150,7 @@ class Model {
/**
* @constructor
* @param {String} name 数据库表名
* @param {Object} options 数据表列对象
* @param {} options 数据表列对象
* @returns
*/
constructor(name, options) {
@@ -129,7 +161,10 @@ class Model {
if (config.isConnect) {
self.repair();
} else {
console.error('no connect');
if(!config.name||!config.path){
console.error('"config.name" or "config.path" is empty');
}
usqlite.connect(config);
}
}
@@ -138,21 +173,27 @@ class Model {
* @param {String|Array} options
* - String WHERE 内容
* - Array 需要查询的列
* @param {*} callback
* @param {Function} callback
* @returns
*/
find(options, callback) {
let sql = '';
let self = this;
self.repair();
if (!callback) {
if(!(Utils.isString(options)||Utils.isArray(options)||Utils.isFunction(options))) {
Utils.error('The first parameter of Model.find should be "Array", "String" or "Function" (when there is only one parameter).')
}
if(!callback&&!(Utils.isFunction(options))) {
Utils.error('The second parameter of Model.find should be "Function".')
}
if (!callback&&Utils.isFunction(options)) {
sql = `SELECT * FROM '${this.name}'`; // 查找全部
callback = options;
} else if (options.constructor == Array) {
} else if (Utils.isArray(options)) {
sql = `SELECT ${options.join()} FROM '${this.name}'`; // 查找制定列
} else if (options.constructor == String) {
} else if (Utils.isString(options)) {
sql = `SELECT * FROM '${this.name}' WHERE ${options}`; // 制定条件查询
};
}
Utils.log(`find: ${sql}`);
@@ -180,6 +221,12 @@ class Model {
let sql = '';
let self = this;
self.repair();
if(!Utils.isObject(options)){
Utils.error('The first parameter of Model.limit should be "Object".')
}
if(!Utils.isFunction(callback)){
Utils.error('The second parameter of Model.limit should be "Function".')
}
if (!options.where) {
// 不存在 where
@@ -215,12 +262,19 @@ class Model {
let self = this;
self.repair();
if(!(Utils.isObject(options)||Util.isArray(options))){
Utils.error('The first parameter of Model.insert should be "Object" or "Array".')
}
if(!Utils.isFunction(callback)){
Utils.error('The second parameter of Model.insert should be "Function".')
}
if (config.isConnect) {
if (options.constructor == Array) {
if (Utils.isArray(options)) {
for (var i = 0; i < options.length; i++) {
this.insert(options[i], callback, i);
}
} else if (options.constructor == Object) {
} else if (Utils.isObject(options)) {
let keys = [];
let values = [];
let index = arguments[3]??null;
@@ -255,7 +309,7 @@ class Model {
/**
* @description 更新数据
* @param {Object} options可选参数 更新条件
* @param {String} options可选参数 更新条件
* @param {Object} obj 修改后的数据
* @param {Function} callback :err,results=>{}
*/
@@ -265,6 +319,13 @@ class Model {
let items = [];
self.repair();
if(!(Utils.isObject(options)||Utils.isString(options))){
Utils.error('The first parameter of Model.update should be "Object" or "String".')
}
if(!(Utils.isObject(obj)||Utils.isFunction(obj))){
Utils.error('The second parameter of Model.update should be "Objrct" or "Function".')
}
if (!callback) {
// 不存在options
callback = obj;
@@ -298,7 +359,7 @@ class Model {
/**
* @description 删除数据
* @param {Object} options :可选参数 删除条件
* @param {String} options :可选参数 删除条件
* @param {Function} callback :err,results=>{}
*/
delete(options, callback) {
@@ -306,6 +367,13 @@ class Model {
let self = this;
self.repair();
if(!(Utils.isString(options)||Utils.isFunction(options))){
Utils.error('The first parameter of Model.delete should be "Object" or "Function".')
}
if(callback&&!Utils.isFunction(callback)){
Utils.error('The second parameter of Model.delete should be "Function".')
}
if (!callback) {
sql = `DELETE FROM '${this.name}'`;
callback = options;
@@ -330,7 +398,7 @@ class Model {
/**
* @description 重命名或者新增列
* @param {Object} options 参数 数组为新增多列 对象为新增单列{aa} 字符串重命名
* @param {Object|Array|String} options 参数 数组为新增多列 对象为新增单列{aa} 字符串重命名
* @param {Function} callback :err,results=>{}
* @return:
*/
@@ -338,12 +406,18 @@ class Model {
let self = this;
let sql = '';
self.repair();
if(!(Utils.isObject(options)||Utils.isArray(options)||Utils.isString(options))){
Utils.error('The first parameter of Model.alter should be "Object", "Array" or "String".')
}
if(!Utils.isFunction(callback)){
Utils.error('The second parameter of Model.alter should be "Function".')
}
if (options.constructor == Array) { // 新增多列
if (Utils.isArray(options)) { // 新增多列
for (let i = 0; i < options.length; i++) {
self.alter(options[i], callback);
}
} else if (options.constructor == Object) { // 新增单列
} else if (Utils.isObject(options)) { // 新增单列
let column = Utils.restrain(options.name, options.option);
sql = `ALTER TABLE '${this.name}' ADD COLUMN ${column}`
} else if (options.constructor == String) { // 重命名
@@ -374,13 +448,13 @@ class Model {
*/
join(model, options, callback) {
if (!model) {
console.error('"model" cannot be empty.');
Utils.error('"model" cannot be empty.');
}
if (options.constructor != Object) {
console.error('The type of "options" is wrong, it should be "Object".');
if (!Utils.isObject(options)) {
Utils.error('The type of "options" is wrong, it should be "Object".');
}
if (!options.type || !options.predicate) {
console.error('Missing required parameters');
Utils.error('Missing required parameters');
}
let leftName = this.name;
@@ -427,6 +501,13 @@ class Model {
* @param {Function} callback :err,results=>{}
*/
sql(sql, callback) {
if (!Utils.isString(sql)) {
Utils.error('"The type of "sql" is wrong, it should be "String".');
}
if (callback&&!Utils.isFunction(callback)) {
Utils.error('The type of "callback" is wrong, it should be "Function".');
}
let self = this;
self.repair();
@@ -449,6 +530,10 @@ class Model {
* @param {Function} callback
*/
isExist(callback) {
if (callback&&!Utils.isFunction(callback)) {
Utils.error('The type of "callback" is wrong, it should be "Function".');
}
let sql = `SELECT count(*) AS isExist FROM sqlite_master WHERE type='table' AND name='${this.name}'`;
let self = this;
Utils.log(`isExist: ${sql}`);
@@ -470,6 +555,10 @@ class Model {
* @param {Function} callback
*/
drop(callback) {
if (callback&&!Utils.isFunction(callback)) {
Utils.error('The type of "callback" is wrong, it should be "Function".');
}
var sql = `DROP TABLE '${this.name}'`;
let self = this;
self.repair();
@@ -493,6 +582,10 @@ class Model {
* @param {Function} callback
*/
create(callback) {
if (callback&&!Utils.isFunction(callback)) {
Utils.error('The type of "callback" is wrong, it should be "Function".');
}
let self = this;
let sql = Utils.modelSql(self.name, self.options);
Utils.log(`create: ${sql}`);
@@ -574,6 +667,7 @@ export class usqlite {
}
});
}
/**
* @description 断开数据库
* @param {*} callback
@@ -591,6 +685,19 @@ export class usqlite {
}
});
}
static closeAsync(options){
plus.sqlite.closeDatabase({
name: config.name, //数据库名称
path: config.path, //数据库地址
success(e) {
config.isConnect = false;
callback(null, e);
},
fail(e) {
callback(e);
}
});
}
/**
* @description 创建 Model 对象
* @example

Binary file not shown.

View File

@@ -1,7 +1,7 @@
{
"id": "onemue-USQLite",
"displayName": "u-SQLite V2",
"version": "2.1.0",
"version": "2.2.2",
"description": "基于ORM技术使用对象的方式来操作sqlite数据库而无需编写任何sql语句.",
"keywords": [
"USQLite,数据库操作,缓存,大数据缓存,sqlite,sql,orm"

View File

@@ -1,5 +1,6 @@
<h2>onemue-USQLite</h2>
<h2>onemue-USQLite</h2><h2>onemue-USQLite</h2>
<h2 style="color:red">没有特别说明,均为异步函数</h2>
> u-SQLite 交流群643867519
> 如果觉的当前插件对你有帮助可以前往 [github](https://github.com/onemue/u-sqlite) 点 star!
@@ -49,6 +50,7 @@ let studentModel = uni.$sql.model('student',{
- unique UNIQUE 不重复
- default DEFAULT 默认值
- notNull NOT NULL 非空
- autoIncrement AUTOINCREMENT 非空
**联合主键**

View File

@@ -1,3 +1,9 @@
## 1.3.52022-01-24
- 优化 size 属性可以传入不带单位的字符串数值
## 1.3.42022-01-24
- 优化 size 支持其他单位
## 1.3.32022-01-17
- 修复 nvue 有些图标不显示的bug兼容老版本图标
## 1.3.22021-12-01
- 优化 示例可复制图标名称
## 1.3.12021-11-23

View File

@@ -173,6 +173,13 @@ export default {
"unicode": "e6bb",
"unicode_decimal": 59067
},
{
"icon_id": "24923353",
"name": "arrowthinright",
"font_class": "arrowthinright",
"unicode": "e6bb",
"unicode_decimal": 59067
},
{
"icon_id": "24923354",
"name": "arrowthinleft",
@@ -180,6 +187,13 @@ export default {
"unicode": "e6bc",
"unicode_decimal": 59068
},
{
"icon_id": "24923354",
"name": "arrowthinleft",
"font_class": "arrowthinleft",
"unicode": "e6bc",
"unicode_decimal": 59068
},
{
"icon_id": "24923355",
"name": "arrowthinup",
@@ -187,12 +201,25 @@ export default {
"unicode": "e6bd",
"unicode_decimal": 59069
},
{
"icon_id": "24923355",
"name": "arrowthinup",
"font_class": "arrowthinup",
"unicode": "e6bd",
"unicode_decimal": 59069
},
{
"icon_id": "24923356",
"name": "arrowthindown",
"font_class": "arrow-down",
"unicode": "e6be",
"unicode_decimal": 59070
},{
"icon_id": "24923356",
"name": "arrowthindown",
"font_class": "arrowthindown",
"unicode": "e6be",
"unicode_decimal": 59070
},
{
"icon_id": "24923349",
@@ -200,6 +227,12 @@ export default {
"font_class": "bottom",
"unicode": "e6b8",
"unicode_decimal": 59064
},{
"icon_id": "24923349",
"name": "arrowdown",
"font_class": "arrowdown",
"unicode": "e6b8",
"unicode_decimal": 59064
},
{
"icon_id": "24923346",
@@ -208,6 +241,13 @@ export default {
"unicode": "e6b5",
"unicode_decimal": 59061
},
{
"icon_id": "24923346",
"name": "arrowright",
"font_class": "arrowright",
"unicode": "e6b5",
"unicode_decimal": 59061
},
{
"icon_id": "24923347",
"name": "arrowup",
@@ -215,6 +255,13 @@ export default {
"unicode": "e6b6",
"unicode_decimal": 59062
},
{
"icon_id": "24923347",
"name": "arrowup",
"font_class": "arrowup",
"unicode": "e6b6",
"unicode_decimal": 59062
},
{
"icon_id": "24923348",
"name": "arrowleft",
@@ -222,6 +269,13 @@ export default {
"unicode": "e6b7",
"unicode_decimal": 59063
},
{
"icon_id": "24923348",
"name": "arrowleft",
"font_class": "arrowleft",
"unicode": "e6b7",
"unicode_decimal": 59063
},
{
"icon_id": "24923334",
"name": "eye",

View File

@@ -1,14 +1,18 @@
<template>
<!-- #ifdef APP-NVUE -->
<text :style="{ color: color, 'font-size': size + 'px' }" class="uni-icons" @click="_onClick">{{unicode}}</text>
<text :style="{ color: color, 'font-size': iconSize }" class="uni-icons" @click="_onClick">{{unicode}}</text>
<!-- #endif -->
<!-- #ifndef APP-NVUE -->
<text :style="{ color: color, 'font-size': size + 'px' }" class="uni-icons" :class="['uniui-'+type,customPrefix,customPrefix?type:'']" @click="_onClick"></text>
<text :style="{ color: color, 'font-size': iconSize }" class="uni-icons" :class="['uniui-'+type,customPrefix,customPrefix?type:'']" @click="_onClick"></text>
<!-- #endif -->
</template>
<script>
import icons from './icons.js';
const getVal = (val) => {
const reg = /^[0-9]*$/g
return (typeof val === 'number' || reg.test(val) )? val + 'px' : val;
}
// #ifdef APP-NVUE
var domModule = weex.requireModule('dom');
import iconUrl from './uniicons.ttf'
@@ -61,6 +65,9 @@
return unescape(`%u${code.unicode}`)
}
return ''
},
iconSize(){
return getVal(this.size)
}
},
methods: {

View File

@@ -1,7 +1,7 @@
{
"id": "uni-icons",
"displayName": "uni-icons 图标",
"version": "1.3.2",
"version": "1.3.5",
"description": "图标组件,用于展示移动端常见的图标,可自定义颜色、大小。",
"keywords": [
"uni-ui",

View File

@@ -1,3 +1,13 @@
## 3.3.122022-01-15
- 新增 preferedAppPlatform 配置用于解决uni-app vue2版本vue3版本获取platform不一致的问题 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=prefered-app-platform)
- 修复 checkToken 未返回自定义token内容的Bug
## 3.3.112022-01-11
- 修复用户名密码登录时多个应用出现重复用户名登录报错的Bug
## 3.3.102022-01-07
- 新增 自定义国际化语言支持 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=custom-i8n)
- 修复 一键登录时未校验重复手机号是否已验证的Bug
- 修复 Apple登录时用户邮箱为空时报错的Bug
- 修复 登录接口未传username时错误提示不正确的Bug
## 3.3.92021-11-09
- 去除重复的context.xxx未找到的提示语
## 3.3.82021-10-28

View File

@@ -1,7 +1,7 @@
{
"id": "uni-id",
"displayName": "uni-id",
"version": "3.3.9",
"version": "3.3.12",
"description": "简单、统一、可扩展的用户中心",
"keywords": [
"uniid",

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
{
"name": "uni-id",
"version": "3.3.5",
"version": "3.3.12",
"description": "uni-id for uniCloud",
"main": "index.js",
"homepage": "https://uniapp.dcloud.io/uniCloud/uni-id",

View File

@@ -1,3 +1,5 @@
## 1.0.32022-01-21
- 优化 组件示例
## 1.0.22021-11-22
- 修复 / 符号在 vue 不同版本兼容问题引起的报错问题
## 1.0.12021-11-22

View File

@@ -1,7 +1,7 @@
{
"id": "uni-scss",
"displayName": "uni-scss 辅助样式",
"version": "1.0.2",
"version": "1.0.3",
"description": "uni-sass是uni-ui提供的一套全局样式 通过一些简单的类名和sass变量实现简单的页面布局操作比如颜色、边距、圆角等。",
"keywords": [
"uni-scss",
@@ -14,8 +14,8 @@
},
"dcloudext": {
"category": [
"uni-app前端模板",
"前端页面模板"
"JS SDK",
"通用 SDK"
],
"sale": {
"regular": {

View File

@@ -9,6 +9,9 @@ import {
getImToken,
getMyGroups
} from '@/apis/interfaces/im.js'
import {
contactModel
} from './models.js'
const initIm = (KEY) => {
RongIMLib.init(KEY)
@@ -20,6 +23,8 @@ const initIm = (KEY) => {
getImToken().then(res => {
connect(res.token, res.userInfo, (res) => {
console.log('IM.CONNECT', res);
// 发布全局事件,有新消息,刷新会话列表
uni.$emit('onReceiveMessage')
})
})
}
@@ -62,13 +67,12 @@ const connect = (token, userInfo, callback) => {
// 设置未读消息数量
setNotifyBadge()
// 首次运行获取好友列表
const FK = 'ZHKD_' + userInfo.targetId
const FK = 'ZH_CONTACT_' + userInfo.targetId
uni.getStorage({
key: FK,
success: () => {
const model = uni.model.contactModel
model.find((err, results) => {
contactModel.find((err, results) => {
results.map(item => {
store.dispatch('launchContact', item)
})

View File

@@ -20,7 +20,30 @@ const onReceiveMessage = (message) => {
}
})
im.setNotifyBadge()
// 发布全局事件,有新消息,刷新会话列表
uni.$emit('onReceiveMessage', message)
// 这个是为了更新消息列表页的
uni.$emit('onReceiveMessage_' + message.targetId, message)
}
// 检测联系人信息,不存在的时候,从服务端获取
const checkContactExists = (message) => {
if (!store.getters.contactIsExist(message.targetId)) {
getUserInfo(message.targetId).then(res => {
console.log('targetId', res);
store.dispatch('initContact', res)
}).catch(err => {
console.error('getUserInfo ERR', err)
})
}
if (!store.getters.contactIsExist(message.senderUserId)) {
getUserInfo(message.senderUserId).then(res => {
console.log('senderUserId', message.senderUserId, res);
store.dispatch('initContact', res)
}).catch(err => {
console.error('getUserInfo ERR', err)
})
}
}
// 允许通知的消息类型,触发更新消息列表操作,提示音
@@ -32,10 +55,7 @@ const notifyMsgTypes = [
IMLib.ObjectName.Location,
IMLib.ObjectName.Voice,
IMLib.ObjectName.HQVoice,
IMLib.ObjectName.Sight,
IMLib.ObjectName.Text,
IMLib.ObjectName.Text,
IMLib.ObjectName.Text
IMLib.ObjectName.Sight
]
const imLibListeners = () => {
@@ -48,40 +68,54 @@ const imLibListeners = () => {
IMLib.addReceiveMessageListener((res) => {
const message = res.data.message
console.error('[收到消息]', message)
checkContactExists(message)
if (utils.inArray(message.objectName, notifyMsgTypes)) {
if (!store.getters.contactIsExist(message.targetId)) {
getUserInfo(message.targetId).then(res => {
store.dispatch('initContact', res)
}).catch(err => {
console.error('getUserInfo ERR', err)
})
}
if (!store.getters.contactIsExist(message.senderUserId)) {
getUserInfo(message.senderUserId).then(res => {
store.dispatch('initContact', res)
}).catch(err => {
console.error('getUserInfo ERR', err)
})
}
onReceiveMessage(message)
} else if (message.objectName === IMLib.ObjectName.ProfileNotification) {
// 更新会话信息
uni.$emit('onUpdateProfile_' + message.targetId)
// 更新联系人信息
store.dispatch('updateContact', JSON.parse(message.content.data))
// 调用完更新之后,删除这条消息
IMLib.deleteMessagesByIds([message.messageId])
} else if (message.objectName === IMLib.ObjectName.ContactNotification) {
console.error('触发一个新好友的通知事件', message);
// 触发一个新好友的通知事件
uni.$emit('onContactNotification', message)
if (message.content.operation === 'Request') {
// 触发一个新好友的通知事件,【会话列表,通讯录,新朋友】页面
uni.$emit('onNewContactConversation', message)
uni.$emit('onNewContactFriends', message)
uni.$emit('onNewContactPendings', message)
} else if (message.content.operation === 'Delete') {
IMLib.cleanHistoryMessages(1, message.targetId, message.sentTime, false)
// 解散了就删了吧
IMLib.removeConversation(1, message.targetId)
// 刷新会话列表
uni.$emit('onUserDelete_' + message.targetId)
uni.$emit('onReceiveMessage', message)
}
} else if (message.objectName === IMLib.ObjectName.GroupNotification) {
// 解散群
if (message.content.operation === 'Dismiss') {
IMLib.cleanHistoryMessages(message.conversationType, message.targetId, message.sentTime,
IMLib.cleanHistoryMessages(3, message.targetId, message.sentTime,
false)
// 解散了就删了吧
IMLib.removeConversation(message.conversationType, message.targetId)
uni.$emit('onGroupDismiss', message.targetId)
IMLib.removeConversation(3, message.targetId)
// 发布群解散的消息
uni.$emit('onGroupDismiss')
uni.$emit('onGroupDismiss_' + message.targetId)
} else if (message.content.operation === 'REMOVE') {
// 要判断是否当前用户,然后把当前用户踢出到主页去, 删除聊天记录,会话列表
if (message.content.extra == store.getters.sender.userId) {
IMLib.cleanHistoryMessages(3, message.targetId, message.sentTime,
false)
// 解散了就删了吧
IMLib.removeConversation(3, message.targetId)
// 为了更新群列表
uni.$emit('onGroupDismiss')
uni.$emit('onGroupRemoveYou_' + message.targetId)
}
uni.$emit('onReceiveMessage_' + message.targetId, message)
// 这个是为了更新消息列表页的
}
// 触发刷新会话列表
uni.$emit('onReceiveMessage', message)
}
})
@@ -93,10 +127,16 @@ const imLibListeners = () => {
uni.$emit('onReadReceiptReceived', data)
})
// 监听消息撤回操作
IMLib.addRecallMessageListener((res) => {
IMLib.getMessage(res.data.messageId, (res) => {
console.error("消息撤回: ", res.message);
uni.$emit('onRecallMessage', res.message)
IMLib.addRecallMessageListener(({
data
}) => {
IMLib.getMessage(data.messageId, ({
message
}) => {
console.error("消息撤回: ", message);
im.setNotifyBadge()
uni.$emit('onReceiveMessage', message)
uni.$emit('onRecallMessage_' + message.targetId, message)
})
})
// 监听需要群聊消息回执

View File

@@ -127,7 +127,7 @@ const sentVoice = (conversationType, targetId, voiceUrl, time, user, callback) =
content: {
objectName: 'RC:HQVCMsg',
local: 'file:///' + plus.io.convertLocalFileSystemURL(voiceUrl),
duration: time,
duration: time == 0 ? 1 : time,
userInfo: user
}
}

View File

@@ -9,14 +9,19 @@ const contactModel = usqlite.model('contacts', {
unique: true
},
name: String,
remark: String,
hash: {
type: String,
unique: true
},
type: {
type: Number,
default: 0
},
portraitUrl: String,
localAvatar: String
})
export default {
export {
contactModel
}