newlifex/newlife.cube/cube-add-page

Claude Code and agent skill by newlifex/newlife.cube

Trust tier 2
  • community
LLM review pending
Source check pending

Checking that the SKILL.md file is still in the repository.

根据后端 NewLife.Cube 控制器定义,在前端项目创建页面组件。当用户说"新增页面"、"创建页面"、"添加功能页面"、"给 XX 模块加页面"时使用。

Install

npx vskill@latest install newlifex/newlife.cube/cube-add-page

SKILL.md

cube-add-page

Cube 前端新增页面技能。根据后端控制器定义,在前端对应应用目录创建页面组件,并配置菜单图标、列表展示字段等。

核心原则

只需创建页面组件文件,不需要关心页面如何注册和渲染。
本框架会自动加载页面、自动注册路由,无需手工配置。

技能触发

当需要新增或修改前端页面时使用,例如:

  • 后端已有 Controller,前端需要创建对应页面
  • 需要配置菜单图标、列表展示字段
  • 需要自定义列表页或表单页的行为

前置条件

  1. 应用是否存在:先查看前端 apps/ 目录,按「页面目录结构」判断该区域是独立成应用(情形 B)还是归在某个综合 app 下(情形 A),确认目标 app 目录已存在
  2. 若应用未创建:先调用 cube-add-app 技能创建应用
  3. 若控制器未创建:先基于 Model 实体创建 Controller

输入参数

参数说明示例
controllerName控制器名称(PascalCase)Product, Device, Alarm
area业务区域(与后端 Area 名一致)Basic, Device, Demo
entityName实体名称(可选,默认同 controllerName)Product
menuIcon菜单图标(Element Plus 图标名)Files, Setting, User
listFields列表页要展示的字段数组(可选,默认全部)["Id", "Name", "Code", "Enable"]
detailUrl详情页 URL 模板(可选)"/{area}/{controller}/Detail?id={Id}"

页面目录结构

页面位置由后端控制器所属的区域(Area) 和前端 `apps/` 目录的部署形态共同决定。

  1. 确定页面所属的后端 Area(区域)和 Controller(控制器)。
  2. 查看前端 apps/ 目录,按下列两种情形取对应的路径:
情形 A:多个区域共用一个应用(或 apps 下只有一个 app)

views 下先按区域、再按控制器分两级文件夹:

{前端项目}/apps/{app-name}/src/views/{area}/{controller}/index.vue

示例:Admin 区域、User 控制器,应用为 cube-admin → apps/cube-admin/src/views/admin/user/index.vue

情形 B:一个区域一个应用(区域即应用)

views 下只有控制器一级文件夹:

{前端项目}/apps/{area-app}/src/views/{controller}/index.vue

示例:Admin 区域、User 控制器,对应应用为 admin → apps/admin/src/views/user/index.vue

判断口诀:apps/ 里区域是"文件夹"还是"应用名"?是文件夹 → 情形 A(两级);是应用名 → 情形 B(一级)。
情形 C:独立宿主(vite.config 在项目根,无 apps/ 子应用)

若项目是独立 Vue 应用(vite.config.ts 直接放在项目根目录,apps/ 下没有子应用的 vite.config.ts/package.json),则必须手动新建 apps/<app-name>/ 层级作为视图容器,否则框架的 import.meta.glob('/apps/*/src/views/**/index.vue') 扫不到页面:

