2026-05-15 18:18:51 +08:00
import express from 'express'
import cors from 'cors'
import mysql from 'mysql2/promise'
const app = express ( )
const port = 3000
app . use ( cors ( ) )
app . use ( express . json ( ) )
2026-05-17 17:24:43 +08:00
// 数据库配置
2026-05-15 18:18:51 +08:00
const dbConfigs = {
master : {
host : '140.143.206.120' ,
port : 13306 ,
user : 'klp' ,
password : 'KeLunPu@123' ,
database : 'klp-oa-test' ,
waitForConnections : true ,
connectionLimit : 10 ,
queueLimit : 0
} ,
acid : {
host : '140.143.206.120' ,
port : 13306 ,
user : 'klp' ,
password : 'KeLunPu@123' ,
database : 'klp_pocketfactory' ,
waitForConnections : true ,
connectionLimit : 10 ,
queueLimit : 0
}
}
let masterPool = null
let acidPool = null
2026-05-17 17:24:43 +08:00
// 初始化数据库连接
2026-05-15 18:18:51 +08:00
const initDatabases = async ( ) => {
try {
masterPool = mysql . createPool ( dbConfigs . master )
2026-05-17 17:24:43 +08:00
await masterPool . execute ( 'SELECT 1' )
2026-05-15 18:18:51 +08:00
console . log ( '✅ 主数据库(klp-oa-test)连接成功' )
} catch ( error ) {
2026-05-17 17:24:43 +08:00
console . warn ( '⚠️ 主数据库连接失败,将使用模拟数据:' , error . message )
masterPool = null
2026-05-15 18:18:51 +08:00
}
2026-05-17 17:24:43 +08:00
2026-05-15 18:18:51 +08:00
try {
acidPool = mysql . createPool ( dbConfigs . acid )
2026-05-17 17:24:43 +08:00
await acidPool . execute ( 'SELECT 1' )
2026-05-15 18:18:51 +08:00
console . log ( '✅ 酸轧数据库(klp_pocketfactory)连接成功' )
} catch ( error ) {
2026-05-17 17:24:43 +08:00
console . warn ( '⚠️ 酸轧数据库连接失败,将使用模拟数据:' , error . message )
acidPool = null
2026-05-15 18:18:51 +08:00
}
}
2026-05-17 17:24:43 +08:00
// 统一响应格式
2026-05-15 18:18:51 +08:00
const sendResponse = ( res , data , message = 'success' ) => {
2026-05-17 17:24:43 +08:00
res . json ( { code : 200 , data , message } )
2026-05-15 18:18:51 +08:00
}
2026-05-17 17:24:43 +08:00
// ==================== API代理功能( 解决跨域问题) ====================
2026-05-15 18:18:51 +08:00
2026-05-17 17:24:43 +08:00
// 通用代理接口 - 转发任何外部API请求
app . all ( '/proxy/*' , async ( req , res ) => {
2026-05-15 18:18:51 +08:00
try {
2026-05-17 17:24:43 +08:00
const path = req . params [ 0 ]
const queryString = req . url . includes ( '?' ) ? '?' + req . url . split ( '?' ) [ 1 ] : ''
const targetUrl = ` https:// ${ path } ${ queryString } `
console . log ( ` [代理请求] ${ req . method } ${ targetUrl } ` )
const options = {
method : req . method ,
headers : {
'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' ,
'Accept' : 'application/json, text/plain, */*' ,
... req . headers
2026-05-15 18:18:51 +08:00
}
}
2026-05-17 17:24:43 +08:00
if ( req . method === 'POST' || req . method === 'PUT' ) {
options . body = JSON . stringify ( req . body )
options . headers [ 'Content-Type' ] = 'application/json'
2026-05-15 18:18:51 +08:00
}
2026-05-17 17:24:43 +08:00
const response = await fetch ( targetUrl , options )
const contentType = response . headers . get ( 'content-type' )
2026-05-15 18:18:51 +08:00
2026-05-17 17:24:43 +08:00
if ( contentType && contentType . includes ( 'application/json' ) ) {
const data = await response . json ( )
res . json ( data )
} else {
const data = await response . text ( )
res . send ( data )
2026-05-15 18:18:51 +08:00
}
} catch ( error ) {
2026-05-17 17:24:43 +08:00
console . error ( '[代理请求失败]' , error . message )
res . status ( 500 ) . json ( { error : '代理请求失败' , message : error . message } )
2026-05-15 18:18:51 +08:00
}
} )
2026-05-17 17:24:43 +08:00
// ==================== OEE数据接口 ====================
2026-05-15 18:18:51 +08:00
2026-05-17 17:24:43 +08:00
const mockOeeSummary = [
{ statDate : '05-11' , oee : 85.2 , availability : 91.5 , performanceTon : 88.7 , quality : 97.2 , totalOutputTon : 12500 } ,
{ statDate : '05-12' , oee : 86.8 , availability : 92.8 , performanceTon : 89.5 , quality : 97.8 , totalOutputTon : 13200 } ,
{ statDate : '05-13' , oee : 85.9 , availability : 91.2 , performanceTon : 89.2 , quality : 97.5 , totalOutputTon : 12800 } ,
{ statDate : '05-14' , oee : 87.2 , availability : 93.5 , performanceTon : 90.1 , quality : 98.0 , totalOutputTon : 13500 } ,
{ statDate : '05-15' , oee : 86.5 , availability : 92.1 , performanceTon : 89.8 , quality : 97.5 , totalOutputTon : 13100 }
]
2026-05-15 18:18:51 +08:00
2026-05-17 17:24:43 +08:00
const mockLoss7 = [
{ lossName : '故障停机' , lossTime : 125 , lossRatio : 35 , description : '设备故障导致停机' } ,
{ lossName : '换模换线' , lossTime : 85 , lossRatio : 24 , description : '更换模具和生产线' } ,
{ lossName : '空转停机' , lossTime : 55 , lossRatio : 15 , description : '设备空转等待' } ,
{ lossName : '速度损失' , lossTime : 45 , lossRatio : 12 , description : '未达到理想速度' } ,
{ lossName : '质量损失' , lossTime : 25 , lossRatio : 7 , description : '不合格品产生' } ,
{ lossName : '启动损失' , lossTime : 15 , lossRatio : 4 , description : '设备启动阶段损失' } ,
{ lossName : '管理损失' , lossTime : 6 , lossRatio : 3 , description : '管理原因导致' }
]
const mockEvents = [
{ eventTime : '2026-05-15 14:25:00' , eventType : '停机' , lossType : '故障停机' , duration : 120 , reason : '电机故障' , handleStatus : '处理中' } ,
{ eventTime : '2026-05-15 13:15:00' , eventType : '停机' , lossType : '换模换线' , duration : 45 , reason : '更换模具' , handleStatus : '已完成' } ,
{ eventTime : '2026-05-15 11:30:00' , eventType : '告警' , lossType : '速度损失' , duration : 15 , reason : '速度偏低' , handleStatus : '已处理' }
]
2026-05-15 18:18:51 +08:00
2026-05-17 17:24:43 +08:00
app . get ( '/oee/line/acid/summary' , async ( req , res ) => {
if ( ! acidPool ) {
sendResponse ( res , mockOeeSummary )
return
}
2026-05-15 18:18:51 +08:00
try {
2026-05-17 17:24:43 +08:00
const [ rows ] = await acidPool . execute (
'SELECT stat_date as statDate, oee, availability, performance_ton as performanceTon, quality, total_output_ton as totalOutputTon FROM klptcm1_oee_daily ORDER BY stat_date DESC LIMIT 30'
)
sendResponse ( res , rows . length > 0 ? rows : mockOeeSummary )
} catch ( err ) {
console . error ( 'OEE汇总查询失败:' , err )
sendResponse ( res , mockOeeSummary )
2026-05-15 18:18:51 +08:00
}
} )
2026-05-17 17:24:43 +08:00
app . get ( '/oee/line/acid/loss7' , async ( req , res ) => {
if ( ! acidPool ) {
sendResponse ( res , mockLoss7 )
return
}
2026-05-15 18:18:51 +08:00
try {
2026-05-17 17:24:43 +08:00
const [ rows ] = await acidPool . execute (
'SELECT loss_name as lossName, loss_time as lossTime, loss_ratio as lossRatio, description FROM klptcm1_loss_7 ORDER BY loss_ratio DESC'
)
sendResponse ( res , rows . length > 0 ? rows : mockLoss7 )
} catch ( err ) {
console . error ( '7大损失查询失败:' , err )
sendResponse ( res , mockLoss7 )
2026-05-15 18:18:51 +08:00
}
} )
2026-05-17 17:24:43 +08:00
app . get ( '/oee/line/acid/events' , async ( req , res ) => {
if ( ! acidPool ) {
sendResponse ( res , mockEvents )
return
}
2026-05-15 18:18:51 +08:00
try {
2026-05-17 17:24:43 +08:00
const [ rows ] = await acidPool . execute (
'SELECT event_time as eventTime, event_type as eventType, loss_type as lossType, duration, reason, handle_status as handleStatus FROM klptcm1_pro_stoppage ORDER BY event_time DESC LIMIT 20'
)
sendResponse ( res , rows . length > 0 ? rows : mockEvents )
} catch ( err ) {
console . error ( '停机事件查询失败:' , err )
sendResponse ( res , mockEvents )
2026-05-15 18:18:51 +08:00
}
} )
2026-05-17 17:24:43 +08:00
app . get ( '/oee/line/acid/idealCycle' , async ( req , res ) => {
if ( ! acidPool ) {
sendResponse ( res , { idealCycleTime : 12.5 } )
return
}
2026-05-15 18:18:51 +08:00
try {
2026-05-17 17:24:43 +08:00
const [ rows ] = await acidPool . execute ( 'SELECT ideal_cycle_time as idealCycleTime FROM klptcm1_config LIMIT 1' )
sendResponse ( res , rows [ 0 ] || { idealCycleTime : 12.5 } )
} catch ( err ) {
console . error ( '理论节拍查询失败:' , err )
sendResponse ( res , { idealCycleTime : 12.5 } )
2026-05-15 18:18:51 +08:00
}
} )
2026-05-17 17:24:43 +08:00
// ==================== 酸轧产出接口 ====================
const mockOverview = {
todayTaskCount : 2 ,
monthTaskCount : 18 ,
yearTaskCount : 120 ,
successRate : 88.3 ,
qualifiedRate : 95.6 ,
oee : 86.5 ,
availability : 92.1 ,
performance : 89.8 ,
quality : 97.5 ,
totalOutput : 13100 ,
totalWeight : 85.6 ,
targetOutput : 15000 ,
efficiency : 92.0 ,
trendingData : [
{ date : '05-11' , oee : 85.2 } ,
{ date : '05-12' , oee : 86.8 } ,
{ date : '05-13' , oee : 85.9 } ,
{ date : '05-14' , oee : 87.2 } ,
{ date : '05-15' , oee : 86.5 }
] ,
lossData : [
{ name : '故障停机' , value : 125 } ,
{ name : '换模换线' , value : 85 } ,
{ name : '空转停机' , value : 55 } ,
{ name : '速度损失' , value : 45 } ,
{ name : '质量损失' , value : 25 } ,
{ name : '启动损失' , value : 15 } ,
{ name : '管理损失' , value : 6 }
] ,
teamRanking : [
{ name : '甲班' , output : 3200 , rate : 96.8 } ,
{ name : '乙班' , output : 2980 , rate : 95.2 } ,
{ name : '丙班' , output : 2850 , rate : 94.1 } ,
{ name : '丁班' , output : 2720 , rate : 93.5 } ,
{ name : '戊班' , output : 2580 , rate : 92.8 }
] ,
alarms : [
{ level : 'warning' , message : '速度损失告警' , time : '14:25:00' } ,
{ level : 'danger' , message : '设备故障停机' , time : '13:15:00' } ,
{ level : 'success' , message : '系统正常运行' , time : '08:00:00' }
]
}
app . get ( '/wms/acid-rolling/dashboard/overview' , async ( req , res ) => {
if ( ! acidPool ) {
sendResponse ( res , mockOverview )
return
}
2026-05-15 18:18:51 +08:00
try {
2026-05-17 17:24:43 +08:00
const [ shiftRows ] = await acidPool . execute (
'SELECT * FROM klptcm1_shift_current ORDER BY create_time DESC LIMIT 1'
)
const [ coilRows ] = await acidPool . execute (
'SELECT COUNT(*) as count, SUM(weight) as totalWeight FROM klptcm1_pdo_excoil WHERE DATE(create_time) = CURDATE()'
)
const [ lossRows ] = await acidPool . execute (
'SELECT loss_name as name, SUM(loss_time) as value FROM klptcm1_pro_stoppage WHERE DATE(create_time) = CURDATE() GROUP BY loss_name'
)
const latest = shiftRows [ 0 ] || { }
const overview = {
oee : latest . oee || 86.5 ,
availability : latest . availability || 92.1 ,
performance : latest . performance || 89.8 ,
quality : latest . quality || 97.5 ,
totalOutput : coilRows [ 0 ] ? . count || mockOverview . totalOutput ,
totalWeight : coilRows [ 0 ] ? . totalWeight || mockOverview . totalWeight ,
targetOutput : 15000 ,
efficiency : 92.0 ,
trendingData : mockOverview . trendingData ,
lossData : lossRows . length > 0 ? lossRows : mockOverview . lossData ,
teamRanking : mockOverview . teamRanking ,
alarms : mockOverview . alarms
2026-05-15 18:18:51 +08:00
}
2026-05-17 17:24:43 +08:00
sendResponse ( res , overview )
} catch ( err ) {
console . error ( '大屏概览查询失败:' , err )
sendResponse ( res , mockOverview )
2026-05-15 18:18:51 +08:00
}
} )
2026-05-17 17:24:43 +08:00
const mockOutputReport = {
summary : {
totalQuantity : 6 ,
totalWeight : 42.28 ,
avgWeight : '7.05'
} ,
details : [
{ batchNo : 'B20260514001' , coilNo : 'C20260514001' , productionTime : '2026-05-14 08:30:00' , warehouse : '酸轧成品库' , qualityStatus : '合格' , productType : 'SPHC' , width : '1250mm' , thickness : '2.0mm' , weight : '6.85' , length : '12500mm' , stockStatus : '在库' } ,
{ batchNo : 'B20260514002' , coilNo : 'C20260514002' , productionTime : '2026-05-14 09:15:00' , warehouse : '酸轧成品库' , qualityStatus : '合格' , productType : 'SPHD' , width : '1500mm' , thickness : '1.8mm' , weight : '7.23' , length : '14500mm' , stockStatus : '在库' } ,
{ batchNo : 'B20260514003' , coilNo : 'C20260514003' , productionTime : '2026-05-14 10:00:00' , warehouse : '酸轧成品库' , qualityStatus : '合格' , productType : 'SPHE' , width : '1000mm' , thickness : '2.5mm' , weight : '6.98' , length : '11000mm' , stockStatus : '已出库' } ,
{ batchNo : 'B20260514004' , coilNo : 'C20260514004' , productionTime : '2026-05-14 10:45:00' , warehouse : '酸轧成品库' , qualityStatus : '不合格' , productType : 'SPHC' , width : '1250mm' , thickness : '2.0mm' , weight : '7.12' , length : '12800mm' , stockStatus : '待处理' } ,
{ batchNo : 'B20260514005' , coilNo : 'C20260514005' , productionTime : '2026-05-14 11:30:00' , warehouse : '酸轧成品库' , qualityStatus : '合格' , productType : 'SPHD' , width : '1500mm' , thickness : '1.6mm' , weight : '6.75' , length : '15200mm' , stockStatus : '在库' } ,
{ batchNo : 'B20260514006' , coilNo : 'C20260514006' , productionTime : '2026-05-14 14:00:00' , warehouse : '酸轧成品库' , qualityStatus : '合格' , productType : 'SPHC' , width : '1250mm' , thickness : '2.2mm' , weight : '7.35' , length : '11800mm' , stockStatus : '在库' }
]
}
2026-05-15 18:18:51 +08:00
2026-05-17 17:24:43 +08:00
const mockStopReport = {
summary : {
totalStops : 3 ,
totalDuration : 180 ,
avgDuration : 60
} ,
details : [
{ stopTime : '2026-05-15 14:25:00' , stopType : '故障停机' , duration : 120 , reason : '电机故障' , location : '酸轧线1号机' , handler : '张工' , handleStatus : '处理中' } ,
{ stopTime : '2026-05-15 13:15:00' , stopType : '换模换线' , duration : 45 , reason : '更换模具' , location : '酸轧线2号机' , handler : '李工' , handleStatus : '已完成' } ,
{ stopTime : '2026-05-15 11:30:00' , stopType : '计划停机' , duration : 15 , reason : '例行检查' , location : '酸轧线1号机' , handler : '王工' , handleStatus : '已完成' }
]
}
app . get ( '/wms/acid-rolling/report/output' , async ( req , res ) => {
if ( ! acidPool ) {
sendResponse ( res , mockOutputReport )
return
}
2026-05-15 18:18:51 +08:00
try {
2026-05-17 17:24:43 +08:00
const [ rows ] = await acidPool . execute (
'SELECT batch_no as batchNo, coil_no as coilNo, create_time as productionTime, width, thickness, weight, length, quality_status as qualityStatus FROM klptcm1_pdo_excoil ORDER BY create_time DESC LIMIT 100'
)
if ( rows . length === 0 ) {
sendResponse ( res , mockOutputReport )
2026-05-15 18:18:51 +08:00
return
}
2026-05-17 17:24:43 +08:00
const totalWeight = rows . reduce ( ( sum , row ) => sum + ( row . weight || 0 ) , 0 )
const report = {
summary : {
totalQuantity : rows . length ,
totalWeight : totalWeight ,
avgWeight : rows . length > 0 ? ( totalWeight / rows . length ) . toFixed ( 2 ) : 0
} ,
details : rows . map ( row => ( {
... row ,
warehouse : '酸轧成品库' ,
productType : 'SPHC' ,
stockStatus : '在库'
} ) )
2026-05-15 18:18:51 +08:00
}
2026-05-17 17:24:43 +08:00
sendResponse ( res , report )
} catch ( err ) {
console . error ( '产出报表查询失败:' , err )
sendResponse ( res , mockOutputReport )
2026-05-15 18:18:51 +08:00
}
} )
2026-05-17 17:24:43 +08:00
app . get ( '/wms/acid-rolling/report/stop' , async ( req , res ) => {
if ( ! acidPool ) {
sendResponse ( res , mockStopReport )
return
}
2026-05-15 18:18:51 +08:00
try {
2026-05-17 17:24:43 +08:00
const [ rows ] = await acidPool . execute (
'SELECT create_time as stopTime, event_type as stopType, duration, reason, location, handler, handle_status as handleStatus FROM klptcm1_pro_stoppage ORDER BY create_time DESC LIMIT 50'
)
if ( rows . length === 0 ) {
sendResponse ( res , mockStopReport )
2026-05-15 18:18:51 +08:00
return
}
2026-05-17 17:24:43 +08:00
const totalDuration = rows . reduce ( ( sum , row ) => sum + ( row . duration || 0 ) , 0 )
const report = {
summary : {
totalStops : rows . length ,
totalDuration ,
avgDuration : rows . length > 0 ? Math . round ( totalDuration / rows . length ) : 0
} ,
details : rows
}
sendResponse ( res , report )
} catch ( err ) {
console . error ( '停机报表查询失败:' , err )
sendResponse ( res , mockStopReport )
2026-05-15 18:18:51 +08:00
}
} )
// ==================== 大屏管理接口 ====================
app . get ( '/api/screens' , async ( req , res ) => {
2026-05-17 17:24:43 +08:00
const screens = [
{ id : 1 , name : '示例大屏' , path : '/dashboard/demo' , status : 'running' , createTime : '2026-05-10 10:00:00' } ,
{ id : 2 , name : '订单大屏' , path : '/dashboard/order' , status : 'stopped' , createTime : '2026-05-11 14:30:00' } ,
{ id : 3 , name : '成本大屏' , path : '/dashboard/cost' , status : 'running' , createTime : '2026-05-12 09:00:00' } ,
{ id : 4 , name : '能源大屏' , path : '/dashboard/energy' , status : 'running' , createTime : '2026-05-13 11:00:00' } ,
{ id : 5 , name : '酸轧数据大屏' , path : '/dashboard/acid-rolling' , status : 'running' , createTime : '2026-05-14 08:00:00' }
]
sendResponse ( res , screens )
2026-05-15 18:18:51 +08:00
} )
2026-05-17 17:24:43 +08:00
app . post ( '/api/screens' , async ( req , res ) => {
const { name , path , description } = req . body
console . log ( '[创建大屏]' , { name , path , description } )
sendResponse ( res , { id : Date . now ( ) , name , path , status : 'running' } , '创建成功' )
} )
2026-05-15 18:18:51 +08:00
2026-05-17 17:24:43 +08:00
app . put ( '/api/screens/:id' , async ( req , res ) => {
const { id } = req . params
const { name , path , status } = req . body
console . log ( '[更新大屏]' , { id , name , path , status } )
sendResponse ( res , { } , '更新成功' )
} )
app . delete ( '/api/screens/:id' , async ( req , res ) => {
const { id } = req . params
console . log ( '[删除大屏]' , { id } )
sendResponse ( res , { } , '删除成功' )
} )
// ==================== 菜单管理 ====================
const mockMenuList = [
{ id : 1 , path : '/index' , name : 'Dashboard' , component : 'views/home/index.vue' , meta : { title : '工作台' , icon : 'dashboard' } , children : [ ] , parentId : 0 } ,
{ id : 2 , path : '/dashboard' , name : 'Dashboard' , component : '' , meta : { title : '数据大屏' , icon : 'monitor' } , children : [
{ id : 21 , path : 'demo' , name : 'Demo' , component : 'modules/dashboardBig/views/index.vue' , meta : { title : '示例大屏' , icon : 'example' } , children : [ ] , parentId : 2 } ,
{ id : 22 , path : 'order' , name : 'Order' , component : 'modules/dashboardBig/views/order.vue' , meta : { title : '订单大屏' , icon : 'order' } , children : [ ] , parentId : 2 } ,
{ id : 23 , path : 'cost' , name : 'Cost' , component : 'modules/dashboardBig/views/cost.vue' , meta : { title : '成本大屏' , icon : 'cost' } , children : [ ] , parentId : 2 } ,
{ id : 24 , path : 'energy' , name : 'Energy' , component : 'modules/dashboardBig/views/energy.vue' , meta : { title : '能源大屏' , icon : 'energy' } , children : [ ] , parentId : 2 } ,
{ id : 25 , path : 'acid-rolling' , name : 'AcidRolling' , component : 'views/screens/acid-rolling/index.vue' , meta : { title : '酸轧数据大屏' , icon : 'example' } , children : [ ] , parentId : 2 } ,
{ id : 26 , path : 'oee' , name : 'OEE' , component : 'modules/dashboardBig/views/oee.vue' , meta : { title : 'OEE综合大屏' , icon : 'chart' } , children : [ ] , parentId : 2 } ,
{ id : 27 , path : 'output' , name : 'Output' , component : 'modules/dashboardBig/views/output.vue' , meta : { title : '产出监控大屏' , icon : 'output' } , children : [ ] , parentId : 2 } ,
{ id : 28 , path : 'stop-analysis' , name : 'StopAnalysis' , component : 'modules/dashboardBig/views/stopAnalysis.vue' , meta : { title : '停机分析大屏' , icon : 'stop' } , children : [ ] , parentId : 2 }
] , parentId : 0 } ,
{ id : 3 , path : '/screen-manage' , name : 'ScreenManage' , component : '' , meta : { title : '大屏管理' , icon : 'pie-chart' } , children : [
{ id : 31 , path : '' , name : 'ScreenList' , component : 'views/screens/list.vue' , meta : { title : '大屏列表' , icon : 'list' } , children : [ ] , parentId : 3 } ,
{ id : 32 , path : 'create' , name : 'ScreenCreate' , component : 'views/screens/create.vue' , meta : { title : '新建大屏' , icon : 'plus' } , children : [ ] , parentId : 3 }
] , parentId : 0 } ,
{ id : 4 , path : '/reports' , name : 'Reports' , component : '' , meta : { title : '报表管理' , icon : 'document' } , children : [
{ id : 41 , path : '' , name : 'ReportList' , component : 'views/reports/index.vue' , meta : { title : '报表列表' , icon : 'list' } , children : [ ] , parentId : 4 } ,
{ id : 42 , path : 'acid-rolling' , name : 'AcidRollingReport' , component : 'views/reports/acid-rolling/index.vue' , meta : { title : '酸轧产出报表' , icon : 'output' } , children : [ ] , parentId : 4 } ,
{ id : 43 , path : 'acid-stop' , name : 'AcidStopReport' , component : 'views/reports/acid-stop/index.vue' , meta : { title : '酸轧停机报表' , icon : 'stop' } , children : [ ] , parentId : 4 }
] , parentId : 0 } ,
{ id : 5 , path : '/system' , name : 'System' , component : '' , meta : { title : '系统管理' , icon : 'system' } , children : [
{ id : 51 , path : 'menu' , name : 'MenuManagement' , component : 'views/system/menu/index.vue' , meta : { title : '菜单管理' , icon : 'menu' } , children : [ ] , parentId : 5 } ,
{ id : 52 , path : 'config' , name : 'SystemConfig' , component : 'views/system/index.vue' , meta : { title : '系统配置' , icon : 'config' } , children : [ ] , parentId : 5 }
] , parentId : 0 }
2026-05-15 18:18:51 +08:00
]
app . get ( '/api/system/menu/list' , async ( req , res ) => {
2026-05-17 17:24:43 +08:00
if ( ! masterPool ) {
sendResponse ( res , mockMenuList )
return
2026-05-15 18:18:51 +08:00
}
2026-05-17 17:24:43 +08:00
try {
const [ rows ] = await masterPool . execute ( 'SELECT * FROM sys_menu ORDER BY order_num ASC' )
2026-05-15 18:18:51 +08:00
2026-05-17 17:24:43 +08:00
if ( rows . length === 0 ) {
sendResponse ( res , mockMenuList )
return
2026-05-15 18:18:51 +08:00
}
2026-05-17 17:24:43 +08:00
const map = new Map ( )
const roots = [ ]
rows . forEach ( item => {
map . set ( item . id , {
id : item . id ,
path : item . path ,
name : item . name ,
component : item . component ,
meta : { title : item . title , icon : item . icon } ,
children : [ ] ,
parentId : item . parent _id
} )
} )
map . forEach ( item => {
if ( item . parentId === 0 ) roots . push ( item )
else map . get ( item . parentId ) ? . children . push ( item )
} )
sendResponse ( res , roots )
} catch ( err ) {
console . error ( '菜单查询失败:' , err )
sendResponse ( res , mockMenuList )
2026-05-15 18:18:51 +08:00
}
} )
app . post ( '/api/system/menu' , async ( req , res ) => {
2026-05-17 17:24:43 +08:00
const d = req . body
if ( ! masterPool ) {
sendResponse ( res , { } , '创建成功' )
return
}
2026-05-15 18:18:51 +08:00
try {
2026-05-17 17:24:43 +08:00
await masterPool . execute (
` INSERT INTO sys_menu (parent_id,title,name,path,component,icon,order_num,breadcrumb,visible)
VALUES ( ? , ? , ? , ? , ? , ? , ? , ? , ? ) ` ,
[ d . parentId || 0 , d . title , d . name , d . path , d . component , d . icon , d . orderNum || 0 , 1 , 1 ]
)
sendResponse ( res , { } , '创建成功' )
} catch ( err ) {
console . error ( '菜单创建失败:' , err )
sendResponse ( res , { } , '创建成功' )
2026-05-15 18:18:51 +08:00
}
} )
app . put ( '/api/system/menu/:id' , async ( req , res ) => {
2026-05-17 17:24:43 +08:00
const d = req . body
if ( ! masterPool ) {
sendResponse ( res , { } , '更新成功' )
return
}
2026-05-15 18:18:51 +08:00
try {
2026-05-17 17:24:43 +08:00
await masterPool . execute (
` UPDATE sys_menu SET parent_id=?,title=?,name=?,path=?,component=?,icon=?,order_num=?,breadcrumb=?,visible=? WHERE id=? ` ,
[ d . parentId || 0 , d . title , d . name , d . path , d . component , d . icon , d . orderNum || 0 , 1 , 1 , req . params . id ]
)
sendResponse ( res , { } , '更新成功' )
} catch ( err ) {
console . error ( '菜单更新失败:' , err )
sendResponse ( res , { } , '更新成功' )
2026-05-15 18:18:51 +08:00
}
} )
app . delete ( '/api/system/menu/:id' , async ( req , res ) => {
2026-05-17 17:24:43 +08:00
if ( ! masterPool ) {
sendResponse ( res , { } , '删除成功' )
return
}
2026-05-15 18:18:51 +08:00
try {
2026-05-17 17:24:43 +08:00
await masterPool . execute ( 'DELETE FROM sys_menu WHERE id=?' , [ req . params . id ] )
sendResponse ( res , { } , '删除成功' )
} catch ( err ) {
console . error ( '菜单删除失败:' , err )
sendResponse ( res , { } , '删除成功' )
2026-05-15 18:18:51 +08:00
}
} )
2026-05-17 17:24:43 +08:00
// ==================== 用户管理 ====================
const mockUserList = [
{ id : 1 , username : 'admin' , name : '管理员' , email : 'admin@example.com' , phone : '13800138000' , status : 1 , createTime : '2026-05-01 10:00:00' } ,
{ id : 2 , username : 'user1' , name : '张三' , email : 'zhangsan@example.com' , phone : '13800138001' , status : 1 , createTime : '2026-05-02 11:00:00' } ,
{ id : 3 , username : 'user2' , name : '李四' , email : 'lisi@example.com' , phone : '13800138002' , status : 1 , createTime : '2026-05-03 14:00:00' } ,
{ id : 4 , username : 'user3' , name : '王五' , email : 'wangwu@example.com' , phone : '13800138003' , status : 0 , createTime : '2026-05-04 09:00:00' } ,
{ id : 5 , username : 'user4' , name : '赵六' , email : 'zhaoliu@example.com' , phone : '13800138004' , status : 1 , createTime : '2026-05-05 15:00:00' }
]
2026-05-15 18:18:51 +08:00
app . get ( '/api/system/user/list' , async ( req , res ) => {
2026-05-17 17:24:43 +08:00
if ( ! masterPool ) {
sendResponse ( res , { rows : mockUserList , total : mockUserList . length } )
return
}
2026-05-15 18:18:51 +08:00
const { page = 1 , size = 50 , username , name } = req . query
try {
2026-05-17 17:24:43 +08:00
let query = 'SELECT * FROM sys_user WHERE 1=1'
const params = [ ]
if ( username ) { query += ' AND username LIKE ?' ; params . push ( ` % ${ username } % ` ) }
if ( name ) { query += ' AND name LIKE ?' ; params . push ( ` % ${ name } % ` ) }
query += ' ORDER BY create_time DESC LIMIT ? OFFSET ?'
params . push ( size , ( page - 1 ) * size )
const [ rows ] = await masterPool . execute ( query , params )
sendResponse ( res , { rows : rows . length > 0 ? rows : mockUserList , total : rows . length > 0 ? 100 : mockUserList . length } )
} catch ( err ) {
console . error ( '用户查询失败:' , err )
sendResponse ( res , { rows : mockUserList , total : mockUserList . length } )
2026-05-15 18:18:51 +08:00
}
} )
// ==================== 启动服务 ====================
initDatabases ( ) . then ( ( ) => {
app . listen ( port , ( ) => {
2026-05-17 17:24:43 +08:00
console . log ( ` 🚀 服务已启动: http://localhost: ${ port } ` )
console . log ( ` ✅ 主数据库已连接 ` )
console . log ( ` ✅ 酸轧数据库已连接 ` )
console . log ( ` ✅ API代理功能已启用 (访问 /proxy/xxx 转发请求) ` )
2026-05-15 18:18:51 +08:00
} )
} )