Files
MrleeAdmin/.windsurf/skills/cross-plugin-web-development/SKILL.md
T
2026-08-31 11:33:59 +08:00

481 lines
15 KiB
Markdown

---
name: cross-plugin-web-development
description: Madong 插件 Web 端开发规范,覆盖 Web 模板源、运行目录同步、页面路由、Web 菜单、API、认证、Element Plus 页面实现、验证与重装防回退。
globs:
- "backend/plugin/**/resource/menu/web.php"
- "backend/plugin/**/resource/template/web/**/*"
- "frontend/web/app/apps/**/pages/**/*.vue"
- "frontend/web/app/apps/**/api/**/*.ts"
- "frontend/web/app/apps/**/pages/routes.ts"
- ".windsurf/skills/**/*.md"
---
# Madong 插件 Web 端开发技能
用于开发和维护插件的 Web 前台功能。重点解决 Web 页面模板源、安装复制、插件路由、Web 菜单、API 调用和卸载重装后的防回退问题。
## 适用场景
- 为已有 Madong 插件增加 Web 页面。
- 将移动端或后台已有业务迁移为 Web 页面。
- 为插件补齐 Web API、路由和 Web 菜单。
- 修复插件卸载重装后 Web 页面、路由或菜单回退。
- 维护插件 Web 模板源与安装后的 Web 运行目录一致性。
## 总原则
1. 先核对项目真实实现,再编写或修改 Web 插件代码。
2. 插件 Web 的权威模板源是 `backend/plugin/{plugin}/resource/template/web`。
3. 安装后的 Web 运行目录是 `frontend/web/app/apps/{plugin}`,属于模板复制产物。
4. 正式修改优先落在模板源,完成后再同步到 Web 运行目录。
5. 页面、API、路由、菜单和后端接口的路径必须一致。
6. 优先复用当前项目的 `~/utils/request`、Element Plus、Pinia 和既有页面风格,不直接照搬移动端 UI。
7. 先解决业务根因,不通过页面层伪造数据或绕过后端校验。
8. 不删除未经确认的内容;新增页面时不要覆盖已有业务页面。
## 目录与复制关系
### 模板源
```text
backend/plugin/{plugin}/resource/template/web/
├── api/
│ ├── data-entry.ts
│ └── exception.ts
├── pages/
│ ├── routes.ts
│ └── {module}/
│ ├── index.vue
│ ├── tasks.vue
│ └── components/
└── .gitkeep
```
### 安装后的运行目录
```text
frontend/web/app/apps/{plugin}/
├── api/
├── pages/
│ ├── routes.ts
│ └── {module}/
└── ...
```
当前项目的实际对应关系:
```text
backend/plugin/produce/resource/template/web/
frontend/web/app/apps/produce/
```
修改 Web 插件时,必须核对以下文件是否同步:
- `api/**/*.ts`
- `pages/**/*.vue`
- `pages/routes.ts`
- 页面使用的组件和辅助文件
## 开发前检查
开始开发前至少核对:
1. 插件名和 Web 运行目录:`frontend/web/app/apps/{plugin}`。
2. 模板源是否存在:`backend/plugin/{plugin}/resource/template/web`。
3. Web 主应用是否通过 `router.options.ts` 加载插件路由。
4. 后端接口的真实路径、请求方法、参数和响应结构。
5. 登录用户信息来源和认证请求头。
6. `resource/menu/web.php` 的真实菜单字段格式。
7. 可参考的 Web 页面,例如:
- `frontend/web/app/apps/produce/pages/data-entry/index.vue`
- `frontend/web/app/apps/produce/pages/data-entry/components/OrderEntryPanel.vue`
8. 移动端页面仅作为业务流程参考,不作为 Web 布局和组件规范来源。
## Web 路由规范
### 1. 插件路由入口
当前 Web 主应用通过以下方式加载插件路由:
```text
frontend/web/app/router.options.ts
```
该文件使用 `import.meta.glob('~/apps/**/pages/routes.ts', { eager: true })` 加载插件路由。因此插件页面应在以下文件注册:
```text
backend/plugin/{plugin}/resource/template/web/pages/routes.ts
frontend/web/app/apps/{plugin}/pages/routes.ts
```
### 2. 路由写法
```typescript
export default [
{
path: '/{plugin}/{module}',
component: () => import('~/apps/{plugin}/pages/{module}/index.vue'),
meta: {
title: '页面标题',
layout: 'default',
},
},
]
```
要求:
- 页面路径使用业务语义,保持与 Web 菜单 URL 一致。
- 组件路径使用 `~/apps/{plugin}/pages/...`。
- 默认使用 `layout: 'default'`,除非已核对项目存在其他布局。
- 一个页面只能注册一次,避免主站路由和插件路由重复。
- 带参数页面使用 Nuxt 约定的 `[param].vue`,但当前插件也可按项目路由表显式注册页面。
### 3. 认证与权限
Web 路由是否需要登录由当前项目权限中间件和路由元信息共同决定。涉及用户数据、异常提报、维修提交等业务时:
- 页面必须使用真实的登录用户信息。
- 不要在前端硬编码用户工号作为提交值。
- 需要登录的页面应按当前项目实际权限配置 `meta.permissions`,先核对现有菜单和中间件实现。
- 如果后端接口本身标记为公共接口,也不能因此在页面中跳过业务必填校验。
## Web 菜单规范
### 1. 菜单文件
插件 Web 菜单文件:
```text
backend/plugin/{plugin}/resource/menu/web.php
```
Web 菜单不是 Admin 菜单,不能直接复制 `resource/menu/admin.php` 的结构。当前项目 Web 菜单使用记录数组,例如:
```php
return [
[
'app' => 'web',
'category' => 1,
'source' => 'plugin',
'code' => null,
'name' => '业务页面',
'url' => '/{plugin}/{module}',
'icon' => 'ri:apps-line',
'level' => 1,
'type' => 2,
'sort' => 10,
'target' => 1,
'is_show' => 1,
'enabled' => 1,
'created_at' => time(),
'updated_at' => time(),
'deleted_at' => null,
],
];
```
字段要求以当前项目和菜单导入实现为准,至少核对:`app`、`source`、`name`、`url`、`type`、`sort`、`is_show`、`enabled`。
### 2. 菜单与路由一致
新增 Web 页面时必须同时检查:
- `resource/menu/web.php` 是否有对应菜单。
- 菜单 `url` 是否等于路由 `path`。
- 路由组件是否真实存在。
- 菜单是否需要显示为一级菜单或子菜单。
- 图标是否使用项目已有图标格式。
不要只添加路由而不添加菜单,也不要只添加菜单而不注册路由。
### 3. 菜单安装行为
菜单通常在插件安装时导入系统菜单。修改 `resource/menu/web.php` 后,当前数据库中已存在的菜单不一定会自动刷新。验证菜单时应区分:
- 文件配置是否正确。
- 安装导入后的系统菜单是否已更新。
- 当前用户是否有访问该菜单的权限。
不要通过前端硬编码菜单代替插件菜单导入机制。
## Web API 规范
### 1. API 文件位置
插件 Web API 正式放在模板源:
```text
backend/plugin/{plugin}/resource/template/web/api/
```
运行目录对应:
```text
frontend/web/app/apps/{plugin}/api/
```
当前项目的实际写法是业务 API 直接放在插件目录,例如:
```typescript
import request from '~/utils/request'
export function getExampleList(params: Record<string, unknown> = {}) {
return request.get('/{plugin}/{resource}', params)
}
```
### 2. 请求约定
- 使用 `~/utils/request`,不要在业务 API 中直接调用 axios 或 fetch。
- 传入后端业务路径,例如 `/produce/process`,不要手动拼接 `/api/`。
- GET 参数作为第二个参数传入。
- POST 数据作为第二个参数传入。
- 默认响应已经解包为 `data`。
- 只有确实需要状态码、消息或完整响应时,才使用 `returnFullResponse: true`。
- 上传使用 `request.upload` 和 `FormData`,统一由 API 层封装。
- API 层负责类型声明、路径和参数;页面负责交互状态和展示。
- 错误提示优先使用请求层统一处理,页面避免重复弹出相同错误。
### 3. API 类型
应根据后端真实返回结构定义接口,例如:
```typescript
export interface ExampleItem {
id: string | number
name?: string
status?: number
}
export function getExampleDetail(id: string | number) {
return request.get<ExampleItem>(`/example/${id}`)
}
```
列表接口要确认返回的是数组还是 `{ items, total }`,不能凭页面名称猜测。
### 4. API 与页面解耦
页面中不要重复实现:
- 基础 URL 拼接。
- Authorization 认证头。
- 响应解包。
- 上传认证。
- 通用错误弹窗。
如果多个页面共享业务请求,应提取到插件 Web API 文件,而不是复制请求代码。
## 页面开发规范
### 1. 技术栈
当前项目 Web 端使用:
- Vue 3 `<script setup lang="ts">`。
- Nuxt 4。
- Element Plus。
- Pinia。
- 当前项目已有的 SCSS / CSS 变量和布局。
### 2. 页面结构
建议结构:
```vue
<template>
<div class="produce-work-page">
<div class="page-shell">
<section class="page-hero">...</section>
<div class="content-grid">
<main class="main-column">...</main>
<aside class="side-column">...</aside>
</div>
</div>
</div>
</template>
```
要求:
- 页面应适配 `layouts/default.vue` 的滚动区域。
- 页面主体避免依赖移动端 `view`、`text`、`u-*` 组件。
- Web 页面使用 `div`、`button`、Element Plus 组件和原生表单语义。
- 页面需要考虑 1440px、1024px、768px 等宽度下的响应式布局。
- 重要操作按钮必须有 loading、禁用或重复提交保护。
- 空数据、加载中、提交失败和成功状态要有明确反馈。
- 不要为了追求视觉效果引入项目没有使用的新 UI 框架。
### 3. 业务迁移
从移动端迁移时:
- 保留业务流程、校验规则、接口参数和状态含义。
- 将 `u-popup` 改为 `el-dialog`、`el-drawer`、`el-select` 或页面内面板。
- 将 `u-input` 改为 `el-input`。
- 将 `u-button` 或自绘点击区域改为 `el-button` 或符合语义的按钮。
- 将移动端图片选择改为 `el-upload`,上传由 API 层完成。
- 将 `uni.showToast` 改为 `ElMessage` 或 `ElNotification`。
- 将移动端本地用户信息读取改为 `useMemberStore()`,但要以当前项目真实 Store 结构为准。
- 不要把移动端的 `uni`、`rpx`、原生扫码插件直接带入 Web 页面。
### 4. 图片上传
推荐流程:
1. 使用 `el-upload` 设置 `:auto-upload="false"`。
2. 读取 `UploadUserFile.raw`。
3. 调用插件 API 的上传方法。
4. 将返回的 URL 放入业务提交参数。
5. 限制文件类型、数量和必要的大小。
6. 上传失败时停止提交并保留用户选择,方便重试。
## 模板源优先与同步流程
标准流程:
1. 核对插件后端接口和业务返回结构。
2. 在 `backend/plugin/{plugin}/resource/template/web` 中创建或修改 Web API。
3. 在模板源中创建或修改页面及页面组件。
4. 在模板源 `pages/routes.ts` 注册路由。
5. 在 `resource/menu/web.php` 增加或更新 Web 菜单。
6. 核对模板源文件之间的导入路径和路由路径。
7. 将模板源同步到 `frontend/web/app/apps/{plugin}`。
8. 核对模板源与运行目录内容一致。
9. 启动 Web 端,验证菜单、路由、页面和接口。
10. 如菜单由安装流程导入,重新安装或执行项目规定的菜单刷新流程后再验证菜单。
禁止只修改以下运行目录而不更新模板源:
```text
frontend/web/app/apps/{plugin}
```
## 验证清单
### 文件与同步
- [ ] 模板源 Web API 存在。
- [ ] 模板源页面存在。
- [ ] 模板源 `pages/routes.ts` 已注册。
- [ ] `resource/menu/web.php` 已配置对应菜单。
- [ ] 运行目录已同步。
- [ ] 模板源与运行目录文件内容一致。
### 页面与交互
- [ ] 页面使用 Web 组件,不包含移动端 `uni`、`u-*`、`rpx`。
- [ ] 加载、空数据、错误和提交状态完整。
- [ ] 提交按钮有重复提交保护。
- [ ] 关键字段有前端校验,后端校验仍然保留。
- [ ] 用户信息来自真实 Store 或当前项目认证机制。
- [ ] 页面在窄屏下仍可用。
### API
- [ ] API 使用 `~/utils/request`。
- [ ] 请求路径未重复拼接 `/api/`。
- [ ] 请求方法、参数名称和响应结构与后端一致。
- [ ] 文件上传通过 API 层完成。
- [ ] 错误提示没有重复弹出。
### 路由与菜单
- [ ] 菜单 URL 与路由 path 一致。
- [ ] 路由 component 路径真实存在。
- [ ] 菜单排序、图标、显示状态符合项目实际格式。
- [ ] 菜单导入后的系统数据已经刷新或重新安装验证。
### 构建与运行
- [ ] Web 端定向 ESLint 检查通过,或已区分本次新增问题与项目历史问题。
- [ ] Web 端类型检查通过,或已记录项目历史类型错误。
- [ ] 页面可以正常打开。
- [ ] API 请求返回预期数据。
- [ ] 提交、上传、跳转和返回流程正常。
## 防回退规则
卸载重装插件会重新从模板源复制 Web 文件。以下情况会导致回退:
- 只修改了 `frontend/web/app/apps/{plugin}`。
- 模板源缺少新增页面或 API。
- 模板源 `pages/routes.ts` 没有同步。
- `resource/menu/web.php` 没有同步。
- 运行目录临时修复后没有回写模板源。
最终交付必须同时满足:
- 模板源版本正确。
- Web 运行目录版本正确。
- 路由和菜单版本正确。
- 重新安装插件后页面不会回退。
## 常见问题
### 1. 页面 404
排查顺序:
1. 页面文件是否位于 `frontend/web/app/apps/{plugin}/pages`。
2. 插件 `pages/routes.ts` 是否存在。
3. `router.options.ts` 是否仍使用插件路由 glob。
4. 路由 `path` 是否与访问地址一致。
5. import 路径大小写是否正确。
6. 模板源和运行目录是否都包含该页面。
### 2. 菜单不显示
排查:
- `resource/menu/web.php` 是否新增记录。
- `app` 是否为 `web`。
- `enabled`、`is_show` 是否启用。
- 菜单是否已重新导入系统表。
- 当前登录用户是否具备对应菜单访问权限。
### 3. 页面打开但请求 404
常见原因:
- API 路径多拼了 `/api/`。
- 请求路径与后端控制器路由不一致。
- 后端插件未加载或运行进程未重载。
- API 文件只同步到了运行目录,重装后被旧模板覆盖。
### 4. 模板源文件出现模块找不到
模板源不一定是主 Web 项目的 TypeScript 编译入口。若编辑器提示 `vue`、`element-plus`、`~/stores/member` 或 `~/apps/{plugin}/api` 找不到,先确认运行目录中的同一文件可以解析,再区分编辑器静态提示和真实构建错误。
### 5. 页面使用了公共接口但无法提交
公共接口不等于无需业务校验。应继续检查:
- 当前用户工号是否存在。
- 必填字段是否完整。
- 业务状态是否允许操作。
- 后端是否要求先校验订单或维修任务。
### 6. Windows 下模板修改未生效
如果修改模板源、菜单、安装逻辑后运行结果仍是旧版本:
- 确认 Webman 进程是否已重新加载插件代码。
- 确认插件安装流程是否重新复制模板。
- 确认菜单数据是否重新导入。
- 不要只根据浏览器缓存判断模板是否更新。
## 输出契约
完成一个插件 Web 功能时,至少交付:
- Web API 模板源。
- Web 页面模板源。
- 插件 Web 路由模板源。
- `resource/menu/web.php` 菜单配置。
- 同步后的 `frontend/web/app/apps/{plugin}` 运行目录。
- 页面、接口、菜单和路由一致性验证。
- 构建或定向检查结果。
- 如发现既有 Web skill 与项目真实实现不一致,应同步更新对应 skill,并说明更新内容。