2026-04-19 19:15:01 +08:00
|
|
|
const express = require('express');
|
|
|
|
|
const cors = require('cors');
|
|
|
|
|
const path = require('path');
|
|
|
|
|
const dotenv = require('dotenv');
|
|
|
|
|
|
|
|
|
|
dotenv.config();
|
|
|
|
|
|
|
|
|
|
const app = express();
|
|
|
|
|
const PORT = process.env.PORT || 3002;
|
|
|
|
|
|
2026-04-19 19:40:40 +08:00
|
|
|
// 中间件 - CORS配置
|
|
|
|
|
// 当前暂无域名,员工通过公网IP访问,暂时允许所有来源
|
|
|
|
|
// TODO: 申请域名后,在 .env 的 CORS_ORIGIN 中填写域名,并切换为严格模式
|
|
|
|
|
const corsWhitelist = process.env.CORS_ORIGIN ? process.env.CORS_ORIGIN.split(',') : [];
|
2026-04-19 19:20:12 +08:00
|
|
|
const corsOptions = {
|
2026-04-19 19:36:58 +08:00
|
|
|
origin: (origin, callback) => {
|
2026-04-19 19:40:40 +08:00
|
|
|
// 暂无域名阶段:允许所有来源访问(公网IP访问需要)
|
|
|
|
|
if (!origin || corsWhitelist.length === 0 || corsWhitelist.includes(origin)) {
|
2026-04-19 19:36:58 +08:00
|
|
|
callback(null, true);
|
|
|
|
|
} else {
|
2026-04-19 19:40:40 +08:00
|
|
|
// 有域名后可改为 callback(new Error('Not allowed'), false) 限制来源
|
|
|
|
|
callback(null, true);
|
2026-04-19 19:36:58 +08:00
|
|
|
}
|
|
|
|
|
},
|
2026-04-19 19:20:12 +08:00
|
|
|
credentials: true,
|
|
|
|
|
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
|
|
|
|
|
allowedHeaders: ['Content-Type', 'Authorization']
|
|
|
|
|
};
|
|
|
|
|
app.use(cors(corsOptions));
|
2026-05-15 12:02:24 +08:00
|
|
|
app.use(express.json({ limit: '50mb' }));
|
|
|
|
|
app.use(express.urlencoded({ extended: true, limit: '50mb' }));
|
2026-04-19 19:15:01 +08:00
|
|
|
|
|
|
|
|
// 静态文件服务 - 前端应用
|
|
|
|
|
app.use(express.static(path.join(__dirname, '../frontend/dist')));
|
|
|
|
|
|
|
|
|
|
// 加载路由模块
|
|
|
|
|
app.use('/api/auth', require('./routes/auth'));
|
|
|
|
|
app.use('/api/users', require('./routes/users'));
|
|
|
|
|
app.use('/api/products', require('./routes/products'));
|
|
|
|
|
app.use('/api/customers', require('./routes/customers'));
|
|
|
|
|
app.use('/api/suppliers', require('./routes/suppliers'));
|
|
|
|
|
app.use('/api/subcontractors', require('./routes/subcontractors'));
|
|
|
|
|
app.use('/api/projects', require('./routes/projects'));
|
|
|
|
|
app.use('/api/upload', require('./routes/upload'));
|
|
|
|
|
app.use('/api/construction', require('./routes/construction'));
|
|
|
|
|
app.use('/api/categories', require('./routes/categories'));
|
|
|
|
|
app.use('/api/payment-nodes', require('./routes/paymentNodes'));
|
|
|
|
|
app.use('/api/payment-records', require('./routes/paymentRecords'));
|
|
|
|
|
app.use('/api/exchange-rates', require('./routes/exchange'));
|
|
|
|
|
app.use('/api/advances', require('./routes/advances'));
|
|
|
|
|
app.use('/api/payment-requests', require('./routes/payments'));
|
|
|
|
|
app.use('/api/verifications', require('./routes/verifications'));
|
|
|
|
|
app.use('/api/executions', require('./routes/executions'));
|
|
|
|
|
app.use('/api/reimbursements', require('./routes/reimbursements'));
|
|
|
|
|
app.use('/api/purchase-requests', require('./routes/purchase'));
|
|
|
|
|
app.use('/api/purchase-orders', require('./routes/purchase-orders'));
|
|
|
|
|
app.use('/api/payment-plans', require('./routes/payment-plans'));
|
|
|
|
|
app.use('/api/inventory', require('./routes/inventory'));
|
|
|
|
|
app.use('/api/finance-stats', require('./routes/finance-stats'));
|
|
|
|
|
app.use('/api/budget-projects', require('./routes/budget'));
|
|
|
|
|
app.use('/api/health', require('./routes/health'));
|
|
|
|
|
app.use('/api/logistics-companies', require('./routes/logistics-companies'));
|
|
|
|
|
app.use('/api/logistics', require('./routes/logistics'));
|
|
|
|
|
app.use('/api/payment-execution', require('./routes/payment-execution'));
|
2026-05-15 12:02:24 +08:00
|
|
|
app.use('/api/verifications-new', require('./routes/verifications-new'));
|
2026-04-19 19:15:01 +08:00
|
|
|
app.use('/api/returns', require('./routes/returns'));
|
|
|
|
|
app.use('/api/project-materials', require('./routes/project-materials'));
|
2026-05-15 12:25:08 +08:00
|
|
|
app.use('/api/process-templates', require('./routes/process-templates'));
|
|
|
|
|
app.use('/api/receiving', require('./routes/receiving'));
|
2026-05-16 03:04:48 +08:00
|
|
|
app.use('/api/expense-categories', require('./routes/expense-categories'));
|
|
|
|
|
app.use('/api/financial-records', require('./routes/financial-records'));
|
2026-04-19 19:15:01 +08:00
|
|
|
|
|
|
|
|
app.get('*', (req, res) => {
|
|
|
|
|
res.sendFile(path.join(__dirname, '../frontend/dist/index.html'));
|
|
|
|
|
});
|
|
|
|
|
|
2026-05-15 12:02:24 +08:00
|
|
|
// 错误处理中间件 - 生产环境隐藏内部错误详情
|
2026-04-19 19:15:01 +08:00
|
|
|
app.use((err, req, res, next) => {
|
2026-05-15 12:02:24 +08:00
|
|
|
console.error('[ERROR]', err.message || err);
|
|
|
|
|
const isDev = process.env.NODE_ENV === 'development';
|
|
|
|
|
res.status(err.status || 500).json({
|
2026-04-19 19:15:01 +08:00
|
|
|
success: false,
|
2026-05-15 12:02:24 +08:00
|
|
|
message: isDev ? (err.message || '服务器内部错误') : '服务器内部错误',
|
|
|
|
|
...(isDev && { stack: err.stack })
|
2026-04-19 19:15:01 +08:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 启动服务器
|
|
|
|
|
app.listen(PORT, () => {
|
|
|
|
|
console.log(`
|
|
|
|
|
🚀 公司财务管理系统 - 模块化后端
|
|
|
|
|
===========================================
|
|
|
|
|
📍 服务器地址: http://0.0.0.0:${PORT}
|
|
|
|
|
🌐 外部访问: http://${process.env.EXTERNAL_IP || 'localhost'}:${PORT}
|
|
|
|
|
|
|
|
|
|
🔗 核心API端点:
|
|
|
|
|
- 健康检查: /api/health
|
|
|
|
|
- 客户管理: /api/customers
|
|
|
|
|
- 供应商管理: /api/suppliers
|
|
|
|
|
- 项目管理: /api/projects
|
|
|
|
|
- 商品管理: /api/products
|
|
|
|
|
- 采购申请: /api/purchase-requests
|
|
|
|
|
- 库存管理: /api/inventory
|
|
|
|
|
- 付款节点: /api/payment-nodes
|
|
|
|
|
- 付款记录: /api/payment-records
|
|
|
|
|
- 汇率管理: /api/exchange-rates
|
|
|
|
|
- 预支款管理: /api/advances
|
|
|
|
|
- 报销管理: /api/reimbursements
|
|
|
|
|
- 财务统计: /api/finance-stats
|
|
|
|
|
|
|
|
|
|
✅ 所有API已就绪
|
|
|
|
|
✅ 前端应用已集成
|
|
|
|
|
✅ 数据库已连接
|
|
|
|
|
✅ 等待用户访问
|
|
|
|
|
|
|
|
|
|
⏰ 启动时间: ${new Date().toISOString()}
|
|
|
|
|
===========================================
|
|
|
|
|
`);
|
|
|
|
|
}).on('error', (err) => {
|
|
|
|
|
console.error('服务器启动失败:', err);
|
|
|
|
|
process.exit(1);
|
|
|
|
|
});
|