Commit 79ed990b authored by 秦海涛's avatar 秦海涛

update

parent 91c83b35
.item-dialog-content {
background: #FFFFFF;
max-height: 507px;
display: flex;
flex-direction: column;
}
.modal-content-btn.choose-modal-footer {
justify-content:space-between;
align-items:center;
}
.choose-content-tab {
padding:10px 20px;
flex-grow:1;
overflow-y:scroll;
height:350px;
}
.choose-content-tab .choose-content-tab-view{
padding:20px 0 5px;
}
.choose-content-tab-baby{
border:1px solid #ccc;
position:relative;
margin:10px 10px 0 0;
}
.choose-content-tab-baby:hover {
border:1px solid #3386F1;
}
.choose-content-tab-image-wrap {
padding:10px;
font-size:0;
}
.choose-content-tab-image-wrap image{
width:134px;
height:134px;
}
.choose-content-tab-baby-wrap{
display:flex;
max-height:300px;
overflow:scroll;
flex-wrap:wrap;
}
.choose-content-tab-baby-info{
background:#EBF3FF;
padding:10px;
}
.choose-content-tab-baby Checkbox{
position:absolute;
right:10px;
top:9px;
}
.choose-content-tab-baby-info-title{
width:134px;
white-space: nowrap;
font-size:12px;
color:#333333;
overflow: hidden;
text-overflow:ellipsis;
margin-bottom:10px;
}
.choose-content-tab-baby-info-prize {
display:flex;
font-size:12px;
justify-content:space-between;
}
.choose-content-tab-baby-info-prize .prize-now{
color: #333;
}
.choose-content-tab-baby-info-prize .prize-now text{
color:#FFA033;
}
.choose-content-tab-baby-info-prize .prize-old{
color:#999999;
text-decoration:line-through;
}
.choose-content-pagination{
display:flex;
justify-content:flex-end;
margin:10px 20px 10px 0;
}
.choose-modal-footer-number{
margin:0 5px;
color:#3386F1;
}
.choose-no-baby{
font-size:14px;
color: #333;
}
.items-dialog-btns {
display: flex;
justify-content: flex-end;
}
.items-dialog-btns_confirm {
margin-right: 10px;
}
\ No newline at end of file
<dialog-wrap
title="选择宝贝"
visible="{{showBaby}}"
hasMask="{{true}}"
onClose="closeBaby"
width="738"
>
<view class="modal-content">
<tab onChange="changeTableItem" class="choose-content-tab">
<tab-item
title="全部宝贝"
key="all"
>
<view class="choose-content-tab-view">
<select onChange="changeStatus" value="{{searchInfo.approveStatus}}" showSearch>
<option value="onsale">出售中</option>
<!-- <option value="instock">仓库中</option> -->
</select>
<text style="margin-left:20px;font-size:12px">标题关键字</text>
<input style="width:120px;margin:0 10px" value="{{searchInfo.title}}" onChange="changeSearchKeyWords" placeholder="标题关键字"/>
<button onTap="searchBabyList" size="medium" type="primary" size="small">搜索</button>
</view>
<view class="choose-content-tab-baby-wrap">
<view class="choose-content-tab-baby" onTap="changeCheckStatus" data-index={{index}} data-item="{{item}}" a:for-index="index" a:for-item="item" a:for="{{babyDialogInfo.list}}">
<view class="choose-content-tab-image-wrap">
<image src="{{item.picUrl}}"></image>
</view>
<view class="choose-content-tab-baby-info">
<view class="choose-content-tab-baby-info-title">{{item.name}}</view>
<view class="choose-content-tab-baby-info-prize"><text class="prize-now">¥<text>{{item.price}}</text></text></view>
</view>
<checkbox class="block" checked="{{chooseId.includes(item.itemId)}}" data-name="{{index}}" data-item="{{item}}"></checkbox>
</view>
</view>
<view class="choose-content-pagination">
<pagination showJump="{{false}}" defaultCurrent="{{babyDialogInfo.pageNo}}" data-type="all" pageSize="{{babyDialogInfo.pageSize}}" onChange="changePagination" pageShowCount="{{5}}" total="{{babyDialogInfo.totalCount}}" a:if="{{babyDialogInfo.totalPages > 1}}" shape="arrow-only" />
</view>
<view class="choose-no-baby" a:if="{{!babyDialogInfo.list.length}}">暂无宝贝,请前去添加</view>
</tab-item>
<tab-item
key="choose"
title="{{`已选择(${chooseId.length})`}}"
>
<view class="choose-content-tab-view">
<view a:if="{{chooseId.length > 0}}" class="choose-content-tab-baby-wrap">
<view class="choose-content-tab-baby" data-item="{{item}}" onTap="changeNoCheckBaby" a:for-index="index" a:for="{{chooseArr}}">
<view class="choose-content-tab-image-wrap">
<image src="{{item.picUrl}}"></image>
</view>
<view class="choose-content-tab-baby-info">
<view class="choose-content-tab-baby-info-title">{{item.name}}</view>
<view class="choose-content-tab-baby-info-prize"><text class="prize-now">¥<text>{{item.price}}</text></text></view>
</view>
<checkbox class="block" checked="true" data-name="{{index}}"></checkbox>
</view>
</view>
<view class="choose-no-baby" a:else>暂无选择的宝贝,请去选择</view>
</view>
</tab-item>
</tab>
<view class="modal-content-btn choose-modal-footer">
<view>已选择<text class="choose-modal-footer-number">{{chooseId.length}}</text>个宝贝</view>
<view class="items-dialog-btns">
<button type="primary" classs="items-dialog-btns_confirm" onTap="sureBabyDialog">确定</button>
<button onTap="closeBaby">取消</button>
</view>
</view>
</view>
</dialog-wrap>
\ No newline at end of file
import API from "/api";
Component({
mixins: [],
data: {
dialogTop: "",
chooseArr: [],
chooseId: [],
firstGetList: false,
searchInfo: {
approveStatus: "onsale",
title: "",
pageNo: 1,
pageSize: 8,
},
babyDialogInfo: {
list: [],
pageNo: 1,
pageSize: 8,
totalCount: "",
totalPages: "",
},
},
props: {
onClose: () => {},
showBaby: false,
browseItemIds: "",
onUpdateBabyChoose: () => {},
},
didMount() {
this.initPosition();
const { searchInfo } = this.data;
this.getBabyList(searchInfo);
},
didUnmount() {},
methods: {
initPosition() {
const { scrollTop } = this.$page.data;
this.setData({
dialogTop: scrollTop * 2,
});
},
getBabyList(info, chooseId) {
API.findItemListByStatus({
...info,
}).then((res) => {
if (res.success) {
const { browseItemIds } = this.props;
this.setData({
chooseId: chooseId
? chooseId
: browseItemIds
? browseItemIds.split(",").map((i) => +i)
: [],
babyDialogInfo: {
...this.data.babyDialogInfo,
...res.data,
list: res.data.list ? res.data.list : [],
},
});
}
});
},
getHasChooseBaby(itemIds) {
API.findItemListByIds({ itemIds })
.then((res) => {
if (res.success) {
this.setData({
chooseArr: res.data.list,
});
} else {
my.showToast({
type: "fail",
content: res.message,
});
}
})
.catch((err) => {
console.log(err);
});
},
changeTableItem(e) {
const { value } = e.detail;
const { chooseId } = this.data;
if (value === ".$choose") {
if (!chooseId.length) {
this.setData({
chooseArr: [],
});
} else {
let itemIds = chooseId.join(",");
this.getHasChooseBaby(itemIds);
}
}
},
searchBabyList() {
const { searchInfo } = this.data;
this.getBabyList(searchInfo, this.data.chooseId);
},
changePagination(e) {
this.setData({
searchInfo: {
...this.data.searchInfo,
pageNo: e.detail.value,
},
});
this.getBabyList(this.data.searchInfo, this.data.chooseId);
},
closeBaby() {
this.props.onClose("baby");
},
changeCheckStatus(e) {
const { chooseId } = this.data;
if (chooseId.length >= 20) {
my.showToast({
type: "fail",
content: "最多选择20个宝贝",
});
}
const { item } = e.target.dataset;
console.log(item, "item");
if (chooseId.includes(item.itemId)) {
this.setData({
chooseId: chooseId,
});
} else {
this.setData({
chooseId: [item.itemId],
});
}
},
sureBabyDialog() {
const { chooseId } = this.data;
console.log(chooseId, "chooseId");
this.props.onUpdateBabyChoose(chooseId.join());
this.closeBaby();
},
changeSearchKeyWords(e) {
this.setData({
searchInfo: {
...this.data.searchInfo,
title: e.detail.value,
},
});
},
changeStatus(e) {
this.setData({
searchInfo: {
...this.data.searchInfo,
approveStatus: e.detail.value,
},
});
},
changeNoCheckBaby(e) {
const { chooseId } = this.data;
const { item } = e.target.dataset;
this.setData(
{
chooseId: chooseId.filter((i) => {
return i !== item.itemId;
}),
},
() => {
this.getHasChooseBaby(this.data.chooseId.join(","));
}
);
},
},
});
{
"component": true,
"usingComponents": {
"dialog-wrap": "../../basic/dialiog-wrap/dialiog-wrap"
}
}
\ No newline at end of file
...@@ -24,17 +24,24 @@ ...@@ -24,17 +24,24 @@
<radio size="small" value="{{3}}" >不限次</radio> <radio size="small" value="{{3}}" >不限次</radio>
</radio-group> </radio-group>
</form-item> </form-item>
<form-item a:if="{{taskRateType === 2}}"> <form-item style="width:100%;" a:if="{{taskRateType === 2}}">
<view class="task-day-limit"> <view class="task-day-limit">
<view>每天最多完成</view> <view>每天最多完成</view>
<view style="margin: 0 6px;"><select value="{{times}}" onChange="onTimesChange" dataSource="{{dataSource}}"/> <view style="margin: 0 6px;">
</view>次任务</view> <select value="{{times}}" onChange="onTimesChange" dataSource="{{dataSource}}"/>
</view>
次任务
</view>
</form-item> </form-item>
<form-item label="跳转链接" a:if="{{!noLink}}"> <form-item label="跳转链接" a:if="{{hasLink}}">
<input style="width: 250px" onChange="onChange" data-name="link" defaultValue="{{link}}" name="link" placeholder="请输入跳转链接"/> <input style="width: 250px" onChange="onChange" data-name="link" defaultValue="{{link}}" name="link" placeholder="请输入跳转链接"/>
</form-item> </form-item>
<form-item label="商品编辑" a:if="{{hasItems}}" style="width:100%;">
<items-config itemIds="{{itemIds}}" onUpdate="onItemIdsChange"/>
</form-item>
<form-item label="任务奖励"> <form-item label="任务奖励">
<input onChange="onChange" data-name="value" defaultValue="{{value}}" name="value" addonTextAfter="{{unit}}"/> <input onChange="onChange" data-name="value" defaultValue="{{value}}" name="value" addonTextAfter="{{unit}}"/>
</form-item> </form-item>
......
...@@ -13,26 +13,44 @@ Component({ ...@@ -13,26 +13,44 @@ Component({
{ label: 7, value:7 }, { label: 7, value:7 },
{ label: 8, value:8 }, { label: 8, value:8 },
{ label: 9, value:9 }, { label: 9, value:9 },
{ label: 10, value:10 } { label: 10, value:10 },
], ],
taskRateType: 1, taskRateType: 1,
times: 1, times: '',
title: '', title: '',
link: '', link: '',
itemIds: '',
value: '' value: ''
}, },
props: { props: {
visible: false, visible: false,
noLink: false, hasLink: false,
hasItems: false,
type: '', type: '',
unit: '', unit: '',
taskData: {
title: '',
taskRateType: 1,
times: '',
value: '',
itemIds: ''
},
onClose: () => {}, onClose: () => {},
onUpdate: () => {} onUpdate: () => {}
}, },
didMount() {}, didMount() {
this.initData();
},
didUpdate() {}, didUpdate() {},
didUnmount() {}, didUnmount() {},
methods: { methods: {
initData() {
Object.keys(this.props.taskData).forEach(key => {
this.setData({
[key]: this.props.taskData[key]
})
});
},
onCloseDialog() { onCloseDialog() {
this.props.onClose(); this.props.onClose();
}, },
...@@ -42,6 +60,11 @@ Component({ ...@@ -42,6 +60,11 @@ Component({
times: value times: value
}) })
}, },
onItemIdsChange(ids) {
this.setData({
itemIds:ids
})
},
onTaskRateTypeChange(e) { onTaskRateTypeChange(e) {
const { value } = e.detail; const { value } = e.detail;
this.setData({ this.setData({
...@@ -57,10 +80,13 @@ Component({ ...@@ -57,10 +80,13 @@ Component({
}, },
validateLink(link) { validateLink(link) {
if(!link) return false; if(!link) return false;
return true; if(link.startsWith('http://') || link.startsWith('https://')) {
return passUrlList.some(url => link.indexOf(url) !== -1);
}
return false;
}, },
onSaveTask() { onSaveTask() {
const { title, link, value, taskRateType, times } = this.data; const { title, link, value, taskRateType, times, itemIds } = this.data;
if(!title) { if(!title) {
my.showToast({ my.showToast({
type: 'fail', type: 'fail',
...@@ -69,7 +95,7 @@ Component({ ...@@ -69,7 +95,7 @@ Component({
return; return;
} }
if(!this.props.noLink && !this.validateLink(link)) { if(this.props.hasLink && !this.validateLink(link)) {
my.showToast({ my.showToast({
type: 'fail', type: 'fail',
content: '请输入正确的链接地址' content: '请输入正确的链接地址'
...@@ -77,7 +103,15 @@ Component({ ...@@ -77,7 +103,15 @@ Component({
return; return;
} }
if(!value) { if(this.props.hasItems && itemIds) {
my.showToast({
type: 'fail',
content: '请输入选择商品'
})
return;
}
if(!value || !Number.isInteger(+value)) {
my.showToast({ my.showToast({
type: 'fail', type: 'fail',
content: '请输入正确的任务奖励' content: '请输入正确的任务奖励'
...@@ -85,7 +119,11 @@ Component({ ...@@ -85,7 +119,11 @@ Component({
return; return;
} }
this.props.onUpdate && this.props.onUpdate({ title, link, value, taskRateType, times, type: this.props.type }) let taskData = { title, link, value, taskRateType, times, itemIds, type: this.props.type };
this.props.onUpdate && this.props.onUpdate(taskData);
this.onCloseDialog(); this.onCloseDialog();
} }
}, },
......
{ {
"component": true, "component": true,
"usingComponents": { "usingComponents": {
"dialog-wrap": "../../basic/dialiog-wrap/dialiog-wrap" "dialog-wrap": "../../basic/dialiog-wrap/dialiog-wrap",
"items-config": "/components/task/items-config/items-config"
} }
} }
\ No newline at end of file
<view class="tb-imageUpload-wrap"> <view class="tb-imageUpload-wrap">
<image style="width:90px;height:90px;border:1px solid #ccc;margin-right:10px" src="{{prizeInitData.image}}"></image> <image style="width:90px;height:90px;border:1px solid #ccc;margin-right:10px" src="{{url}}"></image>
<view class="tb-imageUpload-btn"> <view class="tb-imageUpload-btn">
<view>图片</view> <view>图片</view>
<text>尺寸为{{imageLimit[0]}}px * {{imageLimit[1]}}px,格式为jpg/png</text> <text>尺寸为{{imageLimit[0]}}px * {{imageLimit[1]}}px,格式为jpg/png</text>
......
import { chooseImage, getImageInfo, validateRangeNumber } from "/utils"; import { chooseImage, getImageInfo, validateRangeNumber } from "/utils";
const { cloud } = getApp();
const { function: fc } = cloud;
Component({ Component({
mixins: [], mixins: [],
...@@ -7,7 +8,8 @@ Component({ ...@@ -7,7 +8,8 @@ Component({
props: { props: {
imageLimit: [200, 200], imageLimit: [200, 200],
onSuccess: () => {}, onSuccess: () => {},
onError: () => {} onError: () => {},
url: '',
}, },
didMount() {}, didMount() {},
didUpdate() {}, didUpdate() {},
...@@ -35,9 +37,10 @@ Component({ ...@@ -35,9 +37,10 @@ Component({
fileName: path.split("/").pop(), fileName: path.split("/").pop(),
}); });
onSuccess && onSuccess(url) onSuccess && onSuccess(url)
} catch (error) { } catch (error) {
console.error(error); onError({}, error)
} }
}, },
}, },
......
.items-config {
display: flex;
align-items: center;
height: 30px;
}
\ No newline at end of file
<view class="items-config">
<text style="font-size: 12px">{{itemIds ? `已选择${(itemIds + '').split(',')}个商品` : ''}} </text>
<button type="primary" text size="small" onTap="onOpenDialog">{{itemIds ? '更换商品' : '选择商品'}}</button>
<items-dialog
onUpdateBabyChoose="onUpdateBabyChoose"
browseItemIds="{{itemIds + ''}}"
a:if="{{visible}}"
showBaby="{{visible}}" onClose="onCloseDialog"/>
</view>
\ No newline at end of file
Component({
mixins: [],
data: {
visible: false
},
props: {
itemIds: '',
dataName: '',
onUpdate: () => {}
},
didMount() {},
didUpdate() {},
didUnmount() {},
methods: {
onOpenDialog() {
this.setData({
visible: true
})
},
onUpdateBabyChoose(ids) {
const { onUpdate, dataName } = this.props;
onUpdate && onUpdate(ids, dataName);
},
onCloseDialog() {
this.setData({
visible: false
})
}
},
});
{
"component": true,
"usingComponents": {
"items-dialog": "/components/dialog/items-dialog/items-dialog"
}
}
\ No newline at end of file
<view class="url-task"> <view class="url-task">
<button size="small" type="primary" text="{{true}}" onTap="onOpenDialog" >{{taskData.title || '编辑任务'}}</button> <button size="small" type="primary" text="{{true}}" onTap="onOpenDialog" >{{taskData.title || '编辑任务'}}</button>
<task-dialog visible="{{visible}}" onClose="onClose" onUpdate="onUpdate" unit="炸弹" noLink="{{noLink}}"/> <task-dialog
visible="{{visible}}"
a:if="{{visible}}"
onClose="onClose"
onUpdate="onUpdate"
unit="{{unit}}"
hasItems="{{hasItems}}"
hasLink="{{hasLink}}"
taskData="{{taskData}}"
/>
</view> </view>
Component({ Component({
mixins: [], mixins: [],
data: { data: {
visible: false, visible: false
},
props: {
hasLink: false,
unit: '',
onUpdate: ()=> {},
taskData: { taskData: {
title: '' title: '',
taskRateType: 1,
times: '',
value: ''
}, },
dataName: ''
}, },
props: { didMount() {
noLink: false
}, },
didMount() {},
didUpdate() {}, didUpdate() {},
didUnmount() {}, didUnmount() {},
methods: { methods: {
...@@ -24,9 +31,8 @@ Component({ ...@@ -24,9 +31,8 @@ Component({
}) })
}, },
onUpdate(taskData) { onUpdate(taskData) {
this.setData({ const { onUpdate, dataName } = this.props;
taskData onUpdate && onUpdate(taskData, dataName);
})
} }
}, },
}); });
...@@ -72,6 +72,8 @@ ...@@ -72,6 +72,8 @@
<form-item <form-item
class="edit-content-form-item" class="edit-content-form-item"
label="关注店铺" label="关注店铺"
validateState="{{formState['taskMap.attentionStore'].status}}"
help="{{formState['taskMap.attentionStore'].message}}"
asterisk="{{false}}"> asterisk="{{false}}">
<tb-config-input <tb-config-input
textBefore="获得" textBefore="获得"
...@@ -87,38 +89,130 @@ ...@@ -87,38 +89,130 @@
<form-item <form-item
class="edit-content-form-item" class="edit-content-form-item"
label="成为会员" label="成为会员"
validateState="{{formState['taskMap.beMembership'].status}}"
help="{{formState['taskMap.beMembership'].message}}"
asterisk="{{false}}"> asterisk="{{false}}">
<tb-config-input <tb-config-input
textBefore="获得" textBefore="获得"
textAfter="体力值" textAfter="体力值"
validateRange="{{[1, 99]}}" validateRange="{{[1, 99]}}"
value="{{limitValue}}" value="{{taskMap.beMembership.value}}"
onChange="onConfigInputChange", dataName="taskMap.beMembership.value"
onChange="onTaskInputChange",
placeholder="1-99"
/>
</form-item>
<form-item
class="edit-content-form-item"
label="签到"
validateState="{{formState['taskMap.sign'].status}}"
help="{{formState['taskMap.sign'].message}}"
asterisk="{{false}}">
<tb-config-input
textBefore="每日签到获得"
textAfter="体力值"
validateRange="{{[1, 99]}}"
value="{{taskMap.sign.value}}"
dataName="taskMap.sign.value"
onChange="onTaskInputChange",
placeholder="1-99"
/>
</form-item>
<form-item
class="edit-content-form-item"
label="兑换参与次数"
validateState="{{formState['taskMap.exchangeCredits'].status}}"
help="{{formState['taskMap.exchangeCredits'].message}}"
asterisk="{{false}}">
<tb-config-input
textBefore="可消耗"
textAfter="积分兑换参与次数"
validateRange="{{[1, 99]}}"
value="{{taskMap.exchangeCredits.value}}"
dataName="taskMap.exchangeCredits.value"
onChange="onTaskInputChange",
placeholder="1-99" placeholder="1-99"
/> />
<view style="margin: 10px 0 0 0">
<tb-config-input
textBefore="每天最多可兑换"
textAfter="次"
validateRange="{{[1, 10]}}"
value="{{taskMap.exchangeCredits.times}}"
dataName="taskMap.exchangeCredits.times"
onChange="onTaskInputChange",
placeholder="1-10"
/>
</view>
</form-item> </form-item>
<form-item <form-item
class="edit-content-form-item" class="edit-content-form-item"
label="邀请好友" label="邀请好友"
validateState="{{formState['taskMap.inviteFriends'].status}}"
help="{{formState['taskMap.inviteFriends'].message}}"
asterisk="{{false}}"> asterisk="{{false}}">
<task-config noLink="{{true}}" type="inviteFriends"/> <task-config
unit="体力值"
type="inviteFriends"
taskData="{{taskMap.inviteFriends}}"
dataName="taskMap.inviteFriends"
onUpdate="onTaskDialogChange"
/>
</form-item> </form-item>
<form-item <form-item
class="edit-content-form-item" class="edit-content-form-item"
label="浏览指定页面" label="浏览指定页面"
validateState="{{formState['taskMap.jumpLink'].status}}"
help="{{formState['taskMap.jumpLink'].message}}"
asterisk="{{false}}">
<task-config
unit="体力值"
type="jumpLink"
hasLink
taskData="{{taskMap.jumpLink}}"
dataName="taskMap.jumpLink"
onUpdate="onTaskDialogChange"
/>
</form-item>
<form-item
class="edit-content-form-item"
label="收藏商品"
validateState="{{formState['taskMap.collectGoods'].status}}"
help="{{formState['taskMap.collectGoods'].message}}"
asterisk="{{false}}">
<task-config
unit="体力值"
type="collectGoods"
hasLink
hasItems
taskData="{{taskMap.collectGoods}}"
dataName="taskMap.collectGoods"
onUpdate="onTaskDialogChange"
/>
</form-item>
<form-item
class="edit-content-form-item"
label="寻宝屋商品"
validateState="{{formState['taskMap.browseGoods'].status}}"
help="{{formState['taskMap.browseGoods'].message}}"
asterisk="{{false}}"> asterisk="{{false}}">
<task-config type="jumpLink"/> <items-config itemIds="{{taskMap.browseGoods.itemIds}}" dataName="taskMap.browseGoods" onUpdate="onTaskChange"/>
</form-item> </form-item>
<form-item <form-item
validateState="{{formState.logoImage.status}}" validateState="{{formState.image.status}}"
help="{{formState.logoImage.message}}" help="{{formState.image.message}}"
class="edit-content-form-item" class="edit-content-form-item"
label="logo图片" label="logo图片"
asterisk="{{false}}"> asterisk="{{false}}">
<tb-image-upload/> <tb-image-upload url="{{image}}" onSuccess="onImageChange"/>
</form-item> </form-item>
...@@ -161,7 +255,7 @@ ...@@ -161,7 +255,7 @@
class="edit-content-form-item" class="edit-content-form-item"
label="淘口令图片" label="淘口令图片"
asterisk="{{false}}"> asterisk="{{false}}">
<tb-image-upload/> <tb-image-upload url="{{commandImg}}" onSuccess="onImageChange"/>
</form-item> </form-item>
<view class="submit-btn"> <view class="submit-btn">
......
...@@ -13,23 +13,9 @@ const THANKS_TYPE = 5 ...@@ -13,23 +13,9 @@ const THANKS_TYPE = 5
var validator = new schema(descriptor); var validator = new schema(descriptor);
/**
*
* 1.任务相关
* 体力值 power
* 参与次数 gameTimes
* 粮食(牧草、水滴等) food
* 金币 coins
* 道具(炸弹、复活卡等) tools
*
*/
Component({ Component({
data: { data: {
labelCol: { labelCol: { fixedSpan: 5 },
fixedSpan: 5
},
id: '', id: '',
title: '', title: '',
subtitle: '', subtitle: '',
...@@ -37,9 +23,9 @@ Component({ ...@@ -37,9 +23,9 @@ Component({
endTime: '', endTime: '',
timeRange: [], timeRange: [],
rule: '', rule: '',
limitValue: '',
prizeInfoList: [], prizeInfoList: [],
commandTitle: '', commandTitle: '',
commandImg: '',
beenInvitedText: '', beenInvitedText: '',
taskList:[ taskList:[
{ {
...@@ -103,13 +89,51 @@ Component({ ...@@ -103,13 +89,51 @@ Component({
taskMap: { taskMap: {
attentionStore: { attentionStore: {
value: '', value: '',
}
}, },
beMembership: {
value:''
},
sign: {
value: ''
},
exchangeCredits: {
value: '',
times: '',
},
inviteFriends: {
title: '', // 任务标题
taskRateType: 1, // 任务频率类型
times: 3, // 任务为每日限次次数值
value: '', // 任务奖励
},
browseGoods: {
title: "",
taskRateType: 1,
times: 3,
value: '',
link: ''
},
collectGoods: {
title: "",
taskRateType: 1,
times: 3,
value: '90',
itemIds: "",
},
jumpLink: {
title: "",
taskRateType: 3,
link: "",//跳转链接
times: 3,
value: '',
},
},
image: '',
isEnd: false, isEnd: false,
isStart: false, isStart: false,
originalStartTime: '', originalStartTime: '',
prizeDialogData: {}, prizeDialogData: {},
formState: formatValidator(validator.rules) formState: formatValidator(descriptor)
}, },
props: {}, props: {},
didMount() { didMount() {
...@@ -136,7 +160,9 @@ Component({ ...@@ -136,7 +160,9 @@ Component({
originalStartTime: +rest.startTime, originalStartTime: +rest.startTime,
isStart: +rest.startTime < Date.now(), isStart: +rest.startTime < Date.now(),
isEnd: +rest.endTime < Date.now(), isEnd: +rest.endTime < Date.now(),
prizeInfoList: prizeInfoList && prizeInfoList.length > 0 ? prizeInfoList : this.data.prizeInfoList prizeInfoList: prizeInfoList && prizeInfoList.length > 0 ? prizeInfoList : this.data.prizeInfoList,
taskList: rest.taskList,
taskMap: this.formatTaskListToMap(rest.taskList)
}) })
} catch (error) { } catch (error) {
...@@ -146,33 +172,48 @@ Component({ ...@@ -146,33 +172,48 @@ Component({
onChange(e) { onChange(e) {
const { value } = e.detail; const { value } = e.detail;
const { name } = e.target.dataset; const { name } = e.target.dataset;
this.setDataByKey(name, value); this.setData({
[name]: value
})
}, },
setDataByKey(name, val) { setDataByKey(name, val) {
const keys = name.split('.'); const keys = name.split('.');
if(keys.length === 1) { if(keys.length === 1) {
this.setData({ this.setData({
[{keys[0]]: val [keys[0]]: val
}) })
} }
if(keys.length === 2) { if(keys.length === 2) {
let targetKey = this.data[{keys[0]]; let targetKey = this.data[keys[0]];
targetKey[keys[1]] = val; targetKey[keys[1]] = val;
let newVal = Object.assign({}, targetKey)
this.setData({ this.setData({
[{keys[0]]: targetKey [keys[0]]: newVal
}) })
} }
if(keys.length === 3) { if(keys.length === 3) {
let targetKey = this.data[{keys[0]]; let targetKey = this.data[keys[0]];
targetKey[keys[1]][eys[2]] = val; targetKey[keys[1]][keys[2]] = val;
let newVal = Object.assign({}, targetKey)
this.setData({ this.setData({
[{keys[0]]: targetKey [keys[0]]: newVal
}) })
} }
}, },
onTaskInputChange(e) { onTaskInputChange(e) {
const { name } = e.target.dataset; const { name } = e.target.dataset;
let { taskMap } = this.data; const { value } = e.detail;
this.setDataByKey(name, value);
},
onTaskChange(data, key) {
console.log(data, key)
this.setDataByKey(key, data);
},
onImageChange(image) {
console.log('image', image)
this.setData({
image
})
}, },
onTimeChange(timeRange, error) { onTimeChange(timeRange, error) {
const { formState } = this.data; const { formState } = this.data;
...@@ -201,6 +242,7 @@ Component({ ...@@ -201,6 +242,7 @@ Component({
const _this = this; const _this = this;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
validator.validate(data, (errors, fields) => { validator.validate(data, (errors, fields) => {
console.log(errors, fields)
const { formState } = _this.data; const { formState } = _this.data;
_this.setFormTips(formState, errors, target) _this.setFormTips(formState, errors, target)
if(errors) { if(errors) {
...@@ -236,18 +278,6 @@ Component({ ...@@ -236,18 +278,6 @@ Component({
}, },
// 提交信息 // 提交信息
async onSubmit() { async onSubmit() {
const {
id,
activityId,
startTime,
endTime,
rule,
prizeInfoList,
joinTimesEveryday,
joinNeedCredits
} = this.data;
console.log(this.data)
const isValidForm = await this.validateForm(this.data); const isValidForm = await this.validateForm(this.data);
...@@ -255,55 +285,6 @@ Component({ ...@@ -255,55 +285,6 @@ Component({
console.log('成功') console.log('成功')
return;
if (!prizeInfoList.length) {
this.setDataTips('prizeTipsInfo', 'error', '请至少添加一个奖品配置')
}
if (prizeInfoList.length) {
let totalPercent = prizeInfoList.reduce((total, next) => {
return total = addFloat(total, +next.probablity)
}, 0)
if (totalPercent > 100) {
this.setDataTips('prizeTipsInfo', 'error', '奖品的中奖概率相加不能超过100')
} else {
this.setDataTips('prizeTipsInfo', 'success', '')
}
}
if (joinTimesEveryday !== '' && joinTimesEveryday >= 0 && joinTimesEveryday <= 99 && Number.isInteger(+joinTimesEveryday)) {
this.setDataTips('joinTimesEverydayTipsInfo', 'success', '')
} else {
this.setDataTips('joinTimesEverydayTipsInfo', 'error', '请输入正确的每日可参与次数(0-99)')
}
if (joinNeedCredits !== '' && joinNeedCredits > 0 && joinNeedCredits <= 999 && Number.isInteger(+joinNeedCredits)) {
this.setDataTips('joinNeedCreditsTipsInfo', 'success', '')
} else {
this.setDataTips('joinNeedCreditsTipsInfo', 'error', '请输入正确的购买盲盒消耗积分(1-999)')
}
this.setData({
ruleTipsInfo: !rule
})
const {
prizeTipsInfo,
ruleTipsInfo,
timeRangeTipInfo,
joinTimesEverydayTipsInfo,
joinNeedCreditsTipsInfo
} = this.data
if (
prizeTipsInfo.status === "error" ||
ruleTipsInfo ||
timeRangeTipInfo.status === 'error' ||
joinTimesEverydayTipsInfo.status === 'error' ||
joinNeedCreditsTipsInfo.status === 'error'
) {
this.showFailToast('请检查信息是否全部填写正确')
return
} else {
const params = this.formatActivityParams(this.data) const params = this.formatActivityParams(this.data)
...@@ -317,7 +298,6 @@ Component({ ...@@ -317,7 +298,6 @@ Component({
}).catch(err => { }).catch(err => {
console.log(err) console.log(err)
}) })
}
}, },
showFailToast(text) { showFailToast(text) {
my.showToast({ my.showToast({
...@@ -326,21 +306,60 @@ Component({ ...@@ -326,21 +306,60 @@ Component({
}) })
}, },
// 格式化参数 // 格式化参数
formatActivityParams({ formatActivityParams(params) {
const {
id,
activityId, activityId,
startTime, startTime,
endTime, endTime,
rule, rule,
joinTimesEveryday, prizeInfoList,
joinNeedCredits, taskList,
prizeInfoList taskMap,
}) { commandTitle,
commandImg,
beenInvitedText,
} = params;
return {
activityId,
startTime: new Date(startTime).getTime(),
endTime: new Date(endTime).getTime(),
rule,
prizeInfoList: this.formatPobalityPrizeList(prizeInfoList),
taskList: this.formatTaskMapToList(taskMap),
commandTitle,
commandImg,
beenInvitedText
}
},
// taskMap转化taskList
formatTaskMapToList(taskMap) {
let list = [];
Object.keys(taskMap).forEach(type => {
let task = {
type,
...taskMap[type]
}
list.push(task)
});
return list;
},
// taskList转化taskMap
formatTaskListToMap(taskList) {
let taskMap = {};
taskList.forEach(task => {
taskMap[task[type]] = task;
});
return taskMap
},
// 补足谢谢参与类型 // 补足谢谢参与类型
formatPobalityPrizeList(prizeInfoList = []) {
let totalPercent = prizeInfoList.reduce((total, next) => { let totalPercent = prizeInfoList.reduce((total, next) => {
return total = addFloat(total, +next.probablity) return total = addFloat(total, +next.probablity)
}, 0) }, 0)
let prizeInfoListCopy = prizeInfoList.concat() let prizeInfoListCopy = prizeInfoList.concat().map((v, index) => ({ ...v, level: index }));
if (totalPercent < 100) { if (totalPercent < 100) {
let thanksType = { let thanksType = {
...@@ -350,15 +369,7 @@ Component({ ...@@ -350,15 +369,7 @@ Component({
} }
prizeInfoListCopy.push(thanksType) prizeInfoListCopy.push(thanksType)
} }
return { return prizeInfoListCopy
activityId,
startTime: new Date(startTime).getTime(),
endTime: new Date(endTime).getTime(),
rule,
prizeInfoList: prizeInfoListCopy.map((v, index) => ({ ...v, level: index })),
joinTimesEveryday,
joinNeedCredits
}
}, },
cancelEdit() { cancelEdit() {
this.backList() this.backList()
...@@ -426,24 +437,6 @@ Component({ ...@@ -426,24 +437,6 @@ Component({
}, },
backList() { backList() {
this.$page.$router.push("/activity/list"); this.$page.$router.push("/activity/list");
},
// 更新奖品名次
onUpdateLevel(data, type) {
let dataSourceCopy
if (type || type === 0) {
dataSourceCopy = this.data.prizeInfoList.reduce((s, i, index) => {
if (index === type) {
return s = [...s, data]
} else {
return s = [...s, i]
}
}, [])
} else {
dataSourceCopy = [].concat(this.data.prizeInfoList, data)
}
this.setData({
prizeInfoList: dataSourceCopy
})
} }
}, },
}) })
\ No newline at end of file
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
"rank-config": "/components/rank/rank-config/rank-config", "rank-config": "/components/rank/rank-config/rank-config",
"rank-table": "/components/rank/rank-table/rank-table", "rank-table": "/components/rank/rank-table/rank-table",
"task-config": "/components/task/task-config/task-config", "task-config": "/components/task/task-config/task-config",
"tb-image-upload": "/components/form/tb-image-upload/tb-image-upload" "tb-image-upload": "/components/form/tb-image-upload/tb-image-upload",
"items-config": "/components/task/items-config/items-config"
} }
} }
\ No newline at end of file
import { TASK_RATE_TYPE } from '../const'
export const descriptor = { export const descriptor = {
title: { title: {
required: true, required: true,
...@@ -16,17 +19,74 @@ export const descriptor = { ...@@ -16,17 +19,74 @@ export const descriptor = {
}, },
timeRange: { timeRange: {
required: true required: true
},
image: {
required: true,
message: "请上传正确的图片"
},
taskMap: {
type: 'object',
required: true,
fields: {
attentionStore: {
validator: (rule, val) => {
return !!val.value
},
message: '请输入关注店铺任务的奖励'
},
beMembership: {
validator: (rule, val) => !!val.value,
message: '请输入成为会员任务的奖励'
},
sign: {
validator: (rule, val) => !!val.value,
message: '请输入签到任务的奖励'
},
inviteFriends: {
validator: (rule, val) => !!(val.title && val.value),
message: '请输入邀请任务'
},
jumpLink: {
validator: (rule, val) => {
return !!(val.title && val.value && val.link);
},
message: '请输入浏览指定页面任务'
},
browseGoods: {
validator: (rule, val) => {
return !!(val.title && val.value && val.link);
},
message: '请输入寻宝屋商品任务'
},
exchangeCredits: {
validator: (rule, val) => {
return !!(val.value && val.times);
},
message: '请输入兑换次数任务'
}
}
} }
}; };
export const formatValidator = descriptor => {
const validators = {} export const formatValidator = (descriptor, validators) => {
validators = validators || {}
Object.keys(descriptor).forEach(key => { Object.keys(descriptor).forEach(key => {
if(descriptor[key].fields) {
Object.keys(descriptor[key].fields).forEach(fieldKey => {
validators[`${key}.${fieldKey}`] = {
status: 'success',
message: ''
}
})
} else {
validators[key] = { validators[key] = {
status: 'success', status: 'success',
message: '' message: ''
} }
}
}); });
return validators return validators
} }
\ No newline at end of file
...@@ -17,6 +17,7 @@ export const descriptor = { ...@@ -17,6 +17,7 @@ export const descriptor = {
export const formatValidator = descriptor => { export const formatValidator = descriptor => {
const validators = {} const validators = {}
Object.keys(descriptor).forEach(key => { Object.keys(descriptor).forEach(key => {
validators[key] = { validators[key] = {
status: 'success', status: 'success',
......
export const activityType = 2;
\ No newline at end of file //任务频率类型常量
export const TASK_RATE_TYPE = {
FOREVER: 1,
EVERYDAY: 2,
NOLIMIT: 3,
};
\ No newline at end of file
{
"runtime": "nodejs8",
"version": "1.0"
}
\ No newline at end of file
const ACTIVITY_BASE_CONFIG = "b_activity_config";
const ACTIVITY_PRIZE_CONFIG = "b_prize_config";
const ACTIVITY_SELLER_SAVE = "a_seller_info";
const ACTIVITY_INSTANCE = "miniapp_instantiate";
const USER_PRIZE = "c_awards_info";
const USER_INFO = "c_user"
module.exports = {
ACTIVITY_BASE_CONFIG,
ACTIVITY_PRIZE_CONFIG,
ACTIVITY_SELLER_SAVE,
ACTIVITY_INSTANCE,
USER_PRIZE,
USER_INFO
};
// const {
// formatTime
// } = require('../utils/utils');
// const secret = '99f00e460bfae520f85ae5f5a38e5b4a';
// const appKey = 28640163;
const getSellerInfoByContext = (context) => {
return {
// timestamp: formatTime(new Date(), "yyyy-MM-dd hh:mm:ss"),
// open_id: context.openId,
// 'appkey': appKey,
// 'appsecret': secret,
session: context.accessToken,
// REST_URL: 'http://gw.api.taobao.com/router/rest'
};
};
const getConsumerSeller = ({ accessToken, openId }) => {
return {
// timestamp: formatTime(new Date(), "yyyy-MM-dd hh:mm:ss"),
open_id: openId,
// 'appkey': appKey,
// 'appsecret': secret,
session: accessToken,
// REST_URL: 'http://gw.api.taobao.com/router/rest'
};
};
module.exports = {
getSellerInfoByContext,
getConsumerSeller,
};
const ActivityConfigService = require("../service/activityconfig.service");
const {
CODE_TYPES,
TASK_CHECK_TYPE,
TASK_TYPE_CHINA,
} = require("../utils/constants");
const ResultsModel = require("../utils/results.model");
let resultsModel = new ResultsModel();
const { DELETE_STATUS } = require("../utils/constants");
const ActivitySellerService = require("../service/activityseller.service");
let ActivityTopService = require("../service/activitytop.service");
let ActivityInstanceService = require("../service/activityinstance.service");
const { loginfo, passUrlList } = require("../utils/utils");
const regTestFn = (value, reg) => {
return reg.test(value);
};
const getIds = (data) => {
return data.reduce((s, v) => {
if (v._id) {
s = [...s, v._id];
}
return s;
}, []);
};
const urlCheck = (link, passUrlList) => {
if (!link.startsWith("http://") && !link.startsWith("https://")) {
return {
status: false,
message: "页面链接必须以https://或http://开头",
};
}
let passUrl = false;
passUrlList.some((i) => {
if (~link.indexOf(i)) {
passUrl = true;
return true;
}
return false;
});
if (!passUrl)
return {
status: false,
message: "域名校验不通过",
};
return {
status: true,
message: "",
};
};
//openId获取活动列表
const getActivityListByOpenId = async function (context) {
loginfo(context, "getActivityListByOpenId");
const { openId } = context;
let ActivityConfig = new ActivityConfigService(context);
let ActivityInstance = new ActivityInstanceService(context);
let ActivitySeller = new ActivitySellerService(context);
try {
let sellInfo = await ActivitySeller.findSellerInfo(openId);
console.log(sellInfo, "sellInfo");
if (sellInfo && sellInfo[0]) {
let result = await ActivityConfig.getActivityListByOpenId(
sellInfo && sellInfo[0].shopId,
context.data
);
let instanceInfo = await ActivityInstance.getMiniAppInstanceInfo(
context.openId
);
if (result) {
result.list.map((item) => {
item.activityId = item._id;
item.onlineUrl =
instanceInfo && instanceInfo[0] ? instanceInfo[0].online_url : "";
return item;
});
return resultsModel.success(result);
}
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, "查询活动列表失败");
} else {
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, "小程序未授权");
}
} catch (e) {
console.log("catch", "查询活动列表失败");
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, "查询活动列表失败");
}
};
//保存或编辑活动信息
const saveActivityInfoByHasId = async function (context) {
loginfo(context, "saveActivityInfoByHasId");
let ActivityConfig = new ActivityConfigService(context);
let ActivityTop = new ActivityTopService(context);
let nowTime = Date.now();
const { openId } = context;
let {
title,
subtitle,
activityId = "",
startTime,
endTime,
rule,
logoImg,
prizeInfoList = [],
taskList = [],
commandTitle,
beenInvitedText,
commandImg,
} = context.data;
let initialData;
if (activityId) {
initialData = await ActivityConfig.getActivityInfoByActivityId(activityId);
}
if (!title) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, "活动名称为空");
} else if (title.length > 12) {
return resultsModel.error(
CODE_TYPES.PARAMS_ERROR,
"活动名称不可超过12个字"
);
}
if (!subtitle) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, "活动副标题为空");
} else if (subtitle.length > 16) {
return resultsModel.error(
CODE_TYPES.PARAMS_ERROR,
"活动副标题不可超过16个字"
);
}
if (!logoImg) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, "logo图片必须配置");
}
if (!commandTitle) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, "邀请者淘口令必须配置");
}
if (!beenInvitedText) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, "被邀请者文案必须配置");
}
if (!commandImg) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, "淘口令图片必须配置");
}
if (taskList.length === 0) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, "任务配置必须配置一项");
} else {
let canPassTask = { status: true, message: "" };
taskList = taskList.map((i) => {
if (TASK_CHECK_TYPE.link.list.includes(i.type)) {
if (canPassTask.status) {
canPassTask = urlCheck(i.link, passUrlList);
}
}
if (TASK_CHECK_TYPE.itemIds.list.includes(i.type)) {
if (!i.itemIds) {
canPassTask = {
status: false,
message: TASK_TYPE_CHINA[i.type] + "必须配置",
};
}
}
if (TASK_CHECK_TYPE.value.list.includes(i.type)) {
if (!i.value) {
canPassTask = {
status: false,
message: TASK_TYPE_CHINA[i.type] + "任务值必须配置",
};
}
if (!regTestFn(i.value, TASK_CHECK_TYPE.value.reg)) {
canPassTask = {
status: false,
message:
TASK_TYPE_CHINA[i.type] +
"任务值在" +
TASK_CHECK_TYPE.value.regName,
};
}
}
if (TASK_CHECK_TYPE.times.list.includes(i.type)) {
if (!i.times) {
canPassTask = {
status: false,
message: TASK_TYPE_CHINA[i.type] + "任务次数必须配置",
};
}
}
if (TASK_CHECK_TYPE.title.list.includes(i.type)) {
if (!i.title) {
canPassTask = {
status: false,
message: TASK_TYPE_CHINA[i.type] + "任务标题必须配置",
};
}
}
if (TASK_CHECK_TYPE.taskRateType.list.includes(i.type)) {
if (!i.taskRateType) {
canPassTask = {
status: false,
message: TASK_TYPE_CHINA[i.type] + "任务类型必须配置",
};
}
}
i.value = +i.value;
i.times = +i.times || "";
i.taskRateType = +i.taskRateType || "";
return i;
});
if (!canPassTask.status)
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, canPassTask.message);
}
if (prizeInfoList.length === 0) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, "请配置排行榜奖品");
} else if (prizeInfoList.length > 8) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, "奖品最多配置8个档位");
} else {
let canPassPrize = { status: true, message: "" };
prizeInfoList.forEach((item) => {
if (!item.ename || !item.rank) {
canPassPrize.status = false;
canPassPrize.message = "奖品配置参数缺失";
}
});
let maxRank = ~prizeInfoList[prizeInfoList.length - 1].rank.indexOf("-")
? prizeInfoList[prizeInfoList.length - 1].rank.split("-")[1]
: prizeInfoList[prizeInfoList.length - 1].rank;
if (maxRank > 100)
canPassPrize = { status: false, message: "奖品排名配置不可超过100" };
if (!canPassPrize.status) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, canPassPrize.message);
}
}
if (!rule) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, "活动规则不可为空");
}
if (!startTime || !endTime) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, "请配置活动时间");
} else if (!activityId && startTime < Date.now()) {
return resultsModel.error(
CODE_TYPES.PARAMS_ERROR,
"新建活动开始时间需小于当前时间"
);
} else if (startTime > endTime) {
return resultsModel.error(
CODE_TYPES.PARAMS_ERROR,
"开始时间不得大于结束时间"
);
} else if (
activityId &&
+initialData.baseConfig.startTime <= nowTime &&
nowTime <= +initialData.baseConfig.endTime
) {
if (+startTime !== +initialData.baseConfig.startTime) {
return resultsModel.error(
CODE_TYPES.PARAMS_ERROR,
"活动开始后不可更改活动开始时间"
);
}
}
let shopInfoResult = await ActivityTop.getShopId();
if (!shopInfoResult.success) {
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, "获取淘宝店铺信息失败");
}
console.log(shopInfoResult, "shopInfo");
const baseData = {
title,
subtitle,
startTime,
endTime,
rule,
shopId: shopInfoResult.data.sid,
openId,
beenInvitedText,
commandTitle,
commandImg,
logoImg,
taskList,
};
prizeInfoList = prizeInfoList.map((v, i) => {
return { ...v, level: i + 1 };
});
let result;
let allPrizeList = prizeInfoList;
try {
if (!activityId) {
result = await ActivityConfig.saveNewActivity(
baseData,
prizeInfoList,
openId
);
} else {
result = await ActivityConfig.updateBaseConfigInfo(activityId, baseData);
let allNewIds = getIds(allPrizeList);
let oldPrizeList = await ActivityConfig.getAllOldPrizeList(activityId);
let oldIds = getIds(oldPrizeList);
let deleteIds = [];
let bothIds = oldIds.reduce((s, i) => {
if (allNewIds.includes(i)) {
s = [...s, i];
} else {
deleteIds.push(i);
}
return s;
}, []);
for (let i = 0; i < deleteIds.length; i++) {
result = await ActivityConfig.updateDeleteStatusById(deleteIds[i]);
}
for (let i = 0; i < allPrizeList.length; i++) {
if (!allPrizeList[i]._id) {
result = await ActivityConfig.insertPrizeByActivityId(
activityId,
allPrizeList[i]
);
} else if (bothIds.includes(allPrizeList[i]._id)) {
result = await ActivityConfig.updateOnePrizeById(
allPrizeList[i]._id,
allPrizeList[i]
);
}
}
}
if (result || result === 0) {
return resultsModel.success(true);
} else {
console.log(result, "保存活动失败");
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, "保存活动失败");
}
} catch (e) {
console.log(e, "保存活动失败");
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, "保存活动失败");
}
};
//删除活动
const deleteActivityById = async function (context) {
loginfo(context, "deleteActivityById");
let ActivityConfig = new ActivityConfigService(context);
const { activityId = "" } = context.data;
try {
if (activityId) {
let result = await ActivityConfig.deleteActivityByActivityId(activityId);
if (result === 0 || result) {
return resultsModel.success(true);
} else {
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, "删除活动失败");
}
} else {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, "删除活动id不存在");
}
} catch (e) {
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, "删除活动失败");
}
};
//获取活动信息
const getActivityInfo = async function (context) {
loginfo(context, "getActivityInfoByActivityId");
let ActivityConfig = new ActivityConfigService(context);
const { activityId = "" } = context.data;
try {
if (activityId) {
let result = await ActivityConfig.getActivityInfoByActivityId(activityId);
let prizeInfoList = result.prizeConfig;
let activityInfo = {
activityId,
...result.baseConfig,
prizeInfoList,
};
return resultsModel.success(activityInfo);
} else {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, "当前活动不存在");
}
} catch (e) {
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, "获取活动配置信息失败");
}
};
module.exports = {
getActivityListByOpenId,
saveActivityInfoByHasId,
deleteActivityById,
getActivityInfo,
};
const {
formatTime
} = require('../utils/utils');
const {
CODE_TYPES,
EIGHT_HOURS
} = require('../utils/constants');
const ResultsModel = require('../utils/results.model');
let resultsModel = new ResultsModel();
//生成规则
module.exports = async (context) => {
console.log(JSON.stringify(context.data), 'context.data')
let {
title = '', startTime = '', endTime = '', prizeInfoList = []
} = context.data;
if (!title) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '活动名称为空');
} else if (title.length > 12) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '活动名称不可超过12个字');
}
if (!startTime || !endTime) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '请配置活动时间');
} else if (startTime > endTime) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '开始时间不得大于结束时间');
}
if (prizeInfoList.length === 0) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '奖品至少配置3名');
} else if (prizeInfoList.length > 8) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '奖品最多配置8个档位');
} else {
let canPassPrize = true;
prizeInfoList.forEach(item => {
if (!item.ename || !item.rank) {
canPassPrize = false;
}
})
if (!canPassPrize) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '奖品配置不正确');
}
}
let resultRule = '';
let startTimeDate = formatTime(new Date(+startTime + EIGHT_HOURS), "yyyy-MM-dd hh:mm:ss");
let endTimeDate = formatTime(new Date(+endTime + EIGHT_HOURS), "yyyy-MM-dd hh:mm:ss");
resultRule = `1.活动时间:${startTimeDate}--${endTimeDate};\n2.活动结束根据排行榜排名获得对应的奖励,每个人取活动中单局最高分;\n3.每天3次免费参与资格,超过次数后邀请群内好友参与游戏可获得额外次数(每个用户可助力一次);\n4.参与签到可获得道具,每局结束游戏后可使用道具;\n5.完成任务每天可获得额外的复活机会,每局只能使用一张复活卡;\n\n`
let prizeStr = prizeInfoList.reduce((s, v) => {
let rankArr = v.rank.split('-');
if (rankArr[0] == rankArr[1]) {
return s += `第${rankArr[0]}名: ${v.name}\n`
} else {
return s += `第${v.rank}名: ${v.name}\n`
}
}, '奖品:\n')
resultRule += prizeStr;
return resultsModel.success(resultRule);
}
\ No newline at end of file
const {
loginfo
} = require('../utils/utils');
const {
CODE_TYPES
} = require('../utils/constants');
const ResultsModel = require('../utils/results.model');
let resultsModel = new ResultsModel();
const ActivityTopService = require('../service/activitytop.service');
//通过状态获取top商品列表
const findItemListByStatusAction = async function (context) {
loginfo(context, 'findItemListByStatus');
let ActivityTop = new ActivityTopService(context);
try {
let result = await ActivityTop.getItemListByStatus();
return result;
} catch (e) {
console.log(e, '获取top商品列表失败')
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, '获取top商品列表失败');
}
}
//通过itemIds获取商品列表
const findItemListByIdsAction = async (context) => {
loginfo(context, 'findItemListByIdsAction');
let ActivityTop = new ActivityTopService(context);
try {
let result = ActivityTop.getItemListByIds();
return result;
} catch (e) {
console.log(e, '获取商品列表失败')
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, '获取商品列表失败');
}
}
//通过ename获取权益信息
const getBenefitByEname = async (context) => {
loginfo(context, 'getBenefitByEname');
let ActivityTop = new ActivityTopService(context);
try {
let result = await ActivityTop.getPrizeByEname();
return result;
} catch (e) {
console.log(e, '获取ename权益信息失败')
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, '获取ename权益信息失败');
}
}
//测试getTemplateInstantiate
const getTemplateInstantiate = async (context) => {
loginfo(context, 'getTemplateInstantiate');
let ActivityTop = new ActivityTopService(context);
try {
let result = await ActivityTop.getTemplateInstantiate();
return result;
} catch (e) {
console.log(e, '获取getTemplateInstantiate失败')
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, '获取getTemplateInstantiate失败');
}
}
module.exports = {
findItemListByIdsAction,
findItemListByStatusAction,
getBenefitByEname,
getTemplateInstantiate
}
\ No newline at end of file
const ActivitySellerService = require("../service/activityseller.service");
const { CODE_TYPES, TEMPLATE_INFO } = require("../utils/constants");
const ActivityTopService = require("../service/activitytop.service");
const ActivityInstanceService = require("../service/activityinstance.service");
const { loginfo } = require("../utils/utils");
const ResultsModel = require("../utils/results.model");
let resultsModel = new ResultsModel();
//保存授权信息
module.exports = async (context) => {
loginfo(context, "sellerInfo");
const {
openId,
accessToken,
appKey,
userNick,
appOwnerOpenId,
consumeMiniAppId,
} = context;
let ActivitySeller = new ActivitySellerService(context);
let ActivityTop = new ActivityTopService(context);
let ActivityInstance = new ActivityInstanceService(context);
try {
let hasResult = await ActivitySeller.findSellerInfo(context.openId);
let instanceOldInfo = await ActivityInstance.getMiniAppInstanceInfo(
context.openId
);
console.log(instanceOldInfo, "insabsajs");
if (!instanceOldInfo || !instanceOldInfo[0]) {
let instanceInfo = await ActivityTop.getTemplateInstantiate();
console.log(instanceInfo, "instanceInfo");
const { app_id, app_version } = instanceInfo;
if (instanceInfo) {
let onlineInstance = await ActivityTop.pushOnlineInstance({
app_id,
app_version,
});
console.log(
onlineInstance,
"onlineInstance",
onlineInstance.online_results
);
await ActivityInstance.saveInstanceInfo({
...instanceInfo,
clients: onlineInstance.online_results.miniapp_instance_app_online_dto.reduce(
(s, v) => {
return (s += v.client + ",");
},
""
),
...onlineInstance.app_info,
accessToken,
template_version: TEMPLATE_INFO.template_version,
openId,
appKey,
consumeMiniAppId,
userNick,
appOwnerOpenId,
});
} else {
return resultsModel.error(
CODE_TYPES.SYSTEM_ERROR,
"获取实例化信息失败"
);
}
} else {
console.log(instanceOldInfo[0]);
if (
TEMPLATE_INFO.template_version !== instanceOldInfo[0].template_version
) {
const { clients, app_id, template_id } = instanceOldInfo[0];
let updateInfo = {
clients,
app_id,
template_id,
ext_json: {
name: "online",
},
template_version: TEMPLATE_INFO.template_version,
};
let updateInstanceInfo = await ActivityTop.updateMiniInstance(
updateInfo
);
let onlineInstance = await ActivityTop.pushOnlineInstance({
app_id: updateInstanceInfo.app_id,
app_version: updateInstanceInfo.app_version,
});
await ActivityInstance.updateInstanceInfo({
template_version: TEMPLATE_INFO.template_version,
...onlineInstance.app_info,
});
}
}
if (hasResult && hasResult[0]) {
await ActivitySeller.updateSellerInfo(context.openId, {
accessToken,
});
await ActivityInstance.updateInstanceInfo(context.openId, {
accessToken,
});
return resultsModel.success(true);
} else {
let shopInfoResult = await ActivityTop.getShopId();
if (!shopInfoResult.success) {
return resultsModel.error(
CODE_TYPES.SYSTEM_ERROR,
"获取淘宝店铺信息失败"
);
}
try {
let result = await ActivitySeller.saveSellerInfo({
accessToken,
openId,
appKey,
shopId: shopInfoResult.data.sid,
userNick,
appOwnerOpenId,
});
return resultsModel.success(result);
} catch (e) {
console.log(e, "保存授权信息失败");
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, "保存授权信息失败");
}
}
} catch (e) {
console.log(e, "获取授权信息失败");
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, "获取授权信息失败");
}
};
/**
* 中奖名单 及导出中奖名单
*/
const RankopenprizeService = require('../service/rankopenprize.service');
const ResultsModel = require('../utils/results.model');
const {
CODE_TYPES
} = require('../utils/constants');
const xlsx = require('node-xlsx');
let resultsModel = new ResultsModel();
// 活动中奖名单
const findWinnerInfoList = async (context) => {
let {
activityId
} = context.data;
if (!activityId) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, `缺少activityId`);
}
let rankopenprizeService = new RankopenprizeService(context);
// 获取活动中奖列表
let awardslist = await rankopenprizeService.getAwardslistByActivityId(activityId);
console.log(`awardslist: ${JSON.stringify(awardslist)}`);
let winnersObj = {};
awardslist.forEach((v, index, arr) => {
if (!winnersObj[v.rank]) {
winnersObj[v.rank] = [];
}
winnersObj[v.rank].push({
userNick: v.userNick,
id: v.openId
});
});
console.log(`winnersObj: ${JSON.stringify(winnersObj)}`);
let results = [];
new Map(Object.entries(winnersObj)).forEach((v, index, arr) => {
results.push({
rank: index,
winnerDetailList: v
});
});
return resultsModel.success(results);
}
// 导出活动中奖名单
const exportAwardsList = async (context) => {
let {
cloud
} = context;
let {
activityId,
title
} = context.data;
if (!activityId) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, `缺少activityId`);
}
if (!title) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, `缺少title`);
}
let rankopenprizeService = new RankopenprizeService(context);
// 获取活动中奖列表
let awardslist = await rankopenprizeService.getAwardslistByActivityId(activityId);
console.log(`awardslist: ${JSON.stringify(awardslist)}`);
let xlsxData = [
['序列', '名次', '昵称', '中奖名称']
];
awardslist.forEach((v, index, arr) => {
xlsxData.push([index + 1, v.rank, v.userNick, v.prizeName]);
});
let buffer = xlsx.build([{
name: title + new Date().getTime(),
data: xlsxData
}]);
console.log(`xlsxData: ${JSON.stringify(xlsxData)}`);
try {
let result = await cloud.file.uploadFile({
fileContent: buffer,
fileName: title + new Date().getTime() + '.xlsx'
});
// result.url 需进行处理
if (result.url) {
result.url = result.url.replace('http', 'https').replace('-internal', '');
}
return resultsModel.success(result);
} catch (e) {
console.log('上传文件出错', e);
// 打印日志
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, `上传文件错误`);
}
}
module.exports = {
findWinnerInfoList,
exportAwardsList
}
\ No newline at end of file
const RankscanService = require("../service/activityconfig.service");
const ActivityprizeService = require("../service/activityprize.service");
const RankscoreService = require("../service/rankscore.service");
const RankopenprizeService = require("../service/rankopenprize.service");
const ResultsModel = require("../utils/results.model");
const { Utils, EIGHT_HOURS } = require("../utils/constants");
let resultsModel = new ResultsModel();
// 声明排行榜扫描服务
let rankscanService = null;
// 声明奖品服务
let activityprizeService = null;
// 声明分数排行榜服务
let rankscoreService = null;
// 声明待开奖服务
let rankopenprizeService = null;
// 查询该活动的奖品列表 及 发奖数
const getPrizeListAndAwards = async (activityId) => {
let prizeList = await activityprizeService.getPrizeListByActivityId(
activityId
);
console.log(prizeList);
// 若不存在奖品列表,则为脏数据,不做处理
if (!prizeList.length) {
console.log(`活动Id为${activityId}不存在对应的奖品信息`);
return {
prizeList: [],
totalAwards: 0,
};
}
// 获取总共发奖的个数
let totalAwards = prizeList.reduce((total, curVal, curIndex, arr) => {
// 当没有rank名次,直接返回
if (!curVal.rank) {
return total;
}
let awards = ~curVal.rank.indexOf("-")
? +curVal.rank.split("-")[1]
: +curVal.rank;
if (awards > total) {
total = awards;
}
return total;
}, 0);
return {
prizeList,
totalAwards,
};
};
// 获取待开奖列表
const getWaitAwardsList = (prizeList, topscoreList, totalAwards, shopId) => {
let waitAwardslist = [];
// 若分数排行榜没有数据,或发奖数为0,返回[]
if (!totalAwards || !topscoreList.length) {
return waitAwardslist;
}
prizeList.forEach((v, index, arr) => {
if (!v.rank) {
return;
}
let rankPeriod = ~v.rank.indexOf("-")
? v.rank.split("-")
: [v.rank, v.rank + 1];
// 截取排行区间的分数排行列表
let ranklist = topscoreList.slice(
+rankPeriod[0] - 1,
Math.min(+rankPeriod[1], totalAwards)
);
// 整合开奖数据
ranklist.map((rank) => {
waitAwardslist.push({
activityId: v.activityId,
openId: rank.openId,
rankRange: v.rank,
rank: rank.rank,
ename: v.ename,
startTime: v.startTime,
endTime: v.endTime,
prizeId: v._id,
prizeName: v.name,
userNick: rank.userNick,
rankTime: rank.updateTime,
image: v.image,
maxScore: rank.maxScore,
shopId: shopId,
type: v.type || "",
amount: v.amount || "",
createDay: Utils.default.dateFormatter(
new Date(Date.now() + EIGHT_HOURS),
"yyyy/MM/dd"
),
});
});
});
return waitAwardslist;
};
// 设置活动开奖
const setActivity2openprize = async (waitAwardslist, _id) => {
// 插入排行榜开奖记录表 rank_open_prize 若失败,则变更
let results = await rankopenprizeService.addWaitAwardsList(waitAwardslist);
console.log(`result: ${JSON.stringify(results)}`);
if (results) {
await rankscanService.update2Success(_id);
console.log(`开奖成功`);
return true;
} else {
await rankscanService.update2Fail(_id, `批量插入rank_open_prize表不成功`);
console.log(`开奖失败`);
return false;
}
};
/**
* 定时触发开奖
*/
const endingNotify = async (context) => {
// 初始化排行榜扫描服务
rankscanService = new RankscanService(context);
// 初始化返回结果
let results = {
success: [],
fails: [],
};
// 获取服务器时间
let serverTime = Date.now();
// 触发开奖列表
let notifyList = await rankscanService.getNodifyList(serverTime);
console.log(notifyList.length);
if (!notifyList.length) {
console.log(`没有待开奖的活动`);
return resultsModel.success(results);
}
// 初始化奖品服务
activityprizeService = new ActivityprizeService(context);
// 分数排行榜
rankscoreService = new RankscoreService(context);
// 待开奖服务
rankopenprizeService = new RankopenprizeService(context);
// 遍历列表
for (let i = 0; i < notifyList.length; i++) {
let { _id, shopId } = notifyList[i];
// 将该条记录变更为处理中
let updateResult = await rankscanService.update2Process(_id);
console.log(`updateResult: ${updateResult}`);
if (!updateResult) {
console.log(`将rank_scan该活动的开奖状态变更为处理中失败`);
continue;
}
// 查询该活动的奖品列表 及 发奖数
let { prizeList, totalAwards } = await getPrizeListAndAwards(_id);
// console.log(
// `prizeList: ${JSON.stringify(prizeList)}; totalAwards: ${totalAwards}`
// );
// 没查找到奖品列表, 继续下个活动循环
if (!prizeList.length) {
// 开奖失败,记录日志
await rankscanService.update2Fail(
_id,
`活动不存在对应的奖品列表,开奖失败`
);
results.fails.push(_id);
continue;
}
// 查找排行榜分数榜里的前totalAwards个记录
let topscoreList = await rankscoreService.getToplistByActivityId(
_id,
totalAwards
);
topscoreList = topscoreList.map((v, i) => {
return { ...v, rank: i + 1 };
});
console.log(`topscoreList: ${JSON.stringify(topscoreList)}`);
// 根据分数排行榜列表及奖品列表整合数据,待开奖列表
let waitAwardslist = getWaitAwardsList(
prizeList,
topscoreList,
totalAwards,
shopId
);
// if (!waitAwardslist.length) {
// }
console.log(`waitAwardslist: ${JSON.stringify(waitAwardslist)}`);
// 开奖
let issuccess = await setActivity2openprize(waitAwardslist, _id);
issuccess ? results.success.push(_id) : results.fails.push(_id);
// end
}
return resultsModel.success(results);
};
module.exports = {
endingNotify,
};
const { BaseDao } = require("../utils/constants");
module.exports = BaseDao;
const { endingNotify } = require("./controller/endingNodify.controller");
const {
findWinnerInfoList,
exportAwardsList,
} = require("./controller/awards.controller");
const {
getActivityListByOpenId,
saveActivityInfoByHasId,
deleteActivityById,
getActivityInfo,
} = require("./controller/activity.controller");
const saveSellerInfo = require("./controller/activityseller.controller");
const generateRuleAction = require("./controller/activitygenerateRule.controller");
const {
findItemListByStatusAction,
findItemListByIdsAction,
getBenefitByEname,
} = require("./controller/activitygettbitem.controller");
// 定时开奖
exports.endingNotify = endingNotify;
// 活动中奖名单
exports.findWinnerInfoList = findWinnerInfoList;
// 导出中奖名单
exports.exportAwardsList = exportAwardsList;
exports.getActivityList = getActivityListByOpenId;
exports.saveActivityInfo = saveActivityInfoByHasId;
exports.delActivity = deleteActivityById;
exports.getActivityDetail = getActivityInfo;
exports.sellerSave = saveSellerInfo;
exports.generateRule = generateRuleAction;
exports.findItemListByStatus = findItemListByStatusAction;
exports.findItemListByIds = findItemListByIdsAction;
exports.queryBenefitByEname = getBenefitByEname;
{
"name": "duiba",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"adler-32": {
"version": "1.2.0",
"resolved": "https://registry.npm.taobao.org/adler-32/download/adler-32-1.2.0.tgz",
"integrity": "sha1-aj5r8KY5ALoVZSgIyxXGgT0aXyU=",
"requires": {
"exit-on-epipe": "~1.0.1",
"printj": "~1.1.0"
}
},
"buffer-from": {
"version": "1.1.1",
"resolved": "https://registry.npm.taobao.org/buffer-from/download/buffer-from-1.1.1.tgz",
"integrity": "sha1-MnE7wCj3XAL9txDXx7zsHyxgcO8="
},
"cfb": {
"version": "1.1.4",
"resolved": "https://registry.npm.taobao.org/cfb/download/cfb-1.1.4.tgz",
"integrity": "sha1-gf017eTJGdjwliqUWC4d+vcFHio=",
"requires": {
"adler-32": "~1.2.0",
"commander": "^2.16.0",
"crc-32": "~1.2.0",
"printj": "~1.1.2"
}
},
"codepage": {
"version": "1.14.0",
"resolved": "https://registry.npm.taobao.org/codepage/download/codepage-1.14.0.tgz",
"integrity": "sha1-jL4lSBMjVZ19MHVxsP/5HnodL5k=",
"requires": {
"commander": "~2.14.1",
"exit-on-epipe": "~1.0.1"
},
"dependencies": {
"commander": {
"version": "2.14.1",
"resolved": "https://registry.npm.taobao.org/commander/download/commander-2.14.1.tgz?cache=0&sync_timestamp=1592632075120&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcommander%2Fdownload%2Fcommander-2.14.1.tgz",
"integrity": "sha1-IjUSPjevjKPGXfRbAm29NXsBuao="
}
}
},
"commander": {
"version": "2.17.1",
"resolved": "https://registry.npm.taobao.org/commander/download/commander-2.17.1.tgz?cache=0&sync_timestamp=1592632075120&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcommander%2Fdownload%2Fcommander-2.17.1.tgz",
"integrity": "sha1-vXerfebelCBc6sxy8XFtKfIKd78="
},
"crc-32": {
"version": "1.2.0",
"resolved": "https://registry.npm.taobao.org/crc-32/download/crc-32-1.2.0.tgz",
"integrity": "sha1-yy224puIUI4y2d0OwWk+e0Ghggg=",
"requires": {
"exit-on-epipe": "~1.0.1",
"printj": "~1.1.0"
}
},
"exit-on-epipe": {
"version": "1.0.1",
"resolved": "https://registry.npm.taobao.org/exit-on-epipe/download/exit-on-epipe-1.0.1.tgz",
"integrity": "sha1-C92S6H1ShdJn2qgXHQ6wYVlolpI="
},
"frac": {
"version": "1.1.2",
"resolved": "https://registry.npm.taobao.org/frac/download/frac-1.1.2.tgz",
"integrity": "sha1-PXT39keMiKG1AgMG10fcYxPHTQs="
},
"node-xlsx": {
"version": "0.15.0",
"resolved": "https://registry.npm.taobao.org/node-xlsx/download/node-xlsx-0.15.0.tgz",
"integrity": "sha1-HxsNetzlxwboa/2WpaoABb+KncM=",
"requires": {
"buffer-from": "^1.1.0",
"xlsx": "^0.14.1"
}
},
"printj": {
"version": "1.1.2",
"resolved": "https://registry.npm.taobao.org/printj/download/printj-1.1.2.tgz",
"integrity": "sha1-2Q3rKXWoufYA+zoclOP0xTx4oiI="
},
"ssf": {
"version": "0.10.3",
"resolved": "https://registry.npm.taobao.org/ssf/download/ssf-0.10.3.tgz",
"integrity": "sha1-jq4fwpyQpVLnkhII+BiS1vd6yys=",
"requires": {
"frac": "~1.1.2"
}
},
"taobao-mini-sdk": {
"version": "git+http://luofangping@duiba.com.cn:duiba123@gitlab2.dui88.com/huhu/taobao-mini-sdk.git#7cde981223c800143ae99e1c200a3597b76713d1",
"from": "git+http://luofangping@duiba.com.cn:duiba123@gitlab2.dui88.com/huhu/taobao-mini-sdk.git"
},
"xlsx": {
"version": "0.14.5",
"resolved": "https://registry.npm.taobao.org/xlsx/download/xlsx-0.14.5.tgz?cache=0&sync_timestamp=1593422715008&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fxlsx%2Fdownload%2Fxlsx-0.14.5.tgz",
"integrity": "sha1-NjfpFNeRvcpzgoFuFz99cl7Q4NI=",
"requires": {
"adler-32": "~1.2.0",
"cfb": "^1.1.2",
"codepage": "~1.14.0",
"commander": "~2.17.1",
"crc-32": "~1.2.0",
"exit-on-epipe": "~1.0.1",
"ssf": "~0.10.2"
}
}
}
}
{
"name": "duiba",
"version": "1.0.0",
"description": "",
"main": "index.js",
"author": "",
"license": "ISC",
"sdkVersion": "*",
"dependencies": {
"node-xlsx": "^0.15.0",
"taobao-mini-sdk": "^0.1.2"
},
"config": {
"notNeedLogin": [
"endingNotify"
]
}
}
\ No newline at end of file
const BaseDao = require("../dao/base.dao");
const {
ACTIVITY_BASE_CONFIG,
ACTIVITY_PRIZE_CONFIG,
} = require("../config/db_config");
const { DELETE_STATUS, OPEN_PRIZE_STATUS } = require("../utils/constants");
module.exports = class ActivityConfigService {
constructor(context) {
this.activityconfigDao = new BaseDao(context, ACTIVITY_BASE_CONFIG);
this.activityconfigPrizeDao = new BaseDao(context, ACTIVITY_PRIZE_CONFIG);
}
//保存新建活动
async saveNewActivity(data, prize, openId) {
try {
let result = await this.activityconfigDao.insertOne({
...data,
createTime: Date.now(),
updateTime: Date.now(),
deleteStatus: DELETE_STATUS.EXIST,
openPrizeStatus: OPEN_PRIZE_STATUS.WAIT_AWARD,
});
console.log(result, "保存基础配置result");
if (result) {
try {
prize.map((item) => {
item.activityId = result;
item.openId = openId;
item.createTime = Date.now();
item.updateTime = Date.now();
item.deleteStatus = DELETE_STATUS.EXIST;
return item;
});
return await this.activityconfigPrizeDao.insertMany(prize);
} catch (e) {
console.log(e, "保存奖品配置出错");
// 如果奖品未保存删除之前的活动
await this.activityconfigDao.deleteMany({
_id: result,
});
}
}
} catch (e) {
//保存活动失败
console.log(e, "保存活动失败");
}
}
// 更新活动基本信息
async updateBaseConfigInfo(id, data) {
return await this.activityconfigDao.update(
{
_id: id,
},
{
$set: {
...data,
updateTime: Date.now(),
deleteStatus: DELETE_STATUS.EXIST,
},
}
);
}
// 通过id获取奖品信息
async getPrizeInfoById(id) {
let result = await this.activityconfigPrizeDao.find({
_id: id,
});
if (result && result[0]) {
return result[0];
}
return false;
}
// 奖品置为删除状态
async updateDeleteStatusById(id) {
return await this.activityconfigPrizeDao.update(
{
_id: id,
},
{
$set: {
deleteStatus: DELETE_STATUS.DELETE,
},
}
);
}
// 更新单条数据
async updateOnePrizeById(id, data) {
return await this.activityconfigPrizeDao.update(
{
_id: id,
},
{
$set: {
...data,
updateTime: Date.now(),
deleteStatus: DELETE_STATUS.EXIST,
},
}
);
}
// 插入单条奖品数据
async insertPrizeByActivityId(activityId, data) {
return await this.activityconfigPrizeDao.insertOne({
...data,
activityId,
createTime: Date.now(),
updateTime: Date.now(),
deleteStatus: DELETE_STATUS.EXIST,
});
}
// 获取奖品所有配置
async getAllOldPrizeList(activityId) {
return await this.activityconfigPrizeDao.find({
activityId,
});
}
//更新活动配置
async updateActivity(activityId, data, prizeNoId) {
console.log(
activityId,
data,
prizeNoId,
"activityId, data, prizeNoId, oldPrizeIds"
);
try {
let originalData = await this.activityconfigDao.findOne({
_id: activityId,
});
let result = await this.activityconfigDao.update(
{
_id: activityId,
},
{
$set: {
...data,
createTime: originalData.createTime,
updateTime: Date.now(),
},
}
);
if (result) {
try {
let prizeOldIdsByActivity = (
await this.activityconfigPrizeDao.find({
activityId,
})
).reduce((s, v) => {
return (s = [...s, v._id]);
}, []);
let prizeResult = await this.activityconfigPrizeDao.insertMany(
prizeNoId
);
if (prizeResult) {
//删除之前的奖品
let deleteOldPrizeList = prizeOldIdsByActivity.reduce((s, item) => {
return (s = [
...s,
this.activityconfigPrizeDao.deleteMany({
_id: item,
}),
]);
}, []);
return await Promise.all(deleteOldPrizeList);
}
} catch (e) {
await this.activityconfigDao.update(
{
_id: activityId,
},
{
$set: {
...originalData[0],
},
}
);
}
}
} catch (e) {
//更新失败
}
}
//通过openId去获取当前商家活动列表
async getActivityListByOpenId(shopId, { pageSize = 10, pageNo = 1 }) {
return {
list: await this.activityconfigDao.find(
{
shopId,
deleteStatus: DELETE_STATUS.EXIST,
},
{
projection: {
startTime: 1,
endTime: 1,
title: 1,
},
sort: {
createTime: -1,
},
limit: pageSize,
skip: (pageNo - 1) * pageSize,
}
),
total: await this.activityconfigDao.count({
shopId,
deleteStatus: DELETE_STATUS.EXIST,
}),
pageSize,
pageNo,
};
}
//通过activityId去获取活动配置信息
async getActivityInfoByActivityId(activityId) {
return {
baseConfig: await this.activityconfigDao.findOne(
{
_id: activityId,
deleteStatus: DELETE_STATUS.EXIST,
},
{
projection: {
commandImg: 1,
rule: 1,
taskList: 1,
title: 1,
logoImg: 1,
prizeInfoList: 1,
subtitle: 1,
commandTitle: 1,
startTime: 1,
endTime: 1,
beenInvitedText: 1,
},
}
),
prizeConfig: await this.activityconfigPrizeDao.find(
{
activityId,
deleteStatus: DELETE_STATUS.EXIST,
},
{
sort: {
level: 1,
},
}
),
};
}
//通过activityId去删除活动
async deleteActivityByActivityId(activityId) {
try {
let result = await this.activityconfigDao.update(
{
_id: activityId,
},
{
$set: {
deleteStatus: DELETE_STATUS.DELETE,
},
}
);
if (result) {
return await this.activityconfigPrizeDao.update(
{
activityId,
},
{
$set: {
deleteStatus: DELETE_STATUS.DELETE,
},
}
);
}
} catch (e) {
console.log(e, "删除活动失败");
}
}
// 查询待开奖列表
async getNodifyList(serverTime) {
let list = await this.activityconfigDao.find({
endTime: {
$lt: serverTime,
},
openPrizeStatus: {
$in: [OPEN_PRIZE_STATUS.WAIT_AWARD, OPEN_PRIZE_STATUS.FAIL],
},
deleteStatus: DELETE_STATUS.EXIST,
});
console.log(list);
return list;
}
// 更新openPrizeStatus为处理中
async update2Process(_id) {
try {
await this.activityconfigDao.update(
{
_id,
},
{
$set: {
openPrizeStatus: OPEN_PRIZE_STATUS.PROCESSING,
updateTime: Date.now(),
},
}
);
return true;
} catch (e) {
// 日志记录
console.log(e);
return false;
}
}
// 更新openPrizeStatus为成功
async update2Success(_id) {
try {
await this.activityconfigDao.update(
{
_id,
},
{
$set: {
openPrizeStatus: OPEN_PRIZE_STATUS.SUCCESS,
openPrizeMsg: "",
updateTime: Date.now(),
},
}
);
return true;
} catch (e) {
// 日志记录
console.log(e);
return false;
}
}
// 更新openPrizeStatus为失败
async update2Fail(_id, message) {
try {
await this.activityconfigDao.update(
{
_id,
},
{
$set: {
openPrizeStatus: OPEN_PRIZE_STATUS.FAIL,
openPrizeMsg: message || "",
updateTime: Date.now(),
},
}
);
return true;
} catch (e) {
// 日志记录
console.log(e);
return false;
}
}
};
const BaseDao = require('../dao/base.dao');
const {
ACTIVITY_INSTANCE
} = require('../config/db_config');
module.exports = class ActivitySellerService {
constructor(context) {
this.activityinstanceDao = new BaseDao(context, ACTIVITY_INSTANCE);
}
//保存商家授权信息
async saveInstanceInfo(instanceInfo) {
return await this.activityinstanceDao.insertOne({
...instanceInfo,
updateTime: Date.now(),
createTime: Date.now()
})
}
//查找商家授权信息
async findInstanceInfo(openId) {
return await this.activityinstanceDao.find({
openId
})
}
//更新商家授权信息
async updateInstanceInfo(openId, updateinfo) {
return await this.activityinstanceDao.update({
openId: openId
}, {
$set: {
...updateinfo,
updateTime: Date.now()
}
})
}
async getMiniAppInstanceInfo(openId) {
return await this.activityinstanceDao.find({
openId
})
}
}
\ No newline at end of file
const BaseDao = require("../dao/base.dao");
const { OPEN_PRIZE_STATUS, DELETE_STATUS } = require("../utils/constants");
const { ACTIVITY_PRIZE_CONFIG } = require("../config/db_config");
const DBName = ACTIVITY_PRIZE_CONFIG;
class ActivityprizeService {
constructor(context) {
this.activityprizeDao = new BaseDao(context, DBName);
}
// 根据活动id查询奖品列表
async getPrizeListByActivityId(activityId) {
console.log(13, activityId);
return await this.activityprizeDao.find({
activityId,
deleteStatus: DELETE_STATUS.EXIST,
});
}
}
module.exports = ActivityprizeService;
const BaseDao = require('../dao/base.dao');
const {
ACTIVITY_SELLER_SAVE
} = require('../config/db_config');
module.exports = class ActivitySellerService {
constructor(context) {
this.activitysellerDao = new BaseDao(context, ACTIVITY_SELLER_SAVE);
}
//保存商家授权信息
async saveSellerInfo(sellerInfo) {
return await this.activitysellerDao.insertOne({
...sellerInfo,
updateTime: Date.now(),
createTime: Date.now()
})
}
//查找商家授权信息
async findSellerInfo(openId) {
return await this.activitysellerDao.find({
openId
})
}
//更新商家授权信息
async updateSellerInfo(openId, sellerInfo) {
console.log(openId, sellerInfo, 'openId, sellerInfo')
return await this.activitysellerDao.update({
openId: openId
}, {
$set: {
...sellerInfo,
updateTime: Date.now()
}
})
}
}
\ No newline at end of file
const {
ACTIVITY_SELLER_SAVE,
ACTIVITY_BASE_CONFIG,
} = require("../config/db_config");
const {
getConsumerSeller,
getSellerInfoByContext,
} = require("../config/seller_config");
const {
CODE_TYPES,
GOODSINFO,
B_APP_NAME,
TEMPLATE_INFO,
TBAPIS,
} = require("../utils/constants");
const ResultsModel = require("../utils/results.model");
const { MathRand } = require("../utils/utils");
let resultsModel = new ResultsModel();
const BaseDao = require("../dao/base.dao");
class ActivityTopService {
constructor(context) {
this.activitySellerDao = new BaseDao(context, ACTIVITY_SELLER_SAVE);
this.activityBaseDao = new BaseDao(context, ACTIVITY_BASE_CONFIG);
this.context = context;
}
//获取商家授权session
async getAccessToken(activityId) {
let result = await this.activityBaseDao.find({
_id: activityId,
});
if (result[0]) {
let shopId = result[0].shopId;
let sellResult = await this.activitySellerDao.find(
{
shopId,
},
{
sort: {
createTime: 1,
},
}
);
console.log(sellResult, "sellResult");
if (sellResult[0]) {
let { accessToken } = sellResult[0];
return {
session: accessToken,
};
}
}
}
//通过openId去查找session
async getAccessTokenByOpenId() {
let openId = this.context.openId;
console.log(openId);
let result = await this.activitySellerDao.find({
openId,
});
console.log(result, "getAccessTokenByOpenId");
if (result[0]) {
let shopId = result[0].shopId;
let sellResult = await this.activitySellerDao.find(
{
shopId,
},
{
sort: {
createTime: 1,
},
}
);
console.log(sellResult, "sellResult");
if (sellResult[0]) {
let { accessToken } = sellResult[0];
return {
session: accessToken,
};
}
}
}
//淘宝top接口获取商品列表
async getItemListByIds(activityId, itemIds) {
let sellerConfig;
if (activityId) {
let businessSeller = await this.getAccessToken(activityId);
sellerConfig = getConsumerSeller(businessSeller);
} else {
sellerConfig = await this.getAccessTokenByOpenId();
itemIds = this.context.data.itemIds;
}
console.log(sellerConfig, "sellerConfig");
try {
let result = await TBAPIS.getItemListByItemIds(
this.context,
sellerConfig.session,
itemIds,
{ fields: GOODSINFO }
);
// let result = await this.context.cloud.topApi.invoke({
// api: "taobao.items.seller.list.get",
// data: {
// ...sellerConfig,
// fields: GOODSINFO,
// num_iids: itemIds,
// },
// });
// console.log(JSON.stringify(result), '获取商品通过ids')
if (result) {
let itemsData = {
list:
(result &&
result.items &&
result.items.item.reduce((s, v) => {
return (s = [
...s,
{
itemId: v.num_iid,
name: v.title,
price: v.price,
detailUrl: v.detail_url,
picUrl: v.pic_url,
},
]);
}, [])) ||
[],
totalCount: result.items.item.length,
};
return resultsModel.success(itemsData);
}
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, "获取商家ids列表失败");
} catch (e) {
console.log(e, "获取ids商品列表失败");
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, "获取商家ids列表失败");
}
}
//淘宝top接口获取权益商品信息
async getPrizeByEname(activityId, ename) {
let sellerConfig;
if (activityId) {
let businessSeller = await this.getAccessToken(activityId);
sellerConfig = getConsumerSeller(businessSeller);
} else {
sellerConfig = await this.getAccessTokenByOpenId();
ename = this.context.data.ename;
}
console.log(sellerConfig, "sellerConfig");
try {
let benefitData = await TBAPIS.getPrizeByEname(
this.context,
sellerConfig.session,
ename,
B_APP_NAME
);
console.log(benefitData, benefitData.result, "benefitData.result.");
if (benefitData.result.success) {
const { result } = benefitData;
let data =
result.datas &&
result.datas["oright_dto"].reduce((s, v) => {
return (s = [
...s,
{
benefitName: v.benefit_name,
rightTypeId: v.right_type_id,
startTime: new Date(v.start_date).getTime(),
endTime: new Date(v.end_date).getTime(),
amount: v.amount ? v.amount / 100 + "" : "",
},
]);
}, []);
console.log(JSON.stringify(result), "alibaba.benefit.query");
return resultsModel.success(data);
}
return resultsModel.error(
CODE_TYPES.SYSTEM_ERROR,
"获取ename商品信息失败"
);
} catch (e) {
console.log(e, "权益获取失败");
return resultsModel.error(
CODE_TYPES.SYSTEM_ERROR,
"获取ename商品信息失败"
);
}
}
//淘宝top接口获取店铺会员链接
async getVipUrlByActivity(activityId) {
let businessSeller = await this.getAccessToken(activityId);
let consumerSellerInfo = getConsumerSeller(businessSeller);
try {
let result = await this.context.cloud.topApi.invoke({
api: "taobao.crm.member.joinurl.get",
data: {
...consumerSellerInfo,
extra_info: {
source: "isvapp",
activityId: activityId,
entrance: "duiba",
},
},
});
if (result) {
return resultsModel.success(result);
}
console.log(JSON.stringify(result), "获取商家会员链接");
return resultsModel.error(
CODE_TYPES.SYSTEM_ERROR,
"获取商家会员链接失败"
);
} catch (e) {
console.log(e, "获取商家会员链接失败");
return resultsModel.error(
CODE_TYPES.SYSTEM_ERROR,
"获取商家会员链接失败"
);
}
}
//淘宝top接口获取店铺信息
async getShopId() {
let sellerInfo = await this.getAccessTokenByOpenId();
console.log(sellerInfo, "getShopId sellerInfo");
try {
let result = await TBAPIS.getShopInfo(this.context, {
session: sellerInfo.session,
fields: "sid,title,pic_path",
});
console.log(result, "getShopId result");
if (result) {
return resultsModel.success(result.shop);
} else {
return resultsModel.error(
CODE_TYPES.SYSTEM_ERROR,
"获取淘宝top店铺信息失败"
);
}
} catch (e) {
console.log(e, "获取店铺信息失败");
return resultsModel.error(
CODE_TYPES.SYSTEM_ERROR,
"获取淘宝top店铺信息失败"
);
}
}
async getItemListByStatus() {
let sellerConfig = await this.getAccessTokenByOpenId();
const {
approveStatus = "onsale",
title = "",
pageNo = 1,
pageSize = 10,
} = this.context.data;
let data = {
fields: GOODSINFO,
page_no: pageNo,
q: title,
page_size: pageSize,
...sellerConfig,
};
console.log(data, "data");
try {
let result =
approveStatus === "onsale"
? await TBAPIS.getItemListOnSale(this.context, data)
: await TBAPIS.getItemListInStock(this.context, data);
if (result) {
// console.log(
// JSON.stringify(result),
// `comming ${approveStatus}`,
// "success"
// );
let { items, total_results } = result;
let itemsData = {
pageNo,
pageSize,
totalPages: Math.ceil(total_results / pageSize),
totalCount: total_results,
list:
(items &&
items.item &&
items.item.reduce((s, v) => {
return (s = [
...s,
{
itemId: v.num_iid,
name: v.title,
price: v.price,
approveStatus: v.approveStatus || approveStatus,
picUrl: v.pic_url,
},
]);
}, [])) ||
[],
};
return resultsModel.success(itemsData);
}
return resultsModel.error(
CODE_TYPES.SYSTEM_ERROR,
"获取商家在售列表失败"
);
} catch (e) {
console.log(e, "获取商家在售列表失败");
return resultsModel.error(
CODE_TYPES.SYSTEM_ERROR,
"获取商家在售列表失败"
);
}
}
async getTemplateInstantiate() {
let sellerConfig = await this.getAccessTokenByOpenId();
let data = {
description:
"此应用用于商家引导活动,商家可设置对应的奖品,在一定时间 内出奖,提升店铺用户活跃以及引导购买",
ext_json: {
name: "online",
},
icon:
"https://ossgw.alicdn.com/taobao-miniapp/img/0193eaa9cc037b568acd9ccfe68a8499.jpg",
name: "店铺漂流" + MathRand(),
...TEMPLATE_INFO,
...sellerConfig,
};
console.log("getTemplateInstantiateParams", data);
try {
let result = await TBAPIS.getTemplateInstantiate(this.context, data);
if (result) {
console.log(JSON.stringify(result), "getTemplateInstantiate");
return result;
}
return false;
} catch (e) {
console.log(e, "获取getTemplateInstantiate失败");
return false;
}
}
//模板小程序上线
async pushOnlineInstance(instanceInfo) {
let sellerConfig = await this.getAccessTokenByOpenId();
let data = {
...TEMPLATE_INFO,
...instanceInfo,
...sellerConfig,
};
console.log("pushOnlineInstanceParams", data);
try {
let result = await TBAPIS.pushInstanceOnline(this.context, data);
if (result) {
console.log(JSON.stringify(result), "pushOnlineInstance");
return result;
}
return false;
} catch (e) {
console.log(e, "pushOnlineInstance失败");
return false;
}
}
//模板小程序更新
async updateMiniInstance(instanceInfo) {
let sellerConfig = await this.getAccessTokenByOpenId();
let data = {
...TEMPLATE_INFO,
...instanceInfo,
...sellerConfig,
};
try {
let result = await TBAPIS.updateMiniInstance(this.context, data);
if (result) {
console.log(JSON.stringify(result), "updateMiniInstance");
return result;
}
return false;
} catch (e) {
console.log(e, "updateMiniInstance失败");
return false;
}
}
}
module.exports = ActivityTopService;
// 排行榜开奖记录
const BaseDao = require("../dao/base.dao");
const { DRAW_STATUS } = require("../utils/constants");
const { USER_PRIZE } = require("../config/db_config");
const DBName = USER_PRIZE;
class RankopenprizeService {
constructor(context) {
this.rankopenprizeDao = new BaseDao(context, DBName);
}
// 添加排行榜待开奖列表
async addWaitAwardsList(list) {
if (!list.length) {
return true;
}
list.map((v) => {
(v.drawStatus = DRAW_STATUS.WAITAWARD), (v.message = "");
});
try {
await this.rankopenprizeDao.insertMany(list);
return true;
} catch (e) {
console.log(`添加排行榜待开奖列表出错:${e}`);
return false;
}
}
// 根据活动id查找中奖名单
async getAwardslistByActivityId(activityId) {
if (!activityId) {
return false;
}
return await this.rankopenprizeDao.find(
{
activityId: activityId,
},
{
sort: {
score: -1,
rankTime: -1,
},
}
);
}
}
module.exports = RankopenprizeService;
const BaseDao = require("../dao/base.dao");
const { USER_INFO } = require("../config/db_config");
const DBName = USER_INFO;
class RankscoreService {
constructor(context) {
this.rankscoreDao = new BaseDao(context, DBName);
}
// 根据活动id查询分数排行榜
async getToplistByActivityId(activityId, totalAwards) {
let list = await this.rankscoreDao.find(
{
activityId: activityId,
maxScore: { $ne: 0 },
},
{
sort: {
maxScore: -1,
updateScoreTime: 1,
},
limit: +totalAwards,
}
);
console.log(`getToplistByActivityId: ${JSON.stringify(list)}`);
return list;
}
}
module.exports = RankscoreService;
const { BaseDao, TBAPI, Utils } = require("taobao-mini-sdk").default;
// 活动开奖状态码
const OPEN_PRIZE_STATUS = {
// 待开奖
WAIT_AWARD: 1,
// 开奖中
PROCESSING: 2,
// 开奖成功
SUCCESS: 3,
// 开奖失败
FAIL: 4,
};
// 领取奖品状态
const DRAW_STATUS = {
// 待领取
WAITAWARD: 1,
// 处理中
PROCESSING: 2,
// 领取成功
SUCCESS: 3,
// 领取失败
FAIL: 4,
// 已过期
EXPIRED: 5,
// 重新领取
RETRY: 6,
};
// 日志类型: error,info
const LOGGER_TYPE = {
ERROR: 1,
INFO: 2,
};
// code类型
const CODE_TYPES = {
PARAMS_ERROR: {
code: "100000",
defaultMsg: `参数错误`,
},
SYSTEM_ERROR: {
code: "500000",
defaultMsg: `系统错误`,
},
SUCCESS: {
code: "000000",
defaultMsg: `成功`,
},
// TODO 补充业务类型错误, 固定以2开头,如B端业务错误:200001,200002,C端业务错误:210001,210002
};
const SHARE_TOTAL_COUNT = 5; //验证要求5人后,完成分享任务
const B_APP_NAME = "promotioncenter-3000000002693435"; // B端的APP NAME
const GOODSINFO =
"detail_url,approve_status,num_iid,title,nick,type,cid,pic_url,num,props,valid_thru,list_time,price,has_discount,has_invoice,has_warranty,has_showcase,modified,delist_time,postage_id,seller_cids,outer_id,sold_quantity";
const EIGHT_HOURS = 60 * 60 * 8 * 1000;
const DELETE_STATUS = {
DELETE: 2,
EXIST: 1,
};
const TEMPLATE_INFO = {
clients: "taobao,tmall",
template_id: 3000000002590532,
template_version: "0.0.3",
};
const TASK_TYPE_CHINA = {
beMembership: "成为会员",
attentionStore: "关注店铺",
sign: "签到",
exchangeCredits: "兑换积分",
inviteFriends: "邀请好友",
orderGoods: "下单商品",
browseGoods: "浏览商品",
jumpLink: "跳转链接",
collectGoods: "收藏商品",
};
const TASK_CHECK_TYPE = {
value: {
list: [
"beMembership",
"attentionStore",
"sign",
"exchangeCredits",
"inviteFriends",
"orderGoods",
"browseGoods",
"jumpLink",
"collectGoods",
],
reg: /[1-9]/,
regName: "1-9之内",
},
times: {
list: [
"exchangeCredits",
"inviteFriends",
"orderGoods",
"browseGoods",
"jumpLink",
"collectGoods",
],
},
title: {
list: [
"inviteFriends",
"orderGoods",
"browseGoods",
"jumpLink",
"collectGoods",
],
},
itemIds: {
list: ["orderGoods", "browseGoods", "collectGoods"],
},
taskRateType: {
list: ["inviteFriends", "orderGoods", "browseGoods", "collectGoods"],
},
link: { list: ["jumpLink"] },
};
module.exports = {
OPEN_PRIZE_STATUS,
DRAW_STATUS,
LOGGER_TYPE,
CODE_TYPES,
SHARE_TOTAL_COUNT,
DELETE_STATUS,
GOODSINFO,
B_APP_NAME,
EIGHT_HOURS,
TEMPLATE_INFO,
BaseDao,
TBAPIS: TBAPI.default,
Utils,
TASK_CHECK_TYPE,
TASK_TYPE_CHINA,
};
const errorCode = {
"000000": 'ok',
"000001": '请填写活动名称',
"000002": '请填写活动副标题',
"000003": '活动名称不得大于12个字符',
"000004": '活动副标题不得大于16个字符',
"000005": '任务配置至少选择一项',
"000006": '浏览链接配置错误',
"000007": '奖品至少配置三名',
"000008": "浏览宝贝最多选择20个商品",
"000010": '请先生成规则',
"000011": '请配置活动时间',
"000012": '新建活动开始时间需小于当前时间',
"000013": '开始时间不得大于结束时间',
"000014": '奖品最多配置8个档位',
"000015": '查询列表错误',
"000016": '查询列表总数错误',
"000017": '更新奖品列表出错',
"000020": '删除活动失败',
"000021": '保存活动失败',
"000022": "删除活动id不存在",
"000023": '当前活动不存在',
"000024": '获取授权信息失败',
"000025": '保存授权信息失败',
"000026": '获取商家在售列表失败',
"000027": '获取商家ids列表失败',
"000030": '获取ename商品信息失败',
"000031": '奖品配置不正确'
}
module.exports = {
errorCode
}
\ No newline at end of file
class ResultsModel {
constructor() {
}
// 不填errorType,默认为系统错误
error(errorType, message) {
if (!errorType) {
errorType = { code: '500000', defaultMsg: '系统错误' };
}
return {
success: false,
code: errorType.errorCode,
message: message || errorType.defaultMsg
}
}
success(data) {
return {
success: true,
code: 10000,
data: data,
message: `成功`
}
}
}
module.exports = ResultsModel
\ No newline at end of file
function loginfo(context, handler) {
const {
fcName,
data,
env
} = context;
console.log(`函数名:${fcName}---函数handler:${handler}---当前环境:${env}---请求参数:${JSON.stringify(data)}`)
}
const passUrlList = [
'1688.cn',
'taobao.cn',
'taobao.com',
'taobao.net',
'tb.cn',
'tmall.com',
'zhifu.com',
'zhifubao.com',
'juhuasuan.com',
'tmall.hk',
'tmall.com.hk',
'dingtalk.com',
'yushanfang.com',
'guoguo-app.com',
'umeng.com'
]
/**
* 传入时间戳(毫秒)
* 根据时间戳转换成number型日期进行差值结算,比如:2020318-2020317
*/
function isNewDay(time) {
let date = new Date(time);
let dateNum = +(date.getFullYear() + "" + (date.getMonth() + 1) + "" + date.getDate());
let nowdate = new Date(Date.now());
let nowdateNum = +(nowdate.getFullYear() + "" + (nowdate.getMonth() + 1) + "" + nowdate.getDate());
return nowdateNum - dateNum > 0
}
const formatTime = function dateFormat(thisDate, fmt = "yyyy-MM-dd hh:mm:ss") {
var o = {
"M+": thisDate.getMonth() + 1,
"d+": thisDate.getDate(),
"h+": thisDate.getHours(),
"m+": thisDate.getMinutes(),
"s+": thisDate.getSeconds(),
"q+": Math.floor((thisDate.getMonth() + 3) / 3),
"S": thisDate.getMilliseconds()
};
if (/(y+)/.test(fmt))
fmt = fmt.replace(RegExp.$1, (thisDate.getFullYear() + "").substr(4 - RegExp.$1.length));
for (var k in o)
if (new RegExp("(" + k + ")").test(fmt))
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
return fmt;
}
function MathRand() {
var Num = "";
for (var i = 0; i < 6; i++) {
Num += Math.floor(Math.random() * 10);
}
return Num;
}
module.exports = {
loginfo,
MathRand,
passUrlList,
isNewDay,
formatTime
}
\ No newline at end of file
{
"runtime": "nodejs8",
"version": "1.0"
}
\ No newline at end of file
const ACTIVITY_BASE_CONFIG = 'activity_base_config';
const ACTIVITY_PRIZE_CONFIG = 'activity_prize_config';
const ACTIVITY_SELLER_SAVE = 'activity_seller_save';
module.exports = {
ACTIVITY_BASE_CONFIG,
ACTIVITY_PRIZE_CONFIG,
ACTIVITY_SELLER_SAVE
}
\ No newline at end of file
const {
formatTime
} = require('../utils/utils');
const secret = '99f00e460bfae520f85ae5f5a38e5b4a';
const appKey = 28640163;
const getSellerInfoByContext = (context) => {
return {
timestamp: formatTime(new Date(), "yyyy-MM-dd hh:mm:ss"),
open_id: context.openId,
'appkey': appKey,
'appsecret': secret,
'session': context.accessToken,
REST_URL: 'http://gw.api.taobao.com/router/rest'
}
}
const getConsumerSeller = ({
accessToken,
openId
}) => {
return {
timestamp: formatTime(new Date(), "yyyy-MM-dd hh:mm:ss"),
open_id: openId,
'appkey': appKey,
'appsecret': secret,
'session': accessToken,
REST_URL: 'http://gw.api.taobao.com/router/rest'
}
}
module.exports = {
getSellerInfoByContext,
getConsumerSeller
};
\ No newline at end of file
const ActivityConfigService = require('../service/activityconfig.service')
const {
CODE_TYPES
} = require('../utils/constants')
const ResultsModel = require('../utils/results.model')
let resultsModel = new ResultsModel()
const {
DELETE_STATUS
} = require("../utils/constants");
let ActivityTopService = require('../service/activitytop.service');
const {
loginfo,
passUrlList
} = require('../utils/utils')
const Url = require('url')
//openId获取活动列表
const getActivityListByOpenId = async function (context) {
loginfo(context, 'getActivityListByOpenId')
let ActivityConfig = new ActivityConfigService(context);
try {
let result = await ActivityConfig.getActivityListByOpenId(
context.openId,
context.data
)
if (result) {
result.list.map(item => {
item.activityId = item._id;
return item;
})
return resultsModel.success(result)
}
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, '查询活动列表失败')
} catch (e) {
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, '查询活动列表失败')
}
}
//保存或编辑活动信息
const saveActivityInfoByHasId = async function (context) {
loginfo(context, 'saveActivityInfoByHasId')
let ActivityConfig = new ActivityConfigService(context)
let ActivityTop = new ActivityTopService(context);
const {
openId
} = context
let {
title,
subtitle,
activityId = '',
startTime,
endTime,
specifyPageUrl = '',
rule,
browseItemIds = '',
prizeInfoList = [],
attentionStore = false,
beMembership = false,
inviteFriends = false
} = context.data
if (!title) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '活动名称为空')
} else if (title.length > 12) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '活动名称不可超过12个字')
}
if (!subtitle) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '活动副标题为空')
} else if (subtitle.length > 16) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '活动副标题不可超过16个字')
}
if (
!attentionStore &&
!beMembership &&
!inviteFriends &&
browseItemIds.length === 0 &&
specifyPageUrl.length === 0
) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '任务配置至少选择一项')
} else if (browseItemIds.split(',').length > 20) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '浏览宝贝最多选择20个商品')
}
if (specifyPageUrl) {
const specifyPageUrlParse = Url.parse(specifyPageUrl)
let urlHasPass = false
passUrlList.forEach(item => {
if (~specifyPageUrlParse.host.indexOf(item)) {
urlHasPass = true
}
})
console.log(specifyPageUrlParse.protocol, urlHasPass)
if (!specifyPageUrlParse.protocol || !urlHasPass) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '浏览链接域名校验不通过')
}
}
if (prizeInfoList.length === 0) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '奖品至少配置3名')
} else if (prizeInfoList.length > 8) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '奖品最多配置8个档位')
} else {
let canPassPrize = true
prizeInfoList.forEach(item => {
if (!item.ename || !item.rank) {
canPassPrize = false
}
})
if (+prizeInfoList[prizeInfoList.length - 1].rank.split('-') > 100) canPassPrize = false;
if (!canPassPrize) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '奖品配置不正确');
}
}
if (!rule) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '活动规则不可为空')
}
if (!startTime || !endTime) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '请配置活动时间')
} else if (!activityId && startTime < Date.now()) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '新建活动开始时间需小于当前时间')
} else if (startTime > endTime) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '开始时间不得大于结束时间')
}
let shopInfoResult = await ActivityTop.getShopId();
if (!shopInfoResult.success) {
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, '获取淘宝店铺信息失败')
}
console.log(shopInfoResult, 'shopInfo');
const baseData = {
title,
subtitle,
startTime,
endTime,
rule,
shopId: shopInfoResult.data.sid,
openId,
taskInfo: {
specifyPageUrl,
browseItemIds,
attentionStore,
beMembership,
inviteFriends
}
}
let result
console.log('activityId', activityId)
try {
if (!activityId) {
result = await ActivityConfig.saveNewActivity(
baseData,
prizeInfoList,
openId
)
} else {
let prizeInfoListNoId = prizeInfoList.map(item => {
item.activityId = activityId
item.updateTime = Date.now()
item.createTime = Date.now()
item.deleteStatus = DELETE_STATUS.EXIST
delete item._id
return item
})
// console.log(prizeInfoListNoId, 'prizeInfoListNoId')
result = await ActivityConfig.updateActivity(
activityId,
baseData,
prizeInfoListNoId
)
}
if (result) {
return resultsModel.success(true)
} else {
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, '保存活动失败')
}
} catch (e) {
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, '保存活动失败')
}
}
//删除活动
const deleteActivityById = async function (context) {
loginfo(context, 'deleteActivityById')
let ActivityConfig = new ActivityConfigService(context)
const {
activityId = ''
} = context.data
try {
if (activityId) {
let result = await ActivityConfig.deleteActivityByActivityId(activityId)
if (result === 0 || result) {
return resultsModel.success(true)
} else {
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, '删除活动失败')
}
} else {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '删除活动id不存在')
}
} catch (e) {
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, '删除活动失败')
}
}
//获取活动信息
const getActivityInfo = async function (context) {
loginfo(context, 'getActivityInfoByActivityId')
let ActivityConfig = new ActivityConfigService(context)
const {
activityId = ''
} = context.data
try {
if (activityId) {
let result = await ActivityConfig.getActivityInfoByActivityId(activityId)
const {
taskInfo,
...rest
} = result.baseConfig
let prizeInfoList = result.prizeConfig.sort((a, b) => {
return a.rank.split('-')[0] - b.rank.split('-')[0]
})
let activityInfo = {
...taskInfo,
activityId,
...rest,
prizeInfoList
}
return resultsModel.success(activityInfo)
} else {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '当前活动不存在')
}
} catch (e) {
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, '获取活动配置信息失败')
}
}
module.exports = {
getActivityListByOpenId,
saveActivityInfoByHasId,
deleteActivityById,
getActivityInfo
}
\ No newline at end of file
const {
formatTime
} = require('../utils/utils');
const {
CODE_TYPES
} = require('../utils/constants');
const ResultsModel = require('../utils/results.model');
let resultsModel = new ResultsModel();
//生成规则
module.exports = async (context) => {
console.log(JSON.stringify(context.data), 'context.data')
let {
title = '', startTime = '', endTime = '', prizeInfoList = []
} = context.data;
if (!title) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '活动名称为空');
} else if (title.length > 12) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '活动名称不可超过12个字');
}
if (!startTime || !endTime) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '请配置活动时间');
} else if (startTime > endTime) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '开始时间不得大于结束时间');
}
if (prizeInfoList.length === 0) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '奖品至少配置3名');
} else if (prizeInfoList.length > 8) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '奖品最多配置8个档位');
} else {
let canPassPrize = true;
prizeInfoList.forEach(item => {
if (!item.ename || !item.rank) {
canPassPrize = false;
}
})
if (!canPassPrize) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '奖品配置不正确');
}
}
let resultRule = '';
let startTimeDate = formatTime(new Date(+startTime), "yyyy-MM-dd hh:mm:ss");
let endTimeDate = formatTime(new Date(+endTime), "yyyy-MM-dd hh:mm:ss");
resultRule = `1.活动时间:${startTimeDate}--${endTimeDate};\n2.活动结束根据排行榜排名获得对应的奖励,每个人取活动中单局最高分;\n3.每天3次免费参与资格,超过次数后邀请群内好友参与游戏可获得额外次数(每个用户可助力一次);\n4.参与签到可获得道具,每局结束游戏后可使用道具;\n5.完成任务每天可获得额外的复活机会,每局只能使用一张复活卡;\n\n`
let prizeStr = prizeInfoList.reduce((s, v) => {
let rankArr = v.rank.split('-');
if (rankArr[0] == rankArr[1]) {
return s += `第${rankArr[0]}名: ${v.name}\n`
} else {
return s += `第${v.rank}名: ${v.name}\n`
}
}, '奖品:\n')
resultRule += prizeStr;
return resultsModel.success(resultRule);
}
\ No newline at end of file
const {
loginfo
} = require('../utils/utils');
const {
CODE_TYPES
} = require('../utils/constants');
const ResultsModel = require('../utils/results.model');
let resultsModel = new ResultsModel();
const ActivityTopService = require('../service/activitytop.service');
//通过状态获取top商品列表
const findItemListByStatusAction = async function (context) {
loginfo(context, 'findItemListByStatus');
let ActivityTop = new ActivityTopService(context);
try {
let result = await ActivityTop.getItemListByStatus();
return result;
} catch (e) {
console.log(e, '获取top商品列表失败')
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, '获取top商品列表失败');
}
}
//通过itemIds获取商品列表
const findItemListByIdsAction = async (context) => {
loginfo(context, 'findItemListByIdsAction');
let ActivityTop = new ActivityTopService(context);
try {
let result = ActivityTop.getItemListByIds();
return result;
} catch (e) {
console.log(e, '获取商品列表失败')
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, '获取商品列表失败');
}
}
//通过ename获取权益信息
const getBenefitByEname = async (context) => {
loginfo(context, 'getBenefitByEname');
let ActivityTop = new ActivityTopService(context);
try {
let result = await ActivityTop.getPrizeByEname();
return result;
} catch (e) {
console.log(e, '获取ename权益信息失败')
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, '获取ename权益信息失败');
}
}
module.exports = {
findItemListByIdsAction,
findItemListByStatusAction,
getBenefitByEname
}
\ No newline at end of file
const ActivitySellerService = require('../service/activityseller.service');
const {
CODE_TYPES
} = require('../utils/constants');
const {
getSellerInfoByContext
} = require('../config/seller_config');
const ActivityTopService = require('../service/activitytop.service');
const {
loginfo
} = require('../utils/utils');
const ResultsModel = require('../utils/results.model');
let resultsModel = new ResultsModel();
//保存授权信息
module.exports = async (context) => {
loginfo(context, 'sellerInfo');
const {
openId,
accessToken,
appKey,
userNick,
appOwnerOpenId
} = context;
let ActivitySeller = new ActivitySellerService(context);
let ActivityTop = new ActivityTopService(context);
try {
let hasResult = await ActivitySeller.findSellerInfo(context.openId);
console.log(hasResult, 'hasSellerResult');
if (hasResult && hasResult[0]) {
await ActivitySeller.updateSellerInfo(context.openId, {
accessToken,
appKey,
userNick,
appOwnerOpenId
})
return resultsModel.success(true);
} else {
let shopInfoResult = await ActivityTop.getShopId();
if (!shopInfoResult.success) {
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, '获取淘宝店铺信息失败')
}
try {
let result = await ActivitySeller.saveSellerInfo({
accessToken,
openId,
appKey,
shopId: shopInfoResult.data.sid,
userNick,
appOwnerOpenId
})
return resultsModel.success(result);
} catch (e) {
console.log(e, '保存授权信息失败');
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, '保存授权信息失败');
}
}
} catch (e) {
console.log(e, '获取授权信息失败');
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, '获取授权信息失败');
}
}
\ No newline at end of file
/**
* 中奖名单 及导出中奖名单
*/
const RankopenprizeService = require('../service/rankopenprize.service');
const ResultsModel = require('../utils/results.model');
const {
CODE_TYPES
} = require('../utils/constants');
const xlsx = require('node-xlsx');
let resultsModel = new ResultsModel();
// 活动中奖名单
const findWinnerInfoList = async (context) => {
let {
activityId
} = context.data;
if (!activityId) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, `缺少activityId`);
}
let rankopenprizeService = new RankopenprizeService(context);
// 获取活动中奖列表
let awardslist = await rankopenprizeService.getAwardslistByActivityId(activityId);
console.log(`awardslist: ${JSON.stringify(awardslist)}`);
let winnersObj = {};
awardslist.forEach((v, index, arr) => {
if (!winnersObj[v.rank]) {
winnersObj[v.rank] = [];
}
winnersObj[v.rank].push({
userNick: v.userNick,
id: v.openId
});
});
console.log(`winnersObj: ${JSON.stringify(winnersObj)}`);
let results = [];
new Map(Object.entries(winnersObj)).forEach((v, index, arr) => {
results.push({
rank: index,
winnerDetailList: v
});
});
return resultsModel.success(results);
}
// 导出活动中奖名单
const exportAwardsList = async (context) => {
let {
cloud
} = context;
let {
activityId,
title
} = context.data;
if (!activityId) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, `缺少activityId`);
}
if (!title) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, `缺少title`);
}
let rankopenprizeService = new RankopenprizeService(context);
// 获取活动中奖列表
let awardslist = await rankopenprizeService.getAwardslistByActivityId(activityId);
console.log(`awardslist: ${JSON.stringify(awardslist)}`);
let xlsxData = [
['序列', '名次', '昵称', '中奖名称']
];
awardslist.forEach((v, index, arr) => {
xlsxData.push([index + 1, v.rank, v.userNick, v.prizeName]);
});
let buffer = xlsx.build([{
name: title + new Date().getTime(),
data: xlsxData
}]);
console.log(`xlsxData: ${JSON.stringify(xlsxData)}`);
try {
let result = await cloud.file.uploadFile({
fileContent: buffer,
fileName: title + new Date().getTime() + '.xlsx'
});
// result.url 需进行处理
if (result.url) {
result.url = result.url.replace('http', 'https').replace('-internal', '');
}
return resultsModel.success(result);
} catch (e) {
console.log('上传文件出错', e);
// 打印日志
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, `上传文件错误`);
}
}
module.exports = {
findWinnerInfoList,
exportAwardsList
}
\ No newline at end of file
const RankscanService = require('../service/rankscan.service')
const ActivityprizeService = require('../service/activityprize.service')
const RankscoreService = require('../service/rankscore.service');
const RankopenprizeService = require('../service/rankopenprize.service');
const ResultsModel = require('../utils/results.model');
let resultsModel = new ResultsModel();
// 声明排行榜扫描服务
let rankscanService = null;
// 声明奖品服务
let activityprizeService = null;
// 声明分数排行榜服务
let rankscoreService = null;
// 声明待开奖服务
let rankopenprizeService = null;
// 查询该活动的奖品列表 及 发奖数
const getPrizeListAndAwards = async (activityId) => {
let prizeList = await activityprizeService.getPrizeListByActivityId(activityId);
console.log(prizeList);
// 若不存在奖品列表,则为脏数据,不做处理
if (!prizeList.length) {
console.log(`活动Id为${activityId}不存在对应的奖品信息`);
return {
prizeList: [],
totalAwards: 0
};
}
// 获取总共发奖的个数
let totalAwards = prizeList.reduce((total, curVal, curIndex, arr) => {
// 当没有rank名次,直接返回
if (!curVal.rank) {
return total;
}
let awards = +curVal.rank.split('-')[1];
if (awards > total) {
total = awards;
}
return total;
}, 0);
return {
prizeList,
totalAwards
}
}
// 获取待开奖列表
const getWaitAwardsList = (prizeList, topscoreList, totalAwards, shopId) => {
let waitAwardslist = [];
// 若分数排行榜没有数据,或发奖数为0,返回[]
if (!totalAwards || !topscoreList.length) {
return waitAwardslist;
}
prizeList.forEach((v, index, arr) => {
if (!v.rank) {
return;
}
let rankPeriod = v.rank.split('-');
// 截取排行区间的分数排行列表
let ranklist = topscoreList.slice(+rankPeriod[0] - 1, Math.min(+rankPeriod[1], totalAwards));
// 整合开奖数据
ranklist.map(rank => {
waitAwardslist.push({
activityId: v.activityId,
openId: rank.openId,
rank: v.rank,
ename: v.ename,
startTime: v.startTime,
endTime: v.endTime,
prizeId: v.goodsId,
prizeName: v.name,
userNick: rank.userNick,
rankTime: rank.updateTime,
image: v.image,
score: rank.score,
shopId: shopId
});
});
});
return waitAwardslist;
}
// 设置活动开奖
const setActivity2openprize = async (waitAwardslist, _id) => {
// 插入排行榜开奖记录表 rank_open_prize 若失败,则变更
let results = await rankopenprizeService.addWaitAwardsList(waitAwardslist);
console.log(`result: ${JSON.stringify(results)}`);
if (results) {
await rankscanService.update2Success(_id);
console.log(`开奖成功`);
return true;
} else {
await rankscanService.update2Fail(_id, `批量插入rank_open_prize表不成功`);
console.log(`开奖失败`);
return false;
}
}
/**
* 定时触发开奖
*/
const endingNotify = async (context) => {
// 初始化排行榜扫描服务
rankscanService = new RankscanService(context);
// 初始化返回结果
let results = {
success: [],
fails: []
};
// 获取服务器时间
let serverTime = Date.now();
// 触发开奖列表
let notifyList = await rankscanService.getNodifyList(serverTime);
console.log(notifyList.length);
if (!notifyList.length) {
console.log(`没有待开奖的活动`);
return resultsModel.success(results);
}
// 初始化奖品服务
activityprizeService = new ActivityprizeService(context);
// 分数排行榜
rankscoreService = new RankscoreService(context);
// 待开奖服务
rankopenprizeService = new RankopenprizeService(context);
// 遍历列表
for (let i = 0; i < notifyList.length; i++) {
let {
activityId,
_id,
shopId
} = notifyList[i];
// 将该条记录变更为处理中
let updateResult = await rankscanService.update2Process(_id);
console.log(`updateResult: ${updateResult}`)
if (!updateResult) {
console.log(`将rank_scan该活动的开奖状态变更为处理中失败`);
continue;
}
// 查询该活动的奖品列表 及 发奖数
let {
prizeList,
totalAwards
} = await getPrizeListAndAwards(activityId);
console.log(`prizeList: ${JSON.stringify(prizeList)}; totalAwards: ${totalAwards}`);
// 没查找到奖品列表, 继续下个活动循环
if (!prizeList.length) {
// 开奖失败,记录日志
await rankscanService.update2Fail(_id, `活动不存在对应的奖品列表,开奖失败`);
results.fails.push(activityId);
continue;
}
// 查找排行榜分数榜里的前totalAwards个记录
let topscoreList = await rankscoreService.getToplistByActivityId(activityId, totalAwards);
console.log(`topscoreList: ${JSON.stringify(topscoreList)}`)
// 根据分数排行榜列表及奖品列表整合数据,待开奖列表
let waitAwardslist = getWaitAwardsList(prizeList, topscoreList, totalAwards, shopId);
// if (!waitAwardslist.length) {
// }
console.log(`waitAwardslist: ${JSON.stringify(waitAwardslist)}`)
// 开奖
let issuccess = await setActivity2openprize(waitAwardslist, _id);
issuccess ? results.success.push(activityId) : results.fails.push(activityId);
// end
}
return resultsModel.success(results);
}
module.exports = {
endingNotify
}
\ No newline at end of file
const ResultsModel = require('../utils/results.model');
const { CODE_TYPES } = require('../utils/constants');
const GameService = require("../service/game.service");
/**
* 获取游戏规则标题等相关配置
* @param {*} context
*/
const getGameInfo = async (context) => {
const { activityId,
nickName='暂无昵称' } = context.data;
if (!activityId) {
return new ResultsModel().error(CODE_TYPES.PARAMS_ERROR);
}
const gameService = new GameService(context);
return await gameService.getGameInfo(activityId,nickName);
}
module.exports = {
getGameInfo
}
\ No newline at end of file
const ResultsModel = require('../utils/results.model');
const { CODE_TYPES } = require('../utils/constants');
const ActivityprizeService = require("../service/activityprize.service");
const PrizeService = require("../service/prize.service");
/**
* 获取排行版下方奖品展示
* @param {*} context
*/
const getRankPrize = async (context) => {
let activityId = context.data.activityId;
if (!activityId) {
return new ResultsModel().error(CODE_TYPES.PARAMS_ERROR);
}
const activityprizeService = new ActivityprizeService(context);
let result = await activityprizeService.getPrizeListByActivityId(activityId);
let resultData = result.sort((a,b)=>{
return +a.rank.split("-")[0]>+b.rank.split("-")[0];
})
return new ResultsModel().success(resultData)
}
/**
* 获取我的奖品信息
* @param {*} context
*/
const getMyPrize = async (context) => {
let activityId = context.data.activityId;
if (!activityId) {
return new ResultsModel().error(CODE_TYPES.PARAMS_ERROR);
}
const prizeService = new PrizeService(context);
return await prizeService.getMyPrize(activityId);
}
/**
* 领奖
* @param {*} context
*/
const collectionPrize = async (context) => {
let {activityId, ename } = context.data;
if (!activityId || !ename) {
return new ResultsModel().error(CODE_TYPES.PARAMS_ERROR);
}
const prizeService = new PrizeService(context);
return await prizeService.collectionPrize(activityId,ename);
}
const getPrizeList = async(context)=>{
let {activityId } = context.data;
if (!activityId ) {
return new ResultsModel().error(CODE_TYPES.PARAMS_ERROR);
}
const prizeService = new PrizeService(context);
return await prizeService.getPrizeList(activityId);
}
module.exports = {
getRankPrize,
getMyPrize,
collectionPrize,
getPrizeList
}
const ResultsModel = require('../utils/results.model');
const { CODE_TYPES } = require('../utils/constants');
const RankService = require("../service/rank.service");
/**
* 提交分数
* @param {*} context
*/
const doScoreSubmit = async (context)=>{
let{
activityId,
score,
nickName,
avatar
} = context.data;
if(!activityId || !score || !nickName || !avatar)
{
return new ResultsModel().error(CODE_TYPES.PARAMS_ERROR);
}
const rankService=new RankService(context);
return await rankService.doScoreSubmit(activityId,score,nickName,avatar);
}
/**
* 获取排行
* @param {*} context
*/
const getRankList = async(context)=>{
let{
activityId,
page=1,
limit=10
} = context.data;
if(!activityId)
{
return new ResultsModel().error(CODE_TYPES.PARAMS_ERROR);
}
const rankService=new RankService(context);
return await rankService.getRankList(activityId,page,limit);
}
module.exports={
doScoreSubmit,getRankList
}
\ No newline at end of file
const ResultsModel = require('../utils/results.model');
const { CODE_TYPES } = require('../utils/constants');
const ShareService = require("../service/share.service");
/**
* 获取分享id
* @param {*} context
*/
const getShareId = async (context)=>{
let{
activityId
} = context.data;
if(!activityId )
{
return new ResultsModel().error(CODE_TYPES.PARAMS_ERROR);
}
const shareService=new ShareService(context);
return await shareService.getShareId(activityId);
}
/**
* 验证分享
* @param {*} context
*/
const doShareComplete = async(context)=>{
let{
activityId,
shareId
} = context.data;
if(!activityId || !shareId)
{
return new ResultsModel().error(CODE_TYPES.PARAMS_ERROR);
}
const shareService=new ShareService(context);
return await shareService.doShareComplete(activityId,shareId);
}
module.exports={
getShareId,doShareComplete
}
\ No newline at end of file
const ResultsModel = require('../utils/results.model');
const { CODE_TYPES } = require('../utils/constants');
const StatExportService = require('../service/statexport.service');
const statTotalData = async(context)=>{
let activityId=context.data.activityId;
if(!activityId)
{
return new ResultsModel().error(CODE_TYPES.PARAMS_ERROR);
}
const statExportService=new StatExportService(context);
return await statExportService.statTotalData(activityId);
}
const statJoinData = async(context)=>{
let activityId=context.data.activityId;
if(!activityId)
{
return new ResultsModel().error(CODE_TYPES.PARAMS_ERROR);
}
const statExportService=new StatExportService(context);
return await statExportService.statJoinData(activityId);
}
const statTaskData = async(context)=>{
let activityId=context.data.activityId;
if(!activityId)
{
return new ResultsModel().error(CODE_TYPES.PARAMS_ERROR);
}
const statExportService=new StatExportService(context);
return await statExportService.statTaskData(activityId);
}
const statItemData = async(context)=>{
let activityId=context.data.activityId;
if(!activityId)
{
return new ResultsModel().error(CODE_TYPES.PARAMS_ERROR);
}
const statExportService=new StatExportService(context);
return await statExportService.statItemData(activityId);
}
const statPrizeData = async(context)=>{
let activityId=context.data.activityId;
if(!activityId)
{
return new ResultsModel().error(CODE_TYPES.PARAMS_ERROR);
}
const statExportService=new StatExportService(context);
return await statExportService.statPrizeData(activityId);
}
module.exports = {statTotalData,statJoinData,statTaskData,statItemData,statPrizeData}
\ No newline at end of file
const ResultsModel = require('../utils/results.model');
const { CODE_TYPES } = require('../utils/constants');
const StatItemService = require('../service/statitem.service');
const itemShow = async(context)=>{
let activityId=context.data.activityId;
if(!activityId)
{
return new ResultsModel().error(CODE_TYPES.PARAMS_ERROR);
}
const statItemService=new StatItemService(context);
return await statItemService.itemShow(activityId);
}
const itemTap = async(context)=>{
let activityId=context.data.activityId;
if(!activityId)
{
return new ResultsModel().error(CODE_TYPES.PARAMS_ERROR);
}
const statItemService=new StatItemService(context);
return await statItemService.itemTap(activityId);
}
module.exports = {itemShow,itemTap}
\ No newline at end of file
const ResultsModel = require('../utils/results.model');
const { CODE_TYPES } = require('../utils/constants');
const TaskService = require("../service/task.service");
/**
* 获取任务列表
* @param {} context
*/
const getTaskList=async(context)=>{
let{
activityId
} = context.data;
if(!activityId )
{
return new ResultsModel().error(CODE_TYPES.PARAMS_ERROR);
}
const taskService=new TaskService(context);
return await taskService.getTaskList(activityId);
}
/**
* 完成任务
* @param {*} context
*/
const doTaskComplete= async(context)=>{
let{
activityId,
taskName
} = context.data;
if(!activityId )
{
return new ResultsModel().error(CODE_TYPES.PARAMS_ERROR);
}
const taskService=new TaskService(context);
return await taskService.doTaskComplete(activityId,taskName);
}
/**
* 检查会员
* @param {*} context
*/
const checkMember= async(context)=>{
let{
activityId
} = context.data;
if(!activityId )
{
return new ResultsModel().error(CODE_TYPES.PARAMS_ERROR);
}
const taskService=new TaskService(context);
return await taskService.checkMember(activityId);
}
module.exports={
getTaskList,doTaskComplete,checkMember
}
\ No newline at end of file
const ResultsModel = require('../utils/results.model');
const { CODE_TYPES } = require('../utils/constants');
const UserService = require("../service/user.service");
/**
* 用户登录
*/
const login = async (context) => {
let { activityId,
avatar,
nickName,
isFavor
} = context.data;
if (!activityId || !avatar || !nickName || isFavor == undefined) {
return new ResultsModel().error(CODE_TYPES.PARAMS_ERROR);
}
let userService = new UserService(context);
return await userService.login(activityId, nickName, avatar,isFavor);
}
/**
* 获取体力值
* @param {*} context
*/
const getPower = async (context) => {
let activityId = context.data.activityId;
if (!activityId) new ResultsModel().error(CODE_TYPES.PARAMS_ERROR_2C);
let userService = new UserService(context);
return await userService.getPower(activityId);
}
/**
* 开始游戏
* @param {*} context
*/
const startGame = async (context) => {
let {activityId,nickName='暂无昵称'} = context.data;
if (!activityId ) new ResultsModel().error(CODE_TYPES.PARAMS_ERROR_2C);
let userService = new UserService(context);
return await userService.startGame(activityId,nickName);
}
module.exports = {
login,
getPower,
startGame
}
\ No newline at end of file
class BaseDao {
constructor(context, dbName) {
this.db = context.cloud.db;
this.dbName = dbName;
this.openId = context.openId;
this.context = context;
}
async find(query, options) {
console.log(`query: ${JSON.stringify(query)}`)
console.log(`options: ${JSON.stringify(options)}`)
return await this.db.collection(this.dbName).find(query, options);
}
async findOne(query, options) {
console.log(`query: ${JSON.stringify(query)}`)
console.log(`options: ${JSON.stringify(options)}`)
const result = await this.db.collection(this.dbName).find(query, options);
if(result.length)return result[0];
return null;
}
// 更新数据
async update(query, options) {
return await this.db.collection(this.dbName).updateMany(query, options);
}
//插入单条数据
async insertOne(options) {
return await this.db.collection(this.dbName).insertOne(options);
}
async count(query) {
return await this.db.collection(this.dbName).count(query);
}
async deleteMany(query) {
return await this.db.collection(this.dbName).deleteMany(query);
}
// options Array
async insertMany(options) {
return await this.db.collection(this.dbName).insertMany(options);
}
}
module.exports = BaseDao;
\ No newline at end of file
const ACTIVITY_BASE_CONFIG = 'activity_base_config';
const ACTIVITY_PRIZE_CONFIG = 'activity_prize_config';
const ACTIVITY_SELLER_SAVE = 'activity_seller_save';
module.exports = {
ACTIVITY_BASE_CONFIG,
ACTIVITY_PRIZE_CONFIG,
ACTIVITY_SELLER_SAVE
}
\ No newline at end of file
const {
endingNotify
} = require('./controller/endingNodify.controller');
const {
findWinnerInfoList,
exportAwardsList
} = require('./controller/awards.controller');
const {
login,
getPower,
startGame
} = require('./controller/user.controller');
const {
doScoreSubmit,
getRankList
} = require('./controller/rank.controller');
const {
getShareId,
doShareComplete
} = require('./controller/share.controller');
const {
getTaskList,
doTaskComplete,
checkMember
} = require('./controller/task.controller');
const {
getGameInfo
} = require('./controller/game.controller');
const {
getRankPrize,
getMyPrize,
collectionPrize,
getPrizeList
} = require('./controller/prize.controller');
const {
getActivityListByOpenId,
saveActivityInfoByHasId,
deleteActivityById,
getActivityInfo
} = require('./controller/activity.controller');
const saveSellerInfo = require('./controller/activityseller.controller');
const generateRuleAction = require('./controller/activitygenerateRule.controller');
const {
findItemListByStatusAction,
findItemListByIdsAction,
getBenefitByEname,
getVipUrlAction
} = require("./controller/activitygettbitem.controller");
const {
statTotalData,
statJoinData,
statTaskData,
statItemData,
statPrizeData
} = require("./controller/statexport.controller");
const{
itemShow,
itemTap
}=require("./controller/statitem.controller");
//数据统计相关
exports.statTotalData = statTotalData;
exports.statJoinData = statJoinData;
exports.statTaskData = statTaskData;
exports.statItemData = statItemData;
exports.statPrizeData=statPrizeData;
exports.itemShow = itemShow;
exports.itemTap=itemTap;
// 定时开奖
exports.endingNotify = endingNotify;
// 活动中奖名单
exports.findWinnerInfoList = findWinnerInfoList;
// 导出中奖名单
exports.exportAwardsList = exportAwardsList;
exports.login = login;
exports.getPower = getPower;
exports.startGame = startGame;
exports.doScoreSubmit = doScoreSubmit;
exports.getRankList = getRankList;
exports.getShareId = getShareId;
exports.doShareComplete = doShareComplete;
exports.getTaskList = getTaskList;
exports.doTaskComplete = doTaskComplete;
exports.checkMember=checkMember;
exports.getGameInfo = getGameInfo;
exports.getRankPrize = getRankPrize;
exports.getMyPrize = getMyPrize;
exports.collectionPrize = collectionPrize;
exports.getPrizeList = getPrizeList;
exports.getActivityList = getActivityListByOpenId;
exports.saveActivityInfo = saveActivityInfoByHasId;
exports.delActivity = deleteActivityById;
exports.getActivityDetail = getActivityInfo;
exports.sellerSave = saveSellerInfo;
exports.generateRule = generateRuleAction;
exports.findItemListByStatus = findItemListByStatusAction;
exports.findItemListByIds = findItemListByIdsAction;
exports.queryBenefitByEname = getBenefitByEname;
{
"name": "duiba",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"adler-32": {
"version": "1.2.0",
"resolved": "https://registry.npm.taobao.org/adler-32/download/adler-32-1.2.0.tgz",
"integrity": "sha1-aj5r8KY5ALoVZSgIyxXGgT0aXyU=",
"requires": {
"exit-on-epipe": "~1.0.1",
"printj": "~1.1.0"
}
},
"buffer-from": {
"version": "1.1.1",
"resolved": "https://registry.npm.taobao.org/buffer-from/download/buffer-from-1.1.1.tgz",
"integrity": "sha1-MnE7wCj3XAL9txDXx7zsHyxgcO8="
},
"cfb": {
"version": "1.1.4",
"resolved": "https://registry.npm.taobao.org/cfb/download/cfb-1.1.4.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcfb%2Fdownload%2Fcfb-1.1.4.tgz",
"integrity": "sha1-gf017eTJGdjwliqUWC4d+vcFHio=",
"requires": {
"adler-32": "~1.2.0",
"commander": "^2.16.0",
"crc-32": "~1.2.0",
"printj": "~1.1.2"
}
},
"codepage": {
"version": "1.14.0",
"resolved": "https://registry.npm.taobao.org/codepage/download/codepage-1.14.0.tgz",
"integrity": "sha1-jL4lSBMjVZ19MHVxsP/5HnodL5k=",
"requires": {
"commander": "~2.14.1",
"exit-on-epipe": "~1.0.1"
},
"dependencies": {
"commander": {
"version": "2.14.1",
"resolved": "https://registry.npm.taobao.org/commander/download/commander-2.14.1.tgz",
"integrity": "sha1-IjUSPjevjKPGXfRbAm29NXsBuao="
}
}
},
"commander": {
"version": "2.17.1",
"resolved": "https://registry.npm.taobao.org/commander/download/commander-2.17.1.tgz",
"integrity": "sha1-vXerfebelCBc6sxy8XFtKfIKd78="
},
"crc-32": {
"version": "1.2.0",
"resolved": "https://registry.npm.taobao.org/crc-32/download/crc-32-1.2.0.tgz",
"integrity": "sha1-yy224puIUI4y2d0OwWk+e0Ghggg=",
"requires": {
"exit-on-epipe": "~1.0.1",
"printj": "~1.1.0"
}
},
"exit-on-epipe": {
"version": "1.0.1",
"resolved": "https://registry.npm.taobao.org/exit-on-epipe/download/exit-on-epipe-1.0.1.tgz",
"integrity": "sha1-C92S6H1ShdJn2qgXHQ6wYVlolpI="
},
"frac": {
"version": "1.1.2",
"resolved": "https://registry.npm.taobao.org/frac/download/frac-1.1.2.tgz",
"integrity": "sha1-PXT39keMiKG1AgMG10fcYxPHTQs="
},
"node-xlsx": {
"version": "0.15.0",
"resolved": "https://registry.npm.taobao.org/node-xlsx/download/node-xlsx-0.15.0.tgz",
"integrity": "sha1-HxsNetzlxwboa/2WpaoABb+KncM=",
"requires": {
"buffer-from": "^1.1.0",
"xlsx": "^0.14.1"
}
},
"printj": {
"version": "1.1.2",
"resolved": "https://registry.npm.taobao.org/printj/download/printj-1.1.2.tgz",
"integrity": "sha1-2Q3rKXWoufYA+zoclOP0xTx4oiI="
},
"ssf": {
"version": "0.10.3",
"resolved": "https://registry.npm.taobao.org/ssf/download/ssf-0.10.3.tgz",
"integrity": "sha1-jq4fwpyQpVLnkhII+BiS1vd6yys=",
"requires": {
"frac": "~1.1.2"
}
},
"xlsx": {
"version": "0.14.5",
"resolved": "https://registry.npm.taobao.org/xlsx/download/xlsx-0.14.5.tgz",
"integrity": "sha1-NjfpFNeRvcpzgoFuFz99cl7Q4NI=",
"requires": {
"adler-32": "~1.2.0",
"cfb": "^1.1.2",
"codepage": "~1.14.0",
"commander": "~2.17.1",
"crc-32": "~1.2.0",
"exit-on-epipe": "~1.0.1",
"ssf": "~0.10.2"
}
}
}
}
{
"name": "duiba",
"version": "1.0.0",
"description": "",
"main": "index.js",
"author": "",
"license": "ISC",
"sdkVersion": "*",
"dependencies": {
"node-xlsx": "^0.15.0"
},
"config": {
"notNeedLogin": ["endingNotify"]
}
}
const {
formatTime
} = require('../utils/utils');
const secret = '99f00e460bfae520f85ae5f5a38e5b4a';
const appKey = 28640163;
const getSellerInfoByContext = (context) => {
return {
timestamp: formatTime(new Date(), "yyyy-MM-dd hh:mm:ss"),
open_id: context.openId,
'appkey': appKey,
'appsecret': secret,
'session': context.accessToken,
REST_URL: 'http://gw.api.taobao.com/router/rest'
}
}
const getConsumerSeller = ({
accessToken,
openId
}) => {
return {
timestamp: formatTime(new Date(), "yyyy-MM-dd hh:mm:ss"),
open_id: openId,
'appkey': appKey,
'appsecret': secret,
'session': accessToken,
REST_URL: 'http://gw.api.taobao.com/router/rest'
}
}
module.exports = {
getSellerInfoByContext,
getConsumerSeller
};
\ No newline at end of file
const BaseDao = require('../dao/base.dao');
const {
ACTIVITY_BASE_CONFIG,
ACTIVITY_PRIZE_CONFIG
} = require('../config/db_config');
const {
DELETE_STATUS
} = require("../utils/constants");
module.exports = class ActivityConfigService {
constructor(context) {
this.activityconfigDao = new BaseDao(context, ACTIVITY_BASE_CONFIG);
this.activityconfigPrizeDao = new BaseDao(context, ACTIVITY_PRIZE_CONFIG);
}
//保存新建活动
async saveNewActivity(data, prize, openId) {
try {
let result = await this.activityconfigDao.insertOne({
...data,
createTime: Date.now,
deleteStatus: DELETE_STATUS.EXIST,
updateTime: Date.now
});
console.log(result, '保存基础配置result')
if (result) {
try {
prize.map(item => {
item.activityId = result;
item.openId = openId;
item.createTime = Date.now();
item.updateTime = Date.now();
item.deleteStatus = DELETE_STATUS.EXIST;
return item;
})
return await this.activityconfigPrizeDao.insertMany(prize);
} catch (e) {
console.log(e, '保存奖品配置出错')
// 如果奖品未保存删除之前的活动
await this.activityconfigDao.deleteMany({
_id: result
})
}
}
} catch (e) {
//保存活动失败
console.log(e, '保存活动失败')
}
}
//更新活动配置
async updateActivity(activityId, data, prizeNoId) {
console.log(activityId, data, prizeNoId, 'activityId, data, prizeNoId, oldPrizeIds')
try {
let originalData = await this.activityconfigDao.find({
_id: activityId
})
let result = await this.activityconfigDao.update({
_id: activityId
}, {
$set: {
...data,
createTime: originalData[0].createTime,
updateTime: Date.now()
}
});
if (result) {
try {
let prizeOldIdsByActivity = (await this.activityconfigPrizeDao.find({
activityId
})).reduce((s, v) => {
return s = [...s, v._id];
}, [])
let prizeResult = await this.activityconfigPrizeDao.insertMany(prizeNoId);
if (prizeResult) {
//删除之前的奖品
let deleteOldPrizeList = prizeOldIdsByActivity.reduce((s, item) => {
return s = [...s, this.activityconfigPrizeDao.deleteMany({
_id: item
})]
}, [])
return await Promise.all(deleteOldPrizeList);
}
} catch (e) {
await this.activityconfigDao.update({
_id: activityId
}, {
$set: {
...originalData[0]
}
})
}
}
} catch (e) {
//更新失败
}
}
//通过openId去获取当前商家活动列表
async getActivityListByOpenId(openId, {
pageSize = 10,
pageNo = 1
}) {
return {
list: await this.activityconfigDao.find({
openId,
deleteStatus: DELETE_STATUS.EXIST
}, {
projection: {
startTime: 1,
endTime: 1,
title: 1
},
sort: {
updateTime: -1
},
limit: pageSize,
skip: (pageNo - 1) * pageSize
}),
total: await this.activityconfigDao.count({
openId
}),
pageSize,
pageNo
}
}
//通过activityId去获取活动配置信息
async getActivityInfoByActivityId(activityId) {
return {
baseConfig: (await this.activityconfigDao.find({
_id: activityId,
deleteStatus: DELETE_STATUS.EXIST
}))[0],
prizeConfig: await this.activityconfigPrizeDao.find({
activityId,
deleteStatus: DELETE_STATUS.EXIST
})
}
}
//通过activityId去删除活动
async deleteActivityByActivityId(activityId) {
try {
let result = await this.activityconfigDao.update({
_id: activityId
}, {
$set: {
deleteStatus: DELETE_STATUS.DELETE
}
})
if (result) {
return await this.activityconfigPrizeDao.update({
activityId
}, {
$set: {
deleteStatus: DELETE_STATUS.DELETE
}
})
}
} catch (e) {
console.log(e, '删除活动失败')
}
}
}
\ No newline at end of file
const BaseDao = require('../dao/base.dao');
const { OPEN_PRIZE_STATUS } = require('../utils/constants');
const DBName = 'activity_prize_config';
class ActivityprizeService {
constructor(context) {
this.activityprizeDao = new BaseDao(context, DBName);
}
// 根据活动id查询奖品列表
async getPrizeListByActivityId(activityId) {
console.log(13, activityId)
return await this.activityprizeDao.find({
activityId: activityId
});
}
}
module.exports = ActivityprizeService;
\ No newline at end of file
const BaseDao = require('../dao/base.dao');
const {
ACTIVITY_SELLER_SAVE
} = require('../config/db_config');
module.exports = class ActivitySellerService {
constructor(context) {
this.activitysellerDao = new BaseDao(context, ACTIVITY_SELLER_SAVE);
}
//保存商家授权信息
async saveSellerInfo(sellerInfo) {
return await this.activitysellerDao.insertOne({
...sellerInfo,
updateTime: Date.now(),
createTime: Date.now()
})
}
//查找商家授权信息
async findSellerInfo(openId) {
return await this.activitysellerDao.find({
openId
})
}
//更新商家授权信息
async updateSellerInfo(openId, sellerInfo) {
console.log(openId, sellerInfo, 'openId, sellerInfo')
return await this.activitysellerDao.update({
openId: openId
}, {
$set: {
...sellerInfo,
updateTime: Date.now()
}
})
}
}
\ No newline at end of file
const {
ACTIVITY_SELLER_SAVE,
ACTIVITY_BASE_CONFIG
} = require('../config/db_config');
const {
getConsumerSeller,
getSellerInfoByContext
} = require('../config/seller_config');
const {
CODE_TYPES,
GOODSINFO,
B_APP_NAME
} = require('../utils/constants');
const ResultsModel = require('../utils/results.model');
let resultsModel = new ResultsModel();
const BaseDao = require('../dao/base.dao');
class ActivityTopService {
constructor(context) {
this.activitySellerDao = new BaseDao(context, ACTIVITY_SELLER_SAVE);
this.activityBaseDao = new BaseDao(context, ACTIVITY_BASE_CONFIG);
this.context = context;
}
//获取商家授权session
async getAccessToken(activityId) {
let result = await this.activityBaseDao.find({
_id: activityId
})
if (result[0]) {
let openId = result[0].openId;
let sellResult = await this.activitySellerDao.find({
openId
})
if (sellResult[0]) {
let {
accessToken
} = sellResult[0];
return {
accessToken,
openId
};
}
}
}
//淘宝top接口获取商品列表
async getItemListByIds(activityId, itemIds) {
let sellerConfig;
if (activityId) {
let businessSeller = await this.getAccessToken(activityId);
sellerConfig = getConsumerSeller(businessSeller);
} else {
sellerConfig = getSellerInfoByContext(this.context);
itemIds = this.context.data.itemIds;
}
console.log(sellerConfig, 'sellerConfig')
try {
let result = await this.context.cloud.topApi.invoke({
api: 'taobao.items.seller.list.get',
data: {
...sellerConfig,
fields: GOODSINFO,
num_iids: itemIds
}
});
console.log(JSON.stringify(result), '获取商品通过ids');
if (result) {
let itemsData = {
list: result && result.items && result.items.item.reduce((s, v) => {
return s = [...s, {
"itemId": v.num_iid,
"name": v.title,
"price": v.price,
"detailUrl": v.detail_url,
"picUrl": v.pic_url
}]
}, []) || [],
totalCount: result.items.item.length
}
return resultsModel.success(itemsData);
}
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, '获取商家ids列表失败');
} catch (e) {
console.log(e, '获取ids商品列表失败');
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, '获取商家ids列表失败');
}
}
//淘宝top接口获取权益商品信息
async getPrizeByEname(activityId, ename) {
let sellerConfig;
if (activityId) {
let businessSeller = await this.getAccessToken(activityId);
sellerConfig = getConsumerSeller(businessSeller);
} else {
sellerConfig = getSellerInfoByContext(this.context);
ename = this.context.data.ename;
}
console.log(sellerConfig, 'sellerConfig')
try {
let benefitData = await this.context.cloud.topApi.invoke({
api: 'alibaba.benefit.query',
data: {
...sellerConfig,
ename,
app_name: B_APP_NAME,
award_type: 1,
}
});
if (benefitData.success) {
const {
result
} = benefitData;
let data = result.datas && result.datas["oright_dto"].reduce((s, v) => {
return s = [...s, {
benefitName: v.benefit_name,
rightTypeId: v.right_type_id,
startDate: v.start_date,
endDate: v.end_date
}]
}, []);
console.log(JSON.stringify(result), 'alibaba.benefit.query');
return resultsModel.success(data);
}
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, '获取ename商品信息失败');
} catch (e) {
console.log(e, '权益获取失败');
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, '获取ename商品信息失败');
}
}
//淘宝top接口获取店铺会员链接
async getVipUrlByActivity(activityId) {
let businessSeller = await this.getAccessToken(activityId);
let consumerSellerInfo = getConsumerSeller(businessSeller);
console.log(businessSeller, 'businessSeller', consumerSellerInfo, 'consumerSellerInfo')
try {
let result = await this.context.cloud.topApi.invoke({
api: 'taobao.crm.member.joinurl.get',
data: {
...consumerSellerInfo,
extra_info: {
"source": "isvapp",
"activityId": activityId,
"entrance": "duiba"
},
}
});
if (result) {
return resultsModel.success(result);
}
console.log(JSON.stringify(result), '获取商家会员链接');
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, '获取商家会员链接失败');
} catch (e) {
console.log(e, '获取商家会员链接失败');
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, '获取商家会员链接失败');
}
}
//淘宝top接口获取店铺信息
async getShopId() {
let sellerInfo = getSellerInfoByContext(this.context);
console.log(sellerInfo, 'getShopId sellerInfo')
try {
let result = await this.context.cloud.topApi.invoke({
api: 'taobao.shop.seller.get',
data: {
...sellerInfo,
fields: 'sid,title,pic_path',
v: '2.0'
}
})
console.log(result, 'getShopId result')
if (result) {
return resultsModel.success(result.shop);
} else {
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, '获取淘宝top店铺信息失败');
}
} catch (e) {
console.log(e, '获取店铺信息失败');
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, '获取淘宝top店铺信息失败');
}
}
async getItemListByStatus() {
let sellerConfig = getSellerInfoByContext(this.context);
const {
approveStatus = 'onsale',
title = '',
pageNo = 1,
pageSize = 10
} = this.context.data;
let data = {
fields: GOODSINFO,
page_no: pageNo,
q: title,
page_size: pageSize,
...sellerConfig
}
try {
let result = await this.context.cloud.topApi.invoke({
api: approveStatus === 'onsale' ? 'taobao.items.onsale.get' : 'taobao.items.inventory.get',
data,
autoSession: true
});
if (result) {
console.log(JSON.stringify(result), `comming ${approveStatus}`, 'success')
let {
items,
total_results
} = result;
let itemsData = {
pageNo,
pageSize,
totalPages: Math.ceil(total_results / pageSize),
totalCount: total_results,
list: items && items.item && items.item.reduce((s, v) => {
return s = [...s, {
"itemId": v.num_iid,
"name": v.title,
"price": v.price,
"approveStatus": v.approveStatus || approveStatus,
"picUrl": v.pic_url
}]
}, []) || []
}
return resultsModel.success(itemsData);
}
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, '获取商家在售列表失败');
} catch (e) {
console.log(e, '获取商家在售列表失败')
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, '获取商家在售列表失败');
}
}
}
module.exports = ActivityTopService;
\ No newline at end of file
const ResultsModel = require('../utils/results.model');
const { CODE_TYPES ,ACTIVITY_STATUS} = require('../utils/constants');
const {OPEN_PRIZE_STATUS}=require("../utils/constants");
const BaseDao = require('../dao/base.dao');
const DB_NAME = "activity_base_config";
const DB_RANKSCAN="rank_scan";
const StatPvuvService = require("./statpvuv.service");
class GameService
{
constructor(context)
{
this.baseConfigDao=new BaseDao(context,DB_NAME);
this.rankScanDao=new BaseDao(context,DB_RANKSCAN);
this.resultsModel=new ResultsModel();
this.statPvuvService=new StatPvuvService(context);
}
async getGameInfo(activityId,nickName)
{
try
{
await this.statPvuvService.insertUserOpenData(activityId,nickName);
const result =await this.baseConfigDao.find({_id:activityId},{
projection:{subtitle:1,rule:1,shopId:1}
})
const openPrizeInfo = await this.rankScanDao.find({activityId:activityId},{
projection:{openPrizeStatus:1}
})
const activityStatus = await this.checkActivityStatus(activityId);
if(result.length)
{
let resultData={
...result["0"],
activityStatus:activityStatus,
openPrizeStatus:openPrizeInfo["0"]&&openPrizeInfo["0"].openPrizeStatus || OPEN_PRIZE_STATUS.WAIT_AWARD,
}
return this.resultsModel.success(resultData);
}else{
//该活动ID无效
return this.resultsModel.error(CODE_TYPES.ERROR_NO_ACTIVITY);
}
}catch(e)
{
return this.resultsModel.error(CODE_TYPES.ERROR_SERVER);
}
}
/**
* 检测活动状态 - 未开始,已结束和已删除
* @param {*} activityId
*/
async checkActivityStatus(activityId)
{
const activityStatus = await this.baseConfigDao.find({_id:activityId},{projection:{deleteStatus:1,startTime: 1, endTime: 1}});
if(activityStatus.length)
{
let nowDate = Date.now();
//检测活动是否未开始
if (nowDate < +activityStatus["0"].startTime) {
return ACTIVITY_STATUS.NOSTART;
}
if (nowDate >= +activityStatus["0"].endTime) {
return ACTIVITY_STATUS.OVER;
}
//检测活动是否被删除
if(activityStatus["0"].deleteStatus != 1)
{
return ACTIVITY_STATUS.DELETE;
}
return ACTIVITY_STATUS.ING;
} else {
return ACTIVITY_STATUS.ERRORID;
}
}
}
module.exports=GameService;
\ No newline at end of file
const ResultsModel = require('../utils/results.model');
const ActivityTopService = require("./activitytop.service");
const { CODE_TYPES, DRAW_STATUS, APP_NAME, PRIZE_GET_DELAY_TIME } = require('../utils/constants');
const {formatTime} =require('../utils/utils');
const UserService = require("./user.service");
const BaseDao = require('../dao/base.dao');
const DB_NAME = "rank_open_prize";
const DB_BASECFG = "activity_base_config";
class PrizeService {
constructor(context) {
this.rankOpenDao = new BaseDao(context, DB_NAME);
this.baseConfigDao = new BaseDao(context, DB_BASECFG);
this.resultsModel = new ResultsModel();
this.activityTopService = new ActivityTopService(context);
this.userService = new UserService(context);
}
async getMyPrize(activityId) {
try {
const activityStatus = await this.baseConfigDao.find({ _id: activityId }, { projection: { startTime:1,endTime: 1 } });
let endTime = +activityStatus["0"].endTime + PRIZE_GET_DELAY_TIME;
//已经过期状态
if (Date.now() >= endTime) {
let timeDate = formatTime(new Date(endTime+8*60*60*1000));
let msg = `未在${timeDate}前领取`;
await this.rankOpenDao.update({ activityId: activityId, openId: this.rankOpenDao.openId, drawStatus: { $ne: DRAW_STATUS.SUCCESS } }, {
$set: {
drawStatus: DRAW_STATUS.EXPIRED,
message: msg
}
})
}
const prizeInfo = await this.rankOpenDao.find({ activityId: activityId, openId: this.rankOpenDao.openId }, {
projection: {
activityId: 0, openId: 0, _id: 0
},
sort:{
rankTime:-1
}
});
if (!prizeInfo.length) {
return this.resultsModel.success(null);
}
let startTime = +activityStatus["0"].startTime;
const obj = {
...prizeInfo[0],
endTime,
startTime
}
return this.resultsModel.success(obj);
} catch (e) {
return this.resultsModel.error(CODE_TYPES.ERROR_SERVER);
}
}
/**
* 获取用户当前店铺下的所有奖品列表
* @param {*} activityId
*/
async getPrizeList(activityId) {
try {
const shopId = await this.userService.getShopIdByActivity(activityId);
if (shopId) {
const activityStatus = await this.baseConfigDao.find({ _id: activityId }, { projection: { endTime: 1 } });
let endTime = +activityStatus["0"].endTime + PRIZE_GET_DELAY_TIME;
//已经过期状态
if (Date.now() >= endTime) {
let timeDate = formatTime(new Date(endTime+8*60*60*1000));
let msg = `未在${timeDate}前领取`;
await this.rankOpenDao.update({ activityId: activityId, openId: this.rankOpenDao.openId, drawStatus: { $ne: DRAW_STATUS.SUCCESS } }, {
$set: {
drawStatus: DRAW_STATUS.EXPIRED,
message: msg
}
})
}
const prizeInfo = await this.rankOpenDao.find({ shopId: shopId, openId: this.rankOpenDao.openId }, {
projection: {
openId: 0, _id: 0
},
sort:{
rankTime:-1
}
});
if (prizeInfo.length) {
let resultObj = {
list: prizeInfo,
endTime: endTime
};
return this.resultsModel.success(resultObj);
}
return this.resultsModel.success();
} else {
return this.resultsModel.error(CODE_TYPES.ERROR_NO_SHOP);
}
} catch (e) {
return this.resultsModel.error(CODE_TYPES.PARAMS_ERROR);
}
}
async collectionPrize(activityId, ename) {
try {
//先查询该用户是否有中奖纪录
const prizeInfo = await this.rankOpenDao.find({ activityId: activityId, openId: this.rankOpenDao.openId, ename: ename });
if (!prizeInfo.length) {
return this.resultsModel.error(CODE_TYPES.ERROR_NO_PRIZE);
}
const activityStatus = await this.baseConfigDao.find({ _id: activityId }, { projection: { endTime: 1 } });
let endTime = +activityStatus["0"].endTime + PRIZE_GET_DELAY_TIME;
let timeDate = formatTime(new Date(endTime+8*60*60*1000));
//已经过期状态
if (Date.now() >= endTime) {
let msg = `未在${timeDate}前领取`;
await this.rankOpenDao.update({ activityId: activityId, openId: this.rankOpenDao.openId }, {
$set: {
drawStatus: DRAW_STATUS.EXPIRED,
message: msg
}
})
return this.resultsModel.error(CODE_TYPES.ERROR_PRIZE_EXPIRED);
}
const unique_id = prizeInfo["0"]._id;
const session = await this.activityTopService.getAccessToken(activityId);
const result = await this.rankOpenDao.context.cloud.topApi.invoke({
api: 'alibaba.benefit.send',
data: {
'right_ename': ename,
'receiver_id': this.rankOpenDao.openId,
'user_type': 'taobao',
'unique_id': unique_id,
'app_name': APP_NAME,
'session': session.accessToken
}
});
//发放成功
if (result.result_success) {
await this.rankOpenDao.update({ activityId: activityId, openId: this.rankOpenDao.openId }, {
$set: {
drawStatus: DRAW_STATUS.SUCCESS,
rightId: result.right_id, //新增权益ID
message: result.result_msg
}
})
return this.resultsModel.success();
} else {
//发放失败
let drawStatus = DRAW_STATUS.FAIL;
let msg = "";
switch (result.result_code) {
case "APPLY_SINGLE_COUPON_COUNT_EXCEED_LIMIT": //用户该类型权益超过10张,请至卡券包删除无用权益继续领取
case "APPLY_ONE_SELLER_COUNT_EXCEED_LIMIT": //用户在本店铺该类型权益超过10张,请至卡券包删除无用权益继续领取
msg = `请于${timeDate}前领取`;
drawStatus = DRAW_STATUS.RETRY;
break;
case "USER_PERMISSION_EXCEED_MAX_RIGHT_COUNT_IN_DAY"://用户超过单位时间[每天]内最大权益限
msg = `请于${timeDate}前领取`;
drawStatus = DRAW_STATUS.RETRY;
break;
}
await this.rankOpenDao.update({ activityId: activityId, openId: this.rankOpenDao.openId }, {
$set: {
drawStatus: drawStatus,
message: msg ? msg : result.result_msg
}
})
return this.resultsModel.error(CODE_TYPES.ERROR_SEND_PRIZE_FAIL, msg ? msg : result.result_msg);
}
} catch (e) {
return this.resultsModel.error(CODE_TYPES.ERROR_SERVER)
}
}
}
module.exports = PrizeService;
\ No newline at end of file
const ResultsModel = require('../utils/results.model');
const { CODE_TYPES } = require('../utils/constants');
const {formatName} =require('../utils/utils');
const BaseDao = require('../dao/base.dao');
const DB_NAME = "rank_score";
const DB_BASE_CONFIG = "activity_base_config";
class RankService {
constructor(context) {
this.rankDao = new BaseDao(context, DB_NAME);
this.resultsModel=new ResultsModel();
this.baseConfigDao = new BaseDao(context, DB_BASE_CONFIG);
}
async doScoreSubmit(activityId, score, nickName, avatar) {
try {
const activityErr = await this.checkActivityStatus(activityId);
if(activityErr)
{
return this.resultsModel.error(activityErr);
}
const result = await this.rankDao.find({ activityId: activityId, openId: this.rankDao.openId });
let maxScore=score;
if (result.length) { // 用户已经存在
if (result["0"].score < score) { //当前提交的分数大于库存分数
await this.rankDao.update({ activityId: activityId, openId: this.rankDao.openId }, {
$set: {
score: score,
updateTime: Date.now(),
}
})
}else{
maxScore=result["0"].score;
}
} else {
//新用户新增记录
await this.rankDao.insertOne({
activityId: activityId,
openId: this.rankDao.openId,
userNick: nickName,
avatar: avatar,
score: score,
createTime: Date.now(),
updateTime: Date.now()
});
}
//根据自己的最高分,拿到自己的排名
let myRank= await this.rankDao.count({score:{$gt:maxScore},activityId:activityId});
myRank=myRank+1;
//根据排名,检索自己前后的用户数据
const resultList = await this.rankDao.find({ activityId: activityId }, {
projection: { score: 1, userNick: 1, avatar: 1 },
sort: { score: -1 ,updateTime:-1},
limit: 3,
skip: myRank-2
})
return this.resultsModel.success({rankList:resultList,myRank:myRank,myMaxScore:maxScore});
} catch (e) {
return this.resultsModel.error(CODE_TYPES.ERROR_SERVER);
}
}
async getRankList(activityId, page, limit) {
try {
//获取自己在当前活动的分数
const myScoreInfo = await this.rankDao.find({activityId: activityId,openId:this.rankDao.openId},
{
projection:{score:1}
});
let myScore=0;
let myRank;
if(myScoreInfo && myScoreInfo["0"])
{
myScore=myScoreInfo["0"].score
}
//获取排行版
const result = await this.rankDao.find({ activityId: activityId }, {
projection: { score: 1, userNick: 1},
sort: { score: -1 ,updateTime:1},
limit: limit,
skip: (page - 1) * limit
})
//根据自己的分数,获取排名
if(myScore)
{
let sameScoreList = await this.rankDao.find({score:myScore,activityId:activityId},{
sort:{updateTime:1}
});
let gap =0;
//说明有多个跟自己同分数的人
for(let j=0;j<sameScoreList.length;j++)
{
if(sameScoreList[j].openId == this.rankDao.openId)
{
gap=j;
}
}
myRank= await this.rankDao.count({score:{$gt:myScore},activityId:activityId});
myRank=myRank+1+gap;
}else{
myRank="100+";
}
const totalCount = await this.rankDao.count({activityId:activityId});
if(totalCount>100 && page * limit >100)
{
return this.resultsModel.success({list:[],myRank:myRank,myMaxScore:myScore,totalCount:totalCount});
}
for(var i=0;i<result.length;i++)
{
let nick = result[i].userNick;
result[i].userNick = formatName(nick);
}
return this.resultsModel.success({list:result,myRank:myRank,myMaxScore:myScore,totalCount:totalCount});
} catch (e) {
return this.resultsModel.error(CODE_TYPES.ERROR_SERVER);
}
}
/**
* 检测活动状态 - 未开始,已结束和已删除
* @param {*} activityId
*/
async checkActivityStatus(activityId)
{
const activityStatus = await this.baseConfigDao.find({_id:activityId},{projection:{deleteStatus:1,startTime: 1, endTime: 1}});
if(activityStatus.length)
{
let nowDate = Date.now();
//检测活动是否未开始
if (nowDate < +activityStatus["0"].startTime) {
return CODE_TYPES.ERROR_NO_START
}
if (nowDate >= +activityStatus["0"].endTime) {
return CODE_TYPES.ERROR_ACTIVITY_OVER
}
//检测活动是否被删除
if(activityStatus["0"].deleteStatus != 1)
{
return CODE_TYPES.ERROR_DELETE_ACTIVITY;
}
return "";
} else {
return this.resultsModel.error(CODE_TYPES.ERROR_NO_ACTIVITY);
}
}
}
module.exports = RankService;
\ No newline at end of file
// 排行榜开奖记录
const BaseDao = require('../dao/base.dao');
const { DRAW_STATUS } = require('../utils/constants');
const DBName = 'rank_open_prize';
class RankopenprizeService {
constructor(context) {
this.rankopenprizeDao = new BaseDao(context, DBName);
}
// 添加排行榜待开奖列表
async addWaitAwardsList(list) {
if (!list.length) {
return true;
}
list.map(v => {
v.drawStatus = DRAW_STATUS.WAITAWARD,
v.message = '';
});
try {
await this.rankopenprizeDao.insetMany(list);
return true;
}catch(e) {
console.log(`添加排行榜待开奖列表出错:${e}`);
return false;
}
}
// 根据活动id查找中奖名单
async getAwardslistByActivityId(activityId) {
if (!activityId) {
return false;
}
return await this.rankopenprizeDao.find({
activityId: activityId
}, {
sort: {
score: -1,
rankTime: -1
}
});
}
}
module.exports = RankopenprizeService;
\ No newline at end of file
const BaseDao = require('../dao/base.dao');
const { OPEN_PRIZE_STATUS } = require('../utils/constants');
const DBName = 'rank_scan';
class RankscanService {
constructor(context) {
this.rankscanDao = new BaseDao(context, DBName);
}
// 查询待开奖列表
async getNodifyList(serverTime) {
let list = await this.rankscanDao.find({
openPrizeTime : { $lt: serverTime },
openPrizeStatus: OPEN_PRIZE_STATUS.WAIT_AWARD
});
console.log(list);
return list;
}
// 更新openPrizeStatus为处理中
async update2Process(_id) {
try {
await this.rankscanDao.update({ _id: _id}, {
$set: {
openPrizeStatus: OPEN_PRIZE_STATUS.PROCESSING,
updateTime: Date.now()
}
});
return true;
}catch(e) {
// 日志记录
console.log(e);
return false;
}
}
// 更新openPrizeStatus为成功
async update2Success(_id) {
try {
await this.rankscanDao.update({ _id: _id}, {
$set: {
openPrizeStatus: OPEN_PRIZE_STATUS.SUCCESS,
openPrizeMsg: '',
updateTime: Date.now()
}
});
return true;
}catch(e) {
// 日志记录
console.log(e);
return false;
}
}
// 更新openPrizeStatus为失败
async update2Fail(_id, message) {
try {
await this.rankscanDao.update({ _id: _id}, {
$set: {
openPrizeStatus: OPEN_PRIZE_STATUS.FAIL,
openPrizeMsg: message || '',
updateTime: Date.now()
}
});
return true;
}catch(e) {
// 日志记录
console.log(e);
return false;
}
}
}
module.exports = RankscanService;
\ No newline at end of file
const BaseDao = require('../dao/base.dao');
const DBName = 'rank_score';
class RankscoreService {
constructor(context) {
this.rankscoreDao = new BaseDao(context, DBName);
}
// 根据活动id查询分数排行榜
async getToplistByActivityId(activityId, totalAwards) {
let list = await this.rankscoreDao.find({
activityId: activityId
}, {
sort: {
score: -1,
updateTime: 1
},
limit: +totalAwards
});
console.log(`getToplistByActivityId: ${JSON.stringify(list)}`);
return list;
}
}
module.exports = RankscoreService;
\ No newline at end of file
const ResultsModel = require('../utils/results.model');
const { CODE_TYPES, SHARE_TOTAL_COUNT ,TASK_ADD_POWER} = require('../utils/constants');
const { getDayByTimeFix } = require('../utils/utils');
const BaseDao = require('../dao/base.dao');
const DB_SHAREID = "pl2c_shareidsave"; // 用户shareid保存表
const DB_SHARERECORD = "pl2c_sharerecord"; //用户分享受邀记录表
const DB_TASK = "pl2c_task";
const DB_USER = "pl2c_user";
class ShareService {
constructor(context) {
this.shareIdDao = new BaseDao(context, DB_SHAREID);
this.shareRecordDao = new BaseDao(context, DB_SHARERECORD);
this.taskDao = new BaseDao(context, DB_TASK);
this.resultsModel = new ResultsModel();
this.userDao = new BaseDao(context, DB_USER);
}
async getShareId(activityId) {
try {
let result = await this.shareIdDao.find({ activityId: activityId, openId: this.shareIdDao.openId }, {
projection: { shareId: 1 }
});
//已经存在有shareId,直接返回
if (result["0"]) {
let shareId = result["0"].shareId;
return this.resultsModel.success({ shareId: shareId });
}
const day = getDayByTimeFix(Date.now());
//新建shareId,并且插入数据
let shareId = this.shareIdDao.openId;
await this.shareIdDao.insertOne({
activityId: activityId,
openId: this.shareIdDao.openId,
shareId: shareId,
day: day,
createTime: Date.now(),
updateTime: Date.now()
});
return this.resultsModel.success({ shareId: shareId });
} catch (e) {
return this.resultsModel.error(CODE_TYPES.ERROR_SERVER);
}
}
async doShareComplete(activityId, shareId) {
try {
//根据shareId查询来源openId
let fromUser = await this.shareIdDao.find({ activityId: activityId, shareId: shareId });
if (!fromUser || !fromUser["0"]) {
console.log(`该分享id不存在${shareId}`);
//该分享ID不存在
return this.resultsModel.error(CODE_TYPES.ERROR_NO_SHAREID);
}
let fromOpenId = fromUser["0"].openId;
//自己打开自己分享的链接,直接提示无法邀请自己
if (fromOpenId === this.shareRecordDao.openId) {
console.log(`自己打开自己分享的链接${shareId}`);
// return this.resultsModel.success();
return this.resultsModel.error(CODE_TYPES.ERROR_SHARE_SELF);
}
// 受邀用户是否已经助力过
let shareedInfo = await this.shareRecordDao.find({ activityId: activityId, shareId: shareId, receiveOpenId: this.shareRecordDao.openId });
if (shareedInfo["0"]) {
console.log(`受邀用户已经助力过${shareId}`);
// return this.resultsModel.success();
return this.resultsModel.error(CODE_TYPES.ERROR_SHARE_DID);
}
const day = getDayByTimeFix(Date.now());
let count = await this.shareRecordDao.count({ activityId: activityId, shareId: shareId, day: day });
//记录受邀信息
await this.shareRecordDao.insertOne({
activityId: activityId,
openId: fromOpenId,
shareId: shareId,
day: day,
receiveOpenId: this.shareRecordDao.openId,
createTime: Date.now(),
updateTime: Date.now()
});
//邀请人数超过任务要求的话,插入数据,正常提示成功
if (count && count >= SHARE_TOTAL_COUNT) {
console.log(`邀请人数超过任务要求的话,插入数据${shareId}`);
// return this.resultsModel.success();
return this.resultsModel.error(CODE_TYPES.ERROR_SHARE_DONE);
}
let newCount = count + 1;
//更新任务完成状态
let friendInfo = await this.taskDao.find({ activityId: activityId, openId: fromOpenId, taskName: "inviteFriends", day: day });
//已有记录直接更新
if (friendInfo["0"]) {
await this.taskDao.update({ activityId: activityId, openId: fromOpenId, taskName: "inviteFriends", day: day }, {
$set: {
hasInviteCount: newCount,
isComplete: newCount >= SHARE_TOTAL_COUNT
}
})
} else {
await this.taskDao.insertOne({
activityId: activityId,
openId: fromOpenId,
taskName: "inviteFriends",
hasInviteCount: newCount,
day: day,
isComplete: newCount >= SHARE_TOTAL_COUNT,
createTime: Date.now(),
updateTime: Date.now()
})
}
const userInfo = await this.userDao.find({ openId: fromOpenId, activityId: activityId }, {
projection: { power: 1 }
})
//更新用户体力值
let newPower = userInfo["0"].power + TASK_ADD_POWER;
console.log(`用户最新体力值:${newPower}`);
await this.userDao.update({ openId: fromOpenId, activityId: activityId },
{
$set: {
power: newPower,
updateTime:Date.now()
}
})
return this.resultsModel.success();
} catch (e) {
return this.resultsModel.error(CODE_TYPES.ERROR_SERVER);
}
}
}
module.exports = ShareService;
\ No newline at end of file
const StatPvuvService = require('./statpvuv.service');
const StatItemService = require('./statitem.service');
const ResultsModel = require('../utils/results.model');
const BaseDao = require('../dao/base.dao');
const DB_TASK = "pl2c_task";
const DB_BASE_CFG = "activity_base_config";
const DB_SHAREID = "pl2c_shareidsave"; // 用户shareid保存表
const DB_SHARERECORD = "pl2c_sharerecord"; //用户分享受邀记录表
const DB_OPEN_PRIZE = "rank_open_prize"; //开奖表
const { getdaystarttime, getdayendtime, getDayByTimeFix } = require('../utils/utils');
const { CODE_TYPES,DRAW_STATUS} = require('../utils/constants');
class StatExportService {
constructor(context) {
this.pvService = new StatPvuvService(context);
this.itemService = new StatItemService(context);
this.taskDao = new BaseDao(context, DB_TASK);
this.baseCfgDao = new BaseDao(context, DB_BASE_CFG);
this.shareRecordDao = new BaseDao(context, DB_SHARERECORD);
this.shareIdDao = new BaseDao(context, DB_SHAREID);
this.openPrizeDao = new BaseDao(context,DB_OPEN_PRIZE);
this.resultsModel = new ResultsModel();
}
//数据总览
async statTotalData(activityId) {
try {
//打开活动次数
let totalOpenCount = 0;
//活动参与次数
let totalJoinCount = 0;
let joinData = await this.statJoinData(activityId);
console.log("joinData...",joinData);
joinData=joinData.data;
console.log("joinData1111...",joinData);
for (let date in joinData) {
totalOpenCount += joinData[date].openCount;
totalJoinCount += joinData[date].joinCount;
}
//新增会员数
let newMemberCount = 0;
//新增关注数
let newAttentionStoreCount = 0;
let taskData = await this.statTaskData(activityId);
taskData=taskData.data;
for (let date in taskData) {
newMemberCount += taskData[date].beMemeberCount;
newAttentionStoreCount += taskData[date].attentionStoreCount;
}
//商品曝光数量
let itemShowCount = 0;
let itemData = await this.statItemData(activityId);
itemData=itemData.data;
for (let date in itemData) {
itemShowCount += itemData[date].itemShowCount;
}
let obj = {
totalOpenCount,
totalJoinCount,
newMemberCount,
newAttentionStoreCount,
itemShowCount
}
return this.resultsModel.success(obj);
} catch (e) {
return this.resultsModel.error(CODE_TYPES.ERROR_SERVER);
}
}
//参与数据
async statJoinData(activityId) {
try {
const cfgInfo = await this.baseCfgDao.findOne({ _id: activityId }, {
projection: { startTime: 1, endTime: 1 }
});
const startTime = cfgInfo.startTime; // 活动开始时间戳
const endTime = cfgInfo.endTime; // 活动结束时间戳
const startDay = getDayByTimeFix(startTime); //活动开始日期
const endDay = getDayByTimeFix(endTime); //活动结束日期
let beginStamp = getdaystarttime(startDay); //活动开始日期的0点
let endStamp = getdayendtime(endDay); //活动结束日期的24点
let time = beginStamp;
let list = {};
do {
//日期
let date = getDayByTimeFix(time);
//打开人数
let openUV = await this.pvService.getOpenUV(activityId, date);
//打开次数
let openCount = await this.pvService.getOpenCount(activityId, date);
//参与人数
let joinUV = await this.pvService.getJoinUV(activityId, date);
//参与次数
let joinCount = await this.pvService.getJoinCount(activityId, date);
//人均参与数
let joinRate = joinUV == 0?"0":(joinCount / joinUV).toFixed(2);
list[date] = {
openUV,
openCount,
joinUV,
joinCount,
joinRate
}
time += 24 * 60 * 60 * 1000;
} while (time < endStamp);
return this.resultsModel.success(list);
} catch (e) {
return this.resultsModel.error(CODE_TYPES.ERROR_SERVER);
}
}
//任务数据
async statTaskData(activityId) {
try {
const cfgInfo = await this.baseCfgDao.findOne({ _id: activityId }, {
projection: { startTime: 1, endTime: 1 }
});
const startTime = cfgInfo.startTime; // 活动开始时间戳
const endTime = cfgInfo.endTime; // 活动结束时间戳
const startDay = getDayByTimeFix(startTime); //活动开始日期
const endDay = getDayByTimeFix(endTime); //活动结束日期
let beginStamp = getdaystarttime(startDay); //活动开始日期的0点
let endStamp = getdayendtime(endDay); //活动结束日期的24点
let time = beginStamp;
let list = {};
let taskInfo = this.taskDao.find({ activityId: activityId, isComplete: true }, {
projection: { _id: 0 }
});
const taskInfoLen = taskInfo.length;
do {
//日期
let date = getDayByTimeFix(time);
//发起邀请人数
let doShareCount = await this.shareIdDao.count({ activityId: activityId, day: date });
//成功邀请人数
let friendsCount = await this.shareRecordDao.count({ activityId: activityId, day: date });
//新增会员数
// let beMemeberCount = 0;
let beMemeberCount = await this.taskDao.count({ activityId: activityId, isComplete: true, statDay: date, taskName: "beMembership" });
//关注店铺数
// let attentionStoreCount = 0;
let attentionStoreCount = await this.taskDao.count({ activityId: activityId, isComplete: true, statDay: date, taskName: "attentionStore" });
//浏览指定页面人数
let pageUrlUVArr = await this.taskDao.find({ activityId: activityId, isComplete: true, taskName: "specifyPageUrl", day: date }, {
projection: { _id: 0, openId: 1 }
});
let lenArr=[];
for(let i=0;i<pageUrlUVArr.length;i++)
{
lenArr.push(pageUrlUVArr[i]["openId"]);
}
let pageUrlUV = [...new Set(lenArr)].length;
//浏览指定页面次数
let pageUrlCount = 0;
for (let i = 0; i < taskInfoLen; i++) {
let task = taskInfo[i];
switch (task.taskName) {
case "specifyPageUrl":
pageUrlCount += 1;
break;
}
}
list[date] = {
doShareCount,
friendsCount,
beMemeberCount,
attentionStoreCount,
pageUrlUV,
pageUrlCount
}
time += 24 * 60 * 60 * 1000;
} while (time < endStamp);
return this.resultsModel.success(list);
} catch (e) {
return this.resultsModel.error(CODE_TYPES.ERROR_SERVER);
}
}
//商品曝光数据
async statItemData(activityId) {
try {
const cfgInfo = await this.baseCfgDao.findOne({ _id: activityId }, {
projection: { startTime: 1, endTime: 1 }
});
const startTime = cfgInfo.startTime; // 活动开始时间戳
const endTime = cfgInfo.endTime; // 活动结束时间戳
const startDay = getDayByTimeFix(startTime); //活动开始日期
const endDay = getDayByTimeFix(endTime); //活动结束日期
let beginStamp = getdaystarttime(startDay); //活动开始日期的0点
let endStamp = getdayendtime(endDay); //活动结束日期的24点
let time = beginStamp;
let list = {};
do {
//日期
let date = getDayByTimeFix(time);
//商品曝光数量
let itemShowCount = await this.itemService.getItemShowCount(activityId, date);
//商品点击次数
let itemTapCount = await this.itemService.getItemTapCount(activityId, date);
//商品点击人数
let itemTapUV = await this.itemService.getItemTapUV(activityId, date);
list[date] = {
itemShowCount,
itemTapCount,
itemTapUV
}
time += 24 * 60 * 60 * 1000;
} while (time < endStamp);
return this.resultsModel.success(list);
} catch (e) {
return this.resultsModel.error(CODE_TYPES.ERROR_SERVER);
}
//奖品成功领取人数----暂无
}
//奖品数据
async statPrizeData(activityId)
{
let prizeInfo = await this.openPrizeDao.find({activityId:activityId});
console.log("prizeInfo..",prizeInfo);
//中奖人数
let winningUV = 0;
let winningArr=[];
//奖品成功领取人数
let collectionUV=0;
let collectionArr=[];
for(let i=0;i<prizeInfo.length;i++)
{
winningArr.push(prizeInfo[i].openId);
if(prizeInfo[i].drawStatus == DRAW_STATUS.SUCCESS)
{
collectionArr.push(prizeInfo[i].openId);
}
}
winningUV = [...new Set(winningArr)].length;
collectionUV=[...new Set(collectionArr)].length;
let obj = {
winningUV,
collectionUV
}
return this.resultsModel.success(obj);
}
//TODO 参与用户名单
async statJoinDetailData(activityId)
{
//参与usernick
//首次参与时间
//漂流最远距离
//排名
//奖品名称
//是否领取
//领取状态
}
}
module.exports = StatExportService;
\ No newline at end of file
const BaseDao = require('../dao/base.dao');
const DB_NAME = "stat_item"; //主要是奖品
const { getDayByTimeFix } = require('../utils/utils');
class StatItemService {
constructor(context) {
this.itemDao = new BaseDao(context, DB_NAME);
}
async itemShow(activityId) {
const date = getDayByTimeFix(Date.now());
await this.itemDao.insertOne({
activityId: activityId,
openId: this.itemDao.openId,
day: date,
type:"show",
createTime: Date.now()
});
}
async itemTap(activityId) {
const date = getDayByTimeFix(Date.now());
await this.itemDao.insertOne({
activityId: activityId,
openId: this.itemDao.openId,
day: date,
type:"tap",
createTime: Date.now()
});
}
async getItemShowCount(activityId,day)
{
return await this.itemDao.count({activityId:activityId,day:day,type:"show"});
}
async getItemTapCount(activityId,day)
{
return await this.itemDao.count({activityId:activityId,day:day,type:"tap"});
}
async getItemTapUV(activityId,day)
{
let list = await this.itemDao.find({activityId:activityId,day:day,type:"tap"},{
projection:{_id:0,openId:1}
});
let arr=[];
for(let i=0;i<list.length;i++)
{
arr.push(list[i]["openId"]);
}
return [...new Set(arr)].length;
}
}
module.exports = StatItemService;
\ No newline at end of file
/**
* 主要记录打开和参与的用户数据
*
*/
const BaseDao = require('../dao/base.dao');
const {getDayByTimeFix} =require('../utils/utils');
const DB_NAME="stat_pvuv";
class StatPvuvService
{
constructor(context)
{
this.statDao=new BaseDao(context,DB_NAME);
}
/**
* 记录用户打开数据
* @param {*} activityId
* @param {*} nickName
*/
async insertUserOpenData(activityId,nickName)
{
let day=getDayByTimeFix(Date.now());
this.statDao.insertOne({
activityId:activityId,
nickName:nickName,
openId:this.statDao.openId,
createTime:Date.now(),
updateTime:Date.now(),
day:day,
type:"open"
})
}
async insertUserJoinData(activityId,nickName)
{
let day=getDayByTimeFix(Date.now());
this.statDao.insertOne({
activityId:activityId,
nickName:nickName,
openId:this.statDao.openId,
createTime:Date.now(),
updateTime:Date.now(),
day:day,
type:"join"
})
}
/**
* 打开人数
* @param {*} activityId
* @param {*} day
*/
async getOpenUV(activityId,day)
{
let infoList = await this.statDao.find({activityId:activityId,day:day,type:"open"},{
projection:{_id:0,openId:1}
})
let openIdArr=[];
for(let i=0;i<infoList.length;i++)
{
openIdArr.push(infoList[i]["openId"]);
}
return [...new Set(openIdArr)].length;
}
async getOpenCount(activityId,day)
{
if(day)
{
return await this.statDao.count({activityId:activityId,day:day,type:"open"});
}
return await this.statDao.count({activityId:activityId,type:"open"});
}
/**
* 参与人数UV
* @param {*} activityId
* @param {*} startTime
* @param {*} endTime
*/
async getJoinUV(activityId,day)
{
let infoList = await this.statDao.find({activityId:activityId,day:day,type:"join"},{
projection:{_id:0,openId:1}
})
let openIdArr=[];
for(let i=0;i<infoList.length;i++)
{
openIdArr.push(infoList[i]["openId"]);
}
return [...new Set(openIdArr)].length;
}
/**
*
* 参与次数
* @param {*} activityId
* @param {*} startTime
* @param {*} endTime
*/
async getJoinCount(activityId,day)
{
if(day)
{
return await this.statDao.count({activityId:activityId,day:day,type:"join"});
}
return await this.statDao.count({activityId:activityId,type:"join"});
}
}
module.exports=StatPvuvService;
\ No newline at end of file
const ResultsModel = require('../utils/results.model');
const { CODE_TYPES, SHARE_TOTAL_COUNT, TASK_ADD_POWER } = require('../utils/constants');
const { getDayByTimeFix } = require("../utils/utils");
const ActivityTopService = require("./activitytop.service");
const BaseDao = require('../dao/base.dao');
const DB_TASK = "pl2c_task";
const DB_USER = "pl2c_user";
const DB_activity_base_config = "activity_base_config";
class TaskService {
constructor(context) {
this.taskDao = new BaseDao(context, DB_TASK);
this.userDao = new BaseDao(context, DB_USER);
this.taskConfigDao = new BaseDao(context, DB_activity_base_config);
this.resultsModel = new ResultsModel();
this.activityTopService = new ActivityTopService(context);
}
/**
* 每日重置任务,目前只有浏览指定页面任务
* @param {*} context
*/
async resetTaskStatus(activityId) {
return await this.resetTaskStatus(activityId, "specifyPageUrl");
}
async getTaskList(activityId) {
try {
const taskConfig = await this.taskConfigDao.find({ _id: activityId }, {
projection: { taskInfo: 1 }
})
const day = getDayByTimeFix(Date.now());
let taskList1 = await this.taskDao.find({ activityId: activityId, openId: this.taskDao.openId, day: { $exists: false } }) || [];
let taskList2 = await this.taskDao.find({ activityId: activityId, openId: this.taskDao.openId, day: day }) || [];
const taskList = taskList1.concat(taskList2);
console.log("day..",day);
console.log("taskList1.================.",taskList1);
console.log("taskList2..-------------",taskList2);
if (!taskConfig.length) {
return this.resultsModel.error(CODE_TYPES.ERROR_NO_TASK);
} else {
var result = {};
const taskConfigInfo = taskConfig["0"].taskInfo;
for (const taskname in taskConfigInfo) {
if (taskConfigInfo.hasOwnProperty(taskname)) {
const task = taskConfigInfo[taskname];
if (task) {
if (!result[`${taskname}`]) result[`${taskname}`] = {};
result[`${taskname}`].content = task;
result[`${taskname}`].isComplete = false;
switch (taskname) {
case "inviteFriends":
result[`${taskname}`].hasInviteCount = 0;
result[`${taskname}`].totalInviteCount = SHARE_TOTAL_COUNT;
break;
case "browseItemIds":
result["browseItemIds"].content = [];
const itemsInfoList = await this.activityTopService.getItemListByIds(activityId, task);
if (itemsInfoList.code == 10000) {
result["browseItemIds"].content = itemsInfoList.data.list || [];
} else {
console.log(`获取browseItemIds奖品信息失败`);
}
break;
case "beMembership":
result["beMembership"].content = "";
try {
const vipUrlData = await this.activityTopService.getVipUrlByActivity(activityId);
console.log("vipUrlData.......", vipUrlData);
result["beMembership"].content = vipUrlData.data.result.result;
} catch (e) {
console.log(`获取VIP链接失败`)
}
break;
}
for (var i = 0; i < taskList.length; i++) {
if (taskList[i].taskName == taskname) {
result[`${taskname}`].isComplete = taskList[i][`isComplete`];
if (taskname == "inviteFriends") {
result[`${taskname}`].hasInviteCount = taskList[i]["hasInviteCount"];
}
}
}
}
}
}
}
return this.resultsModel.success(result);
} catch (e) {
return this.resultsModel.error(CODE_TYPES.ERROR_SERVER);
}
}
/**
* 获取用户当前是否已经是会员
* @param {} activityId
*/
async checkMember(activityId) {
try {
let { mixNick } = this.taskDao.context;
const session = await this.activityTopService.getAccessToken(activityId);
const result = await this.taskDao.context.cloud.topApi.invoke({
api: 'taobao.crm.member.identity.get',
data: {
'mix_nick':mixNick,
'session':session.accessToken
}
});
console.log("result--------",result)
if(result.result.member_info)
{
return this.resultsModel.success(result.member_info)
}
return this.resultsModel.error(CODE_TYPES.ERROR_NO_VIP);
} catch (e) {
console.log("isInitVip error.......");
return this.resultsModel.error(CODE_TYPES.ERROR_NO_VIP);
}
}
async doTaskComplete(activityId, taskName) {
try {
const activityErr = await this.checkActivityStatus(activityId);
if(activityErr)
{
return this.resultsModel.error(activityErr);
}
const dayStr = getDayByTimeFix(Date.now());
let taskList = [];
let insertObj = {};
if (taskName == "specifyPageUrl") //浏览指定页面,每日任务,需要保存day值
{
taskList = await this.taskDao.find({ activityId: activityId, openId: this.taskDao.openId, isComplete: true, taskName: taskName, day: dayStr });
insertObj = {
activityId: activityId,
openId: this.taskDao.openId,
taskName: taskName,
isComplete: true,
day: dayStr,
createTime: Date.now(),
updateTime: Date.now()
}
} else { //永久一次性任务,不需要保存day值
taskList = await this.taskDao.find({ activityId: activityId, openId: this.taskDao.openId, isComplete: true, taskName: taskName });
insertObj = {
activityId: activityId,
openId: this.taskDao.openId,
taskName: taskName,
isComplete: true,
statDay:dayStr, //用于数据统计
createTime: Date.now(),
updateTime: Date.now()
}
}
if (taskList.length) {
//该任务已经完成
return this.resultsModel.error(CODE_TYPES.ERROR_TASK_DONE);
}
//检查当前是否已经成为了会员
if(taskName == "beMembership")
{
const {code} = await this.checkMember(activityId);
if(+code != 10000) return this.resultsModel.error(CODE_TYPES.ERROR_NO_VIP);
}
//
const taskConfig = await this.taskConfigDao.find({ _id: activityId }, {
projection: { taskInfo: 1 }
})
//校验该任务是否存在
if (taskConfig[0] && taskConfig[0].taskInfo && taskConfig[0].taskInfo[`${taskName}`]) {
const taskConfigInfo = taskConfig["0"].taskInfo;
if (taskConfigInfo.hasOwnProperty(taskName)) {
await this.taskDao.insertOne(insertObj)
//更新体力值
try {
const userInfo = await this.userDao.find({ openId: this.userDao.openId, activityId: activityId }, {
projection: { power: 1 }
})
if (userInfo["0"]) {
let newPower = userInfo["0"].power + TASK_ADD_POWER;
await this.userDao.update({ openId: this.userDao.openId, activityId: activityId },
{
$set: {
power: newPower
}
})
return this.resultsModel.success({ power: newPower });
} else {
//该用户不存在
return this.resultsModel.error(CODE_TYPES.ERROR_NO_USER);
}
} catch (e) {
return this.resultsModel.error(CODE_TYPES.ERROR_SERVER);
}
} else {
//该任务不存在
return this.resultsModel.error(CODE_TYPES.ERROR_NO_TASK);
}
}
//该任务不存在
return this.resultsModel.error(CODE_TYPES.ERROR_NO_TASK);
} catch (e) {
this.resultsModel.error(CODE_TYPES.ERROR_SERVER);
}
}
/**
* 如果用户在活动之前就已经是会员或者已经关注过店铺了,任务直接完成,但是不加体力值
* @param {*} activityId
* @param {*} taskName
*/
async updateTaskStatus(activityId, taskName) {
try {
const taskList = await this.taskDao.find({ activityId: activityId, openId: this.taskDao.openId, taskName: taskName });
if (taskList["0"]) {
//该任务已经完成
return this.resultsModel.error(CODE_TYPES.ERROR_TASK_DONE);
}
//
const taskConfig = await this.taskConfigDao.find({ _id: activityId }, {
projection: { taskInfo: 1 }
})
// const dayStr = getDayByTimeFix(Date.now());
//校验该任务是否存在
if (taskConfig[0] && taskConfig[0].taskInfo && taskConfig[0].taskInfo[`${taskName}`]) {
const taskConfigInfo = taskConfig["0"].taskInfo;
if (taskConfigInfo.hasOwnProperty(taskName)) {
await this.taskDao.insertOne({
activityId: activityId,
openId: this.taskDao.openId,
taskName: taskName,
isComplete: true,
createTime: Date.now(),
updateTime: Date.now()
})
return this.resultsModel.success();
} else {
//该任务不存在
return this.resultsModel.error(CODE_TYPES.ERROR_NO_TASK);
}
}
//该任务不存在
return this.resultsModel.error(CODE_TYPES.ERROR_NO_TASK);
} catch (e) {
this.resultsModel.error(CODE_TYPES.ERROR_SERVER);
}
}
async resetTaskStatus(activityId, taskName) {
try {
const taskList = await this.taskDao.find({ activityId: activityId, openId: this.taskDao.openId, taskName: taskName });
if (taskList["0"]) {
return await this.taskDao.deleteMany({ activityId: activityId, openId: this.taskDao.openId, taskName: taskName });
}
} catch (e) {
console.log(`重置${activityId}每日${taskName}任务失败`);
}
}
/**
* 检测活动状态 - 未开始,已结束和已删除
* @param {*} activityId
*/
async checkActivityStatus(activityId)
{
const activityStatus = await this.taskConfigDao.find({_id:activityId},{projection:{deleteStatus:1,startTime: 1, endTime: 1}});
if(activityStatus.length)
{
let nowDate = Date.now();
//检测活动是否未开始
if (nowDate < +activityStatus["0"].startTime) {
return CODE_TYPES.ERROR_NO_START
}
if (nowDate >= +activityStatus["0"].endTime) {
return CODE_TYPES.ERROR_ACTIVITY_OVER
}
//检测活动是否被删除
if(activityStatus["0"].deleteStatus != 1)
{
return CODE_TYPES.ERROR_DELETE_ACTIVITY;
}
return "";
} else {
return this.resultsModel.error(CODE_TYPES.ERROR_NO_ACTIVITY);
}
}
}
module.exports = TaskService;
const { isNewDay } = require("../utils/utils");
const ResultsModel = require('../utils/results.model');
const { CODE_TYPES } = require('../utils/constants');
const BaseDao = require('../dao/base.dao');
const { OPEN_PRIZE_STATUS } = require("../utils/constants");
const TaskService = require("./task.service");
const ActivityTopService = require("./activitytop.service");
const StatPvuvService = require("./statpvuv.service");
const DB_NAME = "pl2c_user";
const DB_RANK_SCAN = "rank_scan";
const DB_BASE_CONFIG = "activity_base_config";
const INIT_POWER = 30; //初始体力值
class UserService {
constructor(context) {
this.userDao = new BaseDao(context, DB_NAME);
this.rankScanDao = new BaseDao(context, DB_RANK_SCAN);
this.baseConfigDao = new BaseDao(context, DB_BASE_CONFIG);
this.resultsModel = new ResultsModel();
this.taskService = new TaskService(context);
this.activityTopService = new ActivityTopService(context);
this.statPvuvService=new StatPvuvService(context);
}
/**
* 获取用户当前是否已经是会员
* @param {} activityId
*/
async isInitVip(activityId) {
try {
const session = await this.activityTopService.getAccessToken(activityId);
let { mixNick } = this.userDao.context;
const result = await this.userDao.context.cloud.topApi.invoke({
api: 'taobao.crm.member.identity.get',
data: {
'mix_nick':mixNick,
'session':session.accessToken
}
});
console.log("result--------",result)
if(result.result.member_info)
{
await this.taskService.updateTaskStatus(activityId, "beMembership");
}
} catch (e) {
console.log("isInitVip error.......");
}
}
/**
* 登录
* @param {*} activityId
* @param {*} nickName
* @param {*} avatar
*/
async login(activityId, nickName, avatar, isFavor) {
try {
// const activityErr = await this.checkActivityStatus(activityId);
// if(activityErr)
// {
// return this.resultsModel.error(activityErr);
// }
let isNewGuy = true;
const newUserInfo = await this.userDao.find({
openId: this.userDao.openId
});
if (newUserInfo["0"] && newUserInfo["0"].openId) //所有活动下的老用户
{
isNewGuy = false;
}
console.log("isNewGuy...",isNewGuy);
const userInfo = await this.userDao.find({ openId: this.userDao.openId, activityId: activityId });
console.log("userinfo....",userInfo);
if (userInfo.length)//当前活动的老用户
{
let isResetPower = isNewDay(userInfo["0"].updateTime);//是否当天首次登录,
console.log("isResetPower...",isResetPower)
let power = userInfo["0"].power;
if (isResetPower) {
//是--重置每日任务 不需要重置了,这里任务根据日期判定
// await this.taskService.resetTaskStatus(this.userDao.context);
//是--重置体力值
const result = await this.userDao.update({ openId: this.userDao.openId, activityId: activityId }, {
$set: {
updateTime: Date.now(),
power: INIT_POWER
}
})
power = INIT_POWER;
}
return this.resultsModel.success({ isNewGuy: isNewGuy, power: power, openId: this.userDao.openId });
} else { //新用户
//活动新开始,第一个用户进入
const rankscanCount = await this.rankScanDao.count({ activityId: activityId });
if (!rankscanCount) {
const baseConfig = await this.baseConfigDao.find({ _id: activityId }, {
projection: { startTime: 1, endTime: 1, shopId: 1 }
})
if (baseConfig["0"]) {
let nowDate = Date.now();
if (nowDate >= +baseConfig["0"].startTime) {
await this.rankScanDao.insertOne({
activityId: activityId,
openPrizeTime: baseConfig["0"].endTime,
openPrizeStatus: OPEN_PRIZE_STATUS.WAIT_AWARD,
openPrizeMsg: "",
shopId: baseConfig["0"].shopId,
updateTime: Date.now()
})
} else {
//活动暂未开始
return this.resultsModel.error(CODE_TYPES.ERROR_NO_START);
}
} else {
return this.resultsModel.error(CODE_TYPES.ERROR_NO_ACTIVITY);
}
}
//活动开始之前就已经关注过店铺了,任务直接完成,但是不加体力值
if (isFavor) {
try {
await this.taskService.updateTaskStatus(activityId, "attentionStore");
} catch (e) {
}
}
//活动开始已经是会员了,任务直接完成,但是不加体力值
try {
await this.isInitVip(activityId);
} catch (e) {
}
//插入用户数据
try {
await this.userDao.insertOne({
activityId: activityId,
openId: this.userDao.openId,
nickName: nickName,
avatar: avatar,
power: INIT_POWER,
createTime: Date.now(),
updateTime: Date.now()
});
return this.resultsModel.success({ isNewGuy: isNewGuy, power: INIT_POWER, openId: this.userDao.openId });
} catch (e) {
return this.resultsModel.error(CODE_TYPES.ERROR_SERVER);
}
}
} catch (e) {
return this.resultsModel.error(CODE_TYPES.ERROR_SERVER);
}
}
async getPower(activityId) {
try {
const userInfo = await this.userDao.find({ openId: this.userDao.openId, activityId: activityId }, {
projection: { power: 1 }
})
if (userInfo["0"]) {
return this.resultsModel.success({ power: userInfo["0"].power })
} else {
return this.resultsModel.error(CODE_TYPES.ERROR_NO_USER);
}
} catch (e) {
return this.resultsModel.error(CODE_TYPES.ERROR_SERVER);
}
}
async startGame(activityId,nickName) {
try {
await this.statPvuvService.insertUserJoinData(activityId,nickName);
const activityErr = await this.checkActivityStatus(activityId);
if(activityErr)
{
return this.resultsModel.error(activityErr);
}
const userInfo = await this.userDao.find({ openId: this.userDao.openId, activityId: activityId }, {
projection: { power: 1 }
})
let curPower = userInfo["0"].power;
if (userInfo["0"] && curPower >= 10) {
await this.userDao.update({ openId: this.userDao.openId, activityId: activityId },
{
$set: {
power: curPower - 10
}
})
return this.resultsModel.success({ power: curPower - 10 });
} else {
//体力值不足
return this.resultsModel.error(CODE_TYPES.ERROR_NO_POWER);
}
} catch (e) {
return this.resultsModel.error(CODE_TYPES.ERROR_SERVER);
}
}
/**
*
* @param {活动id} activityId
* @param {新增或者减少的体力值} powerGap
*/
async updatePower(activityId, powerGap) {
try {
const userInfo = await this.userDao.find({ openId: this.userDao.openId, activityId: activityId }, {
projection: { power: 1 }
})
if (userInfo["0"]) {
let newPower = userInfo["0"].power + powerGap;
await this.userDao.update({ openId: this.userDao.openId, activityId: activityId },
{
$set: {
power: newPower
}
})
return newPower;
} else {
//该用户不存在
return this.resultsModel.error(CODE_TYPES.ERROR_NO_USER);
}
} catch (e) {
return this.resultsModel.error(CODE_TYPES.ERROR_SERVER);
}
}
/**
* 检测活动状态 - 未开始,已结束和已删除
* @param {*} activityId
*/
async checkActivityStatus(activityId)
{
const activityStatus = await this.baseConfigDao.find({_id:activityId},{projection:{deleteStatus:1,startTime: 1, endTime: 1}});
if(activityStatus.length)
{
let nowDate = Date.now();
//检测活动是否未开始
if (nowDate < +activityStatus["0"].startTime) {
return CODE_TYPES.ERROR_NO_START
}
if (nowDate >= +activityStatus["0"].endTime) {
return CODE_TYPES.ERROR_ACTIVITY_OVER
}
//检测活动是否被删除
if(activityStatus["0"].deleteStatus != 1)
{
return CODE_TYPES.ERROR_DELETE_ACTIVITY;
}
return "";
} else {
return this.resultsModel.error(CODE_TYPES.ERROR_NO_ACTIVITY);
}
}
/**
* 获取用户的shopId
* @param {*} activityId
*/
async getShopIdByActivity(activityId)
{
try{
const userInfo= await this.baseConfigDao.find({_id:activityId},{
projection:{shopId:1}
})
console.log("userInfo...",userInfo);
if(userInfo.length)
{
return userInfo["0"].shopId;
}else{
return "";
}
}catch(e)
{
return "";
}
}
}
module.exports = UserService;
\ No newline at end of file
// 活动开奖状态码
const OPEN_PRIZE_STATUS = {
// 待开奖
WAIT_AWARD: 1,
// 开奖中
PROCESSING: 2,
// 开奖成功
SUCCESS: 3,
// 开奖失败
FAIL: 4
};
// 领取奖品状态
const DRAW_STATUS = {
// 待领取
WAITAWARD: 1,
// 处理中
PROCESSING: 2,
// 领取成功
SUCCESS: 3,
// 领取失败
FAIL: 4,
// 已过期
EXPIRED: 5,
// 重新领取
RETRY: 6
}
// 日志类型: error,info
const LOGGER_TYPE = {
ERROR: 1,
INFO: 2
}
// code类型
const CODE_TYPES = {
PARAMS_ERROR: {
code: '100000',
defaultMsg: `参数错误`
},
SYSTEM_ERROR: {
code: '500000',
defaultMsg: `系统错误`
},
SUCCESS: {
code: '000000',
defaultMsg: `成功`
},
// TODO 补充业务类型错误, 固定以2开头,如B端业务错误:200001,200002,C端业务错误:210001,210002
ERROR_SERVER: {
code: '210001',
defaultMsg: `服务器异常`
},
ERROR_NO_USER: {
code: '210002',
defaultMsg: `用户不存在`
},
ERROR_INVITE_LIMIT: {
code: '210003',
defaultMsg: `邀请已达上限`
},
ERROR_INVITE_SELF: {
code: '210004',
defaultMsg: `无法邀请自己`
},
ERROR_TASK_DONE: {
code: '210005',
defaultMsg: `该任务已经完成`
},
ERROR_NO_ACTIVITY: {
code: '210006',
defaultMsg: `该活动ID无效`
},
ERROR_NO_TASK: {
code: '210007',
defaultMsg: `该任务不存在`
},
ERROR_NO_POWER: {
code: '210008',
defaultMsg: `体力值不足`
},
ERROR_NO_START: {
code: '210009',
defaultMsg: `该活动暂未开始`
},
ERROR_NO_SHAREID: {
code: '210010',
defaultMsg: `该分享ID不存在`
},
ERROR_NO_TASK: {
code: '210011',
defaultMsg: `该活动无任务`
},
ERROR_NO_PRIZE: {
code: '210012',
defaultMsg: `该用户暂未获奖`
},
ERROR_SEND_PRIZE_FAIL: {
code: '210013',
defaultMsg: `领取失败`
},
ERROR_NO_SHOP: {
code: '210014',
defaultMsg: `该店铺ID不存在`
},
ERROR_DELETE_ACTIVITY: {
code: '210015',
defaultMsg: `该活动已删除`
},
ERROR_ACTIVITY_OVER: {
code: '210016',
defaultMsg: `该活动已经结束`
},
ERROR_NO_VIP: {
code: '210017',
defaultMsg: `当前不是会员`
},
ERROR_SHARE_SELF: {
code: '210018',
defaultMsg: `无法给自己助力哦`
},
ERROR_SHARE_DID: {
code: '210019',
defaultMsg: `您已参与本店铺漂流游戏,助力失败`
},
ERROR_SHARE_DONE: {
code: '210020',
defaultMsg: `对方助力已达今日上限,助力失败`
},
ERROR_PRIZE_EXPIRED: {
code: '210021',
defaultMsg: `奖品已过期`
}
}
const SHARE_TOTAL_COUNT = 3; //验证要求3人后,完成分享任务
const TASK_ADD_POWER = 10; // 完成任务增加的体力值
const APP_NAME = 'promotioncenter-3000000002590532'; // C端的APP NAME
const B_APP_NAME = 'promotioncenter-3000000002693435' // B端的APP NAME
const GOODSINFO = 'detail_url,approve_status,num_iid,title,nick,type,cid,pic_url,num,props,valid_thru,list_time,price,has_discount,has_invoice,has_warranty,has_showcase,modified,delist_time,postage_id,seller_cids,outer_id,sold_quantity';
const ACTIVITY_STATUS={
ING:1, //活动进行中
NOSTART:2, //活动未开始
OVER:3, // 活动已经结束
DELETE:4, //活动已删除
ERRORID:5 //活动id无效
}
const DELETE_STATUS = {
DELETE: 0,
EXIST: 1
}
const PRIZE_GET_DELAY_TIME = 1000*60*60*48; //48小时
module.exports = {
OPEN_PRIZE_STATUS,
DRAW_STATUS,
LOGGER_TYPE,
CODE_TYPES,
SHARE_TOTAL_COUNT,
APP_NAME,
DELETE_STATUS,
GOODSINFO,
B_APP_NAME,
ACTIVITY_STATUS,
TASK_ADD_POWER,
PRIZE_GET_DELAY_TIME
};
\ No newline at end of file
const errorCode = {
"000000": 'ok',
"000001": '请填写活动名称',
"000002": '请填写活动副标题',
"000003": '活动名称不得大于12个字符',
"000004": '活动副标题不得大于16个字符',
"000005": '任务配置至少选择一项',
"000006": '浏览链接配置错误',
"000007": '奖品至少配置三名',
"000008": "浏览宝贝最多选择20个商品",
"000010": '请先生成规则',
"000011": '请配置活动时间',
"000012": '新建活动开始时间需小于当前时间',
"000013": '开始时间不得大于结束时间',
"000014": '奖品最多配置8个档位',
"000015": '查询列表错误',
"000016": '查询列表总数错误',
"000017": '更新奖品列表出错',
"000020": '删除活动失败',
"000021": '保存活动失败',
"000022": "删除活动id不存在",
"000023": '当前活动不存在',
"000024": '获取授权信息失败',
"000025": '保存授权信息失败',
"000026": '获取商家在售列表失败',
"000027": '获取商家ids列表失败',
"000030": '获取ename商品信息失败',
"000031": '奖品配置不正确'
}
module.exports = {
errorCode
}
\ No newline at end of file
class ResultsModel {
constructor() {
}
// 不填errorType,默认为系统错误
error(errorType, message) {
if (!errorType) {
errorType = { code: '500000', defaultMsg: '系统错误' };
}
return {
success: false,
code: errorType.code,
message: message || errorType.defaultMsg
}
}
success(data) {
return {
success: true,
code: 10000,
data: data,
message: `成功`
}
}
}
module.exports = ResultsModel
\ No newline at end of file
function loginfo(context, handler) {
const {
fcName,
data,
env
} = context;
console.log(`函数名:${fcName}---函数handler:${handler}---当前环境:${env}---请求参数:${JSON.stringify(data)}`)
}
const passUrlList = [
'1688.cn',
'taobao.cn',
'taobao.com',
'taobao.net',
'tb.cn',
'tmall.com',
'zhifu.com',
'zhifubao.com',
'juhuasuan.com',
'tmall.hk',
'tmall.com.hk',
'dingtalk.com',
'yushanfang.com',
'guoguo-app.com',
'umeng.com'
]
/**
* 传入时间戳(毫秒)
* 根据时间戳转换成number型日期进行差值结算,比如:2020318-2020317
*/
function isNewDay(time) {
let date = new Date(time + 60 * 60 * 8 * 1000);
let dateNum = +(date.getFullYear() + "" + (date.getMonth() + 1) + "" + date.getDate());
let nowdate = new Date(Date.now()+ 60 * 60 * 8 * 1000);
let nowdateNum = +(nowdate.getFullYear() + "" + (nowdate.getMonth() + 1) + "" + nowdate.getDate());
return nowdateNum - dateNum > 0
}
function getDayByTime(time) {
let date = new Date(time + 60 * 60 * 8 * 1000);
let dateNum = (date.getFullYear() + "" + (date.getMonth() + 1) + "" + date.getDate());
return dateNum;
}
//使用new Date()一定要在时间戳上加8小时
function getDayByTimeFix(time)
{
let date = new Date(time + 60 * 60 * 8 * 1000);
console.log("time:...",time,"...date:",date);
let yy = date.getFullYear();
let MM = date.getMonth() + 1<10?("0"+(date.getMonth() + 1)):date.getMonth() + 1;
let dd = date.getDate()<10?("0"+date.getDate()):date.getDate();
let dateNum = `${yy}/${MM}/${dd}`;
console.log(dateNum)
return dateNum;
}
const formatName = function formatName (name) {
let newStr;
if (name.length === 2) {
newStr = name.substr(0, 1) + '***'+name.substr(-1, 1);
} else if (name.length > 2) {
let char = '***';
newStr = name.substr(0, 1) + char + name.substr(-1, 1);
} else {
newStr = name+"****";
}
return newStr;
}
const formatTime = function dateFormat(thisDate, fmt = "yyyy-MM-dd hh:mm:ss") {
var o = {
"M+": thisDate.getMonth() + 1,
"d+": thisDate.getDate(),
"h+": thisDate.getHours(),
"m+": thisDate.getMinutes(),
"s+": thisDate.getSeconds(),
"q+": Math.floor((thisDate.getMonth() + 3) / 3),
"S": thisDate.getMilliseconds()
};
if (/(y+)/.test(fmt))
fmt = fmt.replace(RegExp.$1, (thisDate.getFullYear() + "").substr(4 - RegExp.$1.length));
for (var k in o)
if (new RegExp("(" + k + ")").test(fmt))
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
return fmt;
}
// 淘宝-时区,加8小时
const getdate = (day) => {
let time = new Date().getTime();
if (day) {
time = new Date(day).getTime();
}
return new Date(time + 8 * 60 * 60 * 1000);
}
const getdaystarttime = (day) => {
let date = new Date(`${day} 00:00:00`).getTime();
let start = date - 8 * 60 * 60 * 1000;
console.log(`getdaystarttime: `, start);
return start;
}
const getdayendtime = (day) => {
let date = new Date(`${day} 23:59:59`).getTime();
let end = date - 8 * 60 * 60 * 1000;
console.log(`getdayendtime: `, end);
return end;
}
module.exports = {
loginfo,
passUrlList,
isNewDay,
formatTime,
getDayByTime,
formatName,
getdate,
getdaystarttime,
getdayendtime,
getDayByTimeFix
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment