@melt-js/docs-bag 0.0.0-stage → 2026.11.7-1
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 +44 -2
- package/dist/404.html +22 -0
- package/dist/README.html +33 -0
- package/dist/assets/README.md.DGU5lUfa.js +9 -0
- package/dist/assets/README.md.DGU5lUfa.lean.js +1 -0
- package/dist/assets/app.Ds2SzgsS.js +1 -0
- package/dist/assets/chunks/@localSearchIndexroot.UvrVlibN.js +1 -0
- package/dist/assets/chunks/VPLocalSearchBox.vT7UNiG_.js +9 -0
- package/dist/assets/chunks/framework.DaGrNpXH.js +20 -0
- package/dist/assets/chunks/theme.Caar5PdV.js +2 -0
- package/dist/assets/guide_complete-host-app.md.BK8IlbVU.js +174 -0
- package/dist/assets/guide_complete-host-app.md.BK8IlbVU.lean.js +1 -0
- package/dist/assets/guide_create-project.md.DdUrJ9TP.js +34 -0
- package/dist/assets/guide_create-project.md.DdUrJ9TP.lean.js +1 -0
- package/dist/assets/guide_deployment.md.Bok2OVNY.js +42 -0
- package/dist/assets/guide_deployment.md.Bok2OVNY.lean.js +1 -0
- package/dist/assets/guide_dictionary-system.md.CBwI_GoJ.js +32 -0
- package/dist/assets/guide_dictionary-system.md.CBwI_GoJ.lean.js +1 -0
- package/dist/assets/guide_getting-started.md.DY8_yjmu.js +9 -0
- package/dist/assets/guide_getting-started.md.DY8_yjmu.lean.js +1 -0
- package/dist/assets/guide_host_auth-and-permissions.md.0lZV8yHP.js +139 -0
- package/dist/assets/guide_host_auth-and-permissions.md.0lZV8yHP.lean.js +1 -0
- package/dist/assets/guide_host_bootstrap.md.lEHuoLl6.js +87 -0
- package/dist/assets/guide_host_bootstrap.md.lEHuoLl6.lean.js +1 -0
- package/dist/assets/guide_host_routing-and-menu.md.BoIgnh8N.js +103 -0
- package/dist/assets/guide_host_routing-and-menu.md.BoIgnh8N.lean.js +1 -0
- package/dist/assets/guide_introduction.md.iXNk9q0Q.js +14 -0
- package/dist/assets/guide_introduction.md.iXNk9q0Q.lean.js +1 -0
- package/dist/assets/guide_local-debugging.md.DUTHJNrd.js +15 -0
- package/dist/assets/guide_local-debugging.md.DUTHJNrd.lean.js +1 -0
- package/dist/assets/guide_network-request.md.CNxuQztV.js +256 -0
- package/dist/assets/guide_network-request.md.CNxuQztV.lean.js +1 -0
- package/dist/assets/guide_official-plugins_index.md.BoDXHNxM.js +15 -0
- package/dist/assets/guide_official-plugins_index.md.BoDXHNxM.lean.js +1 -0
- package/dist/assets/guide_official-plugins_install-and-toggle.md.Dr7JbEG0.js +45 -0
- package/dist/assets/guide_official-plugins_install-and-toggle.md.Dr7JbEG0.lean.js +1 -0
- package/dist/assets/guide_official-plugins_shop.md.DiOYHXuP.js +49 -0
- package/dist/assets/guide_official-plugins_shop.md.DiOYHXuP.lean.js +1 -0
- package/dist/assets/guide_official-plugins_sys-setting.md.zAtX0VM9.js +26 -0
- package/dist/assets/guide_official-plugins_sys-setting.md.zAtX0VM9.lean.js +1 -0
- package/dist/assets/guide_package-core.md.C4zUrJyx.js +45 -0
- package/dist/assets/guide_package-core.md.C4zUrJyx.lean.js +1 -0
- package/dist/assets/guide_package-ecosystem.md.D7XqIXVb.js +1 -0
- package/dist/assets/guide_package-ecosystem.md.D7XqIXVb.lean.js +1 -0
- package/dist/assets/guide_package-plugin-shop.md.fAmp9PnM.js +9 -0
- package/dist/assets/guide_package-plugin-shop.md.fAmp9PnM.lean.js +1 -0
- package/dist/assets/guide_package-plugin-sys-setting.md.B_eYlFsp.js +9 -0
- package/dist/assets/guide_package-plugin-sys-setting.md.B_eYlFsp.lean.js +1 -0
- package/dist/assets/guide_package-publishing.md.B457Mv-9.js +7 -0
- package/dist/assets/guide_package-publishing.md.B457Mv-9.lean.js +1 -0
- package/dist/assets/guide_package-request.md.BxsPauw8.js +195 -0
- package/dist/assets/guide_package-request.md.BxsPauw8.lean.js +1 -0
- package/dist/assets/guide_package-ui.md.BTeJ94Oh.js +50 -0
- package/dist/assets/guide_package-ui.md.BTeJ94Oh.lean.js +1 -0
- package/dist/assets/guide_permissions.md.DAZn1vjP.js +83 -0
- package/dist/assets/guide_permissions.md.DAZn1vjP.lean.js +1 -0
- package/dist/assets/guide_plugin-development.md.BUmEsBpT.js +226 -0
- package/dist/assets/guide_plugin-development.md.BUmEsBpT.lean.js +1 -0
- package/dist/assets/guide_plugins_admin-plugin.md.DPkzLbtK.js +52 -0
- package/dist/assets/guide_plugins_admin-plugin.md.DPkzLbtK.lean.js +1 -0
- package/dist/assets/guide_plugins_create-plugin.md.DvTO3X0-.js +109 -0
- package/dist/assets/guide_plugins_create-plugin.md.DvTO3X0-.lean.js +1 -0
- package/dist/assets/guide_plugins_debug-and-publish.md.6Vl--EVC.js +92 -0
- package/dist/assets/guide_plugins_debug-and-publish.md.6Vl--EVC.lean.js +1 -0
- package/dist/assets/guide_plugins_lifecycle-and-dependencies.md.D4pLzazK.js +45 -0
- package/dist/assets/guide_plugins_lifecycle-and-dependencies.md.D4pLzazK.lean.js +1 -0
- package/dist/assets/guide_plugins_permissions-and-settings.md.t7QTgL3Q.js +78 -0
- package/dist/assets/guide_plugins_permissions-and-settings.md.t7QTgL3Q.lean.js +1 -0
- package/dist/assets/guide_plugins_routes-menus-locales.md.yqtK9Ucl.js +100 -0
- package/dist/assets/guide_plugins_routes-menus-locales.md.yqtK9Ucl.lean.js +1 -0
- package/dist/assets/guide_pro-form.md.CMhQ6QRl.js +116 -0
- package/dist/assets/guide_pro-form.md.CMhQ6QRl.lean.js +1 -0
- package/dist/assets/guide_pro-table.md.I6fEG_lQ.js +54 -0
- package/dist/assets/guide_pro-table.md.I6fEG_lQ.lean.js +1 -0
- package/dist/assets/guide_request-and-components.md.BQIKZknw.js +175 -0
- package/dist/assets/guide_request-and-components.md.BQIKZknw.lean.js +1 -0
- package/dist/assets/guide_routing-and-menu.md.BWLWiMg1.js +74 -0
- package/dist/assets/guide_routing-and-menu.md.BWLWiMg1.lean.js +1 -0
- package/dist/assets/guide_theme-tokens.md.BZ_Qwz_U.js +53 -0
- package/dist/assets/guide_theme-tokens.md.BZ_Qwz_U.lean.js +1 -0
- package/dist/assets/index.md.RFoPWDBP.js +1 -0
- package/dist/assets/index.md.RFoPWDBP.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.BUkIHM41.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,42 @@
|
|
|
1
|
+
import{_ as i,o as a,c as n,a2 as l}from"./chunks/framework.DaGrNpXH.js";const g=JSON.parse('{"title":"上线部署","description":"","frontmatter":{},"headers":[],"relativePath":"guide/deployment.md","filePath":"guide/deployment.md","lastUpdated":1794045200000}'),p={name:"guide/deployment.md"};function h(e,s,t,k,d,r){return a(),n("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 分成前端宿主应用和后端 API。仓库默认带一套 Strapi 5 后端,所以部署时也分两段看:先前端,再后端。</p><h2 id="_1-前端部署" tabindex="-1">1. 前端部署 <a class="header-anchor" href="#_1-前端部署" aria-label="Permalink to "1. 前端部署""></a></h2><p>前端由 Vite 打成静态文件,放到 Nginx 或其他静态服务器上就能跑。</p><h3 id="构建静态文件" tabindex="-1">构建静态文件 <a class="header-anchor" href="#构建静态文件" aria-label="Permalink to "构建静态文件""></a></h3><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:#6A737D;--shiki-dark:#6A737D;"># 只构建后台管理系统前端</span></span>
|
|
2
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --filter</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> @melt-js/tpl-vue3-admin-naive-bag</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> build</span></span></code></pre></div><p>构建完成后,<code>tpl-vue3-admin-naive-bag/dist</code> 里会生成 HTML、CSS 和 JS 文件。</p><h3 id="nginx-部署配置" tabindex="-1">Nginx 部署配置 <a class="header-anchor" href="#nginx-部署配置" aria-label="Permalink to "Nginx 部署配置""></a></h3><p>将 <code>dist</code> 目录下的内容上传到你的服务器(例如放到 <code>/usr/share/nginx/html/admin</code>)。</p><p>Vue-Bag-Admin 默认使用 Vue Router 的 <strong>History 模式</strong>。Nginx 需要把找不到的前端路径回退到 <code>index.html</code>,不然在非根路径刷新页面会 404。</p><div class="language-nginx vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">nginx</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;">server</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
|
3
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> listen </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">80</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
|
4
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> server_name </span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">your-domain.com;</span></span>
|
|
5
|
+
<span class="line"></span>
|
|
6
|
+
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # 前端静态文件目录</span></span>
|
|
7
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> root </span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">/usr/share/nginx/html/admin;</span></span>
|
|
8
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> index </span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">index.html;</span></span>
|
|
9
|
+
<span class="line"></span>
|
|
10
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> location</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> / </span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{</span></span>
|
|
11
|
+
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # History 模式配置:找不到文件时默认指向 index.html</span></span>
|
|
12
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> try_files </span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">$uri $uri/ /index.html;</span></span>
|
|
13
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
14
|
+
<span class="line"></span>
|
|
15
|
+
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # (可选)配置 API 代理,解决跨域问题</span></span>
|
|
16
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> location</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> /api/ </span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{</span></span>
|
|
17
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> proxy_pass </span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">http://127.0.0.1:60010/; </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"># 代理到你的后端地址</span></span>
|
|
18
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> proxy_set_header </span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">Host $host;</span></span>
|
|
19
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> proxy_set_header </span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">X-Real-IP $remote_addr;</span></span>
|
|
20
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
21
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><h2 id="_2-后端部署-strapi" tabindex="-1">2. 后端部署 (Strapi) <a class="header-anchor" href="#_2-后端部署-strapi" aria-label="Permalink to "2. 后端部署 (Strapi)""></a></h2><p>如果你使用的是本项目自带的 Strapi 5 服务,部署步骤如下。</p><h3 id="准备环境" tabindex="-1">准备环境 <a class="header-anchor" href="#准备环境" aria-label="Permalink to "准备环境""></a></h3><p>服务器上先准备好这些:</p><ul><li>Node.js (v24.4.1 或更高版本)</li><li>MySQL 8.0+ 数据库</li><li>PM2 (<code>npm install -g pm2</code>)</li></ul><h3 id="生产环境构建" tabindex="-1">生产环境构建 <a class="header-anchor" href="#生产环境构建" aria-label="Permalink to "生产环境构建""></a></h3><p>在根目录或者 <code>service-bag-strapi</code> 目录中,执行构建命令:</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:#6A737D;--shiki-dark:#6A737D;"># 进入后端目录</span></span>
|
|
22
|
+
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">cd</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> service-bag-strapi</span></span>
|
|
23
|
+
<span class="line"></span>
|
|
24
|
+
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"># 构建 Strapi</span></span>
|
|
25
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> build</span></span></code></pre></div><h3 id="配置环境变量" tabindex="-1">配置环境变量 <a class="header-anchor" href="#配置环境变量" aria-label="Permalink to "配置环境变量""></a></h3><p>在服务器的 <code>service-bag-strapi</code> 目录下,创建一个 <code>.env</code> 文件,填入生产环境的配置:</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:#24292E;--shiki-dark:#E1E4E8;">HOST</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">0.0.0.0</span></span>
|
|
26
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">PORT</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">60010</span></span>
|
|
27
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">APP_KEYS</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">your_app_keys_here</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # 生成几段随机字符串,用逗号隔开</span></span>
|
|
28
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">API_TOKEN_SALT</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">your_api_salt_here</span></span>
|
|
29
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">ADMIN_JWT_SECRET</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">your_admin_jwt_here</span></span>
|
|
30
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">TRANSFER_TOKEN_SALT</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">your_transfer_salt_here</span></span>
|
|
31
|
+
<span class="line"></span>
|
|
32
|
+
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"># 数据库配置</span></span>
|
|
33
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">DATABASE_CLIENT</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">mysql</span></span>
|
|
34
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">DATABASE_HOST</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">127.0.0.1</span></span>
|
|
35
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">DATABASE_PORT</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">3306</span></span>
|
|
36
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">DATABASE_NAME</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">vue_bag_admin_prod</span></span>
|
|
37
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">DATABASE_USERNAME</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">root</span></span>
|
|
38
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">DATABASE_PASSWORD</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">your_password</span></span></code></pre></div><h3 id="使用-pm2-启动服务" tabindex="-1">使用 PM2 启动服务 <a class="header-anchor" href="#使用-pm2-启动服务" aria-label="Permalink to "使用 PM2 启动服务""></a></h3><p>用 PM2 启动 Node.js 进程,服务崩溃后会自动重启:</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:#6A737D;--shiki-dark:#6A737D;"># 启动 Strapi 服务,并命名为 "pm-backend"</span></span>
|
|
39
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pm2</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> start</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> npm</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --name</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "pm-backend"</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> run</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> start</span></span>
|
|
40
|
+
<span class="line"></span>
|
|
41
|
+
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"># 保存 PM2 进程列表,以便开机自启</span></span>
|
|
42
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pm2</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> save</span></span></code></pre></div><p>跑完后重点看两处:</p><ul><li>前端非根路径刷新不会 404</li><li>Strapi 进程在 <code>pm2 list</code> 里处于 online</li></ul>`,28)])])}const c=i(p,[["render",h]]);export{g as __pageData,c as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{_ as i,o as a,c as n,a2 as l}from"./chunks/framework.DaGrNpXH.js";const g=JSON.parse('{"title":"上线部署","description":"","frontmatter":{},"headers":[],"relativePath":"guide/deployment.md","filePath":"guide/deployment.md","lastUpdated":1794045200000}'),p={name:"guide/deployment.md"};function h(e,s,t,k,d,r){return a(),n("div",null,[...s[0]||(s[0]=[l("",28)])])}const c=i(p,[["render",h]]);export{g as __pageData,c as default};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import{_ as i,o as a,c as n,a2 as l}from"./chunks/framework.DaGrNpXH.js";const E=JSON.parse('{"title":"字典系统","description":"","frontmatter":{},"headers":[],"relativePath":"guide/dictionary-system.md","filePath":"guide/dictionary-system.md","lastUpdated":1794045200000}'),t={name:"guide/dictionary-system.md"};function e(h,s,p,k,d,r){return a(),n("div",null,[...s[0]||(s[0]=[l(`<h1 id="字典系统" tabindex="-1">字典系统 <a class="header-anchor" href="#字典系统" aria-label="Permalink to "字典系统""></a></h1><p>框架里内置了一套轻量字典系统,用来管理:</p><ul><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><ul><li>表格里一套状态文案</li><li>表单里另一套下拉选项</li><li>详情页又手写一套颜色映射</li></ul><p>字典系统要做的事很简单,把这些重复映射收进一个注册中心。</p><h2 id="核心结构" tabindex="-1">核心结构 <a class="header-anchor" href="#核心结构" aria-label="Permalink to "核心结构""></a></h2><p>字典协议定义在:</p><ul><li><code>/libs-bag-core/src/types/dictionary.ts</code></li></ul><p>运行时注册与缓存逻辑在:</p><ul><li><code>/libs-bag-core/src/dictionary.ts</code></li></ul><p>字典项结构如下:</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;">type</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> DictionaryOption</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
|
2
|
+
<span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> label</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span></span>
|
|
3
|
+
<span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> value</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> |</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> number</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> |</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> boolean</span></span>
|
|
4
|
+
<span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> color</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span></span>
|
|
5
|
+
<span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> textColor</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span></span>
|
|
6
|
+
<span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> tagType</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'default'</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> |</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'primary'</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> |</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'info'</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> |</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'success'</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> |</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'warning'</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> |</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'error'</span></span>
|
|
7
|
+
<span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> description</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span></span>
|
|
8
|
+
<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>宿主应用可以集中注册内置字典:</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;"> { registerDictionaries } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '@melt-js/libs-bag-core'</span></span>
|
|
9
|
+
<span class="line"></span>
|
|
10
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">registerDictionaries</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">([</span></span>
|
|
11
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
|
12
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> code: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'workspace-mode'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
13
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> options: [</span></span>
|
|
14
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { label: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'专注模式'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, value: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'focus'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, tagType: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'info'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
|
15
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { label: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'协作模式'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, value: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'collaboration'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, tagType: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'success'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
16
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ]</span></span>
|
|
17
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
18
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">])</span></span></code></pre></div><p>当前项目的内置字典入口在:</p><ul><li><code>/tpl-vue3-admin-naive-bag/src/dictionaries/index.ts</code></li></ul><p>并且已经在应用启动时接入:</p><ul><li><code>/tpl-vue3-admin-naive-bag/src/main.ts</code></li></ul><h2 id="运行时-api" tabindex="-1">运行时 API <a class="header-anchor" href="#运行时-api" aria-label="Permalink to "运行时 API""></a></h2><p><code>@melt-js/libs-bag-core</code> 当前暴露了这些方法:</p><ul><li><code>registerDictionary(definition)</code></li><li><code>registerDictionaries(definitions)</code></li><li><code>getDictionaryDefinition(code)</code></li><li><code>getCachedDictionaryOptions(code)</code></li><li><code>resolveDictionaryOptions(code, force?)</code></li><li><code>getDictionaryOption(code, value)</code></li><li><code>clearDictionaryCache(code?)</code></li></ul><h2 id="在-pmproform-中使用" tabindex="-1">在 PmProForm 中使用 <a class="header-anchor" href="#在-pmproform-中使用" aria-label="Permalink to "在 PmProForm 中使用""></a></h2><p><code>PmSchemaForm</code> 和 <code>PmProForm</code> 已经支持通过 <code>dictCode</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:#24292E;--shiki-dark:#E1E4E8;">{</span></span>
|
|
19
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> field</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'workMode'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
20
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> label</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>
|
|
21
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> component</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'select'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
22
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> dictCode</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'workspace-mode'</span></span>
|
|
23
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><p>这意味着 <code>select</code>、<code>radio</code>、<code>checkbox</code> 不一定要手写 <code>options</code>。</p><h2 id="使用字典标签" tabindex="-1">使用字典标签 <a class="header-anchor" href="#使用字典标签" aria-label="Permalink to "使用字典标签""></a></h2><p>如果你想把状态渲染成同一种标签样式,可以使用 <code>PmDictTag</code>:</p><div class="language-vue vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">vue</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 style="--shiki-light:#22863A;--shiki-dark:#85E89D;">PmDictTag</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> code</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"audit-log-type"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> :</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">value</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;">log.type</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> /></span></span></code></pre></div><p>当前组件在这里:</p><ul><li><code>/libs-bag-ui/src/components/PmDictTag.vue</code></li></ul><h2 id="异步字典" tabindex="-1">异步字典 <a class="header-anchor" href="#异步字典" aria-label="Permalink to "异步字典""></a></h2><p>除了静态 <code>options</code>,也支持通过 <code>getOptions</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:#6F42C1;--shiki-dark:#B392F0;">registerDictionary</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
|
24
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> code: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'remote-user-status'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
25
|
+
<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 style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
26
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> async</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> getOptions</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">() {</span></span>
|
|
27
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> [</span></span>
|
|
28
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { label: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'启用'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, value: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">1</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, tagType: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'success'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
|
29
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { label: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'禁用'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, value: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">0</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, tagType: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'warning'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
30
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ]</span></span>
|
|
31
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
32
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">})</span></span></code></pre></div><p>当字典带 <code>ttl</code> 时,运行时会优先读取缓存,超过有效期后再重新拉取。</p><h2 id="使用建议" tabindex="-1">使用建议 <a class="header-anchor" href="#使用建议" aria-label="Permalink to "使用建议""></a></h2><ul><li>枚举型状态优先走字典系统,不要在页面里重复维护 <code>statusMap</code></li><li>表单类选项优先用 <code>dictCode</code>,后面替换成远程字典会轻松很多</li><li>表格状态展示优先用 <code>PmDictTag</code>,让颜色和文案保持一致</li></ul>`,39)])])}const c=i(t,[["render",e]]);export{E as __pageData,c as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{_ as i,o as a,c as n,a2 as l}from"./chunks/framework.DaGrNpXH.js";const E=JSON.parse('{"title":"字典系统","description":"","frontmatter":{},"headers":[],"relativePath":"guide/dictionary-system.md","filePath":"guide/dictionary-system.md","lastUpdated":1794045200000}'),t={name:"guide/dictionary-system.md"};function e(h,s,p,k,d,r){return a(),n("div",null,[...s[0]||(s[0]=[l("",39)])])}const c=i(t,[["render",e]]);export{E as __pageData,c as default};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import{_ as s,o as t,c as i,a2 as e}from"./chunks/framework.DaGrNpXH.js";const k=JSON.parse('{"title":"快速上手","description":"","frontmatter":{},"headers":[],"relativePath":"guide/getting-started.md","filePath":"guide/getting-started.md","lastUpdated":1794045200000}'),n={name:"guide/getting-started.md"};function p(l,a,h,d,r,o){return t(),i("div",null,[...a[0]||(a[0]=[e(`<h1 id="快速上手" tabindex="-1">快速上手 <a class="header-anchor" href="#快速上手" aria-label="Permalink to "快速上手""></a></h1><p>这一页只完成一个目标:创建并运行一个可以登录的 Vue-Bag-Admin 项目。</p><h2 id="环境要求" tabindex="-1">环境要求 <a class="header-anchor" href="#环境要求" aria-label="Permalink to "环境要求""></a></h2><p>推荐使用与仓库一致的环境:</p><table tabindex="0"><thead><tr><th>工具</th><th>版本</th></tr></thead><tbody><tr><td>Node.js</td><td>24 或更高版本</td></tr><tr><td>pnpm</td><td>10 或更高版本</td></tr></tbody></table><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;">node</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -v</span></span>
|
|
2
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -v</span></span></code></pre></div><p>运行脚手架示例不需要数据库。仓库内的 Strapi 参考后端默认使用 SQLite,可直接启动;生产环境建议切换 MySQL。</p><h2 id="创建项目" tabindex="-1">创建项目 <a class="header-anchor" href="#创建项目" aria-label="Permalink to "创建项目""></a></h2><p>使用 pnpm:</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;"> dlx</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> @melt-js/libs-bag-create</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> my-admin</span></span></code></pre></div><p>也可以使用 npx:</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;">npx</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> @melt-js/libs-bag-create</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> my-admin</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:#005CC5;--shiki-dark:#79B8FF;">cd</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> my-admin</span></span>
|
|
3
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> install</span></span>
|
|
4
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> dev</span></span></code></pre></div><p>终端会输出本地访问地址,通常是:</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>http://localhost:5173</span></span></code></pre></div><h2 id="生成项目里有什么" tabindex="-1">生成项目里有什么 <a class="header-anchor" href="#生成项目里有什么" aria-label="Permalink to "生成项目里有什么""></a></h2><p>核心文件只有三类:</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>src/</span></span>
|
|
5
|
+
<span class="line"><span>├── main.ts # 初始化宿主、认证、请求和插件</span></span>
|
|
6
|
+
<span class="line"><span>├── routes.ts # 登录、Dashboard、403、404 等宿主路由</span></span>
|
|
7
|
+
<span class="line"><span>├── App.vue # 挂载 HostApp</span></span>
|
|
8
|
+
<span class="line"><span>├── plugins/ # 本地业务插件</span></span>
|
|
9
|
+
<span class="line"><span>└── views/ # 示例页面</span></span></code></pre></div><p>示例代码不是必须保留的框架文件。开始业务开发时,可以删除示例页面和插件,只保留自己的模块。</p><h2 id="下一步" tabindex="-1">下一步 <a class="header-anchor" href="#下一步" aria-label="Permalink to "下一步""></a></h2><p>继续阅读 <a href="./create-project.html">创建项目</a>,了解脚手架参数、目录职责,以及创建后首先应该修改哪些内容。</p>`,23)])])}const g=s(n,[["render",p]]);export{k as __pageData,g as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{_ as s,o as t,c as i,a2 as e}from"./chunks/framework.DaGrNpXH.js";const k=JSON.parse('{"title":"快速上手","description":"","frontmatter":{},"headers":[],"relativePath":"guide/getting-started.md","filePath":"guide/getting-started.md","lastUpdated":1794045200000}'),n={name:"guide/getting-started.md"};function p(l,a,h,d,r,o){return t(),i("div",null,[...a[0]||(a[0]=[e("",23)])])}const g=s(n,[["render",p]]);export{k as __pageData,g as default};
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import{_ as i,o as a,c as n,a2 as h}from"./chunks/framework.DaGrNpXH.js";const g=JSON.parse('{"title":"登录与权限","description":"","frontmatter":{},"headers":[],"relativePath":"guide/host/auth-and-permissions.md","filePath":"guide/host/auth-and-permissions.md","lastUpdated":1794045200000}'),p={name:"guide/host/auth-and-permissions.md"};function l(t,s,k,e,E,r){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 的权限链路分为四层:</p><ol><li><code>AuthProvider</code> 负责登录和获取用户资料。</li><li><code>userStore</code> 保存 token、角色和权限点。</li><li>路由守卫保护页面,菜单根据同一份数据过滤。</li><li>指令、组件和组合函数控制页面内的按钮或区域。</li></ol><p>后端实现可以不同,但最终需要向前端提供统一的角色和权限数据。</p><h2 id="启用路由鉴权" tabindex="-1">启用路由鉴权 <a class="header-anchor" href="#启用路由鉴权" aria-label="Permalink to "启用路由鉴权""></a></h2><p><code>createHostRouter()</code> 支持三种写法。</p><p>关闭鉴权:</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:#6F42C1;--shiki-dark:#B392F0;">createHostRouter</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
|
2
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> routes: appRoutes,</span></span>
|
|
3
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> auth: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">false</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 关闭登录和页面权限守卫</span></span>
|
|
4
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">})</span></span></code></pre></div><p>使用默认路径:</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:#6F42C1;--shiki-dark:#B392F0;">createHostRouter</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
|
5
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> routes: appRoutes,</span></span>
|
|
6
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> auth: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">true</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 启用默认鉴权规则</span></span>
|
|
7
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">})</span></span></code></pre></div><p>默认约定是:</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>首页 /dashboard</span></span>
|
|
8
|
+
<span class="line"><span>登录 /login</span></span>
|
|
9
|
+
<span class="line"><span>个人中心 /profile</span></span>
|
|
10
|
+
<span class="line"><span>无权限 /403</span></span>
|
|
11
|
+
<span class="line"><span>未找到 /404</span></span></code></pre></div><p>自定义路径和异常处理:</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;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> router</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> createHostRouter</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
|
12
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> routes: appRoutes,</span></span>
|
|
13
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> auth: {</span></span>
|
|
14
|
+
<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 style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// 启用路由鉴权</span></span>
|
|
15
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> homePath: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'/workspace'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// 登录后的默认首页</span></span>
|
|
16
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> loginPath: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'/sign-in'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// 未登录时跳转的登录页</span></span>
|
|
17
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> profilePath: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'/account'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// 个人中心地址</span></span>
|
|
18
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> forbiddenPath: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'/403'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// 权限不足时跳转的页面</span></span>
|
|
19
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> onProfileError</span><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:#032F62;--shiki-dark:#9ECBFF;"> 'logout'</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 用户资料加载失败时清空登录态</span></span>
|
|
21
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
22
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
23
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">})</span></span></code></pre></div><p>启用鉴权时,必须存在对应登录路由,并将它标记为 <code>meta.public: true</code>。</p><h2 id="接入认证服务" tabindex="-1">接入认证服务 <a class="header-anchor" href="#接入认证服务" aria-label="Permalink to "接入认证服务""></a></h2><p>认证服务实现 <code>AuthProvider</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, setAuthProvider, </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">type</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> AuthProvider } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '@melt-js/libs-bag-entry'</span></span>
|
|
24
|
+
<span class="line"></span>
|
|
25
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">interface</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> LoginResponse</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
|
26
|
+
<span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> token</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span></span>
|
|
27
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span>
|
|
28
|
+
<span class="line"></span>
|
|
29
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">interface</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> ProfileResponse</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
|
30
|
+
<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;"> number</span></span>
|
|
31
|
+
<span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> username</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span></span>
|
|
32
|
+
<span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> roles</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>
|
|
33
|
+
<span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> permissions</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>
|
|
34
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span>
|
|
35
|
+
<span class="line"></span>
|
|
36
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> authProvider</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> AuthProvider</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:#D73A49;--shiki-dark:#F97583;"> async</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> login</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>
|
|
38
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> result</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:#005CC5;--shiki-dark:#79B8FF;">any</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">LoginResponse</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">>(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'/api/login'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, payload)</span></span>
|
|
39
|
+
<span class="line"></span>
|
|
40
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
|
41
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> token: result.token</span></span>
|
|
42
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
43
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
|
44
|
+
<span class="line"></span>
|
|
45
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> async</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> fetchProfile</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">() {</span></span>
|
|
46
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> result</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:#005CC5;--shiki-dark:#79B8FF;">any</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">ProfileResponse</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">>(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'/api/me'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
|
|
47
|
+
<span class="line"></span>
|
|
48
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
|
49
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> username: result.username,</span></span>
|
|
50
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> user: result,</span></span>
|
|
51
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> roles: result.roles,</span></span>
|
|
52
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> permissions: result.permissions</span></span>
|
|
53
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
54
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
|
55
|
+
<span class="line"></span>
|
|
56
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> async</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> logout</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">() {</span></span>
|
|
57
|
+
<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;">post</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'/api/logout'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
|
|
58
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
59
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span>
|
|
60
|
+
<span class="line"></span>
|
|
61
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">setAuthProvider</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(authProvider) </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// 将认证实现交给宿主运行时</span></span></code></pre></div><p>如果后端使用仓库提供的 Strapi 参考接口,可以直接使用:</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;"> { createStrapiAuthProvider, setAuthProvider } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '@melt-js/libs-bag-entry'</span></span>
|
|
62
|
+
<span class="line"></span>
|
|
63
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">setAuthProvider</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">createStrapiAuthProvider</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()) </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// 使用框架内置的 Strapi 5 认证适配器</span></span></code></pre></div><p>默认 Strapi 适配器使用 <code>/api/auth/local</code> 登录,并通过 <code>/api/users/me</code> 获取用户资料。</p><h2 id="配置请求-token" tabindex="-1">配置请求 Token <a class="header-anchor" href="#配置请求-token" aria-label="Permalink to "配置请求 Token""></a></h2><p><code>setupHttp()</code> 会在每次请求前读取最新 token:</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;"> { getHostNavigationConfig, setupHttp, useUserStore } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '@melt-js/libs-bag-entry'</span></span>
|
|
64
|
+
<span class="line"></span>
|
|
65
|
+
<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>
|
|
66
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> navigation</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> getHostNavigationConfig</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">() </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// 获取登录页和 403 等导航地址</span></span>
|
|
67
|
+
<span class="line"></span>
|
|
68
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">setupHttp</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
|
69
|
+
<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 style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// 后端接口基础地址</span></span>
|
|
70
|
+
<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 style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// 每次请求前读取最新 token</span></span>
|
|
71
|
+
<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>
|
|
72
|
+
<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>
|
|
73
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> router.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">replace</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
|
74
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> path: navigation.loginPath,</span></span>
|
|
75
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> query: {</span></span>
|
|
76
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> redirect: router.currentRoute.value.fullPath </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// 记录登录后需要返回的页面</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:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
|
80
|
+
<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>
|
|
81
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> router.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">replace</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(navigation.forbiddenPath) </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// 收到 403 后进入无权限页面</span></span>
|
|
82
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
83
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">})</span></span></code></pre></div><p>用户登录成功后,<code>userStore</code> 会把 token 写入 <code>localStorage</code>,默认键名是 <code>bag.auth.token</code>。</p><h2 id="登录页面" tabindex="-1">登录页面 <a class="header-anchor" href="#登录页面" aria-label="Permalink to "登录页面""></a></h2><p>登录页只需要调用 <code>userStore.login()</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;"> { useRoute, useRouter } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'vue-router'</span></span>
|
|
84
|
+
<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;"> '@melt-js/libs-bag-entry'</span></span>
|
|
85
|
+
<span class="line"></span>
|
|
86
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> route</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> useRoute</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()</span></span>
|
|
87
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> router</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> useRouter</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()</span></span>
|
|
88
|
+
<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>
|
|
89
|
+
<span class="line"></span>
|
|
90
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> submitLogin</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>
|
|
91
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> userStore.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">login</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
|
92
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> username: username.value,</span></span>
|
|
93
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> password: password.value</span></span>
|
|
94
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> })</span></span>
|
|
95
|
+
<span class="line"></span>
|
|
96
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> redirect</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> typeof</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> route.query.redirect </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">===</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'string'</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> ?</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> route.query.redirect </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '/dashboard'</span></span>
|
|
97
|
+
<span class="line"></span>
|
|
98
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> router.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">replace</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(redirect)</span></span>
|
|
99
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><p>路由守卫会在用户带 token 进入受保护页面时自动加载资料。如果资料加载失败,默认清空登录态并返回登录页。</p><h2 id="页面权限" tabindex="-1">页面权限 <a class="header-anchor" href="#页面权限" aria-label="Permalink to "页面权限""></a></h2><p>路由通过角色或权限点限制访问:</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:#24292E;--shiki-dark:#E1E4E8;">{</span></span>
|
|
100
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> path</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'/finance/audit'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
101
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> component</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: () </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'./views/FinanceAudit.vue'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">),</span></span>
|
|
102
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> meta</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: {</span></span>
|
|
103
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> title</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>
|
|
104
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> roles</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: [</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'finance'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'manager'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">], </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// 需要检查的角色</span></span>
|
|
105
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> roleMode</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'all'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// 必须同时拥有 finance 和 manager</span></span>
|
|
106
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> permissions</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: [</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'finance.read'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'finance.audit'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">], </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// 需要检查的权限点</span></span>
|
|
107
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> permissionMode</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'all'</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 必须同时拥有两个权限点</span></span>
|
|
108
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
109
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><p>同一个数组默认是 <code>any</code>,配置 <code>all</code> 后才要求全部满足。</p><p>当 <code>roles</code> 和 <code>permissions</code> 同时存在时,两组条件都必须通过。<code>policy</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:#6F42C1;--shiki-dark:#B392F0;">meta</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: {</span></span>
|
|
110
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> permissions</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: [</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'team.read'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">], </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// 先通过基础权限检查</span></span>
|
|
111
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> policy</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: ({ </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">roles</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">user</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span></span>
|
|
112
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> roles.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">includes</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'admin'</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;"> user?.teamId </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">===</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'team-1'</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 管理员或指定团队成员可访问</span></span>
|
|
113
|
+
<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>在 <code>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;"> { PermissionAccess, registerPermissionDirective } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '@melt-js/libs-bag-entry'</span></span>
|
|
114
|
+
<span class="line"></span>
|
|
115
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">app.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">component</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'PermissionAccess'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, PermissionAccess) </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// 全局注册权限区域组件</span></span>
|
|
116
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">registerPermissionDirective</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(app) </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// 全局注册 v-permission 指令</span></span></code></pre></div><h3 id="控制单个元素" tabindex="-1">控制单个元素 <a class="header-anchor" href="#控制单个元素" aria-label="Permalink to "控制单个元素""></a></h3><div class="language-vue vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">vue</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 style="--shiki-light:#22863A;--shiki-dark:#85E89D;">button</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> v-permission</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"'product.create'"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">></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;"></</span><span style="--shiki-light:#22863A;--shiki-dark:#85E89D;">button</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">></span></span>
|
|
119
|
+
<span class="line"></span>
|
|
120
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"><</span><span style="--shiki-light:#22863A;--shiki-dark:#85E89D;">button</span></span>
|
|
121
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> v-permission</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>
|
|
122
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> roles: [</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'admin'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">],</span></span>
|
|
123
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> permissions: [</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'product.delete'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">]</span></span>
|
|
124
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"</span></span>
|
|
125
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">></span></span>
|
|
126
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> 删除商品</span></span>
|
|
127
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"></</span><span style="--shiki-light:#22863A;--shiki-dark:#85E89D;">button</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-vue vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">vue</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 style="--shiki-light:#22863A;--shiki-dark:#85E89D;">PermissionAccess</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> :</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">permissions</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 style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'report.export'</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>
|
|
128
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> <ExportButton /></span></span>
|
|
129
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> <ExportHistory /></span></span>
|
|
130
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"></</span><span style="--shiki-light:#22863A;--shiki-dark:#85E89D;">PermissionAccess</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;"> { canAccess, useAccess } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '@melt-js/libs-bag-entry'</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;"> canEdit</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> useAccess</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
|
133
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> permissions: [</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'product.edit'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">]</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;"> canManageSystem</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> canAccess</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
|
137
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> roles: [</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'admin'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">],</span></span>
|
|
138
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> permissions: [</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'system.manage'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">]</span></span>
|
|
139
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">})</span></span></code></pre></div><p><code>useAccess()</code> 返回响应式的 <code>ComputedRef<boolean></code>;<code>canAccess()</code> 返回当前时刻的布尔值。</p><h2 id="权限设计建议" tabindex="-1">权限设计建议 <a class="header-anchor" href="#权限设计建议" aria-label="Permalink to "权限设计建议""></a></h2><ul><li>页面安全依赖路由守卫,不能只隐藏菜单或按钮。</li><li>菜单与对应路由使用同一组角色和权限条件。</li><li>角色适合描述身份,权限点适合描述具体动作。</li><li>权限点建议采用 <code>业务域.资源.动作</code>,例如 <code>shop.product.create</code>。</li><li>超级管理员可以返回 <code>*</code> 权限,框架会视为拥有所有权限点。</li><li>前端权限用于交互和路由保护,后端仍必须再次校验接口权限。</li></ul><h2 id="下一步" tabindex="-1">下一步 <a class="header-anchor" href="#下一步" aria-label="Permalink to "下一步""></a></h2><p>继续阅读 <a href="./../request-and-components.html">请求与组件</a>,在页面中接入接口、请求状态、表格和表单。</p>`,49)])])}const y=i(p,[["render",l]]);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.DaGrNpXH.js";const g=JSON.parse('{"title":"登录与权限","description":"","frontmatter":{},"headers":[],"relativePath":"guide/host/auth-and-permissions.md","filePath":"guide/host/auth-and-permissions.md","lastUpdated":1794045200000}'),p={name:"guide/host/auth-and-permissions.md"};function l(t,s,k,e,E,r){return a(),n("div",null,[...s[0]||(s[0]=[h("",49)])])}const y=i(p,[["render",l]]);export{g as __pageData,y as default};
|