239 lines
73 KiB
JavaScript
239 lines
73 KiB
JavaScript
import{_ as i,o as a,c as n,a2 as t}from"./chunks/framework.B-QBKwc1.js";const o=JSON.parse('{"title":"前端分层架构","description":"前端采用 Vue 3 + TypeScript 组件化架构,分为 View(视图)→ API(接口)→ Store(状态)→ HTTP(请求)四层。","frontmatter":{},"headers":[],"relativePath":"zh/architecture/frontend-layer.md","filePath":"zh/architecture/frontend-layer.md"}'),p={name:"zh/architecture/frontend-layer.md"};function l(h,s,e,k,d,r){return a(),n("div",null,[...s[0]||(s[0]=[t(`<h1 id="_4-4-前端分层架构" tabindex="-1">4.4 前端分层架构 <a class="header-anchor" href="#_4-4-前端分层架构" aria-label="Permalink to "4.4 前端分层架构""></a></h1><div class="tip custom-block"><p class="custom-block-title">概述</p><p>前端采用 Vue 3 + TypeScript 组件化架构,分为 View(视图)→ API(接口)→ Store(状态)→ HTTP(请求)四层。辅以 Router(路由)、Directives(指令)、Hooks(组合式函数)、Utils(工具)等支撑模块。</p></div><h2 id="架构全景" tabindex="-1">架构全景 <a class="header-anchor" href="#架构全景" aria-label="Permalink to "架构全景""></a></h2><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span>┌─────────────────────────────────────────────────────────────────────┐</span></span>
|
||
<span class="line"><span>│ 支撑模块 │</span></span>
|
||
<span class="line"><span>│ │</span></span>
|
||
<span class="line"><span>│ Router(路由) Directives(指令) Hooks(组合式函数) │</span></span>
|
||
<span class="line"><span>│ src/router/ src/directives/ src/hooks/ │</span></span>
|
||
<span class="line"><span>│ │</span></span>
|
||
<span class="line"><span>│ Utils(工具) Enums(枚举) Styles(样式) │</span></span>
|
||
<span class="line"><span>│ src/utils/ src/enums/ src/styles/ │</span></span>
|
||
<span class="line"><span>└──────────────────────────────┬──────────────────────────────────────┘</span></span>
|
||
<span class="line"><span> │ 被主干层引用</span></span>
|
||
<span class="line"><span> ▼</span></span>
|
||
<span class="line"><span>┌─────────────────────────────────────────────────────────────────────┐</span></span>
|
||
<span class="line"><span>│ 主干链路 │</span></span>
|
||
<span class="line"><span>│ │</span></span>
|
||
<span class="line"><span>│ ┌─────────────────────────────────────────────────────────────┐ │</span></span>
|
||
<span class="line"><span>│ │ View(视图层) │ │</span></span>
|
||
<span class="line"><span>│ │ 页面渲染、用户交互、调用 API 和 Store │ │</span></span>
|
||
<span class="line"><span>│ │ 文件:src/views/**/*.vue │ │</span></span>
|
||
<span class="line"><span>│ └──────────────────────────┬──────────────────────────────────┘ │</span></span>
|
||
<span class="line"><span>│ │ 调用 API 函数 │</span></span>
|
||
<span class="line"><span>│ ▼ │</span></span>
|
||
<span class="line"><span>│ ┌─────────────────────────────────────────────────────────────┐ │</span></span>
|
||
<span class="line"><span>│ │ API(接口层) │ │</span></span>
|
||
<span class="line"><span>│ │ 封装后端 API 调用,定义请求参数和响应类型 │ │</span></span>
|
||
<span class="line"><span>│ │ 文件:src/api/**/*.ts │ │</span></span>
|
||
<span class="line"><span>│ └──────────────────────────┬──────────────────────────────────┘ │</span></span>
|
||
<span class="line"><span>│ │ 调用 http.request() │</span></span>
|
||
<span class="line"><span>│ ▼ │</span></span>
|
||
<span class="line"><span>│ ┌─────────────────────────────────────────────────────────────┐ │</span></span>
|
||
<span class="line"><span>│ │ HTTP(请求层) │ │</span></span>
|
||
<span class="line"><span>│ │ Axios 封装:拦截器、Token 携带、错误处理 │ │</span></span>
|
||
<span class="line"><span>│ │ 文件:src/utils/http/axios/ │ │</span></span>
|
||
<span class="line"><span>│ └──────────────────────────┬──────────────────────────────────┘ │</span></span>
|
||
<span class="line"><span>│ │ │</span></span>
|
||
<span class="line"><span>│ ▼ │</span></span>
|
||
<span class="line"><span>│ ┌─────────────────────────────────────────────────────────────┐ │</span></span>
|
||
<span class="line"><span>│ │ 后端 API(RESTful JSON) │ │</span></span>
|
||
<span class="line"><span>│ └─────────────────────────────────────────────────────────────┘ │</span></span>
|
||
<span class="line"><span>│ │</span></span>
|
||
<span class="line"><span>│ ┌─────────────────────────────────────────────────────────────┐ │</span></span>
|
||
<span class="line"><span>│ │ Store(状态层) │ │</span></span>
|
||
<span class="line"><span>│ │ 全局状态管理:Token、用户信息、权限列表、动态路由 │ │</span></span>
|
||
<span class="line"><span>│ │ 文件:src/store/modules/*.ts │ │</span></span>
|
||
<span class="line"><span>│ └─────────────────────────────────────────────────────────────┘ │</span></span>
|
||
<span class="line"><span>└─────────────────────────────────────────────────────────────────────┘</span></span></code></pre></div><h2 id="各层职责详解" tabindex="-1">各层职责详解 <a class="header-anchor" href="#各层职责详解" aria-label="Permalink to "各层职责详解""></a></h2><h3 id="View-层-视图-" tabindex="-1">View 层(视图) <a class="header-anchor" href="#View-层-视图-" aria-label="Permalink to "View 层(视图)""></a></h3><p><strong>文件</strong>:<code>src/views/**/*.vue</code><strong>职责</strong>:页面渲染、用户交互、调用 API 获取数据</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 dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span>src/views/</span></span>
|
||
<span class="line"><span>├── system/ 系统管理</span></span>
|
||
<span class="line"><span>│ ├── user/ 用户管理</span></span>
|
||
<span class="line"><span>│ │ ├── index.vue 列表页</span></span>
|
||
<span class="line"><span>│ │ └── edit.vue 编辑弹窗</span></span>
|
||
<span class="line"><span>│ ├── role/ 角色管理</span></span>
|
||
<span class="line"><span>│ └── menu/ 菜单管理</span></span>
|
||
<span class="line"><span>├── content/ 内容管理</span></span>
|
||
<span class="line"><span>│ ├── article/ 文章管理</span></span>
|
||
<span class="line"><span>│ └── category/ 分类管理</span></span>
|
||
<span class="line"><span>├── login.vue 登录页</span></span>
|
||
<span class="line"><span>├── dashboard/ 仪表盘</span></span>
|
||
<span class="line"><span>└── ...</span></span></code></pre></div><p><strong>典型页面结构:</strong></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 dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"><</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">template</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">></span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> <!-- 搜索区 --></span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> <</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">el-form</span><span style="--shiki-dark:#62E884;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;"> :model</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">searchForm</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#62E884;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;"> inline</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">></span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> <</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">el-form-item</span><span style="--shiki-dark:#62E884;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;"> label</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">名称</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">></span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> <</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">el-input</span><span style="--shiki-dark:#62E884;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;"> v-model</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">searchForm.name</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> /></span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> </</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">el-form-item</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">></span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> <</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">el-form-item</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">></span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> <</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">el-button</span><span style="--shiki-dark:#62E884;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;"> type</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">primary</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#62E884;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;"> @click</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">fetchData</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">></span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">搜索</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"></</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">el-button</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">></span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> </</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">el-form-item</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">></span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> </</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">el-form</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">></span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> <!-- 操作栏 --></span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> <</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">el-button</span><span style="--shiki-dark:#62E884;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;"> v-perm</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">'sys:example:add'</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#62E884;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;"> type</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">primary</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#62E884;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;"> @click</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">handleAdd</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">></span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">新增</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"></</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">el-button</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">></span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> <!-- 数据表格 --></span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> <</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">el-table</span><span style="--shiki-dark:#62E884;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;"> :data</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">tableData</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">></span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> <</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">el-table-column</span><span style="--shiki-dark:#62E884;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;"> prop</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">id</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#62E884;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;"> label</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">ID</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> /></span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> <</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">el-table-column</span><span style="--shiki-dark:#62E884;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;"> prop</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">name</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#62E884;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;"> label</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">名称</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> /></span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> <</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">el-table-column</span><span style="--shiki-dark:#62E884;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;"> prop</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">statusText</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#62E884;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;"> label</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">状态</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> /></span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> <</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">el-table-column</span><span style="--shiki-dark:#62E884;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;"> label</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">操作</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">></span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> <</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">template</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> #</span><span style="--shiki-dark:#62E884;--shiki-dark-font-style:italic;--shiki-light:#59873A;--shiki-light-font-style:inherit;">default</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#DEE492;--shiki-light:#999999;">"</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">{ </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">row</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> }</span><span style="--shiki-dark:#DEE492;--shiki-light:#999999;">"</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">></span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> <</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">el-button</span><span style="--shiki-dark:#62E884;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;"> v-perm</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">'sys:example:update'</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#62E884;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;"> @click</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">handleEdit(row)</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">></span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">编辑</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"></</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">el-button</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">></span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> <</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">el-button</span><span style="--shiki-dark:#62E884;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;"> v-perm</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">'sys:example:delete'</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#62E884;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;"> type</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">danger</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#62E884;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;"> @click</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">handleDelete(row.id)</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">></span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">删除</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"></</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">el-button</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">></span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> </</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">template</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">></span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> </</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">el-table-column</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">></span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> </</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">el-table</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">></span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> <!-- 分页 --></span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> <</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">el-pagination</span><span style="--shiki-dark:#62E884;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;"> v-model:current-page</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">pageNo</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#62E884;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;"> v-model:page-size</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">pageSize</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span></span>
|
||
<span class="line"><span style="--shiki-dark:#62E884;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;"> :total</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">total</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#62E884;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;"> @change</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">fetchData</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> /></span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"></</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">template</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">></span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"><</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">script</span><span style="--shiki-dark:#62E884;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;"> setup</span><span style="--shiki-dark:#62E884;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;"> lang</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">ts</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">></span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">import</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;"> getExamplePage</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;"> exampleDelete</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> }</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> from</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">@/api/tool/example</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">const</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;"> tableData</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> ref</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">([]);</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">const</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;"> pageNo</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> ref</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;">1</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">const</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;"> pageSize</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> ref</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;">20</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">const</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;"> total</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> ref</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;">0</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">const</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> fetchData</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> async</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> ()</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =></span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> const</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;"> res</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> await</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> getExamplePage</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">({ </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#998418;">pageNo</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;"> pageNo</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">.</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">value</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">, </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#998418;">pageSize</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;"> pageSize</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">.</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">value</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> });</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;"> tableData</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">.</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">value</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;"> res</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">.</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">records</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;"> total</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">.</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">value</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;"> res</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">.</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">total</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">};</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">onMounted</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(()</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =></span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> fetchData</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">());</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"></</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">script</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">></span></span></code></pre></div><h3 id="API-层-接口-" tabindex="-1">API 层(接口) <a class="header-anchor" href="#API-层-接口-" aria-label="Permalink to "API 层(接口)""></a></h3><p><strong>文件</strong>:<code>src/api/**/*.ts</code><strong>职责</strong>:封装后端 API 调用,一个后端模块对应一个 API 文件</p><p><strong>命名规范:</strong></p><table tabindex="0"><thead><tr><th>操作</th><th>函数名</th><th>HTTP 方法</th><th>参数传递</th></tr></thead><tbody><tr><td>分页查询</td><td><code>get{Module}Page</code></td><td>GET</td><td><code>params</code></td></tr><tr><td>全量列表</td><td><code>get{Module}List</code></td><td>GET</td><td><code>params</code></td></tr><tr><td>详情</td><td><code>get{Module}Detail</code></td><td>GET</td><td>URL 参数</td></tr><tr><td>新增</td><td><code>{module}Add</code></td><td>POST</td><td><code>data</code></td></tr><tr><td>修改</td><td><code>{module}Update</code></td><td>PUT</td><td><code>data</code></td></tr><tr><td>删除</td><td><code>{module}Delete</code></td><td>DELETE</td><td>URL 参数</td></tr><tr><td>批量删除</td><td><code>{module}BatchDelete</code></td><td>DELETE</td><td><code>data</code></td></tr><tr><td>导入</td><td><code>{module}Import</code></td><td>POST</td><td>FormData</td></tr><tr><td>导出</td><td><code>{module}Export</code></td><td>GET</td><td><code>params</code></td></tr></tbody></table><p><strong>完整示例:</strong></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 dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">// src/api/system/user.ts</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">import</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;"> http</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> }</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> from</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">@/utils/http/axios</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">// 分页查询</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">export</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> function</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> getUserPage</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#FFB86C;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;">params</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">?</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;"> http</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">.</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">request</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">({ </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#998418;">url</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">/user/page</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">, </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#998418;">method</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">GET</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">, </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">params</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> });</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">}</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">// 详情</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">export</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> function</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> getUserDetail</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#FFB86C;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;">id</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;"> http</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">.</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">request</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">({ </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#998418;">url</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">/user/detail/</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> +</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;"> id</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">, </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#998418;">method</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">GET</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> });</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">}</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">// 新增</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">export</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> function</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> userAdd</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#FFB86C;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;">data</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#2E8F82;--shiki-light-font-style:inherit;"> any</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;"> http</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">.</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">request</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">({ </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#998418;">url</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">/user/add</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">, </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#998418;">method</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">POST</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">, </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">data</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> });</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">}</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">// 修改</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">export</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> function</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> userUpdate</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#FFB86C;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;">data</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#2E8F82;--shiki-light-font-style:inherit;"> any</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;"> http</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">.</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">request</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">({ </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#998418;">url</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">/user/update</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">, </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#998418;">method</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">PUT</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">, </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">data</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> });</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">}</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">// 删除</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">export</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> function</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> userDelete</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#FFB86C;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;">id</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;"> http</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">.</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">request</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">({ </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#998418;">url</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">/user/delete/</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> +</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;"> id</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">, </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#998418;">method</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">DELETE</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> });</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">}</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">// 批量删除</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">export</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> function</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> userBatchDelete</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#FFB86C;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;">data</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#2E8F82;--shiki-light-font-style:inherit;"> any</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;"> http</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">.</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">request</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">({ </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#998418;">url</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">/user/batchDelete</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">, </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#998418;">method</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">DELETE</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">, </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">data</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> });</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">}</span></span></code></pre></div><h3 id="HTTP-层-请求-" tabindex="-1">HTTP 层(请求) <a class="header-anchor" href="#HTTP-层-请求-" aria-label="Permalink to "HTTP 层(请求)""></a></h3><p><strong>文件</strong>:<code>src/utils/http/axios/</code><strong>职责</strong>:Axios 封装,自动处理 Token、响应码、错误提示</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 dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span>src/utils/http/axios/</span></span>
|
||
<span class="line"><span>├── index.ts Axios 实例配置和拦截器</span></span>
|
||
<span class="line"><span>├── Axios.ts VAxios 类封装</span></span>
|
||
<span class="line"><span>├── axiosTransform.ts 数据转换接口</span></span>
|
||
<span class="line"><span>├── checkStatus.ts HTTP 状态码处理</span></span>
|
||
<span class="line"><span>├── helper.ts 辅助函数</span></span>
|
||
<span class="line"><span>└── types.ts 类型定义</span></span></code></pre></div><p><strong>核心拦截器:</strong></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 dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span>请求拦截器:</span></span>
|
||
<span class="line"><span> ┌──────────────────────────────────────────┐</span></span>
|
||
<span class="line"><span> │ 1. 从 Store 获取 Token │</span></span>
|
||
<span class="line"><span> │ 2. 自动添加 Authorization: Bearer <token> │</span></span>
|
||
<span class="line"><span> └──────────────────────────────────────────┘</span></span>
|
||
<span class="line"><span></span></span>
|
||
<span class="line"><span>响应拦截器:</span></span>
|
||
<span class="line"><span> ┌──────────────────────────────────────────┐</span></span>
|
||
<span class="line"><span> │ code === 0 → 成功,返回 data │</span></span>
|
||
<span class="line"><span> │ code === 401 → Token 过期,跳转登录页 │</span></span>
|
||
<span class="line"><span> │ code === 403 → 权限不足,显示错误提示 │</span></span>
|
||
<span class="line"><span> │ 其它 code → 业务失败,显示 msg │</span></span>
|
||
<span class="line"><span> └──────────────────────────────────────────┘</span></span></code></pre></div><h3 id="Store-层-状态-" tabindex="-1">Store 层(状态) <a class="header-anchor" href="#Store-层-状态-" aria-label="Permalink to "Store 层(状态)""></a></h3><p><strong>文件</strong>:<code>src/store/modules/*.ts</code><strong>职责</strong>:全局状态管理(Pinia)</p><table tabindex="0"><thead><tr><th>Store</th><th>文件</th><th>管理的状态</th></tr></thead><tbody><tr><td>userStore</td><td><code>user.ts</code></td><td>Token、用户信息、权限列表、登录/登出</td></tr><tr><td>asyncRouteStore</td><td><code>asyncRoute.ts</code></td><td>动态路由、keep-alive 缓存列表</td></tr><tr><td>projectSettingStore</td><td><code>projectSetting.ts</code></td><td>项目配置(主题、布局等)</td></tr><tr><td>tabsViewStore</td><td><code>tabsView.ts</code></td><td>标签页导航状态</td></tr><tr><td>designSettingStore</td><td><code>designSetting.ts</code></td><td>主题设计配置</td></tr><tr><td>ossConfigStore</td><td><code>ossConfig.ts</code></td><td>云存储配置</td></tr><tr><td>lockscreenStore</td><td><code>lockscreen.ts</code></td><td>锁屏状态</td></tr></tbody></table><p><strong>userStore 核心流程:</strong></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 dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span>登录:</span></span>
|
||
<span class="line"><span> userStore.login(userInfo)</span></span>
|
||
<span class="line"><span> → POST /login → 获取 access_token</span></span>
|
||
<span class="line"><span> → Storage.set(ACCESS_TOKEN, token)</span></span>
|
||
<span class="line"><span> → this.setToken(token)</span></span>
|
||
<span class="line"><span></span></span>
|
||
<span class="line"><span>获取用户信息:</span></span>
|
||
<span class="line"><span> userStore.GetInfo()</span></span>
|
||
<span class="line"><span> → GET /index/getUserInfo</span></span>
|
||
<span class="line"><span> → this.setPermissions(res.permissions)</span></span>
|
||
<span class="line"><span> → this.setUserInfo(res)</span></span>
|
||
<span class="line"><span></span></span>
|
||
<span class="line"><span>登出:</span></span>
|
||
<span class="line"><span> userStore.logout()</span></span>
|
||
<span class="line"><span> → POST /logout</span></span>
|
||
<span class="line"><span> → 清除 Token、用户信息、权限列表</span></span>
|
||
<span class="line"><span> → 跳转登录页</span></span></code></pre></div><h2 id="路由与动态菜单" tabindex="-1">路由与动态菜单 <a class="header-anchor" href="#路由与动态菜单" aria-label="Permalink to "路由与动态菜单""></a></h2><h3 id="路由架构" tabindex="-1">路由架构 <a class="header-anchor" href="#路由架构" aria-label="Permalink to "路由架构""></a></h3><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span>静态路由(固定,src/router/)</span></span>
|
||
<span class="line"><span>├── /login 登录页</span></span>
|
||
<span class="line"><span>├── / 根路径,重定向到首页</span></span>
|
||
<span class="line"><span>├── /redirect/:path 重定向路由</span></span>
|
||
<span class="line"><span>└── /:path(.*)* 404 错误页</span></span>
|
||
<span class="line"><span></span></span>
|
||
<span class="line"><span>动态路由(从后端菜单生成)</span></span>
|
||
<span class="line"><span>├── /dashboard 仪表盘</span></span>
|
||
<span class="line"><span>├── /system/user 用户管理</span></span>
|
||
<span class="line"><span>├── /system/role 角色管理</span></span>
|
||
<span class="line"><span>├── /content/article 文章管理</span></span>
|
||
<span class="line"><span>└── ...</span></span></code></pre></div><h3 id="动态路由生成流程" tabindex="-1">动态路由生成流程 <a class="header-anchor" href="#动态路由生成流程" aria-label="Permalink to "动态路由生成流程""></a></h3><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span>1. 用户登录 → 获取 Token → 存入 Store</span></span>
|
||
<span class="line"><span>2. 路由守卫(router.beforeEach)检测到 Token</span></span>
|
||
<span class="line"><span>3. 调用 GET /index/getMenus 获取菜单树</span></span>
|
||
<span class="line"><span>4. generator-routers.ts 将菜单树转换为路由表</span></span>
|
||
<span class="line"><span>5. router.addRoute() 动态注入路由</span></span>
|
||
<span class="line"><span>6. 渲染侧边栏菜单</span></span></code></pre></div><h3 id="布局系统" tabindex="-1">布局系统 <a class="header-anchor" href="#布局系统" aria-label="Permalink to "布局系统""></a></h3><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span>┌─────────────────────────────────────────────────────────────┐</span></span>
|
||
<span class="line"><span>│ 顶部导航栏 │</span></span>
|
||
<span class="line"><span>│ [Logo] [面包屑] [搜索] [通知] [头像] │</span></span>
|
||
<span class="line"><span>├──────────┬──────────────────────────────────────────────────┤</span></span>
|
||
<span class="line"><span>│ │ │</span></span>
|
||
<span class="line"><span>│ 侧边栏 │ 内容区域 │</span></span>
|
||
<span class="line"><span>│ 菜单 │ │</span></span>
|
||
<span class="line"><span>│ │ ┌──────────────────────────────────────────┐ │</span></span>
|
||
<span class="line"><span>│ ──────── │ │ 标签页导航 │ │</span></span>
|
||
<span class="line"><span>│ 系统管理 │ ├──────────────────────────────────────────┤ │</span></span>
|
||
<span class="line"><span>│ ├ 用户 │ │ │ │</span></span>
|
||
<span class="line"><span>│ ├ 角色 │ │ 页面内容(keep-alive 缓存) │ │</span></span>
|
||
<span class="line"><span>│ └ 菜单 │ │ │ │</span></span>
|
||
<span class="line"><span>│ │ └──────────────────────────────────────────┘ │</span></span>
|
||
<span class="line"><span>└──────────┴──────────────────────────────────────────────────┘</span></span></code></pre></div><h2 id="权限控制" tabindex="-1">权限控制 <a class="header-anchor" href="#权限控制" aria-label="Permalink to "权限控制""></a></h2><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 dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"><!-- v-perm:单权限 --></span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"><</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">el-button</span><span style="--shiki-dark:#62E884;--shiki-dark-font-style:italic;--shiki-light:#59873A;--shiki-light-font-style:inherit;"> v-perm</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#DEE492;--shiki-light:#999999;">"</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">sys:user:add</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#DEE492;--shiki-light:#999999;">"</span><span style="--shiki-dark:#62E884;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;"> type</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">primary</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">></span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">新增</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"></</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">el-button</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">></span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"><!-- v-perms:多权限(满足任一即可) --></span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"><</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">el-button</span><span style="--shiki-dark:#62E884;--shiki-dark-font-style:italic;--shiki-light:#59873A;--shiki-light-font-style:inherit;"> v-perms</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#DEE492;--shiki-light:#999999;">"</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">[</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">sys:user:add</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">sys:user:update</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">]</span><span style="--shiki-dark:#DEE492;--shiki-light:#999999;">"</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">></span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">操作</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"></</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">el-button</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">></span></span></code></pre></div><p>无权限时元素直接从 DOM 移除,而非仅隐藏。</p><div class="tip custom-block"><p class="custom-block-title">超级管理员</p><p>用户权限列表包含 <code>*:*:*</code> 时,表示超级管理员,拥有所有权限,<code>v-perm</code>/<code>v-perms</code> 指令始终放行。</p></div><h2 id="支撑模块" tabindex="-1">支撑模块 <a class="header-anchor" href="#支撑模块" aria-label="Permalink to "支撑模块""></a></h2><h3 id="Hooks-组合式函数-" tabindex="-1">Hooks(组合式函数) <a class="header-anchor" href="#Hooks-组合式函数-" aria-label="Permalink to "Hooks(组合式函数)""></a></h3><table tabindex="0"><thead><tr><th>Hook</th><th>文件</th><th>说明</th></tr></thead><tbody><tr><td><code>usePermission</code></td><td><code>hooks/web/usePermission.ts</code></td><td>权限判断(hasPermission、hasSomePermission)</td></tr><tr><td><code>useTable</code></td><td><code>hooks/web/useTable.ts</code></td><td>表格通用逻辑(分页、搜索、刷新)</td></tr><tr><td><code>useForm</code></td><td><code>hooks/web/useForm.ts</code></td><td>表单通用逻辑(提交、重置、校验)</td></tr></tbody></table><h3 id="Directives-自定义指令-" tabindex="-1">Directives(自定义指令) <a class="header-anchor" href="#Directives-自定义指令-" aria-label="Permalink to "Directives(自定义指令)""></a></h3><table tabindex="0"><thead><tr><th>指令</th><th>说明</th></tr></thead><tbody><tr><td><code>v-perm</code></td><td>单权限控制</td></tr><tr><td><code>v-perms</code></td><td>多权限控制(满足任一)</td></tr></tbody></table><h3 id="Utils-工具函数-" tabindex="-1">Utils(工具函数) <a class="header-anchor" href="#Utils-工具函数-" aria-label="Permalink to "Utils(工具函数)""></a></h3><table tabindex="0"><thead><tr><th>工具</th><th>文件</th><th>说明</th></tr></thead><tbody><tr><td>HTTP</td><td><code>utils/http/axios/</code></td><td>Axios 封装</td></tr><tr><td>Storage</td><td><code>utils/Storage.ts</code></td><td>localStorage 封装</td></tr><tr><td>Dict</td><td><code>utils/dict.ts</code></td><td>字典工具(从 Store 获取字典值)</td></tr></tbody></table><h2 id="数据流向" tabindex="-1">数据流向 <a class="header-anchor" href="#数据流向" aria-label="Permalink to "数据流向""></a></h2><h3 id="完整请求链路" tabindex="-1">完整请求链路 <a class="header-anchor" href="#完整请求链路" aria-label="Permalink to "完整请求链路""></a></h3><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span>用户操作(点击搜索按钮)</span></span>
|
||
<span class="line"><span> │</span></span>
|
||
<span class="line"><span> ▼</span></span>
|
||
<span class="line"><span>View: fetchData()</span></span>
|
||
<span class="line"><span> │ 调用 API 函数</span></span>
|
||
<span class="line"><span> ▼</span></span>
|
||
<span class="line"><span>API: getExamplePage(params)</span></span>
|
||
<span class="line"><span> │ 调用 http.request()</span></span>
|
||
<span class="line"><span> ▼</span></span>
|
||
<span class="line"><span>HTTP: 请求拦截器添加 Token</span></span>
|
||
<span class="line"><span> │ 发送 GET /example/page?pageNo=1&pageSize=20</span></span>
|
||
<span class="line"><span> ▼</span></span>
|
||
<span class="line"><span>后端: Controller → Logic → Model → Database</span></span>
|
||
<span class="line"><span> │</span></span>
|
||
<span class="line"><span> ▼</span></span>
|
||
<span class="line"><span>HTTP: 响应拦截器判断 code</span></span>
|
||
<span class="line"><span> │ code === 0 → 返回 data</span></span>
|
||
<span class="line"><span> ▼</span></span>
|
||
<span class="line"><span>API: 返回 data</span></span>
|
||
<span class="line"><span> │</span></span>
|
||
<span class="line"><span> ▼</span></span>
|
||
<span class="line"><span>View: tableData.value = res.records; total.value = res.total</span></span>
|
||
<span class="line"><span> │</span></span>
|
||
<span class="line"><span> ▼</span></span>
|
||
<span class="line"><span>Vue 响应式 → 表格自动刷新</span></span></code></pre></div><h3 id="Store-数据流" tabindex="-1">Store 数据流 <a class="header-anchor" href="#Store-数据流" aria-label="Permalink to "Store 数据流""></a></h3><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span>登录成功</span></span>
|
||
<span class="line"><span> │</span></span>
|
||
<span class="line"><span> ▼</span></span>
|
||
<span class="line"><span>userStore.setToken(token) → 响应式更新</span></span>
|
||
<span class="line"><span>userStore.setUserInfo(info) → 响应式更新</span></span>
|
||
<span class="line"><span>userStore.setPermissions(perm) → 响应式更新</span></span>
|
||
<span class="line"><span> │</span></span>
|
||
<span class="line"><span> ▼</span></span>
|
||
<span class="line"><span>其他组件通过 userStore.username / userStore.permissions 读取</span></span>
|
||
<span class="line"><span> │</span></span>
|
||
<span class="line"><span> ▼</span></span>
|
||
<span class="line"><span>v-perm 指令读取 permissions 列表 → 控制元素显隐</span></span></code></pre></div><h2 id="前后端对应关系" tabindex="-1">前后端对应关系 <a class="header-anchor" href="#前后端对应关系" aria-label="Permalink to "前后端对应关系""></a></h2><table tabindex="0"><thead><tr><th>后端</th><th>前端</th><th>说明</th></tr></thead><tbody><tr><td><code>app/controller/UserController.php</code></td><td><code>src/api/system/user.ts</code></td><td>API 函数映射</td></tr><tr><td><code>app/logic/UserLogic.php</code></td><td><code>src/views/system/user/</code></td><td>业务页面</td></tr><tr><td><code>app/model/User.php</code></td><td>—</td><td>前端不直接操作模型</td></tr><tr><td><code>app/validate/UserValidate.php</code></td><td>—</td><td>前端校验由表单组件处理</td></tr><tr><td><code>app/validate/*Validate.php</code> 的场景</td><td>表单 <code>rules</code></td><td>前端表单校验规则</td></tr><tr><td><code>route/app.php</code></td><td><code>src/api/**/*.ts</code></td><td>路由 ↔ API 函数</td></tr><tr><td>后端字典 <code>DictService</code></td><td><code>src/enums/</code> + 字典 Store</td><td>枚举常量</td></tr><tr><td>后端 <code>#[Permission]</code> 注解</td><td><code>v-perm</code> 指令</td><td>权限码对应</td></tr></tbody></table><h2 id="层间通信规范" tabindex="-1">层间通信规范 <a class="header-anchor" href="#层间通信规范" aria-label="Permalink to "层间通信规范""></a></h2><table tabindex="0"><thead><tr><th>调用方向</th><th>是否允许</th><th>说明</th></tr></thead><tbody><tr><td>View → API</td><td>✅</td><td>标准调用</td></tr><tr><td>View → Store</td><td>✅</td><td>读取/修改全局状态</td></tr><tr><td>View → Hooks</td><td>✅</td><td>复用逻辑</td></tr><tr><td>API → HTTP</td><td>✅</td><td>调用 http.request()</td></tr><tr><td>API → Store</td><td>❌</td><td>API 层不应操作状态</td></tr><tr><td>Store → API</td><td>✅</td><td>Store actions 中调用 API</td></tr><tr><td>HTTP → Store</td><td>⚠️</td><td>仅在拦截器中读取 Token</td></tr><tr><td>Hooks → API</td><td>✅</td><td>Hooks 中可调用 API</td></tr></tbody></table>`,54)])])}const g=i(p,[["render",l]]);export{o as __pageData,g as default};
|