# 前端页面视图 前端页面视图是用户直接交互的界面。项目使用 Vue3 + AntDesign Vue + Vite 构建。一个完整的 CRUD 页面由 4 个文件组成: ``` ui/src/views/system/position/ ├── index.vue # 主页面:搜索 + 表格 + 操作 ├── edit.vue # 编辑弹窗:新增/编辑表单 ├── columns.ts # 表格列定义 └── querySchemas.ts # 搜索表单 Schema ``` ## 1. 主页面 `index.vue` 主页面是模块的入口页面,包含搜索表单、数据表格和操作按钮。 ### 完整代码 ```vue ``` ### 代码解析 **页面结构**:`PageWrapper` 包裹两个 `a-card`,上方是搜索表单,下方是数据表格。 **搜索表单**:通过 `useForm` 注册,Schema 从 `querySchemas.ts` 导入。 **数据表格**:通过 `BasicTable` 组件渲染,`request` 属性绑定数据加载函数,`columns` 从 `columns.ts` 导入。 **操作列**:通过 `bodyCell` 插槽实现,配合 `v-perm` 指令控制权限。 **编辑弹窗**:使用 `defineAsyncComponent` 懒加载 `edit.vue`,通过 `v-model:visible` 控制显示,`positionId` 传入编辑记录 ID(0 表示新增)。 **删除逻辑**:使用 `Modal.confirm` 确认弹窗,单条删除传入 `id`,批量删除从 `selectionData` 取已选 ID。 ## 2. 编辑弹窗 `edit.vue` 编辑弹窗是独立组件,负责新增和编辑操作的表单展示与提交。 ### 完整代码 ```vue ``` ### 代码解析 **Props 接收**: - `visible`:控制弹窗显示/隐藏,通过 `v-model:visible` 双向绑定 - `positionId`:编辑记录的 ID,为 0 时表示新增模式 **表单数据**:使用 `reactive` 定义,字段与后端 Schema 对应。 **新增/编辑判断**:`props.positionId ? positionUpdate : positionAdd`,通过 ID 是否为 0 区分。 **防重复提交**:`useLockFn` 包装提交函数,点击后按钮变为 loading 状态,防止重复提交。 **数据回填**:`onMounted` 时判断如果是编辑模式,调用 `getPositionDetail` 获取数据并填充表单。 **事件通信**: - `emit('update:visible', false)`:关闭弹窗 - `emit('success')`:通知父页面刷新表格 ## 3. 表格列定义 `columns.ts` 定义表格的列配置,包括列名、字段名、宽度和自定义渲染。 ### 完整代码 ```typescript import { h } from 'vue'; import { Tag } from 'ant-design-vue'; export const columns = [ { title: 'ID', dataIndex: 'id', fixed: 'left', width: 50, }, { title: '岗位名称', dataIndex: 'name', width: 100, }, { title: '岗位状态', dataIndex: 'status', width: 100, customRender({ record }) { return h( Tag, { color: record.status == 1 ? 'success' : 'error' }, { default: () => (record.status == 1 ? '正常' : '停用') }, ); }, }, { title: '排序', dataIndex: 'sort', width: 100, }, { title: '创建人', dataIndex: 'createUser', width: 100, }, { title: '创建时间', dataIndex: 'createTime', width: 180, }, { title: '操作', fixed: 'right', dataIndex: 'action', key: 'action', width: 200, }, ]; ``` ### 代码解析 **列定义**:`title` 为列标题,`dataIndex` 为字段名。 **固定列**:`fixed: 'left'` 固定在左侧,`fixed: 'right'` 固定在右侧(操作列)。 **自定义渲染**:`customRender({ record })` 使用 Vue 的 `h()` 函数创建虚拟 DOM。状态列将 `1/2` 渲染为绿色/红色标签。 **操作列**:需要设置 `key: 'action'`,配合 `bodyCell` 插槽使用。 ## 4. 搜索表单 `querySchemas.ts` 定义搜索表单的字段配置,使用项目封装的 `FormSchema` 类型。 ### 完整代码 ```typescript import { FormSchema } from '@/components/Form/index'; export const schemas: FormSchema[] = [ { name: 'name', component: 'Input', label: '岗位名称', componentProps: { placeholder: '请输入岗位名称', }, }, { name: 'status', component: 'Select', label: '状态', componentProps: { placeholder: '请选择状态', clearable: true, options: [ { label: '正常', value: '1', }, { label: '禁用', value: '2', }, ], }, }, ]; ``` ### 代码解析 **FormSchema 字段**: | 字段 | 说明 | |:----|:----| | `name` | 字段名,与后端查询参数对应 | | `component` | 表单组件类型:`Input` / `Select` / `DatePicker` 等 | | `label` | 标签文本 | | `componentProps` | 组件属性,透传给 AntDesign Vue 组件 | **Select 组件**:`options` 定义下拉选项,`clearable: true` 允许清空选择。 ## 文件关系图 ``` index.vue(主页面) ├── import schemas from './querySchemas' ← 搜索表单配置 ├── import columns from './columns' ← 表格列配置 ├── import editDialog from './edit.vue' ← 编辑弹窗组件 └── import API from '@/api/system/position' ← 接口请求 edit.vue(编辑弹窗) └── import API from '@/api/system/position' ← 接口请求 ``` ## 开发要点 1. **一个模块一个目录**:放在 `ui/src/views/{group}/{module}/` 下 2. **4 个文件各司其职**:主页面、编辑弹窗、列定义、搜索 Schema 3. **编辑弹窗是独立组件**:通过 Props 接收 ID,通过 Emit 通知父页面 4. **列定义使用 `customRender` 渲染复杂内容**:如状态标签、操作按钮 5. **搜索 Schema 使用 `FormSchema` 类型**:配置化定义表单字段 6. **新增/编辑通过 `positionId` 区分**:0 为新增,非 0 为编辑 7. **防重复提交使用 `useLockFn`**:提交时按钮 loading ## 总结 前端页面统一使用 `PageWrapper` + `BasicForm` + `BasicTable` + `bodyCell` 插槽四件套,分页由 `BasicTable` 内置处理。每个模块包含 `index.vue`(列表页)、`edit.vue`(编辑弹窗)、`columns.ts`(列定义)、`querySchemas.ts`(搜索配置)四个文件。