fix: 滚动条主题适配 + 套餐 API 输入校验补全

- 滚动条默认浅色,data-theme="dark" 下切换深色
- admin layout / PayPageLayout 根 div 加 data-theme 属性
- 套餐 POST/PUT: name 类型、空值、长度(100)校验 + trim
- 套餐 PUT: 补全 sort_order 非负整数校验
This commit is contained in:
erio
2026-03-15 17:24:44 +08:00
parent a7089936a4
commit 58d4c7efbf
5 changed files with 48 additions and 10 deletions

View File

@@ -35,7 +35,7 @@ function AdminLayoutInner({ children }: { children: React.ReactNode }) {
};
return (
<div className={['min-h-screen', isDark ? 'bg-slate-950' : 'bg-slate-100'].join(' ')}>
<div data-theme={theme} className={['min-h-screen', isDark ? 'bg-slate-950' : 'bg-slate-100'].join(' ')}>
<div className="px-2 pt-2 sm:px-3 sm:pt-3">
<nav
className={[

View File

@@ -61,10 +61,19 @@ export async function PUT(request: NextRequest, { params }: { params: Promise<{
if (body.validity_days !== undefined && (!Number.isInteger(body.validity_days) || body.validity_days <= 0)) {
return NextResponse.json({ error: 'validity_days 必须是正整数' }, { status: 400 });
}
if (body.name !== undefined && (typeof body.name !== 'string' || body.name.trim() === '')) {
return NextResponse.json({ error: 'name 不能为空' }, { status: 400 });
}
if (body.name !== undefined && body.name.length > 100) {
return NextResponse.json({ error: 'name 不能超过 100 个字符' }, { status: 400 });
}
if (body.sort_order !== undefined && (!Number.isInteger(body.sort_order) || body.sort_order < 0)) {
return NextResponse.json({ error: 'sort_order 必须是非负整数' }, { status: 400 });
}
const data: Record<string, unknown> = {};
if (body.group_id !== undefined) data.groupId = Number(body.group_id);
if (body.name !== undefined) data.name = body.name;
if (body.name !== undefined) data.name = body.name.trim();
if (body.description !== undefined) data.description = body.description;
if (body.price !== undefined) data.price = body.price;
if (body.original_price !== undefined) data.originalPrice = body.original_price;

View File

@@ -93,8 +93,14 @@ export async function POST(request: NextRequest) {
product_name,
} = body;
if (!group_id || !name || price === undefined) {
return NextResponse.json({ error: '缺少必填字段: group_id, name, price' }, { status: 400 });
if (!group_id || price === undefined) {
return NextResponse.json({ error: '缺少必填字段: group_id, price' }, { status: 400 });
}
if (typeof name !== 'string' || name.trim() === '') {
return NextResponse.json({ error: 'name 不能为空' }, { status: 400 });
}
if (name.length > 100) {
return NextResponse.json({ error: 'name 不能超过 100 个字符' }, { status: 400 });
}
if (typeof price !== 'number' || price <= 0 || price > 99999999.99) {
@@ -126,7 +132,7 @@ export async function POST(request: NextRequest) {
const plan = await prisma.subscriptionPlan.create({
data: {
groupId: Number(group_id),
name,
name: name.trim(),
description: description ?? null,
price,
originalPrice: original_price ?? null,

View File

@@ -17,10 +17,10 @@ body {
sans-serif;
}
/* Scrollbar - Dark theme */
/* Scrollbar - Light theme (default) */
* {
scrollbar-width: thin;
scrollbar-color: #475569 #1e293b;
scrollbar-color: #cbd5e1 #f1f5f9;
}
*::-webkit-scrollbar {
@@ -29,18 +29,40 @@ body {
}
*::-webkit-scrollbar-track {
background: #1e293b;
background: #f1f5f9;
}
*::-webkit-scrollbar-thumb {
background: #475569;
background: #cbd5e1;
border-radius: 4px;
}
*::-webkit-scrollbar-thumb:hover {
background: #64748b;
background: #94a3b8;
}
*::-webkit-scrollbar-corner {
background: #f1f5f9;
}
/* Scrollbar - Dark theme */
[data-theme='dark'],
[data-theme='dark'] * {
scrollbar-color: #475569 #1e293b;
}
[data-theme='dark'] *::-webkit-scrollbar-track {
background: #1e293b;
}
[data-theme='dark'] *::-webkit-scrollbar-thumb {
background: #475569;
}
[data-theme='dark'] *::-webkit-scrollbar-thumb:hover {
background: #64748b;
}
[data-theme='dark'] *::-webkit-scrollbar-corner {
background: #1e293b;
}

View File

@@ -26,6 +26,7 @@ export default function PayPageLayout({
return (
<div
data-theme={isDark ? 'dark' : 'light'}
className={[
'relative w-full overflow-hidden',
isEmbedded ? 'min-h-screen p-2' : 'min-h-screen p-3 sm:p-4',