Commit 99f4fcd9 authored by qinhaitao's avatar qinhaitao

Merge branch 'c_server_ts_cultivate' into 'c_server_ts_perf'

C server ts cultivate

See merge request !12
parents 75643666 92f9a78f
This diff is collapsed.
This diff is collapsed.
/** @format */
import { services, checkParams, registeInfos, preCheck, preUpdate } from '../../decorator/common'
import { checkActivityTime, checkTaskLimit, checkExchangeCreditsTask, checkRemainTimes } from '../../utils/common/check'
import { updateVip, updateSignTask, updateOrderGoods } from '../../utils/common/update'
import {
checkActivityTime,
checkGrowTaskLimit,
checkExchangeCreditsTask,
checkRemainTimes
} from '../../utils/common/check'
import { updateVip, updateSignGrowTask, updateGrowOrderGoods } from '../../utils/common/update'
import customUtil from '../../utils/custom'
import { resultsModel } from '../../sdk'
import { CommonTaskService, CommonBaseService } from '../../service/common'
import { CommonGrowtaskService, CommonBaseService } from '../../service/common'
export default class TaskController {
/**
* 任务列表
*/
@checkParams(['activityId'])
@registeInfos(['vipInfo'])
@services([CommonTaskService])
@registeInfos(['vipInfo', 'task'])
@services([CommonGrowtaskService])
@preCheck([checkActivityTime])
@preUpdate([updateVip, updateSignTask, updateOrderGoods])
@preUpdate([updateVip, updateSignGrowTask, updateGrowOrderGoods])
async getTaskList(
context: IContext<IParams>,
{ activityInfo, userInfo, vipInfo }: IControllerInfos,
[commonTaskService]: [CommonTaskService]
{ activityInfo, userInfo, vipInfo, task }: IControllerInfos,
[commonGrowtaskService]: [CommonGrowtaskService]
) {
const commonTaskInitTaskListResult1 = await commonTaskService.initTaskList(userInfo, activityInfo)
const commonGrowtaskInitTaskListResult1 = await commonGrowtaskService.initTaskList(userInfo, activityInfo, task)
return resultsModel.success({
...commonTaskInitTaskListResult1
...commonGrowtaskInitTaskListResult1
})
}
/**
* 完成任务
*/
@checkParams(['activityId', 'taskType'])
@registeInfos(['session'])
@services([CommonTaskService])
@preCheck([checkActivityTime, checkTaskLimit, checkExchangeCreditsTask])
@registeInfos(['session', 'task'])
@services([CommonGrowtaskService])
@preCheck([checkActivityTime, checkGrowTaskLimit, checkExchangeCreditsTask])
async doCompleteTask(
context: IContext<IParams>,
{ activityInfo, userInfo, session }: IControllerInfos,
[commonTaskService]: [CommonTaskService]
{ activityInfo, userInfo, session, task }: IControllerInfos,
[commonGrowtaskService]: [CommonGrowtaskService]
) {
const commonTaskCompleteTaskResult1 = await commonTaskService.completeTask(
const commonGrowtaskCompleteTaskResult1 = await commonGrowtaskService.completeTask(
context.data.taskType,
activityInfo,
userInfo
userInfo,
task
)
return resultsModel.success({
...commonTaskCompleteTaskResult1
...commonGrowtaskCompleteTaskResult1
})
}
/**
* 领取任务奖励
*/
@checkParams(['activityId', 'taskType', 'rewardsKey'])
@services([CommonTaskService])
@services([CommonGrowtaskService])
@preCheck([checkActivityTime, checkRemainTimes])
async receiveTaskRewards(
context: IContext<IParams>,
{ activityInfo, userInfo }: IControllerInfos,
[commonTaskService]: [CommonTaskService]
[commonGrowtaskService]: [CommonGrowtaskService]
) {
const commonTaskReceiveTaskRewardsResult1 = await commonTaskService.receiveTaskRewards(
const commonGrowtaskReceiveTaskRewardsResult1 = await commonGrowtaskService.receiveTaskRewards(
context.data.taskType,
context.data.rewardsKey,
userInfo
)
return resultsModel.success({
...commonTaskReceiveTaskRewardsResult1
...commonGrowtaskReceiveTaskRewardsResult1
})
}
/**
......@@ -71,19 +77,19 @@ export default class TaskController {
*/
@checkParams(['activityId', 'itemIds'])
@registeInfos(['session'])
@services([CommonBaseService, CommonTaskService])
@services([CommonBaseService, CommonGrowtaskService])
async getCollectGoodsList(
context: IContext<IParams>,
{ activityInfo, userInfo, session }: IControllerInfos,
[commonBaseService, commonTaskService]: [CommonBaseService, CommonTaskService]
[commonBaseService, commonGrowtaskService]: [CommonBaseService, CommonGrowtaskService]
) {
const commonBaseGetItemListByIdsResult1 = await commonBaseService.getItemListByIds(context.data.itemIds, session)
const commonTaskGetItemListWithCollectStatusResult2 = await commonTaskService.getItemListWithCollectStatus(
const commonGrowtaskGetItemListWithCollectStatusResult2 = await commonGrowtaskService.getItemListWithCollectStatus(
commonBaseGetItemListByIdsResult1,
userInfo
)
return resultsModel.success({
...commonTaskGetItemListWithCollectStatusResult2
...commonGrowtaskGetItemListWithCollectStatusResult2
})
}
}
/** @format */
import { services, preCheck, registeInfos, preUpdate, checkParams } from '../decorator/common'
import { resultsModel } from '../sdk'
import { CommonStatService, CommonGrowtaskService } from '../service/common'
import { STAT_TYPE } from '../constants'
import { checkActivityTime, checkInviteId, checkHelpRecord, checkNewVip } from '../utils/common/check'
import { updateHelpRecord, updateVip } from '../utils/common/update'
import { getTask } from '../utils'
export default class Share {
/**
* 完成分享
*/
@checkParams(['activityId', 'inviteId'])
@registeInfos(['vipInfo'])
@services([CommonGrowtaskService, CommonStatService])
@preCheck([checkActivityTime, checkInviteId, checkNewVip, checkHelpRecord])
@preUpdate([updateVip, updateHelpRecord])
async doHelp(
context: IContext<IParams>,
{ userInfo, activityInfo }: IControllerInfos,
[growTaskService, statService]: [CommonGrowtaskService, CommonStatService],
{ inviteUserInfo }: IPreCheckData
) {
// 如果邀请任务是每日的,则需要请求每日任务信息
const task = await growTaskService.getTask(context, inviteUserInfo.openId)
const result = await growTaskService.completeTask('invites', activityInfo, inviteUserInfo, task)
statService.addStat(STAT_TYPE.INITE_SUCCESS, userInfo)
return resultsModel.success(result)
}
}
/** @format */
import { checkParams, services, registeInfos, preCheck } from '../decorator/common'
import { resultsModel } from '../sdk'
import { CommonGrowtaskService, CommonBaseService } from '../service/common'
import { ITaskInfo } from '../service/common/task.service'
import {
checkActivityTime,
checkGrowTaskLimit,
checkExchangeCreditsTask,
checkRemainTimes,
checkInviteId
} from '../utils/common/check'
import { preUpdate } from '../decorator/common'
import { updateVip, updateSignGrowTask, updateGrowOrderGoods } from '../utils/common/update'
export default class Task {
/**
* 任务列表
*/
@checkParams(['activityId'])
@registeInfos(['vipInfo', 'task'])
@services([CommonGrowtaskService])
@preCheck([checkActivityTime])
@preUpdate([updateVip, updateSignGrowTask, updateGrowOrderGoods])
async getTaskList(
context: IContext<IParams>,
{ userInfo, activityInfo, task }: IControllerInfos,
[growTaskService]: [CommonGrowtaskService]
): Promise<IResult<{ list: ITaskInfo[] }>> {
// 读取B端 tasks字段配置自动生成任务列表
const result = await growTaskService.initTaskList(userInfo, activityInfo, task)
return resultsModel.success({
...result
})
}
/**
* 完成任务
*
* 商品相关任务 需要传itemId参数
* 积分兑换任务 需要传credits参数
*/
@checkParams(['activityId', 'taskType', 'itemId?', 'credits?'])
@registeInfos(['session', 'task'])
@services([CommonGrowtaskService])
@preCheck([checkActivityTime, checkGrowTaskLimit, checkExchangeCreditsTask])
async doCompleteTask(
context: IContext<IParams>,
{ userInfo, activityInfo, task }: IControllerInfos,
[growTaskService]: [CommonGrowtaskService]
) {
const { taskType } = context.data
// 更新user表
const result = await growTaskService.completeTask(taskType, activityInfo, userInfo, task)
return resultsModel.success(result)
}
/**
* 领取任务奖励
* 领取的奖励增加的key值 如: gameTimes 前端传入
*/
@checkParams(['activityId', 'taskType', 'rewardsKey'])
@services([CommonGrowtaskService])
@preCheck([checkActivityTime, checkRemainTimes])
async receiveTaskRewards(
context: IContext<IParams>,
{ userInfo }: IControllerInfos,
[growTaskService]: [CommonGrowtaskService]
): Promise<IResult<{ rewards: number }>> {
const { rewardsKey } = context.data
const { taskType } = context.data
const rewardsResult = await growTaskService.receiveTaskRewards(taskType, rewardsKey, userInfo)
return resultsModel.success(rewardsResult)
}
/**
* 获取收藏商品列表
*/
@checkParams(['activityId', 'itemIds'])
@registeInfos(['session'])
@services([CommonBaseService, CommonGrowtaskService])
async getCollectGoodsList(
context: IContext<IParams>,
{ session, userInfo }: IControllerInfos,
[commonBaseService, growTaskService]: [CommonBaseService, CommonGrowtaskService]
) {
const { itemIds } = context.data
const list = await commonBaseService.getItemListByIds(itemIds, session)
const listWithCollectStatus = await growTaskService.getItemListWithCollectStatus(list, userInfo)
return resultsModel.success(listWithCollectStatus)
}
}
......@@ -10,6 +10,8 @@ export const JOIN_DB_NAME = 'c_user_join'
export const SIGN_DB_NAME = 'c_user_sign'
export const TASK_DB_NAME = 'c_user_tasks'
export const STAT_DB_NAME = 'c_stats'
export const ERROR_LOG_DB_NAME = 'error_log'
......@@ -19,3 +21,5 @@ export const SELLER_INFO_DB_NAME = 'a_seller_info'
export const PRIZE_CONFIG_DB_NAME = 'b_prize_config'
export const ACTIVITY_CONFIG_DB_NAME = 'b_activity_config'
export const OEDER_DB_NAME = 'c_user_order'
/** @format */
import { CommonUserService, CommonBaseService } from '../../service/common'
import { getSellerSession, getUserOrderlist } from '../../utils'
import { getSellerSession, getUserOrderlist, getTask } from '../../utils'
import { formatVipCbUrl, getShopVip } from '../../utils/common/vip'
import { CODE_TYPES } from '../../errorCode'
import { resultsModel, TBAPIS } from '../../sdk'
export type IInfo = 'session' | 'vipInfo' | 'taobaoOrderList' | 'credits'
export type IInfo = 'session' | 'vipInfo' | 'taobaoOrderList' | 'credits' | 'task'
async function initBaseInfo(context: IContext<IParams>, baseInfos: ICheckControllerInfos, needInfos: IInfo[]) {
const handler = context?.cloud?.dataspace?.context?.handler
......@@ -54,6 +54,12 @@ async function initBaseInfo(context: IContext<IParams>, baseInfos: ICheckControl
baseInfos.credits = credits
}
if (needInfos.includes('task') && !baseInfos.credits) {
const task = await getTask(context)
if (!task._id) return CODE_TYPES.ERROR_UPDATE_RETRY
baseInfos.task = task
}
return baseInfos
}
......
/**
* 任务相关方法
*
* @format
*/
import UserService from './user.service'
import { BaseDao } from '../../sdk'
import { getToday, getUserOrderlist, generateVipUrl, formatVipCbUrl, setNewFollowUserData } from '../../utils'
import { TASK_RATE_TYPE, TASK_STATUS } from '../../constants'
import { TASK_DB_NAME } from '../../db'
import {
getTotalCompleteTask,
setGrowTaskStatus,
updateTaskInfo,
getTodayCompleteGrowTask,
getOrderCount
} from '../../utils/common/task'
import { CODE_TYPES } from '../../errorCode'
export interface ITaskInfo {
taskType?: string // 任务类型
url?: string // 链接地址
rewards: number // 任务奖励
itemIds?: string // 商品配置ids 商品相关任务返回
todayCompleteTimes?: number // 今日完成次数
completeTimes?: number // 总共完成次数
taskRateType: number // 任务频率
times?: number // 任务每日限制次数
waitReceive?: number // 待领取次数
title: string // 任务文案
status: number // 任务状态 1未完成 2 待领取 3 已完成
}
export default class TaskService extends UserService {
taskInfodao: IBaseDao
constructor(context: IContext<IParams>) {
super(context)
this.taskInfodao = new BaseDao(context, TASK_DB_NAME)
}
// 根据活动tasks字段渲染任务
async initTaskList(userInfo: IUserInfo, activityInfo: IActivityInfo, task: ITask) {
let list = []
const keyList = Object.keys(activityInfo?.tasks || {})
for (let index = 0; index < keyList.length; index++) {
// @ts-ignore
const taskType: ITaskType = keyList[index]
list.push(await this.initTask(task, taskType, activityInfo?.tasks?.[taskType]?.title, userInfo, activityInfo))
}
return {
list
}
}
/**
* 根据任务类型初始化 b端 tasks字段必须有相应的配置
*
* @param {ITaskType} taskType 任务类型
* @param {string} title 任务标题
* @param {IActivityInfo} activityInfo 任务配置
* @param {IUserInfo} userInfo 用户信息
* @return {ITaskInfo} {ITaskInfo} 任务信息
* @memberof TaskService
*/
async initTask(
task: ITask,
taskType: ITaskType,
title: string,
userInfo: IUserInfo,
activityInfo: IActivityInfo
): Promise<ITaskInfo> {
if (!activityInfo?.tasks?.[taskType]) {
console.error(`活动缺少${taskType}任务配置项`)
}
const { value, itemIds = '', taskRateType, times = 1, link = '' } = activityInfo?.tasks?.[taskType] || {}
const { remainTimes } = userInfo
let { todayCompleteTimes } = getTodayCompleteGrowTask(taskType, task)
let { completeTimes } = getTotalCompleteTask(taskType, userInfo)
if (taskType === 'orderGoods') {
//如果是下单任务,需要单独去根据订单类型去订单表获取下单列表
todayCompleteTimes = completeTimes = await getOrderCount(
this.context,
userInfo.openId,
activityInfo._id,
taskRateType
)
}
return {
taskType,
title,
itemIds,
rewards: value,
taskRateType,
times,
url: taskType === 'member' ? generateVipUrl(formatVipCbUrl(this.context)) : link,
todayCompleteTimes,
completeTimes,
status: setGrowTaskStatus(userInfo, taskType, taskRateType, times, todayCompleteTimes, completeTimes),
waitReceive: remainTimes?.[taskType]
}
}
/**
*
* 领取任务奖励
*
* @param {ITaskType} taskType
* @param {string} awardsTargetKey
* @param {IUserInfo} userInfo
* @return {number} rewards
* @memberof TaskService
*/
async receiveTaskRewards(
taskType: ITaskType,
awardsTargetKey: string,
userInfo: IUserInfo
): Promise<{
rewards: number
}> {
const waitReceiveTimes = userInfo?.remainTimes?.[taskType]
await this.updateUser(userInfo._id, {
$set: {
[`remainTimes.${taskType}`]: 0
},
$inc: {
[awardsTargetKey]: waitReceiveTimes
}
})
return {
rewards: waitReceiveTimes
}
}
/**
*根据任务类型更新任务待领取次数和任务记录
*
* @param {string} taskType
* @param {number} activityInfo
* @param {IActivityInfo} userInfo
* @returns {boolean}
* @memberof TaskService
*/
async completeTask(
taskType: ITaskType,
activityInfo: IActivityInfo,
userInfo: IUserInfo,
task: ITask = {},
customRecord: Object = {}
) {
const today = getToday()
const rewards = activityInfo?.tasks?.[taskType]?.value || 0
const { tasks } = activityInfo
const {
[taskType]: { taskRateType }
} = tasks
const {
openId,
data: { itemId }
} = this.context
const record = {
itemId,
openId: taskType === 'invites' ? openId : undefined,
createTime: Date.now(),
...customRecord
}
if (taskRateType === TASK_RATE_TYPE.EVERYDAY) {
//如果是每日任务,则更新每日任务表
const result = await updateTaskInfo(this.context, task._id, taskType, record)
if (result === 1) {
const updateResult = await this.updateUser(userInfo._id, {
$inc: {
[`remainTimes.${taskType}`]: +rewards
}
})
return updateResult === 1 ? { ok: 1 } : CODE_TYPES.ERROR_DO_TASK
}
return CODE_TYPES.ERROR_DO_TASK
} else {
//永久任务就更新永久任务表
let updateQuery: IUpdateQuery = {
$inc: {
[`remainTimes.${taskType}`]: +rewards
},
$push: {
[`taskInfo.${today}.${taskType}`]: { ...record, createTime: Date.now() }
}
}
if (taskType === 'follow') {
updateQuery.$set = {
follow: setNewFollowUserData(userInfo.follow)
}
}
const result = await this.updateUser(userInfo._id, updateQuery)
return result === 1 ? { ok: 1 } : CODE_TYPES.ERROR_DO_TASK
}
}
async getItemListWithCollectStatus(list: { list: ITaoBaoItems[] }, userInfo: IUserInfo) {
const { taskInfo } = getTotalCompleteTask('collectGoods', userInfo)
return {
list: list.list.map(v => {
return {
...v,
// 完成列表是否含有itemId
collected: taskInfo.some(completeItem => completeItem.itemId === v.itemId)
}
})
}
}
/**
* 获取用户任务参与信息
* @param context
* @param openId
* @param activityId
*/
async getTask(context: IContext<IParams>, openId: string = '', activityId?: string): Promise<ITask> {
activityId = activityId ? activityId : context.data.activityId
openId = openId ? openId : context.openId
const createDay = getToday()
//查询每日任务完成记录
const result: ITask = await this.taskInfodao.findOne({
openId,
activityId,
createDay
})
//如果还没有今天的任务数据,则新增一条用户任务数据
if (!result) {
const insertObj = {
openId,
activityId,
taskInfo: {},
createTime: Date.now(),
createDay: createDay
}
const insertResult = await this.taskInfodao.insertOne(insertObj)
return { ...insertObj, _id: insertResult }
}
return result
}
}
......@@ -8,6 +8,7 @@ import CommonTaskService from './task.service'
import CommonStatService from './stat.service'
import CommonGameService from './game.service'
import CommonSignService from './sign.service'
import CommonGrowtaskService from './growTask.service'
const common = {
CommonAccessService,
......@@ -17,7 +18,8 @@ const common = {
CommonTaskService,
CommonStatService,
CommonGameService,
CommonSignService
CommonSignService,
CommonGrowtaskService
}
export default common
......@@ -30,5 +32,6 @@ export {
CommonTaskService,
CommonStatService,
CommonGameService,
CommonSignService
CommonSignService,
CommonGrowtaskService
}
......@@ -10,6 +10,7 @@ import { ACTIVITY_STATUS } from '../../constants'
import UserService from './user.service'
import { getToday } from '../../utils'
import { CODE_TYPES } from '../../errorCode'
import { getDistanceDays } from '../../utils/common/sign'
import { formatDate } from '../../utils/common/date'
export default class SignService extends UserService {
......@@ -30,9 +31,7 @@ export default class SignService extends UserService {
userNick,
isSignLater: !!subscribeSignDay,
createDay: today,
signTime: subscribeSignDay
? formatDate(subscribeSignDay).format('YYYY-MM-DD')
: formatDate().format('YYYY-MM-DD'),
signTime: subscribeSignDay ? formatDate(subscribeSignDay).getDate() : formatDate().getDate(),
signDay: subscribeSignDay || today,
createTime: Date.now()
})
......@@ -48,7 +47,14 @@ export default class SignService extends UserService {
const { openId } = this.context
const signInfoList: ISignInfoAggregate[] = await this.signdao.aggregate(
{ $match: { activityId, openId } },
{ $project: { d: { $dayOfYear: '$signTime' }, y: { $year: '$signTime' }, signTime: '$signTime' } }
{
$project: {
d: { $dayOfYear: '$signTime' },
y: { $year: '$signTime' },
signTime: '$signTime',
signDay: '$signDay'
}
}
)
return signInfoList
......
......@@ -37,7 +37,7 @@ export default class TaskService extends UserService {
}
}
/**
* 根据任务类型初始化 b端 tasks字段必须有相应的配置
* 根据任务类型初始化 b端 tasks字段必须有相应的配置TODO
*
* @param {ITaskType} taskType 任务类型
* @param {string} title 任务标题
......
......@@ -29,6 +29,7 @@ interface IControllerInfos {
activityInfo: IActivityInfo
session?: string
credits?: number
task?: ITask
taobaoOrderList?: ITaoBaoOrders[]
}
......@@ -51,6 +52,15 @@ interface IVipInfo {
url?: string
}
interface ITask {
_id?: string
openId?: string
activityId?: string
taskInfo?: any
createDay?: string
createTime?: number
}
type IFunction = (...args: any[]) => any
type ValueOf<T> = T extends any[] ? T[number] : T[keyof T]
......@@ -6,7 +6,7 @@ interface IUserSign {
userNick: string
createTime: number
createDay: string
signTime: string
signTime?: any
signDay: string
isSignLater?: boolean // 是否补签
}
......@@ -15,5 +15,11 @@ interface ISignInfoAggregate {
_id?: string
d: number
y: number
signDay: string
signTime: Date
}
interface signDayList {
isSing: boolean
signDay: string
}
/** @format */
import { resultsModel } from '../../../sdk'
import { CODE_TYPES } from '../../../errorCode'
import { getTotalCompleteTask, getTodayCompleteGrowTask } from '../task'
import { TASK_RATE_TYPE } from '../../../constants'
export default async function checkTaskLimit(
context: IContext<{ activityId: string; taskType: ITaskType; itemId?: string }>,
{ userInfo, activityInfo, task }: IControllerInfos
) {
const { taskType, itemId } = context.data
const { itemIds } = activityInfo?.tasks?.[taskType] || {}
if (!taskType) {
console.error('使用checkTaskLimit, 云函数必须传入taskType参数')
return
}
if (!activityInfo?.tasks?.[taskType]) {
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, `该活动缺少${taskType}配置项`)
}
if (itemId && !itemIds) {
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, `该任务缺少商品配置项`)
}
// B端配置商品ids不匹配正确
if (itemId && itemIds) {
const itemIdArray: number[] = Array.isArray(itemIds) ? itemIds : itemIds.split(',').map(v => +v)
if (!itemIdArray.includes(+itemId)) return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '商品id不匹配')
}
const { taskRateType, times = 1 } = activityInfo?.tasks?.[taskType]
// 永久任务已经完成
const { completeTimes } = getTotalCompleteTask(taskType, userInfo)
const hasComplete = completeTimes >= times && taskRateType === TASK_RATE_TYPE.FOREVER
if (hasComplete) return resultsModel.error(CODE_TYPES.ERROR_TASK_LIMIT, `该任务已完成,去看看其它任务吧~`)
// 每日任务今天已经完成
const { todayCompleteTimes, todayTaskInfo } = getTodayCompleteGrowTask(taskType, task)
const hasCompleteToday = times && todayCompleteTimes === times && taskRateType === TASK_RATE_TYPE.EVERYDAY
if (hasCompleteToday) {
return resultsModel.error(CODE_TYPES.ERROR_TASK_LIMIT, `该任务今天已完成,明天再来吧~`)
}
// 今日任务该商品已经完成
const itemHasCompleteToday =
todayTaskInfo.find(v => v.itemId && v.itemId === itemId) && taskRateType === TASK_RATE_TYPE.EVERYDAY
if (itemHasCompleteToday) {
return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '今日该商品任务已完成')
}
}
......@@ -13,6 +13,7 @@ import checkUserInfo, { checkGameTimes } from './checkUserInfo'
import checkJoinId from './checkJoinId'
import checkOpenPrizeStatus from './checkOpenPrizeStatus'
import checkSign from './checkSign'
import checkGrowTaskLimit from './checkGrowTaskLimit'
const check = {
checkActivityTime,
......@@ -31,7 +32,8 @@ const check = {
checkJoinId,
checkGameTimes,
checkOpenPrizeStatus,
checkSign
checkSign,
checkGrowTaskLimit
}
export default check
......@@ -53,5 +55,6 @@ export {
checkJoinId,
checkGameTimes,
checkOpenPrizeStatus,
checkSign
checkSign,
checkGrowTaskLimit
}
......@@ -42,6 +42,7 @@ export function formatDate(date: string | number = Date.now()) {
getHour: () => dayjs(beijingDate).get('hour'),
getMinute: () => dayjs(beijingDate).get('minute'),
geSecond: () => dayjs(beijingDate).get('second'),
getMillisecond: () => dayjs(beijingDate).get('millisecond')
getMillisecond: () => dayjs(beijingDate).get('millisecond'),
getDate: () => dayjs(beijingDate).date()
}
}
......@@ -3,8 +3,10 @@
import * as dayjs from 'dayjs'
import { uniq } from 'lodash'
import { getToday } from './getToday'
import { formatDate } from './date'
const isLeapYear = (year: number) => (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0
const oneDayTime = 24 * 3600 * 1000
// 获取最大连续签到天数
export const getMaxContinusSignDays = (signInfoList: ISignInfoAggregate[]): number => {
......@@ -37,3 +39,48 @@ export const getMaxContinusSignDays = (signInfoList: ISignInfoAggregate[]): numb
export const getSignedByDay = (signInfoList: ISignInfoAggregate[], day = getToday()): boolean => {
return signInfoList.some(v => dayjs(v.signTime).format('yyyy/MM/dd') === day)
}
// 获取当前几天签到信息(包含今天)
export const getDistanceDays = (days: number, signInfoList: ISignInfoAggregate[]): signDayList[] => {
let signDayList = []
for (let index = 0; index < days; index++) {
let signDay = formatDate(dayjs().subtract(index, 'day').valueOf()).format()
const signInfo = signInfoList.find(v => v.signDay === signDay)
signDayList.push({
signDay,
isSign: signInfo ? true : false
})
}
return signDayList
}
// 获取几天前至今连续签到天数(包含今天),如果昨天签到今天未签到,则也算连续签到,不算断签
export const getContinueDays = (days: number, signInfoList: ISignInfoAggregate[]): number => {
const minYear = Math.min.apply(
null,
signInfoList.map(v => +v.y)
)
const list: number[] = signInfoList
.map(v => {
const gap = (isLeapYear ? 366 : 365) * (v.y - minYear)
return gap + v.d
})
.sort((a, b) => a - b)
if (list.length === 0) return 0
let m = uniq(list.sort((a, b) => a - b))
let max = 0
//判断当天或者昨天是否已经签到
const isSign = signInfoList.some(
v => v.signDay === getToday() || v.signDay === formatDate(dayjs().subtract(-1, 'day').valueOf()).format()
)
for (let i = 0; i < days; i++) {
if (isSign && m[i + 1] - m[i] === 1) {
//当天或者昨天已经签到,则开始计算连续签到天数
max++
} else {
break
}
}
return max
}
......@@ -2,6 +2,9 @@
import { getToday } from './getToday'
import { TASK_STATUS, TASK_RATE_TYPE } from '../../constants'
import { TASK_DB_NAME, OEDER_DB_NAME } from '../../db'
import { BaseDao } from '../../sdk'
import Task from '../../controller/task.controller'
/**
* 根据任务类型获取任务完成情况
......@@ -97,3 +100,139 @@ export function setTaskStatus(
break
}
}
/**
* 获取用户任务参与信息
* @param context
* @param openId
* @param activityId
*/
export const getTask = async (context: IContext<IParams>, openId: string = '', activityId?: string): Promise<ITask> => {
activityId = activityId ? activityId : context.data.activityId
openId = openId ? openId : context.openId
const taskInfodao: IBaseDao = new BaseDao(context, TASK_DB_NAME)
const createDay = getToday()
//查询每日任务完成记录
const result: ITask = await taskInfodao.findOne({
openId,
activityId,
createDay
})
//如果还没有今天的任务数据,则新增一条用户任务数据
if (!result) {
const insertObj = {
openId,
activityId,
taskInfo: {},
createTime: Date.now(),
createDay: createDay
}
const insertResult = await taskInfodao.insertOne(insertObj)
return { ...insertObj, _id: insertResult }
}
return result
}
/**
* 获取养成类每日任务信息
* @param taskType
* @param task
*/
export function getTodayCompleteGrowTask(
taskType: string,
task: ITask
): {
todayCompleteTimes: number
todayTaskInfo: ITaskDetail[]
} {
const today = getToday()
return {
todayCompleteTimes: task?.taskInfo?.[today]?.[taskType]?.length || 0,
todayTaskInfo: task?.taskInfo?.[today]?.[taskType] || []
}
}
/**
* 更新每日任务,适用于购买商品每日任务
* @param context
* @param activityId
*/
export async function updateTaskInfo(context: IContext<IParams>, _id: string, taskType: string, value) {
let taskInfodao: IBaseDao = new BaseDao(context, TASK_DB_NAME)
const today = getToday()
return await taskInfodao.update(
{
_id
},
{
$push: {
[`taskInfo.${today}.${taskType}`]: value
}
}
)
}
/**
* 更新每日任务,适用于购买商品每日任务
* @param context
* @param activityId
*/
export async function getOrderCount(
context: IContext<IParams>,
openId: string,
activityId: string,
taskRateType: number
) {
let orderdao: IBaseDao = new BaseDao(context, OEDER_DB_NAME)
const project =
taskRateType === TASK_RATE_TYPE.EVERYDAY
? {
openId,
activityId,
createDay: getToday()
}
: {
openId,
activityId
}
return await orderdao.count(project)
}
/**
*
* 根据用户和任务完成情况,设置任务状态
*
* @param {IUserInfo} useInfo
* @param {string} taskType
* @param {number} taskRateType
* @param {number} [limitTimesEverday] 每天限制次数 任务频率为每天的时候必填
* @return {taskTatus} 1未完成 2 待领取 3 已完成
* @memberof TaskService
*/
export function setGrowTaskStatus(
userInfo: IUserInfo,
taskType: string,
taskRateType: number,
limitTimesEveryday: number = 1,
todayCompleteTimes: number,
completeTimes: number
): number {
const waitReceive = userInfo?.remainTimes?.[taskType] || 0
if (waitReceive) return TASK_STATUS.WAIT_RECEIVE
switch (taskRateType) {
case TASK_RATE_TYPE.FOREVER:
return completeTimes >= limitTimesEveryday ? TASK_STATUS.DONE : TASK_STATUS.WAIT_DO
break
case TASK_RATE_TYPE.EVERYDAY:
return todayCompleteTimes >= limitTimesEveryday ? TASK_STATUS.DONE : TASK_STATUS.WAIT_DO
break
case TASK_RATE_TYPE.NOLIMIT:
return TASK_STATUS.WAIT_DO
break
}
}
......@@ -4,6 +4,8 @@ import updateSignTask from './updateSignTask'
import updateOrderGoods from './updateOrderGoods'
import updateFirstLoginToday from './updateFirstLoginToday'
import updateUserInfo, { reduceGameTimes, updateHelpRecord } from './updateUserInfo'
import updateSignGrowTask from './updateSignGrowTask'
import updateGrowOrderGoods from './updateGrowOrderGoods'
const update = {
updateVip,
......@@ -12,7 +14,9 @@ const update = {
updateFirstLoginToday,
updateUserInfo,
reduceGameTimes,
updateHelpRecord
updateHelpRecord,
updateSignGrowTask,
updateGrowOrderGoods
}
export default update
......@@ -24,5 +28,7 @@ export {
updateFirstLoginToday,
updateUserInfo,
reduceGameTimes,
updateHelpRecord
updateHelpRecord,
updateSignGrowTask,
updateGrowOrderGoods
}
/** @format */
import { getToday } from '../getToday'
import { TASK_RATE_TYPE } from '../../../constants'
import { getUserOrderlist } from '../getUserOrderlist'
import { OEDER_DB_NAME } from '../../../db'
import { resultsModel } from '../../../sdk'
import { BaseDao } from '../../../sdk'
import { CODE_TYPES } from '../../../errorCode'
import { formatDate } from '../date'
export default async function updateGrowOrderGoods(
context: IContext<IParams>,
{ userInfo, activityInfo }: IControllerInfos
): Promise<IPreUpdateQuery> {
const taskType = 'orderGoods'
const { value, itemIds, taskRateType, times } = activityInfo?.tasks?.[taskType] || {}
let orderdao: IBaseDao = new BaseDao(context, OEDER_DB_NAME)
const orderList =
taskRateType === TASK_RATE_TYPE.EVERYDAY
? await orderdao.find({
openId: userInfo.openId,
activityId: userInfo.activityId,
createDay: getToday
})
: await orderdao.find({
openId: userInfo.openId,
activityId: userInfo.activityId
})
const completeTimes = orderList?.length || 0
if (!activityInfo?.tasks?.[taskType]) return {}
// 每日任务或者是永久任务的任务且已完成
if (taskRateType !== TASK_RATE_TYPE.NOLIMIT && completeTimes >= times) {
return {}
}
const today = getToday()
//设置查询淘宝订单时间
let startTime = Date.now()
if (taskRateType === TASK_RATE_TYPE.EVERYDAY) {
let TodayTime = formatDate(today).getTimestamp()
startTime = TodayTime > userInfo.createTime ? TodayTime : userInfo.createTime
} else {
startTime = userInfo.createTime || activityInfo?.startTime || Date.now()
}
const orderResult = await getUserOrderlist(
context,
//@ts-ignore
startTime,
Date.now()
)
const itemIdsArr = itemIds.split(',').map(v => +v)
let projection = {
$inc: {
[`remainTimes.${taskType}`]: 0
},
$set: {}
}
//筛选符合任务的订单并添加到下单表
let targetOrders = []
orderResult.forEach(v => {
if (
// 商品订单包含目标商品 且orderId为新订单
itemIdsArr.includes(v.itemId) &&
// @ts-ignore
!orderList.some(order => order.orderId === v.orderId) &&
!targetOrders.some(order => order.orderId === v.orderId)
) {
if (targetOrders.length + completeTimes >= times) {
return
}
targetOrders.push({
openId: userInfo.openId,
activityId: activityInfo._id,
itemId: v.itemId,
orderId: v.orderId,
tId: v.tId,
createTime: Date.now(),
createDay: today
})
}
})
if (targetOrders?.length) {
const result = await orderdao.insertMany(targetOrders)
if (!result || result.length === 0) {
// @ts-ignore
return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, '订单任务更新失败')
}
projection.$inc[`remainTimes.${taskType}`] = result.length * value
}
return projection
}
/** @format */
import { getToday } from '../getToday'
import { getTodayCompleteGrowTask, updateTaskInfo } from '../task'
export default async function updateSignTask(
context: IContext<IParams>,
{ activityInfo, task }: IControllerInfos
): Promise<IPreUpdateQuery | undefined> {
if (!activityInfo?.tasks?.sign) return
// 获取签到奖励
const { value } = activityInfo?.tasks?.sign || {}
const { todayCompleteTimes } = getTodayCompleteGrowTask('sign', task)
if (todayCompleteTimes === 0) {
const result = await updateTaskInfo(context, task._id, 'sign', { createTime: Date.now() })
return result === 1
? {
$inc: {
'remainTimes.sign': value || 0
}
}
: {}
}
return {}
}
......@@ -27,3 +27,5 @@ export * from './common/userUpdate'
export * from './common/format'
export * from './common/doHandler'
export * from './common/task'
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