geo/frontend/app/(dashboard)/dashboard/settings/platforms/page.tsx

369 lines
16 KiB
TypeScript

"use client";
import { useState, useEffect } from "react";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { platformRulesApi, PlatformBrief, PlatformDetailResponse } from "@/lib/api/platform-rules";
const PRIORITY_COLORS: Record<string, string> = {
P0: "bg-red-100 text-red-800",
P1: "bg-yellow-100 text-yellow-800",
P2: "bg-green-100 text-green-800",
};
const SENSITIVITY_COLORS: Record<string, string> = {
high: "bg-red-100 text-red-800",
medium: "bg-yellow-100 text-yellow-800",
low: "bg-green-100 text-green-800",
};
export default function PlatformRulesPage() {
const [platforms, setPlatforms] = useState<PlatformBrief[]>([]);
const [selectedPlatform, setSelectedPlatform] = useState<string | null>(null);
const [platformDetail, setPlatformDetail] = useState<PlatformDetailResponse | null>(null);
const [loading, setLoading] = useState(true);
const [detailLoading, setDetailLoading] = useState(false);
useEffect(() => {
loadPlatforms();
}, []);
useEffect(() => {
if (selectedPlatform) {
loadPlatformDetail(selectedPlatform);
}
}, [selectedPlatform]);
const loadPlatforms = async () => {
try {
setLoading(true);
const response = await platformRulesApi.listPlatforms();
setPlatforms(response.platforms);
if (response.platforms.length > 0 && !selectedPlatform) {
setSelectedPlatform(response.platforms[0].id);
}
} catch (error) {
console.error("加载平台列表失败:", error);
} finally {
setLoading(false);
}
};
const loadPlatformDetail = async (platformId: string) => {
try {
setDetailLoading(true);
const detail = await platformRulesApi.getPlatformDetail(platformId);
setPlatformDetail(detail);
} catch (error) {
console.error("加载平台详情失败:", error);
} finally {
setDetailLoading(false);
}
};
if (loading) {
return (
<div className="flex items-center justify-center h-64">
<div className="text-muted-foreground">...</div>
</div>
);
}
return (
<div className="space-y-6">
<div>
<h1 className="text-2xl font-bold tracking-tight"></h1>
<p className="text-muted-foreground"></p>
</div>
<div className="grid grid-cols-1 lg:grid-cols-4 gap-6">
{/* 平台列表 */}
<Card className="lg:col-span-1">
<CardHeader>
<CardTitle className="text-lg"></CardTitle>
<CardDescription> {platforms.length} </CardDescription>
</CardHeader>
<CardContent className="p-0">
<div className="divide-y">
{platforms.map((platform) => (
<button
key={platform.id}
onClick={() => setSelectedPlatform(platform.id)}
className={`w-full px-4 py-3 text-left hover:bg-muted/50 transition-colors ${
selectedPlatform === platform.id ? "bg-muted" : ""
}`}
>
<div className="flex items-center justify-between">
<span className="font-medium">{platform.name}</span>
<Badge className={PRIORITY_COLORS[platform.priority] || "bg-gray-100"}>
{platform.priority}
</Badge>
</div>
<div className="text-sm text-muted-foreground mt-1">
{platform.platform_type}
</div>
</button>
))}
</div>
</CardContent>
</Card>
{/* 平台详情 */}
<Card className="lg:col-span-3">
<CardHeader>
<div className="flex items-center justify-between">
<div>
<CardTitle className="text-xl">
{platformDetail?.name || "选择平台"}
</CardTitle>
<CardDescription>
{platformDetail?.platform_type} - {platformDetail?.id}
</CardDescription>
</div>
{platformDetail && (
<div className="flex gap-2">
<Badge
className={
SENSITIVITY_COLORS[
platformDetail.ai_sensitivity.detection_level
] || "bg-gray-100"
}
>
AI检测: {platformDetail.ai_sensitivity.detection_level}
</Badge>
<Badge variant={platformDetail.enabled ? "default" : "secondary"}>
{platformDetail.enabled ? "已启用" : "已禁用"}
</Badge>
</div>
)}
</div>
</CardHeader>
<CardContent>
{detailLoading ? (
<div className="flex items-center justify-center h-64">
<div className="text-muted-foreground">...</div>
</div>
) : !platformDetail ? (
<div className="flex items-center justify-center h-64">
<div className="text-muted-foreground"></div>
</div>
) : (
<Tabs defaultValue="basic" className="space-y-4">
<TabsList>
<TabsTrigger value="basic"></TabsTrigger>
<TabsTrigger value="ai">AI检测</TabsTrigger>
<TabsTrigger value="sensitive"></TabsTrigger>
<TabsTrigger value="seo">SEO规则</TabsTrigger>
<TabsTrigger value="html">HTML规则</TabsTrigger>
<TabsTrigger value="publish"></TabsTrigger>
</TabsList>
<TabsContent value="basic" className="space-y-4">
<div className="grid grid-cols-2 gap-4">
<div>
<h4 className="font-semibold mb-2"></h4>
<div className="text-sm space-y-1">
<p>: {platformDetail.content_length.min} </p>
<p>: {platformDetail.content_length.max} </p>
<p>: {platformDetail.content_length.recommended} </p>
</div>
</div>
<div>
<h4 className="font-semibold mb-2"></h4>
<div className="text-sm space-y-1">
<p>: {platformDetail.structure_preference.has_intro ? "需要" : "不需要"}</p>
<p>: {platformDetail.structure_preference.has_conclusion ? "需要" : "不需要"}</p>
<p>: {platformDetail.structure_preference.has_toc ? "需要" : "不需要"}</p>
</div>
</div>
</div>
<div>
<h4 className="font-semibold mb-2"></h4>
<div className="text-sm space-y-1">
<p>: {platformDetail.title_rules.min_length} - {platformDetail.title_rules.max_length} </p>
<p>: {platformDetail.title_rules.case_style}</p>
{platformDetail.title_rules.avoid_patterns.length > 0 && (
<p>: {platformDetail.title_rules.avoid_patterns.join(", ")}</p>
)}
</div>
</div>
<div>
<h4 className="font-semibold mb-2"></h4>
<div className="text-sm space-y-1">
<p>: {platformDetail.tag_rules.min_tags} - {platformDetail.tag_rules.max_tags} </p>
<p>: {platformDetail.tag_rules.tag_style}</p>
</div>
</div>
<div>
<h4 className="font-semibold mb-2"></h4>
<div className="flex flex-wrap gap-2">
{platformDetail.best_publish_times.map((time, i) => (
<Badge key={i} variant="outline">{time}</Badge>
))}
</div>
</div>
<div>
<h4 className="font-semibold mb-2"></h4>
<div className="flex flex-wrap gap-2">
{platformDetail.best_publish_days.map((day, i) => (
<Badge key={i} variant="outline">{day}</Badge>
))}
</div>
</div>
</TabsContent>
<TabsContent value="ai" className="space-y-4">
<div>
<h4 className="font-semibold mb-2">AI检测级别</h4>
<Badge className={SENSITIVITY_COLORS[platformDetail.ai_sensitivity.detection_level]}>
{platformDetail.ai_sensitivity.detection_level.toUpperCase()}
</Badge>
<p className="text-sm text-muted-foreground mt-2">
{platformDetail.ai_sensitivity.humanization_required
? "需要去AI化处理"
: "无需去AI化处理"}
</p>
</div>
<div>
<h4 className="font-semibold mb-2"></h4>
{platformDetail.ai_sensitivity.banned_patterns.length > 0 ? (
<div className="flex flex-wrap gap-1">
{platformDetail.ai_sensitivity.banned_patterns.map((pattern, i) => (
<Badge key={i} variant="destructive" className="text-xs">
{pattern}
</Badge>
))}
</div>
) : (
<p className="text-sm text-muted-foreground"></p>
)}
</div>
<div>
<h4 className="font-semibold mb-2"></h4>
{platformDetail.ai_sensitivity.safe_patterns.length > 0 ? (
<div className="flex flex-wrap gap-1">
{platformDetail.ai_sensitivity.safe_patterns.map((pattern, i) => (
<Badge key={i} variant="default" className="text-xs bg-green-600">
{pattern}
</Badge>
))}
</div>
) : (
<p className="text-sm text-muted-foreground"></p>
)}
</div>
</TabsContent>
<TabsContent value="sensitive" className="space-y-4">
<div>
<h4 className="font-semibold mb-2"></h4>
<div className="text-sm space-y-2">
<p>: {platformDetail.sensitive_words.check_required ? "是" : "否"}</p>
<p>: {platformDetail.sensitive_words.auto_filter ? "是" : "否"}</p>
<p>: {platformDetail.sensitive_words.max_tolerance}</p>
</div>
</div>
<div>
<h4 className="font-semibold mb-2"></h4>
<div className="flex flex-wrap gap-2">
{platformDetail.sensitive_words.categories.map((cat, i) => (
<Badge key={i} variant="outline">{cat}</Badge>
))}
</div>
</div>
</TabsContent>
<TabsContent value="seo" className="space-y-4">
<div>
<h4 className="font-semibold mb-2"></h4>
<div className="text-sm space-y-1">
<p>: {platformDetail.seo_rules.keyword_density.min}% - {platformDetail.seo_rules.keyword_density.max}%</p>
<p>: {platformDetail.seo_rules.keyword_density.recommended}%</p>
</div>
</div>
<div>
<h4 className="font-semibold mb-2"></h4>
<div className="flex flex-wrap gap-2">
{platformDetail.seo_rules.keyword_position.map((pos, i) => (
<Badge key={i} variant="outline">{pos}</Badge>
))}
</div>
</div>
<div>
<h4 className="font-semibold mb-2"></h4>
<div className="text-sm space-y-1">
<p>
: {platformDetail.seo_rules.internal_links.min || 0} - {platformDetail.seo_rules.internal_links.max || 0}
</p>
</div>
</div>
</TabsContent>
<TabsContent value="html" className="space-y-4">
<div>
<h4 className="font-semibold mb-2">HTML标签</h4>
<div className="flex flex-wrap gap-1">
{platformDetail.html_rules.supported_tags.map((tag, i) => (
<Badge key={i} variant="default" className="text-xs">
&lt;{tag}&gt;
</Badge>
))}
</div>
</div>
<div>
<h4 className="font-semibold mb-2">HTML标签</h4>
<div className="flex flex-wrap gap-1">
{platformDetail.html_rules.banned_tags.map((tag, i) => (
<Badge key={i} variant="destructive" className="text-xs">
&lt;{tag}&gt;
</Badge>
))}
</div>
</div>
<div>
<h4 className="font-semibold mb-2"></h4>
<div className="text-sm space-y-1">
<p>: {platformDetail.html_rules.image_support ? "支持" : "不支持"}</p>
<p>: {platformDetail.html_rules.video_support ? "支持" : "不支持"}</p>
<p>: {platformDetail.html_rules.code_block_support ? "支持" : "不支持"}</p>
</div>
</div>
</TabsContent>
<TabsContent value="publish" className="space-y-4">
<div>
<h4 className="font-semibold mb-2"></h4>
<div className="text-sm space-y-2">
<p>: {platformDetail.publish_rules.auto_publish ? "是" : "否"}</p>
<p>: {platformDetail.publish_rules.require_review ? "是" : "否"}</p>
<p>: {platformDetail.publish_rules.publish_timing}</p>
</div>
</div>
<div>
<h4 className="font-semibold mb-2"></h4>
<p className="text-sm">{platformDetail.content_style}</p>
</div>
</TabsContent>
</Tabs>
)}
</CardContent>
</Card>
</div>
</div>
);
}