#!/usr/bin/env node /** * API 文档自动生成脚本 * 从后端 Swagger 自动生成前端文档 */ const fs = require('fs'); const path = require('path'); const axios = require('axios'); // 配置 const config = { backendUrl: process.env.BACKEND_URL || 'http://localhost:3000', docsDir: path.join(__dirname, '../src/wwjcloud/openapi/api'), apiGroups: { full: { name: '全量 API', swaggerPath: process.env.OPENAPI_FULL_PATH || '/api-json', outputDir: 'full', prefix: '', }, admin: { name: '管理端 API', swaggerPath: process.env.OPENAPI_ADMIN_PATH || '/api/admin-json', outputDir: 'admin', prefix: '/adminapi', }, frontend: { name: '前端 API', swaggerPath: process.env.OPENAPI_FRONTEND_PATH || '/api/frontend-json', outputDir: 'frontend', prefix: '/api', }, }, // 固定 Token(与后端 swagger.token 保持一致) token: '9f2a7c1e4b5d8a90c3f6e2b17a4c58d0f1b2c3d4e5f67890ab12cd34ef56a789', }; /** * 获取 Swagger JSON */ async function getSwaggerJson(group) { try { const url = `${config.backendUrl}${group.swaggerPath}`; console.log(`获取 ${group.name} API: ${url}`); const headers = {}; if (config.token) headers.Authorization = `Bearer ${config.token}`; const response = await axios.get(url, { headers }); return response.data; } catch (error) { console.error(`获取失败: ${error.message}`); return null; } } /** * 生成模块文档 */ function generateModuleDoc(group, tag, paths) { const moduleName = tag.name; let markdown = `--- :title: ${moduleName} API :description: ${tag.description || `${moduleName} 相关接口`} --- # ${moduleName} API :::: info ${moduleName} ${tag.description || `${moduleName} 相关接口`} :::: ## API 列表 `; // 查找该标签下的接口 Object.keys(paths).forEach((p) => { Object.keys(paths[p]).forEach((method) => { const operation = paths[p][method]; if (operation.tags && operation.tags.includes(tag.name)) { markdown += generateApiDoc(p, method, operation); } }); }); return markdown; } /** * 生成单个 API 文档 */ function generateApiDoc(pathname, method, operation) { const summary = operation.summary || operation.operationId || '未命名接口'; let doc = `### ${summary}\n\n`; doc += `**接口**: \`${method.toUpperCase()} ${pathname}\`\n\n`; if (operation.description) { doc += `**描述**: ${operation.description}\n\n`; } // 请求参数 if (operation.parameters && operation.parameters.length > 0) { doc += `**参数**:\n\n`; doc += `| 参数 | 类型 | 必填 | 说明 |\n`; doc += `|------|------|------|------|\n`; operation.parameters.forEach((param) => { const required = param.required ? '是' : '否'; const type = param.type || param.schema?.type || 'string'; doc += `| ${param.name} | ${type} | ${required} | ${param.description || ''} |\n`; }); doc += `\n`; } // 请求体 if (operation.requestBody) { doc += `**请求体**:\n\n`; doc += `\`\`\`json\n`; doc += `{}\n`; doc += `\`\`\`\n\n`; } // 响应 doc += `**响应**:\n\n`; doc += `\`\`\`json\n`; doc += `{"code":200,"message":"success","data":{}}\n`; doc += `\`\`\`\n\n`; doc += `---\n\n`; return doc; } /** * 保存文档 */ function saveDocument(outputPath, content) { try { const dir = path.dirname(outputPath); if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }); } fs.writeFileSync(outputPath, content, 'utf8'); console.log(`已保存: ${outputPath}`); } catch (error) { console.error(`保存失败: ${error.message}`); } } /** * 主函数 */ async function main() { console.log('开始自动生成 API 文档...\n'); for (const [_key, group] of Object.entries(config.apiGroups)) { console.log(`处理 ${group.name}...`); const swaggerData = await getSwaggerJson(group); if (!swaggerData) { console.log(`跳过 ${group.name}\n`); continue; } const tags = swaggerData.tags || []; const paths = swaggerData.paths || {}; // 为每个标签生成文档 for (const tag of tags) { const moduleName = tag.name.toLowerCase().replace(/\s+/g, '-'); const content = generateModuleDoc(group, tag, paths); const outputPath = path.join( config.docsDir, group.outputDir, `${moduleName}.md`, ); saveDocument(outputPath, content); } console.log(`${group.name} 完成\n`); } console.log('API 文档生成完成!'); console.log('访问: http://localhost:6173/wwjcloud/openapi/api/'); } // 运行 if (require.main === module) { main().catch((error) => { console.error('执行失败:', error); process.exit(1); }); } module.exports = { config, getSwaggerJson, generateModuleDoc };