前言 前面使用 Admin.Core 的代碼生成器生成了通用代碼生成器的基礎模塊 分組,模板,項目,項目模型,項目欄位的基礎功能,本篇繼續完善,實現最核心的模板生成功能,並提供生成預覽及代碼文件壓縮下載 準備 首先清楚幾個模塊的關係,如何使用,簡單畫一個流程圖 前面完成了基礎的模板組,模板管理,項目 ...
前言
前面使用 Admin.Core 的代碼生成器生成了通用代碼生成器的基礎模塊 分組,模板,項目,項目模型,項目欄位的基礎功能,本篇繼續完善,實現最核心的模板生成功能,並提供生成預覽及代碼文件壓縮下載
準備
首先清楚幾個模塊的關係,如何使用,簡單畫一個流程圖
前面完成了基礎的模板組,模板管理,項目,模型,欄位管理,都是由 Admin.Core 框架的代碼生成器完成,感興趣的可參考前篇使用,文末也會給出倉庫地址,有問題歡迎交流
本文主要分享項目代碼的生成,先放出效果圖
- 項目生成管理,支持多模板組
- 模板生成預覽,預覽頁可以直接編輯模板
- 模板生成,將生成壓縮包並下載
實現
需要實現上面效果的代碼生成器,基礎的增刪改查都可以藉由代碼生成器生成,也寫過幾篇了這裡就不再贅述,我們只需要關註核心部分:如何生成?如何預覽?如何下載?
根據模板生成對應項目的代碼文件
當我們有了一個模板(模板內容),也有了對應的配置項(項目&項目模型&項目欄位),中間肯定是需要一個模板引擎來將模板根據配置項解析出來的。
市面上有很多模板引擎,比如 ejs,art 等,但既然是搞C#的,那不妨試試看 Razor (之前的Admin.Core代碼生成器也是基於razor模板引擎,也可以換其他的或者支持多種模板引擎),C#的語法寫起來還是挺舒服的,並且其實還可以新建一個.net core 的項目添加頁面後可以複製模板和模型到頁面為自己的模板增加智能提示
模板引擎的使用
-
項目中引用包:RazorEngine.NetCore
- 原版只支持 framework,大佬打包的 netcore 版本
<ItemGroup>
<PackageReference Include="RazorEngine.NetCore" Version="3.1.0" />
</ItemGroup>
- 使用方式:指定模型,內容,模板名稱即可
var code="模板內容";
var key="模板名";
//模型名稱
var model=new DevProjectRazorRenderModel();
RazorEngine.Engine.Razor.RunCompile(new LoadedTemplateSource(code), key, model.GetType(), model);
-
模板內容的寫法
- 我這裡定義了固定模型,所以需要先什麼模型的變數,這裡指定了 gen
- 模板語法文檔
@{
var gen = Model as ZhonTai.Module.Dev.DevProjectRazorRenderModel;
}
- 這裡定義了一個公共的項目模型,後續增加項目模型欄位的信息都無需更搞代碼,生成即可,另外也可以再屬性模型中添加字典等屬性,即可靈魂的再模板中使用動態配置了
//模型渲染
var gen = new DevProjectRazorRenderModel()
{
Project = Mapper.Map<DevProjectGetOutput>(project),
Model = Mapper.Map<DevProjectModelGetOutput>(model),
Fields = Mapper.Map<List<DevProjectModelFieldGetOutput>>(modelFields),
};
模板內容的生成
- 這裡分為了兩部分,一個是文件路徑,一個是文件內容
- 因為要生成的路徑可能也會包含一些模塊或者模型的信息,所以可以將模板路徑也使用模板生成,這裡直接拼接一個模板即可
var pathCodeText = @"
@{
var gen = Model as ZhonTai.Module.Dev.DevProjectRazorRenderModel;
}
" + outPath;
//轉換路徑
var outPath = RazorCompile(gen, $"{project.Code}_{model.Code}_{tpl.Name}_Path.tpl", pathCodeText).Trim();
文末附完整代碼
內容文件的下載
- 因為是多模板組多模板,所以每次生成項目代碼都基本是多個文件,一個個下載很明顯不合理,所以可以將所有代碼內容文件打包成壓縮包進行下載,下麵是核心壓縮代碼,無需引用包,暫時只在Windows中測試使用
- 完整代碼如下,做了一些文件和文件夾的判斷處理,可自行封裝
- 通過GenerateAsync獲取到文件信息後寫入文件,再將目錄進行打包返回即可
/// <summary>
/// 下載
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost]
public async Task<ActionResult> DownAsync(DevProjectGenGenerateInput input)
{
var path = Path.Combine(AppContext.BaseDirectory, "DownCodes", DateTime.Now.ToString("yyyyMMddHHmmss"));
var zipFileName = $"源碼{DateTime.Now.ToString("yyyyMMddHHmmss")}.zip";
var zipPath = Path.Combine(AppContext.BaseDirectory, "DownCodes", zipFileName);
try
{
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
//獲取內容信息
var codes = await GenerateAsync(input);
foreach (var code in codes)
{
var codePath = Path.Combine(path, code.Path);
var directory = Path.GetDirectoryName(codePath);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
if (!File.Exists(codePath))
{
using (var fs = File.Open(codePath, FileMode.Create, FileAccess.ReadWrite))
{
await fs.WriteAsync(Encoding.UTF8.GetBytes(code.Content));
}
}
}
ZipFile.CreateFromDirectory(path, zipPath);
var bytes = await File.ReadAllBytesAsync(zipPath);
return new FileContentResult(bytes, "application/zip")
{
FileDownloadName = zipFileName
};
}
finally
{
if (Directory.Exists(path))
{
Directory.Delete(path, true);
}
if (File.Exists(zipPath))
{
File.Delete(zipPath);
}
}
}
前端對應需要支持文件下載,可以修改為生成對應下載URL,用GET請求直接打開新視窗進行下載
項目中前端頁面的重點
整個框架主要使用者肯定是.net開發,如果沒有寫過 vue 項目,寫起來的時候可能會有一些吃力,但因為現在有了代碼生成器,大部分代碼都可以生成,也可以做參考,所以這裡只做一些關鍵點的說明
框架頁面菜單的添加說明:具體可參考前文進行創建
- 系統管理-添加視圖->指定 vue 頁面文件的路徑,可再許可權菜單中復用這個視圖生成不同的路由地址
- 介面管理-同步介面->將後端服務映射為許可權點,對應後端功能許可權
- 許可權管理-添加許可權->添加菜單,功能點
- 用戶-角色->通過角色分配角色許可權,用戶管理角色
Vue 文檔
有時間的話至少過一遍再開始,磨刀不誤砍柴工
生命周期的一定花時間看看:官方文檔
頁面中獲取路由信息與頁面跳轉
以項目生成頁面調整到預覽頁面為例
- 項目生成頁和預覽頁引入定義
//引入路由
import { useRoute, useRouter } from 'vue-router'
//路由信息
const route = useRoute()
//路由跳轉
const router = useRouter()
- 跳轉到預覽頁
router.push({
path: '/dev/dev-project-gen/preview', query: {
projectId: row.projectId,
groupIds: row.groupIds_Values
}
})
- 預覽頁獲取生成列表傳遞的參數
//從路由中獲取query參數
onMounted(() => {
state.filter.projectId = route.query.projectId
state.filter.groupIds = route.query.groupIds
})
左側樹/列表右側預覽實現
將左側的列表列封裝為一個組件,右側如果簡單可封裝,也可以直接寫到預覽頁面
這裡參考框架中用戶列表做的
<my-layout class="my-layout">
<pane size="30" min-size="20" max-size="35">
<div class="my-flex-column w100 h100">
<group-template-menu :groupIds="state.filter.groupIds" :projectId="state.filter.projectId"
@node-click="onNodeClick" select-first-node></group-template-menu>
</div>
</pane>
<pane size="70" v-loading="state.loading">
<div class="my-flex-column w100 h100">
內容預覽部分
</div>
</pane>
</my-layout>
當然,封裝了組件記得引入用到的組件
const GroupTemplateMenu = defineAsyncComponent(() => import('./components/dev-group-template-menu.vue'))
const MyLayout = defineAsyncComponent(() => import('/@/components/my-layout/index.vue'))
組件中獲取傳遞的參數示例
interface Props {
modelValue: number[] | null | undefined
selectFirstNode: boolean,
projectId: number,
groupIds: number[]
}
const props = withDefaults(defineProps<Props>(), {
modelValue: () => [],
selectFirstNode: false,
projectId: 0,
groupIds: () => []
})
在預覽左側菜單中,我們可以看到一個標記的小圖標,用來直接編輯模板
這個彈窗其實是直接引用了編輯模板的組件
<template>
...
<dev-template-form ref="devTemplateFormRef" :title="'編輯模板'"></dev-template-form>
...
</template>
<script>
...
// 引入組件
const DevTemplateForm = defineAsyncComponent(() => import('../../dev-template/components/dev-template-form.vue'))
//使用
const devTemplateFormRef = ref()
const editTemplate = (node, data) => {
devTemplateFormRef.value.open({
id: data.id
})
}
...
</script>
defineExpose({
open,
})
如上可以看到我們使用和組件同名的 const devTemplateFormRef = ref() 即可獲取到組件引用
另外調用的方法可以查看 dev-template-form.vue 是開放了方法的
defineExpose({
open,
})
下載壓縮包文件
首先需要後端返迴文件流,然後調用對應介面的時候指定format格式為blob,並創建下載連接點擊即可
const genCode = async (row: DevProjectGenGetOutput) => {
new DevProjectGenApi().down({ projectId: row.projectId, groupIds: row.groupIds_Values?.map(s => Number(s)) }, {
loading: false,
showErrorMessage: false,
format: 'blob'
})
.then((res) => {
const a = document.createElement('a');
a.href = URL.createObjectURL(res as Blob);
a.download = '源碼.zip';
a.click();
});
}
後語
本文所有代碼皆在 yimogit/Emo.Dev 倉庫中可以找到,覺得有用的來個 Star 吧
基於前面代碼生成器生成的功能模塊上,周末花了兩天完善項目生成,終於算是搞定
後面還需要逐步完善生成器,歡迎點個贊,留個言,交流指點一二
相關文檔
- Emo.Dev 本文代碼倉庫,一個通用代碼生成器
- 代碼生成器系列文章
- abp-vnext-pro-suite 一個abp的生成器,功能設計上和下載都是參考借鑒了這個項目
- Admin.Core 項目所用到的框架
- RazorEngine.NetCore 模板引擎
- Razor 模板引擎語法
未經許可,禁止轉載!!!
作者:易墨
Github:yimogit
純靜態工具站點:metools