| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- import jwt from 'jsonwebtoken';
- import { v4 as uuidv4 } from 'uuid';
- import { config } from '../../config';
- import { prisma } from '../../models';
- import { JwtPayload } from '../../types';
- import { handleInvite } from '../invite/invite.service';
- // 验证码存储(生产环境应使用 Redis)
- const smsCodes = new Map<string, { code: string; expireAt: number }>();
- // 生成验证码
- export function generateSmsCode(phone: string): string {
- const code = Math.random().toString().slice(2, 6);
- smsCodes.set(phone, {
- code,
- expireAt: Date.now() + 5 * 60 * 1000, // 5分钟有效
- });
- console.log(`📱 验证码已生成: ${phone} -> ${code}`);
- return code;
- }
- // 验证验证码
- export function verifySmsCode(phone: string, code: string): boolean {
- const stored = smsCodes.get(phone);
- if (!stored) return false;
- if (Date.now() > stored.expireAt) {
- smsCodes.delete(phone);
- return false;
- }
- if (stored.code !== code) return false;
- smsCodes.delete(phone);
- return true;
- }
- // 生成 JWT Token
- export function generateToken(userId: string, phone?: string): string {
- const secret = config.jwt.secret;
- const payload: Omit<JwtPayload, 'iat' | 'exp'> = { userId, phone };
- return jwt.sign(payload, secret, {
- expiresIn: '7d',
- });
- }
- // 手机号登录/注册
- export async function loginWithPhone(phone: string, code?: string, inviteCode?: string): Promise<{
- token: string;
- user: {
- id: string;
- phone: string;
- nickname: string;
- avatar: string;
- memberLevel: number;
- isNewUser: boolean;
- };
- }> {
- // 免密登录:code 为空或为"123456"时直接登录(线上线下都关闭验证)
- const skipVerify = !code || code === '123456';
- if (!skipVerify) {
- // 验证验证码
- const isValid = verifySmsCode(phone, code || '');
- if (!isValid) {
- throw new Error('验证码错误或已过期');
- }
- }
- // 查找或创建用户
- let user = await prisma.user.findFirst({ where: { phone } });
- let isNewUser = false;
- if (!user) {
- user = await prisma.user.create({
- data: {
- phone,
- nickname: `用户${phone.slice(-4)}`,
- avatar: `https://api.dicebear.com/7.x/avataaars/svg?seed=${phone}`,
- memberLevel: 0,
- dailyUsage: 0,
- lastUsageDate: '',
- },
- });
- isNewUser = true;
- // 处理邀请关系
- if (inviteCode) {
- const shareRecord = await prisma.shareRecord.findFirst({
- where: { shareCode: inviteCode },
- });
- if (shareRecord) {
- await handleInvite(shareRecord.userId, user.id, inviteCode);
- }
- }
- }
- const token = generateToken(user.id.toString(), phone);
- return {
- token,
- user: {
- id: user.id.toString(),
- phone: user.phone!,
- nickname: user.nickname,
- avatar: user.avatar,
- memberLevel: user.memberLevel,
- isNewUser,
- },
- };
- }
- // 获取用户信息
- export async function getUserInfo(userId: string) {
- const user = await prisma.user.findUnique({ where: { id: parseInt(userId) } });
- if (!user) {
- throw new Error('用户不存在');
- }
- return {
- id: user.id.toString(),
- phone: user.phone,
- nickname: user.nickname,
- avatar: user.avatar,
- memberLevel: user.memberLevel,
- memberExpireAt: user.memberExpireAt,
- dailyUsage: user.dailyUsage,
- };
- }
|