Authored by y.huang

Merge branch 'feature/redpack' into 'release/6.7.9'

Feature/redpack



See merge request !1558
const redbagModel = require('../models/red-envelope');
const headerModel = require('../../../doraemon/models/header'); // 头部model
const valid = require('../../../utils/validator');
const redbagPage = async(req, res, next) => {
try {
let isApp = req.yoho.isApp;
let obj = {uid: req.user.uid || false, shareCode: req.query.shareCode || ''};
let isWechat = await req.ctx(redbagModel).isWechatService(obj);
if (isWechat) {
let userInfo = await req.ctx(redbagModel).renderByCs(obj);
let isGetRedBag = false;
if (userInfo.code === 200) {
isGetRedBag = true;
if (userInfo.data && userInfo.data.rewardType === 1) {
userInfo.data.rewardType = true;
} else if (userInfo.data && userInfo.data.rewardType === 2) {
userInfo.data.rewardType = false;
}
}
return res.render('red-envelope/redbag-cs', {
pageHeader: headerModel.setNav({
navTitle: '红包-客服'
}),
isApp,
isGetRedBag,
width750: true,
localCss: true,
module: 'activity',
page: 'redbag-cs',
userInfo: userInfo.data,
title: '红包-客服'
});
} else {
const pageData = await req.ctx(redbagModel).renderByUser(obj);
return res.render('red-envelope/redbag-user', {
pageHeader: headerModel.setNav({
navTitle: '红包-用户'
}),
isApp,
width750: true,
localCss: true,
module: 'activity',
page: 'redbag-user',
pageData: Object.assign({
shareCode: obj.shareCode
}, pageData),
title: '红包-用户'
});
}
} catch (error) {
return next(error);
}
};
const receiveRedBag = async(req, res, next) => {
const {shareCode} = req.body;
if (!shareCode) {
return res.json({
code: 400,
message: '分享码不能为空'
});
}
try {
const result = await req.ctx(redbagModel).receiveRedBag({
uid: req.user.uid,
shareCode
});
if (result.code === 200) {
return res.json({
code: 200,
message: '领取成功'
});
} else {
return res.json({
code: 201,
message: result.message
});
}
} catch (error) {
return next(error);
}
};
const submitWxCode = async(req, res, next) => {
try {
let obj = {uid: req.user.uid || null,
userUid: req.body.userUid || '',
userCode: req.body.userCode || ''};
obj = valid(obj, {
uid: {type: 'uid', empty: false},
userUid: {type: 'number', empty: false},
userCode: {type: 'String', empty: false}
});
let result = await req.ctx(redbagModel).submitWxCode(obj);
return res.json(result);
} catch (error) {
return next(error);
}
};
module.exports = {
redbagPage,
receiveRedBag,
submitWxCode
};
... ...
class redEnvelopeModel extends global.yoho.BaseModel {
constructor(ctx) {
super(ctx);
}
async isWechatService(obj) {
let isWechatService = false; // 是否是微信客服
if (obj.uid) {
// 校验是客服还是用户 y则是客服
let ret = await this.get({
data: {
method: 'app.passport.checkIsWechatCs',
uid: obj.uid,
}
});
if (ret && ret.code && ret.code === 200) {
isWechatService = ret.data.isWechatService === 'Y' ? true : false;
}
}
return Promise.resolve(isWechatService);
}
async renderByCs(obj) {
let result = await this.get({
data: {
method: 'app.passport.getUserInfoByShareCode',
uid: obj.uid,
shareCode: obj.shareCode
}
});
if (result.code === 200) {
return Promise.resolve({code: 200, data: result.data, result: true});
} else {
return Promise.resolve(result);
}
}
async submitWxCode(obj) {
return await this.get({
data: {
method: 'app.passport.submitUserWechatCode',
uid: obj.userUid,
wechat_uid: obj.uid,
userCode: obj.userCode
}
});
}
async renderByUser({uid, shareCode}) {
const {code, data = {}} = await this.get({
data: {
method: 'app.passport.getIsCanReceive',
uid,
shareCode
}
});
if (code !== 200) {
return {};
}
switch (data.recieveCode) {
case 200:
return {
received: false,
};
case 201:
return {
received: true,
rewardType: data.rewardType,
couponAmount: data.couponAmount,
rewardUrl: data.rewardUrl,
};
case 202:
return {
received: false,
message: data.recieveMessage,
};
default:
return {
received: false,
message: data.message,
};
}
}
receiveRedBag({uid, shareCode}) {
return this.get({
data: {
method: 'app.passport.receiveCouponForWxCS',
uid,
shareCode
}
});
}
}
module.exports = redEnvelopeModel;
... ...
... ... @@ -69,6 +69,8 @@ const grouthNew = require(`${cRoot}/grouth-new`);
const haveGain = require(`${cRoot}/have-gain`);
const redPack = require(`${cRoot}/red-envelope`);
// routers
router.get('/demo', demo.index);
... ... @@ -272,7 +274,6 @@ router.get('/individuation/shop', individuation.shop);
router.get('/feature/:code.html', feature.index);
router.get('/featuresidebar/:code.html', feature.sidebar);
router.get('/featurebottombar/:code.html', feature.bottombar);
router.get('/feature/goods', feature.goods);
router.get('/feature/couponSend', feature.couponSend); // 获取优惠券
router.get('/tide/category', auth, tide.category); // 潮品推介
router.get('/tide/shop', auth, tide.shop); // 潮牌推介
... ... @@ -339,6 +340,10 @@ router.get('/have-gain/fail', auth, haveGain.fail); // 揮恣銝
router.post('/have-gain/resetApply', auth, haveGain.resetApply); // 有货有赚审核不通过,重新申请API
router.post('/have-gain/submitApply', auth, haveGain.submitApply); // 有货有赚-申请开通
router.get('/red-envelope/index', auth, redPack.redbagPage);
router.post('/red-envelope/receive', auth, redPack.receiveRedBag);
router.post('/red-envelope/submitWxCode', auth, redPack.submitWxCode);
// 有货有赚推广活动
router.get('/have-gain/promo/:id.html', haveGain.promoDetail);
router.post('/have-gain/promo/:id', auth, haveGain.promoSubmit);
... ...
<div class="content-service">
{{#if isGetRedBag}}
<div class="user-coupon-info">
<input type="hidden" id="uid" value="{{userInfo.uid}}"/>
<div class="coupon-desc">
<div>{{userInfo.userName}},已成功获取</div>
{{#if userInfo.rewardType }}
<div class="desc-li">{{userInfo.couponName}}</div>
{{else}}
<div class="desc-li">{{userInfo.rewardName}}</div>
{{/if}}
<div class="desc-li">{{userInfo.recievedTime}}</div>
</div>
<div class="user-info">
<div class="copy-account">
<div class="account">{{userInfo.vipLevel}} {{userInfo.uid}}</div>
<button class="copy">点击复制</button>
</div>
{{#if userInfo.related}}
<div class="wx-account">
<input placeholder="请输入用户微信号" class="account-input" bindinput="bindAccount" value="{{account}}"/>
<button class="submitWxAccount">提交微信</button>
</div>
{{/if}}
<div class="wx-account-info">
{{#if userInfo.submitWechat}}
<div>已提交微信号:{{userInfo.userWechatCode}}</div>
{{else}}
<div>未提交微信</div>
{{/if}}
</div>
</div>
<div class="user-label">
<div class="title">用户标签</div>
<div>
<span class="label">{{userInfo.tag_address}}</span>
<span class="label">{{userInfo.tag_createTime}}</span>
</div>
</div>
<div class="relation-list">
<div class="title">已关联潮流顾问</div>
{{#each userInfo.relatedWechatList}}
<div class="list-item">
<span class="item-jqm">{{machineCode}}</span>
<span class="item-wx-acount">{{wechatCode}}</span>
</div>
{{/each}}
</div>
</div>
</div>
{{else}}
<div class="no-box">
<div class="no-received">
<image src="http://img12.static.yhbimg.com/sns/2018/09/20/10/02f45a44a7dc9012468441eae604f1c910.png" class="no-icon"/>
<div class="no-txt">礼包尚未被领取</div>
<div class="no-txt">可以微信提醒用户尽快领取!</div>
</div>
</div>
{{/if}}
</div>
... ...
<div class="redbag-user-container" data-received="{{pageData.received}}" data-sharecode="{{pageData.shareCode}}">
{{# pageData}}
{{#if received}}
<div class="received-content">
{{#isEqualOr rewardType 1}}
{{#isEqualOr couponAmount 5}}
<img src="http://img12.static.yhbimg.com/sns/2018/08/02/15/02a4fbd09374acfdc2b97cabd059e32669.png" class="red-bag1 use" />
{{/isEqualOr}}
{{#isEqualOr couponAmount 10}}
<img src="http://img11.static.yhbimg.com/sns/2018/08/02/15/0188ee9e04c067fa701f33f7be24bb97ca.png" class="red-bag2 use" />
{{/isEqualOr}}
{{#isEqualOr couponAmount 20}}
<img src="http://img11.static.yhbimg.com/sns/2018/08/02/15/0185441fd89c3bc4a78cd202c9c40eb633.png" class="red-bag3 use" />
{{/isEqualOr}}
{{#isEqualOr couponAmount 50}}
<img src="http://img11.static.yhbimg.com/sns/2018/08/02/15/01645486f02c4d38679b5058bde79abf02.png" class="red-bag50 use" />
{{/isEqualOr}}
{{#isEqualOr couponAmount 80}}
<img src="http://img12.static.yhbimg.com/sns/2018/08/02/15/02c329c8192bcdddd7467a8c44501b4525.png" class="red-bag80 use" />
{{/isEqualOr}}
{{#isEqualOr couponAmount 100}}
<img src="http://img11.static.yhbimg.com/sns/2018/08/02/15/01b6568f91129e886548ab5ff0f5a71ae8.png" class="red-bag100 use" />
{{/isEqualOr}}
{{/isEqualOr}}
{{#isEqualOr rewardType 2}}
<img src="{{rewardUrl}}" class="red-bag-other use"/>
{{/isEqualOr}}
<button type="button" class="go-use"></button>
</div>
{{else}}
<div class="rewards-content">
<i class="cuo-icon"></i>
<img src="http://img12.static.yhbimg.com/sns/2018/10/09/18/02c54d5277b89d3b72a4ac4eae7624bbf3.png" class="receiveRedBag"/>
</div>
{{/if}}
<input type="hidden" id="msg" value="{{message}}">
{{/ pageData}}
<div class="activity-rule">
<i class="hand"></i>
<p class="title">活动规则</p>
<p class="txt txt-1">领取权益需填写注册有货账户时绑定的手机号,认证后即可参与抽奖;</p>
<p class="txt txt-2">若忘记或不确定手机号是否绑定账户,请先联系微信客服进行查询;</p>
<p class="txt txt-3">抽中的优惠券将被放入您的有货账户中,若抽中免单/微信红包/实物奖品,请截图后联系微信客服;</p>
<p class="txt last">*此活动最终解释权归Yoho!Buy所有</p>
</div>
</div>
\ No newline at end of file
... ...
... ... @@ -18,7 +18,7 @@ let channels = {
lifestyle: 4
};
exports.index = (req, res, next) => {
exports.index = async(req, res, next) => {
let responseData = {
isLogin: req.user.uid ? true : false,
module: 'home',
... ... @@ -46,12 +46,26 @@ exports.index = (req, res, next) => {
(req.cookies._Channel && channels[req.cookies._Channel]) || 1
};
req.ctx(newHomeModel).index(params).then(result => {
// 为你优选开关
let recommendHide = _.get(req.app.locals.wap, 'ucenter.removePrefer', false);
try {
let isWxcs = false, shareUrl = '';
if (req.user.uid !== null) {
isWxcs = await req.ctx(newHomeModel).checkCs(req.user.uid);
}
if (isWxcs) {
let shareCode = await req.ctx(newHomeModel).getShareCode(req.user.uid);
shareUrl = '/activity/red-envelope/index?shareCode=' + shareCode.data;
}
let result = await req.ctx(newHomeModel).index(params);
let recommendHide = await _.get(req.app.locals.wap, 'ucenter.removePrefer', false);
responseData.isWxcs = isWxcs;
responseData.shareUrl = shareUrl;
res.render('new-home', Object.assign(responseData, result, {
recommendHide: recommendHide
}));
}).catch(next);
} catch (e) {
return next(e);
}
};
... ...
... ... @@ -131,7 +131,32 @@ class newHome extends global.yoho.BaseModel {
}
});
}
async checkCs(uid) {
let isWechatService = false; // 是否是微信客服
if (uid !== null || uid !== undefined) {
// 校验是客服还是用户 y则是客服
let ret = await this.get({
data: {
method: 'app.passport.checkIsWechatCs',
uid,
}
});
if (ret && ret.code && ret.code === 200) {
isWechatService = ret.data.isWechatService === 'Y' ? true : false;
}
}
return Promise.resolve(isWechatService);
}
getShareCode(uid) {
return this.get({
data: {
method: 'app.passport.getWechatShareCode',
uid
}
});
}
index(params) {
return Promise.all([
this._userData(params),
... ...
... ... @@ -154,6 +154,16 @@
<div class="arr iconfont">&#xe604;</div>
</div>
</a>
{{#if @root.isWxcs}}
<a class="list-item" id="wxcs" data-url="{{@root.shareUrl}}">
<div class="pic iconfont">&#xe730;</div>
<div class="body">
<div class="main eps">潮流顾问专属分享</div>
<div class="value"></div>
<div class="arr iconfont">&#xe604;</div>
</div>
</a>
{{/if}}
</div>
{{/ infoNum}}
<div class="ad-pic res-c clearfix">
... ... @@ -179,4 +189,4 @@
<div class="yoho-footer wechat-footer">
<div class="float-top"></div>
</div>
{{/if}}
\ No newline at end of file
{{/if}}
... ...
require('scss/activity/redbag-cs.page.scss');
import $ from 'yoho-jquery';
import tip from 'js/plugin/tip';
import Clipboard from 'clipboard';
// 提交微信客服账号
$('.submitWxAccount').click(function() {
let userCode = $('.account-input')[0].value;
if (!userCode) {
tip.show('请输入用户微信号');
return;
}
$.ajax({
method: 'POST',
url: '/activity/red-envelope/submitWxCode',
data: {
userUid: parseInt($('#uid')[0].value),
userCode
},
success: function(data) {
if (data.code === 200) {
tip.show('提交成功');
} else {
tip.show(data.message);
}
}
});
});
$('.copy').click(function() {
let clipboard = new Clipboard('.copy', {
text: function() {
return document.getElementsByClassName('account')[0].innerText;
}
});
clipboard.on('success', function(e) {
e.clearSelection();
tip.show('复制成功');
});
clipboard.on('error', function() {
tip.show('复制失败');
});
});
... ...
import 'scss/activity/redbag-user.page';
import $ from 'yoho-jquery';
import tip from 'js/plugin/tip';
$(() => {
const $container = $('.redbag-user-container'),
$msg = $('#msg');
if ($msg.length && $msg.val()) {
tip.show($msg.val());
}
if ($container.data('received')) {
$(document).on('click', '.go-use', () => {
tip.show('请下载App');
});
} else {
let posting = false;
$(document).on('click', '.receiveRedBag', () => {
const shareCode = $container.data('sharecode');
if (!shareCode) {
return;
}
if (posting) {
return;
}
posting = true;
$.ajax({
method: 'POST',
url: '/activity/red-envelope/receive',
data: {
shareCode
},
success: function(res) {
if (res.code === 200) {
// setTimeout(() => {
// window.location.reload();
// }, 500);
}
tip.show(res.message);
},
complete() {
posting = false;
}
});
});
}
});
... ...
... ... @@ -6,6 +6,8 @@ import 'js/common/set-trend-world';
import Swiper from 'yoho-swiper2';
import yoho from 'js/yoho-app';
import AutoScroll from './new-home/auto-scroll';
import Clipboard from 'clipboard';
import tip from 'js/plugin/tip';
class NewHome extends Page {
constructor() {
... ... @@ -17,7 +19,8 @@ class NewHome extends Page {
$resYas: $('.res-c').find('a'),
$trendCode: $('.trend-code'),
$floatTop: $('.float-top'),
$recommendC: $('#new-recommend-c')
$recommendC: $('#new-recommend-c'),
$wxcs: $('#wxcs')
};
this.init();
... ... @@ -30,9 +33,30 @@ class NewHome extends Page {
this.showTrend();
this.autoScroll();
this.backToTop();
this.copyShareUrl();
window.reMarginFooter('.footer-tab');
}
copyShareUrl() {
this.selector.$wxcs.click(function() {
let clipboard = new Clipboard('#wxcs', {
text: ()=> {
return location.origin + $(this).attr('data-url');
}
});
clipboard.on('success', function(e) {
e.clearSelection();
tip.show('复制分享地址成功');
});
clipboard.on('error', function() {
tip.show('复制失败');
});
});
}
backToTop() {
if (this.selector.$recommendC.length > 0) {
$(document).scroll(() => {
... ...
... ... @@ -136,8 +136,7 @@ body {
width: 34px;
height: 34px;
vertical-align: middle;
background-image: url("img/activity/have-gain/agree@2x.png");
background-repeat: no-repeat;
background: url("img/activity/have-gain/agree@2x.png") no-repeat;
background-size: contain;
display: inline-block;
}
... ... @@ -163,4 +162,3 @@ body {
}
}
}
... ...
html {
width: 100%;
height: 100%;
}
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
background-color: #f0f0f0;
font-family: Arial, sans-serif;
}
.desc-li {
margin-top: 13px;
}
.desc-li:before {
content: "";
width: 10px;
height: 10px;
background: #fff;
display: inline-block;
margin-right: 22px;
vertical-align: middle;
}
.content-service {
margin: 30px;
height: 100%;
}
.coupon-desc {
width: 100%;
min-height: 122px;
text-align: left;
font-family: PingFang-SC-Medium, sans-serif;
font-size: 32px;
line-height: 44px;
color: #fff;
letter-spacing: 0;
background: #444;
padding: 40px 20px;
box-sizing: border-box;
word-break: break-all;
}
.user-info {
width: 100%;
background: #fff;
border-bottom: 1px dashed #979797;
padding-bottom: 26px;
}
.copy-account,
.wx-account {
clear: both;
margin: 30px auto 0;
width: 650px;
height: 96px;
}
.user-info button {
width: 180px;
height: 96px;
line-height: 96px;
background: #d0021b;
font-family: PingFang-SC-Medium, sans-serif;
font-size: 36px;
color: #fff;
letter-spacing: 0;
text-align: center;
margin-left: -1px;
border-radius: 0;
float: left;
padding: 0;
}
.account {
width: 468px;
height: 96px;
line-height: 96px;
border: 1px solid #b0b0b0;
font-family: PingFang-SC-Medium, sans-serif;
font-size: 36px;
color: #444;
letter-spacing: 0;
text-align: left;
padding: 0 0 0 20px;
box-sizing: border-box;
float: left;
}
.account-input {
width: 468px;
height: 96px;
line-height: 96px;
border: 1px solid #b0b0b0;
font-family: PingFang-SC-Medium, sans-serif;
font-size: 36px;
color: #b0b0b0;
letter-spacing: 0;
text-align: left;
padding: 0 0 0 20px;
box-sizing: border-box;
float: left;
background: #f0f0f0;
}
.wx-account-info {
color: #d0021b;
font-size: 24px;
width: 650px;
margin: 24px auto 0;
}
.user-label {
padding: 0 20px 30px;
border-bottom: 1px dashed #979797;
}
.user-label .title,
.relation-list .title {
font-family: PingFang-SC-Medium, sans-serif;
font-size: 28px;
color: #000;
letter-spacing: 0;
margin-top: 42px;
margin-bottom: 33px;
text-align: left;
border-left: 7px solid #444;
padding-left: 20px;
}
.user-label .label {
background: #d8d8d8;
border-radius: 4px;
font-family: PingFang-SC-Medium, sans-serif;
font-size: 32px;
color: #444;
letter-spacing: 0;
text-align: center;
display: inline-block;
padding: 0 40px;
height: 52px;
line-height: 52px;
margin: 10px;
box-sizing: border-box;
}
.relation-list {
padding: 0 20px;
}
.relation-list .list-item {
width: 650px;
height: 52px;
line-height: 52px;
background: #d8d8d8;
color: #444;
border-radius: 6px;
margin-bottom: 20px;
font-size: 32px;
font-family: PingFang-SC-Medium, sans-serif;
}
.relation-list .item-jqm {
width: 202px;
text-align: left;
padding-left: 24px;
display: inline-block;
}
.no-box {
padding: 348px 0 0;
}
.no-received {
width: 670px;
height: 372px;
margin: 0 auto;
}
.no-txt {
color: #b0b0b0;
font-size: 36px;
font-family: PingFang-SC-Bold, sans-serif;
text-align: center;
}
.no-icon {
width: 240px;
height: 240px;
display: block;
margin: 0 auto 40px;
}
.user-coupon-info {
background: #fff;
height: 87vh;
}
... ...
.redbag-user-container {
width: 100%;
background: url(http://img12.static.yhbimg.com/sns/2018/09/27/11/025d67e459f2b67afd343540569e56d7b9.jpg) no-repeat;
background-size: cover;
padding-top: 244px;
.rewards-content {
position: relative;
overflow: hidden;
padding-bottom: 100px;
.cuo-icon {
width: 284px;
height: 111px;
top: 0;
right: 49px;
background: url(//img12.static.yhbimg.com/sns/2018/09/27/12/02598d832b6ecfae4ef6a18c3dd904e90c.png) no-repeat;
background-size: contain;
position: absolute;
}
img {
width: 570px;
height: 553px;
overflow: hidden;
margin-top: 130px;
}
}
.received-content {
padding-top: 176px;
overflow: hidden;
padding-bottom: 160px;
position: relative;
.use {
width: 750px;
height: 443px;
background-size: contain;
&.red-bag1 {
height: 458px;
}
&.red-bag2 {
height: 464px;
}
&.red-bag3 {
height: 454px;
}
&.red-bag50 {
height: 439px;
}
&.red-bag80 {
height: 431px;
}
&.red-bag100 {
height: 443px;
}
&.red-bag-other {
height: 443px;
}
}
.go-use {
position: absolute;
width: 310px;
height: 180px;
top: 386px;
left: 200px;
background: none !important;
border: none !important;
}
}
.activity-rule {
width: 680px;
height: 440px;
margin: 0 auto;
padding: 33px;
background: url("img/activity/red-envelope/txt-bg.png") no-repeat;
background-size: contain;
position: relative;
font-family: PingFang-SC-Medium, sans-serif;
color: #000;
letter-spacing: 0;
.hand {
position: absolute;
width: 91px;
height: 91px;
right: 33px;
top: -39px;
background: url(http://img11.static.yhbimg.com/sns/2018/09/27/11/01c13a6c46302940f9c1656f5893236d97.png) no-repeat;
background-size: contain;
}
.title {
font-size: 38px;
font-weight: bold;
margin-bottom: 18px;
position: relative;
}
.txt {
font-size: 25px;
line-height: 34px;
width: 100%;
margin-bottom: 14px;
padding-left: 50px;
&:before {
font-size: 32px;
font-family: Arial, sans-serif;
font-weight: bold;
margin-left: -50px;
margin-right: 25px;
}
&.txt-1:before {
content: "1.";
}
&.txt-2:before {
content: "2.";
}
&.txt-3:before {
content: "3.";
}
&.last {
font-size: 20px;
}
}
}
}
... ...
/**
* 接口参数校验
*
* Created by y.huang on 17/5/21.
*/
/**
* 返回一个错误对象
*
* msg 提示语
*/
const _errJson = (message) => {
return {
code: '203',
description: message,
name: '数据错误',
errKey: 'valid'
};
};
/**
* 数字校验方法、支持小数负数、支持字符串数字自动转换
*
* option object类型,包含校验条件,如下
* require 是否必须,boolean类型,默认false不必须
* empty 可以是空字符串, boolean类型,默认true可以
* isInteger 是否必须整数,boolean类型,默认false不必须
* equal 等于某个值,number类型
* equalArr 等于几个值中的一个,array类型,array元素为number类型,长度不限
* smaller 小于某个值,number类型
* bigger 大于某个值,number类型
*/
const _numberValid = (option) => {
const value = option.value;
// 设置默认值
option.require = option.require === undefined ? false : option.require;
option.integer = option.integer === undefined ? false : option.integer;
option.empty = option.empty === undefined ? true : option.empty;
if (value === undefined) {
if (option.require === true) {
throw _errJson(`${option.param} 参数是必须的`);
} else {
return value;
}
}
if (typeof value === 'boolean' || typeof value === 'object') {
throw _errJson(`${option.param} 参数类型必须是数字或字符串数字`);
}
if (value === '') {
if (option.empty === false) {
throw _errJson(`${option.param} 参数不能为空字符串`);
} else {
return undefined;
}
}
const numValue = Number(value);
if (!Number.isNaN(numValue) && Math.abs(numValue) !== Infinity) {
if (option.equal !== undefined) {
if (numValue !== option.equal) {
throw _errJson(`${option.param} 参数必须等于 ${option.equal}`);
}
return numValue;
}
if (option.equalArr !== undefined) {
let result = false;
for (let item of option.equalArr) {
if (item === numValue) {
result = true;
break;
}
}
if (!result) {
throw _errJson(`${option.param} 参数必须等于 ${option.equalArr} 中的某个`);
}
return numValue;
}
if (option.integer === true) {
if (!Number.isInteger(numValue)) {
throw _errJson(`${option.param} 参数必须是整数`);
}
}
if (option.smaller !== undefined) {
if (!numValue < option.smaller) {
throw _errJson(`${option.param} 参数必须小于 ${option.smaller}`);
}
}
if (option.bigger !== undefined) {
if (!numValue > option.bigger) {
throw _errJson(`${option.param} 参数必须大于 ${option.bigger}`);
}
}
return numValue;
} else {
throw _errJson(`${option.param} 参数类型必须是数字或字符串数字`);
}
};
/**
* 字符串校验方法、支持数字自动转换
*
* option object类型,包含校验条件,如下
* require 是否必须,boolean类型,默认false不必须
* empty 是否可以为空字符串,boolean类型,默认true可以
* emptyFilter 过滤空字符串,boolean类型,true为需要过滤, 使用时empty必须为true
* regex 正则匹配,其值应该是'phone,email'中的一个,或是一个自定义的正则对象或正则自面量
* start 字符串长度大于,number类型
* end 字符串长度小于,number类型
*/
const _stringValid = (option) => {
const value = option.value;
// 设置默认值
option.require = option.require || false;
option.empty = option.empty || true;
if (value === undefined) {
if (option.require === true) {
throw _errJson(`${option.param} 参数是必须的`);
} else {
return value;
}
}
if (Number.isNaN(value) || Math.abs(value) === Infinity ||
typeof value === 'boolean' || typeof value === 'object') {
throw _errJson(`${option.param} 参数类型必须是数字或字符串`);
}
const strValue = String(value).trim();
if (strValue === '') {
if (option.empty === false) {
throw _errJson(`${option.param} 参数不能为空`);
} else {
if (option.emptyFilter === true) {
return undefined;
}
return strValue;
}
}
if (option.regex !== undefined) {
switch (option.regex) {
case 'phone':
if (!/^1[0-9]{10}$/.test(strValue)) {
throw _errJson(`${option.param} 参数不符合手机格式`);
}
break;
case 'email':
if (!/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/.test(strValue)) {
throw _errJson(`${option.param} 参数不符合邮箱格式`);
}
break;
default:
if (!option.regex.test(strValue)) {
throw _errJson(`${option.param} 参数不符合自定义格式`);
}
}
return strValue;
}
if (option.end !== undefined) {
if (!strValue.length < option.end) {
throw _errJson(`${option.param} 参数长度必须小于 ${option.end}`);
}
}
if (option.start !== undefined) {
if (!strValue.length > option.start) {
throw _errJson(`${option.param} 参数长度必须大于 ${option.start}`);
}
}
return strValue;
};
/**
* 布尔校验方法、支持字符串布尔类型自动转换
*
* option object类型,包含校验条件,如下
* require 是否必须,boolean类型,默认false不必需
* empty 是否可以为空字符串,boolean类型,默认true可以
* emptyFilter 过滤空字符串,boolean类型,true为需要过滤, 使用时empty必须为true
*/
const _booleanValid = (option) => {
const value = option.value;
// 设置默认值
option.require = option.require || false;
option.empty = option.empty || true;
if (value === undefined) {
if (option.require === true) {
throw _errJson(`${option.param} 参数是必须的`);
} else {
return value;
}
}
if (value === '') {
if (option.empty === false) {
throw _errJson(`${option.param} 参数不能为空`);
} else {
if (option.emptyFilter === true) {
return undefined;
}
return value;
}
} else {
if (typeof value !== 'boolean' && value !== 'true' && value !== 'false') {
throw _errJson(`${option.param} 参数类型必须为boolean`);
}
return Boolean(value);
}
};
const _objectValid = (option) => {
const value = option.value;
// 设置默认值
option.require = option.require || false;
option.empty = option.empty || true;
if (value === undefined || value === null) {
if (option.require === true) {
throw _errJson(`${option.param} 参数是必须的`);
} else {
return null;
}
}
if (typeof value === 'object') {
let valueArr = Object.keys(value);
if (!valueArr.length) {
if (option.empty === false) {
throw _errJson(`${option.param} 参数不能为空`);
} else {
return null;
}
} else {
return value;
}
} else {
throw _errJson(`${option.param} 参数格式错误`);
}
};
/*
* data: 需要校验的数据对象
* option: 校验规则对象,eg: {'name', {type: 'string', require: true}}
*
*/
const valid = (data, option) => {
Object.keys(option).forEach(item => {
let opt = option[item];
opt.value = data[item];
opt.param = item;
switch (opt.type) {
case 'number':
data[item] = _numberValid(opt);
if (data[item] === undefined) {
delete data[item];
}
break;
case 'string':
data[item] = _stringValid(opt);
if (data[item] === undefined) {
delete data[item];
}
break;
case 'boolean':
data[item] = _booleanValid(opt);
if (data[item] === undefined) {
delete data[item];
}
break;
case 'object':
data[item] = _objectValid(opt);
if (data[item] === undefined) {
delete data[item];
}
break;
}
});
return data;
};
module.exports = valid;
... ...