diff --git a/aspnet-core/LINGYUN.MicroService.All.sln b/aspnet-core/LINGYUN.MicroService.All.sln index 88a92b028..4f7ed2e39 100644 --- a/aspnet-core/LINGYUN.MicroService.All.sln +++ b/aspnet-core/LINGYUN.MicroService.All.sln @@ -639,7 +639,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.EntityChange.Ap EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.EntityChange.Application", "modules\entity-change\LINGYUN.Abp.EntityChange.Application\LINGYUN.Abp.EntityChange.Application.csproj", "{AC41F335-E240-47E0-B409-AFAD1400E626}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.EntityChange.HttpApi", "modules\entity-change\LINGYUN.Abp.EntityChange.HttpApi\LINGYUN.Abp.EntityChange.HttpApi.csproj", "{1D420BA6-2155-4E0D-AAAF-EECC0330A38C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.EntityChange.HttpApi", "modules\entity-change\LINGYUN.Abp.EntityChange.HttpApi\LINGYUN.Abp.EntityChange.HttpApi.csproj", "{1D420BA6-2155-4E0D-AAAF-EECC0330A38C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "cli", "cli", "{59627844-A66A-46AC-B882-E8F302D0EC24}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Cli", "modules\cli\LINGYUN.Abp.Cli\LINGYUN.Abp.Cli.csproj", "{2F49E870-DAE2-4D89-98CA-46BBD91C68E2}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -1643,6 +1647,10 @@ Global {1D420BA6-2155-4E0D-AAAF-EECC0330A38C}.Debug|Any CPU.Build.0 = Debug|Any CPU {1D420BA6-2155-4E0D-AAAF-EECC0330A38C}.Release|Any CPU.ActiveCfg = Release|Any CPU {1D420BA6-2155-4E0D-AAAF-EECC0330A38C}.Release|Any CPU.Build.0 = Release|Any CPU + {2F49E870-DAE2-4D89-98CA-46BBD91C68E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2F49E870-DAE2-4D89-98CA-46BBD91C68E2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2F49E870-DAE2-4D89-98CA-46BBD91C68E2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2F49E870-DAE2-4D89-98CA-46BBD91C68E2}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1953,6 +1961,8 @@ Global {7779D9BD-5928-49A2-965F-537967004238} = {DD1B10ED-73E2-41BE-928A-46501050FE2A} {AC41F335-E240-47E0-B409-AFAD1400E626} = {DD1B10ED-73E2-41BE-928A-46501050FE2A} {1D420BA6-2155-4E0D-AAAF-EECC0330A38C} = {DD1B10ED-73E2-41BE-928A-46501050FE2A} + {59627844-A66A-46AC-B882-E8F302D0EC24} = {C5CAD011-DF84-4914-939C-0C029DCEF26F} + {2F49E870-DAE2-4D89-98CA-46BBD91C68E2} = {59627844-A66A-46AC-B882-E8F302D0EC24} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C95FDF91-16F2-4A8B-A4BE-0E62D1B66718} diff --git a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN.Abp.Cli.csproj b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN.Abp.Cli.csproj index 1de0cde7a..0b75adb34 100644 --- a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN.Abp.Cli.csproj +++ b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN.Abp.Cli.csproj @@ -21,6 +21,8 @@ + + diff --git a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/AbpCliModule.cs b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/AbpCliModule.cs index 82776be13..be4a949b1 100644 --- a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/AbpCliModule.cs +++ b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/AbpCliModule.cs @@ -1,7 +1,9 @@ using LINGYUN.Abp.Cli.Commands; using LINGYUN.Abp.Cli.ServiceProxying.CSharp; +using LINGYUN.Abp.Cli.ServiceProxying.Flutter; using LINGYUN.Abp.Cli.ServiceProxying.TypeScript; using LINGYUN.Abp.Cli.UI; +using LINGYUN.Abp.Cli.UI.Flutter.GetX; using LINGYUN.Abp.Cli.UI.Vben; using Volo.Abp.Autofac; using Volo.Abp.Cli; @@ -39,6 +41,7 @@ namespace LINGYUN.Abp.Cli { options.Generators[TypeScriptServiceProxyGenerator.Name] = typeof(TypeScriptServiceProxyGenerator); options.Generators[CSharpServiceProxyGenerator.Name] = typeof(CSharpServiceProxyGenerator); + options.Generators[FlutterServiceProxyGenerator.Name] = typeof(FlutterServiceProxyGenerator); }); Configure(options => @@ -49,9 +52,15 @@ namespace LINGYUN.Abp.Cli options.ScriptGenerators[UniAppAxiosHttpApiScriptGenerator.Name] = new UniAppAxiosHttpApiScriptGenerator(); }); + Configure(options => + { + options.ScriptGenerators[RestServiceScriptGenerator.Name] = new RestServiceScriptGenerator(); + }); + Configure(options => { options.Generators[VbenViewGenerator.Name] = typeof(VbenViewGenerator); + options.Generators[FlutterViewGenerator.Name] = typeof(FlutterViewGenerator); }); } } diff --git a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/Commands/GenerateProxyCommand.cs b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/Commands/GenerateProxyCommand.cs index 0da93ff83..0a6042512 100644 --- a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/Commands/GenerateProxyCommand.cs +++ b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/Commands/GenerateProxyCommand.cs @@ -121,6 +121,10 @@ public class GenerateProxyCommand : IConsoleCommand, ITransientDependency sb.AppendLine(" ts"); sb.AppendLine(" -asp|--api-script-proxy The generated api proxy type(axios, vben-axios, vben-dynamic). default: vben-dynamic."); sb.AppendLine(" -o|--output TypeScript file path or folder to place generated code in."); + sb.AppendLine(" flutter"); + sb.AppendLine(" -asp|--api-script-proxy The generated api proxy type(dio, rest-service). default: rest-service."); + sb.AppendLine(" -o|--output Flutter script file path or folder to place generated code in."); + sb.AppendLine("-p|--provider The client proxy provider(http, dapr)."); sb.AppendLine("See the documentation for more info: https://docs.abp.io/en/abp/latest/CLI"); @@ -133,6 +137,7 @@ public class GenerateProxyCommand : IConsoleCommand, ITransientDependency sb.AppendLine(" labp generate-proxy --folder MyProxies/InnerFolder -url https://localhost:44302/"); sb.AppendLine(" labp generate-proxy -t ts -m identity -o api/identity -url https://localhost:44302/"); sb.AppendLine(" labp generate-proxy -t ts -asp vben-dynamic -m identity -o api/identity -url https://localhost:44302/"); + sb.AppendLine(" labp generate-proxy -t flutter -asp rest-service -m identity -o api/identity -url https://localhost:44302/"); return sb.ToString(); } diff --git a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/Commands/GenerateViewCommand.cs b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/Commands/GenerateViewCommand.cs index f95c16a64..3bea21ff4 100644 --- a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/Commands/GenerateViewCommand.cs +++ b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/Commands/GenerateViewCommand.cs @@ -90,6 +90,8 @@ public class GenerateViewCommand : IConsoleCommand, ITransientDependency sb.AppendLine("-t|--type The name of generate type (vben-view)."); sb.AppendLine(" vben-view"); sb.AppendLine(" -o|--output js/vue file path or folder to place generated code in."); + sb.AppendLine(" flutter-view"); + sb.AppendLine(" -o|--output flutter file path or folder to place generated code in."); sb.AppendLine("-u|--url API definition URL from."); sb.AppendLine("-m|--module (default: 'app') The name of the backend module you wish to generate proxies for."); sb.AppendLine(""); @@ -97,6 +99,7 @@ public class GenerateViewCommand : IConsoleCommand, ITransientDependency sb.AppendLine(""); sb.AppendLine(" labp generate-proxy -t vben-view -m identity -o api/identity -url https://localhost:44302/"); + sb.AppendLine(" labp generate-proxy -t flutter-view -m identity -o api/identity -url https://localhost:44302/"); return sb.ToString(); } diff --git a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/ServiceProxying/Flutter/FlutterModelScriptGenerator.cs b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/ServiceProxying/Flutter/FlutterModelScriptGenerator.cs new file mode 100644 index 000000000..310dbc814 --- /dev/null +++ b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/ServiceProxying/Flutter/FlutterModelScriptGenerator.cs @@ -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 Logger { protected get; set; } + + public FlutterModelScriptGenerator() + { + Logger = NullLogger.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(); + var modelTypes = new List(); + + 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? data; + List? validationErrors; + + factory RemoteServiceErrorInfo.fromJson(Map json) => _$RemoteServiceErrorInfoFromJson(json); + Map 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 json) => _${modelName}FromJson(json);"); + modelBuilder.AppendLine($" Map 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 = ""; + } + + if (appModel.Types.TryGetValue(model.BaseType.Replace(replaceKey, ""), 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 FindBaseTypes(ApplicationApiDescriptionModel apiModel, TypeApiDescriptionModel model) + { + var types = new List(); + + 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 FindBaseTypes(ApplicationApiDescriptionModel apiModel, PropertyApiDescriptionModel model) + { + var types = new List(); + + 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)..]; + } +} diff --git a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/ServiceProxying/Flutter/FlutterServiceProxyGenerator.cs b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/ServiceProxying/Flutter/FlutterServiceProxyGenerator.cs new file mode 100644 index 000000000..4b286b267 --- /dev/null +++ b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/ServiceProxying/Flutter/FlutterServiceProxyGenerator.cs @@ -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, ITransientDependency +{ + public const string Name = "FLUTTER"; + + private readonly IFlutterModelScriptGenerator _flutterModelScriptGenerator; + private readonly FlutterServiceProxyOptions _flutterServiceProxyOptions; + + public FlutterServiceProxyGenerator( + CliHttpClientFactory cliHttpClientFactory, + IJsonSerializer jsonSerializer, + IFlutterModelScriptGenerator flutterModelScriptGenerator, + IOptions 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; + } +} diff --git a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/ServiceProxying/Flutter/FlutterServiceProxyOptions.cs b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/ServiceProxying/Flutter/FlutterServiceProxyOptions.cs new file mode 100644 index 000000000..b0b841cc5 --- /dev/null +++ b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/ServiceProxying/Flutter/FlutterServiceProxyOptions.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; + +namespace LINGYUN.Abp.Cli.ServiceProxying.Flutter; +public class FlutterServiceProxyOptions +{ + public IDictionary ScriptGenerators { get; } + public FlutterServiceProxyOptions() + { + ScriptGenerators = new Dictionary(); + } +} diff --git a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/ServiceProxying/Flutter/IFlutterHttpScriptGenerator.cs b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/ServiceProxying/Flutter/IFlutterHttpScriptGenerator.cs new file mode 100644 index 000000000..f7e4b33a8 --- /dev/null +++ b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/ServiceProxying/Flutter/IFlutterHttpScriptGenerator.cs @@ -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); +} diff --git a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/ServiceProxying/Flutter/IFlutterModelScriptGenerator.cs b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/ServiceProxying/Flutter/IFlutterModelScriptGenerator.cs new file mode 100644 index 000000000..385eeb7d9 --- /dev/null +++ b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/ServiceProxying/Flutter/IFlutterModelScriptGenerator.cs @@ -0,0 +1,10 @@ +using Volo.Abp.Http.Modeling; + +namespace LINGYUN.Abp.Cli.ServiceProxying.Flutter; + +public interface IFlutterModelScriptGenerator +{ + string CreateScript( + ApplicationApiDescriptionModel appModel, + ControllerApiDescriptionModel actionModel); +} diff --git a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/ServiceProxying/Flutter/RestServiceScriptGenerator.cs b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/ServiceProxying/Flutter/RestServiceScriptGenerator.cs new file mode 100644 index 000000000..aad618463 --- /dev/null +++ b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/ServiceProxying/Flutter/RestServiceScriptGenerator.cs @@ -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(); + } +} diff --git a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/UI/Flutter/GetX/FlutterGetXViewScriptGenerator.cs b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/UI/Flutter/GetX/FlutterGetXViewScriptGenerator.cs new file mode 100644 index 000000000..cebaa83de --- /dev/null +++ b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/UI/Flutter/GetX/FlutterGetXViewScriptGenerator.cs @@ -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 CreateView(GenerateViewArgs args, ApplicationApiDescriptionModel appModel, ControllerApiDescriptionModel controllerModel) + { + throw new NotImplementedException(); + } +} diff --git a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/UI/Flutter/GetX/FlutterViewGenerator.cs b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/UI/Flutter/GetX/FlutterViewGenerator.cs new file mode 100644 index 000000000..84b0258be --- /dev/null +++ b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/UI/Flutter/GetX/FlutterViewGenerator.cs @@ -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, 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."); + } +} diff --git a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/UI/Flutter/GetX/IFlutterGetXViewScriptGenerator.cs b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/UI/Flutter/GetX/IFlutterGetXViewScriptGenerator.cs new file mode 100644 index 000000000..213340ab8 --- /dev/null +++ b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/UI/Flutter/GetX/IFlutterGetXViewScriptGenerator.cs @@ -0,0 +1,11 @@ +using System.Threading.Tasks; +using Volo.Abp.Http.Modeling; + +namespace LINGYUN.Abp.Cli.UI.Flutter.GetX; +public interface IFlutterGetXViewScriptGenerator +{ + Task CreateView( + GenerateViewArgs args, + ApplicationApiDescriptionModel appModel, + ControllerApiDescriptionModel controllerModel); +} diff --git a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/UI/Flutter/GetX/Templates/FlutterGetXBindingScript.tpl b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/UI/Flutter/GetX/Templates/FlutterGetXBindingScript.tpl new file mode 100644 index 000000000..01bb05096 --- /dev/null +++ b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/UI/Flutter/GetX/Templates/FlutterGetXBindingScript.tpl @@ -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()); + } +} \ No newline at end of file diff --git a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/UI/Flutter/GetX/Templates/FlutterGetXControllerScript.tpl b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/UI/Flutter/GetX/Templates/FlutterGetXControllerScript.tpl new file mode 100644 index 000000000..651705298 --- /dev/null +++ b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/UI/Flutter/GetX/Templates/FlutterGetXControllerScript.tpl @@ -0,0 +1,5 @@ +import 'package:get/get.dart'; + +class {{ model.application }}Controller extends GetxController { + +} \ No newline at end of file diff --git a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/UI/Flutter/GetX/Templates/FlutterGetXIndexScript.tpl b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/UI/Flutter/GetX/Templates/FlutterGetXIndexScript.tpl new file mode 100644 index 000000000..5560c90df --- /dev/null +++ b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/UI/Flutter/GetX/Templates/FlutterGetXIndexScript.tpl @@ -0,0 +1,5 @@ +export 'binding.dart'; +export 'controller.dart'; +export 'route.dart'; +export 'route.names.dart'; +export 'view.dart'; \ No newline at end of file diff --git a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/UI/Flutter/GetX/Templates/FlutterGetXRouteNamesScript.tpl b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/UI/Flutter/GetX/Templates/FlutterGetXRouteNamesScript.tpl new file mode 100644 index 000000000..f1b3c702f --- /dev/null +++ b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/UI/Flutter/GetX/Templates/FlutterGetXRouteNamesScript.tpl @@ -0,0 +1,3 @@ +class {{ model.application }}Routes { + static String index = '/{{ model.application }}/index'; +} \ No newline at end of file diff --git a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/UI/Flutter/GetX/Templates/FlutterGetXRouteScript.tpl b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/UI/Flutter/GetX/Templates/FlutterGetXRouteScript.tpl new file mode 100644 index 000000000..9375c7da1 --- /dev/null +++ b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/UI/Flutter/GetX/Templates/FlutterGetXRouteScript.tpl @@ -0,0 +1,14 @@ +import 'package:get/get.dart'; + +import 'view.dart'; +import 'route.names.dart'; + +class {{ model.application }}Route { + static List routes = [ + GetPage( + name: {{ model.application }}Routes.index, + page: () => const {{ model.application }}Page(), + binding: {{ model.application }}Binding(), + ), + ]; +} \ No newline at end of file diff --git a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/UI/Flutter/GetX/Templates/FlutterGetXViewScript.tpl b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/UI/Flutter/GetX/Templates/FlutterGetXViewScript.tpl new file mode 100644 index 000000000..7194b5a6b --- /dev/null +++ b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/UI/Flutter/GetX/Templates/FlutterGetXViewScript.tpl @@ -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 }}'), + ); + } +} \ No newline at end of file diff --git a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/Properties/launchSettings.json b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/Properties/launchSettings.json index 7fa08e303..b0bcefea9 100644 --- a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/Properties/launchSettings.json +++ b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/Properties/launchSettings.json @@ -2,8 +2,8 @@ "profiles": { "LINGYUN.Abp.Cli": { "commandName": "Project", - "commandLineArgs": "generate-view -t vben-view -m auditing -o D:\\Projects\\Development\\view-script -url http://127.0.0.1:30000/" - //"commandLineArgs": "generate-proxy -t ts -asp vben-dynamic -u http://127.0.0.1:30000 -m platform -o D:\\Projects\\Development\\type-script" + //"commandLineArgs": "generate-view -t vben-view -m auditing -o D:\\Projects\\Development\\view-script -url http://127.0.0.1:30000/" + "commandLineArgs": "generate-proxy -t flutter -asp rest-service -u http://99.11.10.2:30000 -m platform -o D:\\Projects\\Development\\flutter-script -skip-cli-version-check" } } } \ No newline at end of file diff --git a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/System/StringExtensions.cs b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/System/StringExtensions.cs index bf4ba9b75..cdded9a04 100644 --- a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/System/StringExtensions.cs +++ b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/System/StringExtensions.cs @@ -5,11 +5,11 @@ internal static class StringExtensions public static string ReplaceTypeSimple(this string typeSimple) { typeSimple = typeSimple - .Replace("?", "") .Replace("", "") .Replace("", "") .Replace("", "") .Replace("", "") + .Replace("", "") .Replace("IRemoteStreamContent", "Blob") .Replace("{string:string}", "Dictionary") .Replace("{number:string}", "Dictionary") @@ -25,6 +25,70 @@ internal static class StringExtensions return typeSimple; } + public static string ReplaceFlutterType(this string type) + { + type = type + .Replace("{System.String:System.String}", "Map") + .Replace("{System.Int32:System.String}", "Map") + .Replace("{System.Int64:System.String}", "Map") + .Replace("{System.String:System.Int32}", "Map") + .Replace("{System.String:System.Int64}", "Map") + .Replace("{System.String:System.Object}", "Map") + .Replace("System.String", "String") + .Replace("System.Guid", "String") + .Replace("System.Int32", "num") + .Replace("System.Int64", "num") + .Replace("System.DateTime", "DateTime") + .Replace("System.Boolean", "bool") + .Replace("System.Object", "dynamic") + .Replace("IRemoteStreamContent", "Blob"); + + if (type.StartsWith("[") && type.EndsWith("]")) + { + if (type.LastIndexOf('.') >= 0) + { + type = type[(type.LastIndexOf('.') + 1)..]; + } + + type = type.RemovePreFix("[", "<").RemovePostFix("]", ">"); + + type = "List<" + type + ">"; + } + else + { + if (type.LastIndexOf('.') >= 0) + { + type = type[(type.LastIndexOf('.') + 1)..]; + } + } + + return type; + } + + public static string ReplaceFlutterTypeSimple(this string typeSimple) + { + typeSimple = typeSimple + .Replace("?", "") + .Replace("", "") + .Replace("", "") + .Replace("", "") + .Replace("", "") + .Replace("", "") + .Replace("IRemoteStreamContent", "Blob") + .Replace("{string:string}", "Map") + .Replace("{number:string}", "Map") + .Replace("{string:number}", "Map") + .Replace("{string:object}", "Map"); + + if (typeSimple.StartsWith("[") && typeSimple.EndsWith("]")) + { + typeSimple = typeSimple.RemovePreFix("[", "<").RemovePostFix("]", ">"); + typeSimple = "List<" + typeSimple + ">"; + } + + return typeSimple; + } + public static string MiddleString(this string sourse, string startstr, string endstr) { var result = string.Empty;