在前面随笔《基于SqlSugar的开发框架循序渐进介绍(12)-- 拆分页面模块内容为组件,实现分而治之的处理》中我们已经介绍过,对于相关的业务表的界面代码,我们已经尽可能把不同的业务逻辑封装在不同的页面组件中,隔离变化的差异,因此界面组件化后,就可以利用代码生成工具进行统一的界面代码的生成了,而且由于变化的隔离处理,我们实际上维护的代码变得更加方便维护了。本篇随笔介绍在整合代码生成工具进行前端界面的生成的一些思路和实际的界面代码的生成。

1、页面的模块化处理

在前面随笔《基于SqlSugar的开发框架循序渐进介绍(12)-- 拆分页面模块内容为组件,实现分而治之的处理》中我们已经介绍过,常规页面包含有列表界面,新增、编辑、查看、导入等界面,除了列表页面,其他内容以弹出层对话框的方式进行处理,如下界面示意图所示。

根据以上的页面划分,我们把一个页面分为search.vue、edit.vue、import.vue、view.vue、index.vue,其中index.vue为整合各个组件的主页面,在视图中如下所示。我们每个业务模块都是如此统一划分,因此比较统一,同时也是为后续的代码生成工具批量生成做好准备。

因此在index.vue页面中,我们整合了几个组件页面即可,如下所示。

<template>
<div class="main">
<!--条件及列表展示-->
<Search ref="searchRef" @show-import="showImport" @show-add="showAdd" @show-view="showView" @show-edit="showEdit" /> <!--查看详细组件界面-->
<view-data ref="viewRef" />
<!--新增、编辑组件界面-->
<edit-data ref="editRef" @submit="refreshData" />
<!--模板导入信息-->
<import-data ref="importRef" @finish="finishImport" />
</div>
</template> <script setup lang="ts">
import { reactive, ref, onMounted } from 'vue'; import Search from './search.vue';
import ViewData from './view.vue';
import EditData from './edit.vue';
import ImportData from './import.vue';

1)查看视图页面

我们先以view.vue查看页面为例进行介绍,它是一个查看明细的界面,因此也是一个弹出对话框页面,我们把它的代码处理如下所示。

<template>
<el-dialog v-if="isVisible" v-model="isVisible" title="查看信息" append-to-body @close="closeDialog">
<el-form ref="viewRef" :model="viewForm" label-width="100px">
<el-tabs type="border-card">
<el-tab-pane label="基本信息">
<el-descriptions title="" :column="2" border>
<el-descriptions-item label="显示名称">
{{ viewForm.name }}
</el-descriptions-item>
<el-descriptions-item label="Web地址">
{{ viewForm.url }}
</el-descriptions-item>
<el-descriptions-item label="Web图标">
<!-- {{ viewForm.webIcon }} -->
<icon :icon="viewForm.webIcon" />
</el-descriptions-item>
<el-descriptions-item label="排序">
{{ viewForm.seq }}
</el-descriptions-item>
<el-descriptions-item label="可见">
<el-tag v-if="viewForm.visible" type="success" effect="dark">可见</el-tag>
<el-tag v-else type="danger" effect="dark">隐藏</el-tag>
</el-descriptions-item>
<el-descriptions-item label="展开">
<el-tag v-if="viewForm.expand" type="success" effect="dark">展开</el-tag>
<el-tag v-else type="" effect="dark">收缩</el-tag>
</el-descriptions-item>
<el-descriptions-item label="创建时间">
<el-date-picker v-model="viewForm.createTime" align="right" type="datetime" placeholder="选择日期"
value-format="YYYY-MM-DD HH:mm" disabled />
</el-descriptions-item>
<el-descriptions-item label="特殊标签">
{{ viewForm.tag }}
</el-descriptions-item>
</el-descriptions>
</el-tab-pane>
</el-tabs>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="closeDialog">关闭</el-button>
</span>
</template>
</el-dialog>
</template>

其他的js代码采用tyepscript语法,我们把它放在

<script setup lang="ts">
//逻辑代码
</script>

然后我们在js代码中抛出show的方法,便于父组件的调用。

