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;