Authored by yyq

Merge branch 'feature/message' into release/5.4

... ... @@ -17,7 +17,7 @@ let ALL_TYPES = {
ellipsis: 'p-pe-n'
};
exports.pager = function() {
exports.gpager = function() {
let options = arguments[arguments.length - 1];
... ...
... ... @@ -20,7 +20,7 @@
{{/ msgs}}
</div>
<div class="msg-pager pager">
{{pager baseUrl totalRecords=total page=page type="ellipsis" theme="msg-pager"}}
{{gpager baseUrl totalRecords=total page=page type="ellipsis" theme="msg-pager"}}
</div>
</div>
<div class="right-side">
... ...
... ... @@ -30,7 +30,7 @@
{{> msg}}
{{/ msgs}}
</div>
{{pager baseUrl totalRecords=total page=page type="ellipsis" theme="msg-pager"}}
{{gpager baseUrl totalRecords=total page=page type="ellipsis" theme="msg-pager"}}
</div>
</div>
<div class="right-side">
... ...
... ... @@ -12,7 +12,7 @@
{{/ msgs}}
</div>
{{pager baseUrl totalRecords=total page=page type="ellipsis" theme="msg-pager"}}
{{gpager baseUrl totalRecords=total page=page type="ellipsis" theme="msg-pager"}}
</div>
<div class="right-side">
{{> right-side}}
... ...
... ... @@ -18,6 +18,6 @@
</li>
{{/ list}}
</ul>
<div class="comment-pager pager">{{pager baseUrl totalRecords=commentNum page=page pageSize=pageSize type="ellipsis" theme="msg-pager"}}</div>
<div class="comment-pager pager">{{gpager baseUrl totalRecords=commentNum page=page pageSize=pageSize type="ellipsis" theme="msg-pager"}}</div>
</div>
{{/ comment}}
... ...
... ... @@ -9,13 +9,12 @@ const message = require('../models/message');
const index = (req, res, next) => {
let uid = req.user.uid;
let page = req.query.page || 1;
if (!uid) {
return next();
}
message.getMessageList(uid, page).then(result => {
message.getMessageList(uid, req.query || {}).then(result => {
res.render('message', result);
}).catch(next);
};
... ... @@ -23,13 +22,12 @@ const index = (req, res, next) => {
const detail = (req, res, next) => {
let uid = req.user.uid;
let id = parseInt(req.query.id, 10);
let page = req.query.page;
if (!uid || !id || !page) {
if (!uid || !id) {
return next();
}
message.getMessageDetail(uid, id, page).then(result => {
message.getMessageDetail(uid, req.query || {}).then(result => {
res.render('message-detail', result);
}).catch(next);
};
... ...
... ... @@ -10,17 +10,31 @@ const api = global.yoho.API;
const _ = require('lodash');
const Promise = require('bluebird');
const userApi = require('./user-api');
const setPager = require(`${global.utils}/pager`).setPager;
const co = Promise.coroutine;
const getMessageAsync = (uid, page, size) => {
const getMessageTabList = (uid) => {
return api.get('', {
method: 'app.inbox.getlist',
method: 'app.inbox.getAllInboxCatInfo',
uid: uid
}, {code: 200});
};
const getMessageAsync = (uid, page, size, type) => {
let params = {
method: 'app.inbox.getlistnew',
uid: uid,
page: page || 1,
size: size || 10
}, {code: 200});
};
if (type) {
params.displayTab = type;
}
return api.get('', params, {code: 200});
};
const delMessageAsync = (uid, id) => {
... ... @@ -66,28 +80,69 @@ const getCouponAsync = (uid) => {
* 获取消息列表
* @function getMessageList
* @param { Number } uid 用户uid
* @param { Number } page 页码
* @param { Object } params url参数
* @param { Number } limit 每页数目
* @return { Object } 消息列表数据
*/
const getMessageList = (uid, page, limit) => {
let process = function*() {
let resData = {};
let result = yield getMessageAsync(uid, page, limit);
const getMessageList = (uid, params, limit) => {
let resData = {};
let page = parseInt(`0${params.page}`, 10) || 1,
type = parseInt(`0${params.type}`, 10);
return Promise.all([
userApi.getUserInfo(uid),
getMessageTabList(uid),
getMessageAsync(uid, page, limit, type)
]).then(result => {
const msgBaseUrl = '/home/message';
resData.userThumb = _.get(result, '[0].data.head_ico', '');
let tabList = [{
name: '全部',
focus: !type,
href: msgBaseUrl
}];
let focusTabName = '';
_.forEach(_.get(result, '[1]data.list', []), value => {
let tab = {
name: `${value.inboxCatName}`,
focus: type === value.id * 1,
href: `${msgBaseUrl}?type=${value.id}`
};
if (value.unReadCount * 1) {
tab.name += ` (${value.unReadCount})`;
}
if (tab.focus) {
focusTabName = value.inboxCatName;
}
tabList.push(tab);
});
resData.tabList = tabList;
if (result.data) {
if (result[2].data) {
let data = result[2].data;
let msg = [];
_.forEach(_.get(result, 'data.list', []), value => {
_.forEach(_.get(data, 'list', []), value => {
// 信息过滤
if (value.type === '$inboxval' || value.type === 'notice') {
return;
}
let href = `/home/message/detail?id=${value.id}&page=${page}`;
msg.push({
id: value.id || 0,
href: `/home/message/detail?id=${value.id}&page=${page}`,
href: type ? href + `&type=${type}` : href,
title: value.title || '',
content: _.get(value, 'body.content', ''),
sender: value.from || '',
time: value.create_date,
isNew: value.is_read === 'Y' ? false : true
... ... @@ -96,40 +151,47 @@ const getMessageList = (uid, page, limit) => {
resData.messages = msg;
let pagerList = setPager(_.get(result, 'data.page_total', 0),
Object.assign(params, {page: page}));
resData.pager = Object.assign({
count: _.get(result, 'data.total', 0),
count: _.get(data, 'total', 0),
curPage: page,
totalPages: _.get(result, 'data.page_total', 0)
}, setPager(_.get(result, 'data.page_total', 0), {
page: page
}));
totalPages: _.get(data, 'page_total', 0)
}, pagerList);
}
if (_.isEmpty(resData.messages)) {
resData.messages = {empty: '您尚未收到任何短消息'};
resData.messages = {empty: `您尚未收到任何${focusTabName}消息`};
}
return resData;
};
return co(process)();
});
};
/**
* 获取消息内容
* @function getMessageDetail
* @param { Number } uid 用户uid
* @param { Number } page 页码
* @param { Object } params url参数
* @param { Number } limit 每页数目
* @return { Object } 消息列表数据
*/
const getMessageDetail = (uid, mid, page, limit) => {
const getMessageDetail = (uid, params, limit) => {
let mid = parseInt(`0${params.id}`, 10);
let page = parseInt(`0${params.page}`, 10) || 1;
let type = parseInt(`0${params.type}`, 10);
let process = function*() {
let result = yield Promise.all([
userApi.getUserInfo(uid),
getMessageAsync(uid, page, limit, type)
]);
let resData = {
backUrl: `/home/message?page=${page}`
backUrl: `/home/message?page=${page}`,
userThumb: _.get(result, '[0].data.head_ico', '')
};
let result = yield getMessageAsync(uid, page, limit);
let msg = _.find(_.get(result, 'data.list', []), {id: mid});
let msg = _.find(_.get(result, '[1]data.list', []), {id: mid});
if (!_.isEmpty(msg)) {
resData.message = {
... ... @@ -140,6 +202,26 @@ const getMessageDetail = (uid, mid, page, limit) => {
switch (msg.type) {
case 'pullCoupon': // eslint-disable-line
resData.message.birthCoupon = {
text: `${_.get(result, '[0].data.nickname', '')} 有货祝您生日快乐!感谢您对有货的支持,特赠您VIP生日专属礼,即刻享受生日福利吧!`
};
if (_.get(msg, 'body.is_collar', '') === 'Y') {
Object.assign(resData.message.birthCoupon, {
over: true,
overText: '已领取'
});
break;
}
if (_.get(msg, 'body.is_over_time', '') === 'Y') {
Object.assign(resData.message.birthCoupon, {
over: true,
overText: '生日券已过期'
});
break;
}
let couponInfo = yield getCouponAsync(uid);
let coupons = [];
... ...
... ... @@ -16,7 +16,8 @@ const commentController = require(`${cRoot}/comment`);
// const consultController = require(`${cRoot}/consult`);
// const complaintsController = require(`${cRoot}/complaints`);
// const messageController = require(`${cRoot}/message`);
const messageController = require(`${cRoot}/message`);
// const returnsController = require(`${cRoot}/returns`);
// const IndexController = require(`${cRoot}/Index`);
// const CurrencyController = require(`${cRoot}/Currency`);
... ... @@ -180,11 +181,11 @@ router.get('/comment/order', [getCommonHeader, getHomeNav], commentController.co
// router.post('/complaints/cancel', complaintsController.cancel);
// 我的消息
// router.get('/message', messageController.index);
// router.get('/message/detail', messageController.detail);
// router.get('/message/del', messageController.delMsg);
// router.get('/message/read', messageController.readMsg);
// router.get('/message/pickCoupon', messageController.pickCoupon);
router.get('/message', [getCommonHeader, getHomeNav], messageController.index);
router.get('/message/detail', [getCommonHeader, getHomeNav], messageController.detail);
router.get('/message/del', messageController.delMsg);
router.get('/message/read', messageController.readMsg);
router.get('/message/pickCoupon', messageController.pickCoupon);
// 我的退/换货
// router.get('/returns', returnsController.index);
... ...
... ... @@ -13,38 +13,61 @@
{{# message}}
<div class="text-title">
<h1>{{title}}</h1>
<span>{{sender}} 发送于{{time}}</span>
<span>{{sender}} 发送于{{time}}</span>
</div>
<div class="text-content">
{{# text}}
<!-- 文本消息 -->
<p>{{{content}}}</p>
{{/ text}}
{{# coupons}}
<!-- 优惠券消息 -->
<div class="coupon-item">
<div class="coupon-img">
<img src="//static.yohobuy.com/images/v2/activity/default_coupon.jpg">
</div>
<div class="coupon-info">
<p>{{remark}}</p>
{{#if url}}
<p>面值:{{price}}</p>
<p>有效期:{{useTime}}</p>
{{^}}
<p>使用时间:{{useTime}}</p>
<p>领取时间:{{pickTime}}</p>
{{/if}}
</div>
<div class="coupon-action">
{{#if url}}
<a href="{{url}}" class="view-coupon-btn">立即查看</a>
{{^}}
<a{{#if canPick}} class="pick-coupon-btn" data-id="{{id}}"{{/if}}>立即领取</a>
{{/if}}
</div>
{{# birthCoupon}}
<p>{{text}}</p>
<p class="birth-card">
{{#if @root.devEnv}}
<img src="////{{@root.devHost}}:5002/img/home/birth-card.jpg">
{{^}}
<img src="//cdn.yoho.cn/yohobuy-node/assets/img/home/birth-card.jpg">
{{/if}}
</p>
{{#if over}}
<div>{{overText}}</div>
{{^}}
<div class="show-birth-coupon"{{#if errMsg}} data-msg="{{errMsg}}"{{/if}}>点这里领取</div>
{{/if}}
{{/ birthCoupon}}
{{#if coupons}}
<div class="{{#if birthCoupon}}birth-coupon-wrap{{/if}}">
{{#if birthCoupon}}
<p>您365天内有且仅有一次领劵生日礼券的机会,每次限领1张哦</p>
{{/if}}
{{# coupons}}
<!-- 优惠券消息 -->
<div class="coupon-item">
<div class="coupon-img">
<img src="//static.yohobuy.com/images/v2/activity/default_coupon.jpg">
</div>
<div class="coupon-info">
<p>{{remark}}</p>
{{#if url}}
<p>面值:{{price}}</p>
<p>有效期:{{useTime}}</p>
{{^}}
<p>使用时间:{{useTime}}</p>
<p>领取时间:{{pickTime}}</p>
{{/if}}
</div>
<div class="coupon-action">
{{#if url}}
<a href="{{url}}" class="view-coupon-btn">立即查看</a>
{{^}}
<a{{#if canPick}} class="pick-coupon-btn" data-id="{{id}}"{{/if}}>立即领取</a>
{{/if}}
</div>
</div>
{{/ coupons}}
</div>
{{/ coupons}}
{{/if}}
{{# sale}}
<!-- 促销消息 -->
<div class="sale-img">
... ... @@ -60,4 +83,4 @@
{{> help-us}}
</div>
</div>
\ No newline at end of file
</div>
... ...
... ... @@ -6,19 +6,19 @@
<div class="me-main">
<div class="message block">
<h2 class="title"></h2>
<p class="message-table-header table-header clearfix">
<span class="sender">发件人</span>
<span class="heading">标题</span>
<span class="time">发件时间</span>
<span class="action">操作</span>
</p>
<div class="msg-tabs-wrap">
<ul class="tabs-list clearfix">
{{# tabList}}
<li{{#if focus}} class="active"{{/if}}>
<a href="{{href}}">{{name}}</a>
</li>
{{/ tabList}}
</ul>
</div>
<div id="message-main-container">
{{> message/message-list}}
{{> pager}}
</div>
{{> pager}}
</div>
{{> help-us}}
</div>
</div>
\ No newline at end of file
</div>
... ...
... ... @@ -4,29 +4,17 @@
{{> empty}}
{{/with}}
{{^}}
<table>
{{# messages}}
<tr{{#if isNew}} class="new-msg"{{/if}}>
<td width="37">
<input type="checkbox" class="msg-check" value="{{id}}">
</td>
<td class="td-sender"><a href="{{href}}">{{sender}}</a></td>
<td class="td-title"><a href="{{href}}">{{title}}</a></td>
<td width="130">{{time}}</td>
<td>
<a class="del-btn" data-id="{{id}}">删除</a>
</td>
</tr>
{{/ messages}}
<tr class="list-foot">
<td>
<input type="checkbox" class="choose-all">
</td>
<td colspan="4">
<button class="del-choose-btn">删除选中的消息</button>
<button class="read-choose-btn">标记为已读</button>
</td>
</tr>
</table>
{{# messages}}
<div class="msg-item{{#if isNew}} new-msg{{/if}}">
<a href="{{href}}">
<p class="it-title">{{title}}</p>
<p class="it-content">{{content}}</p>
<p class="it-time">{{time}}</p>
</a>
<div class="del-btn" data-id="{{id}}">
<i class="iconfont">&#xe60d;</i>
</div>
</div>
{{/ messages}}
{{/if}}
</div>
... ...
... ... @@ -2,7 +2,9 @@
<p class="title ucenter"></p>
<div class="user-thumb">
<div class="thumb-bg">
<img id="user-thumb" src="{{image2 userThumb}}">
{{#if userThumb}}
<img id="user-thumb" src="{{image2 userThumb w=100 h=100}}">
{{/if}}
</div>
</div>
{{# homeNav}}
... ... @@ -23,4 +25,4 @@
</ul>
</div>
{{/ homeNav}}
</div>
\ No newline at end of file
</div>
... ...
... ... @@ -16,11 +16,11 @@
{{# pages}}
<a{{#if url}} href="{{url}}"{{/if}}{{#if cur}} class="cur"{{/if}}>{{num}}</a>
{{/ pages}}
{{# nextPage}}
<a href="{{url}}" title="下一页">下一页<span class="iconfont">&#xe60c;</span></a>
{{/ nextPage}}
</div>
</div>
</div>
{{/ pager}}
\ No newline at end of file
{{/ pager}}
... ...

1.79 KB | W: | H:

4.51 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
... ... @@ -7,125 +7,51 @@ var $ = require('yoho-jquery');
var Dialog = require('../common/dialog');
var $container = $('#message-main-container'),
$msgCheck = $container.find('.msg-check'),
$readBtn = $container.find('.read-choose-btn'),
$checked;
var $container = $('#message-main-container');
var $pickBtn = $('.pick-coupon-btn');
var operationId = [];
var pickBusy = false;
var Alert = Dialog.Alert,
Confirm = Dialog.confirm;
function hasNew() {
var newMsg = false;
$checked = $container.find('.msg-check:checked');
operationId = [];
$checked.each(function() {
var $par = $(this).parent().parent();
operationId.push($(this).val());
if ($par.hasClass('new-msg')) {
newMsg = true;
}
});
Confirm = Dialog.Confirm;
if (newMsg) {
$readBtn.addClass('has-new');
} else {
$readBtn.removeClass('has-new');
}
}
function msgOperation(type, data) {
var url;
switch (type) {
case 'del':
url = '/home/message/del';
break;
case 'read':
url = '/home/message/read';
break;
default:
break;
}
if (!url) {
function msgOperation(data) {
if (!data) {
return;
}
$.ajax({
type: 'GET',
url: url,
url: '/home/message/del',
data: data
}).then(function(jsonData) {
if (jsonData.code === 200) {
if (type === 'read') {
$checked.removeAttr('checked');
$checked.parent().parent().removeClass('new-msg');
hasNew();
} else {
window.location.reload();
}
window.location.reload();
} else {
new Alert(jsonData.message);
}
});
}
$container.on('change', 'input[type="checkbox"]', function() {
var checked = $(this).attr('checked');
if ($(this).hasClass('choose-all')) {
if (checked === 'checked') {
$msgCheck.attr('checked', true);
} else {
$msgCheck.removeAttr('checked');
}
}
hasNew();
});
$container.on('click', '.del-btn', function() {
var data = $(this).data();
new Confirm({
content: '您确定要删除这条短消息?',
cb: function() {
msgOperation('del', data);
}
}).show();
});
$container.on('click', '.del-choose-btn', function() {
if (!operationId.length) {
new Alert('请选中您要删除的消息');
return;
if (data.id) {
new Confirm({
content: '您确定要删除这条短消息?',
cb: function() {
msgOperation(data);
}
}).show();
}
new Confirm({
content: '确定要删除您选中的消息?',
cb: function() {
msgOperation('del', {
id: operationId.join(',')
});
}
}).show();
});
$container.on('click', '.read-choose-btn', function() {
if ($(this).hasClass('has-new')) {
msgOperation('read', {
id: operationId.join(',')
});
}
$('.show-birth-coupon').click(function() {
var $this = $(this);
$this.siblings('.birth-coupon-wrap').show();
$this.hide().siblings('p').hide();
$(window).scrollTop(0);
});
$pickBtn.click(function() {
... ...
... ... @@ -32,6 +32,19 @@
}
}
.birth-card > img {
width: 100%;
margin: 6px 0;
}
.show-birth-coupon {
cursor: pointer;
}
.birth-coupon-wrap {
display: none;
}
.coupon-item {
display: table-row;
... ...
.message-me-page {
.message .title {
.message > .title {
background-image: resolve('home/message.png');
}
.message-table-header {
font-size: 12px;
.sender {
width: 118px;
padding-left: 38px;
text-align: left;
}
.heading {
width: 408px;
text-align: left;
}
.time {
width: 130px;
}
.msg-tabs-wrap {
padding: 0 10px;
}
.action {
padding-left: 10px;
width: 66px;
.tabs-list {
height: 31px;
font-size: 14px;
padding-left: 4px;
margin-top: 8px;
border-bottom: 1px solid #e6e6e6;
li {
display: block;
float: left;
min-width: 80px;
height: 30px;
line-height: 30px;
padding: 0 10px;
text-align: center;
background-color: #eaeaea;
border: 1px solid #e6e6e6;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
margin-left: 6px;
color: #333;
cursor: pointer;
&.active {
background-color: #fff;
border-bottom-color: #fff;
}
}
}
.message-list {
padding: 10px;
font-size: 12px;
table {
width: 100%;
line-height: 38px;
tr {
color: #999;
border: 1px solid #e6e6e6;
td {
text-align: center;
}
input {
vertical-align: middle;
margin: 0;
}
font-size: 14px;
color: #3a3a3a;
}
.del-btn {
color: #468fa2;
text-decoration: none;
cursor: pointer;
}
}
.msg-item:first-child {
border-top: 1px solid #e6e6e6;
}
.list-foot {
background: #f8f8f8;
.msg-item {
padding: 10px 150px 10px 30px;
position: relative;
border-bottom: 1px solid #e6e6e6;
button {
float: left;
line-height: 18px;
padding: 2px 10px;
border: 1px solid #ccc;
border-radius: 2px;
cursor: pointer;
outline: none;
}
.it-title {
line-height: 2;
padding-bottom: 10px;
}
.del-choose-btn {
background: #da044a;
border-color: #cc0345;
margin-right: 10px;
color: #fff;
}
&.new-msg .it-title {
color: #468fa2;
}
.read-choose-btn {
background: #ddd;
color: #b3b3b3;
}
.has-new {
background: #3797af;
border-color: #147e98;
color: #fff;
}
}
.it-content {
line-height: 1.5;
}
.td-sender {
width: 110px;
color: #666;
text-align: left;
white-space: nowrap;
overflow: hidden;
}
.it-time {
color: #b0b0b0;
line-height: 2;
}
.td-title {
width: 410px;
padding-left: 10px;
color: #666;
text-align: left;
white-space: nowrap;
overflow: hidden;
.del-btn {
width: 30px;
height: 30px;
line-height: 30px;
text-align: center;
position: absolute;
top: 50%;
right: 20px;
margin-top: -15px;
cursor: pointer;
display: none;
.iconfont {
font-size: 26px;
}
}
.new-msg {
background: #f0f5f8;
border-bottom: 1px #becfd3 solid;
.td-sender a,
.td-title a {
font-weight: bold;
color: #468fa2;
}
}
&:hover > .del-btn {
display: block;
}
}
}
... ...