//显示窗口
const show = (id: string | number) => {
if (!$u.test.isNullOrUnDef(id)) {
menu.Get(id).then((data) => {
Object.assign(viewForm, data); isVisible.value = true; //显示对话框
});
}
};
//暴露组件属性和方法
defineExpose({
show,
});

同时在页面里面,也定义一个表单的对象引用,便于上面模板组件的显示。

const viewRef = ref<FormInstance>(); //表单引用
// 表单属性定义
let viewForm = reactive({
iD: '',
pid: '',
name: '',
icon: '',
seq: '',
functionId: '',
visible: 0,
expand: 0,
winformType: '',
url: '',
webIcon: '',
creator: '',
createTime: '',
tag: '',
});

如果是查看详细的视图中有树形列表,我们还可以在onMounted的处理中,添加获取树列表的数据即可,如下代码所示。

//挂载的时候初始化数据
onMounted(() => {
// 设置默认值
getTree();
});
// 初始化树列表
let treedata = ref([]);
const getTree = () => {
// 树列表数据获取
menu.GetAll().then((data) => {
treedata.value = []; // 树列表清空
var list = data?.items;
if (list) {
var newTreedata = $u.util.getJsonTree(list, {
id: 'id',
pid: 'pid',
label: 'name',
children: 'children',
});
treedata.value = newTreedata;
}
});
};

而查看视图的触发,往往在列表的操作按钮中,或者双击表格行进行触发,界面如下所示。

界面如下代码所示。

而调用查看详细页面的事件,传递对应的id并调用组件实例抛出的方法即可。如下代码所示。

// 显示查看对话框处理
const viewRef = ref<InstanceType<typeof ViewData>>();
function showView(id) {
viewRef.value.show(id);
}

至此,一个独立的视图页面组件,以及如何触发调用就完成了,视图页面单独维护,便于代码的管理,同时也隔离了复杂的页面逻辑。

视图页面效果如下所示。

2)新增编辑视图页面

在常规的处理中,往往编辑和新增的界面是差不多的,差异不同的地方,我们可以通过条件 if 的方式进行处理即可。因此可以把两者放在一个组件中实现对话框内容和逻辑处理。

刚才我们提到了Index.vue页面,是对几个组件的统筹处理,如下代码所示。

<template>
<div class="main">
<!--条件及列表展示-->
<Search ref="searchRef" @show-import="showImport" @show-add="showAdd" @show-view="showView" @show-edit="showEdit" /> <!--查看详细组件界面-->
<view-data ref="viewRef" />
<!--新增、编辑组件界面-->
<edit-data ref="editRef" @submit="refreshData" />
<!--模板导入信息-->
<import-data ref="importRef" @finish="finishImport" />
</div>
</template>

从上面代码我们看到,在HTML代码中,我们引入对应的组件,并在主查询页面中触发事件即可,如下所示。

其中showAdd和ShowEdit类似,都是调用编辑/新增的对话框,不同的是,通过传递id来辨别是否为新增,如果需要传入pid的父节点信息,那么我们也可以创建一个showAdd的方法。

//新增、编辑表单引用
const editRef = ref<InstanceType<typeof EditData>>();
//显示新增对话框
function showAdd(pid?: string | number) {
editRef.value.showAdd(pid);
}
// 显示编辑对话框
function showEdit(id) {
editRef.value.show(id);
}
//新增/更新后刷新
function refreshData() {
searchRef.value.getlist();
}

编辑业务数据的对话框和查看详细的类似,不过这里是需要使用输入控件进行内容编辑修改处理的。

对于一些复杂控件,我们可以自定义组件来简化在界面上的使用,尽可能的快捷、简单。

我们在组件中定义showAdd和show的方法,便于父组件的调用即可,如果传递了id值,我们根据业务对象的get方法获取详细的数据,赋值到表单对象上就可以正常显示了。

//默认标题为[编辑信息],当show传入id为空的时候,为[新建信息]
let title = ref('编辑信息');
let isAdd = ref(false); //是否新增状态 //显示窗口(编辑/新建)
const showAdd = async (pid?: string | number) => {
title.value = '新建信息';
isAdd.value = true;
resetFields(); //清空表单
editForm.pid = pid + '';
isVisible.value = true; //显示对话框
};
const show = async (id?: string | number) => {
if (!$u.test.isNullOrUnDef(id)) {
title.value = '编辑信息';
isAdd.value = false;
await menu.Get(id).then((data) => {
Object.assign(editForm, data);
});
} else {
title.value = '新建信息';
isAdd.value = true;
resetFields(); //清空表单
}
isVisible.value = true; //显示对话框
};

