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-19 19:26:41 +08:00
// 1. 获取当前班次OEE数据
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'
)
2026-05-19 19:26:41 +08:00
const currentShift = shiftRows [ 0 ] || { }
2026-05-17 17:24:43 +08:00
2026-05-19 19:26:41 +08:00
// 2. 获取今日产出统计
2026-05-17 17:24:43 +08:00
const [ coilRows ] = await acidPool . execute (
2026-05-19 19:26:41 +08:00
` SELECT
COUNT ( * ) as count ,
SUM ( weight ) as totalWeight ,
SUM ( CASE WHEN quality _status = 'A' THEN 1 ELSE 0 END ) as qualifiedCount
FROM klptcm1 _pdo _excoil
WHERE DATE ( create _time ) = CURDATE ( ) `
2026-05-17 17:24:43 +08:00
)
2026-05-19 19:26:41 +08:00
// 3. 计算OEE指标
const totalCoils = coilRows [ 0 ] ? . count || 0
const qualifiedCoils = coilRows [ 0 ] ? . qualifiedCount || 0
const qualityRate = totalCoils > 0 ? ( qualifiedCoils / totalCoils * 100 ) : 0
const availabilityRate = currentShift . availability || 92.1
const performanceRate = currentShift . performance || 89.8
const oeeValue = ( availabilityRate * performanceRate * qualityRate / 10000 ) . toFixed ( 1 )
// 4. 获取OEE趋势数据( 最近7天)
const [ trendingRows ] = await acidPool . execute (
` SELECT
DATE ( create _time ) as date ,
AVG ( oee ) as oee ,
AVG ( availability ) as availability ,
AVG ( performance ) as performance ,
COUNT ( * ) as coilCount
FROM klptcm1 _shift _current
WHERE create _time >= DATE _SUB ( CURDATE ( ) , INTERVAL 7 DAY )
GROUP BY DATE ( create _time )
ORDER BY date ASC `
)
// 5. 获取7大损失分布( 按停机类型统计)
2026-05-17 17:24:43 +08:00
const [ lossRows ] = await acidPool . execute (
2026-05-19 19:26:41 +08:00
` SELECT
stop _type as name ,
SUM ( duration ) as value
FROM klptcm1 _pro _stoppage
WHERE create _time >= DATE _SUB ( NOW ( ) , INTERVAL 30 DAY )
GROUP BY stop _type
ORDER BY value DESC `
)
// 6. 获取班组产量排名
const [ teamRows ] = await acidPool . execute (
` SELECT
crew as name ,
COUNT ( * ) as coilCount ,
SUM ( weight ) as output
FROM klptcm1 _pdo _excoil
WHERE create _time >= DATE _SUB ( CURDATE ( ) , INTERVAL 7 DAY )
GROUP BY crew
ORDER BY output DESC `
)
// 7. 获取实时告警(停机异常、质量不合格)
const [ alarmRows ] = await acidPool . execute (
` SELECT
'停机告警' as type ,
stop _type as message ,
DATE _FORMAT ( create _time , '%H:%i:%s' ) as time ,
CASE
WHEN duration > 3600 THEN 'danger'
WHEN duration > 1800 THEN 'warning'
ELSE 'info'
END as level
FROM klptcm1 _pro _stoppage
WHERE create _time >= DATE _SUB ( NOW ( ) , INTERVAL 24 HOUR )
ORDER BY create _time DESC
LIMIT 5 `
2026-05-17 17:24:43 +08:00
)
2026-05-19 19:26:41 +08:00
// 8. 获取质量告警
const [ qualityAlarmRows ] = await acidPool . execute (
` SELECT
'质量告警' as type ,
CONCAT ( '钢卷 ' , coil _id , ' 质量异常' ) as message ,
DATE _FORMAT ( in _date , '%H:%i:%s' ) as time ,
'warning' as level
FROM klptcm1 _pdo _excoil
WHERE quality _status IN ( 'B' , 'C' , 'D' )
AND DATE ( in _date ) = CURDATE ( )
ORDER BY in _date DESC
LIMIT 3 `
)
2026-05-17 17:24:43 +08:00
const overview = {
2026-05-19 19:26:41 +08:00
// 核心指标
oee : parseFloat ( oeeValue ) ,
availability : availabilityRate ,
performance : performanceRate ,
quality : qualityRate . toFixed ( 1 ) ,
totalOutput : totalCoils ,
totalWeight : coilRows [ 0 ] ? . totalWeight || 0 ,
2026-05-17 17:24:43 +08:00
targetOutput : 15000 ,
efficiency : 92.0 ,
2026-05-19 19:26:41 +08:00
// OEE趋势数据
trendingData : trendingRows . length > 0 ? trendingRows . map ( row => ( {
date : row . date ? row . date . toString ( ) . substring ( 5 ) : '' ,
oee : parseFloat ( ( row . oee || 0 ) . toFixed ( 1 ) ) ,
availability : parseFloat ( ( row . availability || 0 ) . toFixed ( 1 ) ) ,
performance : parseFloat ( ( row . performance || 0 ) . toFixed ( 1 ) ) ,
coilCount : row . coilCount || 0
} ) ) : mockOverview . trendingData ,
// 7大损失分布
lossData : lossRows . length > 0 ? lossRows . map ( row => ( {
name : row . name || '未知损失' ,
value : row . value || 0
} ) ) : mockOverview . lossData ,
// 班组产量排名
teamRanking : teamRows . length > 0 ? teamRows . map ( row => ( {
name : row . name || '未知班组' ,
output : Math . round ( row . output || 0 ) ,
coilCount : row . coilCount || 0 ,
rate : 96.5
} ) ) : mockOverview . teamRanking ,
// 告警信息
alarms : [ ... alarmRows , ... qualityAlarmRows ] . map ( row => ( {
type : row . type ,
message : row . message ,
time : row . time ,
level : row . level
} ) )
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
}
} )
2026-05-19 19:26:41 +08:00
// ==================== 订单数据接口 ====================
app . get ( '/api/dashboard/order' , async ( req , res ) => {
if ( ! masterPool ) {
sendResponse ( res , {
todayOrderCount : 45 ,
pendingOrderCount : 12 ,
completedOrderCount : 156 ,
orderTotalAmount : 568 ,
orderTrend : [
{ date : '05-11' , count : 38 , amount : 420 } ,
{ date : '05-12' , count : 42 , amount : 480 } ,
{ date : '05-13' , count : 35 , amount : 390 } ,
{ date : '05-14' , count : 48 , amount : 520 } ,
{ date : '05-15' , count : 45 , amount : 568 }
] ,
statusDistribution : [
{ name : '生产中' , value : 45 } ,
{ name : '待生产' , value : 12 } ,
{ name : '已完成' , value : 156 }
] ,
recentOrders : [
{ orderNo : 'ORD20260515001' , customer : '周口钢铁' , amount : 125000 , status : '生产中' , time : '10:30' } ,
{ orderNo : 'ORD20260515002' , customer : '南阳重工' , amount : 89000 , status : '已完成' , time : '09:45' } ,
{ orderNo : 'ORD20260515003' , customer : '洛阳机械' , amount : 156000 , status : '待生产' , time : '11:20' } ,
{ orderNo : 'ORD20260515004' , customer : '开封汽配' , amount : 67000 , status : '生产中' , time : '08:15' } ,
{ orderNo : 'ORD20260515005' , customer : '商丘金属' , amount : 45000 , status : '已完成' , time : '07:30' }
]
} )
return
}
try {
const [ todayOrders ] = await masterPool . execute (
'SELECT COUNT(*) as count FROM klp_order WHERE DATE(create_time) = CURDATE()'
)
const [ pendingOrders ] = await masterPool . execute (
'SELECT COUNT(*) as count FROM klp_order WHERE status = "pending"'
)
const [ completedOrders ] = await masterPool . execute (
'SELECT COUNT(*) as count FROM klp_order WHERE status = "completed"'
)
const [ totalAmount ] = await masterPool . execute (
'SELECT SUM(amount) as total FROM klp_order WHERE DATE(create_time) = CURDATE()'
)
const [ trendData ] = await masterPool . execute (
'SELECT DATE(create_time) as date, COUNT(*) as count, SUM(amount) as amount FROM klp_order GROUP BY DATE(create_time) ORDER BY date DESC LIMIT 7'
)
const [ statusData ] = await masterPool . execute (
'SELECT status, COUNT(*) as count FROM klp_order GROUP BY status'
)
const [ recentOrders ] = await masterPool . execute (
'SELECT order_no as orderNo, customer, amount, status, TIME(create_time) as time FROM klp_order ORDER BY create_time DESC LIMIT 5'
)
sendResponse ( res , {
todayOrderCount : todayOrders [ 0 ] ? . count || 0 ,
pendingOrderCount : pendingOrders [ 0 ] ? . count || 0 ,
completedOrderCount : completedOrders [ 0 ] ? . count || 0 ,
orderTotalAmount : ( totalAmount [ 0 ] ? . total || 0 ) / 10000 ,
orderTrend : trendData . map ( row => ( {
date : row . date ? . substring ( 5 ) || '' ,
count : row . count || 0 ,
amount : Math . round ( ( row . amount || 0 ) / 10000 )
} ) ) ,
statusDistribution : statusData . map ( row => ( {
name : row . status === 'pending' ? '待生产' : row . status === 'processing' ? '生产中' : '已完成' ,
value : row . count || 0
} ) ) ,
recentOrders : recentOrders . map ( row => ( {
orderNo : row . orderNo || '' ,
customer : row . customer || '' ,
amount : row . amount || 0 ,
status : row . status === 'pending' ? '待生产' : row . status === 'processing' ? '生产中' : '已完成' ,
time : row . time ? . substring ( 0 , 5 ) || ''
} ) )
} )
} catch ( err ) {
console . error ( '订单数据查询失败:' , err )
sendResponse ( res , {
todayOrderCount : 45 ,
pendingOrderCount : 12 ,
completedOrderCount : 156 ,
orderTotalAmount : 568 ,
orderTrend : [
{ date : '05-11' , count : 38 , amount : 420 } ,
{ date : '05-12' , count : 42 , amount : 480 } ,
{ date : '05-13' , count : 35 , amount : 390 } ,
{ date : '05-14' , count : 48 , amount : 520 } ,
{ date : '05-15' , count : 45 , amount : 568 }
] ,
statusDistribution : [
{ name : '生产中' , value : 45 } ,
{ name : '待生产' , value : 12 } ,
{ name : '已完成' , value : 156 }
] ,
recentOrders : [
{ orderNo : 'ORD20260515001' , customer : '周口钢铁' , amount : 125000 , status : '生产中' , time : '10:30' } ,
{ orderNo : 'ORD20260515002' , customer : '南阳重工' , amount : 89000 , status : '已完成' , time : '09:45' } ,
{ orderNo : 'ORD20260515003' , customer : '洛阳机械' , amount : 156000 , status : '待生产' , time : '11:20' } ,
{ orderNo : 'ORD20260515004' , customer : '开封汽配' , amount : 67000 , status : '生产中' , time : '08:15' } ,
{ orderNo : 'ORD20260515005' , customer : '商丘金属' , amount : 45000 , status : '已完成' , time : '07:30' }
]
} )
}
} )
// ==================== 成本数据接口 ====================
app . get ( '/api/dashboard/cost' , async ( req , res ) => {
if ( ! acidPool ) {
sendResponse ( res , {
totalCost : 156.8 ,
materialCost : 89.5 ,
laborCost : 32.6 ,
energyCost : 24.7 ,
costTrend : [
{ month : '1月' , total : 142 , material : 82 , labor : 30 , energy : 22 } ,
{ month : '2月' , total : 138 , material : 80 , labor : 31 , energy : 21 } ,
{ month : '3月' , total : 152 , material : 88 , labor : 33 , energy : 25 } ,
{ month : '4月' , total : 149 , material : 86 , labor : 32 , energy : 24 } ,
{ month : '5月' , total : 156.8 , material : 89.5 , labor : 32.6 , energy : 24.7 }
] ,
costComposition : [
{ name : '材料成本' , value : 57.1 } ,
{ name : '人工成本' , value : 20.8 } ,
{ name : '能源成本' , value : 15.7 } ,
{ name : '其他成本' , value : 6.4 }
] ,
analysisList : [
{ label : '材料成本' , value : '89.5万' , change : 3.2 , color : '#ff6b6b' } ,
{ label : '人工成本' , value : '32.6万' , change : - 1.5 , color : '#00d4ff' } ,
{ label : '能源成本' , value : '24.7万' , change : 5.8 , color : '#00ff88' } ,
{ label : '总成本' , value : '156.8万' , change : 2.1 , color : '#7c63ff' }
]
} )
return
}
try {
const [ costData ] = await acidPool . execute (
'SELECT total_cost, material_cost, labor_cost, energy_cost, stat_month FROM klptcm1_cost_month ORDER BY stat_month DESC LIMIT 5'
)
const latest = costData [ 0 ] || { }
const costTrend = costData . map ( row => ( {
month : row . stat _month ? . substring ( 5 ) + '月' || '' ,
total : row . total _cost || 0 ,
material : row . material _cost || 0 ,
labor : row . labor _cost || 0 ,
energy : row . energy _cost || 0
} ) )
const total = latest . total _cost || 0
sendResponse ( res , {
totalCost : total ,
materialCost : latest . material _cost || 0 ,
laborCost : latest . labor _cost || 0 ,
energyCost : latest . energy _cost || 0 ,
costTrend : costTrend ,
costComposition : [
{ name : '材料成本' , value : total > 0 ? Math . round ( ( latest . material _cost || 0 ) / total * 1000 ) / 10 : 57.1 } ,
{ name : '人工成本' , value : total > 0 ? Math . round ( ( latest . labor _cost || 0 ) / total * 1000 ) / 10 : 20.8 } ,
{ name : '能源成本' , value : total > 0 ? Math . round ( ( latest . energy _cost || 0 ) / total * 1000 ) / 10 : 15.7 } ,
{ name : '其他成本' , value : total > 0 ? 100 - Math . round ( ( ( latest . material _cost || 0 ) + ( latest . labor _cost || 0 ) + ( latest . energy _cost || 0 ) ) / total * 1000 ) / 10 : 6.4 }
] ,
analysisList : [
{ label : '材料成本' , value : ( latest . material _cost || 89.5 ) + '万' , change : 3.2 , color : '#ff6b6b' } ,
{ label : '人工成本' , value : ( latest . labor _cost || 32.6 ) + '万' , change : - 1.5 , color : '#00d4ff' } ,
{ label : '能源成本' , value : ( latest . energy _cost || 24.7 ) + '万' , change : 5.8 , color : '#00ff88' } ,
{ label : '总成本' , value : total + '万' , change : 2.1 , color : '#7c63ff' }
]
} )
} catch ( err ) {
console . error ( '成本数据查询失败:' , err )
sendResponse ( res , {
totalCost : 156.8 ,
materialCost : 89.5 ,
laborCost : 32.6 ,
energyCost : 24.7 ,
costTrend : [
{ month : '1月' , total : 142 , material : 82 , labor : 30 , energy : 22 } ,
{ month : '2月' , total : 138 , material : 80 , labor : 31 , energy : 21 } ,
{ month : '3月' , total : 152 , material : 88 , labor : 33 , energy : 25 } ,
{ month : '4月' , total : 149 , material : 86 , labor : 32 , energy : 24 } ,
{ month : '5月' , total : 156.8 , material : 89.5 , labor : 32.6 , energy : 24.7 }
] ,
costComposition : [
{ name : '材料成本' , value : 57.1 } ,
{ name : '人工成本' , value : 20.8 } ,
{ name : '能源成本' , value : 15.7 } ,
{ name : '其他成本' , value : 6.4 }
] ,
analysisList : [
{ label : '材料成本' , value : '89.5万' , change : 3.2 , color : '#ff6b6b' } ,
{ label : '人工成本' , value : '32.6万' , change : - 1.5 , color : '#00d4ff' } ,
{ label : '能源成本' , value : '24.7万' , change : 5.8 , color : '#00ff88' } ,
{ label : '总成本' , value : '156.8万' , change : 2.1 , color : '#7c63ff' }
]
} )
}
} )
// ==================== 能源数据接口 ====================
app . get ( '/api/dashboard/energy' , async ( req , res ) => {
if ( ! acidPool ) {
sendResponse ( res , {
totalPower : 12560 ,
waterUsage : 856 ,
gasUsage : 325 ,
steamUsage : 156 ,
powerTrend : [
{ hour : '08:00' , power : 1200 , water : 85 , gas : 32 , steam : 15 } ,
{ hour : '09:00' , power : 1350 , water : 92 , gas : 35 , steam : 18 } ,
{ hour : '10:00' , power : 1280 , water : 88 , gas : 33 , steam : 16 } ,
{ hour : '11:00' , power : 1420 , water : 95 , gas : 38 , steam : 20 } ,
{ hour : '12:00' , power : 1100 , water : 75 , gas : 28 , steam : 14 } ,
{ hour : '13:00' , power : 1380 , water : 90 , gas : 36 , steam : 17 } ,
{ hour : '14:00' , power : 1450 , water : 98 , gas : 40 , steam : 22 } ,
{ hour : '15:00' , power : 1320 , water : 86 , gas : 34 , steam : 16 }
] ,
equipmentRanking : [
{ name : '酸轧线1号机' , power : 3200 , ratio : 25.5 } ,
{ name : '酸轧线2号机' , power : 2850 , ratio : 22.7 } ,
{ name : '退火炉A' , power : 2100 , ratio : 16.7 } ,
{ name : '退火炉B' , power : 1980 , ratio : 15.8 } ,
{ name : '酸洗线' , power : 1560 , ratio : 12.4 } ,
{ name : '其他设备' , power : 870 , ratio : 6.9 }
] ,
energyComposition : [
{ name : '电力' , value : 78.5 } ,
{ name : '水' , value : 10.2 } ,
{ name : '天然气' , value : 7.8 } ,
{ name : '蒸汽' , value : 3.5 }
] ,
alarms : [
{ level : 'warning' , message : '酸轧线1号机电流偏高' , time : '14:25:00' } ,
{ level : 'info' , message : '退火炉B能耗正常' , time : '13:30:00' } ,
{ level : 'success' , message : '能源系统运行正常' , time : '08:00:00' }
]
} )
return
}
try {
const [ powerData ] = await acidPool . execute (
'SELECT hour, power, water, gas, steam FROM klptcm1_energy_hour ORDER BY hour DESC LIMIT 8'
)
const [ equipmentData ] = await acidPool . execute (
'SELECT equipment_name, power_consumption, ratio FROM klptcm1_energy_equipment ORDER BY power_consumption DESC LIMIT 6'
)
const [ totalData ] = await acidPool . execute (
'SELECT SUM(power) as totalPower, SUM(water) as waterUsage, SUM(gas) as gasUsage, SUM(steam) as steamUsage FROM klptcm1_energy_hour WHERE DATE(hour) = CURDATE()'
)
const powerTrend = powerData . map ( row => ( {
hour : row . hour ? . substring ( 11 , 16 ) || '' ,
power : row . power || 0 ,
water : row . water || 0 ,
gas : row . gas || 0 ,
steam : row . steam || 0
} ) ) . reverse ( )
const totalPower = totalData [ 0 ] ? . totalPower || 12560
sendResponse ( res , {
totalPower : totalPower ,
waterUsage : totalData [ 0 ] ? . waterUsage || 856 ,
gasUsage : totalData [ 0 ] ? . gasUsage || 325 ,
steamUsage : totalData [ 0 ] ? . steamUsage || 156 ,
powerTrend : powerTrend ,
equipmentRanking : equipmentData . map ( row => ( {
name : row . equipment _name || '' ,
power : row . power _consumption || 0 ,
ratio : row . ratio || 0
} ) ) ,
energyComposition : [
{ name : '电力' , value : totalPower > 0 ? Math . round ( ( totalPower / ( totalPower + 1500 ) ) * 100 ) : 78.5 } ,
{ name : '水' , value : 10.2 } ,
{ name : '天然气' , value : 7.8 } ,
{ name : '蒸汽' , value : 3.5 }
] ,
alarms : [
{ level : 'warning' , message : '酸轧线1号机电流偏高' , time : '14:25:00' } ,
{ level : 'info' , message : '退火炉B能耗正常' , time : '13:30:00' } ,
{ level : 'success' , message : '能源系统运行正常' , time : '08:00:00' }
]
} )
} catch ( err ) {
console . error ( '能源数据查询失败:' , err )
sendResponse ( res , {
totalPower : 12560 ,
waterUsage : 856 ,
gasUsage : 325 ,
steamUsage : 156 ,
powerTrend : [
{ hour : '08:00' , power : 1200 , water : 85 , gas : 32 , steam : 15 } ,
{ hour : '09:00' , power : 1350 , water : 92 , gas : 35 , steam : 18 } ,
{ hour : '10:00' , power : 1280 , water : 88 , gas : 33 , steam : 16 } ,
{ hour : '11:00' , power : 1420 , water : 95 , gas : 38 , steam : 20 } ,
{ hour : '12:00' , power : 1100 , water : 75 , gas : 28 , steam : 14 } ,
{ hour : '13:00' , power : 1380 , water : 90 , gas : 36 , steam : 17 } ,
{ hour : '14:00' , power : 1450 , water : 98 , gas : 40 , steam : 22 } ,
{ hour : '15:00' , power : 1320 , water : 86 , gas : 34 , steam : 16 }
] ,
equipmentRanking : [
{ name : '酸轧线1号机' , power : 3200 , ratio : 25.5 } ,
{ name : '酸轧线2号机' , power : 2850 , ratio : 22.7 } ,
{ name : '退火炉A' , power : 2100 , ratio : 16.7 } ,
{ name : '退火炉B' , power : 1980 , ratio : 15.8 } ,
{ name : '酸洗线' , power : 1560 , ratio : 12.4 } ,
{ name : '其他设备' , power : 870 , ratio : 6.9 }
] ,
energyComposition : [
{ name : '电力' , value : 78.5 } ,
{ name : '水' , value : 10.2 } ,
{ name : '天然气' , value : 7.8 } ,
{ name : '蒸汽' , value : 3.5 }
] ,
alarms : [
{ level : 'warning' , message : '酸轧线1号机电流偏高' , time : '14:25:00' } ,
{ level : 'info' , message : '退火炉B能耗正常' , time : '13:30:00' } ,
{ level : 'success' , message : '能源系统运行正常' , time : '08:00:00' }
]
} )
}
} )
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
} )
} )