verify-construction-feedback.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. const WebSocket = require('ws')
  2. const http = require('http')
  3. const BASE_URL = 'http://localhost:8080/api'
  4. const WS_URL = 'ws://localhost:8080/api/ws/notify'
  5. const TOKENS = {
  6. sales: 'mock-token-mp-21',
  7. dispatch: 'mock-token-mp-13',
  8. construction: 'mock-token-mp-15',
  9. }
  10. const ROLES = {
  11. sales: { userId: 21, name: '徐云辉' },
  12. dispatch: { userId: 13, name: '张智城' },
  13. construction: { userId: 15, name: '测试实施1' },
  14. }
  15. function request(method, path, data, token) {
  16. return new Promise((resolve, reject) => {
  17. const options = {
  18. hostname: 'localhost',
  19. port: 8080,
  20. path: '/api' + path,
  21. method,
  22. headers: {
  23. 'Content-Type': 'application/json',
  24. 'Authorization': `Bearer ${token}`,
  25. },
  26. }
  27. const req = http.request(options, (res) => {
  28. let body = ''
  29. res.on('data', (chunk) => (body += chunk))
  30. res.on('end', () => {
  31. try {
  32. resolve(JSON.parse(body))
  33. } catch (e) {
  34. resolve(body)
  35. }
  36. })
  37. })
  38. req.on('error', reject)
  39. if (data) req.write(JSON.stringify(data))
  40. req.end()
  41. })
  42. }
  43. function connectWebSocket(role) {
  44. return new Promise((resolve, reject) => {
  45. const ws = new WebSocket(`${WS_URL}?token=${encodeURIComponent(TOKENS[role])}`)
  46. const messages = []
  47. ws.on('open', () => {
  48. console.log(`[${role}] WebSocket connected`)
  49. resolve({ ws, messages })
  50. })
  51. ws.on('message', (data) => {
  52. const msg = JSON.parse(data.toString())
  53. console.log(`[${role}] received raw:`, msg.type, msg.title || '', msg.content || '')
  54. messages.push(msg)
  55. })
  56. ws.on('error', (err) => {
  57. console.error(`[${role}] WebSocket error:`, err.message)
  58. reject(err)
  59. })
  60. ws.on('close', () => {
  61. console.log(`[${role}] WebSocket closed`)
  62. })
  63. })
  64. }
  65. function wait(ms) {
  66. return new Promise((resolve) => setTimeout(resolve, ms))
  67. }
  68. function filterMessages(messages, taskId, taskNo) {
  69. return messages.filter(m => m.type !== 'connected' && m.type !== 'pong')
  70. .filter(m => m.businessId == taskId || m.extraData == taskId || (m.content || '').includes(taskNo))
  71. }
  72. async function main() {
  73. console.log('Connecting WebSockets...')
  74. const sales = await connectWebSocket('sales')
  75. const dispatch = await connectWebSocket('dispatch')
  76. const construction = await connectWebSocket('construction')
  77. await wait(1000)
  78. // Step 1: Sales creates a task
  79. console.log('\n--- Step 1: Sales creates task ---')
  80. const taskNo = 'TK-TEST-' + Date.now()
  81. const createRes = await request('POST', '/task', {
  82. taskNo,
  83. projectId: 33,
  84. taskType: 'dredge',
  85. planDate: '2026-07-26',
  86. address: '测试地址',
  87. taskName: '测试任务-' + Date.now(),
  88. }, TOKENS.sales)
  89. console.log('Create task response:', createRes.code, createRes.msg)
  90. if (createRes.code !== 200) {
  91. console.error('Failed to create task:', createRes)
  92. process.exit(1)
  93. }
  94. const taskId = createRes.data
  95. await wait(2000)
  96. // Step 2: Dispatch approves task
  97. console.log('\n--- Step 2: Dispatch approves task ---')
  98. const approveRes = await request('POST', `/task/audit/${taskId}/approve`, {
  99. auditUserId: ROLES.dispatch.userId,
  100. auditUserName: ROLES.dispatch.name,
  101. }, TOKENS.dispatch)
  102. console.log('Approve task response:', approveRes.code, approveRes.msg)
  103. await wait(2000)
  104. // Step 3: Dispatch dispatches task to team 90
  105. console.log('\n--- Step 3: Dispatch dispatches task to team 90 ---')
  106. const vehicleRes = await request('GET', '/vehicle/list?pageNum=1&pageSize=1', null, TOKENS.dispatch)
  107. const vehicleId = vehicleRes.data?.rows?.[0]?.vehicleId || 1
  108. const dispatchRes = await request('POST', `/task/audit/${taskId}/dispatch`, {
  109. teamId: 90,
  110. vehicleId,
  111. auditUserId: ROLES.dispatch.userId,
  112. auditUserName: ROLES.dispatch.name,
  113. }, TOKENS.dispatch)
  114. console.log('Dispatch task response:', dispatchRes.code, dispatchRes.msg)
  115. await wait(2000)
  116. // Clear previous messages so we only capture reject/feedback notifications
  117. sales.messages.length = 0
  118. dispatch.messages.length = 0
  119. construction.messages.length = 0
  120. // Step 4: Construction rejects task
  121. console.log('\n--- Step 4: Construction rejects task ---')
  122. const taskRes = await request('GET', `/task/${taskId}`, null, TOKENS.construction)
  123. const task = taskRes.data
  124. const rejectReason = '测试拒绝原因-' + Date.now()
  125. const rejectUpdateRes = await request('PUT', '/task', {
  126. taskId,
  127. taskNo: task.taskNo,
  128. address: task.address,
  129. taskType: task.taskType,
  130. projectId: task.projectId,
  131. planDate: task.planDate,
  132. status: 'rejected',
  133. remark: rejectReason,
  134. }, TOKENS.construction)
  135. console.log('Reject update response:', rejectUpdateRes.code, rejectUpdateRes.msg)
  136. const rejectLogRes = await request('POST', `/task/${taskId}/log`, {
  137. operationType: 'reject',
  138. operation: '拒绝任务',
  139. remark: rejectReason,
  140. operatorId: ROLES.construction.userId,
  141. operatorName: ROLES.construction.name,
  142. }, TOKENS.construction)
  143. console.log('Reject log response:', rejectLogRes.code, rejectLogRes.msg)
  144. await wait(2000)
  145. // Step 5: Construction submits feedback
  146. console.log('\n--- Step 5: Construction submits feedback ---')
  147. const feedbackContent = '测试反馈内容-' + Date.now()
  148. const feedbackRes = await request('POST', `/task/${taskId}/log`, {
  149. operationType: 'feedback',
  150. operation: '反馈问题',
  151. remark: feedbackContent,
  152. operatorId: ROLES.construction.userId,
  153. operatorName: ROLES.construction.name,
  154. }, TOKENS.construction)
  155. console.log('Feedback response:', feedbackRes.code, feedbackRes.msg)
  156. await wait(2000)
  157. // Step 6: Check task logs
  158. console.log('\n--- Step 6: Task logs ---')
  159. const logsRes = await request('GET', `/task/${taskId}/logs`, null, TOKENS.construction)
  160. const logs = logsRes.data || []
  161. console.log('Recent logs for task:')
  162. logs.slice(-5).forEach(log => {
  163. console.log(` [${log.operationType}] ${log.operation} | ${log.remark || '-'} | by ${log.operatorName}`)
  164. })
  165. const hasRejectLog = logs.some(l => l.operationType === 'reject')
  166. const hasFeedbackLog = logs.some(l => l.operationType === 'feedback')
  167. console.log('Has reject log:', hasRejectLog)
  168. console.log('Has feedback log:', hasFeedbackLog)
  169. // Step 7: Check WebSocket messages received after reject/feedback
  170. console.log('\n--- Step 7: WebSocket messages after reject/feedback ---')
  171. console.log('Sales:', filterMessages(sales.messages, taskId, taskNo).map(m => ({ type: m.type, title: m.title, content: m.content })))
  172. console.log('Dispatch:', filterMessages(dispatch.messages, taskId, taskNo).map(m => ({ type: m.type, title: m.title, content: m.content })))
  173. console.log('Construction:', filterMessages(construction.messages, taskId, taskNo).map(m => ({ type: m.type, title: m.title, content: m.content })))
  174. // Step 8: Check persisted messages
  175. console.log('\n--- Step 8: Persisted messages ---')
  176. const salesMsgRes = await request('GET', '/message/list?pageNum=1&pageSize=50', null, TOKENS.sales)
  177. const dispatchMsgRes = await request('GET', '/message/list?pageNum=1&pageSize=50', null, TOKENS.dispatch)
  178. console.log('Sales persisted messages related to task:',
  179. 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 })))
  180. console.log('Dispatch persisted messages related to task:',
  181. 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 })))
  182. sales.ws.close()
  183. dispatch.ws.close()
  184. construction.ws.close()
  185. console.log('\n=== Summary ===')
  186. console.log('Reject recorded in logs:', hasRejectLog)
  187. console.log('Feedback recorded in logs:', hasFeedbackLog)
  188. console.log('Sales WS notifications after reject/feedback:', filterMessages(sales.messages, taskId, taskNo).length)
  189. console.log('Dispatch WS notifications after reject/feedback:', filterMessages(dispatch.messages, taskId, taskNo).length)
  190. console.log('Sales persisted messages after reject/feedback:', (salesMsgRes.data?.rows || []).filter(m => m.extraData == taskId || m.content?.includes(taskNo)).length)
  191. console.log('Dispatch persisted messages after reject/feedback:', (dispatchMsgRes.data?.rows || []).filter(m => m.extraData == taskId || m.content?.includes(taskNo)).length)
  192. }
  193. main().catch((err) => {
  194. console.error('Test failed:', err)
  195. process.exit(1)
  196. })