{前端项目}/apps/{app-name}/src/views/{area}/{controller}/index.vue
  • app-name 可任取(如 myapp),仅作目录标识,不要求是真实微应用(无需配 package.json/main.ts)。
  • 建议用情形 A 的两级结构(area/controller/index.vue)。
  • 一个根目录下可以有多个 apps/*,彼此独立。

示例:Demo 区域、Demo 控制器,独立宿主 app 名为 myapp → apps/myapp/src/views/demo/demo/index.vue

此情形同样适用情形 A 的判断口诀(区域是文件夹 → 两级)。

工作流程

第一步:确认准备
  1. 确认后端 Controller 已创建,继承 EntityController<TEntity>
  2. 确认 Area 已注册(继承 AreaBase,构造函数传入 Area 名)
  3. 确认前端应用目录已存在(apps/{app-name}/),不存在则调用 cube-add-app
第二步:配置菜单图标

在后端 Controller 上通过 [Menu] 特性设置图标:

csharp
[Menu(30, true, Icon = "Files")] // Icon 为 Element Plus 图标名
public class DemoController : EntityController<DemoEntity>
图标也可通过 Cube 后台 → 菜单管理修改。常用图标:Files、Setting、User、List、Document、DataBoard、Coin、Clock。
第三步:配置列表展示字段

在 Controller 静态构造函数中配置 ListFields。常用操作:

场景代码
移除审计字段ListFields.RemoveCreateField().RemoveUpdateField()
清空并自定义list.Clear(); foreach(...) list.AddListField(item)
设置详情链接df.Url = "/{area}/{controller}/Detail?id={Id}"
完整 ListFields 方法表、ListField 属性表、AddFormFields/EditFormFields 配置详见 references/api-and-styling.md。
第四步:创建页面组件(唯一任务)

本框架路由和 CRUD 由后端自动驱动,你的唯一任务就是创建页面组件文件。

默认列表页(无需创建前端文件)

若只需标准表格列表 + 弹窗新增/编辑,无需创建任何前端文件,后端 Controller 创建完成后刷新即可访问。

字段标签禁止手写:实体页/设置页的字段名与提示由 /meta 的 displayName / description 提供(后端已按 Accept-Language 翻译),前端不要写 t('xxx.fieldName') 字段键,也不要手写列清单。只有元数据表达不了的交互才建自定义页面,并在提交说明里写明理由。
自定义页面(需创建 index.vue)

非标准 CRUD 布局、看板、图表、自定义交互等场景,按「页面目录结构」在对应路径创建 index.vue:

# 情形 A(两级)
apps/{app-name}/src/views/{area}/{controller}/index.vue
# 情形 B(一级)
apps/{area-app}/src/views/{controller}/index.vue

创建后框架自动加载并渲染,无需以下任何操作:

  • ❌ 不要注册路由(框架自动注册 /{area}/{controller}/{action}/{id?})
  • ❌ 不要修改 routes.ts、main.ts
  • ❌ 不要配置菜单(后端 [Menu] 特性控制)

必须先提供原型参考(原型 HTML / 截图 / 详细描述),再根据原型实现 Vue 组件。

样式规范:自定义页面必须使用 Element Plus CSS token(--el-*),配合自己的 class 名进行样式编排;禁止定义任何自定义 CSS 变量、禁止硬编码色值、禁止私占框架保留的 --cube-layout-* 命名空间。详见 references/api-and-styling.md。

API 对接:通过 usePageApi(area, controller) composable 对接后端 CRUD,无需为每个模块手写 api/xxx.ts:

ts
import { usePageApi } from '@newlifex/cube-vue/core/composables/useCubeApi';
const api = usePageApi("Demo", "Demo");
const res = await api.getList({ pageIndex: 0, pageSize: 20 });
// res.data: 当前页数据数组; res.page: { pageIndex, pageSize, totalCount } 分页信息
完整 usePageApi 方法表、使用示例、错误处理约定、完整示例、枚举字段处理详见 references/api-and-styling.md。
第五步:刷新验证
  • 确保后端项目正在运行
  • 刷新浏览器,框架自动加载新页面
  • 页面路径为 /{area}/{controller},无需手动输入路由配置
第六步(收尾·强制):派子代理审查整改
这是技能流程的强制收尾步骤,不得跳过。 落实完页面后,必须派一个子代理对本次新增/修改的前端文件做合规审查,确保不重复历史踩坑:
  1. 派子代理检查本次页面是否满足全部红线(见下「红线 / 禁止自行发挥」),重点核对:
  • 页面路径是否落在正确的 apps/<app-name>/src/views/... 下(独立宿主是否已建 apps/ 层级);
  • API 是否走 usePageApi(真实导出在 @newlifex/cube-vue/core/composables/useCubeApi),没有误用不存在的 @/composables/usePageApi 路径;
  • 是否误手写路由 / 改 main.ts 注册;
  • 样式是否全部用 Element Plus --el-* token(或框架保留的 --cube-layout-*),无自定义 CSS 变量、无硬编码色值、无私占 `--cube-layout-*`。
  1. 子代理返回问题清单后,按红线逐项整改,直至 0 问题、lint 通过。
  2. 整改完成后,本技能流程才算结束。
目的:把"落实后自查"固化进流程,保证下次再跑技能不会重复发生相同问题。

注意事项

  1. 图标名必须是 Element Plus 图标 PascalCase 名称(如 Files、Setting),不可用 fa- 旧格式
  2. 字段名必须与实体属性名一致,大小写敏感
  3. Area 注册:Controller 必须加上 [XxxArea] 特性
  4. 路由由框架自动注册:不要在 routes.ts 中写路由,不要修改 main.ts
  5. 页面自动加载:menuRoutes.ts 通过 import.meta.glob('/apps/*/src/views/**/index.vue') 扫描并自动注册路由,匹配后端菜单。注意:Vite 插件的 scanSectionFiles(虚拟模块 virtual:*-sections)是另一套机制,只会收集 PascalCase 文件名的 Section 覆盖组件、排除 `index.vue`,二者不要混淆。
  6. 新增/编辑默认通过弹窗打开,无需注册独立前端路由
  7. API 调用:通过 usePageApi(area, controller) 对接后端,不需要为每个模块建 api/xxx.ts
  8. 分页参数:后端分页从 0 开始,getList 需传 pageIndex: page - 1;totalCount 在 res.page.totalCount

