v1.19 全面改版:VIP会员系统、我的收益、创业老板排行、阅读量排序
- 后端: users表新增VIP字段, 4个VIP API (purchase/status/profile/members) - 后端: hot接口改按user_tracks阅读量排序 - 后端: orders表支持vip产品类型, migrate新增vip_fields迁移 - 小程序「我的」: 推广中心改为我的收益, 头像VIP标识, VIP入口卡片 - 小程序「我的」: 最近阅读显示真实章节名称 - 小程序首页: 去掉内容概览, 新增创业老板排行(4列网格) - 小程序首页: 精选推荐从hot接口获取, goToRead增加track记录 - 新增页面: VIP详情页, 会员详情页 - 开发文档精简为10个标准目录, 创建SKILL.md, 需求日志规范化 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,74 +1,86 @@
|
||||
/**
|
||||
* 热门章节API
|
||||
* 返回点击量最高的章节
|
||||
* 按阅读量(user_tracks view_chapter)排序
|
||||
*/
|
||||
import { NextResponse } from 'next/server'
|
||||
import { query } from '@/lib/db'
|
||||
|
||||
const DEFAULT_CHAPTERS = [
|
||||
{ id: '1.1', title: '荷包:电动车出租的被动收入模式', tag: '免费', tagClass: 'tag-free', part: '真实的人', views: 0 },
|
||||
{ id: '9.12', title: '美业整合:一个人的公司如何月入十万', tag: '热门', tagClass: 'tag-pink', part: '真实的赚钱', views: 0 },
|
||||
{ id: '3.1', title: '3000万流水如何跑出来', tag: '热门', tagClass: 'tag-pink', part: '真实的行业', views: 0 },
|
||||
{ id: '8.1', title: '流量杠杆:抖音、Soul、飞书', tag: '推荐', tagClass: 'tag-purple', part: '真实的赚钱', views: 0 },
|
||||
{ id: '9.13', title: 'AI工具推广:一个隐藏的高利润赛道', tag: '最新', tagClass: 'tag-green', part: '真实的赚钱', views: 0 },
|
||||
]
|
||||
|
||||
const SECTION_INFO: Record<string, any> = {
|
||||
'1.1': { title: '荷包:电动车出租的被动收入模式', part: '真实的人', tag: '免费', tagClass: 'tag-free' },
|
||||
'1.2': { title: '老墨:资源整合高手的社交方法', part: '真实的人', tag: '推荐', tagClass: 'tag-purple' },
|
||||
'2.1': { title: '电商的底层逻辑', part: '真实的行业', tag: '推荐', tagClass: 'tag-purple' },
|
||||
'3.1': { title: '3000万流水如何跑出来', part: '真实的行业', tag: '热门', tagClass: 'tag-pink' },
|
||||
'4.1': { title: '我的第一次创业失败', part: '真实的错误', tag: '热门', tagClass: 'tag-pink' },
|
||||
'5.1': { title: '未来职业的三个方向', part: '真实的社会', tag: '推荐', tagClass: 'tag-purple' },
|
||||
'8.1': { title: '流量杠杆:抖音、Soul、飞书', part: '真实的赚钱', tag: '推荐', tagClass: 'tag-purple' },
|
||||
'9.12': { title: '美业整合:一个人的公司如何月入十万', part: '真实的赚钱', tag: '热门', tagClass: 'tag-pink' },
|
||||
'9.13': { title: 'AI工具推广:一个隐藏的高利润赛道', part: '真实的赚钱', tag: '最新', tagClass: 'tag-green' },
|
||||
'9.14': { title: '大健康私域:一个月150万的70后', part: '真实的赚钱', tag: '热门', tagClass: 'tag-pink' },
|
||||
'9.15': { title: '本地同城运营拿150万投资', part: '真实的赚钱', tag: '热门', tagClass: 'tag-pink' },
|
||||
}
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
// 从数据库查询点击量高的章节(如果有统计表)
|
||||
let hotChapters = []
|
||||
|
||||
let hotChapters: any[] = []
|
||||
|
||||
try {
|
||||
// 尝试从订单表统计购买量高的章节
|
||||
// 按 user_tracks 的 view_chapter 阅读量排序
|
||||
const rows = await query(`
|
||||
SELECT
|
||||
section_id as id,
|
||||
COUNT(*) as purchase_count
|
||||
FROM orders
|
||||
WHERE status = 'completed' AND section_id IS NOT NULL
|
||||
GROUP BY section_id
|
||||
ORDER BY purchase_count DESC
|
||||
SELECT chapter_id as id, COUNT(*) as view_count
|
||||
FROM user_tracks
|
||||
WHERE action = 'view_chapter' AND chapter_id IS NOT NULL AND chapter_id != ''
|
||||
GROUP BY chapter_id
|
||||
ORDER BY view_count DESC
|
||||
LIMIT 10
|
||||
`) as any[]
|
||||
|
||||
if (rows && rows.length > 0) {
|
||||
// 补充章节信息
|
||||
const sectionInfo: Record<string, any> = {
|
||||
'1.1': { title: '荷包:电动车出租的被动收入模式', part: '真实的人', tag: '免费' },
|
||||
'9.12': { title: '美业整合:一个人的公司如何月入十万', part: '真实的赚钱', tag: '热门' },
|
||||
'3.1': { title: '3000万流水如何跑出来', part: '真实的行业', tag: '热门' },
|
||||
'8.1': { title: '流量杠杆:抖音、Soul、飞书', part: '真实的赚钱', tag: '推荐' },
|
||||
'9.13': { title: 'AI工具推广:一个隐藏的高利润赛道', part: '真实的赚钱', tag: '最新' },
|
||||
'9.14': { title: '大健康私域:一个月150万的70后', part: '真实的赚钱', tag: '热门' },
|
||||
'1.2': { title: '老墨:资源整合高手的社交方法', part: '真实的人', tag: '推荐' },
|
||||
'2.1': { title: '电商的底层逻辑', part: '真实的行业', tag: '推荐' },
|
||||
'4.1': { title: '我的第一次创业失败', part: '真实的错误', tag: '热门' },
|
||||
'5.1': { title: '未来职业的三个方向', part: '真实的社会', tag: '推荐' }
|
||||
}
|
||||
|
||||
hotChapters = rows.map((row: any) => ({
|
||||
id: row.id,
|
||||
...(sectionInfo[row.id] || { title: `章节${row.id}`, part: '', tag: '热门' }),
|
||||
purchaseCount: row.purchase_count
|
||||
}))
|
||||
|
||||
if (rows?.length) {
|
||||
hotChapters = rows.map((row: any) => {
|
||||
const info = SECTION_INFO[row.id] || {}
|
||||
return {
|
||||
id: row.id,
|
||||
title: info.title || `章节 ${row.id}`,
|
||||
part: info.part || '',
|
||||
tag: info.tag || '热门',
|
||||
tagClass: info.tagClass || 'tag-pink',
|
||||
views: row.view_count
|
||||
}
|
||||
})
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('[Hot] 数据库查询失败,使用默认数据')
|
||||
console.log('[Hot] user_tracks查询失败,尝试订单统计')
|
||||
// 降级:从订单表统计
|
||||
try {
|
||||
const rows = await query(`
|
||||
SELECT product_id as id, COUNT(*) as purchase_count
|
||||
FROM orders WHERE status = 'paid' AND product_id IS NOT NULL
|
||||
GROUP BY product_id ORDER BY purchase_count DESC LIMIT 10
|
||||
`) as any[]
|
||||
if (rows?.length) {
|
||||
hotChapters = rows.map((row: any) => ({
|
||||
id: row.id,
|
||||
...(SECTION_INFO[row.id] || { title: `章节 ${row.id}`, part: '', tag: '热门', tagClass: 'tag-pink' }),
|
||||
views: row.purchase_count
|
||||
}))
|
||||
}
|
||||
} catch { /* 使用默认 */ }
|
||||
}
|
||||
|
||||
// 如果没有数据,返回默认热门章节
|
||||
if (hotChapters.length === 0) {
|
||||
hotChapters = [
|
||||
{ id: '1.1', title: '荷包:电动车出租的被动收入模式', tag: '免费', part: '真实的人' },
|
||||
{ id: '9.12', title: '美业整合:一个人的公司如何月入十万', tag: '热门', part: '真实的赚钱' },
|
||||
{ id: '3.1', title: '3000万流水如何跑出来', tag: '热门', part: '真实的行业' },
|
||||
{ id: '8.1', title: '流量杠杆:抖音、Soul、飞书', tag: '推荐', part: '真实的赚钱' },
|
||||
{ id: '9.13', title: 'AI工具推广:一个隐藏的高利润赛道', tag: '最新', part: '真实的赚钱' }
|
||||
]
|
||||
|
||||
if (!hotChapters.length) {
|
||||
hotChapters = DEFAULT_CHAPTERS
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
chapters: hotChapters
|
||||
})
|
||||
|
||||
|
||||
return NextResponse.json({ success: true, chapters: hotChapters })
|
||||
} catch (error) {
|
||||
console.error('[Hot] Error:', error)
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
chapters: []
|
||||
})
|
||||
return NextResponse.json({ success: true, chapters: DEFAULT_CHAPTERS })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,6 +115,47 @@ export async function POST(request: NextRequest) {
|
||||
}
|
||||
}
|
||||
|
||||
// VIP会员字段
|
||||
if (!migration || migration === 'vip_fields') {
|
||||
const vipFields = [
|
||||
{ name: 'is_vip', def: "BOOLEAN DEFAULT FALSE COMMENT 'VIP会员'" },
|
||||
{ name: 'vip_expire_date', def: "TIMESTAMP NULL COMMENT 'VIP到期时间'" },
|
||||
{ name: 'vip_name', def: "VARCHAR(100) COMMENT '会员真实姓名'" },
|
||||
{ name: 'vip_project', def: "VARCHAR(200) COMMENT '会员项目名称'" },
|
||||
{ name: 'vip_contact', def: "VARCHAR(100) COMMENT '会员联系方式'" },
|
||||
{ name: 'vip_avatar', def: "VARCHAR(500) COMMENT '会员展示头像'" },
|
||||
{ name: 'vip_bio', def: "VARCHAR(500) COMMENT '会员简介'" },
|
||||
]
|
||||
let addedCount = 0
|
||||
let existCount = 0
|
||||
for (const field of vipFields) {
|
||||
try {
|
||||
await query(`SELECT ${field.name} FROM users LIMIT 1`)
|
||||
existCount++
|
||||
} catch {
|
||||
try {
|
||||
await query(`ALTER TABLE users ADD COLUMN ${field.name} ${field.def}`)
|
||||
addedCount++
|
||||
} catch (e: any) {
|
||||
if (e.code !== 'ER_DUP_FIELDNAME') {
|
||||
results.push(`⚠️ 添加VIP字段 ${field.name} 失败: ${e.message}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 扩展 orders.product_type 支持 vip
|
||||
try {
|
||||
await query(`ALTER TABLE orders MODIFY COLUMN product_type ENUM('section', 'fullbook', 'match', 'vip') NOT NULL`)
|
||||
results.push('✅ orders.product_type 已支持 vip')
|
||||
} catch (e: any) {
|
||||
results.push('ℹ️ orders.product_type 更新跳过: ' + e.message)
|
||||
}
|
||||
|
||||
if (addedCount > 0) results.push(`✅ VIP字段新增 ${addedCount} 个`)
|
||||
if (existCount > 0) results.push(`ℹ️ VIP字段已有 ${existCount} 个存在`)
|
||||
}
|
||||
|
||||
// 用户标签定义表
|
||||
if (!migration || migration === 'user_tag_definitions') {
|
||||
try {
|
||||
@@ -189,7 +230,7 @@ export async function GET() {
|
||||
|
||||
// 检查用户表字段
|
||||
const userFields: Record<string, boolean> = {}
|
||||
const checkFields = ['ckb_user_id', 'ckb_synced_at', 'ckb_tags', 'tags', 'merged_tags']
|
||||
const checkFields = ['ckb_user_id', 'ckb_synced_at', 'ckb_tags', 'tags', 'merged_tags', 'is_vip', 'vip_expire_date', 'vip_name']
|
||||
|
||||
for (const field of checkFields) {
|
||||
try {
|
||||
|
||||
67
app/api/vip/members/route.ts
Normal file
67
app/api/vip/members/route.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* VIP会员列表 - 用于「创业老板排行」展示
|
||||
*/
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { query } from '@/lib/db'
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
const limit = parseInt(new URL(request.url).searchParams.get('limit') || '20')
|
||||
const memberId = new URL(request.url).searchParams.get('id')
|
||||
|
||||
try {
|
||||
// 查询单个会员详情
|
||||
if (memberId) {
|
||||
const rows = await query(
|
||||
`SELECT id, nickname, avatar, vip_name, vip_project, vip_contact, vip_avatar, vip_bio,
|
||||
is_vip, vip_expire_date, created_at
|
||||
FROM users WHERE id = ? AND is_vip = TRUE AND vip_expire_date > NOW()`,
|
||||
[memberId]
|
||||
) as any[]
|
||||
|
||||
if (!rows.length) {
|
||||
return NextResponse.json({ success: false, error: '会员不存在或已过期' }, { status: 404 })
|
||||
}
|
||||
|
||||
const m = rows[0]
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: {
|
||||
id: m.id,
|
||||
name: m.vip_name || m.nickname || '创业者',
|
||||
avatar: m.vip_avatar || m.avatar || '',
|
||||
project: m.vip_project || '',
|
||||
contact: m.vip_contact || '',
|
||||
bio: m.vip_bio || '',
|
||||
joinDate: m.created_at
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 获取VIP会员列表(已填写资料的优先排前面)
|
||||
const members = await query(
|
||||
`SELECT id, nickname, avatar, vip_name, vip_project, vip_avatar, vip_bio
|
||||
FROM users
|
||||
WHERE is_vip = TRUE AND vip_expire_date > NOW()
|
||||
ORDER BY
|
||||
CASE WHEN vip_name IS NOT NULL AND vip_name != '' THEN 0 ELSE 1 END,
|
||||
vip_expire_date DESC
|
||||
LIMIT ?`,
|
||||
[limit]
|
||||
) as any[]
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: members.map((m: any) => ({
|
||||
id: m.id,
|
||||
name: m.vip_name || m.nickname || '创业者',
|
||||
avatar: m.vip_avatar || m.avatar || '',
|
||||
project: m.vip_project || '',
|
||||
bio: m.vip_bio || ''
|
||||
})),
|
||||
total: members.length
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('[VIP Members]', error)
|
||||
return NextResponse.json({ success: false, error: '查询失败', data: [], total: 0 })
|
||||
}
|
||||
}
|
||||
77
app/api/vip/profile/route.ts
Normal file
77
app/api/vip/profile/route.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* VIP会员资料填写/更新
|
||||
*/
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { query } from '@/lib/db'
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const { userId, name, project, contact, avatar, bio } = await request.json()
|
||||
if (!userId) {
|
||||
return NextResponse.json({ success: false, error: '缺少userId' }, { status: 400 })
|
||||
}
|
||||
|
||||
const users = await query('SELECT is_vip, vip_expire_date FROM users WHERE id = ?', [userId]) as any[]
|
||||
if (!users.length) {
|
||||
return NextResponse.json({ success: false, error: '用户不存在' }, { status: 404 })
|
||||
}
|
||||
|
||||
const user = users[0]
|
||||
if (!user.is_vip || !user.vip_expire_date || new Date(user.vip_expire_date) <= new Date()) {
|
||||
return NextResponse.json({ success: false, error: '仅VIP会员可填写资料' }, { status: 403 })
|
||||
}
|
||||
|
||||
const updates: string[] = []
|
||||
const params: any[] = []
|
||||
|
||||
if (name !== undefined) { updates.push('vip_name = ?'); params.push(name) }
|
||||
if (project !== undefined) { updates.push('vip_project = ?'); params.push(project) }
|
||||
if (contact !== undefined) { updates.push('vip_contact = ?'); params.push(contact) }
|
||||
if (avatar !== undefined) { updates.push('vip_avatar = ?'); params.push(avatar) }
|
||||
if (bio !== undefined) { updates.push('vip_bio = ?'); params.push(bio) }
|
||||
|
||||
if (!updates.length) {
|
||||
return NextResponse.json({ success: false, error: '无更新内容' }, { status: 400 })
|
||||
}
|
||||
|
||||
params.push(userId)
|
||||
await query(`UPDATE users SET ${updates.join(', ')} WHERE id = ?`, params)
|
||||
|
||||
return NextResponse.json({ success: true, message: '资料已更新' })
|
||||
} catch (error) {
|
||||
console.error('[VIP Profile]', error)
|
||||
return NextResponse.json({ success: false, error: '更新失败' }, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
const userId = new URL(request.url).searchParams.get('userId')
|
||||
if (!userId) {
|
||||
return NextResponse.json({ success: false, error: '缺少userId' }, { status: 400 })
|
||||
}
|
||||
|
||||
try {
|
||||
const rows = await query(
|
||||
'SELECT vip_name, vip_project, vip_contact, vip_avatar, vip_bio FROM users WHERE id = ?',
|
||||
[userId]
|
||||
) as any[]
|
||||
|
||||
if (!rows.length) {
|
||||
return NextResponse.json({ success: false, error: '用户不存在' }, { status: 404 })
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: {
|
||||
name: rows[0].vip_name || '',
|
||||
project: rows[0].vip_project || '',
|
||||
contact: rows[0].vip_contact || '',
|
||||
avatar: rows[0].vip_avatar || '',
|
||||
bio: rows[0].vip_bio || ''
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('[VIP Profile GET]', error)
|
||||
return NextResponse.json({ success: false, error: '查询失败' }, { status: 500 })
|
||||
}
|
||||
}
|
||||
57
app/api/vip/purchase/route.ts
Normal file
57
app/api/vip/purchase/route.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* VIP会员购买 - 创建VIP订单
|
||||
*/
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { query, getConfig } from '@/lib/db'
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const { userId } = await request.json()
|
||||
if (!userId) {
|
||||
return NextResponse.json({ success: false, error: '缺少userId' }, { status: 400 })
|
||||
}
|
||||
|
||||
const users = await query(
|
||||
'SELECT id, open_id, is_vip, vip_expire_date FROM users WHERE id = ?',
|
||||
[userId]
|
||||
) as any[]
|
||||
if (!users.length) {
|
||||
return NextResponse.json({ success: false, error: '用户不存在' }, { status: 404 })
|
||||
}
|
||||
const user = users[0]
|
||||
|
||||
// 如果已经是VIP且未过期
|
||||
if (user.is_vip && user.vip_expire_date && new Date(user.vip_expire_date) > new Date()) {
|
||||
return NextResponse.json({ success: false, error: '当前已是VIP会员' }, { status: 400 })
|
||||
}
|
||||
|
||||
let vipPrice = 1980
|
||||
try {
|
||||
const config = await getConfig('vip_price')
|
||||
if (config) vipPrice = Number(config) || 1980
|
||||
} catch { /* 默认 */ }
|
||||
|
||||
const orderId = 'vip_' + Date.now().toString(36) + Math.random().toString(36).substr(2, 6)
|
||||
const orderSn = 'VIP' + Date.now() + Math.floor(Math.random() * 1000)
|
||||
|
||||
await query(
|
||||
`INSERT INTO orders (id, order_sn, user_id, open_id, product_type, amount, description, status)
|
||||
VALUES (?, ?, ?, ?, 'vip', ?, 'VIP年度会员', 'created')`,
|
||||
[orderId, orderSn, userId, user.open_id || '', vipPrice]
|
||||
)
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: {
|
||||
orderId,
|
||||
orderSn,
|
||||
amount: vipPrice,
|
||||
productType: 'vip',
|
||||
description: 'VIP年度会员(365天)'
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('[VIP Purchase]', error)
|
||||
return NextResponse.json({ success: false, error: '创建订单失败' }, { status: 500 })
|
||||
}
|
||||
}
|
||||
73
app/api/vip/status/route.ts
Normal file
73
app/api/vip/status/route.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* VIP会员状态查询
|
||||
*/
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { query, getConfig } from '@/lib/db'
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
const userId = new URL(request.url).searchParams.get('userId')
|
||||
if (!userId) {
|
||||
return NextResponse.json({ success: false, error: '缺少userId' }, { status: 400 })
|
||||
}
|
||||
|
||||
try {
|
||||
const rows = await query(
|
||||
`SELECT is_vip, vip_expire_date, vip_name, vip_project, vip_contact, vip_avatar, vip_bio,
|
||||
has_full_book, nickname, avatar
|
||||
FROM users WHERE id = ?`,
|
||||
[userId]
|
||||
) as any[]
|
||||
|
||||
if (!rows.length) {
|
||||
return NextResponse.json({ success: false, error: '用户不存在' }, { status: 404 })
|
||||
}
|
||||
|
||||
const user = rows[0]
|
||||
const now = new Date()
|
||||
const isVip = user.is_vip && user.vip_expire_date && new Date(user.vip_expire_date) > now
|
||||
|
||||
// 若过期则自动标记
|
||||
if (user.is_vip && !isVip) {
|
||||
await query('UPDATE users SET is_vip = FALSE WHERE id = ?', [userId]).catch(() => {})
|
||||
}
|
||||
|
||||
let vipPrice = 1980
|
||||
let vipRights: string[] = []
|
||||
try {
|
||||
const priceConfig = await getConfig('vip_price')
|
||||
if (priceConfig) vipPrice = Number(priceConfig) || 1980
|
||||
const rightsConfig = await getConfig('vip_rights')
|
||||
if (rightsConfig) vipRights = Array.isArray(rightsConfig) ? rightsConfig : JSON.parse(rightsConfig)
|
||||
} catch { /* 使用默认 */ }
|
||||
|
||||
if (!vipRights.length) {
|
||||
vipRights = [
|
||||
'解锁全部章节内容(365天)',
|
||||
'匹配所有创业伙伴',
|
||||
'创业老板排行榜展示',
|
||||
'专属VIP标识'
|
||||
]
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: {
|
||||
isVip,
|
||||
expireDate: user.vip_expire_date,
|
||||
daysRemaining: isVip ? Math.ceil((new Date(user.vip_expire_date).getTime() - now.getTime()) / 86400000) : 0,
|
||||
profile: {
|
||||
name: user.vip_name || '',
|
||||
project: user.vip_project || '',
|
||||
contact: user.vip_contact || '',
|
||||
avatar: user.vip_avatar || user.avatar || '',
|
||||
bio: user.vip_bio || ''
|
||||
},
|
||||
price: vipPrice,
|
||||
rights: vipRights
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('[VIP Status]', error)
|
||||
return NextResponse.json({ success: false, error: '查询失败' }, { status: 500 })
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user