Authored by 周少峰

Merge branch 'master' into feature/seoUrl302

@@ -33,7 +33,7 @@ exports.index = (req, res, next) => { @@ -33,7 +33,7 @@ exports.index = (req, res, next) => {
33 exports.getCouponStatus = (req, res, next) => { 33 exports.getCouponStatus = (req, res, next) => {
34 couponModel.getCouponStatus({ 34 couponModel.getCouponStatus({
35 uid: req.user.uid, 35 uid: req.user.uid,
36 - contentCode: req.query.contentCode 36 + contentCode: req.query.contentCode || contentCode
37 }).then(result => { 37 }).then(result => {
38 res.json(result); 38 res.json(result);
39 }).catch(next); 39 }).catch(next);
@@ -6,10 +6,10 @@ @@ -6,10 +6,10 @@
6 'use strict'; 6 'use strict';
7 7
8 const _ = require('lodash'); 8 const _ = require('lodash');
9 -const pinyin = require('pinyin-converter');  
10 9
11 const crypto = global.yoho.crypto; 10 const crypto = global.yoho.crypto;
12 11
  12 +const pinyin = require('../models/province-pinyin');
13 const addressApi = require('../models/address-api'); 13 const addressApi = require('../models/address-api');
14 14
15 const worldSort = 'abcdefghijklmnopqrstuvwxyz'; 15 const worldSort = 'abcdefghijklmnopqrstuvwxyz';
@@ -20,14 +20,11 @@ const getAreaListData = (id) => { @@ -20,14 +20,11 @@ const getAreaListData = (id) => {
20 20
21 if (id * 1 === 0 && list.length) { 21 if (id * 1 === 0 && list.length) {
22 _.forEach(list, value => { 22 _.forEach(list, value => {
23 - value.initial = _.get(pinyin(value.caption, {  
24 - style: pinyin.STYLE_FIRST_LETTER  
25 - }), '[0][0]', 'w'); 23 + value.initial = pinyin[value.caption] || 'z';
26 value.pySort = _.indexOf(worldSort, value.initial); 24 value.pySort = _.indexOf(worldSort, value.initial);
27 }); 25 });
28 result.data = list; 26 result.data = list;
29 } 27 }
30 -  
31 return result; 28 return result;
32 }); 29 });
33 }; 30 };
@@ -619,8 +619,10 @@ const formatCart = (cartDataRet, uid, shoppingKey, cartDelList) => { @@ -619,8 +619,10 @@ const formatCart = (cartDataRet, uid, shoppingKey, cartDelList) => {
619 } 619 }
620 620
621 // promotionInfos, gifts, priceGifts 放一起展示 621 // promotionInfos, gifts, priceGifts 放一起展示
622 - let hasGifts = _.get(result, 'ordinaryCart.gifts') && _.get(result, 'ordinaryCart.gifts').length;  
623 - let hasPrices = _.get(result, 'ordinaryCart.priceGifts') && _.get(result, 'ordinaryCart.priceGifts').length; 622 + let hasGifts = _.get(result, 'ordinaryCart.giftsPromotionInfos') &&
  623 + _.get(result, 'ordinaryCart.giftsPromotionInfos').length;
  624 + let hasPrices = _.get(result, 'ordinaryCart.priceGiftsPromotionInfos') &&
  625 + _.get(result, 'ordinaryCart.priceGiftsPromotionInfos').length;
624 let hasPromo = _.get(result, 'ordinaryCart.promotionInfos') && _.get(result, 'ordinaryCart.promotionInfos').length; 626 let hasPromo = _.get(result, 'ordinaryCart.promotionInfos') && _.get(result, 'ordinaryCart.promotionInfos').length;
625 let orderAmount = (parseFloat(_.get(advStat, 'orderAmount', 0)) + 627 let orderAmount = (parseFloat(_.get(advStat, 'orderAmount', 0)) +
626 parseFloat(_.get(ordStat, 'orderAmount', 0))).toFixed(2); 628 parseFloat(_.get(ordStat, 'orderAmount', 0))).toFixed(2);
  1 +module.exports = {
  2 + '北京市': 'b',
  3 + '天津市': 't',
  4 + '河北省': 'h',
  5 + '山西省': 's',
  6 + '内蒙古自治区': 'n',
  7 + '辽宁省': 'l',
  8 + '吉林省': 'j',
  9 + '黑龙江省': 'h',
  10 + '上海市': 's',
  11 + '江苏省': 'j',
  12 + '浙江省': 'z',
  13 + '安徽省': 'a',
  14 + '福建省': 'f',
  15 + '江西省': 'j',
  16 + '山东省': 's',
  17 + '河南省': 'h',
  18 + '湖北省': 'h',
  19 + '湖南省': 'h',
  20 + '广东省': 'g',
  21 + '广西壮族自治区': 'g',
  22 + '海南省': 'h',
  23 + '重庆市': 'c',
  24 + '四川省': 's',
  25 + '贵州省': 'g',
  26 + '云南省': 'y',
  27 + '西藏自治区': 'x',
  28 + '陕西省': 's',
  29 + '甘肃省': 'g',
  30 + '青海省': 'q',
  31 + '宁夏回族自治区': 'n',
  32 + '新疆维吾尔自治区': 'x'
  33 +};
