--- name: vben3-tree-wrapper-crud description: 生成基于 TreeWrapper + EditTable + Drawer 的 Vben v3 CRUD 页面模板。适用于需要左侧菜单树 + 右侧数据表格的列表页面,含状态切换、文件上传预览下载、权限抽屉、批量删除等完整功能。当用户需要在成堪数智平台创建带左树的 CRUD 页面时使用此 skill。 --- # Vben v3 TreeWrapper CRUD 页面模板 > 基于 `apps/micro-apps/system/src/views/manager/` 提取的 TreeWrapper + EditTable + Drawer + DrawerAuth 四件套模板。 > 适用于**左侧有系统/菜单树、右侧展示关联数据的 CRUD 页面**。 --- ## 一、适用场景 | 场景 | 是否适用 | |------|---------| | 左侧菜单树,点击过滤右侧表格数据 | ✅ 使用此模板 | | 需要文件上传、预览、下载 | ✅ 使用此模板 | | 需要角色/权限授权抽屉 | ✅ 使用此模板 | | 需要开关启禁用状态 | ✅ 使用此模板 | | 纯表格 CRUD,无左树 | ❌ 使用 vben3.md 基础版 | | 机构树 + 普通 CRUD | ❌ 使用 vben3.md 带左树版(CommonPage) | --- ## 二、文件清单与生成顺序 ``` views/{module}/ ├── comp/ │ ├── tree.vue # ① 先创建:BussinessTree 树组件 │ └── treeWrapper.vue # ② 复用:左树+右内容布局容器 ├── config.ts # ③ 配置:表格+表单+权限树 ├── drawer.vue # ④ 抽屉:新增/编辑 ├── drawerAuth.vue # ⑤ 可选:角色授权抽屉 └── index.vue # ⑥ 最后:主页面组装 ``` **关键导入来源**: - `@vben/adapter` → `EditTable`, `Drawer`, `BussinessTree` - `@vben/wflow` → `AddForm` - `@vben/common-ui` → `Page` - `@vben/icons` → `getIconFont` - `@vben/utils` → `cloneDeep`, `session`, `commWay` - `element-plus` → `ElButton`, `ElMessage`, `ElPopconfirm`, `ElSwitch`, `ElRow`, `ElCol` --- ## 三、与标准 CRUD 模板的关键差异 | 特性 | 此模板 | 标准 CRUD(vben3.md) | |------|--------|----------------------| | 布局 | `TreeWrapper`(ElRow 5:19) | `CommonPage` 或 `Page` | | 左树 | 自定义 `tree.vue` + `BussinessTree` | 无 / CommonPage 内置 | | 树↔表格数据流 | `activeMenuId` → `menuId` 参数 | `organizationId` → globParams | | 新增预设 | 当前树节点 ID → drawer `menusArr` | 直接开空表单 | | 权限抽屉 | `drawerAuth.vue` + `TreeTransfer` | 无 | --- ## 四、数据流 ``` TreeWrapper ├── tree.vue @node-click → handleNodeClick(node) │ └── activeMenuId = node.id │ └── editTable.getData({ ...values, menuId: node.id }) │ └── EditTable ├── @operation-click → operationClick(data) │ ├── 'add'/'edit' → drawer.openModal(data) // data.menusArr 预设菜单 │ ├── 'delete' → deleteClick(row) │ └── 'menuAuth' → drawerAuth.openModal(data) │ └── drawer/drawerAuth @on-confirm → getData() → refreshTree() ``` --- ## 五、模板代码 > 完整模板代码见 [templates.md](templates.md),包含所有 6 个文件的完整内容。 ### 5.1 treeWrapper.vue(直接复用,无需修改) ```vue ``` ### 5.2 tree.vue 要点 基于 `BussinessTree`,核心配置: - `searchOptions.show: true` — 搜索框 - `treeOptions.api.query` — 调用你的树数据 API,返回含 `id/name/children` 的数组 - `treeOptions.api.isUseApi: true` - 需要 `defineExpose({ refreshTree })` 供父组件刷新 - 树数据存入 `session.setItem("menuNode", list)` 供 drawer 的 ApiTreeSelect 使用 ### 5.3 index.vue 核心事件 ```typescript const events = { operationClick(data) { // add/edit → drawer.openModal(data); data.menusArr = [activeMenuId] // delete → deleteClick(row) // menuAuth → drawerAuth.openModal(data) }, changeStatus(row) { /* updateApi → getData */ }, deleteClick(row?) { /* row?.id 或 getCheckboxRecords → removeApi → getData */ }, async getData() { /* gridApi.formApi.getValues → editTable.getData → refreshTree */ }, async handleNodeClick(node) { /* activeMenuId = node.id → getData({ menuId }) */ }, }; ``` 模板中 `