"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; Object.defineProperty(exports, "__esModule", { value: true }); exports.SignInService = void 0; const common_1 = require("@nestjs/common"); const typeorm_1 = require("@nestjs/typeorm"); const typeorm_2 = require("typeorm"); const user_sign_in_model_1 = require("../../../model/user_sign_in.model"); const user_sign_in_calendar_model_1 = require("../../../model/user_sign_in_calendar.model"); const user_sign_in_task_model_1 = require("../../../model/user_sign_in_task.model"); const user_sign_in_task_reward_model_1 = require("../../../model/user_sign_in_task_reward.model"); const user_financial_product_model_1 = require("../../../model/user_financial_product.model"); const api_1 = require("../../common/api"); const signin_vo_1 = require("../vo/signin.vo"); const user_id_context_1 = require("../../common/context/user_id.context"); const data_source_context_1 = require("../../common/context/data_source.context"); const help_1 = require("../../common/util/help"); const financial_product_model_1 = require("../../../model/financial_product.model"); let SignInService = class SignInService { userSignInModel; userSignInCalendarModel; userSignInTaskModel; userSignInTaskRewardModel; userFinancialProductModel; dataSource; constructor(userSignInModel, userSignInCalendarModel, userSignInTaskModel, userSignInTaskRewardModel, userFinancialProductModel, dataSource) { this.userSignInModel = userSignInModel; this.userSignInCalendarModel = userSignInCalendarModel; this.userSignInTaskModel = userSignInTaskModel; this.userSignInTaskRewardModel = userSignInTaskRewardModel; this.userFinancialProductModel = userFinancialProductModel; this.dataSource = dataSource; } async getSignInInfo(userId) { const signInStats = await this.userSignInModel.findOne({ where: { userId }, }); const nowYYYMMDD = help_1.Help.formatDate(Date.now(), 'YYYY-MM-DD'); return api_1.Api.success({ ...signInStats, signToDay: nowYYYMMDD == signInStats?.lastSignInDate, }); } async getSignInCalendar(userId, year, month) { const firstDay = `${year}-${String(month).padStart(2, '0')}-01`; const lastDay = new Date(year, month, 0).toISOString().split('T')[0]; const signInRecords = await this.userSignInCalendarModel.find({ where: { userId, signInDate: (0, typeorm_2.Between)(firstDay, lastDay), }, order: { signInDate: 'ASC' }, }); return api_1.Api.pagination(signInRecords, signInRecords.length); } async getProgress() { const userId = (0, user_id_context_1.getUserIdContext)(); const userSignIn = await this.userSignInModel.findOneByOrFail({ userId, }); const existFirst = userSignIn.firstSignInDate != null; const nowDate = new Date(); const nowYYYMMDD = help_1.Help.formatDate(nowDate, 'YYYY-MM-DD'); const startDate = new Date(); startDate.setDate(startDate.getDate() - (existFirst ? 3 : 0)); let startYYYMMDD = help_1.Help.formatDate(startDate, 'YYYY-MM-DD'); const firstSignDate = userSignIn.firstSignInDate || nowYYYMMDD; if (firstSignDate > startYYYMMDD) { startYYYMMDD = firstSignDate; } const signInCalendars = await this.userSignInCalendarModel.find({ where: { userId, signInDate: (0, typeorm_2.Between)(startYYYMMDD, nowYYYMMDD), }, }); const signedDates = new Map(); signInCalendars.forEach((it) => { signedDates.set(it.signInDate, it); }); const dates = []; const current = new Date(startYYYMMDD); const endDate = new Date(startYYYMMDD); endDate.setDate(endDate.getDate() + 6); while (current <= endDate) { const dateStr = help_1.Help.formatDate(current, 'YYYY-MM-DD'); dates.push(dateStr); current.setDate(current.getDate() + 1); } return api_1.Api.pagination(dates.map((date) => { const vo = new signin_vo_1.SignInProgressDayVo(); vo.date = date; vo.isFutureDay = date > nowYYYMMDD; vo.signedIn = signedDates.has(date); vo.isMakeUp = signedDates.get(date)?.isMakeUp || user_sign_in_calendar_model_1.SignInType.Normal; vo.isDay = date == nowYYYMMDD; vo.consecutiveDay = help_1.Help.diffDays(date, firstSignDate) + 1; return vo; }), 0); } async getTaskList(userId) { const tasks = await this.userSignInTaskModel.find({ order: { requiredDays: 'ASC' }, }); if (tasks.length === 0) { return api_1.Api.success([]); } const taskIds = tasks.map((t) => t.id); const rewards = await this.userSignInTaskRewardModel.find({ where: { userId, userSignInTaskId: (0, typeorm_2.In)(taskIds), }, }); const rewardMap = new Map(); for (const reward of rewards) { rewardMap.set(reward.userSignInTaskId, reward); } const taskList = tasks.map((task) => { const reward = rewardMap.get(task.id); if (reward) { const status = reward.claimStatus === user_sign_in_task_reward_model_1.ClaimStatus.Claimed ? signin_vo_1.TaskStatus.Completed : signin_vo_1.TaskStatus.Pending; return { id: task.id, title: task.title, subtitle: task.subtitle, requiredDays: task.requiredDays, icon: task.icon, status, rewardId: reward.id, }; } return { id: task.id, title: task.title, subtitle: task.subtitle, requiredDays: task.requiredDays, icon: task.icon, status: signin_vo_1.TaskStatus.InProgress, rewardId: undefined, }; }); return api_1.Api.pagination(taskList, taskList.length); } async todaySignIn(userId) { const nowYYYMMDD = help_1.Help.formatDate(Date.now(), 'YYYY-MM-DD'); const signInStats = await this.userSignInModel.findOneOrFail({ where: { userId }, }); if (signInStats && signInStats.lastSignInDate === nowYYYMMDD) { return api_1.Api.error('今日已签到'); } const yesterday = help_1.Help.formatDate(new Date(Date.now() - 86400000), 'YYYY-MM-DD'); let consecutiveDays = 1; if (signInStats && signInStats.lastSignInDate === yesterday) { consecutiveDays = signInStats.consecutiveDays + 1; } else { consecutiveDays = 1; } await data_source_context_1.DataSourceContext.startTransaction(async (tx) => { const signInRepo = tx.getRepository(user_sign_in_model_1.UserSignInModel); const calendarRepo = tx.getRepository(user_sign_in_calendar_model_1.UserSignInCalendarModel); const taskRepo = tx.getRepository(user_sign_in_task_model_1.UserSignInTaskModel); const rewardRepo = tx.getRepository(user_sign_in_task_reward_model_1.UserSignInTaskRewardModel); await signInRepo.update({ userId }, { lastSignInDate: nowYYYMMDD, consecutiveDays, }); const calendarRecord = calendarRepo.create({ userId, signInDate: nowYYYMMDD, isMakeUp: user_sign_in_calendar_model_1.SignInType.Normal, }); await calendarRepo.save(calendarRecord); const tasks = await taskRepo.find({ order: { requiredDays: 'ASC' }, }); for (const task of tasks) { if (consecutiveDays >= task.requiredDays) { const existingReward = await rewardRepo.findOne({ where: { userId, userSignInTaskId: task.id, }, }); if (!existingReward) { const reward = rewardRepo.create({ userId, userSignInTaskId: task.id, title: task.title, subtitle: task.subtitle, requiredDays: task.requiredDays, icon: task.icon, financialProductId: task.financialProductId, claimStatus: user_sign_in_task_reward_model_1.ClaimStatus.Pending, }); await rewardRepo.save(reward); } } } }); return api_1.Api.successMsg('签到成功'); } async makeUpSignIn(userId, date) { const nowYYYMMDD = help_1.Help.formatDate(Date.now(), 'YYYY-MM-DD'); if (date >= nowYYYMMDD) { return api_1.Api.error('只能补签今天之前的日期'); } const signInStats = await this.userSignInModel.findOneOrFail({ where: { userId }, }); const existingRecord = await this.userSignInCalendarModel.findOne({ where: { userId, signInDate: date }, }); if (existingRecord) { return api_1.Api.error('该日期已签到,无需补签'); } const makeUpCount = signInStats.makeUpCount; if (makeUpCount <= 0) { return api_1.Api.error('补签次数已用完'); } if (!signInStats.lastSignInDate) { return api_1.Api.error('请先完成首次签到'); } await data_source_context_1.DataSourceContext.startTransaction(async (tx) => { const calendarRepo = tx.getRepository(user_sign_in_calendar_model_1.UserSignInCalendarModel); const signInRepo = tx.getRepository(user_sign_in_model_1.UserSignInModel); const taskRepo = tx.getRepository(user_sign_in_task_model_1.UserSignInTaskModel); const rewardRepo = tx.getRepository(user_sign_in_task_reward_model_1.UserSignInTaskRewardModel); const calendarRecord = calendarRepo.create({ userId, signInDate: date, isMakeUp: user_sign_in_calendar_model_1.SignInType.MakeUp, }); await calendarRepo.save(calendarRecord); const newConsecutiveDays = await this.calcConsecutiveDays(tx, userId, signInStats.lastSignInDate, signInStats.consecutiveDays); await signInRepo.update({ userId }, { consecutiveDays: newConsecutiveDays, makeUpCount: () => `makeUpCount - 1`, usedMakeUpCount: () => `usedMakeUpCount + 1`, }); const tasks = await taskRepo.find({ order: { requiredDays: 'ASC' }, }); for (const task of tasks) { if (newConsecutiveDays >= task.requiredDays) { const existingReward = await rewardRepo.findOne({ where: { userId, userSignInTaskId: task.id, }, }); if (!existingReward) { const reward = rewardRepo.create({ userId, userSignInTaskId: task.id, title: task.title, subtitle: task.subtitle, requiredDays: task.requiredDays, icon: task.icon, financialProductId: task.financialProductId, claimStatus: user_sign_in_task_reward_model_1.ClaimStatus.Pending, }); await rewardRepo.save(reward); } } } }); return api_1.Api.successMsg('补签成功'); } async calcConsecutiveDays(tx, userId, endDate, expectedDays) { const startDate = help_1.Help.formatDate(new Date(endDate).getTime() - expectedDays * 86400000, 'YYYY-MM-DD'); const calendarRepo = tx.getRepository(user_sign_in_calendar_model_1.UserSignInCalendarModel); const count = await calendarRepo.count({ where: { userId, signInDate: (0, typeorm_2.Between)(startDate, endDate), }, }); return count === expectedDays + 1 ? expectedDays + 1 : expectedDays; } async claimReward(userId, rewardId) { await data_source_context_1.DataSourceContext.startTransaction(async (tx) => { const rewardRepo = tx.getRepository(user_sign_in_task_reward_model_1.UserSignInTaskRewardModel); const financialProductRepo = tx.getRepository(financial_product_model_1.FinancialProductModel); const financialRepo = tx.getRepository(user_financial_product_model_1.UserFinancialProductModel); const reward = await rewardRepo.findOne({ where: { id: rewardId, userId }, }); if (!reward) { throw new Error('奖励记录不存在'); } if (reward.claimStatus === user_sign_in_task_reward_model_1.ClaimStatus.Claimed) { throw new Error('该奖励已领取'); } const financialProduct = await financialProductRepo.findOneBy({ id: reward.financialProductId, }); if (!financialProduct) { throw new Error('理财产品不存在'); } const now = Date.now(); const periodDays = financialProduct.period; const expireTime = Math.floor((now + periodDays * 86400000) / 1000); const userFinancialProduct = financialRepo.create({ userId, financialProductId: reward.financialProductId, name: reward.title, period: periodDays, principal: financialProduct.principal, yieldRate: financialProduct.yieldRate, source: user_financial_product_model_1.HoldingSource.Gift, status: user_financial_product_model_1.HoldingStatus.Earning, expireTime, }); await financialRepo.save(userFinancialProduct); await rewardRepo.update({ id: rewardId }, { userFinancialProductId: userFinancialProduct.id, claimStatus: user_sign_in_task_reward_model_1.ClaimStatus.Claimed, }); }); return api_1.Api.successMsg('领取成功'); } }; exports.SignInService = SignInService; exports.SignInService = SignInService = __decorate([ (0, common_1.Injectable)(), __param(0, (0, typeorm_1.InjectRepository)(user_sign_in_model_1.UserSignInModel)), __param(1, (0, typeorm_1.InjectRepository)(user_sign_in_calendar_model_1.UserSignInCalendarModel)), __param(2, (0, typeorm_1.InjectRepository)(user_sign_in_task_model_1.UserSignInTaskModel)), __param(3, (0, typeorm_1.InjectRepository)(user_sign_in_task_reward_model_1.UserSignInTaskRewardModel)), __param(4, (0, typeorm_1.InjectRepository)(user_financial_product_model_1.UserFinancialProductModel)), __metadata("design:paramtypes", [typeorm_2.Repository, typeorm_2.Repository, typeorm_2.Repository, typeorm_2.Repository, typeorm_2.Repository, typeorm_2.DataSource]) ], SignInService); //# sourceMappingURL=signin.service.js.map