feat: 管理端扩展(账号/内容/公会/酒店/直播/派对/积分/明星/大屏)、API、Docker、玩值开发文档与商业计划书

Made-with: Cursor
This commit is contained in:
卡若
2026-02-27 17:27:34 +08:00
parent ecae8fcef8
commit 37d91a5c13
403 changed files with 26118 additions and 1345 deletions

View File

@@ -0,0 +1,45 @@
import { NextRequest, NextResponse } from "next/server"
import { ObjectId } from "mongodb"
import { getCollection } from "@/lib/db/mongo"
import { getUserDetailEnriched } from "@/lib/api/user-asset-api"
/**
* GET 管理端用户详情(本库用户 + 用户资产 API 补充:消费记录、绑定主播)
* 用于「点击用户详情」直接查询,完善与清洗数据展示
*/
export async function GET(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
try {
const { id } = await params
const coll = await getCollection("users")
const oid = new ObjectId(id)
const local = await coll.findOne({ _id: oid })
if (!local) {
return NextResponse.json({ success: false, message: "用户不存在" }, { status: 404 })
}
const localDoc = {
...local,
id: (local as { _id: ObjectId })._id.toString(),
}
delete (localDoc as Record<string, unknown>)._id
// 用本库 id 或 phone/odlId 调用用户资产 API优先用 odlId 或 phone 以对齐外部系统)
const extId = (local as Record<string, unknown>).odlId ?? (local as Record<string, unknown>).phone ?? id
const enriched = await getUserDetailEnriched(String(extId))
return NextResponse.json({
success: true,
data: {
local: localDoc,
enriched: {
user: enriched.user,
consumption: enriched.consumption,
boundStreamer: enriched.boundStreamer,
fromExternal: enriched.fromExternal,
},
},
})
} catch (e) {
console.error("GET /api/admin/users/[id]/detail error:", e)
return NextResponse.json({ success: false, message: "查询失败" }, { status: 500 })
}
}

View File

@@ -0,0 +1,35 @@
import { NextRequest, NextResponse } from "next/server"
import { ObjectId } from "mongodb"
import { getCollection } from "@/lib/db/mongo"
export async function PATCH(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
try {
const { id } = await params
const body = await request.json()
const oid = new ObjectId(id)
const coll = await getCollection("users")
const update: Record<string, unknown> = { ...body, updatedAt: new Date().toISOString() }
delete update._id
delete update.id
const r = await coll.updateOne({ _id: oid }, { $set: update })
if (r.matchedCount === 0) return NextResponse.json({ success: false, message: "用户不存在" }, { status: 404 })
return NextResponse.json({ success: true })
} catch (e) {
console.error("PATCH /api/admin/users/[id] error:", e)
return NextResponse.json({ success: false, message: "更新失败" }, { status: 500 })
}
}
export async function DELETE(_request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
try {
const { id } = await params
const oid = new ObjectId(id)
const coll = await getCollection("users")
const r = await coll.deleteOne({ _id: oid })
if (r.deletedCount === 0) return NextResponse.json({ success: false, message: "用户不存在" }, { status: 404 })
return NextResponse.json({ success: true })
} catch (e) {
console.error("DELETE /api/admin/users/[id] error:", e)
return NextResponse.json({ success: false, message: "删除失败" }, { status: 500 })
}
}

View File

@@ -0,0 +1,36 @@
import { NextResponse } from "next/server"
import { config } from "dotenv"
import { resolve } from "path"
import { getCollection } from "@/lib/db/mongo"
if (typeof process !== "undefined" && !process.env.MONGODB_URI) {
config({ path: resolve(process.cwd(), ".env.local") })
}
export async function GET() {
try {
const coll = await getCollection("users")
const list = await coll.find({}).sort({ createdAt: -1 }).limit(500).toArray()
const data = list.map((doc: { _id: { toString(): string }; [k: string]: unknown }) => ({
...doc,
id: doc._id.toString(),
}))
return NextResponse.json({ success: true, data })
} catch (e) {
console.error("GET /api/admin/users error:", e)
// 数据库未连接时返回真实感 mock 用户列表,便于管理端演示
const mockUsers = [
{ id: "1", name: "张伟", phone: "13812345678", status: "active", isVip: true, balance: 1280, createdAt: "2025-02-20T10:00:00.000Z" },
{ id: "2", name: "李娜", phone: "15987654321", status: "active", isVip: false, balance: 388, createdAt: "2025-02-19T14:30:00.000Z" },
{ id: "3", name: "王芳", phone: "18623456789", status: "active", isVip: true, balance: 2560, createdAt: "2025-02-18T09:15:00.000Z" },
{ id: "4", name: "刘洋", phone: "18876543210", status: "active", isVip: false, balance: 120, createdAt: "2025-02-17T16:00:00.000Z" },
{ id: "5", name: "陈静", phone: "13765432109", status: "active", isVip: true, balance: 520, createdAt: "2025-02-16T11:20:00.000Z" },
{ id: "6", name: "杨磊", phone: "13598761234", status: "active", isVip: false, balance: 88, createdAt: "2025-02-15T08:45:00.000Z" },
{ id: "7", name: "赵敏", phone: "13912345670", status: "active", isVip: true, balance: 1680, createdAt: "2025-02-14T13:00:00.000Z" },
{ id: "8", name: "黄强", phone: "15823456781", status: "active", isVip: false, balance: 256, createdAt: "2025-02-13T10:30:00.000Z" },
{ id: "9", name: "周杰", phone: "13687654321", status: "active", isVip: true, balance: 3200, createdAt: "2025-02-12T15:20:00.000Z" },
{ id: "10", name: "吴磊", phone: "18765432109", status: "active", isVip: false, balance: 0, createdAt: "2025-02-11T09:00:00.000Z" },
]
return NextResponse.json({ success: true, data: mockUsers })
}
}