161 lines
5.4 KiB
JavaScript
161 lines
5.4 KiB
JavaScript
import { generate } from 'openapi-typescript-codegen';
|
||
import { readFileSync, writeFileSync, existsSync, readdirSync } from 'fs';
|
||
import { join } from 'path';
|
||
import axios from 'axios';
|
||
|
||
// 配置
|
||
const config = {
|
||
// input: process.env.OPENAPI_URL || 'https://bowongai--glam-api-fastapi-app.modal.run/openapi.json', // OpenAPI规范URL
|
||
input: process.env.OPENAPI_URL || 'http://192.168.0.127:8010/openapi.json', // OpenAPI规范URL
|
||
output: './src/api', // 生成的API代码输出目录
|
||
client: 'axios', // 使用axios作为HTTP客户端
|
||
useOptions: true,
|
||
useUnionTypes: true,
|
||
exportSchemas: true,
|
||
exportServices: true,
|
||
exportCore: true,
|
||
exportModels: true,
|
||
exportClient: true,
|
||
};
|
||
|
||
async function fetchOpenApiSpec(url) {
|
||
try {
|
||
console.log(`📡 正在获取OpenAPI规范: ${url}`);
|
||
const response = await axios.get(url);
|
||
return response.data;
|
||
} catch (error) {
|
||
console.error(`❌ 获取OpenAPI规范失败: ${error.message}`);
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
function createIndexFiles() {
|
||
const apiDir = config.output;
|
||
|
||
// 创建services/index.ts
|
||
const servicesDir = join(apiDir, 'services');
|
||
if (existsSync(servicesDir)) {
|
||
const serviceFiles = readdirSync(servicesDir)
|
||
.filter(file => file.endsWith('.ts') && file !== 'index.ts' && file !== 'Service.ts')
|
||
.map(file => file.replace('.ts', ''));
|
||
|
||
const servicesIndexContent = serviceFiles.map(service => `export * from './${service}';`).join('\n');
|
||
|
||
writeFileSync(join(servicesDir, 'index.ts'), servicesIndexContent);
|
||
console.log('📝 创建services/index.ts完成');
|
||
}
|
||
|
||
// 创建models/index.ts
|
||
const modelsDir = join(apiDir, 'models');
|
||
if (existsSync(modelsDir)) {
|
||
const modelFiles = readdirSync(modelsDir)
|
||
.filter(file => file.endsWith('.ts') && file !== 'index.ts')
|
||
.map(file => file.replace('.ts', ''));
|
||
|
||
const modelsIndexContent = modelFiles.map(model => `export * from './${model}';`).join('\n');
|
||
|
||
writeFileSync(join(modelsDir, 'index.ts'), modelsIndexContent);
|
||
console.log('📝 创建models/index.ts完成');
|
||
}
|
||
}
|
||
|
||
function createApiEntry() {
|
||
const servicesDir = join(config.output, 'services');
|
||
const modelsDir = join(config.output, 'models');
|
||
const apiDir = join('src', 'api');
|
||
const apiFile = join(apiDir, 'index.ts');
|
||
|
||
// 读取 service 文件
|
||
let serviceFiles = [];
|
||
if (existsSync(servicesDir)) {
|
||
serviceFiles = readdirSync(servicesDir)
|
||
.filter(file => file.endsWith('.ts') && file !== 'index.ts' && file !== 'Service.ts')
|
||
.map(file => file.replace('.ts', ''));
|
||
}
|
||
|
||
// 读取 model 文件
|
||
let modelFiles = [];
|
||
if (existsSync(modelsDir)) {
|
||
modelFiles = readdirSync(modelsDir)
|
||
.filter(file => file.endsWith('.ts') && file !== 'index.ts')
|
||
.map(file => file.replace('.ts', ''));
|
||
}
|
||
|
||
// 生成 import 语句
|
||
const importStatements = [
|
||
`import { OpenAPI } from '@/api/core/OpenAPI';`,
|
||
...serviceFiles.map(name => `import * as ${name} from '@/api/services/${name}';`),
|
||
].join('\n');
|
||
|
||
// 生成 api 对象
|
||
const apiObject = ['export const api = {', ...serviceFiles.map(name => ` ...${name},`), ' OpenAPI,', '};'].join('\n');
|
||
|
||
// 生成 baseURL 逻辑
|
||
const baseUrlLogic = `\nconst baseURL = (() => {\n const url = import.meta.env.VITE_API_BASE_URL || '';
|
||
return url;\n})();\nOpenAPI.BASE = baseURL;\n`;
|
||
|
||
// 生成类型 re-export
|
||
const typeExports = modelFiles.map(name => `export type { ${name} } from '@/api/models/${name}';`).join('\n');
|
||
|
||
// 合成文件内容
|
||
const content = `${importStatements}\n${baseUrlLogic}\n${apiObject}\n\n${typeExports}\n`;
|
||
|
||
// 确保 api 目录存在
|
||
if (!existsSync(apiDir)) {
|
||
require('fs').mkdirSync(apiDir, { recursive: true });
|
||
}
|
||
|
||
// 写入文件
|
||
writeFileSync(apiFile, content);
|
||
console.log('📝 自动生成 src/api/index.ts 完成');
|
||
}
|
||
|
||
async function generateApi() {
|
||
try {
|
||
console.log('🚀 开始生成API代码...');
|
||
|
||
let openApiSpec;
|
||
|
||
// 检查输入是URL还是本地文件
|
||
if (config.input.startsWith('http://') || config.input.startsWith('https://')) {
|
||
// 从URL获取OpenAPI规范
|
||
openApiSpec = await fetchOpenApiSpec(config.input);
|
||
} else {
|
||
// 从本地文件读取
|
||
if (!existsSync(config.input)) {
|
||
console.error(`❌ OpenAPI文件不存在: ${config.input}`);
|
||
console.log('请确保openapi.json文件存在于项目根目录,或设置OPENAPI_URL环境变量');
|
||
return;
|
||
}
|
||
openApiSpec = JSON.parse(readFileSync(config.input, 'utf8'));
|
||
}
|
||
|
||
// 生成API代码
|
||
await generate({
|
||
input: openApiSpec, // 直接传入规范对象
|
||
output: config.output,
|
||
client: config.client,
|
||
useOptions: config.useOptions,
|
||
useUnionTypes: config.useUnionTypes,
|
||
exportSchemas: config.exportSchemas,
|
||
exportServices: config.exportServices,
|
||
exportCore: config.exportCore,
|
||
exportModels: config.exportModels,
|
||
exportClient: config.exportClient,
|
||
});
|
||
|
||
console.log('✅ API代码生成完成!');
|
||
console.log(`📁 输出目录: ${config.output}`);
|
||
|
||
// 创建索引文件
|
||
createIndexFiles();
|
||
// 自动生成 api/index.ts(包含 api 和 ApiModel)
|
||
createApiEntry();
|
||
} catch (error) {
|
||
console.error('❌ 生成API代码时出错:', error);
|
||
}
|
||
}
|
||
|
||
// 运行生成器
|
||
generateApi();
|