新增订单推荐人和邀请码功能,优化支付流程中的订单插入逻辑,确保订单记录准确。更新小程序支付请求,支持传递邀请码以便于分销归属和对账。同时,调整数据库结构以支持新字段,提升系统的稳定性和用户体验。
This commit is contained in:
@@ -63,8 +63,6 @@ export async function query(sql: string, params?: any[]) {
|
||||
}
|
||||
// mysql2 内部会读 params.length,不能传 undefined
|
||||
const safeParams = Array.isArray(params) ? params : []
|
||||
console.log('[DB Query] SQL:', sql.slice(0, 100))
|
||||
console.log('[DB Query] Params Type:', typeof params, '| Is Array:', Array.isArray(params), '| safeParams:', safeParams)
|
||||
try {
|
||||
const [results] = await connection.execute(sql, safeParams)
|
||||
// 确保调用方拿到的始终是数组,避免 undefined.length 报错
|
||||
|
||||
140
lib/prisma-helpers.ts
Normal file
140
lib/prisma-helpers.ts
Normal file
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* Prisma 辅助函数库
|
||||
* 提供常用的数据库操作封装
|
||||
*/
|
||||
|
||||
import { prisma } from '@/lib/prisma'
|
||||
|
||||
/**
|
||||
* 读取系统配置
|
||||
*/
|
||||
export async function getPrismaConfig(key: string): Promise<any> {
|
||||
try {
|
||||
const config = await prisma.system_config.findUnique({
|
||||
where: { config_key: key }
|
||||
})
|
||||
return config?.config_value
|
||||
} catch (e) {
|
||||
console.warn(`[Config] 读取配置 ${key} 失败:`, e)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新系统配置
|
||||
*/
|
||||
export async function setPrismaConfig(key: string, value: any, description?: string): Promise<void> {
|
||||
await prisma.system_config.upsert({
|
||||
where: { config_key: key },
|
||||
update: {
|
||||
config_value: value,
|
||||
description: description || null,
|
||||
updated_at: new Date()
|
||||
},
|
||||
create: {
|
||||
config_key: key,
|
||||
config_value: value,
|
||||
description: description || null
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询用户(通过 ID 或 openId)
|
||||
*/
|
||||
export async function findUserByIdOrOpenId(userId?: string, openId?: string) {
|
||||
if (!userId && !openId) return null
|
||||
|
||||
return await prisma.users.findFirst({
|
||||
where: userId ? { id: userId } : { open_id: openId }
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量查询用户
|
||||
*/
|
||||
export async function findUsersByIds(userIds: string[]) {
|
||||
return await prisma.users.findMany({
|
||||
where: { id: { in: userIds } }
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录用户追踪
|
||||
*/
|
||||
export async function trackUserAction(
|
||||
userId: string,
|
||||
action: string,
|
||||
chapterId?: string,
|
||||
target?: string,
|
||||
extraData?: any
|
||||
) {
|
||||
try {
|
||||
await prisma.user_tracks.create({
|
||||
data: {
|
||||
id: `track_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
||||
user_id: userId,
|
||||
action,
|
||||
chapter_id: chapterId || null,
|
||||
target: target || null,
|
||||
extra_data: extraData || null
|
||||
}
|
||||
})
|
||||
} catch (e) {
|
||||
console.error('[Track] 记录失败:', e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户是否购买章节
|
||||
*/
|
||||
export async function hasUserPurchasedChapter(userId: string, chapterId: string): Promise<boolean> {
|
||||
const user = await prisma.users.findUnique({
|
||||
where: { id: userId },
|
||||
select: { has_full_book: true, purchased_sections: true }
|
||||
})
|
||||
|
||||
if (!user) return false
|
||||
if (user.has_full_book) return true
|
||||
|
||||
const purchasedSections = user.purchased_sections as any
|
||||
if (Array.isArray(purchasedSections)) {
|
||||
return purchasedSections.includes(chapterId)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户购买的章节列表
|
||||
*/
|
||||
export async function getUserPurchasedChapters(userId: string): Promise<string[]> {
|
||||
const user = await prisma.users.findUnique({
|
||||
where: { id: userId },
|
||||
select: { purchased_sections: true }
|
||||
})
|
||||
|
||||
const sections = user?.purchased_sections as any
|
||||
return Array.isArray(sections) ? sections : []
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加用户购买的章节
|
||||
*/
|
||||
export async function addUserPurchasedChapter(userId: string, chapterId: string): Promise<void> {
|
||||
const user = await prisma.users.findUnique({
|
||||
where: { id: userId },
|
||||
select: { purchased_sections: true }
|
||||
})
|
||||
|
||||
const sections = user?.purchased_sections as any
|
||||
const purchased = Array.isArray(sections) ? sections : []
|
||||
|
||||
if (!purchased.includes(chapterId)) {
|
||||
purchased.push(chapterId)
|
||||
await prisma.users.update({
|
||||
where: { id: userId },
|
||||
data: { purchased_sections: purchased }
|
||||
})
|
||||
}
|
||||
}
|
||||
36
lib/prisma.ts
Normal file
36
lib/prisma.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Prisma Client 单例实例
|
||||
* Prisma 7 使用 engineType="client" 时必须提供 adapter
|
||||
* 使用 @prisma/adapter-mariadb 连接 MySQL
|
||||
*/
|
||||
|
||||
import { PrismaMariaDb } from '@prisma/adapter-mariadb'
|
||||
import { PrismaClient } from '@/lib/generated/prisma'
|
||||
|
||||
const DEFAULT_DATABASE_URL =
|
||||
'mysql://cdb_outerroot:Zhiqun1984@56b4c23f6853c.gz.cdb.myqcloud.com:14413/soul_miniprogram'
|
||||
|
||||
declare global {
|
||||
// eslint-disable-next-line no-var
|
||||
var prisma: PrismaClient | undefined
|
||||
}
|
||||
|
||||
// Prisma 7 要求:使用 client 引擎时必须传入 adapter
|
||||
const adapter = new PrismaMariaDb(
|
||||
process.env.DATABASE_URL || DEFAULT_DATABASE_URL
|
||||
)
|
||||
|
||||
const prismaInstance = new PrismaClient({
|
||||
adapter,
|
||||
log: process.env.NODE_ENV === 'development' ? ['error', 'warn'] : ['error'],
|
||||
})
|
||||
|
||||
export const prisma = global.prisma || prismaInstance
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
global.prisma = prisma
|
||||
}
|
||||
|
||||
process.on('beforeExit', async () => {
|
||||
await prisma.$disconnect()
|
||||
})
|
||||
Reference in New Issue
Block a user