快乐的梦鱼 2 周之前
父節點
當前提交
56e750a57d

+ 225 - 0
src/api/BaseAppServerRequestModule.ts

@@ -0,0 +1,225 @@
+import BugReporter from "@/common/BugReporter";
+import ApiCofig from "@/common/config/ApiCofig";
+import AppCofig, { isDev } from "@/common/config/AppCofig";
+import { RequestCoreInstance, RequestApiError, UniappImplementer, StringUtils, appendGetUrlParams, appendPostParams, RequestResponse, RequestOptions, type RequestApiInfoStruct, RequestApiResult, type RequestApiErrorType, defaultResponseDataGetErrorInfo, defaultResponseDataHandlerCatch } from "@imengyu/imengyu-utils";
+import type { DataModel, KeyValue, NewDataModel } from "@imengyu/js-request-transform";
+
+/**
+ * 说明:业务相关的请求模块
+ * * 请求数据处理函数。
+ * * 自定义请求模块。
+ * * 自定义错误报告处理函数。
+ */
+
+function matchNotReportMessage(code: number, str: string) {
+  if (ApiCofig.notReportErrorCode.includes(code))
+    return true;
+  for (let i = 0; i < ApiCofig.notReportMessages.length; i++) {
+    if (ApiCofig.notReportMessages[i].test(str))
+      return true;
+  }
+  return false;
+}
+//错误报告处理
+export function reportError<T extends DataModel>(instance: RequestCoreInstance<T>, response: RequestApiError | Error) {
+  if (isDev) {
+    //开发模式下直接弹窗显示
+    if (response instanceof RequestApiError) {
+      uni.showModal({
+        title: `请求错误 ${response.apiName} : ${response.errorMessage}`,
+        content: response.toString() +
+          '\r\n请求接口:' + response.apiName +
+          '\r\n请求地址:' + response.apiUrl +
+          '\r\n请求参数:' + JSON.stringify(response.apiRawReq) +
+          '\r\n返回参数:' + JSON.stringify(response.rawData) +
+          '\r\n状态码:' + response.code +
+          '\r\n信息:' + response.errorCodeMessage,
+        type: 'error',
+        showCancel: false,
+      });
+    } else {
+      uni.showModal({
+        title: '错误报告 代码错误',
+        content: response?.stack || ('' + response),
+        type: 'error',
+        showCancel: false,
+      });
+    }
+  } else {   
+    //生产模式下收集错误信息,报告错误服务器
+    let errMsg = '';
+    if (response instanceof RequestApiError) {
+      BugReporter.reportRequestBug({
+        errorType: response.errorType,
+        errorMessage: response.errorMessage,
+        apiName: response.apiName,
+        apiUrl: response.apiUrl,
+        rawRequest: response.apiRawReq,
+        rawData: response.rawData,
+        code: response.code.toString(),
+        errorCodeMessage: response.errorCodeMessage,
+        data: response.rawData,
+      });
+    } else  {
+      errMsg += '服务出现了异常,请稍后重试或联系客服。';
+      errMsg += '版本:' + AppCofig.version;
+      uni.showModal({
+        title: '抱歉',
+        content: errMsg,
+        showCancel: false,
+      });
+      BugReporter.reportError(response);
+    }
+  }
+}
+
+export class BaseAppServerRequestModule<T extends DataModel> extends RequestCoreInstance<T> {
+  constructor(baseUrl: string) {
+    super(UniappImplementer);
+    this.config.baseUrl = baseUrl;
+    this.config.errCodes = [];
+    //请求拦截器
+    this.config.requestInceptor = (url, req) => {
+      //获取app中的token,追加到头;
+      const app = getApp();
+      if (StringUtils.isNullOrEmpty((req.headers as KeyValue).token as string)) {
+        const t = app?.globalData?.token ?? '';
+        req.headers['token'] = t
+        req.headers['__token__'] = t;
+      }
+      const main_body_user_id = app?.globalData?.userId ?? '';
+      const append_main_body_user_id = !(url.includes('content/content'));
+
+      if (req.method == 'GET') {
+        //追加GET参数
+        url = appendGetUrlParams(url, 'main_body_id', ApiCofig.mainBodyId);
+        //url = appendGetUrlParams(url, 'platform', ApiCofig.platformId);
+        if (append_main_body_user_id)
+          url = appendGetUrlParams(url, 'main_body_user_id', main_body_user_id);
+      } else {
+        req.data = appendPostParams(req.data,'main_body_id', ApiCofig.mainBodyId);
+        //req.data = appendPostParams(req.data,'platform', ApiCofig.platformId);
+        if (append_main_body_user_id)
+          req.data = appendPostParams(req.data,'main_body_user_id', main_body_user_id);
+      } 
+      return { newUrl: url, newReq: req };
+    };
+    //响应数据处理函数
+    this.config.responseDataHandler = async function responseDataHandler<T extends DataModel>(response: RequestResponse, req: RequestOptions, resultModelClass: NewDataModel | undefined, instance: RequestCoreInstance<T>, apiInfo: RequestApiInfoStruct): Promise<RequestApiResult<T>> {
+      const method = req.method || 'GET';
+      try {
+        const json = await response.json();
+        if (response.ok) {
+          if (!json) {
+            throw new RequestApiError(
+              'businessError',
+              '后端未返回数据',
+              '',
+              response.status,
+              null,
+              null,
+              response.headers,
+              apiInfo
+            );
+          }
+
+          //code == 0 错误
+          if (json.code === 0) {
+            throw createError(json);
+          }
+
+          //处理后端的数据
+          let message = '未知错误';
+          let data = {} as any;
+
+          //后端返回格式不统一,所以在这里处理格式
+          if (typeof json.data === 'object') {
+            data = json.data;
+            message = json.data?.msg || response.statusText;
+          }
+          else {
+            //否则返回上层对象
+            data = json;
+            message = json.msg || response.statusText;
+          }
+
+          return new RequestApiResult(
+            resultModelClass ?? instance.config.modelClassCreator,
+            json?.code || response.status,
+            message,
+            data,
+            json,
+            response.headers,
+            apiInfo
+          );
+        }
+        else {
+          throw createError(json);
+        }
+
+        function createError(json: any): RequestApiError {
+          let errType : RequestApiErrorType = 'unknow';
+          let errString = '';
+          let errCodeStr = '';
+
+          if (typeof json.message === 'string') 
+            errString = json.message;
+          if (typeof json.msg === 'string') 
+            errString += json.msg;
+
+          if (StringUtils.isStringAllEnglish(errString))
+            errString = '服务器返回:' + errString;
+
+          //错误处理
+          if (errString) {
+            //如果后端有返回错误信息,则收集错误信息并返回
+            errType = 'businessError';
+            if (typeof json.data === 'object' && json.data?.errmsg) {
+              errString += '\n' + json.data.errmsg;
+            }
+            if (typeof json.errors === 'object') {
+              for (const key in json.errors) {
+                if (Object.prototype.hasOwnProperty.call(json.errors, key)) {
+                  errString += '\n' + json.errors[key];
+                }
+              }
+            }
+          } else {
+            const res = defaultResponseDataGetErrorInfo(response, json);
+            errType = res.errType;
+            errString = res.errString;
+            errCodeStr = res.errCodeStr;
+          }
+
+          return new RequestApiError(
+            errType,
+            errString,
+            errCodeStr,
+            response.status,
+            null,
+            null,
+            response.headers,
+            apiInfo
+          );
+        }
+      } catch (err) {
+        if (err instanceof RequestApiError) {
+          throw err;
+        }
+        //错误统一处理
+        return new Promise<RequestApiResult<T>>((resolve, reject) => {
+          defaultResponseDataHandlerCatch(method, req, response, null, err as any, apiInfo, response.url, reject, instance);
+        });
+      }
+    };
+    //错误报告处理
+    this.config.responseErrReoprtInceptor = (instance, response) => {
+      return (
+        (response.errorType !== 'businessError' && response.errorType !== 'networkError') ||
+        matchNotReportMessage(response.code, response.errorMessage) === true
+      );
+    };
+    //错误报告处理函数
+    this.config.reportError = reportError;
+  }
+}

