Work 业务组件开发规范¶
📄 创建: 刘泽伟 2026-08-18 · 修改: 刘泽伟_w 2026-08-20
本文档为
business-component-specSkill 的完整规范,供 AI 按此规范开发 BAMS-Work 业务组件(devextreme-vue 表格 + antd 抽屉表单 + PageVo 接口 + UI 规范接入)。
本规范用于在 BAMS-Work 项目中按统一规范开发一个完整的业务组件,涵盖:组件骨架创建、接口封装、字典配置、devextreme-vue 增删改查表格、antd 抽屉表单、根组件配置、UI 规范接入,以及开发完成后启动开发服务器验证。
依赖检查(开发前必做)¶
开始开发前,先检查以下依赖是否已安装/可用,缺失时先向用户确认或补齐:
依赖 Skill(在当前 AI 工具的 Skill 目录下检查)¶
通过当前 AI 工具的 Skill 面板/技能列表(如 Skill 工具返回的可用技能)确认依赖 Skill 是否已加载,缺失时先向用户确认或补齐:
| 依赖 Skill | 用途 |
|---|---|
component-page-creator |
创建组件骨架 |
api-standard-helper |
PageVo 接口规范 |
component-ui-spec-integration |
UI 规范接入 |
Skill 目录位置:项目内自定义 Skill 位于
<项目根>/.trae/skills/;AI 工具内置/全局 Skill 位于工具安装目录的 skills 目录下(如~/.trae-cn/builtin/global/skills/)。以当前 AI 工具实际加载的 Skill 为准。
依赖 MCP¶
| 依赖 MCP | 用途 | 检查方式 |
|---|---|---|
mcp_dx |
查询 DevExpress 组件文档(DataGrid/Form 等) | 查看 MCP 服务器是否启用 |
mcp_Zhi_Shi_Ku |
读取知识库 UI 规范文档 | 查看 MCP 服务器是否启用 |
运行环境¶
- 项目根目录需存在
work/scripts/create-ui-component.js(骨架脚本) - 当前环境
yarn不在 PATH,需使用 nvm 下的 node:~/.nvm/versions/node/v22.14.0/bin/node(实际版本以ls ~/.nvm/versions/node为准) - 启动开发服务器前需存在
vue.config.dev.js(缺失时按vue.config.dev_template.js复制生成)
触发条件¶
当用户包含以下意图时触发:
- "开发/创建/生成一个业务组件"
- "实现一个增删改查的表格"
- "使用 devextreme-vue 开发页面/表格"
- "表单使用 antd 抽屉从右侧滑出"
- "组件接入 UI 规范"
- 明确提到基于
energy-ui/device-ui/mes-ui等目录开发组件
操作流程¶
第 1 步:创建组件骨架¶
执行项目根目录预设脚本,注意当前环境 yarn 不在 PATH,需用 nvm 下的 node 直接执行脚本,并通过 echo "n" 跳过交互式 yarn install:
echo "n" | ~/.nvm/versions/node/v22.14.0/bin/node work/scripts/create-ui-component.js --dir energy-ui --name ui-xxx --desc "组件描述"
命名规范:
- 业务组件:
ui-xxx(kebab-case) - 页面组件:
page-xxx - 基础组件:
base-xxx(仅 base-ui 目录)
生成的标准目录结构:
ui-xxx/
├── index.js # 组件入口
├── package.json # 包名 @<目录>/ui-xxx
└── src/
├── component.vue # 根组件(只做通用配置)
├── apis/index.js # 接口封装
├── constants/index.js # 字典配置
├── i18n/index.js # 国际化(模板已生成)
└── business/
├── MainContent.vue # 主业务组件(表格)
└── components/ # 子组件(抽屉表单等)
第 2 步:接口封装(apis/index.js)¶
必须严格遵循 api-standard-helper skill 的 PageVo 请求规范 与 通用响应结构:
- 使用
@bams-app/service提供的bams.post/bams.get发起请求 - 查询参数通过
new bams.PageVo({...})封装 - PageVo 字段:
current(页码,默认1)、size(每页条数,默认20)、likeMap(模糊查询)、andMap(等值查询)、geMap/leMap(范围查询)、orderBy(排序)、param(扩展参数) - 后端响应统一为
{ code, msg, data: { records, total, size, current, pages }, errorMsg },列表数据取data.records
import { bams } from "@bams-app/service";
// 分页查询
export const getList = params => {
const pageVo = new bams.PageVo({
current: params.page ?? 1,
size: params.pageSize ?? 20,
likeMap: { code: params.keyword, name: params.keyword },
andMap: { category: params.category, enableState: params.enableState },
orderBy: { updatedTime: "desc" },
});
return bams.post(config.baseURL, "/bdXxx/list", pageVo);
};
// 新增或修改
export const saveOrUpdate = params => bams.post(config.baseURL, "/bdXxx/saveOrUpdate", params);
// 按 Id 删除
export const deleteById = id => bams.post(config.baseURL, "/bdXxx/delete/" + id);
// 批量删除
export const batchDelete = ids => bams.post(config.baseURL, "/bdXxx/batchDelete", ids);
注意:
- 接口路径(如
/bdXxx/list)为占位约定,需按实际后端确认后替换 - 查询参数的空值(空字符串、null、undefined)不要传入,避免污染查询条件
- 拦截器已统一处理
code !== "200"的异常,业务层直接消费data即可
第 3 步:字典配置(constants/index.js)¶
集中管理下拉/状态等字典:
第 4 步:主表格组件(business/MainContent.vue)¶
页面组件一律使用 devextreme-vue 组件库。
依赖引入¶
import DxButton from "devextreme-vue/button";
import DxTextBox from "devextreme-vue/text-box";
import DxSelectBox from "devextreme-vue/select-box";
import DxDataGrid, { DxColumn, DxPaging, DxScrolling, DxSelection } from "devextreme-vue/data-grid";
import { DxPagination } from "devextreme-vue/pagination";
import message from "@bams-app/message"; // 轻提示
表格要点¶
DxDataGrid::data-source绑定列表数据、key-expr="id"、@selection-changed记录选中行DxSelection mode="multiple" show-check-boxes-mode="always":多选用于批量删除- 操作列:
cell-template="operationCell"配合<template #operationCell="{ data }">渲染「编辑/删除」按钮,数据取data.data - 列值映射:状态/类别等字典字段需映射为文本列(如
enableStateText、categoryText) DxPagination分页:v-model:page-index/v-model:page-size,监听@option-changed区分pageIndex与pageSize变化触发刷新
页面结构¶
工具栏(搜索区 + 新增/删除按钮)
├── DxTextBox 关键字搜索(@enter-key 触发查询)
├── DxSelectBox 类别/状态筛选
├── 查询 / 重置按钮
└── 新增 / 删除(删除需勾选行,二次确认)
DxDataGrid 表格
DxPagination 分页条
抽屉表单组件(v-model:visible / :mode / :edit-data / @saved)
查询参数构建¶
const buildQueryParams = () => {
const params = {
page: pageState.current,
pageSize: pageState.size,
keyword: searchForm.keyword?.trim() || "",
category: searchForm.category,
enableState: searchForm.enableState,
};
return params;
};
(将业务查询条件组装为接口层入参,PageVo 的 likeMap/andMap 封装放在 apis 层完成,空值由 apis 层过滤。)
第 5 步:抽屉表单组件(business/components/XxxFormDrawer.vue)¶
表单使用 antd Drawer 从右侧滑出,表单项使用 devextreme-vue 的 DxForm。
核心实现¶
<a-drawer placement="right" :open="visibleState" :width="560" destroyOnClose @close="handleClose">
<DxForm
:form-data="formModel"
:items="formItems"
:col-count="2"
:show-validation-summary="true"
:validation-group="formValidationGroup"
label-mode="outside"
/>
</a-drawer>
关键约定¶
- Props:
visible、mode(add/edit)、editData;Emits:update:visible、saved - 校验:
validationEngine.validateGroup(group)提交前校验,validationEngine.resetGroup(group)关闭时重置 - 表单项:
dataField+editorType(dxTextBox/dxSelectBox/dxNumberBox/dxTextArea)+validationRules - 编辑回填:
watch(visible)打开时按 mode 初始化 formModel,编辑态回填editData - 保存:
saveOrUpdate成功 →message.success→ 关闭抽屉 →emit("saved")通知父组件刷新列表 - 数值/文本归一化:保存前对 sort 等数值、空字符串做归一化处理
第 6 步:根组件配置(component.vue)¶
根组件不写业务逻辑,使用 ComponentContainer 包裹(内置主题变量处理):
<template>
<ComponentContainer>
<MainContent />
</ComponentContainer>
</template>
<script setup>
import { ComponentContainer } from "@bams-app/components";
import MainContent from "./business/MainContent.vue";
defineOptions({
name: "uiXxx",
dicts: [],
config: { pageTitle: "xxx" },
});
</script>
第 7 步:UI 规范接入¶
依据知识库 tech/frontend/theme/ui-spec.md(MCP 服务 开发文档,工具 get_doc):
- 业务组件只消费
var(--bams-*)变量,不操作主题状态(不使用useThemeStore) - 常用替换对照(以 light 模式实际值为准校验匹配度,差异大不要强行替换):
| 硬编码 | 替换变量 |
|---|---|
#fff 背景 |
var(--bams-surface-bg) |
链接蓝#1677ff |
var(--bams-link-color) |
错误红#ff4d4f |
var(--bams-error-color) |
灰色文本#999 |
var(--bams-text-tertiary) |
| 主文本 | var(--bams-text-color) |
- 颜色替换前需先确认变量定义(
work/packages/theme/src/styles/theme-light.less、root-tokens.less),替换后全局 grep 确认无遗漏硬编码 - 局部主题仅在组件有独立主题诉求时引入(
LocalThemeContainer等,配置必须抽取到src/theme/xxxTheme.js) - 弹层继承:普通全局变量方案下 devextreme/antd 弹层挂载 body 仍可继承
:root变量,无需getPopupContainer;若引入局部主题则必须设置
第 8 步:启动开发服务器验证(开发完成后必做)¶
开发完成后,引导用户带上环境标识启动开发服务器预览组件:
- 前置检查:确认项目根目录存在
vue.config.dev.js(缺失时执行cp vue.config.dev_template.js vue.config.dev.js生成,并按需修改代理) - 启动命令(
yarn不在 PATH 时用 node 直跑,需带环境标识与组件名):
# 方式一:yarn 可用时(dev:ui 后先跟环境标识,再跟 --component 组件名)
yarn dev:ui <环境标识> --component ui-xxx
# 方式二:当前环境(yarn 不在 PATH)
~/.nvm/versions/node/v22.14.0/bin/node work/cli/shared-env/run-shared-env-command.js ui serve <环境标识> --component ui-xxx
示例(使用 bxjc 环境启动 ui-base-data):
~/.nvm/versions/node/v22.14.0/bin/node work/cli/shared-env/run-shared-env-command.js ui serve bxjc --component ui-base-data
- 环境标识列表(对应
.envs/.env.dev-<标识>文件,端口以各文件PORT为准):
| 环境标识 | 环境文件 | 说明 | 端口 |
|---|---|---|---|
bams |
.env.dev-bams |
BAMS 生产管理系统 | 8090 |
apex |
.env.dev-apex |
APEX 系统 | 8700 |
bxjc |
.env.dev-bxjc |
变速箱集成系统 | 8085 |
mock |
.env.dev-mock |
Mock 模拟环境 | 8088 |
pdc |
.env.dev-pdc |
PDC 系统 | 8702 |
qls |
.env.dev-qls |
QLS 系统 | 8090 |
production |
.env.production |
生产环境模板(仅构建,不用于 dev) | - |
-
如何创建新环境:
-
方法一(推荐):运行交互式创建工具
yarn create-env(支持基于现有环境快速复制或逐项自定义,自动推荐可用端口并可选生成快捷启动脚本) -
方法二(手动):
然后修改以下关键配置:
PROXY_TARGET:后端服务地址(端口号为基准)PORT:开发服务器端口,必须与 PROXY_TARGET 端口保持一致,否则代理异常VUE_APP_TITLE/VUE_APP_SYS_NAME:系统名称VUE_APP_SYS_CODE:系统唯一编码VUE_APP_LOGIN_URL/VUE_APP_WEBSOCKET_URL:对应服务地址- 命名规范:文件必须为
.env.dev-<标识>格式,标识仅允许小写字母、数字和连字符,且以字母或数字开头 - 组件名解析:短名(如
ui-xxx)会自动在 workspaces 中匹配 scope 并解析为包名(如@energy-ui/ui-xxx);存在多个同名组件时会交互式选择,非 TTY 环境需传完整包名或绝对路径 - 访问地址:默认
http://localhost:<PORT>(端口取自环境文件的PORT;若被占用 vue-cli-service 会自动切换并在终端输出提示) - 验证内容:打开页面后检查表格加载、搜索、新增/编辑抽屉、删除确认、分页是否正常,并观察终端有无编译错误
自检清单¶
- 组件名符合
ui-xxxkebab-case 命名,目录位于指定 UI 目录下 - 接口遵循
api-standard-helper规范(bams.post + bams.PageVo,likeMap/andMap/orderBy),路径经后端确认 - 表格使用 DxDataGrid + DxPagination,操作列含编辑/删除
- 表单使用 antd Drawer(placement="right")+ DxForm,校验分组正确,保存后 emit("saved")
- 字典集中在 constants 管理,状态/类别列已映射文本
- 根组件使用 ComponentContainer,配置了 pageTitle
- 样式无硬编码颜色,全部使用 var(--bams-*),颜色替换经过匹配度校验
- 未自动格式化现有代码,保留原代码风格
- 无 IDE 诊断错误
- 已启动 dev 服务器验证组件可运行
注意事项¶
- 开发前先完成「依赖检查」:三个 Skill、两个 MCP 是否就绪,缺少时先向用户确认
- 当前环境
yarn不在 PATH,建骨架/启动 dev 均用 nvm 下 node 直接执行脚本 - 绝对禁止自动格式化现有代码,保留用户原始代码风格(工作区规则)
- 页面组件一律使用 devextreme-vue;表单抽屉使用 antd Drawer,轻提示统一引入
@bams-app/message - 接口封装规范以
api-standard-helperskill 为准(bams.post/bams.get+bams.PageVo),不一致时以该 skill 为权威