抛出这两个实例的方法,供外面调用。

//暴露组件属性和方法
defineExpose({
show,
showAdd,
});

为了承载表单的数据模型,我们创建相关的业务对象

const editRef = ref<FormInstance>(); //表单引用
// 表单属性定义(初始化)
let editForm = reactive({
id: '',
pid: '',
name: '',
icon: '',
functionId: '',
winformType: '',
url: '',
seq: '001',
isTop: false,
expand: 1,
visible: 1,
webIcon: '',
tag: 'web', // Web专用
});

保存数据的时候,我们判断表单的rules规则,如果符合通过,那么提交数据并提示用户即可。

// 保存数据处理
async function submitData() {
var formEl = editRef.value;
if (!formEl) return; await formEl.validate(async (valid) => {
if (valid) {
//验证成功,执行下面方法
var result = false;
if (isAdd.value) {
result = await menu.Create(editForm); //新增保存
} else {
result = await menu.Update(editForm); //编辑保存
} if (result) {
$u.success('操作成功!'); // 提示信息
emit('submit'); // 提示刷新数据
closeDialog(); // 重置窗口状态
} else {
$u.error('操作失败');
}
}
});
}

编辑界面的效果如下所示。

3)导入界面的处理

导入界面,一般我们分为几个步骤,一个是提供导入模板下载,然后上传文件并显示数据,然后确认提交即可。

由于导入数据的逻辑上大致类似,不同的是他们的业务数据和验证规则,因此我们通过自定义组件的方式,来简化相关的处理。

我通过改造ele-import 的第三方组件,让它支持Vue3+Typescript语法,实现对业务数据的上传操作。

<template>
<div class="main">
<!--条件及列表展示-->
<Search ref="searchRef" @show-import="showImport" @show-add="showAdd" @show-view="showView" @show-edit="showEdit" />
<import-data ref="importRef" @finish="finishImport" />
</div>
</template>

而在import.vue页面里面,我们的代码是使用ele-import来处理即可。

<template>
<div>
<!-- 模板导入信息 -->
<ele-import :fields="importForm.fields" :filepath="importForm.filepath" :append="importForm.append"
:formatter="importForm.formatter" :rules="importForm.rules" :tips="importForm.tips" :title="importForm.title"
:visible="isVisible" :request-fn="saveImport" @close="close" @finish="finishImport" />
</div>
</template>

通过传入对应的数据,如导入字段,以及规则,以及下载文件等相关参数,就可以实现了文件的上传处理了。

// 请求服务端处理上传数据,返回一个Promise对象
const saveImport = async (data) => {
// console.log(data);
const result = await menu.SaveImport(data);
// console.log(result);
if (result) {
return Promise.resolve();
} else {
return Promise.reject();
}
};

同时,这也是一个弹出窗口,因此也需要暴露show方法给外部调用。

//显示窗口
const show = () => {
isVisible.value = true; //显示对话框
};
//暴露组件属性和方法
defineExpose({
show,
});

而这个组件的相关数据信息,定义在importForm中,我们来看看对应的数据格式。

const importForm = reactive({
// Excel 模板导入数据
// 弹出层标题
title: '功能菜单导入',
// 提示信息
tips: [], // ['商品编号 必填', '产品类型 必填', '商品名称 必填'],
// 字段名称参照表
fields: {
// 字段根据需要裁剪
pid: '父ID',
name: '显示名称',
icon: '图标',
seq: '排序',
url: 'Url地址',
webIcon: '菜单图标',
systemType_ID: '系统编号',
tag: '特殊标签',
},// 附加数据, 在每条记录上都会加这两个字段和值
append: {
// company: '广州爱奇迪',
// leader: '伍华聪'
},
// 参数校检, 和 element-ui 中 form表单中传递的rules一样, 都是使用的 async-validator 库
// https://element.eleme.cn/#/zh-CN/component/form#biao-dan-yan-zheng
rules: {
pid: { type: 'string', required: true, message: '父ID必填' },
name: { type: 'string', required: true, message: '显示名称必填' },
url: { type: 'string', required: true, message: 'Url地址必填' },
webIcon: { type: 'string', required: true, message: '菜单图标必填' },
systemType_ID: { type: 'string', required: true, message: '系统编号必填' },
tag: { type: 'string', required: true, message: '特殊标签必填' },
},
// Excel模板下载地址。注意, 只能是.xlsx的文件, .xls或者.cvs都会报错
filepath: 'http://localhost:5043/UploadFiles/template/功能菜单.xlsx',
});

