feat: expose API markdown doc

This commit is contained in:
ittoview
2026-05-09 17:04:22 +01:00
parent 693aa7df61
commit 1a8948761b
5 changed files with 69 additions and 3 deletions

1
.gitignore vendored
View File

@@ -9,3 +9,4 @@ dist/
pdf_images/
public/api/
public/apidoc

View File

@@ -25,6 +25,7 @@
| 单绩效域详情 | `/api/performance-domains/{id}.json` |
| 工件反查使用情况 | `/api/artifacts/{id}/usage.json` |
| 工具反查使用情况 | `/api/tools/{id}/usage.json` |
| Markdown 接口文档 | `/apidoc` |
## 3. 接口说明
@@ -397,6 +398,23 @@
|---|---|
| `usedIn` | 使用该工具与技术的过程数组 |
---
### 3.13 Markdown 接口文档
用于让外部系统直接读取本说明文档。
`GET /apidoc`
响应体为 Markdown 文本字符串,不作为附件下载。
示例响应:
```markdown
# 知识库 API 接口说明
...
```
## 4. 常用调用示例
```text
@@ -420,4 +438,7 @@
反查专家判断在哪些过程中使用:
/api/tools/TT001/usage.json
读取接口 Markdown 文档:
/apidoc
```

View File

@@ -10,6 +10,15 @@ server {
}
# Markdown 接口说明,直接返回文本内容
location = /apidoc {
default_type text/markdown;
charset utf-8;
try_files /apidoc =404;
add_header Cache-Control "no-store";
}
# 知识库静态 JSON API接口路径不存在时返回 404避免被 SPA 回退到 index.html
location /api/ {
try_files $uri =404;

View File

@@ -7,6 +7,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url))
const rootDir = path.resolve(__dirname, '..')
const dataDir = path.join(rootDir, 'src', 'data')
const apiDir = path.join(rootDir, 'public', 'api')
const apiDocPath = path.join(rootDir, 'public', 'apidoc')
function readJson(relativePath) {
return JSON.parse(fs.readFileSync(path.join(rootDir, relativePath), 'utf8'))
@@ -24,9 +25,21 @@ function writeJson(relativePath, data) {
function cleanApiDir() {
fs.rmSync(apiDir, { recursive: true, force: true })
fs.rmSync(apiDocPath, { force: true })
ensureDir(apiDir)
}
function writeTextFile(target, content) {
ensureDir(path.dirname(target))
fs.writeFileSync(target, content, 'utf8')
}
function copyApiDoc() {
const source = path.join(rootDir, 'docs', '知识库API接口说明.md')
const content = fs.readFileSync(source, 'utf8')
writeTextFile(apiDocPath, content)
}
function extractConstArrayFromTs(filePath, constName) {
const text = fs.readFileSync(filePath, 'utf8')
const marker = `export const ${constName}`
@@ -280,4 +293,7 @@ for (const tool of tools) {
writeJson(`tools/${tool.id}/usage.json`, toolUsage(tool))
}
copyApiDoc()
console.log(`已生成静态 API 文件:${path.relative(rootDir, apiDir)}`)
console.log(`已生成 Markdown 接口文档:${path.relative(rootDir, apiDocPath)}`)

View File

@@ -121,6 +121,15 @@ const endpoints: ApiEndpoint[] = [
description: '返回指定工具与技术出现的过程。',
fields: ['id工具 ID', 'name工具名称', 'usedIn使用该工具的过程数组'],
},
{
id: 'api-doc-markdown',
name: 'Markdown 接口文档',
method: 'GET',
path: '/apidoc',
samplePath: '/apidoc',
description: '返回接口说明 Markdown 文本字符串。',
fields: ['响应体Markdown 文本字符串', '用途:供知识库或外部系统直接读取接口说明'],
},
]
const fieldGroups = [
@@ -167,7 +176,7 @@ export function ApiDocPage() {
setResult('')
try {
const response = await fetch(requestPath, { headers: { Accept: 'application/json' } })
const response = await fetch(requestPath, { headers: { Accept: 'application/json, text/markdown, text/plain, */*' } })
const contentType = response.headers.get('content-type') ?? ''
const body = contentType.includes('application/json') ? await response.json() : await response.text()
@@ -200,8 +209,18 @@ export function ApiDocPage() {
</div>
<h1 className="text-2xl font-bold text-gray-900 dark:text-white">API </h1>
<p className="mt-2 max-w-2xl text-sm leading-6 text-gray-500 dark:text-gray-400">
JSON GET /api
GET /api JSON/apidoc Markdown
</p>
<div className="mt-4 flex flex-wrap gap-2">
<a
href="/apidoc"
target="_blank"
rel="noreferrer"
className="inline-flex items-center rounded-lg bg-gray-900 px-3 py-2 text-sm font-medium text-white transition hover:bg-gray-700 dark:bg-white dark:text-gray-900 dark:hover:bg-gray-200"
>
Markdown /apidoc
</a>
</div>
</div>
<div className="grid grid-cols-3 gap-3 text-center">
<div className="rounded-xl bg-gray-50 px-4 py-3 dark:bg-gray-900/50">
@@ -213,7 +232,7 @@ export function ApiDocPage() {
<div className="text-xs text-gray-500 dark:text-gray-400"></div>
</div>
<div className="rounded-xl bg-gray-50 px-4 py-3 dark:bg-gray-900/50">
<div className="text-lg font-bold text-gray-900 dark:text-white">JSON</div>
<div className="text-lg font-bold text-gray-900 dark:text-white">JSON/MD</div>
<div className="text-xs text-gray-500 dark:text-gray-400"></div>
</div>
</div>