@melt-js/docs-bag 0.0.0-stage → 2026.11.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -2
- package/dist/404.html +22 -0
- package/dist/README.html +33 -0
- package/dist/assets/README.md.BEUJStMI.js +9 -0
- package/dist/assets/README.md.BEUJStMI.lean.js +1 -0
- package/dist/assets/app.CPZ-gtYR.js +1 -0
- package/dist/assets/chunks/@localSearchIndexroot.7ill5i5O.js +1 -0
- package/dist/assets/chunks/VPLocalSearchBox.BVA3GWxn.js +9 -0
- package/dist/assets/chunks/framework.B3lxS50j.js +20 -0
- package/dist/assets/chunks/theme.C4rSMcmz.js +2 -0
- package/dist/assets/guide_complete-host-app.md.CDRzLz0E.js +174 -0
- package/dist/assets/guide_complete-host-app.md.CDRzLz0E.lean.js +1 -0
- package/dist/assets/guide_create-project.md.LRNhDD9x.js +34 -0
- package/dist/assets/guide_create-project.md.LRNhDD9x.lean.js +1 -0
- package/dist/assets/guide_deployment.md.B8aEUabm.js +42 -0
- package/dist/assets/guide_deployment.md.B8aEUabm.lean.js +1 -0
- package/dist/assets/guide_dictionary-system.md.Dy0tQYMR.js +32 -0
- package/dist/assets/guide_dictionary-system.md.Dy0tQYMR.lean.js +1 -0
- package/dist/assets/guide_getting-started.md.B-mobXxi.js +9 -0
- package/dist/assets/guide_getting-started.md.B-mobXxi.lean.js +1 -0
- package/dist/assets/guide_host_auth-and-permissions.md.DWH3Vape.js +139 -0
- package/dist/assets/guide_host_auth-and-permissions.md.DWH3Vape.lean.js +1 -0
- package/dist/assets/guide_host_bootstrap.md.DpbxPIZw.js +87 -0
- package/dist/assets/guide_host_bootstrap.md.DpbxPIZw.lean.js +1 -0
- package/dist/assets/guide_host_routing-and-menu.md.BdCMIOxn.js +103 -0
- package/dist/assets/guide_host_routing-and-menu.md.BdCMIOxn.lean.js +1 -0
- package/dist/assets/guide_introduction.md.1MiCcWyO.js +14 -0
- package/dist/assets/guide_introduction.md.1MiCcWyO.lean.js +1 -0
- package/dist/assets/guide_local-debugging.md.CLJoKVb9.js +15 -0
- package/dist/assets/guide_local-debugging.md.CLJoKVb9.lean.js +1 -0
- package/dist/assets/guide_network-request.md.DDlA8bc0.js +256 -0
- package/dist/assets/guide_network-request.md.DDlA8bc0.lean.js +1 -0
- package/dist/assets/guide_official-plugins_index.md.DPwemCGy.js +15 -0
- package/dist/assets/guide_official-plugins_index.md.DPwemCGy.lean.js +1 -0
- package/dist/assets/guide_official-plugins_install-and-toggle.md.Eq2hWjYn.js +45 -0
- package/dist/assets/guide_official-plugins_install-and-toggle.md.Eq2hWjYn.lean.js +1 -0
- package/dist/assets/guide_official-plugins_shop.md.yBltEx-o.js +49 -0
- package/dist/assets/guide_official-plugins_shop.md.yBltEx-o.lean.js +1 -0
- package/dist/assets/guide_official-plugins_sys-setting.md.BmkuOqGv.js +26 -0
- package/dist/assets/guide_official-plugins_sys-setting.md.BmkuOqGv.lean.js +1 -0
- package/dist/assets/guide_package-core.md.-E29SYy8.js +45 -0
- package/dist/assets/guide_package-core.md.-E29SYy8.lean.js +1 -0
- package/dist/assets/guide_package-ecosystem.md.Di3RcVpF.js +1 -0
- package/dist/assets/guide_package-ecosystem.md.Di3RcVpF.lean.js +1 -0
- package/dist/assets/guide_package-plugin-shop.md.D-xXN7Yg.js +9 -0
- package/dist/assets/guide_package-plugin-shop.md.D-xXN7Yg.lean.js +1 -0
- package/dist/assets/guide_package-plugin-sys-setting.md.Dx3nxHVF.js +9 -0
- package/dist/assets/guide_package-plugin-sys-setting.md.Dx3nxHVF.lean.js +1 -0
- package/dist/assets/guide_package-publishing.md.B7hzTYDH.js +7 -0
- package/dist/assets/guide_package-publishing.md.B7hzTYDH.lean.js +1 -0
- package/dist/assets/guide_package-request.md.DxaD65eM.js +195 -0
- package/dist/assets/guide_package-request.md.DxaD65eM.lean.js +1 -0
- package/dist/assets/guide_package-ui.md.wBZ_iQLb.js +50 -0
- package/dist/assets/guide_package-ui.md.wBZ_iQLb.lean.js +1 -0
- package/dist/assets/guide_permissions.md.B_5re4AR.js +83 -0
- package/dist/assets/guide_permissions.md.B_5re4AR.lean.js +1 -0
- package/dist/assets/guide_plugin-development.md.BQzTwLRr.js +226 -0
- package/dist/assets/guide_plugin-development.md.BQzTwLRr.lean.js +1 -0
- package/dist/assets/guide_plugins_admin-plugin.md.d_XC5U-4.js +52 -0
- package/dist/assets/guide_plugins_admin-plugin.md.d_XC5U-4.lean.js +1 -0
- package/dist/assets/guide_plugins_create-plugin.md.C-wDq4Un.js +109 -0
- package/dist/assets/guide_plugins_create-plugin.md.C-wDq4Un.lean.js +1 -0
- package/dist/assets/guide_plugins_debug-and-publish.md.CeTc01QN.js +92 -0
- package/dist/assets/guide_plugins_debug-and-publish.md.CeTc01QN.lean.js +1 -0
- package/dist/assets/guide_plugins_lifecycle-and-dependencies.md.BtwKS5jY.js +45 -0
- package/dist/assets/guide_plugins_lifecycle-and-dependencies.md.BtwKS5jY.lean.js +1 -0
- package/dist/assets/guide_plugins_permissions-and-settings.md.05CsB1I6.js +78 -0
- package/dist/assets/guide_plugins_permissions-and-settings.md.05CsB1I6.lean.js +1 -0
- package/dist/assets/guide_plugins_routes-menus-locales.md.B2dzO2DN.js +100 -0
- package/dist/assets/guide_plugins_routes-menus-locales.md.B2dzO2DN.lean.js +1 -0
- package/dist/assets/guide_pro-form.md.DbSHbrMu.js +116 -0
- package/dist/assets/guide_pro-form.md.DbSHbrMu.lean.js +1 -0
- package/dist/assets/guide_pro-table.md.DBuYQYgG.js +54 -0
- package/dist/assets/guide_pro-table.md.DBuYQYgG.lean.js +1 -0
- package/dist/assets/guide_request-and-components.md.BQXI_ZxY.js +175 -0
- package/dist/assets/guide_request-and-components.md.BQXI_ZxY.lean.js +1 -0
- package/dist/assets/guide_routing-and-menu.md.-zrm3BV9.js +74 -0
- package/dist/assets/guide_routing-and-menu.md.-zrm3BV9.lean.js +1 -0
- package/dist/assets/guide_theme-tokens.md.DXpbrOjS.js +53 -0
- package/dist/assets/guide_theme-tokens.md.DXpbrOjS.lean.js +1 -0
- package/dist/assets/index.md.BUgI8r98.js +1 -0
- package/dist/assets/index.md.BUgI8r98.lean.js +1 -0
- package/dist/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 +0 -0
- package/dist/assets/inter-italic-cyrillic.By2_1cv3.woff2 +0 -0
- package/dist/assets/inter-italic-greek-ext.1u6EdAuj.woff2 +0 -0
- package/dist/assets/inter-italic-greek.DJ8dCoTZ.woff2 +0 -0
- package/dist/assets/inter-italic-latin-ext.CN1xVJS-.woff2 +0 -0
- package/dist/assets/inter-italic-latin.C2AdPX0b.woff2 +0 -0
- package/dist/assets/inter-italic-vietnamese.BSbpV94h.woff2 +0 -0
- package/dist/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 +0 -0
- package/dist/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 +0 -0
- package/dist/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 +0 -0
- package/dist/assets/inter-roman-greek.BBVDIX6e.woff2 +0 -0
- package/dist/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 +0 -0
- package/dist/assets/inter-roman-latin.Di8DUHzh.woff2 +0 -0
- package/dist/assets/inter-roman-vietnamese.BjW4sHH5.woff2 +0 -0
- package/dist/assets/style.0snOvk0r.css +1 -0
- package/dist/guide/complete-host-app.html +198 -0
- package/dist/guide/create-project.html +58 -0
- package/dist/guide/deployment.html +66 -0
- package/dist/guide/dictionary-system.html +56 -0
- package/dist/guide/getting-started.html +33 -0
- package/dist/guide/host/auth-and-permissions.html +163 -0
- package/dist/guide/host/bootstrap.html +111 -0
- package/dist/guide/host/routing-and-menu.html +127 -0
- package/dist/guide/introduction.html +38 -0
- package/dist/guide/local-debugging.html +39 -0
- package/dist/guide/network-request.html +280 -0
- package/dist/guide/official-plugins/index.html +39 -0
- package/dist/guide/official-plugins/install-and-toggle.html +69 -0
- package/dist/guide/official-plugins/shop.html +73 -0
- package/dist/guide/official-plugins/sys-setting.html +50 -0
- package/dist/guide/package-core.html +69 -0
- package/dist/guide/package-ecosystem.html +25 -0
- package/dist/guide/package-plugin-shop.html +33 -0
- package/dist/guide/package-plugin-sys-setting.html +33 -0
- package/dist/guide/package-publishing.html +31 -0
- package/dist/guide/package-request.html +219 -0
- package/dist/guide/package-ui.html +74 -0
- package/dist/guide/permissions.html +107 -0
- package/dist/guide/plugin-development.html +250 -0
- package/dist/guide/plugins/admin-plugin.html +76 -0
- package/dist/guide/plugins/create-plugin.html +133 -0
- package/dist/guide/plugins/debug-and-publish.html +116 -0
- package/dist/guide/plugins/lifecycle-and-dependencies.html +69 -0
- package/dist/guide/plugins/permissions-and-settings.html +102 -0
- package/dist/guide/plugins/routes-menus-locales.html +124 -0
- package/dist/guide/pro-form.html +140 -0
- package/dist/guide/pro-table.html +78 -0
- package/dist/guide/request-and-components.html +199 -0
- package/dist/guide/routing-and-menu.html +98 -0
- package/dist/guide/theme-tokens.html +77 -0
- package/dist/hashmap.json +1 -0
- package/dist/index.html +25 -0
- package/dist/logo.png +0 -0
- package/dist/logo.svg +1 -0
- package/dist/vp-icons.css +1 -0
- package/dist/wechat-group-qr.png +0 -0
- package/package.json +24 -4
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import{_ as i,o as a,c as n,a2 as h}from"./chunks/framework.B3lxS50j.js";const g=JSON.parse('{"title":"网络请求与拦截","description":"","frontmatter":{},"headers":[],"relativePath":"guide/network-request.md","filePath":"guide/network-request.md","lastUpdated":1794045200000}'),l={name:"guide/network-request.md"};function t(p,s,k,e,E,d){return a(),n("div",null,[...s[0]||(s[0]=[h(`<h1 id="网络请求与拦截" tabindex="-1">网络请求与拦截 <a class="header-anchor" href="#网络请求与拦截" aria-label="Permalink to "网络请求与拦截""></a></h1><p>Vue-Bag-Admin 把网络请求放在 <code>@melt-js/libs-bag-request</code> 里处理。它同时支持 <code>axios</code> 和原生 <code>fetch</code>,主要管这些事:</p><ul><li>Token 注入</li><li>HTTP 状态码拦截</li><li>业务错误转异常</li><li>宿主自定义错误处理</li><li>面向 PWA 场景的离线缓存与离线写入队列</li><li>页面层的 <code>loading</code> / <code>data</code> / <code>error</code> 执行状态管理</li><li>基于 Lodash 的防抖 / 节流请求控制</li></ul><h2 id="基础使用" tabindex="-1">基础使用 <a class="header-anchor" href="#基础使用" aria-label="Permalink to "基础使用""></a></h2><p>你可以在业务插件中直接使用 <code>http</code> 实例:</p><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { http } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '@melt-js/libs-bag-request'</span></span>
|
|
2
|
+
<span class="line"></span>
|
|
3
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> fetchUsers</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> async</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> () </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
|
4
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> data</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> http.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">get</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'/api/users'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, {</span></span>
|
|
5
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> params: { page: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">1</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
6
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> })</span></span>
|
|
7
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> data</span></span>
|
|
8
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span>
|
|
9
|
+
<span class="line"></span>
|
|
10
|
+
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// 发起 POST 请求</span></span>
|
|
11
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> createUser</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> async</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">payload</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
|
12
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> data</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> http.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">post</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'/api/users'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, payload)</span></span>
|
|
13
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> data</span></span>
|
|
14
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><p>默认情况下,响应拦截器直接返回 <code>response.data</code>,业务层不用再手动解构 <code>.data</code>。</p><p>如果你更想直接使用原生 <code>fetch</code>,也可以使用 <code>fetchHttp</code>:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { fetchHttp } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '@melt-js/libs-bag-request'</span></span>
|
|
15
|
+
<span class="line"></span>
|
|
16
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> fetchUsers</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> async</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> () </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
|
17
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> data</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> fetchHttp.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">get</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'/api/users'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, {</span></span>
|
|
18
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> params: { page: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">1</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
19
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> })</span></span>
|
|
20
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> data</span></span>
|
|
21
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><h2 id="初始化配置" tabindex="-1">初始化配置 <a class="header-anchor" href="#初始化配置" aria-label="Permalink to "初始化配置""></a></h2><p>为了不把请求层和宿主绑死,Token 获取和错误处理都在启动阶段通过 <code>setupHttp()</code> 注入。</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { setupHttp } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '@melt-js/libs-bag-request'</span></span>
|
|
22
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { useUserStore } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '@/stores/user'</span></span>
|
|
23
|
+
<span class="line"></span>
|
|
24
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> userStore</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> useUserStore</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()</span></span>
|
|
25
|
+
<span class="line"></span>
|
|
26
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">setupHttp</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
|
27
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> baseURL: </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">.</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">meta</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">.env.</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">VITE_API_URL</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
28
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> getToken</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: () </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> userStore.token,</span></span>
|
|
29
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> onUnauthorized</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: () </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
|
30
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> userStore.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">logout</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()</span></span>
|
|
31
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> window.location.href </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '/login'</span></span>
|
|
32
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
|
33
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> onForbidden</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: () </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
|
34
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">warn</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'当前账号没有访问权限'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
|
|
35
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
|
36
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> onServerError</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: () </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
|
37
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">error</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'服务异常,请稍后重试'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
|
|
38
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
|
39
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> resolveError</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">payload</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
|
40
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> data</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> payload </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">as</span></span>
|
|
41
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> |</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { success</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> boolean; code</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> string </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">|</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> number; message</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> string }</span></span>
|
|
42
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> |</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> undefined</span></span>
|
|
43
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (data?.success </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">===</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> false</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) {</span></span>
|
|
44
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
|
45
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> code: data.code,</span></span>
|
|
46
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> message: data.message </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">||</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'Request failed'</span></span>
|
|
47
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
48
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
49
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> null</span></span>
|
|
50
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
51
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">})</span></span></code></pre></div><p>如果项目更偏向原生 API,也可以直接用 <code>setupFetch()</code>:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { setupFetch } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '@melt-js/libs-bag-request'</span></span>
|
|
52
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { useUserStore } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '@/stores/user'</span></span>
|
|
53
|
+
<span class="line"></span>
|
|
54
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> userStore</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> useUserStore</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()</span></span>
|
|
55
|
+
<span class="line"></span>
|
|
56
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">setupFetch</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
|
57
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> baseURL: </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">.</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">meta</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">.env.</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">VITE_API_URL</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
58
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> getToken</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: () </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> userStore.token,</span></span>
|
|
59
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> onUnauthorized</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: () </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
|
60
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> userStore.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">logout</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()</span></span>
|
|
61
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> window.location.href </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '/login'</span></span>
|
|
62
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
|
63
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> onForbidden</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: () </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
|
64
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">warn</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'当前账号没有访问权限'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
|
|
65
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
|
66
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> onServerError</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: () </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
|
67
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">error</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'服务异常,请稍后重试'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
|
|
68
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
|
69
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> resolveError</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">payload</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
|
70
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> data</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> payload </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">as</span></span>
|
|
71
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> |</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { success</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> boolean; code</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> string </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">|</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> number; message</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> string }</span></span>
|
|
72
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> |</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> undefined</span></span>
|
|
73
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (data?.success </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">===</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> false</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) {</span></span>
|
|
74
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
|
75
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> code: data.code,</span></span>
|
|
76
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> message: data.message </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">||</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'Request failed'</span></span>
|
|
77
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
78
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
79
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> null</span></span>
|
|
80
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
81
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">})</span></span></code></pre></div><h2 id="setuphttpconfig-支持什么" tabindex="-1">SetupHttpConfig 支持什么 <a class="header-anchor" href="#setuphttpconfig-支持什么" aria-label="Permalink to "SetupHttpConfig 支持什么""></a></h2><p><code>setupHttp()</code> 主要接这几类配置:</p><ul><li><code>axios</code> 原生配置:如 <code>baseURL</code>、<code>timeout</code>、<code>headers</code></li><li>宿主注入项:如 <code>getToken</code>、错误钩子、业务错误识别函数</li><li>PWA 缓存项:如缓存命名空间、缓存策略、缓存时长</li></ul><p><code>setupFetch()</code> 也有一组对应配置:</p><ul><li>原生 <code>fetch</code> 配置:如 <code>baseURL</code>、<code>headers</code>、<code>credentials</code></li><li>宿主注入项:如 <code>getToken</code>、错误钩子、业务错误识别函数</li><li>PWA 增强项:如离线缓存策略、断网入队、联网后自动重放</li></ul><h2 id="pwa-模式" tabindex="-1">PWA 模式 <a class="header-anchor" href="#pwa-模式" aria-label="Permalink to "PWA 模式""></a></h2><p>如果你的管理端希望在弱网、断网,或者被安装为桌面应用后还能保持基本可用,可以直接在 <code>setupHttp()</code> 或 <code>setupFetch()</code> 里开启 <code>pwa</code> 配置。</p><p><code>axios</code> 版本适合继续沿用 <code>http</code> 的项目:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { http, setupHttp } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '@melt-js/libs-bag-request'</span></span>
|
|
82
|
+
<span class="line"></span>
|
|
83
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">setupHttp</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
|
84
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> baseURL: </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">.</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">meta</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">.env.</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">VITE_API_URL</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
85
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> getToken</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: () </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> localStorage.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">getItem</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'token'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">),</span></span>
|
|
86
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> onUnauthorized</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: () </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
|
87
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> window.location.href </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '/login'</span></span>
|
|
88
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
|
89
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> pwa: {</span></span>
|
|
90
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> enabled: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">true</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
91
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> cache: {</span></span>
|
|
92
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> enabled: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">true</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
93
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> strategy: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'cache-first'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
94
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ttl: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">5</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> *</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> 60</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> *</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> 1000</span></span>
|
|
95
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
96
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
97
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">})</span></span>
|
|
98
|
+
<span class="line"></span>
|
|
99
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> dashboardData</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> http.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">get</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'/dashboard'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, {</span></span>
|
|
100
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> pwa: {</span></span>
|
|
101
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> strategy: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'cache-first'</span></span>
|
|
102
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
103
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">})</span></span></code></pre></div><p><code>fetch</code> 版本适合同时要离线队列的项目:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
|
104
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> clearOfflineQueue,</span></span>
|
|
105
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> fetchHttp,</span></span>
|
|
106
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> getNetworkStatus,</span></span>
|
|
107
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> replayOfflineQueue,</span></span>
|
|
108
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> setupFetch,</span></span>
|
|
109
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> subscribeNetworkStatus</span></span>
|
|
110
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">} </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '@melt-js/libs-bag-request'</span></span>
|
|
111
|
+
<span class="line"></span>
|
|
112
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">setupFetch</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
|
113
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> baseURL: </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">.</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">meta</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">.env.</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">VITE_API_URL</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
114
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> getToken</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: () </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> localStorage.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">getItem</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'token'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">),</span></span>
|
|
115
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> onUnauthorized</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: () </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
|
116
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> window.location.href </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '/login'</span></span>
|
|
117
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
|
118
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> pwa: {</span></span>
|
|
119
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> enabled: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">true</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
120
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> cache: {</span></span>
|
|
121
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> enabled: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">true</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
122
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> strategy: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'cache-first'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
123
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ttl: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">5</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> *</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> 60</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> *</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> 1000</span></span>
|
|
124
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
|
125
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> queue: {</span></span>
|
|
126
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> enabled: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">true</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
127
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> autoReplay: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">true</span></span>
|
|
128
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
129
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
130
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">})</span></span>
|
|
131
|
+
<span class="line"></span>
|
|
132
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> stopListening</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> subscribeNetworkStatus</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">((</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">status</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
|
133
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">log</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'network status:'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, status)</span></span>
|
|
134
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">})</span></span>
|
|
135
|
+
<span class="line"></span>
|
|
136
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> dashboardData</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> fetchHttp.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">get</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'/dashboard'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, {</span></span>
|
|
137
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> pwa: {</span></span>
|
|
138
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> strategy: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'stale-while-revalidate'</span></span>
|
|
139
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
140
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">})</span></span>
|
|
141
|
+
<span class="line"></span>
|
|
142
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">try</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
|
143
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> fetchHttp.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">post</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'/orders'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, {</span></span>
|
|
144
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> title: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'离线创建订单'</span></span>
|
|
145
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> })</span></span>
|
|
146
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">} </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">catch</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (error) {</span></span>
|
|
147
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">getNetworkStatus</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">() </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">===</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'offline'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) {</span></span>
|
|
148
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">log</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'request has been queued'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
|
|
149
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
150
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span>
|
|
151
|
+
<span class="line"></span>
|
|
152
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">await</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> replayOfflineQueue</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()</span></span>
|
|
153
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">clearOfflineQueue</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()</span></span>
|
|
154
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">stopListening</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()</span></span></code></pre></div><p>当前这层 PWA 模式主要覆盖三件事:</p><ul><li><code>http</code> 和 <code>fetchHttp</code> 的 <code>GET</code> / <code>HEAD</code> 请求默认支持缓存优先读取</li><li><code>fetchHttp</code> 的写请求在断网时可进入离线队列</li><li><code>fetchHttp</code> 的离线队列可在网络恢复后自动或手动重放</li></ul><h2 id="高频请求控制" tabindex="-1">高频请求控制 <a class="header-anchor" href="#高频请求控制" aria-label="Permalink to "高频请求控制""></a></h2><p>如果页面里有搜索联想、自动保存、按钮防连点这类高频交互,可以直接使用 <code>@melt-js/libs-bag-request</code> 提供的 <code>debounceRequest()</code> 和 <code>throttleRequest()</code>。</p><p>这层底层还是 Lodash 的 <code>debounce</code> / <code>throttle</code>,只是针对请求补了三点:</p><ul><li>返回值保持为 <code>Promise</code>,可以继续 <code>await</code></li><li>提供 <code>cancel()</code>、<code>flush()</code>、<code>pending()</code> 便于页面控制</li><li>直接包裹 <code>http</code>、<code>fetchHttp</code> 或你自己的 API 函数都可以</li></ul><h3 id="搜索联想" tabindex="-1">搜索联想 <a class="header-anchor" href="#搜索联想" aria-label="Permalink to "搜索联想""></a></h3><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { debounceRequest, http } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '@melt-js/libs-bag-request'</span></span>
|
|
155
|
+
<span class="line"></span>
|
|
156
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> fetchUsers</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> debounceRequest</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span></span>
|
|
157
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">keyword</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span></span>
|
|
158
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> http.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">get</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'/api/users'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, {</span></span>
|
|
159
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> params: {</span></span>
|
|
160
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> keyword</span></span>
|
|
161
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
162
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }),</span></span>
|
|
163
|
+
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> 300</span></span>
|
|
164
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
|
|
165
|
+
<span class="line"></span>
|
|
166
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> users</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> fetchUsers</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'bag admin'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span></code></pre></div><h3 id="自动保存" tabindex="-1">自动保存 <a class="header-anchor" href="#自动保存" aria-label="Permalink to "自动保存""></a></h3><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { fetchHttp, throttleRequest } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '@melt-js/libs-bag-request'</span></span>
|
|
167
|
+
<span class="line"></span>
|
|
168
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> saveDraft</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> throttleRequest</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span></span>
|
|
169
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">payload</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">title</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">; </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">content</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> fetchHttp.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">post</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'/api/drafts'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, payload),</span></span>
|
|
170
|
+
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> 1000</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
171
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
|
172
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> leading: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">false</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
173
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> trailing: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">true</span></span>
|
|
174
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
175
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
|
|
176
|
+
<span class="line"></span>
|
|
177
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">await</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> saveDraft</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
|
178
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> title: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'草稿标题'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
179
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> content: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'草稿内容'</span></span>
|
|
180
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">})</span></span></code></pre></div><h3 id="重复提交保护" tabindex="-1">重复提交保护 <a class="header-anchor" href="#重复提交保护" aria-label="Permalink to "重复提交保护""></a></h3><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { throttleRequest, http } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '@melt-js/libs-bag-request'</span></span>
|
|
181
|
+
<span class="line"></span>
|
|
182
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> submitOrder</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> throttleRequest</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span></span>
|
|
183
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">orderId</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span></span>
|
|
184
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> http.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">post</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'/api/orders/submit'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, {</span></span>
|
|
185
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> orderId</span></span>
|
|
186
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }),</span></span>
|
|
187
|
+
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> 1500</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
188
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
|
189
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> leading: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">true</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
190
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> trailing: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">false</span></span>
|
|
191
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
192
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
|
|
193
|
+
<span class="line"></span>
|
|
194
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">await</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> submitOrder</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'order_1001'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span></code></pre></div><h3 id="控制方法" tabindex="-1">控制方法 <a class="header-anchor" href="#控制方法" aria-label="Permalink to "控制方法""></a></h3><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { debounceRequest, http } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '@melt-js/libs-bag-request'</span></span>
|
|
195
|
+
<span class="line"></span>
|
|
196
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> fetchUsers</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> debounceRequest</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span></span>
|
|
197
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">keyword</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span></span>
|
|
198
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> http.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">get</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'/api/users'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, {</span></span>
|
|
199
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> params: {</span></span>
|
|
200
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> keyword</span></span>
|
|
201
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
202
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }),</span></span>
|
|
203
|
+
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> 300</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
204
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
|
205
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> maxWait: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">1000</span></span>
|
|
206
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
207
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
|
|
208
|
+
<span class="line"></span>
|
|
209
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">fetchUsers</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'a'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
|
|
210
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">fetchUsers</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'ab'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
|
|
211
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">fetchUsers</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'abc'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
|
|
212
|
+
<span class="line"></span>
|
|
213
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (fetchUsers.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pending</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()) {</span></span>
|
|
214
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> fetchUsers.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">flush</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()</span></span>
|
|
215
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span>
|
|
216
|
+
<span class="line"></span>
|
|
217
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">fetchUsers.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">cancel</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'component unmount'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span></code></pre></div><p>默认行为:</p><ul><li><code>debounceRequest()</code> 默认尾触发</li><li><code>throttleRequest()</code> 默认首尾都触发</li><li>两者都支持 <code>leading</code>、<code>trailing</code>、<code>maxWait</code></li><li>它们只限制调用频率,不会取消已经发出的真实请求</li></ul><h2 id="页面请求状态" tabindex="-1">页面请求状态 <a class="header-anchor" href="#页面请求状态" aria-label="Permalink to "页面请求状态""></a></h2><p>如果页面里总是在手写 <code>loading</code>、<code>data</code>、<code>error</code>、<code>run</code>,可以用 <code>useRequest()</code> 把这层状态收起来。</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { http, useRequest } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '@melt-js/libs-bag-request'</span></span>
|
|
218
|
+
<span class="line"></span>
|
|
219
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">interface</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> UserProfile</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
|
220
|
+
<span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> id</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span></span>
|
|
221
|
+
<span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> nickname</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span></span>
|
|
222
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span>
|
|
223
|
+
<span class="line"></span>
|
|
224
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> userRequest</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> useRequest</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">((</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">userId</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> http.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">get</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"><</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">UserProfile</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">>(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">\`/api/users/\${</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">userId</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">}\`</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">), {</span></span>
|
|
225
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> strategy: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'latest'</span></span>
|
|
226
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">})</span></span>
|
|
227
|
+
<span class="line"></span>
|
|
228
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">await</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> userRequest.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">run</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'user_1'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
|
|
229
|
+
<span class="line"></span>
|
|
230
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">log</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(userRequest.loading.value)</span></span>
|
|
231
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">log</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(userRequest.data.value)</span></span>
|
|
232
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">log</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(userRequest.error.value)</span></span></code></pre></div><h3 id="常用方法" tabindex="-1">常用方法 <a class="header-anchor" href="#常用方法" aria-label="Permalink to "常用方法""></a></h3><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { fetchHttp, useRequest } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '@melt-js/libs-bag-request'</span></span>
|
|
233
|
+
<span class="line"></span>
|
|
234
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> articleRequest</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> useRequest</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span></span>
|
|
235
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">articleId</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> fetchHttp.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">get</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">\`/api/articles/\${</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">articleId</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">}\`</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">),</span></span>
|
|
236
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
|
237
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> defaultData: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">null</span></span>
|
|
238
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
239
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
|
|
240
|
+
<span class="line"></span>
|
|
241
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">await</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> articleRequest.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">run</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'article_1'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
|
|
242
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">await</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> articleRequest.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">refresh</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()</span></span>
|
|
243
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">articleRequest.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">cancel</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'dialog closed'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
|
|
244
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">articleRequest.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">reset</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()</span></span></code></pre></div><ul><li><code>loading</code>:当前这个请求控制器是否还有活跃任务</li><li><code>data</code>:最近一次有效成功结果</li><li><code>error</code>:最近一次有效失败结果</li><li><code>run(...args)</code>:执行请求并返回 <code>Promise</code></li><li><code>refresh()</code>:用上一次参数重新执行</li><li><code>cancel()</code>:让当前活跃请求失效,并立即退出当前控制器的 loading 统计</li><li><code>reset()</code>:清空当前控制器状态,并把 <code>data</code> 恢复到 <code>defaultData</code></li></ul><h3 id="并发策略" tabindex="-1">并发策略 <a class="header-anchor" href="#并发策略" aria-label="Permalink to "并发策略""></a></h3><p><code>useRequest()</code> 现在支持三种执行策略:</p><ul><li><code>latest</code>:默认值。新请求开始时,旧请求立即失效,适合搜索、筛选、切页</li><li><code>parallel</code>:允许多个请求并发执行,谁最后回来谁覆盖 <code>data</code></li><li><code>block</code>:执行中再次调用 <code>run()</code> 会直接抛错,适合按钮防重复提交</li></ul><p>支持的缓存策略有:</p><ul><li><code>network-first</code></li><li><code>cache-first</code></li><li><code>stale-while-revalidate</code></li><li><code>cache-only</code></li><li><code>network-only</code></li></ul><h2 id="错误处理模型" tabindex="-1">错误处理模型 <a class="header-anchor" href="#错误处理模型" aria-label="Permalink to "错误处理模型""></a></h2><h3 id="_1-http-状态码错误" tabindex="-1">1. HTTP 状态码错误 <a class="header-anchor" href="#_1-http-状态码错误" aria-label="Permalink to "1. HTTP 状态码错误""></a></h3><p>当接口返回 <code>401</code>、<code>403</code>、<code>5xx</code> 时,请求层会分别触发:</p><ul><li><code>onUnauthorized</code></li><li><code>onForbidden</code></li><li><code>onServerError</code></li></ul><h3 id="_2-业务错误" tabindex="-1">2. 业务错误 <a class="header-anchor" href="#_2-业务错误" aria-label="Permalink to "2. 业务错误""></a></h3><p>很多后端会返回 HTTP 200,但实际业务失败,例如:</p><div class="language-json vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">json</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{</span></span>
|
|
245
|
+
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> "success"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">false</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
246
|
+
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> "code"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"PRODUCT_NOT_FOUND"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
247
|
+
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> "message"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"商品不存在"</span></span>
|
|
248
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><p>这时可以通过 <code>resolveError()</code> 把它识别为业务错误,再转成异常抛出。</p><h3 id="_3-httperror" tabindex="-1">3. HttpError <a class="header-anchor" href="#_3-httperror" aria-label="Permalink to "3. HttpError""></a></h3><p>请求层会抛出 <code>HttpError</code>,里面包含:</p><ul><li><code>message</code></li><li><code>code</code></li><li><code>status</code></li><li><code>payload</code></li><li><code>response</code></li></ul><p>业务层可以在 <code>catch</code> 中集中处理:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { HttpError, http } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '@melt-js/libs-bag-request'</span></span>
|
|
249
|
+
<span class="line"></span>
|
|
250
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">try</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
|
251
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> http.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">get</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'/api/products/1'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
|
|
252
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">} </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">catch</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (error) {</span></span>
|
|
253
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (error </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">instanceof</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> HttpError</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) {</span></span>
|
|
254
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">error</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(error.status, error.code, error.message)</span></span>
|
|
255
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
256
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><h2 id="拦截器流程" tabindex="-1">拦截器流程 <a class="header-anchor" href="#拦截器流程" aria-label="Permalink to "拦截器流程""></a></h2><ol><li><strong>请求阶段</strong>:发起请求时,执行 <code>getToken()</code> 获取最新凭证,并自动附加上 <code>Authorization: Bearer <Token></code> 请求头。</li><li><strong>响应拦截</strong>: <ul><li>默认提取响应数据。</li><li>若 <code>resolveError()</code> 识别出业务错误,则转成 <code>HttpError</code> 抛出。</li><li>若捕获到 <code>401</code> / <code>403</code> / <code>5xx</code>,则触发对应钩子。</li></ul></li></ol><h2 id="使用建议" tabindex="-1">使用建议 <a class="header-anchor" href="#使用建议" aria-label="Permalink to "使用建议""></a></h2><ul><li>插件页面里只写业务请求,不要重复处理 Token</li><li>宿主应用在入口注入 <code>setupHttp()</code> 或 <code>setupFetch()</code></li><li>用 <code>resolveError()</code> 适配你的后端业务错误格式</li><li>页面层优先用 <code>useRequest()</code> 收口执行状态,避免重复维护 <code>loading</code>、<code>data</code>、<code>error</code></li><li>PWA 模式更适合列表、详情、配置查询这类可缓存读请求</li><li>如果项目主线仍是 <code>axios</code>,可以先只启用 <code>setupHttp({ pwa: { cache } })</code></li><li>离线队列更适合 JSON / 字符串请求体,不建议直接拿来排队文件上传</li><li>页面层 <code>catch</code> 时优先判断 <code>HttpError</code></li></ul>`,69)])])}const y=i(l,[["render",t]]);export{g as __pageData,y as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{_ as i,o as a,c as n,a2 as h}from"./chunks/framework.B3lxS50j.js";const g=JSON.parse('{"title":"网络请求与拦截","description":"","frontmatter":{},"headers":[],"relativePath":"guide/network-request.md","filePath":"guide/network-request.md","lastUpdated":1794045200000}'),l={name:"guide/network-request.md"};function t(p,s,k,e,E,d){return a(),n("div",null,[...s[0]||(s[0]=[h("",69)])])}const y=i(l,[["render",t]]);export{g as __pageData,y as default};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import{_ as a,o as i,c as t,a2 as l}from"./chunks/framework.B3lxS50j.js";const k=JSON.parse('{"title":"官方插件","description":"","frontmatter":{},"headers":[],"relativePath":"guide/official-plugins/index.md","filePath":"guide/official-plugins/index.md","lastUpdated":1794045200000}'),n={name:"guide/official-plugins/index.md"};function e(p,s,h,d,o,r){return i(),t("div",null,[...s[0]||(s[0]=[l(`<h1 id="官方插件" tabindex="-1">官方插件 <a class="header-anchor" href="#官方插件" aria-label="Permalink to "官方插件""></a></h1><p>官方插件用于展示一块完整业务如何接入 Vue-Bag-Admin。它们和本地插件遵循同一套 <code>AdminPlugin</code> 协议,但可以作为独立 npm 包安装和升级。</p><p>当前提供两个官方参考插件:</p><table tabindex="0"><thead><tr><th>插件</th><th>插件 ID</th><th style="text-align:right;">默认顺序</th><th>用途</th></tr></thead><tbody><tr><td><code>@melt-js/comps-bag-shop</code></td><td><code>plugin-shop</code></td><td style="text-align:right;">10</td><td>演示商城业务域、复杂路由和多级菜单</td></tr><tr><td><code>@melt-js/comps-bag-sys</code></td><td><code>plugin-sys-setting</code></td><td style="text-align:right;">100</td><td>演示系统设置、外观配置和插件管理</td></tr></tbody></table><h2 id="官方插件的定位" tabindex="-1">官方插件的定位 <a class="header-anchor" href="#官方插件的定位" aria-label="Permalink to "官方插件的定位""></a></h2><p>这两个插件首先是架构和页面组织方式的参考实现,不是已经接好生产接口的完整业务系统。</p><p>它们可以帮助你理解:</p><ul><li>一个插件如何同时提供路由、菜单和多语言。</li><li>详情页、编辑页如何保持列表菜单高亮。</li><li>多个路由如何复用同一个缓存视图。</li><li>插件管理页如何读取运行时插件清单。</li><li>宿主能力和具体业务页面应该如何划分边界。</li></ul><p>正式项目通常需要继续补充:</p><ul><li>真实后端接口和数据模型。</li><li>细粒度角色与权限点。</li><li>表单校验和服务端错误处理。</li><li>配置持久化和审计记录。</li><li>与自身业务一致的页面和交互。</li></ul><h2 id="安装" tabindex="-1">安装 <a class="header-anchor" href="#安装" aria-label="Permalink to "安装""></a></h2><p>已经通过脚手架创建项目时,宿主依赖已经具备,只需安装需要的插件:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> add</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> @melt-js/comps-bag-shop</span></span>
|
|
2
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> add</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> @melt-js/comps-bag-sys</span></span></code></pre></div><p>也可以一起安装:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> add</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> @melt-js/comps-bag-shop</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> @melt-js/comps-bag-sys</span></span></code></pre></div><h2 id="挂载" tabindex="-1">挂载 <a class="header-anchor" href="#挂载" aria-label="Permalink to "挂载""></a></h2><p>在宿主 <code>src/main.ts</code> 中导入插件:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> shopPlugin </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '@melt-js/comps-bag-shop'</span></span>
|
|
3
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> sysSettingPlugin </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '@melt-js/comps-bag-sys'</span></span>
|
|
4
|
+
<span class="line"></span>
|
|
5
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">await</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> bootstrapPlugins</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
|
6
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> app,</span></span>
|
|
7
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> router,</span></span>
|
|
8
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> i18n,</span></span>
|
|
9
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> plugins: [shopPlugin, sysSettingPlugin] </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// 传入需要参与本次引导的插件</span></span>
|
|
10
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">})</span></span></code></pre></div><p><code>bootstrapPlugins()</code> 会根据插件的 <code>order</code> 排序,所以数组书写顺序不决定最终菜单顺序。</p><p>完成引导后:</p><ul><li>商城插件会注册商品、订单、用户、营销、客服、财务和店铺设置页面。</li><li>系统设置插件会注册常规设置、高级设置和插件管理页面。</li><li>两个插件的中文、英文词条会合并到宿主 i18n。</li><li>菜单会根据当前用户的角色和权限过滤。</li></ul><h2 id="与脚手架本地插件的区别" tabindex="-1">与脚手架本地插件的区别 <a class="header-anchor" href="#与脚手架本地插件的区别" aria-label="Permalink to "与脚手架本地插件的区别""></a></h2><p>脚手架默认生成的 <code>src/plugins/*</code> 是项目内部插件,不需要单独安装。官方插件则位于独立包中:</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>本地插件</span></span>
|
|
11
|
+
<span class="line"><span>src/plugins/report.ts</span></span>
|
|
12
|
+
<span class="line"><span></span></span>
|
|
13
|
+
<span class="line"><span>官方插件</span></span>
|
|
14
|
+
<span class="line"><span>node_modules/@melt-js/comps-bag-shop</span></span>
|
|
15
|
+
<span class="line"><span>node_modules/@melt-js/comps-bag-sys</span></span></code></pre></div><p>两者的运行方式相同。一个本地插件需要被多个项目复用时,可以再迁移成独立包。</p><h2 id="选择建议" tabindex="-1">选择建议 <a class="header-anchor" href="#选择建议" aria-label="Permalink to "选择建议""></a></h2><ul><li>想学习复杂路由和菜单设计:阅读<a href="./shop.html">商城插件</a>。</li><li>想增加设置中心和插件管理页:阅读<a href="./sys-setting.html">系统设置插件</a>。</li><li>想控制插件启用状态:阅读<a href="./install-and-toggle.html">安装与启停</a>。</li><li>想创建自己的业务插件:进入<a href="./../plugins/create-plugin.html">插件开发</a>。</li></ul><h2 id="下一步" tabindex="-1">下一步 <a class="header-anchor" href="#下一步" aria-label="Permalink to "下一步""></a></h2><p>继续阅读<a href="./install-and-toggle.html">安装与启停</a>,了解插件如何进入运行集合,以及为什么切换状态后需要刷新应用。</p>`,29)])])}const g=a(n,[["render",e]]);export{k as __pageData,g as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{_ as a,o as i,c as t,a2 as l}from"./chunks/framework.B3lxS50j.js";const k=JSON.parse('{"title":"官方插件","description":"","frontmatter":{},"headers":[],"relativePath":"guide/official-plugins/index.md","filePath":"guide/official-plugins/index.md","lastUpdated":1794045200000}'),n={name:"guide/official-plugins/index.md"};function e(p,s,h,d,o,r){return i(),t("div",null,[...s[0]||(s[0]=[l("",29)])])}const g=a(n,[["render",e]]);export{k as __pageData,g as default};
|