Commit 2eae9797 authored by 罗超's avatar 罗超

调整IM列表,补充聊天界面和功能

parent 10d51510
...@@ -54,7 +54,8 @@ App( ...@@ -54,7 +54,8 @@ App(
emitter: null, emitter: null,
netcallController: null, netcallController: null,
ENVIRONMENT_CONFIG, ENVIRONMENT_CONFIG,
PAGE_CONFIG PAGE_CONFIG,
queryUser:{}
}, },
onShow: function (e) { onShow: function (e) {
if (e.scene == 1007 || e.scene == 1008) { if (e.scene == 1007 || e.scene == 1008) {
......
...@@ -7,8 +7,11 @@ ...@@ -7,8 +7,11 @@
"pages/validateForm/validateEnd/validateEnd", "pages/validateForm/validateEnd/validateEnd",
"pages/logs/logs", "pages/logs/logs",
"pages/me/index", "pages/me/index",
"partials/chating/chating",
"pages/video/index" "pages/video/index",
"components/emoji/emoji",
"components/inputclear/inputclear",
"components/inputmodal/inputmodal"
], ],
"window": { "window": {
"backgroundTextStyle": "light", "backgroundTextStyle": "light",
......
import EmojiObj from '../../utils/emojimap.js'
Component({
/**
* 组件的属性列表
*/
properties: {
},
/**
* 组件的初始数据
*/
data: {
localAlbumImages: ['/images/album-emoji.png', '/images/album-ajtd.png', '/images/album-xxy.png', '/images/album-lt.png'],
albumArr: [],
currentAlbum: 'emoji',
emojiList: {},
currentAlbumKeys: [] //存储每一类别的key
},
attached: function() {
let currentAlbumKeys = this.splitAlbumKeys(Object.keys(EmojiObj.emojiList[this.data.currentAlbum]), this.data.currentAlbum == 'emoji' ? 23 : 10)
this.setData({
albumArr: EmojiObj.albumArr,
emojiList: EmojiObj.emojiList,
currentAlbumKeys
})
},
/**
* 组件的方法列表
*/
methods: {
/**
* 切换emoji类别
*/
switchAlbum: function(e) {
let currentAlbum = e.currentTarget.dataset.album
// 提前跟新一次,下面分类需要用到
this.setData({
currentAlbum
})
let currentAlbumKeys = this.splitAlbumKeys(Object.keys(this.data.emojiList[currentAlbum]), currentAlbum == 'emoji' ? 23 : 10, currentAlbum)
this.setData({
currentAlbumKeys
})
},
/**
* 每页显示固定个数
* arr数据源数组,space每个数组最大容量
* [[], [], []]
*/
splitAlbumKeys: function (arr, space, currentAlbum) {
const delta = space || 23
let result = [],
factor = Math.ceil(arr.length / delta),
begin = 0,
end = 1
if (factor == 1) {
result = [[...arr]]
} else {
for (let i = 1; i < factor; i++) {
let temp = []
temp = [...arr.slice(begin, i * delta)]
begin = i * delta
result.push(temp)
}
result.push([...arr.slice(delta * (factor - 1), arr.length)])
}
if (currentAlbum == 'emoji' || this.data.currentAlbum == 'emoji') { // 只有emoji才添加删除按钮
result.map((cata, index) => {
if(index != (result.length-1)) {
cata.push('[删除]')
}
})
// console.log(result)
}
return result
},
/**
* 单击emoji
*/
emojiTap: function(e) {
let emoji = e.target.dataset.emoji
if (!emoji) return
// console.log(emoji)
this.triggerEvent("EmojiClick", emoji)
},
/**
* 发送emoji
*/
emojiSend: function () {
this.triggerEvent("EmojiSend")
}
},
})
{
"component": true
}
\ No newline at end of file
<view class='emoji-wrapper'>
<view class='emoji-content'>
<swiper indicator-dots='true' class='emoji-content-swiper'>
<block>
<view style='display: inline-block;' wx:for="{{currentAlbumKeys}}" wx:for-item="currentEmojiArr" wx:key="{{Math.random()}}" bindtap='emojiTap'>
<swiper-item>
<view class='emoji-content-item' wx:for="{{currentEmojiArr}}" wx:for-item="currentEmojiKey" wx:key="{{currentEmojiKey}}">
<image src="{{emojiList[currentAlbum][currentEmojiKey].img}}" class='{{currentAlbum == "emoji" ? "emoji-content-img-emoji" : "emoji-content-img-other"}}' data-emoji='{{currentEmojiKey}}'></image>
</view>
</swiper-item>
</view>
</block>
</swiper>
</view>
<view class='emoji-album'>
<!-- <view class='emoji-album-left' wx:for="{{albumArr}}" wx:for-item="album" wx:key="{{album.album}}" data-album="{{album.album}}" bindtap='switchAlbum'>
<image src='{{album.img}}' class='{{album.album == currentAlbum ? "emoji-album-left-img album-active" : "emoji-album-left-img"}}'></image>
</view> -->
<view class='emoji-album-left' wx:for="{{albumArr}}" wx:for-item="album" wx:for-index="index" wx:key="{{album.album}}" data-album="{{album.album}}" bindtap='switchAlbum'>
<image src='{{localAlbumImages[index]}}' class='{{album.album == currentAlbum ? "emoji-album-left-img album-active" : "emoji-album-left-img"}}'></image>
</view>
<view class='emoji-send' bindtap='emojiSend'>发送</view>
</view>
</view>
\ No newline at end of file
.emoji-wrapper {
width: 100%;
height: 100%;
background-color: #fff;
}
/*内容 */
.emoji-content {
width: 100%;
height: 400rpx;
/* padding-top: 30rpx; */
padding-left: 20rpx;
box-sizing:border-box;
}
.emoji-content-swiper {
width: 100%;
height: 100%;
}
.emoji-content-item {
display: inline-block;
margin: 17rpx;
}
.emoji-content-img-emoji {
width: 56rpx;
height: 56rpx;
}
.emoji-content-img-other {
width: 100rpx;
height: 100rpx;
}
/*底部类别 */
.emoji-album {
width: 100%;
height: 88rpx;
border: 2rpx solid #999;
box-sizing: border-box;
background-color: #fff;
}
.emoji-album-left {
display: inline-block;
height: 100%;
}
.emoji-album-left-img {
width:88rpx;
height:100%;
padding:8rpx 10rpx;
box-sizing:border-box;
border-right:2rpx soild #999
}
.emoji-send {
width: 88rpx;
height: 100%;
line-height:88rpx;
background-color: #0091e4;
text-align: center;
float: right;
color: #fff;
}
.album-active {
background-color: #aaa;
}
// components/inputclear/inputclear.js
Component({
/**
* 组件的属性列表
*/
properties: {
type: {
type: String,
value: 'text'
},
placeholder: {
type: String,
value: '请输入内容'
},
maxlength: {
type: Number,
value: 10
}
},
/**
* 组件的初始数据
*/
data: {
inputVal: ''
},
/**
* 组件的方法列表
*/
methods: {
/**
* 输入响应
*/
bindInput(e) {
this.setData({
inputVal: e.detail.value
})
this.triggerEvent('inputClearChange', { data: this.data.inputVal }, {})
},
/**
* 清除输入框
*/
clearInput() {
this.setData({
inputVal: ''
})
},
/**
* 确定
*/
confirmHandler() {
this.triggerEvent('inputClearFinish', { data: this.data.inputVal }, {})
}
}
})
{
"component": true,
"usingComponents": {}
}
\ No newline at end of file
<view class='input-clear-wrapper'>
<input type='{{type}}' value='{{inputVal}}' placeholder='{{placeholder}}' maxlength='{{maxlength}}' bindinput='bindInput' bindconfirm='confirmHandler'></input>
<icon wx:if="{{inputVal.length != 0}}" catchtap='clearInput' type='clear' size='17' class='clear-icon'></icon>
</view>
\ No newline at end of file
.input-clear-wrapper {
position: relative;
width: 100%;
}
.input-clear-wrapper input {
background-color: #fff;
width: 100%;
padding: 15rpx 0 15rpx 20rpx;
}
.input-clear-wrapper .clear-icon {
position: absolute;
top:50%;
right:17rpx;
margin-top:-17rpx;
z-index: 100;
}
\ No newline at end of file
// components/inputmodal/inputmodal.js
Component({
/**
* 组件的属性列表
*/
properties: {
title: {
type: String,
value: '默认标题'
}
},
/**
* 组件的初始数据
*/
data: {
},
attached: function () {
// let systemInfo = wx.getSystemInfoSync()
// console.log(systemInfo)
},
/**
* 组件的方法列表
*/
methods: {
cancel() {
this.triggerEvent('inputModalClick', {data: 'cancel'}, {})
},
confirm() {
this.triggerEvent('inputModalClick', { data: 'confirm' }, {})
}
}
})
{
"component": true,
"usingComponents": {}
}
\ No newline at end of file
<view class='inputmodal-wrapper'>
<view class='content'>
<view class='title'>{{title}}</view>
<view class='slot'>
<slot></slot>
</view>
<view class='button-group'>
<view class='btn' hover-class='btn-hover' style='border-right: 2rpx solid #ccc;' bindtap='cancel'>取消</view>
<view class='btn' hover-class='btn-hover' style='color: rgb(99,181,130);' bindtap='confirm'>确定</view>
</view>
</view>
</view>
\ No newline at end of file
.inputmodal-wrapper {
position: fixed;
top: 0;
bottom: 0;
right: 0;
left: 0;
background-color: rgba(0, 0, 0, .5);
z-index: 9998;
}
.inputmodal-wrapper .content {
width: 540rpx;
height: 300rpx;
background-color: #F3F4F6;
position: absolute;
top: 50%;
left: 50%;
margin-left: -270rpx;
margin-top: -150rpx;
border-radius: 24rpx;
z-index: 9999;
}
.inputmodal-wrapper .content .title {
width:100%;
text-align:center;
line-height:114rpx;
font-size:34rpx;
color: #030303;
}
.inputmodal-wrapper .content .slot {
height: 110rpx;
display: flex;
flex-direction: column;
/* justify-content: center; */
}
.inputmodal-wrapper .content input{
margin: 0 auto;
width: 90%;
height: 64rpx;
padding: 0 8rpx;
line-height: 64rpx;
background-color: #fff;
border: 0 solid #4D4D4D;
font-size: 30rpx;
}
.button-group {
position: absolute;
bottom: 0;
width: 100%;
height: 84rpx;
display: flex;
flex-direction: row;
border-top: 2rpx solid #ccc;
font-size: 34rpx;
color: #007AFF;
}
.button-group .btn {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
}
.button-group .btn-hover {
background-color: rgba(0, 0, 0, .1);
}
let startX = 0
Component({
/**
* 组件的初始数据
*/
data: {
translateX: 0
},
/**
* 组件的方法列表
*/
methods: {
deleteItem: function (e) {
this.setData({
translateX: 0
})
this.triggerEvent('deleteChatItem', {}, {bubbles: true})
},
/**
* 滑动删除事件-滑动开始
*/
touchStartHandler: function(e) {
startX = e.touches[0].pageX
},
/**
* 滑动删除事件-滑动
*/
touchMoveHandler: function(e) {
let pageX = e.touches[0].pageX
let moveX = pageX - startX
if(Math.abs(moveX) < 40) {
return
}
// e.target.style.WebkitTransform = `translateX(${moveX}px)`
if (moveX > 0) { // 右滑 隐藏删除
if (Math.abs(this.data.translateX) == 0) {
return
} else {
this.setData({
translateX: 0
})
}
} else { // 左滑 显示删除
if (Math.abs(this.data.translateX) >= 80) {
return
} else {
this.setData({
translateX: -80
})
}
}
}
}
})
{
"component": true,
"usingComponents": {}
}
\ No newline at end of file
<view class='swipedelete-wrapper' bindtouchmove='touchMoveHandler' bindtouchstart='touchStartHandler' style="transform:translateX({{translateX}}px)">
<slot></slot>
<view class='swipedelete-btn' bindtap='deleteItem'>删除</view>
</view>
\ No newline at end of file
.swipedelete-wrapper {
transition: all .4s ease;
}
.swipedelete-btn {
position:absolute;
top:0;
right:-180rpx;
text-align:center;
background: #f00;
color:#fff;
width:160rpx;
height:100%;
display:flex;
justify-content:center;
align-items:center;
}
\ No newline at end of file
Component({
properties: {
config: {
type: Object,
value: {
x: 0,
y: 0,
width: 0,
height: 0
}
},
debug: {
type: Boolean,
value: false
},
/**
* 加载状态:loading、ready、error
*/
status: {
type: String,
value: 'loading',
observer: function (newVal, oldVal, changedPath) {
console.log(`player status changed from ${oldVal} to ${newVal}`)
}
},
/**
* 画面方向,可选值有 vertical,horizontal
*/
orientation: {
type: String,
value: 'vertical'
},
objectFit: {
type: String,
value: 'fillCrop'
},
name: {
type: String,
value: ''
},
uid: {
type: String,
value: ''
},
coverText: {
type: String,
value: ''
},
url: {
type: String,
value: '',
observer: function (newVal, oldVal, changedPath) {
}
}
},
data: {
livePlayerContext: null,
detached: false
},
/**
* 组件的方法列表
*/
methods: {
/**
* 组件生命周期:在组件布局完成后执行,此时可以获取节点信息
*/
ready() {
console.log(`yunxinplayer-${this.data.uid} ready`)
if (this.data.livePlayerContext) {
this.data.livePlayerContext = wx.createLivePlayerContext(`yunxinplayer-${this.data.uid}`, this)
}
if (this.data.url) {
this.start()
}
},
/**
* 组件生命周期:在组件实例被从页面节点树移除时执行
*/
detached() {
console.log(`yunxinplayer-${this.data.uid} detached`)
wx.createLivePlayerContext(`yunxinplayer-${this.data.uid}`, this).stop()
this.data.detached = true
},
/**
* 开始拉流播放
*/
start() {
const uid = this.data.uid
if (this.data.status === 'ready') {
console.log(`player ${uid} already started`)
return
}
if (this.data.detached) {
console.log(`try to start player while component already detached`)
return
}
console.log(`starting player ${uid}`)
this.data.livePlayerContext.play()
},
/**
* 停止拉流播放
*/
stop() {
console.log(`stopping player ${this.data.uid}`)
wx.createLivePlayerContext(`yunxinplayer-${this.data.uid}`, this).stop()
},
/**
* 切换画面方向
* true为 horizontal,false为 vertical
*/
changeOrientation(isHorizontal) {
let orientation = isHorizontal ? 'horizontal' : 'vertical'
this.setData({
orientation: orientation
})
},
/**
* 切换填充模式
* true为 fillCrop,false为 contain
*/
changeObjectFit(isFillCrop) {
let objectFit = isFillCrop ? 'fillCrop' : 'contain'
this.setData({
objectFit: objectFit
})
},
/**
* 播放器状态更新回调
*/
stateChangeHandler(e) {
console.warn(`yunxin-player code: ${e.detail.code} - ${e.detail.message}`)
let uid = parseInt(e.target.id.split('-')[1])
if (e.detail.code === 2004) {
console.log(`live-player ${uid} started playing`)
if (this.data.status === 'loading') {
this.setData({
status: 'ready'
})
}
} else if (e.detail.code === -2301) {
console.log(`live-player ${uid} stopped`, 'error')
this.setData({
status: 'error'
})
this.triggerEvent('pullfailed');
}
},
/**
* 改变画面蒙面
*/
changeStatus(status) {
switch(status) {
case 'leave':
case 'notConnected': {
break
}
default: {
status = this.data.status
}
}
// console.error(status)
this.setData({
status
})
},
/**
* 开启调试
*/
toggleDebug(isDebug) {
this.setData({
debug: isDebug
})
}
}
})
{
"component": true,
"usingComponents": {}
}
\ No newline at end of file
<!--components/yunxin-player/yunxin-player.wxml-->
<view class="play-container" style="left:{{config.x}}px; top:{{config.y}}px; width: {{config.width}}px; height: {{config.height}}px; ">
<live-player
id="yunxinplayer-{{uid}}"
src="{{url}}"
mode="RTC"
class="player"
orientation="{{orientation}}"
min-cache="0.2"
max-cache="0.8"
bindstatechange="stateChangeHandler"
object-fit="{{objectFit}}"
autoplay
style="height: {{config.height}}px; position: absolute; width: 100%; top: 0; left: 0;background-color: transparent;"
debug="{{debug}}">
<slot />
<cover-view
wx-if="{{status !== 'ready'}}"
class="sud flex-center-column"
style="display:none;">
<!-- style="position: absolute; width: 100%; height:100%;display:flex;justify-content:center;align-items:center;"> -->
<cover-image style="width: 182rpx;height:240rpx" src="../../images/yunxin/{{status}}.png"></cover-image>
</cover-view>
<cover-view style="position: absolute;top:10px;left:10px;font-size: 28rpx; right: 10px;color:#ccc;" wx-if="{{coverText.length != 0}}">
{{coverText}}
</cover-view>
</live-player>
</view>
\ No newline at end of file
/* components/yunxin-player/yunxin-player.wxss */
.play-container{
background: black;
display: block;
position: absolute;
}
.sud{
background-color: #1B2A38;
opacity:0.65;
}
\ No newline at end of file
Component({
properties: {
config: {
type: Object,
value: {
x: 0,
y: 0,
width: 0,
height: 0
}
},
debug: {
type: Boolean,
value: false
},
minBitrate: {
type: Number,
value: 200
},
maxBitrate: {
type: Number,
value: 500
},
enableCamera: {
type: Boolean,
value: true
},
muted: {
type: Boolean,
value: false
},
beauty: {
type: String,
value: 0
},
aspect: {
type: String,
value: "3:4"
},
/**
* 加载状态:loading、ready、error
*/
status: {
type: String,
value: "loading",
observer: function (newVal, oldVal, changedPath) {
console.log(`yunxin-pusher status changed from ${oldVal} to ${newVal}`);
}
},
coverText: {
type: String,
value: ''
},
url: {
type: String,
value: "",
observer: function (newVal, oldVal, changedPath) {
}
}
},
/**
* 组件的初始数据
*/
data: {
livePusherContext: null, // 组件操作上下文
detached: false // 组件是否被移除标记
},
/**
* 组件生命周期
*/
lifetimes: {
/**
* 在组件实例被从页面节点树移除时执行
*/
detached: function () {
console.log("yunxin-pusher detached");
// auto stop yunxin-pusher when detached
// this.stop()
this.setData({
detached: true
})
},
/**
* 在组件布局完成后执行,此时可以获取节点信息
*/
attached: function () {
console.log("yunxin-pusher ready")
this.start()
this.setData({
detached: false
})
},
},
/**
* 组件的方法列表
*/
methods: {
/**
* 播放推流
* 一般情况下不应手动调用,在推流组件预备好后会自动被调用
*/
start(options = {}) {
if (!this.livePusherContext) {
this.livePusherContext = wx.createLivePusherContext()
}
console.log(`starting yunxin-pusher`);
this.livePusherContext.start(options)
},
/**
* 停止推流
*/
stop(options = {}) {
if (this.livePusherContext) {
console.log(`stopping yunxin-pusher`);
this.livePusherContext.stop(options)
}
},
/**
* 切换前后摄像头
*/
switchCamera() {
this.livePusherContext.switchCamera()
},
/**
* 快照
*/
snapshot() {
this.livePusherContext.snapshot()
},
/**
* 推流状态变化事件回调
*/
stateChangeHandler(e) {
console.warn(`yunxin-pusher code: ${e.detail.code} - ${e.detail.message}`)
if (e.detail.code === -1307) { // 网络断连,且经多次重连抢救无效,更多重试请自行重启推
console.log('yunxin-pusher stopped', `code: ${e.detail.code}`);
this.setData({
status: "error"
})
this.livePusherContext.stop({
complete: () => {
this.livePusherContext.start()
}
})
this.triggerEvent('pushfailed');
} else if (e.detail.code === 1008) { // 编码器启动
console.log(`yunxin-pusher started`, `code: ${e.detail.code}`);
if (this.data.status === "loading") {
this.setData({
status: "ready"
})
}
}
},
/**
* 网络状态通知回调
*/
netChangeHandler(e) {
// console.log(`network: ${JSON.stringify(e.detail)}`);
},
/**
* 开启调试
*/
toggleDebug(isDebug) {
this.setData({
debug: isDebug
})
}
}
})
{
"component": true,
"usingComponents": {}
}
\ No newline at end of file
<!--components/yunxin-pusher/yunxin-pusher.wxml-->
<view class="pusher-container" id="rtcpusher" style="left: {{config.x}}px; top: {{config.y}}px; width: {{config.width}}px; height: {{config.height}}px; position: absolute;">
<live-pusher
style="height:{{config.height}}px; position: absolute; width: 100%; "
url="{{url}}"
wx:if="{{url.length !== 0}}"
mode="RTC"
aspect="{{aspect}}"
class="camera"
bindstatechange="stateChangeHandler"
bindnetstatus="netChangeHandler"
background-mute="true"
enable-camera="{{enableCamera}}"
muted="{{muted}}"
beauty="{{beauty}}"
max-bitrate="500"
min-bitrate="200"
debug="{{debug}}"
autopush="true">
<slot />
<cover-view
wx-if="{{status !== 'ready'}}"
class="sud flex-center-column"
style="display:flex;position: absolute; width: 100%; height: 100%;justify-content:center;align-items:center;">
<cover-image style="width: 182rpx;height:240rpx" src="../../images/yunxin/{{status}}.png"></cover-image>
</cover-view>
<cover-view style="position: absolute;top:10px;left:10px;font-size: 28rpx; right: 10px;color:#ccc;" wx-if="{{coverText.length != 0}}">
{{coverText}}
</cover-view>
</live-pusher>
</view>
/* components/yunxin-pusher/yunxin-pusher.wxss */
.pusher-container{
background: black;
display: block;
position: absolute;
}
.sud{
background-color: #1B2A38;
opacity:0.65;
}
\ No newline at end of file
...@@ -18,7 +18,7 @@ let configMap = { ...@@ -18,7 +18,7 @@ let configMap = {
url: 'http://preapp.netease.im:8184' url: 'http://preapp.netease.im:8184'
}, },
online: { online: {
appkey: '45c6af3c98409b18a84451215d0bdd6e', appkey: 'b612b31e837c79c68f141aeb719d2b20',
url: 'https://app.netease.im' url: 'https://app.netease.im'
}, },
}; };
......
...@@ -15,7 +15,7 @@ export default class IMController { ...@@ -15,7 +15,7 @@ export default class IMController {
// 初始化SDk // 初始化SDk
// debug: true, // debug: true,
appKey: app.globalData.ENVIRONMENT_CONFIG.appkey, appKey: app.globalData.ENVIRONMENT_CONFIG.appkey,
token: MD5(headers.token), token: headers.token,
account: headers.account, account: headers.account,
promise: true, promise: true,
transports: ['websocket'], transports: ['websocket'],
......
import IMController from '../../../controller/im.js' import IMController from '../../../controller/im.js'
import { connect } from '../../../redux/index.js' import { connect } from '../../../redux/index.js'
import { showToast, calcTimeHeader, clickLogoJumpToCard } from '../../../utils/util.js' import { showToast, calcTimeHeader, clickLogoJumpToCard, getUsers, formatDate } from '../../../utils/util.js'
import { iconNoMessage } from '../../../utils/imageBase64.js' import { iconNoMessage } from '../../../utils/imageBase64.js'
let app = getApp() let app = getApp()
let store = app.store let store = app.store
let queryUserQueuee = app.globalData.queryUser
let startX = 0 let startX = 0
...@@ -206,7 +207,7 @@ let pageConfig = { ...@@ -206,7 +207,7 @@ let pageConfig = {
app.globalData.nim.resetSessionUnread(session) app.globalData.nim.resetSessionUnread(session)
// 跳转 // 跳转
wx.navigateTo({ wx.navigateTo({
url: `../../partials/chating/chating?chatTo=${account}&type=${chatType}`, url: `../../../partials/chating/chating?chatTo=${account}&type=${chatType}`,
}) })
}, },
/** /**
...@@ -259,17 +260,19 @@ let pageConfig = { ...@@ -259,17 +260,19 @@ let pageConfig = {
/** /**
* 将原生消息转化为最近会话列表渲染数据 * 将原生消息转化为最近会话列表渲染数据
*/ */
convertRawMessageListToRenderChatList(rawMessageList, friendCard, groupList, unreadInfo) { convertRawMessageListToRenderChatList(rawMessageList, friendCard, groupList, unreadInfo,userCard) {
let chatList = [] let chatList = []
let sessions = Object.keys(rawMessageList) let sessions = Object.keys(rawMessageList)
let index = 0 let index = 0
let unQueryUsers=[]
sessions.map(session => { sessions.map(session => {
let account = session.indexOf('team-') === 0 ? session.slice(5, session.length) : session.slice(4, session.length) let account = session.indexOf('team-') === 0 ? session.slice(5, session.length) : session.slice(4, session.length)
let isP2p = session.indexOf('p2p-') === 0 let isP2p = session.indexOf('p2p-') === 0
let chatType = isP2p ? 'p2p' : (groupList[account] && groupList[account].type) let chatType = isP2p ? 'p2p' : (groupList[account] && groupList[account].type)
let sessionCard = (isP2p ? friendCard[account] : groupList[account]) || {} let sessionCard = (isP2p ? friendCard[account] : groupList[account]) || {}
let ucard = (isP2p ? userCard[account] : {}) || {}
let unixtimeList = Object.keys(rawMessageList[session]) let unixtimeList = Object.keys(rawMessageList[session])
if (!unixtimeList) { if (!unixtimeList || account =='684cb79fe92f46877777') {
return return
} }
let maxTime = Math.max(...unixtimeList) let maxTime = Math.max(...unixtimeList)
...@@ -278,8 +281,17 @@ let pageConfig = { ...@@ -278,8 +281,17 @@ let pageConfig = {
let msgType = this.judgeMessageType(msg) let msgType = this.judgeMessageType(msg)
let lastestMsg = msgType let lastestMsg = msgType
let status = isP2p ? (sessionCard.status || '离线') : '' let status = isP2p ? (sessionCard.status || '离线') : ''
let nick = isP2p ? (sessionCard.nick || '非好友') : sessionCard.name let nick = isP2p ? (sessionCard.nick || ucard.nick || '非好友') : sessionCard.name
let avatar = isP2p ? (sessionCard.avatar || app.globalData.PAGE_CONFIG.defaultUserLogo) : (sessionCard.avatar || app.globalData.PAGE_CONFIG.defaultUserLogo) if(nick=='非好友'){
for (var key in rawMessageList[session]) {
nick = rawMessageList[session][key].fromNick;
}
if (!queryUserQueuee[account]){
queryUserQueuee[account]=account
getUsers(account, store)
}
}
let avatar = isP2p ? (sessionCard.avatar || ucard.avatar || app.globalData.PAGE_CONFIG.defaultUserLogo) : (sessionCard.avatar || app.globalData.PAGE_CONFIG.defaultUserLogo)
chatList.push({ chatList.push({
chatType, chatType,
session, session,
...@@ -291,7 +303,7 @@ let pageConfig = { ...@@ -291,7 +303,7 @@ let pageConfig = {
type: msgType || msg.type, type: msgType || msg.type,
timestamp: msg.time, timestamp: msg.time,
unread: unreadInfo[session] || 0, unread: unreadInfo[session] || 0,
displayTime: msg.time ? calcTimeHeader(msg.time) : '' displayTime: msg.time ? formatDate(msg.time) : ''
}) })
} }
}) })
...@@ -301,6 +313,11 @@ let pageConfig = { ...@@ -301,6 +313,11 @@ let pageConfig = {
}) })
return chatList return chatList
}, },
getUserNick(obj) { //obj为我们的对象
var n = {};
return n.fromNick||"";
},
/** /**
* 计算最近一条发送的通知消息列表 * 计算最近一条发送的通知消息列表
*/ */
...@@ -331,7 +348,7 @@ let pageConfig = { ...@@ -331,7 +348,7 @@ let pageConfig = {
} }
} }
let mapStateToData = (state) => { let mapStateToData = (state) => {
let chatList = pageConfig.convertRawMessageListToRenderChatList(state.rawMessageList, state.friendCard, state.groupList, state.unreadInfo) let chatList = pageConfig.convertRawMessageListToRenderChatList(state.rawMessageList, state.friendCard, state.groupList, state.unreadInfo, state.userCard)
let latestNotification = pageConfig.caculateLastestNotification(state.notificationList) let latestNotification = pageConfig.caculateLastestNotification(state.notificationList)
return { return {
rawMessageList: state.rawMessageList, rawMessageList: state.rawMessageList,
......
...@@ -9,24 +9,8 @@ ...@@ -9,24 +9,8 @@
<input type='text' bindinput='searchInput' class="search-input {{showSearchBox==1?'':'hide'}}" bindblur="changeSearchBox" data-type="0" focus='{{isFocus}}'/> <input type='text' bindinput='searchInput' class="search-input {{showSearchBox==1?'':'hide'}}" bindblur="changeSearchBox" data-type="0" focus='{{isFocus}}'/>
</view> </view>
<view class="msg-box"> <view class="msg-box">
<view class="msg-item">
<image class="avater" src="http://imgfile.oytour.com/New/Upload/User/20191018150051176.png"></image> <view class="msg-item" wx:if="{{chatList.length != 0}}" wx:for="{{chatList}}" wx:for-item="message" wx:key="message.time" data-session='{{message.session}}' data-account='{{message.account}}' data-session='{{message.session}}' bindtap='switchToChating'>
<view class="msg-content">
<view class="item-name">
罗超
</view>
<view class="lst-msg">
如果来不及的话,就直接使用Vue-table来做,这样会快一点
</view>
</view>
<view class="times">
<view class="timer">16:23</view>
<view>
<text class="pops">9</text>
</view>
</view>
</view>
<view class="msg-item" wx:if="{{chatList.length != 0}}" wx:for="{{chatList}}" wx:for-item="message" wx:key="message.time" data-session='{{message.session}}'>
<image class="avater" src="{{message.avatar}}"></image> <image class="avater" src="{{message.avatar}}"></image>
<view class="msg-content"> <view class="msg-content">
<view class="item-name"> <view class="item-name">
...@@ -37,7 +21,7 @@ ...@@ -37,7 +21,7 @@
</view> </view>
</view> </view>
<view class="times"> <view class="times">
<view class="timer">昨天</view> <view class="timer">{{message.displayTime}}</view>
<view wx:if="{{message.unread}}"> <view wx:if="{{message.unread}}">
<text class="pops">{{message.unread || ''}}</text> <text class="pops">{{message.unread || ''}}</text>
</view> </view>
......
...@@ -70,8 +70,9 @@ page{ ...@@ -70,8 +70,9 @@ page{
flex: 1; flex: 1;
} }
.msg-box .msg-item .msg-content .item-name{ .msg-box .msg-item .msg-content .item-name{
font-size: 36rpx; font-size: 32rpx;
font-weight: 600; font-weight: 600;
margin-top: 10rpx;
} }
.msg-box .msg-item .msg-content .lst-msg{ .msg-box .msg-item .msg-content .lst-msg{
font-size: 28rpx; font-size: 28rpx;
......
This diff is collapsed.
{
"navigationBarTitleText": "",
"navigationStyle":"default",
"usingComponents": {
"component-emoji": "/components/emoji/emoji",
"input-modal": "/components/inputmodal/inputmodal"
}
}
This diff is collapsed.
page{
height: 100%;
}
.chating-wrapper {
width: 100%;
min-height: 100%;
position: relative;
/* margin: 70rpx 0 100rpx; */
box-sizing: border-box;
/* overflow: hidden; */
background: #F3F4F6;
}
/* 收起键盘热区 */
.fold-keyboad-wrapper {
position: fixed;
top: 70rpx;
width: 100%;
height: 500rpx;
}
/*历史消息 */
.chating-history {
position: fixed;
padding: 0 20rpx;
width:100%;
height:80rpx;
line-height:80rpx;
box-sizing: border-box;
border: 1px solid #E7E7E7;
background-color: #E7E7E7;
z-index: 1;
color: #888888;
font-size: 30rpx;
}
.chating-history-left {
float: left;
color: #666;
}
.chating-history-right {
float: right;
}
/*聊天输入框 */
.chatinput-wrapper {
width: 100%;
background-color: #fff;
border: 2rpx solid #ccc;
position: fixed;
bottom: 0;
left: 0;
}
.chatinput-content {
width: 100%;
height: 100rpx;
}
.chatinput-img{
width: 60rpx;
height: 60rpx;
border-radius: 100%;
margin: 20rpx 20rpx;
display: inline-block;
}
.chatinput-img.emoji{
margin-right: 0;
}
.chatinput-img:active {
opacity: .6;
}
.chatinput-input {
width: 466rpx;
min-height: 72rpx;
border-radius: 12rpx;
border: 1px solid #ccc;
margin-top: 15rpx;
display: inline-block;
vertical-align:top;
box-sizing:border-box;
padding-left: 20rpx;
font-size: 30rpx;
}
.chatinput-voice-mask {
width: 466rpx;
height: 76rpx;
line-height: 76rpx;
display: inline-block;
border-radius: 12rpx;
border: 1px solid #ccc;
margin-top: 12rpx;
vertical-align:top;
box-sizing:border-box;
/* padding-left: 20rpx; */
font-size: 30rpx;
text-align: center;
color: #333336;
background-color: #fff;
letter-spacing: 4rpx;
}
.chatinput-voice-mask-hover {
background-color: #cecece;
color: #333336;
}
/*subcontent wrapper */
.chatinput-subcontent {
width: 100%;
height: 470rpx;
background-color: #999;
}
.fr {
float: right;
}
/* more-subcontent */
.more-subcontent {
padding: 40rpx 30rpx;
border:2rpx solid #ccc;
}
.more-subcontent .more-subcontent-item {
display:flex;
flex-direction:column;
margin-bottom: 30rpx;
}
.more-subcontent .more-subcontent-item .image {
width:112rpx;
height:112rpx;
border-radius:50%;
margin-bottom: 12rpx;
}
.more-subcontent .more-subcontent-item .text {
font-size: 24rpx;
text-align:center;
color: #6C7074;
}
/*聊天记录 */
.record-wrapper {
width: 100%;
padding-bottom: 100rpx;
padding-top:80rpx;
}
.record-chatting-item {
width: 100%;
padding: 20rpx 20rpx;
box-sizing: border-box;
}
.record-item-time-wrapper {
display:flex;
flex-direction:row;
justify-content:center;
}
.record-item-time {
padding:4rpx 10rpx;
background: #D6D6D6;
border-radius: 8rpx;
font-size: 24rpx;
color: #fff;
}
.record-chatting-item-img {
width: 80rpx;
height: 80rpx;
border-radius: 100%;
display: inline-block;
}
.record-chatting-item-text {
max-width: 70%;
border-radius: 8rpx;
background-color: #3387FF;
padding: 16rpx;
box-sizing:border-box;
word-wrap:break-word;
overflow: hidden;
font-size: 32rpx;
line-height: 48rpx;
}
.record-chatting-item-text.nobg {
background: transparent;
margin-left: 20rpx;
margin-right: 20rpx;
}
/* tip消息富文本 */
.tip-rich-text {
background-color:#ccc;
text-align:center;
align-self:center;
min-height:40rpx;
word-break:break-word;
font-size:26rpx;
padding:0 20rpx;
color:#000;
border-radius: 10rpx;
}
.self {
display: flex;
flex-direction: row;
justify-content: flex-end;
color: #fff;
}
.other {
display: flex;
flex-direction: row;
justify-content: flex-start;
color: #222;
}
.left-triangle{
height:0px;
width:0px;
border-width:20rpx;
border-style:solid;
border-color:transparent #fff transparent transparent;
margin-top: 20rpx;
}
.right-triangle{
height:0px;
width:0px;
border-width:20rpx;
border-style:solid;
border-color:transparent transparent transparent #3387FF;
margin-top: 20rpx;
}
.video-triangle {
height:0px;
width:0px;
border-width:30rpx;
border-style:solid;
border-color:transparent transparent transparent #777;
margin-top: 20rpx;
margin-left: 30rpx;
}
.small-map-wrapper {
overflow: hidden;
width: 452rpx;
height:300rpx;
position:relative;
border-radius:8rpx;
}
.self .small-map-wrapper {
margin-right: 20rpx;
}
.other .small-map-wrapper {
margin-left: 20rpx;
}
.small-map-wrapper .small-geo-img {
width: 100%;
height: 100%;
background-color: pink;
}
.small-map-wrapper .text {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
position: absolute;
bottom: 0;
left: 0;
right: 0;
box-sizing: border-box;
width: 100%;
padding: 10rpx;
min-height: 70rpx;
/* line-height: 70rpx; */
opacity: 0.75;
font-size: 28rpx;
/* white-space: nowrap; */
text-align: center;
text-overflow: ellipsis;
background-color:#444;
color:#fff;
}
.small-video-wrapper {
margin-left: 20rpx;
margin-right: 20rpx;
width:200rpx;
height:200rpx;
padding:10rpx;
background-color:#fff;
border-radius:20rpx;
display:flex;
justify-content:center;
flex-direction:column;
align-items:center;
}
.small-video-wrapper .video {
max-width:200px;
max-height:300px;
}
.audio-wrapper {
background-color:#fff;
border-radius:28rpx;
display:flex;
justify-content:space-between;
padding:0 20rpx;
min-width: 30%;
box-sizing:border-box;
margin-left:-2px;
}
.audio-wrapper .image {
width:70rpx;
height:70rpx;
align-self:center;
}
.audio-wrapper .text {
align-self:center;
color:#fff;
}
...@@ -78,6 +78,7 @@ function shallowEqual(objA, objB) { ...@@ -78,6 +78,7 @@ function shallowEqual(objA, objB) {
} }
return true return true
} }
module.exports = { module.exports = {
isPlainObject, isPlainObject,
ActionTypes, ActionTypes,
......
...@@ -635,6 +635,15 @@ let indexReducer = (state = INITIAL_STATE, action) => { ...@@ -635,6 +635,15 @@ let indexReducer = (state = INITIAL_STATE, action) => {
tempState.netcallGroupCallInfo = Object.assign({}, groupCall) tempState.netcallGroupCallInfo = Object.assign({}, groupCall)
return Object.assign({}, state, tempState) return Object.assign({}, state, tempState)
} }
case 'Update_Im_Usercard':{
let tempState = Object.assign({}, state)
let card=action.payload.user
console.log(card)
tempState.userCard = Object.assign({}, tempState.userCard)
tempState.userCard[card.account] = Object.assign({}, tempState.userCard[card.account], card)
console.log(tempState.userCard)
return Object.assign({}, state, tempState)
}
default: default:
return state return state
} }
......
...@@ -5,6 +5,7 @@ const INITIAL_STATE = { ...@@ -5,6 +5,7 @@ const INITIAL_STATE = {
currentChatTo: '', // 正在聊天 sessionId currentChatTo: '', // 正在聊天 sessionId
friendCard: {}, //好友列表,含名片信息,额外添加在线信息 friendCard: {}, //好友列表,含名片信息,额外添加在线信息
onlineList: {}, // 在线好友列表 onlineList: {}, // 在线好友列表
userCard:{},//非好友用户资料
// messageListToRender: {}, // messageListToRender: {},
currentGroup: {}, currentGroup: {},
currentGroupMembers: [], currentGroupMembers: [],
......
...@@ -470,6 +470,24 @@ function clickLogoJumpToCard(friendsCard, account, isPush) { ...@@ -470,6 +470,24 @@ function clickLogoJumpToCard(friendsCard, account, isPush) {
}) })
} }
} }
/**
* 获取指定数组内的用户资料
*/
function getUsers(account,store){
app.globalData.nim.getUser({
account,
done: function(error,user){
if(user){
store.dispatch({
type: 'Update_Im_Usercard',
payload: {
user
}
})
}
}
});
}
/** /**
* 获取格式化后的好友列表 * 获取格式化后的好友列表
* friendCard: 好友列表(含名片信息) * friendCard: 好友列表(含名片信息)
...@@ -913,6 +931,63 @@ function dealMsg(msg, store, app) { ...@@ -913,6 +931,63 @@ function dealMsg(msg, store, app) {
}) })
} }
} }
function stringifyDate (datetime, simple = false) {
// let weekMap = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
let weekMap = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
datetime = new Date(datetime)
let year = datetime.getFullYear()
let simpleYear = datetime.getYear() - 100
let month = datetime.getMonth() + 1
month = month > 9 ? month : '0' + month
let day = datetime.getDate()
day = day > 9 ? day : '0' + day
let hour = datetime.getHours()
hour = hour > 9 ? hour : '0' + hour
let min = datetime.getMinutes()
min = min > 9 ? min : '0' + min
let week = datetime.getDay()
week = weekMap[week]
let thatDay = (new Date(year, month - 1, day, 0, 0, 0)).getTime()
if (simple) {
return {
withYear: `${day}/${month}/${simpleYear}`,
withMonth: `${month}-${day}`,
withDay: `${week}`,
withLastDay: `昨天`,
withHour: `${hour}:${min}`,
thatDay
}
} else {
return {
withYear: `${year}-${month}-${day} ${hour}:${min}`,
withMonth: `${month}-${day} ${hour}:${min}`,
withDay: `${week} ${hour}:${min}`,
withLastDay: `昨天 ${hour}:${min}`,
withHour: `${hour}:${min}`,
thatDay
}
}
}
function formatDate(datetime, simple = true) {
let tempDate = (new Date()).getTime()
let result = stringifyDate(datetime, simple)
let thatDay = result.thatDay
let deltaTime = (tempDate - thatDay) / 1000
if (deltaTime < 3600 * 24) {
return result.withHour
} else if (deltaTime < 3600 * 24 * 2) {
return result.withLastDay
} else if (deltaTime < 3600 * 24 * 7) {
return result.withDay
} else if (deltaTime < 3600 * 24 * 30) {
return result.withMonth
} else {
return result.withYear
}
}
module.exports = { module.exports = {
calculateMeetingPosition, calculateMeetingPosition,
formatDate, formatDate,
...@@ -929,10 +1004,12 @@ module.exports = { ...@@ -929,10 +1004,12 @@ module.exports = {
correctData, correctData,
deepClone, deepClone,
clickLogoJumpToCard, clickLogoJumpToCard,
getUsers,
generateRichTextNode, generateRichTextNode,
generateFingerGuessImageFile, generateFingerGuessImageFile,
generateBigEmojiImageFile, generateBigEmojiImageFile,
generateImageNode, generateImageNode,
getFormatFriendList, getFormatFriendList,
dealMsg dealMsg,
formatDate
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment