status.ts 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. /**
  2. * 状态查询相关API
  3. * 用于查询设备状态、识别结果和订单信息
  4. */
  5. import { post } from '../utils/request';
  6. /**
  7. * 设备状态响应
  8. */
  9. export interface DeviceStatusResponse {
  10. deviceId: string;
  11. doorStatus: 'open' | 'close' | 'error' | 'busy' | 'unknown';
  12. activityId: string;
  13. userId: string;
  14. status: string;
  15. openType: string;
  16. timestamp: string;
  17. }
  18. /**
  19. * 识别结果响应
  20. */
  21. export interface RecognizeResultResponse {
  22. activityId: string;
  23. deviceId: string;
  24. userId: string;
  25. nobuy: string;
  26. result: string;
  27. skuList: string;
  28. resourceInfo: string;
  29. timestamp: string;
  30. }
  31. /**
  32. * 订单信息响应
  33. */
  34. export interface OrderInfoResponse {
  35. orderId: string;
  36. activityId: string;
  37. deviceId: string;
  38. userId: string;
  39. orderName: string;
  40. totalAmount: string;
  41. products: string;
  42. timestamp: string;
  43. }
  44. /**
  45. * 综合状态响应
  46. */
  47. export interface AllStatusResponse {
  48. deviceStatus: DeviceStatusResponse;
  49. recognizeResult?: RecognizeResultResponse;
  50. orderInfo?: OrderInfoResponse;
  51. }
  52. /**
  53. * 查询设备状态
  54. * @param deviceId 设备ID
  55. */
  56. export const queryDeviceStatus = (deviceId: string): Promise<DeviceStatusResponse> => {
  57. return post<DeviceStatusResponse>('/status/device', { deviceId }, { silent: true });
  58. };
  59. /**
  60. * 查询识别结果
  61. * @param activityId 活动ID
  62. */
  63. export const queryRecognizeResult = (activityId: string): Promise<RecognizeResultResponse> => {
  64. return post<RecognizeResultResponse>('/status/recognize', { activityId }, { silent: true });
  65. };
  66. /**
  67. * 查询订单信息
  68. * @param orderId 订单ID
  69. * @param activityId 活动ID(与orderId二选一)
  70. */
  71. export const queryOrderInfo = (orderId?: string, activityId?: string): Promise<OrderInfoResponse> => {
  72. return post<OrderInfoResponse>('/status/order', { orderId, activityId }, { silent: true });
  73. };
  74. /**
  75. * 综合状态查询
  76. * @param deviceId 设备ID
  77. */
  78. export const queryAllStatus = (deviceId: string): Promise<AllStatusResponse> => {
  79. return post<AllStatusResponse>('/status/all', { deviceId }, { silent: true });
  80. };
  81. /**
  82. * 轮询设备状态
  83. * @param deviceId 设备ID
  84. * @param timeout 超时时间(毫秒)
  85. * @param interval 轮询间隔(毫秒)
  86. */
  87. export const pollDeviceStatus = (
  88. deviceId: string,
  89. timeout: number = 60000,
  90. interval: number = 3000,
  91. maxConsecutiveFailures: number = 3
  92. ): Promise<DeviceStatusResponse> => {
  93. return new Promise((resolve, reject) => {
  94. const startTime = Date.now();
  95. let timerId: ReturnType<typeof setTimeout> | null = null;
  96. let settled = false;
  97. let failCount = 0;
  98. const cleanup = () => {
  99. if (timerId !== null) {
  100. clearTimeout(timerId);
  101. timerId = null;
  102. }
  103. };
  104. const done = (result: DeviceStatusResponse | null, err?: Error) => {
  105. if (settled) return;
  106. settled = true;
  107. cleanup();
  108. if (err) {
  109. reject(err);
  110. } else if (result) {
  111. resolve(result);
  112. }
  113. };
  114. const poll = async () => {
  115. if (settled) return;
  116. try {
  117. const response = await queryDeviceStatus(deviceId);
  118. if (settled) return;
  119. // 成功一次就重置失败计数
  120. failCount = 0;
  121. if (response && response.doorStatus && response.doorStatus !== 'unknown') {
  122. const statusTime = parseInt(response.timestamp) || 0;
  123. if (statusTime > startTime - 10000) {
  124. done(response);
  125. return;
  126. }
  127. }
  128. if (Date.now() - startTime >= timeout) {
  129. done(null, new Error('轮询超时'));
  130. return;
  131. }
  132. timerId = setTimeout(poll, interval);
  133. } catch (error) {
  134. if (settled) return;
  135. failCount++;
  136. if (failCount >= maxConsecutiveFailures) {
  137. done(null, new Error('网络异常,轮询中断'));
  138. return;
  139. }
  140. if (Date.now() - startTime >= timeout) {
  141. done(null, new Error('轮询超时'));
  142. return;
  143. }
  144. timerId = setTimeout(poll, interval);
  145. }
  146. };
  147. poll();
  148. });
  149. };
  150. /**
  151. * 轮询识别结果
  152. * @param activityId 活动ID
  153. * @param timeout 超时时间(毫秒)
  154. * @param interval 轮询间隔(毫秒)
  155. */
  156. export const pollRecognizeResult = (
  157. activityId: string,
  158. timeout: number = 30000,
  159. interval: number = 3000,
  160. maxConsecutiveFailures: number = 3
  161. ): Promise<RecognizeResultResponse> => {
  162. return new Promise((resolve, reject) => {
  163. const startTime = Date.now();
  164. let timerId: ReturnType<typeof setTimeout> | null = null;
  165. let settled = false;
  166. let failCount = 0;
  167. const cleanup = () => {
  168. if (timerId !== null) {
  169. clearTimeout(timerId);
  170. timerId = null;
  171. }
  172. };
  173. const done = (result: RecognizeResultResponse | null, err?: Error) => {
  174. if (settled) return;
  175. settled = true;
  176. cleanup();
  177. if (err) {
  178. reject(err);
  179. } else if (result) {
  180. resolve(result);
  181. }
  182. };
  183. const poll = async () => {
  184. if (settled) return;
  185. try {
  186. const result = await queryRecognizeResult(activityId);
  187. if (settled) return;
  188. failCount = 0;
  189. if (result && result.result) {
  190. done(result);
  191. return;
  192. }
  193. if (Date.now() - startTime >= timeout) {
  194. done(null, new Error('识别超时'));
  195. return;
  196. }
  197. timerId = setTimeout(poll, interval);
  198. } catch (error) {
  199. if (settled) return;
  200. failCount++;
  201. if (failCount >= maxConsecutiveFailures) {
  202. done(null, new Error('网络异常,轮询中断'));
  203. return;
  204. }
  205. if (Date.now() - startTime >= timeout) {
  206. done(null, new Error('识别超时'));
  207. return;
  208. }
  209. timerId = setTimeout(poll, interval);
  210. }
  211. };
  212. poll();
  213. });
  214. };
  215. /**
  216. * 轮询订单信息
  217. * @param activityId 活动ID
  218. * @param timeout 超时时间(毫秒)
  219. * @param interval 轮询间隔(毫秒)
  220. */
  221. export const pollOrderInfo = (
  222. activityId: string,
  223. timeout: number = 30000,
  224. interval: number = 3000,
  225. maxConsecutiveFailures: number = 3
  226. ): Promise<OrderInfoResponse> => {
  227. return new Promise((resolve, reject) => {
  228. const startTime = Date.now();
  229. let timerId: ReturnType<typeof setTimeout> | null = null;
  230. let settled = false;
  231. let failCount = 0;
  232. const cleanup = () => {
  233. if (timerId !== null) {
  234. clearTimeout(timerId);
  235. timerId = null;
  236. }
  237. };
  238. const done = (result: OrderInfoResponse | null, err?: Error) => {
  239. if (settled) return;
  240. settled = true;
  241. cleanup();
  242. if (err) {
  243. reject(err);
  244. } else if (result) {
  245. resolve(result);
  246. }
  247. };
  248. const poll = async () => {
  249. if (settled) return;
  250. try {
  251. const order = await queryOrderInfo(undefined, activityId);
  252. if (settled) return;
  253. failCount = 0;
  254. if (order && order.orderId) {
  255. done(order);
  256. return;
  257. }
  258. if (Date.now() - startTime >= timeout) {
  259. done(null, new Error('获取订单超时'));
  260. return;
  261. }
  262. timerId = setTimeout(poll, interval);
  263. } catch (error) {
  264. if (settled) return;
  265. failCount++;
  266. if (failCount >= maxConsecutiveFailures) {
  267. done(null, new Error('网络异常,轮询中断'));
  268. return;
  269. }
  270. if (Date.now() - startTime >= timeout) {
  271. done(null, new Error('获取订单超时'));
  272. return;
  273. }
  274. timerId = setTimeout(poll, interval);
  275. }
  276. };
  277. poll();
  278. });
  279. };