Skip to content

Instantly share code, notes, and snippets.

@TooBug
Created December 23, 2016 09:36
Show Gist options
  • Save TooBug/175428658f0d3e081fc977809c4b9918 to your computer and use it in GitHub Desktop.
Save TooBug/175428658f0d3e081fc977809c4b9918 to your computer and use it in GitHub Desktop.
未上线的聊天系统前端代码
/**
* 封装Comet长连接操作,其中extraRequestData暴露出来,可供动态修改下次请求时的参数
* @author TooBug
* @version 2014-08-02
* @example
var a=new Comet({
url:'http://echo.113.im/',
data:{
data:JSON.stringify({test:123}),
timeout:10000
},
onData:function(data){
console.log(data);
if(!this.extraRequestData.test){
this.extraRequestData.test = 1;
}else{
this.extraRequestData.test ++;
}
}
});
*/
define([
'jquery'
],function($){
// 默认配置项
var defaultOptions = {
onData:$.noop,
onClose:$.noop,
onError:$.noop,
dataType:'json',
data:{},
method:'get',
timeout:300*1000 //默认300秒超时
};
/**
* @constructor Comet构造函数
* @param {Object} options 参数对象
* @param {String} options.url 远程地址URL
* @param {Object} options.data 请求要带的参数
* @param {String} options.dataType 数据类型,与jQuery.ajax相同
* @param {Number} options.timeout Ajax超时时间(非Comet超时时间,Comet超时由后台定义)
* @param {Function} options.onData 有数据返回时的回调函数,this为Comet实例
* @param {Function} options.onError 出错时的回调函数,this为Comet实例
* @param {Function} options.onClose 关闭连接时的回调函数,this为Comet实例
* @return {Object} Comet实例
*/
var Comet = function(options){
this.init(options);
};
/**
* Comet实例初始化
* @param {Object} options 与默认参数合并后的参数对象,与构建函数接受的参数项目相同
* @return {Object} 返回当前Comet实例
*/
Comet.prototype.init = function(options){
this.options = $.extend({},defaultOptions,options);
this.extraRequestData = {};
this.doConnect();
this.working = true;
return this;
};
/**
* 连接远程服务器
* @return {Object} 返回当前Comet实例
*/
Comet.prototype.doConnect = function(){
var _this = this;
var data = $.extend({},this.extraRequestData,this.options.data);
$.ajax({
url:this.options.url,
dataType:this.options.dataType,
data:data,
type:this.options.method,
timeout:this.options.timeout
}).done(function(data){
if(_this.working){
_this.options.onData.call(_this,data);
}
}).fail(function(xhr,msg,err){
if(_this.working){
_this.options.onError.call(_this,msg,err);
}
}).always(function(){
if(_this.working){
_this.doConnect();
}
});
return this;
};
/**
* 暂停Comet实例工作,将暂停ajax轮询及函数回调(包括已经在进行中的请求的回调)
* @return {Object} 返回当前Comet实例
*/
Comet.prototype.pause = function(){
this.working = false;
return this;
};
/**
* 恢复Comet实例工作,将立刻发起连接
* @return {Object} 返回当前Comet实例
*/
Comet.prototype.resume = function(){
this.doConnect();
this.working = true;
return this;
};
/**
* 关闭Comet实例连接
* @return {Object} 返回当前Comet实例
*/
Comet.prototype.close = function(){
this.working = false;
this.options.onClose.call(this);
return this;
};
return Comet;
});
/*global moment*/
define([
'underscore.min',
'jquery',
'app/futu5/chat/memberpicker',
'app/futu5/chat/emotion'
],function(_,$,memberPicker,emotion){
var messageItemTmpl = $('#messageItemTmpl').html();
var renderMessageFunc = _.template(messageItemTmpl);
var $chatBox = $('#chatBox');
var $conversationDetail = $('#conversationDetail');
var $messageWrapper = $('#messageWrapper');
var $messageTitle = $('#messageTitle');
var $showDetail = $('#operateWrapper .showDetail');
var $isBlockedTrue = $('#operateWrapper .isBlockedTrue');
var $isBlockedFalse = $('#operateWrapper .isBlockedFalse');
var $doBlockConversation = $('#operateWrapper .doBlockConversation');
var $doUnblockConversation = $('#operateWrapper .doUnblockConversation');
var conversationMemberItemTmpl = $('#conversationMemberItemTmpl').html();
var renderConversationMemberFunc = _.template(conversationMemberItemTmpl);
var currentConversation;
var Conversation = function(conversation){
$.extend(this,conversation);
this.messageList = this.messageList || [];
// this.active();
};
Conversation.TYPE_MAP = {
1:'group',
2:'single',
3:'stock',
4:'service',
5:'bbs',
6:'notice',
7:'company'
};
Conversation.ROLE_MAP = {
1:'master',
3:'member'
};
Conversation.STATUS_MAP = {
1:'normal'
};
Conversation.MESSAGE_TYPE_MAP = {
1:'text',
2:'image',
3:'invited',
4:'exited',
5:'kicked',
6:'titleChangeed'
};
/*Conversation.getCurrnetConversation = function(){
return currentConversation;
};*/
Conversation.scroll2Bottom = function(){
$messageWrapper.scrollTop($messageWrapper.get(0).scrollHeight);
};
Conversation.clearMessageList = function(){
$messageWrapper.empty();
};
Conversation.prototype.dealFeeds = function(message){
if(message.userId === window.MyUid) return;
var _this = this;
var uid;
if(message.type === 'invited'){
for(uid in message.extra.user_list){
this.memberList.push({
uid:+uid,
nickname:message.extra.user_list[uid].member_nick,
avatarUrl:message.extra.user_list[uid].member_icon,
});
}
}else if(message.type === 'exited'){
this.memberList.forEach(function(memberItem,index){
if(memberItem.uid === message.userId){
_this.memberList.splice(index,1);
}
});
}else if(message.type === 'kicked'){
for(uid in message.extra.user_list){
this.memberList.forEach(function(memberItem,index){
if(memberItem.uid === +uid){
_this.memberList.splice(index,1);
}
// 如果自己被T
if(+uid === window.MyUid){
alert('您已被群主 '+message.nickname+' 移出讨论组 “'+currentConversation.title+'”');
$(window).trigger('Conversation_Quit',[currentConversation.conversationId]);
}
});
}
}else if(message.type === 'titleChangeed'){
this.title = message.extra.group_name;
}
this.renderConversationDetail();
$(window).trigger('Conversation_Update',[this.conversationId]);
};
Conversation.prototype.renderMessage = function(data,onlyReturn){
var renderMap = {
text:{
type:'text',
},
image:{
type:'image',
},
invited:{
type:'notice',
html:'{%=nickname%}邀请 {%for(uid in extra.user_list){%}'+
'{%=extra.user_list[uid].member_nick%} '+
'{%}%}加入了会话'
},
exited:{
type:'notice',
html:'{%=nickname%}退出了会话'
},
kicked:{
type:'notice',
html:'{%=nickname%}将 {%for(uid in extra.user_list){%}'+
'{%=extra.user_list[uid].member_nick%} '+
'{%}%}踢出了会话'
},
titleChangeed:{
type:'notice',
html:'{%=nickname%}将会话标题修改为“{%=extra.group_name%}”'
},
};
var render = renderMap[data.type || 'text'];
var html;
switch(render.type){
case 'text':
html = renderMessageFunc(data);
break;
case 'notice':
html = '<div class="box_notice">'+_.template(render.html)(data)+'</div>';
break;
}
if(onlyReturn){
return html;
}
$messageWrapper.append(html);
Conversation.scroll2Bottom();
};
Conversation.prototype.renderAllMessage = function(){
var _this = this;
var html = this.messageList.map(function(messageItem){
return _this.renderMessage(messageItem,true);
});
$messageWrapper.html(html);
};
Conversation.prototype.renderTitle = function(){
$messageTitle.text(this.title);
};
Conversation.prototype.renderIsBlocked = function(){
if(this.isBlocked){
$isBlockedTrue.show();
$isBlockedFalse.hide();
}else{
$isBlockedTrue.hide();
$isBlockedFalse.show();
}
};
Conversation.prototype.renderConversationDetail = function(){
$conversationDetail.find('.memberCount span').text(this.memberList.length);
$conversationDetail.find('.conversationName').val(this.title);
$messageTitle.text(this.title);
$conversationDetail.find('.conversationMemberList').find('.conversationMemberItem').remove().end()
.prepend(renderConversationMemberFunc(this.memberList));
};
Conversation.prototype.pushMessage = function(message){
this.messageList.push(message);
if(!this.isActive){
if(message.type === 'text' || message.type === 'image'){
this.unreadCount++;
}
return;
}
if((message.type !== 'text' && message.type !== 'image') ||
message.role === 'other' || !Conversation.me){
this.renderMessage(message);
}
};
Conversation.prototype.getHistory = function(timestamp,direction){
return $.getJSON('/chat/get-group-message',{group_id:this.conversationId}).then(ajaxDoneFilter,ajaxFailFilter);
};
Conversation.prototype.update = function(){
var _this = this;
$.getJSON('/chat/group_info',{
group_id:this.conversationId
}).then(ajaxDoneFilter,ajaxFailFilter).done(function(data){
_this.avatarUrl = data.group_info.group_image_url;
_this.title = data.group_info.group_name;
_this.type = Conversation.TYPE_MAP[data.group_info.type];
_this.isBlocked = +data.is_shielded;
delete _this._isFake;
_this.memberList = data.group_info.member_list.map(function(memberItem){
return {
uid:+memberItem.member_uid,
role:Conversation.ROLE_MAP[memberItem.role],
status:Conversation.STATUS_MAP[memberItem.status],
avatarUrl:memberItem.member_icon,
nickname:memberItem.member_nick,
isBlocked:+memberItem.is_shielded
};
});
_this.renderTitle();
_this.renderIsBlocked();
_this.renderConversationDetail();
$(window).trigger('Conversation_Update',[_this.conversationId]);
});
};
Conversation.prototype.updateUnreadCount = function(){
this.unreadCount = 0;
};
Conversation.prototype.active = function(){
currentConversation = this;
var _this = this;
Conversation.clearMessageList();
this.renderTitle();
this.renderIsBlocked();
this.renderConversationDetail();
this.isActive = true;
this.switchDetail(false);
if(this.messageList && this.messageList.length){
doRender();
}else{
this.getHistory().done(function(data){
if(!data.message_list){
_this.messageList = [];
}else{
_this.messageList = data.message_list.map(function(item){
return {
messageId:+item.msg_id,
avatarUrl:item.member_icon,
nickname:item.member_nick,
role:+item.member_uid === window.MyUid?'my':'other',
userId:+item.member_uid,
time:item.create_time,
content:item.content,
type:Conversation.MESSAGE_TYPE_MAP[item.msg_type],
extra:item.extra
};
});
}
doRender();
});
}
function doRender(){
if(!_this.isActive) return;
_this.messageList.sort(function(message1,message2){
return message1.time < message2.time?-1:1;
});
_this.renderAllMessage();
Conversation.scroll2Bottom();
_this.updateUnreadCount();
updateReadTime(_this.conversationId);
// 发出事件,聚焦了,由list处理高亮
$(window).trigger('Conversation_Active',[currentConversation.conversationId]);
}
};
Conversation.prototype.sendMessage = function(content){
var _this = this;
var dfd = $.Deferred();
// 为了体验,先渲染,再在后台发送
var message = {
userId:window.MyUid,
time:Date.now(),
content:htmlEncode(content),
role:'my'
};
if(Conversation.me){
message.avatarUrl = Conversation.me.avatarUrl;
message.nickname = Conversation.me.nickname;
_this.renderMessage(message);
}
$.post('/chat/send-message',{
content:content,
group_id:this.conversationId
},$.noop,'json').then(ajaxDoneFilter,ajaxFailFilter).done(function(data){
dfd.resolve();
}).fail(function(){
_this.renderMessage({
avatarUrl:'https://my.futu5.com/images/noimg/bbsHead.jpg?2014.07.28.5.hk',
nickname:'test',
role:'my',
userId:1234,
time:Date.now(),
content:'“'+content+'”发送失败……'
});
dfd.reject();
});
return dfd;
};
Conversation.prototype.switchDetail = function(isShow){
if(isShow){
// if(this.type !== 'group') return;
$conversationDetail.show();
$chatBox.hide();
}else{
$conversationDetail.hide();
$chatBox.show();
}
};
Conversation.prototype.switchBlocked = function(isBlocked){
var _this = this;
$.post('/chat/shield-group',{
group_id:this.conversationId,
type:isBlocked?undefined:1
},$.noop,'json').then(ajaxDoneFilter,ajaxFailFilter).done(function(){
_this.isBlocked = isBlocked;
_this.renderIsBlocked();
}).fail(function(){
});
};
Conversation.prototype.delete = function(){
var _this = this;
$.post('/chat/delete-group',{
group_id:this.conversationId
},$.noop,'json').then(ajaxDoneFilter,ajaxFailFilter).done(function(){
// 发出删除事件,列表接收事件处理会话列表
$(window).trigger('Conversation_Delete',[_this.conversationId]);
}).fail(function(msg){
alert(msg);
});
};
Conversation.bindEvents = function(){
var _this = this;
// 发送消息
$('#sendMessage').click(function(){
var $textarea = $('#sendWrapper textarea');
if(!$textarea.val()) return false;
if(!currentConversation){
alert('暂无会话,请先新建会话再发送消息!');
return false;
}
currentConversation.sendMessage($textarea.val()).done(function(){
}).fail(function(){
$textarea.val($textarea.data('lastval'));
});
// 为了体验,先清空再发送
$textarea.data('lastval',$textarea.val()).val('');
return false;
});
// CTRL/Command+ENTER
$('#sendWrapper textarea').on('keydown',function(e){
var ctrlOrCmd = e.metaKey || e.ctrlKey;
if(e.keyCode === 13 && ctrlOrCmd){
$('#sendMessage').click();
return false;
}
});
// 表情
$('#sendWrapper .insertEmotion').on('click',function(){
emotion({
$trigger:$(this),
$container:$(this),
type:'niuniu',
$input:$('#sendWrapper textarea')
});
return false;
});
// 是否屏蔽
$doUnblockConversation.click(function(){
currentConversation.switchBlocked(false);
});
$doBlockConversation.click(function(){
currentConversation.switchBlocked(true);
});
// 显示会话详情
$showDetail.click(function(){
currentConversation.switchDetail(true);
return false;
});
// 关闭会话详情
$conversationDetail.find('.closeBtn').click(function(){
currentConversation.switchDetail(false);
return false;
});
// 添加成员
$conversationDetail.find('.conversationAddMember').click(function(){
memberPicker.init({
onSelect:function(memberList){
var memberStr = memberList.map(function(memberItem){
return memberItem.uid;
}).join(',');
$.post('/chat/add-member',{
group_id:currentConversation.conversationId,
uid_str:memberStr
},$.noop,'json').then(ajaxDoneFilter,ajaxFailFilter).done(function(data){
memberList.forEach(function(newMemberItem){
if(!currentConversation.memberList.some(function(exsitMemberItem){
return exsitMemberItem.uid === newMemberItem.uid;
})){
currentConversation.memberList.push({
uid:newMemberItem.uid,
role:'member',
status:'normal',
avatarUrl:newMemberItem.avatarUrl,
nickname:newMemberItem.nickname,
isBlocked:false
});
}
});
currentConversation.renderConversationDetail();
}).fail(function(msg){
alert('添加成员失败:'+msg);
});
memberPicker.hide();
}
});
return false;
});
// 删除成员
$conversationDetail.on('click','.deleteMember',function(){
var uid = +$(this).closest('li').data('uid');
$.post('/chat/delete-member',{
group_id:currentConversation.conversationId,
uid_str:uid
},$.noop,'json').then(ajaxDoneFilter,ajaxFailFilter).done(function(data){
currentConversation.memberList.forEach(function(memberItem,index){
if(memberItem.uid === uid){
currentConversation.memberList.splice(index,1);
}
});
currentConversation.renderConversationDetail();
}).fail(function(msg){
alert('删除成员失败:'+msg);
});
});
// 更改群聊名称
$conversationDetail.find('.conversationName').on('blur',function(){
var $input = this;
var newTitle = $input.value;
if(newTitle === currentConversation.title) return;
if(newTitle){
$.post('/chat/modify-group-name',{
group_id:currentConversation.conversationId,
group_name:newTitle
},$.noop,'json').then(ajaxDoneFilter,ajaxFailFilter).done(function(data){
currentConversation.title = newTitle;
currentConversation.renderTitle();
}).fail(function(msg){
alert(msg);
$input.value = currentConversation.title;
});
}
});
// 退出聊天
$('#operateWrapper .quitBtn').click(function(){
$.post('/chat/quit-group',{
group_id:currentConversation.conversationId
},$.noop,'json').then(ajaxDoneFilter,ajaxFailFilter).done(function(data){
// 发出退出会话的事件,让list来处理
$(window).trigger('Conversation_Quit',[currentConversation.conversationId]);
}).fail(function(msg){
alert(msg);
});
return false;
});
};
Conversation.createConversation = function(type,members){
var dfd = $.Deferred();
$.post('/chat/create-group',{
uid_str:members
}).then(ajaxDoneFilter,ajaxFailFilter).done(function(data){
var conversation = {};
conversation.conversationId = +data.group_info.group_id;
conversation.avatarUrl = data.group_info.group_image_url;
conversation.title = data.group_info.group_name;
conversation.type = Conversation.TYPE_MAP[data.group_info.type];
conversation.unreadCount = 0;
conversation.recentMessage = '会话已建立!';
conversation.recentTime = moment().format('YYYY-MM-DD HH:mm:ss');
conversation.isBlocked = +data.is_shielded;
conversation.memberList = data.group_info.member_list.map(function(memberItem){
// 对服务端而言,会话的屏蔽状态是针对每个人的
// 但对客户端而言,会话的屏蔽状态不需要管别人
/*if(memberItem.member_uid === window.MyUid){
conversation.isBlocked = +memberItem.is_shielded;
}*/
return {
uid:+memberItem.member_uid,
role:Conversation.ROLE_MAP[memberItem.role],
status:Conversation.STATUS_MAP[memberItem.status],
avatarUrl:memberItem.member_icon,
nickname:memberItem.member_nick,
isBlocked:+memberItem.is_shielded
};
});
dfd.resolve(new Conversation(conversation));
}).fail(function(msg){
dfd.reject(msg);
});
return dfd;
};
Conversation.clearConversation = function(){
$messageWrapper.empty();
$messageTitle.text('');
$isBlockedTrue.hide();
$isBlockedFalse.hide();
$conversationDetail.hide();
$chatBox.show();
};
// 更新最后阅读时间
// 使用了一个代理,每10秒钟上报一次
var updateReadTime = function(){
var timeOut = 10*1000; //每10秒上报一次
var timer;
var proxyList = {}; //待上报的数据列表
return function(id){
proxyList[id] = Math.floor(Date.now()/1000);
if(!timer){
timer = setTimeout(function(){
$.post('/chat/set-time-flag',proxyList,$.noop,'json').done(ajaxDoneFilter,ajaxFailFilter).done(function(data){
proxyList = {};
timer = null;
});
},timeOut);
}
};
}();
function ajaxDoneFilter(data){
var dfd = $.Deferred();
if(+data.result === 0){
dfd.resolve(data.data || data);
}else{
dfd.reject(data.ret_msg);
}
return dfd;
}
function ajaxFailFilter(xhr,msg,err){
var dfd = $.Deferred();
dfd.reject(msg);
return dfd;
}
function htmlEncode(str){
return str.replace(/</g,'&lt;')
.replace(/ /g,'&nbsp;')
.replace(/>/g,'&gt;')
.replace(/"/g,'&quot;')
.replace(/'/g,'&apos;');
}
return Conversation;
});
<div class="wrap">
<div class="main05 clearBox">
<div class="main05Fleft">
<div class="cBox01">
<div class="t01 t01Bt0">
<h3><span>消息列表</span><!-- <i class="num01">139</i> --></h3>
<div class="fr01">
<a class="addBtn01" id="memberPickerTrigger" href="#"><i></i>发起</a>
</div>
</div>
<div class="inboxLeftBox01">
<ul id="listWrapper">
<!-- <li>
<a href="#">
<div class="imgBox">
<i class="num01">53</i>
<div class="danren"><img width="50" height="50" alt="" src="/icon-100007-120-1369363659?2014.07.28.5.cn"></div>
</div>
<div class="txt01">
<p class="p01">糊涂的鱼儿</p>
<p class="p02 fachu"><i></i>美股通了吗大哥?</p>
</div>
<span class="time">上午11:02</span>
<span title="删除" class="del01"></span>
</a>
</li> -->
</ul>
</div>
</div>
</div>
<div class="main05Fright" id="chatBox">
<div class="inboxTopBar01">
<div class="fl" id="messageTitle">暂无会话</div>
<div class="fr" id="operateWrapper">
<a href="#" class="quitBtn">退出聊天</a>
<a href="#" class="showDetail">查看成员</a>
<span class="gapS01">|</span>
<a href="#" class="doBlockConversation isBlockedFalse">屏蔽</a>
<span class="isBlockedTrue">已屏蔽,<a href="#" class="doUnblockConversation">取消</a></span>
</div>
</div>
<div class="inboxList01" id="messageWrapper">
<!-- <div class="box01 other">
<div class="imgBox"><img width="38" height="38" alt="" src="/icon-100007-120-1369363659?2014.07.28.5.cn"></div>
<div class="c01">
<span class="timeBar"><font>刘德华</font><font class="time001">11:32</font></span>
<span class="txt01"><i></i>说实话我也不知道要改成什么样子,也没说清楚啊,要想想。</span>
</div>
</div>
<div class="box01 my">
<div class="imgBox"><img width="38" height="38" alt="" src="/icon-100007-120-1369363659?2014.07.28.5.cn"></div>
<div class="c01">
<span class="timeBar"><font>刘德华</font><font class="time001">11:32</font></span>
<span class="txt01">
<i></i>
貌似有大师发生,围观!
<div class="fjBar01">
<ul>
<li name="attachTxt" class="pdfIcon"><a title="点击下载:开户表格.pdf" href="http://futu.cn/data/attach/201407/31/185/1406808036035877_585_185.pdf" class="tf" target="_blank">开户表格.pdf</a></li>
<li name="attachTxt" class="docIcon"><a title="点击下载:熟人开户指引.doc" href="http://futu.cn/data/attach/201407/31/185/1406808036144822_585_185.doc" class="tf" target="_blank">熟人开户指引.doc</a></li>
</ul>
</div>
</span>
</div>
</div> -->
</div>
<div class="inboxPostBox01" id="sendWrapper">
<div class="postBox01">
<div class="textareaBox">
<textarea accesskey="u" autocomplete="off" tabindex="1" name="content"></textarea>
</div>
<div class="upImgBox01" name="upImageBox">
<div key="0" extension="" org_name="" file_id="" class="upImgC01" name="pic_swf_up_row_sample" style="display:none;">
<a onclick="return false;" href="#" class="moveBtn01" name="drag_handle" title="拖动调整图片顺序" onmousedown="return false;"></a>
<a onclick="return false;" href="#" class="edCloseBtn01" name="close" title="关闭" onmousedown="return false;"></a>
<div style="background-position: -250px 0px;" name="progress" class="uploadBar01"></div>
<div name="uploading_txt" class="upImgNameBar">新建位图图像.bmp</div>
<div style="display:none;" name="img" class="upImgBox"><img src="" onmousedown="return false;" alt=""></div>
<div style="display:none;" name="uploaded_txt" class="upTextarea"><textarea style="display:none;" name="uploaded_img_desc"></textarea></div>
</div>
</div>
<div class="upImgBox01" name="upAttachBox">
<div key="0" extension="" org_name="" file_id="" name="attach_swf_up_row_sample" class="upImgC01" style="display:none;">
<a onclick="return false;" href="#" name="close" class="edCloseBtn01" title="关闭"></a>
<div style="background-position: -250px 0px;" class="uploadBar02" name="progress"></div>
<div class="uploadBar01Fj" name="complete" style="display:none;"><span style="margin-top:2px; margin-right:2px;vertical-align:top;" class="msgInputOk"></span><span style="display:inline-block; vertical-align:top;">上传完毕</span></div>
<div class="upImgNameBarFj"><span class="pdfIcon" name="txt">Hydrangeas.jpg</span></div>
</div>
</div>
<div class="toolBar001">
<div class="fl">
<div class="creatBar">
<div title="插入表情" class="creatBq insertEmotion" name="createBq" onmouseover="$(this).addClass('creatBqC');" onmouseout="$(this).removeClass('creatBqC');" style="">
</div>
</div>
</div>
<div class="fr">
<span class="loading" name="show_posting" style="display:none">正在发表</span>
<span class="countTxt" name="tips" style="display:none;">
<span>
<font>还能输入</font><em name="count_txt" class="">9</em>字
</span>
<span class="orange" name="alert_txt" style="display: none; ">请先填写内容</span>
</span>
<span class="countTxt">
<span>按 ctrl+enter 发送</span>
</span>
<a class="button btn01" id="sendMessage" href="#" title="Ctrl+Enter" onclick="return false;" name="ensure">发 表</a>
</div>
<div class="clear"></div>
</div>
</div>
</div>
</div>
<div class="main05Fright" id="conversationDetail" style="display:none;">
<div class="inboxTopBar01">
<div class="fl memberCount"><a href="#" class="closeBtn">&lt; 返回</a><font class="gapS01">|</font>查看成员:<span>0</span>人</div>
<div class="fr">
<a href="#">退出聊天</a>
</div>
</div>
<div class="inboxUserList01 clearBox">
<ul class="conversationMemberList">
<!-- <li onmouseover="this.className='onmouse01'" onmouseout="this.className=''">
<a href="javascript:void(0);" title="删除" class="edCloseBtn01"></a>
<div class="imgBox"><a target="_blank" href="http://bbs.futu5.com/my-100007"><img width="120" height="120" alt="港股美股开户,美股港股交易-富途证券" src="http://bbs.futu5.com/icon-100007-120-1369363659?2014.07.28.5.cn"></a></div>
<div class="div01"><a href="http://bbs.futu5.com/my-100007" target="_blank">富途证券</a></div>
</li> -->
<li>
<a class="addBox conversationAddMember" title="添加" href="#"><em></em></a>
</li>
</ul>
</div>
<div class="inboxNameModiBar">
<span class="t001">群聊名称:</span>
<!-- <div class="c001">杨荣德、刘德华、朱广沪等9人</div> -->
<div class="c002"><input type="text" name="textfield" class="conversationName" value="" /></div>
</div>
<script type="text/tmpl" id="conversationMemberItemTmpl">
{%for(var i=0;i<obj.length;i++){%}
<li class="conversationMemberItem" data-uid="{%=obj[i].uid%}">
{%if(window.MyUid !== obj[i].uid){%}
<a href="javascript:void(0);" title="删除" class="edCloseBtn01 deleteMember"></a>
{%}%}
<div class="imgBox"><a target="_blank" href="http://bbs.futu5.com/my-{%=obj[i].uid%}"><img width="120" height="120" alt="{%=obj[i].nickname%}" src="{%=obj[i].avatarUrl%}"></a></div>
<div class="div01"><a href="http://bbs.futu5.com/my-{%=obj[i].uid%}" target="_blank">{%=obj[i].nickname%}</a></div>
</li>
{%}%}
</script>
</div>
</div>
</div>
<div class="floatBox01" id="memberPicker" style="display:none;">
<div class="alphaDiv01"></div>
<div class="m001">
<div class="t01"><h3 name="header">发起聊天</h3><a onclick="return false;" href="#" name="close" class="closeBtn01 closeBtn" title="关闭"></a></div>
<div class="c01">
<div class="inboxFloatSearchBar01"><span class="t001">搜索</span><input type="text" placeholder="昵称/牛牛号" class="inputTxt01 gray01 keywords"></div>
<div class="inboxFloatSearchList01">
<ul class="memberList">
<!-- <li>
<span class="span01"><input type="checkbox" id="noCommission"></span>
<span class="imgBox"><img width="38" height="38" alt="王军" src="http://bbs.futu5.com/icon-100007-120-1369363659?2014.07.28.5.cn"/></span>
<span class="span02">
<font>Listy</font><font class="font02">110006</font>
</span>
</li> -->
</ul>
</div>
<div class="inboxFloatSearchBar02 clearBox checkedList">
<!-- <span><a href="javascript:void(0);" title="删除" class="edCloseBtn01"></a><img width="38" height="38" alt="王军" src="http://bbs.futu5.com/icon-100007-120-1369363659?2014.07.28.5.cn"/></span> -->
</div>
</div>
<div class="f01">
<div class="fl checkedCount">共<span>0</span>人</div>
<div class="fr">
<a onclick="return false;" id="doSelectMember" name="confirm" href="#" class="button btn01">确 定</a>
</div>
</div>
</div>
<script type="text/tmpl" id="memberItemTmpl">
{%for(var i=0;i<obj.length;i++){%}
<li data-uid="{%=obj[i].uid%}" data-avatarurl="{%=obj[i].avatarUrl%}" data-nickname="{%=obj[i].nickname%}">
<span class="span01"><input type="checkbox"></span>
<span class="imgBox"><img width="38" height="38" alt="{%=obj[i].nickname%}" src="{%=obj[i].avatarUrl%}"/></span>
<span class="span02">
<font>{%=obj[i].nickname%}</font><font class="font02">{%=obj[i].uid%}</font>
</span>
</li>
{%}%}
</script>
<script type="text/tmpl" id="checkedMemberItemTmpl">
{%for(var i=0;i<obj.length;i++){%}
<span class="checkedItem" data-uid="{%=obj[i].uid%}">
<a href="javascript:void(0);" title="删除" class="edCloseBtn01 uncheckMember"></a>
<img width="38" height="38" alt="{%=obj[i].nickname%}" src="{%=obj[i].avatarUrl%}"/>
</span>
{%}%}
</script>
</div>
define([
'underscore.min',
'jquery',
'app/futu5/chat/conversation'
],function(_,$,Conversation){
var listItemTmpl = $('#listItemTmpl').html();
var $listWrapper = $('#listWrapper');
var list = {};
var conversationList = [];
var renderListFunc = _.template(listItemTmpl);
list.renderList = function(renderList){
if(!renderList){
renderList = conversationList;
}
renderList.sort(function(conversation1,conversation2){
return conversation1.recentTime > conversation2.recentTime?-1:1;
});
var html = renderList.map(function(item){
return renderListFunc(item);
});
$listWrapper.html(html);
};
list.getList = function(){
return $.getJSON('/chat/my-group-list').then(ajaxDoneFilter,ajaxFailFilter);
};
list.updateList = function(){
this.getList().done(function(data){
conversationList = data.group_list.map(function(dataItem){
// var conversationData = dataItem;
var conversationData = {};
conversationData.recentMessage = dataItem.last_message;
conversationData.recentTime = dataItem.last_update_time;
conversationData.title = dataItem.group_name;
conversationData.conversationId = +dataItem.group_id;
conversationData.avatarUrl = dataItem.group_image_url;
conversationData.isBlocked = +dataItem.is_shielded;
conversationData.unreadCount = +dataItem.unread_messages;
conversationData.isActive = false;
conversationData.memberList = dataItem.member_list.map(function(memberItem){
return {
uid:+memberItem.member_uid,
role:Conversation.ROLE_MAP[memberItem.role],
status:Conversation.STATUS_MAP[memberItem.status],
avatarUrl:memberItem.member_icon,
nickname:memberItem.member_nick,
};
});
return new Conversation(conversationData);
});
if(conversationList[0]){
conversationList[0].active();
}else{
Conversation.clearMessageList();
}
list.renderList(conversationList);
}).fail(function(msg){
console.log('fail',msg);
});
};
list.appendConversation = function(conversation){
conversationList.push(conversation);
};
list.prependConversation = function(conversation){
conversationList.unshift(conversation);
};
list.getConversationById = function(conversationId){
var targetConversation;
conversationList.forEach(function(conversationItem){
if(conversationItem.conversationId === conversationId){
targetConversation = conversationItem;
}
});
return targetConversation;
};
list.bindEvents = function(){
$listWrapper.on('click','.list-item',function(){
var targetConversation;
var conversationId = +$(this).data('conversationid');
conversationList.forEach(function(conversationItem){
if(conversationItem.conversationId === conversationId){
targetConversation = conversationItem;
}
});
targetConversation.active();
return false;
});
// 从列表中删除某个会话
$listWrapper.on('click','.list-item .delConversation',function(e){
var targetConversation;
var conversationId = +$(this).closest('li').data('conversationid');
conversationList.forEach(function(conversationItem){
if(conversationItem.conversationId === conversationId){
targetConversation = conversationItem;
}
});
targetConversation.delete();
return false;
});
// 接收Conversation的事件,处理列表
/*$(window).on('Conversation_Delete',function(e,conversationId){
});*/
// 接收Conversation删除、退出的事件,重新选取会话进行聚焦
$(window).on('Conversation_Delete Conversation_Quit',function(e,conversationId){
conversationList.forEach(function(conversationItem,index){
if(conversationItem.conversationId === conversationId){
conversationList.splice(index,1);
}
});
if(conversationList.length){
conversationList[0].active();
}else{
Conversation.clearConversation();
}
list.renderList();
});
// 接收Conversation聚焦(激活)事件,处理左侧高亮
$(window).on('Conversation_Active',function(e,conversationId){
conversationList.forEach(function(conversationItem){
if(conversationItem.conversationId === conversationId){
conversationItem.isActive = true;
}else{
conversationItem.isActive = false;
}
});
list.renderList();
});
// 接收Conversation更新事件,刷新列表
$(window).on('Conversation_Update',function(e,conversationId){
list.renderList();
});
};
function ajaxDoneFilter(data){
var dfd = $.Deferred();
if(+data.result === 0){
dfd.resolve(data.data || data);
}else{
dfd.reject(data.ret_msg);
}
return dfd;
}
function ajaxFailFilter(xhr,msg,err){
var dfd = $.Deferred();
dfd.reject(msg);
return dfd;
}
return list;
});
require([
'jquery',
'underscore.min',
'app/common/comet',
'app/futu5/chat/list',
'app/futu5/chat/conversation',
'app/futu5/chat/memberpicker'
],function($,_,Comet,list,Conversation,memberPicker){
list.updateList();
list.bindEvents();
Conversation.bindEvents();
$('#memberPickerTrigger').click(function(){
memberPicker.init({
onSelect:function(memberList){
Conversation.createConversation('group',memberList.map(function(memberItem){
return memberItem.uid;
}).join(',')).done(function(conversation){
list.prependConversation(conversation);
conversation.active();
list.renderList();
memberPicker.hide();
}).fail(function(){
});
}
});
return false;
});
// 聊天信息长连接
var chatConnection = new Comet({
url:'/chat/get-message',
method:'post',
onData:function(data){
console.log(data);
for(var conversationId in data.message_list){
var targetConversation = list.getConversationById(+conversationId);
// 新会话,先建立一个占位,然后去更新它
if(!targetConversation){
targetConversation = new Conversation({
conversationId: +conversationId,
avatarUrl: '',
title:'',
type:'',
unreadCount:1,
recentMessage:'',
recentTime: '',
isBlocked:false,
isActive:false,
memberList:[],
_isFake:true //表示从前端创建的会话
});
list.prependConversation(targetConversation);
targetConversation.update();
}
data.message_list[conversationId].message_list.forEach(function(message){
console.log(message);
var messageToPush = {
avatarUrl:message.member_icon,
nickname:message.member_nick,
role:+message.from_uid === window.MyUid ? 'my':'other',
userId:message.from_uid,
time:message.create_time,
content:message.content,
type:Conversation.MESSAGE_TYPE_MAP[message.msg_type],
extra:message.extra
};
targetConversation.pushMessage(messageToPush);
targetConversation.dealFeeds(messageToPush);
if(message.from_uid === window.MyUid && !Conversation.me){
// 如果是自己的消息,并且没有个人信息,则需要渲染并填充个人信息
Conversation.me = {
avatarUrl:message.member_icon,
nickname:message.member_nick
};
}
if(targetConversation.recentTime < message.create_time){
targetConversation.recentTime = message.create_time;
targetConversation.recentMessage = message.content;
if(targetConversation._isFake){
targetConversation.title = 'Loading...';
}
}
});
}
list.renderList();
}
});
});
define([
'underscore.min',
'jquery'
],function(_,$){
var memberPicker = {};
var options = {};
var memberItemTmpl = $('#memberPicker #memberItemTmpl').html();
var memberItemFunc = _.template(memberItemTmpl);
var checkedMemberList = [];
var checkedMemberItemTmpl = $('#memberPicker #checkedMemberItemTmpl').html();
var checkedMemberItemFunc = _.template(checkedMemberItemTmpl);
memberPicker.init = function(opts){
var defaultOptions = {
onSelect:$.noop,
onCancel:$.noop
};
options = $.extend({},defaultOptions,opts);
if(!$('#memberPicker').data('inited')){
bindEvents();
}
this.show();
};
memberPicker.show = function(){
$('#memberPicker .keywords').val('');
$('#memberPicker .memberList').empty();
$('#memberPicker .checkedList').empty();
$('#memberPicker .checkedCount span').text('0');
checkedMemberList = [];
showDialog();
};
memberPicker.hide = function(){
$('#memberPicker').fadeOut(200);
};
function showDialog(){
$('#memberPicker').data('inited',true).fadeIn(200);
}
function searchMember(keyword){
return $.getJSON('/chat/search-user',{
keyword:keyword
}).then(ajaxDoneFilter,ajaxFailFilter);
}
function bindEvents(){
$('#memberPicker .closeBtn').click(function(){
$('#memberPicker').fadeOut(200);
});
$('#memberPicker .keywords').on('input textinput paste propertychange',function(){
var value = $(this).val();
if(!value) return;
searchMember(value).done(function(data){
var memberArr = data.map(function(memberItem){
return {
uid:memberItem.id,
nickname:memberItem.nick,
avatarUrl:memberItem.icon
};
});
var html = memberItemFunc(memberArr);
$('#memberPicker .memberList').html(html);
}).fail(function(){
});
});
$('#memberPicker').on('change','.memberList input[type=checkbox]',function(){
var checked = $(this).prop('checked');
var item = $(this).closest('li');
var itemData = {
uid:+item.data('uid'),
avatarUrl:item.data('avatarurl'),
nickname:item.data('nickname')
};
if(checked){
checkedMemberList.push(itemData);
}else{
checkedMemberList.forEach(function(item,index){
if(item.uid === itemData.uid){
checkedMemberList.splice(index,1);
}
});
}
var html = checkedMemberItemFunc(checkedMemberList);
$('#memberPicker .checkedList').html(html);
$('#memberPicker .checkedCount span').text(checkedMemberList.length);
});
$('#memberPicker').on('click','.checkedList .uncheckMember',function(){
var uid = $(this).closest('.checkedItem').data('uid');
checkedMemberList.forEach(function(item,index){
if(item.uid === uid){
checkedMemberList.splice(index,1);
}
});
$('#memberPicker input[type=checkbox]').each(function(){
var $this = $(this);
if($this.closest('li').data('uid') === uid){
$this.prop('checked',false);
}
});
var html = checkedMemberItemFunc(checkedMemberList);
$('#memberPicker .checkedList').html(html);
$('#memberPicker .checkedCount span').text(checkedMemberList.length);
});
$('#memberPicker #doSelectMember').click(function(){
options.onSelect(checkedMemberList);
});
}
function ajaxDoneFilter(data){
var dfd = $.Deferred();
if(+data.result === 0){
dfd.resolve(data.user_list);
}else{
dfd.reject(data.ret_msg);
}
return dfd;
}
function ajaxFailFilter(xhr,msg,err){
var dfd = $.Deferred();
dfd.reject(msg);
return dfd;
}
return memberPicker;
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment