通过代码获取接口文档工具
介绍
1.通过前后端代码来生成规格化的接口文档
2.支持拖拽上传或点击选择文件,可以一次选择多个文件或选择文件夹
3.用户选择前后端代码,工具调用GPT解析,得到规范化的接口文档
4.接口文档为markdown格式,可在线预览,也可以将文档导出
使用到的技术
1.vue3
2.v-md-editor
3.通义千问的接口
4.代码由mastergo设计页面,trae进一步调整代码
使用说明
需要配置sk,可在阿里云申请;然后替换代码 util/util.js 的sk
核心源码
App.vue
html
<script setup>
import {nextTick, ref} from 'vue'
import Message from './utils/message.js'
import {callGpt} from "@/utils/util";
// 存储选中的文件
const selectedFiles = ref([])
// 预览的markdown内容
const previewContent = ref('')
// 控制预览对话框显示
const showPreview = ref(false)
// 处理文件拖拽
const handleDrop = (e) => {
e.preventDefault()
const files = e.dataTransfer.files
handleFiles(files)
}
const fileInputLoading = ref(false);
const fileInput = ref();
// 处理文件选择
const handleFileSelect = (e) => {
const files = e.target.files
handleFiles(files)
nextTick(() => {
fileInputLoading.value = true;
});
}
const selectBtn = () => {
fileInputLoading.value = false;
nextTick(() => {
fileInput.value.click()
});
}
const selectDirBtn = async () => {
try {
const dirHandle = await window.showDirectoryPicker()
// 清空已选择的文件
selectedFiles.value = []
// 递归处理文件夹
await processDirectory(dirHandle, '')
Message.success('文件夹导入成功')
} catch (err) {
if (err.name !== 'AbortError') {
Message.error('选择文件夹失败')
console.error(err)
}
}
}
// 递归处理文件夹
const processDirectory = async (dirHandle, path) => {
for await (const entry of dirHandle.values()) {
if (entry.kind === 'file') {
const file = await entry.getFile()
selectedFiles.value.push({
file: file,
relativePath: path ? `${path}/${file.name}` : file.name
})
} else if (entry.kind === 'directory') {
const newPath = path ? `${path}/${entry.name}` : entry.name
await processDirectory(entry, newPath)
}
}
}
// 处理文件
const handleFiles = (files) => {
for (let file of files) {
// 检查文件类型
if (!isValidFileType(file)) {
Message.warning(`不支持的文件类型: ${file.name}`)
continue
}
selectedFiles.value.push({
file: file,
relativePath: file.name
})
}
}
// 检查文件类型
const isValidFileType = (file) => {
const validTypes = ['.java', '.py', '.js', '.ts', '.go', '.cpp', '.c', '.h', '.txt', '.json']
return validTypes.some(type => file.name.toLowerCase().endsWith(type))
}
// 清空文件列表
const clearFiles = () => {
selectedFiles.value = []
Message.info('文件列表已清空')
}
// 移除单个文件
const removeFile = (index) => {
selectedFiles.value.splice(index, 1)
}
// 生成接口文档
const generateDocs = async () => {
if (selectedFiles.value.length === 0) {
Message.warning('请先选择文件');
return;
}
try {
// 读取所有文件内容
const fileContents = await Promise.all(
selectedFiles.value.map(async (item) => {
const content = await item.file.text();
return {
path: item.relativePath,
content: content
};
})
);
// 构建提示词
const prompt = `请帮我分析以下代码文件,生成一份完整的接口文档,接口文档要规范化,要包含请求和返回示例:\n\n${
fileContents.map(file =>
`文件路径:${file.path}\n文件内容:\n${file.content}\n---\n`
).join('\n')
}`;
Message.info('正在生成文档...');
previewContent.value = ''; // 清空之前的内容
showPreview.value = true;
await callGpt(prompt, (content) => {
// 实时更新预览内容
previewContent.value = content;
}, ()=> {
Message.success('文档生成成功');
});
} catch (error) {
Message.error('文档生成失败');
console.error(error);
}
}
// 导出markdown文档
const exportMarkdown = () => {
const blob = new Blob([previewContent.value], { type: 'text/markdown' })
const url = URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
link.download = 'api-docs.md'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
URL.revokeObjectURL(url)
Message.success('文档导出成功')
}
</script>
<template>
<div class="bg-gray-50" style="width: 100%; height: 100%">
<div class="w-[1200px] mx-auto">
<nav class="h-16 bg-white shadow-sm flex items-center justify-between px-8">
<div class="flex items-center space-x-2">
<span class="text-2xl font-['Pacifico'] text-primary">logo</span>
<span class="text-lg font-medium">接口文档生成器</span>
</div>
<button class="w-10 h-10 rounded-button flex items-center justify-center hover:bg-gray-100 transition-colors">
<i class="fas fa-sun text-gray-600"></i>
</button>
</nav>
<main class="px-8 py-12">
<div class="max-w-3xl mx-auto">
<div class="bg-white rounded-lg shadow-sm p-8">
<div id="dropArea"
class="drag-area rounded-lg p-12 text-center"
@drop="handleDrop"
@dragover.prevent
@dragenter.prevent>
<input v-if="!fileInputLoading"
ref="fileInput"
type="file"
id="fileInput"
class="file-input"
multiple
@change="handleFileSelect">
<div class="space-y-4">
<div class="w-20 h-20 mx-auto bg-gray-50 rounded-full flex items-center justify-center">
<i class="fas fa-cloud-upload-alt text-4xl text-gray-400"></i>
</div>
<div>
<h3 class="text-lg font-medium">拖拽文件到这里,或</h3>
<button @click="selectBtn"
class="mt-2 px-6 py-2 bg-primary text-white rounded-button hover:bg-primary/90 button-hover whitespace-nowrap">
点击选择文件
</button>
<button @click="selectDirBtn"
class="ml-4 mt-2 px-6 py-2 bg-primary text-white rounded-button hover:bg-primary/90 button-hover whitespace-nowrap">
点击选择文件夹
</button>
</div>
<p class="text-sm text-gray-500">
支持的文件格式:.java, .py, .js, .ts, .go, .cpp, .c, .h, .txt, .json
</p>
</div>
</div>
<div id="fileList" class="mt-8 space-y-4" :class="selectedFiles.length > 0 ? '' : ' hidden'">
<div class="text-lg font-medium mb-4">已选择的文件</div>
<div class="space-y-3">
<template v-for="(item, index) in selectedFiles" :key="index">
<div class="flex items-center justify-between p-3 bg-gray-50 rounded-md">
<div class="flex items-center">
<i class="fas fa-file-code text-primary mr-3"></i>
<span class="text-gray-600 text-sm mr-2">{{ item.relativePath }}</span>
<span>{{ item.file.name }}</span>
</div>
<button class="text-red-500 hover:text-red-700" @click="removeFile(index)">
<i class="fas fa-times"></i>
</button>
</div>
</template>
</div>
<div class="flex justify-end space-x-3 mt-6">
<button @click="clearFiles"
class="px-6 py-2 text-gray-600 bg-gray-100 rounded-button hover:bg-gray-200 button-hover whitespace-nowrap">
清空列表
</button>
<button @click="generateDocs"
class="px-6 py-2 text-white bg-primary rounded-button hover:bg-primary/90 button-hover whitespace-nowrap">
生成接口文档
</button>
</div>
</div>
</div>
<div class="mt-12 bg-white rounded-lg shadow-sm p-8">
<h2 class="text-xl font-medium mb-6">使用说明</h2>
<div class="space-y-4 text-gray-600">
<div class="flex items-start space-x-3">
<div class="w-6 h-6 rounded-full bg-primary/10 flex items-center justify-center flex-shrink-0 mt-0.5">
<i class="fas fa-check text-sm text-primary"></i>
</div>
<p>支持拖拽上传或点击选择文件,可以一次选择多个文件或选择文件夹</p>
</div>
<div class="flex items-start space-x-3">
<div class="w-6 h-6 rounded-full bg-primary/10 flex items-center justify-center flex-shrink-0 mt-0.5">
<i class="fas fa-check text-sm text-primary"></i>
</div>
<p>在选择文件夹时会将之前选择的文件列表清空,请注意操作</p>
</div>
<div class="flex items-start space-x-3">
<div class="w-6 h-6 rounded-full bg-primary/10 flex items-center justify-center flex-shrink-0 mt-0.5">
<i class="fas fa-check text-sm text-primary"></i>
</div>
<p>用户选择前后端代码,工具调用GPT解析,得到规范化的接口文档</p>
</div>
<div class="flex items-start space-x-3">
<div class="w-6 h-6 rounded-full bg-primary/10 flex items-center justify-center flex-shrink-0 mt-0.5">
<i class="fas fa-check text-sm text-primary"></i>
</div>
<p>接口文档为markdown格式,可在线预览,也可以将文档导出</p>
</div>
</div>
</div>
</div>
</main>
</div>
</div>
<!-- 添加预览对话框 -->
<div v-if="showPreview" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
<div class="bg-white w-4/5 h-4/5 rounded-lg p-6 flex flex-col">
<div class="flex justify-between items-center mb-4">
<h3 class="text-xl font-medium">接口文档预览</h3>
<div class="space-x-2">
<button @click="exportMarkdown" class="px-4 py-2 bg-primary text-white rounded-button hover:bg-primary/90">
导出文档
</button>
<button @click="showPreview = false" class="px-4 py-2 bg-gray-100 text-gray-600 rounded-button hover:bg-gray-200">
关闭
</button>
</div>
</div>
<div class="flex-1 overflow-auto preview">
<v-md-editor v-model="previewContent" mode="preview"></v-md-editor>
</div>
</div>
</div>
</template>
<style>
body {
min-height: 100vh;
}
#app {
min-height: 100vh;
}
body::-webkit-scrollbar {
width: 15px;
}
body::-webkit-scrollbar-track {
background: #f1f5f9;
border-radius: 8px;
}
body::-webkit-scrollbar-thumb {
background: #6366f1;
border-radius: 8px;
border: 2px solid #f1f5f9;
}
body::-webkit-scrollbar-thumb:hover {
background: #4f46e5;
}
.drag-area {
border: 2px dashed #E5E7EB;
transition: all 0.3s ease;
}
.drag-area:hover {
border-color: #4F46E5;
}
.file-input {
display: none;
}
.button-hover {
transition: transform 0.2s ease;
}
.button-hover:active {
transform: translateY(2px);
}
.preview::-webkit-scrollbar {
width: 15px;
}
.preview::-webkit-scrollbar-track {
background: #f1f5f9;
border-radius: 8px;
}
.preview::-webkit-scrollbar-thumb {
background: #6366f1;
border-radius: 8px;
border: 2px solid #f1f5f9;
}
.preview::-webkit-scrollbar-thumb:hover {
background: #4f46e5;
}
</style>
演示截图
1.工具首页
2.操作页面-选择文件
3.生成接口文档页面1
4.生成接口文档页面2