整个导入模块,会通过这个对象的数据格式,进行不同的显示和校验处理等操作。界面效果如下所示。

其中第一步提示信息,并提供模板文件下载

第二步提供文件上传处理。

第三步确认数据并完成处理。

这种统一的操作,我们通过封装,隔离了逻辑步骤的协调处理,只需要在业务组件中生成相关的数据即可,便于使用。

2、利用代码生成工具快速生成

通过上面的介绍,我们了解到整个页面的组件代码结构,因此可以利用它们和数据表之间的关系,生成对应的页面组件,利用代码生成工具Database2Sharp强大的数据库元数据和模板引擎,我们构建了对应的框架代码生成规则,因此统一生成即可,提高了代码开发的效能,同时也统一了代码的结构,便于大项目的维护。

对于SQLSugar的项目框架,我们为了方便,分别单独提供后端代码和Web API代码的生成、Winform界面代码的生成,以及前面介绍到的Vue3+TypeScript+ElementPlus的代码生成操作。

代码生成工具的界面效果如下所示,通过入口菜单,可以实现不同部分的代码快速生成。

通过隔离页面组件的内容变化,实现变化不同通过数据库表关系生成,固定部分采用规定模板预置内容,实现了代码的快速生成操作。

基于SqlSugar的开发框架循序渐进介绍(15)-- 整合代码生成工具进行前端界面的生成的更多相关文章

  1. 基于SqlSugar的开发框架循序渐进介绍(17)-- 基于CSRedis实现缓存的处理

    在一个应用系统的开发框架中,往往很多地方需要用到缓存的处理,有些地方是为了便于记录用户的数据,有些地方是为了提高系统的响应速度,如有时候我们在发送一个短信验证码的时候,可以在缓存中设置几分钟的过期时间 ...

  2. 基于SqlSugar的开发框架循序渐进介绍(20)-- 在基于UniApp+Vue的移动端实现多条件查询的处理

    在做一些常规应用的时候,我们往往需要确定条件的内容,以便在后台进行区分的进行精确查询,在移动端,由于受限于屏幕界面的情况,一般会对多个指定的条件进行模糊的搜索,而这个搜索的处理,也是和前者强类型的条件 ...

  3. 基于SqlSugar的开发框架循序渐进介绍(21)-- 在工作流列表页面中增加一些转义信息的输出,在后端进行内容转换

    有时候,为了给前端页面输出内容,有时候我们需要准备和数据库不一样的实体信息,因为数据库可能记录的是一些引用的ID或者特殊字符,那么我们为了避免前端单独的进行转义处理,我们可以在后端进行统一的格式化后再 ...

  4. 基于SqlSugar的开发框架循序渐进介绍(3)-- 实现代码生成工具Database2Sharp的整合开发

    我喜欢在一个项目开发模式成熟的时候,使用代码生成工具Database2Sharp来配套相关的代码生成,对于我介绍的基于SqlSugar的开发框架,从整体架构确定下来后,我就着手为它们量身定做相关的代码 ...

  5. 基于SqlSugar的开发框架循序渐进介绍(4)-- 在数据访问基类中对GUID主键进行自动赋值处理

    我们在设计数据库表的时候,往往为了方便,主键ID一般采用字符串类型或者GUID类型,这样对于数据库表记录的迁移非常方便,而且有时候可以在处理关联记录的时候,提前对应的ID值.但有时候进行数据记录插入的 ...

  6. 基于SqlSugar的开发框架循序渐进介绍(5)-- 在服务层使用接口注入方式实现IOC控制反转

    在前面随笔,我们介绍过这个基于SqlSugar的开发框架,我们区分Interface.Modal.Service三个目录来放置不同的内容,其中Modal是SqlSugar的映射实体,Interface ...

  7. 基于SqlSugar的开发框架循序渐进介绍(6)-- 在基类接口中注入用户身份信息接口

    在基于SqlSugar的开发框架中,我们设计了一些系统服务层的基类,在基类中会有很多涉及到相关的数据处理操作的,如果需要跟踪具体是那个用户进行操作的,那么就需要获得当前用户的身份信息,包括在Web A ...

  8. 基于SqlSugar的开发框架循序渐进介绍(8)-- 在基类函数封装实现用户操作日志记录

    在我们对数据进行重要修改调整的时候,往往需要跟踪记录好用户操作日志.一般来说,如对重要表记录的插入.修改.删除都需要记录下来,由于用户操作日志会带来一定的额外消耗,因此我们通过配置的方式来决定记录那些 ...

  9. 基于SqlSugar的开发框架循序渐进介绍(12)-- 拆分页面模块内容为组件,实现分而治之的处理

    在早期的随笔就介绍过,把常规页面的内容拆分为几个不同的组件,如普通的页面,包括列表查询.详细资料查看.新增资料.编辑资料.导入资料等页面场景,这些内容相对比较独立,而有一定的代码量,本篇随笔介绍基于V ...

