Update soul-content project
This commit is contained in:
BIN
app/api/.DS_Store
vendored
Normal file
BIN
app/api/.DS_Store
vendored
Normal file
Binary file not shown.
55
app/api/config/route.ts
Normal file
55
app/api/config/route.ts
Normal 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
28
app/api/content/route.ts
Normal 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 })
|
||||
}
|
||||
}
|
||||
55
app/api/documentation/generate/route.ts
Normal file
55
app/api/documentation/generate/route.ts
Normal 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
12
app/api/menu/route.ts
Normal 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 })
|
||||
}
|
||||
}
|
||||
9
app/api/payment/checkout/route.js
Normal file
9
app/api/payment/checkout/route.js
Normal 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 });
|
||||
}
|
||||
9
app/api/payment/create/route.js
Normal file
9
app/api/payment/create/route.js
Normal 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 });
|
||||
}
|
||||
20
app/api/payment/notify/[gateway]/route.js
Normal file
20
app/api/payment/notify/[gateway]/route.js
Normal 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 });
|
||||
}
|
||||
Reference in New Issue
Block a user