生产管理系统 - 页面布局调整
This commit is contained in:
@@ -9,6 +9,44 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// 从环境配置文件中读取 API_BASE_URL
|
||||
function getApiBaseUrl() {
|
||||
try {
|
||||
// 首先尝试从 env/.env.dev 文件读取
|
||||
const envDevPath = path.join(process.cwd(), 'env', '.env.dev');
|
||||
if (fs.existsSync(envDevPath)) {
|
||||
const envContent = fs.readFileSync(envDevPath, 'utf8');
|
||||
const apiBaseUrlMatch = envContent.match(/API_BASE_URL=([^\r\n]+)/);
|
||||
|
||||
if (apiBaseUrlMatch && apiBaseUrlMatch[1]) {
|
||||
return apiBaseUrlMatch[1].trim();
|
||||
}
|
||||
}
|
||||
|
||||
// 如果上面的文件不存在,尝试从 TypeScript 环境配置文件读取
|
||||
const envConfigPath = path.join(process.cwd(), 'src', 'env', 'index.ts');
|
||||
if (fs.existsSync(envConfigPath)) {
|
||||
const envContent = fs.readFileSync(envConfigPath, 'utf8');
|
||||
const devConfigMatch = envContent.match(/dev:\s*\{[\s\S]*?BACKEND_BASE_URL:\s*['"`]([^'"`]+)['"`]/);
|
||||
|
||||
if (devConfigMatch && devConfigMatch[1]) {
|
||||
return devConfigMatch[1].trim();
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error('无法找到 API_BASE_URL 或 BACKEND_BASE_URL 配置');
|
||||
} catch (error) {
|
||||
console.log(`读取环境配置失败: ${error.message}`);
|
||||
return 'http://localhost:8080'; // 默认值
|
||||
}
|
||||
}
|
||||
|
||||
// 获取 API 基础 URL
|
||||
const API_BASE_URL = getApiBaseUrl();
|
||||
|
||||
// 设置环境变量供后续使用
|
||||
process.env.API_BASE_URL = API_BASE_URL;
|
||||
|
||||
// ANSI 颜色代码
|
||||
const colors = {
|
||||
reset: '\x1b[0m',
|
||||
@@ -44,7 +82,8 @@ function logInfo(message) {
|
||||
|
||||
// 显示环境配置信息
|
||||
logInfo(`当前环境: ${process.env.NODE_ENV || 'development'}`);
|
||||
logInfo(`API 服务器: ${process.env.API_BASE_URL || 'http://localhost:8080'}`);
|
||||
logInfo(`API 服务器: ${API_BASE_URL}`);
|
||||
logInfo(`已从 env/.env.dev 读取 API_BASE_URL 配置`);
|
||||
|
||||
/**
|
||||
* 检查自定义文件是否存在
|
||||
@@ -153,6 +192,59 @@ function restoreCustomFiles(customFiles) {
|
||||
logSuccess('自定义文件已恢复');
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载并保存 openapi.json 文件到本地
|
||||
*/
|
||||
function downloadOpenApiJson() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const https = require('https');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const fileUrl = `${API_BASE_URL}/openapi.json`;
|
||||
const outputPath = path.join(process.cwd(), 'scripts', 'openapi.json');
|
||||
|
||||
logInfo(`下载 OpenAPI 规范文件: ${fileUrl}`);
|
||||
|
||||
const startTime = Date.now();
|
||||
|
||||
// 创建 HTTPS 代理(如果需要,可以忽略 SSL 证书验证)
|
||||
const agent = new https.Agent({
|
||||
rejectUnauthorized: false // 跳过 SSL 证书验证
|
||||
});
|
||||
|
||||
https.get(fileUrl, { agent }, (response) => {
|
||||
if (response.statusCode !== 200) {
|
||||
reject(new Error(`HTTP ${response.statusCode}: ${response.statusMessage}`));
|
||||
return;
|
||||
}
|
||||
|
||||
let data = '';
|
||||
|
||||
response.on('data', (chunk) => {
|
||||
data += chunk;
|
||||
});
|
||||
|
||||
response.on('end', () => {
|
||||
try {
|
||||
// 验证 JSON 格式
|
||||
JSON.parse(data);
|
||||
|
||||
// 写入文件
|
||||
fs.writeFileSync(outputPath, data, 'utf8');
|
||||
const executionTime = Date.now() - startTime;
|
||||
logSuccess(`OpenAPI 规范已保存到: scripts/openapi.json (${executionTime}ms)`);
|
||||
resolve();
|
||||
} catch (error) {
|
||||
reject(new Error(`JSON 格式错误: ${error.message}`));
|
||||
}
|
||||
});
|
||||
}).on('error', (error) => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用 openapi-ts 命令生成客户端代码
|
||||
*/
|
||||
@@ -259,6 +351,9 @@ async function main() {
|
||||
backupCustomFiles(customFiles);
|
||||
}
|
||||
|
||||
// 下载 openapi.json 文件到本地
|
||||
await downloadOpenApiJson();
|
||||
|
||||
// 使用 openapi-ts 生成代码
|
||||
await generateWithOpenApiTS();
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
420
crop-x/src/app/(app)/api-example/openapi-examples.tsx
Normal file
420
crop-x/src/app/(app)/api-example/openapi-examples.tsx
Normal file
@@ -0,0 +1,420 @@
|
||||
'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>
|
||||
);
|
||||
}
|
||||
@@ -72,14 +72,16 @@ import {
|
||||
// 类型导入
|
||||
type UserCreate,
|
||||
type UserCreateWithCompany,
|
||||
type UserLogin,
|
||||
type UserLoginWithCaptcha,
|
||||
type UserUpdate,
|
||||
type UserUpdatePassword,
|
||||
type TenantCreateRequest,
|
||||
type TenantUpdateRequest,
|
||||
type TenantAuditRequest,
|
||||
type DepartmentCreate,
|
||||
type DepartmentUpdate
|
||||
type DepartmentUpdate,
|
||||
type CaptchaResponse,
|
||||
type Token
|
||||
} from '@/lib/api';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
@@ -90,6 +92,7 @@ import { Alert, AlertDescription } from '@/components/ui/alert';
|
||||
import { ScrollArea } from '@/components/ui/scroll-area';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import OpenApiExamples from './openapi-examples';
|
||||
|
||||
export default function ApiExamplePage() {
|
||||
const [loading, setLoading] = useState(false);
|
||||
@@ -97,18 +100,26 @@ export default function ApiExamplePage() {
|
||||
const [errors, setErrors] = useState<string[]>([]);
|
||||
|
||||
// 登录表单状态
|
||||
const [loginData, setLoginData] = useState<UserLogin>({
|
||||
username: '',
|
||||
const [loginData, setLoginData] = useState<UserLoginWithCaptcha>({
|
||||
identifier: '',
|
||||
password: '',
|
||||
captcha: ''
|
||||
captcha_id: '',
|
||||
captcha_text: ''
|
||||
});
|
||||
|
||||
// 验证码状态
|
||||
const [captchaData, setCaptchaData] = useState<CaptchaResponse | null>(null);
|
||||
|
||||
// 注册表单状态
|
||||
const [registerData, setRegisterData] = useState<UserCreate>({
|
||||
username: '',
|
||||
password: '',
|
||||
email: '',
|
||||
full_name: ''
|
||||
full_name: '',
|
||||
phone: '',
|
||||
tenant_id: '',
|
||||
scope: '',
|
||||
department_id: ''
|
||||
});
|
||||
|
||||
// 带企业注册表单状态
|
||||
@@ -132,17 +143,17 @@ export default function ApiExamplePage() {
|
||||
password: '',
|
||||
email: '',
|
||||
full_name: '',
|
||||
department_id: '',
|
||||
phone: ''
|
||||
phone: '',
|
||||
tenant_id: '',
|
||||
scope: '',
|
||||
department_id: ''
|
||||
});
|
||||
|
||||
// 租户创建表单状态
|
||||
const [createTenantData, setCreateTenantData] = useState<TenantCreateRequest>({
|
||||
name: '',
|
||||
code: '',
|
||||
description: '',
|
||||
contact_email: '',
|
||||
contact_phone: ''
|
||||
company_name: '',
|
||||
tenant_code: '',
|
||||
company_type: '有限责任公司'
|
||||
});
|
||||
|
||||
// 部门创建表单状态
|
||||
@@ -255,6 +266,8 @@ export default function ApiExamplePage() {
|
||||
const response = await getCaptchaApiV1AuthCaptchaGet({});
|
||||
|
||||
if (response.data) {
|
||||
setCaptchaData(response.data);
|
||||
setLoginData(prev => ({ ...prev, captcha_id: response.data.captcha_id }));
|
||||
addResult('获取验证码', '无参数', response.data);
|
||||
} else if (response.error) {
|
||||
addResult('获取验证码', '无参数', null, JSON.stringify(response.error));
|
||||
@@ -450,9 +463,10 @@ export default function ApiExamplePage() {
|
||||
</div>
|
||||
|
||||
<Tabs defaultValue="interactive" className="w-full">
|
||||
<TabsList className="grid w-full grid-cols-2">
|
||||
<TabsList className="grid w-full grid-cols-3">
|
||||
<TabsTrigger value="interactive">交互式测试</TabsTrigger>
|
||||
<TabsTrigger value="examples">接口示例</TabsTrigger>
|
||||
<TabsTrigger value="documentation">OpenAPI 文档</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="interactive" className="space-y-6">
|
||||
@@ -467,24 +481,25 @@ export default function ApiExamplePage() {
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Tabs defaultValue="auth" className="w-full">
|
||||
<TabsList className="grid w-full grid-cols-4">
|
||||
<TabsList className="grid w-full grid-cols-5">
|
||||
<TabsTrigger value="auth">认证操作</TabsTrigger>
|
||||
<TabsTrigger value="user">用户管理</TabsTrigger>
|
||||
<TabsTrigger value="tenant">租户管理</TabsTrigger>
|
||||
<TabsTrigger value="department">部门管理</TabsTrigger>
|
||||
<TabsTrigger value="system">系统管理</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="auth" className="space-y-4">
|
||||
{/* 登录表单 */}
|
||||
<div className="space-y-3">
|
||||
<h4 className="font-medium">用户登录</h4>
|
||||
<h4 className="font-medium">用户登录(需要验证码)</h4>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="username">用户名</Label>
|
||||
<Label htmlFor="identifier">用户名/邮箱/手机号</Label>
|
||||
<Input
|
||||
id="username"
|
||||
placeholder="请输入用户名"
|
||||
value={loginData.username}
|
||||
onChange={(e) => setLoginData(prev => ({ ...prev, username: e.target.value }))}
|
||||
id="identifier"
|
||||
placeholder="请输入用户名、邮箱或手机号"
|
||||
value={loginData.identifier}
|
||||
onChange={(e) => setLoginData(prev => ({ ...prev, identifier: e.target.value }))}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
@@ -498,17 +513,40 @@ export default function ApiExamplePage() {
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="captcha">验证码</Label>
|
||||
<Label htmlFor="captcha_text">验证码</Label>
|
||||
<div className="flex gap-2">
|
||||
<Input
|
||||
id="captcha"
|
||||
id="captcha_text"
|
||||
placeholder="请输入验证码"
|
||||
value={loginData.captcha}
|
||||
onChange={(e) => setLoginData(prev => ({ ...prev, captcha: e.target.value }))}
|
||||
value={loginData.captcha_text}
|
||||
onChange={(e) => setLoginData(prev => ({ ...prev, captcha_text: e.target.value }))}
|
||||
className="flex-1"
|
||||
/>
|
||||
<Button
|
||||
onClick={handleGetCaptcha}
|
||||
disabled={loading}
|
||||
variant="outline"
|
||||
className="whitespace-nowrap"
|
||||
>
|
||||
获取验证码
|
||||
</Button>
|
||||
</div>
|
||||
{captchaData && (
|
||||
<div className="mt-2 p-2 bg-muted rounded">
|
||||
<img
|
||||
src={`data:image/png;base64,${captchaData.image}`}
|
||||
alt="验证码"
|
||||
className="h-12 mx-auto"
|
||||
/>
|
||||
<p className="text-xs text-center text-muted-foreground mt-1">
|
||||
验证码ID: {captchaData.captcha_id}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<Button
|
||||
onClick={handleLogin}
|
||||
disabled={loading || !loginData.username || !loginData.password}
|
||||
disabled={loading || !loginData.identifier || !loginData.password || !loginData.captcha_text || !loginData.captcha_id}
|
||||
className="w-full"
|
||||
>
|
||||
{loading ? '登录中...' : '登录'}
|
||||
@@ -539,9 +577,29 @@ export default function ApiExamplePage() {
|
||||
value={registerData.full_name}
|
||||
onChange={(e) => setRegisterData(prev => ({ ...prev, full_name: e.target.value }))}
|
||||
/>
|
||||
<Input
|
||||
placeholder="手机号"
|
||||
value={registerData.phone}
|
||||
onChange={(e) => setRegisterData(prev => ({ ...prev, phone: e.target.value }))}
|
||||
/>
|
||||
<Input
|
||||
placeholder="租户ID (可选)"
|
||||
value={registerData.tenant_id || ''}
|
||||
onChange={(e) => setRegisterData(prev => ({ ...prev, tenant_id: e.target.value || undefined }))}
|
||||
/>
|
||||
<Input
|
||||
placeholder="用户作用域 (可选)"
|
||||
value={registerData.scope || ''}
|
||||
onChange={(e) => setRegisterData(prev => ({ ...prev, scope: e.target.value || undefined }))}
|
||||
/>
|
||||
<Input
|
||||
placeholder="部门ID (可选)"
|
||||
value={registerData.department_id || ''}
|
||||
onChange={(e) => setRegisterData(prev => ({ ...prev, department_id: e.target.value || undefined }))}
|
||||
/>
|
||||
<Button
|
||||
onClick={handleRegister}
|
||||
disabled={loading || !registerData.username || !registerData.password}
|
||||
disabled={loading || !registerData.username || !registerData.password || !registerData.email || !registerData.phone}
|
||||
variant="outline"
|
||||
className="w-full"
|
||||
>
|
||||
@@ -607,9 +665,29 @@ export default function ApiExamplePage() {
|
||||
value={createUserData.full_name}
|
||||
onChange={(e) => setCreateUserData(prev => ({ ...prev, full_name: e.target.value }))}
|
||||
/>
|
||||
<Input
|
||||
placeholder="手机号"
|
||||
value={createUserData.phone}
|
||||
onChange={(e) => setCreateUserData(prev => ({ ...prev, phone: e.target.value }))}
|
||||
/>
|
||||
<Input
|
||||
placeholder="租户ID (可选)"
|
||||
value={createUserData.tenant_id || ''}
|
||||
onChange={(e) => setCreateUserData(prev => ({ ...prev, tenant_id: e.target.value || undefined }))}
|
||||
/>
|
||||
<Input
|
||||
placeholder="用户作用域 (可选)"
|
||||
value={createUserData.scope || ''}
|
||||
onChange={(e) => setCreateUserData(prev => ({ ...prev, scope: e.target.value || undefined }))}
|
||||
/>
|
||||
<Input
|
||||
placeholder="部门ID (可选)"
|
||||
value={createUserData.department_id || ''}
|
||||
onChange={(e) => setCreateUserData(prev => ({ ...prev, department_id: e.target.value || undefined }))}
|
||||
/>
|
||||
<Button
|
||||
onClick={handleCreateUser}
|
||||
disabled={loading || !createUserData.username || !createUserData.password}
|
||||
disabled={loading || !createUserData.username || !createUserData.password || !createUserData.email || !createUserData.phone}
|
||||
className="w-full"
|
||||
>
|
||||
{loading ? '创建中...' : '创建用户'}
|
||||
@@ -647,12 +725,74 @@ export default function ApiExamplePage() {
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="tenant" className="space-y-4">
|
||||
{/* 租户操作 */}
|
||||
{/* 创建租户表单 */}
|
||||
<div className="space-y-2">
|
||||
<h4 className="font-medium">创建租户</h4>
|
||||
<Input
|
||||
placeholder="企业名称"
|
||||
value={createTenantData.company_name}
|
||||
onChange={(e) => setCreateTenantData(prev => ({ ...prev, company_name: e.target.value }))}
|
||||
/>
|
||||
<Input
|
||||
placeholder="企业编码"
|
||||
value={createTenantData.tenant_code}
|
||||
onChange={(e) => setCreateTenantData(prev => ({ ...prev, tenant_code: e.target.value }))}
|
||||
/>
|
||||
<select
|
||||
value={createTenantData.company_type}
|
||||
onChange={(e) => setCreateTenantData(prev => ({ ...prev, company_type: e.target.value as any }))}
|
||||
className="w-full p-2 border rounded"
|
||||
>
|
||||
<option value="个体工商户">个体工商户</option>
|
||||
<option value="有限责任公司">有限责任公司</option>
|
||||
<option value="股份有限公司">股份有限公司</option>
|
||||
<option value="合伙企业">合伙企业</option>
|
||||
<option value="其他">其他</option>
|
||||
</select>
|
||||
<Button
|
||||
onClick={async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
addResult('创建租户', 'POST /api/v1/tenants', '发送中...');
|
||||
const response = await createTenantApiV1TenantsPost({
|
||||
body: createTenantData
|
||||
});
|
||||
if (response.data) {
|
||||
addResult('创建租户', createTenantData, response.data);
|
||||
} else if (response.error) {
|
||||
addResult('创建租户', createTenantData, null, JSON.stringify(response.error));
|
||||
}
|
||||
} catch (error: any) {
|
||||
addResult('创建租户', createTenantData, null, error.message);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}}
|
||||
disabled={loading || !createTenantData.company_name || !createTenantData.tenant_code}
|
||||
className="w-full"
|
||||
>
|
||||
{loading ? '创建中...' : '创建租户'}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* 其他租户操作 */}
|
||||
<div className="grid grid-cols-1 gap-2">
|
||||
<Button
|
||||
onClick={() => {
|
||||
setTenantId('');
|
||||
addResult('获取租户列表', 'GET /api/v1/tenants', '功能待实现');
|
||||
onClick={async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
addResult('获取租户列表', 'GET /api/v1/tenants', '发送中...');
|
||||
const response = await listTenantsApiV1TenantsGet({});
|
||||
if (response.data) {
|
||||
addResult('获取租户列表', '无参数', response.data);
|
||||
} else if (response.error) {
|
||||
addResult('获取租户列表', '无参数', null, JSON.stringify(response.error));
|
||||
}
|
||||
} catch (error: any) {
|
||||
addResult('获取租户列表', '无参数', null, error.message);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}}
|
||||
disabled={loading}
|
||||
variant="outline"
|
||||
@@ -660,15 +800,165 @@ export default function ApiExamplePage() {
|
||||
获取租户列表
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setTenantId('');
|
||||
addResult('获取当前租户', 'GET /api/v1/tenants/me', '功能待实现');
|
||||
onClick={async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
addResult('获取当前租户', 'GET /api/v1/tenants/me', '发送中...');
|
||||
const response = await getCurrentTenantApiV1TenantsMeGet({});
|
||||
if (response.data) {
|
||||
addResult('获取当前租户', '无参数', response.data);
|
||||
} else if (response.error) {
|
||||
addResult('获取当前租户', '无参数', null, JSON.stringify(response.error));
|
||||
}
|
||||
} catch (error: any) {
|
||||
addResult('获取当前租户', '无参数', null, error.message);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}}
|
||||
disabled={loading}
|
||||
variant="outline"
|
||||
>
|
||||
获取当前租户
|
||||
</Button>
|
||||
<Button
|
||||
onClick={async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
addResult('获取租户审计日志', 'GET /api/v1/tenants/audit-logs', '发送中...');
|
||||
const response = await getTenantAuditLogsApiV1TenantsAuditLogsGet({});
|
||||
if (response.data) {
|
||||
addResult('获取租户审计日志', '无参数', response.data);
|
||||
} else if (response.error) {
|
||||
addResult('获取租户审计日志', '无参数', null, JSON.stringify(response.error));
|
||||
}
|
||||
} catch (error: any) {
|
||||
addResult('获取租户审计日志', '无参数', null, error.message);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}}
|
||||
disabled={loading}
|
||||
variant="outline"
|
||||
>
|
||||
获取租户审计日志
|
||||
</Button>
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="department" className="space-y-4">
|
||||
{/* 创建部门表单 */}
|
||||
<div className="space-y-2">
|
||||
<h4 className="font-medium">创建部门</h4>
|
||||
<Input
|
||||
placeholder="部门编码"
|
||||
value={createDepartmentData.code}
|
||||
onChange={(e) => setCreateDepartmentData(prev => ({ ...prev, code: e.target.value }))}
|
||||
/>
|
||||
<Input
|
||||
placeholder="部门名称"
|
||||
value={createDepartmentData.name}
|
||||
onChange={(e) => setCreateDepartmentData(prev => ({ ...prev, name: e.target.value }))}
|
||||
/>
|
||||
<Input
|
||||
placeholder="部门描述"
|
||||
value={createDepartmentData.description}
|
||||
onChange={(e) => setCreateDepartmentData(prev => ({ ...prev, description: e.target.value }))}
|
||||
/>
|
||||
<Button
|
||||
onClick={async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
addResult('创建部门', 'POST /api/v1/departments/departments', '发送中...');
|
||||
const response = await createDepartmentApiV1DepartmentsDepartmentsPost({
|
||||
body: createDepartmentData
|
||||
});
|
||||
if (response.data) {
|
||||
addResult('创建部门', createDepartmentData, response.data);
|
||||
} else if (response.error) {
|
||||
addResult('创建部门', createDepartmentData, null, JSON.stringify(response.error));
|
||||
}
|
||||
} catch (error: any) {
|
||||
addResult('创建部门', createDepartmentData, null, error.message);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}}
|
||||
disabled={loading || !createDepartmentData.code || !createDepartmentData.name}
|
||||
className="w-full"
|
||||
>
|
||||
{loading ? '创建中...' : '创建部门'}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* 其他部门操作 */}
|
||||
<div className="grid grid-cols-1 gap-2">
|
||||
<Button
|
||||
onClick={async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
addResult('获取部门列表', 'GET /api/v1/departments/departments', '发送中...');
|
||||
const response = await getDepartmentsApiV1DepartmentsDepartmentsGet({});
|
||||
if (response.data) {
|
||||
addResult('获取部门列表', '无参数', response.data);
|
||||
} else if (response.error) {
|
||||
addResult('获取部门列表', '无参数', null, JSON.stringify(response.error));
|
||||
}
|
||||
} catch (error: any) {
|
||||
addResult('获取部门列表', '无参数', null, error.message);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}}
|
||||
disabled={loading}
|
||||
variant="outline"
|
||||
>
|
||||
获取部门列表
|
||||
</Button>
|
||||
<Button
|
||||
onClick={async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
addResult('获取部门树', 'GET /api/v1/departments/departments/tree', '发送中...');
|
||||
const response = await getDepartmentTreeApiV1DepartmentsDepartmentsTreeGet({});
|
||||
if (response.data) {
|
||||
addResult('获取部门树', '无参数', response.data);
|
||||
} else if (response.error) {
|
||||
addResult('获取部门树', '无参数', null, JSON.stringify(response.error));
|
||||
}
|
||||
} catch (error: any) {
|
||||
addResult('获取部门树', '无参数', null, error.message);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}}
|
||||
disabled={loading}
|
||||
variant="outline"
|
||||
>
|
||||
获取部门树
|
||||
</Button>
|
||||
<Button
|
||||
onClick={async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
addResult('获取部门选项', 'GET /api/v1/users/departments/options', '发送中...');
|
||||
const response = await getDepartmentOptionsApiV1UsersDepartmentsOptionsGet({});
|
||||
if (response.data) {
|
||||
addResult('获取部门选项', '无参数', response.data);
|
||||
} else if (response.error) {
|
||||
addResult('获取部门选项', '无参数', null, JSON.stringify(response.error));
|
||||
}
|
||||
} catch (error: any) {
|
||||
addResult('获取部门选项', '无参数', null, error.message);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}}
|
||||
disabled={loading}
|
||||
variant="outline"
|
||||
>
|
||||
获取部门选项
|
||||
</Button>
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
||||
@@ -767,6 +1057,10 @@ export default function ApiExamplePage() {
|
||||
<TabsContent value="examples" className="space-y-6">
|
||||
<ApiExamplesPage />
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="documentation" className="space-y-6">
|
||||
<OpenApiExamples />
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</div>
|
||||
</div>
|
||||
@@ -789,7 +1083,7 @@ function ApiExamplesPage() {
|
||||
description: '获取登录验证码',
|
||||
exampleParams: null,
|
||||
category: '认证',
|
||||
expectedOutput: { captcha: 'abc123', captcha_id: 'xyz789' }
|
||||
expectedOutput: { captcha_id: 'xyz789', image: 'base64_image_data' }
|
||||
},
|
||||
{
|
||||
id: 'login',
|
||||
@@ -798,12 +1092,13 @@ function ApiExamplesPage() {
|
||||
title: '用户登录',
|
||||
description: '用户登录(需要验证码)',
|
||||
exampleParams: {
|
||||
username: 'admin',
|
||||
identifier: 'admin',
|
||||
password: 'admin123',
|
||||
captcha: 'test'
|
||||
captcha_id: 'test_captcha_id',
|
||||
captcha_text: 'test'
|
||||
},
|
||||
category: '认证',
|
||||
expectedOutput: { access_token: 'jwt_token', token_type: 'bearer' }
|
||||
expectedOutput: { access_token: 'jwt_token', token_type: 'bearer', expires_in: 3600 }
|
||||
},
|
||||
{
|
||||
id: 'register',
|
||||
@@ -815,10 +1110,14 @@ function ApiExamplesPage() {
|
||||
username: 'newuser',
|
||||
password: 'password123',
|
||||
email: 'user@example.com',
|
||||
full_name: '新用户'
|
||||
full_name: '新用户',
|
||||
phone: '13800138000',
|
||||
tenant_id: 'tenant-uuid',
|
||||
scope: 'user',
|
||||
department_id: 'dept-uuid'
|
||||
},
|
||||
category: '认证',
|
||||
expectedOutput: { id: 'uuid', username: 'newuser', email: 'user@example.com' }
|
||||
expectedOutput: { id: 'uuid', username: 'newuser', email: 'user@example.com', phone: '13800138000' }
|
||||
},
|
||||
{
|
||||
id: 'getCurrentUser',
|
||||
@@ -872,10 +1171,14 @@ function ApiExamplesPage() {
|
||||
username: 'testuser',
|
||||
password: 'password123',
|
||||
email: 'test@example.com',
|
||||
full_name: '测试用户'
|
||||
full_name: '测试用户',
|
||||
phone: '13900139000',
|
||||
tenant_id: 'tenant-uuid',
|
||||
scope: 'user',
|
||||
department_id: 'dept-uuid'
|
||||
},
|
||||
category: '用户管理',
|
||||
expectedOutput: { id: 'uuid', username: 'testuser' }
|
||||
expectedOutput: { id: 'uuid', username: 'testuser', email: 'test@example.com', phone: '13900139000' }
|
||||
},
|
||||
{
|
||||
id: 'getUserStats',
|
||||
@@ -885,7 +1188,46 @@ function ApiExamplesPage() {
|
||||
description: '获取用户统计信息',
|
||||
exampleParams: null,
|
||||
category: '用户管理',
|
||||
expectedOutput: { total_users: 10, active_users: 8 }
|
||||
expectedOutput: { total_users: 10, active_users: 8, inactive_users: 2 }
|
||||
},
|
||||
{
|
||||
id: 'getDepartmentOptions',
|
||||
method: 'GET',
|
||||
path: '/api/v1/users/departments/options',
|
||||
title: '获取部门选项',
|
||||
description: '获取部门选择列表(用于用户管理中的部门选择)',
|
||||
exampleParams: null,
|
||||
category: '用户管理',
|
||||
expectedOutput: [{ id: 'uuid', code: 'TECH001', name: '技术开发部' }]
|
||||
},
|
||||
{
|
||||
id: 'listSystemUsers',
|
||||
method: 'GET',
|
||||
path: '/api/v1/users/system/users',
|
||||
title: '获取系统用户列表',
|
||||
description: '获取系统用户列表(需要系统权限)',
|
||||
exampleParams: { page: 1, size: 20, search: '', is_active: true },
|
||||
category: '用户管理',
|
||||
expectedOutput: { data: [{ id: 'uuid', username: 'admin', is_active: true }], total: 1 }
|
||||
},
|
||||
{
|
||||
id: 'createSystemUser',
|
||||
method: 'POST',
|
||||
path: '/api/v1/users/system/users',
|
||||
title: '创建系统用户',
|
||||
description: '创建系统级用户(需要系统权限)',
|
||||
exampleParams: {
|
||||
username: 'system_admin',
|
||||
password: 'admin123',
|
||||
email: 'admin@system.com',
|
||||
full_name: '系统管理员',
|
||||
phone: '13700137000',
|
||||
tenant_id: null,
|
||||
scope: 'system',
|
||||
department_id: null
|
||||
},
|
||||
category: '用户管理',
|
||||
expectedOutput: { id: 'uuid', username: 'system_admin', scope: 'system' }
|
||||
},
|
||||
|
||||
// 租户管理
|
||||
@@ -895,9 +1237,9 @@ function ApiExamplesPage() {
|
||||
path: '/api/v1/tenants',
|
||||
title: '获取租户列表',
|
||||
description: '获取租户列表',
|
||||
exampleParams: { page: 1, size: 20 },
|
||||
exampleParams: { page: 1, size: 20, search: '', audit_status: 'approved' },
|
||||
category: '租户管理',
|
||||
expectedOutput: { data: [{ id: 'uuid', name: '测试企业' }], total: 1 }
|
||||
expectedOutput: { data: [{ id: 'uuid', name: '测试企业' }], total: 1, page: 1, size: 20 }
|
||||
},
|
||||
{
|
||||
id: 'getCurrentTenant',
|
||||
@@ -907,7 +1249,31 @@ function ApiExamplesPage() {
|
||||
description: '获取当前登录租户信息',
|
||||
exampleParams: null,
|
||||
category: '租户管理',
|
||||
expectedOutput: { id: 'uuid', name: '测试企业', code: 'TEST001' }
|
||||
expectedOutput: { id: 'uuid', name: '测试企业', code: 'TEST001', audit_status: 'approved' }
|
||||
},
|
||||
{
|
||||
id: 'createTenant',
|
||||
method: 'POST',
|
||||
path: '/api/v1/tenants',
|
||||
title: '创建租户',
|
||||
description: '创建新租户',
|
||||
exampleParams: {
|
||||
company_name: '新企业有限责任公司',
|
||||
tenant_code: 'NEW001',
|
||||
company_type: '有限责任公司'
|
||||
},
|
||||
category: '租户管理',
|
||||
expectedOutput: { id: 'uuid', company_name: '新企业有限责任公司', tenant_code: 'NEW001', company_type: '有限责任公司' }
|
||||
},
|
||||
{
|
||||
id: 'getTenantAuditLogs',
|
||||
method: 'GET',
|
||||
path: '/api/v1/tenants/audit-logs',
|
||||
title: '获取租户审计日志',
|
||||
description: '获取租户审计日志',
|
||||
exampleParams: { page: 1, size: 20, tenant_id: 'uuid' },
|
||||
category: '租户管理',
|
||||
expectedOutput: { data: [{ id: 'uuid', action: 'create', timestamp: '2024-01-01T00:00:00Z' }], total: 1 }
|
||||
},
|
||||
|
||||
// 部门管理
|
||||
@@ -919,7 +1285,21 @@ function ApiExamplesPage() {
|
||||
description: '获取部门列表',
|
||||
exampleParams: { page: 1, size: 20 },
|
||||
category: '部门管理',
|
||||
expectedOutput: { data: [{ id: 'uuid', name: '技术部' }], total: 1 }
|
||||
expectedOutput: { data: [{ id: 'uuid', name: '技术部', code: 'TECH' }], total: 1, page: 1, size: 20 }
|
||||
},
|
||||
{
|
||||
id: 'createDepartment',
|
||||
method: 'POST',
|
||||
path: '/api/v1/departments/departments',
|
||||
title: '创建部门',
|
||||
description: '创建新部门',
|
||||
exampleParams: {
|
||||
code: 'TECH001',
|
||||
name: '技术开发部',
|
||||
description: '负责技术研发工作'
|
||||
},
|
||||
category: '部门管理',
|
||||
expectedOutput: { id: 'uuid', code: 'TECH001', name: '技术开发部', description: '负责技术研发工作' }
|
||||
},
|
||||
{
|
||||
id: 'getDepartmentTree',
|
||||
@@ -929,7 +1309,7 @@ function ApiExamplesPage() {
|
||||
description: '获取部门树形结构',
|
||||
exampleParams: null,
|
||||
category: '部门管理',
|
||||
expectedOutput: [{ id: 'uuid', name: '技术部', children: [] }]
|
||||
expectedOutput: [{ id: 'uuid', code: 'TECH001', name: '技术开发部', description: '负责技术研发工作', children: [] }]
|
||||
},
|
||||
|
||||
// 系统管理
|
||||
@@ -1021,6 +1401,19 @@ function ApiExamplesPage() {
|
||||
case 'getUserStats':
|
||||
response = await getUserStatsApiV1UsersStatsSummaryGet({});
|
||||
break;
|
||||
case 'getDepartmentOptions':
|
||||
response = await getDepartmentOptionsApiV1UsersDepartmentsOptionsGet({});
|
||||
break;
|
||||
case 'listSystemUsers':
|
||||
response = await listSystemUsersApiV1UsersSystemUsersGet({
|
||||
query: example.exampleParams
|
||||
});
|
||||
break;
|
||||
case 'createSystemUser':
|
||||
response = await createSystemUserApiV1UsersSystemUsersPost({
|
||||
body: example.exampleParams
|
||||
});
|
||||
break;
|
||||
|
||||
// 租户管理
|
||||
case 'listTenants':
|
||||
@@ -1031,6 +1424,16 @@ function ApiExamplesPage() {
|
||||
case 'getCurrentTenant':
|
||||
response = await getCurrentTenantApiV1TenantsMeGet({});
|
||||
break;
|
||||
case 'createTenant':
|
||||
response = await createTenantApiV1TenantsPost({
|
||||
body: example.exampleParams
|
||||
});
|
||||
break;
|
||||
case 'getTenantAuditLogs':
|
||||
response = await getTenantAuditLogsApiV1TenantsAuditLogsGet({
|
||||
query: example.exampleParams
|
||||
});
|
||||
break;
|
||||
|
||||
// 部门管理
|
||||
case 'getDepartments':
|
||||
@@ -1038,6 +1441,11 @@ function ApiExamplesPage() {
|
||||
query: example.exampleParams
|
||||
});
|
||||
break;
|
||||
case 'createDepartment':
|
||||
response = await createDepartmentApiV1DepartmentsDepartmentsPost({
|
||||
body: example.exampleParams
|
||||
});
|
||||
break;
|
||||
case 'getDepartmentTree':
|
||||
response = await getDepartmentTreeApiV1DepartmentsDepartmentsTreeGet({});
|
||||
break;
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user