{"_id":"@chuangxi/ajax-package","_rev":"8-8c1f928c62f397d7f172525bcc5d11bc","name":"@chuangxi/ajax-package","dist-tags":{"latest":"0.0.9"},"versions":{"0.0.3":{"name":"@chuangxi/ajax-package","version":"0.0.3","license":"MIT","_id":"@chuangxi/ajax-package@0.0.3","maintainers":[{"name":"chuangxi","email":"397171278@qq.com"}],"dist":{"shasum":"502e2eff4c6c652cf1675bb0ee75a3ea6a8b9f06","tarball":"https://registry.npmjs.org/@chuangxi/ajax-package/-/ajax-package-0.0.3.tgz","fileCount":16,"integrity":"sha512-FGRvArmteFjob7w1Ojt1DhvucHmLN2Ly/N6pCbJnBF5WzDRNsFHPW5obhuaBNT77KsDIrVXLRJvd+LTU10xEDg==","signatures":[{"sig":"MEQCIGHyMkT2qUYigqf8tRDkFPPJEiM22ugf4Wwx3naTHdjGAiA8nHp79DaJ0/rIk8gEakFPhzwL+d/SYn03NDd5nEtlwQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":329928},"types":"es/index.d.ts","module":"es/index.mjs","exports":{".":{"import":{"types":"./es/index.d.ts","default":"./es/index.mjs"}},"./es":{"import":{"types":"./es/index.d.ts","default":"./es/index.mjs"}}},"gitHead":"c0e1834df2d17db7145b67c2e137da805738ed65","_npmUser":{"name":"chuangxi","email":"397171278@qq.com"},"_npmVersion":"10.8.2","description":"AjaxPackage 组件","directories":{},"sideEffects":["*.css","*.scss"],"_nodeVersion":"20.19.4","dependencies":{},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"vue":"^3.5.27"},"_npmOperationalInternal":{"tmp":"tmp/ajax-package_0.0.3_1781143274942_0.008146546377312491","host":"s3://npm-registry-packages-npm-production"}},"0.0.4":{"name":"@chuangxi/ajax-package","version":"0.0.4","license":"MIT","_id":"@chuangxi/ajax-package@0.0.4","maintainers":[{"name":"chuangxi","email":"397171278@qq.com"}],"dist":{"shasum":"20bc8e0254fc122740d0d733bc5f8b78361bc6f5","tarball":"https://registry.npmjs.org/@chuangxi/ajax-package/-/ajax-package-0.0.4.tgz","fileCount":16,"integrity":"sha512-NP/I2sJv7wrXcOpxdZgGkeEHB4D5WLzWvTyX/+vG4DSDieJKaS34gBRDPOzek8lYBh90kXiw160U6A8cQCRedA==","signatures":[{"sig":"MEQCIADIZTp2d6LzZPP7cyo23cGa2qC7u8f3+690YQ2QkBZ/AiBqxpQstgIOks7NJrByRuYiJAHInRkSXx95V0FhCM2zPg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":329942},"types":"es/index.d.ts","module":"es/index.mjs","exports":{".":{"import":{"types":"./es/index.d.ts","default":"./es/index.mjs"}},"./es":{"import":{"types":"./es/index.d.ts","default":"./es/index.mjs"}}},"gitHead":"c0e1834df2d17db7145b67c2e137da805738ed65","_npmUser":{"name":"chuangxi","email":"397171278@qq.com"},"_npmVersion":"10.8.2","description":"AjaxPackage 组件","directories":{},"sideEffects":["*.css","*.scss"],"_nodeVersion":"20.19.4","dependencies":{},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"vue":"^3.5.27"},"_npmOperationalInternal":{"tmp":"tmp/ajax-package_0.0.4_1781152560698_0.04102850369458344","host":"s3://npm-registry-packages-npm-production"}},"0.0.5":{"name":"@chuangxi/ajax-package","version":"0.0.5","license":"MIT","_id":"@chuangxi/ajax-package@0.0.5","maintainers":[{"name":"chuangxi","email":"397171278@qq.com"}],"dist":{"shasum":"cf88b8d2cd7dbe981e6722bcf43e114176627973","tarball":"https://registry.npmjs.org/@chuangxi/ajax-package/-/ajax-package-0.0.5.tgz","fileCount":16,"integrity":"sha512-x56z3HN8wnrPfJ/n1Wgu5QuPhn/Cq2oKWPoKEmojwDG3APqHfZdlA3vbn4XJpOf5/1Z7XCzewBfcQXkqC4RNAg==","signatures":[{"sig":"MEYCIQCv8Lh+V8yxsmxGbHYlTEhHyUvdMyOv5CwZV1UIWK078gIhAPjcCutgcIkt5sQWIwvql6a3K4vpkQE4KNQfx1ZnrZox","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":330041},"types":"es/index.d.ts","module":"es/index.mjs","exports":{".":{"import":{"types":"./es/index.d.ts","default":"./es/index.mjs"}},"./es":{"import":{"types":"./es/index.d.ts","default":"./es/index.mjs"}}},"gitHead":"c0e1834df2d17db7145b67c2e137da805738ed65","_npmUser":{"name":"chuangxi","email":"397171278@qq.com"},"_npmVersion":"10.8.2","description":"AjaxPackage 组件","directories":{},"sideEffects":["*.css","*.scss"],"_nodeVersion":"20.19.4","dependencies":{},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"vue":"^3.5.27"},"_npmOperationalInternal":{"tmp":"tmp/ajax-package_0.0.5_1781153850232_0.1442407430232273","host":"s3://npm-registry-packages-npm-production"}},"0.0.6":{"name":"@chuangxi/ajax-package","version":"0.0.6","license":"MIT","_id":"@chuangxi/ajax-package@0.0.6","maintainers":[{"name":"chuangxi","email":"397171278@qq.com"}],"dist":{"shasum":"4c6531c2ef5b7ff6d762443e390f0f7ebf755916","tarball":"https://registry.npmjs.org/@chuangxi/ajax-package/-/ajax-package-0.0.6.tgz","fileCount":16,"integrity":"sha512-wCIOTGXQ3PQ9UZFzO5rqbSSjxdNmLP5JrTZylCH+N/ZeBOdMDY/88k2TLnT3ydp8xNPJvngXyCMm6Z08DldKtg==","signatures":[{"sig":"MEQCIAmOO3dgdfA1ZmjV2Q72gY5y9CY1fVpz0Huyof3cqQSPAiARKHesVj5s4uRVcakS7Kge3bBWyxtzXTByq6ItQv6Y4w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":330041},"types":"es/index.d.ts","module":"es/index.mjs","exports":{".":{"import":{"types":"./es/index.d.ts","default":"./es/index.mjs"}},"./es":{"import":{"types":"./es/index.d.ts","default":"./es/index.mjs"}}},"gitHead":"c0e1834df2d17db7145b67c2e137da805738ed65","_npmUser":{"name":"chuangxi","email":"397171278@qq.com"},"_npmVersion":"10.8.2","description":"AjaxPackage 组件","directories":{},"sideEffects":["*.css","*.scss"],"_nodeVersion":"20.19.4","dependencies":{},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"vue":"^3.5.27"},"_npmOperationalInternal":{"tmp":"tmp/ajax-package_0.0.6_1781154571475_0.910905780703269","host":"s3://npm-registry-packages-npm-production"}},"0.0.7":{"name":"@chuangxi/ajax-package","version":"0.0.7","license":"MIT","_id":"@chuangxi/ajax-package@0.0.7","maintainers":[{"name":"chuangxi","email":"397171278@qq.com"}],"dist":{"shasum":"ee63596fedc2fdcd7211eb739dccfdc5db1d4984","tarball":"https://registry.npmjs.org/@chuangxi/ajax-package/-/ajax-package-0.0.7.tgz","fileCount":16,"integrity":"sha512-YdV+DrQvan8yMqg16SYP9ayxRTYJFPxAAjLOuX5fZ1JVrd3ko1hGwVbBZnLPvTNYBVxGKZ9YsOTme6umWrQH/w==","signatures":[{"sig":"MEQCIAzhOpNjl1eBp+8b4Y6+TemxCwCLGL11HKMS0nnk3jXcAiBYai+nvWelYY4i6ljS4myYyoKDk2Ny2QSqgnfbUB6S8Q==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":330165},"types":"es/index.d.ts","module":"es/index.mjs","exports":{".":{"import":{"types":"./es/index.d.ts","default":"./es/index.mjs"}},"./es":{"import":{"types":"./es/index.d.ts","default":"./es/index.mjs"}}},"gitHead":"c0e1834df2d17db7145b67c2e137da805738ed65","_npmUser":{"name":"chuangxi","email":"397171278@qq.com"},"_npmVersion":"10.8.2","description":"AjaxPackage 组件","directories":{},"sideEffects":["*.css","*.scss"],"_nodeVersion":"20.19.4","dependencies":{},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"vue":"^3.5.27"},"_npmOperationalInternal":{"tmp":"tmp/ajax-package_0.0.7_1781154727121_0.8182269576814971","host":"s3://npm-registry-packages-npm-production"}},"0.0.8":{"name":"@chuangxi/ajax-package","version":"0.0.8","license":"MIT","_id":"@chuangxi/ajax-package@0.0.8","maintainers":[{"name":"chuangxi","email":"397171278@qq.com"}],"dist":{"shasum":"9f089b8a8d6f1603f15d8250b733658d4bd7d714","tarball":"https://registry.npmjs.org/@chuangxi/ajax-package/-/ajax-package-0.0.8.tgz","fileCount":16,"integrity":"sha512-IjUURgA3XBAOV/6GfWVaxM6a5gGKbjQBBowipxhMkj3qgWQhyYaw8x4275Jt+AODOIYEQMRc5lBQH/mH/yVPpw==","signatures":[{"sig":"MEUCIQDzToQ0YjbW2Z9JxbIPwzm4x57VgHrF+1N3t34+kj19RAIgB/v0JiaXPodKAa6qY9Drt3H72eIlYfxTeb/ekIcQC58=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":329928},"types":"es/index.d.ts","module":"es/index.mjs","exports":{".":{"import":{"types":"./es/index.d.ts","default":"./es/index.mjs"}},"./es":{"import":{"types":"./es/index.d.ts","default":"./es/index.mjs"}}},"gitHead":"c0e1834df2d17db7145b67c2e137da805738ed65","_npmUser":{"name":"chuangxi","email":"397171278@qq.com"},"_npmVersion":"10.8.2","description":"AjaxPackage 组件","directories":{},"sideEffects":["*.css","*.scss"],"_nodeVersion":"20.19.4","dependencies":{},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"vue":"^3.5.27"},"_npmOperationalInternal":{"tmp":"tmp/ajax-package_0.0.8_1781504387779_0.6687700046679572","host":"s3://npm-registry-packages-npm-production"}},"0.0.9":{"name":"@chuangxi/ajax-package","version":"0.0.9","description":"AjaxPackage 组件","sideEffects":["*.css","*.scss"],"peerDependencies":{"vue":"^3.5.40"},"dependencies":{},"publishConfig":{"access":"public"},"license":"MIT","module":"es/index.mjs","types":"es/index.d.ts","exports":{"./es":{"import":{"types":"./es/index.d.ts","default":"./es/index.mjs"}},".":{"import":{"types":"./es/index.d.ts","default":"./es/index.mjs"}}},"_id":"@chuangxi/ajax-package@0.0.9","gitHead":"ff5fdd777bf39064a107643ebb9d4ddc5a7a451c","_nodeVersion":"22.18.0","_npmVersion":"10.9.3","dist":{"integrity":"sha512-LYvYzBhMSd8r2YmyxPBJ4un3JIWWoVRhhotcEdWcd8jYl8EkQDWTknDgRdnWT31gDwy57ArJ2AMQ4gwtXSDWmg==","shasum":"e05f2a6b13dc5280e1280dc2f14651fd6512a9b8","tarball":"https://registry.npmjs.org/@chuangxi/ajax-package/-/ajax-package-0.0.9.tgz","fileCount":16,"unpackedSize":330345,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCiB1x7K6DJk4jzjbGcVPkqc4c6H6wW0n7cjUt9ECBHlwIhAN3vgejGJSqq2KDM9vfxPjYEaAn/OEQ6x/ZQ6IoSfOcy"}]},"_npmUser":{"name":"chuangxi","email":"397171278@qq.com"},"directories":{},"maintainers":[{"name":"chuangxi","email":"397171278@qq.com"},{"name":"leonfu","email":"396156398@qq.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/ajax-package_0.0.9_1787645566637_0.9751437830035963"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-11T02:01:14.755Z","modified":"2026-08-25T08:12:46.943Z","0.0.3":"2026-06-11T02:01:15.082Z","0.0.4":"2026-06-11T04:36:00.878Z","0.0.5":"2026-06-11T04:57:30.371Z","0.0.6":"2026-06-11T05:09:31.656Z","0.0.7":"2026-06-11T05:12:07.248Z","0.0.8":"2026-06-15T06:19:47.912Z","0.0.9":"2026-08-25T08:12:46.783Z"},"license":"MIT","description":"AjaxPackage 组件","maintainers":[{"name":"chuangxi","email":"397171278@qq.com"},{"name":"leonfu","email":"396156398@qq.com"}],"readme":"# AjaxPackage\n\n统一的 HTTP 服务封装与约定。提供 `getHttpService` 工厂函数、`BaseApi` 类以及 Vue 插件等多种使用方式，内置超时、token、响应字段映射、错误处理等能力。\n\n## 导出\n\n- 函数：`getHttpService(options: HttpServiceOptions): HttpService`\n  - 创建 HTTP 服务实例，提供快捷方法\n- 函数：`createHttpService(options: HttpServiceOptions): HttpService`\n  - 与 `getHttpService` 功能相同\n- 类：`BaseApi`\n  - 基于 axios 封装的类式 API 请求工具\n- 插件：`VueAxiosPlugin`\n  - Vue Axios 插件，提供全局的 `$http` 方法\n\n## 快速开始\n\n### 使用 getHttpService\n\n```ts\nimport { getHttpService } from '@chuangxi/ajaxpackage'\n\nconst httpApi = getHttpService({\n  baseURL: 'https://api.example.com',\n  timeout: 5000,\n  getToken: () => localStorage.getItem('token'),\n  responseFields: {\n    code: 'Code',\n    message: 'Message',\n    data: 'data',\n  },\n})\n\nexport function getUserList(params: any) {\n  return httpApi.get('/users', params)\n}\n\nexport function createUser(data: any) {\n  return httpApi.post('/users', data)\n}\n```\n\n### 使用 BaseApi 类\n\n```ts\nimport { BaseApi } from '@chuangxi/ajaxpackage'\n\nconst api = new BaseApi({\n  baseURL: 'https://api.example.com',\n  timeout: 5000,\n  responseFields: {\n    code: 'code',\n    message: 'message',\n    data: 'data',\n  },\n})\n\nexport async function getUserList(params: any) {\n  return api.get('/users', params)\n}\n\nexport async function createUser(data: any) {\n  return api.post('/users', data)\n}\n```\n\n### 使用 Vue 插件\n\n```ts\nimport { createApp } from 'vue'\nimport VueAxiosPlugin from '@chuangxi/ajaxpackage'\n\nconst app = createApp(App)\n\napp.use(VueAxiosPlugin, {\n  default: {\n    baseURL: 'https://api.example.com',\n    timeout: 5000,\n    getToken: () => localStorage.getItem('token'),\n  },\n})\n\n// 在组件中使用\nexport default {\n  async mounted() {\n    const data = await this.$http.get('/users')\n  },\n}\n```\n\n## getHttpService 配置项\n\n### HttpServiceOptions\n\n| 选项 | 说明 | 类型 | 必填 | 默认值 |\n| --- | --- | --- | --- | --- |\n| `baseURL` | 服务地址 | `string` | 是 | `''` |\n| `timeout` | 超时时间（毫秒） | `number` | 否 | `5000` |\n| `getToken` | 获取 token 的函数 | ^[Function]`() => string \\| null` | 否 | `() => null` |\n| `onLoginRequired` | 登录失效回调函数 | ^[Function]`() => void` | 否 | `() => { window.location.href = '/login?redirect=' + encodeURIComponent(window.location.href) }` |\n| `responseFields` | 响应字段映射 | ^[Object]`{ code?: string; message?: string; data?: string; errors?: string; tips?: string }` | 否 | `{ code: 'code', message: 'msg', data: 'data' }` |\n\n### responseFields 字段说明\n\n| 字段 | 说明 | 类型 | 默认值 |\n| --- | --- | --- | --- |\n| `code` | 状态码字段名，支持路径解析（如 `'result.code'`） | `string` | `'code'` |\n| `message` | 消息字段名，支持路径解析 | `string` | `'msg'` |\n| `data` | 数据字段名，支持路径解析 | `string` | `'data'` |\n| `errors` | 错误数组字段名 | `string` | `undefined` |\n| `tips` | 提示信息字段名 | `string` | `undefined` |\n\n### 使用示例：基础配置\n\n```ts\nimport { getHttpService } from '@chuangxi/ajaxpackage'\n\nconst httpApi = getHttpService({\n  baseURL: 'https://api.example.com',\n  timeout: 5000,\n  getToken: () => {\n    return localStorage.getItem('token') || ''\n  },\n  responseFields: {\n    code: 'Code',\n    message: 'Message',\n    data: 'data',\n  },\n})\n```\n\n### 使用示例：自定义响应字段映射\n\n```ts\nimport { getHttpService } from '@chuangxi/ajaxpackage'\n\nconst httpApi = getHttpService({\n  baseURL: 'https://api.example.com',\n  timeout: 5000,\n  responseFields: {\n    code: 'status', // 自定义状态码字段\n    message: 'msg', // 自定义消息字段\n    data: 'result', // 自定义数据字段\n    errors: 'errorList', // 自定义错误数组字段\n    tips: 'tipList', // 自定义提示信息字段\n  },\n})\n```\n\n### 使用示例：路径解析\n\n```ts\nimport { getHttpService } from '@chuangxi/ajaxpackage'\n\nconst httpApi = getHttpService({\n  baseURL: 'https://api.example.com',\n  responseFields: {\n    code: 'result.code', // 支持嵌套路径解析\n    message: 'result.message',\n    data: 'result.data',\n  },\n})\n```\n\n### 使用示例：登录失效处理\n\n```ts\nimport { getHttpService } from '@chuangxi/ajaxpackage'\n\nconst httpApi = getHttpService({\n  baseURL: 'https://api.example.com',\n  getToken: () => localStorage.getItem('token'),\n  onLoginRequired: () => {\n    // 清除本地 token\n    localStorage.removeItem('token')\n    // 跳转到登录页\n    window.location.href = '/login?redirect=' + encodeURIComponent(window.location.href)\n  },\n})\n```\n\n## HttpService 实例方法\n\n### get(url, params, config)\n\n发送 GET 请求。\n\n**参数：**\n- `url: string` - 请求 URL\n- `params?: object` - 查询参数\n- `config?: AxiosRequestConfig` - axios 配置\n\n**返回：** `Promise<any>`\n\n**示例：**\n\n```ts\nimport { getHttpService } from '@chuangxi/ajaxpackage'\n\nconst httpApi = getHttpService({\n  baseURL: 'https://api.example.com',\n})\n\nasync function getUserList() {\n  const data = await httpApi.get('/users', { page: 1, size: 10 })\n  return data\n}\n\nasync function getUserById(id: string) {\n  const data = await httpApi.get(`/users/${id}`)\n  return data\n}\n\nasync function searchUsers(keyword: string) {\n  const data = await httpApi.get('/users/search', { keyword }, {\n    headers: {\n      'X-Custom-Header': 'custom-value',\n    },\n  })\n  return data\n}\n```\n\n### post(url, data, config, addSign)\n\n发送 POST 请求。\n\n**参数：**\n- `url: string` - 请求 URL\n- `data?: any` - 请求体数据\n- `config?: AxiosRequestConfig` - axios 配置\n- `addSign?: (config: AxiosRequestConfig) => void` - 签名函数，用于在请求前修改配置\n\n**返回：** `Promise<any>`\n\n**示例：**\n\n```ts\nimport { getHttpService } from '@chuangxi/ajaxpackage'\nimport type { AxiosRequestConfig } from 'axios'\n\nconst httpApi = getHttpService({\n  baseURL: 'https://api.example.com',\n})\n\nasync function createUser(userData: any) {\n  const data = await httpApi.post('/users', userData)\n  return data\n}\n\nasync function updateUser(id: string, userData: any) {\n  const data = await httpApi.post(`/users/${id}`, userData, {\n    headers: {\n      'Content-Type': 'application/json',\n    },\n  })\n  return data\n}\n\nasync function createUserWithSign(userData: any) {\n  function addSign(config: AxiosRequestConfig) {\n    const timestamp = Date.now()\n    const sign = generateSign(userData, timestamp)\n    config.headers = config.headers || {}\n    config.headers['X-Timestamp'] = timestamp.toString()\n    config.headers['X-Sign'] = sign\n  }\n\n  const data = await httpApi.post('/users', userData, {}, addSign)\n  return data\n}\n\nfunction generateSign(data: any, timestamp: number): string {\n  // 签名生成逻辑\n  return 'signature'\n}\n```\n\n### put(url, data, config)\n\n发送 PUT 请求。\n\n**参数：**\n- `url: string` - 请求 URL\n- `data?: any` - 请求体数据\n- `config?: AxiosRequestConfig` - axios 配置\n\n**返回：** `Promise<any>`\n\n**示例：**\n\n```ts\nimport { getHttpService } from '@chuangxi/ajaxpackage'\n\nconst httpApi = getHttpService({\n  baseURL: 'https://api.example.com',\n})\n\nasync function updateUser(id: string, userData: any) {\n  const data = await httpApi.put(`/users/${id}`, userData)\n  return data\n}\n\nasync function updateUserPartial(id: string, partialData: any) {\n  const data = await httpApi.put(`/users/${id}`, partialData, {\n    headers: {\n      'Content-Type': 'application/json-patch+json',\n    },\n  })\n  return data\n}\n```\n\n### delete(url, params, config)\n\n发送 DELETE 请求。\n\n**参数：**\n- `url: string` - 请求 URL\n- `params?: object` - 查询参数\n- `config?: AxiosRequestConfig` - axios 配置\n\n**返回：** `Promise<any>`\n\n**示例：**\n\n```ts\nimport { getHttpService } from '@chuangxi/ajaxpackage'\n\nconst httpApi = getHttpService({\n  baseURL: 'https://api.example.com',\n})\n\nasync function deleteUser(id: string) {\n  const data = await httpApi.delete(`/users/${id}`)\n  return data\n}\n\nasync function deleteUsers(ids: string[]) {\n  const data = await httpApi.delete('/users', { ids }, {\n    headers: {\n      'X-Batch-Delete': 'true',\n    },\n  })\n  return data\n}\n```\n\n### uploadFile(url, file, config)\n\n上传文件。\n\n**参数：**\n- `url: string` - 上传 URL\n- `file: File` - 要上传的文件\n- `config?: AxiosRequestConfig` - axios 配置\n\n**返回：** `Promise<any>`\n\n**示例：**\n\n```ts\nimport { getHttpService } from '@chuangxi/ajaxpackage'\n\nconst httpApi = getHttpService({\n  baseURL: 'https://api.example.com',\n})\n\nasync function uploadAvatar(file: File) {\n  const data = await httpApi.uploadFile('/upload/avatar', file)\n  return data\n}\n\nasync function uploadFileWithProgress(file: File, onProgress: (progress: number) => void) {\n  const data = await httpApi.uploadFile('/upload/file', file, {\n    onUploadProgress: (progressEvent) => {\n      const progress = progressEvent.total\n        ? Math.round((progressEvent.loaded * 100) / progressEvent.total)\n        : 0\n      onProgress(progress)\n    },\n  })\n  return data\n}\n```\n\n### all(requests)\n\n批量请求。\n\n**参数：**\n- `requests: Promise<any>[]` - 请求 Promise 数组\n\n**返回：** `Promise<any[]>`\n\n**示例：**\n\n```ts\nimport { getHttpService } from '@chuangxi/ajaxpackage'\n\nconst httpApi = getHttpService({\n  baseURL: 'https://api.example.com',\n})\n\nasync function loadDashboardData() {\n  const [users, posts, comments] = await httpApi.all([\n    httpApi.get('/users'),\n    httpApi.get('/posts'),\n    httpApi.get('/comments'),\n  ])\n  return { users, posts, comments }\n}\n\nasync function loadUserData(userId: string) {\n  const [user, posts, followers] = await httpApi.all([\n    httpApi.get(`/users/${userId}`),\n    httpApi.get(`/users/${userId}/posts`),\n    httpApi.get(`/users/${userId}/followers`),\n  ])\n  return { user, posts, followers }\n}\n```\n\n## BaseApi 类\n\n### 构造函数配置\n\n| 选项 | 说明 | 类型 | 必填 | 默认值 |\n| --- | --- | --- | --- | --- |\n| `baseURL` | 服务地址 | `string` | 是 | - |\n| `timeout` | 超时时间（毫秒） | `number` | 否 | `5000` |\n| `responseFields` | 响应字段映射 | ^[Object]`{ code?: string; message?: string; data?: string; errors?: string; tips?: string }` | 否 | `{ code: 'code', message: 'message', data: 'data', errors: 'errors', tips: 'tips' }` |\n| `onTimeout` | 超时回调函数 | ^[Function]`() => void` | 否 | `() => {}` |\n\n### BaseApi 实例方法\n\n#### get(url, params, data, config)\n\n发送 GET 请求。\n\n**示例：**\n\n```ts\nimport { BaseApi } from '@chuangxi/ajaxpackage'\n\nconst api = new BaseApi({\n  baseURL: 'https://api.example.com',\n})\n\nasync function getUserList() {\n  const data = await api.get('/users', { page: 1, size: 10 })\n  return data\n}\n```\n\n#### post(url, data, params, config)\n\n发送 POST 请求。\n\n**示例：**\n\n```ts\nimport { BaseApi } from '@chuangxi/ajaxpackage'\n\nconst api = new BaseApi({\n  baseURL: 'https://api.example.com',\n})\n\nasync function createUser(userData: any) {\n  const data = await api.post('/users', userData)\n  return data\n}\n```\n\n#### put(url, data, params, config)\n\n发送 PUT 请求。\n\n**示例：**\n\n```ts\nimport { BaseApi } from '@chuangxi/ajaxpackage'\n\nconst api = new BaseApi({\n  baseURL: 'https://api.example.com',\n})\n\nasync function updateUser(id: string, userData: any) {\n  const data = await api.put(`/users/${id}`, userData)\n  return data\n}\n```\n\n#### delete(url, params, data, config)\n\n发送 DELETE 请求。\n\n**示例：**\n\n```ts\nimport { BaseApi } from '@chuangxi/ajaxpackage'\n\nconst api = new BaseApi({\n  baseURL: 'https://api.example.com',\n})\n\nasync function deleteUser(id: string) {\n  const data = await api.delete(`/users/${id}`)\n  return data\n}\n```\n\n#### upload(url, formData, config)\n\n上传文件，自动携带 `multipart/form-data` 头信息。\n\n**示例：**\n\n```ts\nimport { BaseApi } from '@chuangxi/ajaxpackage'\n\nconst api = new BaseApi({\n  baseURL: 'https://api.example.com',\n})\n\nasync function uploadFile(file: File) {\n  const formData = new FormData()\n  formData.append('file', file)\n  const data = await api.upload('/upload', formData, {\n    onUploadProgress: (event) => {\n      const percent = event.total ? Math.round(event.loaded / event.total * 100) : 0\n      console.log(`上传进度：${percent}%`)\n    },\n  })\n  return data\n}\n```\n\n#### all(requests)\n\n批量请求。`requests` 既可以是 `AxiosRequestConfig[]`，也可以是已经发起的请求 `Promise[]`。\n\n**示例：**\n\n```ts\nimport { BaseApi } from '@chuangxi/ajaxpackage'\nimport type { AxiosRequestConfig } from 'axios'\n\nconst api = new BaseApi({\n  baseURL: 'https://api.example.com',\n})\n\nasync function loadDashboardData() {\n  const requests: AxiosRequestConfig[] = [\n    { url: '/users', method: 'get' },\n    { url: '/posts', method: 'get' },\n    { url: '/comments', method: 'get' },\n  ]\n  const [users, posts, comments] = await api.all(requests)\n  return { users, posts, comments }\n}\n\n// 也可以传入已经发起的请求\nasync function loadDashboardDataByPromises() {\n  const api = new BaseApi({ baseURL: 'https://api.example.com' })\n  const [users, posts, comments] = await api.all([\n    api.get('/users'),\n    api.get('/posts'),\n    api.get('/comments'),\n  ])\n  return { users, posts, comments }\n}\n```\n\n### 继承扩展 BaseApi\n\n可以通过继承 `BaseApi` 创建自定义的 API 类，重写 `processRequestConfig` 和 `processResponseError` 方法。\n\n**示例：**\n\n```ts\nimport { BaseApi } from '@chuangxi/ajaxpackage'\nimport type { InternalAxiosRequestConfig, AxiosError } from 'axios'\n\nclass UserApi extends BaseApi {\n  constructor() {\n    super({\n      baseURL: 'https://api.example.com/users',\n      timeout: 5000,\n    })\n  }\n\n  processRequestConfig(config: InternalAxiosRequestConfig) {\n    // 自定义请求拦截器处理\n    config.headers = config.headers || {}\n    config.headers['X-Custom-Header'] = 'custom-value'\n    return config\n  }\n\n  async processResponseError(error: AxiosError): Promise<AxiosError> {\n    // 自定义错误处理\n    if (error.response?.status === 404) {\n      console.error('资源未找到')\n    }\n    return error\n  }\n\n  async getUserById(id: string) {\n    return this.get(`/${id}`)\n  }\n\n  async createUser(userData: any) {\n    return this.post('/', userData)\n  }\n}\n\nconst userApi = new UserApi()\nexport default userApi\n```\n\n## VueAxiosPlugin 插件\n\n### 安装插件\n\n```ts\nimport { createApp } from 'vue'\nimport VueAxiosPlugin from '@chuangxi/ajaxpackage'\n\nconst app = createApp(App)\n\napp.use(VueAxiosPlugin, {\n  default: {\n    baseURL: 'https://api.example.com',\n    timeout: 5000,\n    getToken: () => localStorage.getItem('token'),\n  },\n})\n```\n\n### 插件配置选项\n\n| 选项 | 说明 | 类型 | 必填 |\n| --- | --- | --- | --- |\n| `default` | 默认实例配置 | `HttpServiceOptions` | 否 |\n| `instances` | 其他实例配置 | ^[Object]`Record<string, HttpServiceOptions>` | 否 |\n| `globalMixin` | 是否启用全局 mixin | `boolean` | 否，默认 `true` |\n\n### 使用示例：单实例\n\n```ts\nimport { createApp } from 'vue'\nimport VueAxiosPlugin from '@chuangxi/ajaxpackage'\n\nconst app = createApp(App)\n\napp.use(VueAxiosPlugin, {\n  default: {\n    baseURL: 'https://api.example.com',\n    timeout: 5000,\n    getToken: () => localStorage.getItem('token'),\n  },\n})\n\n// 在组件中使用\nexport default {\n  async mounted() {\n    const users = await this.$http.get('/users')\n    console.log(users)\n  },\n}\n```\n\n### 使用示例：多实例\n\n```ts\nimport { createApp } from 'vue'\nimport VueAxiosPlugin from '@chuangxi/ajaxpackage'\n\nconst app = createApp(App)\n\napp.use(VueAxiosPlugin, {\n  default: {\n    baseURL: 'https://api.example.com',\n  },\n  instances: {\n    admin: {\n      baseURL: 'https://admin-api.example.com',\n      getToken: () => localStorage.getItem('adminToken'),\n    },\n    public: {\n      baseURL: 'https://public-api.example.com',\n    },\n  },\n})\n\n// 在组件中使用\nexport default {\n  async mounted() {\n    // 使用默认实例\n    const users = await this.$http.get('/users')\n    \n    // 使用 admin 实例\n    const adminData = await this.$httpAdmin.get('/admin/users')\n    \n    // 使用 public 实例\n    const publicData = await this.$httpPublic.get('/public/news')\n  },\n}\n```\n\n### 使用示例：Composition API\n\n```ts\nimport { inject } from 'vue'\n\nexport default {\n  setup() {\n    const $http = inject('$http')\n    \n    async function loadData() {\n      const data = await $http.get('/users')\n      return data\n    }\n    \n    return {\n      loadData,\n    }\n  },\n}\n```\n\n## 错误处理\n\n### 自动错误处理\n\nAjaxPackage 会自动处理以下错误：\n\n1. **401 错误（登录失效）**\n   - 自动调用 `onLoginRequired` 回调\n   - 显示错误提示\n\n2. **超时错误**\n   - 显示超时提示信息\n\n3. **网络错误**\n   - 显示网络错误提示\n\n4. **响应错误码**\n   - 根据 `responseFields.code` 判断错误\n   - 显示错误消息\n\n5. **错误数组（errors）**\n   - 如果响应中包含错误数组，会以通知形式显示所有错误\n\n6. **提示信息（tips）**\n   - 如果响应中包含提示信息，会以警告通知形式显示\n\n### 自定义错误处理\n\n如果需要对响应结构进行更细粒度的处理，可以继承 `BaseApi` 并重写 `processResponseConfig` 或 `processResponseError`。在这些方法中根据业务规则解析数据、抛出错误或执行额外的副作用。\n\n## SSR 支持\n\nAjaxPackage 支持 SSR（服务端渲染）环境。当 `document` 不存在时，会自动使用 `console` 输出消息和通知，而不是使用 Element Plus 的组件。\n\n## 注意事项\n\n1. **响应字段映射**\n   - 支持路径解析，如 `'result.code'` 可以访问嵌套字段\n   - 如果路径解析失败，会尝试使用默认字段名\n\n2. **Token 处理**\n   - Token 会自动添加到请求头的 `Token` 字段\n   - 如果 `getToken` 返回 `null` 或空字符串，不会添加 Token\n\n3. **错误处理**\n   - 401 错误会自动触发登录失效回调\n   - 其他错误会显示错误提示，但不会自动处理\n\n4. **批量请求**\n   - `all` 方法使用 `Promise.all`，如果任何一个请求失败，整个批量请求会失败\n   - 建议在业务代码中处理错误情况\n\n5. **请求取消**\n   - 当前版本未提供请求取消封装，若业务需要可直接使用 axios 自带的取消能力自行实现\n\n## SystemErrorDialog 组件\n\n### 概述\n\n`SystemErrorDialog` 是一个用于显示系统异常信息的对话框组件，专门用于展示请求错误时的详细信息，包括用户信息、科室信息、网络信息和错误详情。\n\n### 组件特性\n\n- 🎯 **轻量级设计**：只接收必要的字符串参数，避免大对象响应式开销\n- 📱 **响应式布局**：支持移动端和桌面端的良好显示效果\n- 🔧 **高度可配置**：支持自定义标题、宽度和各种信息字段\n- 🎨 **美观界面**：采用现代化的UI设计，信息展示清晰易读\n\n### Props 参数\n\n| 参数 | 说明 | 类型 | 默认值 | 必填 |\n|------|------|------|--------|------|\n| `title` | 对话框标题 | `string` | `'系统异常信息'` | 否 |\n| `width` | 对话框宽度 | `number \\| string` | `520` | 否 |\n| `userName` | 用户名 | `string` | - | 否 |\n| `userId` | 用户ID | `string` | - | 否 |\n| `deptName` | 科室名称 | `string` | - | 否 |\n| `deptId` | 科室ID | `string` | - | 否 |\n| `clientIp` | 客户端IP地址 | `string` | - | 否 |\n| `requestUrl` | 请求URL路径 | `string` | - | 否 |\n| `traceId` | 链路追踪ID | `string` | - | 否 |\n| `errorMessage` | 错误消息 | `string` | - | 否 |\n| `errorCode` | 错误代码 | `string` | - | 否 |\n\n### Events 事件\n\n| 事件名 | 说明 | 参数 |\n|--------|------|------|\n| `close` | 关闭对话框时触发 | - |\n| `confirm` | 点击确认按钮时触发 | - |\n\n### 使用示例\n\n#### 基础用法\n\n```vue\n<template>\n  <div>\n    <ElButton @click=\"showErrorDialog\">显示异常信息</ElButton>\n    \n    <SystemErrorDialog\n      v-model=\"dialogVisible\"\n      :user-name=\"errorInfo.userName\"\n      :user-id=\"errorInfo.userId\"\n      :dept-name=\"errorInfo.deptName\"\n      :dept-id=\"errorInfo.deptId\"\n      :client-ip=\"errorInfo.clientIp\"\n      :request-url=\"errorInfo.requestUrl\"\n      :trace-id=\"errorInfo.traceId\"\n      @close=\"dialogVisible = false\"\n      @confirm=\"handleConfirm\"\n    />\n  </div>\n</template>\n\n<script setup>\nimport { ref } from 'vue'\nimport { ElButton } from 'element-plus'\nimport SystemErrorDialog from '@chuangxi/ajaxpackage/SystemErrorDialog.vue'\n\nconst dialogVisible = ref(false)\n\nconst errorInfo = {\n  userName: '张三',\n  userId: '12345',\n  deptName: '信息科',\n  deptId: 'IT001',\n  clientIp: '192.168.1.100',\n  requestUrl: '/api/user/login',\n  traceId: 'trace-123456789',\n}\n\nfunction showErrorDialog() {\n  dialogVisible.value = true\n}\n\nfunction handleConfirm() {\n  console.log('用户确认了异常信息')\n  dialogVisible.value = false\n}\n</script>\n```\n\n#### 完整配置\n\n```vue\n<template>\n  <SystemErrorDialog\n    v-model=\"dialogVisible\"\n    title=\"详细系统异常信息\"\n    :width=\"600\"\n    :user-name=\"fullErrorInfo.userName\"\n    :user-id=\"fullErrorInfo.userId\"\n    :dept-name=\"fullErrorInfo.deptName\"\n    :dept-id=\"fullErrorInfo.deptId\"\n    :client-ip=\"fullErrorInfo.clientIp\"\n    :request-url=\"fullErrorInfo.requestUrl\"\n    :trace-id=\"fullErrorInfo.traceId\"\n    :error-code=\"fullErrorInfo.errorCode\"\n    :error-message=\"fullErrorInfo.errorMessage\"\n    @close=\"dialogVisible = false\"\n    @confirm=\"handleConfirm\"\n  />\n</template>\n\n<script setup>\nimport { ref } from 'vue'\nimport SystemErrorDialog from '@chuangxi/ajaxpackage/SystemErrorDialog.vue'\n\nconst dialogVisible = ref(false)\n\nconst fullErrorInfo = {\n  userName: '李四',\n  userId: '67890',\n  deptName: '财务科',\n  deptId: 'FIN001',\n  clientIp: '192.168.1.200',\n  requestUrl: '/api/finance/report',\n  traceId: 'trace-987654321',\n  errorCode: 'ERR_500',\n  errorMessage: '服务器内部错误，请联系系统管理员',\n}\n\nfunction handleConfirm() {\n  // 处理确认逻辑\n  dialogVisible.value = false\n}\n</script>\n```\n\n#### 从响应对象提取信息\n\n```typescript\nimport type { AxiosResponse } from 'axios'\nimport SystemErrorDialog from '@chuangxi/ajaxpackage/SystemErrorDialog.vue'\n\n// 工具函数：从响应对象提取异常信息\nfunction extractErrorInfo(response: AxiosResponse) {\n  const requestData = {\n    ...response.config?.params,\n    ...normalizePayload(response.config?.data),\n  }\n\n  return {\n    userName: requestData.userName || requestData.username,\n    userId: requestData.userId || requestData.userid,\n    deptName: requestData.deptName || requestData.departmentName,\n    deptId: requestData.deptId || requestData.departmentId,\n    clientIp: requestData.clientIp || requestData.ip,\n    requestUrl: response.config?.url,\n    traceId: resolveTraceId(response.headers),\n    errorCode: response.data?.code || response.status?.toString(),\n    errorMessage: response.data?.message || response.statusText,\n  }\n}\n\n// 在错误处理中使用\nfunction handleApiError(error: any) {\n  if (error.response) {\n    const errorInfo = extractErrorInfo(error.response)\n    // 显示异常对话框\n    showSystemErrorDialog(errorInfo)\n  }\n}\n```\n\n### 组件方法\n\n通过 `ref` 可以访问组件的方法：\n\n```vue\n<template>\n  <SystemErrorDialog\n    ref=\"errorDialogRef\"\n    v-model=\"dialogVisible\"\n    :user-name=\"errorInfo.userName\"\n    @close=\"dialogVisible = false\"\n  />\n</template>\n\n<script setup>\nimport { ref } from 'vue'\nimport SystemErrorDialog from '@chuangxi/ajaxpackage/SystemErrorDialog.vue'\n\nconst errorDialogRef = ref()\n\n// 通过方法关闭对话框\nfunction closeDialog() {\n  errorDialogRef.value?.close()\n}\n</script>\n```\n\n### 样式定制\n\n组件使用 scoped 样式，如需自定义样式，可以通过深度选择器：\n\n```vue\n<style>\n.custom-error-dialog :deep(.error-info-container) {\n  background-color: #f5f5f5;\n}\n\n.custom-error-dialog :deep(.error-code) {\n  color: #ff4757;\n  font-weight: bold;\n}\n</style>\n```\n\n### 设计理念\n\n#### 为什么不直接传递 response 对象？\n\n1. **性能考虑**：response 对象通常很大，包含大量不必要的信息，将其变为响应式会造成性能开销\n2. **数据安全**：避免在组件中暴露完整的请求/响应信息\n3. **接口清晰**：明确的 props 定义让组件的使用更加清晰和可控\n4. **灵活性**：调用方可以自由决定传递哪些信息，支持多种数据来源\n\n#### 信息展示逻辑\n\n- **菜单名称**：自动获取当前页面的 URL（`location.href`）\n- **未知值处理**：对于未传递的信息显示\"未知\"\n- **错误信息**：错误代码和错误消息会以不同颜色突出显示\n- **响应式设计**：在移动端会自动调整布局为垂直排列\n","readmeFilename":"README.md"}