22 changed files with 915 additions and 4 deletions
@ -0,0 +1,340 @@ |
|||
using LINGYUN.Abp.Cli.ServiceProxying.TypeScript; |
|||
using Microsoft.Extensions.Logging; |
|||
using Microsoft.Extensions.Logging.Abstractions; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Reflection.Emit; |
|||
using System.Text; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Http.Modeling; |
|||
|
|||
namespace LINGYUN.Abp.Cli.ServiceProxying.Flutter; |
|||
public class FlutterModelScriptGenerator : IFlutterModelScriptGenerator, ITransientDependency |
|||
{ |
|||
public ILogger<FlutterModelScriptGenerator> Logger { protected get; set; } |
|||
|
|||
public FlutterModelScriptGenerator() |
|||
{ |
|||
Logger = NullLogger<FlutterModelScriptGenerator>.Instance; |
|||
} |
|||
|
|||
public string CreateScript( |
|||
ApplicationApiDescriptionModel appModel, |
|||
ControllerApiDescriptionModel actionModel) |
|||
{ |
|||
var modelScriptBuilder = new StringBuilder(); |
|||
// dto基类
|
|||
modelScriptBuilder.AppendLine("import 'package:core/models/abp.dto.dart';"); |
|||
// json库
|
|||
// flutter pub add json_annotation
|
|||
// flutter pub add build_runner --dev
|
|||
// flutter pub add json_serializable --dev
|
|||
// flutter pub run build_runner build --delete-conflicting-outputs
|
|||
modelScriptBuilder.AppendLine("import 'package:json_annotation/json_annotation.dart';"); |
|||
// json库实现,
|
|||
modelScriptBuilder.AppendLine("part 'models.g.dart';"); |
|||
// modelScriptBuilder.AppendLine($"part '{actionModel.ControllerName.ToSnakeCase()}.g.dart';");
|
|||
modelScriptBuilder.AppendLine(); |
|||
|
|||
var modelBaseTypes = new List<string>(); |
|||
var modelTypes = new List<string>(); |
|||
|
|||
foreach (var action in actionModel.Actions) |
|||
{ |
|||
foreach (var paramter in action.Value.Parameters) |
|||
{ |
|||
if (!TypeScriptModelGenerator.AbpBaseTypes.Contains(paramter.TypeSimple) && |
|||
appModel.Types.TryGetValue(paramter.Type, out var modelType)) |
|||
{ |
|||
var modelTypeName = paramter.Type[(paramter.Type.LastIndexOf('.') + 1)..]; |
|||
|
|||
if (!modelTypes.Contains(modelTypeName)) |
|||
{ |
|||
Logger.LogInformation($" Generating flutter model: {modelTypeName} script."); |
|||
|
|||
modelScriptBuilder.AppendLine(CreateModel(modelTypeName, appModel, modelType)); |
|||
|
|||
Logger.LogInformation($" Flutter model: {modelTypeName} generated successful."); |
|||
|
|||
modelTypes.AddIfNotContains(modelTypeName); |
|||
} |
|||
|
|||
// 字段类型
|
|||
foreach (var propertity in modelType.Properties) |
|||
{ |
|||
modelBaseTypes.AddIfNotContains(FindBaseTypes(appModel, propertity)); |
|||
} |
|||
|
|||
// 类型基类
|
|||
modelBaseTypes.AddIfNotContains(FindBaseTypes(appModel, modelType)); |
|||
} |
|||
} |
|||
|
|||
foreach (var paramter in action.Value.ParametersOnMethod) |
|||
{ |
|||
if (appModel.Types.TryGetValue(paramter.Type, out var modelType)) |
|||
{ |
|||
var modelTypeName = paramter.Type[(paramter.Type.LastIndexOf('.') + 1)..]; |
|||
|
|||
if (!modelTypes.Contains(modelTypeName)) |
|||
{ |
|||
Logger.LogInformation($" Generating flutter model: {modelTypeName} script."); |
|||
|
|||
modelScriptBuilder.AppendLine(CreateModel(modelTypeName, appModel, modelType)); |
|||
|
|||
Logger.LogInformation($" Flutter model: {modelTypeName} generated successful."); |
|||
|
|||
modelTypes.AddIfNotContains(modelTypeName); |
|||
} |
|||
|
|||
// 字段类型
|
|||
foreach (var propertity in modelType.Properties) |
|||
{ |
|||
modelBaseTypes.AddIfNotContains(FindBaseTypes(appModel, propertity)); |
|||
} |
|||
|
|||
// 类型基类
|
|||
modelBaseTypes.AddIfNotContains(FindBaseTypes(appModel, modelType)); |
|||
} |
|||
} |
|||
|
|||
|
|||
// 返回类型
|
|||
var returnType = action.Value.ReturnValue.TypeSimple; |
|||
var abpBaseType = TypeScriptModelGenerator.AbpBaseTypes.FirstOrDefault(basType => returnType.StartsWith(basType)); |
|||
if (!abpBaseType.IsNullOrWhiteSpace()) |
|||
{ |
|||
returnType = returnType |
|||
.Replace(abpBaseType, "") |
|||
.Replace("<", "") |
|||
.Replace(">", ""); |
|||
} |
|||
|
|||
returnType = returnType.ReplaceFlutterTypeSimple(); |
|||
|
|||
if (appModel.Types.TryGetValue(returnType, out var returnBaseType)) |
|||
{ |
|||
foreach (var propertity in returnBaseType.Properties) |
|||
{ |
|||
var propType = propertity.TypeSimple; |
|||
if (propertity.TypeSimple.StartsWith("[") && propertity.TypeSimple.EndsWith("]")) |
|||
{ |
|||
propType = propType.ReplaceFirst("[", "").RemovePostFix("]", ""); |
|||
} |
|||
|
|||
if (appModel.Types.TryGetValue(propType, out var propBaseType)) |
|||
{ |
|||
modelBaseTypes.AddIfNotContains(propType); |
|||
modelBaseTypes.AddIfNotContains(FindBaseTypes(appModel, propBaseType)); |
|||
} |
|||
} |
|||
} |
|||
|
|||
modelBaseTypes.AddIfNotContains(returnType); |
|||
} |
|||
|
|||
// 基类导出
|
|||
foreach (var baseType in modelBaseTypes) |
|||
{ |
|||
if (appModel.Types.TryGetValue(baseType, out var modelType)) |
|||
{ |
|||
var modelTypeName = baseType[(baseType.LastIndexOf('.') + 1)..]; |
|||
|
|||
Logger.LogInformation($" Generating base flutter model: {modelTypeName} script."); |
|||
|
|||
modelScriptBuilder.AppendLine(CreateModel(modelTypeName, appModel, modelType)); |
|||
|
|||
Logger.LogInformation($" The base flutter model: {modelTypeName} generate successful."); |
|||
} |
|||
} |
|||
|
|||
return modelScriptBuilder.ToString(); |
|||
} |
|||
|
|||
protected virtual string CreateModel( |
|||
string modelName, |
|||
ApplicationApiDescriptionModel appModel, |
|||
TypeApiDescriptionModel model) |
|||
{ |
|||
var modelBuilder = new StringBuilder(); |
|||
|
|||
if (model.IsEnum) |
|||
{ |
|||
modelBuilder.AppendLine($"enum {modelName} {{"); |
|||
for (var index = 0; index < model.EnumNames.Length; index++) |
|||
{ |
|||
var enumName = model.EnumNames[index].Replace("\"", "'"); |
|||
modelBuilder.AppendFormat(" {0}('{1}', {2})", enumName.ToCamelCase().Replace("'", ""), enumName, model.EnumValues[index]); |
|||
if (index == model.EnumNames.Length - 1) |
|||
{ |
|||
modelBuilder.Append(';'); |
|||
modelBuilder.AppendLine(); |
|||
} |
|||
else |
|||
{ |
|||
modelBuilder.Append(','); |
|||
modelBuilder.AppendLine(); |
|||
} |
|||
} |
|||
|
|||
modelBuilder.AppendLine(" final String name;"); |
|||
modelBuilder.AppendLine(" final int value;"); |
|||
modelBuilder.AppendLine($" const {modelName}(this.name, this.value);"); |
|||
modelBuilder.AppendLine("}"); |
|||
} |
|||
else |
|||
{ |
|||
// example:
|
|||
/* |
|||
@JsonSerializable() |
|||
class RemoteServiceErrorInfo { |
|||
RemoteServiceErrorInfo({ |
|||
required this.code, |
|||
required this.message, |
|||
this.details, |
|||
this.data, |
|||
this.validationErrors, |
|||
}); |
|||
String code; |
|||
String message; |
|||
String? details; |
|||
Map<String, String>? data; |
|||
List<RemoteServiceValidationErrorInfo>? validationErrors; |
|||
|
|||
factory RemoteServiceErrorInfo.fromJson(Map<String, dynamic> json) => _$RemoteServiceErrorInfoFromJson(json); |
|||
Map<String, dynamic> toJson() => _$RemoteServiceErrorInfoToJson(this); |
|||
} |
|||
*/ |
|||
|
|||
modelBuilder.AppendLine("@JsonSerializable()"); |
|||
modelBuilder.AppendFormat("class {0} ", modelName); |
|||
|
|||
if (!model.BaseType.IsNullOrWhiteSpace()) |
|||
{ |
|||
var baseType = ReplaceAbpBaseType(model.BaseType); |
|||
baseType = baseType.ReplaceFlutterTypeSimple(); |
|||
|
|||
modelBuilder.AppendFormat("extends {0} ", baseType[(baseType.LastIndexOf('.') + 1)..]); |
|||
} |
|||
modelBuilder.AppendLine("{"); |
|||
|
|||
modelBuilder.AppendLine($" {modelName}({{"); |
|||
|
|||
CreateCtorProperties(modelBuilder, appModel, model); |
|||
|
|||
modelBuilder.AppendLine(" });"); |
|||
|
|||
CreateProperties(modelBuilder, model.Properties); |
|||
|
|||
modelBuilder.AppendLine($" factory {modelName}.fromJson(Map<String, dynamic> json) => _${modelName}FromJson(json);"); |
|||
modelBuilder.AppendLine($" Map<String, dynamic> toJson() => _${modelName}ToJson(this);"); |
|||
modelBuilder.AppendLine("}"); |
|||
modelBuilder.AppendLine(""); |
|||
} |
|||
|
|||
return modelBuilder.ToString(); |
|||
} |
|||
|
|||
protected virtual void CreateCtorProperties( |
|||
StringBuilder modelScript, |
|||
ApplicationApiDescriptionModel appModel, |
|||
TypeApiDescriptionModel model, |
|||
bool abstractMember = false) |
|||
{ |
|||
for (var index = 0; index < model.Properties.Length; index++) |
|||
{ |
|||
var isRequired = model.Properties[index].IsRequired; |
|||
if (!isRequired) |
|||
{ |
|||
isRequired = !model.Properties[index].Type.Equals("System.String") && model.Properties[index].Type.EndsWith("?"); |
|||
} |
|||
var propCharacter = isRequired ? " required" : " "; |
|||
modelScript.AppendFormat("{0} {1}.{2},", propCharacter, abstractMember ? "super" : "this", model.Properties[index].Name.ToCamelCase()); |
|||
modelScript.AppendLine(""); |
|||
} |
|||
|
|||
if (!model.BaseType.IsNullOrWhiteSpace()) |
|||
{ |
|||
var replaceKey = model.BaseType.MiddleString("<", ">"); |
|||
if (replaceKey.IsNullOrWhiteSpace()) |
|||
{ |
|||
replaceKey = "<TPrimaryKey>"; |
|||
} |
|||
|
|||
if (appModel.Types.TryGetValue(model.BaseType.Replace(replaceKey, "<T0>"), out var abpBaseModel)) |
|||
{ |
|||
CreateCtorProperties(modelScript, appModel, abpBaseModel, true); |
|||
} |
|||
else |
|||
{ |
|||
if (appModel.Types.TryGetValue(model.BaseType, out var baseModel)) |
|||
{ |
|||
CreateCtorProperties(modelScript, appModel, baseModel, true); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
protected virtual void CreateProperties(StringBuilder modelScript, PropertyApiDescriptionModel[] properties) |
|||
{ |
|||
for (var index = 0; index < properties.Length; index++) |
|||
{ |
|||
var propTypeName = properties[index].Type.ReplaceFlutterType(); |
|||
if (!properties[index].IsRequired && properties[index].Type.Equals("System.String")) |
|||
{ |
|||
propTypeName += "?"; |
|||
} |
|||
modelScript.AppendFormat(" {0}", propTypeName); |
|||
//var propCharacter = properties[index].IsRequired ? " " : "? ";
|
|||
modelScript.AppendFormat("{0}{1};", " ", properties[index].Name.ToCamelCase()); |
|||
modelScript.AppendLine(""); |
|||
} |
|||
} |
|||
|
|||
protected virtual bool IsAbpBaseType(string typeSimple) => TypeScriptModelGenerator.AbpBaseTypes.Any(typeSimple.StartsWith); |
|||
|
|||
protected virtual List<string> FindBaseTypes(ApplicationApiDescriptionModel apiModel, TypeApiDescriptionModel model) |
|||
{ |
|||
var types = new List<string>(); |
|||
|
|||
if (!model.BaseType.IsNullOrWhiteSpace() && |
|||
!TypeScriptModelGenerator.AbpBaseTypes.Contains(model.BaseType) && |
|||
apiModel.Types.TryGetValue(model.BaseType, out var baseType)) |
|||
{ |
|||
types.Add(model.BaseType); |
|||
|
|||
types.AddRange(FindBaseTypes(apiModel, baseType)); |
|||
} |
|||
|
|||
return types; |
|||
} |
|||
|
|||
protected virtual List<string> FindBaseTypes(ApplicationApiDescriptionModel apiModel, PropertyApiDescriptionModel model) |
|||
{ |
|||
var types = new List<string>(); |
|||
|
|||
var propertityType = model.Type.ReplaceFlutterType(); |
|||
|
|||
if (!TypeScriptModelGenerator.AbpBaseTypes.Contains(propertityType) && |
|||
apiModel.Types.TryGetValue(propertityType, out var baseType)) |
|||
{ |
|||
types.Add(propertityType); |
|||
|
|||
types.AddRange(FindBaseTypes(apiModel, baseType)); |
|||
} |
|||
|
|||
return types; |
|||
} |
|||
|
|||
protected virtual string ReplaceAbpBaseType(string typeSimple) |
|||
{ |
|||
var abpBaseType = TypeScriptModelGenerator.AbpBaseTypes.FirstOrDefault(t => t.StartsWith(typeSimple)); |
|||
if (abpBaseType.IsNullOrWhiteSpace()) |
|||
{ |
|||
return typeSimple; |
|||
} |
|||
|
|||
return abpBaseType[(abpBaseType.LastIndexOf('.') + 1)..]; |
|||
} |
|||
} |
|||
@ -0,0 +1,128 @@ |
|||
using Microsoft.Extensions.Logging; |
|||
using Microsoft.Extensions.Options; |
|||
using System; |
|||
using System.IO; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Cli; |
|||
using Volo.Abp.Cli.Http; |
|||
using Volo.Abp.Cli.ServiceProxying; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.IO; |
|||
using Volo.Abp.Json; |
|||
|
|||
namespace LINGYUN.Abp.Cli.ServiceProxying.Flutter; |
|||
public class FlutterServiceProxyGenerator : ServiceProxyGeneratorBase<FlutterServiceProxyGenerator>, ITransientDependency |
|||
{ |
|||
public const string Name = "FLUTTER"; |
|||
|
|||
private readonly IFlutterModelScriptGenerator _flutterModelScriptGenerator; |
|||
private readonly FlutterServiceProxyOptions _flutterServiceProxyOptions; |
|||
|
|||
public FlutterServiceProxyGenerator( |
|||
CliHttpClientFactory cliHttpClientFactory, |
|||
IJsonSerializer jsonSerializer, |
|||
IFlutterModelScriptGenerator flutterModelScriptGenerator, |
|||
IOptions<FlutterServiceProxyOptions> flutterServiceProxyOptions) |
|||
: base(cliHttpClientFactory, jsonSerializer) |
|||
{ |
|||
_flutterModelScriptGenerator = flutterModelScriptGenerator; |
|||
_flutterServiceProxyOptions = flutterServiceProxyOptions.Value; |
|||
} |
|||
|
|||
public async override Task GenerateProxyAsync(Volo.Abp.Cli.ServiceProxying.GenerateProxyArgs args) |
|||
{ |
|||
var applicationApiDescriptionModel = await GetApplicationApiDescriptionModelAsync( |
|||
args, |
|||
new Volo.Abp.Http.Modeling.ApplicationApiDescriptionModelRequestDto |
|||
{ |
|||
IncludeTypes = true |
|||
}); |
|||
var outputFolderRoot = args.Output; |
|||
|
|||
foreach (var module in applicationApiDescriptionModel.Modules) |
|||
{ |
|||
Logger.LogInformation($"Generating flutter model script with remote service: {module.Value.RemoteServiceName}."); |
|||
|
|||
foreach (var controller in module.Value.Controllers) |
|||
{ |
|||
Logger.LogInformation($" [{module.Value.RemoteServiceName}], Generating flutter model script with controller: {controller.Value.ControllerName}."); |
|||
|
|||
var modelScript = _flutterModelScriptGenerator |
|||
.CreateScript(applicationApiDescriptionModel, controller.Value); |
|||
|
|||
Logger.LogInformation($" [{module.Value.RemoteServiceName}], {controller.Value.ControllerName} model script generated."); |
|||
|
|||
var scriptPath = Path.Combine( |
|||
outputFolderRoot, |
|||
module.Value.RemoteServiceName.ToKebabCase(), |
|||
controller.Value.ControllerGroupName.ToKebabCase()); |
|||
|
|||
DirectoryHelper.CreateIfNotExists(scriptPath); |
|||
|
|||
var modelScriptFile = Path.Combine(scriptPath, "models.dart"); |
|||
|
|||
Logger.LogInformation($"The flutter model script output file: {modelScriptFile}."); |
|||
Logger.LogInformation($"Saving flutter model script: {modelScriptFile}."); |
|||
|
|||
FileHelper.DeleteIfExists(modelScriptFile); |
|||
|
|||
await File.AppendAllTextAsync(modelScriptFile, modelScript); |
|||
|
|||
Logger.LogInformation($"Saved flutter model script: {modelScriptFile} has successful."); |
|||
|
|||
// api script
|
|||
|
|||
var apiScriptType = (args as GenerateProxyArgs).ApiScriptProxy; |
|||
if (!_flutterServiceProxyOptions.ScriptGenerators.ContainsKey(apiScriptType)) |
|||
{ |
|||
throw new CliUsageException($"Option Api Script Type {apiScriptType} value is invalid."); |
|||
} |
|||
var httpApiScriptProxy = _flutterServiceProxyOptions.ScriptGenerators[apiScriptType]; |
|||
|
|||
Logger.LogInformation($" [{module.Value.RemoteServiceName}], Generating flutter api script with {apiScriptType}."); |
|||
Logger.LogInformation($" [{module.Value.RemoteServiceName}], Generating flutter api script with controller: {controller.Value.ControllerName}."); |
|||
|
|||
var apiScript = httpApiScriptProxy.CreateScript( |
|||
applicationApiDescriptionModel, |
|||
module.Value, |
|||
controller.Value); |
|||
|
|||
Logger.LogInformation($" [{module.Value.RemoteServiceName}], {controller.Value.ControllerName} api script generated."); |
|||
|
|||
DirectoryHelper.CreateIfNotExists(scriptPath); |
|||
|
|||
var apiScriptFile = Path.Combine(scriptPath, "service.dart"); |
|||
|
|||
Logger.LogInformation($"The flutter api script output file: {apiScriptFile}."); |
|||
Logger.LogInformation($"Saving flutter api script: {apiScriptFile}."); |
|||
|
|||
FileHelper.DeleteIfExists(apiScriptFile); |
|||
|
|||
await File.AppendAllTextAsync(apiScriptFile, apiScript); |
|||
|
|||
var scriptExportFile = Path.Combine(scriptPath, "index.dart"); |
|||
|
|||
Logger.LogInformation($"The flutter export script output file: {scriptExportFile}."); |
|||
Logger.LogInformation($"Saving flutter export script: {scriptExportFile}."); |
|||
|
|||
FileHelper.DeleteIfExists(scriptExportFile); |
|||
|
|||
var scriptExportScript = new StringBuilder(); |
|||
scriptExportScript.AppendLine("export 'models.dart';"); |
|||
scriptExportScript.AppendLine("export 'service.dart';"); |
|||
|
|||
await File.AppendAllTextAsync(scriptExportFile, scriptExportScript.ToString()); |
|||
|
|||
Logger.LogInformation($"Saved api script: {apiScriptFile} has successful."); |
|||
} |
|||
} |
|||
|
|||
Logger.LogInformation($"Generate type script proxy has completed."); |
|||
} |
|||
|
|||
protected override ServiceType? GetDefaultServiceType(Volo.Abp.Cli.ServiceProxying.GenerateProxyArgs args) |
|||
{ |
|||
return ServiceType.Application; |
|||
} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
using System.Collections.Generic; |
|||
|
|||
namespace LINGYUN.Abp.Cli.ServiceProxying.Flutter; |
|||
public class FlutterServiceProxyOptions |
|||
{ |
|||
public IDictionary<string, IFlutterHttpScriptGenerator> ScriptGenerators { get; } |
|||
public FlutterServiceProxyOptions() |
|||
{ |
|||
ScriptGenerators = new Dictionary<string, IFlutterHttpScriptGenerator>(); |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
using Volo.Abp.Http.Modeling; |
|||
|
|||
namespace LINGYUN.Abp.Cli.ServiceProxying.Flutter; |
|||
public interface IFlutterHttpScriptGenerator |
|||
{ |
|||
string CreateScript( |
|||
ApplicationApiDescriptionModel appModel, |
|||
ModuleApiDescriptionModel apiModel, |
|||
ControllerApiDescriptionModel actionModel); |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
using Volo.Abp.Http.Modeling; |
|||
|
|||
namespace LINGYUN.Abp.Cli.ServiceProxying.Flutter; |
|||
|
|||
public interface IFlutterModelScriptGenerator |
|||
{ |
|||
string CreateScript( |
|||
ApplicationApiDescriptionModel appModel, |
|||
ControllerApiDescriptionModel actionModel); |
|||
} |
|||
@ -0,0 +1,194 @@ |
|||
using LINGYUN.Abp.Cli.ServiceProxying.TypeScript; |
|||
using System; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Http.Modeling; |
|||
|
|||
namespace LINGYUN.Abp.Cli.ServiceProxying.Flutter; |
|||
public class RestServiceScriptGenerator : IFlutterHttpScriptGenerator, ITransientDependency |
|||
{ |
|||
public const string Name = "rest-service"; |
|||
|
|||
public string CreateScript( |
|||
ApplicationApiDescriptionModel appModel, |
|||
ModuleApiDescriptionModel apiModel, |
|||
ControllerApiDescriptionModel actionModel) |
|||
{ |
|||
var apiScriptBuilder = new StringBuilder(); |
|||
|
|||
apiScriptBuilder.AppendLine($"import 'models.dart';"); |
|||
apiScriptBuilder.AppendLine("import 'package:core/modles/abp.dto.dart';"); |
|||
apiScriptBuilder.AppendLine("import 'package:core/services/rest.service.dart';"); |
|||
apiScriptBuilder.AppendLine("import 'package:dio/dio.dart';"); |
|||
apiScriptBuilder.AppendLine("import 'package:get/get.dart';"); |
|||
apiScriptBuilder.AppendLine(""); |
|||
apiScriptBuilder.AppendLine($"class {actionModel.ControllerName.ToPascalCase()}Service {{"); |
|||
apiScriptBuilder.AppendLine(" RestService get _restService => Get.find();"); |
|||
apiScriptBuilder.AppendLine(""); |
|||
|
|||
foreach (var action in actionModel.Actions) |
|||
{ |
|||
var url = action.Value.Url.EnsureStartsWith('/'); |
|||
var isFormatUrl = false; |
|||
var formatUrlIndex = 0; |
|||
|
|||
var apiRetuanName = action.Value.ReturnValue.TypeSimple; |
|||
|
|||
if (apiRetuanName.Contains("ListResultDto")) |
|||
{ |
|||
apiRetuanName = apiRetuanName[(apiRetuanName.IndexOf("<") + 1)..]; |
|||
apiRetuanName = apiRetuanName[..^1]; |
|||
apiRetuanName = apiRetuanName[(apiRetuanName.LastIndexOf('.') + 1)..]; |
|||
apiRetuanName = $"ListResultDto<{apiRetuanName}>"; |
|||
} |
|||
else if (apiRetuanName.Contains("PagedResultDto")) |
|||
{ |
|||
apiRetuanName = apiRetuanName[(apiRetuanName.IndexOf("<") + 1)..]; |
|||
apiRetuanName = apiRetuanName[..^1]; |
|||
apiRetuanName = apiRetuanName[(apiRetuanName.LastIndexOf('.') + 1)..]; |
|||
apiRetuanName = $"PagedResultDto<{apiRetuanName}>"; |
|||
} |
|||
else |
|||
{ |
|||
apiRetuanName = apiRetuanName[(apiRetuanName.LastIndexOf('.') + 1)..]; |
|||
} |
|||
|
|||
apiRetuanName = apiRetuanName.Replace("Void", "void"); |
|||
|
|||
apiScriptBuilder.AppendFormat(" Future<{0}> {1}(", apiRetuanName, action.Value.UniqueName.ToCamelCase()); |
|||
|
|||
var optionalParams = action.Value.ParametersOnMethod.Where(p => p.IsOptional).ToList(); |
|||
var notOptionalParams = action.Value.ParametersOnMethod.Where(p => !p.IsOptional).ToList(); |
|||
|
|||
for (var index = 0; index < notOptionalParams.Count; index++) |
|||
{ |
|||
var paramter = notOptionalParams[index]; |
|||
var apiParamName = paramter.Type.ReplaceFlutterType(); |
|||
apiParamName = apiParamName[(apiParamName.LastIndexOf('.') + 1)..]; |
|||
apiScriptBuilder.AppendFormat("{0} {1}", apiParamName, paramter.Name); |
|||
|
|||
if (index < notOptionalParams.Count - 1) |
|||
{ |
|||
apiScriptBuilder.Append(", "); |
|||
} |
|||
|
|||
// 需要格式化url
|
|||
var formatUrlPath = paramter.Name; |
|||
if (url.Contains(formatUrlPath)) |
|||
{ |
|||
formatUrlIndex = url.IndexOf(formatUrlPath) + formatUrlPath.Length; |
|||
// 'api/platform/packages/{id}/blob/{Name}' => `api/platform/packages/$id/blob/{input.name}`
|
|||
url = url.Replace(formatUrlPath, $"${formatUrlPath}").Replace($"{{${formatUrlPath}}}", $"${formatUrlPath}"); |
|||
isFormatUrl = true; |
|||
} |
|||
|
|||
if (formatUrlIndex >= 0 && formatUrlIndex + formatUrlPath.Length <= url.Length) |
|||
{ |
|||
var formatUrl = url[(formatUrlIndex + formatUrlPath.Length)..].MiddleString("{", "}"); |
|||
if (!formatUrl.IsNullOrWhiteSpace()) |
|||
{ |
|||
if (appModel.Types.TryGetValue(paramter.Type, out var paramType)) |
|||
{ |
|||
var formatParamInUrl = paramType.Properties |
|||
.FirstOrDefault(p => formatUrl.Contains(p.Name)); |
|||
|
|||
if (formatParamInUrl != null) |
|||
{ |
|||
// 'api/platform/packages/xxx/blob/{Name}' => `api/platform/packages/xxx/blob/${input.name}`
|
|||
url = url.Replace( |
|||
formatUrl, |
|||
string.Concat("${", paramter.Name, ".", formatParamInUrl.Name.ToCamelCase(), "}")); |
|||
isFormatUrl = true; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (optionalParams.Count > 0) |
|||
{ |
|||
apiScriptBuilder.AppendLine(",{"); |
|||
for (var index = 0; index < optionalParams.Count; index++) |
|||
{ |
|||
var paramter = optionalParams[index]; |
|||
var apiParamName = paramter.Type.ReplaceFlutterType(); |
|||
apiParamName = apiParamName[(apiParamName.LastIndexOf('.') + 1)..]; |
|||
apiScriptBuilder.AppendFormat("{0} {1}", apiParamName, paramter.Name); |
|||
apiScriptBuilder.AppendLine(""); |
|||
} |
|||
apiScriptBuilder.AppendLine("}"); |
|||
} |
|||
|
|||
apiScriptBuilder.AppendLine(") {"); |
|||
|
|||
apiScriptBuilder.AppendFormat(" return _restService.{0}('{1}',", action.Value.HttpMethod.ToLower(), url); |
|||
apiScriptBuilder.AppendLine(""); |
|||
|
|||
var inPathParams = action.Value.Parameters |
|||
.Where(p => TypeScriptModelGenerator.DataInParamSources.Contains(p.BindingSourceId)) |
|||
.DistinctBy(p => p.NameOnMethod); |
|||
var inBodyParams = action.Value.Parameters.Where(p => p.BindingSourceId == "Body"); |
|||
var inFormParams = action.Value.Parameters |
|||
.Where(p => TypeScriptModelGenerator.DataInFormSources.Contains(p.BindingSourceId)) |
|||
.DistinctBy(p => p.NameOnMethod); |
|||
|
|||
if (!isFormatUrl && inPathParams.Any()) |
|||
{ |
|||
apiScriptBuilder.AppendLine(" queryParameters: {"); |
|||
foreach (var paramter in inPathParams) |
|||
{ |
|||
apiScriptBuilder.AppendFormat(" {0}: {1}.{2},", paramter.Name, paramter.NameOnMethod, paramter.Name); |
|||
apiScriptBuilder.AppendLine(""); |
|||
} |
|||
apiScriptBuilder.AppendLine(" },"); |
|||
} |
|||
|
|||
if (inBodyParams.Any()) |
|||
{ |
|||
apiScriptBuilder.AppendFormat(" data: {0},", inBodyParams.First().NameOnMethod); |
|||
apiScriptBuilder.AppendLine(""); |
|||
} |
|||
|
|||
if (inFormParams.Any()) |
|||
{ |
|||
apiScriptBuilder.AppendFormat(" data: {0},", inFormParams.First().NameOnMethod); |
|||
apiScriptBuilder.AppendLine(""); |
|||
} |
|||
|
|||
if (action.Value.AllowAnonymous == true || inFormParams.Any()) |
|||
{ |
|||
apiScriptBuilder.AppendLine(" options: Options("); |
|||
if (action.Value.AllowAnonymous == true) |
|||
{ |
|||
apiScriptBuilder.AppendLine(" extra: {"); |
|||
apiScriptBuilder.AppendLine(" 'ignore_token': true"); |
|||
apiScriptBuilder.AppendLine(" },"); |
|||
} |
|||
apiScriptBuilder.AppendLine(" headers: {"); |
|||
if (inFormParams.Any()) |
|||
{ |
|||
apiScriptBuilder.AppendLine(" 'Content-type': 'multipart/form-data'"); |
|||
} |
|||
apiScriptBuilder.AppendLine(" },"); |
|||
apiScriptBuilder.AppendLine($" ),"); |
|||
} |
|||
|
|||
if (apiRetuanName.Equals("void")) |
|||
{ |
|||
apiScriptBuilder.AppendLine($" );"); |
|||
} |
|||
else |
|||
{ |
|||
apiScriptBuilder.AppendLine($" ).then((json) => {apiRetuanName}.fromJson(json));"); |
|||
} |
|||
apiScriptBuilder.AppendLine(" }"); |
|||
apiScriptBuilder.AppendLine(); |
|||
} |
|||
|
|||
apiScriptBuilder.AppendLine("}"); |
|||
apiScriptBuilder.AppendLine(); |
|||
|
|||
return apiScriptBuilder.ToString(); |
|||
} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Http.Modeling; |
|||
|
|||
namespace LINGYUN.Abp.Cli.UI.Flutter.GetX; |
|||
public class FlutterGetXViewScriptGenerator : IFlutterGetXViewScriptGenerator |
|||
{ |
|||
public Task<string> CreateView(GenerateViewArgs args, ApplicationApiDescriptionModel appModel, ControllerApiDescriptionModel controllerModel) |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
} |
|||
@ -0,0 +1,47 @@ |
|||
using Microsoft.Extensions.Logging; |
|||
using System.IO; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Cli.Http; |
|||
using Volo.Abp.Cli.ServiceProxying; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.IO; |
|||
using Volo.Abp.Json; |
|||
|
|||
namespace LINGYUN.Abp.Cli.UI.Flutter.GetX; |
|||
public class FlutterViewGenerator : ViewGeneratorBase<FlutterViewGenerator>, ISingletonDependency |
|||
{ |
|||
public const string Name = "Flutter-View"; |
|||
|
|||
protected IFlutterGetXViewScriptGenerator ViewScriptGenerator { get; } |
|||
|
|||
public FlutterViewGenerator( |
|||
CliHttpClientFactory cliHttpClientFactory, |
|||
IJsonSerializer jsonSerializer, |
|||
IFlutterGetXViewScriptGenerator viewScriptGenerator) |
|||
: base(cliHttpClientFactory, jsonSerializer) |
|||
{ |
|||
ViewScriptGenerator = viewScriptGenerator; |
|||
} |
|||
|
|||
public override Task GenerateAsync(GenerateViewArgs args) |
|||
{ |
|||
throw new System.NotImplementedException(); |
|||
} |
|||
|
|||
protected override ServiceType? GetDefaultServiceType(GenerateViewArgs args) |
|||
{ |
|||
return ServiceType.Application; |
|||
} |
|||
|
|||
private async Task CreateAndSaveSciptToDisk(string scriptFile, string script) |
|||
{ |
|||
Logger.LogInformation($"The script output file: {scriptFile}."); |
|||
Logger.LogInformation($"Saving script: {scriptFile}."); |
|||
|
|||
FileHelper.DeleteIfExists(scriptFile); |
|||
|
|||
await File.AppendAllTextAsync(scriptFile, script); |
|||
|
|||
Logger.LogInformation($"Saved script: {scriptFile} has successful."); |
|||
} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Http.Modeling; |
|||
|
|||
namespace LINGYUN.Abp.Cli.UI.Flutter.GetX; |
|||
public interface IFlutterGetXViewScriptGenerator |
|||
{ |
|||
Task<string> CreateView( |
|||
GenerateViewArgs args, |
|||
ApplicationApiDescriptionModel appModel, |
|||
ControllerApiDescriptionModel controllerModel); |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
import 'package:get/get.dart'; |
|||
|
|||
import 'controller.dart'; |
|||
|
|||
class {{ model.application }}Binding extends Bindings { |
|||
@override |
|||
void dependencies() { |
|||
Get.lazyPut(() => {{ model.application }}Controller()); |
|||
} |
|||
} |
|||
@ -0,0 +1,5 @@ |
|||
import 'package:get/get.dart'; |
|||
|
|||
class {{ model.application }}Controller extends GetxController { |
|||
|
|||
} |
|||
@ -0,0 +1,5 @@ |
|||
export 'binding.dart'; |
|||
export 'controller.dart'; |
|||
export 'route.dart'; |
|||
export 'route.names.dart'; |
|||
export 'view.dart'; |
|||
@ -0,0 +1,3 @@ |
|||
class {{ model.application }}Routes { |
|||
static String index = '/{{ model.application }}/index'; |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
import 'package:get/get.dart'; |
|||
|
|||
import 'view.dart'; |
|||
import 'route.names.dart'; |
|||
|
|||
class {{ model.application }}Route { |
|||
static List<GetPage> routes = [ |
|||
GetPage( |
|||
name: {{ model.application }}Routes.index, |
|||
page: () => const {{ model.application }}Page(), |
|||
binding: {{ model.application }}Binding(), |
|||
), |
|||
]; |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
import 'package:flutter/material.dart'; |
|||
|
|||
import 'controller.dart'; |
|||
import 'package:get/get.dart'; |
|||
|
|||
class {{ model.application }}Page extends GetView<{{ model.application }}Controller> { |
|||
const {{ model.application }}Page({super.key}); |
|||
|
|||
@override |
|||
Widget build(BuildContext context) { |
|||
return const Center( |
|||
child: Text('{{ model.application }}'), |
|||
); |
|||
} |
|||
} |
|||
Loading…
Reference in new issue