修改路由
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "department-api",
|
||||
"version": "1.0.0",
|
||||
"description": "机型信息管理系统后端API",
|
||||
"description": "通信技术部后端API",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
"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 aircraftRoutes = require('./routes/aircraft');
|
||||
const pdfRoutes = require('./routes/pdf');
|
||||
const docsRoutes = require('./routes/docs');
|
||||
const { authenticateToken } = require('./middleware/auth');
|
||||
|
||||
const app = express();
|
||||
@@ -21,6 +22,7 @@ app.use('/uploads', express.static(path.join(__dirname, 'uploads')));
|
||||
app.use('/api/auth', authRoutes);
|
||||
app.use('/api/aircraft', authenticateToken, aircraftRoutes);
|
||||
app.use('/api/pdf', authenticateToken, pdfRoutes);
|
||||
app.use('/api/docs', docsRoutes);
|
||||
|
||||
// 健康检查
|
||||
app.get('/api/health', (req, res) => {
|
||||
|
||||
Reference in New Issue
Block a user