红线 / 禁止自行发挥

以下为历史踩坑固化的强制约束,落实时严格照办,禁止凭记忆或"想当然"自行发挥:
  1. 页面自动加载,禁止手写路由 / 改 `main.ts`:框架通过 menuRoutes.ts 的 import.meta.glob('/apps/*/src/views/**/index.vue') 自动注册路由,匹配后端菜单。不要写 routes.ts、不要改 main.ts、不要配菜单(后端 [Menu] 特性控制)。
  2. `usePageApi` 真实导出路径是 `useCubeApi`:import 必须写 import { usePageApi } from '@newlifex/cube-vue/core/composables/useCubeApi',禁止写成 @/composables/usePageApi 或 @newlifex/cube-vue/core/composables/usePageApi(这些路径不存在)。
  3. 独立宿主必须建 `apps/` 层级:若 vite.config.ts 在项目根目录(无 apps/<name>/ 子应用),页面必须放进 apps/<app-name>/src/views/...,否则扫不到。先按「页面目录结构」判断情形 A / B / C,再落文件。
  4. 样式规范(硬约束):自定义页面只用 Element Plus --el-* token 配合自己的 class 名编排样式;禁止定义任何自定义 CSS 变量(包括 --{布局名}-* 之类),禁止硬编码色值,禁止私占框架保留的 --cube-layout-* 命名空间。详见 references/api-and-styling.md 与 cube-layout 技能。
  5. `useCubeApi` 内置 `onFieldError` 会 `ElMessage.error`:业务页不要再对字段错误重复弹窗;只在需要时处理业务级错误。
  6. 不要臆造后端字段名 / Area 名:字段名必须与实体属性名大小写一致;Area 必须加 [XxxArea] 特性;分页从 0 开始,getList 传 pageIndex: page - 1,总条数取 res.page.totalCount。
  7. 先有原型再写组件:自定义页面(看板/图表等)必须先拿到原型参考(HTML/截图/描述),不要凭空发挥布局。
  8. 字段标签禁止手写(元数据红线):实体页/设置页的字段名与字段提示一律取后端 /meta(displayName / description / category / dataSource),禁止写 t('模块.字段') 字段键或手写 el-table-column 列清单;前端词表只放界面文案(按钮、空态、确认框、客户端校验)。需要局部定制用 M2(CubeTable + 具名插槽),整页自定义(M3)仅限元数据表达不了的交互(工作台、图表、表结构诊断、列配置、权限树、拖拽、上传),且提交说明写明理由。详见仓库 Doc/规范/前端.md §3。

参考文件

文件内容
references/api-and-styling.mdListFields 配置、自定义页面样式规范、usePageApi 通用 CRUD Composable、错误处理约定、完整示例、枚举字段处理

Security

  • Security scanPassed, 100 of 100Pattern checks on the skill's files.
  • Model reviewNot runA model review is scheduled for the next rescan.

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
632
Repository forks
168
7-day trend score
32

Stars and forks are for the whole GitHub repository, not this skill alone. Refreshed 6 Sep 2026, a month ago.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/newlifex/newlife.cube/cube-add-page/badge)](https://verified-skill.com/skills/newlifex/newlife.cube/cube-add-page)

Something wrong with this skill or its page? Tell us.