Files
chaohua_coze/server/src/signin/signin.service.ts
jaystar e209fe02a4 feat: 实现微博签到小程序功能
- 实现签到主页面,包含签到按钮、连续天数、今日状态展示
- 实现签到记录页面,包含日历视图和签到历史列表
- 实现个人中心页面,包含用户信息和签到统计
- 后端实现签到、查询状态、查询历史三个接口
- 使用 Supabase 存储签到记录数据
- 采用星空主题设计,深蓝紫渐变背景 + 金色星光强调色
- 完成所有接口测试和前后端匹配验证
- 通过 ESLint 检查和编译验证
2026-03-16 11:17:17 +08:00

149 lines
3.3 KiB
TypeScript

import { Injectable } from '@nestjs/common';
import { getSupabaseClient } from '@/storage/database/supabase-client';
@Injectable()
export class SignInService {
/**
* 用户签到
*/
async signIn(userId: string) {
const client = getSupabaseClient();
const today = new Date().toISOString().split('T')[0]; // YYYY-MM-DD
// 检查今日是否已签到
const { data: existingRecord } = await client
.from('sign_in_records')
.select('*')
.eq('user_id', userId)
.eq('sign_date', today)
.single();
if (existingRecord) {
return {
code: 400,
msg: '今日已签到',
data: null,
};
}
// 创建签到记录
const { data, error } = await client
.from('sign_in_records')
.insert({
user_id: userId,
sign_date: today,
})
.select()
.single();
if (error) {
console.error('签到失败:', error);
return {
code: 500,
msg: '签到失败',
data: null,
};
}
return {
code: 200,
msg: '签到成功',
data,
};
}
/**
* 获取签到状态
*/
async getSignInStatus(userId: string) {
const client = getSupabaseClient();
const today = new Date().toISOString().split('T')[0];
// 检查今日是否已签到
const { data: todayRecord } = await client
.from('sign_in_records')
.select('*')
.eq('user_id', userId)
.eq('sign_date', today)
.single();
// 获取所有签到记录
const { data: allRecords } = await client
.from('sign_in_records')
.select('sign_date')
.eq('user_id', userId)
.order('sign_date', { ascending: false });
const totalDays = allRecords?.length || 0;
// 计算连续签到天数
let continuousDays = 0;
if (allRecords && allRecords.length > 0) {
const dates = allRecords.map((r) => r.sign_date).sort().reverse();
continuousDays = this.calculateContinuousDays(dates, today);
}
return {
code: 200,
msg: 'success',
data: {
todaySignedIn: !!todayRecord,
continuousDays,
totalDays,
},
};
}
/**
* 计算连续签到天数
*/
private calculateContinuousDays(dates: string[], today: string): number {
let continuousDays = 0;
let checkDate = new Date(today);
for (const dateStr of dates) {
const date = new Date(dateStr);
const diffTime = checkDate.getTime() - date.getTime();
const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24));
if (diffDays === 0 || diffDays === 1) {
continuousDays++;
checkDate = date;
} else {
break;
}
}
return continuousDays;
}
/**
* 获取签到历史记录
*/
async getSignInHistory(userId: string, limit: number = 30) {
const client = getSupabaseClient();
const { data, error } = await client
.from('sign_in_records')
.select('*')
.eq('user_id', userId)
.order('sign_date', { ascending: false })
.limit(limit);
if (error) {
console.error('获取签到历史失败:', error);
return {
code: 500,
msg: '获取签到历史失败',
data: null,
};
}
return {
code: 200,
msg: 'success',
data,
};
}
}