15 KiB
name, description, globs
| name | description | globs | ||||||
|---|---|---|---|---|---|---|---|---|
| cross-plugin-web-development | Madong 插件 Web 端开发规范,覆盖 Web 模板源、运行目录同步、页面路由、Web 菜单、API、认证、Element Plus 页面实现、验证与重装防回退。 |
|
Madong 插件 Web 端开发技能
用于开发和维护插件的 Web 前台功能。重点解决 Web 页面模板源、安装复制、插件路由、Web 菜单、API 调用和卸载重装后的防回退问题。
适用场景
- 为已有 Madong 插件增加 Web 页面。
- 将移动端或后台已有业务迁移为 Web 页面。
- 为插件补齐 Web API、路由和 Web 菜单。
- 修复插件卸载重装后 Web 页面、路由或菜单回退。
- 维护插件 Web 模板源与安装后的 Web 运行目录一致性。
总原则
- 先核对项目真实实现,再编写或修改 Web 插件代码。
- 插件 Web 的权威模板源是
backend/plugin/{plugin}/resource/template/web。 - 安装后的 Web 运行目录是
frontend/web/app/apps/{plugin},属于模板复制产物。 - 正式修改优先落在模板源,完成后再同步到 Web 运行目录。
- 页面、API、路由、菜单和后端接口的路径必须一致。
- 优先复用当前项目的
~/utils/request、Element Plus、Pinia 和既有页面风格,不直接照搬移动端 UI。 - 先解决业务根因,不通过页面层伪造数据或绕过后端校验。
- 不删除未经确认的内容;新增页面时不要覆盖已有业务页面。
目录与复制关系
模板源
backend/plugin/{plugin}/resource/template/web/
├── api/
│ ├── data-entry.ts
│ └── exception.ts
├── pages/
│ ├── routes.ts
│ └── {module}/
│ ├── index.vue
│ ├── tasks.vue
│ └── components/
└── .gitkeep
安装后的运行目录
frontend/web/app/apps/{plugin}/
├── api/
├── pages/
│ ├── routes.ts
│ └── {module}/
└── ...
当前项目的实际对应关系:
backend/plugin/produce/resource/template/web/
frontend/web/app/apps/produce/
修改 Web 插件时,必须核对以下文件是否同步:
api/**/*.tspages/**/*.vuepages/routes.ts- 页面使用的组件和辅助文件
开发前检查
开始开发前至少核对:
- 插件名和 Web 运行目录:
frontend/web/app/apps/{plugin}。 - 模板源是否存在:
backend/plugin/{plugin}/resource/template/web。 - Web 主应用是否通过
router.options.ts加载插件路由。 - 后端接口的真实路径、请求方法、参数和响应结构。
- 登录用户信息来源和认证请求头。
resource/menu/web.php的真实菜单字段格式。- 可参考的 Web 页面,例如:
frontend/web/app/apps/produce/pages/data-entry/index.vuefrontend/web/app/apps/produce/pages/data-entry/components/OrderEntryPanel.vue
- 移动端页面仅作为业务流程参考,不作为 Web 布局和组件规范来源。
Web 路由规范
1. 插件路由入口
当前 Web 主应用通过以下方式加载插件路由:
frontend/web/app/router.options.ts
该文件使用 import.meta.glob('~/apps/**/pages/routes.ts', { eager: true }) 加载插件路由。因此插件页面应在以下文件注册:
backend/plugin/{plugin}/resource/template/web/pages/routes.ts
frontend/web/app/apps/{plugin}/pages/routes.ts
2. 路由写法
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 菜单文件:
backend/plugin/{plugin}/resource/menu/web.php
Web 菜单不是 Admin 菜单,不能直接复制 resource/menu/admin.php 的结构。当前项目 Web 菜单使用记录数组,例如:
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 正式放在模板源:
backend/plugin/{plugin}/resource/template/web/api/
运行目录对应:
frontend/web/app/apps/{plugin}/api/
当前项目的实际写法是业务 API 直接放在插件目录,例如:
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 类型
应根据后端真实返回结构定义接口,例如:
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. 页面结构
建议结构:
<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. 图片上传
推荐流程:
- 使用
el-upload设置:auto-upload="false"。 - 读取
UploadUserFile.raw。 - 调用插件 API 的上传方法。
- 将返回的 URL 放入业务提交参数。
- 限制文件类型、数量和必要的大小。
- 上传失败时停止提交并保留用户选择,方便重试。
模板源优先与同步流程
标准流程:
- 核对插件后端接口和业务返回结构。
- 在
backend/plugin/{plugin}/resource/template/web中创建或修改 Web API。 - 在模板源中创建或修改页面及页面组件。
- 在模板源
pages/routes.ts注册路由。 - 在
resource/menu/web.php增加或更新 Web 菜单。 - 核对模板源文件之间的导入路径和路由路径。
- 将模板源同步到
frontend/web/app/apps/{plugin}。 - 核对模板源与运行目录内容一致。
- 启动 Web 端,验证菜单、路由、页面和接口。
- 如菜单由安装流程导入,重新安装或执行项目规定的菜单刷新流程后再验证菜单。
禁止只修改以下运行目录而不更新模板源:
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
排查顺序:
- 页面文件是否位于
frontend/web/app/apps/{plugin}/pages。 - 插件
pages/routes.ts是否存在。 router.options.ts是否仍使用插件路由 glob。- 路由
path是否与访问地址一致。 - import 路径大小写是否正确。
- 模板源和运行目录是否都包含该页面。
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,并说明更新内容。