@@ -64,7 +64,7 @@ const homeNav = (req) => { @@ -64,7 +64,7 @@ const homeNav = (req) => {
64 {name: '我的信息', href: '/home/message', count: 0}, 64 {name: '我的信息', href: '/home/message', count: 0},
65 { 65 {
66 name: '在线客服', 66 name: '在线客服',
67 - href: _.get(req.app.locals.pc, 'clientService.new', false) ? 'http://chat8.live800.com/live800/chatClient/chatbox.jsp?companyID=620092&configID=149091&jid=8732423409' : '/service/client', 67 + href: _.get(req.app.locals.pc, 'clientService.new', false) ? 'http://chat8.live800.com/live800/chatClient/chatbox.jsp?companyID=620092&configID=149091&jid=8732423409' : '/service/client',
68 isBlank: true 68 isBlank: true
69 } 69 }
70 ] 70 ]
@@ -50,12 +50,6 @@ passport.use('local', new LocalStrategy({ @@ -50,12 +50,6 @@ passport.use('local', new LocalStrategy({
50 return done({message: '登录参数错误'}, null); 50 return done({message: '登录参数错误'}, null);
51 } 51 }
52 52
53 - let verifyCode = req.body.captcha;  
54 -  
55 - if (verifyCode && verifyCode !== req.session.captcha) {  
56 - return done({message: '验证码不正确或验证码过期', needCaptcha: true}, null);  
57 - }  
58 -  
59 let shoppingKey = cookie.getShoppingKey(req); 53 let shoppingKey = cookie.getShoppingKey(req);
60 54
61 let account = req.body.account; 55 let account = req.body.account;
@@ -35,7 +35,16 @@ router.post('/passport/login/qrcode/refresh', login.local.qrcode.refresh); @@ -35,7 +35,16 @@ router.post('/passport/login/qrcode/refresh', login.local.qrcode.refresh);
35 router.post('/passport/login/qrcode/check', login.local.qrcode.check); // 验证二维码的状态 35 router.post('/passport/login/qrcode/check', login.local.qrcode.check); // 验证二维码的状态
36 36
37 router.get('/passport/login', login.common.beforeLogin, login.local.loginPage); 37 router.get('/passport/login', login.common.beforeLogin, login.local.loginPage);
38 -router.post('/passport/login/auth', login.local.login); 38 +router.post('/passport/login/auth',
  39 + (req, res, next) => {
  40 + if (req.body.loginType === 'password') {
  41 + return captcha.requiredAPI(req, res, next);
  42 + } else {
  43 + return next();
  44 + }
  45 + },
  46 + login.local.login
  47 +);
39 router.get('/passport/logout', login.local.logout); 48 router.get('/passport/logout', login.local.logout);
40 49
41 // 微信登录 50 // 微信登录
@@ -55,7 +55,7 @@ @@ -55,7 +55,7 @@
55 </span> 55 </span>
56 </li> 56 </li>
57 57
58 - <li class="clearfix captcha-wrap hide"> 58 + <li class="clearfix captcha-wrap">
59 </li> 59 </li>
60 60
61 <li class="relative clearfix sms-login hide"> 61 <li class="relative clearfix sms-login hide">
@@ -6,7 +6,7 @@ @@ -6,7 +6,7 @@
6 <span class="title">留言</span> 6 <span class="title">留言</span>
7 </div> 7 </div>
8 <div class="cus-body"> 8 <div class="cus-body">
9 - <textarea maxlength="120" placeholder="请输入留言信息" spellcheck="false"></textarea> 9 + <textarea maxlength="500" placeholder="请输入留言信息" spellcheck="false"></textarea>
10 <i class="leave-msg-tip hide">留言内容不能为空</i> 10 <i class="leave-msg-tip hide">留言内容不能为空</i>
11 </div> 11 </div>
12 <div class="cus-footer"> 12 <div class="cus-footer">
@@ -19,7 +19,7 @@ @@ -19,7 +19,7 @@
19 <div class="edit-left"> 19 <div class="edit-left">
20 <div class="util"> 20 <div class="util">
21 <span class="icon emoji">表情</span> 21 <span class="icon emoji">表情</span>
22 - <span class="icon">图片<label for="sendImg"></label></span> 22 + <span class="icon image">图片<label for="sendImg"></label></span>
23 <span class="icon evaluate">评价</span> 23 <span class="icon evaluate">评价</span>
24 <span class="icon manual-service">人工客服</span> 24 <span class="icon manual-service">人工客服</span>
25 </div> 25 </div>
@@ -36,8 +36,7 @@ module.exports = { @@ -36,8 +36,7 @@ module.exports = {
36 // service: 'http://dev-service.yohops.com:9999/', 36 // service: 'http://dev-service.yohops.com:9999/',
37 37
38 imSocket: 'ws://socket.yohobuy.com:10240', 38 imSocket: 'ws://socket.yohobuy.com:10240',
39 - imCs: 'http://im.yohobuy.com/api',  
40 - imServer: 'http://im.yohobuy.com/server' 39 + imCs: 'http://im.yohobuy.com/api'
41 }, 40 },
42 subDomains: { 41 subDomains: {
43 host: '.yohobuy.com', 42 host: '.yohobuy.com',
@@ -130,8 +129,7 @@ if (isProduction) { @@ -130,8 +129,7 @@ if (isProduction) {
130 service: 'http://service.yoho.yohoops.org/', 129 service: 'http://service.yoho.yohoops.org/',
131 search: 'http://search.yohoops.org/yohosearch/', 130 search: 'http://search.yohoops.org/yohosearch/',
132 imSocket: 'ws://imsocket.yohobuy.com:10000', 131 imSocket: 'ws://imsocket.yohobuy.com:10000',
133 - imCs: 'https://imhttp.yohobuy.com/api',  
134 - imServer: 'https://imhttp.yohobuy.com/server' 132 + imCs: 'https://imhttp.yohobuy.com/api'
135 }, 133 },
136 memcache: { 134 memcache: {
137 master: ['memcache1.yohoops.org:12111', 'memcache2.yohoops.org:12111', 'memcache3.yohoops.org:12111'], 135 master: ['memcache1.yohoops.org:12111', 'memcache2.yohoops.org:12111', 'memcache3.yohoops.org:12111'],
@@ -160,8 +158,7 @@ if (isProduction) { @@ -160,8 +158,7 @@ if (isProduction) {
160 service: process.env.TEST_SERVICE || 'http://testservice.yoho.cn:28077/', 158 service: process.env.TEST_SERVICE || 'http://testservice.yoho.cn:28077/',
161 search: process.env.TEST_SEARCH || 'http://192.168.102.216:8080/yohosearch/', 159 search: process.env.TEST_SEARCH || 'http://192.168.102.216:8080/yohosearch/',
162 imSocket: 'ws://socket.yohobuy.com:10240', 160 imSocket: 'ws://socket.yohobuy.com:10240',
163 - imCs: 'http://im.yohobuy.com/api',  
164 - imServer: 'http://im.yohobuy.com/server' 161 + imCs: 'http://im.yohobuy.com/api'
165 }, 162 },
166 useOneapm: true, 163 useOneapm: true,
167 useCache: true, 164 useCache: true,
@@ -28,44 +28,45 @@ const channelMap = { @@ -28,44 +28,45 @@ const channelMap = {
28 const sortMap = { 28 const sortMap = {
29 boys: [ 29 boys: [
30 30
31 - {misort: 16, viewNum: 5}, // 卫衣  
32 - {misort: 21, viewNum: 5}, // 夹克  
33 - {misort: 44, viewNum: 5}, // 休闲运动鞋  
34 - {misort: 22, viewNum: 5}, // 大衣/风衣  
35 {misort: 12, viewNum: 5}, // 衬衫 31 {misort: 12, viewNum: 5}, // 衬衫
  32 + {misort: 11, viewNum: 5}, // T恤
  33 + {misort: 16, viewNum: 5}, // 卫衣
  34 + {misort: 21, viewNum: 5}, // 大衣/风衣
  35 + {misort: 44, viewNum: 5}, // 休闲/运动鞋
36 {misort: 26, viewNum: 5}, // 休闲裤 36 {misort: 26, viewNum: 5}, // 休闲裤
37 {misort: 27, viewNum: 5}, // 牛仔裤 37 {misort: 27, viewNum: 5}, // 牛仔裤
38 - {misort: 48, viewNum: 5}, // 时装鞋  
39 - {misort: 20, viewNum: 5}, // 棉衣  
40 - {misort: 257, viewNum: 5}, // 毛衣/针织  
41 - {misort: 172, viewNum: 5}, // 皮衣 38 + {misort: 45, viewNum: 5}, // 靴子
42 {misort: 226, viewNum: 5}, // 防风外套 39 {misort: 226, viewNum: 5}, // 防风外套
43 - {misort: 18, viewNum: 5}, // 羽绒服 40 + {misort: 13, viewNum: 5}, // POLO
  41 + {misort: 28, viewNum: 5}, // 短裤
44 {misort: 49, viewNum: 5}, // 双肩包 42 {misort: 49, viewNum: 5}, // 双肩包
45 {misort: 60, viewNum: 5}, // 帽子 43 {misort: 60, viewNum: 5}, // 帽子
46 {misort: 59, viewNum: 5}, // 手表 44 {misort: 59, viewNum: 5}, // 手表
47 {misort: 66, viewNum: 5}, // 配饰 45 {misort: 66, viewNum: 5}, // 配饰
  46 + {misort: 50, viewNum: 5}, // 手拎包/单肩包
48 {misort: 65, viewNum: 5}, // 首饰 47 {misort: 65, viewNum: 5}, // 首饰
49 {misort: 309, viewNum: 5}, // 内裤 48 {misort: 309, viewNum: 5}, // 内裤
50 - {misort: 259, viewNum: 5} // 美妆 49 + {misort: 237, viewNum: 5}, // 钱包/卡包/手包/钥匙包
  50 + {misort: 61, viewNum: 5} // 太阳镜/眼镜
51 51
52 ], 52 ],
53 girls: [ 53 girls: [
54 54
  55 + {misort: 31, viewNum: 4}, // 连衣裙
  56 + {misort: 11, viewNum: 4}, // T恤
  57 + {misort: 32, viewNum: 4}, // 半身裙
55 {misort: 16, viewNum: 4}, // 卫衣 58 {misort: 16, viewNum: 4}, // 卫衣
  59 + {misort: 257, viewNum: 4}, // 毛衣/针织
56 {misort: 21, viewNum: 4}, // 夹克 60 {misort: 21, viewNum: 4}, // 夹克
  61 + {misort: 12, viewNum: 4}, // 衬衫
57 {misort: 44, viewNum: 4}, // 休闲/运动鞋 62 {misort: 44, viewNum: 4}, // 休闲/运动鞋
58 - {misort: 22, viewNum: 4}, // 大衣/风衣  
59 - {misort: 31, viewNum: 4}, // 连衣裙  
60 - {misort: 48, viewNum: 4}, // 时装鞋  
61 - {misort: 257, viewNum: 4}, // 毛衣/针织  
62 - {misort: 172, viewNum: 4}, // 皮衣  
63 - {misort: 226, viewNum: 4}, // 防风外套  
64 - {misort: 20, viewNum: 4}, // 棉服 63 + {misort: 26, viewNum: 4}, // 休闲裤
65 {misort: 27, viewNum: 4}, // 牛仔裤 64 {misort: 27, viewNum: 4}, // 牛仔裤
66 - {misort: 18, viewNum: 4}, // 羽绒服  
67 - {misort: 12, viewNum: 4}, // 衬衫 65 + {misort: 28, viewNum: 4}, // 短裤
  66 + {misort: 48, viewNum: 4}, // 时装鞋
68 {misort: 49, viewNum: 4}, // 双肩包 67 {misort: 49, viewNum: 4}, // 双肩包
  68 + {misort: 50, viewNum: 4}, // 手拎包/单肩包
  69 + {misort: 39, viewNum: 4}, // 袜子
69 {misort: 60, viewNum: 4}, // 帽子 70 {misort: 60, viewNum: 4}, // 帽子
70 {misort: 61, viewNum: 4}, // 太阳镜/眼镜 71 {misort: 61, viewNum: 4}, // 太阳镜/眼镜
71 {misort: 65, viewNum: 4}, // 首饰 72 {misort: 65, viewNum: 4}, // 首饰
@@ -76,21 +77,25 @@ const sortMap = { @@ -76,21 +77,25 @@ const sortMap = {
76 kids: [ 77 kids: [
77 78
78 {misort: 396, viewNum: 4}, // 卫衣 79 {misort: 396, viewNum: 4}, // 卫衣
  80 + {misort: 368, viewNum: 4}, // 休闲/运动鞋
  81 + {misort: 369, viewNum: 4}, // 休闲裤
  82 + {misort: 366, viewNum: 4}, // T恤
79 {misort: 404, viewNum: 4}, // 夹克 83 {misort: 404, viewNum: 4}, // 夹克
80 {misort: 400, viewNum: 4}, // 毛衣/针织 84 {misort: 400, viewNum: 4}, // 毛衣/针织
81 - {misort: 369, viewNum: 4}, // 休闲裤 85 + {misort: 371, viewNum: 4}, // 连衣裙
  86 + {misort: 367, viewNum: 4}, // 衬衫
  87 + {misort: 462, viewNum: 4}, // 靴子
82 {misort: 406, viewNum: 4}, // 大衣/风衣 88 {misort: 406, viewNum: 4}, // 大衣/风衣
83 - {misort: 390, viewNum: 4}, // 运动裤  
84 - {misort: 368, viewNum: 4}, // 休闲/运动鞋  
85 - {misort: 423, viewNum: 4}, // 棉衣  
86 {misort: 392, viewNum: 4}, // 双肩包 89 {misort: 392, viewNum: 4}, // 双肩包
87 - {misort: 402, viewNum: 4}, // 马甲  
88 - {misort: 470, viewNum: 4}, // 连体裤 90 + {misort: 448, viewNum: 4}, // 玩具娱乐
  91 + {misort: 382, viewNum: 4}, // 凉鞋/凉拖
  92 + {misort: 388, viewNum: 4}, // 牛仔裤
  93 + {misort: 417, viewNum: 4}, // 套装
89 {misort: 408, viewNum: 4}, // 袜子 94 {misort: 408, viewNum: 4}, // 袜子
90 - {misort: 367, viewNum: 4}, // 衬衫  
91 - {misort: 371, viewNum: 4}, // 连衣裙  
92 - {misort: 429, viewNum: 4}, // 太阳镜/眼镜  
93 - {misort: 414, viewNum: 4} // 帽子 95 + {misort: 470, viewNum: 4}, // 连体裤
  96 + {misort: 372, viewNum: 4}, // 短裤
  97 + {misort: 370, viewNum: 4}, // 半身裙
  98 + {misort: 460, viewNum: 4} // 时装鞋
94 99
95 ], 100 ],
96 lifestyle: [ 101 lifestyle: [
@@ -29,8 +29,6 @@ module.exports = (limiter, policy) => { @@ -29,8 +29,6 @@ module.exports = (limiter, policy) => {
29 29
30 const key = `pc:limiter:${limiter.remoteIp}`; 30 const key = `pc:limiter:${limiter.remoteIp}`;
31 31
32 - let isNew = true;  
33 -  
34 res.on('render', function() { 32 res.on('render', function() {
35 let route = req.route ? req.route.path : ''; 33 let route = req.route ? req.route.path : '';
36 let appPath = req.app.mountpath; 34 let appPath = req.app.mountpath;
@@ -46,15 +44,14 @@ module.exports = (limiter, policy) => { @@ -46,15 +44,14 @@ module.exports = (limiter, policy) => {
46 pageIncr = 5; 44 pageIncr = 5;
47 } 45 }
48 46
49 - if (pageIncr > 0 && !isNew) {  
50 - cache.incrAsync(key, pageIncr); 47 + if (pageIncr > 0) {
  48 + cache.incr(key, pageIncr, (err) => {});
51 } 49 }
52 }); 50 });
53 51
54 return cache.getAsync(key).then((result) => { 52 return cache.getAsync(key).then((result) => {
55 logger.debug('qps limiter: ' + key + '@' + result + ' max: ' + MAX_QPS); 53 logger.debug('qps limiter: ' + key + '@' + result + ' max: ' + MAX_QPS);
56 if (result && _.isNumber(result)) { 54 if (result && _.isNumber(result)) {
57 - isNew = false;  
58 if (result === -1) { 55 if (result === -1) {
59 return Promise.resolve(true); 56 return Promise.resolve(true);
60 } 57 }
@@ -189,7 +189,7 @@ @@ -189,7 +189,7 @@
189 </div> 189 </div>
190 <div class="left"> 190 <div class="left">
191 <span class="iconfont rgbf">&#xe602;</span> 191 <span class="iconfont rgbf">&#xe602;</span>
192 - <a href="{{#if @root.pc.clientService.new}}http://chat8.live800.com/live800/chatClient/chatbox.jsp?companyID=620092&amp;configID=149091&amp;jid=8732423409{{else}}/service/client{{/if}}" target="_blank"> 192 + <a href="{{#if @root.pc.clientService.new}}http://chat8.live800.com/live800/chatClient/chatbox.jsp?companyID=620092&configID=149091&jid=8732423409{{else}}/service/client{{/if}}" target="_blank">
193 <span class="red">便捷</span> 193 <span class="red">便捷</span>
194 <span class="rgbf">在线客服</span> 194 <span class="rgbf">在线客服</span>
195 </a> 195 </a>
1 { 1 {
2 "name": "yohobuy-node", 2 "name": "yohobuy-node",
3 - "version": "5.4.14", 3 + "version": "5.4.18",
4 "private": true, 4 "private": true,
5 "description": "A New Yohobuy Project With Express", 5 "description": "A New Yohobuy Project With Express",
6 "repository": { 6 "repository": {
@@ -56,7 +56,6 @@ @@ -56,7 +56,6 @@
56 "passport-sina": "^0.1.0", 56 "passport-sina": "^0.1.0",
57 "passport-strategy": "1.x.x", 57 "passport-strategy": "1.x.x",
58 "passport-weixin": "^0.1.0", 58 "passport-weixin": "^0.1.0",
59 - "pinyin-converter": "^2.8.1",  
60 "request-ip": "^1.2.2", 59 "request-ip": "^1.2.2",
61 "request-promise": "^3.0.0", 60 "request-promise": "^3.0.0",
62 "serve-favicon": "^2.3.0", 61 "serve-favicon": "^2.3.0",
@@ -173,10 +173,6 @@ function getCouponStatus() { @@ -173,10 +173,6 @@ function getCouponStatus() {
173 data[hash[0]] = hash[1]; 173 data[hash[0]] = hash[1];
174 } 174 }
175 175
176 - if (!data.contentCode) {  
177 - return;  
178 - }  
179 -  
180 $.ajax({ 176 $.ajax({
181 type: 'GET', 177 type: 'GET',
182 url: '/coupon/couponstatus', 178 url: '/coupon/couponstatus',
@@ -103,7 +103,7 @@ ColorPanelAction = { @@ -103,7 +103,7 @@ ColorPanelAction = {
103 }, 103 },
104 selectColor: function() { 104 selectColor: function() {
105 var $this = $(this); 105 var $this = $(this);
106 - var index = $this.index($this.parent().find('.dt')); 106 + var index = $this.parent().find('.dt').index($this);
107 var $srows = $this.closest('.goods-info').find('.choose-size .size-row'); 107 var $srows = $this.closest('.goods-info').find('.choose-size .size-row');
108 var $bigImgs = $this.closest('.goods-choose-box').find('.goods-info-bigImg .bigImg'); 108 var $bigImgs = $this.closest('.goods-choose-box').find('.goods-info-bigImg .bigImg');
109 109
@@ -55,7 +55,7 @@ var $accountInput1 = $('#account1'), @@ -55,7 +55,7 @@ var $accountInput1 = $('#account1'),
55 // 图像验证码 55 // 图像验证码
56 $captchaImgWrapper = $('.captcha-wrap'), 56 $captchaImgWrapper = $('.captcha-wrap'),
57 captchaImg = new Captcha('.captcha-wrap').init(), 57 captchaImg = new Captcha('.captcha-wrap').init(),
58 - $showCaptchaImg = false, 58 + $showCaptchaImg = true,
59 getCaptchaImgVal = function() { 59 getCaptchaImgVal = function() {
60 return captchaImg.getResults(); 60 return captchaImg.getResults();
61 }, 61 },
@@ -250,6 +250,8 @@ var tpl = function(text) { @@ -250,6 +250,8 @@ var tpl = function(text) {
250 ].join(''); 250 ].join('');
251 }; 251 };
252 252
  253 +require('../../common/promise');
  254 +
253 // 切换登录方式 255 // 切换登录方式
254 accountChangeEvent.add(function(type) { 256 accountChangeEvent.add(function(type) {
255 currentLogin = AccountLoginData[type]; 257 currentLogin = AccountLoginData[type];
@@ -278,7 +280,10 @@ accountChangeEvent.add(function(type) { @@ -278,7 +280,10 @@ accountChangeEvent.add(function(type) {
278 if (type === AccountLoginData.PasswordLogin.name) { 280 if (type === AccountLoginData.PasswordLogin.name) {
279 if ($showCaptchaImg) { 281 if ($showCaptchaImg) {
280 $captchaImgWrapper.removeClass('hide'); 282 $captchaImgWrapper.removeClass('hide');
  283 +
  284 + $.sleep(500).then(function() {
281 captchaImg.refresh(); 285 captchaImg.refresh();
  286 + });
282 } 287 }
283 } 288 }
284 289
@@ -648,7 +653,9 @@ function validateSmsCaptchaImg() { @@ -648,7 +653,9 @@ function validateSmsCaptchaImg() {
648 } 653 }
649 654
650 function refreshSmsCaptchaImg() { 655 function refreshSmsCaptchaImg() {
  656 + $.sleep(1000).then(function() {
651 smsCaptchaImg.refresh(); 657 smsCaptchaImg.refresh();
  658 + });
652 } 659 }
653 660
654 /** ************************************************************************/ 661 /** ************************************************************************/
@@ -848,7 +855,7 @@ function loginAsync() { @@ -848,7 +855,7 @@ function loginAsync() {
848 areaCode: getAreaCodeVal(), 855 areaCode: getAreaCodeVal(),
849 account: currentLogin.getAccountVal(), 856 account: currentLogin.getAccountVal(),
850 password: currentLogin.creditableToken(), 857 password: currentLogin.creditableToken(),
851 - captcha: currentLogin.type() === 'password' ? getCaptchaImgVal() : '', 858 + verifyCode: currentLogin.type() === 'password' ? getCaptchaImgVal() : '',
852 isRemember: getRememberMeVal(), 859 isRemember: getRememberMeVal(),
853 loginType: currentLogin.type() 860 loginType: currentLogin.type()
854 } 861 }
@@ -576,6 +576,8 @@ exports.init = function(page) { @@ -576,6 +576,8 @@ exports.init = function(page) {
576 }; 576 };
577 } 577 }
578 578
  579 + var isRegRequesting = false; // eslint-disable-line
  580 +
579 // ajax表单提交 581 // ajax表单提交
580 $registerBtn.click(function() { 582 $registerBtn.click(function() {
581 var url; 583 var url;
@@ -590,6 +592,12 @@ exports.init = function(page) { @@ -590,6 +592,12 @@ exports.init = function(page) {
590 return; 592 return;
591 } else { 593 } else {
592 594
  595 + if (isRegRequesting) {
  596 + return;
  597 + }
  598 +
  599 + isRegRequesting = true;
  600 +
593 // ajax提交 601 // ajax提交
594 $.ajax({ 602 $.ajax({
595 type: 'POST', 603 type: 'POST',
@@ -636,6 +644,8 @@ exports.init = function(page) { @@ -636,6 +644,8 @@ exports.init = function(page) {
636 alert(data.message); //eslint-disable-line 644 alert(data.message); //eslint-disable-line
637 } 645 }
638 646
  647 + }).always(function() {
  648 + isRegRequesting = false;
639 }); 649 });
640 } 650 }
641 }); 651 });
  1 +/**
  2 + * 浏览器相关功能扩展
  3 + * @author: liqi <qi.li@yoho.cn>
  4 + * @date: 2016/11/26
  5 + */
  6 +
  7 +var $ = require('yoho-jquery');
  8 +
  9 +var state;
  10 +var isHidden;
  11 +var changeEvent;
  12 +
  13 +/**
  14 + * 获取光标位置
  15 + */
  16 +function _getCursorPosition() {
  17 + var sel,
  18 + pos = 0,
  19 + selLength,
  20 + el = $(this).get(0);
  21 +
  22 + if ('selectionStart' in el) {
  23 + pos = el.selectionStart;
  24 + } else if ('selection' in document) {
  25 + sel = document.selection.createRange();
  26 + selLength = document.selection.createRange().text.length;
  27 +
  28 + el.focus();
  29 + sel.moveStart('character', -el.value.length);
  30 + pos = sel.text.length - selLength;
  31 + }
  32 + return pos;
  33 +}
  34 +
  35 +/**
  36 + * 判断当前tab页是否可见
  37 + */
  38 +function tabIsHidden() {
  39 + if (typeof document.hidden !== 'undefined') {
  40 + changeEvent = 'visibilitychange';
  41 + state = 'visibilityState';
  42 + } else if (typeof document.mozHidden !== 'undefined') {
  43 + changeEvent = 'mozvisibilitychange';
  44 + state = 'mozVisibilityState';
  45 + } else if (typeof document.msHidden !== 'undefined') {
  46 + changeEvent = 'msvisibilitychange';
  47 + state = 'msVisibilityState';
  48 + } else if (typeof document.webkitHidden !== 'undefined') {
  49 + changeEvent = 'webkitvisibilitychange';
  50 + state = 'webkitVisibilityState';
  51 + }
  52 + return document[state] === 'hidden';
  53 +}
  54 +
  55 +/**
  56 + * 判断当前tab页可见
  57 + * @param callback 可见回调
  58 + */
  59 +function tabVisible(callback) {
  60 + isHidden = tabIsHidden();
  61 + document.addEventListener(changeEvent, function() {
  62 + if (!isHidden) {
  63 + if (callback) {
  64 + return callback();
  65 + }
  66 + }
  67 + }, false);
  68 +}
  69 +
  70 +/**
  71 + * 设置光标位置
  72 + * @param el 元素
  73 + * @param pos 位置
  74 + */
  75 +function setCursor(el, pos) {
  76 + var range;
  77 +
  78 + if (el.setSelectionRange) {
  79 + // chrome and firefox support
  80 + el.setSelectionRange(pos, pos);
  81 + el.focus();
  82 + } else if (el.createTextRange) {
  83 + // IE support
  84 + range = el.createTextRange();
  85 + range.collapse(true);
  86 + range.moveEnd('character', pos);
  87 + range.moveStart('character', pos);
  88 + range.select();
  89 + }
  90 +}
  91 +
  92 +/**
  93 + * 回车发送
  94 + * 回车 & CTRL 换行
  95 + * @param e 事件
  96 + * @param fn 回车事件
  97 + */
  98 +function ctrlEnter(e, send) {
  99 + var code = e.keyCode,
  100 + tag = $(e.target),
  101 + val = tag.val(),
  102 + pos = tag.getCursorPosition(),
  103 + start = val.substring(0, pos),
  104 + end = val.substring(pos),
  105 + newVal = [start, '\n', end].join(''),
  106 + ctrlLike = e.ctrlKey || e.metaKey;
  107 +
  108 + if (code !== 13) {
  109 + return;
  110 + }
  111 +
  112 + if (!ctrlLike) {
  113 + e.preventDefault();
  114 + send(e);
  115 + } else {
  116 + tag.val(newVal);
  117 + setCursor(tag[0], pos + 1);
  118 + }
  119 +}
  120 +
  121 +// 获取光标位置
  122 +// jquery.fn.extend
  123 +$.fn.extend({
  124 + getCursorPosition: _getCursorPosition
  125 +});
  126 +
  127 +module.exports = {
  128 + ctrlEnter: ctrlEnter,
  129 + setCursor: setCursor,
  130 + tabVisible: tabVisible,
  131 + tabIsHidden: tabIsHidden
  132 +};
  133 +
@@ -10,7 +10,8 @@ @@ -10,7 +10,8 @@
10 var $ = require('yoho-jquery'), 10 var $ = require('yoho-jquery'),
11 uuid = require('uuid'), 11 uuid = require('uuid'),
12 emojiMap = require('./emoji-map'), 12 emojiMap = require('./emoji-map'),
13 - tab = require('./tab-hidden'), 13 + editArea = require('./edit-area'),
  14 + broswer = require('./broswer'),
14 socketChat = require('./socket-chat'), 15 socketChat = require('./socket-chat'),
15 socketConf = require('./socket-config'); 16 socketConf = require('./socket-config');
16 17
@@ -76,35 +77,11 @@ encryptedUid = $encryptedUid.val(); @@ -76,35 +77,11 @@ encryptedUid = $encryptedUid.val();
76 assetsPrefix = $assetsPrefix.val(); 77 assetsPrefix = $assetsPrefix.val();
77 socketConfCM = socketConf.conversationMessage; 78 socketConfCM = socketConf.conversationMessage;
78 socketConfCM.encryptedUid = encryptedUid; 79 socketConfCM.encryptedUid = encryptedUid;
  80 +// 原始配置信息用于重新连线
  81 +originConf = JSON.parse(JSON.stringify(socketConf));
79 82
80 // 页面初始化 83 // 页面初始化
81 function pageInit() { 84 function pageInit() {
82 -  
83 - // 原始配置信息用于重新连线  
84 - originConf = JSON.parse(JSON.stringify(socketConf));  
85 -  
86 - /**  
87 - * 设置光标位置  
88 - * @param el  
89 - * @param pos  
90 - */  
91 - function setCurPos(el, pos) {  
92 - var range;  
93 -  
94 - if (el.setSelectionRange) {  
95 - // chrome and firefox support  
96 - el.setSelectionRange(pos, pos);  
97 - el.focus();  
98 - } else if (el.createTextRange) {  
99 - // IE support  
100 - range = el.createTextRange();  
101 - range.collapse(true);  
102 - range.moveEnd('character', pos);  
103 - range.moveStart('character', pos);  
104 - range.select();  
105 - }  
106 - }  
107 -  
108 /** 85 /**
109 * 添加新的消息 86 * 添加新的消息
110 */ 87 */
@@ -152,7 +129,7 @@ function pageInit() { @@ -152,7 +129,7 @@ function pageInit() {
152 129
153 textDom = area[0]; 130 textDom = area[0];
154 pos = cursorPosition ? cursorPosition : newVal.length; 131 pos = cursorPosition ? cursorPosition : newVal.length;
155 - setCurPos(textDom, pos); 132 + broswer.setCursor(textDom, pos);
156 } 133 }
157 134
158 /** 135 /**
@@ -234,33 +211,6 @@ function pageInit() { @@ -234,33 +211,6 @@ function pageInit() {
234 } 211 }
235 212
236 /** 213 /**
237 - * enter提交  
238 - * enter+ctrl换行  
239 - */  
240 - function msgEnterAction(e) {  
241 - var code = e.keyCode,  
242 - tag = $(e.target),  
243 - val = tag.val(),  
244 - pos = tag.getCursorPosition(),  
245 - start = val.substring(0, pos),  
246 - end = val.substring(pos),  
247 - newVal = [start, '\n', end].join(''),  
248 - ctrlLike = e.ctrlKey || e.metaKey;  
249 -  
250 - if (code !== 13) {  
251 - return;  
252 - }  
253 -  
254 - if (!ctrlLike) {  
255 - e.preventDefault();  
256 - sendMessage(e);  
257 - } else {  
258 - tag.val(newVal);  
259 - setCurPos(tag[0], pos + 1);  
260 - }  
261 - }  
262 -  
263 - /**  
264 * 常见问题 214 * 常见问题
265 */ 215 */
266 function toggleAnswer(e) { 216 function toggleAnswer(e) {
@@ -307,8 +257,6 @@ function pageInit() { @@ -307,8 +257,6 @@ function pageInit() {
307 * @param message 消息对象 257 * @param message 消息对象
308 */ 258 */
309 function enterSuccess(message) { 259 function enterSuccess(message) {
310 - var $ms = $('.icon.manual-service');  
311 -  
312 // 删除重新连线 260 // 删除重新连线
313 $msgList.find('.reconnect').parents('.push-tip').remove(); 261 $msgList.find('.reconnect').parents('.push-tip').remove();
314 262
@@ -316,7 +264,9 @@ function pageInit() { @@ -316,7 +264,9 @@ function pageInit() {
316 systemTip(message.content); 264 systemTip(message.content);
317 265
318 // 显示人工客服 266 // 显示人工客服
319 - $ms.show(); 267 + editArea.setIcons({
  268 + 'manual-service': true
  269 + });
320 } 270 }
321 271
322 /** 272 /**
@@ -333,9 +283,7 @@ function pageInit() { @@ -333,9 +283,7 @@ function pageInit() {
333 ADMIN_MANUAL_SERVICE = 3; 283 ADMIN_MANUAL_SERVICE = 3;
334 284
335 var dom, 285 var dom,
336 - tipText,  
337 - $iconEval = $('.icon.evaluate'),  
338 - $iconMs = $('.icon.manual-service'); 286 + tipText;
339 287
340 switch (msgType) { 288 switch (msgType) {
341 289
@@ -355,7 +303,9 @@ function pageInit() { @@ -355,7 +303,9 @@ function pageInit() {
355 }); 303 });
356 304
357 // 隐藏人工 305 // 隐藏人工
358 - $iconMs.hide(); 306 + editArea.setIcons({
  307 + 'manual-service': false
  308 + });
359 break; 309 break;
360 310
361 case MANUAL_SERVICE: // 2是接入人工成功 311 case MANUAL_SERVICE: // 2是接入人工成功
@@ -368,8 +318,12 @@ function pageInit() { @@ -368,8 +318,12 @@ function pageInit() {
368 processInfo.manual = true; 318 processInfo.manual = true;
369 319
370 // 显示评价&隐藏人工 320 // 显示评价&隐藏人工
371 - $iconEval.show();  
372 - $iconMs.hide(); 321 + editArea.setIcons({
  322 + emoji: true,
  323 + image: true,
  324 + evaluate: true,
  325 + 'manual-service': false
  326 + });
373 break; 327 break;
374 328
375 case ADMIN_MANUAL_SERVICE: // 3是管理员分配客服成功 329 case ADMIN_MANUAL_SERVICE: // 3是管理员分配客服成功
@@ -382,8 +336,12 @@ function pageInit() { @@ -382,8 +336,12 @@ function pageInit() {
382 processInfo.manual = true; 336 processInfo.manual = true;
383 337
384 // 显示评价&隐藏人工 338 // 显示评价&隐藏人工
385 - $iconEval.show();  
386 - $iconMs.hide(); 339 + editArea.setIcons({
  340 + emoji: true,
  341 + image: true,
  342 + evaluate: true,
  343 + 'manual-service': false
  344 + });
387 break; 345 break;
388 346
389 default: 347 default:
@@ -395,6 +353,14 @@ function pageInit() { @@ -395,6 +353,14 @@ function pageInit() {
395 } 353 }
396 354
397 /** 355 /**
  356 + * 人工接入队列中
  357 + * @param message 内部消息对象
  358 + */
  359 + function inQueue(message) {
  360 + systemTip(message.content);
  361 + }
  362 +
  363 + /**
398 * 返回表情路径处理 364 * 返回表情路径处理
399 * @param text 文本 365 * @param text 文本
400 * @private 366 * @private
@@ -570,7 +536,7 @@ function pageInit() { @@ -570,7 +536,7 @@ function pageInit() {
570 recType = rec.type, 536 recType = rec.type,
571 message = rec.chatMessage, 537 message = rec.chatMessage,
572 msgType = message ? message.type : -1, 538 msgType = message ? message.type : -1,
573 - isHidden = tab.tabIsHidden(), 539 + isHidden = broswer.tabIsHidden(),
574 allTypes = socketConf.recType; 540 allTypes = socketConf.recType;
575 541
576 // 删除上个定时器 542 // 删除上个定时器
@@ -596,6 +562,10 @@ function pageInit() { @@ -596,6 +562,10 @@ function pageInit() {
596 linkSuccess(msgType, message); 562 linkSuccess(msgType, message);
597 break; 563 break;
598 564
  565 + case allTypes.IN_QUNEUE:
  566 + inQueue(message);
  567 + break;
  568 +
599 case allTypes.CU_SEND: 569 case allTypes.CU_SEND:
600 handleCusMsg(rec, msgType, message); 570 handleCusMsg(rec, msgType, message);
601 break; 571 break;
@@ -632,11 +602,19 @@ function pageInit() { @@ -632,11 +602,19 @@ function pageInit() {
632 602
633 case allTypes.OP_LEAVE: 603 case allTypes.OP_LEAVE:
634 socketChat.clear(); 604 socketChat.clear();
  605 + editArea.setIcons({
  606 + emoji: false,
  607 + image: false
  608 + });
635 offlineTip(message); 609 offlineTip(message);
636 break; 610 break;
637 611
638 case allTypes.OFFLINE: 612 case allTypes.OFFLINE:
639 socketChat.clear(); 613 socketChat.clear();
  614 + editArea.setIcons({
  615 + emoji: false,
  616 + image: false
  617 + });
640 offlineTip(message); 618 offlineTip(message);
641 break; 619 break;
642 620
@@ -654,8 +632,6 @@ function pageInit() { @@ -654,8 +632,6 @@ function pageInit() {
654 */ 632 */
655 function connectSocket() { 633 function connectSocket() {
656 var $reconnect, 634 var $reconnect,
657 - $iconEval = $('.icon.evaluate'),  
658 - $iconMs = $('.icon.manual-service'),  
659 $connectFail = $('.connect-fail'), 635 $connectFail = $('.connect-fail'),
660 636
661 // 获取上次会话id 637 // 获取上次会话id
@@ -680,13 +656,19 @@ function pageInit() { @@ -680,13 +656,19 @@ function pageInit() {
680 }, 656 },
681 657
682 onOpen: function() { 658 onOpen: function() {
683 - $iconMs.hide();  
684 - $iconEval.hide(); 659 + editArea.setIcons({
  660 + evaluate: false,
  661 + 'manual-service': false
  662 + });
685 }, 663 },
686 664
687 onClose: function() { 665 onClose: function() {
688 - $iconEval.hide();  
689 - $iconMs.hide(); 666 + editArea.setIcons({
  667 + emoji: false,
  668 + image: false,
  669 + evaluate: false,
  670 + 'manual-service': false
  671 + });
690 $reconnect = $msgList.find('.list-item') 672 $reconnect = $msgList.find('.list-item')
691 .last().find('.reconnect'); 673 .last().find('.reconnect');
692 674
@@ -843,7 +825,7 @@ function pageInit() { @@ -843,7 +825,7 @@ function pageInit() {
843 }()); 825 }());
844 826
845 // tab页title重置 827 // tab页title重置
846 - tab.tabVisible(function() { 828 + broswer.tabVisible(function() {
847 document.title = docTitle; 829 document.title = docTitle;
848 clearInterval(titleInterval); 830 clearInterval(titleInterval);
849 }); 831 });
@@ -952,28 +934,10 @@ function pageInit() { @@ -952,28 +934,10 @@ function pageInit() {
952 height: '100%' 934 height: '100%'
953 }); 935 });
954 936
955 - // 获取鼠标位置  
956 - $.fn.getCursorPosition = function() {  
957 - var sel,  
958 - pos = 0,  
959 - selLength,  
960 - el = $(this).get(0);  
961 -  
962 - if ('selectionStart' in el) {  
963 - pos = el.selectionStart;  
964 - } else if ('selection' in document) {  
965 - sel = document.selection.createRange();  
966 - selLength = document.selection.createRange().text.length;  
967 -  
968 - el.focus();  
969 - sel.moveStart('character', -el.value.length);  
970 - pos = sel.text.length - selLength;  
971 - }  
972 - return pos;  
973 - };  
974 -  
975 // enter提交 ctrl+enter换行 937 // enter提交 ctrl+enter换行
976 - $msgArea.on('keydown', msgEnterAction); 938 + $msgArea.on('keydown', function(e) {
  939 + broswer.ctrlEnter(e, sendMessage);
  940 + });
977 941
978 // 常见问题 942 // 常见问题
979 $('.qa-list .q').on('click', toggleAnswer); 943 $('.qa-list .q').on('click', toggleAnswer);
@@ -996,7 +960,7 @@ function pageInit() { @@ -996,7 +960,7 @@ function pageInit() {
996 dataType: 'json', 960 dataType: 'json',
997 acceptFileTypes: /(\.|\/)(bmp|gif|jpe?g|png)$/i, 961 acceptFileTypes: /(\.|\/)(bmp|gif|jpe?g|png)$/i,
998 maxFileSize: 5000000, // 5M 962 maxFileSize: 5000000, // 5M
999 - url: configDomains.imServer + '/fileManage/uploadFile', 963 + url: configDomains.imCs + '/fileManage/uploadFile',
1000 progressall: function(e, data) { 964 progressall: function(e, data) {
1001 var progress = parseInt(data.loaded / data.total * 100, 10); 965 var progress = parseInt(data.loaded / data.total * 100, 10);
1002 966
1 -/**  
2 - * 倒计时 mm:ss  
3 - *  
4 - * @author: liqi <qi.li@yoho.cn>  
5 - * @date: 2016/11/11  
6 - */  
7 -  
8 -/**  
9 - * 格式化  
10 - * @param total 总的分钟数  
11 - * @param el 倒计时显示元素  
12 - * @returns {string}  
13 - */  
14 -function _secsFormat(total, el) {  
15 - var mins = Math.floor(total / 60);  
16 - var secs = total - mins * 60;  
17 -  
18 - mins < 10 && (mins = '0' + mins);  
19 - secs < 10 && (secs = '0' + secs);  
20 -  
21 - el && el.html(mins + ':' + secs);  
22 -  
23 - if (!el) {  
24 - return mins + ':' + secs;  
25 - }  
26 -}  
27 -  
28 -function countdown(mins, el) {  
29 - var interval,  
30 - secs = mins * 60;  
31 -  
32 - interval = setInterval(function() {  
33 - _secsFormat(--secs, el);  
34 - secs === 0 && clearInterval(interval);  
35 - }, 1000);  
36 - _secsFormat(secs, el);  
37 -}  
38 -  
39 -module.exports = countdown;  
40 -  
  1 +/**
  2 + * 消息编辑区
  3 + * @author: liqi <qi.li@yoho.cn>
  4 + * @date: 2016/11/26
  5 + */
  6 +
  7 +var $ = require('yoho-jquery');
  8 +
  9 +module.exports = {
  10 + /**
  11 + * 消息编辑区图标显示
  12 + * true: 显示 false: 隐藏
  13 + */
  14 + setIcons: function(opt) {
  15 + var $util = $('.msg-edit .util');
  16 +
  17 + $.each(opt, function(key, val) {
  18 + var $el = $util.find('.' + key);
  19 +
  20 + if (!$el.length || !val && val !== false) {
  21 + return;
  22 + }
  23 + val === true && $el.show();
  24 + val === false && $el.hide();
  25 + });
  26 + }
  27 +};
  28 +
@@ -29,6 +29,7 @@ var config = { @@ -29,6 +29,7 @@ var config = {
29 SUC_DISTRIBUTE: 10009, // 客服管理员收到会话分配成功的回执 29 SUC_DISTRIBUTE: 10009, // 客服管理员收到会话分配成功的回执
30 CS_LOGOUT: 10011, // 客服注销 30 CS_LOGOUT: 10011, // 客服注销
31 END_WORK: 444444, // 成功保存工单 31 END_WORK: 444444, // 成功保存工单
  32 + IN_QUNEUE: 777777, // 队列中发送消息后收到的反馈)
32 CS_CHATTING: 5000000, // 客服管理员收到会话分配成功的回执 33 CS_CHATTING: 5000000, // 客服管理员收到会话分配成功的回执
33 OP_LEAVE: 999999998, // 对方断开 34 OP_LEAVE: 999999998, // 对方断开
34 OFFLINE: 999999999 // 断线 35 OFFLINE: 999999999 // 断线
1 -/**  
2 - * 判断当前tab页是否可见  
3 - *  
4 - * @author: liqi <qi.li@yoho.cn>  
5 - * @date: 2016/11/26  
6 - */  
7 -  
8 -var state;  
9 -var isHidden;  
10 -var changeEvent;  
11 -  
12 -function tabIsHidden() {  
13 - if (typeof document.hidden !== 'undefined') {  
14 - changeEvent = 'visibilitychange';  
15 - state = 'visibilityState';  
16 - } else if (typeof document.mozHidden !== 'undefined') {  
17 - changeEvent = 'mozvisibilitychange';  
18 - state = 'mozVisibilityState';  
19 - } else if (typeof document.msHidden !== 'undefined') {  
20 - changeEvent = 'msvisibilitychange';  
21 - state = 'msVisibilityState';  
22 - } else if (typeof document.webkitHidden !== 'undefined') {  
23 - changeEvent = 'webkitvisibilitychange';  
24 - state = 'webkitVisibilityState';  
25 - }  
26 - return document[state] === 'hidden';  
27 -}  
28 -  
29 -  
30 -function tabVisible(callback) {  
31 - isHidden = tabIsHidden();  
32 - document.addEventListener(changeEvent, function() {  
33 - if (!isHidden) {  
34 - if (callback) {  
35 - return callback();  
36 - }  
37 - }  
38 - }, false);  
39 -}  
40 -  
41 -module.exports = {  
42 - tabVisible: tabVisible,  
43 - tabIsHidden: tabIsHidden  
44 -};  
45 -  
@@ -196,8 +196,8 @@ $color-3a3a3a: #3a3a3a; @@ -196,8 +196,8 @@ $color-3a3a3a: #3a3a3a;
196 196
197 .main-body { 197 .main-body {
198 padding: 12px 17px; 198 padding: 12px 17px;
199 - height: 474px;  
200 - max-height: 474px; 199 + height: 408px;
  200 + max-height: 408px;
201 overflow-y: auto; 201 overflow-y: auto;
202 202
203 .msg-list { 203 .msg-list {
@@ -270,7 +270,7 @@ $color-3a3a3a: #3a3a3a; @@ -270,7 +270,7 @@ $color-3a3a3a: #3a3a3a;
270 .time { 270 .time {
271 display: block; 271 display: block;
272 margin-bottom: 3px; 272 margin-bottom: 3px;
273 - color: #c5c5c5; 273 + color: #666;
274 font-size: 12px; 274 font-size: 12px;
275 font-family: Helvetica; 275 font-family: Helvetica;
276 } 276 }
@@ -327,7 +327,7 @@ $color-3a3a3a: #3a3a3a; @@ -327,7 +327,7 @@ $color-3a3a3a: #3a3a3a;
327 .time { 327 .time {
328 display: block; 328 display: block;
329 margin-bottom: 3px; 329 margin-bottom: 3px;
330 - color: #c5c5c5; 330 + color: #666;
331 font-size: 12px; 331 font-size: 12px;
332 font-family: Helvetica; 332 font-family: Helvetica;
333 text-align: right; 333 text-align: right;
@@ -426,7 +426,7 @@ $color-3a3a3a: #3a3a3a; @@ -426,7 +426,7 @@ $color-3a3a3a: #3a3a3a;
426 426
427 .msg-edit { 427 .msg-edit {
428 position: relative; 428 position: relative;
429 - height: 85px; 429 + height: 150px;
430 width: 100%; 430 width: 100%;
431 border-top: 1px #e0e0e0 solid; 431 border-top: 1px #e0e0e0 solid;
432 border-bottom-left-radius: 3px; 432 border-bottom-left-radius: 3px;
@@ -434,7 +434,7 @@ $color-3a3a3a: #3a3a3a; @@ -434,7 +434,7 @@ $color-3a3a3a: #3a3a3a;
434 background-color: #ffffff; 434 background-color: #ffffff;
435 435
436 .edit-left { 436 .edit-left {
437 - height: 85px; 437 + height: 150px;
438 padding: 6px 17px; 438 padding: 6px 17px;
439 margin-right: 60px; 439 margin-right: 60px;
440 440
@@ -449,6 +449,8 @@ $color-3a3a3a: #3a3a3a; @@ -449,6 +449,8 @@ $color-3a3a3a: #3a3a3a;
449 line-height: 13px; 449 line-height: 13px;
450 cursor: pointer; 450 cursor: pointer;
451 451
  452 + &.emoji,
  453 + &.image,
452 &.evaluate, 454 &.evaluate,
453 &.manual-service { 455 &.manual-service {
454 display: none; 456 display: none;
@@ -531,7 +533,7 @@ $color-3a3a3a: #3a3a3a; @@ -531,7 +533,7 @@ $color-3a3a3a: #3a3a3a;
531 color: #ffffff; 533 color: #ffffff;
532 font-size: 12px; 534 font-size: 12px;
533 text-align: center; 535 text-align: center;
534 - line-height: 85px; 536 + line-height: 150px;
535 background-color: #3a3a3a; 537 background-color: #3a3a3a;
536 border-bottom-right-radius: 3px; 538 border-bottom-right-radius: 3px;
537 cursor: pointer; 539 cursor: pointer;