+ 46 - 54
src/api/CommonContent.ts

@@ -388,13 +388,12 @@ export class CommonContentApi extends AppServerRequestModule<DataModel> {
     type?: number,
     withself?: boolean,
   ) {
-    return (this.get<KeyValue[]>('/content/category/getCategoryList', '获取分类列表', {
+    const res = await (this.get<KeyValue[]>('/content/category/getCategoryList', '获取分类列表', {
       type,
       is_tree: false,
       withself,
     }))
-      .then(res => transformArrayDataModel<CategoryListItem>(CategoryListItem, res.data!, `获取分类列表`, true))
-      .catch(e => { throw e });
+    return transformArrayDataModel<CategoryListItem>(CategoryListItem, res.data!, `获取分类列表`, true);
   }
   /**
    * 用于获取某一个分类需要用的子级
@@ -402,16 +401,15 @@ export class CommonContentApi extends AppServerRequestModule<DataModel> {
    * @returns 
    */
   async getCategoryChildList(pid?: number) {
-    return (this.get('/content/category/getCategoryOnlyChildList', '获取分类子级列表', {
+    const res = await this.get('/content/category/getCategoryOnlyChildList', '获取分类子级列表', {
       pid,
-    }))
-      .then(res => transformArrayDataModel<CategoryListItem>(
-        CategoryListItem, 
-        transformSomeToArray(res.data), 
-        `获取分类列表`, 
-        true
-      ))
-      .catch(e => { throw e });
+    });
+    return transformArrayDataModel<CategoryListItem>(
+      CategoryListItem, 
+      transformSomeToArray(res.data), 
+      `获取分类列表`, 
+      true
+    );
   }
   /**
    * 模型的主体栏目列表
@@ -419,16 +417,15 @@ export class CommonContentApi extends AppServerRequestModule<DataModel> {
    * @param querys 额外参数
    * @returns 
    */
-  getModelColumList<T extends DataModel = GetModelColumContentList>(model_id: number, page: number, pageSize: number = 10,querys?: QueryParams) {
-    return this.get('/content/main_body_column/getColumnList', `${this.debugName} 模型的主体栏目列表`, {
+  async getModelColumList<T extends DataModel = GetModelColumContentList>(model_id: number, page: number, pageSize: number = 10, querys?: QueryParams) {
+    const res = await this.get('/content/main_body_column/getColumnList', `${this.debugName} 模型的主体栏目列表`, {
       main_body_id: this.mainBodyId,
       model_id: model_id ?? this.modelId,
       page,
       pageSize,
       ...querys
-    })
-      .then(res => transformArrayDataModel<T>(GetModelColumContentList, res.data as any, `${this.debugName} 模型的主体栏目列表`, true))
-      .catch(e => { throw e });
+    });
+    return transformArrayDataModel<T>(GetModelColumContentList, res.data as any, `${this.debugName} 模型的主体栏目列表`, true);
   }
   /**
    * 主体栏目列表
@@ -436,18 +433,17 @@ export class CommonContentApi extends AppServerRequestModule<DataModel> {
    * @param querys 额外参数
    * @returns 
    */
-  getColumList<T extends DataModel = GetColumContentList>(params: GetColumListParams, modelClassCreator: NewDataModel = GetColumContentList, querys?: QueryParams) {
-    return this.get<{ list: T[], total: number }>('/content/content/getMainBodyColumnContentList', `${this.debugName} 主体栏目列表`, {
+  async getColumList<T extends DataModel = GetColumContentList>(params: GetColumListParams, modelClassCreator: NewDataModel = GetColumContentList, querys?: QueryParams) {
+    const res = await this.get<{ list: T[], total: number }>('/content/content/getMainBodyColumnContentList', `${this.debugName} 主体栏目列表`, {
       main_body_id: this.mainBodyId,
       model_id: this.modelId,
       ...params.toServerSide(),
       ...querys,
-    })
-      .then(res => ({
-        list: transformArrayDataModel<T>(modelClassCreator, requireNotNull(res.data).list, `${this.debugName} 主体栏目列表`, true),
-        total: requireNotNull(res.data).total as number,
-      }))
-      .catch(e => { throw e });
+    });
+    return {
+      list: transformArrayDataModel<T>(modelClassCreator, requireNotNull(res.data).list, `${this.debugName} 主体栏目列表`, true),
+      total: requireNotNull(res.data).total as number,
+    };
   }
   /**
    * 模型内容列表
@@ -457,8 +453,8 @@ export class CommonContentApi extends AppServerRequestModule<DataModel> {
    * @param querys 额外参数
    * @returns 
    */
-  getContentList<T extends DataModel = GetContentListItem>(params: GetContentListParams, page: number, pageSize: number = 10, modelClassCreator: NewDataModel = GetContentListItem, querys?: QueryParams) {
-    return this.get<{ list: T[], total: number }>('/content/content/getContentList', `${this.debugName} 模型内容列表`, {
+  async getContentList<T extends DataModel = GetContentListItem>(params: GetContentListParams, page: number, pageSize: number = 10, modelClassCreator: NewDataModel = GetContentListItem, querys?: QueryParams) {
+    const res = await this.get<{ list: T[], total: number }>('/content/content/getContentList', `${this.debugName} 模型内容列表`, {
       ...params.toServerSide(),
       model_id: params.modelId || this.modelId,
       main_body_id: params.mainBodyId || this.mainBodyId,
@@ -466,29 +462,26 @@ export class CommonContentApi extends AppServerRequestModule<DataModel> {
       page,
       pageSize,
       ...querys,
-    })
-      .then(res => {
-        let resList : any = null;
-        let resTotal : any = null;
-        if (res.data?.list && Array.isArray(res.data.list)) {
-          resList = res.data.list;
-          resTotal = res.data.total ?? resList.length;
-        }
-        else if (res.data && Array.isArray(res.data)) {
-          resList = res.data;
-          resTotal = resList.length;
-        } else
-          resList = res.data;
+    });
+    let resList : any = null;
+    let resTotal : any = null;
+    if (res.data?.list && Array.isArray(res.data.list)) {
+      resList = res.data.list;
+      resTotal = res.data.total ?? resList.length;
+    }
+    else if (res.data && Array.isArray(res.data)) {
+      resList = res.data;
+      resTotal = resList.length;
+    } else
+      resList = res.data;
 
-        if (resList === null)
-          return { list: [], total: 0 };
-        
-        return { 
-          list: transformArrayDataModel<T>(modelClassCreator, resList, `${this.debugName} 模型内容列表`, true),
-          total: resTotal as number,
-        }
-      })
-      .catch(e => { throw e });
+    if (resList === null)
+      return { list: [], total: 0 };
+    
+    return { 
+      list: transformArrayDataModel<T>(modelClassCreator, resList, `${this.debugName} 模型内容列表`, true),
+      total: resTotal as number,
+    };
   }
   /**
    * 内容详情
@@ -496,15 +489,14 @@ export class CommonContentApi extends AppServerRequestModule<DataModel> {
    * @param querys 额外参数
    * @returns 
    */
-  getContentDetail<T extends DataModel = GetContentDetailItem>(id: number, modelClassCreator: NewDataModel = GetContentDetailItem, modelId?: number, querys?: QueryParams) {
-    return this.get('/content/content/getContentDetail', `${this.debugName} (${id}) 内容详情`, {
+  async getContentDetail<T extends DataModel = GetContentDetailItem>(id: number, modelClassCreator: NewDataModel = GetContentDetailItem, modelId?: number, querys?: QueryParams) {
+    const res = await this.get('/content/content/getContentDetail', `${this.debugName} (${id}) 内容详情`, {
       main_body_id: this.mainBodyId,
       model_id: modelId ?? this.modelId,
       id,
       ...querys,
-    }, modelClassCreator)
-      .then(res => res.data as T)
-      .catch(e => { throw e });
+    }, modelClassCreator);
+    return res.data as T;
   }
 
   

+ 8 - 235
src/api/RequestModules.ts

@@ -1,246 +1,19 @@
 
 /**
- * 这里写的是业务相关的:
- * * 请求数据处理函数。
- * * 自定义请求模块。
- * * 自定义错误报告处理函数。
+ * 说明:
+ * * 不同服务器的请求模块。
  */
 
-import AppCofig, { isDev } from "../common/config/AppCofig";
 import ApiCofig from "@/common/config/ApiCofig";
-import { 
-  RequestCoreInstance, RequestOptions, RequestApiError, RequestApiResult, type RequestApiErrorType,
-  defaultResponseDataGetErrorInfo, defaultResponseDataHandlerCatch,
-  RequestResponse,
-  appendGetUrlParams, 
-  appendPostParams,
-  UniappImplementer,
-  type RequestApiInfoStruct,
-} from "@imengyu/imengyu-utils";
-import type { DataModel, KeyValue, NewDataModel } from "@imengyu/js-request-transform";
-import { StringUtils } from "@imengyu/imengyu-utils";
+import type { DataModel } from "@imengyu/js-request-transform";
+import { BaseAppServerRequestModule } from "./BaseAppServerRequestModule";
+import { isDev } from "@/common/config/AppCofig";
 
 /**
- * 不报告错误的 code
+ * 主应用服务请求模块
  */
-const notReportErrorCode = [401] as number[];
-const notReportMessages = [
-  /请授权绑定手机号/g,
-] as RegExp[];
-function matchNotReportMessage(str: string) {
-  for (let i = 0; i < notReportMessages.length; i++) {
-    if (notReportMessages[i].test(str))
-      return true;
-  }
-  return false;
-}
-
-//请求拦截器
-function requestInceptor(url: string, req: RequestOptions) {
-  //获取app中的token,追加到头;
-  const app = getApp();
-  if (StringUtils.isNullOrEmpty((req.headers as KeyValue).token as string)) {
-    const t = app?.globalData?.token ?? '';
-    req.headers['token'] = t
-    req.headers['__token__'] = t;
-  }
-  const main_body_user_id = app?.globalData?.userId ?? '';
-  const append_main_body_user_id = !(url.includes('content/content'));
-
-  if (req.method == 'GET') {
-    //追加GET参数
-    url = appendGetUrlParams(url, 'main_body_id', ApiCofig.mainBodyId);
-    //url = appendGetUrlParams(url, 'platform', ApiCofig.platformId);
-    if (append_main_body_user_id)
-      url = appendGetUrlParams(url, 'main_body_user_id', main_body_user_id);
-  } else {
-    req.data = appendPostParams(req.data,'main_body_id', ApiCofig.mainBodyId);
-    //req.data = appendPostParams(req.data,'platform', ApiCofig.platformId);
-    if (append_main_body_user_id)
-      req.data = appendPostParams(req.data,'main_body_user_id', main_body_user_id);
-  } 
-  return { newUrl: url, newReq: req };
-}
-//响应数据处理函数
-function responseDataHandler<T extends DataModel>(response: RequestResponse, req: RequestOptions, resultModelClass: NewDataModel | undefined, instance: RequestCoreInstance<T>, apiInfo: RequestApiInfoStruct): Promise<RequestApiResult<T>> {
-  return new Promise<RequestApiResult<T>>((resolve, reject) => {
-    const method = req.method || 'GET';
-    response.json().then((json) => {
-      if (response.ok) {
-        if (!json) {
-          reject(new RequestApiError(
-            'businessError',
-            '后端未返回数据',
-            '',
-            response.status,
-            null,
-            null,
-            response.headers,
-            apiInfo
-          ));
-          return;
-        }
-
-        //code == 0 错误
-        if (json.code === 0) {
-          handleError();
-          return;
-        }
-
-        //处理后端的数据
-        let message = '未知错误';
-        let data = {} as any;
-
-        //后端返回格式不统一,所以在这里处理格式
-        if (typeof json.data === 'object') {
-          data = json.data;
-          message = json.data?.msg || response.statusText;
-        }
-        else {
-          //否则返回上层对象
-          data = json;
-          message = json.msg || response.statusText;
-        }
-
-        resolve(new RequestApiResult(
-          resultModelClass ?? instance.config.modelClassCreator,
-          json?.code || response.status,
-          message,
-          data,
-          json,
-          response.headers,
-          apiInfo
-        ));
-      }
-      else {
-        handleError();
-      }
-
-      function handleError() {
-        let errType : RequestApiErrorType = 'unknow';
-        let errString = '';
-        let errCodeStr = '';
-
-        if (typeof json.message === 'string') 
-          errString = json.message;
-        if (typeof json.msg === 'string') 
-          errString += json.msg;
-
-        if (StringUtils.isStringAllEnglish(errString))
-          errString = '服务器返回:' + errString;
-
-        //错误处理
-        if (errString) {
-          //如果后端有返回错误信息,则收集错误信息并返回
-          errType = 'businessError';
-          if (typeof json.data === 'object' && json.data?.errmsg) {
-            errString += '\n' + json.data.errmsg;
-          }
-          if (typeof json.errors === 'object') {
-            for (const key in json.errors) {
-              if (Object.prototype.hasOwnProperty.call(json.errors, key)) {
-                errString += '\n' + json.errors[key];
-              }
-            }
-          }
-        } else {
-          const res = defaultResponseDataGetErrorInfo(response, json);
-          errType = res.errType;
-          errString = res.errString;
-          errCodeStr = res.errCodeStr;
-        }
-
-        reject(new RequestApiError(
-          errType,
-          errString,
-          errCodeStr,
-          response.status,
-          null,
-          null,
-          response.headers,
-          apiInfo
-        ));
-      }
-    }).catch((err) => {
-      //错误统一处理
-      defaultResponseDataHandlerCatch(method, req, response, null, err, apiInfo, response.url, reject, instance);
-    });
-  });
-}
-//错误报告处理
-function responseErrReoprtInceptor<T extends DataModel>(instance: RequestCoreInstance<T>, response: RequestApiError) {
-  return (
-    (response.errorType !== 'businessError' && response.errorType !== 'networkError') ||
-    notReportErrorCode.indexOf(response.code) >= 0 ||
-    matchNotReportMessage(response.errorMessage) === true
-  );
-}
-
-//错误报告处理
-export function reportError<T extends DataModel>(instance: RequestCoreInstance<T>, response: RequestApiError | Error) {
-  if (isDev) {
-    if (response instanceof RequestApiError) {
-      uni.showModal({
-        title: `请求错误 ${response.apiName} : ${response.errorMessage}`,
-        content: response.toString() +
-          '\r\n请求接口:' + response.apiName +
-          '\r\n请求地址:' + response.apiUrl +
-          '\r\n请求参数:' + JSON.stringify(response.apiRawReq) +
-          '\r\n返回参数:' + JSON.stringify(response.rawData) +
-          '\r\n状态码:' + response.code +
-          '\r\n信息:' + response.errorCodeMessage,
-        type: 'error',
-        showCancel: false,
-      });
-    } else {
-      uni.showModal({
-        title: '错误报告 代码错误',
-        content: response?.stack || ('' + response),
-        type: 'error',
-        showCancel: false,
-      });
-    }
-  } else {    
-    let errMsg = '';
-    if (response instanceof RequestApiError)
-      errMsg = response.errorMessage + '。';
-      
-    errMsg += '服务出现了异常,请稍后重试或联系客服。';
-    errMsg += '版本:' + AppCofig.version;
-
-    uni.showModal({
-      title: '抱歉',
-      content: errMsg,
-      showCancel: false,
-    });
-}
-}
-
-/**
- * App服务请求模块
- */
-export class AppServerRequestModule<T extends DataModel> extends RequestCoreInstance<T> {
-  constructor() {
-    super(UniappImplementer);
-    this.config.baseUrl = ApiCofig.serverProd;
-    this.config.errCodes = []; //
-    this.config.requestInceptor = requestInceptor;
-    this.config.responseDataHandler = responseDataHandler;
-    this.config.responseErrReoprtInceptor = responseErrReoprtInceptor;
-    this.config.reportError = reportError;
-  }
-}
-/**
- * App服务请求模块
- */
-export class AppServerRequestModule2<T extends DataModel> extends RequestCoreInstance<T> {
+export class AppServerRequestModule<T extends DataModel> extends BaseAppServerRequestModule<T> {
   constructor() {
-    super(UniappImplementer);
-    this.config.baseUrl = 'https://huli-app.wenlvti.net';
-    this.config.errCodes = []; //
-    this.config.requestInceptor = requestInceptor;
-    this.config.responseDataHandler = responseDataHandler;
-    this.config.responseErrReoprtInceptor = responseErrReoprtInceptor;
-    this.config.reportError = reportError;
+    super(isDev ? ApiCofig.server.Dev : ApiCofig.server.Prod);
   }
 }

+ 15 - 20
src/api/inhert/VillageApi.ts

@@ -139,18 +139,16 @@ export class VillageApi extends AppServerRequestModule<DataModel> {
   }
 
   async getClaimedVallageList(volunteerId?: string) {
-    return (this.get('/village/village/getVillageList', '获取已认领村落', {
+    const res = await this.get('/village/village/getVillageList', '获取已认领村落', {
       village_volunteer_id: volunteerId,
-    })) 
-      .then(res => transformArrayDataModel<VillageListItem>(VillageListItem, res.data as any, `村落`, true))
-      .catch(e => { throw e });
+    });
+    return transformArrayDataModel<VillageListItem>(VillageListItem, res.data as any, `村落`, true);
   }
   async getCanClaimVallageList() {
-    return (this.get('/village/village/getClaimList', '可认领村落列表', {
+    const res = await this.get('/village/village/getClaimList', '可认领村落列表', {
       main_body_id: 2,
-    })) 
-      .then(res => transformArrayDataModel<VillageListItem>(VillageListItem, transformSomeToArray(res.data), `可认领村落`, true))
-      .catch(e => { throw e });
+    });
+    return transformArrayDataModel<VillageListItem>(VillageListItem, transformSomeToArray(res.data), `可认领村落`, true);
   }
   async claimVallage(data: any) {
     return (this.post('/village/village/addVillageClaim', '认领村落', {
@@ -158,31 +156,28 @@ export class VillageApi extends AppServerRequestModule<DataModel> {
     })) ;
   }
   async getVallageList(level?: number) {
-    return (this.get('/village/village/getList', '村落列表', {
+    const res = await this.get('/village/village/getList', '村落列表', {
       history_level: level,
-    })) 
-      .then(res => transformArrayDataModel<VillageListItem>(VillageListItem, transformSomeToArray(res.data), `村落`, true))
-      .catch(e => { throw e });
+    });
+    return transformArrayDataModel<VillageListItem>(VillageListItem, transformSomeToArray(res.data), `村落`, true);
   }
 
   async getVolunteerInfo() {
     return (await this.post('/village/volunteer/getInfo', '获取志愿者信息', {}, undefined, VolunteerInfo)).data as VolunteerInfo
   }
   async getVolunteerRanklist(category?: number) {
-    return (this.post('/village/volunteer/getRanklist', '志愿者排行榜', {
+    const res = await this.post('/village/volunteer/getRanklist', '志愿者排行榜', {
       category,
-    })) 
-      .then(res => transformArrayDataModel<VolunteerRanklistItem>(VolunteerRanklistItem, res.data as any, ``, true))
-      .catch(e => { throw e });
+    });
+    return transformArrayDataModel<VolunteerRanklistItem>(VolunteerRanklistItem, res.data as any, ``, true);
   }
   
   async getVillageMenuList(id: number) {
-    return (this.get('/village/menu/getList', '村落菜单列表', {
+    const res = await this.get('/village/menu/getList', '村落菜单列表', {
       village_id: id,
       platform: 2,
-    })) 
-      .then(res => transformArrayDataModel<VillageMenuListItem>(VillageMenuListItem, res.data as any, `村落菜单`, true))
-      .catch(e => { throw e });
+    });
+    return transformArrayDataModel<VillageMenuListItem>(VillageMenuListItem, res.data as any, `村落菜单`, true);
   }
 
 }

+ 2 - 40
src/api/inhert/VillageInfoApi.ts

@@ -1,6 +1,5 @@
 import { DataModel, transformArrayDataModel } from '@imengyu/js-request-transform';
 import { AppServerRequestModule } from '../RequestModules';
-import { transformSomeToArray } from '../Utils';
 
 export class CategoryListItem extends DataModel<CategoryListItem> {
   constructor() {
@@ -137,42 +136,6 @@ export class VillageInfoApi extends AppServerRequestModule<DataModel> {
     super();
   }
 
-  /**
-   * 获取分类列表
-   * @param type 根级类型:1=区域、2=级别、3=文物类型、4=非遗类型、42=事件类型
-   * @param withself 是否返回包含自己:true=是,false=否 ,默认false
-   * @returns 
-   */
-  async getCategoryList(
-    type?: number,
-    withself?: boolean,
-  ) {
-    return (this.get('/village/village/getVillageList', '获取分类列表', {
-      type,
-      is_tree: false,
-      withself,
-    }))
-      .then(res => transformArrayDataModel<CategoryListItem>(CategoryListItem, res.data as any, `获取分类列表`, true))
-      .catch(e => { throw e });
-  }
-  /**
-   * 用于获取某一个分类需要用的子级
-   * @param pid 父级
-   * @returns 
-   */
-  async getCategoryChildList(pid?: number) {
-    return (this.get('/content/category/getCategoryOnlyChildList', '获取分类子级列表', {
-      pid,
-    }))
-      .then(res => transformArrayDataModel<CategoryListItem>(
-        CategoryListItem, 
-        transformSomeToArray(res.data), 
-        `获取分类列表`, 
-        true
-      ))
-      .catch(e => { throw e });
-  }
-
   async getInfo<T extends DataModel>(
     sub: string,
     subId: number,
@@ -196,13 +159,12 @@ export class VillageInfoApi extends AppServerRequestModule<DataModel> {
     villageVolunteerId: number,
     modelClassCreator: (new () => T) = VillageListItem as any 
   ) {
-    return (this.post(`/village/${sub}/getList`, '获取信息列表', {
+    const res = await (this.post(`/village/${sub}/getList`, '获取信息列表', {
       [subKey ? subKey : 'type']: subId,
       village_id: villageId,
       village_volunteer_id: villageVolunteerId,
     }))
-      .then(res => transformArrayDataModel<T>(modelClassCreator, res.data as any, `获取分类列表`, true))
-      .catch(e => { throw e });
+    return transformArrayDataModel<T>(modelClassCreator, res.data as any, `获取分类列表`, true);
   }
   async updateInfo<T extends DataModel>(
     sub: string,

+ 12 - 16
src/api/running/RunningApi.ts

@@ -176,12 +176,11 @@ export class RunningApi extends AppServerRequestModule<DataModel> {
   }
 
   async getActivityList(searchText?: string) {
-    return (this.get('/activity/activity/lists', '获取活动列表', {
+    const res = await this.get('/activity/activity/lists', '获取活动列表', {
       keywords: searchText,
       type: 3,
-    })) 
-      .then(res => transformArrayDataModel<ActivityListItem>(ActivityListItem, res.data as any, `活动列表`, true))
-      .catch(e => { throw e });
+    });
+    return transformArrayDataModel<ActivityListItem>(ActivityListItem, res.data as any, `活动列表`, true);
   }
   async getActivityDetail(id: number) {
     return (await this.get('/activity/activity/details', '获取活动详情', {
@@ -190,28 +189,25 @@ export class RunningApi extends AppServerRequestModule<DataModel> {
   }
  
   async getGuideList(searchText?: string) {
-    return (this.get('/volunteer/volunteer/getXuanjiangList', '获取宣讲员列表', {
+    const res = await this.get('/volunteer/volunteer/getXuanjiangList', '获取宣讲员列表', {
       keywords: searchText,
       type: 3,
-    })) 
-      .then(res => transformArrayDataModel<GuideListItem>(GuideListItem, res.data as any, `宣讲员列表`, true))
-      .catch(e => { throw e });
+    });
+    return transformArrayDataModel<GuideListItem>(GuideListItem, res.data as any, `宣讲员列表`, true);
   }
 
   async getScheduleList(activity_id: number) {
-    return (this.get('/activity/schedule/lists', '获取活动日程列表', {
+    const res = await this.get('/activity/schedule/lists', '获取活动日程列表', {
       activity_id,
-    })) 
-      .then(res => transformArrayDataModel<ActivityListDetail>(ActivityListDetail, res.data as any, `活动日程列表`, true))
-      .catch(e => { throw e });
+    });
+    return transformArrayDataModel<ActivityListDetail>(ActivityListDetail, res.data as any, `活动日程列表`, true);
   }
 
   async getSignupParamsList(activity_id: number) {
-    return (this.get('/activity/signup_params/lists', '获取活动报名参数列表', {
+    const res = await this.get('/activity/signup_params/lists', '获取活动报名参数列表', {
       activity_id,
-    })) 
-      .then(res => transformArrayDataModel<SignupParamsItem>(SignupParamsItem, res.data as any, `活动报名参数列表`, true))
-      .catch(e => { throw e });
+    });
+    return transformArrayDataModel<SignupParamsItem>(SignupParamsItem, res.data as any, `活动报名参数列表`, true);
   }
 
   async getGuideDetail(id: string) {

+ 2 - 3
src/api/user/ContributeApi.ts

@@ -26,11 +26,10 @@ export class ContributeApi extends AppServerRequestModule<DataModel> {
   }
 
   async getContributeList(page: number, pageSize: number) {
-    return (this.get('/content/main_body_user/getUserContribute', '用户投稿列表', {
+    const res = await (this.get('/content/main_body_user/getUserContribute', '用户投稿列表', {
       page, pageSize,
     })) 
-      .then(res => transformArrayDataModel<GetContentListItem>(GetContentListItem, res.data as any, `用户投稿列表`, true))
-      .catch(e => { throw e });
+    return transformArrayDataModel<GetContentListItem>(GetContentListItem, res.data as any, `用户投稿列表`, true);
   }
   async contribute(data: ContributeItem) {
     return (this.post('/content/content/contribute', '投稿', data));

+ 5 - 8
src/api/user/UserApi.ts

@@ -21,17 +21,14 @@ export class UserApi extends AppServerRequestModule<DataModel> {
     return (this.post('/content/main_body_user/unCollect', '取消收藏', { content_ids: id }));   
   }
   async getUserCollect(page: number, pageSize: number) {
-    return (this.post<{
+    const res = await (this.post<{
       data: GetContentDetailItem[],
       total: number,
     }>('/content/main_body_user/getUserCollect', '获取用户收藏', { page, pageSize })) 
-      .then(res => {
-        return { 
-          list: transformArrayDataModel(GetContentDetailItem, res.data?.data ?? [], `获取用户收藏列表`, true),
-          total: res.data?.total as number ?? 0,
-        }
-      })
-      .catch(e => { throw e });
+    return { 
+      list: transformArrayDataModel(GetContentDetailItem, res.data?.data ?? [], `获取用户收藏列表`, true),
+      total: res.data?.total as number ?? 0,
+    };
   }
 }
 

+ 57 - 0
src/common/BugReporter/impl/BugReporterAbstractionUniapp.ts

@@ -0,0 +1,57 @@
+/**
+ * BUG数据提交工具层
+ * 
+ * Copyright © 2025 imengyu.top imengyu-bugreport-server
+ */
+
+import Constants, { isProd } from '@/common/config/AppCofig';
+import type { BugDetailDeviceInfo, BugReporterAbstractionLayer } from '../index'
+
+const tagString = '[BugReporter] ';
+const errStorageClientDataKey = 'BugReporterClientData';
+
+export class BugReporterAbstractionUniapp implements BugReporterAbstractionLayer {
+  log(str: string): void {
+    console.log(tagString + str);
+  }
+  async getDeviceInfo(): Promise<BugDetailDeviceInfo> {
+    let dataStorage = await this.getStorage(errStorageClientDataKey);
+    if (!dataStorage) {
+      const res = await uni.getSystemInfo({}) as unknown as Record<string, unknown>;
+
+      dataStorage = {
+        deviceName: res.mode + '/' + res.model + '/' + res.brand + '/' + res.pixelRatio,
+        deviceVersion: res.system + '/' + res.version + '/SDKVersion: ' + res.SDKVersion,
+        appVersion: Constants.version,
+      } as BugDetailDeviceInfo;
+      
+      await this.setStorage(errStorageClientDataKey, dataStorage);
+    }
+    return dataStorage as BugDetailDeviceInfo;
+  }
+  async enable(): Promise<boolean> {
+    return isProd;
+  }
+  async doPost(url: string, body: unknown): Promise<void> {
+    await uni.request({
+      url,
+      data: body as AnyObject,
+      method: 'POST'
+    });
+  }
+  async getStorage(key: string): Promise<unknown> {
+    try {
+      const str = await uni.getStorage({ key }) as unknown as Record<string, string>;
+      return str.data ? JSON.parse(str.data) : null;
+    } catch {
+      return null;
+    }
+  }
+  async setStorage(key: string, value: unknown): Promise<void> {
+    await uni.setStorage({ key, data: JSON.stringify(value) });
+  }
+  async reomveStorage(key: string): Promise<void> {
+    await uni.removeStorage({ key });
+  }
+}
+

+ 393 - 0
src/common/BugReporter/index.ts

@@ -0,0 +1,393 @@
+/**
+ * BUG数据提交工具层
+ * 
+ * Copyright © 2025 imengyu.top imengyu-bugreport-server
+ */
+
+export interface BugReporterConfig {
+  /**
+   * 设置抽象层以 BugReporter 正常工作
+   */
+  abstractionLayer: BugReporterAbstractionLayer,
+  /**
+   * 错误收集服务器URL
+   */
+  serverUrl: string,
+  /**
+   * 应用ID
+   */
+  appId: number,
+  /**
+   * 应用KEY
+   */
+  appKey: string,
+  /**
+   * 是否立即提交错误(通常用于调试),否则为定时收集错误发送。默认:false
+   */
+  reportImmediately?: boolean,
+  /**
+   * 定时收集错误模式时错误数量超过此数值,进行提交。默认:8
+   */
+  delayMaxCount?: number,
+  /**
+   * 定时收集错误模式时, 超过指定时间(天),则进行提交。默认:2
+   */
+  delayTime?: number,
+  /**
+   * 在应用一次运行中,如果相同数量的错误出现次数超出此阈值,则强制提交一次错误。默认:4
+   */
+  errorSameRunTimeLimit?: number,
+}
+export interface BugReporterAbstractionLayer {
+  /**
+   * 获取设备信息钩子
+   */
+  getDeviceInfo: () => Promise<BugDetailDeviceInfo>;
+  /**
+   * 输出调试日志的钩子函数,这个函数返回false,将不启用错误提交功能
+   * 通常用于在开发时禁止提交错误到服务器
+   */
+  log: (str: string) => void;
+  /**
+   * 是否启用
+   */
+  enable: () => Promise<boolean>;
+  /**
+   * 自定义HTTP请求钩子
+   */
+  doPost: (url: string, body: unknown) => Promise<void>;
+  /**
+   * 自定义获取存储钩子
+   */
+  getStorage: (key: string) => Promise<unknown>;
+  /**
+   * 自定义设置存储钩子
+   */
+  setStorage: (key: string, value: unknown) => Promise<void>;
+  /**
+   * 自定义删除存储钩子
+   */
+  reomveStorage: (key: string) => Promise<void>;
+}
+
+//========================================================
+
+export function stringHash(str: string) : string {
+  let hash = 0, i, chr;
+  if (str.length === 0) return hash.toString();
+  for (i = 0; i < str.length; i++) {
+    chr   = str.charCodeAt(i);
+    hash  = ((hash << 5) - hash) + chr;
+    hash |= 0; // Convert to 32bit integer
+  }
+  return hash.toString();
+}
+function pad(num: number|string, n: number) : string {
+  let str = num.toString();
+  let len = str.length;
+  while (len < n) {
+    str = "0" + num;
+    len++;
+  }
+  return str;
+}
+function formatDate(date: Date, formatStr?: string) {
+  let str = formatStr ? formatStr : "YYYY-MM-dd HH:ii:ss";
+  str = str.replace(/yyyy|YYYY/, date.getFullYear().toString());
+  str = str.replace(/MM/, pad(date.getMonth() + 1, 2));
+  str = str.replace(/M/, (date.getMonth() + 1).toString());
+  str = str.replace(/dd|DD/, pad(date.getDate(), 2));
+  str = str.replace(/d/, date.getDate().toString());
+  str = str.replace(/HH/, pad(date.getHours(), 2));
+  str = str.replace(/hh/, pad(date.getHours() > 12 ? date.getHours() - 12 : date.getHours(), 2));
+  str = str.replace(/mm/, pad(date.getMinutes(), 2));
+  str = str.replace(/ii/, pad(date.getMinutes(), 2));
+  str = str.replace(/ss/, pad(date.getSeconds(), 2));
+  return str;
+}
+
+//========================================================
+
+const errStorageKey = 'BugReporterStorage';
+const errStorageCountKey = 'BugReporterStorageCount';
+const errStorageTimeKey = 'BugReporterStorageLastSubmitTime';
+const errStorageCustomKey = 'BugReporterStorageData';
+
+//========================================================
+
+const customDataArr = new Map<string, string>();
+const onceTimeHashCheck = new Map<string, number>();
+const defaultConfig : BugReporterConfig = {
+  abstractionLayer: {} as BugReporterAbstractionLayer,
+  serverUrl: '',
+  appId: 0,
+  appKey: '',
+  reportImmediately: false,
+  delayMaxCount: 8,
+  delayTime: 2,
+  errorSameRunTimeLimit: 4,
+};
+let abstractionLayer : BugReporterAbstractionLayer = {} as BugReporterAbstractionLayer;
+let config : BugReporterConfig = {} as BugReporterConfig;
+
+//========================================================
+
+const BugReporter = {
+  /**
+   * 配置
+   */
+  config(configData: BugReporterConfig) : void {
+    abstractionLayer = configData.abstractionLayer;
+    config = {
+      ...defaultConfig,
+      ...configData,
+    };
+    if (!abstractionLayer)
+      throw new Error('[BugReporter] You have not configured abstractionLayer, so you cannot use BugReporter.');
+    if (!configData.serverUrl)
+      abstractionLayer.log('serverUrl is not configured!');
+    if (!configData.appId)
+      abstractionLayer.log('appId is not configured!');
+    if (!configData.appKey)
+      abstractionLayer.log('appKey is empty!');
+  },
+  /**
+   * 添加与错误一并提交的自定义数据。注意,自定义数据不是持久保存的,在应用关闭后会丢失
+   * @param key 
+   * @param value 
+   */
+  addCustomData(key: string, value: string) : void {
+    customDataArr.set(key, value);
+  },
+  /**
+   * 获取之前设置的自定义数据
+   * @param key 
+   */
+  getCustomData(key: string) : string|null {
+    return customDataArr.get(key) || null;
+  },
+  /**
+   * 删除与错误一并提交的自定义数据
+   * @param key 
+   */
+  deleteCustomData(key: string) : void {
+    customDataArr.delete(key);
+  },
+  /**
+   * 设置与错误一并提交的用户ID数据
+   * @param userId 
+   */
+  async setUserId(userId: string) : Promise<void> {
+    await abstractionLayer.setStorage(errStorageCustomKey + 'UserId', userId);
+  },
+  /**
+   * 获取之前设置的用户ID
+   * @returns 
+   */
+  async getUserId(): Promise<string | null> {
+    return await abstractionLayer.getStorage(errStorageCustomKey + 'UserId') as string|null;
+  },
+  /**
+   * 程序启动时收集错误信息并提交
+   */
+  async checkAndReportBug() : Promise<boolean> {
+    if(!await abstractionLayer.enable())
+      return false;
+      
+    const errorCount = await abstractionLayer.getStorage(errStorageCountKey) as number || 0;
+    const submitLastTime = new Date(await abstractionLayer.getStorage(errStorageTimeKey) as string);
+  
+    if (
+      errorCount > 0 && 
+      (
+        errorCount > (config.delayMaxCount as number) 
+        || new Date().getTime() - submitLastTime.getTime() > (config.delayTime as number) * 1000 * 60 * 60 * 24
+      )
+    ) {
+      abstractionLayer.log('The number or time exceeds the threshold, now submit bug ');
+      abstractionLayer.log('Last submit time ' + formatDate(submitLastTime));
+      abstractionLayer.log('Error count ' + errorCount + '/' + config.delayMaxCount);
+  
+      this.reportBugsInStorage();
+      return true;
+    } else {
+      abstractionLayer.log('No need to submit bug now');
+    }
+   
+    return false;
+  },
+  /**
+   * 提交在暂存区中的错误信息
+   */
+  async reportBugsInStorage() : Promise<void> {
+    if(!await abstractionLayer.enable())
+      return ;
+   
+    const errorCount = await abstractionLayer.getStorage(errStorageCountKey) as number || 0;
+    abstractionLayer.log('Error count ' + errorCount + '/' + config.delayMaxCount);
+
+    //开始提交
+    const bugArr = [] as unknown[];
+    for(let i = 0; i < errorCount; i++) {
+      const obj = await abstractionLayer.getStorage(errStorageKey + i);
+      if (obj && typeof obj === 'object' && typeof (obj as Record<string, unknown>).errorType === 'number')
+        bugArr.push(obj);
+    }
+
+    abstractionLayer.log('Submit error now, count ' + bugArr.length + ' storage count: ' + errorCount);
+
+    try {
+      //立即提交错误
+      abstractionLayer.doPost(config.serverUrl, {
+        appId: config.appId,
+        app_key: config.appKey,
+        data: {
+          errorList: bugArr
+        }
+      })
+    } catch (e) {
+      abstractionLayer.log('Failed to report bug, will submit next time error: ' + e);
+      
+      //太多错误堆积,需要删除一些
+      if (errorCount > 256) {
+        abstractionLayer.log('Too many errors, clear some errors ' + (errorCount / 3));
+        for(let i = 0; i < errorCount / 3; i++)
+          abstractionLayer.reomveStorage(errStorageKey + i);
+      }
+      return;
+    }
+
+    //清除之前存储的数据
+    for(let i = 0; i < errorCount; i++)
+      abstractionLayer.reomveStorage(errStorageKey + i);
+    abstractionLayer.setStorage(errStorageCountKey, 0);
+    abstractionLayer.log('Clear bug storage count: ' + errorCount);
+    abstractionLayer.setStorage(errStorageTimeKey, new Date().toISOString()); //设置当前时间
+  },
+  /**
+   * 提交Bug
+   * @param type 0 普通Bug 1 请求Bug 2 崩溃Bug  3 其他
+   * @param hash 对这个错误信息进行归类的hash,当相同hash错误发生时,将在后台系统中归类显示,有助于您查找Bug
+   * @param summary 对这个错误进行简要描述的文案,有助于您查找Bug
+   * @param data 主要错误信息
+   * @param extendData 附加错误信息
+   */
+  async reportBug(type: number, hash: string, summary: string, data: unknown, extendData?: Record<string, string>) : Promise<void> {
+    if(!await abstractionLayer.enable())
+      return;
+
+    //获取设备信息
+    const deviceInfo = await abstractionLayer.getDeviceInfo();
+  
+    //追加自定义数据
+    const finalExtendData : Record<string, string> = extendData || {};
+    customDataArr.forEach((v, k) => finalExtendData[k] = v);
+
+    //检查本次运行错误数量
+    let forceReportThisTime = false;
+    const onceTimeCount = onceTimeHashCheck.get(hash);
+    if (onceTimeCount) {
+      onceTimeHashCheck.set(hash, onceTimeCount + 1);
+      if (onceTimeCount > (config.errorSameRunTimeLimit as number))
+        forceReportThisTime = true;
+    } else {
+      onceTimeHashCheck.set(hash, 1);
+    }
+  
+    //错误对象
+    const errorObj = {
+      errorHash: hash,
+      errorSummary: summary,
+      errorData: JSON.stringify(data),
+      errorDeviceName: deviceInfo.deviceName,
+      errorDeviceVersion: deviceInfo.deviceVersion,
+      errorAppVersion: deviceInfo.appVersion,
+      errorUserId: await this.getUserId(),
+      errorAdditionData: JSON.stringify(finalExtendData),
+      errorTime: formatDate(new Date()),
+      errorType: type
+    };
+  
+    if (config.reportImmediately) {
+      try {
+        //立即提交错误
+        abstractionLayer.doPost(config.serverUrl, {
+          appId: config.appId,
+          appKey: config.appKey,
+          data: {
+            errorList: [ errorObj ]
+          }
+        });
+      } catch (e) {
+        abstractionLayer.log('Failed to report bug. error: ' + e);
+      }
+    } else {
+      //存储当前条目至存储中
+      const errorCount = await abstractionLayer.getStorage(errStorageCountKey) as number || 0;
+      abstractionLayer.setStorage(errStorageKey + errorCount, errorObj);//设置存储
+      abstractionLayer.setStorage(errStorageCountKey, errorCount + 1);//数量+1
+      
+      //检查相关阈值,并提交错误
+      if (forceReportThisTime)
+        this.reportBugsInStorage();
+      else
+        await this.checkAndReportBug();
+    }
+  },
+  /**
+   * 提交请求类错误
+   * @param data 主要错误信息
+   * @param extendData 附加错误信息
+   */
+  async reportRequestBug(data: BugDetailErrorRequestData, extendData?: Record<string, string>) : Promise<void> {
+    await this.reportBug(1, stringHash(data.errorMessage), `请求错误:${data.errorMessage}`, data, extendData);
+  },
+  /**
+   * 提交崩溃类错误
+   * @param data 主要错误信息
+   * @param extendData 附加错误信息
+   */
+  async reportCrashBug(data: BugDetailErrorCrashData, extendData?: Record<string, string>) : Promise<void> {
+    await this.reportBug(2, stringHash(data.errorMessage), `崩溃:${data.errorMessage}`, data, extendData);
+  },
+  /**
+   * 提交普通错误
+   * @param e 主要错误信息
+   * @param extendData 附加错误信息
+   */
+  async reportError(e: Error|string, extendData?: Record<string, string>) : Promise<void> {
+    await this.reportBug(2, 
+      stringHash(typeof e === 'string' ? e : (e.message || ('' + e))), 
+      '' + e, 
+      (e instanceof Error ? e.stack : ''), 
+      extendData
+    );
+  }
+}
+
+export interface BugDetailDeviceInfo {
+  deviceName: string;
+  deviceVersion: string;
+  appVersion: string;
+}
+export interface BugDetailErrorRequestData {
+  apiName: string;
+  apiUrl: string;
+  code: string;
+  errorType: string;
+  errorMessage: string;
+  errorCodeMessage: string;
+  data: unknown;
+  rawData: unknown;
+  rawRequest: unknown;
+}
+export interface BugDetailErrorCrashData {
+  deviceName: string;
+  deviceRom: string;
+  deviceSystemVersion: string;
+  errorCode: string;
+  errorMessage: string;
+  errorStack: string;
+}
+
+export default BugReporter;

+ 14 - 2
src/common/config/ApiCofig.ts

@@ -3,8 +3,20 @@
  * 说明:后端接口配置
  */
 export default {
-  serverDev: 'https://mn.wenlvti.net/api',
-  serverProd: 'https://mn.wenlvti.net/api',
+  server: {
+    Dev: 'https://mn.wenlvti.net/api',
+    Prod: 'https://mn.wenlvti.net/api',
+  },
   mainBodyId: 1,
   platformId: 327,
+  /**
+   * 不报告错误的 code
+   */
+  notReportErrorCode: [401],
+  /**
+   * 不报告错误的 message
+   */
+  notReportMessages: [
+    /请授权绑定手机号/g,
+  ] as RegExp[],
 }