Update soul-content project

This commit is contained in:
卡若
2025-12-29 14:01:37 +08:00
commit 087849d509
1112 changed files with 401606 additions and 0 deletions

BIN
app/api/.DS_Store vendored Normal file

Binary file not shown.

55
app/api/config/route.ts Normal file
View File

@@ -0,0 +1,55 @@
import { NextResponse } from 'next/server';
export async function GET() {
const config = {
paymentMethods: {
wechat: {
enabled: true,
qrCode: "/images/wechat-pay.png",
account: "卡若",
appId: process.env.TENCENT_APP_ID || "1251077262", // From .env or default
// 敏感信息后端处理,不完全暴露给前端
},
alipay: {
enabled: true,
qrCode: "/images/alipay.png",
account: "卡若",
appId: process.env.ALIPAY_ACCESS_KEY_ID || "LTAI5t9zkiWmFtHG8qmtdysW", // Using Access Key as placeholder ID
},
usdt: {
enabled: true,
network: "TRC20",
address: process.env.USDT_WALLET_ADDRESS || "TWeq9xxxxxxxxxxxxxxxxxxxx",
exchangeRate: 7.2
},
paypal: {
enabled: false,
email: process.env.PAYPAL_CLIENT_ID || "",
exchangeRate: 7.2
}
},
marketing: {
partyGroup: {
url: "https://soul.cn/party",
liveCodeUrl: "https://soul.cn/party-live",
qrCode: "/images/party-group-qr.png"
},
banner: {
text: "每日早上6-9点Soul派对房不见不散",
visible: true
}
},
authorInfo: {
name: "卡若",
description: "私域运营与技术公司主理人",
liveTime: "06:00-09:00",
platform: "Soul"
},
system: {
version: "1.0.0",
maintenance: false
}
};
return NextResponse.json(config);
}

28
app/api/content/route.ts Normal file
View File

@@ -0,0 +1,28 @@
import { type NextRequest, NextResponse } from "next/server"
import fs from "fs"
import path from "path"
export async function GET(request: NextRequest) {
const searchParams = request.nextUrl.searchParams
const filePath = searchParams.get("path")
const sectionId = searchParams.get("sectionId")
if (!filePath && !sectionId) {
return NextResponse.json({ error: "Path or sectionId is required" }, { status: 400 })
}
if (filePath?.startsWith("custom/")) {
// Custom sections have their content stored in localStorage on the client
// Return empty content, client will handle it
return NextResponse.json({ content: "", isCustom: true })
}
try {
const fullPath = path.join(process.cwd(), filePath || "")
const content = fs.readFileSync(fullPath, "utf-8")
return NextResponse.json({ content, isCustom: false })
} catch (error) {
console.error("Error reading file:", error)
return NextResponse.json({ error: "File not found" }, { status: 404 })
}
}

View File

@@ -0,0 +1,55 @@
import { NextResponse, type NextRequest } from "next/server"
import { getDocumentationCatalog } from "@/lib/documentation/catalog"
import { captureScreenshots } from "@/lib/documentation/screenshot"
import { renderDocumentationDocx } from "@/lib/documentation/docx"
export const runtime = "nodejs"
function getBaseUrl(request: NextRequest) {
const proto = request.headers.get("x-forwarded-proto") || "http"
const host = request.headers.get("x-forwarded-host") || request.headers.get("host")
if (!host) return null
return `${proto}://${host}`
}
function isAuthorized(request: NextRequest) {
const token = process.env.DOCUMENTATION_TOKEN
// If no token is configured, allow access (internal tool)
if (!token || token === "") return true
const header = request.headers.get("x-documentation-token")
const query = request.nextUrl.searchParams.get("token")
return header === token || query === token
}
export async function POST(request: NextRequest) {
if (!isAuthorized(request)) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 })
}
const baseUrl = getBaseUrl(request)
if (!baseUrl) {
return NextResponse.json({ error: "Host is required" }, { status: 400 })
}
try {
const pages = getDocumentationCatalog()
const screenshots = await captureScreenshots(pages, {
baseUrl,
timeoutMs: 60000,
viewport: { width: 430, height: 932 },
})
const docxBuffer = await renderDocumentationDocx(screenshots)
return new NextResponse(docxBuffer, {
status: 200,
headers: {
"Content-Type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"Content-Disposition": `attachment; filename="app-documentation.docx"`,
"Cache-Control": "no-store",
},
})
} catch (error) {
const message = error instanceof Error ? error.message : String(error)
return NextResponse.json({ error: message }, { status: 500 })
}
}

12
app/api/menu/route.ts Normal file
View File

@@ -0,0 +1,12 @@
import { NextResponse } from "next/server"
import { getBookStructure } from "@/lib/book-file-system"
export async function GET() {
try {
const structure = getBookStructure()
return NextResponse.json(structure)
} catch (error) {
console.error("Error generating menu:", error)
return NextResponse.json({ error: "Failed to generate menu" }, { status: 500 })
}
}

View File

@@ -0,0 +1,9 @@
import { paymentService } from '../../../services/paymentService';
import { connectDB } from '../../../lib/db';
export async function POST(req) {
await connectDB();
const { orderId, gateway } = await req.json();
const result = await paymentService.pay(orderId, gateway);
return Response.json({ success: true, result });
}

View File

@@ -0,0 +1,9 @@
import { paymentService } from '../../../services/paymentService';
import { connectDB } from '../../../lib/db';
export async function POST(req) {
await connectDB();
const data = await req.json();
const order = await paymentService.createOrder(data);
return Response.json({ success: true, order });
}

View File

@@ -0,0 +1,20 @@
import { Order } from '../../../../models/Order';
import { connectDB } from '../../../../lib/db';
export async function POST(req, { params }) {
await connectDB();
const { gateway } = await params;
const data = await req.json();
// 根据gateway处理通知并更新订单状态
// 这是一个简化版本实际需要验证签名和处理不同gateway的逻辑
const orderId = data.out_trade_no || data.order_id || data.metadata?.order_id;
if (orderId) {
const order = await Order.findById(orderId);
if (order) {
order.status = 'paid';
await order.save();
}
}
return Response.json({ success: true });
}