编写页面从0到1
开始之前
本小节主要以 PF 模板作为基础,讲解如何从 0 到 1 搭建一个后台管理页面,以在授权模块下面新建一个管理员页面为例。部分公共方法在根目录下的 package 中的 hooks 和 utils 等中。
# 1. 创建 vue 文件
在 src/views/setting/auth
目录下创建一个名为admin/index.vue
的文件,编写基础部分。
可以用代码片段生成基础模板,如何使用代码片段,PF 使用说明--->其他--->模板代码生成
<template>
<div></div>
</template>
<script setup></script>
<style lang="scss" scoped></style>
# 2. 添加路由
新页面需要添加路由,否则无法正常访问,普通组件则不需要。
路由配置讲解
# 2.1 路由配置文件
路由文件位置:src/router/index.js

# 2.2 路由配置
vue-router (opens new window)路由讲解
- path: 页面路径
- name: 路由名称
- component: 页面组件
- meta: 路由元信息,用于存储一些数据,例如:是否需要登录才能访问
- title: 页面标题
- icon: 页面图标
- code: 页面权限码
- hidden: 是否隐藏在侧边栏,默认 false
- children: 子路由

⚡️ TIP
该示例只是在后台管理,授权模块下的新建页面,实际开发中,可以根据需要,在任意模块下,新建任意页面。找到对应的路由模块进行配置即可,也可以自己新建一个模块
# 3. 编写页面内容
如在常规的后台管理页面中,需要展示的内容有:
- 顶部搜索栏
- 中间表格展示部分
# 顶部搜索栏
<template>
<!-- 外层加入table-form类名,可以统一约束该容器下子类型的样式,框架有做统一处理 -->
<div class="table-form">
<el-form ref="formRef" :model="form" :inline="true" class="pro-select-box">
<el-form-item label="用户名" prop="name">
<el-input v-model="form.name" placeholder="请输入用户名" />
</el-form-item>
<el-form-item>
<el-button type="primary" v-permission="['system:menu:get']"
>查询</el-button
>
<el-button type="primary" v-permission="['system:menu:add']"
>新增</el-button
>
</el-form-item>
</el-form>
</div>
</template>
<script setup>
import { reactive, toRefs } from "vue";
const data = reactive({
// 绑定数据
form: {
name: "",
},
});
const { form } = toRefs(data);
</script>
<style lang="scss" scoped></style>
解析:
el-form
为表单组件,el-form-item
为表单项组件,el-input
为输入框组件,el-button
为按钮组件,v-permission
为权限控制指令。

此时页面上就有了搜索栏部分
# 中间表格展示部分
<template>
<!-- 外层加入table-form类名,可以统一约束该容器下子类型的样式,框架有做统一处理 -->
<div class="table-form">
<el-form ref="formRef" :model="form" :inline="true" class="pro-select-box">
<el-form-item label="用户名" prop="name">
<el-input v-model="form.name" placeholder="请输入用户名" />
</el-form-item>
<el-form-item>
<el-button type="primary" v-permission="['system:menu:get']"
>查询</el-button
>
<el-button type="primary" v-permission="['system:menu:add']"
>新增</el-button
>
</el-form-item>
</el-form>
<!-- 表格 -->
<hmx-table
:table-data="list"
:options="tableOptions"
:columns="tableColumn"
>
<!-- 同过插槽自定义单元格内显示的内容 -->
<template #state="{ row }">
<div class="flex-a-c">
<div
class="state-icon"
:class="[row.state ? 'state-start' : 'state-stop']"
></div>
<span style="padding-left: 8px">{{
row.state ? "启用" : "停用"
}}</span>
</div>
</template>
</hmx-table>
</div>
</template>
<script setup>
import { reactive, toRefs, computed, ref } from "vue";
import HmxTable from "@/components/hmx-table/index.vue"; // 引入表格组件
const data = reactive({
// 绑定数据
form: {
name: "",
},
page: {
pageSize: 10,
pageIndex: 1,
},
});
// 定义表头
const tableColumn = [
{
type: "index", // 类型 可扩展为复选框
width: "50", // 表头单元格宽度
label: "No.", // 表头显示内容
align: "center", // 文字对齐方式
fixed: true, // 是否固定
},
{
prop: "cardId",
label: "表头1",
showOverflowTooltip: true, // 内容超出是否显示省略号
},
{
prop: "name",
label: "表头2",
showOverflowTooltip: true,
fixed: true,
},
{
prop: "state",
label: "表头4",
slot: "state", // 定义插槽名称
},
{
width: "245",
label: "操作",
align: "center",
fixed: "right",
buttons: [
{
name: "编辑", // 按钮名称
type: "primary", // 按钮类型
command: "edit", // 事件触发关键字
permission: ["system:user:edit"], // 权限控制
},
],
},
];
// 定义表格数据
const list = ref([]);
// 定义表格配置
const tableOptions = computed(() => {
return {
loading: false,
showPagination: true,
border: false,
paginationConfig: {
total: 0,
currentPage: data.page.pageIndex,
pageSize: data.page.pageSize,
},
};
});
const { form } = toRefs(data);
</script>
<style lang="scss" scoped></style>
table 相关配置请参考 element-plus 官方文档和模板内二次封装的 table 组件。路径:
src--> components--> hmx-table

