feie-api.service.ts 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. import axios, { AxiosInstance, AxiosError } from 'axios';
  2. import { createHash } from 'crypto';
  3. import { FeieApiConfig, FeiePrinterInfo, FeiePrintRequest, FeiePrintResponse, FeiePrinterStatusResponse, FeieOrderStatusResponse, FeieAddPrinterResponse, FeieDeletePrinterResponse } from '../types/feie.types';
  4. export class FeieApiService {
  5. private client: AxiosInstance;
  6. private config: FeieApiConfig;
  7. private maxRetries: number;
  8. constructor(config: FeieApiConfig) {
  9. // 确保baseUrl有默认值
  10. const defaultBaseUrl = 'http://api.feieyun.cn/Api/Open/';
  11. this.config = {
  12. baseUrl: defaultBaseUrl,
  13. timeout: 10000,
  14. maxRetries: 3,
  15. ...config
  16. };
  17. this.maxRetries = this.config.maxRetries || 3;
  18. this.client = axios.create({
  19. baseURL: this.config.baseUrl,
  20. timeout: this.config.timeout,
  21. headers: {
  22. 'Content-Type': 'application/x-www-form-urlencoded'
  23. }
  24. });
  25. }
  26. /**
  27. * 生成飞鹅API签名
  28. */
  29. private generateSignature(timestamp: number): string {
  30. const content = `${this.config.user}${this.config.ukey}${timestamp}`;
  31. return createHash('sha1').update(content).digest('hex');
  32. }
  33. /**
  34. * 执行API请求,支持重试
  35. */
  36. private async executeRequest<T>(endpoint: string, params: Record<string, any>): Promise<T> {
  37. const timestamp = Math.floor(Date.now() / 1000);
  38. const signature = this.generateSignature(timestamp);
  39. const requestParams = {
  40. user: this.config.user,
  41. stime: timestamp,
  42. sig: signature,
  43. ...params
  44. };
  45. let lastError: Error | null = null;
  46. for (let attempt = 1; attempt <= this.maxRetries; attempt++) {
  47. try {
  48. const response = await this.client.post(endpoint, requestParams);
  49. if (response.data.ret !== 0) {
  50. throw new Error(`飞鹅API错误: ${response.data.msg} (ret: ${response.data.ret})`);
  51. }
  52. return response.data;
  53. } catch (error) {
  54. lastError = error as Error;
  55. if (attempt < this.maxRetries) {
  56. // 等待指数退避
  57. const delay = Math.pow(2, attempt) * 1000;
  58. await new Promise(resolve => setTimeout(resolve, delay));
  59. continue;
  60. }
  61. }
  62. }
  63. throw lastError || new Error('飞鹅API请求失败');
  64. }
  65. /**
  66. * 添加打印机
  67. */
  68. async addPrinter(printerInfo: FeiePrinterInfo): Promise<FeieAddPrinterResponse> {
  69. const { sn, key, name = '' } = printerInfo;
  70. const snlist = `${sn}#${key}#${name}`;
  71. return this.executeRequest<FeieAddPrinterResponse>('Open_printerAddlist', {
  72. printerContent: snlist
  73. });
  74. }
  75. /**
  76. * 删除打印机
  77. */
  78. async deletePrinter(sn: string): Promise<FeieDeletePrinterResponse> {
  79. const snlist = sn;
  80. return this.executeRequest<FeieDeletePrinterResponse>('Open_printerDelList', {
  81. snlist
  82. });
  83. }
  84. /**
  85. * 查询打印机状态
  86. */
  87. async queryPrinterStatus(sn: string): Promise<FeiePrinterStatusResponse> {
  88. const snlist = sn;
  89. return this.executeRequest<FeiePrinterStatusResponse>('Open_queryPrinterStatus', {
  90. snlist
  91. });
  92. }
  93. /**
  94. * 打印小票
  95. */
  96. async printReceipt(printRequest: FeiePrintRequest): Promise<FeiePrintResponse> {
  97. const { sn, content, times = 1 } = printRequest;
  98. return this.executeRequest<FeiePrintResponse>('Open_printMsg', {
  99. sn,
  100. content,
  101. times
  102. });
  103. }
  104. /**
  105. * 查询订单打印状态
  106. */
  107. async queryOrderStatus(orderId: string): Promise<FeieOrderStatusResponse> {
  108. return this.executeRequest<FeieOrderStatusResponse>('Open_queryOrderState', {
  109. orderid: orderId
  110. });
  111. }
  112. /**
  113. * 根据时间查询订单
  114. */
  115. async queryOrdersByDate(date: string, page: number = 1): Promise<any> {
  116. return this.executeRequest<any>('Open_queryOrderInfoByDate', {
  117. date,
  118. page
  119. });
  120. }
  121. /**
  122. * 批量查询打印机状态
  123. */
  124. async batchQueryPrinterStatus(snList: string[]): Promise<FeiePrinterStatusResponse> {
  125. const snlist = snList.join('-');
  126. return this.executeRequest<FeiePrinterStatusResponse>('Open_queryPrinterStatus', {
  127. snlist
  128. });
  129. }
  130. /**
  131. * 获取打印机在线状态
  132. */
  133. async getPrinterOnlineStatus(sn: string): Promise<boolean> {
  134. try {
  135. const response = await this.queryPrinterStatus(sn);
  136. if (response.data && response.data.length > 0) {
  137. const printerStatus = response.data[0];
  138. return printerStatus.online === 1;
  139. }
  140. return false;
  141. } catch (error) {
  142. console.error('获取打印机在线状态失败:', error);
  143. return false;
  144. }
  145. }
  146. /**
  147. * 验证打印机配置
  148. */
  149. async validatePrinterConfig(sn: string, key: string): Promise<boolean> {
  150. try {
  151. // 临时创建一个配置来测试打印机
  152. const tempConfig: FeieApiConfig = {
  153. baseUrl: this.config.baseUrl,
  154. user: this.config.user,
  155. ukey: this.config.ukey
  156. };
  157. const tempService = new FeieApiService(tempConfig);
  158. const response = await tempService.queryPrinterStatus(sn);
  159. return response.ret === 0;
  160. } catch (error) {
  161. return false;
  162. }
  163. }
  164. }