3f1c291486
- 恢复被误删的5家门店旧账单数据(58377行) - 合并哈马尔罕大钟寺店费用到大钟寺店(0022) - 修改v_store_operating_expense_monthly视图按sales_store_code聚合费用 - 修复利润机会池食材成本差异为负时opportunity不为负 - 修复前端totalOpportunity只累加正数机会 - 刷新bill_fact/mv_store_risk_rating_monthly等物化视图 - 新增PromotionPage和promotion路由
93 lines
3.3 KiB
TypeScript
93 lines
3.3 KiB
TypeScript
import 'dotenv/config'
|
|
import express from 'express'
|
|
import cors from 'cors'
|
|
import { authMiddleware, AuthRequest } from './middleware/auth.js'
|
|
import { errorHandler, notFoundHandler } from './middleware/error.js'
|
|
import { tenantDbMiddleware } from './middleware/tenant-db.js'
|
|
import authRoutes from './routes/auth.js'
|
|
import dataRoutes from './routes/data.js'
|
|
import taskRoutes from './routes/tasks.js'
|
|
import costAnalysisRoutes from './routes/cost-analysis.js'
|
|
import storeExpenseRoutes from './routes/store-expense.js'
|
|
import smartSchedulingRoutes from './routes/smart-scheduling.js'
|
|
import situationalAwarenessRoutes from './routes/situational-awareness.js'
|
|
import analyticsEnhancedRoutes from './routes/analytics-enhanced.js'
|
|
import adminRoutes from './routes/admin.js'
|
|
import ttsRoutes from './routes/tts.js'
|
|
import targetRoutes from './routes/target.js'
|
|
import schedulerRoutes from './routes/scheduler.js'
|
|
import alertRoutes from './routes/alert.js'
|
|
import storeGradeRoutes from './routes/store-grade.js'
|
|
import productRoutes from './routes/product.js'
|
|
import enterpriseRoutes from './routes/enterprise.js'
|
|
import intelligenceRoutes from './routes/intelligence.js'
|
|
import promotionRoutes from './routes/promotion.js'
|
|
import { startScheduler } from './scheduler/index.js'
|
|
import { registerAllTaskHandlers } from './scheduler/task-handlers.js'
|
|
|
|
const app = express()
|
|
const PORT = parseInt(process.env.PORT || '3333')
|
|
|
|
app.use(cors({
|
|
origin: process.env.CLIENT_URL || true,
|
|
credentials: true,
|
|
}))
|
|
app.use(express.json())
|
|
|
|
app.get('/api/health', (req, res) => {
|
|
res.json({ success: true, data: { status: 'ok', time: new Date().toISOString() } })
|
|
})
|
|
|
|
app.use('/api/auth', authRoutes)
|
|
|
|
// admin login 不需要 auth 中间件
|
|
app.post('/api/admin/login', (req, res, next) => {
|
|
req.url = '/login'
|
|
adminRoutes(req, res, next)
|
|
})
|
|
|
|
app.use((req, res, next) => {
|
|
if (req.path === '/api/health' || req.path.startsWith('/api/auth')) {
|
|
return next()
|
|
}
|
|
authMiddleware(req as AuthRequest, res, next)
|
|
})
|
|
|
|
app.use('/api/admin', adminRoutes)
|
|
|
|
// 租户数据隔离中间件:根据 JWT 中的 tenantId 动态切换数据库连接池
|
|
app.use((req, res, next) => {
|
|
if (req.path.startsWith('/api/admin') || req.path === '/api/health' || req.path.startsWith('/api/auth')) {
|
|
return next()
|
|
}
|
|
tenantDbMiddleware(req as AuthRequest, res, next)
|
|
})
|
|
|
|
app.use('/api', dataRoutes)
|
|
app.use('/api/tasks', taskRoutes)
|
|
app.use('/api/cost-analysis', costAnalysisRoutes)
|
|
app.use('/api/store-expense', storeExpenseRoutes)
|
|
app.use('/api/smart-scheduling', smartSchedulingRoutes)
|
|
app.use('/api/situational-awareness', situationalAwarenessRoutes)
|
|
app.use('/api/analytics-enhanced', analyticsEnhancedRoutes)
|
|
app.use('/api/tts', ttsRoutes)
|
|
app.use('/api/target', targetRoutes)
|
|
app.use('/api/scheduler', schedulerRoutes)
|
|
app.use('/api/alert', alertRoutes)
|
|
app.use('/api/store-grade', storeGradeRoutes)
|
|
app.use('/api/product', productRoutes)
|
|
app.use('/api/enterprise', enterpriseRoutes)
|
|
app.use('/api/intelligence', intelligenceRoutes)
|
|
app.use('/api/promotion', promotionRoutes)
|
|
|
|
app.use(notFoundHandler)
|
|
app.use(errorHandler)
|
|
|
|
app.listen(PORT, () => {
|
|
console.log(`Server running on http://localhost:${PORT}`)
|
|
registerAllTaskHandlers()
|
|
startScheduler().catch(err => console.error('[Scheduler] Failed to start:', err))
|
|
})
|
|
|
|
export default app
|