修改路由
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
# 机型信息管理系统 - 后端API
|
# 通信技术部 - 后端API
|
||||||
|
|
||||||
## 技术栈
|
## 技术栈
|
||||||
- Node.js
|
- Node.js
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "department-api",
|
"name": "department-api",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "机型信息管理系统后端API",
|
"description": "通信技术部后端API",
|
||||||
"main": "server.js",
|
"main": "server.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node server.js",
|
"start": "node server.js",
|
||||||
|
|||||||
166
routes/docs.js
Normal file
166
routes/docs.js
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const router = express.Router();
|
||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
const sanitizeSegment = (seg) => String(seg || '').replace(/[^a-zA-Z0-9_\-]/g, '');
|
||||||
|
|
||||||
|
router.get('/list', (req, res) => {
|
||||||
|
try {
|
||||||
|
const series = sanitizeSegment(req.query.series);
|
||||||
|
const sub = sanitizeSegment(req.query.sub);
|
||||||
|
|
||||||
|
if (!series || !sub) {
|
||||||
|
return res.status(400).json({ error: '缺少必要参数 series 或 sub' });
|
||||||
|
}
|
||||||
|
|
||||||
|
const modelsDocsDir = path.join(__dirname, '..', 'uploads', 'models', series, sub, 'docs');
|
||||||
|
const legacyDocsDir = path.join(__dirname, '..', 'uploads', 'docs', series, sub);
|
||||||
|
const docsDir = fs.existsSync(modelsDocsDir) ? modelsDocsDir : legacyDocsDir;
|
||||||
|
|
||||||
|
if (!fs.existsSync(docsDir)) {
|
||||||
|
return res.json({ success: true, data: [] });
|
||||||
|
}
|
||||||
|
|
||||||
|
const entries = fs.readdirSync(docsDir, { withFileTypes: true });
|
||||||
|
const files = entries
|
||||||
|
.filter((e) => e.isFile())
|
||||||
|
.filter((e) => /\.(pdf|doc|docx|xls|xlsx|ppt|pptx)$/i.test(e.name))
|
||||||
|
.map((e) => {
|
||||||
|
const fullPath = path.join(docsDir, e.name);
|
||||||
|
let size = 0;
|
||||||
|
try {
|
||||||
|
size = fs.statSync(fullPath).size;
|
||||||
|
} catch {}
|
||||||
|
const base = docsDir === modelsDocsDir ? `/uploads/models/${series}/${sub}/docs` : `/uploads/docs/${series}/${sub}`;
|
||||||
|
const url = `${base}/${e.name}`;
|
||||||
|
return { name: e.name, url, size };
|
||||||
|
});
|
||||||
|
|
||||||
|
res.json({ success: true, data: files });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取资料列表错误:', error);
|
||||||
|
res.status(500).json({ error: '服务器内部错误' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 图片列表(支持每机型统一文件夹结构)
|
||||||
|
router.get('/images', (req, res) => {
|
||||||
|
try {
|
||||||
|
const series = sanitizeSegment(req.query.series);
|
||||||
|
const sub = sanitizeSegment(req.query.sub);
|
||||||
|
|
||||||
|
if (!series || !sub) {
|
||||||
|
return res.status(400).json({ error: '缺少必要参数 series 或 sub' });
|
||||||
|
}
|
||||||
|
|
||||||
|
const candidates = [
|
||||||
|
path.join(__dirname, '..', 'uploads', 'models', series, sub, 'image'),
|
||||||
|
path.join(__dirname, '..', 'uploads', 'models', series, sub, 'images'),
|
||||||
|
path.join(__dirname, '..', 'uploads', 'images', series, sub),
|
||||||
|
path.join(__dirname, '..', 'uploads', 'image', series, sub)
|
||||||
|
];
|
||||||
|
const imgDir = candidates.find((p) => fs.existsSync(p));
|
||||||
|
|
||||||
|
if (!fs.existsSync(imgDir)) {
|
||||||
|
return res.json({ success: true, data: [] });
|
||||||
|
}
|
||||||
|
|
||||||
|
const entries = fs.readdirSync(imgDir, { withFileTypes: true });
|
||||||
|
const files = entries
|
||||||
|
.filter((e) => e.isFile())
|
||||||
|
.filter((e) => /\.(png|jpg|jpeg|gif|webp|svg)$/i.test(e.name))
|
||||||
|
.map((e) => {
|
||||||
|
const fullPath = path.join(imgDir, e.name);
|
||||||
|
let size = 0;
|
||||||
|
try { size = fs.statSync(fullPath).size; } catch {}
|
||||||
|
let base = `/uploads/images/${series}/${sub}`;
|
||||||
|
if (imgDir.includes(path.join('uploads', 'models'))) {
|
||||||
|
if (imgDir.endsWith(path.join(series, sub, 'image'))) {
|
||||||
|
base = `/uploads/models/${series}/${sub}/image`;
|
||||||
|
} else if (imgDir.endsWith(path.join(series, sub, 'images'))) {
|
||||||
|
base = `/uploads/models/${series}/${sub}/images`;
|
||||||
|
}
|
||||||
|
} else if (imgDir.includes(path.join('uploads', 'image'))) {
|
||||||
|
base = `/uploads/image/${series}/${sub}`;
|
||||||
|
}
|
||||||
|
const url = `${base}/${e.name}`;
|
||||||
|
return { name: e.name, url, size };
|
||||||
|
});
|
||||||
|
|
||||||
|
res.json({ success: true, data: files });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取图片列表错误:', error);
|
||||||
|
res.status(500).json({ error: '服务器内部错误' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
|
// 使用相同 router 添加规格读取接口
|
||||||
|
router.get('/specs', (req, res) => {
|
||||||
|
try {
|
||||||
|
const series = sanitizeSegment(req.query.series);
|
||||||
|
const sub = sanitizeSegment(req.query.sub);
|
||||||
|
|
||||||
|
if (!series || !sub) {
|
||||||
|
return res.status(400).json({ error: '缺少必要参数 series 或 sub' });
|
||||||
|
}
|
||||||
|
|
||||||
|
const dirCandidates = [
|
||||||
|
path.join(__dirname, '..', 'uploads', 'models', series, sub, 'specs'),
|
||||||
|
path.join(__dirname, '..', 'uploads', 'specs', series, sub)
|
||||||
|
];
|
||||||
|
|
||||||
|
const parseCsvFile = (filePath) => {
|
||||||
|
const raw = fs.readFileSync(filePath, 'utf8');
|
||||||
|
const lines = raw.replace(/^\uFEFF/, '').split(/\r?\n/).filter((l) => l.trim().length);
|
||||||
|
const normalize = (s) => String(s || '').trim().replace(/^"(.*)"$/, '$1').replace(/^'(.*)'$/, '$1');
|
||||||
|
const parseLine = (l) => {
|
||||||
|
const replaced = l.replace(/;/g, ';').replace(/,/g, ',').replace(/\uff0c/g, ',').replace(/\uff1b/g, ';');
|
||||||
|
let tokens = replaced.match(/"([^"]*)"|[^,;\t]+/g) || [];
|
||||||
|
if (tokens.length < 2) {
|
||||||
|
const parts = replaced.split(/:|:/);
|
||||||
|
if (parts.length >= 2) {
|
||||||
|
tokens = [parts[0], parts.slice(1).join(':')];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const key = normalize(tokens[0] || '');
|
||||||
|
const val = normalize(tokens[1] || '');
|
||||||
|
return { key, value: val };
|
||||||
|
};
|
||||||
|
return lines.map(parseLine).filter((r) => r.key.length);
|
||||||
|
};
|
||||||
|
|
||||||
|
const dirPath = dirCandidates.find((p) => fs.existsSync(p) && fs.statSync(p).isDirectory());
|
||||||
|
if (dirPath) {
|
||||||
|
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
||||||
|
const csvFiles = entries.filter((e) => e.isFile() && /\.csv$/i.test(String(e.name).trim()));
|
||||||
|
if (csvFiles.length) {
|
||||||
|
const sections = csvFiles.map((e) => {
|
||||||
|
const fp = path.join(dirPath, e.name);
|
||||||
|
const title = e.name.replace(/\.csv$/i, '');
|
||||||
|
return { title, rows: parseCsvFile(fp) };
|
||||||
|
});
|
||||||
|
return res.json({ success: true, data: sections });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileCandidates = [
|
||||||
|
path.join(__dirname, '..', 'uploads', 'models', series, sub, 'specs', 'specs.csv'),
|
||||||
|
path.join(__dirname, '..', 'uploads', 'models', series, sub, 'specs.csv'),
|
||||||
|
path.join(__dirname, '..', 'uploads', 'specs', series, `${sub}.csv`),
|
||||||
|
path.join(__dirname, '..', 'uploads', 'specs', series, sub, 'specs.csv')
|
||||||
|
];
|
||||||
|
const filePath = fileCandidates.find((p) => fs.existsSync(p));
|
||||||
|
|
||||||
|
if (!filePath) {
|
||||||
|
return res.json({ success: true, data: [] });
|
||||||
|
}
|
||||||
|
|
||||||
|
const specs = parseCsvFile(filePath);
|
||||||
|
res.json({ success: true, data: specs });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('读取规格CSV错误:', error);
|
||||||
|
res.status(500).json({ error: '服务器内部错误' });
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -4,6 +4,7 @@ const path = require('path');
|
|||||||
const authRoutes = require('./routes/auth');
|
const authRoutes = require('./routes/auth');
|
||||||
const aircraftRoutes = require('./routes/aircraft');
|
const aircraftRoutes = require('./routes/aircraft');
|
||||||
const pdfRoutes = require('./routes/pdf');
|
const pdfRoutes = require('./routes/pdf');
|
||||||
|
const docsRoutes = require('./routes/docs');
|
||||||
const { authenticateToken } = require('./middleware/auth');
|
const { authenticateToken } = require('./middleware/auth');
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
@@ -21,6 +22,7 @@ app.use('/uploads', express.static(path.join(__dirname, 'uploads')));
|
|||||||
app.use('/api/auth', authRoutes);
|
app.use('/api/auth', authRoutes);
|
||||||
app.use('/api/aircraft', authenticateToken, aircraftRoutes);
|
app.use('/api/aircraft', authenticateToken, aircraftRoutes);
|
||||||
app.use('/api/pdf', authenticateToken, pdfRoutes);
|
app.use('/api/pdf', authenticateToken, pdfRoutes);
|
||||||
|
app.use('/api/docs', docsRoutes);
|
||||||
|
|
||||||
// 健康检查
|
// 健康检查
|
||||||
app.get('/api/health', (req, res) => {
|
app.get('/api/health', (req, res) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user