1. MySQL安装和配置
1.1 安装MySQL
# Windows用户可以从官网下载MySQL安装包
# https://dev.mysql.com/downloads/installer/
# 验证安装
mysql --version
# 启动MySQL服务
# Windows:
net start mysql
# Linux/Mac:
sudo service mysql start
1.2 创建数据库
CREATE DATABASE mindai_db;
2. Prisma设置
2.1 安装Prisma
npm install prisma --save-dev
npm install @prisma/client
# 初始化Prisma
npx prisma init
2.2 配置数据库连接
# .env
DATABASE_URL="mysql://用户名:密码@localhost:3306/mindai_db"
3. 数据模型设计
3.1 创建Prisma模型
// prisma/schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}
// 用户模型
model User {
id String @id @default(cuid())
email String @unique
name String?
password String
role Role @default(USER)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
profile Profile?
assessments Assessment[]
emotions Emotion[]
consultations Consultation[]
posts Post[]
comments Comment[]
}
// 用户角色枚举
enum Role {
USER
COUNSELOR
ADMIN
}
// 用户档案
model Profile {
id String @id @default(cuid())
userId String @unique
age Int?
gender String?
avatar String?
bio String? @db.Text
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id])
}
// 心理测评
model Assessment {
id String @id @default(cuid())
userId String
type String
answers Json
score Int
result Json
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id])
}
// 情绪记录
model Emotion {
id String @id @default(cuid())
userId String
content String @db.Text
type String
intensity Float
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id])
}
// 咨询会话
model Consultation {
id String @id @default(cuid())
userId String
counselorId String?
status String @default("PENDING")
topic String
description String @db.Text
startTime DateTime?
endTime DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id])
messages Message[]
}
// 咨询消息
model Message {
id String @id @default(cuid())
consultationId String
senderId String
content String @db.Text
createdAt DateTime @default(now())
consultation Consultation @relation(fields: [consultationId], references: [id])
}
// 社区帖子
model Post {
id String @id @default(cuid())
userId String
title String
content String @db.Text
tags String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id])
comments Comment[]
}
// 评论
model Comment {
id String @id @default(cuid())
postId String
userId String
content String @db.Text
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
post Post @relation(fields: [postId], references: [id])
user User @relation(fields: [userId], references: [id])
}
4. 数据库操作封装
4.1 创建Prisma客户端实例
// src/lib/prisma.ts
import { PrismaClient } from '@prisma/client'
const globalForPrisma = global as unknown as { prisma: PrismaClient }
export const prisma = globalForPrisma.prisma || new PrismaClient()
if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma
4.2 创建数据库服务类
// src/services/database/user.service.ts
import { prisma } from '@/lib/prisma'
import { hash } from 'bcryptjs'
import type { User } from '@prisma/client'
export class UserService {
static async create(data: {
email: string
password: string
name?: string
}) {
const hashedPassword = await hash(data.password, 12)
return prisma.user.create({
data: {
...data,
password: hashedPassword,
},
})
}
static async findByEmail(email: string) {
return prisma.user.findUnique({
where: { email },
include: { profile: true },
})
}
static async updateProfile(userId: string, data: {
age?: number
gender?: string
avatar?: string
bio?: string
}) {
return prisma.profile.upsert({
where: { userId },
update: data,
create: {
userId,
...data,
},
})
}
}
// src/services/database/assessment.service.ts
export class AssessmentService {
static async create(data: {
userId: string
type: string
answers: any
score: number
result: any
}) {
return prisma.assessment.create({
data,
})
}
static async findByUser(userId: string) {
return prisma.assessment.findMany({
where: { userId },
orderBy: { createdAt: 'desc' },
})
}
}
// 其他服务类似...
5. 数据迁移与验证
5.1 创建数据库迁移
# 生成迁移文件
npx prisma migrate dev --name init
# 应用迁移
npx prisma migrate deploy
5.2 验证数据模型
// src/scripts/test-db.ts
import { prisma } from '@/lib/prisma'
async function main() {
// 创建测试用户
const user = await prisma.user.create({
data: {
email: 'test@example.com',
password: 'hashed_password',
name: '测试用户',
profile: {
create: {
age: 25,
gender: '男',
},
},
},
})
console.log('Created user:', user)
// 创建测试评估
const assessment = await prisma.assessment.create({
data: {
userId: user.id,
type: 'personality',
answers: {},
score: 85,
result: {},
},
})
console.log('Created assessment:', assessment)
}
main()
.catch(console.error)
.finally(() => prisma.$disconnect())
6. API路由实现
6.1 用户API
// src/app/api/users/route.ts
import { NextResponse } from 'next/server'
import { UserService } from '@/services/database/user.service'
export async function POST(req: Request) {
try {
const body = await req.json()
const user = await UserService.create(body)
return NextResponse.json(user)
} catch (error) {
return NextResponse.json(
{ error: 'Failed to create user' },
{ status: 500 }
)
}
}
export async function GET(req: Request) {
const { searchParams } = new URL(req.url)
const email = searchParams.get('email')
if (!email) {
return NextResponse.json(
{ error: 'Email is required' },
{ status: 400 }
)
}
try {
const user = await UserService.findByEmail(email)
return NextResponse.json(user)
} catch (error) {
return NextResponse.json(
{ error: 'Failed to fetch user' },
{ status: 500 }
)
}
}
6.2 评估API
// src/app/api/assessments/route.ts
import { NextResponse } from 'next/server'
import { AssessmentService } from '@/services/database/assessment.service'
export async function POST(req: Request) {
try {
const body = await req.json()
const assessment = await AssessmentService.create(body)
return NextResponse.json(assessment)
} catch (error) {
return NextResponse.json(
{ error: 'Failed to create assessment' },
{ status: 500 }
)
}
}
export async function GET(req: Request) {
const { searchParams } = new URL(req.url)
const userId = searchParams.get('userId')
if (!userId) {
return NextResponse.json(
{ error: 'User ID is required' },
{ status: 400 }
)
}
try {
const assessments = await AssessmentService.findByUser(userId)
return NextResponse.json(assessments)
} catch (error) {
return NextResponse.json(
{ error: 'Failed to fetch assessments' },
{ status: 500 }
)
}
}
7. 下一步计划