@ -6385,308 +6385,8 @@ app.get('/api/online-stats', async (req, res) => {
}
} ) ;
// REST API接口 - 获取客服列表 - 修改为按照用户需求:工位名为采购员且有电话号码
app . get ( '/api/managers' , async ( req , res ) => {
try {
// 查询userlogin数据库中的personnel表,获取工位为采购员且有电话号码的用户
// 根据表结构选择所有需要的字段
const [ personnelData ] = await sequelize . query (
'SELECT id, managerId, managercompany, managerdepartment, organization, projectName, name, alias, phoneNumber, avatarUrl FROM userlogin.personnel WHERE projectName = ? AND phoneNumber IS NOT NULL AND phoneNumber != "" ORDER BY id ASC' ,
{ replacements : [ '采购员' ] }
) ;
// 其次从数据库查询结果检查
const dbStatus = onlineStatusMap [ stringId ] || ( stringManagerId && onlineStatusMap [ stringManagerId ] ) || false ;
console . log ( ` 客服在线状态(数据库): id= ${ id } , status= ${ dbStatus } ` ) ;
return dbStatus ;
} ;
const managers = personnelData . map ( ( person , index ) => ( {
id : person . id ,
managerId : person . managerId || ` PM ${ String ( index + 1 ) . padStart ( 3 , '0' ) } ` ,
managercompany : person . managercompany || '未知公司' ,
managerdepartment : person . managerdepartment || '采购部' ,
organization : person . organization || '采购组' ,
projectName : person . projectName || '采购员' ,
name : person . name || '未知' ,
alias : person . alias || person . name || '未知' ,
phoneNumber : person . phoneNumber || '' ,
avatar : person . avatarUrl || '' , // 使用表中的avatarUrl字段
online : isManagerOnline ( person . id , person . managerId ) // 综合检查在线状态
} ) ) ;
res . status ( 200 ) . json ( {
success : true ,
code : 200 ,
data : managers
} ) ;
} catch ( error ) {
console . error ( '获取客服列表失败:' , error ) ;
res . status ( 500 ) . json ( {
success : false ,
code : 500 ,
message : '获取客服列表失败: ' + error . message
} ) ;
}
} ) ;
// WebSocket服务器事件处理
wss . on ( 'connection' , ( ws , req ) => {
console . log ( '新的WebSocket连接建立' ) ;
// 生成连接ID
const connectionId = crypto . randomUUID ( ) ;
ws . connectionId = connectionId ;
// 存储连接信息
connections . set ( connectionId , {
ws ,
userId : null ,
managerId : null ,
isUser : false ,
isManager : false ,
connectedAt : getBeijingTime ( )
} ) ;
// 连接认证处理
ws . on ( 'message' , async ( message ) => {
try {
// 更新连接活动时间
updateConnectionActivity ( ws . connectionId ) ;
const data = JSON . parse ( message . toString ( ) ) ;
// 处理认证消息
if ( data . type === 'auth' || data . action === 'auth' ) {
await handleAuth ( ws , data ) ;
return ;
}
// 处理心跳消息
if ( data . type === 'ping' ) {
// 更新连接活动时间
updateConnectionActivity ( ws . connectionId ) ;
// 更新心跳时间到chat_online_status表
const connection = connections . get ( ws . connectionId ) ;
if ( connection ) {
const userId = connection . isUser ? connection . userId : connection . managerId ;
const type = connection . isUser ? 1 : 2 ;
updateChatOnlineStatusHeartbeat ( userId , type ) ;
}
ws . send ( JSON . stringify ( { type : 'pong' } ) ) ;
return ;
}
// 处理创建会话请求
if ( data . type === 'create_conversation' ) {
console . log ( '接收到创建会话请求:' , JSON . stringify ( data ) ) ;
try {
const { userId , managerId , timestamp } = data ;
// 验证必要参数
if ( ! userId || ! managerId ) {
console . error ( '错误: 创建会话缺少必要参数' ) ;
ws . send ( JSON . stringify ( {
type : 'error' ,
message : '创建会话失败: 缺少用户ID或客服ID'
} ) ) ;
return ;
}
// 创建或获取会话
const conversation = await createOrGetConversation ( userId , managerId ) ;
console . log ( '会话创建成功:' , conversation ) ;
// 返回会话创建成功响应
ws . send ( JSON . stringify ( {
type : 'conversation_created' ,
conversationId : conversation . conversation_id ,
userId : conversation . userId ,
managerId : conversation . managerId ,
status : conversation . status ,
timestamp : timestamp || Date . now ( )
} ) ) ;
} catch ( error ) {
console . error ( '创建会话失败:' , error ) ;
ws . send ( JSON . stringify ( {
type : 'error' ,
message : '创建会话失败: ' + error . message
} ) ) ;
}
return ;
}
// 处理聊天消息
if ( data . type === 'chat_message' ) {
console . log ( '接收到聊天消息:' , JSON . stringify ( data ) ) ;
// 直接使用接收到的数据作为payload,确保格式正确
const payload = data ;
// 确保必要字段都已设置
if ( ! payload . senderId && ! payload . userId ) {
console . error ( '错误: 缺少用户ID字段' ) ;
ws . send ( JSON . stringify ( {
type : 'error' ,
message : '消息缺少用户ID'
} ) ) ;
return ;
}
// 确保senderType是数字类型
if ( payload . senderType && typeof payload . senderType === 'string' ) {
if ( payload . senderType . includes ( 'customer' ) || payload . senderType . includes ( 'user' ) ) {
payload . senderType = 1 ; // 普通用户
} else if ( payload . senderType . includes ( 'service' ) || payload . senderType . includes ( 'manager' ) ) {
payload . senderType = 2 ; // 客服
}
} else if ( ! payload . senderType ) {
// 设置默认值
const connection = connections . get ( ws . connectionId ) ;
if ( connection && connection . isManager ) {
payload . senderType = 2 ;
} else {
payload . senderType = 1 ;
}
}
// 确保所有数字字段都是数字类型
payload . senderType = Number ( payload . senderType ) ;
payload . contentType = Number ( payload . contentType || 1 ) ;
console . log ( '处理聊天消息 - 准备传递的payload:' , JSON . stringify ( payload ) ) ;
// 调用handleChatMessage处理消息
try {
await handleChatMessage ( ws , payload ) ;
console . log ( '消息处理完成' ) ;
} catch ( error ) {
console . error ( '处理聊天消息时出错:' , error ) ;
ws . send ( JSON . stringify ( {
type : 'error' ,
message : '消息处理失败' ,
error : error . message
} ) ) ;
}
return ;
}
// 处理会话相关消息
if ( data . type === 'session' ) {
// 直接传递整个data对象给handleSessionMessage,因为action可能在data根级别
await handleSessionMessage ( ws , data ) ;
return ;
}
// 直接处理get_messages请求
if ( data . type === 'get_messages' ) {
// 直接传递整个data对象给handleSessionMessage,因为action可能在data根级别
await handleSessionMessage ( ws , data ) ;
return ;
}
// 处理未读消息标记
if ( data . type === 'mark_read' ) {
const payload = data . data || data . payload || data ;
await handleMarkRead ( ws , payload ) ;
return ;
}
} catch ( error ) {
console . error ( '处理WebSocket消息错误:' , error ) ;
ws . send ( JSON . stringify ( {
type : 'error' ,
message : '消息处理失败'
} ) ) ;
}
} ) ;
// 连接关闭处理
ws . on ( 'close' , async ( ) => {
console . log ( 'WebSocket连接关闭' ) ;
const connection = connections . get ( connectionId ) ;
if ( connection ) {
// 更新在线状态
if ( connection . isUser && connection . userId ) {
onlineUsers . delete ( connection . userId ) ;
await updateUserOnlineStatus ( connection . userId , 0 ) ;
// 更新chat_online_status表为离线
await updateChatOnlineStatusOffline ( connection . userId , 1 ) ;
} else if ( connection . isManager && connection . managerId ) {
onlineManagers . delete ( connection . managerId ) ;
await updateManagerOnlineStatus ( connection . managerId , 0 ) ;
// 更新chat_online_status表为离线
await updateChatOnlineStatusOffline ( connection . managerId , 2 ) ;
}
// 从连接池中移除
connections . delete ( connectionId ) ;
}
} ) ;
// 更新chat_online_status表的心跳时间
async function updateChatOnlineStatusHeartbeat ( userId , type ) {
try {
const now = getBeijingTime ( ) ;
// 根据userId是否为null使用不同的SQL语句
let sql ;
let replacements ;
if ( userId === null || userId === undefined ) {
sql = ` UPDATE chat_online_status
SET last_heartbeat = ? , updated_at = ?
WHERE userId IS NULL AND type = ? AND is_online = 1 ` ;
replacements = [ now , now , type ] ;
} else {
sql = ` UPDATE chat_online_status
SET last_heartbeat = ? , updated_at = ?
WHERE userId = ? AND type = ? AND is_online = 1 ` ;
replacements = [ now , now , userId , type ] ;
}
await sequelize . query ( sql , { replacements } ) ;
} catch ( error ) {
// 心跳更新失败不影响主流程,仅记录日志
console . error ( '更新chat_online_status心跳时间失败:' , error ) ;
}
}
// 更新chat_online_status表为离线状态
async function updateChatOnlineStatusOffline ( userId , type ) {
try {
const now = getBeijingTime ( ) ;
// 根据userId是否为null使用不同的SQL语句
let sql ;
let replacements ;
if ( userId === null || userId === undefined ) {
sql = ` UPDATE chat_online_status
SET is_online = 0 , updated_at = ?
WHERE userId IS NULL AND type = ? ` ;
replacements = [ now , type ] ;
} else {
sql = ` UPDATE chat_online_status
SET is_online = 0 , updated_at = ?
WHERE userId = ? AND type = ? ` ;
replacements = [ now , userId , type ] ;
}
await sequelize . query ( sql , { replacements } ) ;
console . log ( ` 更新chat_online_status离线状态成功: userId= ${ userId } , type= ${ type } ` ) ;
} catch ( error ) {
console . error ( '更新chat_online_status离线状态失败:' , error ) ;
}
}
// 连接错误处理
ws . on ( 'error' , ( error ) => {
console . error ( 'WebSocket连接错误:' , error ) ;
} ) ;
} ) ;
// 认证处理函数
async function handleAuth ( ws , data ) {