初始化本地仓库
This commit is contained in:
@@ -0,0 +1,480 @@
|
||||
---
|
||||
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,并说明更新内容。
|
||||
Reference in New Issue
Block a user