Authored by 陈轩

Merge branch 'master' into feature/captcha

... ... @@ -9,8 +9,12 @@
const onlineModel = require('../models/onlineService');
const headerModel = require('../../../doraemon/models/header'); // 头部model
const _ = require('lodash');
const helpers = global.yoho.helpers;
const getOnlineServiceInfo = (req, res, next) => {
let serviceUrl = _.get(req.app.locals.wap, 'clientService.new', false) ?
helpers.urlFormat('/service/im') :
'http://chat8.live800.com/live800/chatClient/chatbox.jsp?companyID=620092&configID=149091&jid=8732423409&info=';
onlineModel.getOnlineServiceInfo().then((result) => {
... ... @@ -25,7 +29,7 @@ const getOnlineServiceInfo = (req, res, next) => {
title: '在线客服',
pageFooter: true,
service: result,
serviceUrl: 'http://chat80.live800.com/live800/chatClient/chatbox.jsp?companyID=493979&configID=123576&jid=9277320930'
serviceUrl: serviceUrl
});
}).catch(next);
};
... ...
... ... @@ -6,15 +6,20 @@
'use strict';
const helpers = global.yoho.helpers;
const _ = require('lodash');
const headerModel = require('../../../doraemon/models/header'); // 头部model
const orderDetailModel = require('../models/orderDetail');
const orderDetailData = (req, res, next) => {
let uid = req.user.uid;
let orderCode = req.query.order_code;
let serviceUrl = _.get(req.app.locals.wap, 'clientService.new', false) ?
helpers.urlFormat('/service/im') :
'http://chat8.live800.com/live800/chatClient/chatbox.jsp?companyID=620092&configID=149091&jid=8732423409&info=';
orderDetailModel.orderDetailData(uid, orderCode).then(result => {
result.serviceUrl = 'http://chat8.live800.com/live800/chatClient/chatbox.jsp?companyID=620092&configID=149091&jid=8732423409&info=';
result.serviceUrl = serviceUrl;
res.render('orderDetail', {
module: 'home',
page: 'order-detail',
... ...
... ... @@ -32,6 +32,9 @@ const bind = {
let openId = req.query.openId;
let sourceType = req.query.sourceType;
let serviceUrl = _.get(req.app.locals.wap, 'clientService.new', false) ?
helpers.urlFormat('/service/im') :
'http://chat8.live800.com/live800/chatClient/chatbox.jsp?companyID=620092&configID=149091&jid=8732423409&info=';
res.render('bind/index', {
bindIndex: true, // js标识
... ... @@ -44,7 +47,7 @@ const bind = {
openId: openId, // openId
areaCode: '+86', // 默认区号
countrys: RegService.getAreaData(), // 国别码
serviceUrl: 'http://chat8.live800.com/live800/chatClient/chatbox.jsp?companyID=620092&configID=149091&jid=8732423409&info=', // 在线客服
serviceUrl: serviceUrl, // 在线客服
module: 'passport',
page: 'bind',
title: '绑定手机号'
... ...
... ... @@ -196,6 +196,10 @@ let codeAction = (req, res, next) => {
});
}
let serviceUrl = _.get(req.app.locals.wap, 'clientService.new', false) ?
helpers.urlFormat('/service/im') :
'http://chat8.live800.com/live800/chatClient/chatbox.jsp?companyID=620092&configID=149091&jid=8732423409&info=';
res.render('reg/code', {
page: 'code',
title: '注册-验证码',
... ... @@ -204,7 +208,7 @@ let codeAction = (req, res, next) => {
areaCode: area, // 默认的区号
phoneNum: mobile, // 手机号
token: token, // 访问令牌
serviceUrl: 'http://chat8.live800.com/live800/chatClient/chatbox.jsp?companyID=620092&configID=149091&jid=8732423409&info=' // 在线客服
serviceUrl: serviceUrl // 在线客服
});
};
... ...
... ... @@ -45,14 +45,14 @@ const shop = {
params.brand = brandId;
let searchParam = {
let searchParam = Object.assign({
isApp: req.yoho.isApp,
brand: brandId,
type: 'newest',
order: '1',
page: 1,
limit: 4
};
limit: 4,
}, params);
if (req.query.from !== 'search' && brandLogo.type === '2' && brandLogo.shopId) {
req.query.shop_id = brandLogo.shopId;
... ... @@ -67,7 +67,7 @@ const shop = {
if (brandId === 0) {
params.query = domain;
}
if (brandShop.length > 0) {
if (brandShop.length > 0 || brandLogo) {
params = _.assign({
brandWay: _.isEmpty(brandShop) ? brandLogo : brandShop,
search: {
... ... @@ -97,6 +97,7 @@ const shop = {
});
}
}).then((isBrand) => {
// console.log(params);
if (isBrand) {
res.render('newshop/brand', {
module: 'product',
... ...
... ... @@ -139,6 +139,7 @@
{{> common/goods}}
{{/@root.firstPageGoodsList}}
</div>
<div class="search-divide">正在加载...</div>
<div class="default-goods container clearfix"></div>
<div class="new-goods container clearfix"></div>
<div class="sale-goods container clearfix"></div>
... ...
'use strict';
const orderModel = require('../../home/models/order');
const crypto = global.yoho.crypto;
const imApi = require('../../serverAPI/im');
const imApi = require('../models/im-api');
const userApi = require('../../passport/models/auth-helper');
const imModel = require('../models/im');
const helpers = global.yoho.helpers;
const sign = global.yoho.sign;
... ... @@ -20,31 +21,51 @@ exports.appAdapter = (req, res, next) => {
next();
};
exports.page = (req, res) => {
res.render('chat/index', {
module: 'service',
page: 'chat',
pageStyle: 'service-chat',
width750: true,
localCss: true,
imServer: global.yoho.config.domains.imServer,
imSocket: global.yoho.config.domains.imSocket,
userData: {
uid: req.user.uid,
encrypteduid: req.user.ENCRYPTION_UID || (crypto.encryption(null, req.user.uid + '' || '0')),
avatar: helpers.image(req.user.AVATAR, 100, 100),
uname: req.user.NAME
}
});
exports.page = (req, res, next) => {
let uid = req.user.uid;
if (!uid) {
uid = req.query.uid;
}
userApi.profile(req.user.uid)
.then(userinfo => {
userinfo = userinfo.data;
res.render('chat/index', {
module: 'service',
page: 'chat',
pageStyle: 'service-chat',
width750: true,
localCss: true,
imServer: global.yoho.config.domains.imServer,
imSocket: global.yoho.config.domains.imSocket,
userData: {
uid: uid,
encrypteduid: crypto.encryption(null, uid + ''),
avatar: helpers.image(userinfo.head_ico, 100, 100),
uname: userinfo.profile_name
}
});
})
.catch(next);
};
exports.getOrders = (req, res, next) => {
let uid = req.user.uid;
if (!uid) {
uid = req.query.uid;
}
orderModel.getOrders({
type: req.query.type || 1,
page: req.query.page || 1,
gender: req.query.gender || '1,3',
yh_channel: req.query.channel || 1,
uid: req.user.uid
uid
}).then(result => {
res.render('chat/chat-order', {
layout: false,
... ... @@ -59,7 +80,12 @@ exports.getOrders = (req, res, next) => {
*
*/
exports.fetchHistory = (req, res) => {
const uid = req.user.uid;
let uid = req.user.uid;
if (!uid) {
uid = req.query.uid;
}
const endTime = req.query.endTime;
imApi.fetchImHistory(uid, endTime).then(result => {
... ... @@ -69,7 +95,12 @@ exports.fetchHistory = (req, res) => {
exports.msghistory = (req, res) => {
const uid = req.user.uid;
let uid = req.user.uid;
if (!uid) {
uid = req.query.uid;
}
imApi.fetchImHistory(uid).then(result => {
res.json(result);
... ... @@ -84,7 +115,12 @@ exports.msghistory = (req, res) => {
* content 留言内容
*/
exports.saveMSG = (req, res) => {
const uid = req.user.uid;
let uid = req.user.uid;
if (!uid) {
uid = req.body.uid;
}
const conversationId = req.body.conversationId;
const content = req.body.content;
... ... @@ -103,26 +139,42 @@ exports.saveMSG = (req, res) => {
* 2. 失败情况
*/
exports.fetchOrders = (req, res) => {
const uid = req.user.uid;
let uid = req.user.uid;
if (!uid) {
uid = req.query.uid;
}
imApi.fetchOrderList(uid)
.then(result => {
imModel.handleOrderList(result.data);
imModel.handleOrderList(result.data, 128, 170);
res.json(result);
}).catch(() =>{
return res.json({
code: 500,
data: []
});
});
};
exports.saveEvalute = (req, res) => {
const uid = req.user.uid;
let uid = req.user.uid;
if (!uid) {
uid = req.body.uid;
}
const conversationId = req.body.conversationId;
const promoter = req.body.promoter;
const stars = req.body.stars;
const reasonMsg = req.body.reasonMsg || '';
imApi.saveEvalute(uid, conversationId, promoter, stars)
imApi.saveEvalute(uid, conversationId, promoter, stars, reasonMsg)
.then(result => {
return res.json(result);
}, () => {
}).catch(() => {
return res.json({
code: 500,
message: '评价失败'
... ... @@ -131,3 +183,27 @@ exports.saveEvalute = (req, res) => {
};
exports.queryGlobalOrder = (req, res) => {
let uid = req.user.uid;
if (!uid) {
uid = req.query.uid;
}
let emptyOrder = {
code: 200,
data: [],
message: '获取失败'
};
imApi.queryGlobalOrder(uid)
.then(result=> {
imModel.handleOrderList(result.data, 128, 170);
res.json(result);
}, () => {
res.json(emptyOrder);
});
};
... ...
... ... @@ -59,8 +59,8 @@ const qaDetail = (params) => {
// 根据子id,父id,关键字,匹配问题详情
if (params.keyword) {
// 从搜索列表进入,有关键字
if (result && result[1] && result[1].data && result[1].data.data) {
let keyList = result[1].data.data.helper_list;
if (result && result[1] && result[1].data) {
let keyList = result[1].data.helper_list;
_.forEach(keyList, function(val) {
if (val.id == params.sonId) {
... ...
... ... @@ -4,7 +4,7 @@ const _ = require('lodash');
const crypto = global.yoho.crypto;
const config = global.yoho.config;
const ImAPI = new global.yoho.ApiBase(config.domains.imCs, {
const ImService = new global.yoho.ApiBase(config.domains.imCs, {
name: 'im',
cache: global.yoho.cache,
useCache: false
... ... @@ -29,7 +29,7 @@ exports.saveMessage = (uid, conversationId, content) => {
};
return ImAPI.post('/api/leavemessage/saveLeavemessage', params);
return ImService.post('/api/leavemessage/saveLeavemessage', params);
};
... ... @@ -50,11 +50,11 @@ exports.fetchImHistory = (uid, endTime, pageSize, startTime) => {
encryptedUid: encryptedUid(uid)
};
_.forEach({startTime, endTime}, (key, val) => {
_.forEach({startTime, endTime}, (val, key) => {
val && (params[key] = val);
});
return ImAPI.get('/api/conversationMessage/pageList', params)
return ImService.get('/api/conversationMessage/pageList', params)
.then(result => {
return result;
}, () => {
... ... @@ -83,7 +83,7 @@ exports.fetchOrderList = (uid, createTimeBegin) => {
val && (params[key] = val);
});
return ImAPI.get('/api/order/queryLastTenOrder', params);
return ImService.get('/api/order/queryLastTenOrder', params);
};
... ... @@ -108,14 +108,28 @@ exports.fetchOrderList = (uid, createTimeBegin) => {
| reasonMsg | string | N | 其他原因 |
*/
exports.saveEvalute = (uid, conversationId, promoter, stars) => {
exports.saveEvalute = (uid, conversationId, promoter, stars, reasonMsg) => {
let params = {
conversationId,
uid,
encryptedUid: encryptedUid(uid),
promoter,
stars
stars,
reasonMsg
};
return ImAPI.post('/api/evalute/saveEvalute', params);
return ImService.post('/api/evalute/saveEvalute', params);
};
/**
* 获取全球购的订单
*/
exports.queryGlobalOrder = uid => {
let params = {
uId: uid
};
return ImService.get('/api/order/queryGlobalOrder', params);
};
... ...
... ... @@ -9,21 +9,33 @@ const _ = require('lodash');
/**
* function: 处理 订单返回的数据
*/
exports.handleOrderList = data => {
exports.handleOrderList = (data, w, h) => {
if (_.isEmpty(data)) {
return;
}
function replaceWH(img) {
return img.replace(/(\{width\}|\{height\})/g, function($0) {
const dict = {
'{width}': w,
'{height}': h,
};
return dict[$0];
});
}
data.forEach(order => {
order.goods = order.ordersGoodsBoList.map(good => {
return {
id: good.productSku,
name: good.productName,
thumb: good.imgUrl,
thumb: replaceWH(good.imgUrl),
color: good.colorName,
size: good.sizeName,
count: good.buyNumber,
price: good.lastPrice
price: good.lastPrice,
tariffPrice: good.tariffPrice
};
});
order.count = order.ordersGoodsBoList.reduce((sum, good) => {
... ...
... ... @@ -16,12 +16,14 @@ const chatQa = require(`${cRoot}/chatQa`); // 问题搜索列表页
// middlware
const authGuard = require('../../doraemon/middleware/auth');
const disableBFCache = require('../../doraemon/middleware/disable-BFCache');
// Your controller here
router.get('/im', chat.appAdapter, authGuard, chat.page);
router.get('/im', disableBFCache, chat.appAdapter, authGuard, chat.page);
router.get('/im/fetchHistory', chat.fetchHistory);
router.get('/getOrders', chat.getOrders);
router.get('/order-list', chat.fetchOrders);
router.get('/im/global-list', chat.queryGlobalOrder);
router.get('/im/order-list', chat.fetchOrders);
router.post('/leavemsg/save.json', chat.saveMSG);
router.post('/im/saveEvalute', chat.saveEvalute);
... ...
<div class="chat-qa-c">
<div class="search-c">
<a href="./qaSearch">
<a href="//m.yohobuy.com/service/qaSearch">
<i class="search-icon iconfont">&#xe60f;</i>
<input type="text" placeholder="有问题?点我搜搜看吧" readonly="readonly" / >
</a>
... ... @@ -10,7 +10,7 @@
{{# categorys}}
<div class="list clearfix open-down">
<div class="ico-pic">
<img src="{{categoryIco}}" />
<img src="{{image categoryIco 60 60}}" />
</div>
<div>
<p class="title">{{categoryName}}</p>
... ... @@ -20,7 +20,7 @@
</div>
<div class="down-item">
{{# contentItems}}
<a href="./qaDetail?sonId={{id}}&parentId={{parentId}}">
<a href="//m.yohobuy.com/service/qaDetail?sonId={{id}}&parentId={{parentId}}">
<p>{{caption}}</p>
<i class="arr-ico iconfont">&#xe604;</i>
</a>
... ... @@ -31,7 +31,7 @@
<div class="list-title">常见问题</div>
<div class="list-group">
{{# faqs}}
<a class="common-item" href="./qaDetail?sonId={{id}}">
<a class="common-item" href="//m.yohobuy.com/service/qaDetail?sonId={{id}}">
<p>{{caption}}</p>
<i class="arr-ico iconfont">&#xe604;</i>
</a>
... ...
<div class="ios-gap"></div>
<div id="chat-main-wrap">
<!--im 头部-->
<header class="yoho-header chat-header">
... ... @@ -23,7 +24,9 @@
<a href="javascript:;" class="input-method input-text"></a>
</span>--}}
<span class="table-cell cell-max">
<input type="text" class="input-in text-in" placeholder="发送新消息">
<form action="" onsubmit="return false">
<input type="text" class="input-in text-in" placeholder="发送新消息">
</form>
</span>
<span class="table-cell">
<a href="javascript:;" class="menu-trigger"></a>
... ... @@ -32,20 +35,20 @@
<div class="menu">
<div class="icon-wrap camera">
<input type="file" class="upload-img" style="position: absolute;right: -3px;top: -3px;z-index: 999;" accept="image/*">
<input type="file" class="upload-img" style="position: absolute;right: -3px;top: -3px;" accept="image/*">
<div class="icon"></div>
<p class="menu-name">拍照</p>
</div>
<div class="icon-wrap photo">
<input type="file" name="filename" class="upload-img" style="position: absolute;right: -3px;top: -3px;z-index: 999;" accept="image/*">
<input type="file" name="filename" class="upload-img" style="position: absolute;right: -3px;top: -3px;" accept="image/*">
<div class="icon"></div>
<p class="menu-name">相册</p>
</div>
<div class="icon-wrap order" data-trigger="order-list">
<div class="icon-wrap order" data-trigger="order-list" data-type="order">
<div class="icon"></div>
<p class="menu-name">订单</p>
</div>
<div class="icon-wrap broad-order" data-trigger="order-list" data-param="international">
<div class="icon-wrap broad-order" data-trigger="order-list" data-type="global">
<div class="icon"></div>
<p class="menu-name">境外订单</p>
</div>
... ...
... ... @@ -8,7 +8,7 @@
</div>
<div class="list-group hot-group">
{{# hotSearch}}
<a class="common-item" href="./qaDetail?sonId={{id}}">
<a class="common-item" href="//m.yohobuy.com/service/qaDetail?sonId={{id}}">
<p>{{caption}}</p>
<i class="arr-ico iconfont">&#xe604;</i>
</a>
... ...
<!--评价 主体-->
<div id="chat-comment" class="comment">
<div class="comment-inner">
<div class="intro">请对我们的服务做出评价<span class="close">X</span></div>
<div class="intro">请对我们的服务做出评价<span class="close iconfont">&#xe623</span></div>
<div class="stars">
<i></i>
<i></i>
... ... @@ -10,7 +10,7 @@
<i></i>
</div>
<div class="rank"> </div>
<textarea class="words-to-say" placeholder="还想吐槽下(选填)"></textarea>
<textarea class="words-to-say" maxlength="50" placeholder="还想吐槽下(选填)"></textarea>
<button class="submit">提交</button>
</div>
</div>
\ No newline at end of file
... ...
... ... @@ -5,7 +5,7 @@
<div class="title">留言</div>
</header>
<div class="main">
<textarea name="leave-text" class="leave-text" placeholder="请输入留言文字,Yoho!客服会以短信形式回复您,谢谢您对Yoho!有货的支持!"></textarea>
<textarea name="leave-text" maxlength="120" class="leave-text" placeholder="请输入留言文字,Yoho!Buy有货客服会以短信形式回复您,谢谢您对Yoho!Buy有货的支持!"></textarea>
<button class="leave-submit">提交</button>
</div>
</div>
\ No newline at end of file
... ...
... ... @@ -28,9 +28,9 @@ module.exports = {
service: 'http://service.yoho.cn/',
liveApi: 'http://api.live.yoho.cn/',
singleApi: 'http://single.yoho.cn/',
imSocket: 'ws://imsocket.yohobuy.com:10000',
imCs: 'http://imhttp.yohobuy.com/api',
imServer: 'http://imhttp.yohobuy.com/server'
imSocket: 'wss://imsocket.yohobuy.com:443',
imCs: 'https://imhttp.yohobuy.com/api',
imServer: 'https://imhttp.yohobuy.com/server'
},
subDomains: {
host: '.m.yohobuy.com',
... ...
... ... @@ -19,15 +19,6 @@ module.exports = () => {
req.user.uid = cookie.getUid(req);
}
// app 特殊读法
if (!req.user.uid && req.yoho.isApp) {
let userAgent = _.get(req.headers, 'user-agent', '');
if (userAgent.indexOf('YohoBuy') >= 0) {
req.user.uid = req.cookies._YOHOUID || 0;
}
}
next();
};
};
... ...
{
"name": "m-yohobuy-node",
"version": "5.3.1",
"version": "5.3.2",
"private": true,
"description": "A New Yohobuy Project With Express",
"repository": {
... ...
... ... @@ -239,6 +239,8 @@ gulp.task('webpack-dev-server', () => {
hot: true,
inline: true,
quiet: true,
clientLogLevel: 'error',
compress: true,
stats: {
colors: true
},
... ...
{{#each .}}
<div class="msg-wrap {{style from}}" data-uuid={{uuid}}>
<img src="http:{{image avatar 80 80}}" alt="" class="head-icon">
<img src="{{image avatar 80 80}}" alt="" class="head-icon">
<div class="chat-info clearfix">
{{#with data}}
{{> (lookup .. 'type')}}
... ... @@ -8,7 +7,6 @@
<i class="msg-status iconfont"></i>
</div>
</div>
{{/each}}
{{!--inline partails--}}
... ... @@ -35,7 +33,7 @@
{{#*inline 'picture'}}
<div class="msg-content msg-pic">
<img src="{{content}}" alt="" class="image chat-image">
<img src="{{content}}?imageView2/0/q/50" alt="" class="image chat-image">
</div>
{{/inline}}
... ...
... ... @@ -48,7 +48,9 @@
</section>
<footer class="footer">
{{count}}件商品 实付<span class="sum-cost">¥{{lastOrderAmount}}</span>
{{#shippingCost}}(含运费¥{{.}}){{/shippingCost}}
{{#unless @root.isGlobal}}
{{#shippingCost}}(含运费¥{{.}}){{/shippingCost}}
{{/unless}}
</footer>
<div class="send-order clearfix">
<button class="send-order-btn" data-action="select">发送订单</button>
... ... @@ -60,6 +62,5 @@
<div class="no-orders">
<i class="no-orders-pic"></i>
<p>您暂时没有订单</p>
<a href="//m.yohobuy.com/product/new">随便逛逛</a>
</div>
{{/each}}
\ No newline at end of file
... ...
... ... @@ -16,7 +16,9 @@ var missStatus; // 是否忽略选中状态
// 隐藏筛选界面
function hideFilter() {
$filter.addClass('hide');
setTimeout(function () {
$filter.addClass('hide');
}, 301);
}
// 显示筛选界面
... ...
... ... @@ -599,8 +599,13 @@ function search(opt) {
} else {
if (nav.reload) {
$container.html(data);
num = $container.find('.good-info').length;
$('.search-divide').remove();
$container.append('<div class="search-divide">正在加载...</div>');
lazyLoad($container.find('.lazy'));
if (num < 12) {
$('.search-divide').remove();
}
RES_QTY = $container.find('.total').data('id');
... ... @@ -632,6 +637,9 @@ function search(opt) {
$('.search-divide').remove();
$container.append(data);
$container.append('<div class="search-divide">正在加载...</div>');
if (num < 12) {
$('.search-divide').remove();
}
if ($container.find('.total')[1]) {
$container.find('.total')[1].remove();
... ... @@ -1209,3 +1217,7 @@ $('#goods-container').on('click', '.good-info', function() {
}, true);
}
});
var fuckNum = $('.good-info').length;
fuckNum < 12 && $('.search-divide').remove();
... ...
... ... @@ -53,7 +53,7 @@ $('.get-qa').on('keyup focus',
$searchGroup.show();
$noResult.hide();
$hotGroup.hide();
var keyList = result.data.data.helper_list;
var keyList = result.data.helper_list;
if (keyList == '') {
$searchGroup.empty();
... ...
... ... @@ -10,22 +10,26 @@ import appBridge from 'yoho-app';
import {time} from './time';
import {api} from './store';
import {RatingView, LeaveMSGView, OrderListView } from './view';
import tip from 'plugin/tip';
var socket = require('./socket-chat'),
socketConf = require('./socket-config');
let FastClick = require('yoho-fastclick');
var cmEntity = socketConf.conversationMessage;
FastClick.attach(document.body);
const chatBox = $('#chat-window');
window.requestAnimFrame = (function() {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
}());
var qs = require('yoho-qs');
// 聊天调整footer位置
const resizeFooter = () => {
let bottom = $('#chat-footer').height();
var socket = require('./socket-chat'),
socketConf = require('./socket-config');
chatBox.css('bottom', `${bottom}px`);
chatBox[0].scrollTop = chatBox[0].scrollHeight;
};
var cmEntity = socketConf.conversationMessage;
// 配置
const msgTypeMap = {
... ... @@ -37,18 +41,41 @@ const msgTypeMap = {
let userName = $('#js-uname').val();
let uid = cmEntity.userId = $('#js-uid').val() || 0;
let encryptedUid = cmEntity.encryptedUid = $('#js-eid').val() || 0;
let userAvatar = cmEntity.userHead = $('#js-avatar').val() || socketConf.defaultUserHead;
let userAvatar = cmEntity.userHead = socketConf.defaultUserHead;
let imgSrc = $('#js-avatar').val();
// 客服配置
let customerService = {
head: socketConf.defaultUserHead,
name: ''
};
function checkUserAvatarValid(src, success) {
let imgDOM = new Image();
imgDOM.src = src;
imgDOM.style.display = 'none';
imgDOM.onload = function() {
success(src);
document.body.removeChild(this);
};
imgDOM.onerror = function() {
document.body.removeChild(this);
};
document.body.appendChild(imgDOM);
}
// window.checkUserAvatarValid = checkUserAvatarValid;
checkUserAvatarValid(imgSrc, src => {
userAvatar = cmEntity.userHead = src;
});
let isAndroid = /YohoBuy-android/i.test(navigator.userAgent);
// 历史消息分页
let msgHistory = {
conversationId: '', // 会话id
endTime: null,
curCount: 0,
totalCount: null
... ... @@ -65,6 +92,8 @@ var chat = {
unFinshMSGs: {}, // 没有发送出去消息
$ratingView: $('#chat-comment'),
canEvalute: true,
canManualService: true,
canLeaveMSG: false,
messageT: require('service/chat/msg.hbs'),
... ... @@ -88,9 +117,6 @@ var chat = {
cmEntity.encryptedUid = encryptedUid;
self.fetchHistoryMsg().always(function() {
let chatWinDOM = self.$chatWin[0];
chatWinDOM.scrollTop = chatWinDOM.scrollHeight;
self.$chatWin.append(time(Date.now()).show());
self.connect();
... ... @@ -137,8 +163,17 @@ var chat = {
// 处理消息
self.handleReceiveMSG(received);
},
onClose: function() {
self._sysInfo('连接已断开');
},
onOpen: $.noop,
onClose: $.noop
sendFailCallback: function() {
self._sysInfo('<p>连接断开,请尝试<span class="blue">重连</span></p>')
.one('click', function() {
self.connect();
});
},
};
let config = $.extend(socketConf, actions);
... ... @@ -154,18 +189,45 @@ var chat = {
this.$chat
.on('click.Rating.toggle', '[data-trigger=rating]', function() {
self.canEvalute && self.ratingView.toggle();
if (self.canEvalute) {
self.ratingView.toggle()
} else {
tip.show('您已评价,请勿重复评价');
}
})
.on('click.leaveMSG', '[data-trigger=leave-msg]', function() {
self.leaveMSGView.trigger('show.LeaveMSGView');
self.canLeaveMSG && self.leaveMSGView.trigger('show.LeaveMSGView');
})
.on('click.orderList', '[data-trigger=order-list]', function() {
self.orderListView.trigger('show.OderListView');
let orderType = $(this).data('type') || '';
self.orderListView.trigger('show.OderListView', [orderType]);
})
.on('click.chat.switchServer', '[data-action=change-human]', function() {
self.switchService('human');
self.canManualService && self.switchService('human');
})
.on('focus.chat.sendText', '.text-in', function() {
self.toggleMenu(false);
window.requestAnimFrame(() => {
$('#chat-footer')[0].scrollIntoView();
});
})
.on('click', '#chat-window', function() {
self.toggleMenu(false);
})
.on('focus', '.text-in', function() {
self.chatWinScrollToBottom();
return false;
})
.on('keydown.chat.sendText', '.text-in', function(event) {
event.stopPropagation();
window.requestAnimFrame(() => {
$('#chat-footer')[0].scrollIntoView();
});
if (event.which === 13) {
let val = $.trim(event.target.value);
... ... @@ -185,7 +247,6 @@ var chat = {
}
});
this.orderListView
.on('selectOrder.OrderListView', function(event, data) {
let msg = {
... ... @@ -195,6 +256,7 @@ var chat = {
};
self.sendMSG(msg);
self.$chatWin[0].scrollTop = self.$chatWin[0].scrollHeight;
});
this.leaveMSGView
... ... @@ -213,9 +275,12 @@ var chat = {
self.canEvalute = false;
cmEntity.type = socketConf.recType.EVALUTE_SUCCESS;
socket.send(JSON.stringify(cmEntity));
resizeFooter();
// resizeFooter();
});
window.addEventListener('online', function() {
self.$netTip.toggleClass('hide', true);
self.connect();
... ... @@ -224,8 +289,21 @@ var chat = {
window.addEventListener('offline', function() {
self.$chat.toggleClass('online', false);
self.$netTip.toggleClass('hide', false);
self.toggleMenu(false);
// self.disconnect();
});
// app 不支持打开链接
if (isAndroid || appBridge.isApp) {
this.$chatWin.on('click', '.link', function(event) {
event.preventDefault();
// tip.show('抱歉,暂不支持,长按复制到手机浏览器打开');
return false;
});
}
},
/**
... ... @@ -242,11 +320,14 @@ var chat = {
/**
* 当断开时
*/
disconnect() {
disconnect(content) {
var self = this;
this.canLeaveMSG = true;
this.$chat.toggleClass('online', false);
this._sysInfo('<p>会话断开,点击<span class="blue">重连</span></p>')
this.toggleMenu(false);
this._sysInfo(`<p>${content}<span class="blue">连接客服</span></p>`)
.one('click', function() {
self.connect();
});
... ... @@ -282,8 +363,6 @@ var chat = {
msg.uuid = uuid;
cmEntity.userHead = msg.avatar = userAvatar;
cmEntity.csHead = customerService.head;
cmEntity.csName = customerService.name;
cmEntity.uuid = uuid;
cmEntity.type = socketConf.recType.CU_SEND;
... ... @@ -291,7 +370,7 @@ var chat = {
case 'order':
arr = [
'单号:', data.orderCode,
'金额: ', '¥' + data.cost,
'金额: ', data.cost,
'下单时间: ', data.createTime,
'状态: ', data.orderStatus
];
... ... @@ -300,6 +379,10 @@ var chat = {
cmEntity.chatMessage.type = 10;
cmEntity.chatMessage.content = arr;
break;
case 'picture':
cmEntity.chatMessage.type = 2;
cmEntity.chatMessage.content = data.content;
break;
case 'text':
default:
cmEntity.chatMessage.type = 1;
... ... @@ -345,8 +428,11 @@ var chat = {
$msg.trigger('send.sendEvent');
});
})
.on('success.sendEvent', function() {
.on('success.sendEvent', function(event, rec) {
clearTimeout($msg.data('timeoutId'));
if (rec.type === 1) {
$msg.find('.msg-content').html(rec.chatMessage.newContent);
}
$msg.removeClass('send-loading send-fail')
.off('sendEvent')
.removeData();
... ... @@ -380,6 +466,9 @@ var chat = {
var chatMessage = cm.chatMessage;
var allTypes = socketConf.recType;
//设置默认用户头像
cm.userHead = userAvatar;
switch (cm.type) {
case allTypes.CU_SEND:
viewData.from = 'customer';
... ... @@ -387,7 +476,7 @@ var chat = {
break;
case allTypes.CS_SEND:
viewData.from = 'employee';
viewData.avatar = customerService.head || socketConf.defaultUserHead;
viewData.avatar = cm.csHead || socketConf.employeHead;
break;
case allTypes.ROBOT_SEND:
viewData.from = 'rebot';
... ... @@ -413,7 +502,7 @@ var chat = {
case 1:
viewData.type = msgTypeMap[1];
viewData.data = {
content: emojiHanlder(chatMessage.newContent)
content: emojiHanlder(chatMessage.newContent) || chatMessage.content
};
break;
... ... @@ -457,12 +546,15 @@ var chat = {
if (this.unFinshMSGs[uuid]) {
let $msg = this.unFinshMSGs[uuid];
$msg.trigger('success.sendEvent');
$msg.trigger('success.sendEvent', rec);
}
// var uuid = rec.uuid;
var viewData;
this.canManualService = true;
this.canLeaveMSG = false;
// 服务状态: 离线
if (
recType === allTypes.OFFLINE ||
... ... @@ -490,6 +582,7 @@ var chat = {
case allTypes.CS_CHATTING:
if (chatMessage.type === 5) { // 重复登陆
this.canManualService = false;
this._sysInfo(chatMessage.newContent);
}
break;
... ... @@ -501,6 +594,7 @@ var chat = {
// 客服邀请评价
case allTypes.EVAL_INVITE:
this._sysInfo('<p data-trigger="rating">请对我们的服务进行<span class="blue">评价</span></p>');
this.ratingView.toggle(true);
break;
// 客服进入
... ... @@ -510,7 +604,7 @@ var chat = {
break;
case allTypes.OP_LEAVE:
case allTypes.OFFLINE:
this.disconnect();
this.disconnect(chatMessage.content);
break;
case allTypes.TRANSFER:
break;
... ... @@ -546,18 +640,26 @@ var chat = {
const chatMessage = cmEntity.chatMessage;
customerService.head = cmEntity.csHead;
customerService.name = cmEntity.csName;
function noService() {
$chatHeader.find('.js-service-txt').text('YOHO客服');
$chat.append(time(Date.now()).show());
}
// state: 0 没有人工客服
function noEmploye() {
$chatHeader.find('.js-service-txt').text('YOHO客服');
$chat.append(time(Date.now()).show());
sysInfo(chatMessage.content);
sysInfo();
}
// state 1: 排队中
function inQueue() {
let info = `${chatMessage.content}您可以<span class="blue" data-trigger="leave-msg">留言</span>`;
// let info = `${chatMessage.content}您可以<span class="blue" data-trigger="leave-msg">留言</span>`;
let info = '您可以选择<span class="blue" data-trigger="leave-msg">留言</span>,客服会以短信形式回复您';
self.canLeaveMSG = true;
sysInfo(info);
}
... ... @@ -574,8 +676,11 @@ var chat = {
}
switch (state) {
case 0: noEmploye(); break;
case 1: inQueue(); break;
case 2: linkSuccess(); break;
case 2:
case 3:
linkSuccess(); break;
default: noService(); break;
}
},
... ... @@ -594,10 +699,6 @@ var chat = {
_drawMSG: function(viewData, cusAction = null) {
let chatWin = this.$chatWin[0];
if (!$.isArray(viewData)) {
viewData = [viewData];
}
// console.log(viewData);
let $html = $(this.messageT(viewData));
... ... @@ -663,22 +764,46 @@ var chat = {
let records = result.records || [];
records.reverse();
// records.reverse();
let oldFister = self.$chatWin.find('.msg-wrap:first')[0];
let grap = oldFister ? oldFister.offsetTop : 0 ;
let $docFragment = $(document.createDocumentFragment());
records.forEach(chatMessage => {
records.forEach((chatMessage, index, arr) => {
let nextChat = records[index + 1];
let data = self.buildViewData(chatMessage); //eslint-disable-line
if (data) {
arr.push(data);
let conversationId = chatMessage.conversationId;
let timstamp = Math.ceil(chatMessage.sendTime / 1000); // 原来是微妙 转换成毫秒
let $html = self._drawMSG(data);
$docFragment.prepend($html);
if (index === 0 && !msgHistory.conversationId) {
msgHistory.conversationId = conversationId;
}
if (
nextChat &&
(nextChat.conversationId !== msgHistory.conversationId)
) {
$docFragment.prepend(time(timstamp).show());
msgHistory.conversationId = nextChat.conversationId;
}
}
});
self._drawMSG(arr, function($html) {
self.$historyLoader.after($html);
});
self.$historyLoader.after($docFragment);
oldFister && self.$chatWin.scrollTop(oldFister.offsetTop - grap );
if (records.length) {
msgHistory.endTime = records[0].sendTime;
msgHistory.endTime = records[records.length - 1].sendTime;
msgHistory.curCount += records.length;
}
... ... @@ -693,7 +818,7 @@ var chat = {
if (type === 'human') {
cmEntity.type = socketConf.recType.MANUAL_SERVICE;
socket.send(JSON.stringify(cmEntity));
this._sysInfo();
// this._sysInfo();
} else {
// todo;
}
... ... @@ -722,17 +847,46 @@ var chat = {
.find('.header-right').html(header.right);
return this;
},
toggleMenu: function(willShow) {
if (willShow === void 0) {
willShow = !this.$chat.hasClass('menu-open');
}
this.$chat.toggleClass('menu-open', willShow);
this.chatWinScrollToBottom();
// let chatWin = this.$chatWin[0];
// let footerH = $('#chat-footer .menu').outerHeight() || 0;
// if (willShow) {
// chatWin.scrollTop += footerH;
// } else {
// chatWin.scrollTop -= footerH;
// }
},
chatWinScrollToBottom: function() {
let chatWin = chat.$chatWin[0];
window.requestAnimationFrame(() => {
chatWin.scrollTop = chatWin.scrollHeight;
});
}
};
chat.init();
// 触发菜单
$('.menu-trigger').on('click', function() {
let $menu = $('.menu');
chat.toggleMenu();
// let $menu = $('.menu');
$menu.toggle();
resizeFooter();
// $menu.toggle();
// resizeFooter();
});
let $upload = $('.upload-img');
... ... @@ -772,8 +926,11 @@ $upload.on('change', function() {
.done(function(res) {
if (res.code === 200) {
$elem.removeClass('send-loading')
.find('.chat-image').attr('src', res.data.filePath);
.find('.chat-image').attr('src', res.data.filePath)
.on('load', function() {
chat.chatWinScrollToBottom();
});
msg.data.content = res.data.filePath;
chat.sendMSG(msg, true); // only send msg, no draw msg;
}
})
... ... @@ -783,6 +940,11 @@ $upload.on('change', function() {
.removeClass('send-loading')
.addClass('send-fail')
.one('click', _action);
})
.always(function() {
input.value = '';
chat.chatWinScrollToBottom();
});
};
... ... @@ -803,16 +965,59 @@ $('#chat-window').on('click', '.chat-image', function() {
});
});
if (appBridge.isApp) {
$('#js-back').on('click', function(e) {
function tellAppSuccess() {
window.setTimeout(() => {
appBridge.invokeMethod('im.page_success', {url: location.href});
}, 1000);
window.addEventListener('pageshow', tellAppSuccess);
}
function setChannelColor(channel) {
var dict = {
1: 'boys',
2: 'girls',
3: 'kids',
4: 'lifestyle'
};
$(document.body)
.removeClass('boys girls kids lifestyle')
.addClass(dict[channel]);
}
if (appBridge.isApp && /YohoBuy-iOS/i.test(navigator.userAgent)) {
document.body.classList.add('app-ios');
}
if (isAndroid) {
$('#js-back').removeAttr('href').on('click', function(e) {
e.preventDefault();
window.im.goBack();
});
setChannelColor(qs.yh_channel);
} else if (appBridge.isApp) {
$('#js-back').removeAttr('href').on('click', function(e) {
e.preventDefault();
appBridge.invokeMethod('go.back', {});
});
tellAppSuccess();
setChannelColor(qs.yh_channel);
}
window.channelChanged = function(channel) {
setChannelColor(channel);
};
window.$ = $;
window.chat = chat;
window.cmEntity = cmEntity;
... ...
... ... @@ -9,6 +9,7 @@ var param,
servers,
socket,
server,
sendFailCallback,
conversationMessage;
function _randomServer() {
... ... @@ -40,6 +41,10 @@ function socketInit(options) {
socket.onclose = options.onClose || function() {
console.log('websocket is closed');
};
socket.onerror = options.onError || function() {
console.log('websocket meet error');
};
sendFailCallback = options.sendFailCallback || $.noop;
} else {
console.log('websocket is not support');
}
... ... @@ -57,6 +62,7 @@ function sendMsg(msg) {
console.log('websocket send: ', JSON.parse(msg));
socket.send(msg);
} else {
sendFailCallback();
console.log('The socket is not open.');
}
}
... ...
... ... @@ -10,6 +10,7 @@ var config = {
servers: [gDomains.imSocket],
defaultUserHead: '//img10.static.yhbimg.com/headimg/2013/11/28/09/01cae078abe5fe320c88cdf4c220212688.gif',
rebotUserHead: `${window.STATIC_RESOURCE_PATH}/img/service/chat/im-robot.png`,
employeHead: '//img12.static.yhbimg.com/imserver/2016/11/17/11/02bc3c3de856432175c01d937342a1f2ce.jpg',
recType: {
ENTER: 1, // 用户进入
LINK_SUCCESS: 2, // 连线人工客服回应
... ... @@ -45,15 +46,15 @@ var config = {
encryptedUid: 0,
userHead: '//img10.static.yhbimg.com/headimg/2013/11/28/09/01cae078abe5fe320c88cdf4c220212688.gif', // 用户头像
userName: '', // 用户账号
csId: 0,
type: 1,
csId: 0, // 客服 ID
type: 1, // type => [0:没人在线,1:排队,2:接通,3:管理员分配]
serviceSortId: 0,
serviceSortCode: '',
customerSettingId: 0,
roleType: 0,
chatMessage: {
messageObjectId: '',
type: 0,
type: 0, // 消息内容类型: 1:文本 2:图片 3:语音 4: 订单
content: '',
newContent: ''
}
... ...
... ... @@ -5,6 +5,8 @@ const socketConf = require('./socket-config');
const conversation = socketConf.conversationMessage;
const slice = Array.prototype.slice;
let uid = $('#js-uid').val();
// EventEmitter
//--------------------------------------------------------
const EventEmitter = function() {};
... ... @@ -53,6 +55,7 @@ let api = {
return $.post('/service/leavemsg/save.json', {
conversationId: conversation.conversationId,
content,
uid
});
},
... ... @@ -61,8 +64,10 @@ let api = {
* TODO:
* 1. 目前接口不支持分页
*/
fetchOrders: function() {
return $.get('/service/order-list');
fetchOrders: function(type) {
let url = `/service/im/${type}-list`;
return $.get(url, {uid});
},
// 获取10条历史记录
... ... @@ -79,6 +84,7 @@ let api = {
},
saveEvalute: function(data) {
data.uid = uid;
return $.post('/service/im/saveEvalute', data);
}
};
... ...
... ... @@ -44,6 +44,10 @@ class Time {
timef = this._format(this.timestamp, 'yyyy.MM.dd hh:mm');
}
return this.render(timef);
}
render(timef) {
return `<div class="chat-time">
${timef}
</div>`;
... ...
... ... @@ -5,6 +5,7 @@ const loading = require('../../plugin/loading'),
require('../../common');
import {EventEmitter, api} from './store';
import appBridge from 'yoho-app';
const LeaveMSGView = function(elem) {
... ... @@ -12,6 +13,7 @@ const LeaveMSGView = function(elem) {
this.$input = this.$elem.find('.leave-text');
this.$doc = $(document);
this.bindEvents();
this.isSending = false;
};
LeaveMSGView.prototype = $.extend({}, EventEmitter.prototype, {
... ... @@ -23,10 +25,12 @@ LeaveMSGView.prototype = $.extend({}, EventEmitter.prototype, {
let self = this;
this.$elem
.on('click', '.chat-page-back', function() {
.on('click', '.chat-page-back', function(event) {
event.stopPropagation();
self.toggleHide(true);
})
.on('click.LeavseMSG.submit', '.leave-submit', function() {
event.stopPropagation();
self.submit();
});
... ... @@ -40,13 +44,20 @@ LeaveMSGView.prototype = $.extend({}, EventEmitter.prototype, {
toggleHide(willHide) {
this.$elem.toggleClass('chat-page-hide', willHide);
return this;
return false;
},
/**
* 提交留言的hanlder
*/
submit() {
if (this.isSending) {
tip.show('正在发送..');
return;
}
this.isSending = true;
let self = this;
let content = $.trim(this.$input.val());
... ... @@ -57,9 +68,13 @@ LeaveMSGView.prototype = $.extend({}, EventEmitter.prototype, {
api.leaveMsg(content)
.done(function() {
self.trigger('save.LeaveMSGView', '留言成功,');
self.$input.val('');
})
.fail(function() {
self.trigger('save.LeaveMSGView', '留言失败');
})
.always(function() {
self.isSending = false;
});
self.toggleHide(true);
... ... @@ -79,6 +94,7 @@ const RatingView = function(elem, socket) {
this.rank = 3;
this.bindEvents();
this.socket = socket;
this.isSending = false;
};
RatingView.prototype = $.extend({}, EventEmitter.prototype, {
... ... @@ -88,6 +104,8 @@ RatingView.prototype = $.extend({}, EventEmitter.prototype, {
this.elem
.on('click.RatingView.rating', '.stars i', function(event) {
event.stopPropagation();
let starVal = $(this).index();
self.rating(starVal);
... ... @@ -115,6 +133,12 @@ RatingView.prototype = $.extend({}, EventEmitter.prototype, {
},
post(data) {
if (this.isSending) {
tip.show('正在发送..');
return;
}
this.isSending = true;
const self = this,
elem = this.elem;
var params = {
... ... @@ -138,12 +162,20 @@ RatingView.prototype = $.extend({}, EventEmitter.prototype, {
})
.fail(()=> {
tip.show('评价失败');
})
.always(() => {
self.isSending = false;
});
},
toggle(willShow) {
if (willShow === this.elem.is(':visible')) {
return;
}
this.elem.toggle(willShow);
this.rating(3);
this.rating(4);
return false;
}
});
... ... @@ -156,8 +188,20 @@ const OrderListView = function(elem) {
this.$localOrders = this.$elem.find('[data-tab=local]');
this.$globalOrders = this.$elem.find('[data-tab=global]');
// 分页数据
this.state = {
global: {
curCount: 0,
totalCount: null
},
order: {
curCount: 0,
totalCount: null
}
};
this.bindEvents();
this.fetchOrders();
// this.fetchOrders();
};
OrderListView.prototype = $.extend({}, EventEmitter.prototype, {
... ... @@ -165,15 +209,19 @@ OrderListView.prototype = $.extend({}, EventEmitter.prototype, {
const self = this;
this.$elem
.on('click.OrderListView.back', '.chat-page-back', function() {
.on('click.OrderListView.back', '.chat-page-back', function(event) {
event.stopPropagation();
self.toggleHide(true);
})
.on('click.OrderListView.select', '[data-action=select]', function() {
.on('click.OrderListView.select', '[data-action=select]', function(event) {
event.stopPropagation();
self.selectOrder($(event.target));
});
// 被通知显示,执行显示
this.on('show.OderListView', $.proxy(this.toggleHide, this, false));
this.on('show.OderListView', (event, type) => {
self.toggleHide(false, type);
});
},
/**
... ... @@ -203,25 +251,55 @@ OrderListView.prototype = $.extend({}, EventEmitter.prototype, {
* @param boolean willHide;
* @return this
*/
toggleHide: function(willHide) {
toggleHide: function(willHide, type) {
this.$elem.toggleClass('chat-page-hide', willHide);
if (!willHide) {
let orderState = this.state[type];
let {totalCount} = orderState;
totalCount === null && this.fetchOrderByType(type, orderState);
if (type === 'global') {
this.$globalOrders.show();
this.$localOrders.hide();
} else if (type === 'order') {
this.$globalOrders.hide();
this.$localOrders.show();
}
} else {
this.$globalOrders.hide();
this.$localOrders.hide();
}
return this;
},
fetchOrderByType: function(type, orderState) {
let self = this;
let $order = type === 'global' ? this.$globalOrders : this.$localOrders;
let {totalCount} = orderState;
/**
* method: 获取订单
*/
fetchOrders: function() {
const self = this;
// TODO: 分页
if (totalCount === null) { // 还未加载数据
api.fetchOrders(type).done(
result => {
let html = self.orderListT({
orders: result.data,
isApp: appBridge.isApp,
isGlobal: type === 'global'
});
return api.fetchOrders().done(result => {
let html = self.orderListT({orders: result.data});
orderState.totalCount = result.data.length;
orderState.curCount = result.data.length;
self.$localOrders.append(html);
lazyLoad($('img.lazy'));
});
$order.append(html);
}
);
}
}
});
... ...
... ... @@ -104,15 +104,24 @@
}
.gm-ico {
background-image: resolve("service/chat/gm-ico.png");
background-image: url("/service/chat/gm-ico.png");
width: 60px;
height: 60px;
margin: 30px 20px;
}
.advice-ico {
background-image: resolve("service/chat/advice-ico.png");
background-image: url("/service/chat/advice-ico.png");
width: 60px;
height: 60px;
margin: 30px 20px;
}
.tel-ico {
background-image: resolve("service/chat/tel-ico.png");
background-image: url("/service/chat/tel-ico.png");
width: 60px;
height: 60px;
margin: 30px 20px;
}
.arr-ico {
... ... @@ -420,15 +429,24 @@
}
.gm-ico {
background-image: resolve("service/chat/gm-ico.png");
background-image: url("/service/chat/gm-ico.png");
width: 60px;
height: 60px;
margin: 30px 20px;
}
.advice-ico {
background-image: resolve("service/chat/advice-ico.png");
background-image: url("/service/chat/advice-ico.png");
width: 60px;
height: 60px;
margin: 30px 20px;
}
.tel-ico {
background-image: resolve("service/chat/tel-ico.png");
background-image: url("/service/chat/tel-ico.png");
width: 60px;
height: 60px;
margin: 30px 20px;
}
.arr-ico {
... ...
... ... @@ -6,7 +6,7 @@
.input-method,
.menu-trigger {
width: 60px;
width: 100px;
height: 60px;
background-repeat: no-repeat;
background-size: 60px 60px;
... ... @@ -33,12 +33,15 @@
height: 70px;
border: 1PX solid #e0e0e0;
border-radius: 8px;
padding: 16px;
}
.menu-trigger {
display: none;
margin-left: 20px;
padding-left: 20px;
padding-right: 20px;
background-image: resolve("service/chat/menu-trigger.png");
background-position: center center;
}
}
}
... ...
html, body {
height: 100%;
width: 100%;
}
.service-chat {
/* -------------------------------- *\
atom, util
... ... @@ -68,7 +73,7 @@
i {
display: none;
background: resolve('img/service/chat/loading.gif') no-repeat;
background: resolve('service/chat/loading.gif') no-repeat;
background-size: contain;
width: 20px;
height: 20px;
... ... @@ -131,6 +136,8 @@
.chat-rating-trigger {
display: none;
min-width: 80px;
text-align: right;
}
/* 客服在线 */
... ... @@ -147,4 +154,56 @@
display: inline-block;
}
}
/* menu open*/
.menu-open {
.menu {
display: block;
}
#chat-window {
bottom: 360px;
}
#chat-send-box {
padding-right: 0;
}
}
}
body.app-ios {
.nav-back {
text-align: left;
}
#chat-window,
.connection-failed,
.chat-page {
margin-top: 20PX;
}
.ios-gap {
height: 20PX;
}
}
body.boys, .boys .chat-header {
background-color: #414141 !important;
background-image: none;
}
body.girls, .girls .chat-header {
background-color: #ff88ae !important;
background-image: none;
}
body.kids, .kids .chat-header {
background-color: #7ad9f9 !important;
background-image: none;
}
body.lifestyle, .lifestyle .chat-header {
background-color: #4f4138 !important;
background-image: none;
}
... ...
... ... @@ -3,7 +3,6 @@
.head-icon {
height: 90px;
width: 90px;
background: green;
border-radius: 50%;
}
... ... @@ -137,6 +136,7 @@
}
.msg-content {
max-width: 90%;
margin: 0 0 0 10px;
background: #646464;
color: #fff;
... ...
... ... @@ -27,6 +27,8 @@
span {
float: right;
min-width: 80px;
text-align: right;
}
}
... ... @@ -63,6 +65,7 @@
height: 110px;
width: 100%;
margin: 50px 0 0;
padding: 16px;
resize: none;
border: 1px solid #e0e0e0;
border-radius: 5px;
... ...