Compare commits

43 Commits

Author SHA1 Message Date
唐明明
e07d40908b 剥离im,剥离钱包 2022-03-17 13:28:10 +08:00
e4d73085bc marge 2022-03-07 14:31:06 +08:00
ca40d790b1 聊天页面处理没有聊天内容展示 2022-03-07 14:29:37 +08:00
唐明明
aadef3c148 merge 2022-03-07 09:18:00 +08:00
81d4b9017d tongbi 2022-03-01 13:04:45 +08:00
335a3aa8d6 消息间隔30分钟,插入一条时间消息,记录消息大概的发送时间 2022-03-01 11:29:04 +08:00
9628c8ccec clean 2022-03-01 10:40:59 +08:00
dbda19870f 优化消息发送函数,设定音视频通话的记录发送规则 2022-03-01 10:40:00 +08:00
04d9d772c4 发送消息的回执请求完善 2022-02-28 16:52:37 +08:00
bce7822e51 文件消息,地理位置消息 2022-02-28 16:28:14 +08:00
39b8f158c0 更改发送消息模式为promise 2022-02-28 13:45:17 +08:00
bf94cca533 键盘高度计算,改善聊天页面内容少的时候推屏的问题,但是有点卡断 2022-02-28 12:15:11 +08:00
e8e496cf37 获取好友信息的时候,排除自己,但是还要把自己的信息加载到内存中 2022-02-28 10:26:48 +08:00
3e1275fc74 ... 2022-02-25 17:04:31 +08:00
033d0e6317 预览图片 2022-02-25 16:57:40 +08:00
fb3d8ff950 健康模块首页调整样式 2022-02-25 16:51:45 +08:00
76064b3ea2 替换个人信息页面图标 2022-02-25 16:36:42 +08:00
cd63785274 私人聊天右上角跳转到别人的介绍页面 2022-02-25 15:36:28 +08:00
唐明明
33f1899b75 merge 2022-02-25 15:20:40 +08:00
唐明明
76854d3714 修复发送文本消息成功后在次发送表情残留上次输入内容的bug 2022-02-25 15:20:17 +08:00
1b027783ea update 2022-02-25 15:15:53 +08:00
唐明明
0b61a8c7f4 merge 2022-02-25 15:13:05 +08:00
唐明明
17899df882 merge 2022-02-25 15:12:37 +08:00
c69722491c ... 2022-02-25 15:07:04 +08:00
e9184b90c1 群通知,更新群消息页面 2022-02-25 15:05:11 +08:00
748ff74731 Merge branch 'master' of https://git.yuzhankeji.cn/TmOct5/ZhHealth 2022-02-25 15:03:51 +08:00
d3b33e3c26 permission 2022-02-25 15:03:47 +08:00
唐明明
d9f379d489 merge 2022-02-25 14:50:21 +08:00
唐明明
92d43c50bc 新增表情包组件 2022-02-25 14:50:02 +08:00
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
95 changed files with 2070 additions and 8265 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -1,13 +1,9 @@
<script> <script>
import { import { getVersions } from './apis/interfaces/versions'
getVersions
} from './apis/interfaces/versions'
import im from '@/utils/im/index.js'
export default { export default {
onLaunch: function() { onLaunch: function() {
im.initIm('lmxuhwaglu76d') // return
return
//#ifdef APP-PLUS //#ifdef APP-PLUS
// 获取系统版本号 // 获取系统版本号
getVersions({ getVersions({

View File

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

View File

@@ -1,330 +0,0 @@
/**
* Web唐明明
* 匆匆数载恍如梦,岁月迢迢华发增。
* 碌碌无为枉半生,一朝惊醒万事空。
* moduleName: 聊聊
*/
import store from '@/store'
import {
request
} from '../index'
// 获取好友列表
const getFriends = () => {
return request({
url: 'im/friends',
}, true)
}
// 获取好友列表
const getFriendsLetter = () => {
return request({
url: 'im/friends/letter',
}, true)
}
// 获取融云token
const getImToken = () => {
return request({
url: 'im/token',
}, true)
}
// 删除好友
const deleteFriend = (targetId) => {
return request({
method: 'DELETE',
url: 'im/friends/' + targetId,
})
}
// 获取用户信息
const getUserInfo = (targetId) => {
return request({
url: 'im/userInfo/' + targetId,
})
}
/**
* 查看好友资料,附带好友关系
*/
const getFriendInfo = (userId) => {
return request({
url: 'im/friendInfo/' + userId
})
}
/**
* 获取好友申请列表
*/
const getPedings = () => {
return request({
url: 'im/friends/pending'
})
}
const resolveFriend = (targetId) => {
return request({
method: 'POST',
url: 'im/friends/accept/' + targetId
})
}
const rejectFriend = (targetId) => {
return request({
method: 'DELETE',
url: 'im/friends/accept/' + targetId
})
}
const searchFriend = (value) => {
return request({
url: 'im/search',
data: {
keyword: value
}
})
}
const pedingFriend = (recipient, message) => {
return request({
method: 'POST',
url: 'im/friends/' + recipient,
data: {
message
}
})
}
// 以下是群组相关业务的接口
const getMyGroups = () => {
return request({
url: 'im/groups'
})
}
/**
* 获取群信息,包含基础信息和 14 个用户
*/
const getGroupInfo = (groupId) => {
return request({
url: 'im/groups/' + groupId
})
}
/**
* 群组基础信息
*/
const getGroupBase = (groupId) => {
return request({
url: 'im/groups/' + groupId + '/base'
})
}
const getGroupUsers = (groupId, limit) => {
limit = limit || 0
return request({
url: 'im/groups/' + groupId + '/users?limit=' + limit
})
}
// 公告列表
const getGroupAnnouncements = (groupId) => {
return request({
url: 'im/groups/' + groupId + '/announcements'
})
}
// 创建公告
const createGroupAnnouncement = (groupId, content) => {
return request({
method: 'POST',
url: 'im/groups/' + groupId + '/announcements',
data: {
content: content
}
})
}
// 查看该公告详情
const getGroupAnnouncement = (groupId, announcementId) => {
return request({
method: 'GET',
url: 'im/groups/' + groupId + '/announcements/' + announcementId
})
}
// 删除该公告
const deleteGroupAnnouncement = (groupId, announcementId) => {
return request({
method: 'DELETE',
url: 'im/groups/' + groupId + '/announcements/' + announcementId
})
}
// 置顶群公告
const topGroupAnnouncement = (groupId, announcementId) => {
return request({
method: 'POST',
url: 'im/groups/' + groupId + '/announcements/' + announcementId + '/top',
})
}
/**
* 创建群聊
*/
const createGroup = (data) => {
return request({
method: 'POST',
url: 'im/groups',
data: data
})
}
const updateGroup = (groupId, data) => {
return request({
method: 'PUT',
url: 'im/groups/' + groupId,
data: data
})
}
/**
* 搜索群聊
*/
const searchGroup = (name) => {
return request({
url: 'im/groups/search?name=' + name
})
}
/**
* 加群前,获取的群信息
*/
const joinGroupPre = (groupId) => {
return request({
url: 'im/groups/' + groupId + '/join'
})
}
const joinGroup = (groupId, message) => {
return request({
method: 'POST',
url: 'im/groups/' + groupId + '/join',
data: {
message
}
})
}
const quitGroup = (groupId) => {
return request({
method: 'DELETE',
url: 'im/groups/' + groupId + '/quit'
})
}
/**
* 解散群聊
*/
const dismissGroup = (groupId) => {
return request({
method: 'DELETE',
url: 'im/groups/' + groupId
})
}
/**
* 移除群成员
*/
const removeGroupUser = (groupId, userId) => {
return request({
method: 'DELETE',
url: 'im/groups/' + groupId + '/users/' + userId
})
}
/**
* 邀请群成员
*/
const inviteGroupUser = (groupId, userIds, allowIds) => {
return request({
method: 'POST',
url: 'im/groups/' + groupId + '/invite',
data: {
userIds: userIds,
allowIds: allowIds
}
})
}
/**
* 设置群管理
*/
const setGroupAdmin = (groupId, userId) => {
return request({
method: 'POST',
url: 'im/groups/' + groupId + '/admin/' + userId
})
}
/**
* 移除群管理
*/
const removeGroupAdmin = (groupId, userId) => {
return request({
method: 'DELETE',
url: 'im/groups/' + groupId + '/admin/' + userId
})
}
/**
* 转移群主
*/
const transferGroupOwner = (groupId, userId) => {
return request({
method: 'POST',
url: 'im/groups/' + groupId + '/owner/' + userId
})
}
// 通过审核验证群成员
const groupMakeSure = (groupId, user) => {
return request({
url: `im/groups/${groupId}/makesure/${user}`,
method: 'POST'
})
}
export {
getImToken,
deleteFriend,
getFriends,
getFriendsLetter,
getUserInfo,
getFriendInfo,
getPedings,
resolveFriend,
rejectFriend,
searchFriend,
pedingFriend,
getMyGroups,
createGroup,
updateGroup,
getGroupInfo,
getGroupBase,
getGroupUsers,
getGroupAnnouncements,
getGroupAnnouncement,
createGroupAnnouncement,
deleteGroupAnnouncement,
topGroupAnnouncement,
searchGroup,
joinGroupPre,
joinGroup,
quitGroup,
dismissGroup,
inviteGroupUser,
removeGroupUser,
transferGroupOwner,
setGroupAdmin,
removeGroupAdmin,
groupMakeSure, // 通过审核
}

View File

@@ -0,0 +1,188 @@
<template xlang="wxml" minapp="mpvue">
<view>
</view>
</template>
<script>
export default {
name: 'tki-file-manager',
props: {},
data() {
return {}
},
methods: {
_openFile() {
// #ifdef APP-PLUS
if (plus.os.name.toLowerCase() != "android") {
uni.showModal({
title: '提示',
content: '仅支持Android平台',
success: function(res) {}
});
return false
}
let that = this
// java 代码来自 http://www.cnblogs.com/panhouye/archive/2017/04/23/6751710.html
let main = plus.android.runtimeMainActivity();
let Intent = plus.android.importClass("android.content.Intent");
//
let fileIntent = new Intent(Intent.ACTION_GET_CONTENT)
//fileIntent.setType(“image/*”);//选择图片
//fileIntent.setType(“audio/*”); //选择音频
//fileIntent.setType(“video/*”); //选择视频 mp4 3gp 是android支持的视频格式
//fileIntent.setType(“video/*;image/*”);//同时选择视频和图片
fileIntent.setType("*/*"); //无类型限制
fileIntent.addCategory(Intent.CATEGORY_OPENABLE);
main.startActivityForResult(fileIntent, 1);
// 获取回调
main.onActivityResult = function(requestCode, resultCode, data) {
let Activity = plus.android.importClass("android.app.Activity");
let ContentUris = plus.android.importClass("android.content.ContentUris");
let Cursor = plus.android.importClass("android.database.Cursor");
let Uri = plus.android.importClass("android.net.Uri");
let Build = plus.android.importClass("android.os.Build");
let Environment = plus.android.importClass("android.os.Environment");
let DocumentsContract = plus.android.importClass("android.provider.DocumentsContract");
let MediaStore = plus.android.importClass("android.provider.MediaStore");
// 给系统导入 contentResolver
let contentResolver = main.getContentResolver()
plus.android.importClass(contentResolver);
// 返回路径
let path = '';
if (resultCode == Activity.RESULT_OK) {
let uri = data.getData()
if ("file" == uri.getScheme().toLowerCase()) { //使用第三方应用打开
path = uri.getPath();
return;
}
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) { //4.4以后
path = getPath(this, uri);
} else { //4.4以下下系统调用方法
path = getRealPathFromURI(uri)
}
// 回调
that.$emit('result', path)
}
// 4.4 以上 从Uri 获取文件绝对路径
function getPath(context, uri) {
let isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
let scheme = uri.getScheme().toLowerCase()
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
let docId = DocumentsContract.getDocumentId(uri);
let split = docId.split(":");
let type = split[0];
// 如果是手机内部存储
if ("primary" == type.toLowerCase()) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
} else {
return '/storage/' + type + "/" + split[1];
}
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
let docId = DocumentsContract.getDocumentId(uri);
let split = docId.split(":");
return split[1]
// console.log(id)
// let contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), id);
// return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
let docId = DocumentsContract.getDocumentId(uri);
let split = docId.split(":");
let type = split[0];
let contentUri = null;
if ("image" == type.toLowerCase()) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video" == type.toLowerCase()) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio" == type.toLowerCase()) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
let selection = "_id=?";
let selectionArgs = [split[1]];
return getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content" == scheme) {
return getDataColumn(context, uri, null, null);
}
// File
else if ("file" == scheme) {
return uri.getPath();
}
}
// 4.4 以下 获取 绝对路径
function getRealPathFromURI(uri) {
let res = null
let proj = [MediaStore.Images.Media.DATA]
let cursor = contentResolver.query(uri, proj, null, null, null);
if (null != cursor && cursor.moveToFirst()) {
;
let column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
res = cursor.getString(column_index);
cursor.close();
}
return res;
}
// 通过uri 查找出绝对路径
function getDataColumn(context, uri, selection, selectionArgs) {
let cursor = null;
let column = "_data";
let projection = [column];
// let contentResolver = context.getContentResolver()
// plus.android.importClass(contentResolver);
cursor = contentResolver.query(uri, projection, selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
let column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
}
function isExternalStorageDocument(uri) {
return "com.android.externalstorage.documents" == uri.getAuthority() ? true : false
}
function isDownloadsDocument(uri) {
return "com.android.providers.downloads.documents" == uri.getAuthority() ? true : false
}
function isMediaDocument(uri) {
return "com.android.providers.media.documents" == uri.getAuthority() ? true : false
}
}
// #endif
// #ifndef APP-PLUS
uni.showModal({
title: '提示',
content: '仅支持Android平台',
success: function(res) {
}
});
// #endif
},
},
onLoad() {
// plus.io.resolveLocalFileSystemURL( '/storage/emulated/0', function(fs) {
// var directoryReader = fs.createReader();
// directoryReader.readEntries(function(entries) {
// var i;
// for (i = 0; i < entries.length; i++) {
// console.log(entries[i].name);
// }
// }, function(e) {
// console.log("Read entries failed: " + e.message);
// });
// }, function(e) {
// console.log("Request file system failed: " + e.message);
// });
}
}
</script>

15
main.js
View File

@@ -10,32 +10,17 @@ import Vue from 'vue'
import store from './store' import store from './store'
import uView from 'uview-ui' import uView from 'uview-ui'
import filters from './utils/filters.js' 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 { import {
router, router,
RouterMount RouterMount
} from 'router' } from 'router'
Object.keys(filters).forEach(key => {
Vue.filter(key, filters[key])
})
Vue.use(uView); Vue.use(uView);
Vue.use(router) Vue.use(router)
Vue.config.productionTip = false Vue.config.productionTip = false
Vue.prototype.$store = store Vue.prototype.$store = store
uni.$sql = usqlite
uni.model = model
uni.$sql.connect({
name: 'zh-health',// 数据库名称
path:'_doc/health.db', // 路径
})
App.mpType = 'app' App.mpType = 'app'
const app = new Vue({ const app = new Vue({

View File

@@ -2,7 +2,7 @@
"name" : "ZH-HEALTH", "name" : "ZH-HEALTH",
"appid" : "__UNI__C29473D", "appid" : "__UNI__C29473D",
"description" : "ZH-HEALTH您手上的健康管理专家", "description" : "ZH-HEALTH您手上的健康管理专家",
"versionName" : "1.0.16", "versionName" : "1.0.22",
"versionCode" : 100, "versionCode" : 100,
"transformPx" : false, "transformPx" : false,
/* 5+App */ /* 5+App */
@@ -47,6 +47,7 @@
"<uses-permission android:name=\"android.permission.INTERNET\"/>", "<uses-permission android:name=\"android.permission.INTERNET\"/>",
"<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>", "<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>", "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>", "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>", "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>", "<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>",
@@ -59,7 +60,15 @@
"autoSdkPermissions" : true "autoSdkPermissions" : true
}, },
/* ios */ /* ios */
"ios" : {}, "ios" : {
"privacyDescription" : {
"NSMicrophoneUsageDescription" : "发送语音消息以及音视频通话",
"NSCameraUsageDescription" : "发送图文消息以及视频通话",
"NSPhotoLibraryUsageDescription" : "发送图文消息",
"NSPhotoLibraryAddUsageDescription" : "保存图片消息",
"NSLocationWhenInUseUsageDescription" : "发送当前位置信息"
}
},
/* SDK */ /* SDK */
"sdkConfigs" : { "sdkConfigs" : {
"oauth" : { "oauth" : {
@@ -89,7 +98,7 @@
"amap" : { "amap" : {
"__platform__" : [ "android" ], "__platform__" : [ "android" ],
"appkey_ios" : "", "appkey_ios" : "",
"appkey_android" : "05b7f32ca9c897c8b63c505d92cd654b" "appkey_android" : "1dfbe526a37dcb1f13263e0b5871ca4d"
}, },
"system" : { "system" : {
"__platform__" : [ "android" ] "__platform__" : [ "android" ]
@@ -98,7 +107,7 @@
"maps" : { "maps" : {
"amap" : { "amap" : {
"appkey_ios" : "", "appkey_ios" : "",
"appkey_android" : "05b7f32ca9c897c8b63c505d92cd654b" "appkey_android" : "1dfbe526a37dcb1f13263e0b5871ca4d"
} }
} }
}, },
@@ -133,38 +142,12 @@
"spotlight@3x" : "unpackage/res/icons/120x120.png" "spotlight@3x" : "unpackage/res/icons/120x120.png"
} }
} }
},
"splashscreen" : {
"androidStyle" : "common"
} }
}, },
"nativePlugins" : { "nativePlugins" : {}
"RongCloud-Call" : {
"__plugin_info__" : {
"name" : "RCUniCall",
"description" : "融云实时音视频 SDK uni 原生插件",
"platforms" : "Android,iOS",
"url" : "https://ext.dcloud.net.cn/plugin?id=6372",
"android_package_name" : "io.zhhealth.app",
"ios_bundle_id" : "io.zhhealth.app",
"isCloud" : true,
"bought" : 1,
"pid" : "6372",
"parameters" : {}
}
},
"RongCloud-IM" : {
"__plugin_info__" : {
"name" : "RCUniIM",
"description" : "融云即时通讯 SDK uni 原生插件",
"platforms" : "Android,iOS",
"url" : "https://ext.dcloud.net.cn/plugin?id=6120",
"android_package_name" : "io.zhhealth.app",
"ios_bundle_id" : "io.zhhealth.app",
"isCloud" : true,
"bought" : 1,
"pid" : "6120",
"parameters" : {}
}
}
}
}, },
/* */ /* */
"quickapp" : {}, "quickapp" : {},

32
package-lock.json generated
View File

@@ -12,10 +12,8 @@
"moment": "^2.29.1", "moment": "^2.29.1",
"uni-read-pages": "^1.0.5", "uni-read-pages": "^1.0.5",
"uni-simple-router": "^2.0.7", "uni-simple-router": "^2.0.7",
"uview-ui": "^2.0.19", "uview-ui": "^2.0.27"
"vuex": "^3.6.2" }
},
"devDependencies": {}
}, },
"node_modules/moment": { "node_modules/moment": {
"version": "2.29.1", "version": "2.29.1",
@@ -37,20 +35,12 @@
"integrity": "sha512-8FKv5dw7Eoonm0gkO8udprrxzin0fNUI0+AvIphFkFRH5ZmP5ZWJ2pvnWzb2NiiqQSECTSU5VSB7HhvOSwD5eA==" "integrity": "sha512-8FKv5dw7Eoonm0gkO8udprrxzin0fNUI0+AvIphFkFRH5ZmP5ZWJ2pvnWzb2NiiqQSECTSU5VSB7HhvOSwD5eA=="
}, },
"node_modules/uview-ui": { "node_modules/uview-ui": {
"version": "2.0.19", "version": "2.0.29",
"resolved": "https://registry.npmjs.org/uview-ui/-/uview-ui-2.0.19.tgz", "resolved": "https://registry.npmjs.org/uview-ui/-/uview-ui-2.0.29.tgz",
"integrity": "sha512-ddZiaP7R9wsUxMzAuhuXgh5OswgCm2lKuulTqjnRXFr0uUWsgL1iBifU3GbOwpwP0LtTHKJOo9rYv1LP0WXmzA==", "integrity": "sha512-d5SttbPcowomrgpL7A1LMKRbemXtyyzpPCy98/+VQR3jfSyyHC9tfj/ZeAOKpqTn1rf9gOj2wc5tda/kVmYX2Q==",
"engines": { "engines": {
"HBuilderX": "^3.1.0" "HBuilderX": "^3.1.0"
} }
},
"node_modules/vuex": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/vuex/-/vuex-3.6.2.tgz",
"integrity": "sha512-ETW44IqCgBpVomy520DT5jf8n0zoCac+sxWnn+hMe/CzaSejb/eVw2YToiXYX+Ex/AuHHia28vWTq4goAexFbw==",
"peerDependencies": {
"vue": "^2.0.0"
}
} }
}, },
"dependencies": { "dependencies": {
@@ -70,15 +60,9 @@
"integrity": "sha512-8FKv5dw7Eoonm0gkO8udprrxzin0fNUI0+AvIphFkFRH5ZmP5ZWJ2pvnWzb2NiiqQSECTSU5VSB7HhvOSwD5eA==" "integrity": "sha512-8FKv5dw7Eoonm0gkO8udprrxzin0fNUI0+AvIphFkFRH5ZmP5ZWJ2pvnWzb2NiiqQSECTSU5VSB7HhvOSwD5eA=="
}, },
"uview-ui": { "uview-ui": {
"version": "2.0.19", "version": "2.0.29",
"resolved": "https://registry.npmjs.org/uview-ui/-/uview-ui-2.0.19.tgz", "resolved": "https://registry.npmjs.org/uview-ui/-/uview-ui-2.0.29.tgz",
"integrity": "sha512-ddZiaP7R9wsUxMzAuhuXgh5OswgCm2lKuulTqjnRXFr0uUWsgL1iBifU3GbOwpwP0LtTHKJOo9rYv1LP0WXmzA==" "integrity": "sha512-d5SttbPcowomrgpL7A1LMKRbemXtyyzpPCy98/+VQR3jfSyyHC9tfj/ZeAOKpqTn1rf9gOj2wc5tda/kVmYX2Q=="
},
"vuex": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/vuex/-/vuex-3.6.2.tgz",
"integrity": "sha512-ETW44IqCgBpVomy520DT5jf8n0zoCac+sxWnn+hMe/CzaSejb/eVw2YToiXYX+Ex/AuHHia28vWTq4goAexFbw==",
"requires": {}
} }
} }
} }

View File

@@ -363,169 +363,6 @@
"navigationBarBackgroundColor": "#FFFFFF" "navigationBarBackgroundColor": "#FFFFFF"
} }
}, },
{
"path": "pages/im/index",
"name": "IM",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/im/private/chat",
"style": {
}
},
{
"path": "pages/im/private/call",
"name": "imPrivateCall",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/im/friends/index",
"name": "imFriends",
"style": {
"navigationBarTitleText": "通讯录",
"app-plus": {
"titleNView": {
"type": "default",
"buttons": [{
"float": "right",
"fontSrc": "/static/iconfont.ttf",
"text": "\ue603",
"fontSize": "20px"
}]
}
}
}
},
{
"path": "pages/im/friends/pending",
"name": "imFriendsPending",
"style": {
"navigationBarTitleText": "新朋友"
}
},
{
"path": "pages/im/friends/search",
"name": "SearchFriend",
"style": {
"navigationBarTitleText": "好友搜索"
}
},
{
"path": "pages/im/friends/info",
"name": "imFriendsInfo",
"style": {
"navigationBarTitleText": "用户资料"
}
},
{
"path": "pages/im/friends/mine",
"name": "imFriendsMine",
"style": {
"navigationBarTitleText": "我的二维码",
"navigationBarBackgroundColor": "#34CE98",
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/im/group/index",
"name": "imGroups",
"style": {
"navigationBarTitleText": "我的群聊",
"app-plus": {
"titleNView": {
"type": "default",
"buttons": [{
"float": "right",
"fontSrc": "/static/iconfont.ttf",
"text": "\ue60a",
"fontSize": "20px"
}]
}
}
}
},
{
"path": "pages/im/group/chat",
"name": "imGroupChat",
"style": {
"navigationBarTitleText": "群聊",
"app-plus": {
"titleNView": {
"type": "default",
"buttons": [{
"float": "right",
"fontSrc": "/static/iconfont.ttf",
"text": "\ue607",
"fontSize": "20px"
}]
}
}
}
},
{
"path": "pages/im/group/apply",
"name": "imGroupApply",
"style": {
"navigationBarTitleText": "申请加群"
}
},
{
"path": "pages/im/group/info",
"name": "imGroupInfo",
"style": {
"navigationBarTitleText": "群信息"
}
},
{
"path": "pages/im/group/invite",
"name": "imGroupInvite",
"style": {
"navigationBarTitleText": "选择联系人"
}
},
{
"path": "pages/im/group/reviewed",
"name": "imGroupReviewed",
"style": {
"navigationBarTitleText": "群聊邀请确认"
}
},
{
"path": "pages/im/group/users",
"name": "imGroupUsers",
"style": {
"navigationBarTitleText": "群成员"
}
},
{
"path": "pages/im/group/announcement",
"name": "imGroupAnnouncement",
"style": {
"navigationBarTitleText": "群公告",
"app-plus": {
"titleNView": {
"type": "default",
"buttons": [{
"float": "right",
"fontSrc": "/static/iconfont.ttf",
"text": "\ue60a",
"fontSize": "20px"
}]
}
}
}
},
{
"path": "pages/im/group/announceCreate",
"name": "imGroupAnnouncementCreate",
"style": {
"navigationBarTitleText": "发布群公告"
}
},
{ {
"path": "pages/wallet/add", "path": "pages/wallet/add",
"name": "WalletAdd", "name": "WalletAdd",
@@ -659,12 +496,6 @@
"pagePath": "pages/service/index", "pagePath": "pages/service/index",
"text": "生活" "text": "生活"
}, },
{
"iconPath": "static/tabBar/tabBar_04.png",
"selectedIconPath": "static/tabBar/tabBar_show_04.png",
"pagePath": "pages/im/index",
"text": "聊聊"
},
{ {
"iconPath": "static/tabBar/tabBar_03.png", "iconPath": "static/tabBar/tabBar_03.png",
"selectedIconPath": "static/tabBar/tabBar_show_03.png", "selectedIconPath": "static/tabBar/tabBar_show_03.png",

BIN
pages/.DS_Store vendored

Binary file not shown.

View File

@@ -34,15 +34,8 @@
</template> </template>
<script> <script>
import { import { getSms, smsAuth } from "@/apis/interfaces/auth";
getSms,
smsAuth
} from "@/apis/interfaces/auth";
import userAuth from "@/public/userAuth"; import userAuth from "@/public/userAuth";
import {
getImToken
} from '@/apis/interfaces/im.js'
import im from '@/utils/im/index.js'
export default { export default {
data() { data() {
@@ -64,11 +57,6 @@
"setToken", "setToken",
res.token_type + " " + res.access_token res.token_type + " " + res.access_token
); );
// 在这里登录成功链接IM服务
getImToken().then(res => {
console.log('在这获取IM-TOKEN', res);
im.connect(res.token, res.userInfo, () => {})
})
this.$Router.back(); this.$Router.back();
}).catch((err) => { }).catch((err) => {
uni.showToast({ uni.showToast({

View File

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

View File

@@ -1,95 +0,0 @@
<template>
<view class="message--cell">
<view class="avatar">
<u-badge max="99" shape="horn" absolute :offset="[-5, -8]" :value="item.unreadMessageCount" />
<u-avatar :src="contact(item.targetId).portraitUrl" shape="square" :size="avatarSize" />
</view>
<view class="content">
<view class="header">
<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"
:conversationType="item.conversationType" :user="item.latestMessage.userInfo" />
</view>
</view>
</template>
<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,
default: function() {
return {}
}
}
},
components: {
messagePreview
}
}
</script>
<style lang="scss" scoped>
.message--cell {
display: flex;
padding: 20rpx 10rpx 0 30rpx;
.avatar {
position: relative;
padding-top: 5rpx;
.u-badge {
z-index: 998;
}
}
.content {
margin-left: 30rpx;
box-sizing: border-box;
position: relative;
flex: 1;
border-bottom-width: 0.5px !important;
border-color: #eee !important;
border-bottom-style: solid;
.header {
display: flex;
justify-content: space-between;
.name {
font-size: $title-size + 2;
color: #454545;
.group {
color: $main-color;
font-size: $title-size-m - 4;
margin-left: 4px;
position: relative;
top: -4rpx;
}
}
.time {
font-size: $title-size-sm - 3;
color: $text-gray-m;
position: absolute;
right: 30rpx;
padding-top: 4rpx;
font-weight: normal;
}
}
}
}
</style>

View File

@@ -1,85 +0,0 @@
<template>
<view>
<view class="preview" v-if="draft">
<text class="draft">[草稿]</text> {{ draft }}
</view>
<block v-else>
<view class="preview" v-if="msg.objectName=='RC:TxtMsg'">
<text v-if="conversationType == 3">{{ user.name }}</text>{{ msg.content || '' }}
</view>
<view class="preview" v-if="msg.objectName=='RC:HQVCMsg'">
<text v-if="conversationType == 3">{{ user.name }}</text>[语音]
</view>
<view class="preview" v-if="msg.objectName=='RC:ImgMsg'">
<text v-if="conversationType == 3">{{ user.name }}</text>[图片]
</view>
<view class="preview" v-if="msg.objectName=='RC:GIFMsg'">
<text v-if="conversationType == 3">{{ user.name }}</text>[表情]
</view>
<view class="preview" v-if="msg.objectName=='RC:FileMsg'">
<text v-if="conversationType == 3">{{ user.name }}</text>[文件]
</view>
<view class="preview" v-if="msg.objectName=='RC:LBSMsg'">
<text v-if="conversationType == 3">{{ user.name }}</text>[位置]
</view>
<view class="preview" v-if="msg.objectName=='RC:InfoNtf' && JSON.parse(msg.message).mediaType==0">
<text v-if="conversationType == 3">{{ user.name }}</text>[语音通话]
</view>
<view class="preview" v-if="msg.objectName=='RC:InfoNtf' && JSON.parse(msg.message).mediaType==1">
<text v-if="conversationType == 3">{{ user.name }}</text>[视频通话]
</view>
<view class="preview" v-if="msg.objectName=='RC:GrpNtf'">
[{{ msg.message }}]
</view>
<view class="preview" v-if="msg.objectName=='RC:RcNtf'">
<text v-if="conversationType == 3">{{ user.name }}</text> 撤回了一条消息
</view>
</block>
</view>
</template>
<script>
export default {
props: {
msg: {
type: Object,
default: {}
},
conversationType: {
type: Number,
default: 0
},
draft: {
type: String,
default: ''
},
user: {
type: Object,
default: function() {
return {
name: ''
}
}
}
}
}
</script>
<style lang="scss" scoped>
.preview {
word-break: break-all;
color: $text-gray-m;
padding-top: 6rpx;
padding-bottom: $padding;
font-size: $title-size-m - 2;
height: 32rpx;
line-height: 32rpx;
width: 520rpx;
@extend .nowrap;
.draft {
color: $text-price;
padding-right: 10rpx;
}
}
</style>

View File

@@ -1,181 +0,0 @@
<template>
<view>
<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(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 './conversation/messageCell'
export default {
props: {
conversations: {
type: Array,
default: function() {
return []
}
}
},
components: {
messageCell
},
data() {
return {
/* 窗口尺寸 */
winSize: {},
/* 显示操作弹窗 */
showPop: false,
/* 弹窗按钮列表 */
popButton: ['置顶聊天', '标记已读', '删除该聊天'],
/* 弹窗定位样式 */
popStyle: "",
pickedItem: {},
}
},
created() {
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(index) {
if (index == 0) {
RongIMLib.setConversationToTop(this.pickedItem.conversationType, this.pickedItem.targetId, !this
.pickedItem.isTop)
} else if (index == 1) {
RongIMLib.clearMessagesUnreadStatus(this.pickedItem.conversationType, this.pickedItem.targetId, this
.pickedItem.sentTime)
} else {
RongIMLib.removeConversation(this.pickedItem.conversationType, this.pickedItem.targetId)
RongIMLib.deleteMessages(this.pickedItem.conversationType, this.pickedItem.targetId)
}
this.$emit('refresh')
im.setNotifyBadge()
this.hidePop()
},
// 长按会话,展示功能菜单
onLongPress(e) {
let [touches, style, item] = [e.touches[0], "", e.currentTarget.dataset.item]
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`
}
this.popButton[0] = item.isTop ? '取消置顶' : '置顶聊天'
this.popStyle = style
this.pickedItem = item
this.$nextTick(() => {
setTimeout(() => {
this.showPop = true;
}, 10)
})
},
toDetail(item) {
if (item.conversationType == 1) {
uni.navigateTo({
url: '/pages/im/private/chat?targetId=' + item.targetId
})
} else if (item.conversationType == 3) {
uni.navigateTo({
url: '/pages/im/group/chat?targetId=' + item.targetId
})
}
this.hidePop()
}
}
}
</script>
<style lang="scss" scoped>
.message {
background: white;
&.is-top {
background: $window-color;
}
&.is-active {
background: #F8FAFF;
}
}
/* 遮罩 */
.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

@@ -1,126 +0,0 @@
<template>
<view class="apply--cell">
<view class="avatar">
<u-avatar :src="user.portraitUrl || require('@/static/user/cover.png')" shape="square" :size="avatarSize" />
</view>
<view class="info">
<view class="name"> {{ user.name }}</view>
<view class="message"> {{ message.message!=='null' ? message.message : '听说你很优秀,想认识下你~' }} </view>
</view>
<view class="action">
<u-button class="u-button" size="default" type="success" @click="resolve">通过</u-button>
<u-button class="u-button" size="default" type="warning" @click="reject">拒绝</u-button>
</view>
</view>
</template>
<script>
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
import {
resolveFriend,
rejectFriend
} from '@/apis/interfaces/im.js'
import imBase from '../mixins/imBase.js'
export default {
mixins: [
imBase
],
props: {
message: {
type: Object,
default: {}
}
},
computed: {
user() {
return JSON.parse(this.message.extra)
}
},
methods: {
resolve() {
resolveFriend(this.message.sourceUserId).then(res => {
uni.showToast({
icon: 'none',
title: '通过好友申请'
})
uni.navigateBack({})
}).catch(err => {
uni.showToast({
icon: 'none',
title: err.message
})
}).finally(() => {
this.clearMessages()
})
},
reject() {
uni.showModal({
title: '拒绝申请',
success: (res) => {
if (res.confirm) {
rejectFriend(this.message.sourceUserId).then(res => {
this.clearMessages()
}).catch(err => {
uni.showToast({
icon: 'none',
title: err.message
})
})
}
}
})
},
// 不管是通过还是拒绝,都要把相关的信息清理
clearMessages() {
RongIMLib.deleteMessages(RongIMLib.ConversationType.SYSTEM, this.message.sourceUserId)
this.$emit('success')
uni.$emit('onNewContactConversation')
uni.$emit('onNewContactFriends')
uni.$emit('onNewContactPendings')
}
}
}
</script>
<style lang="scss" scoped>
.apply--cell {
display: flex;
padding: $padding;
align-items: center;
border-bottom: solid 1rpx #f9f9f9;
.info {
flex: 1;
margin-left: $padding;
.name {
font-size: $title-size + 2;
}
.message {
color: $text-gray-m;
font-size: $title-size-m;
margin-top: 10rpx;
}
}
.action {
justify-content: space-between;
display: flex;
flex-direction: row;
align-items: center;
box-sizing: border-box;
.u-button {
padding: 10rpx 20rpx !important;
font-size: $title-size-m;
height: 60rpx !important;
}
.u-button+.u-button {
margin-left: 10rpx;
}
}
}
</style>

View File

@@ -1,147 +0,0 @@
<template>
<view class="friend-apply">
<block v-for="(item, index) in lists" v-if="lists.length > 0" :key="index">
<view class="lists">
<view class="" style="width: 100rpx;height: 100rpx;">
<u-avatar :src="JSON.parse(item.latestMessage.extra).portraitUrl" shape="square" :size="avatarSize" />
</view>
<view class="right">
<view class="title">
<view class="name">{{ item.name }}</view>
<view class="des">{{ item.latestMessage.message || '--' }}</view>
</view>
<view class="agress-btn">
<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>
</view>
</view>
</view>
</block>
</view>
</template>
<script>
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
});
}
}
};
</script>
<style lang="scss" scoped>
.lists {
padding: 0 $padding;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
box-sizing: border-box;
font-size: $title-size;
color: $text-gray;
.cover {
background-color: #ffffff;
}
.right {
width: 570rpx;
margin-left: $margin - 10;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: $padding 0;
border-bottom: solid 1rpx #f9f9f9;
.title {
width: 370rpx;
.name {
width: 100%;
color: $text-color;
font-size: $title-size + 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;
}
}
.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

@@ -1,144 +0,0 @@
<template>
<view class="friend-apply">
<block v-for="(item, index) in lists" v-if="lists.length > 0" :key="index">
<view class="lists">
<view class="" style="width: 100rpx;height: 100rpx;">
<u-avatar :src="item.portraitUrl || require('@/static/user/cover.png')" shape="square" :size="avatarSize" />
</view>
<view class="right">
<view class="title">
<view class="name">{{ item.name }}</view>
<view class="des">{{ item.address }}</view>
</view>
<view class="agress-btn">
<span v-if="isApply && item.friendship !=='accepted'" @click="action('apply', item)">查看</span>
<span class="isFri" v-if="isApply && item.friendship ==='accepted'" @click="action('isFriend', item)">已是好友</span>
</view>
</view>
</view>
</block>
</view>
</template>
<script>
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
});
}
}
};
</script>
<style lang="scss" scoped>
.lists {
padding: 0 $padding;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
box-sizing: border-box;
font-size: $title-size;
color: $text-gray;
.cover {
background-color: #ffffff;
}
.right {
width: 570rpx;
margin-left: $margin - 10;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: $padding 0;
border-bottom: solid 1rpx #f9f9f9;
.title {
width: 370rpx;
.name {
width: 100%;
color: $text-color;
font-size: $title-size;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.des {
width: 100%;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: $title-size-m - 2;
margin-top: $margin - 10;
color: $text-gray-m;
}
}
.agress-btn {
display: flex;
color: #fff;
font-size: $title-size-m;
span {
display: inline-block;
padding: 6rpx 14rpx;
background-color: $text-price;
border-radius: 10rpx;
}
span:nth-child(1) {
background-color: $main-color;
margin-right: 10rpx;
}
.isFri {
background-color: #f9f9f9 !important;
color: #666;
}
}
}
}
</style>

View File

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

View File

@@ -1,168 +0,0 @@
<template>
<view class="sent--popups u-border-top" v-if="show">
<view class="item" @click="onPopupsItem('picture')">
<image class="icon" src="@/static/icon/popups-icon-00.png" mode="widthFix"></image>
<text class="text">相册</text>
</view>
<view class="item" @click="onPopupsItem('camera')">
<image class="icon" src="@/static/icon/popups-icon-01.png" mode="widthFix"></image>
<text class="text">拍摄</text>
</view>
<view class="item" @click="onPopupsItem('video')" v-if="conversationType == 1">
<image class="icon" src="@/static/icon/popups-icon-02.png" mode="widthFix"></image>
<text class="text">视频通话</text>
</view>
<view class="item" @click="onPopupsItem('location')">
<image class="icon" src="@/static/icon/popups-icon-03.png" mode="widthFix"></image>
<text class="text">位置</text>
</view>
<view class="item" @click="onPopupsItem('redpacket')">
<image class="icon" src="@/static/icon/popups-icon-04.png" mode="widthFix"></image>
<text class="text">红包</text>
</view>
<view class="item" @click="onPopupsItem('file')">
<image class="icon" src="@/static/icon/popups-icon-05.png" mode="widthFix"></image>
<text class="text">文件</text>
</view>
<u-action-sheet :actions="callActions" cancelText="取消" @close="callShow = false" @select="singleCall"
:show="callShow">
</u-action-sheet>
</view>
</template>
<script>
import im from '@/utils/im/index.js'
import imBase from '../../mixins/imBase.js'
export default {
mixins: [
imBase
],
data() {
return {
callActions: [{
type: 0,
name: '语音通话'
},
{
type: 1,
name: '视频通话'
}
],
callShow: false
}
},
props: {
show: {
type: Boolean,
default: false
},
conversationType: {
type: Number,
default: 0
},
targetId: {
type: String,
default: ''
}
},
methods: {
singleCall(e) {
uni.navigateTo({
url: '/pages/im/private/call?targetId=' + this.targetId + '&mediaType=' + e.type +
'&isCall=true'
})
},
onPopupsItem(type) {
switch (type) {
case 'picture':
uni.chooseImage({
count: 9,
sourceType: ['album'],
success: res => {
im.sentImage(this.conversationType, this.targetId, res.tempFilePaths[0],
this.sender, (res) => {
this.success()
})
}
})
break;
case 'camera':
uni.chooseImage({
sourceType: ['camera'],
success: res => {
im.sentImage(this.conversationType, this.targetId, res.tempFilePaths[0],
this.sender, (res) => {
this.success()
})
}
})
break;
case 'video':
this.callShow = true
break;
case 'location':
// uni.showToast({
// icon: 'none',
// title: '功能正在开发中'
// })
// uni.chooseLocation({
// success: res => {
// console.log(res);
// // this.success()
// }
// })
break;
case 'redpacket':
uni.showToast({
icon: 'none',
title: '功能正在开发中'
})
break;
case 'file':
uni.showToast({
icon: 'none',
title: '功能正在开发中'
})
break;
}
},
// 处理返回
success() {
this.$emit('success')
}
}
}
</script>
<style lang="scss" scoped>
.sent--popups {
background: white;
padding: 30rpx 15rpx;
display: flex;
flex-wrap: wrap;
flex-direction: row;
.item {
width: 150rpx;
margin: 15rpx;
text-align: center;
}
.text {
text-align: center;
font-size: 26rpx;
color: #555;
padding-top: 15rpx;
}
.icon {
width: 110rpx;
height: 110rpx;
margin: 0 20rpx;
border-radius: 20rpx;
background: #F3F6FB;
}
}
</style>

View File

@@ -1,84 +0,0 @@
<template>
<view class="sent--text">
<input class="input" type="text" :auto-blur="true" @focus="focus" @blur="blur" :focus="focusState"
v-model="inputTxt" confirm-type="send" @confirm="sent" cursor-spacing="10" />
</view>
</template>
<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,
default: 0
},
targetId: {
type: String,
default: ''
}
},
computed: {
disabled() {
return this.inputTxt.length === 0
}
},
mounted() {
RongIMLib.getTextMessageDraft(this.conversationType, this.targetId, ({
draft
}) => {
draft ? this.inputTxt = draft : ''
})
},
beforeDestroy() {
// 保存草稿
RongIMLib.saveTextMessageDraft(this.conversationType, this.targetId, this.inputTxt)
},
data() {
return {
focusState: false,
inputTxt: ''
}
},
methods: {
sent() {
if (!this.disabled) {
im.sentText(this.conversationType, this.targetId, this.inputTxt, this.sender, () => {
RongIMLib.clearTextMessageDraft(this.conversationType, this.targetId)
this.$emit('success')
this.inputTxt = ''
})
}
},
focus() {
this.$emit('focus')
},
blur() {
uni.hideKeyboard()
this.$emit('blur')
}
}
}
</script>
<style scoped lang="scss">
.sent--text {
display: flex;
flex-direction: row;
justify-content: space-between;
.input {
background: #F3F6FB;
height: 70rpx;
width: 460rpx;
border-radius: 10rpx;
margin-right: 15rpx;
padding: 0 20rpx;
}
}
</style>

View File

@@ -1,276 +0,0 @@
<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,
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.showConfirm = true
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 => {
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')
}, 500)
})
},
// 移动按钮
touchmove(e){
if(this.startOffsetTop - e.changedTouches[0].pageY > 100){
if(this.showRecordTip){
this.showRecordTip = false
clearInterval(this.interval)
this.recorderManager.stop()
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()
})
}
}
}
</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

@@ -1,84 +0,0 @@
<template>
<view class="messageBar">
<!-- footer -->
<view class="footer">
<view class="msg-type" @click="changeMessageType">
<image class="icon" src="@/static/icon/key-icon.png" v-if="chatType === 0" mode="widthFix" />
<image class="icon" src="@/static/icon/msg-icon.png" v-if="chatType === 1" mode="widthFix" />
</view>
<sent-voice v-if="chatType === 0" :conversationType="conversationType" :targetId="targetId" @success="onSuccess" />
<sent-text v-if="chatType === 1" :conversationType="conversationType" :targetId="targetId" @success="onSuccess" />
<view class="msg-type msg-popups" @click="showPopups = !showPopups"> <image class="icon" src="@/static/icon/popups-icon.png" /> </view>
</view>
<!-- 弹出层 -->
<sent-popups :show="showPopups" :conversationType="conversationType" :targetId="targetId" @success="() => {showPopups = false, onSuccess()}" />
</view>
</template>
<script>
import sentText from './sent/sentText'
import sentVoice from './sent/sentVoice'
import sentPopups from './sent/sentPopups'
export default {
props: {
conversationType: {
type: Number,
default: 0
},
targetId: {
type: String,
default: ''
}
},
components: {
sentText,
sentVoice,
sentPopups
},
data() {
return {
chatType: 1, // 0 语音1 文本
showPopups: false
}
},
methods: {
// 切换聊天类型,语音/文本
changeMessageType() {
this.chatType = this.chatType === 1 ? 0 : 1
},
onSuccess() {
this.$emit('onSuccess')
},
// 处理弹出层
onHidePopus(){
if(this.showPopups){
this.showPopups = false
}
}
}
}
</script>
<style lang="scss" scoped>
.messageBar{
border-radius: ($radius*2) ($radius*2) 0 0;
background: white;
.footer {
padding: 20rpx 30rpx;
display: flex;
justify-content: space-between;
flex-direction: row;
.msg-type {
width: 70rpx;
height: 70rpx;
.icon {
margin: 5rpx;
width: 60rpx;
height: 60rpx;
}
}
}
}
</style>

View File

@@ -1,81 +0,0 @@
<template>
<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' " />
<!-- 已阅读 -->
<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' " />
</view>
</view>
</template>
<script>
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
import utils from '@/utils/index.js'
export default {
name: 'showText',
props: {
message: {
type: Object,
default: () => {
return {}
}
},
isGroup: {
type: Boolean,
default: false
},
isRemote: {
type: Boolean,
default: false
}
},
computed: {
iconSize() {
return utils.rpx2px(28)
},
readers() {
if (this.message.extra) {
return JSON.parse(this.message.extra).readers || 0
}
return 0
}
}
}
</script>
<style scoped lang="scss">
.state {
padding: 10rpx;
border-radius: 30rpx;
background-color: #ddd;
display: flex;
margin-right: 10rpx;
.sent {
z-index: 2;
}
.receive {
z-index: 1;
margin-left: -20rpx;
}
.readers {
font-size: 20rpx;
margin-left: -6rpx;
color: $text-gray-m;
}
}
</style>

View File

@@ -1,89 +0,0 @@
<template>
<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" />
</view>
</view>
</template>
<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: {
type: Object,
default: () => {
return {}
}
},
isGroup: {
type: Boolean,
default: false
}
},
mounted() {
},
computed: {
msg() {
return JSON.parse(this.message.content.message)
},
label() {
return this.msg.connected ? '通话时长:' + duration : '未接通'
},
isRemote() {
return this.message.messageDirection == 2
},
duration() {
if (this.message.duration > 3600) {
return moment.utc(this.message.duration * 1000).format('HH:mm:ss')
} else {
return moment.utc(this.message.duration * 1000).format('mm:ss')
}
}
}
}
</script>
<style scoped lang="scss">
.msg--call {
.name {
font-size: 26rpx;
color: $text-gray-m;
display: inline-block;
}
.im--text {
max-width: 508rpx;
padding: 20rpx;
line-height: 46rpx;
font-size: 32rpx;
color: $text-color;
display: flex;
flex-direction: row;
&.left {
border-radius: 0 20rpx 20rpx 20rpx;
background: white;
}
&.right {
border-radius: 20rpx 0 20rpx 20rpx;
background: $main-color;
color: white;
.u-icon {
color: white;
}
}
}
}
</style>

View File

@@ -1,105 +0,0 @@
<template>
<view class="msg--image">
<message-state :message="message" :isGroup="isGroup" :isRemote="isRemote" />
<view class="">
<view class="name" v-if="isGroup && isRemote">{{ contact(message.senderUserId).name }}</view>
<view class="image" :class="isRemote ? 'left': 'right'">
<image class="img" :src="content.thumbnail" @click="previewImage" mode="widthFix"></image>
</view>
</view>
</view>
</template>
<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: {
type: Object,
default: () => {
return {}
}
},
isGroup: {
type: Boolean,
default: false
}
},
components: {
messageState
},
computed: {
isRemote() {
return this.message.messageDirection == 2
},
content() {
return this.message.content
}
},
methods: {
showImage(path) {
uni.previewImage({
urls: [
path
]
})
},
previewImage() {
if (this.content.local && this.content.local.indexOf('///data/user/') < 0) {
this.showImage(this.content.local)
} else {
this.showImage(this.content.remote)
RongIMLib.downloadMediaMessage(this.message.messageId, {
success: (path) => {
this.content.local = path
},
error: (errorCode, messageId) => {
uni.showToast({
icon: 'none',
title: errorCode
})
}
})
}
}
}
}
</script>
<style scoped lang="scss">
.msg--image {
display: flex;
align-items: flex-end;
.name {
font-size: 24rpx;
color: $text-gray-m;
}
.image {
.img {
width: 180rpx;
}
&.left {
.img {
border-radius: 0 10rpx 10rpx 10rpx;
}
}
&.right {
.img {
border-radius: 10rpx 0 10rpx 10rpx;
}
}
}
}
</style>

View File

@@ -1,78 +0,0 @@
<template>
<view class="msg--text">
<message-state :message="message" :isGroup="isGroup" :isRemote="isRemote" />
<view class="">
<view class="name" v-if="isGroup && isRemote">{{ contact(message.senderUserId).name }}</view>
<view :class="['text', isRemote ? 'left': 'right']">{{ content }}</view>
</view>
</view>
</template>
<script>
import messageState from './messageState'
import imBase from '../../mixins/imBase.js'
export default {
name: 'showText',
mixins: [
imBase,
],
props: {
message: {
type: Object,
default: () => {
return {}
}
},
isGroup: {
type: Boolean,
default: false
}
},
components: {
messageState
},
computed: {
isRemote() {
return this.message.messageDirection == 2
},
content() {
return this.message.content.content
}
}
}
</script>
<style scoped lang="scss">
.msg--text {
display: flex;
align-items: flex-end;
.name {
font-size: 24rpx;
color: $text-gray-m;
}
.text {
box-sizing: border-box;
max-width: 502rpx;
padding: 20rpx 24rpx;
line-height: 46rpx;
font-size: 32rpx;
color: $text-color;
word-break: break-all;
&.left {
border-radius: 0 20rpx 20rpx 20rpx;
background: white;
}
&.right {
border-radius: 20rpx 0 20rpx 20rpx;
background: $main-color;
color: white;
}
}
}
</style>

View File

@@ -1,247 +0,0 @@
<template>
<view class="msg--voice">
<message-state :message="message" :isGroup="isGroup" :isRemote="isRemote" />
<view class="">
<view class="name" v-if="isGroup && isRemote">{{ contact(message.senderUserId).name }}</view>
<view class="msg-voice">
<view :class="['voice', isRemote ? 'left': 'right', {'onPlay': onPlay}]" :style="{width: width + 'rpx'}"
@click="startPlay">
<image v-if="isRemote" class="icon"
:class="{ 'videoFlicker' : onPlay && msgId == message.messageId }"
src="@/static/icon/audio_green.png" mode="widthFix"></image>
<image v-else class="icon" :class="{ 'videoFlicker' : onPlay && msgId == message.messageId }"
src="@/static/icon/audio_white.png" mode="widthFix"></image>
<text class="duration">{{ duration }}"</text>
</view>
<u-badge isDot :show="message.content.local =='' && isRemote" />
</view>
</view>
</view>
</template>
<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,
default: () => {
return {}
}
},
isGroup: {
type: Boolean,
default: false
}
},
components: {
messageState
},
data() {
return {
onPlay: false,
innerAC: null,
msgId: null
}
},
computed: {
duration() {
return this.message.content.duration
},
isRemote() {
return this.message.messageDirection == 2
},
width() {
if (this.duration > 3) {
return (this.duration * 5) + 150
} else {
return 120
}
}
},
mounted() {
// 这样能临时解决,但是会一直监听
uni.$on('onVoiceMessagePlay', (messageId) => {
if (this.message.messageId != messageId) {
this.stopPlay()
}
})
},
methods: {
// 播放语音消息
startPlay() {
// 如果是正在播放的,停止当前播放
if (this.onPlay) {
this.stopPlay()
return
}
this.onPlay = true
// 如果下载到了本地,那么直接播放,否则调用下载语音消息接口,下载后再播放
if (this.message.content.local && this.message.content.local.indexOf('///data/user/') < 0) {
this.playVoice(this.message.content.local)
} else {
RongIMLib.downloadMediaMessage(this.message.messageId, {
success: (path) => {
this.message.content.local = path
this.playVoice(path)
},
progress: (progress, messageId) => {},
cancel: (messageId) => {},
error: (errorCode, messageId) => {
uni.showToast({
icon: 'none',
title: '语音播放失败'
})
}
})
}
},
playVoice(path) {
console.log('准备播放', this.message.content);
this.innerAC = uni.createInnerAudioContext()
this.innerAC.src = path
this.innerAC.autoplay = false
this.msgId = this.message.messageId
this.innerAC.onCanplay(res => {
console.log('onCanplay')
this.innerAC.play()
})
this.innerAC.onPlay(res => {
console.log('onPlay')
uni.$emit('onVoiceMessagePlay', this.message.messageId)
})
this.innerAC.onEnded(res => {
this.innerAC.stop()
})
this.innerAC.onStop(() => {
this.onPlay = false
this.innerAC.destroy()
this.innerAC = null
this.msgId = null
uni.$emit('onVoiceMessageStop', this.message.messageId)
})
this.innerAC.onError(err => {
uni.showToast({
icon: 'none',
title: '语音播放失败'
})
})
},
stopPlay() {
if (this.innerAC) {
this.innerAC.stop()
}
}
}
}
</script>
<style>
@keyframes playFlicker {
0% {
opacity: 1;
}
50% {
opacity: .5;
}
100% {
opacity: 1;
}
}
.videoFlicker {
animation: playFlicker 1s infinite;
}
</style>
<style scoped lang="scss">
.msg--voice {
display: flex;
align-items: flex-end;
.state {
padding: 10rpx;
border-radius: 30rpx;
width: 40rpx;
background-color: #ddd;
display: flex;
margin-right: 10rpx;
.sent {
z-index: 2;
}
.receive {
z-index: 1;
margin-left: -20rpx;
}
}
.name {
font-size: 24rpx;
color: $text-gray-m;
}
.msg-voice {
display: flex;
align-items: center;
.u-badge {
margin-left: 20rpx;
}
.voice {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
height: 84rpx;
padding: 0 30rpx;
box-sizing: border-box;
.icon {
width: 38rpx;
height: 38rpx;
}
&.left {
border-radius: 0 20rpx 20rpx 20rpx;
background: white;
&.onPlay {
background-color: #EEEEEE;
}
.duration {
color: #333;
font-size: 30rpx;
}
}
&.right {
border-radius: 20rpx 0 20rpx 20rpx;
background: $main-color;
flex-direction: row-reverse;
&.onPlay {
background-color: darken($main-color, 10);
}
.duration {
color: white;
font-size: 30rpx;
}
}
}
}
}
</style>

View File

@@ -1,146 +0,0 @@
<template>
<view class="">
<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="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" />
<show-call v-else-if="message.objectName === 'RC:InfoNtf'" :message="message" :isGroup="isGroup" />
<view v-else class="">
[未处理的消息类型 {{ message.objectName }}]
</view>
</view>
<!-- <view class="time">{{ item.sentTime|timeCustomCN }}</view> 时间判断最好是隔一段时间没有消息才展示一个 -->
</view>
</view>
</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,
showImage,
showText
},
props: {
message: {
type: Object,
default: function() {
return {}
}
},
isGroup: {
type: Boolean,
default: false
}
},
methods: {
messageAction(event, message) {
this.$emit('messageAction', {
event,
message
})
},
toUser(item) {
if (item.messageDirection == 1) {
uni.navigateTo({
url: '/pages/im/friends/mine?targetId=' + item.senderUserId
})
} else {
uni.navigateTo({
url: '/pages/im/friends/info?targetId=' + item.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: '旧版本,无链接'
})
}
}
}
}
</script>
<style lang="scss" scoped>
.notify {
text-align: center;
font-size: 24rpx;
color: #666;
.link {
color: $main-color;
margin-left: 10rpx;
}
}
.cell-item {
display: flex;
width: 710rpx;
justify-content: flex-start;
&.left {
flex-direction: row;
}
&.right {
flex-direction: row-reverse;
.state {
flex-direction: row;
justify-content: flex-end;
}
}
.msg {
margin: 0 20rpx;
}
}
</style>

View File

@@ -1,188 +0,0 @@
<template>
<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-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')" />
<view class="info">我的群聊</view>
</view>
<block v-if="friends.length > 0">
<u-index-item v-for="(item, fkey) in friends" :key="fkey">
<u-index-anchor :text="indexs[fkey]" bgColor="#f9f9f9" height="20" size="12" color="#666"
class="anchor" />
<view v-for="(friendItem, index) in item" :key="index" class="friend-flex"
@click="toFriend(friendItem.targetId)">
<u-avatar class="avatar-img" size="40" shape="square"
:src="contact(friendItem.targetId).portraitUrl" />
<view class="info">
<view class="name">{{ contact(friendItem.targetId).name }}</view>
</view>
</view>
</u-index-item>
</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>
<script>
import {
getFriendsLetter
} 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: [],
friends: [],
pendingCount: 0
};
},
computed: {
contact() {
return function(targetId) {
return this.$store.getters.contactInfo(targetId)
}
}
},
onLoad() {
uni.$on('onNewContactFriends', this.checkNewFriendPending)
},
onShow() {
this.getFriendList()
this.checkNewFriendPending()
},
onUnload() {
uni.$off("onNewContactFriends")
},
methods: {
getFriendList() {
getFriendsLetter().then(res => {
this.indexs = res.indexList
this.friends = res.itemArr
})
},
checkNewFriendPending() {
im.getPendingList((pendings) => {
this.pendingCount = pendings.length
})
},
toGroup() {
uni.navigateTo({
url: '/pages/im/group/index'
})
},
toFriend(targetId) {
uni.navigateTo({
url: '/pages/im/friends/info?targetId=' + targetId
})
},
// 新朋友
toPending() {
uni.navigateTo({
url: '/pages/im/friends/pending'
})
}
},
onNavigationBarButtonTap(e) {
uni.navigateTo({
url: '/pages/im/friends/search'
})
}
};
</script>
<style lang="scss" scoped>
// 页面空
.pages-null {
height: 70vh;
}
.anchor {
background-color: #f9f9f9 !important;
padding: 10rpx 30rpx;
border-bottom: none !important;
}
// 好友列表
.friend-flex {
position: relative;
padding: 0 $padding 0 $padding;
display: flex;
flex-direction: row;
align-items: center;
box-sizing: border-box;
.avatar-img {
box-shadow: 0 0 20rpx rgba($color: $main-color, $alpha: 0.2);
}
.info {
flex: 1;
margin-left: $padding;
border-bottom: solid 1rpx #f9f9f9;
height: 120rpx;
line-height: 120rpx;
.name {
font-size: $title-size;
color: #454545 !important;
@extend .nowrap;
}
.address {
color: $text-gray-m;
font-size: $title-size-m - 3;
padding-top: 10rpx;
word-break: break-word;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 600rpx;
}
}
}
.list-cell {
display: flex;
box-sizing: border-box;
width: 100%;
padding: 10px 24rpx;
overflow: hidden;
color: #323233;
font-size: 14px;
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

@@ -1,355 +0,0 @@
<template>
<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>
<view class="info-text">
<view class="nickname">{{ userInfo.name }}</view>
<view class="address" @longpress="copyAddress">地址{{ userInfo.address }}</view>
</view>
</view>
<!-- 用户资料 -->
<view class="info-btns">
<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>
</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" />
</view>
<view class="item u-border-bottom">
<label>消息免打扰</label>
<u-switch size="22" v-model="status" activeColor="#34CE98" @change="setStatus"></u-switch>
</view>
<view class="item">
<label>聊天置顶</label>
<u-switch size="22" v-model="isTop" activeColor="#34CE98" @change="setTop"></u-switch>
</view>
</view>
<view class="footer">
<view class="footer-item" @click="deleteFriend">
<view class="icon">
<u-icon class="icon-u" name="close-circle-fill" color="#fff" size="30" />
</view>
<view class="text">删除好友</view>
</view>
<view class="footer-item" @click="toPrivate">
<view class="icon ">
<u-icon class="icon-u" name="chat-fill" color="#fff" size="30" />
</view>
<view class="text">发送消息</view>
</view>
<view class="footer-item" @click="callShow = true">
<view class="icon">
<u-icon class="icon-u" name="camera-fill" color="#fff" size="30" />
</view>
<view class="text">/视频通话</view>
</view>
</view>
</block>
<block v-else>
<view class="footer">
<view class="footer-item" @click="toBeFriend">
<view class="icon">
<u-icon class="icon-u" name="plus-people-fill" color="#fff" size="30" />
</view>
<view class="text">申请好友</view>
</view>
</view>
</block>
<u-action-sheet :actions="callActions" cancelText="取消" @close="callShow = false" @select="singleCall"
:show="callShow">
</u-action-sheet>
</view>
</template>
<script>
import {
getFriendInfo,
pedingFriend,
deleteFriend
} 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'
// friendship: '' 没有好友关系
// accepted 好友
// pending 申请中
// denied 拒绝
// blocked 黑名单
export default {
data() {
return {
targetId: '',
userInfo: {},
status: false, // 0 是免打扰1是正常通知
isTop: false,
block: false,
conversationType: 1,
callActions: [{
type: 0,
name: '语音通话'
},
{
type: 1,
name: '视频通话'
}
],
callShow: false,
hasPeding: false
}
},
onLoad(e) {
this.targetId = e.targetId
getFriendInfo(e.targetId).then(res => {
this.userInfo = res
// 获取到用户信息之后,去检查一下要不要更新
this.$store.dispatch('updateContact', res)
uni.setNavigationBarTitle({
title: res.name
})
})
RongIMLib.getConversationNotificationStatus(this.conversationType, this.targetId, ({
status
}) => {
this.status = !Boolean(status)
})
RongIMLib.getConversation(this.conversationType, this.targetId, ({
code,
conversation
}) => {
if (code == 0) {
this.isTop = conversation.isTop
}
})
},
methods: {
copyAddress() {
uni.setClipboardData({
data: this.userInfo.address,
success: () => {
uni.showToast({
icon: 'none',
title: '复制成功'
})
}
})
},
toPrivate() {
uni.navigateTo({
url: '/pages/im/private/chat?targetId=' + this.targetId
});
},
setRemark() {
uni.showToast({
title: '开发中',
icon: 'none'
});
},
deleteFriend() {
uni.showModal({
title: '删除确认',
content: '确认删除后不可恢复',
success: e => {
if (e.confirm) {
deleteFriend(this.targetId).then(res => {
uni.$emit('onContactNotification')
// 删除聊天记录
RongIMLib.deleteMessages(1, this.targetId);
RongIMLib.removeConversation(1, this.targetId);
uni.showToast({
icon: 'none',
title: '好友删除成功',
success() {
uni.switchTab({
url: '/pages/im/index'
})
}
})
})
}
}
})
},
setStatus() {
RongIMLib.setConversationNotificationStatus(this.conversationType, this.targetId, this.status,
({
status
}) => {
this.status = !Boolean(status)
})
},
setTop() {
RongIMLib.setConversationToTop(this.conversationType, this.targetId, this.isTop, (res) => {
RongIMLib.getConversation(this.conversationType, this.targetId, ({
conversation
}) => {
this.isTop = conversation.isTop
})
})
},
// 申请好友
toBeFriend() {
if (this.hasPeding) {
uni.showToast({
icon: 'none',
title: '请不要频繁操作'
})
return
}
pedingFriend(this.targetId, '').then(res => {
uni.showToast({
title: ` 申请成功,等待审核 `,
icon: 'none',
duration: 3000,
mask: true
});
this.hasPeding = true
})
.catch(err => {
uni.showToast({
icon: 'error',
title: err.message,
duration: 2000,
mask: true
})
})
},
singleCall(e) {
uni.navigateTo({
url: '/pages/im/private/call?targetId=' + this.targetId + '&mediaType=' + e.type +
'&isCall=true'
})
}
}
}
</script>
<style lang="scss" scoped>
.content {
min-height: 100vh;
background: $window-color;
padding-top: $padding;
box-sizing: border-box;
}
// 用户信息
.info-flex {
padding: $padding;
margin: 0 $margin;
display: flex;
background: white;
border-radius: $radius;
.info-text {
width: calc(100% - 50px);
padding-left: $padding;
box-sizing: border-box;
.nickname {
line-height: 30px;
font-size: $title-size + 6;
color: #454545;
text-align: left;
}
.address {
line-height: 20px;
font-size: $title-size-sm;
color: $text-gray;
text-align: left;
@extend .nowrap;
}
}
}
// footer
.footer {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: $padding*2 $padding;
display: flex;
justify-content: space-around;
.footer-item {
margin: 0 $margin/2;
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
.icon {
background: $main-color;
width: 88rpx;
height: 88rpx;
// line-height: 88rpx;
// display: inline-block;
border-radius: 50%;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
box-sizing: border-box;
.icon-u {
// margin-top: calc((88rpx/2) - 13px);
// margin-left: calc((88rpx/2) - 13px);
}
}
.text {
color: $main-color;
font-size: $title-size-m - 2;
text-align: center;
padding-top: 16rpx;
}
}
}
// btns
.info-btns {
background: white;
margin: $margin;
border-radius: $radius;
.u-border-bottom {
border-bottom: solid 1rpx #f9f9f9 !important;
}
.item {
line-height: 100rpx;
display: flex;
align-items: center;
padding: 10rpx $padding;
justify-content: space-between;
font-size: $title-size-lg;
label {
width: 200rpx;
}
.text {
width: calc(100% - 200rpx);
color: $text-gray-m;
text-align: right;
@extend .nowrap;
}
}
}
</style>

View File

@@ -1,170 +0,0 @@
<template>
<view class="friend-ewm-content">
<view class="bg"></view>
<!-- 用户信息 -->
<view class="info-flex">
<view class="info-flex-item">
<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">
<uqrcode class="info-code-src" :size="160" :text="qrContent" />
<view class="info-code-text">扫描二维码加我ZH大健康好友</view>
</view>
<u-icon class="download" :name="require('@/static/imgs/copy-333.png')" size="14" :bold="true"
@click="copy" :label="'应用下载:'+ downUrl" labelPos="left" labelSize="14" space="6"
labelColor="#26a377" />
<view class="copy" @click="copy"> 复制地址 </view>
</view>
</view>
</view>
</template>
<script>
import {
getUserInfo
} from '@/apis/interfaces/im.js'
export default {
data() {
return {
infoObj: {
userId: '',
username: '',
name: '',
address: '',
portraitUrl: '',
gender: 0,
hash: ''
},
downUrl: 'http://www.baidu.com',
qrContent: 'ADDFRIEND|'
}
},
onLoad(e) {
this.qrContent += e.targetId
getUserInfo(e.targetId).then(res => {
this.infoObj = res
})
},
methods: {
previewImg(item){
console.log(item)
uni.previewImage({
urls:[item]
})
},
copy() {
uni.setClipboardData({
data: this.downUrl,
success: function() {
uni.showToast({
title: ` 下载链接已复制到剪贴板 `,
icon: 'none',
position:'bottom',
mask: true,
duration: 2000
})
}
});
}
}
}
</script>
<style lang="scss" scoped>
.friend-ewm-content {
background: #fff;
min-height: 100vh;
box-sizing: border-box;
.bg {
background-color: red;
width: 100%;
height: 340rpx;
background-color: $main-color;
}
// 用户信息
.info-flex {
padding: $padding 0;
// margin: 0 $margin;
background: white;
border-radius: 50rpx 50rpx 0 0;
position: relative;
top: -100rpx;
.info-flex-item {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
box-sizing: border-box;
position: relative;
top: -160rpx;
.avatar {
// padding: 14rpx;
border-radius: 20rpx;
background-color: #fff;
border: solid 14rpx rgba($color: #fff, $alpha:1);
}
.nickname {
line-height: 80rpx;
font-size: $title-size + 5;
color: $text-color;
font-weight: 600;
}
.address {
line-height: 60rpx;
font-size: $title-size-m + 2;
color: $text-gray;
text-align: left;
@extend .nowrap;
}
.info-code {
background: white;
margin: 0 $margin;
border-radius: $radius;
padding: $padding * 1.4 $padding $padding;
text-align: center;
&-src {
display: inline-block;
border-radius: 10rpx;
border: solid 20rpx rgba($color: #f9f9f9, $alpha:1);
background-color: #fff;
padding: 14rpx;
}
&-text {
text-align: center;
color: $text-gray;
font-size: $title-size-m + 1;
line-height: 40rpx;
padding: 8rpx 0 $padding 0;
}
}
.download {
background-color: #f9f9fb;
padding: 20rpx 30rpx 10rpx 30rpx;
border-radius: 10rpx;
}
.copy {
font-size: $title-size + 4;
color: $main-color;
background-color: rgba($color: $main-color, $alpha: .1);
padding: 20rpx 100rpx;
border-radius: 50rpx;
margin-top: 40rpx;
}
}
}
}
</style>

View File

@@ -1,79 +0,0 @@
<template>
<view class="pending">
<u-sticky>
<view class="header-search" @click="$Router.push({ name: 'SearchFriend' })">
<u-search placeholder="输入手机号码搜索" searchIcon="search" inputAlign="center" bgColor="white"
:disabled="true" :show-action="false" />
</view>
</u-sticky>
<block v-if="pendings.length > 0">
<view v-for="(item, index) in pendings" :key="index">
<apply-cell :message="item.latestMessage" @success="getPendingList" />
</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" />
<span> 暂无好友申请 ~ </span>
</view>
</view>
</template>
<script>
import applyCell from '../components/friendApplyCell'
import im from '@/utils/im/index.js'
export default {
components: {
applyCell
},
data() {
return {
pendings: [],
bg: '#fff'
}
},
onShow() {
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 {
this.bg = '#fff'
}
this.pendings = pendings
})
}
}
};
</script>
<style lang="scss" scoped>
.header-search {
padding: $padding/2 $padding;
background: $window-color;
}
.no-lists {
padding-top: $padding * 5;
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

@@ -1,109 +0,0 @@
<!--
* @Description:搜索新朋友页面
* @Author: Aimee·Zhang
* @Date: 2022-01-24 10:49:15
* @LastEditors: Aimee·Zhang
* @LastEditTime: 2022-01-25 10:18:26
-->
<template>
<view class="search">
<!-- 搜索 -->
<u-sticky>
<view class="header-search">
<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-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>
</template>
<script>
import {
searchFriend,
pedingFriend
} from '@/apis/interfaces/im.js';
import applyFriend from '../components/friendSearchList.vue';
export default {
components: {
applyFriend
},
data() {
return {
searchResult: [],
searchValue: '',
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 黑名单
searchFriend(this.searchValue)
.then(res => {
this.searchResult = res;
console.log(res)
})
.catch(err => {
uni.showToast({
title: err.message,
icon: 'none'
});
});
},
action(e) {
uni.navigateTo({
url: '/pages/im/friends/info?targetId=' + e.item.targetId
})
}
}
};
</script>
<style lang="scss" scoped>
.header-search {
padding: $padding/2 $padding;
// background: $window-color;
}
.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

@@ -1,120 +0,0 @@
<template>
<view class="create">
<view class="create-title">公告内容</view>
<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>
</view>
</template>
<script>
import {
createGroupAnnouncement,
getGroupAnnouncement
} from '@/apis/interfaces/im.js'
import onGroupDismiss from '../mixins/onGroupDismiss.js'
export default {
mixins: [
onGroupDismiss
],
data() {
return {
targetId: '',
content: '',
aId: '',
type: '' // cheack ' 查看详情'
}
},
onLoad(e) {
this.targetId = e.targetId
if (e.aId) {
this.type = e.type
uni.setNavigationBarTitle({
title: '群公告'
})
this.aId = e.aId
getGroupAnnouncement(this.targetId, this.aId).then(res => {
this.content = res.content
}).catch(err => {
if (err.status_code == 404) {
this.$nextTick(() => {
uni.navigateBack()
})
} else {
uni.showToast({
title: err.message,
icon: 'none',
mask: true
})
}
})
}
},
computed: {
disabled() {
return this.content.length == 0 || this.content.length > 200
}
},
methods: {
onCreate() {
createGroupAnnouncement(this.targetId, this.content).then(res => {
uni.$emit('groupAnnouncementCreated')
uni.showToast({
title: '发布成功',
success: () => {
setTimeout(() => {
uni.navigateBack()
}, 1000)
}
})
}).catch(err => {
uni.showToast({
icon: 'none',
title: err.message
})
})
}
}
}
</script>
<style lang="scss" scoped>
.create {
padding: $padding;
.create-title {
font-size: $title-size + 4;
padding: $padding - 10 0 $padding - 10 $padding - 10;
color: $text-color;
font-weight: 800;
position: relative;
&::before {
content: "";
position: absolute;
width: 10rpx;
height: 34rpx;
background-color: $main-color;
left: 0;
top: 26rpx;
}
}
.content {
color: $text-color;
font-size: $title-size;
line-height: 1.7;
}
.u-button {
margin-top: $padding;
}
}
</style>

View File

@@ -1,224 +0,0 @@
<template>
<view class="announce" :style="`background-color:${bg};`">
<!-- 有列表 -->
<u-skeleton rows="2" :loading="loading" avatar :rows="5" v-if="announcements.length>0">
<view v-for="(item,index) in announcements" :key="index" class="item"
@longpress="actions(item.announcement_id)" @click="tabA(item.announcement_id)">
<view class="content-a"><span v-if="item.is_top">置顶</span>{{ item.content }}</view>
<view class="user">
<u-avatar :src="item.user.portraitUrl" size="40rpx" />
<view class="name">{{ item.user.name }}</view>
<view class="time">{{ item.created_at }}</view>
</view>
<!-- <view class="delete" v-if="isAdmin" @click="onDelete(item.announcement_id)">删除</view> -->
</view>
</u-skeleton>
<!-- 没有列表 -->
<view class="no-lists" v-else>
<u-image class="cover" radius="4" width="400rpx" height="400rpx"
:src="require('@/static/imgs/no-level-list.png')" :lazy-load="true" />
<span>暂无公告内容~</span>
</view>
<!-- 弹出 -->
<u-action-sheet :actions="actionMap" :title="actionTitle" :show="actionShow" cancelText="取消"
@close="actionShow = false" @select="handleAction" />
</view>
</template>
<script>
import {
getGroupInfo,
getGroupAnnouncements,
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: '',
groupAnnouncementId: '', // 选择公告 id
announcements: [], // 公告列表
loading: true,
isAdmin: false,
actionShow: false,
actionMap: [{
key: 2,
name: ' 删除该公告',
disabled: false
}, {
key: 3,
name: '置顶该公告',
disabled: false
}],
actionTitle: '请选择操作',
bg: '#fff'
}
},
onLoad(e) {
this.targetId = e.targetId
getGroupInfo(this.targetId).then(res => {
this.isAdmin = res.group.is_admin
})
this.initData()
uni.$on('groupAnnouncementCreated', this.initData)
},
onUnload() {
uni.$off('groupAnnouncementCreated')
},
onNavigationBarButtonTap() {
if (this.isAdmin) {
uni.navigateTo({
url: '/pages/im/group/announceCreate?targetId=' + this.targetId
})
} else {
uni.showToast({
icon: 'none',
title: '没有权限'
})
}
},
methods: {
// 获取公告信息
initData() {
getGroupAnnouncements(this.targetId).then(res => {
if (res.length > 0) {
this.bg = '#f9f9f9'
} else {
this.bg = '#fff'
}
this.announcements = res
this.loading = false
})
},
// 选择公告 并显示操作弹窗
actions(id) {
if (this.isAdmin) {
this.groupAnnouncementId = id
this.actionShow = true
}
},
// 选择了操作出发事件
handleAction(e) {
console.log(e.key)
switch (e.key) {
case 2:
this.onDelete(this.groupAnnouncementId)
break;
case 3:
this.onTop(this.groupAnnouncementId)
break;
}
},
tabA(id) {
uni.navigateTo({
url: '/pages/im/group/announceCreate?type=check&targetId=' + this.targetId + '&aId=' + id
})
},
onTop(aId) {
topGroupAnnouncement(this.targetId, aId).then(res => {
uni.showToast({
icon: 'none',
title: ' 置顶成功',
mask: true
})
uni.$emit('updateAnnouncement')
this.initData()
})
},
// 删除公告
onDelete(aId) {
deleteGroupAnnouncement(this.targetId, aId).then(res => {
uni.showToast({
icon: 'none',
title: '删除成功',
mask: true
})
uni.$emit('updateAnnouncement')
this.initData()
})
}
}
}
</script>
<style lang="scss" scoped>
.announce {
min-height: 99vh;
.no-lists {
padding-top: $padding * 5;
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;
}
}
.item {
background-color: #fff;
padding: $padding $padding + 10 10rpx $padding + 10;
border-bottom: $padding solid #f9f9f9;
.user {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
box-sizing: border-box;
font-size: $title-size-m;
color: $text-gray-m;
padding: 20rpx 10rpx 10rpx 10rpx;
border-top: solid 1rpx #F9F9F9;
.name {
padding-left: 10rpx;
}
.time {
margin-left: 20rpx;
}
}
.content-a {
font-size: $title-size;
color: $text-color;
max-width: 100%;
margin-bottom: 10rpx;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
line-height: 1.5;
span {
color: #fff;
display: inline-block;
border-radius: 10rpx;
background-color: $main-color;
font-size: $title-size-m - 4;
padding: 4rpx 10rpx;
margin-right: 10rpx;
line-height: 1.4;
margin-bottom: 10rpx;
}
}
}
}
</style>

View File

@@ -1,120 +0,0 @@
<template>
<view class="apply" v-if="loaded">
<u-avatar :src="group.cover || require('@/static/user/cover.png')" size="128" shape="square" />
<view class="name"> {{ group.name }} </view>
<u-button class="apply-btn" v-if="group.can_join" @click="modalShow = true" text="申请加群" :disabled="disabled" color="#34CE98" />
<view class="" v-else>
<view class="" v-if="group.is_full">群已满员</view>
<view class="" v-if="group.deny_apply">禁止申请</view>
<u-button class="apply-btn2" v-if="group.state === 'accepted'" color="#34CE98" text="进入群聊" @click="toGroupChat" />
</view>
<u-modal negativeTop="300" :show="modalShow" title="申请原因" showCancelButton @cancel="onHideModal" @confirm="onJoinGroup">
<view class="slot-content"> <u--input placeholder="申请原因" border="surround" focus v-model="message" /> </view>
</u-modal>
</view>
</template>
<script>
import {
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: '',
group: {},
modalShow: false,
message: '',
disabled: false,
loaded: false
}
},
onLoad(e) {
this.targetId = e.targetId
joinGroupPre(this.targetId).then(res => {
console.log(res, 'res.返回群的基本信息')
this.group = res
this.loaded = true
}).catch(err => {
uni.showToast({
title: err.message,
icon: 'none',
mask: true,
duration: 3000
})
})
},
methods: {
toGroupChat() {
uni.redirectTo({
url: '/pages/im/group/chat?targetId=' + this.targetId
})
},
onHideModal() {
this.message = ''
this.modalShow = false
},
onJoinGroup() {
joinGroup(this.targetId, this.message).then(res => {
console.log('申请结果', res);
uni.showToast({
icon: 'none',
title: '申请成功',
duration: 2000,
mast: true
})
setTimeout(() => {
this.$Router.back()
}, 2000)
}).catch(err => {
uni.showToast({
icon: 'none',
title: err.message
})
})
this.disabled = true
this.onHideModal()
}
}
}
</script>
<style lang="scss" scoped>
.apply {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
min-height: 100vh;
background-color: $window-color;
.u-avatar {
margin-top: 60rpx;
width: 180rpx;
height: 180rpx;
}
.name {
margin: 40rpx 0;
font-size: $title-size + 2;
}
.apply-btn {
width: 80%;
font-size: $title-size;
}
.apply-btn2 {
padding: 0 100rpx;
}
}
</style>

View File

@@ -1,266 +0,0 @@
<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>
<view class="body">
<view class="scroll">
<view class="cell" v-for="(message, index) in messages" :key="index">
<show-message-cell :message="message" isGroup @messageAction="messageAction" />
</view>
</view>
</view>
</view>
</template>
<script>
import {
getGroupBase
} from '@/apis/interfaces/im.js'
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
import im from '@/utils/im/index.js'
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
},
data() {
return {
avatarRpx: 84,
targetId: '',
conversationType: RongIMLib.ConversationType.GROUP,
messages: [],
groupInfo: {
name: ''
}
}
},
computed: {
latestMessage() {
if (this.messages.length) {
return this.messages[0]
} else {
return {
sentTime: 0
}
}
}
},
onShow() {
this.initGroupInfo()
},
onLoad(e) {
this.targetId = e.targetId
// 获取历史消息列表
this.getMessageList()
// 监听新消息
uni.$on('onReceiveMessage_' + this.targetId, (message) => {
this.getNewMessage()
})
uni.$on('onReceiptRequest', (msg) => {
if (msg.targetId == this.targetId) {
RongIMLib.getMessageByUId(msg.messageUId, (result) => {
RongIMLib.sendReadReceiptResponse(3, this.targetId, [result.message], (res) => {
console.error('发送群聊已读回执成功', res);
})
})
}
})
// 群已读回执
uni.$on('onReceiptResponse', (msg) => {
if (msg.targetId == this.targetId) {
this.messages = this.messages.map(item => {
if (msg.messageId == item.messageId) {
return msg
} else {
return item
}
})
}
})
// 清理聊天记录
uni.$once('cleanGroupMessage', this.getMessageList)
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('onRemoveMessage_' + this.targetId)
uni.$off('onReceiveMessage_' + this.targetId)
uni.$off('onUpdateProfile_' + this.targetId)
uni.$off('onRecallMessage_' + this.targetId)
uni.$off('onReceiptRequest')
uni.$off('onReceiptResponse')
},
onNavigationBarButtonTap() {
uni.navigateTo({
url: '/pages/im/group/info?targetId=' + this.targetId
})
},
methods: {
initGroupInfo() {
// 获取群信息,成员数量,设置标题
getGroupBase(this.targetId).then(res => {
uni.setNavigationBarTitle({
title: res.name + `(${res.members})`
})
})
},
onScroll(e) {
this.$refs.messageBar.onHidePopus()
},
getNewMessage() {
im.getMessageList(
this.conversationType,
this.targetId,
this.latestMessage.sentTime,
10,
false,
(messages) => {
this.messages.unshift(...messages)
this.scrollBottom()
})
},
// 获取消息列表
getMessageList() {
im.getMessageList(
this.conversationType,
this.targetId,
0,
20,
true,
(messages) => {
console.log('获取消息列表', messages);
const msgs = messages.filter(item => item.receivedStatus == 0)
console.log('未读消息', msgs);
if (msgs.length) {
RongIMLib.sendReadReceiptResponse(3, this.targetId, msgs, (res) => {
console.error('发送群聊已读回执成功', res);
msgs.map(item => {
RongIMLib.setMessageReceivedStatus(item.messageId, 1)
})
})
}
this.messages = messages
this.scrollBottom()
})
},
// 滚动到底部
scrollBottom(type) {
if (this.latestMessage) {
// 清理当前会话,未读消息数量
RongIMLib.clearMessagesUnreadStatus(this.conversationType, this.targetId, this.latestMessage
.sentTime)
// 更新badge提醒数量
im.setNotifyBadge()
}
}
},
onHide() {
// console.log(JSON.stringify(this.$refs))
// this.$refs.voice.stopPlay()
}
}
</script>
<style scoped lang="scss">
/* 窗口 */
.chat {
background: $window-color;
height: 100vh;
display: flex;
flex-direction: column-reverse;
.body {
overflow: scroll;
flex: 1;
height: 0;
display: flex;
flex-direction: column-reverse;
.scroll {
display: flex;
flex-direction: column-reverse;
justify-content: flex-end;
.cell {
padding: 10rpx 20rpx;
}
}
}
}
/* 遮罩 */
.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

@@ -1,168 +0,0 @@
<template>
<view class="group" :style="`background-color:${bg};`">
<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="36" shape="square" :src="contact(item.targetId).portraitUrl" />
<view class="info">
<view class="name">{{ item.name }} <span class="total">{{ item.members }} 成员</span></view>
</view>
</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" />
<span>空空如也~</span>
</view>
<u-modal negativeTop="300" :show="createModal" title="创建群聊" showCancelButton @cancel="onHideModal"
@confirm="onCreateGroup">
<view class="slot-content">
<u--input placeholder="群名称" border="surround" focus v-model="groupName"></u--input>
</view>
</u-modal>
</view>
</template>
<script>
import {
getMyGroups,
createGroup
} from '@/apis/interfaces/im.js'
export default {
data() {
return {
groups: [],
createModal: false,
groupName: '',
bg: '#fff'
}
},
computed: {
contact() {
return function(targetId) {
return this.$store.getters.contactInfo(targetId)
}
}
},
onNavigationBarButtonTap() {
this.createModal = true
},
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 {
this.bg = '#fff'
}
this.groups = res
res.map(item => {
this.$store.dispatch('updateContact', item)
})
})
},
onHideModal() {
this.createModal = false
this.groupName = ''
},
onCreateGroup() {
createGroup({
name: this.groupName
}).then(res => {
uni.showToast({
title: '创建成功'
})
}).catch(err => {
uni.showToast({
icon: 'none',
title: err.message
})
}).finally(() => {
this.initData()
this.onHideModal()
})
},
toGroup(targetId) {
uni.navigateTo({
url: '/pages/im/group/chat?targetId=' + targetId
})
}
}
}
</script>
<style lang="scss" scoped>
.group {
min-height: 100vh;
background-color: $window-color;
.title {
font-size: $title-size-m;
color: $text-gray-m;
padding: 10rpx $padding;
}
.group-count {
text-align: center;
font-size: $title-size;
color: $text-gray;
background-color: #fff;
padding: 10rpx $padding 20rpx $padding;
font-weight: normal;
}
}
// 好友列表
.friend-flex {
position: relative;
padding: 20rpx $padding;
display: flex;
flex-direction: row;
align-items: center;
background-color: #fff;
.info {
flex: 1;
margin-left: $padding + 10;
border-bottom: solid 1rpx #f9f9f9;
padding-bottom: $padding;
.name {
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;
font-size: $title-size-m - 5;
}
}
}
.no-lists {
padding-top: $padding * 5;
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

@@ -1,378 +0,0 @@
<template>
<view class="container">
<view class="members u-border-bottom">
<group-user-list ref="userList" :targetId="targetId" :count="14" />
</view>
<u-cell-group class="cells" :border="false">
<u-cell :border="false" class="u-border-bottom" isLink title="群公告" @click="toAnnouncement">
<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" 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-switch slot="value" size="20" v-model="status" activeColor="#34CE98" @change="setStatus" />
</u-cell>
</u-cell-group>
<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-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-group>
<view class="cells actions" v-if="loaded">
<view class="action u-border-bottom" @click="onClean">清空聊天记录</view>
<view class="action u-border-bottom" v-if="group.is_owner" @click="onDismiss">解散群聊</view>
<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" 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>
</u-modal>
<u-action-sheet @select="doAction" :actions="joinTypeMap" cancelText="取消" :show="showActions" @close="showActions=false" />
</view>
</template>
<script>
import {
getGroupInfo,
updateGroup,
quitGroup,
dismissGroup
} from '@/apis/interfaces/im.js'
import {
uploads
} 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: '',
group: {},
conversationType: 3,
announcement: '',
status: false,
isTop: false,
loaded: false,
modalShow: false,
groupName: '',
qrCodeShow: false,
qrContent: 'JOINGROUP|',
joinType: '',
joinTypeMap: [],
showActions: false
}
},
onLoad(e) {
this.targetId = e.targetId
this.qrContent += e.targetId
RongIMLib.getConversationNotificationStatus(this.conversationType, this.targetId, ({
status
}) => {
this.status = !Boolean(status)
})
RongIMLib.getConversation(this.conversationType, this.targetId, ({
code,
conversation
}) => {
if (code == 0) {
this.isTop = conversation.isTop
}
})
this.initData()
uni.$on('groupAnnouncementCreated', this.initData)
uni.$on('groupInvitedUser', this.updateUserList)
uni.$on('updateAnnouncement', this.initData)
},
onUnload() {
uni.$off('groupAnnouncementCreated')
uni.$off('groupInvitedUser')
uni.$off('updateAnnouncement')
},
methods: {
updateUserList() {
this.$refs.userList.initUsers()
},
initData() {
getGroupInfo(this.targetId).then(res => {
this.group = res.group
this.groupName = res.group.name
this.announcement = res.announcement
this.members = res.members
this.loaded = true
this.joinTypeMap = res.join_type_map.map(item => {
item.disabled = item.key == res.join_type
return item
})
this.joinType = res.join_type_map.filter(item => {
return item.key == res.join_type
})[0].name
}).catch(err => {
uni.showToast({
icon: 'none',
title: '群不存在'
})
})
},
setStatus() {
RongIMLib.setConversationNotificationStatus(this.conversationType, this.targetId, this.status,
({
status
}) => {
this.status = !Boolean(status)
})
},
setTop() {
RongIMLib.setConversationToTop(this.conversationType, this.targetId, this.isTop, (res) => {
RongIMLib.getConversation(this.conversationType, this.targetId, ({
conversation
}) => {
this.isTop = conversation.isTop
})
})
},
toAnnouncement() {
uni.navigateTo({
url: '/pages/im/group/announcement?targetId=' + this.targetId
})
},
showGroupQrCode() {
this.qrCodeShow = true
},
// 群聊邀请待确认
showGroupsSure() {
uni.navigateTo({
url: "/pages/im/group/reviewed?targetId=" + this.targetId
})
},
onGroupName() {
this.modalShow = true
},
onChangeGroupName() {
if (this.groupName != this.group.name) {
updateGroup(this.targetId, {
name: this.groupName
}).then(res => {
this.modalShow = false
uni.showToast({
icon: 'none',
title: '群名称修改成功'
})
})
} else {
uni.showToast({
icon: 'none',
title: '无修改'
})
}
},
onHideModal() {
this.modalShow = false
this.groupName = this.group.name
},
// 修改群头像
onGroupAvatar() {
uni.chooseImage({
count: 1,
sourceType: ['album'],
crop: {
quality: 100,
width: 128,
height: 128,
resize: true
},
success: res => {
console.log(res);
let path = res.tempFiles.map((val, index) => {
return {
name: 'uploads' + index,
uri: val.path
}
})
uploads(path).then(path => {
updateGroup(this.targetId, {
cover: path.path[0]
}).then(res => {
uni.showToast({
icon: 'none',
title: '群头像修改成功'
})
this.modalShow = false
this.group.cover = path.url[0]
})
}).catch(err => {
uni.showToast({
title: err.message,
icon: 'none'
})
})
},
fail: (err) => {
console.log(err);
}
})
},
onChangeJoinType() {
this.showActions = true
},
doAction(e) {
updateGroup(this.targetId, {
join_type: e.key
}).then(res => {
uni.showToast({
icon: 'none',
title: '修改成功'
})
this.joinTypeMap = this.joinTypeMap.map(item => {
if (item.key == e.key) {
item.disabled = true
} else {
item.disabled = false
}
return item
})
this.joinType = e.name
this.$nextTick(() => {
this.$refs.userList.initGroupInfo()
this.initData()
})
this.showActions = false
}).catch(err => {
console.log(err);
uni.showToast({
icon: 'error',
title: err.message
})
})
},
onClean() {
uni.showModal({
title: '清空聊天记录',
content: '清空聊天记录,只会清空本地的记录,其他成员不会变化',
success: (res) => {
if (res.confirm) {
RongIMLib.deleteMessages(3, this.targetId, () => {
uni.showToast({
icon: 'none',
title: '清空成功'
})
uni.$emit('cleanGroupMessage')
})
}
}
})
},
onDismiss() {
uni.showModal({
title: '解散群聊',
success: (res) => {
if (res.confirm) {
dismissGroup(this.targetId).then(res => {
console.log('解散群', res);
uni.showToast({
icon: 'none',
title: '解散成功'
})
uni.switchTab({
url: '/pages/im/index'
})
})
}
}
})
},
onQuite() {
uni.showModal({
title: '退出群聊',
success: (res) => {
if (res.confirm) {
quitGroup(this.targetId).then(res => {
uni.showToast({
icon: 'none',
title: '退出群聊成功'
})
// 移除指定的会话
RongIMLib.removeConversation(this.conversationType, this.targetId)
uni.switchTab({
url: '/pages/im/index'
})
}).catch(err => {
console.log(err);
})
}
}
})
}
}
}
</script>
<style lang="scss" scoped>
.container {
min-height: 100vh;
background: $window-color;
}
.cells {
margin-top: $padding;
background-color: white;
.announcement-label {
font-size: $title-size-m + 2;
padding-top: 10rpx;
color: $text-gray-m;
overflow: hidden;
width: 620rpx;
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
}
}
.members {
background-color: white;
padding-bottom: 40rpx;
}
.actions {
margin-top: $padding;
text-align: center;
.action {
padding: $padding;
color: $text-price;
justify-content: center;
}
}
.u-border-bottom {
border-bottom: solid 1rpx #f9f9f9 !important;
}
</style>

View File

@@ -1,278 +0,0 @@
<template>
<view class="invite">
<view class="search u-border-bottom">
<u--input class="search-input" placeholder="搜索好友" border="none" prefixIcon="search" v-model="searchTxt"
disabledColor="#Fff" prefixIconStyle="font-size: 22px;color: #909399" @change="onSearch" />
</view>
<block v-if="friends.length > 0">
<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;" />
<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"
style="margin-right: 20rpx;" :disabled="canSelect(friendItem.targetId)"
:checked="canSelect(friendItem.targetId)" />
<u-avatar class="avatar-img" size="40" shape="square"
:src="contact(friendItem.targetId).portraitUrl" />
<view class="info">
<view class="name">{{ contact(friendItem.targetId).name }}</view>
</view>
</view>
</u-index-item>
</u-checkbox-group>
</u-index-list>
<view class="bottom">
<span class="onInvite" @click="onInvite">完成<span>{{`(${checkboxValue.length})` || ''}}</span></span>
</view>
</block>
<view class="no-lists" v-else>
<u-image class="cover" radius="4" width="400rpx" height="400rpx"
:src="searchTxt=== '' ? require('@/static/imgs/no-friend.png') :require('@/static/imgs/no-search.png')"
:lazy-load="true" />
<span>{{searchTxt=== ''?'暂无好友列表~':'暂无搜索内容~'}}</span>
</view>
</view>
</template>
<script>
import {
getFriendsLetter,
inviteGroupUser,
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: '',
targetId: '',
indexs: [],
orignalIndexs: [],
friends: [],
orignalFriends: [],
checkboxValue: [],
selectValue: []
};
},
onLoad(e) {
this.targetId = e.targetId
this.getFriendList()
},
methods: {
onSearch() {
if (this.searchTxt) {
this.friends = this.orignalFriends.map((list, index) => {
const resList = list.filter(item => {
return item.name.indexOf(this.searchTxt) >= 0
})
return resList
})
this.indexs = this.orignalIndexs.map((t, i) => {
if (this.friends[i].length > 0) {
return t
}
})
} else {
this.friends = this.orignalFriends
this.indexs = this.orignalIndexs
}
},
canSelect(targetId) {
return utils.inArray(targetId, this.selectValue)
},
getFriendList() {
getFriendsLetter().then(res => {
this.indexs = res.indexList
this.friends = res.itemArr
this.orignalFriends = res.itemArr
this.orignalIndexs = res.indexList
})
getGroupUsers(this.targetId).then(res => {
res.map(res => {
console.log(res)
this.checkboxValue.push(String(res.targetId))
this.selectValue.push(String(res.targetId))
})
})
},
// 点击名字新增或删除选中数据
addContact(targetId) {
const index = this.checkboxValue.findIndex(item => item == targetId)
if (utils.inArray(targetId, this.selectValue)) {
} else {
if (index === -1) {
this.checkboxValue.push(targetId)
} else {
this.checkboxValue.splice(index, 1)
}
}
},
onInvite() {
console.log(this.checkboxValue, 'userIds.....')
console.log(this.selectValue, 'userIds.....')
let userIds = []
this.checkboxValue.filter(item => {
if (!utils.inArray(item, this.selectValue)) {
userIds.push(item)
}
})
// console.log(userIds)
inviteGroupUser(this.targetId, this.checkboxValue, userIds).then(res => {
uni.navigateBack({
delta: 1,
animationType: 'pop-out',
animationDuration: 200
});
uni.$emit('groupInvitedUser')
}).catch(err => {
uni.showToast({
icon: 'none',
title: err.message
})
})
}
}
};
</script>
<style lang="scss" scoped>
// 页面空
.pages-null {
height: 70vh;
}
// 好友列表
.friend-flex {
position: relative;
padding: 0 $padding 0 $padding;
display: flex;
flex-direction: row;
align-items: center;
box-sizing: border-box;
.avatar-img {
box-shadow: 0 0 20rpx rgba($color: $main-color, $alpha: 0.2);
}
.info {
flex: 1;
margin-left: $padding;
border-bottom: solid 1rpx #f9f9f9;
height: 120rpx;
line-height: 120rpx;
.name {
font-size: $title-size;
color: #454545 !important;
@extend .nowrap;
}
.address {
color: $text-gray-m;
font-size: $title-size-m - 3;
padding-top: 10rpx;
word-break: break-word;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 600rpx;
}
}
}
.list-cell {
display: flex;
box-sizing: border-box;
width: 100%;
padding: 10px 24rpx;
overflow: hidden;
color: #323233;
font-size: 14px;
line-height: 24px;
background-color: #fff;
}
.invite {
position: relative;
padding: 100rpx 0;
box-sizing: border-box;
z-index: 0;
.bottom {
position: fixed;
bottom: 0;
width: 100%;
height: 120rpx;
background-color: $window-color;
z-index: 100;
color: #fff;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-end;
box-sizing: border-box;
padding-right: 30rpx;
padding-bottom: 10rpx;
.onInvite {
background-color: $main-color;
font-size: $title-size;
display: inline-block;
padding: 10rpx 30rpx;
border-radius: 10rpx;
span {
font-size: $title-size - 2;
}
}
}
.search {
background-color: #fff;
padding: 30rpx;
position: fixed;
width: 100%;
box-sizing: border-box;
top: 0;
z-index: 100;
.search-input {
padding: 10rpx $padding;
width: 100%;
}
.searchTxt {}
}
}
.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

@@ -1,175 +0,0 @@
<!-- 群聊邀请确认列表页面 -->
<template>
<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"
: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'">
<view class="nickname">{{ JSON.parse(item.content.extra).name }} 申请加入群聊</view>
<view> 申请原因{{ item.content.message }}</view>
</view>
<view style="flex:1;" v-if="item.content.operation == 'GroupInvite'">
<view class="nickname">
<text>{{ contact(item.content.sourceUserId).name }}</text>想邀请<span>{{ JSON.parse(item.content.extra).name }}</span>加入群聊
</view>
</view>
<view class="sure" @click="sure(item.content.targetUserId,item.messageId)"> 通过 </view>
</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" />
<span>暂无群聊申请数据</span>
</view>
</view>
</template>
<script>
import {
getGroupMakeSure,
getGroupMakeSureAllow,
groupMakeSure
} 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: '',
pendings: [],
};
},
computed: {
contact() {
return function(targetId) {
return this.$store.getters.contactInfo(targetId)
}
}
},
onLoad(e) {
this.targetId = e.targetId
this.getList()
},
methods: {
getList() {
im.getGroupPendinglist(this.targetId, (result) => {
console.log(result)
this.pendings = result
})
},
sure(userId, latestMessageId) {
groupMakeSure(this.targetId, userId).then(res => {
// 清除聊天列表
RongIMLib.deleteMessagesByIds([latestMessageId], ({
code
}) => {
console.log('code', code)
if (code == 0) {
uni.showToast({
title: ` 通过 `,
icon: 'none',
mask: true,
duration: 2000
})
this.getList()
uni.$emit('groupInvitedUser')
}
})
}).catch(err => {
// uni.showToast({
// title: err.message,
// icon: 'none',
// mask: true,
// duration: 2000
// })
RongIMLib.deleteMessagesByIds([latestMessageId], ({
code
}) => {
console.log('code', code)
if (code == 0) {
uni.showToast({
title: err.message,
icon: 'none',
mask: true,
duration: 2000
})
this.getList()
uni.$emit('groupInvitedUser')
}
})
})
// 直接调用通过或拒绝的接口
}
}
};
</script>
<style lang="scss" scoped>
.reviewed {
.reviewed-item {
margin: $padding - 10;
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: flex-start;
box-sizing: border-box;
border-bottom: solid 1rpx #f9f9f9;
font-size: $title-size-m;
padding-bottom: 20rpx;
color: $text-gray-m;
.avatar {
background-color: $main-color;
border-radius: 6rpx;
margin-right: 20rpx;
}
.nickname {
font-size: $title-size;
color: $text-color;
padding-bottom: 6rpx;
span {
color: $text-color;
font-size: $title-size-m +1;
padding-top: 20rpx;
}
}
.sure {
background-color: $main-color;
color: #Fff;
text-align: center;
font-size: $title-size-m;
padding: 6rpx 20rpx;
border-radius: 10rpx;
margin-left: 10rpx;
}
}
}
.no-lists {
padding-top: $padding * 5;
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

@@ -1,29 +0,0 @@
<template>
<group-user-list :targetId="targetId" />
</template>
<script>
import groupUserList from '../components/groupUserList'
import onGroupDismiss from '../mixins/onGroupDismiss.js'
export default {
mixins: [
onGroupDismiss
],
components: {
groupUserList
},
data() {
return {
targetId: '',
}
},
onLoad(e) {
this.targetId = e.targetId
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -1,217 +0,0 @@
<template>
<view class="contents">
<view class="ios-top"></view>
<!-- header -->
<view class="custom-header">
<view class="header-flex">
<view class="tabs">
<view class="item active">聊聊</view>
</view>
<view class="btns">
<view class="item" @click="scanQrCode">
<uni-icons color="#555" type="scan" size="22" />
</view>
<view class="item" @click="toFriendList">
<u-badge absolute max="99" :offset="[-5, -5]" :value="hasNewFriends" />
<uni-icons color="#555" custom-prefix="iconfont" type="icon-tuandui" size="22" />
</view>
</view>
</view>
</view>
<!-- content -->
<view v-if="$store.state.token !== ''">
<connection-status :connection="connection" />
<conversation-list @refresh="getConversationList()" :conversations="conversations" />
</view>
<!-- 未登录 -->
<view v-else class="vertical null-list">
<u-empty icon="http://cdn.uviewui.com/uview/empty/permission.png" textColor="#999" text="登录后开启聊天吧~">
<template>
<view class="null-list-btn" @click="toLogin">去登录</view>
</template>
</u-empty>
</view>
</view>
</template>
<script>
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
import im from '@/utils/im/index.js'
import userAuth from '@/public/userAuth'
import conversationList from './components/conversationList'
import connectionStatus from './components/connectionStatus'
export default {
data() {
return {
conversations: [], // 会话列表
connection: 0,
hasNewFriends: 0,
perPage: 200
}
},
components: {
conversationList,
connectionStatus
},
onLoad() {
// 监听新的好友申请
uni.$on('onNewContactConversation', () => {
console.log('更新好友申请数量');
// 更新好友申请数量
this.checkNewFriendPending()
})
},
onShow() {
// 好友申请数量
this.checkNewFriendPending()
if (this.$store.state.token !== '') {
this.getConversationList()
}
// 监听新消息
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() {
im.getPendingList((pendings) => {
this.hasNewFriends = pendings.length
})
},
// 检查登录
toLogin() {
if (this.$store.state.token === '') {
const Auth = new userAuth()
Auth.Login()
return false
}
return true
},
// 获取会话列表,最新的一千条
getConversationList() {
RongIMLib.getConversationList([1, 3], this.perPage, 0, ({
code,
conversations
}) => {
if (code === 0) {
this.conversations = conversations
}
})
},
// 调起扫码
scanQrCode() {
uni.scanCode({
success: (res) => {
if (res.scanType == 'QR_CODE') {
if (res.result.substr(0, 10) == 'ADDFRIEND|') {
uni.navigateTo({
url: '/pages/im/friends/info?targetId=' + res.result.substr(10)
})
} else if (res.result.substr(0, 10) == 'JOINGROUP|') {
uni.navigateTo({
url: '/pages/im/group/apply?targetId=' + res.result.substr(10)
})
} else {
uni.showToast({
title: '暂不支持的二维码'
})
}
}
}
})
},
toFriendList() {
uni.navigateTo({
url: '/pages/im/friends/index'
})
}
}
}
</script>
<style lang="scss" scoped>
// contents
.contents {
background-color: #fff;
min-height: 100vh;
padding-top: 90rpx + 6rpx;
box-sizing: border-box;
.custom-header {
@extend .ios-top;
background: $window-color;
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 9999;
.header-flex {
padding: 20rpx $padding;
display: flex;
justify-content: space-between;
height: 60rpx;
line-height: 60rpx;
.tabs {
.item {
position: relative;
display: inline-block;
font-size: $title-size-lg;
color: $text-gray;
padding: 0 ($padding - 10);
border-radius: 30rpx;
&.active {
background: rgba($color: $main-color, $alpha: .1);
color: $main-color;
font-weight: bold;
}
}
}
.btns {
.item {
position: relative;
display: inline-block;
margin-left: $margin;
}
}
}
}
.null-list {
height: 100vh;
text-align: center;
&-btn {
margin-top: $margin * 2;
line-height: 70rpx;
color: $main-color;
border: solid 2rpx $main-color;
padding: 0 ($padding*3);
font-size: $title-size-m;
border-radius: 35rpx;
box-sizing: border-box;
}
}
}
.u-border-bottom {
border-bottom: solid 1rpx #f9f9f9 !important;
}
</style>

View File

@@ -1,17 +0,0 @@
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
}
}
}

View File

@@ -1,134 +0,0 @@
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: '消息撤回成功'
})
IMLib.getMessage(msg.messageId, res => {
uni.$emit('onRecallMessage_' + msg.targetId, res.message)
})
} 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

@@ -1,34 +0,0 @@
// 监听群解散的消息,直接跳转到会话列表页面
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

@@ -1,338 +0,0 @@
<template>
<view class="call">
<view class="video">
<RongCloud-Call-RCUniCallView ref="bigVideoView" :style="bigVideoStyle" class="bigVideoView">
</RongCloud-Call-RCUniCallView>
<movable-area class="movableArea" :style="movableAreaStyle">
<movable-view class="movableView" direction="all" :x="50" :y="50" v-if="mediaType == 1 && connected">
<RongCloud-Call-RCUniCallView ref="smallVideoView" class="smallVideoView" @click="changeMine">
</RongCloud-Call-RCUniCallView>
</movable-view>
</movable-area>
</view>
<view class="status" v-if="!connected">
<view class="remote">
<u-avatar :src="contact(targetId).portraitUrl" shape="square" :size="avatarSize" bgColor="#fff" />
<view><text class="nickname">{{ contact(targetId).name }}</text></view>
<view v-if="remoteRinging"><text class="mediaType">等待对方接听</text></view>
<view v-if="connected"><text class="mediaType">已接通</text></view>
</view>
</view>
<view class="buttons">
<view class="btn" v-if="connected" @click="changeMicrophone">
<view class="icon">
<u-icon name="mic-off" color="#ffffff" size="30" v-if="micOff" />
<u-icon name="mic" color="#ffffff" size="30" v-else />
</view>
<text class="text">麦克风</text>
</view>
<view class="btn" @click="hangup">
<view class="icon hangup">
<u-icon name="close" color="#ffffff" size="25" />
</view>
<text class="text">挂断</text>
</view>
<view class="btn" v-if="!connected && this.isCall == false" @click="accept">
<view class="icon">
<u-icon name="checkmark" color="#ffffff" size="30" />
</view>
<text class="text">接听</text>
</view>
<view class="btn" v-if="connected" @click="changeSpeaker">
<view class="icon">
<u-icon name="volume-off-fill" color="#ffffff" size="27" v-if="volumeOff" />
<u-icon name="volume-fill" color="#ffffff" size="27" v-else />
</view>
<text class="text">扬声器</text>
</view>
</view>
</view>
</template>
<script>
import * as CallLib from '@/uni_modules/RongCloud-CallWrapper/lib/index'
import * as IMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
import utils from '@/utils/index.js'
export default {
data() {
return {
targetId: '',
mediaType: 0, // 0 语音 1 视频
connected: false,
micStatus: false,
speStatus: false,
remoteRinging: false,
ring: null,
isCall: false,
avatarSize: 96,
bigVideoStyle: {},
movableAreaStyle: {},
// 关闭麦克风
micOff: false,
// 关闭扬声器
volumeOff: false,
// 通话时长
duration: 0,
interval: null
}
},
onLoad(e) {
this.avatarSize = utils.rpx2px(200)
this.targetId = e.targetId
this.mediaType = e.mediaType
this.isCall = Boolean(e.isCall)
// 进入页面开启外呼
if (this.isCall) {
CallLib.startSingleCall(this.targetId, this.mediaType, '');
if (this.mediaType == 1) {
const session = CallLib.getCurrentCallSession()
setTimeout(() => {
CallLib.setVideoView(session.mine.userId, this.$refs.bigVideoView.ref, 0, false)
}, 200)
}
}
// 响铃
this.startRing()
// 监听通话链接状态
uni.$once('onCallConnected', this.onCallConnected)
uni.$once('onCallDisconnected', this.hangup)
uni.$once('onRemoteUserRinging', () => {
this.remoteRinging = true
})
uni.$once('onRemoteUserJoined', () => {
this.remoteRinging = false
})
this.bigVideoStyle = {
width: this.windowWidth + 'px',
height: this.windowHeight + 'px',
}
this.movableAreaStyle = {
width: this.windowWidth + 'px',
height: this.windowHeight + 'px',
}
},
beforeDestroy() {
},
computed: {
windowWidth() {
return uni.getSystemInfoSync().windowWidth
},
windowHeight() {
return uni.getSystemInfoSync().windowHeight
},
contact() {
return function(targetId) {
return this.$store.getters.contactInfo(targetId)
}
}
},
methods: {
afterHangup() {
clearInterval(this.interval)
const targetId = this.targetId
const sentStatus = 30
const messageContent = {
objectName: 'RC:InfoNtf',
userInfo: this.$store.getters.sender,
message: JSON.stringify({
mediaType: this.mediaType,
connected: this.connected,
duration: this.duration
})
}
const sentTime = 0
if (this.isCall) {
IMLib.insertOutgoingMessage(1, targetId, sentStatus, messageContent, sentTime)
} else {
IMLib.insertIncomingMessage(1, targetId, targetId, sentStatus, messageContent, sentTime)
}
uni.$emit('onReceiveMessage_' + this.targetId, {
targetId: this.targetId
})
},
changeMicrophone() {
this.micOff = !this.micOff
CallLib.enableMicrophone(this.micStatus)
this.micStatus = !this.micStatus
},
changeSpeaker() {
this.volumeOff = !this.volumeOff
CallLib.enableSpeaker(this.speStatus)
this.speStatus = !this.speStatus
},
accept() {
CallLib.accept()
},
onCallConnected() {
// 关掉铃声
this.stopRing()
// 设置链接状态
this.connected = true
// 视频通话,才开摄像头
if (this.mediaType == 1) {
const session = CallLib.getCurrentCallSession()
setTimeout(() => {
CallLib.setVideoView(session.targetId, this.$refs.bigVideoView.ref, 0, false)
CallLib.setVideoView(session.mine.userId, this.$refs.smallVideoView.ref, 0, true)
}, 200)
}
this.interval = setInterval(() => {
this.duration++
}, 1000)
},
// 切换主屏显示人
changeMine() {
// if (this.isCall) {
// const session = CallLib.getCurrentCallSession()
// setTimeout(() => {
// CallLib.setVideoView(session.targetId, this.$refs.bigVideoView.ref, 0, false)
// CallLib.setVideoView(session.mine.userId, this.$refs.smallVideoView.ref, 0, true)
// }, 200)
// } else {
// const session = CallLib.getCurrentCallSession()
// setTimeout(() => {
// CallLib.setVideoView(session.targetId, this.$refs.smallVideoView.ref, 0, true)
// CallLib.setVideoView(session.mine.userId, this.$refs.bigVideoView.ref, 0, false)
// }, 200)
// }
// this.isCall = !this.isCall
},
hangup() {
CallLib.hangup()
this.afterHangup()
this.stopRing()
setTimeout(() => {
this.downRing()
uni.navigateBack()
}, 200);
},
toHome() {
uni.switchTab({
url: '/pages/im/index'
})
},
startRing() {
const ring = uni.createInnerAudioContext()
this.ring = ring
ring.autoplay = true
ring.loop = true
ring.src = '/static/im/sounds/call-ring.mp3'
ring.onEnded(() => {
ring.destroy()
})
},
stopRing() {
this.ring.stop()
},
downRing() {
const ding = uni.createInnerAudioContext()
ding.autoplay = true
ding.src = '/static/im/sounds/call-down.mp3'
ding.onEnded(() => {
ding.destroy()
})
}
}
}
</script>
<style scoped lang="scss">
.call {
display: flex;
flex: 1;
flex-direction: column;
position: relative;
.video {
.movableArea {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
.movableView {
width: 180rpx;
height: 320rpx;
position: relative;
.smallVideoView {
width: 180rpx;
height: 320rpx;
background-color: #666;
}
}
}
.bigVideoView {
background-color: #666;
}
}
.status {
flex: 1;
width: 750rpx;
position: fixed;
bottom: 0;
top: 0;
.remote {
flex: 1;
width: 750rpx;
display: flex;
align-items: center;
top: 300rpx;
.mediaType {
font-size: 32rpx;
color: #aaa;
}
.nickname {
margin: 30rpx;
font-size: 44rpx;
color: #ffffff;
}
}
}
.buttons {
position: fixed;
bottom: 100rpx;
width: 750rpx;
display: flex;
flex-direction: row;
justify-content: space-around;
}
.btn {
align-items: center;
.icon {
background: $main-color;
width: 132rpx;
height: 132rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
&.hangup {
background-color: $text-price;
}
}
.text {
margin-top: 16rpx;
color: #FFFFFF;
font-size: 32rpx;
}
}
}
</style>

View File

@@ -1,259 +0,0 @@
<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" @messageAction="messageAction" />
</view>
</view>
</view>
</view>
</template>
<script>
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
import im from '@/utils/im/index.js'
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
},
data() {
return {
targetId: '',
messages: [],
conversationType: 1,
userInfo: {
name: '',
userId: '',
portraitUrl: ''
}
}
},
computed: {
latestMessage() {
if (this.messages.length) {
return this.messages[0]
} else {
return {
sentTime: 0
}
}
}
},
onLoad(e) {
this.targetId = e.targetId
this.userInfo = this.$store.getters.contactInfo(this.targetId)
uni.setNavigationBarTitle({
title: this.contact(this.targetId).name
})
// 获取消息列表
this.getMessageList()
// 监听新消息
uni.$on('onReceiveMessage_' + this.targetId, (message) => {
this.getNewMessage()
})
// 监听消息已读状态
uni.$on('onReadReceiptReceived', (data) => {
if (data.targetId == this.targetId) {
this.messages = this.messages.map((item) => {
if (item.messageDirection == 1 && item.sentStatus == 30 && item.receivedTime <
data.messageTime + 1000) {
item.sentStatus = 50
}
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.$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')
},
methods: {
getNewMessage() {
im.getMessageList(
this.conversationType,
this.targetId,
this.latestMessage.sentTime || 0,
1,
false,
(messages) => {
this.messages.unshift(...messages)
this.scrollBottom()
})
},
// 获取消息列表
getMessageList() {
im.getMessageList(
this.conversationType,
this.targetId,
0,
20,
true,
(messages) => {
this.messages = messages
this.scrollBottom()
})
},
// 滚动到底部
scrollBottom(type) {
if (this.latestMessage) {
// 清理当前会话,未读消息数量
RongIMLib.clearMessagesUnreadStatus(this.conversationType, this.targetId, this.latestMessage
.sentTime)
// // 发送消息已读状态给对方
RongIMLib.sendReadReceiptMessage(this.conversationType, this.targetId, this.latestMessage.sentTime)
// 更新badge提醒数量
im.setNotifyBadge()
}
}
}
}
</script>
<style scoped lang="scss">
/* 窗口 */
.chat {
background: $window-color;
height: 100vh;
display: flex;
flex-direction: column-reverse;
.body {
overflow: scroll;
flex: 1;
height: 0;
display: flex;
flex-direction: column-reverse;
.scroll {
display: flex;
flex-direction: column-reverse;
justify-content: flex-end;
.cell {
padding: 10rpx 20rpx;
.time {
text-align: center;
font-size: 24rpx;
color: #666;
margin-bottom: 10rpx;
}
.cell-item {
display: flex;
width: 710rpx;
justify-content: flex-start;
&.left {
flex-direction: row;
}
&.right {
flex-direction: row-reverse;
.state {
text-align: right;
}
}
.msg {
margin: 0 20rpx;
}
}
.cell-footer {
height: 20rpx;
}
}
}
}
}
/* 遮罩 */
.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

@@ -14,7 +14,7 @@
<!-- 头像 --> <!-- 头像 -->
<view class="user" @click="$Router.back()"> <view class="user" @click="$Router.back()">
<u-icon name="arrow-left" color="#525252" size="22" class="downIcon" :bold="true" /> <u-icon name="arrow-left" color="#525252" size="22" class="downIcon" :bold="true" />
<!-- <u-image class="avatar" width="90rpx" height="90rpx" :src="user.avatar ? user.avatar : require('../../static/imgs/avatar.png')" :lazy-load="true" shape="circle" /> <!-- <u-image class="avatar" width="90rpx" height="90rpx" :src="user.avatar ? user.avatar : require('@/static/imgs/avatar.png')" :lazy-load="true" shape="circle" />
<view class="nickname">{{user.nickname}}</view> --> <view class="nickname">{{user.nickname}}</view> -->
<!-- <u-icon name="arrow-down-fill" color="#525252" size="10" class="downIcon" :bold="true" space="1"/> --> <!-- <u-icon name="arrow-down-fill" color="#525252" size="10" class="downIcon" :bold="true" space="1"/> -->
</view> </view>
@@ -42,7 +42,6 @@
<!-- 体重管理模块 --> <!-- 体重管理模块 -->
<view class="weight-manage"> <view class="weight-manage">
<!-- 体重管理 --> <!-- 体重管理 -->
<!-- @click="$Router.push({name:'EssentialInfo'})" -->
<view class="manage">体重管理</view> <view class="manage">体重管理</view>
<!-- 单位:公斤 --> <!-- 单位:公斤 -->
<u-icon class="eye" name="eye" color="#fff" size="14" :bold="true" label="单位 : 公斤" labelPos="left" labelSize="12" labelColor="#fff" space="6" /> <u-icon class="eye" name="eye" color="#fff" size="14" :bold="true" label="单位 : 公斤" labelPos="left" labelSize="12" labelColor="#fff" space="6" />
@@ -81,13 +80,13 @@
</view> </view>
<!-- 健康测评 --> <!-- 健康测评 -->
<u-image <u-image
:src="banner.cover || require('../../static/imgs/health1.png')" :src="banner.cover || require('@/static/imgs/health1.png')"
class="eval-img" class="eval-img"
@click="$Router.push({ name: 'EvaluationList' })" @click="$Router.push({ name: 'EvaluationList' })"
:lazy-load="true" :lazy-load="true"
radius="10rpx" radius="10rpx"
mode="widthFix"
width="100%" width="100%"
height="300rpx"
/> />
<!-- 健康记录 --> <!-- 健康记录 -->
<view class="title">健康记录</view> <view class="title">健康记录</view>
@@ -101,7 +100,7 @@
千卡 千卡
</view> </view>
</view> </view>
<u-image :src="require('../../static/imgs/eat.png')" :lazy-load="true" radius="10rpx" mode="widthFix" width="140rpx" /> <u-image class="h-icon" :src="require('@/static/imgs/eat.png')" :lazy-load="true" radius="10rpx" mode="widthFix" width="150rpx" height="150rpx"/>
</view> </view>
<view class="health-2"> <view class="health-2">
<view class="health" @click="$Router.push({ name: 'Drink' })"> <view class="health" @click="$Router.push({ name: 'Drink' })">
@@ -115,7 +114,7 @@
毫升 毫升
</view> </view>
</view> </view>
<u-image :src="require('../../static/imgs/drink.png')" :lazy-load="true" radius="10rpx" mode="widthFix" width="110rpx" class="h-icon" /> <u-image :src="require('@/static/imgs/drink.png')" :lazy-load="true" radius="10rpx" mode="widthFix" width="120rpx" class="h-icon" height="120rpx" />
</view> </view>
<view class="health" @click="$Router.push({ name: 'Weight' })"> <view class="health" @click="$Router.push({ name: 'Weight' })">
<view> <view>
@@ -127,18 +126,18 @@
公斤 公斤
</view> </view>
</view> </view>
<u-image :src="require('../../static/imgs/weight.png')" :lazy-load="true" radius="10rpx" mode="widthFix" width="140rpx" class="h-icon" /> <u-image :src="require('@/static/imgs/weight.png')" :lazy-load="true" radius="10rpx" mode="widthFix" width="140rpx" height="140rpx" class="h-icon" />
</view> </view>
</view> </view>
<!-- 营养管理 --> <!-- 营养管理 -->
<view class="title">营养管理</view> <view class="title">营养管理</view>
<view class="nutrition"> <view class="nutrition">
<view class="--item" @click="$Router.push({ name: 'VipFoods' })"> <view class="--item" @click="$Router.push({ name: 'VipFoods' })">
<u-icon :name="require('../../static/icon/vip.png')" size="20" :bold="true" label="会员专享食谱" labelPos="right" labelSize="16" labelColor="#525252" space="10" /> <u-icon :name="require('@/static/icon/vip.png')" size="20" :bold="true" label="会员专享食谱" labelPos="right" labelSize="16" labelColor="#525252" space="10" />
<u-icon name="arrow-right" color="#999" /> <u-icon name="arrow-right" color="#999" />
</view> </view>
<view class="--item mt20" @click="$Router.push({ name: 'topicIndex' })"> <view class="--item mt20" @click="$Router.push({ name: 'topicIndex' })">
<u-icon :name="require('../../static/icon/helper.png')" size="20" :bold="true" label="营养小助手" labelPos="right" labelSize="16" labelColor="#525252" space="10" /> <u-icon :name="require('@/static/icon/helper.png')" size="20" :bold="true" label="营养小助手" labelPos="right" labelSize="16" labelColor="#525252" space="10" />
<u-icon name="arrow-right" color="#999" /> <u-icon name="arrow-right" color="#999" />
</view> </view>
</view> </view>
@@ -149,7 +148,7 @@
<view class="search" > <view class="search" >
<!-- 头像 --> <!-- 头像 -->
<view class="user" @click="$Router.back()"> <view class="user" @click="$Router.back()">
<!-- <u-image class="avatar" width="90rpx" height="90rpx" :src="require('../../static/imgs/avatar.png')" :lazy-load="true" shape="circle" /> <!-- <u-image class="avatar" width="90rpx" height="90rpx" :src="require('@/static/imgs/avatar.png')" :lazy-load="true" shape="circle" />
<u-icon name="arrow-down-fill" color="#525252" size="10" class="downIcon" :bold="true" space="1" /> --> <u-icon name="arrow-down-fill" color="#525252" size="10" class="downIcon" :bold="true" space="1" /> -->
<u-icon name="arrow-left" color="#525252" size="22" class="downIcon" :bold="true"/> <u-icon name="arrow-left" color="#525252" size="22" class="downIcon" :bold="true"/>
</view> </view>
@@ -201,7 +200,7 @@
</view> </view>
</view> </view>
<!-- 健康测评 --> <!-- 健康测评 -->
<u-image :src="banner.cover || require('../../static/imgs/health1.png')" class="eval-img" @click="Login" :lazy-load="true" radius="10rpx" mode="widthFix" width="100%" /> <u-image :src="banner.cover || require('@/static/imgs/health1.png')" class="eval-img" @click="Login" :lazy-load="true" radius="10rpx" mode="widthFix" width="100%" />
<!-- 健康记录 --> <!-- 健康记录 -->
<view class="title">健康记录</view> <view class="title">健康记录</view>
<view class="health" @click="Login"> <view class="health" @click="Login">
@@ -210,7 +209,7 @@
<!-- <view class="h-date">--</view> --> <!-- <view class="h-date">--</view> -->
<view class="h-eat"><span>--</span></view> <view class="h-eat"><span>--</span></view>
</view> </view>
<u-image :src="require('../../static/imgs/eat.png')" :lazy-load="true" radius="10rpx" mode="widthFix" width="140rpx" /> <u-image :src="require('@/static/imgs/eat.png')" :lazy-load="true" radius="10rpx" mode="widthFix" width="140rpx" />
</view> </view>
<view class="health-2"> <view class="health-2">
<view class="health" @click="Login"> <view class="health" @click="Login">
@@ -219,7 +218,7 @@
<!-- <view class="h-date">--</view> --> <!-- <view class="h-date">--</view> -->
<view class="h-eat"><span>--</span></view> <view class="h-eat"><span>--</span></view>
</view> </view>
<u-image :src="require('../../static/imgs/drink.png')" :lazy-load="true" radius="10rpx" mode="widthFix" width="110rpx" class="h-icon" /> <u-image :src="require('@/static/imgs/drink.png')" :lazy-load="true" radius="10rpx" mode="widthFix" width="110rpx" class="h-icon" />
</view> </view>
<view class="health" @click="Login"> <view class="health" @click="Login">
<view> <view>
@@ -227,18 +226,18 @@
<!-- <view class="h-date">--</view> --> <!-- <view class="h-date">--</view> -->
<view class="h-eat"><span>--</span></view> <view class="h-eat"><span>--</span></view>
</view> </view>
<u-image :src="require('../../static/imgs/weight.png')" :lazy-load="true" radius="10rpx" mode="widthFix" width="140rpx" class="h-icon" /> <u-image :src="require('@/static/imgs/weight.png')" :lazy-load="true" radius="10rpx" mode="widthFix" width="140rpx" class="h-icon" />
</view> </view>
</view> </view>
<!-- 营养管理 --> <!-- 营养管理 -->
<view class="title">营养管理</view> <view class="title">营养管理</view>
<view class="nutrition"> <view class="nutrition">
<view class="--item" @click="Login"> <view class="--item" @click="Login">
<u-icon :name="require('../../static/icon/vip.png')" size="24" :bold="true" label="会员专享食谱" labelPos="right" labelSize="17" labelColor="#525252" space="10" /> <u-icon :name="require('@/static/icon/vip.png')" size="24" :bold="true" label="会员专享食谱" labelPos="right" labelSize="17" labelColor="#525252" space="10" />
<u-icon name="arrow-right" color="#999" /> <u-icon name="arrow-right" color="#999" />
</view> </view>
<view class="--item mt20" @click="Login"> <view class="--item mt20" @click="Login">
<u-icon :name="require('../../static/icon/helper.png')" size="24" :bold="true" label="营养小助手" labelPos="right" labelSize="17" labelColor="#525252" space="10" /> <u-icon :name="require('@/static/icon/helper.png')" size="24" :bold="true" label="营养小助手" labelPos="right" labelSize="17" labelColor="#525252" space="10" />
<u-icon name="arrow-right" color="#999" /> <u-icon name="arrow-right" color="#999" />
</view> </view>
</view> </view>
@@ -249,7 +248,7 @@
<view class="search" > <view class="search" >
<!-- 头像 --> <!-- 头像 -->
<view class="user" @click='$Router.back()'> <view class="user" @click='$Router.back()'>
<!-- <u-image class="avatar" width="90rpx" height="90rpx" :src="require('../../static/imgs/avatar.png')" :lazy-load="true" shape="circle" /> <!-- <u-image class="avatar" width="90rpx" height="90rpx" :src="require('@/static/imgs/avatar.png')" :lazy-load="true" shape="circle" />
<u-icon name="arrow-down-fill" color="#525252" size="10" class="downIcon" :bold="true" space="1" /> --> <u-icon name="arrow-down-fill" color="#525252" size="10" class="downIcon" :bold="true" space="1" /> -->
<u-icon name="arrow-left" color="#525252" size="22" class="downIcon" :bold="true"/> <u-icon name="arrow-left" color="#525252" size="22" class="downIcon" :bold="true"/>
</view> </view>
@@ -302,7 +301,7 @@
</view> </view>
<!-- 健康测评 --> <!-- 健康测评 -->
<u-image <u-image
:src="banner.cover || require('../../static/imgs/health1.png')" :src="banner.cover || require('@/static/imgs/health1.png')"
class="eval-img" class="eval-img"
@click="toCreateInfo" @click="toCreateInfo"
:lazy-load="true" :lazy-load="true"
@@ -318,7 +317,7 @@
<!-- <view class="h-date">--</view> --> <!-- <view class="h-date">--</view> -->
<view class="h-eat"><span>--</span></view> <view class="h-eat"><span>--</span></view>
</view> </view>
<u-image :src="require('../../static/imgs/eat.png')" :lazy-load="true" radius="10rpx" mode="widthFix" width="140rpx" /> <u-image :src="require('@/static/imgs/eat.png')" :lazy-load="true" radius="10rpx" mode="widthFix" width="140rpx" />
</view> </view>
<view class="health-2"> <view class="health-2">
<view class="health" @click="toCreateInfo"> <view class="health" @click="toCreateInfo">
@@ -327,7 +326,7 @@
<!-- <view class="h-date">--</view> --> <!-- <view class="h-date">--</view> -->
<view class="h-eat"><span>--</span></view> <view class="h-eat"><span>--</span></view>
</view> </view>
<u-image :src="require('../../static/imgs/drink.png')" :lazy-load="true" radius="10rpx" mode="widthFix" width="110rpx" class="h-icon" /> <u-image :src="require('@/static/imgs/drink.png')" :lazy-load="true" radius="10rpx" mode="widthFix" width="110rpx" class="h-icon" />
</view> </view>
<view class="health" @click="toCreateInfo"> <view class="health" @click="toCreateInfo">
<view> <view>
@@ -335,18 +334,18 @@
<!-- <view class="h-date">--</view> --> <!-- <view class="h-date">--</view> -->
<view class="h-eat"><span>--</span></view> <view class="h-eat"><span>--</span></view>
</view> </view>
<u-image :src="require('../../static/imgs/weight.png')" :lazy-load="true" radius="10rpx" mode="widthFix" width="140rpx" class="h-icon" /> <u-image :src="require('@/static/imgs/weight.png')" :lazy-load="true" radius="10rpx" mode="widthFix" width="140rpx" class="h-icon" />
</view> </view>
</view> </view>
<!-- 营养管理 --> <!-- 营养管理 -->
<view class="title">营养管理</view> <view class="title">营养管理</view>
<view class="nutrition"> <view class="nutrition">
<view class="--item" @click="toCreateInfo"> <view class="--item" @click="toCreateInfo">
<u-icon :name="require('../../static/icon/vip.png')" size="24" :bold="true" label="会员专享食谱" labelPos="right" labelSize="17" labelColor="#525252" space="10" /> <u-icon :name="require('@/static/icon/vip.png')" size="24" :bold="true" label="会员专享食谱" labelPos="right" labelSize="17" labelColor="#525252" space="10" />
<u-icon name="arrow-right" color="#999" /> <u-icon name="arrow-right" color="#999" />
</view> </view>
<view class="--item mt20" @click="toCreateInfo"> <view class="--item mt20" @click="toCreateInfo">
<u-icon :name="require('../../static/icon/helper.png')" size="24" :bold="true" label="营养小助手" labelPos="right" labelSize="17" labelColor="#525252" space="10" /> <u-icon :name="require('@/static/icon/helper.png')" size="24" :bold="true" label="营养小助手" labelPos="right" labelSize="17" labelColor="#525252" space="10" />
<u-icon name="arrow-right" color="#999" /> <u-icon name="arrow-right" color="#999" />
</view> </view>
</view> </view>
@@ -498,7 +497,7 @@ export default {
// 体重管理 // 体重管理
.weight-manage { .weight-manage {
height: 288rpx; height: 288rpx;
background-image: url(../../static/imgs/banner-bg.png); background-image: url(@/static/imgs/banner-bg.png);
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: cover; background-size: cover;
border-radius: $radius + 1; border-radius: $radius + 1;

View File

@@ -98,11 +98,7 @@
</view> </view>
<!-- 功能块 --> <!-- 功能块 -->
<view class="btns-box"> <view class="btns-box">
<view class="btns-box-item" @click="onWallet"> <!-- 开通钱包方法 onWallet -->
<image class="icon" src="@/static/user/userIcon_00.png" mode="widthFix" />
ZH钱包
<uni-icons class="forward" type="forward" color="#999" />
</view>
<view class="btns-box-item" @click="onFiles"> <view class="btns-box-item" @click="onFiles">
<image class="icon" src="@/static/user/userIcon_02.png" mode="widthFix" /> <image class="icon" src="@/static/user/userIcon_02.png" mode="widthFix" />
健康档案 健康档案
@@ -133,7 +129,6 @@
info info
} from '@/apis/interfaces/user'; } from '@/apis/interfaces/user';
import userAuth from '@/public/userAuth'; import userAuth from '@/public/userAuth';
import im from '@/utils/im/index.js'
export default { export default {
data() { data() {

View File

@@ -12,10 +12,6 @@ import {
keyAuth keyAuth
} from '../apis/interfaces/auth' } from '../apis/interfaces/auth'
import store from '../store' import store from '../store'
import {
getImToken
} from '@/apis/interfaces/im.js'
import im from '@/utils/im/index.js'
class userAuth { class userAuth {
constructor() { constructor() {

BIN
static/.DS_Store vendored

Binary file not shown.

BIN
static/icon/emoji-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

795
static/im/emoji.js Normal file
View File

@@ -0,0 +1,795 @@
var EmojiFactory = {
"u1F603": {
"en": "Smiley Face",
"zh": "绗戣劯",
"tag": "\uD83D\uDE03",
"position": "-75px 0px"
},
"u1F600": {
"en": "Grinning Face",
"zh": "绗戝樆鍢<E6A886>",
"tag": "\uD83D\uDE00",
"position": "0px 0px"
},
"u1F60A": {
"en": "Smiley",
"zh": "寰瑧",
"tag": "\uD83D\uDE0A",
"position": "-1725px 0px"
},
"u263A": {
"en": "Cute",
"zh": "钀岃悓鍝<E68293>",
"tag": "\u263A",
"position": "-2950px 0px"
},
"u1F609": {
"en": "Winking Face",
"zh": "鐪ㄧ溂",
"tag": "\uD83D\uDE09",
"position": "-200px 0px"
},
"u1F60D": {
"en": "Heart Eyes",
"zh": "鑹茶糠杩<E7B3A0>",
"tag": "\uD83D\uDE0D",
"position": "-1800px 0px"
},
"u1F618": {
"en": "Blowing Kiss",
"zh": "椋炲惢",
"tag": "\uD83D\uDE18",
"position": "-375px 0px"
},
"u1F61A": {
"en": "Kiss Face",
"zh": "涔堜箞鍝<E7AE9E>",
"tag": "\uD83D\uDE1A",
"position": "-1875px 0px"
},
"u1F61C": {
"en": "Crazy Face",
"zh": "璋冪毊",
"tag": "\uD83D\uDE1C",
"position": "-1900px 0px"
},
"u1F61D": {
"en": "Tongue Out",
"zh": "鍚愯垖澶<E59E96>",
"tag": "\uD83D\uDE1D",
"position": "-1925px 0px"
},
"u1F633": {
"en": "Flushed Face",
"zh": "鑴哥孩",
"tag": "\uD83D\uDE33",
"position": "-625px 0px"
},
"u1F601": {
"en": "Grinning With Smiling",
"zh": "闇查娇鑰岀瑧",
"tag": "\uD83D\uDE01",
"position": "-25px 0px"
},
"u1F614": {
"en": "Pensive",
"zh": "娌夋€<E5A48B>",
"tag": "\uD83D\uDE14",
"position": "-300px 0px"
},
"u1F60C": {
"en": "Pleased",
"zh": "婊℃剰",
"tag": "\uD83D\uDE0C",
"position": "-1775px 0px"
},
"u1F612": {
"en": "Dissatisfied",
"zh": "涓嶆弧",
"tag": "\uD83D\uDE12",
"position": "-250px 0px"
},
"u1F61F": {
"en": "Worried Face",
"zh": "鑻︾摐鑴<E69190>",
"tag": "\uD83D\uDE1F",
"position": "-1975px 0px"
},
"u1F61E": {
"en": "Disappointed Face",
"zh": "澶辨湜",
"tag": "\uD83D\uDE1E",
"position": "-1950px 0px"
},
"u1F623": {
"en": "Helpless Face",
"zh": "鏃犲姪",
"tag": "\uD83D\uDE23",
"position": "-450px 0px"
},
"u1F62D": {
"en": "Crying",
"zh": "浼ゅ績",
"tag": "\uD83D\uDE22",
"position": "-425px 0px"
},
"u1F602": {
"en": "Laughing Tears",
"zh": "鍠滄瀬鑰屾常",
"tag": "\uD83D\uDE02",
"position": "-50px 0px"
},
"u1F622": {
"en": "Sobbing",
"zh": "鍝常",
"tag": "\uD83D\uDE2D",
"position": "-2075px 0px"
},
"u1F62A": {
"en": "Sleepy Face",
"zh": "鍥<>",
"tag": "\uD83D\uDE2A",
"position": "-2000px 0px"
},
"u1F630": {
"en": "Cold Sweat",
"zh": "鍐锋睏",
"tag": "\uD83D\uDE30",
"position": "-550px 0px"
},
"u1F605": {
"en": "Happy Sweat",
"zh": "灏村艾",
"tag": "\uD83D\uDE05",
"position": "-100px 0px"
},
"u1F613": {
"en": "Sweat",
"zh": "姹<>",
"tag": "\uD83D\uDE13",
"position": "-275px 0px"
},
"u1F62B": {
"en": "Tired Face",
"zh": "鎶撶媯",
"tag": "\uD83D\uDE2B",
"position": "-2025px 0px"
},
"u1F629": {
"en": "Weary Face",
"zh": "鐤叉儷",
"tag": "\uD83D\uDE29",
"position": "-525px 0px"
},
"u1F628": {
"en": "Fearful Face",
"zh": "鍙€<EE889B>",
"tag": "\uD83D\uDE28",
"position": "-500px 0px"
},
"u1F631": {
"en": "Scream",
"zh": "灏栧彨",
"tag": "\uD83D\uDE31",
"position": "-575px 0px"
},
"u1F621": {
"en": "Angry Face",
"zh": "鐢熸皵",
"tag": "\uD83D\uDE21",
"position": "-400px 0px"
},
"u1F624": {
"en": "Mad Face",
"zh": "鎬掓皵鍐插啿",
"tag": "\uD83D\uDE24",
"position": "-475px 0px"
},
"u1F616": {
"en": "Confounded Face",
"zh": "钂欑緸",
"tag": "\uD83D\uDE16",
"position": "-350px 0px"
},
"u1F606": {
"en": "Big Grin",
"zh": "澶х瑧",
"tag": "\uD83D\uDE06",
"position": "-125px 0px"
},
"u1F60B": {
"en": "Hungry",
"zh": "棣<>",
"tag": "\uD83D\uDE0B",
"position": "-1750px 0px"
},
"u1F637": {
"en": "Mask Face",
"zh": "鍙g僵",
"tag": "\uD83D\uDE37",
"position": "-725px 0px"
},
"u1F60E": {
"en": "Sunglasses",
"zh": "澧ㄩ暅",
"tag": "\uD83D\uDE0E",
"position": "-1825px 0px"
},
"u1F634": {
"en": "Sleeping",
"zh": "鐫$湢",
"tag": "\uD83D\uDE34",
"position": "-650px 0px"
},
"u1F635": {
"en": "Dizzy Face",
"zh": "澶存檿鐪艰姳",
"tag": "\uD83D\uDE35",
"position": "-675px 0px"
},
"u1F632": {
"en": "Shocked Face",
"zh": "闇囨儕",
"tag": "\uD83D\uDE32",
"position": "-600px 0px"
},
"u1F608": {
"en": "Purple Devil",
"zh": "灏忔伓榄<E4BC93>",
"tag": "\uD83D\uDE08",
"position": "-175px 0px"
},
"u1F47F": {
"en": "Devil",
"zh": "鎭堕瓟",
"tag": "\uD83D\uDC7F",
"position": "-1600px 0px"
},
"u1F62F": {
"en": "Surprised Face",
"zh": "鎯婂憜",
"tag": "\uD83D\uDE2F",
"position": "-2100px 0px"
},
"u1F62C": {
"en": "Grimacing Face",
"zh": "鎵鑴<EE8397>",
"tag": "\uD83D\uDE2C",
"position": "-2050px 0px"
},
"u1F615": {
"en": "Confused",
"zh": "鍥版儜",
"tag": "\uD83D\uDE15",
"position": "-325px 0px"
},
"u1F636": {
"en": "Mouthless",
"zh": "鏃犲彛",
"tag": "\uD83D\uDE36",
"position": "-700px 0px"
},
"u1F607": {
"en": "Halo",
"zh": "澶╀娇鍏夌幆",
"tag": "\uD83D\uDE07",
"position": "-150px 0px"
},
"u1F60F": {
"en": "Smirking Face",
"zh": "鍌荤瑧",
"tag": "\uD83D\uDE0F",
"position": "-1850px 0px"
},
"u1F611": {
"en": "Expressionless Face",
"zh": "闈㈡棤琛ㄦ儏",
"tag": "\uD83D\uDE11",
"position": "-225px 0px"
},
"u1F648": {
"en": "See No Monkey",
"zh": "涓嶇湅",
"tag": "\uD83D\uDE48",
"position": "-2675px 0px"
},
"u1F649": {
"en": "Hear No Monkey",
"zh": "涓嶅惉",
"tag": "\uD83D\uDE49",
"position": "-2700px 0px"
},
"u1F64A": {
"en": "No Speaking",
"zh": "闂槾",
"tag": "\uD83D\uDE4A",
"position": "-2125px 0px"
},
"u1F47D": {
"en": "Alien",
"zh": "澶栨槦浜<E6A7A6>",
"tag": "\uD83D\uDC7D",
"position": "-1575px 0px"
},
"u1F4A9": {
"en": "Pile Of Poo",
"zh": "渚夸究",
"tag": "\uD83D\uDCA9",
"position": "-1025px 0px"
},
"u1F494": {
"en": "Broken Heart",
"zh": "蹇冪",
"tag": "\uD83D\uDC94",
"position": "-2600px 0px"
},
"u1F525": {
"en": "Fire",
"zh": "鐏<>",
"tag": "\uD83D\uDD25",
"position": "-2625px 0px"
},
"u1F4A2": {
"en": "Anger",
"zh": "鎰ゆ€<E38286>",
"tag": "\uD83D\uDCA2",
"position": "-950px 0px"
},
"u1F4A4": {
"en": "Zzz",
"zh": "ZZZ",
"tag": "\uD83D\uDCA4",
"position": "-1000px 0px"
},
"u1F6AB": {
"en": "Prohibited",
"zh": "绂佹",
"tag": "\uD83D\uDEAB",
"position": "-1175px 0px"
},
"u2B50": {
"en": "Star",
"zh": "鏄熸槦",
"tag": "\u2B50",
"position": "-2750px 0px"
},
"u26A1": {
"en": "Lightning Bolt",
"zh": "闂數",
"tag": "\u26A1",
"position": "-2825px 0px"
},
"u1F319": {
"en": "Drescent Moon",
"zh": "寮湀",
"tag": "\uD83C\uDF19",
"position": "-2175px 0px"
},
"u2600": {
"en": "Sunny",
"zh": "鏅存湕",
"tag": "\u2600",
"position": "-3075px 0px"
},
"u26C5": {
"en": "Cloudy",
"zh": "澶氫簯",
"tag": "\u26C5",
"position": "-2900px 0px"
},
"u2601": {
"en": "Cloud",
"zh": "浜戝僵",
"tag": "\u2601",
"position": "-3100px 0px"
},
"u2744": {
"en": "Snowflake",
"zh": "闆姳",
"tag": "\u2744",
"position": "-3175px 0px"
},
"u2614": {
"en": "Umbrella",
"zh": "闆ㄤ紴",
"tag": "\u2614",
"position": "-3125px 0px"
},
"u26C4": {
"en": "Snowman",
"zh": "闆汉",
"tag": "\u26C4",
"position": "-2875px 0px"
},
"u1F44D": {
"en": "Thumbs Up",
"zh": "璧<>",
"tag": "\uD83D\uDC4D",
"position": "-1400px 0px"
},
"u1F44E": {
"en": "Thumbs Down",
"zh": "鍠濆€掑僵",
"tag": "\uD83D\uDC4E",
"position": "-1425px 0px"
},
"u1F91D": {
"en": "Handshake",
"zh": "鎻℃墜",
"tag": "\uD83E\uDD1D",
"position": "-3200px 0px"
},
"u1F44C": {
"en": "Ok Hand",
"zh": "娌¢棶棰<E6A3B6>",
"tag": "\uD83D\uDC4C",
"position": "-1375px 0px"
},
"u1F44A": {
"en": "Raised Fist",
"zh": "涓捐捣鎷冲ご",
"tag": "\u270A",
"position": "-2975px 0px"
},
"u270A": {
"en": "Oncoming Fist",
"zh": "鍑绘嫵",
"tag": "\uD83D\uDC4A",
"position": "-1350px 0px"
},
"u270C": {
"en": "Victory Hand",
"zh": "鑰<>",
"tag": "\u270C",
"position": "-3025px 0px"
},
"u270B": {
"en": "Raised Hand",
"zh": "涓炬墜",
"tag": "\u270B",
"position": "-3000px 0px"
},
"u1F64F": {
"en": "Folded Hands",
"zh": "绁堢シ",
"tag": "\uD83D\uDE4F",
"position": "-2150px 0px"
},
"u261D": {
"en": "Pointing Up",
"zh": "绗竴",
"tag": "\u261D",
"position": "-2925px 0px"
},
"u1F44F": {
"en": "Clapping Hands",
"zh": "榧撴帉",
"tag": "\uD83D\uDC4F",
"position": "-1450px 0px"
},
"u1F4AA": {
"en": "Flexed Biceps",
"zh": "鑲岃倝",
"tag": "\uD83D\uDCAA",
"position": "-1050px 0px"
},
"u1F46A": {
"en": "Family",
"zh": "瀹跺涵",
"tag": "\uD83D\uDC6A",
"position": "-1475px 0px"
},
"u1F46B": {
"en": "Couple",
"zh": "鎯呬荆",
"tag": "\uD83D\uDC6B",
"position": "-1500px 0px"
},
"u1F47C": {
"en": "Baby Angel",
"zh": "瀹濊礉澶╀娇",
"tag": "\uD83D\uDC7C",
"position": "-1550px 0px"
},
"u1F434": {
"en": "Horse",
"zh": "椹<>",
"tag": "\uD83D\uDC34",
"position": "-2475px 0px"
},
"u1F436": {
"en": "Dog",
"zh": "鐙<>",
"tag": "\uD83D\uDC36",
"position": "-2500px 0px"
},
"u1F437": {
"en": "Pig",
"zh": "鐚<>",
"tag": "\uD83D\uDC37",
"position": "-2525px 0px"
},
"u1F47B": {
"en": "Ghost",
"zh": "楝<>",
"tag": "\uD83D\uDC7B",
"position": "-1525px 0px"
},
"u1F339": {
"en": "Rose",
"zh": "鐜懓",
"tag": "\uD83C\uDF39",
"position": "-2225px 0px"
},
"u1F33B": {
"en": "Sunflower",
"zh": "鍚戞棩钁<E6A3A9>",
"tag": "\uD83C\uDF3B",
"position": "-1250px 0px"
},
"u1F332": {
"en": "Pine Tree",
"zh": "鏉炬爲",
"tag": "\uD83C\uDF32",
"position": "-2200px 0px"
},
"u1F384": {
"en": "Christmas Tree",
"zh": "鍦癁鏍<E79981>",
"tag": "\uD83C\uDF84",
"position": "-2400px 0px"
},
"u1F381": {
"en": "Wrapped Gift",
"zh": "绀肩墿",
"tag": "\uD83C\uDF81",
"position": "-2350px 0px"
},
"u1F389": {
"en": "Party Popper",
"zh": "鑱氫細绀艰姳",
"tag": "\uD83C\uDF89",
"position": "-2425px 0px"
},
"u1F4B0": {
"en": "Money Bag",
"zh": "閽辫",
"tag": "\uD83D\uDCB0",
"position": "-1075px 0px"
},
"u1F382": {
"en": "Birthday Cake",
"zh": "鐢熸棩铔嬬硶",
"tag": "\uD83C\uDF82",
"position": "-2375px 0px"
},
"u1F356": {
"en": "Barbecue",
"zh": "BBQ",
"tag": "\uD83C\uDF56",
"position": "-2275px 0px"
},
"u1F35A": {
"en": "Cooked Rice",
"zh": "绫抽キ",
"tag": "\uD83C\uDF5A",
"position": "-1275px 0px"
},
"u1F366": {
"en": "Ice Cream",
"zh": "鍐版穱娣<E7A9B1>",
"tag": "\uD83C\uDF66",
"position": "-2300px 0px"
},
"u1F36B": {
"en": "Chocolate Bar",
"zh": "宸у厠鍔<E58EA0>",
"tag": "\uD83C\uDF6B",
"position": "-1300px 0px"
},
"u1F349": {
"en": "Watermelon",
"zh": "瑗跨摐",
"tag": "\uD83C\uDF49",
"position": "-2250px 0px"
},
"u1F377": {
"en": "Wine Glass",
"zh": "绾㈤厭",
"tag": "\uD83C\uDF77",
"position": "-2325px 0px"
},
"u1F37B": {
"en": "Cheers",
"zh": "骞叉澂",
"tag": "\uD83C\uDF7B",
"position": "-1325px 0px"
},
"u2615": {
"en": "Coffee",
"zh": "鍜栧暋",
"tag": "\u2615",
"position": "-3150px 0px"
},
"u1F3C0": {
"en": "Basketball",
"zh": "绡悆",
"tag": "\uD83C\uDFC0",
"position": "-825px 0px"
},
"u26BD": {
"en": "Soccer Ball",
"zh": "瓒崇悆",
"tag": "\u26BD",
"position": "-2850px 0px"
},
"u1F3C2": {
"en": "Snowboarder",
"zh": "鍗曟澘婊戦洩",
"tag": "\uD83C\uDFC2",
"position": "-850px 0px"
},
"u1F3A4": {
"en": "Microphone",
"zh": "楹﹀厠椋<E58EA0>",
"tag": "\uD83C\uDFA4",
"position": "-750px 0px"
},
"u1F3B5": {
"en": "Musical Note",
"zh": "闊充箰",
"tag": "\uD83C\uDFB5",
"position": "-800px 0px"
},
"u1F3B2": {
"en": "Game Die",
"zh": "楠板瓙",
"tag": "\uD83C\uDFB2",
"position": "-775px 0px"
},
"u1F004": {
"en": "Mahjong Red Dragon",
"zh": "楹诲皢",
"tag": "\uD83C\uDC04",
"position": "-900px 0px"
},
"u1F451": {
"en": "Crown",
"zh": "鐜嬪啝",
"tag": "\uD83D\uDC51",
"position": "-2550px 0px"
},
"u1F484": {
"en": "Lipstick",
"zh": "鍙g孩",
"tag": "\uD83D\uDC84",
"position": "-2575px 0px"
},
"u1F48B": {
"en": "Kiss",
"zh": "鍚<>",
"tag": "\uD83D\uDC8B",
"position": "-1650px 0px"
},
"u1F48D": {
"en": "Ring",
"zh": "鎴掓寚",
"tag": "\uD83D\uDC8D",
"position": "-1675px 0px"
},
"u1F4DA": {
"en": "Books",
"zh": "涔︾睄",
"tag": "\uD83D\uDCDA",
"position": "-1100px 0px"
},
"u1F393": {
"en": "Graduation Cap",
"zh": "姣曚笟甯<E7AC9F>",
"tag": "\uD83C\uDF93",
"position": "-2450px 0px"
},
"u270F": {
"en": "Pencil",
"zh": "閾呯瑪",
"tag": "\u270F",
"position": "-3050px 0px"
},
"u1F3E1": {
"en": "House With Garden",
"zh": "鎴垮瓙",
"tag": "\uD83C\uDFE1",
"position": "-875px 0px"
},
"u1F6BF": {
"en": "Shower",
"zh": "娣嬫荡",
"tag": "\uD83D\uDEBF",
"position": "-1200px 0px"
},
"u1F4A1": {
"en": "Light Bulb",
"zh": "鐏场",
"tag": "\uD83D\uDCA1",
"position": "-925px 0px"
},
"u1F4DE": {
"en": "Telephone Receiver",
"zh": "鐢佃瘽鍚瓛",
"tag": "\uD83D\uDCDE",
"position": "-1125px 0px"
},
"u1F4E2": {
"en": "Loudspeaker",
"zh": "鎵╅煶鍣<E785B6>",
"tag": "\uD83D\uDCE2",
"position": "-1150px 0px"
},
"u1F556": {
"en": "Clock",
"zh": "琛<>",
"tag": "\uD83D\uDD56",
"position": "-2650px 0px"
},
"u23F0": {
"en": "Alarm Clock",
"zh": "闂归挓",
"tag": "\u23F0",
"position": "-2775px 0px"
},
"u23F3": {
"en": "Hourglass",
"zh": "娌欐紡",
"tag": "\u23F3",
"position": "-2800px 0px"
},
"u1F4A3": {
"en": "Bomb",
"zh": "鐐稿脊",
"tag": "\uD83D\uDCA3",
"position": "-975px 0px"
},
"u1F52B": {
"en": "Pistol",
"zh": "鎵嬫灙",
"tag": "\uD83D\uDD2B",
"position": "-1700px 0px"
},
"u1F48A": {
"en": "Capsule",
"zh": "鑽<>",
"tag": "\uD83D\uDC8A",
"position": "-1625px 0px"
},
"u1F680": {
"en": "Rocket",
"zh": "鐏",
"tag": "\uD83D\uDE80",
"position": "-2725px 0px"
},
"u1F30F": {
"en": "Globe",
"zh": "鍦扮悆",
"tag": "\uD83C\uDF0F",
"position": "-1225px 0px"
}
};
let EmojiList = []
function setEmojiList() {
EmojiList.length = 0;
for (var unicode in EmojiFactory) {
var detail = EmojiFactory[unicode];
if (detail.tag) {
var lang = 'en';
var symbol = detail[lang];
EmojiList.push({
unicode: unicode,
symbol: '[' + symbol + ']',
emoji: detail.tag,
});
}
}
}
setEmojiList()
export default EmojiList

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

Binary file not shown.

BIN
static/imgs/map.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

BIN
static/imgs/no-new-news.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

BIN
static/imgs/tel-call.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -6,7 +6,6 @@
import Vue from 'vue' import Vue from 'vue'
import Vuex from 'vuex' import Vuex from 'vuex'
import im from './modules/im.js'
Vue.use(Vuex) Vue.use(Vuex)
@@ -38,8 +37,5 @@ export default new Vuex.Store({
setRefresh(state, value) { setRefresh(state, value) {
state.refresh = value state.refresh = value
} }
},
modules: {
im
} }
}) })

View File

@@ -1,4 +1,7 @@
import im from "@/utils/im/index.js" import im from "@/utils/im/index.js"
import {
contactModel
} from '@/utils/im/models.js'
export default { export default {
state: { state: {
@@ -14,7 +17,7 @@ export default {
const info = state.contacts[targetId] const info = state.contacts[targetId]
return { return {
name: info.name, name: info.remark ? info.remark : info.name,
hash: info.hash, hash: info.hash,
portraitUrl: info.localAvatar ? info.localAvatar : require('@/static/user/cover.png') portraitUrl: info.localAvatar ? info.localAvatar : require('@/static/user/cover.png')
} }
@@ -38,18 +41,40 @@ export default {
updateContactInfo(state, contactInfo) { updateContactInfo(state, contactInfo) {
Vue.set(state.contacts, contactInfo.targetId, contactInfo) Vue.set(state.contacts, contactInfo.targetId, contactInfo)
}, },
// 设置我的资料
setSenderInfo(state, contactInfo) { setSenderInfo(state, contactInfo) {
state.myInfo = { state.myInfo = {
userId: contactInfo.targetId, userId: contactInfo.targetId,
name: contactInfo.name, name: contactInfo.name,
portraitUrl: contactInfo.portraitUrl portraitUrl: contactInfo.portraitUrl
} }
},
setContactRemark(state, contactInfo) {
Vue.set(state.contacts, contactInfo.targetId, contactInfo)
} }
}, },
actions: { actions: {
setSenderInfo({ setContactRemark({
commit 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,
dispatch
}, contactInfo) { }, contactInfo) {
contactInfo.type = 0 // type 更改为0标记是我自己
dispatch('updateContact', contactInfo)
commit('setSenderInfo', contactInfo) commit('setSenderInfo', contactInfo)
}, },
// 载入好友信息 // 载入好友信息
@@ -63,8 +88,7 @@ export default {
commit, commit,
dispatch dispatch
}, contactInfo) { }, contactInfo) {
const model = uni.model.contactModel contactModel.find('targetId="' + contactInfo.targetId + '"', (err, result) => {
model.find('targetId="' + contactInfo.targetId + '"', (err, result) => {
if (result.length == 0) { if (result.length == 0) {
// 没有数据,直接新增一条 // 没有数据,直接新增一条
dispatch('initContact', contactInfo) dispatch('initContact', contactInfo)
@@ -75,13 +99,13 @@ export default {
targetId: contactInfo.targetId, targetId: contactInfo.targetId,
name: contactInfo.name, name: contactInfo.name,
hash: contactInfo.hash, hash: contactInfo.hash,
type: contactInfo.type,
portraitUrl: contactInfo.portraitUrl, portraitUrl: contactInfo.portraitUrl,
localAvatar: savedFilePath, localAvatar: savedFilePath
type: contactInfo.type
} }
model.update('targetId="' + contactInfo.targetId + '"', info, (err, contactModel.update('targetId="' + contactInfo.targetId + '"', info, (err,
res) => { res) => {
console.log('UPDATE AVATAR, ERR', err, info); console.log('UPDATE AVATAR, ERR', err, info)
}) })
commit('updateContactInfo', info) commit('updateContactInfo', info)
}) })
@@ -90,17 +114,17 @@ export default {
targetId: contactInfo.targetId, targetId: contactInfo.targetId,
name: contactInfo.name, name: contactInfo.name,
hash: contactInfo.hash, hash: contactInfo.hash,
type: contactInfo.type,
portraitUrl: contactInfo.portraitUrl, portraitUrl: contactInfo.portraitUrl,
localAvatar: result[0].localAvatar, localAvatar: result[0].localAvatar
type: contactInfo.type
} }
model.update('targetId="' + contactInfo.targetId + '"', info, (err, res) => { contactModel.update('targetId="' + contactInfo.targetId + '"', info, (err, res) => {
console.log('UPDATE NAME, ERR', err, info); console.log('UPDATE NAME, ERR', err, info);
}) })
commit('updateContactInfo', info) commit('updateContactInfo', info)
} }
} else { } else {
console.log('updateContact, 无操作'); console.log('updateContact, 无操作')
} }
}) })
}, },
@@ -110,7 +134,6 @@ export default {
}, contactInfo) { }, contactInfo) {
// 将好友信息保存到vuex的内存中方便立即使用 // 将好友信息保存到vuex的内存中方便立即使用
commit('updateContactInfo', contactInfo) commit('updateContactInfo', contactInfo)
const model = uni.model.contactModel
// 用户头像,是否需要下载到本地 // 用户头像,是否需要下载到本地
if (contactInfo.portraitUrl) { if (contactInfo.portraitUrl) {
saveAvatar(contactInfo, (savedFilePath) => { saveAvatar(contactInfo, (savedFilePath) => {
@@ -118,11 +141,13 @@ export default {
targetId: contactInfo.targetId, targetId: contactInfo.targetId,
name: contactInfo.name, name: contactInfo.name,
hash: contactInfo.hash, hash: contactInfo.hash,
type: contactInfo.type,
portraitUrl: contactInfo.portraitUrl, portraitUrl: contactInfo.portraitUrl,
localAvatar: savedFilePath, localAvatar: savedFilePath
type: contactInfo.type
} }
model.insert(info, (err, res) => {}) contactModel.insert(info, (err, res) => {
console.error('保存头像', err, res)
})
// 保存头像后,更新信息 // 保存头像后,更新信息
commit('updateContactInfo', info) commit('updateContactInfo', info)
}) })
@@ -132,11 +157,13 @@ export default {
targetId: contactInfo.targetId, targetId: contactInfo.targetId,
name: contactInfo.name, name: contactInfo.name,
hash: contactInfo.hash, hash: contactInfo.hash,
type: contactInfo.type,
portraitUrl: contactInfo.portraitUrl, portraitUrl: contactInfo.portraitUrl,
localAvatar: '', localAvatar: ''
type: contactInfo.type
} }
model.insert(info, (err, res) => {}) contactModel.insert(info, (err, res) => {
console.error('没保存头像', err, res)
})
} }
} }
} }

View File

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

View File

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

Binary file not shown.

View File

@@ -1,7 +1,7 @@
{ {
"id": "onemue-USQLite", "id": "onemue-USQLite",
"displayName": "u-SQLite V2", "displayName": "u-SQLite V2",
"version": "2.1.0", "version": "2.2.2",
"description": "基于ORM技术使用对象的方式来操作sqlite数据库而无需编写任何sql语句.", "description": "基于ORM技术使用对象的方式来操作sqlite数据库而无需编写任何sql语句.",
"keywords": [ "keywords": [
"USQLite,数据库操作,缓存,大数据缓存,sqlite,sql,orm" "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 > u-SQLite 交流群643867519
> 如果觉的当前插件对你有帮助可以前往 [github](https://github.com/onemue/u-sqlite) 点 star! > 如果觉的当前插件对你有帮助可以前往 [github](https://github.com/onemue/u-sqlite) 点 star!
@@ -49,6 +50,7 @@ let studentModel = uni.$sql.model('student',{
- unique UNIQUE 不重复 - unique UNIQUE 不重复
- default DEFAULT 默认值 - default DEFAULT 默认值
- notNull NOT NULL 非空 - 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.22021-12-01
- 优化 示例可复制图标名称 - 优化 示例可复制图标名称
## 1.3.12021-11-23 ## 1.3.12021-11-23

View File

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

View File

@@ -1,14 +1,18 @@
<template> <template>
<!-- #ifdef APP-NVUE --> <!-- #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 --> <!-- #endif -->
<!-- #ifndef APP-NVUE --> <!-- #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 --> <!-- #endif -->
</template> </template>
<script> <script>
import icons from './icons.js'; 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 // #ifdef APP-NVUE
var domModule = weex.requireModule('dom'); var domModule = weex.requireModule('dom');
import iconUrl from './uniicons.ttf' import iconUrl from './uniicons.ttf'
@@ -61,6 +65,9 @@
return unescape(`%u${code.unicode}`) return unescape(`%u${code.unicode}`)
} }
return '' return ''
},
iconSize(){
return getVal(this.size)
} }
}, },
methods: { methods: {

View File

@@ -1,7 +1,7 @@
{ {
"id": "uni-icons", "id": "uni-icons",
"displayName": "uni-icons 图标", "displayName": "uni-icons 图标",
"version": "1.3.2", "version": "1.3.5",
"description": "图标组件,用于展示移动端常见的图标,可自定义颜色、大小。", "description": "图标组件,用于展示移动端常见的图标,可自定义颜色、大小。",
"keywords": [ "keywords": [
"uni-ui", "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 ## 3.3.92021-11-09
- 去除重复的context.xxx未找到的提示语 - 去除重复的context.xxx未找到的提示语
## 3.3.82021-10-28 ## 3.3.82021-10-28

View File

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

File diff suppressed because one or more lines are too long

View File

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

View File

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

View File

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

View File

@@ -1,16 +0,0 @@
// 获取新好友申请数量
const getPendingCount = (callback) => {
RongIMLib.getConversationList([RongIMLib.ConversationType.SYSTEM], 100, 0, (res) => {
if (res.code === 0) {
const pendingCount = res.conversations.filter((item) => {
return item.objectName == RongIMLib.ObjectName.ContactNotification
}).length
callback(pendingCount)
}
})
}
export default {
getPendingCount
}

View File

@@ -1,130 +0,0 @@
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
import * as CallLib from '@/uni_modules/RongCloud-CallWrapper/lib/index'
import store from '@/store/index.js'
import message from './message.js'
import listeners from './listeners.js'
import {
getFriends,
getUserInfo,
getImToken,
getMyGroups
} from '@/apis/interfaces/im.js'
const initIm = (KEY) => {
RongIMLib.init(KEY)
CallLib.init()
listeners.imLibListeners()
listeners.callLibListeners()
// 初始化的时候 自动链接
if (store.getters.getToken !== '') {
getImToken().then(res => {
connect(res.token, res.userInfo, (res) => {
console.log('IM.CONNECT', res);
})
})
}
}
const setNotifyBadge = () => {
// 获取未读消息数量
RongIMLib.getTotalUnreadCount(({
code,
count
}) => {
if (code === 0) {
// #ifdef APP-PLUS
plus.runtime.setBadgeNumber(count)
// #endif
if (count > 0) {
uni.setTabBarBadge({
index: 3,
text: String(count > 99 ? '99+' : count)
})
} else {
uni.removeTabBarBadge({
index: 3
})
}
}
})
}
/**
* 连接IM服务
* @param {string} token token
* @param {object} userInfo {targetId: string, name: string, portraitUrl: string}
*/
const connect = (token, userInfo, callback) => {
RongIMLib.connect(token, res => {
callback(res)
// 更新个人信息
store.dispatch('setSenderInfo', userInfo)
// 设置未读消息数量
setNotifyBadge()
// 首次运行获取好友列表
const FK = 'ZH_V_' + userInfo.targetId
uni.getStorage({
key: FK,
success: () => {
const model = uni.model.contactModel
model.find((err, results) => {
results.map(item => {
store.dispatch('launchContact', item)
})
})
},
fail: () => {
// 程序是首次运行,初始化加载好友和群组信息
Promise.all([getFriends(), getMyGroups()]).then(result => {
result.map(contacts => {
contacts.map(item => {
store.dispatch('initContact', item)
})
})
uni.setStorageSync(FK, userInfo.targetId)
})
}
})
})
}
/**
* 断开链接
*/
const disconnect = () => {
RongIMLib.disconnect()
// 移除提醒数量
// #ifdef APP-PLUS
plus.runtime.setBadgeNumber(0)
// #endif
uni.removeTabBarBadge({
index: 3
})
}
// 播放状态
let tipState = false
const triTone = () => {
if (tipState == false) {
const innerAudioContext = uni.createInnerAudioContext()
innerAudioContext.autoplay = true
innerAudioContext.src = '/utils/im/sounds/new-msg.mp3'
innerAudioContext.onPlay(() => {
tipState = true
})
innerAudioContext.onEnded(() => {
tipState = false
innerAudioContext.destroy()
})
}
}
export default {
initIm,
connect,
disconnect,
setNotifyBadge,
...message
}

View File

@@ -1,215 +0,0 @@
import * as CallLib from '@/uni_modules/RongCloud-CallWrapper/lib/index'
import * as IMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
import store from '@/store/index.js'
import im from "@/utils/im/index.js"
import utils from '../index.js'
import {
getUserInfo
} from '@/apis/interfaces/im.js'
// 维护消息列表,检查是否需要通知声音,设置新消息提醒的数量
const onReceiveMessage = (message) => {
IMLib.getConversationNotificationStatus(message.conversationType, message.targetId, ({
code,
status
}) => {
if (code === 0) {
if (status) {
// triTone()
}
}
})
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)
})
}
}
// 允许通知的消息类型,触发更新消息列表操作,提示音
const notifyMsgTypes = [
IMLib.ObjectName.Text,
IMLib.ObjectName.File,
IMLib.ObjectName.Image,
IMLib.ObjectName.GIF,
IMLib.ObjectName.Location,
IMLib.ObjectName.Voice,
IMLib.ObjectName.HQVoice,
IMLib.ObjectName.Sight
]
const imLibListeners = () => {
// 添加连接状态监听函数
IMLib.addConnectionStatusListener((res) => {
console.error('连接状态监听', res.data.status)
uni.$emit('onConnectionStatusChange', res.data.status)
})
// 添加消息监听函数
IMLib.addReceiveMessageListener((res) => {
const message = res.data.message
console.error('[收到消息]', message)
checkContactExists(message)
if (utils.inArray(message.objectName, notifyMsgTypes)) {
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) {
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(3, message.targetId, message.sentTime,
false)
// 解散了就删了吧
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)
}
})
// 监听私聊消息已读回执
IMLib.addReadReceiptReceivedListener(({
data
}) => {
console.error("监听私聊消息已读回执: ", data);
uni.$emit('onReadReceiptReceived', data)
})
// 监听消息撤回操作
IMLib.addRecallMessageListener(({
data
}) => {
IMLib.getMessage(data.messageId, ({
message
}) => {
console.error("消息撤回: ", message);
im.setNotifyBadge()
uni.$emit('onReceiveMessage', message)
uni.$emit('onRecallMessage_' + message.targetId, message)
})
})
// 监听需要群聊消息回执
IMLib.addReceiptRequestListener(({
data
}) => {
uni.$emit('onReceiptRequest', data)
})
// 群消息已读的回执
IMLib.addReceiptResponseListener(({
data
}) => {
// 获取本地消息
IMLib.getMessageByUId(data.messageUId, ({
message
}) => {
const readers = Object.keys(data.users).length
const extra = JSON.stringify({
readers
})
// 在消息的扩展数据中,设置已读数量
IMLib.setMessageExtra(message.messageId, extra, (result) => {
message.extra = extra
uni.$emit('onReceiptResponse', message)
})
})
})
}
const callLibListeners = () => {
// 音视频通话相关的
// 监听通话呼入
CallLib.onCallReceived(({
data
}) => {
console.error('onCallReceived');
uni.navigateTo({
url: '/pages/im/private/call?targetId=' + data.targetId + '&mediaType=' +
data.mediaType
})
})
// 通话建立成功
CallLib.onCallConnected(() => {
uni.$emit('onCallConnected')
})
// 外呼
CallLib.onCallOutgoing((res) => {
console.error('onCallOutgoing', res);
uni.$emit('onCallOutgoing')
})
// 远端响铃
CallLib.onRemoteUserRinging((res) => {
console.error('onRemoteUserRinging', res);
uni.$emit('onRemoteUserRinging')
})
// 远端加入
CallLib.onRemoteUserJoined((res) => {
console.error('远端接听');
uni.$emit('onRemoteUserJoined')
})
// 断开链接
CallLib.onCallDisconnected((res) => {
console.error('断开链接', res)
uni.$emit('onCallDisconnected')
})
// 远端挂断
CallLib.onRemoteUserLeft((res) => {
console.error('远端离开', res)
uni.$emit('onRemoteUserLeft')
})
}
export default {
imLibListeners,
callLibListeners
}

View File

@@ -1,239 +0,0 @@
import store from '@/store/index.js'
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
const getMessageList = (conversationType, targetId, timeStamp, count, isForward, callback) => {
// 获取消息列表 https://doc.rongcloud.cn/imserver/server/v1/message/objectname#objectName
const objectNames = [
'RC:TxtMsg',
'RC:VcMsg',
'RC:HQVCMsg',
'RC:ImgMsg',
'RC:GIFMsg',
'RC:ImgTextMsg',
'RC:FileMsg',
'RC:LBSMsg',
'RC:SightMsg',
'RC:ReferenceMsg',
'RC:CombineMsg',
'RC:GrpNtf',
'RC:InfoNtf',
'RC:RcNtf'
]
RongIMLib.getHistoryMessagesByTimestamp(
conversationType,
targetId,
objectNames,
timeStamp,
count,
isForward,
({
code,
messages
}) => {
if (code === 0) {
callback(messages)
} else {
uni.showToast({
icon: 'error',
title: code
})
}
}
)
}
// 获取好友申请列表
const getPendingList = (callback, total) => {
total = total || 100
RongIMLib.getConversationList([RongIMLib.ConversationType.SYSTEM], total, 0, (res) => {
if (res.code === 0) {
const pendings = res.conversations.filter((item) => {
return item.objectName == RongIMLib.ObjectName.ContactNotification &&
item.latestMessage.operation === 'Request'
})
callback(pendings)
}
})
}
// 群组申请列表,邀请列表
const getGroupPendinglist = (targetId, callback) => {
const conversationType = RongIMLib.ConversationType.SYSTEM
const objectNames = ['RC:ContactNtf']
RongIMLib.getHistoryMessagesByTimestamp(conversationType, targetId, objectNames, 0, 1000, true,
({
messages
}) => {
callback(messages)
}
)
}
/**
* 发送文本消息
* @param {number} conversationType 消息类型
* @param {string} targetId 会话id
* @param {string} content 消息内容
* @param {function} callback 回调函数
*/
const sentText = (conversationType, targetId, content, user, callback) => {
const msg = {
conversationType: conversationType,
targetId: String(targetId),
content: {
objectName: 'RC:TxtMsg',
content: content,
userInfo: user
}
}
RongIMLib.sendMessage(msg, ({
code,
messageId
}) => {
if (code === 0) {
if (conversationType == 3) {
RongIMLib.sendReadReceiptRequest(messageId, (res) => {
console.log('发送回执请求', res);
})
}
callback(messageId)
} else {
console.log('发送失败', msg);
uni.showToast({
icon: 'none',
title: '发送失败' + code
})
}
})
}
/**
* 发送消息
* @param {number} conversationType 消息类型
* @param {string} targetId 会话id
* @param {string} voiceUrl 录音的本地路径
* @param {integer} time 录音时长
* @param {function} callback 录音时长
*/
const sentVoice = (conversationType, targetId, voiceUrl, time, user, callback) => {
const msg = {
conversationType: conversationType,
targetId: String(targetId),
content: {
objectName: 'RC:HQVCMsg',
local: 'file:///' + plus.io.convertLocalFileSystemURL(voiceUrl),
duration: time,
userInfo: user
}
}
RongIMLib.sendMediaMessage(msg, {
success: (messageId) => {
callback(messageId);
},
progress: (progress, messageId) => {
console.log(messageId);
},
cancel: (messageId) => {
// 发送取消回调
},
error: (errorCode, messageId) => {
console.log(errorCode, messageId);
}
})
}
const sentImage = (conversationType, targetId, imageUrl, user, callback) => {
const msg = {
conversationType: conversationType,
targetId: String(targetId),
content: {
objectName: 'RC:ImgMsg',
local: 'file:///' + plus.io.convertLocalFileSystemURL(imageUrl),
userInfo: user
}
}
RongIMLib.sendMediaMessage(msg, {
success: (messageId) => {
callback(messageId);
},
progress: (progress, messageId) => {
console.log(messageId);
},
cancel: (messageId) => {
// 发送取消回调
},
error: (errorCode, messageId) => {
console.log(errorCode, messageId);
}
})
}
const sentGif = (conversationType, targetId, gifUrl, time, user, callback) => {
const msg = {
conversationType: conversationType,
targetId: String(targetId),
content: {
objectName: 'RC:GIFMsg',
local: 'file:///' + plus.io.convertLocalFileSystemURL(gifUrl),
duration: time,
userInfo: user
}
}
RongIMLib.sendMediaMessage(msg, {
success: (messageId) => {
callback(messageId);
},
progress: (progress, messageId) => {
console.log(messageId);
},
cancel: (messageId) => {
// 发送取消回调
},
error: (errorCode, messageId) => {
console.log(errorCode, messageId);
}
})
}
const sendFile = (conversationType, targetId, fileUrl, time, user, callback) => {
const msg = {
conversationType: conversationType,
targetId: String(targetId),
content: {
objectName: 'RC:FileMsg',
local: 'file:///' + plus.io.convertLocalFileSystemURL(fileUrl),
duration: time,
userInfo: user
}
}
RongIMLib.sendMediaMessage(msg, {
success: (messageId) => {
callback(messageId);
},
progress: (progress, messageId) => {
console.log(messageId);
},
cancel: (messageId) => {
// 发送取消回调
},
error: (errorCode, messageId) => {
console.log(errorCode, messageId);
}
})
}
export default {
getMessageList,
getPendingList,
getGroupPendinglist,
sentText,
sentVoice,
sentImage,
sentGif,
sendFile
}

View File

@@ -1,26 +0,0 @@
import {
usqlite
} from '@/uni_modules/onemue-USQLite/js_sdk/usqlite.js'
const contactModel = usqlite.model('contacts', {
targetId: {
type: String,
primaryKey: true,
unique: true
},
name: String,
hash: {
type: String,
unique: true
},
type: {
type: Number,
default: 0
},
portraitUrl: String,
localAvatar: String
})
export default {
contactModel
}

View File

@@ -2,22 +2,22 @@
# yarn lockfile v1 # yarn lockfile v1
moment@^2.29.1: "moment@^2.29.1":
version "2.29.1" "integrity" "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
resolved "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz" "resolved" "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz"
integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ== "version" "2.29.1"
uni-read-pages@^1.0.5: "uni-read-pages@^1.0.5":
version "1.0.5" "integrity" "sha512-GkrrZ0LX0vn9R5k6RKEi0Ez3Q3e2vUpjXQ8Z6/K/d28KudI9ajqgt8WEjQFlG5EPm1K6uTArN8LlqmZTEixDUA=="
resolved "https://registry.npmjs.org/uni-read-pages/-/uni-read-pages-1.0.5.tgz" "resolved" "https://registry.npmjs.org/uni-read-pages/-/uni-read-pages-1.0.5.tgz"
integrity sha512-GkrrZ0LX0vn9R5k6RKEi0Ez3Q3e2vUpjXQ8Z6/K/d28KudI9ajqgt8WEjQFlG5EPm1K6uTArN8LlqmZTEixDUA== "version" "1.0.5"
uni-simple-router@^2.0.7: "uni-simple-router@^2.0.7":
version "2.0.7" "integrity" "sha512-8FKv5dw7Eoonm0gkO8udprrxzin0fNUI0+AvIphFkFRH5ZmP5ZWJ2pvnWzb2NiiqQSECTSU5VSB7HhvOSwD5eA=="
resolved "https://registry.npmjs.org/uni-simple-router/-/uni-simple-router-2.0.7.tgz" "resolved" "https://registry.npmjs.org/uni-simple-router/-/uni-simple-router-2.0.7.tgz"
integrity sha512-8FKv5dw7Eoonm0gkO8udprrxzin0fNUI0+AvIphFkFRH5ZmP5ZWJ2pvnWzb2NiiqQSECTSU5VSB7HhvOSwD5eA== "version" "2.0.7"
uview-ui@^2.0.27: "uview-ui@^2.0.27":
version "2.0.27" "integrity" "sha512-d5SttbPcowomrgpL7A1LMKRbemXtyyzpPCy98/+VQR3jfSyyHC9tfj/ZeAOKpqTn1rf9gOj2wc5tda/kVmYX2Q=="
resolved "https://registry.yarnpkg.com/uview-ui/-/uview-ui-2.0.27.tgz#1a7dde9c6246e851d768f3efd44b5fb26774a2e1" "resolved" "https://registry.npmjs.org/uview-ui/-/uview-ui-2.0.29.tgz"
integrity sha512-fl35rlguNPfXnwNoVv0w4zS1blFFxxSPuGR1+9SbpFGC33aiTBaoFWs/4Fppj0foS/kDCqSWcJiymNmQjPBD4g== "version" "2.0.29"