5 lines
13 KiB
JavaScript
5 lines
13 KiB
JavaScript
import{_ as a,o as i,c as s,a2 as l}from"./chunks/framework.B-QBKwc1.js";const k=JSON.parse('{"title":"常见问题与排错","description":"本页汇总模块开发实战中的常见问题与排错方法,按前后端分类覆盖 401/403、路由注册、参数校验等高频问题,开发受阻时按症状索引即可定位。","frontmatter":{},"headers":[],"relativePath":"zh/guide/faq.md","filePath":"zh/guide/faq.md"}'),t={name:"zh/guide/faq.md"};function o(d,e,h,r,c,n){return i(),s("div",null,[...e[0]||(e[0]=[l(`<h1 id="_3-11-常见问题与排错" tabindex="-1">3.11 常见问题与排错 <a class="header-anchor" href="#_3-11-常见问题与排错" aria-label="Permalink to "3.11 常见问题与排错""></a></h1><div class="tip custom-block"><p class="custom-block-title">概述</p><p>本页汇总模块开发实战中的常见问题与排错方法,按前后端分类覆盖 401/403、路由注册、参数校验等高频问题,开发受阻时按症状索引即可定位。</p></div><h2 id="后端问题" tabindex="-1">后端问题 <a class="header-anchor" href="#后端问题" aria-label="Permalink to "后端问题""></a></h2><h3 id="Q-新增接口返回-401" tabindex="-1">Q: 新增接口返回 401 <a class="header-anchor" href="#Q-新增接口返回-401" aria-label="Permalink to "Q: 新增接口返回 401""></a></h3><p>A: 检查以下几点:</p><ol><li>请求头是否携带 <code>Authorization: Bearer <token></code></li><li>Token 是否过期(access_token 默认 2 小时,可调 <code>/api/refresh</code> 续签)</li><li>路由是否在 <code>routes/api.php</code> 的认证中间件组内(组外为公开接口)</li></ol><h3 id="Q-新增接口返回-403" tabindex="-1">Q: 新增接口返回 403 <a class="header-anchor" href="#Q-新增接口返回-403" aria-label="Permalink to "Q: 新增接口返回 403""></a></h3><p>A: 权限不足,检查:</p><ol><li>是否在 Controller 方法上添加了 <code>#[Permission]</code> 注解</li><li>权限码是否在菜单管理中配置(<code>permission</code> 字段与注解完全一致)</li><li>用户角色是否包含该权限节点(角色管理 → 勾选菜单/按钮)</li></ol><h3 id="Q-报-Table-xxx-example-doesn-t-exist" tabindex="-1">Q: 报 <code>Table 'xxx.example' doesn't exist</code> <a class="header-anchor" href="#Q-报-Table-xxx-example-doesn-t-exist" aria-label="Permalink to "Q: 报 \`Table 'xxx.example' doesn't exist\`""></a></h3><p>A: <code>DB_PREFIX</code> 未配置。建表 SQL 使用 <code>laravel_</code> 前缀,<code>.env</code> 中必须保留 <code>DB_PREFIX=laravel_</code>,改后执行 <code>php artisan config:clear</code>。</p><h3 id="Q-枚举显示名-statusText-为空" tabindex="-1">Q: 枚举显示名(statusText)为空 <a class="header-anchor" href="#Q-枚举显示名-statusText-为空" aria-label="Permalink to "Q: 枚举显示名(statusText)为空""></a></h3><p>A: 检查:</p><ol><li>字典表中是否存在对应的字典编码(如 <code>example_status</code>)</li><li>字典项的 value 是否与数据中的值匹配</li><li>Service 中 <code>serializeMaps</code> 配置是否正确</li><li>字典缓存是否为旧数据:<code>php artisan dict:clear-cache</code></li></ol><div class="language-php vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">php</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;">// ExampleService 中的配置</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">protected</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> array</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">serializeMaps</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:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">status</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =></span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">example_status</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></code></pre></div><h3 id="Q-唯一性校验不生效-误报重复" tabindex="-1">Q: 唯一性校验不生效 / 误报重复 <a class="header-anchor" href="#Q-唯一性校验不生效-误报重复" aria-label="Permalink to "Q: 唯一性校验不生效 / 误报重复""></a></h3><p>A: 检查:</p><ol><li>Service 是否 <code>use HasUniqueCheck</code>(未启用时 <code>uniqueFields</code> 不生效)</li><li><code>uniqueFields</code> 字段名是否与入参键名一致(snake_case)</li><li>修改时是否正确排除自身(<code>checkUnique($data, $excludeId)</code> 由基类传入 id)</li><li>软删除的旧记录仍占唯一规则——这正是不用数据库唯一索引的原因,如需彻底放开需先清理历史数据</li></ol><h3 id="Q-排序不生效" tabindex="-1">Q: 排序不生效 <a class="header-anchor" href="#Q-排序不生效" aria-label="Permalink to "Q: 排序不生效""></a></h3><p>A: 检查 Service 中 <code>pageOrderBy</code> 配置:</p><div class="language-php vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">php</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">protected</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> array</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">pageOrderBy</span><span style="--shiki-dark:#F286C4;--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;">field</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =></span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">sort</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;">type</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =></span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">asc</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">];</span></span></code></pre></div><p>前端可通过 <code>orderField</code> / <code>orderType</code> 参数覆盖默认排序,但字段必须命中 <code>pageOrderBy</code> 默认字段与 <code>orderFieldAllow</code> 的<strong>并集</strong>(白名单防注入),否则被忽略。</p><h3 id="Q-新增-修改时报-参数验证失败-data-里没有字段明细" tabindex="-1">Q: 新增/修改时报"参数验证失败",data 里没有字段明细 <a class="header-anchor" href="#Q-新增-修改时报-参数验证失败-data-里没有字段明细" aria-label="Permalink to "Q: 新增/修改时报"参数验证失败",data 里没有字段明细""></a></h3><p>A: 两种校验路径的响应结构不同:</p><ul><li>FormRequest 注入失败:<code>data</code> 为 <code>{字段: [错误数组]}</code>(code=1)</li><li>Service 业务异常:<code>data</code> 为 null(code=1,看 msg)</li></ul><p>确认控制器方法是否类型注入了 FormRequest,以及是否误把格式规则写进了 Service。</p><h3 id="Q-审计字段-create-user-为空" tabindex="-1">Q: 审计字段(create_user)为空 <a class="header-anchor" href="#Q-审计字段-create-user-为空" aria-label="Permalink to "Q: 审计字段(create_user)为空""></a></h3><p>A: <code>create_user</code> 取自当前登录用户(<code>Auth::username()</code>),需经 <code>auth.jwt</code> 中间件(登录态)调用;命令行/队列等无登录态场景需手动赋值。</p><h2 id="前端问题" tabindex="-1">前端问题 <a class="header-anchor" href="#前端问题" aria-label="Permalink to "前端问题""></a></h2><h3 id="Q-菜单不显示" tabindex="-1">Q: 菜单不显示 <a class="header-anchor" href="#Q-菜单不显示" aria-label="Permalink to "Q: 菜单不显示""></a></h3><p>A: 检查:</p><ol><li>后端菜单管理中是否添加了对应菜单</li><li>菜单的组件路径是否正确(如 <code>tool/example/index</code>)</li><li>前端 <code>views</code> 目录下是否有对应的 <code>.vue</code> 文件</li><li>用户角色是否包含该菜单权限</li></ol><h3 id="Q-API-请求-404" tabindex="-1">Q: API 请求 404 <a class="header-anchor" href="#Q-API-请求-404" aria-label="Permalink to "Q: API 请求 404""></a></h3><p>A: 检查:</p><ol><li><code>routes/api.php</code> 中是否注册了对应路由</li><li>路由路径是否与前端 API 模块中的 <code>url</code> 一致</li><li>HTTP 方法是否正确(GET/POST/PUT/DELETE)</li><li>批量删除是 <strong>DELETE</strong> <code>batchDelete</code>(请求体 <code>ids</code> 数组——方法为 DELETE 但仍携带 body)</li></ol><h3 id="Q-表格数据不显示" tabindex="-1">Q: 表格数据不显示 <a class="header-anchor" href="#Q-表格数据不显示" aria-label="Permalink to "Q: 表格数据不显示""></a></h3><p>A: 检查:</p><ol><li>API 返回的数据结构是否正确(<code>data</code> 应包含 <code>records</code> 和 <code>total</code>)</li><li>前端是否正确绑定了 <code>tableData</code>(<code>res.records</code>)</li><li>浏览器控制台是否有报错</li></ol><h3 id="Q-导入失败" tabindex="-1">Q: 导入失败 <a class="header-anchor" href="#Q-导入失败" aria-label="Permalink to "Q: 导入失败""></a></h3><p>A: 检查:</p><ol><li>文件格式是否为 <code>.xls</code> 或 <code>.xlsx</code>(基类 <code>_import</code> 校验扩展名 + MIME + 10MB 上限)</li><li>表头是否与 <code>headerMap</code> 中定义的中文名一致</li><li>枚举字段的值是否在字典中存在(文本值需能反查到字典)</li></ol><h3 id="Q-接口返回的键名大小写与预期不符" tabindex="-1">Q: 接口返回的键名大小写与预期不符 <a class="header-anchor" href="#Q-接口返回的键名大小写与预期不符" aria-label="Permalink to "Q: 接口返回的键名大小写与预期不符""></a></h3><p>A: 项目开启了驼峰/下划线自动转换(<code>API_CAMEL_SNAKE_CONVERT=true</code>):</p><ul><li>响应:<code>create_time</code> → <code>createTime</code>(数据库字段 → 前端字段)</li><li>请求:前端传 camelCase,Service 写入入口(doAdd/doUpdate)统一转为 snake_case</li></ul><p>如需原样返回,使用 <code>Result::success($data, $msg, true)</code>(<code>$raw=true</code>)。</p><h2 id="生成器问题" tabindex="-1">生成器问题 <a class="header-anchor" href="#生成器问题" aria-label="Permalink to "生成器问题""></a></h2><h3 id="Q-用生成器生成的模块菜单没有出现" tabindex="-1">Q: 用生成器生成的模块菜单没有出现 <a class="header-anchor" href="#Q-用生成器生成的模块菜单没有出现" aria-label="Permalink to "Q: 用生成器生成的模块菜单没有出现""></a></h3><p>A: 检查生成配置中的父菜单 ID(<code>.env</code> 中 <code>GENERATOR_PARENT_MENU_ID</code>)是否存在,以及当前角色是否被分配了新菜单;生成后重新登录或刷新获取最新菜单。</p><h3 id="Q-生成的路由-404" tabindex="-1">Q: 生成的路由 404 <a class="header-anchor" href="#Q-生成的路由-404" aria-label="Permalink to "Q: 生成的路由 404""></a></h3><p>A: 确认生成时是否勾选路由注册;手动检查 <code>routes/api.php</code> 中是否已有对应路由(重复注册会报错),改完执行 <code>php artisan route:list</code> 核对。</p>`,50)])])}const u=a(t,[["render",o]]);export{k as __pageData,u as default};
|