此时就完成了搜索栏+表格静态部分
# 动态获取表格数据和相应的交互
<template>
<!-- 外层加入table-form类名,可以统一约束该容器下子类型的样式,框架有做统一处理 -->
<div class="table-form">
<el-form ref="formRef" :model="form" :inline="true" class="pro-select-box">
<el-form-item label="用户名" prop="name">
<el-input v-model="form.name" placeholder="请输入用户名" />
</el-form-item>
<el-form-item>
<el-button type="primary" v-permission="['system:menu:get']"
>查询</el-button
>
<el-button type="primary" v-permission="['system:menu:add']"
>新增</el-button
>
</el-form-item>
</el-form>
<!-- 表格 command 事件 size-change 改变页的显示数量 current-change 获取当前页码 -->
<hmx-table
:table-data="list"
:options="tableOptions"
:columns="tableColumn"
@command="handleAction"
@size-change="handlerPageSize"
@current-change="handlerPageIndex"
>
<!-- 同过插槽自定义单元格内显示的内容 -->
<template #state="{ row }">
<div class="flex-a-c">
<div
class="state-icon"
:class="[row.state ? 'state-start' : 'state-stop']"
></div>
<span style="padding-left: 8px">{{
row.state ? "启用" : "停用"
}}</span>
</div>
</template>
</hmx-table>
<!-- 新增、编辑用户弹框 -->
<user-dialog :options="options" @onCancel="closeDialog" @onSure="onSure" />
</div>
</template>
<script setup>
import { reactive, toRefs, computed, ref } from "vue";
import HmxTable from "@/components/hmx-table/index.vue"; // 引入表格组件
import UserDialog from "./components/user-dialog.vue"; // 引入用于增改的弹窗组件。具体实现方法请参考其他页面
import useTable from "@/hooks/useTable"; // 引入表格hooks
import { config } from "@/config"; // 从顶层配置文件中引入配置
const homeServerPrefix = config.base_url.homeServerPrefix; // 接口地址前缀
// 从useTable 里面导出表格所需要的通用数据和方法,例如:list、数据加载loading、增伤改等等
const { list, total, loading, getList, addFun, updateFun, deleteFun } =
useTable(`${homeServerPrefix}/xxxxxx`); // 传入接口地址,该地址需严格按照前后端约定的接口规则来
const data = reactive({
// 绑定数据
form: {
name: "",
},
// 分页数据
page: {
pageSize: 10,
pageIndex: 1,
},
// 弹窗
options: {
show: false,
type: "", // 用于判断是编辑还是删除 add edit
curUser: null,
},
});
// 定义表头
const tableColumn = [
{
type: "index", // 类型 可扩展为复选框
width: "50", // 表头单元格宽度
label: "No.", // 表头显示内容
align: "center", // 文字对齐方式
fixed: true, // 是否固定
},
{
prop: "cardId",
label: "表头1",
showOverflowTooltip: true, // 内容超出是否显示省略号
},
{
prop: "name",
label: "表头2",
showOverflowTooltip: true,
fixed: true,
},
{
prop: "state",
label: "表头4",
slot: "state", // 定义插槽名称
},
{
width: "245",
label: "操作",
align: "center",
fixed: "right",
buttons: [
{
name: "编辑", // 按钮名称
type: "primary", // 按钮类型
command: "edit", // 事件触发关键字
permission: ["system:user:edit"], // 权限控制
},
],
},
];
// 定义表格配置
const tableOptions = computed(() => {
return {
loading: loading.value,
showPagination: true, // 是否显示分页
border: false,
paginationConfig: {
total: total.value, // 数据总条数
currentPage: data.page.pageIndex, // 当前页
pageSize: data.page.pageSize, // 一页的容量
},
};
});
// 处理分页信息和搜索框信息
const params = computed(() => {
let form = JSON.parse(JSON.stringify(data.form));
Object.keys(form).forEach((key) => {
if (form[key] === null) {
form[key] = "";
}
});
return {
...form,
...data.page,
};
});
// 操作事件 示例中只加了一个事件,可添加多个事件,关键字在此处理
const handleAction = (command, row) => {
switch (command) {
case "edit":
handlerEdit(row);
break;
default:
break;
}
};
// 点击查询
const checkList = () => {
data.page.pageIndex = 1;
getList(params.value);
};
// 表请求条数改变
const handlerPageSize = (pageSize) => {
data.page.pageSize = pageSize;
data.page.pageIndex = 1;
getList(params.value);
};
// 表格页数改变
const handlerPageIndex = (pageIndex) => {
data.page.pageIndex = pageIndex;
getList(params.value);
};
// 新增
const handlerAdd = () => {
data.options = {
show: true,
type: "add", // 用于判断是编辑还是删除 add edit
curUser: null,
};
};
// 编辑
const handlerEdit = async (item) => {
data.options = {
show: true,
type: "edit", // 用于判断是编辑还是删除 add edit
curUser: item,
};
};
// 删除
const handlerDel = async (item) => {
deleteFun([item]);
};
// 保存弹框
const onSure = async (options) => {
if (options.type === "add") {
// 新增用户
addFun(options.form);
} else {
await updateFun(options.id, options.form);
if (userInfo.value.user.id === options.id) {
getUserInfo();
}
}
closeDialog();
};
// 关闭弹框
const closeDialog = () => {
data.options = {
show: false,
type: "", // 用于判断是编辑还是删除 add edit
curUser: null,
};
};
const { form, options } = toRefs(data);
</script>
<style lang="scss" scoped></style>
table 的 usetable 的 Hooks 相关配置请查看源码。路径:
src--> hooks--> useTable--> index
提示
其余组件或者页面请参考模板内的实现方法