138 lines
5.2 KiB
TypeScript
138 lines
5.2 KiB
TypeScript
import 'dotenv/config'
|
|
import path from 'path'
|
|
import express from 'express'
|
|
import cors from 'cors'
|
|
import session from 'express-session'
|
|
import equipmentRoutes from './routes/equipment'
|
|
import borrowRoutes, { returnRouter } from './routes/borrow'
|
|
import statisticsRoutes from './routes/statistics'
|
|
import authRoutes from './routes/auth'
|
|
import barcodeRoutes from './routes/barcode'
|
|
import settingsRoutes from './routes/settings'
|
|
import usersRoutes from './routes/users'
|
|
import personRoutes from './routes/persons'
|
|
import storageLocationRoutes from './routes/storageLocations'
|
|
import assetTypeRoutes from './routes/assetTypes'
|
|
import departmentRoutes from './routes/departments'
|
|
import operationLogRoutes from './routes/operationLog'
|
|
import batchImportRoutes from './routes/batchImport'
|
|
import mountRoutes from './routes/mount'
|
|
import disposalRoutes from './routes/disposal'
|
|
import maintenanceRoutes from './routes/maintenance'
|
|
import batchRoutes from './routes/batch'
|
|
import exportRoutes from './routes/export'
|
|
import searchRoutes from './routes/search'
|
|
import syncRoutes from './routes/sync'
|
|
import notificationRoutes from './routes/notifications'
|
|
import inventoryRoutes from './routes/inventory'
|
|
import publicInventoryRoutes from './routes/publicInventory'
|
|
import printTerminalRoutes from './routes/printTerminals'
|
|
import printJobRoutes from './routes/printJobs'
|
|
import printAgentRoutes from './routes/printAgent'
|
|
import printDownloadRoutes from './routes/printDownloads'
|
|
import myAssetRoutes from './routes/myAssets'
|
|
import dingtalkRoutes from './routes/dingtalk'
|
|
import { keycloak, memoryStore } from './utils/keycloak'
|
|
import { protect } from './middleware/auth'
|
|
import { startHrSyncScheduler } from './services/hrSyncService'
|
|
import { ensurePublicAssetPersonExists } from './services/systemReservedPersonService'
|
|
import { startDingTalkDeliveryWorker } from './services/dingtalkDeliveryService'
|
|
import { isCorsOriginAllowed } from './utils/corsPolicy'
|
|
import { unsafeOriginGuard } from './middleware/originGuard'
|
|
import { assertSupportedAuthMode, resolveSessionSecret } from './utils/authMode'
|
|
|
|
const app = express()
|
|
const PORT = process.env.PORT || 3000
|
|
const AUTH_MODE = assertSupportedAuthMode()
|
|
const SESSION_SECRET = resolveSessionSecret()
|
|
const SESSION_COOKIE_SECURE = process.env.SESSION_COOKIE_SECURE === undefined
|
|
? process.env.NODE_ENV === 'production'
|
|
: process.env.SESSION_COOKIE_SECURE === 'true'
|
|
|
|
// Middleware
|
|
app.set('trust proxy', 1)
|
|
app.use(cors({
|
|
origin: (origin, callback) => callback(null, isCorsOriginAllowed(origin) ? (origin || true) : false),
|
|
credentials: true
|
|
}))
|
|
app.use(unsafeOriginGuard)
|
|
app.use(express.json({ limit: '50mb' }))
|
|
app.use(express.urlencoded({ extended: true, limit: '50mb' }))
|
|
app.use(
|
|
session({
|
|
secret: SESSION_SECRET,
|
|
resave: false,
|
|
saveUninitialized: false,
|
|
store: memoryStore,
|
|
cookie: {
|
|
secure: SESSION_COOKIE_SECURE,
|
|
httpOnly: true,
|
|
sameSite: 'lax',
|
|
maxAge: 1000 * 60 * 60 // 1 hour
|
|
}
|
|
})
|
|
)
|
|
if (AUTH_MODE === 'keycloak') {
|
|
app.use(keycloak.middleware({ logout: '/api/auth/logout', admin: '/keycloak' }))
|
|
}
|
|
|
|
app.use('/uploads', express.static(path.resolve(__dirname, '..', 'uploads')))
|
|
|
|
// Routes
|
|
app.use('/api/equipment', protect(), equipmentRoutes)
|
|
app.use('/api/borrow', protect(), borrowRoutes)
|
|
app.use('/api/return', protect(), returnRouter)
|
|
app.use('/api/statistics', protect(), statisticsRoutes)
|
|
app.use('/api/barcode', protect(), barcodeRoutes)
|
|
app.use('/api/auth', authRoutes)
|
|
app.use('/api/settings', settingsRoutes)
|
|
app.use('/api/users', protect(), usersRoutes)
|
|
app.use('/api/persons', personRoutes)
|
|
app.use('/api/storage-locations', storageLocationRoutes)
|
|
app.use('/api/asset-types', assetTypeRoutes)
|
|
app.use('/api/departments', departmentRoutes)
|
|
app.use('/api/operation-logs', operationLogRoutes)
|
|
app.use('/api/batch-import', batchImportRoutes)
|
|
app.use('/api/mount', mountRoutes)
|
|
app.use('/api/disposal', disposalRoutes)
|
|
app.use('/api/maintenance', maintenanceRoutes)
|
|
app.use('/api/batch', protect(), batchRoutes)
|
|
app.use('/api/export', protect(), exportRoutes)
|
|
app.use('/api/search', protect(), searchRoutes)
|
|
app.use('/api/sync', syncRoutes)
|
|
app.use('/api/notifications', notificationRoutes)
|
|
app.use('/api/inventory', inventoryRoutes)
|
|
app.use('/api/public/inventory', publicInventoryRoutes)
|
|
app.use('/api/print-terminals', protect(), printTerminalRoutes)
|
|
app.use('/api/print-jobs', protect(), printJobRoutes)
|
|
app.use('/api/print-agent', printAgentRoutes)
|
|
app.use('/api/my-assets', myAssetRoutes)
|
|
app.use('/api/dingtalk', dingtalkRoutes)
|
|
app.use('/downloads', printDownloadRoutes)
|
|
|
|
// Health check
|
|
app.get('/api/health', (req, res) => {
|
|
res.json({ status: 'ok', message: 'Server is running' })
|
|
})
|
|
|
|
// Error handling middleware
|
|
app.use((err: any, req: express.Request, res: express.Response, next: express.NextFunction) => {
|
|
console.error('Error:', err)
|
|
res.status(err.status || 500).json({
|
|
code: err.status || 500,
|
|
message: err.message || 'Internal Server Error',
|
|
data: null
|
|
})
|
|
})
|
|
|
|
app.listen(PORT, () => {
|
|
console.log(`Server is running on http://localhost:${PORT}`)
|
|
})
|
|
|
|
ensurePublicAssetPersonExists().catch((error) => {
|
|
console.error('初始化系统保留人员失败:', error)
|
|
})
|
|
|
|
startHrSyncScheduler()
|
|
startDingTalkDeliveryWorker()
|