const WebSocket = require('ws') const http = require('http') const BASE_URL = 'http://localhost:8080/api' const WS_URL = 'ws://localhost:8080/api/ws/notify' const TOKENS = { sales: 'mock-token-mp-21', dispatch: 'mock-token-mp-13', construction: 'mock-token-mp-15', } const ROLES = { sales: { userId: 21, name: '徐云辉' }, dispatch: { userId: 13, name: '张智城' }, construction: { userId: 15, name: '测试实施1' }, } function request(method, path, data, token) { return new Promise((resolve, reject) => { const options = { hostname: 'localhost', port: 8080, path: '/api' + path, method, headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`, }, } const req = http.request(options, (res) => { let body = '' res.on('data', (chunk) => (body += chunk)) res.on('end', () => { try { resolve(JSON.parse(body)) } catch (e) { resolve(body) } }) }) req.on('error', reject) if (data) req.write(JSON.stringify(data)) req.end() }) } function connectWebSocket(role) { return new Promise((resolve, reject) => { const ws = new WebSocket(`${WS_URL}?token=${encodeURIComponent(TOKENS[role])}`) const messages = [] ws.on('open', () => { console.log(`[${role}] WebSocket connected`) resolve({ ws, messages }) }) ws.on('message', (data) => { const msg = JSON.parse(data.toString()) console.log(`[${role}] received raw:`, msg.type, msg.title || '', msg.content || '') messages.push(msg) }) ws.on('error', (err) => { console.error(`[${role}] WebSocket error:`, err.message) reject(err) }) ws.on('close', () => { console.log(`[${role}] WebSocket closed`) }) }) } function wait(ms) { return new Promise((resolve) => setTimeout(resolve, ms)) } function filterMessages(messages, taskId, taskNo) { return messages.filter(m => m.type !== 'connected' && m.type !== 'pong') .filter(m => m.businessId == taskId || m.extraData == taskId || (m.content || '').includes(taskNo)) } async function main() { console.log('Connecting WebSockets...') const sales = await connectWebSocket('sales') const dispatch = await connectWebSocket('dispatch') const construction = await connectWebSocket('construction') await wait(1000) // Step 1: Sales creates a task console.log('\n--- Step 1: Sales creates task ---') const taskNo = 'TK-TEST-' + Date.now() const createRes = await request('POST', '/task', { taskNo, projectId: 33, taskType: 'dredge', planDate: '2026-07-26', address: '测试地址', taskName: '测试任务-' + Date.now(), }, TOKENS.sales) console.log('Create task response:', createRes.code, createRes.msg) if (createRes.code !== 200) { console.error('Failed to create task:', createRes) process.exit(1) } const taskId = createRes.data await wait(2000) // Step 2: Dispatch approves task console.log('\n--- Step 2: Dispatch approves task ---') const approveRes = await request('POST', `/task/audit/${taskId}/approve`, { auditUserId: ROLES.dispatch.userId, auditUserName: ROLES.dispatch.name, }, TOKENS.dispatch) console.log('Approve task response:', approveRes.code, approveRes.msg) await wait(2000) // Step 3: Dispatch dispatches task to team 90 console.log('\n--- Step 3: Dispatch dispatches task to team 90 ---') const vehicleRes = await request('GET', '/vehicle/list?pageNum=1&pageSize=1', null, TOKENS.dispatch) const vehicleId = vehicleRes.data?.rows?.[0]?.vehicleId || 1 const dispatchRes = await request('POST', `/task/audit/${taskId}/dispatch`, { teamId: 90, vehicleId, auditUserId: ROLES.dispatch.userId, auditUserName: ROLES.dispatch.name, }, TOKENS.dispatch) console.log('Dispatch task response:', dispatchRes.code, dispatchRes.msg) await wait(2000) // Clear previous messages so we only capture reject/feedback notifications sales.messages.length = 0 dispatch.messages.length = 0 construction.messages.length = 0 // Step 4: Construction rejects task console.log('\n--- Step 4: Construction rejects task ---') const taskRes = await request('GET', `/task/${taskId}`, null, TOKENS.construction) const task = taskRes.data const rejectReason = '测试拒绝原因-' + Date.now() const rejectUpdateRes = await request('PUT', '/task', { taskId, taskNo: task.taskNo, address: task.address, taskType: task.taskType, projectId: task.projectId, planDate: task.planDate, status: 'rejected', remark: rejectReason, }, TOKENS.construction) console.log('Reject update response:', rejectUpdateRes.code, rejectUpdateRes.msg) const rejectLogRes = await request('POST', `/task/${taskId}/log`, { operationType: 'reject', operation: '拒绝任务', remark: rejectReason, operatorId: ROLES.construction.userId, operatorName: ROLES.construction.name, }, TOKENS.construction) console.log('Reject log response:', rejectLogRes.code, rejectLogRes.msg) await wait(2000) // Step 5: Construction submits feedback console.log('\n--- Step 5: Construction submits feedback ---') const feedbackContent = '测试反馈内容-' + Date.now() const feedbackRes = await request('POST', `/task/${taskId}/log`, { operationType: 'feedback', operation: '反馈问题', remark: feedbackContent, operatorId: ROLES.construction.userId, operatorName: ROLES.construction.name, }, TOKENS.construction) console.log('Feedback response:', feedbackRes.code, feedbackRes.msg) await wait(2000) // Step 6: Check task logs console.log('\n--- Step 6: Task logs ---') const logsRes = await request('GET', `/task/${taskId}/logs`, null, TOKENS.construction) const logs = logsRes.data || [] console.log('Recent logs for task:') logs.slice(-5).forEach(log => { console.log(` [${log.operationType}] ${log.operation} | ${log.remark || '-'} | by ${log.operatorName}`) }) const hasRejectLog = logs.some(l => l.operationType === 'reject') const hasFeedbackLog = logs.some(l => l.operationType === 'feedback') console.log('Has reject log:', hasRejectLog) console.log('Has feedback log:', hasFeedbackLog) // Step 7: Check WebSocket messages received after reject/feedback console.log('\n--- Step 7: WebSocket messages after reject/feedback ---') console.log('Sales:', filterMessages(sales.messages, taskId, taskNo).map(m => ({ type: m.type, title: m.title, content: m.content }))) console.log('Dispatch:', filterMessages(dispatch.messages, taskId, taskNo).map(m => ({ type: m.type, title: m.title, content: m.content }))) console.log('Construction:', filterMessages(construction.messages, taskId, taskNo).map(m => ({ type: m.type, title: m.title, content: m.content }))) // Step 8: Check persisted messages console.log('\n--- Step 8: Persisted messages ---') const salesMsgRes = await request('GET', '/message/list?pageNum=1&pageSize=50', null, TOKENS.sales) const dispatchMsgRes = await request('GET', '/message/list?pageNum=1&pageSize=50', null, TOKENS.dispatch) console.log('Sales persisted messages related to task:', salesMsgRes.data?.rows?.filter(m => m.extraData == taskId || m.content?.includes(taskNo)).map(m => ({ type: m.messageType, title: m.title, content: m.content, isRead: m.isRead }))) console.log('Dispatch persisted messages related to task:', dispatchMsgRes.data?.rows?.filter(m => m.extraData == taskId || m.content?.includes(taskNo)).map(m => ({ type: m.messageType, title: m.title, content: m.content, isRead: m.isRead }))) sales.ws.close() dispatch.ws.close() construction.ws.close() console.log('\n=== Summary ===') console.log('Reject recorded in logs:', hasRejectLog) console.log('Feedback recorded in logs:', hasFeedbackLog) console.log('Sales WS notifications after reject/feedback:', filterMessages(sales.messages, taskId, taskNo).length) console.log('Dispatch WS notifications after reject/feedback:', filterMessages(dispatch.messages, taskId, taskNo).length) console.log('Sales persisted messages after reject/feedback:', (salesMsgRes.data?.rows || []).filter(m => m.extraData == taskId || m.content?.includes(taskNo)).length) console.log('Dispatch persisted messages after reject/feedback:', (dispatchMsgRes.data?.rows || []).filter(m => m.extraData == taskId || m.content?.includes(taskNo)).length) } main().catch((err) => { console.error('Test failed:', err) process.exit(1) })