基于Admin.NET框架的前端的一些改进和代码生成处理(1)
<p>Admin.NET 是一套基于Furion/.NET 6实现的通用管理平台,模块插件式开发,框架包含了常规的权限管理、字典等管理模块,以及一些Vue3的Demo案例,框架前后端分离。后端基于基于Furion/.NET 6实现,底层集成SqlSugar;前端则是采用Vue-Next-Admin的前端框架,整体是一套非常不错的框架。本人比较喜欢研究一些技术框架,最近对该框架进行了一些研究分析,结合我自己开发框架的思路,对其前后端进行一定的修改调整,本篇随笔记录一些对该框架的相关修改内容。</p><p>Admin.NET官网的的地址:https://gitee.com/zuohuaijun/Admin.NET,Vue-Next-Admin的官网地址:https://lyt-top.gitee.io/vue-next-admin-doc-preview/,有兴趣可以分别到官网上进行预览了解。</p>
<h3>1、API及对象接口的处理</h3>
<p>一般的前端,为了访问后端接口,以及转换对象,都需要构建后端接口的API代理类,以及相关的对象接口定义,Admin.NET的前端这部分内容放在 <strong>api-services </strong>目录 下,包含了apis和models两个目录</p>
<p><img src="https://img2023.cnblogs.com/blog/8867/202303/8867-20230328160558240-1290244019.png" alt="" width="219" height="127" loading="lazy"></p>
<p> 不过由于它们可能使用基于类似 generator-swagger-2-ts 插件的方式进行前端代码的生成,因此代码显得非常臃肿,一个简单的API需要来回的封装接口进行调用,以字典API为例,每个API的类代码都显得很臃肿,接近1000行代码,这个和我们实际的API调用不太匹配,我们一般只需要简单的调用就可以做到了,太多的代码不利于阅读和维护。</p>
<p>在我的随笔《基于SqlSugar的开发框架循序渐进介绍(10)-- 利用axios组件的封装,实现对后端API数据的访问和基类的统一封装处理》中介绍过前端的API调用过程场景,如下所示。</p>
<p><img src="https://img2020.cnblogs.com/blog/8867/202104/8867-20210427152546877-276221271.png" alt="" class="medium-zoom-image" loading="lazy"></p>
<p>前端一般根据框架后端的接口进行前端JS端的类的封装处理,引入了ES6类的概念实现业务基类接口的统一封装,简化代码。</p>
<p>一般我们在基类BaseApi中创建一些常用API的调用处理,那么常用的业务类继承BaseApi,就会具有相关的接口了,如下所示继承关系。</p>
<p><img src="https://img2020.cnblogs.com/blog/8867/202007/8867-20200713152737929-890201160.png" alt="" class="medium-zoom-image" loading="lazy"></p>
<p>这样我们代码就会变得简洁很多,维护阅读都非常方便。</p>
<p>我们遵循Admin.NET的目录结构,如下所示放置Api接口和业务对象接口类。</p>
<p><img src="https://img2023.cnblogs.com/blog/8867/202303/8867-20230328161609137-1226211726.png" alt="" width="342" height="140" loading="lazy"></p>
<p> 根据是否具有常规接口的后台接口定义,我们创建两个不同的基类BaseNormal 和 <span>BaseApi ,</span>这样我们便于实际的业务类Api的封装抽象。</p>
<p>如下是常规的基类,不具有任何基类接口,只是为了方便构造一些参数</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 此类作为普通API的基类,不继承常规的通用CRUD方法,如文件操作,服务器信息等类
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
export </span><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> BaseNormal {
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 服务器请求的起始路径, 类似 '</span><span style="color: rgba(0, 128, 0, 1); text-decoration: underline">http://localhost</span><span style="color: rgba(0, 128, 0, 1)">:**
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">protected</span> basePath =<span style="color: rgba(0, 0, 0, 1)"> serveConfig.basePath;
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* Api路径。子类通过构造函数修改, 其中api转义为具体的路径,如'/api/test'
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">protected</span> apiPath = <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/api/test</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 请求完整路径(除了方法名),类似 `</span><span style="color: rgba(0, 128, 0, 1); text-decoration: underline">http://localhost</span><span style="color: rgba(0, 128, 0, 1)">:**\/api/test`
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">protected</span> baseUrl = <span style="color: rgba(0, 0, 255, 1)">this</span>.basePath + <span style="color: rgba(0, 0, 255, 1)">this</span>.apiPath;<span style="color: rgba(0, 128, 0, 1)">//
</span>
<span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 定义一个axios变量,便于子类访问
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">protected</span> axiosInstance =<span style="color: rgba(0, 0, 0, 1)"> axiosInstance;
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 构造函数,接受Api路径,如'/api/test'
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
constructor(apiPath: </span><span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 构造函数</span>
<span style="color: rgba(0, 0, 255, 1)">this</span>.apiPath =<span style="color: rgba(0, 0, 0, 1)"> apiPath;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.baseUrl = <span style="color: rgba(0, 0, 255, 1)">this</span>.basePath + <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.apiPath;
}
}</span></pre>
</div>
<p>下面是一个具有数据访问CRUD的操作接口,如下所示。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 服务器请求基础类
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
export </span><span style="color: rgba(0, 0, 255, 1)">class</span> BaseApi<EntityType = any, AddType = any, UpdateType = any><span style="color: rgba(0, 0, 0, 1)"> extends BaseNormal {
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 分页获取列表
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
page </span>= <span style="color: rgba(0, 0, 255, 1)">async</span> (data: <span style="color: rgba(0, 0, 255, 1)">object</span> | <span style="color: rgba(0, 0, 255, 1)">null</span>) =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">const</span> url = <span style="color: rgba(0, 0, 255, 1)">this</span>.baseUrl + `/<span style="color: rgba(0, 0, 0, 1)">page`;
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">await</span> <span style="color: rgba(0, 0, 255, 1)">this</span>.axiosInstance.<span style="color: rgba(0, 0, 255, 1)">get</span><<span style="color: rgba(255, 0, 0, 1)"><strong>UnifyResult</strong></span><<span style="color: rgba(255, 0, 0, 1)"><strong>SqlSugarPagedList</strong></span><EntityType>>>(url, { <span style="color: rgba(0, 0, 255, 1)">params</span><span style="color: rgba(0, 0, 0, 1)">: data })
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 获取列表
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
list </span>= <span style="color: rgba(0, 0, 255, 1)">async</span> (data: <span style="color: rgba(0, 0, 255, 1)">object</span> | <span style="color: rgba(0, 0, 255, 1)">null</span>) =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">const</span> url = <span style="color: rgba(0, 0, 255, 1)">this</span>.baseUrl + `/<span style="color: rgba(0, 0, 0, 1)">list`;
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">await</span> <span style="color: rgba(0, 0, 255, 1)">this</span>.axiosInstance.<span style="color: rgba(0, 0, 255, 1)">get</span><<strong><span style="color: rgba(255, 0, 0, 1)">UnifyResult</span></strong><Array<EntityType>>>(url, { <span style="color: rgba(0, 0, 255, 1)">params</span><span style="color: rgba(0, 0, 0, 1)">: data })
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 新增记录
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
add </span>= <span style="color: rgba(0, 0, 255, 1)">async</span> (data: AddType) =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">const</span> url = <span style="color: rgba(0, 0, 255, 1)">this</span>.baseUrl + `/<span style="color: rgba(0, 0, 0, 1)">add`;
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">await</span> <span style="color: rgba(0, 0, 255, 1)">this</span>.axiosInstance.post<<strong><span style="color: rgba(255, 0, 0, 1)">UnifyResult</span></strong><<span style="color: rgba(0, 0, 255, 1)">void</span>>><span style="color: rgba(0, 0, 0, 1)">(url, data)
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 更新记录
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
update </span>= <span style="color: rgba(0, 0, 255, 1)">async</span> (data: UpdateType) =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">const</span> url = <span style="color: rgba(0, 0, 255, 1)">this</span>.baseUrl + `/<span style="color: rgba(0, 0, 0, 1)">update`;
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">await</span> <span style="color: rgba(0, 0, 255, 1)">this</span>.axiosInstance.post<<span style="color: rgba(255, 0, 0, 1)"><strong>UnifyResult</strong></span><<span style="color: rgba(0, 0, 255, 1)">void</span>>><span style="color: rgba(0, 0, 0, 1)">(url, data)
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 删除记录
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
delete </span>= <span style="color: rgba(0, 0, 255, 1)">async</span> (data: <span style="color: rgba(0, 0, 255, 1)">object</span>) =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">const</span> url = <span style="color: rgba(0, 0, 255, 1)">this</span>.baseUrl + `/<span style="color: rgba(0, 0, 0, 1)">delete`;
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">await</span> <span style="color: rgba(0, 0, 255, 1)">this</span>.axiosInstance.post<<span style="color: rgba(255, 0, 0, 1)"><strong>UnifyResult</strong></span><<span style="color: rgba(0, 0, 255, 1)">void</span>>><span style="color: rgba(0, 0, 0, 1)">(url, data)
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">* 批量删除 </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
batchDelete </span>= <span style="color: rgba(0, 0, 255, 1)">async</span> (data: <span style="color: rgba(0, 0, 255, 1)">object</span>) =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">const</span> url = <span style="color: rgba(0, 0, 255, 1)">this</span>.baseUrl + `/<span style="color: rgba(0, 0, 0, 1)">BatchDelete`;
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">await</span> <span style="color: rgba(0, 0, 255, 1)">this</span>.axiosInstance.post<<span style="color: rgba(255, 0, 0, 1)"><strong>UnifyResult</strong></span><<span style="color: rgba(0, 0, 255, 1)">void</span>>><span style="color: rgba(0, 0, 0, 1)">(url, data)
}
}</span></pre>
</div>
<p>根据接口返回的内容,其中<strong style="color: rgba(255, 0, 0, 1); font-family: "Courier New"; font-size: 12px">UnifyResult</strong> 对象接口是统一接口返回的处理对象,我们在types目录中定义即可,而<strong style="color: rgba(255, 0, 0, 1)">SqlSugarPagedList</strong>则是Admin.NET分页返回的结果集合,这些基础类接口也是定义types目录中即可。</p>
<p><img src="https://img2023.cnblogs.com/blog/8867/202303/8867-20230328162331550-1535318449.png" alt="" loading="lazy"></p>
<p> <img src="https://img2023.cnblogs.com/blog/8867/202303/8867-20230328162350888-1822370630.png" alt="" width="866" height="675" loading="lazy"></p>
<p> 而对于对应后端业务类对象接口的定义,我们倾向于把它按业务区分,一个业务类对应的放在一个独立的文件中定义即可,如下所示。</p>
<p><img src="https://img2023.cnblogs.com/blog/8867/202303/8867-20230328162636455-1917509593.png" alt="" width="856" height="729" loading="lazy"></p>
<p> 一般包含一个标准的对象接口,增加对象、修改对象、查询对象等接口对象。</p>
<p>其中由于常规的业务对象接口,往往都具备一些基础的属性,因此我们把这些基础属性放到基类里面定义,然后在实际的业务对象接口中继承基类对象就可以了。</p>
<p><img src="https://img2023.cnblogs.com/blog/8867/202303/8867-20230329095517019-1940873318.png" alt="" width="856" height="938" loading="lazy"></p>
<p> </p>
<p> 业务API代理类的定义,这是根据这些模型的信息进行简单的声明即可,如下对于菜单,如果不考虑除了增删改查的其他额外的接口,那么只需要简单的继承BaseApi即可。</p>
<div class="cnblogs_code">
<pre>import { BaseApi } <span style="color: rgba(0, 0, 255, 1)">from</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">./base-api</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">;
import { SysMenu, UpdateMenuInput, AddMenuInput, MenuOutput } </span><span style="color: rgba(0, 0, 255, 1)">from</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/@/api/models</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 菜单管理Api
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">class</span> SysMenuApi extends <span style="color: rgba(255, 0, 0, 1)"><strong>BaseApi<SysMenu, AddMenuInput, UpdateMenuInput></strong></span><span style="color: rgba(0, 0, 0, 1)"> {
.............</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">其他接口定义</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
}
export </span><span style="color: rgba(0, 0, 255, 1)">default</span> <span style="color: rgba(0, 0, 255, 1)">new</span> SysMenuApi(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/api/sysMenu</span><span style="color: rgba(128, 0, 0, 1)">'</span>);</pre>
</div>
<p>对于没有标准CRUD接口的非常规API接口,我们可以让它继承NormalApi即可。</p>
<div class="cnblogs_code">
<pre>import { BaseNormal} <span style="color: rgba(0, 0, 255, 1)">from</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">./base-api</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">;
import { ConstOutput } </span><span style="color: rgba(0, 0, 255, 1)">from</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/@/api/models</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 系统常量服务 管理Api
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> SysConstApi extends BaseNormal {
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 获取所有常量列表
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
list </span>= <span style="color: rgba(0, 0, 255, 1)">async</span> () =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">const</span> url = <span style="color: rgba(0, 0, 255, 1)">this</span>.baseUrl + `/<span style="color: rgba(0, 0, 0, 1)">list`;
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">await</span> <span style="color: rgba(0, 0, 255, 1)">this</span>.axiosInstance.<span style="color: rgba(0, 0, 255, 1)">get</span><UnifyResult<Array<ConstOutput>>>(url, { <span style="color: rgba(0, 0, 255, 1)">params</span>: <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)"> })
}
}
export </span><span style="color: rgba(0, 0, 255, 1)">default</span> <span style="color: rgba(0, 0, 255, 1)">new</span> SysConstApi(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/api/sysConst</span><span style="color: rgba(128, 0, 0, 1)">'</span>);</pre>
</div>
<p>有了这些内容我们就可以在实际业务视图中进行API接口的调用了。</p>
<p>对于原先的Admin.NET的业务接口调用,他们需要先引入一个工厂类,然后构造处理才能调用接口,如下定义:</p>
<div class="cnblogs_code">
<pre>import { getAPI } <span style="color: rgba(0, 0, 255, 1)">from</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/@/utils/axios-utils</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">;
import { SysMenuApi } </span><span style="color: rgba(0, 0, 255, 1)">from</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/@/api-services/api</span><span style="color: rgba(128, 0, 0, 1)">'</span>;</pre>
</div>
<p>原先的Admin.NET视图组件中的实际的调用代码如下所示。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 查询操作</span>
<span style="color: rgba(0, 0, 255, 1)">const</span> handleQuery = <span style="color: rgba(0, 0, 255, 1)">async</span> () =><span style="color: rgba(0, 0, 0, 1)"> {
state.loading </span>= <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">var</span> res = <span style="color: rgba(0, 0, 255, 1)">await</span><span style="color: rgba(0, 0, 0, 1)"><strong><span style="color: rgba(255, 0, 0, 1)"> getAPI(SysMenuApi).apiSysMenuListGet</span></strong>(state.queryParams.title, state.queryParams.type);
state.menuData </span>= res.data.result ??<span style="color: rgba(0, 0, 0, 1)"> [];
state.loading </span>= <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
};</span></pre>
</div>
<p>由于他们是采用Swagger的接口生成,因此默认接口名称都带有api的前缀,Get或者Post的后缀,感觉不是那么易读。</p>
<p>而对于我们重构过的处理逻辑,定义代码如下所示。</p>
<div class="cnblogs_code">
<pre>import { SysMenu } <span style="color: rgba(0, 0, 255, 1)">from</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/@/api/models</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">;
import <strong><span style="color: rgba(255, 0, 0, 1)">menuApi</span> </strong></span><span style="color: rgba(0, 0, 255, 1)">from</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/@/api/apis/sys-menu-api</span><span style="color: rgba(128, 0, 0, 1)">'</span></pre>
</div>
<p>实际视图或者组件中的调用代码如下所示。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 查询操作</span>
<span style="color: rgba(0, 0, 255, 1)">const</span> handleQuery = <span style="color: rgba(0, 0, 255, 1)">async</span> () =><span style="color: rgba(0, 0, 0, 1)"> {
state.loading </span>= <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">var</span> res = <span style="color: rgba(0, 0, 255, 1)">await</span><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(255, 0, 0, 1)"><strong> menuApi.list</strong></span>(state.queryParams);
state.menuData </span>= res.data.result ??<span style="color: rgba(0, 0, 0, 1)"> [];
state.loading </span>= <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
};</span></pre>
</div>
<p>实际调用代码简单只是一点点,但是Api的定义代码,从上千行调用代码则锐减到仅仅几行代码就可以了,减少了大量重复的累赘接口定义,以及很多模型接口重复定义操作(例如对于分页返回的对象,他们每次都生成一遍重读的类型,而这里则是使用泛型基于<strong style="color: rgba(255, 0, 0, 1)">SqlSugarPagedList的方式进行简化</strong>)。</p>
<p> </p>
<h3>2、基于代码生成工具的生成</h3>
<p>有些人说他们虽然代码多了一点,贵在能够根据接口自动生成前端代码呀,确实能自动生成代码是非常不错的一件事情,可以极大提高效率。</p>
<p>那么我们也根据接口的通用性,来构建代码生成的相关规则即可。由于这些接口的生成,大多数情况下,都是以数据库表和字段的规则进行生成的,因此我把它整合在代码生成工具的功能上生成即可。</p>
<p><img src="https://img2023.cnblogs.com/blog/8867/202303/8867-20230328164253520-409937357.png" alt="" width="729" height="752" loading="lazy"></p>
<p> <img src="https://img2023.cnblogs.com/blog/8867/202303/8867-20230328164418167-1172020496.png" alt="" width="779" height="438" loading="lazy"></p>
<p> <img src="https://img2023.cnblogs.com/blog/8867/202303/8867-20230328164531665-729044419.png" alt="" width="774" height="682" loading="lazy"></p>
<p>最后我们把生成的Api部分代码放在目录中</p>
<p><img src="https://img2023.cnblogs.com/blog/8867/202303/8867-20230328164635230-964259944.png" alt="" loading="lazy"></p>
<p> 视图代码放在views目录里面对应的目录即可,如下是测试生成的页面,包括有index.vue 页面,以及edit.vue,以及import.vue的页面。</p>
<p>其中index是主页面查询及列表展示内容,edit.vue是新增和编辑界面内容,而import.vue这是导入界面内容。</p>
<p>目录文件如下图所示。</p>
<p><img src="https://img2023.cnblogs.com/blog/8867/202303/8867-20230328164737780-1889460850.png" alt="" loading="lazy"></p>
<p>自动生成的index.vue页面代码,根据预定义的模板进行生成,经过多次的校准,已经比较完美的根据数据库表字段及备注信息,生成视图代码了。</p>
<p><img src="https://img2023.cnblogs.com/blog/8867/202303/8867-20230328165534271-739775968.png" alt="" width="1213" height="1256" loading="lazy"></p>
<p>生成的页面,进行一定的微调即可用于实际的生产业务中了。 </p>
<p>该测试页面添加完成后,在后端创建一个菜单指向它即可,编译运行界面效果如下所示。</p>
<p>我改变了一下常规的界面功能,增加了导入、导出、批量删除的操作入口。</p>
<p><img src="https://img2023.cnblogs.com/blog/8867/202303/8867-20230328165044442-2141615400.png" alt="" width="1112" height="336" loading="lazy"></p>
<p> </p>
<p> 默认进行折叠,展开则列出所有条件,如下界面所示。</p>
<p><img src="https://img2023.cnblogs.com/blog/8867/202303/8867-20230328165237626-2140439758.png" alt="" width="1075" height="299" loading="lazy"></p>
<p> </p>
<p>导入界面是改进了ele-Import插件,得到界面效果如下所示。</p>
<p><img src="https://img2023.cnblogs.com/blog/8867/202303/8867-20230328165354176-723771351.png" alt="" width="1050" height="542" loading="lazy"></p>
<p> 导出则是利用xlsx的插件进行导出Excel文件。 </p>
<p> 如果需要了解代码生成,可以下载Database2Sharp代码生成工具 进行了解。</p>
<p> </p>
</div>
<div id="MySignature" role="contentinfo">
<div style="border-right-color: #cccccc; border-right-width: 1px; border-right-style: solid; padding-right: 5px; border-top-color: #cccccc; border-top-width: 1px; border-top-style: solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left-color: #cccccc; border-left-width: 1px; border-left-style: solid; width: 98%; padding-top: 4px; border-bottom-color: #cccccc; border-bottom-width: 1px; border-bottom-style: solid; background-color: #eeeeee;">
<img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt>
<span style="color: #000000"><span class="Apple-tab-span" style="white-space: pre"></span>
专注于代码生成工具、.Net/Python 框架架构及软件开发,以及各种Vue.js的前端技术应用。著有Winform开发框架/混合式开发框架、微信开发框架、Bootstrap开发框架、ABP开发框架、SqlSugar开发框架、Python开发框架等框架产品。
<br> 转载请注明出处:撰写人:伍华聪 http://www.iqidi.com <br> </span></div><br><br>
来源:https://www.cnblogs.com/wuhuacong/p/17265578.html
頁:
[1]