-
Notifications
You must be signed in to change notification settings - Fork 23
feat(demo): enhance demo preview component with loading state and error handling #32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
❌ Deploy Preview for super-cobbler-53ff65 failed. Why did it fail? →
|
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Walkthrough重构并美化了 VitePress 的两个组件( Changes
Sequence Diagram(s)sequenceDiagram
participant U as 用户
participant DP as DemoPreview 组件
participant DOM as Transition/DOM
participant CB as 剪贴板
U->>DP: 点击“查看代码/收起”
alt 打开代码面板
DP->>DP: isLoading = true
DP->>DOM: nextTick 触发 enter 动画 (onCodeEnter)
DOM-->>DP: 动画完成
DP->>DP: isOpen = true, isLoading = false
else 关闭代码面板
DP->>DOM: 触发 leave 动画 (onCodeLeave)
DOM-->>DP: 动画完成
DP->>DP: isOpen = false
end
U->>DP: 点击“复制代码”
DP->>CB: navigator.clipboard.writeText(...)
CB-->>DP: 返回成功或失败
Estimated code review effort🎯 4 (Complex) | ⏱️ ~55 minutes Possibly related PRs
Poem
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (9)
.vitepress/components/code-group.vue (1)
34-53: currentTab 初始值写死为 index.vue,易与传入 files 不匹配当传入的
files不包含index.vue时,el-tabs的受控值将与任一 pane 的name不一致,可能导致初始选中状态异常。建议默认选择files[0],并在files/tabs变化时同步修正。可采用如下方式(在脚本中,展示用法,不要求本段内改动):
// 建议:避免解构 props 导致非响应(详见下条建议),以 props 访问 const props = withDefaults(defineProps<{ files?: string[] }>(), { files: [] }) const slots = useSlots() const tabs = computed(() => props.files.map(file => ({ component: slots[file], label: file })) ) const currentTab = ref<string>('') watch( () => tabs.value.map(t => t.label).join('|'), () => { const names = tabs.value.map(t => t.label) if (!names.includes(currentTab.value)) { currentTab.value = names[0] ?? '' } }, { immediate: true } ).vitepress/components/demo-preview.vue (5)
14-14: 直接解构 props 会丢失响应性,建议改用 withDefaults/props 访问
const { files, title, description } = defineProps<Props>()会使files/title/description脱离响应系统,父组件后续更新将无法触发本组件的computed重新计算。建议:const props = withDefaults(defineProps<Props>(), { files: '' }) const codeFiles = computed(() => { try { return JSON.parse(decodeURIComponent(props.files ?? '')) } catch { return [] } })
95-107: 避免传递无效的 Button type 值Element Plus 的
type通常为'primary' | 'success' | 'warning' | 'danger' | 'info' | 'text',传'default'可能触发运行时告警。建议不用时传undefined或直接移除该 prop。- :type="isOpen ? 'primary' : 'default'" + :type="isOpen ? 'primary' : undefined"或改为用
plain配合样式控制未展开态:<el-button :type="isOpen ? 'primary' : undefined" :plain="!isOpen" ... />
2-5: 为“复制代码”按钮补充图标导入当前模板中复制按钮未渲染任何图标,建议引入
DocumentCopy图标以提升可识别度:-import { View, Hide } from '@element-plus/icons-vue' +import { View, Hide, DocumentCopy } from '@element-plus/icons-vue'
110-117: 复制按钮缺少图标与无障碍文本
- 建议渲染一个复制图标;
- 同时为按钮补充
aria-label/title以便无障碍与可发现性。- <el-button + <el-button class="demo-action-btn demo-copy-btn" size="small" text + aria-label="复制代码" + title="复制代码" @click="copyCode" > - <el-icon></el-icon> + <el-icon><DocumentCopy /></el-icon> </el-button>
27-39: 加载态与 nextTick 使用建议
await nextTick()在当前实现中无后续 DOM 操作依赖,可省略以减少一次微任务调度。若保留,请在其后实际读取布局或触发测量(例如用于动画计算),否则不会带来实际收益。.vitepress/config.mts (3)
69-73: visualizer 在 CI/生产构建时不应自动打开
open: true会尝试在构建完成后打开浏览器,CI/无头环境下可能报错或卡顿。建议按环境开关:- visualizer({ - filename: 'stats.html', - open: true - }) + visualizer({ + filename: 'stats.html', + open: process.env.CI ? false : true + })
109-117: CDN CSS 版本与本地依赖需一致,并建议增加 SRI 与预连接
- 请核对本仓库实际安装的 element-plus 版本是否为
2.10.6,避免“组件版本 ≠ 样式版本”的错配导致 UI 异常。- 建议为外链 CSS 增加
integrity与crossorigin,并添加preconnect以优化首屏加载。如需,我可以帮你产出一个脚本在仓库中查找
package.json的 element-plus 版本并对比head中的版本。
75-90: cssCodeSplit: false 可修复样式丢失,但会增加单文件体积这是一种务实解,利于稳定性但会牺牲一定的缓存与懒加载收益。后续可评估是否通过定位丢失来源(例如动态导入、按需样式)来回退到拆分模式。
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (4)
.vitepress/dist/.gitignoreis excluded by!**/dist/**.vitepress/dist/static/images/create_app.pngis excluded by!**/dist/**,!**/*.png.vitepress/dist/static/images/gitee.svgis excluded by!**/dist/**,!**/*.svg.vitepress/dist/static/logo.svgis excluded by!**/dist/**,!**/*.svg
📒 Files selected for processing (4)
.vitepress/components/code-group.vue(1 hunks).vitepress/components/demo-preview.vue(2 hunks).vitepress/config.mts(2 hunks).vitepress/theme/index.ts(0 hunks)
💤 Files with no reviewable changes (1)
- .vitepress/theme/index.ts
🔇 Additional comments (1)
.vitepress/components/code-group.vue (1)
55-258: 大量 :deep 定制依赖 Element Plus DOM 结构,需确认版本一致性并评估维护成本
- 强依赖
.el-tabs*的 DOM 结构与类名,若 Element Plus 升级(或 CDN 与依赖版本不一致),样式可能失效或出现细微错位。- 建议确认 CDN 引入的 Element Plus 版本与项目依赖的运行时版本严格一致,避免“样式来自 CDN、组件来自本地包”的版本错配。
- 可考虑为外链 CSS 增加 SRI 与
crossorigin以提升供应链安全。需要我帮你生成一个脚本在仓库中比对本地依赖的 element-plus 版本并与
head中的 CDN 版本进行核对吗?
| <div class="code-content-wrapper"> | ||
| <component :is="tab.component" class="code-content" /> | ||
| </div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
动态渲染插槽可能不稳定:slot 函数并非组件,建议用 render 包装后再挂载
slots[file] 返回的是插槽函数而非组件定义,直接作为 <component :is="..."> 的值在某些场景下会出现渲染异常或丢失 class 的问题。建议用一个带 render 的对象包装,且将样式类应用在稳定的包裹元素上。
可在本段内做最小改动如下:
- <div class="code-content-wrapper">
- <component :is="tab.component" class="code-content" />
- </div>
+ <div class="code-content-wrapper">
+ <div class="code-content">
+ <component :is="tab.component ? { render: () => tab.component?.() } : 'div'" />
+ </div>
+ </div>抱歉,我注意到未生成任何验证脚本。为了确认 tab.component 的类型及其在模板中的使用,建议先查看 .vitepress/components/code-group.vue 中相关代码。请允许我运行以下脚本来获取上下文:
#!/bin/bash
# 输出 code-group.vue 前 100 行以查看 template 部分
sed -n '1,100p' .vitepress/components/code-group.vue为确认 tab.component 的真实类型及用法,先查看 .vitepress/components/code-group.vue 的 template 和 script 部分:
🏁 Script executed:
#!/bin/bash
# 输出前 200 行以查看 template 和 script 上下文
sed -n '1,200p' .vitepress/components/code-group.vue
# 查找所有 tab.component 的引用位置
grep -n "tab.component" .vitepress/components/code-group.vue || trueLength of output: 4327
封装动态插槽渲染以避免渲染异常和样式丢失
直接把 slots[file](插槽渲染函数)作为 <component :is="…"> 会在部分场景下丢失 class 或渲染异常。建议将它包装成带 render 方法的组件定义,并把样式类放到稳定的外层容器上:
• 文件:.vitepress/components/code-group.vue
• 位置:约第 47–49 行
<div class="code-content-wrapper">
- <component :is="tab.component" class="code-content" />
+ <div class="code-content">
+ <component
+ :is="
+ tab.component
+ ? { render: () => tab.component?.() }
+ : 'div'
+ "
+ />
+ </div>
</div>请在合并前采纳此改动,确保插槽渲染稳定且样式正确生效。
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <div class="code-content-wrapper"> | |
| <component :is="tab.component" class="code-content" /> | |
| </div> | |
| <div class="code-content-wrapper"> | |
| <div class="code-content"> | |
| <component | |
| :is=" | |
| tab.component | |
| ? { render: () => tab.component?.() } | |
| : 'div' | |
| " | |
| /> | |
| </div> | |
| </div> |
🤖 Prompt for AI Agents
In .vitepress/components/code-group.vue around lines 47–49, directly using the
slot render function as <component :is="tab.component" class="code-content" />
can lose classes or cause render errors; wrap the slot function into a component
object that exposes a render(h) (or render) method (e.g., { render: () =>
slots[file]() }) and pass that to :is, and move the "code-content" class to a
stable outer wrapper element so styles are applied reliably while the inner
dynamic component only handles rendering.
| const onCodeEnter = (el: Element) => { | ||
| const htmlEl = el as HTMLElement | ||
| htmlEl.style.height = '0' | ||
| htmlEl.style.opacity = '0' | ||
|
|
||
| // 强制重排 | ||
| htmlEl.offsetHeight | ||
|
|
||
| htmlEl.style.transition = 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)' | ||
| htmlEl.style.height = 'auto' | ||
| htmlEl.style.opacity = '1' | ||
| } | ||
|
|
||
| const onCodeLeave = (el: Element) => { | ||
| const htmlEl = el as HTMLElement | ||
| htmlEl.style.transition = 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)' | ||
| htmlEl.style.height = '0' | ||
| htmlEl.style.opacity = '0' | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
展开/收起动画使用 height: auto 不可动画,导致跳变;应使用 scrollHeight 过渡
CSS 无法从/到 height: auto 做平滑过渡,当前实现会出现跳变。建议使用元素的 scrollHeight 作为过渡目标,并在过渡结束后将高度重置为 auto。
在本段内应用如下修改:
-const onCodeEnter = (el: Element) => {
- const htmlEl = el as HTMLElement
- htmlEl.style.height = '0'
- htmlEl.style.opacity = '0'
-
- // 强制重排
- htmlEl.offsetHeight
-
- htmlEl.style.transition = 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)'
- htmlEl.style.height = 'auto'
- htmlEl.style.opacity = '1'
-}
+const onCodeEnter = (el: Element) => {
+ const htmlEl = el as HTMLElement
+ htmlEl.style.height = '0px'
+ htmlEl.style.opacity = '0'
+ // 强制重排
+ void htmlEl.offsetHeight
+ htmlEl.style.transition = 'height 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1)'
+ htmlEl.style.height = `${htmlEl.scrollHeight}px`
+ htmlEl.style.opacity = '1'
+ const cleanup = () => {
+ htmlEl.style.height = 'auto'
+ htmlEl.removeEventListener('transitionend', cleanup)
+ }
+ htmlEl.addEventListener('transitionend', cleanup)
+}
-const onCodeLeave = (el: Element) => {
- const htmlEl = el as HTMLElement
- htmlEl.style.transition = 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)'
- htmlEl.style.height = '0'
- htmlEl.style.opacity = '0'
-}
+const onCodeLeave = (el: Element) => {
+ const htmlEl = el as HTMLElement
+ htmlEl.style.transition = 'height 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1)'
+ // 先设置起始高度为当前 scrollHeight,再触发到 0 的过渡
+ htmlEl.style.height = `${htmlEl.scrollHeight}px`
+ void htmlEl.offsetHeight
+ htmlEl.style.height = '0px'
+ htmlEl.style.opacity = '0'
+}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const onCodeEnter = (el: Element) => { | |
| const htmlEl = el as HTMLElement | |
| htmlEl.style.height = '0' | |
| htmlEl.style.opacity = '0' | |
| // 强制重排 | |
| htmlEl.offsetHeight | |
| htmlEl.style.transition = 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)' | |
| htmlEl.style.height = 'auto' | |
| htmlEl.style.opacity = '1' | |
| } | |
| const onCodeLeave = (el: Element) => { | |
| const htmlEl = el as HTMLElement | |
| htmlEl.style.transition = 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)' | |
| htmlEl.style.height = '0' | |
| htmlEl.style.opacity = '0' | |
| } | |
| const onCodeEnter = (el: Element) => { | |
| const htmlEl = el as HTMLElement | |
| htmlEl.style.height = '0px' | |
| htmlEl.style.opacity = '0' | |
| // 强制重排 | |
| void htmlEl.offsetHeight | |
| htmlEl.style.transition = | |
| 'height 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1)' | |
| htmlEl.style.height = `${htmlEl.scrollHeight}px` | |
| htmlEl.style.opacity = '1' | |
| const cleanup = () => { | |
| htmlEl.style.height = 'auto' | |
| htmlEl.removeEventListener('transitionend', cleanup) | |
| } | |
| htmlEl.addEventListener('transitionend', cleanup) | |
| } | |
| const onCodeLeave = (el: Element) => { | |
| const htmlEl = el as HTMLElement | |
| htmlEl.style.transition = | |
| 'height 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1)' | |
| // 先设置起始高度为当前 scrollHeight,再触发到 0 的过渡 | |
| htmlEl.style.height = `${htmlEl.scrollHeight}px` | |
| void htmlEl.offsetHeight | |
| htmlEl.style.height = '0px' | |
| htmlEl.style.opacity = '0' | |
| } |
🤖 Prompt for AI Agents
.vitepress/components/demo-preview.vue around lines 50 to 68: the enter/leave
animation currently sets height to 'auto' which cannot be smoothly transitioned
and causes a jump; change the logic to measure the element's scrollHeight and
transition between explicit pixel heights: on enter set height to '0', force
reflow, set transition, set height to `${scrollHeight}px`, then listen for
transitionend to clear the explicit height and set it to 'auto'; on leave first
set the explicit height to the element's current offsetHeight (px) to lock it,
force reflow, set transition, then set height to '0' and remove the explicit
height after the transition ends; ensure you attach and remove the transitionend
handler to avoid leaks.
…ing structure, lifecycle, and API references
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (14)
docs/zh/plugin/examples.md (3)
14-26: 为目录/映射类代码块补充语言标记,消除 markdownlint MD040若不指定语言,CI 的 markdownlint 会报 MD040。目录树/路径映射建议使用
text,有助于渲染与语法高亮一致性。-``` +```text plugin/mine-admin/app-store/ ... -``` +```对文中所有目录结构与路径映射代码块(如“核心文件结构”“目录结构规范”等)均建议采用
text作为 fenced 语言。Also applies to: 349-370, 48-57, 61-89
938-941: API 引用路径与示例文件路径不一致,易造成读者混淆上文 API 文件示例为
web/api/user.js,而组件中导入路径为@/api/plugin/example/user-manager/user。建议对齐为统一示例路径,降低读者代入成本。-import UserApi from '@/api/plugin/example/user-manager/user' +import UserApi from '@/api/user'同时,保留
web/api/user.js的标题/注释,确保上下文一致:-// web/api/user.js +// web/api/user.jsAlso applies to: 1127-1200
1226-1231: 重复/冗余索引:唯一约束已隐式创建索引,无需再单独对相同字段建立普通索引对
username、unique,重复index会徒增维护成本与迁移时间。建议移除这三行,保留其它必要索引。- $table->index(['username']); - $table->index(['email']); - $table->index(['phone']); + // 唯一键已隐式具备索引能力,无需额外索引docs/zh/plugin/structure.md (1)
9-77: 为目录结构代码块添加语言标记,修复 MD040这些代码块为目录树/结构示例,建议统一使用
text作为 fenced 语言。-``` +```text plugin/vendor/plugin-name/ # 插件根目录 ... -``` +```同理修正 “Backend (后端插件)” 与 “Frontend (前端插件)” 两处结构块。
Also applies to: 376-386, 390-399
docs/zh/plugin/api.md (1)
462-468: JSON 片段包含注释,建议使用 jsonc 标记避免语法冲突示例里包含
// enabled | disabled注释,严格 JSON 不允许注释。改用jsonc可保留注释且获得正确高亮。-```json +```jsonc { "name": "vendor/plugin-name", "status": "enabled" // enabled | disabled }</blockquote></details> <details> <summary>docs/zh/plugin/lifecycle.md (2)</summary><blockquote> `313-318`: **路径映射示意代码块缺少语言标记,建议使用 text** 为消除 markdownlint MD040 并提升可读性。 ```diff -``` +```text plugin/vendor/plugin-name/web/ → 前端项目对应目录 ... -``` +```
392-400: JSON 示例包含注释,建议使用 jsonc 以兼容注释状态存储示例使用了注释字段说明,改为
jsonc更贴合实际展示。-```json +```jsonc { "installed_at": "2024-01-01 12:00:00", "version": "1.0.0", "status": "enabled", // enabled | disabled "disabled_at": null, "disabled_reason": null }</blockquote></details> <details> <summary>docs/zh/plugin/develop.md (2)</summary><blockquote> `47-57`: **目录结构代码块缺少语言标记,建议统一使用 text** 为修复 MD040 并保持多处目录树展示一致性。 ```diff -``` +```text plugin/mine-admin/plugin-name/ ... -``` +```Also applies to: 61-89
144-238: 控制器示例缺少对 AbstractController 的 use 导入,可能引起读者复制运行时的类未找到文中直接
extends AbstractController,建议在片段顶部增加对应 use,或改为与其它文档一致的基类(如 MineController)。是否需在此处补充如下导入以避免复制即用时报错?
namespace Plugin\MineAdmin\AppStore\Controller; +use Mine\MineController as AbstractController; // 若实际项目中基类命名不同,请对齐docs/zh/plugin/index.md (3)
9-41: PlantUML 在 VitePress 中默认不渲染,建议确认渲染方案或提供降级方案若站点未接入 PlantUML 渲染插件,这段会以代码块形式展示而非图表。可选方案:
- 接入渲染插件(CI 构建侧或运行时);
- 转为 Mermaid(配合 mermaid 插件);
- 预渲染为图片并引用,或用 ASCII/表格替代。
请确认当前站点是否支持 PlantUML;若不支持,建议改用上述替代方案以避免读者看到原始源码。
96-99: 统一术语与语气:「你的」→「您的」为与 guide.md 的“您的AccessToken”保持一致,建议统一为更正式的“您的AccessToken”。
```ini # .env 文件 -MINE_ACCESS_TOKEN=你的AccessToken +MINE_ACCESS_TOKEN=您的AccessToken--- `112-117`: **与侧边栏保持一致,补充 mine.json 与 ConfigProvider 文档链接** 侧边栏已新增“mine.json 配置”“ConfigProvider 说明”,索引页的“相关文档”建议同步列出,便于检索。 ```diff - [快速入门指南](./guide.md) - 创建第一个插件 - [开发指南](./develop.md) - 详细开发流程 - [插件结构](./structure.md) - 目录结构规范 - [生命周期管理](./lifecycle.md) - 安装卸载流程 +- [mine.json 配置](./mineJson.md) - 元数据与依赖管理 +- [ConfigProvider 说明](./configProvider.md) - 服务注册与扫描 - [API 参考](./api.md) - 接口文档 - [示例代码](./examples.md) - 实际案例docs/zh/plugin/guide.md (2)
67-79: 修复 markdownlint MD040:为目录结构代码块补充语言标识静态分析提示代码块缺少语言标识。建议标注为 text,以获得一致的渲染与通过 lint。
-``` +```text plugin/mycompany/hello-world/ ├── mine.json # 插件配置文件 ├── src/ # 后端源码目录 │ ├── ConfigProvider.php # 配置提供者 │ ├── InstallScript.php # 安装脚本 │ └── UninstallScript.php # 卸载脚本 ├── web/ # 前端源码目录 └── Database/ # 数据库相关 ├── Migrations/ # 数据库迁移 └── Seeders/ # 数据填充 -``` +```
269-272: 优化“配置热重载”指引:明确重启步骤或提供 watch 模式直接执行 start 在服务已运行时可能失败。建议给出 stop && start 的重启示例,或补充 watch 模式(若项目支持)。
-# 重启 Hyperf 服务 -php bin/hyperf.php start +# 重启 Hyperf 服务(先停止再启动) +php bin/hyperf.php stop && php bin/hyperf.php start +# 如项目支持 watch 模式,可使用(可选): +# php bin/hyperf.php server:watch
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (8)
.vitepress/src/zh/sidebars.ts(2 hunks)docs/zh/plugin/api.md(1 hunks)docs/zh/plugin/develop.md(1 hunks)docs/zh/plugin/examples.md(1 hunks)docs/zh/plugin/guide.md(1 hunks)docs/zh/plugin/index.md(1 hunks)docs/zh/plugin/lifecycle.md(1 hunks)docs/zh/plugin/structure.md(1 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.17.2)
docs/zh/plugin/examples.md
67-67: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
docs/zh/plugin/structure.md
9-9: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
376-376: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
390-390: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
docs/zh/plugin/api.md
67-67: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
docs/zh/plugin/develop.md
67-67: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
docs/zh/plugin/guide.md
67-67: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
docs/zh/plugin/lifecycle.md
313-313: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
357-357: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🪛 LanguageTool
docs/zh/plugin/structure.md
[uncategorized] ~450-~450: 动词的修饰一般为‘形容词(副词)+地+动词’。您的意思是否是:清晰"地"提交
Context: .... 版本控制 - 使用 .gitignore 排除不必要的文件 - 创建清晰的提交信息 - 使用语义化版本号 ## 示例项目结构 查看官方插件的实际结构:...
(wb4)
docs/zh/plugin/api.md
[grammar] ~17-~17: There might be a mistake here.
Context: ....php mine-extension:initial ``` 功能: - 发布 app-store 配置文件 - 初始化插件系统配置 - 创建必要的目录结...
(QB_NEW_EN)
[grammar] ~18-~18: There might be a mistake here.
Context: ...nitial ``` 功能: - 发布 app-store 配置文件 - 初始化插件系统配置 - 创建必要的目录结构 实现类: `Mine\Ap...
(QB_NEW_EN)
[grammar] ~19-~19: There might be a mistake here.
Context: ...功能: - 发布 app-store 配置文件 - 初始化插件系统配置 - 创建必要的目录结构 实现类: `Mine\AppStore\Comma...
(QB_NEW_EN)
[grammar] ~32-~32: There might be a mistake here.
Context: ...ne-extension:list [options] ``` 参数: | 参数 | 类型 | 默认值 | 说明 | |------|------|--...
(QB_NEW_EN)
[grammar] ~33-~33: There might be a mistake here.
Context: ...ons] ``` 参数: | 参数 | 类型 | 默认值 | 说明 | |------|------|--------|------| | --type...
(QB_NEW_EN)
[grammar] ~34-~34: There might be a mistake here.
Context: ...值 | 说明 | |------|------|--------|------| | --type | string | all | 筛选扩展类型 (mixed/...
(QB_NEW_EN)
[grammar] ~35-~35: There might be a mistake here.
Context: ... all | 筛选扩展类型 (mixed/backend/frontend) | | --name | string | - | 筛选扩展名称 | | --cat...
(QB_NEW_EN)
[grammar] ~36-~36: There might be a mistake here.
Context: ...tend) | | --name | string | - | 筛选扩展名称 | | --category | string | - | 筛选分类 | | --a...
(QB_NEW_EN)
[grammar] ~37-~37: There might be a mistake here.
Context: ...展名称 | | --category | string | - | 筛选分类 | | --author | string | - | 筛选作者 | 示例...
(QB_NEW_EN)
[grammar] ~62-~62: There might be a mistake here.
Context: ...ension:local-list [options] ``` 参数: | 参数 | 类型 | 默认值 | 说明 | |------|------|--...
(QB_NEW_EN)
[grammar] ~63-~63: There might be a mistake here.
Context: ...ons] ``` 参数: | 参数 | 类型 | 默认值 | 说明 | |------|------|--------|------| | --stat...
(QB_NEW_EN)
[grammar] ~64-~64: There might be a mistake here.
Context: ...值 | 说明 | |------|------|--------|------| | --status | string | all | 筛选状态 (instal...
(QB_NEW_EN)
[grammar] ~65-~65: There might be a mistake here.
Context: ...ll | 筛选状态 (installed/enabled/disabled) | | --type | string | all | 筛选类型 | *实现类...
(QB_NEW_EN)
[grammar] ~78-~78: There might be a mistake here.
Context: ...-name=plugin-name [options] ``` 参数: | 参数 | 类型 | 必选 | 说明 | |------|------|---...
(QB_NEW_EN)
[grammar] ~79-~79: There might be a mistake here.
Context: ...ions] ``` 参数: | 参数 | 类型 | 必选 | 说明 | |------|------|------|------| | --name |...
(QB_NEW_EN)
[grammar] ~80-~80: There might be a mistake here.
Context: ... 必选 | 说明 | |------|------|------|------| | --name | string | 是 | 插件名称 | | --versi...
(QB_NEW_EN)
[grammar] ~81-~81: There might be a mistake here.
Context: ...-|------| | --name | string | 是 | 插件名称 | | --version | string | 否 | 指定版本 | | --fo...
(QB_NEW_EN)
[grammar] ~82-~82: There might be a mistake here.
Context: ...插件名称 | | --version | string | 否 | 指定版本 | | --force | bool | 否 | 强制覆盖已存在的插件 | **实...
(QB_NEW_EN)
[grammar] ~95-~95: There might be a mistake here.
Context: ...on:install {path} [options] ``` 参数: | 参数 | 类型 | 必选 | 说明 | |------|------|---...
(QB_NEW_EN)
[grammar] ~96-~96: There might be a mistake here.
Context: ...ions] ``` 参数: | 参数 | 类型 | 必选 | 说明 | |------|------|------|------| | path | s...
(QB_NEW_EN)
[grammar] ~97-~97: There might be a mistake here.
Context: ... 必选 | 说明 | |------|------|------|------| | path | string | 是 | 插件路径 (vendor/plugi...
(QB_NEW_EN)
[grammar] ~98-~98: There might be a mistake here.
Context: ...string | 是 | 插件路径 (vendor/plugin-name) | | --yes | bool | 否 | 跳过确认提示 | | --force ...
(QB_NEW_EN)
[grammar] ~99-~99: There might be a mistake here.
Context: ...in-name) | | --yes | bool | 否 | 跳过确认提示 | | --force | bool | 否 | 强制重新安装 | | --skip...
(QB_NEW_EN)
[grammar] ~100-~100: There might be a mistake here.
Context: ...跳过确认提示 | | --force | bool | 否 | 强制重新安装 | | --skip-dependencies | bool | 否 | 跳过依赖检...
(QB_NEW_EN)
[grammar] ~122-~122: There might be a mistake here.
Context: ...:uninstall {path} [options] ``` 参数: | 参数 | 类型 | 必选 | 说明 | |------|------|---...
(QB_NEW_EN)
[grammar] ~123-~123: There might be a mistake here.
Context: ...ions] ``` 参数: | 参数 | 类型 | 必选 | 说明 | |------|------|------|------| | path | s...
(QB_NEW_EN)
[grammar] ~124-~124: There might be a mistake here.
Context: ... 必选 | 说明 | |------|------|------|------| | path | string | 是 | 插件路径 | | --yes | b...
(QB_NEW_EN)
[grammar] ~125-~125: There might be a mistake here.
Context: ...---|------| | path | string | 是 | 插件路径 | | --yes | bool | 否 | 跳过确认提示 | | --force ...
(QB_NEW_EN)
[grammar] ~126-~126: There might be a mistake here.
Context: ...是 | 插件路径 | | --yes | bool | 否 | 跳过确认提示 | | --force | bool | 否 | 强制卸载 (忽略错误) | | -...
(QB_NEW_EN)
[grammar] ~127-~127: There might be a mistake here.
Context: ...示 | | --force | bool | 否 | 强制卸载 (忽略错误) | | --keep-data | bool | 否 | 保留用户数据 | **实...
(QB_NEW_EN)
[grammar] ~140-~140: There might be a mistake here.
Context: ...ion:create {path} [options] ``` 参数: | 参数 | 类型 | 默认值 | 说明 | |------|------|--...
(QB_NEW_EN)
[grammar] ~141-~141: There might be a mistake here.
Context: ...ons] ``` 参数: | 参数 | 类型 | 默认值 | 说明 | |------|------|--------|------| | path |...
(QB_NEW_EN)
[grammar] ~142-~142: There might be a mistake here.
Context: ...值 | 说明 | |------|------|--------|------| | path | string | - | 插件路径 (vendor/plugi...
(QB_NEW_EN)
[grammar] ~143-~143: There might be a mistake here.
Context: ...string | - | 插件路径 (vendor/plugin-name) | | --name | string | example | 插件显示名称 | |...
(QB_NEW_EN)
[grammar] ~144-~144: There might be a mistake here.
Context: ...| | --name | string | example | 插件显示名称 | | --type | string | mixed | 插件类型 (mixed/...
(QB_NEW_EN)
[grammar] ~145-~145: There might be a mistake here.
Context: ... mixed | 插件类型 (mixed/backend/frontend) | | --author | string | - | 作者名称 | | --des...
(QB_NEW_EN)
[grammar] ~146-~146: There might be a mistake here.
Context: ...tend) | | --author | string | - | 作者名称 | | --description | string | - | 插件描述 | | ...
(QB_NEW_EN)
[grammar] ~147-~147: There might be a mistake here.
Context: ... | | --description | string | - | 插件描述 | | --license | string | MIT | 许可证类型 | **...
(QB_NEW_EN)
[grammar] ~182-~182: There might be a mistake here.
Context: ... // 初始化插件系统 Plugin::init(); ``` 功能: - 扫描 plugin/ 目录 - 加载已安装的插件 - 注册 ConfigPr...
(QB_NEW_EN)
[grammar] ~183-~183: There might be a mistake here.
Context: ...::init(); ``` 功能: - 扫描 plugin/ 目录 - 加载已安装的插件 - 注册 ConfigProvider - 自动加载插件类 ...
(QB_NEW_EN)
[grammar] ~184-~184: There might be a mistake here.
Context: ...`` 功能: - 扫描 plugin/ 目录 - 加载已安装的插件 - 注册 ConfigProvider - 自动加载插件类 #### Plugin...
(QB_NEW_EN)
[grammar] ~185-~185: There might be a mistake here.
Context: ...ugin/` 目录 - 加载已安装的插件 - 注册 ConfigProvider - 自动加载插件类 #### Plugin::getInstalled() 获取...
(QB_NEW_EN)
[grammar] ~629-~629: There might be a mistake here.
Context: ...} ``` #### 可用钩子列表 | 钩子名称 | 触发时机 | 参数 | |----------|----------|------| | `user.l...
(QB_NEW_EN)
[grammar] ~630-~630: There might be a mistake here.
Context: ...时机 | 参数 | |----------|----------|------| | user.login.before | 用户登录前 | User $us...
(QB_NEW_EN)
[grammar] ~631-~631: There might be a mistake here.
Context: ...ser.login.before| 用户登录前 | User $user | |user.login.after` | 用户登录后 | User $use...
(QB_NEW_EN)
[grammar] ~632-~632: There might be a mistake here.
Context: ...user.login.after| 用户登录后 | User $user | |user.logout.before` | 用户退出前 | User $u...
(QB_NEW_EN)
[grammar] ~633-~633: There might be a mistake here.
Context: ...er.logout.before| 用户退出前 | User $user | |user.logout.after` | 用户退出后 | User $us...
(QB_NEW_EN)
[grammar] ~634-~634: There might be a mistake here.
Context: ...ser.logout.after| 用户退出后 | User $user | |menu.render.before` | 菜单渲染前 | array $...
(QB_NEW_EN)
[grammar] ~635-~635: There might be a mistake here.
Context: ....render.before| 菜单渲染前 | array $menus | |menu.render.after` | 菜单渲染后 | array $m...
(QB_NEW_EN)
[grammar] ~636-~636: There might be a mistake here.
Context: ...u.render.after| 菜单渲染后 | array $menus | |permission.check.before` | 权限检查前 | st...
(QB_NEW_EN)
[grammar] ~637-~637: There might be a mistake here.
Context: ...权限检查前 | string $permission, User $user | | permission.check.after | 权限检查后 | boo...
(QB_NEW_EN)
[grammar] ~727-~727: There might be a mistake here.
Context: ... 错误码参考 ### 插件安装错误码 | 错误码 | 说明 | 解决方案 | |--------|------|----------| | 10001 | 插...
(QB_NEW_EN)
[grammar] ~728-~728: There might be a mistake here.
Context: ...说明 | 解决方案 | |--------|------|----------| | 10001 | 插件目录不存在 | 检查插件路径是否正确 | | 10002...
(QB_NEW_EN)
[grammar] ~729-~729: There might be a mistake here.
Context: ...------| | 10001 | 插件目录不存在 | 检查插件路径是否正确 | | 10002 | mine.json 文件不存在 | 确保插件包含配置文件 |...
(QB_NEW_EN)
[grammar] ~730-~730: There might be a mistake here.
Context: ...| 10002 | mine.json 文件不存在 | 确保插件包含配置文件 | | 10003 | mine.json 格式错误 | 检查 JSON 语法 | ...
(QB_NEW_EN)
[grammar] ~731-~731: There might be a mistake here.
Context: ... | 10003 | mine.json 格式错误 | 检查 JSON 语法 | | 10004 | 依赖插件未安装 | 先安装依赖插件 | | 10005 | ...
(QB_NEW_EN)
[grammar] ~732-~732: There might be a mistake here.
Context: ... JSON 语法 | | 10004 | 依赖插件未安装 | 先安装依赖插件 | | 10005 | 版本冲突 | 解决版本兼容性问题 | | 10006 | 数...
(QB_NEW_EN)
[grammar] ~733-~733: There might be a mistake here.
Context: ...| 先安装依赖插件 | | 10005 | 版本冲突 | 解决版本兼容性问题 | | 10006 | 数据库迁移失败 | 检查数据库连接和权限 | | 10007...
(QB_NEW_EN)
[grammar] ~734-~734: There might be a mistake here.
Context: ...兼容性问题 | | 10006 | 数据库迁移失败 | 检查数据库连接和权限 | | 10007 | 文件复制失败 | 检查文件权限 | | 10008 | 安装...
(QB_NEW_EN)
[grammar] ~735-~735: There might be a mistake here.
Context: ...检查数据库连接和权限 | | 10007 | 文件复制失败 | 检查文件权限 | | 10008 | 安装脚本执行失败 | 查看安装脚本错误日志 | ### 插...
(QB_NEW_EN)
[grammar] ~740-~740: There might be a mistake here.
Context: ...错误日志 | ### 插件卸载错误码 | 错误码 | 说明 | 解决方案 | |--------|------|----------| | 20001 | 插...
(QB_NEW_EN)
[grammar] ~741-~741: There might be a mistake here.
Context: ...说明 | 解决方案 | |--------|------|----------| | 20001 | 插件未安装 | 无需卸载 | | 20002 | 存在依赖插...
(QB_NEW_EN)
[grammar] ~742-~742: There might be a mistake here.
Context: ...---|----------| | 20001 | 插件未安装 | 无需卸载 | | 20002 | 存在依赖插件 | 先卸载依赖插件或使用强制卸载 | | 20...
(QB_NEW_EN)
[grammar] ~743-~743: There might be a mistake here.
Context: ...卸载 | | 20002 | 存在依赖插件 | 先卸载依赖插件或使用强制卸载 | | 20003 | 卸载脚本执行失败 | 查看卸载脚本错误日志 | | 2000...
(QB_NEW_EN)
[grammar] ~744-~744: There might be a mistake here.
Context: ...强制卸载 | | 20003 | 卸载脚本执行失败 | 查看卸载脚本错误日志 | | 20004 | 数据库清理失败 | 手动清理数据库数据 | | 20005 ...
(QB_NEW_EN)
[grammar] ~745-~745: There might be a mistake here.
Context: ...脚本错误日志 | | 20004 | 数据库清理失败 | 手动清理数据库数据 | | 20005 | 文件删除失败 | 检查文件权限 | ## 相关文档 - ...
(QB_NEW_EN)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: translate
- GitHub Check: Redirect rules - super-cobbler-53ff65
- GitHub Check: Header rules - super-cobbler-53ff65
- GitHub Check: Pages changed - super-cobbler-53ff65
🔇 Additional comments (7)
docs/zh/plugin/api.md (1)
1-160: 整体结构与内容完善度高,命令与类接口说明清晰CLI 与核心类 API 梳理到位,示例贴合实际工程,便于快速上手。
docs/zh/plugin/lifecycle.md (1)
1-37: 流程与时序图清晰,覆盖生命周期关键环节PlantUML 图与流程分解准确,便于读者把握安装/更新/卸载的主干路径。
Also applies to: 121-182, 488-521
docs/zh/plugin/develop.md (1)
870-899: 配置发布与迁移的最佳实践强调得当明确建议在 InstallScript 中处理发布与迁移,避免 ConfigProvider::publish 带来的不确定性,方向正确。
.vitepress/src/zh/sidebars.ts (2)
426-432: “插件系统概述 / 快速入门指南”入口调整清晰易用,信息架构更合理与新增文档的定位一致,放在“🚀 快速开始”下非常合适,命名也直观。
Also applies to: 440-442
443-466: ✅ 文档链接校验通过
已在docs/zh/plugin目录下验证所有侧边栏引用的 Markdown 文件均存在,无需额外隐藏或补齐,侧边栏配置可放心合并。docs/zh/plugin/index.md (1)
45-49: 确认链接有效性:经查验,仓库默认分支为 master,且 bin/hyperf.php 文件在该分支下存在,无需调整链接。docs/zh/plugin/guide.md (1)
39-41: 请确认 CLI 命令名称 initial / init 并统一文档所有语言版本的文档(如 docs/zh/plugin/guide.md、docs/en/plugin/command.md、docs/ja/plugin/command.md 等)目前都使用了
php bin/hyperf.php mine-extension:initial,但在本地仓库中未能直接定位到该命令的定义(可能位于依赖的插件包中)。
- 请在插件源码或已安装的环境中核对实际可执行命令是
mine-extension:initial还是mine-extension:init。- 如命令名为
init,请将全文示例统一替换为php bin/hyperf.php mine-extension:init;- 如确认使用
initial,可保留现有文档但请补充说明,以避免读者误执行失败。
| <?php | ||
|
|
||
| namespace Plugin\MyCompany\Example\Controller; | ||
|
|
||
| use Hyperf\HttpServer\Annotation\Controller; | ||
| use Hyperf\HttpServer\Annotation\GetMapping; | ||
| use Hyperf\HttpServer\Annotation\PostMapping; | ||
| use Mine\MineController; | ||
|
|
||
| #[Controller(prefix: '/plugin/example')] | ||
| class ExampleController extends MineController | ||
| { | ||
| public function __construct( | ||
| private ExampleService $service | ||
| ) {} | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
控制器代码片段存在缺失与拼接错误,需补全方法与导入注解
- 片段中使用了
#[PutMapping]与#[DeleteMapping],但缺少对应 use 导入。 - 行为代码(Line 415-422 附近)出现了无方法签名的散落语句(
$user = $this->userService->find($id);等),应当是“查询详情”的方法,建议补齐为show方法。
建议如下:
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\GetMapping;
use Hyperf\HttpServer\Annotation\PostMapping;
+use Hyperf\HttpServer\Annotation\PutMapping;
+use Hyperf\HttpServer\Annotation\DeleteMapping;
use Mine\MineController;并将散落代码整理为标准方法:
- $user = $this->userService->find($id);
-
- if (!$user) {
- return $this->error('用户不存在', 404);
- }
-
- return $this->success($user);
+ #[GetMapping('/users/{id:\d+}')]
+ public function show(int $id): array
+ {
+ $user = $this->userService->find($id);
+ if (!$user) {
+ return $this->error('用户不存在', 404);
+ }
+ return $this->success($user);
+ }Also applies to: 427-447
🤖 Prompt for AI Agents
In docs/zh/plugin/examples.md around lines 384 to 399, the controller snippet is
missing use imports for PutMapping and DeleteMapping and has orphaned statements
that should be a method; add "use Hyperf\HttpServer\Annotation\PutMapping;" and
"use Hyperf\HttpServer\Annotation\DeleteMapping;" to the top imports, then
convert the scattered lines (around 415–422) into a proper public function
show(int $id): \Illuminate\Http\JsonResponse (or the project’s response type)
that calls $user = $this->userService->find($id); and returns the user in the
standard response format; apply the same fix for the similar orphaned code block
at lines 427–447 by wrapping it into a properly annotated method (e.g.,
#[GetMapping('/{id}')] public function show(...)) and ensuring method signature,
annotation, and return are consistent with the rest of the controller.
| const response = await UserApi.getList(params) | ||
| tableData.value = response.data.list | ||
| pagination.total = response.data.total | ||
| } catch (error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
前后端分页返回结构不一致,导致列表与总数取值错误
后端 UserService::getPageList 返回的是 items 与 pageInfo.total,但前端取的是 response.data.list 与 response.data.total。这会导致页面空表或分页异常。
建议对齐前端取值为后端返回结构:
- tableData.value = response.data.list
- pagination.total = response.data.total
+ tableData.value = response.data.items
+ pagination.total = response.data.pageInfo.totalAlso applies to: 217-225
🤖 Prompt for AI Agents
In docs/zh/plugin/examples.md around lines 982 to 985 (also apply same fix to
lines 217-225), the front-end expects response.data.list and response.data.total
but the backend returns items and pageInfo.total; update the front-end accessors
to use response.data.items for the list and response.data.pageInfo.total for the
total so the table and pagination read the correct fields from the backend
response.
| protected function clearCache(): void | ||
| { | ||
| // 清理插件相关缓存 | ||
| $redis = \Hyperf\Context\ApplicationContext::getContainer() | ||
| ->get(\Hyperf\Redis\Redis::class); | ||
|
|
||
| $redis->del('plugin:cache:*'); | ||
| echo "缓存已清理\n"; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Redis 通配符删除用法不当:DEL 不支持通配符,建议使用 SCAN 配合批量删除
$redis->del('plugin:cache:*') 不会按预期删除匹配键。推荐使用 SCAN 游标迭代删除,避免 KEYS 带来的阻塞风险。
- $redis->del('plugin:cache:*');
- echo "缓存已清理\n";
+ // 使用 SCAN 非阻塞遍历匹配键并批量删除
+ $it = null;
+ do {
+ $keys = $redis->scan($it, 'plugin:cache:*', 1000);
+ if ($keys && is_array($keys) && count($keys) > 0) {
+ // 批量删除(注意不同客户端对可变参数的支持)
+ $redis->del(...$keys);
+ }
+ } while ($it !== 0 && $it !== null);
+ echo "缓存已清理\n";📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| protected function clearCache(): void | |
| { | |
| // 清理插件相关缓存 | |
| $redis = \Hyperf\Context\ApplicationContext::getContainer() | |
| ->get(\Hyperf\Redis\Redis::class); | |
| $redis->del('plugin:cache:*'); | |
| echo "缓存已清理\n"; | |
| } | |
| protected function clearCache(): void | |
| { | |
| // 清理插件相关缓存 | |
| $redis = \Hyperf\Context\ApplicationContext::getContainer() | |
| ->get(\Hyperf\Redis\Redis::class); | |
| // 使用 SCAN 非阻塞遍历匹配键并批量删除 | |
| $it = null; | |
| do { | |
| $keys = $redis->scan($it, 'plugin:cache:*', 1000); | |
| if ($keys && is_array($keys) && count($keys) > 0) { | |
| // 批量删除(注意不同客户端对可变参数的支持) | |
| $redis->del(...$keys); | |
| } | |
| } while ($it !== 0 && $it !== null); | |
| echo "缓存已清理\n"; | |
| } |
🤖 Prompt for AI Agents
In docs/zh/plugin/structure.md around lines 318 to 326, the current use of
$redis->del('plugin:cache:*') is incorrect because DEL does not accept
wildcards; replace it with a SCAN-based cursor loop that iterates matching keys
(e.g. SCAN with pattern 'plugin:cache:*'), collect keys in reasonable-size
batches, and call DEL on each batch until the cursor returns 0; avoid using KEYS
to prevent blocking and ensure the loop handles pagination and empty results
safely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 26
🧹 Nitpick comments (47)
docs/en/plugin/guide.md (2)
67-79: 为目录结构代码块显式指定语言,消除 MD040 规则告警当前使用了未标注语言的围栏代码块(目录树)。为提高渲染与可读性,并通过 markdownlint MD040 校验,建议将开头的
改为text。可直接替换开头围栏为 text:
-``` +```text plugin/mycompany/hello-world/ ├── mine.json # Plugin configuration file ├── src/ # Backend source directory │ ├── ConfigProvider.php # Configuration provider │ ├── InstallScript.php # Installation script │ └── UninstallScript.php # Uninstallation script ├── web/ # Frontend source directory └── Database/ # Database related ├── Migrations/ # Database migrations └── Seeders/ # Data seeders -``` +```
38-41: 核对初始化指令是否为mine-extension:initial(可能存在指令名差异)文档使用了
php bin/hyperf.php mine-extension:initial。为避免读者踩坑,请确认 MineAdmin 当前版本真实的初始化指令名称(例如是否为 initial、init 或 initialize)。如需,我可以根据你们仓库命令列表补一段“常见 CLI 指令速查表”并统一到多语言文档。
docs/ja/plugin/develop.md (1)
47-57: 为目录结构代码块添加语言标注,修复 MD040 告警两处目录树代码块使用了无语言围栏,建议标为 text,以提升一致性与工具链友好度。
示例(两处开头围栏均改为 text):
-``` +```text plugin/mine-admin/plugin-name/ ... -``` +```Also applies to: 61-89
docs/zh-hk/plugin/develop.md (2)
47-57: 为目录结构代码块添加语言标注,修复 MD040 告警两处目录树使用了未声明语言的围栏,建议使用 text。
示例修改:
-``` +```text plugin/mine-admin/plugin-name/ ... -``` +```Also applies to: 61-89
841-856: 避免推荐可能不可用的dd()调试函数Hyperf 项目未必默认提供 Laravel 风格的
dd()。文档在“調試技巧”中推荐dd()可能误导用户。建议改为更通用的做法(日志或 VarDumper):
- 推荐使用 Logger:
$logger->info('debug', [...])- 若已安装 symfony/var-dumper,可用
dump($var);生产环境谨慎使用。
是否要我统一修订多语言版本的调试章节?docs/en/plugin/develop.md (1)
47-57: 为目录结构代码块添加语言标注,修复 MD040 告警与其他语言版本一致,目录树建议标注为 text。
示例:
-``` +```text plugin/mine-admin/plugin-name/ ... -``` +```Also applies to: 61-89
docs/ja/plugin/examples.md (2)
14-26: 为目录结构代码块添加语言标注,修复 MD040 告警目录树未指定语言,建议使用 text。
-``` +```text plugin/mine-admin/app-store/ ... -``` +```
484-491: 命名空间与示例前后不一致,可能导致读者混淆控制器示例使用
Plugin\MyCompany\Example\Controller,服务层示例使用Plugin\Example\UserManager\Service。建议统一 vendor 与插件名以提升连贯性。如需,我可以统一为
Plugin\MyCompany\Example\...并同步修正文中的 mine.json/psr-4 片段。Also applies to: 490-497
.vitepress/src/zh-hk/sidebars.ts (1)
457-459: 繁體字形修正:將「説明」改為「說明」在繁體中文(香港)語境中,「說明」比「説明」更為正確、常用。建議更新此處標題文字。
請應用以下修改:
- text:"⚙️ ConfigProvider 説明", + text:"⚙️ ConfigProvider 說明",docs/en/plugin/examples.md (2)
14-27: 為代碼塊補充語言標識(MD040)「Core File Structure」代碼塊無語言標識,易觸發 markdownlint MD040。建議標為 text。
請應用以下修改:
-``` +```text plugin/mine-admin/app-store/ ├── mine.json # Plugin configuration ├── src/ # Backend code │ ├── ConfigProvider.php # Configuration provider │ ├── Controller/ # Controllers │ ├── Service/ # Service layer │ └── Command/ # Commands ├── web/ # Frontend code │ ├── views/ # Page components │ └── api/ # API interfaces └── Database/ # Database -``` +```
349-370: 為代碼塊補充語言標識(MD040)「Directory Structure Standards」結構樹無語言標識。建議標為 text。
-``` +```text plugin/vendor-name/plugin-name/ ├── mine.json # Plugin configuration ├── src/ # PHP backend code │ ├── ConfigProvider.php # Configuration provider │ ├── Controller/ # Controllers │ ├── Service/ # Service layer │ ├── Model/ # Models │ ├── Command/ # Commands │ ├── Listener/ # Event listeners │ └── Middleware/ # Middleware ├── web/ # Frontend code │ ├── views/ # Vue components │ ├── api/ # API wrappers │ ├── components/ # Shared components │ └── locales/ # Localization ├── Database/ # Database │ ├── Migrations/ # Migration files │ └── Seeders/ # Seeders └── publish/ # Published files └── config.php # Configuration files -``` +```docs/ja/plugin/api.md (1)
463-468: JSON 示例包含註釋,將語言標識改為 jsonc 更精確當前標記為 json,但內含
// enabled | disabled註釋,屬於 JSON with comments。建議改為 jsonc。-```json +```jsonc { "name": "vendor/plugin-name", "status": "enabled" // enabled | disabled } -``` +```docs/en/plugin/api.md (2)
3-3: 措辞收紧:将 “API interfaces” 改为 “APIs”“API interfaces” 存在同义重复(I 即 interfaces)。精简后更地道。
-This document provides detailed information about all API interfaces, command-line tools, and core libraries of the MineAdmin plugin system. +This document provides detailed information about all APIs, command-line tools, and core libraries of the MineAdmin plugin system.
462-468: JSON 示例包含注释,建议标记为 jsonc该示例包含
// enabled | disabled注释,使用 jsonc 更贴近实际。-```json +```jsonc { "name": "vendor/plugin-name", "status": "enabled" // enabled | disabled } -``` +```.vitepress/src/en/sidebars.ts (1)
3-3: 类型注解微调以提升可读性(非必须)在冒号两侧保留空格更符合常见 TS 风格,易读性更好。
-const sidebar:DefaultTheme.Sidebar = { +const sidebar: DefaultTheme.Sidebar = {docs/zh-hk/plugin/examples.md (1)
14-14: 为目录树代码块补充语言标注,修复 MD040两个目录树代码块缺少语言标注,建议标为 text。
-``` +```text-``` +```textAlso applies to: 349-349
docs/en/plugin/structure.md (2)
9-9: 为未标注语言的代码块补充语言标注,修复 MD040目录树代码块使用 text 作为语言标注更符合规范。
-``` +```text-``` +```text-``` +```textAlso applies to: 376-376, 390-390
387-399: 表述微调建议(可选)“Frontend (Frontend Plugin) Only contains web/ directory” 下仍示例包含 src/ConfigProvider.php,建议补一句说明:前端插件通常仅含 web/;如需与后端系统注册最小配置,可保留 src/ConfigProvider.php。以免读者困惑。
docs/ja/plugin/structure.md (6)
9-9: 为未标注语言的代码块添加语言标识(修复 markdownlint MD040)目录树属于纯文本展示,建议标注为 text,避免 lint 报错并提升可读性。
可以直接将代码围栏语言设置为 text:
-``` +```text
376-376: 为“Backend 插件示例”代码块添加语言标识(修复 MD040)该代码块为目录树示例,推荐标注 text 以通过 markdownlint。
-``` +```text
390-390: 为“Frontend 插件示例”代码块添加语言标识(修复 MD040)同上,建议标注为 text。
-``` +```text
214-223: InstallScript 发布配置时缺少健壮性处理(源文件存在性与目标目录创建)当前仅在目标文件不存在时 copy,未校验 source 是否存在/可读,也未确保目标目录存在;在部分环境下会报错或静默失败。
建议补充存在性检查与目录创建:
protected function publishConfig(): void { - $source = __DIR__ . '/../publish/config/plugin.php'; - $target = BASE_PATH . '/config/autoload/plugin.php'; + $source = __DIR__ . '/../publish/config/plugin.php'; + $target = BASE_PATH . '/config/autoload/plugin.php'; - if (!file_exists($target)) { - copy($source, $target); - echo "設定ファイルが公開されました: {$target}\n"; - } + if (!is_file($source) || !is_readable($source)) { + echo "設定ファイルのソースが見つかりません: {$source}\n"; + return; + } + $dir = \dirname($target); + if (!is_dir($dir)) { + @mkdir($dir, 0755, true); + } + if (!file_exists($target)) { + if (@copy($source, $target)) { + echo "設定ファイルが公開されました: {$target}\n"; + } else { + echo "設定ファイルの公開に失敗しました: {$target}\n"; + } + } }
308-316: 卸载时直接删除全局 config/autoload/plugin.php 风险较高示例代码会删除全局配置文件,可能影响其他插件或主应用。应仅移除当前插件发布的具体文件(命名可包含 vendor/plugin-name),或在删除前校验内容归属。
建议将目标文件指向插件专属配置(示例):
- $configFile = BASE_PATH . '/config/autoload/plugin.php'; + $configFile = BASE_PATH . '/config/autoload/plugin_vendor_plugin-name.php';如需稳妥,可在删除前检测文件内容签名或通过安装记录定位发布清单。
321-326: Redis 使用通配符删除键无效且不安全,应改用扫描删除
$redis->del('plugin:cache:*')不会按通配符匹配删除,多数客户端会将其视为一个字面量 key;即使支持,也不建议 KEYS + DEL。应使用 SCAN 游标批量删除。可在文档中示例更安全的删除方式:
$redis = \Hyperf\Context\ApplicationContext::getContainer() ->get(\Hyperf\Redis\Redis::class); $cursor = '0'; $pattern = 'plugin:cache:*'; do { [$cursor, $keys] = $redis->scan($cursor, ['match' => $pattern, 'count' => 1000]); if (!empty($keys)) { $redis->del(...$keys); } } while ($cursor !== '0'); echo "キャッシュがクリアされました\n";docs/en/plugin/lifecycle.md (2)
313-318: 为“Frontend File Copying”代码块添加语言标识(修复 MD040)该块是路径映射示例,建议标注 text。
-``` +```text plugin/vendor/plugin-name/web/ → Frontend project directory ├── views/example.vue → src/views/plugin/vendor/plugin-name/example.vue ├── components/ExampleComp.vue → src/components/plugin/vendor/plugin-name/ExampleComp.vue └── api/example.js → src/api/plugin/vendor/plugin-name/example.js
357-359: 为 install.lock 路径代码块添加语言标识(修复 MD040)-``` +```text plugin/vendor/plugin-name/install.lockdocs/ja/plugin/lifecycle.md (2)
313-318: 为“フロントエンドファイルコピー”代码块添加语言标识(修复 MD040)-``` +```text plugin/vendor/plugin-name/web/ → フロントエンドプロジェクト対応ディレクトリ ├── views/example.vue → src/views/plugin/vendor/plugin-name/example.vue ├── components/ExampleComp.vue → src/components/plugin/vendor/plugin-name/ExampleComp.vue └── api/example.js → src/api/plugin/vendor/plugin-name/example.js
357-359: 为 install.lock 路径代码块添加语言标识(修复 MD040)-``` +```text plugin/vendor/plugin-name/install.lockdocs/zh-tw/plugin/lifecycle.md (2)
313-318: 為“前端檔案複製”代碼塊添加語言標識(修復 MD040)-``` +```text plugin/vendor/plugin-name/web/ → 前端專案對應目錄 ├── views/example.vue → src/views/plugin/vendor/plugin-name/example.vue ├── components/ExampleComp.vue → src/components/plugin/vendor/plugin-name/ExampleComp.vue └── api/example.js → src/api/plugin/vendor/plugin-name/example.js
357-359: 為 install.lock 路徑代碼塊添加語言標識(修復 MD040)-``` +```text plugin/vendor/plugin-name/install.lockdocs/zh-tw/plugin/examples.md (4)
14-26: 为目录树代码块补充语言标识,解决 markdownlint MD040这里用于展示目录结构的围栏代码块缺少语言标识,触发 MD040。建议标记为 text,便于渲染与语法高亮一致。
应用以下变更:
-``` +```text plugin/mine-admin/app-store/ ├── mine.json # 外掛配置 ├── src/ # 後端程式碼 @@ └── Database/ # 資料庫--- `349-371`: **第二处目录树代码块同样补充语言标识** 同上,目录结构代码块建议标注为 text。 ```diff -``` +```text plugin/vendor-name/plugin-name/ ├── mine.json # 外掛配置檔案 ├── src/ # PHP 後端程式碼 @@ └── config.php # 配置檔案--- `1185-1188`: **multipart/form-data 头部无需手动设置,避免 boundary 丢失** 使用 FormData 时不应显式设置 `Content-Type`,让浏览器/HTTP 客户端自动注入带 boundary 的头部。 ```diff return request({ url: `${API_BASE}/users/import`, method: 'post', data: formData, - headers: { - 'Content-Type': 'multipart/form-data' - } })
935-941: 前端 API 导入路径与文档示例不一致,易造成混淆此处导入为
@/api/plugin/example/user-manager/user,而文档第 8 节提供的示例文件路径为web/api/user.js。建议二选一保持一致:
- 若以文档示例为准:
-import UserApi from './components/ImportDialog.vue' +import UserApi from '@/api/user'
- 若以当前工程路径为准:请在文档中同步更新对应的 import 示例,避免读者复制后找不到模块。
docs/zh-tw/plugin/api.md (1)
47-61: 为围栏代码块补充语言标识,解决 MD040markdownlint 报告本段附近存在未指定语言的围栏代码块。请统一为所有命令/代码块补充语言,例如 bash/json/http/php。
示例修正:
-``` +```bash php bin/hyperf.php mine-extension:list --type=mixed</blockquote></details> <details> <summary>docs/ja/plugin/guide.md (1)</summary><blockquote> `67-79`: **目录树代码块缺少语言标识(MD040)** 该处为目录结构展示,建议标注为 text,消除 lint 告警并获得更好的渲染。 ```diff -``` +```text plugin/mycompany/hello-world/ ├── mine.json # プラグイン設定ファイル ├── src/ # バックエンドソースディレクトリ @@ └── Database/ # データベース関連docs/zh-tw/plugin/guide.md (2)
29-33: 在 AccessToken 示例后补充安全警示,避免泄露建议在
.env示例之后立即加入一个 warning 提示,提醒不要将 AccessToken 提交到版本库,并建议使用更安全的密钥管理方式。可以在此处直接追加以下内容:
```ini # MineAdmin AccessToken MINE_ACCESS_TOKEN=您的AccessToken
+::: warning 注意
+請妥善保管 AccessToken,切勿提交到版本庫。建議使用 .env.local 或 CI/部署平台的密鑰管理功能託管憑證。
+:::--- `171-201`: **改进前端示例:加入加载与错误状态,贴合“加载态与错误处理”的 PR 主题** 当前示例仅简单调用接口,建议加入 loading 与 error 状态,提升示例的教学价值。 对模板与脚本做如下微调: ```diff <!-- web/components/HelloWorld.vue --> <template> <div class="hello-world"> <h2>Hello World Plugin</h2> - <p>{{ message }}</p> - <el-button @click="fetchGreeting" type="primary"> + <p>{{ message }}</p> + <el-alert + v-if="error" + type="error" + :title="error" + show-icon + class="mb-2" + /> + <el-button @click="fetchGreeting" type="primary" :loading="loading"> 獲取問候語 </el-button> </div> </template> <script setup> import { ref } from 'vue' const message = ref('歡迎使用 Hello World 外掛!') +const loading = ref(false) +const error = ref('') const fetchGreeting = async () => { // 呼叫後端 API - try { - const response = await fetch('/hello-world/greeting') - const data = await response.json() - message.value = data.message - } catch (error) { - console.error('獲取問候語失敗:', error) - } + loading.value = true + error.value = '' + try { + const response = await fetch('/hello-world/greeting') + if (!response.ok) throw new Error(`HTTP ${response.status}`) + const data = await response.json() + message.value = data.message ?? 'Hello from MineAdmin Plugin!' + } catch (e) { + console.error('獲取問候語失敗:', e) + error.value = '獲取問候語失敗,請稍後重試。' + } finally { + loading.value = false + } } </script>docs/zh-tw/plugin/structure.md (4)
9-77: 为目录树代码块添加语言标识以通过 MD040 规则当前围栏代码块缺少语言标识,markdownlint 报告 MD040。建议使用
text。-``` +```text plugin/vendor/plugin-name/ # 外掛根目錄 ... -``` +```
376-386: 为“Backend 插件”目录树代码块添加语言标识同上,补齐语言标识,便于渲染与静态检查通过。
-``` +```text plugin/vendor/backend-plugin/ ... -``` +```
390-399: 为“Frontend 插件”目录树代码块添加语言标识同上,建议标注为
text。-``` +```text plugin/vendor/frontend-plugin/ ... -``` +```
168-170: 移除未使用的MigrateCommand引用,避免示例混淆
use Hyperf\Database\Commands\Migrations\MigrateCommand;未在示例中使用,会误导读者。use Hyperf\Contract\ApplicationInterface; -use Hyperf\Database\Commands\Migrations\MigrateCommand;docs/zh-tw/plugin/index.md (1)
95-104: AccessToken 安全提示很到位,可考虑补充“不提交到 VCS”的提醒当前有泄露警示,若再强调“不提交到版本库/PR/日志”,会更全面。
docs/zh-hk/plugin/structure.md (4)
9-77: 为目录树代码块添加语言标识以通过 MD040建议标注为
text。-``` +```text plugin/vendor/plugin-name/ # 插件根目錄 ... -``` +```
376-385: 为“Backend 插件”目录树添加语言标识同上。
-``` +```text plugin/vendor/backend-plugin/ ... -``` +```
390-399: 为“Frontend 插件”目录树添加语言标识同上。
-``` +```text plugin/vendor/frontend-plugin/ ... -``` +```
168-170: 移除未使用的MigrateCommand引用示例中未使用该类,保留会造成困惑。
use Hyperf\Contract\ApplicationInterface; -use Hyperf\Database\Commands\Migrations\MigrateCommand;
| text:"📚 コアコンセプト", | ||
| collapsed: false, | ||
| items: | ||
| [ | ||
| { | ||
| text:"📁 プラグインディレクトリ構造", | ||
| link:"/plugin/structure" | ||
| }, | ||
| { | ||
| text:"📄 mine.json 説明と例", | ||
| text:"📄 mine.json 設定", | ||
| link:"/plugin/mineJson" | ||
| }, | ||
| { | ||
| text:"⚙️ ConfigProvider 説明", | ||
| link:"/plugin/configProvider" | ||
| } | ||
| text:"⚙️ ConfigProvider 説明", | ||
| link:"/plugin/configProvider" | ||
| }, | ||
| { | ||
| text:"🔄 ライフサイクル管理", | ||
| link:"/plugin/lifecycle" | ||
| } | ||
| ] | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
核心概念分組 LGTM,請同步校驗鏈接對應文檔
命名與結構清晰。為避免 404,建議驗證 docs/ja/plugin 目錄下是否存在 structure、mineJson、configProvider、lifecycle 對應頁面。
請運行:
🏁 Script executed:
#!/bin/bash
set -euo pipefail
expected=(structure mineJson configProvider lifecycle)
echo "Checking ja plugin core concepts docs..."
missing=0
for name in "${expected[@]}"; do
hits=$(fd -a -t f "$name.md" docs | rg -n "/ja/.*/plugin/$name\.md" || true)
if [ -z "$hits" ]; then
echo "MISSING: docs/ja/**/plugin/$name.md"
missing=$((missing+1))
else
echo "OK: $hits"
fi
done
test $missing -eq 0Length of output: 1150
缺少插件核心概念文档,存在 404 风险
请在 docs/ja/plugin 目录下确认并补充以下文件,或根据实际文件名更新侧边栏链接:
- docs/ja/plugin/structure.md
- docs/ja/plugin/mineJson.md
- docs/ja/plugin/configProvider.md
- docs/ja/plugin/lifecycle.md
🤖 Prompt for AI Agents
.in .vitepress/src/ja/sidebars.ts around lines 444 to 465, the sidebar
references four Japanese plugin docs that may not exist and therefore cause
404s; verify that
docs/ja/plugin/{structure.md,mineJson.md,configProvider.md,lifecycle.md} exist
and either create those Markdown files with appropriate content (or
redirects/TOC placeholders) or update the sidebar links to match the actual
filenames/paths; ensure filenames and link paths are exact (including case) and
run a local dev build to confirm no 404s.
| text:"💡 開発ガイド", | ||
| collapsed: false, | ||
| items: | ||
| [ | ||
| { | ||
| text:"🛠️ プラグイン開発ガイド", | ||
| link:"/plugin/develop" | ||
| }, | ||
| { | ||
| text:"📚 API リファレンスドキュメント", | ||
| link:"/plugin/api" | ||
| }, | ||
| { | ||
| text:"📝 サンプルコード", | ||
| link:"/plugin/examples" | ||
| } | ||
| ] | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
開発ガイド分組 LGTM,請校驗 develop/api/examples 是否存在
導航合理。請確認 docs/ja/plugin/ 下存在 develop.md、api.md、examples.md。
請運行:
🏁 Script executed:
#!/bin/bash
set -euo pipefail
expected=(develop api examples)
echo "Checking ja plugin development docs..."
missing=0
for name in "${expected[@]}"; do
hits=$(fd -a -t f "$name.md" docs | rg -n "/ja/.*/plugin/$name\.md" || true)
if [ -z "$hits" ]; then
echo "MISSING: docs/ja/**/plugin/$name.md"
missing=$((missing+1))
else
echo "OK: $hits"
fi
done
test $missing -eq 0Length of output: 836
缺少日语插件开发指南文档
在 docs/ja/plugin/ 目录下未找到以下文件,导致侧边栏链接无效:
- develop.md
- api.md
- examples.md
请补充对应文档文件或同步修改侧边栏路径以保证链接正确。
🤖 Prompt for AI Agents
In .vitepress/src/ja/sidebars.ts around lines 467 to 484, the sidebar references
Japanese plugin docs (/plugin/develop, /plugin/api, /plugin/examples) but the
corresponding files (docs/ja/plugin/develop.md, docs/ja/plugin/api.md,
docs/ja/plugin/examples.md) are missing, causing broken links; either add those
markdown files with the proper Japanese content at docs/ja/plugin/ or change the
sidebar links to point to existing files or translated paths, and ensure the
files are committed so the links resolve.
| { | ||
| text:"🛠️ 插件開發指南", | ||
| link:"/plugin/develop" | ||
| }, | ||
| { | ||
| text:"📚 API 參考文檔", | ||
| link:"/plugin/api" | ||
| }, | ||
| { | ||
| text:"📝 示例代碼", | ||
| link:"/plugin/examples" | ||
| } | ||
| ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
請校驗新增文檔鏈接在 zh-hk 語言包下是否存在
為避免 404,建議確認 docs/zh-hk/plugin 目錄下是否已存在 develop.md、api.md、examples.md 等對應頁面。
下面腳本將檢查常見目標文件是否存在於 zh-hk 語料目錄中(從倉庫根目錄執行):
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 需要存在的文檔文件名(不含路徑)
expected=(index guide structure mineJson configProvider lifecycle develop api examples)
echo "Checking zh-hk plugin docs..."
missing=0
for name in "${expected[@]}"; do
# 搜索 zh-hk 語料下的 plugin 目錄中是否存在對應 md 文件
hits=$(fd -a -t f "$name.md" docs | rg -n "/zh-hk/.*/plugin/$name\.md" || true)
if [ -z "$hits" ]; then
echo "MISSING: docs/zh-hk/**/plugin/$name.md"
missing=$((missing+1))
else
echo "OK: $hits"
fi
done
if [ $missing -gt 0 ]; then
echo "Total missing: $missing"
exit 1
else
echo "All zh-hk plugin docs found."
fiLength of output: 2404
请补充 zh-hk 语言包下 plugin 目录对应文档以避免 404
当前经验证,docs/zh-hk/plugin 目录下缺少侧边栏中引用的页面,新增链接会导致 404 错误。请在合适位置添加以下文件或调整侧边栏配置:
• docs/zh-hk/plugin/develop.md
• docs/zh-k plugin/api.md
• docs/zh-hk/plugin/examples.md
🤖 Prompt for AI Agents
.vitepress/src/zh-hk/sidebars.ts around lines 471-483: the sidebar references
three plugin pages but the corresponding files under docs/zh-hk/plugin are
missing causing 404s; fix by either (A) add the missing markdown files
docs/zh-hk/plugin/develop.md, docs/zh-hk/plugin/api.md, and
docs/zh-hk/plugin/examples.md with appropriate frontmatter and translated
content, or (B) if those pages are intentionally absent, remove or comment out
the three entries in this sidebar or change their links to existing pages;
ensure filenames and paths exactly match the sidebar links and that each new
file includes title/frontmatter so VitePress can render them.
| ### Plugin Uninstallation Error Codes | ||
|
|
||
| | Error Code | Description | Solution | | ||
| |------------|-------------|----------| | ||
| | 20001 | Plugin not installed | No need to uninstall | | ||
| | 20002 | Dependent plugins exist | Uninstall dependencies first or use force uninstall | | ||
| | 20003 | Uninstallation script execution failed | Check uninstallation script error logs | | ||
| | No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
“Plugin Uninstallation Error Codes” 表格未完整收尾
表格在行首 | 截断,缺失若干错误码行与结尾分隔线,影响可读性。
可按如下补全(示例):
-|
+| 20004 | File delete failed | Check file permissions |
+| 20005 | Uninstallation script not found | Ensure uninstall scripts exist and are executable |
+📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ### Plugin Uninstallation Error Codes | |
| | Error Code | Description | Solution | | |
| |------------|-------------|----------| | |
| | 20001 | Plugin not installed | No need to uninstall | | |
| | 20002 | Dependent plugins exist | Uninstall dependencies first or use force uninstall | | |
| | 20003 | Uninstallation script execution failed | Check uninstallation script error logs | | |
| | | |
| ### Plugin Uninstallation Error Codes | |
| | Error Code | Description | Solution | | |
| |------------|-------------|----------| | |
| | 20001 | Plugin not installed | No need to uninstall | | |
| | 20002 | Dependent plugins exist | Uninstall dependencies first or use force uninstall | | |
| | 20003 | Uninstallation script execution failed | Check uninstallation script error logs | | |
| | 20004 | File delete failed | Check file permissions | | |
| | 20005 | Uninstallation script not found | Ensure uninstall scripts exist and are executable | | |
🧰 Tools
🪛 LanguageTool
[grammar] ~740-~740: There might be a mistake here.
Context: ... | Error Code | Description | Solution | |------------|-------------|----------| ...
(QB_NEW_EN)
[grammar] ~741-~741: There might be a mistake here.
Context: ... |------------|-------------|----------| | 20001 | Plugin not installed | No need...
(QB_NEW_EN)
[grammar] ~742-~742: There might be a mistake here.
Context: ...n not installed | No need to uninstall | | 20002 | Dependent plugins exist | Unin...
(QB_NEW_EN)
[grammar] ~743-~743: There might be a mistake here.
Context: ...endencies first or use force uninstall | | 20003 | Uninstallation script executio...
(QB_NEW_EN)
🤖 Prompt for AI Agents
In docs/en/plugin/api.md around lines 738 to 745 the "Plugin Uninstallation
Error Codes" markdown table is truncated (there's a stray leading '|' and the
final separator/rows are missing), so restore the table by adding the missing
error-code rows and the closing table line(s), ensure each row uses the correct
pipe-separated columns (Error Code | Description | Solution), keep the header
separator (|---|---|---|) intact, and add a trailing newline after the table so
it renders correctly.
| ```php | ||
| <?php | ||
| declare(strict_types=1); | ||
|
|
||
| namespace Plugin\MineAdmin\CodeGenerator; | ||
|
|
||
| use Hyperf\Command\Concerns\InteractsWithIO; | ||
| use Hyperf\Context\ApplicationContext; | ||
| use Hyperf\Contract\ApplicationInterface; | ||
| use Mine\Helper\Filesystem; | ||
| use Symfony\Component\Console\Input\ArrayInput; | ||
| use Symfony\Component\Console\Output\ConsoleOutput; | ||
| use Symfony\Component\Console\Output\NullOutput; | ||
|
|
||
| class InstallScript | ||
| { | ||
| use InteractsWithIO; | ||
|
|
||
| public function __invoke() | ||
| { | ||
| // Set output | ||
| $this->output = new ConsoleOutput(); | ||
|
|
||
| try { | ||
| $this->info('========================================'); | ||
| $this->info('MineAdmin Code Generator Plugin'); | ||
| $this->info('========================================'); | ||
| $this->info('Starting plugin installation...'); | ||
|
|
||
| // 1. Copy template files | ||
| $this->copyTemplates(); | ||
|
|
||
| // 2. Copy language packs | ||
| $this->copyLanguages(); | ||
|
|
||
| // 3. Publish dependency resources | ||
| $this->publishVendor(); | ||
|
|
||
| // 4. Run database migrations | ||
| $this->runMigrations(); | ||
|
|
||
| $this->info('Plugin installed successfully!'); | ||
| $this->info('========================================'); | ||
|
|
||
| } catch (\Throwable $e) { | ||
| $this->error('Plugin installation failed: ' . $e->getMessage()); | ||
| throw $e; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Copy template files | ||
| */ | ||
| protected function copyTemplates(): void | ||
| { | ||
| $source = dirname(__DIR__) . '/publish/template'; | ||
| $target = BASE_PATH . '/runtime/generate/template'; | ||
|
|
||
| if (!is_dir($target)) { | ||
| mkdir($target, 0755, true); | ||
| } | ||
|
|
||
| Filesystem::copy($source, $target, false); | ||
| $this->info('Template files copied successfully'); | ||
| } | ||
|
|
||
| /** | ||
| * Copy language packs | ||
| */ | ||
| protected function copyLanguages(): void | ||
| { | ||
| $source = dirname(__DIR__) . '/languages'; | ||
| $target = BASE_PATH . '/storage/languages'; | ||
|
|
||
| Filesystem::copy($source, $target, false); | ||
| $this->info('Language packs copied successfully'); | ||
| } | ||
|
|
||
| /** | ||
| * Publish dependency resources | ||
| */ | ||
| protected function publishVendor(): void | ||
| { | ||
| $app = ApplicationContext::getContainer()->get(ApplicationInterface::class); | ||
| $app->setAutoExit(false); | ||
|
|
||
| $input = new ArrayInput([ | ||
| 'command' => 'vendor:publish', | ||
| 'package' => 'hyperf/translation', | ||
|
No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
文档在 InstallScript 片段处被截断,代码块未闭合
从 Line 653 起代码块未完整展示,读者无法复制运行,渲染也可能异常。请补全或删除未完成片段,并正确闭合代码围栏。
如果你提供完整段落(或原始文件链接),我可以帮你补齐并在 EN/JA/ZH 版本间做一致性对齐。
🤖 Prompt for AI Agents
docs/en/plugin/develop.md around lines 564 to 653: the InstallScript code block
is truncated and the fenced code block is not closed, breaking rendering and
preventing readers from copying the full install script; restore the missing
portion or remove the incomplete block and properly close the triple-backtick
fence. If you have the original file, paste the remaining PHP code to complete
the class (ensure the final ArrayInput array and subsequent command execution,
closing braces, and the ending ``` are present) or delete the incomplete snippet
and replace it with a short note plus a link to the full script, then verify
EN/JA/ZH docs have the same corrected change.
| public function login(array $credentials): bool | ||
| { | ||
| // 登入前鉤子 | ||
| HookManager::trigger('user.login.before', $user); | ||
|
|
||
| // 執行登入邏輯 | ||
| $result = $this->authenticate($credentials); | ||
|
|
||
| if ($result) { | ||
| // 登入後鉤子 | ||
| HookManager::trigger('user.login.after', $user); | ||
| } | ||
|
|
||
| return $result; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Hook 示例中 $user 未定义,代码不可运行
UserService::login() 中在认证前/后触发 Hook 时传入了 $user,但该变量未定义。建议根据实际设计修正参数来源:
- 方案 A:登录前传入
$credentials,登录后传入当前用户对象
- HookManager::trigger('user.login.before', $user);
+ HookManager::trigger('user.login.before', $credentials);
@@
- if ($result) {
- // 登入後鉤子
- HookManager::trigger('user.login.after', $user);
- }
+ if ($result) {
+ // 登入後鉤子
+ HookManager::trigger('user.login.after', $this->getCurrentUser());
+ }(getCurrentUser() 代表实际获取当前用户的方法,请替换为项目真实实现)
- 方案 B:让
authenticate()返回用户对象,基于是否为 null 判断登录是否成功,并传入该对象。
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| public function login(array $credentials): bool | |
| { | |
| // 登入前鉤子 | |
| HookManager::trigger('user.login.before', $user); | |
| // 執行登入邏輯 | |
| $result = $this->authenticate($credentials); | |
| if ($result) { | |
| // 登入後鉤子 | |
| HookManager::trigger('user.login.after', $user); | |
| } | |
| return $result; | |
| } | |
| public function login(array $credentials): bool | |
| { | |
| // 登入前鉤子 | |
| HookManager::trigger('user.login.before', $credentials); | |
| // 執行登入邏輯 | |
| $result = $this->authenticate($credentials); | |
| if ($result) { | |
| // 登入後鉤子 | |
| HookManager::trigger('user.login.after', $this->getCurrentUser()); | |
| } | |
| return $result; | |
| } |
🤖 Prompt for AI Agents
In docs/zh-tw/plugin/api.md around lines 609 to 623, the Hook example calls
HookManager::trigger('user.login.before', $user) and
HookManager::trigger('user.login.after', $user') but $user is not defined; fix
by either (A) passing $credentials to the before hook and the actual user object
to the after hook (retrieve current user via the project’s real getCurrentUser()
method) or (B) change authenticate() to return the user object (or null) and use
that return value to determine success and pass the user to both hooks (before
can receive credentials or null), updating the trigger arguments accordingly.
| #[PostMapping('/create')] | ||
| public function create(): array | ||
| { | ||
| $data = $this->request->all(); | ||
| $result = $this->service->create($data); | ||
| return $this->success($result, '建立成功'); | ||
| } | ||
| $user = $this->userService->find($id); | ||
|
|
||
| if (!$user) { | ||
| return $this->error('使用者不存在', 404); | ||
| } | ||
|
|
||
| return $this->success($user); | ||
| } | ||
|
|
||
| /** | ||
| * 更新使用者 | ||
| */ | ||
| #[PutMapping('/users/{id:\d+}')] | ||
| public function update(int $id): array | ||
| { | ||
| $data = $this->request->all(); | ||
|
|
||
| $user = $this->userService->update($id, $data); | ||
|
|
||
| return $this->success($user, '使用者更新成功'); | ||
| } | ||
|
|
||
| /** | ||
| * 刪除使用者 | ||
| */ | ||
| #[DeleteMapping('/users/{id:\d+}')] | ||
| public function destroy(int $id): array | ||
| { | ||
| $this->userService->delete($id); | ||
|
|
||
| return $this->success([], '使用者刪除成功'); | ||
| } | ||
|
|
||
| /** | ||
| * 批次匯入使用者 | ||
| */ | ||
| #[PostMapping('/users/import')] | ||
| public function import(): array | ||
| { | ||
| $file = $this->request->file('file'); | ||
|
|
||
| if (!$file || !$file->isValid()) { | ||
| return $this->error('請上傳有效的檔案'); | ||
| } | ||
|
|
||
| $result = $this->userService->importFromFile($file); | ||
|
|
||
| return $this->success($result, '匯入完成'); | ||
| } | ||
|
|
||
| /** | ||
| * 匯出使用者資料 | ||
| */ | ||
| #[GetMapping('/users/export')] | ||
| public function export(): array | ||
| { | ||
| $params = $this->request->all(); | ||
| $filePath = $this->userService->exportToFile($params); | ||
|
|
||
| return $this->success(['file_path' => $filePath], '匯出成功'); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PHP 控制器示例存在语法与逻辑错误(方法体缺失/未定义属性)
在 ExampleController 示例中:
- Line 415-423 的代码段未置于任何方法体内,属于游离语句,导致语法错误。
- 多处使用
$this->userService,但类构造函数仅注入了$this->service,将造成未定义属性错误。
建议:
- 将游离语句重构为一个独立的 show 动作方法。
- 将所有
$this->userService替换为$this->service以与构造注入保持一致。
参考修复:
@@
public function create(): array
{
$data = $this->request->all();
$result = $this->service->create($data);
return $this->success($result, '建立成功');
}
+ #[GetMapping('/users/{id:\d+}')]
+ public function show(int $id): array
+ {
+ $user = $this->service->find($id);
+ if (!$user) {
+ return $this->error('使用者不存在', 404);
+ }
+ return $this->success($user);
+ }
@@
- $user = $this->userService->update($id, $data);
+ $user = $this->service->update($id, $data);
@@
- $this->userService->delete($id);
+ $this->service->delete($id);
@@
- $result = $this->userService->importFromFile($file);
+ $result = $this->service->importFromFile($file);
@@
- $filePath = $this->userService->exportToFile($params);
+ $filePath = $this->service->exportToFile($params);Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
docs/zh-tw/plugin/examples.md around lines 408 to 476: the snippet contains
stray statements (lines ~415-423) that are not inside any method and will cause
a PHP syntax error, and the class uses $this->userService while the constructor
only injects $this->service causing undefined property errors; move the stray
block into a new show(int $id): array method (or appropriate controller action)
and replace all occurrences of $this->userService with $this->service so they
match the injected property, ensuring method signature, return type, and
request/ID handling follow the surrounding controller patterns.
| .table-card { | ||
| .table-header { | ||
| display: flex; | ||
| justify-content: space-between; | ||
| align-items: center; | ||
| margin-bottom: 20px; | ||
| } | ||
|
|
||
| .pagination-wrapper { | ||
| margin-top: 20px; | ||
| text-align: right; | ||
| } | ||
| } | ||
| </style> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
<style scoped> 使用了嵌套选择器,原生 CSS 无法解析
.table-card 内部使用了嵌套写法(仅 SCSS/LESS 支持),在原生 CSS 下无效。两种修复方式:
- 方式 A(不引入预处理器,推荐):展开为普通选择器
-.table-card {
- .table-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 20px;
- }
-
- .pagination-wrapper {
- margin-top: 20px;
- text-align: right;
- }
-}
+.table-card .table-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 20px;
+}
+
+.table-card .pagination-wrapper {
+ margin-top: 20px;
+ text-align: right;
+}- 方式 B(若项目已启用 SCSS):将
<style scoped>改为<style scoped lang="scss">
(此修改发生在 Line 1099,需同步变更)
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| .table-card { | |
| .table-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 20px; | |
| } | |
| .pagination-wrapper { | |
| margin-top: 20px; | |
| text-align: right; | |
| } | |
| } | |
| </style> | |
| .table-card .table-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 20px; | |
| } | |
| .table-card .pagination-wrapper { | |
| margin-top: 20px; | |
| text-align: right; | |
| } | |
| </style> |
🤖 Prompt for AI Agents
In docs/zh-tw/plugin/examples.md around lines 1108 to 1121 there is a CSS block
using nested selectors (e.g., .table-card { .table-header { ... } }) which
native CSS does not support; fix by either (A) expanding the nested rules into
flat selectors like .table-card .table-header { ... } and .table-card
.pagination-wrapper { ... } so the style block remains <style scoped>, or (B) if
the project uses SCSS, change the style tag at line 1099 from <style scoped> to
<style scoped lang="scss"> so the nested syntax is parsed correctly—apply one of
these two fixes and ensure the corresponding line 1099 change is made if
choosing option B.
| protected function dropTables(): void | ||
| { | ||
| // 刪除外掛建立的資料表 | ||
| $tables = ['plugin_example_table', 'plugin_settings']; | ||
|
|
||
| foreach ($tables as $table) { | ||
| if (Db::schema()->hasTable($table)) { | ||
| Db::schema()->drop($table); | ||
| echo "已刪除資料表: {$table}\n"; | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
使用 Hyperf Schema Facade 进行表存在检测与删除,避免 Db::schema() 误用
Db::schema() 在 Hyperf 中并非推荐用法,建议改为 Schema。同时使用 dropIfExists 更安全。
- // 刪除外掛建立的資料表
- $tables = ['plugin_example_table', 'plugin_settings'];
-
- foreach ($tables as $table) {
- if (Db::schema()->hasTable($table)) {
- Db::schema()->drop($table);
- echo "已刪除資料表: {$table}\n";
- }
- }
+ // 刪除外掛建立的資料表
+ $tables = ['plugin_example_table', 'plugin_settings'];
+
+ foreach ($tables as $table) {
+ if (\Hyperf\Database\Schema\Schema::hasTable($table)) {
+ \Hyperf\Database\Schema\Schema::dropIfExists($table);
+ echo "已刪除資料表: {$table}\n";
+ }
+ }如需更完整示例,也可在代码块顶部补充:
use Hyperf\Database\Schema\Schema;🤖 Prompt for AI Agents
docs/zh-tw/plugin/structure.md around lines 295 to 306: the code uses
Db::schema() to check and drop tables which is not the recommended Hyperf API;
replace Db::schema()->hasTable(...) and Db::schema()->drop(...) with the Schema
facade methods and a safer dropIfExists, i.e. add at the top `use
Hyperf\Database\Schema\Schema;` and change the loop to call
Schema::hasTable($table) and Schema::dropIfExists($table) so existence-check and
deletion use the Schema facade and avoid potential misuse of Db::schema().
| protected function clearCache(): void | ||
| { | ||
| // 清理外掛相關快取 | ||
| $redis = \Hyperf\Context\ApplicationContext::getContainer() | ||
| ->get(\Hyperf\Redis\Redis::class); | ||
|
|
||
| $redis->del('plugin:cache:*'); | ||
| echo "快取已清理\n"; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
修正 Redis 清理逻辑:DEL 不支持通配符,需通过 SCAN 遍历删除
当前示例使用 del('plugin:cache:*') 只能删除同名键(不会匹配通配符)。建议改用 SCAN 批量删除,避免阻塞和误导。
- $redis->del('plugin:cache:*');
- echo "快取已清理\n";
+ $pattern = 'plugin:cache:*';
+ $iterator = null;
+ do {
+ $keys = $redis->scan($iterator, $pattern, 1000);
+ if ($keys && is_array($keys)) {
+ // 逐个删除,避免一次性 DEL 过多键
+ foreach ($keys as $k) {
+ $redis->del($k);
+ }
+ }
+ } while ($iterator !== 0 && $iterator !== '0');
+ echo "快取已清理\n";📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| protected function clearCache(): void | |
| { | |
| // 清理外掛相關快取 | |
| $redis = \Hyperf\Context\ApplicationContext::getContainer() | |
| ->get(\Hyperf\Redis\Redis::class); | |
| $redis->del('plugin:cache:*'); | |
| echo "快取已清理\n"; | |
| } | |
| protected function clearCache(): void | |
| { | |
| // 清理外掛相關快取 | |
| $redis = \Hyperf\Context\ApplicationContext::getContainer() | |
| ->get(\Hyperf\Redis\Redis::class); | |
| $pattern = 'plugin:cache:*'; | |
| $iterator = null; | |
| do { | |
| $keys = $redis->scan($iterator, $pattern, 1000); | |
| if ($keys && is_array($keys)) { | |
| // 逐个删除,避免一次性 DEL 过多键 | |
| foreach ($keys as $k) { | |
| $redis->del($k); | |
| } | |
| } | |
| } while ($iterator !== 0 && $iterator !== '0'); | |
| echo "快取已清理\n"; | |
| } |
🤖 Prompt for AI Agents
In docs/zh-tw/plugin/structure.md around lines 318 to 326, the Redis cache-clear
example wrongly calls del('plugin:cache:*') which does not support wildcards;
replace it with a SCAN-based loop that iterates keys matching "plugin:cache:*"
using the cursor, collect keys in reasonable-sized batches, and delete them
(prefer UNLINK if available) using pipelined/batched del/unlink calls to avoid
blocking the server and ensure all matching keys are removed.
…or handling
Summary by CodeRabbit
新功能
样式
配置(Chores)
文档