生产管理系统 - 删除api-example

This commit is contained in:
2025-11-05 09:11:29 +08:00
parent d751fc10a7
commit c10b507cf6
3 changed files with 1 additions and 2133 deletions

View File

@@ -1,420 +0,0 @@
'use client';
import { useState } from 'react';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { Copy, Eye, EyeOff, Code, FileJson } from 'lucide-react';
interface OpenApiExample {
path: string;
method: string;
summary?: string;
description?: string;
parameters?: any[];
requestBody?: any;
responses?: any;
examples?: any;
}
interface OpenApiExamplesProps {
className?: string;
}
// 示例数据 - 这些通常从 OpenAPI 规范中提取
const openApiExamples: OpenApiExample[] = [
{
path: '/api/v1/auth/login',
method: 'POST',
summary: '用户登录',
description: '用户登录(需要验证码)',
requestBody: {
'application/json': {
example: {
identifier: 'admin',
password: 'admin123',
captcha_id: 'test-captcha-id',
captcha_text: '1234'
}
}
},
responses: {
200: {
description: 'Successful Response',
content: {
'application/json': {
example: {
access_token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
token_type: 'bearer',
expires_in: 3600
}
}
}
}
}
},
{
path: '/api/v1/auth/register',
method: 'POST',
summary: '用户注册',
description: '用户注册',
requestBody: {
'application/json': {
example: {
username: 'newuser',
password: 'password123',
email: 'user@example.com',
full_name: '新用户',
phone: '13800138000',
tenant_id: 'tenant-uuid',
scope: 'user',
department_id: 'dept-uuid'
}
}
},
responses: {
200: {
description: 'Successful Response',
content: {
'application/json': {
example: {
id: 'uuid-12345',
username: 'newuser',
email: 'user@example.com',
phone: '13800138000',
is_active: true,
created_at: '2024-01-01T00:00:00Z'
}
}
}
}
}
},
{
path: '/api/v1/users',
method: 'POST',
summary: '创建用户',
description: '创建用户(需要管理员权限)',
requestBody: {
'application/json': {
example: {
username: 'testuser',
password: 'password123',
email: 'test@example.com',
full_name: '测试用户',
phone: '13900139000',
tenant_id: 'tenant-uuid',
scope: 'user',
department_id: 'dept-uuid'
}
}
},
responses: {
200: {
description: 'Successful Response',
content: {
'application/json': {
example: {
id: 'uuid-67890',
username: 'testuser',
email: 'test@example.com',
phone: '13900139000',
is_active: true,
created_at: '2024-01-01T00:00:00Z'
}
}
}
}
}
},
{
path: '/api/v1/tenants',
method: 'POST',
summary: '创建租户',
description: '创建新租户',
requestBody: {
'application/json': {
example: {
company_name: '新企业有限责任公司',
tenant_code: 'NEW001',
company_type: '有限责任公司'
}
}
},
responses: {
201: {
description: 'Successful Response',
content: {
'application/json': {
example: {
id: 'tenant-uuid',
company_name: '新企业有限责任公司',
tenant_code: 'NEW001',
company_type: '有限责任公司',
audit_status: 'pending',
created_at: '2024-01-01T00:00:00Z'
}
}
}
}
}
}
];
export default function OpenApiExamples({ className }: OpenApiExamplesProps) {
const [copiedCode, setCopiedCode] = useState<string | null>(null);
const [visibleExamples, setVisibleExamples] = useState<Set<string>>(new Set());
const copyToClipboard = async (text: string, id: string) => {
try {
await navigator.clipboard.writeText(text);
setCopiedCode(id);
setTimeout(() => setCopiedCode(null), 2000);
} catch (err) {
console.error('Failed to copy:', err);
}
};
const toggleExampleVisibility = (id: string) => {
setVisibleExamples(prev => {
const newSet = new Set(prev);
if (newSet.has(id)) {
newSet.delete(id);
} else {
newSet.add(id);
}
return newSet;
});
};
const getMethodColor = (method: string) => {
switch (method.toUpperCase()) {
case 'GET': return 'bg-green-100 text-green-800 border-green-200';
case 'POST': return 'bg-blue-100 text-blue-800 border-blue-200';
case 'PUT': return 'bg-yellow-100 text-yellow-800 border-yellow-200';
case 'DELETE': return 'bg-red-100 text-red-800 border-red-200';
default: return 'bg-gray-100 text-gray-800 border-gray-200';
}
};
const formatJson = (obj: any) => {
return JSON.stringify(obj, null, 2);
};
return (
<Card className={className}>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<FileJson className="h-5 w-5" />
OpenAPI
</CardTitle>
<CardDescription>
OpenAPI
</CardDescription>
</CardHeader>
<CardContent>
<Tabs defaultValue="all" className="w-full">
<TabsList className="grid w-full grid-cols-4">
<TabsTrigger value="all"></TabsTrigger>
<TabsTrigger value="auth"></TabsTrigger>
<TabsTrigger value="users"></TabsTrigger>
<TabsTrigger value="tenants"></TabsTrigger>
</TabsList>
<TabsContent value="all" className="space-y-4">
{openApiExamples.map((example) => (
<OpenApiExampleCard
key={`${example.method}-${example.path}`}
example={example}
getMethodColor={getMethodColor}
formatJson={formatJson}
copyToClipboard={copyToClipboard}
copiedCode={copiedCode}
visibleExamples={visibleExamples}
toggleExampleVisibility={toggleExampleVisibility}
/>
))}
</TabsContent>
<TabsContent value="auth" className="space-y-4">
{openApiExamples
.filter(e => e.path.includes('/auth/'))
.map((example) => (
<OpenApiExampleCard
key={`${example.method}-${example.path}`}
example={example}
getMethodColor={getMethodColor}
formatJson={formatJson}
copyToClipboard={copyToClipboard}
copiedCode={copiedCode}
visibleExamples={visibleExamples}
toggleExampleVisibility={toggleExampleVisibility}
/>
))}
</TabsContent>
<TabsContent value="users" className="space-y-4">
{openApiExamples
.filter(e => e.path.includes('/users'))
.map((example) => (
<OpenApiExampleCard
key={`${example.method}-${example.path}`}
example={example}
getMethodColor={getMethodColor}
formatJson={formatJson}
copyToClipboard={copyToClipboard}
copiedCode={copiedCode}
visibleExamples={visibleExamples}
toggleExampleVisibility={toggleExampleVisibility}
/>
))}
</TabsContent>
<TabsContent value="tenants" className="space-y-4">
{openApiExamples
.filter(e => e.path.includes('/tenants'))
.map((example) => (
<OpenApiExampleCard
key={`${example.method}-${example.path}`}
example={example}
getMethodColor={getMethodColor}
formatJson={formatJson}
copyToClipboard={copyToClipboard}
copiedCode={copiedCode}
visibleExamples={visibleExamples}
toggleExampleVisibility={toggleExampleVisibility}
/>
))}
</TabsContent>
</Tabs>
</CardContent>
</Card>
);
}
interface OpenApiExampleCardProps {
example: OpenApiExample;
getMethodColor: (method: string) => string;
formatJson: (obj: any) => string;
copyToClipboard: (text: string, id: string) => void;
copiedCode: string | null;
visibleExamples: Set<string>;
toggleExampleVisibility: (id: string) => void;
}
function OpenApiExampleCard({
example,
getMethodColor,
formatJson,
copyToClipboard,
copiedCode,
visibleExamples,
toggleExampleVisibility
}: OpenApiExampleCardProps) {
const exampleId = `${example.method}-${example.path}`;
const isVisible = visibleExamples.has(exampleId);
return (
<div className="border rounded-lg p-4 space-y-3">
<div className="flex items-start justify-between">
<div className="flex items-center gap-3">
<Badge className={getMethodColor(example.method)}>
{example.method}
</Badge>
<div>
<h3 className="font-semibold text-lg">{example.summary}</h3>
<p className="text-sm text-muted-foreground font-mono">
{example.path}
</p>
</div>
</div>
<Button
variant="ghost"
size="sm"
onClick={() => toggleExampleVisibility(exampleId)}
>
{isVisible ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
</Button>
</div>
{example.description && (
<p className="text-sm text-muted-foreground">{example.description}</p>
)}
{isVisible && (
<div className="space-y-4">
{/* Request Body Examples */}
{example.requestBody && (
<div className="space-y-2">
<h4 className="font-medium text-sm flex items-center gap-2">
<Code className="h-4 w-4" />
</h4>
{Object.entries(example.requestBody).map(([contentType, content]: [string, any]) => (
<div key={contentType} className="space-y-2">
<div className="flex items-center justify-between">
<Badge variant="outline">{contentType}</Badge>
<Button
variant="ghost"
size="sm"
onClick={() => copyToClipboard(formatJson(content.example), `request-${exampleId}`)}
>
{copiedCode === `request-${exampleId}` ? '已复制!' : <Copy className="h-4 w-4" />}
</Button>
</div>
<pre className="bg-muted p-3 rounded-md overflow-x-auto text-xs">
<code>{formatJson(content.example)}</code>
</pre>
</div>
))}
</div>
)}
{/* Response Examples */}
{example.responses && (
<div className="space-y-2">
<h4 className="font-medium text-sm flex items-center gap-2">
<Code className="h-4 w-4" />
</h4>
{Object.entries(example.responses).map(([statusCode, response]: [string, any]) => (
<div key={statusCode} className="space-y-2">
<div className="flex items-center gap-2">
<Badge variant={statusCode.startsWith('2') ? 'default' : 'destructive'}>
{statusCode}
</Badge>
<span className="text-sm text-muted-foreground">
{response.description}
</span>
</div>
{response.content && Object.entries(response.content).map(([contentType, content]: [string, any]) => (
<div key={contentType} className="space-y-2">
<div className="flex items-center justify-between">
<Badge variant="outline">{contentType}</Badge>
{content.example && (
<Button
variant="ghost"
size="sm"
onClick={() => copyToClipboard(formatJson(content.example), `response-${exampleId}-${statusCode}`)}
>
{copiedCode === `response-${exampleId}-${statusCode}` ? '已复制!' : <Copy className="h-4 w-4" />}
</Button>
)}
</div>
{content.example && (
<pre className="bg-muted p-3 rounded-md overflow-x-auto text-xs">
<code>{formatJson(content.example)}</code>
</pre>
)}
</div>
))}
</div>
))}
</div>
)}
</div>
)}
</div>
);
}

File diff suppressed because it is too large Load Diff

View File

@@ -61,13 +61,7 @@ const navbarData = {
url: "/central-config", url: "/central-config",
description: "租户管理、用户管理、系统监控", description: "租户管理、用户管理、系统监控",
icon: <Settings className="size-5 shrink-0" />, icon: <Settings className="size-5 shrink-0" />,
}, }
{
title: "API 测试示例",
url: "/api-example",
description: "测试和展示 OpenAPI 客户端调用",
icon: <Brain className="size-5 shrink-0" />,
},
], ],
auth: { auth: {
login: { title: "登录", url: "/login" }, login: { title: "登录", url: "/login" },