随机推荐

  1. 基于python3.7利用Motor来异步读写Mongodb提高效率

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_111 如果使用Python做大型海量数据批量任务时,并且backend用mongodb做数据储存时,常常面临大量读写数据库的情况. ...

  2. 关于Google词向量模型(googlenews-vectors-negative300.bin)的导入问题

    起因 项目中有如下代码: word2vec = KeyedVectors.load_word2vec_format('./GoogleNews-vectors-negative300.bin', bi ...

  3. mybatis 04: mybatis对象分析 + 测试代码简化 + 配置优化

    MyBatis对象分析 测试代码示例 package com.example.test; import com.example.pojo.Student; import org.apache.ibat ...

  4. 从零开始Blazor Server(12)--编辑菜单

    上个星期有点事,导致没法及时更新.现在我们继续更我们的从零开始系列. 这个系列也快要结束了,目前规划再有2-3篇,就结束了. 今天我们来说编辑菜单的问题,说实话菜单这种东西,你不更新代码加个页面,单独 ...

  5. SpringMVC完整版详解

    1.回顾MVC 1.1什么是MVC MVC是模型(Model).视图(View).控制器(Controller)的简写,是一种软件设计规范. 是将业务逻辑.数据.显示分离的方法来组织代码. MVC主要 ...

  6. Maven中使用ssm框架出现:org.apache.tomcat.util.modeler.BaseModelMBean.invoke 调用方法[manageApp]时发生异常

    org.apache.tomcat.util.modeler.BaseModelMBean.invoke 调用方法[manageApp]时发生异常 首先可以排查一下像: @RequestMapping ...

  7. 变废为宝: 使用废旧手机实现实时监控方案(RTSP/RTMP方案)

    随着手机淘汰的速度越来越快,大多数手机功能性能很强劲就不再使用了,以大牛直播SDK现有方案为例,本文探讨下,如何用废旧手机实现实时监控方案(把手机当摄像头做监控之用): 本方案需要准备一个手机作为采集 ...

  8. C++基础入门:C++初始

    1. C++环境:Clion搭建 下载链接:clion官方网址 1.1 点击下载 1.2 下载对应版本 1.3 安装步骤: 1.3.1 下载完毕后,打开exe文件,进入安装界面,点击[Next > ...

  9. PostgreSQL 绑定变量窥探

    今天我们要探讨的是 custom执行计划和通用执行计划.这一技术在 Oracle中被称为绑定变量窥视.但 Kingbase中并没有这样的定义,更严格地说,Kingbase叫做custom执行计划和通用 ...

  10. 用bash反弹shell

    用bash反弹shell 受害主机:linux系统 攻击机:需要安装netcat(nc) 受害主机执行:ifconfig  ## 查看受害主机ip 攻击机执行:nc -lvp 19999 ## 在攻击 ...