809 lines
35 KiB
C#
809 lines
35 KiB
C#
using StringHelper = SimpleTool.StringHelper;
|
|
|
|
namespace SimpleAdmin.System;
|
|
|
|
/// <summary>
|
|
/// <inheritdoc cref="IGenbasicService"/>
|
|
/// </summary>
|
|
public class GenBasicService : DbRepository<GenBasic>, IGenbasicService
|
|
{
|
|
private readonly ILogger<GenBasicService> _logger;
|
|
private readonly IViewEngine _viewEngine;
|
|
private readonly IGenConfigService _genConfigService;
|
|
private readonly IMenuService _menuService;
|
|
private readonly IButtonService _buttonService;
|
|
private readonly ISysRoleService _roleService;
|
|
private readonly string _sqlDir = "Sql";
|
|
private readonly string _backendDir = "Backend";
|
|
private readonly string _frontDir = "Frontend";
|
|
private const string _interfaceDir = "interface";
|
|
private const string _modulesDir = "modules";
|
|
private const string _indexTs = "index.ts";
|
|
|
|
public GenBasicService(ILogger<GenBasicService> logger,
|
|
IViewEngine viewEngine,
|
|
IGenConfigService genConfigService,
|
|
IMenuService menuService,
|
|
IButtonService buttonService, ISysRoleService roleService)
|
|
{
|
|
_logger = logger;
|
|
_viewEngine = viewEngine;
|
|
_genConfigService = genConfigService;
|
|
_menuService = menuService;
|
|
_buttonService = buttonService;
|
|
_roleService = roleService;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public async Task<SqlSugarPagedList<GenBasic>> Page(BasePageInput input)
|
|
{
|
|
var query = Context.Queryable<GenBasic>()
|
|
.OrderByIF(!string.IsNullOrEmpty(input.SortField), $"{input.SortField} {input.SortOrder}")//排序
|
|
.OrderBy(it => it.SortCode, OrderByType.Desc)//默认排序
|
|
.OrderBy(it => it.CreateTime, OrderByType.Desc)//默认排序
|
|
.Mapper(it =>
|
|
{
|
|
it.FuncList = it.Functions.Split(",", StringSplitOptions.RemoveEmptyEntries).ToList();//功能集合转为列表
|
|
});
|
|
var pageInfo = await query.ToPagedListAsync(input.PageNum, input.PageSize);//分页
|
|
return pageInfo;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public List<SqlSugarTableInfo> GetTables(bool isAll = false)
|
|
{
|
|
if (isAll)
|
|
return SqlSugarUtils.GetTablesByAttribute<SugarTable>();
|
|
return SqlSugarUtils.GetTablesByAttribute<CodeGenAttribute>();
|
|
}
|
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
public List<string> GetAssemblies()
|
|
{
|
|
var names = new List<string>();//结果集
|
|
var excludeList = new List<string>
|
|
{
|
|
"Web.Entry", "Core", "Cache", "SqlSugar", "Plugin.Core", "Plugin.Aop"
|
|
};//排除的程序集
|
|
//获取所有程序集名称
|
|
var assemblies = App.Assemblies
|
|
.Where(it => !it.FullName.StartsWith("MoYu"))
|
|
.Select(it => it.FullName).ToList();
|
|
assemblies.ForEach(it =>
|
|
{
|
|
var name = it.Split(",")[0];//根据逗号分割取第一个
|
|
//根据.分割获取最后两个
|
|
|
|
|
|
var projectName = string.Join(".", name.Split(".").Skip(1).ToList());
|
|
if (!excludeList.Contains(projectName))//去掉排除的程序集
|
|
{
|
|
names.Add(name);
|
|
}
|
|
});
|
|
return names;
|
|
}
|
|
|
|
|
|
/// <inheritdoc/>
|
|
public async Task<GenBasic> Add(GenBasicAddInput input)
|
|
{
|
|
var entity = input.Adapt<GenBasic>();//输入参数转实体
|
|
entity.Functions = string.Join(",", input.FuncList);//功能集合
|
|
var tableColumns = SqlSugarUtils.GetTableColumns(input.ConfigId, input.DbTable);//获取表的字段信息
|
|
var genConfigs = new List<GenConfig>();//代码生成配置字段集合
|
|
//遍历字段
|
|
var sortCode = 0;
|
|
//遍历字段
|
|
tableColumns.ForEach(it =>
|
|
{
|
|
#region 判断是否想显示
|
|
|
|
var yesOrNo = GenConst.Yes;
|
|
if (it.IsPrimaryKey || SqlSugarUtils.IsCommonColumn(it.ColumnName))//如果是主键或者是公共字段则不显示
|
|
yesOrNo = GenConst.No;
|
|
else
|
|
yesOrNo = GenConst.Yes;
|
|
|
|
#endregion 判断是否想显示
|
|
|
|
//添加到字段集合
|
|
genConfigs.Add(new GenConfig
|
|
{
|
|
IsPrimaryKey = it.IsPrimaryKey ? GenConst.Yes : GenConst.No,
|
|
FieldName = it.ColumnName,
|
|
FieldType = it.DataType,
|
|
FieldNetType = SqlSugarUtils.ConvertDataType(it.DataType),
|
|
FieldRemark = it.ColumnDescription ?? it.ColumnName,
|
|
EffectType = EffTypeConst.INPUT,
|
|
Width = 100,
|
|
WhetherTable = yesOrNo,
|
|
WhetherAddUpdate = yesOrNo,
|
|
WhetherImportExport = yesOrNo,
|
|
WhetherResizable = GenConst.No,
|
|
WhetherRequired = GenConst.No,
|
|
WhetherRetract = GenConst.No,
|
|
QueryWhether = GenConst.No,
|
|
SortCode = yesOrNo == GenConst.No ? 99 : sortCode//如果是公共字段就排最后
|
|
});
|
|
sortCode++;
|
|
});
|
|
var index = 0;
|
|
genConfigs = genConfigs.OrderBy(it => it.SortCode).ToList();//排序
|
|
genConfigs.ForEach(it =>
|
|
{
|
|
it.FieldIndex = index;
|
|
index++;
|
|
});
|
|
if (!genConfigs.Any(it => it.IsPrimaryKey == GenConst.Yes))//判断是否有主键
|
|
{
|
|
throw Oops.Bah("要生成的表必须有主键");
|
|
}
|
|
|
|
//事务
|
|
var result = await Tenant.UseTranAsync(async () =>
|
|
{
|
|
entity = await InsertReturnEntityAsync(entity);//输入参数转实体并插入
|
|
genConfigs.ForEach(it => { it.BasicId = entity.Id; });//遍历字段赋值基础Id
|
|
await Context.Insertable(genConfigs).ExecuteCommandAsync();
|
|
});
|
|
if (!result.IsSuccess)//如果失败了
|
|
{
|
|
//写日志
|
|
_logger.LogError(result.ErrorMessage, result.ErrorException);
|
|
throw Oops.Oh(ErrorCodeEnum.A0003);
|
|
}
|
|
|
|
return entity;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public async Task Delete(BaseIdListInput input)
|
|
{
|
|
//获取所有ID
|
|
var ids = input.Ids.ToList();
|
|
if (ids.Count > 0)
|
|
{
|
|
//事务
|
|
var result = await Tenant.UseTranAsync(async () =>
|
|
{
|
|
await DeleteByIdsAsync(ids.Cast<object>().ToArray());//删除基础表
|
|
await Context.Deleteable<GenConfig>().Where(it => ids.Contains(it.BasicId))
|
|
.ExecuteCommandAsync();//删除配置表
|
|
});
|
|
if (!result.IsSuccess)//如果失败了
|
|
{
|
|
//写日志
|
|
_logger.LogError(result.ErrorMessage, result.ErrorException);
|
|
throw Oops.Oh(ErrorCodeEnum.A0002);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public async Task<GenBasic> Edit(GenBasicEditInput input)
|
|
{
|
|
var entity = input.Adapt<GenBasic>();//输入参数转实体
|
|
entity.Functions = string.Join(",", input.FuncList);//功能集合
|
|
await UpdateAsync(entity);
|
|
return entity;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public async Task<GenBasePreviewOutput> PreviewGen(BaseIdInput input)
|
|
{
|
|
var genBasic = await GetGenBasic(input.Id);//获取代码生成基础
|
|
return await PreviewGen(genBasic);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public async Task ExecGenPro(ExecGenInput input)
|
|
{
|
|
var genBasic = await GetGenBasic(input.Id);//获取代码生成基础
|
|
if (genBasic.GenerateType != GenConst.Pro) throw Oops.Bah("当前配置生成方式为:项目中");
|
|
var backendPath =
|
|
Path.Combine(new DirectoryInfo(App.WebHostEnvironment.ContentRootPath).Parent.FullName);//获取主工程目录
|
|
if (await CreateMenuButtonAndRelation(genBasic))
|
|
{
|
|
var previewCode = await PreviewGen(genBasic);//获取代码生成预览
|
|
if (input.ExecType != GenConst.ExecAll)//如果不是全部执行
|
|
{
|
|
if (input.ExecType == GenConst.ExecBackend)
|
|
ExecBackend(previewCode.CodeBackendResults);//执行后端代码生成
|
|
else if (input.ExecType == GenConst.ExecFrontend)
|
|
ExecFronted(previewCode.CodeFrontendResults);//执行前端代码生成
|
|
}
|
|
else
|
|
{
|
|
ExecBackend(previewCode.CodeBackendResults);//执行后端代码生成
|
|
|
|
ExecFronted(previewCode.CodeFrontendResults);//执行前端代码生成
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw Oops.Bah("代码生成失败");
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public async Task<FileStreamResult> ExecGenZip(ExecGenInput input)
|
|
{
|
|
var genBasic = await GetGenBasic(input.Id);//获取代码生成基础
|
|
// if (genBasic.GenerateType != GenConst.Zip) throw Oops.Bah("当前配置生成方式为:压缩包");
|
|
var temDir = Path.GetTempPath().CombinePath(genBasic.ClassName);//获取临时目录并用类名做存放代码文件文件夹
|
|
File.Delete(temDir + ".zip");// 先删除压缩包
|
|
var previewCode = await PreviewGen(genBasic);//获取代码生成预览
|
|
if (input.ExecType != GenConst.ExecAll)//如果不是全部执行
|
|
{
|
|
if (input.ExecType == GenConst.ExecBackend)
|
|
{
|
|
ExecBackend(previewCode.CodeBackendResults, temDir.CombinePath(_backendDir), true);//执行后端代码生成
|
|
ExecSql(previewCode.SqlResults, temDir);//执行sql生成
|
|
}
|
|
else if (input.ExecType == GenConst.ExecFrontend)
|
|
ExecFronted(previewCode.CodeFrontendResults, temDir.CombinePath(_frontDir));//执行前端生成
|
|
}
|
|
else
|
|
{
|
|
ExecBackend(previewCode.CodeBackendResults, temDir.CombinePath(_backendDir), true);//执行后端代码生成
|
|
ExecFronted(previewCode.CodeFrontendResults, temDir.CombinePath(_frontDir));//执行前端生成
|
|
ExecSql(previewCode.SqlResults, temDir);//执行sql生成
|
|
}
|
|
var zipPath = ZipUtils.CompressDirectory(temDir, true);//压缩文件夹
|
|
var result = new FileStreamResult(new FileStream(zipPath, FileMode.Open), "application/octet-stream")
|
|
{ FileDownloadName = $"{genBasic.ClassName}.zip" };
|
|
return result;
|
|
}
|
|
|
|
#region 方法
|
|
|
|
/// <summary>
|
|
/// 生成后端代码文件
|
|
/// </summary>
|
|
/// <param name="baseCodeResults">后端代码模板</param>
|
|
/// <param name="genBasic">代码基础</param>
|
|
/// <param name="backendPath">后端生成路径</param>
|
|
/// <param name="isZip">是否是zip方式</param>
|
|
// public void ExecBackend(List<GenBasePreviewOutput.GenBaseCodeResult> baseCodeResults, GenBasic genBasic,
|
|
// string backendPath, bool isZip = false)
|
|
// {
|
|
// var serviceDir = "Services";//服务代码文件夹
|
|
// var controllerDir = "Controllers";//服务代码文件夹
|
|
// var tempDicName = "";//临时文件夹名称
|
|
// var dirList = new HashSet<string> { };//文件夹列表
|
|
// var postion = "";//文件夹位置
|
|
// var parentDir = _backendDir;//父文件文件夹名称
|
|
// var serviceName = genBasic.ServicePosition.Split(".").Last();//取服务层最后一个单词命名为接口层控制器下的文件夹
|
|
// baseCodeResults.ForEach(it =>
|
|
// {
|
|
// var fileInfo = new FileInfo(it.FilePath);//获取文件信息
|
|
// var dirName = fileInfo.Directory.Name;//获取文件文件夹名称
|
|
// var parentName = fileInfo.Directory.Parent.Name;//获取父文件文件夹名称
|
|
// if (dirName == controllerDir)//如果是控制器
|
|
// {
|
|
// dirList.Add(dirName);//添加到当前文件夹到文件夹列表
|
|
// dirList.Add(serviceName);//添加服务层目录名到文件夹列表
|
|
// postion = genBasic.ControllerPosition;//设置文件夹创建位置为Api层
|
|
// }
|
|
// else if (dirName == serviceDir)//如果是服务
|
|
// {
|
|
// dirList.Remove(controllerDir);//删除接口文件夹
|
|
// dirList.Remove(serviceName);//删除服务层目录
|
|
// dirList.Add(genBasic.ClassName);//添加ClassName到文件夹列表
|
|
// dirList.Add(dirName);//添加到当前文件夹到文件夹列表
|
|
// postion = genBasic.ServicePosition;//设置文件夹创建位置为服务层
|
|
// }
|
|
//
|
|
// if (parentDir != parentName)//如果当前文件的父文件夹不等于partDir表示层级有变动
|
|
// {
|
|
// dirList.Add(dirName);//添加到文件夹列表
|
|
// parentDir = parentName;//重新赋值父文件夹
|
|
// }
|
|
// else
|
|
// {
|
|
// if (tempDicName != dirName)//如果临时文件夹不是当前文件夹表示同级目录下的另一个文件夹
|
|
// {
|
|
// dirList.Remove(tempDicName);//删除上一个文件夹
|
|
// dirList.Add(dirName);//添加当前文件夹到文件夹列表
|
|
// }
|
|
// }
|
|
//
|
|
// tempDicName = dirName;//给临时文件夹赋值
|
|
// var path = backendPath;//后端文件目录
|
|
// if (!isZip) path = backendPath.CombinePath(postion);//如果不是zip方式就加上命名空间
|
|
// path = path.CombinePath(dirList.ToArray());
|
|
// if (!Directory.Exists(path))//如果文件夹不存在就创建文件夹
|
|
// Directory.CreateDirectory(path);
|
|
// //var fileName = genBasic.ClassName + it.CodeFileName;//文件名等于类名加代码文件名
|
|
// //if (it.CodeFileName.StartsWith("IService"))
|
|
// // fileName = $"I{genBasic.ClassName}Service.cs";//对IService接口要特殊处理
|
|
// //path = path.CombinePath(fileName);//最终生成文件地址
|
|
// File.WriteAllText(path.CombinePath(it.CodeFileName), it.CodeFileContent, Encoding.UTF8);//写入文件
|
|
// });
|
|
// }
|
|
public void ExecBackend(List<GenBasePreviewOutput.GenBaseCodeResult> baseCodeResults, string backendPath = null, bool isZip = false)
|
|
{
|
|
//遍历baseCodeResults
|
|
baseCodeResults.ForEach(it =>
|
|
{
|
|
var path = it.FilePath;
|
|
//判断path所属的文件夹
|
|
var dir = Path.GetDirectoryName(path);
|
|
//如果backendPath不为空,则将path设置为backendPath.CombinePath($"{it.CodeFileName}")
|
|
if (backendPath != null)
|
|
{
|
|
path = backendPath.CombinePath($"{it.CodeFileName}");
|
|
//重新获取path所属的文件夹
|
|
dir = Path.GetDirectoryName(path);
|
|
}
|
|
//如果不存在就创建文件夹
|
|
if (!Directory.Exists(dir))
|
|
{
|
|
Directory.CreateDirectory(dir);
|
|
}
|
|
File.WriteAllText(path, it.CodeFileContent, Encoding.UTF8);//写入文件
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// 生成前端代码文件
|
|
/// </summary>
|
|
/// <param name="baseCodeResults">前端代码模板</param>
|
|
/// <param name="frontedPath">前端生成路径</param>
|
|
public void ExecFronted(List<GenBasePreviewOutput.GenBaseCodeResult> baseCodeResults, string frontedPath = null)
|
|
{
|
|
baseCodeResults.ForEach(it =>
|
|
{
|
|
var path = it.FilePath;
|
|
//判断path所属的文件夹
|
|
var dir = Path.GetDirectoryName(path);
|
|
if (frontedPath != null)
|
|
{
|
|
path = frontedPath.CombinePath($"{it.CodeFileName}");
|
|
dir = Path.GetDirectoryName(path);
|
|
}
|
|
|
|
//如果不存在就创建文件夹
|
|
if (!Directory.Exists(dir))
|
|
{
|
|
Directory.CreateDirectory(dir);
|
|
}
|
|
File.WriteAllText(path, it.CodeFileContent, Encoding.UTF8);//写入文件
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// 生成sql代码文件
|
|
/// </summary>
|
|
/// <param name="baseCodeResults">后端代码模板</param>
|
|
/// <param name="execPath">生成路径</param>
|
|
public void ExecSql(List<GenBasePreviewOutput.GenBaseCodeResult> baseCodeResults, string execPath)
|
|
{
|
|
execPath = execPath.CombinePath(_sqlDir);//写在sql目录里面
|
|
if (!Directory.Exists(execPath))//如果文件夹不存在就创建文件夹
|
|
Directory.CreateDirectory(execPath);
|
|
baseCodeResults.ForEach(it =>
|
|
{
|
|
File.WriteAllText(execPath.CombinePath(it.CodeFileName), it.CodeFileContent, Encoding.UTF8);//写入文件
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取sql代码预览结果
|
|
/// </summary>
|
|
/// <param name="genViewModel">视图</param>
|
|
/// <param name="templatePath">模板路径</param>
|
|
/// <returns></returns>
|
|
public async Task<List<GenBasePreviewOutput.GenBaseCodeResult>> GetSqlCodeResult(GenViewModel genViewModel,
|
|
string templatePath)
|
|
{
|
|
var sqlCodeResults = new List<GenBasePreviewOutput.GenBaseCodeResult>();//结果集
|
|
var sqlTemplatePath = Path.Combine(templatePath, _sqlDir);//获取sql模板文件路径
|
|
|
|
var files = GetAllFileInfo(sqlTemplatePath);
|
|
foreach (var fileInfo in files)
|
|
{
|
|
var fileName = fileInfo.Name;//文件名
|
|
var fileNoPrefix = fileName.Split(fileInfo.Extension)[0];//不带模板后缀的文件名
|
|
var tContent = File.ReadAllText(fileInfo.FullName);//读取文件
|
|
var tResult = await GetViewEngine(tContent, genViewModel);//渲染
|
|
//将渲染结果添加到结果集
|
|
sqlCodeResults.Add(new GenBasePreviewOutput.GenBaseCodeResult
|
|
{
|
|
CodeFileContent = tResult,
|
|
CodeFileName = fileNoPrefix,
|
|
FilePath = fileInfo.FullName
|
|
});
|
|
}
|
|
|
|
return sqlCodeResults;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取后端代码预览结果
|
|
/// </summary>
|
|
/// <param name="genViewModel">视图</param>
|
|
/// <param name="templatePath">模板路径</param>
|
|
/// <returns></returns>
|
|
public async Task<List<GenBasePreviewOutput.GenBaseCodeResult>> GetBackendCodeResult(GenViewModel genViewModel,
|
|
string templatePath)
|
|
{
|
|
var backendCodeResults = new List<GenBasePreviewOutput.GenBaseCodeResult>();//结果集
|
|
var backendTemplatePath = Path.Combine(templatePath, _backendDir);//获取后端模板文件路径
|
|
var serviceDir = new DirectoryInfo(App.WebHostEnvironment.ContentRootPath).Parent.FullName.CombinePath(genViewModel.ServicePosition);//服务文件夹
|
|
var serviceDicList = genViewModel.ServiceDictionary.Split("/").Where(it => !string.IsNullOrWhiteSpace(it)).ToList();//获取文件夹
|
|
foreach (var item in serviceDicList)
|
|
{
|
|
serviceDir = serviceDir.CombinePath(item);
|
|
}
|
|
serviceDir = serviceDir.CombinePath(genViewModel.ClassName);
|
|
//获取控制器文件夹和后面的路径
|
|
var controllerDir = new DirectoryInfo(App.WebHostEnvironment.ContentRootPath).Parent.FullName.CombinePath(genViewModel.ControllerPosition);
|
|
var controllerDicList = genViewModel.ControllerDictionary.Split("/").Where(it => !string.IsNullOrWhiteSpace(it)).ToList();
|
|
foreach (var item in controllerDicList)
|
|
{
|
|
controllerDir = controllerDir.CombinePath(item);
|
|
}
|
|
controllerDir = controllerDir.CombinePath(genViewModel.ClassName);
|
|
var files = GetAllFileInfo(backendTemplatePath);
|
|
// files = files.Where(it => it.Name == "Service.cs.vm").ToArray();//测试用
|
|
var serviceFiles = files.Where(it => it.FullName.Contains("Service.cs")).ToList();
|
|
var controllerFiles = files.Where(it => it.FullName.Contains("Controller.cs")).ToList();
|
|
var dtoDir = files.Where(it => it.FullName.Contains("Dto")).ToList();
|
|
foreach (var fileInfo in serviceFiles)
|
|
{
|
|
var nameWithPrefix = fileInfo.Name;//文件名
|
|
var fileNoPrefix = nameWithPrefix.Split(fileInfo.Extension)[0];//不带模板后缀的文件名
|
|
var tContent = File.ReadAllText(fileInfo.FullName);//读取文件
|
|
var fileName = genViewModel.ClassName + fileNoPrefix;//文件名等于类名加代码文件名
|
|
if (fileNoPrefix.StartsWith("IService"))
|
|
fileName = $"I{genViewModel.ClassName}Service.cs";//对IService接口要特殊处理
|
|
var tResult = await GetViewEngine(tContent, genViewModel);//渲染
|
|
//将渲染结果添加到结果集
|
|
backendCodeResults.Add(new GenBasePreviewOutput.GenBaseCodeResult
|
|
{
|
|
CodeFileContent = tResult,
|
|
CodeFileName = $"{genViewModel.ClassName}{fileNoPrefix}",
|
|
FilePath = serviceDir.CombinePath(fileName)
|
|
});
|
|
}
|
|
foreach (var fileInfo in controllerFiles)
|
|
{
|
|
var nameWithPrefix = fileInfo.Name;//文件名
|
|
var fileNoPrefix = nameWithPrefix.Split(fileInfo.Extension)[0];//不带模板后缀的文件名
|
|
var tContent = File.ReadAllText(fileInfo.FullName);//读取文件
|
|
var fileName = genViewModel.ClassName + fileNoPrefix;//文件名等于类名加代码文件名
|
|
var tResult = await GetViewEngine(tContent, genViewModel);//渲染
|
|
//将渲染结果添加到结果集
|
|
backendCodeResults.Add(new GenBasePreviewOutput.GenBaseCodeResult
|
|
{
|
|
CodeFileContent = tResult,
|
|
CodeFileName = $"{genViewModel.ClassName}{fileNoPrefix}",
|
|
FilePath = controllerDir.CombinePath(fileName)
|
|
});
|
|
}
|
|
foreach (var fileInfo in dtoDir)
|
|
{
|
|
var nameWithPrefix = fileInfo.Name;//文件名
|
|
var fileNoPrefix = nameWithPrefix.Split(fileInfo.Extension)[0];//不带模板后缀的文件名
|
|
var tContent = File.ReadAllText(fileInfo.FullName);//读取文件
|
|
var fileName = genViewModel.ClassName + fileNoPrefix;//文件名等于类名加代码文件名
|
|
var tResult = await GetViewEngine(tContent, genViewModel);//渲染
|
|
//将渲染结果添加到结果集
|
|
backendCodeResults.Add(new GenBasePreviewOutput.GenBaseCodeResult
|
|
{
|
|
CodeFileContent = tResult,
|
|
CodeFileName = $"{genViewModel.ClassName}{fileNoPrefix}",
|
|
FilePath = serviceDir.CombinePath("Dto").CombinePath(fileName)
|
|
});
|
|
}
|
|
return backendCodeResults;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 获取前端代码预览结果
|
|
/// </summary>
|
|
/// <param name="genViewModel">视图</param>
|
|
/// <param name="templatePath">模板路径</param>
|
|
/// <returns></returns>
|
|
public async Task<List<GenBasePreviewOutput.GenBaseCodeResult>> GetForntCodeResult(GenViewModel genViewModel,
|
|
string templatePath)
|
|
{
|
|
var frontCodeResults = new List<GenBasePreviewOutput.GenBaseCodeResult>();//结果集
|
|
var frontTemplatePath = Path.Combine(templatePath, _frontDir);//获取前端模板文件路径
|
|
var files = GetAllFileInfo(frontTemplatePath);
|
|
var srcDir = genViewModel.FrontedPath.CombinePath("src");//src文件夹
|
|
var templateVm = "template.vm";//模板文件
|
|
var view = "views";//视图文件夹
|
|
var api = "api";//接口文件夹
|
|
var componentsDir = "components";//组件文件夹
|
|
var apiDir = srcDir.CombinePath(api);
|
|
var viewsDir = srcDir.CombinePath(view);
|
|
var template = files.Where(it => it.Name == templateVm).FirstOrDefault();
|
|
if (templatePath == null) throw Oops.Bah($"{templateVm}文件不存在");
|
|
var dirs = genViewModel.RouteName.Split("/").Where(it => !string.IsNullOrWhiteSpace(it)).ToList();// 根据路/分隔,获取文件夹名字
|
|
//读取模板文件内容,utf-8编码
|
|
var templateContent = File.ReadAllText(template.FullName, Encoding.UTF8);
|
|
var apiFiles = files.Where(it => it.FullName.Contains(api)).ToList();
|
|
var viewFiles = files.Where(it => it.FullName.Contains(view)).ToList();
|
|
foreach (var fileInfo in apiFiles)
|
|
{
|
|
var fileName = fileInfo.Name;//文件名
|
|
//获取文件所在文件夹名字
|
|
var dirName = fileInfo.Directory.Name;
|
|
var fileWhich = fileName.Split(".")[0];//获取是接口还是实现
|
|
if (fileName == templateVm) continue;
|
|
var fileNoPrefix = $"{fileWhich}{genViewModel.RouteName}/{genViewModel.BusName}.ts";//不带模板后缀的文件名
|
|
var filePath = apiDir.CombinePath(fileWhich);//生成文件路径
|
|
//以["biz","ops"]为例,先去找api/interface文件夹下的index.ts文件
|
|
//如果有就在index.ts文件中添加export * from "./biz",然后interfacePath路径就变成了api/interface/biz
|
|
//如果不存在这个文件夹,就表示需要创建这个文件夹,然后在这个文件夹下创建index.ts文件,导入下一层的文件也就是ops
|
|
for (var i = 0; i < dirs.Count; i++)
|
|
{
|
|
var it = dirs[i];//获取文件夹名
|
|
var indexPath = filePath.CombinePath(_indexTs);
|
|
// 判断interfacePath路径下是否有index.ts文件,这里因为是typescript,所以需要引入
|
|
if (File.Exists(indexPath))
|
|
{
|
|
//读取文件内容
|
|
var indexContent = File.ReadAllText(indexPath);
|
|
var content = $"export * from \"./{it}\";";//需要添加的内容
|
|
//判断content是否存在
|
|
if (!indexContent.Contains(content))
|
|
{
|
|
indexContent += content;
|
|
}
|
|
var pathSplit = indexPath.Split($"{fileWhich}")[1];
|
|
//先通过\分隔再用/合并字符串
|
|
var codeFileName = $"{fileWhich}{pathSplit}".Split("\\").Aggregate((a, b) => a + "/" + b);
|
|
//加到结果集
|
|
frontCodeResults.Add(new GenBasePreviewOutput.GenBaseCodeResult
|
|
{
|
|
CodeFileContent = indexContent,
|
|
CodeFileName = codeFileName,
|
|
FilePath = indexPath
|
|
});
|
|
}
|
|
filePath = filePath.CombinePath(it);//拼接文件夹路径
|
|
|
|
if (!Directory.Exists(filePath))//如果文件夹不存在
|
|
{
|
|
var index = filePath.CombinePath(_indexTs);
|
|
var pathSplit = index.Split($"{fileWhich}")[1];
|
|
var indexContent = i + 1 == dirs.Count ? genViewModel.BusName : dirs[i + 1];//如果是最后一个就是busName
|
|
// 在当前内容下添加内容
|
|
var content = templateContent + $"\n\nexport * from \"./{indexContent}\";";
|
|
//加到结果集
|
|
frontCodeResults.Add(new GenBasePreviewOutput.GenBaseCodeResult
|
|
{
|
|
CodeFileContent = content,
|
|
CodeFileName = $"{fileWhich}{pathSplit}",
|
|
FilePath = index
|
|
});
|
|
}
|
|
}
|
|
var tContent = File.ReadAllText(fileInfo.FullName);//读取文件
|
|
var tResult = await GetViewEngine(tContent, genViewModel);//渲染
|
|
//将渲染结果添加到结果集
|
|
frontCodeResults.Add(new GenBasePreviewOutput.GenBaseCodeResult
|
|
{
|
|
CodeFileContent = tResult,
|
|
CodeFileName = fileNoPrefix,
|
|
FilePath = filePath.CombinePath($"{genViewModel.BusName}.ts")
|
|
});
|
|
}
|
|
//遍历视图文件
|
|
foreach (var fileInfo in viewFiles)
|
|
{
|
|
var fileName = fileInfo.Name;//文件名
|
|
//获取文件所在文件夹名字
|
|
var dirName = fileInfo.Directory.Name;
|
|
var name = fileName.Split(".vm")[0];//不带模板后缀的文件名
|
|
var fileNoPrefix = $"{dirName}/{name}";//不带模板后缀的文件名
|
|
var filePath = viewsDir;
|
|
foreach (var dir in dirs)
|
|
{
|
|
filePath = filePath.CombinePath(dir);
|
|
}
|
|
filePath = filePath.CombinePath(genViewModel.BusName);
|
|
if (dirName == componentsDir)//如果是组件文件夹
|
|
{
|
|
fileNoPrefix = $"{view}/{dirName}/{name}";//不带模板后缀的文件名
|
|
filePath = filePath.CombinePath(componentsDir).CombinePath(name);//生成文件路径
|
|
}
|
|
else
|
|
filePath = filePath.CombinePath(name);//生成文件路径
|
|
var tContent = File.ReadAllText(fileInfo.FullName);//读取文件
|
|
var tResult = await GetViewEngine(tContent, genViewModel);//渲染
|
|
//将渲染结果添加到结果集
|
|
frontCodeResults.Add(new GenBasePreviewOutput.GenBaseCodeResult
|
|
{
|
|
CodeFileContent = tResult,
|
|
CodeFileName = fileNoPrefix,
|
|
FilePath = filePath
|
|
});
|
|
}
|
|
return frontCodeResults;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 获取代码生成视图
|
|
/// </summary>
|
|
/// <param name="genBasic"></param>
|
|
/// <returns></returns>
|
|
public async Task<GenViewModel> GetGenViewModel(GenBasic genBasic)
|
|
{
|
|
//实体转视图
|
|
var genViewEngine = genBasic.Adapt<GenViewModel>();
|
|
//获取字段信息
|
|
var tableFieldList = await _genConfigService.List(genBasic.Id);
|
|
tableFieldList.ForEach(it =>
|
|
{
|
|
it.FieldNameFirstLower = StringHelper.FirstCharToLower(it.FieldName);//首字母小写
|
|
it.FieldNameFirstUpper = StringHelper.FirstCharToUpper(it.FieldName);//首字母大写
|
|
});
|
|
genViewEngine.TableFields = tableFieldList;//赋值表字段信息
|
|
|
|
return genViewEngine;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 视图渲染
|
|
/// </summary>
|
|
/// <param name="tContent">模板内容</param>
|
|
/// <param name="genViewModel">参数</param>
|
|
/// <returns></returns>
|
|
public async Task<string> GetViewEngine(string tContent, GenViewModel genViewModel)
|
|
{
|
|
//视图引擎渲染
|
|
var tResult = await _viewEngine.RunCompileFromCachedAsync(tContent, genViewModel, builderAction: builder =>
|
|
{
|
|
builder.AddAssemblyReference(typeof(GenBasic));//添加程序集
|
|
builder.AddAssemblyReferenceByName("System.Collections");//添加程序集
|
|
builder.AddAssemblyReferenceByName("SimpleTool");//添加程序集
|
|
});
|
|
return tResult;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获得文件夹下所有的文件
|
|
/// </summary>
|
|
/// <param name="path">文件夹路径</param>
|
|
/// <returns></returns>
|
|
private FileInfo[] GetAllFileInfo(string path)
|
|
{
|
|
var dir = new DirectoryInfo(path);
|
|
return dir.GetFiles(".", SearchOption.AllDirectories);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 代码生成预览
|
|
/// </summary>
|
|
/// <param name="genBasic">基础配置</param>
|
|
/// <returns></returns>
|
|
public async Task<GenBasePreviewOutput> PreviewGen(GenBasic genBasic)
|
|
{
|
|
var basePath = AppContext.BaseDirectory;//获取项目目录
|
|
var templatePath = basePath.CombinePath("ViewEngine").CombinePath("CodeGen");//获取文件路径
|
|
templatePath = "D:\\胡国东\\SimpleAdmin.Net\\SimpleAdmin\\SimpleAdmin.System\\ViewEngine\\CodeGen";//测试用
|
|
var genViewModel = await GetGenViewModel(genBasic);
|
|
var frontendResult = await GetForntCodeResult(genViewModel, templatePath);
|
|
var backendResult = await GetBackendCodeResult(genViewModel, templatePath);
|
|
var sqlResult = await GetSqlCodeResult(genViewModel, templatePath);
|
|
return new GenBasePreviewOutput
|
|
{
|
|
CodeBackendResults = backendResult,
|
|
SqlResults = sqlResult,
|
|
CodeFrontendResults = frontendResult
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取代码生成基础
|
|
/// </summary>
|
|
/// <param name="id"></param>
|
|
/// <returns></returns>
|
|
private async Task<GenBasic> GetGenBasic(long id)
|
|
{
|
|
var genBasic = await GetByIdAsync(id);
|
|
if (genBasic == null)
|
|
throw Oops.Bah("代码生成配置不存在");
|
|
genBasic.FuncList = genBasic.Functions.Split(',').ToList();
|
|
return genBasic;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 创建代码生成相关的菜单按钮和授权关系
|
|
/// </summary>
|
|
/// <param name="genBasic"></param>
|
|
/// <returns></returns>
|
|
private async Task<bool> CreateMenuButtonAndRelation(GenBasic genBasic)
|
|
{
|
|
try
|
|
{
|
|
#region 菜单
|
|
|
|
var title = genBasic.FunctionName + genBasic.FunctionNameSuffix;
|
|
var menuRep = ChangeRepository<DbRepository<SysResource>>();//切换仓储
|
|
//获取已经存在的旧菜单
|
|
var oldMenu = await menuRep.GetFirstAsync(it => it.Title == title
|
|
&& it.Category == CateGoryConst.RESOURCE_MENU
|
|
&& it.MenuType == SysResourceConst.MENU &&
|
|
it.Code != SysResourceConst.SYSTEM);
|
|
if (oldMenu != null)//如果存在就直接和删除(同时删除其下面的菜单、按钮,清除对应的角色与资源信息)
|
|
await _menuService.Delete(new BaseIdListInput()
|
|
{
|
|
Ids = new List<long>()
|
|
{
|
|
oldMenu.Id
|
|
}
|
|
});
|
|
//添加菜单参数
|
|
var menu = new MenuAddInput
|
|
{
|
|
Id = CommonUtils.GetSingleId(),
|
|
ParentId = genBasic.MenuPid,
|
|
Title = title,
|
|
Category = CateGoryConst.RESOURCE_MENU,
|
|
Module = genBasic.Module,
|
|
Icon = genBasic.Icon,
|
|
Name = genBasic.BusName,
|
|
Code = RandomHelper.CreateRandomString(10),
|
|
Path = $"{genBasic.RouteName}/{genBasic.BusName}",
|
|
Component = $"{genBasic.RouteName}/{genBasic.BusName}/index".TrimStart('/'),
|
|
SortCode = 99,
|
|
Status = CommonStatusConst.ENABLE,
|
|
IsKeepAlive = true
|
|
};
|
|
await _menuService.Add(menu);//添加菜单
|
|
|
|
#endregion 菜单
|
|
|
|
#region 按钮
|
|
|
|
//添加按钮参数
|
|
var button = new ButtonAddInput
|
|
{
|
|
Title = genBasic.FunctionName,
|
|
ParentId = menu.Id,
|
|
Code = StringHelper.FirstCharToLower(genBasic.ClassName),
|
|
Status = CommonStatusConst.ENABLE
|
|
};
|
|
var buttonIds = await _buttonService.AddBatch(button);//添加按钮
|
|
|
|
#endregion 按钮
|
|
|
|
#region 角色授权
|
|
|
|
var roleRep = ChangeRepository<DbRepository<SysRole>>();//切换仓储
|
|
var superAdmin = await roleRep.GetFirstAsync(it =>
|
|
it.Code == SysRoleConst.SUPER_ADMIN && it.Category == CateGoryConst.ROLE_GLOBAL);//获取超级管理员
|
|
//授权菜单参数
|
|
var grantResource = new GrantResourceInput
|
|
{
|
|
Id = superAdmin.Id,
|
|
GrantInfoList = new List<RelationRoleResource>
|
|
{ new RelationRoleResource { MenuId = menu.Id, ButtonInfo = buttonIds } },
|
|
IsCodeGen = true
|
|
};
|
|
await _roleService.GrantResource(grantResource);//授权菜单
|
|
|
|
#endregion 角色授权
|
|
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError($"代码生成创建菜单和授权报错{ex.Message}", ex.InnerException);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
#endregion 方法
|
|
}
|