From d018c787892307f7d17cfeb2bb8eed10e1f4e061 Mon Sep 17 00:00:00 2001 From: Rex Lei Date: Wed, 24 Jun 2026 12:16:07 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E6=8B=86=E5=88=86=E7=A6=BB=E7=BA=BF?= =?UTF-8?q?=E8=A1=A8=E5=8D=95=E6=9E=84=E5=BB=BA=E4=B8=8E=E4=B8=8B=E8=BD=BD?= =?UTF-8?q?=E5=91=BD=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AndroidPDACommand.csproj:加入 OfflinePlusBuildPattern.cs 编译项和 Icon_OfflineBuild.png 资源项,确保新增构建命令及其图标能被插件编译和打包。 OfflinePlusAddPattern_Async.cs:收敛为下载离线表单命令,只保留离线表单 JSON、手册附件单元格和员工签名单元格参数,避免下载命令继续承担表单结构配置职责。 OfflinePlusBuildPattern.cs:新增构建离线表单命令文件,承接原下载命令中的项目元信息、步骤、节点和字段配置,并将构建出的结构 JSON 返回到变量,避免在构建阶段写入手册或签名大字段。 Resources/AndroidPDACommand.js:新增构建命令运行时注册,生成纯表单结构 JSON;调整下载命令从 JSON 解析表单结构,在下载阶段生成 ticket,并沿用 Android 端现有三参桥协议传入表单 JSON、手册 URL 和签名 Base64。 Resources/Icon_OfflineBuild.png:新增构建离线表单命令图标,使新命令在设计器命令列表中和下载命令区分。 --- AndroidPDACommand.csproj | 2 + OfflinePlusAddPattern_Async.cs | 311 +----------------------------- OfflinePlusBuildPattern.cs | 332 ++++++++++++++++++++++++++++++++ Resources/AndroidPDACommand.js | 108 ++++++++--- Resources/Icon_OfflineBuild.png | Bin 0 -> 295 bytes 5 files changed, 415 insertions(+), 338 deletions(-) create mode 100644 OfflinePlusBuildPattern.cs create mode 100644 Resources/Icon_OfflineBuild.png diff --git a/AndroidPDACommand.csproj b/AndroidPDACommand.csproj index 13b436e..575c3e8 100644 --- a/AndroidPDACommand.csproj +++ b/AndroidPDACommand.csproj @@ -50,6 +50,7 @@ + @@ -166,6 +167,7 @@ + diff --git a/OfflinePlusAddPattern_Async.cs b/OfflinePlusAddPattern_Async.cs index fd5a6e7..8f7612d 100644 --- a/OfflinePlusAddPattern_Async.cs +++ b/OfflinePlusAddPattern_Async.cs @@ -1,7 +1,5 @@ -using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.DataAnnotations; -using System.Linq; using GrapeCity.Forguncy.Commands; using GrapeCity.Forguncy.Plugin; @@ -11,24 +9,11 @@ namespace AndroidPDACommand [Category("活字格安卓容器(HAC)")] public class OfflinePlusAddPattern_Async : BaseAsyncCommand { - [FormulaProperty] - [DisplayName("项目编号")] - [Description("项目的唯一标识,全局唯一")] - public object PatternId { get; set; } - - [DisplayName("名称")] - [FormulaProperty] - public object Title { get; set; } - - [DisplayName("描述")] - [FormulaProperty] - public object Description { get; set; } - [Required] [FormulaProperty] - [DisplayName("版本号")] - [Description("同一项目编号下的表单定义版本,用于区分表单结构变更。")] - public string SchemaVersion { get; set; } = "1.0"; + [DisplayName("离线表单JSON")] + [Description("由“构建离线表单”命令生成的表单JSON。")] + public object PatternJson { get; set; } [FormulaProperty] [DisplayName("手册附件单元格")] @@ -40,299 +25,9 @@ namespace AndroidPDACommand [Description("选择保存员工签名附件的单元格。下载离线表单时会把签名文件随表单一起保存到离线设备。")] public object SignatureAttachmentCell { get; set; } - [DisplayName("步骤")] - [ObjectListProperty(ItemType = typeof(OfflineFormStep))] - public List Steps { get; set; } - public override string ToString() { return "下载离线表单"; } } - - public class OfflineFormStep : ObjectPropertyBase, INamedObject - { - public string Name { get; set; } - - [FormulaProperty] - [DisplayName("步骤编号")] - [Description("该步骤的唯一标识,同一个离线表单项目内必须唯一。")] - public object StepId { get; set; } - - [FormulaProperty] - [DisplayName("标题")] - public object Title { get; set; } - - [TreeProperty(NodeType = typeof(OfflineFormNode), DefaultNodeName = "节点")] - [DisplayName("页面内容")] - public List Items { get; set; } = new List(); - } - - public class OfflineFormNode : ObjectPropertyBase, ITreeNode - { - private static readonly string[] CommonFieldVisibleProperties = - { - nameof(ItemId), - nameof(ItemType), - nameof(Title), - nameof(Hint), - nameof(Required) - }; - - private static readonly HashSet FieldTypeControlledProperties = new HashSet(CommonFieldVisibleProperties) - { - nameof(Value), - nameof(CheckOptions), - nameof(SelectOptionsList), - nameof(IncludeSeconds), - nameof(MaxCount), - nameof(AllowImageUpload), - nameof(CompressionOptions), - nameof(WatermarkOptions), - nameof(FileItemConfig) - }; - - private static readonly Dictionary> FieldVisiblePropertiesByType = new Dictionary> - { - { "textItem", CreateFieldVisibleProperties(nameof(Value), nameof(CheckOptions)) }, - { "passwordItem", CreateFieldVisibleProperties(nameof(Value), nameof(CheckOptions)) }, - { "selectItem", CreateFieldVisibleProperties(nameof(Value), nameof(SelectOptionsList)) }, - { "datePicker", CreateFieldVisibleProperties(nameof(Value)) }, - { "timePicker", CreateFieldVisibleProperties(nameof(Value), nameof(IncludeSeconds)) }, - { "imageItem", CreateFieldVisibleProperties(nameof(MaxCount), nameof(AllowImageUpload), nameof(CompressionOptions), nameof(WatermarkOptions)) }, - { "fileItem", CreateFieldVisibleProperties(nameof(FileItemConfig)) } - }; - - [DisplayName("节点名称")] - public string Text { get; set; } - - [Browsable(false)] - public IEnumerable Children { get; set; } = new List(); - - [DisplayName("节点类型")] - [ComboProperty(ValueList = "group|text|field", DisplayList = "分组|普通文本|表单项")] - public string NodeType { get; set; } = "group"; - - [FormulaProperty] - [DisplayName("说明内容")] - public object Content { get; set; } - - [DisplayName("默认折叠")] - public bool DefaultCollapsed { get; set; } - - [FormulaProperty] - [DisplayName("编号")] - [Description("该表单项的唯一标识,全局唯一,无论是同一项目内,还是跨项目,都必须唯一,更建议使用项目编号作为前缀拼接;例如项目为Project01,则该表单项编号为Project01_Name")] - public object ItemId { get; set; } - - [DisplayName("类型")] - [ComboProperty(ValueList = "textItem|passwordItem|selectItem|datePicker|timePicker|imageItem|fileItem", DisplayList = "文本框|密码框|选择框|日期选择|时间选择|图片列表|文件上传")] - public string ItemType { get; set; } = "textItem"; - - [FormulaProperty] - [DisplayName("标题")] - public object Title { get; set; } - - [FormulaProperty] - [DisplayName("水印")] - public object Hint { get; set; } - - [DisplayName("必填")] - public bool Required { get; set; } - - [FormulaProperty] - [DisplayName("默认值")] - public object Value { get; set; } - - [DisplayName("包含秒")] - [Description("仅时间选择类型生效。启用后可选择时分秒;关闭时使用系统原生时分选择器。")] - public bool IncludeSeconds { get; set; } - - - [ObjectProperty(ObjType = typeof(CheckOptions))] - [DisplayName("校验规则")] - public CheckOptions CheckOptions { get; set; } - - [ListProperty] - [DisplayName("选则项")] - public List SelectOptionsList { get; set; } - - [FormulaProperty] - [DisplayName("图片最大数量")] - [Description("0表示不限制图片数量。")] - public object MaxCount { get; set; } = 0; - - [DisplayName("允许图片上传")] - [Description("仅图片列表类型生效。启用后填报时除拍照外还可以从本地选择图片。")] - public bool AllowImageUpload { get; set; } - - [ObjectProperty(ObjType = typeof(ImageCompressionOptions))] - [DisplayName("图片压缩设置")] - public ImageCompressionOptions CompressionOptions { get; set; } = new ImageCompressionOptions(); - - [ObjectProperty(ObjType = typeof(ImageWatermarkOptions))] - [DisplayName("拍照水印配置")] - public ImageWatermarkOptions WatermarkOptions { get; set; } = new ImageWatermarkOptions(); - - [ObjectProperty(ObjType = typeof(FileItemConfig))] - [DisplayName("文件上传配置")] - public FileItemConfig FileItemConfig { get; set; } = new FileItemConfig(); - - public override bool GetDesignerPropertyVisible(string propertyName) - { - var isField = NodeType == "field"; - var isText = NodeType == "text"; - var isGroup = NodeType == "group"; - - switch (propertyName) - { - case nameof(Content): - return isText; - case nameof(DefaultCollapsed): - return isGroup; - default: - if (FieldTypeControlledProperties.Contains(propertyName)) - { - return isField && IsFieldPropertyVisible(ItemType, propertyName); - } - return base.GetDesignerPropertyVisible(propertyName); - } - } - - public override object Clone() - { - return new OfflineFormNode - { - Text = Text, - Children = Children == null ? new List() : Children.ToList(), - NodeType = NodeType, - Content = Content, - DefaultCollapsed = DefaultCollapsed, - ItemId = ItemId, - ItemType = ItemType, - Title = Title, - Hint = Hint, - Required = Required, - Value = Value, - IncludeSeconds = IncludeSeconds, - CheckOptions = CheckOptions, - SelectOptionsList = SelectOptionsList, - MaxCount = MaxCount, - AllowImageUpload = AllowImageUpload, - CompressionOptions = CompressionOptions, - WatermarkOptions = WatermarkOptions, - FileItemConfig = FileItemConfig - }; - } - - private static HashSet CreateFieldVisibleProperties(params string[] propertyNames) - { - var visibleProperties = new HashSet(CommonFieldVisibleProperties); - foreach (var propertyName in propertyNames) - { - visibleProperties.Add(propertyName); - } - return visibleProperties; - } - - private static bool IsFieldPropertyVisible(string itemType, string propertyName) - { - HashSet visibleProperties; - if (!FieldVisiblePropertiesByType.TryGetValue(itemType ?? "textItem", out visibleProperties)) - { - visibleProperties = FieldVisiblePropertiesByType["textItem"]; - } - return visibleProperties.Contains(propertyName); - } - } - - public class CheckOptions : ObjectPropertyBase - { - [FormulaProperty] - [DisplayName("最小长度")] - public object MinLength { get; set; } - - [FormulaProperty] - [DisplayName("最大长度")] - public object MaxLength { get; set; } - - [FormulaProperty] - [DisplayName("正则表达式")] - public object RegexPattern { get; set; } - } - - public class SelectOptions : ObjectPropertyBase - { - [FormulaProperty] - [DisplayName("值")] - public object Value { get; set; } - - [FormulaProperty] - [DisplayName("显示文本")] - public object Label { get; set; } - } - - public class ImageCompressionOptions : ObjectPropertyBase - { - [DisplayName("启用压缩")] - [Description("默认关闭,关闭时按原图保存。启用后才使用下面的压缩参数。")] - public bool EnableCompression { get; set; } - - [FormulaProperty] - [DisplayName("最长边像素")] - public object MaxLongEdge { get; set; } = 1600; - - [FormulaProperty] - [DisplayName("JPEG质量")] - public object JpegQuality { get; set; } = 80; - - [FormulaProperty] - [DisplayName("目标大小KB")] - [Description("0表示不按文件大小继续压缩。")] - public object MaxFileSizeKb { get; set; } = 0; - - [FormulaProperty] - [DisplayName("最低JPEG质量")] - public object MinQuality { get; set; } = 60; - } - - public class ImageWatermarkOptions : ObjectPropertyBase - { - [DisplayName("时间戳水印")] - public bool EnableTimestamp { get; set; } = false; - - [ListProperty] - [DisplayName("自定义字段")] - public List Fields { get; set; } = new List - { - }; - } - - public class ImageWatermarkField : ObjectPropertyBase - { - [DisplayName("Key")] - public string Key { get; set; } - - [FormulaProperty] - [DisplayName("Value")] - public object Value { get; set; } - } - - public class FileItemConfig : ObjectPropertyBase - { - [FormulaProperty] - [DisplayName("最大数量")] - [Description("0表示不限制上传文件数量。")] - public object MaxCount { get; set; } = 0; - - [FormulaProperty] - [DisplayName("允许扩展名")] - [Description("逗号分隔,每个扩展名前带点;留空表示不限制,例如:.pdf,.doc,.docx。")] - public object AllowedExtensions { get; set; } - - [FormulaProperty] - [DisplayName("单文件最大大小KB")] - [Description("0表示不限制单文件大小。")] - public object MaxFileSizeKb { get; set; } = 0; - } } diff --git a/OfflinePlusBuildPattern.cs b/OfflinePlusBuildPattern.cs new file mode 100644 index 0000000..853e627 --- /dev/null +++ b/OfflinePlusBuildPattern.cs @@ -0,0 +1,332 @@ +using System.Collections.Generic; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using GrapeCity.Forguncy.Commands; +using GrapeCity.Forguncy.Plugin; + +namespace AndroidPDACommand +{ + [Icon("pack://application:,,,/AndroidPDACommand;component/Resources/Icon_OfflineBuild.png")] + [Category("活字格安卓容器(HAC)")] + public class OfflinePlusBuildPattern : BaseCommand + { + [FormulaProperty] + [DisplayName("项目编号")] + [Description("项目的唯一标识,全局唯一")] + public object PatternId { get; set; } + + [DisplayName("名称")] + [FormulaProperty] + public object Title { get; set; } + + [DisplayName("描述")] + [FormulaProperty] + public object Description { get; set; } + + [Required] + [FormulaProperty] + [DisplayName("版本号")] + [Description("同一项目编号下的表单定义版本,用于区分表单结构变更。")] + public string SchemaVersion { get; set; } = "1.0"; + + [DisplayName("步骤")] + [ObjectListProperty(ItemType = typeof(OfflineFormStep))] + public List Steps { get; set; } + + [DisplayName("将离线表单JSON返回到变量")] + [ResultToProperty] + public string PatternJson { get; set; } = "OfflinePatternJson"; + + public override string ToString() + { + return "构建离线表单"; + } + } + + public class OfflineFormStep : ObjectPropertyBase, INamedObject + { + public string Name { get; set; } + + [FormulaProperty] + [DisplayName("步骤编号")] + [Description("该步骤的唯一标识,同一个离线表单项目内必须唯一。")] + public object StepId { get; set; } + + [FormulaProperty] + [DisplayName("标题")] + public object Title { get; set; } + + [TreeProperty(NodeType = typeof(OfflineFormNode), DefaultNodeName = "节点")] + [DisplayName("页面内容")] + public List Items { get; set; } = new List(); + } + + public class OfflineFormNode : ObjectPropertyBase, ITreeNode + { + private static readonly string[] CommonFieldVisibleProperties = + { + nameof(ItemId), + nameof(ItemType), + nameof(Title), + nameof(Hint), + nameof(Required) + }; + + private static readonly HashSet FieldTypeControlledProperties = new HashSet(CommonFieldVisibleProperties) + { + nameof(Value), + nameof(CheckOptions), + nameof(SelectOptionsList), + nameof(IncludeSeconds), + nameof(MaxCount), + nameof(AllowImageUpload), + nameof(CompressionOptions), + nameof(WatermarkOptions), + nameof(FileItemConfig) + }; + + private static readonly Dictionary> FieldVisiblePropertiesByType = new Dictionary> + { + { "textItem", CreateFieldVisibleProperties(nameof(Value), nameof(CheckOptions)) }, + { "passwordItem", CreateFieldVisibleProperties(nameof(Value), nameof(CheckOptions)) }, + { "selectItem", CreateFieldVisibleProperties(nameof(Value), nameof(SelectOptionsList)) }, + { "datePicker", CreateFieldVisibleProperties(nameof(Value)) }, + { "timePicker", CreateFieldVisibleProperties(nameof(Value), nameof(IncludeSeconds)) }, + { "imageItem", CreateFieldVisibleProperties(nameof(MaxCount), nameof(AllowImageUpload), nameof(CompressionOptions), nameof(WatermarkOptions)) }, + { "fileItem", CreateFieldVisibleProperties(nameof(FileItemConfig)) } + }; + + [DisplayName("节点名称")] + public string Text { get; set; } + + [Browsable(false)] + public IEnumerable Children { get; set; } = new List(); + + [DisplayName("节点类型")] + [ComboProperty(ValueList = "group|text|field", DisplayList = "分组|普通文本|表单项")] + public string NodeType { get; set; } = "group"; + + [FormulaProperty] + [DisplayName("说明内容")] + public object Content { get; set; } + + [DisplayName("默认折叠")] + public bool DefaultCollapsed { get; set; } + + [FormulaProperty] + [DisplayName("编号")] + [Description("该表单项的唯一标识,全局唯一,无论是同一项目内,还是跨项目,都必须唯一,更建议使用项目编号作为前缀拼接;例如项目为Project01,则该表单项编号为Project01_Name")] + public object ItemId { get; set; } + + [DisplayName("类型")] + [ComboProperty(ValueList = "textItem|passwordItem|selectItem|datePicker|timePicker|imageItem|fileItem", DisplayList = "文本框|密码框|选择框|日期选择|时间选择|图片列表|文件上传")] + public string ItemType { get; set; } = "textItem"; + + [FormulaProperty] + [DisplayName("标题")] + public object Title { get; set; } + + [FormulaProperty] + [DisplayName("水印")] + public object Hint { get; set; } + + [DisplayName("必填")] + public bool Required { get; set; } + + [FormulaProperty] + [DisplayName("默认值")] + public object Value { get; set; } + + [DisplayName("包含秒")] + [Description("仅时间选择类型生效。启用后可选择时分秒;关闭时使用系统原生时分选择器。")] + public bool IncludeSeconds { get; set; } + + + [ObjectProperty(ObjType = typeof(CheckOptions))] + [DisplayName("校验规则")] + public CheckOptions CheckOptions { get; set; } + + [ListProperty] + [DisplayName("选则项")] + public List SelectOptionsList { get; set; } + + [FormulaProperty] + [DisplayName("图片最大数量")] + [Description("0表示不限制图片数量。")] + public object MaxCount { get; set; } = 0; + + [DisplayName("允许图片上传")] + [Description("仅图片列表类型生效。启用后填报时除拍照外还可以从本地选择图片。")] + public bool AllowImageUpload { get; set; } + + [ObjectProperty(ObjType = typeof(ImageCompressionOptions))] + [DisplayName("图片压缩设置")] + public ImageCompressionOptions CompressionOptions { get; set; } = new ImageCompressionOptions(); + + [ObjectProperty(ObjType = typeof(ImageWatermarkOptions))] + [DisplayName("拍照水印配置")] + public ImageWatermarkOptions WatermarkOptions { get; set; } = new ImageWatermarkOptions(); + + [ObjectProperty(ObjType = typeof(FileItemConfig))] + [DisplayName("文件上传配置")] + public FileItemConfig FileItemConfig { get; set; } = new FileItemConfig(); + + public override bool GetDesignerPropertyVisible(string propertyName) + { + var isField = NodeType == "field"; + var isText = NodeType == "text"; + var isGroup = NodeType == "group"; + + switch (propertyName) + { + case nameof(Content): + return isText; + case nameof(DefaultCollapsed): + return isGroup; + default: + if (FieldTypeControlledProperties.Contains(propertyName)) + { + return isField && IsFieldPropertyVisible(ItemType, propertyName); + } + return base.GetDesignerPropertyVisible(propertyName); + } + } + + public override object Clone() + { + return new OfflineFormNode + { + Text = Text, + Children = Children == null ? new List() : Children.ToList(), + NodeType = NodeType, + Content = Content, + DefaultCollapsed = DefaultCollapsed, + ItemId = ItemId, + ItemType = ItemType, + Title = Title, + Hint = Hint, + Required = Required, + Value = Value, + IncludeSeconds = IncludeSeconds, + CheckOptions = CheckOptions, + SelectOptionsList = SelectOptionsList, + MaxCount = MaxCount, + AllowImageUpload = AllowImageUpload, + CompressionOptions = CompressionOptions, + WatermarkOptions = WatermarkOptions, + FileItemConfig = FileItemConfig + }; + } + + private static HashSet CreateFieldVisibleProperties(params string[] propertyNames) + { + var visibleProperties = new HashSet(CommonFieldVisibleProperties); + foreach (var propertyName in propertyNames) + { + visibleProperties.Add(propertyName); + } + return visibleProperties; + } + + private static bool IsFieldPropertyVisible(string itemType, string propertyName) + { + HashSet visibleProperties; + if (!FieldVisiblePropertiesByType.TryGetValue(itemType ?? "textItem", out visibleProperties)) + { + visibleProperties = FieldVisiblePropertiesByType["textItem"]; + } + return visibleProperties.Contains(propertyName); + } + } + + public class CheckOptions : ObjectPropertyBase + { + [FormulaProperty] + [DisplayName("最小长度")] + public object MinLength { get; set; } + + [FormulaProperty] + [DisplayName("最大长度")] + public object MaxLength { get; set; } + + [FormulaProperty] + [DisplayName("正则表达式")] + public object RegexPattern { get; set; } + } + + public class SelectOptions : ObjectPropertyBase + { + [FormulaProperty] + [DisplayName("值")] + public object Value { get; set; } + + [FormulaProperty] + [DisplayName("显示文本")] + public object Label { get; set; } + } + + public class ImageCompressionOptions : ObjectPropertyBase + { + [DisplayName("启用压缩")] + [Description("默认关闭,关闭时按原图保存。启用后才使用下面的压缩参数。")] + public bool EnableCompression { get; set; } + + [FormulaProperty] + [DisplayName("最长边像素")] + public object MaxLongEdge { get; set; } = 1600; + + [FormulaProperty] + [DisplayName("JPEG质量")] + public object JpegQuality { get; set; } = 80; + + [FormulaProperty] + [DisplayName("目标大小KB")] + [Description("0表示不按文件大小继续压缩。")] + public object MaxFileSizeKb { get; set; } = 0; + + [FormulaProperty] + [DisplayName("最低JPEG质量")] + public object MinQuality { get; set; } = 60; + } + + public class ImageWatermarkOptions : ObjectPropertyBase + { + [DisplayName("时间戳水印")] + public bool EnableTimestamp { get; set; } = false; + + [ListProperty] + [DisplayName("自定义字段")] + public List Fields { get; set; } = new List + { + }; + } + + public class ImageWatermarkField : ObjectPropertyBase + { + [DisplayName("Key")] + public string Key { get; set; } + + [FormulaProperty] + [DisplayName("Value")] + public object Value { get; set; } + } + + public class FileItemConfig : ObjectPropertyBase + { + [FormulaProperty] + [DisplayName("最大数量")] + [Description("0表示不限制上传文件数量。")] + public object MaxCount { get; set; } = 0; + + [FormulaProperty] + [DisplayName("允许扩展名")] + [Description("逗号分隔,每个扩展名前带点;留空表示不限制,例如:.pdf,.doc,.docx。")] + public object AllowedExtensions { get; set; } + + [FormulaProperty] + [DisplayName("单文件最大大小KB")] + [Description("0表示不限制单文件大小。")] + public object MaxFileSizeKb { get; set; } = 0; + } +} diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 6022923..6b22098 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -2840,17 +2840,16 @@ var Biometric_Available_Async_Command = (function (_super) { Forguncy.CommandFactory.registerCommand("AndroidPDACommand.Biometric_Available_Async, AndroidPDACommand", Biometric_Available_Async_Command); -var OfflinePlusAddPattern_Async_Command = (function (_super) { - __extends(OfflinePlusAddPattern_Async_Command, _super); - function OfflinePlusAddPattern_Async_Command() { +var OfflinePlusBuildPattern_Command = (function (_super) { + __extends(OfflinePlusBuildPattern_Command, _super); + function OfflinePlusBuildPattern_Command() { return _super !== null && _super.apply(this, arguments) || this; } - OfflinePlusAddPattern_Async_Command.prototype.execute = async function () { + OfflinePlusBuildPattern_Command.prototype.execute = function () { let me = this; let params = this.CommandParam; - let patternParamJson = ""; function evaluate(value) { if (value === undefined || value === null) { @@ -3106,27 +3105,82 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { }); } - function getManualPdfUrl() { - if (params.ManualAttachmentCell === undefined || params.ManualAttachmentCell === null || params.ManualAttachmentCell === "") { - return undefined; + const steps = buildSteps(params.Steps); + let patternParam = { + patternId: this.evaluateFormula(params.PatternId), + schemaVersion: this.evaluateFormula(params.SchemaVersion), + title: this.evaluateFormula(params.Title), + description: this.evaluateFormula(params.Description), + steps: steps + }; + + var patternParamJson = JSON.stringify(patternParam, null, 2); + console.log(patternParam); + HAC_ReturnToParam(params.PatternJson, patternParamJson); + }; + + + return OfflinePlusBuildPattern_Command; +}(Forguncy.CommandBase)); + +Forguncy.CommandFactory.registerCommand("AndroidPDACommand.OfflinePlusBuildPattern, AndroidPDACommand", OfflinePlusBuildPattern_Command); + +var OfflinePlusAddPattern_Async_Command = (function (_super) { + __extends(OfflinePlusAddPattern_Async_Command, _super); + function OfflinePlusAddPattern_Async_Command() { + return _super !== null && _super.apply(this, arguments) || this; + } + + OfflinePlusAddPattern_Async_Command.prototype.execute = async function () { + + let me = this; + let params = this.CommandParam; + let finalPatternParamJson = ""; + + function evaluate(value) { + if (value === undefined || value === null) { + return value; } + return me.evaluateFormula(value); + } - var manualValue = evaluate(params.ManualAttachmentCell); + function getManualPdfUrl(manualValue) { if (!manualValue) { - return undefined; + return ""; } var fileId = (manualValue + "").split("|")[0]; if (!fileId) { console.warn("手册附件单元格没有文件标识。", manualValue); - return undefined; + return ""; } return Forguncy.Helper.SpecialPath.getFileDownloadUrl(fileId); } - let _ticket = HAC_GenerateCallbackTicket(me, function (payload, payload2) { - alert("离线表单项目设置成功\r\n\r\nJSON Schema:\r\n" + patternParamJson); + var patternJson = evaluate(params.PatternJson); + if (!patternJson) { + alert("离线表单JSON不能为空。"); + return; + } + + var patternParam; + try { + patternParam = typeof patternJson === "string" ? JSON.parse(patternJson) : patternJson; + } catch (e) { + alert("离线表单JSON格式不正确:" + (e ? e.message : "")); + return; + } + + var manualAttachmentValue = params.ManualAttachmentCell === undefined || params.ManualAttachmentCell === null || params.ManualAttachmentCell === "" + ? "" + : evaluate(params.ManualAttachmentCell); + var signatureBase64 = params.SignatureAttachmentCell === undefined || params.SignatureAttachmentCell === null || params.SignatureAttachmentCell === "" + ? "" + : evaluate(params.SignatureAttachmentCell); + + let ticket = HAC_GenerateCallbackTicket(me, function (payload, payload2) { + alert("离线表单项目设置成功\r\n\r\nJSON Schema:\r\n" + finalPatternParamJson); me.CommandExecutor.excuteCommand(me.CommandParam.CommandList, { runTimePageName: me.CommandExecutingInfo.runTimePageName, commandID: new Date().valueOf().toString(), @@ -3136,27 +3190,21 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { }, locationString: "执行window.offlinePlus.offlinePlusAddPattern" }); - }, HAC_GetOfflinePlusDebugInfo("添加离线表单项目", "生成回调ticket")); - const steps = buildSteps(params.Steps); - let patternParam = { - ticket: _ticket, - patternId: this.evaluateFormula(params.PatternId), - schemaVersion: this.evaluateFormula(params.SchemaVersion), - title: this.evaluateFormula(params.Title), - description: this.evaluateFormula(params.Description), - steps: steps - }; - const signatureBase64 = params.SignatureAttachmentCell === undefined || params.SignatureAttachmentCell === null || params.SignatureAttachmentCell === "" - ? "" - : this.evaluateFormula(params.SignatureAttachmentCell); - var manualPdfUrl = getManualPdfUrl(); + }, HAC_GetOfflinePlusDebugInfo("下载离线表单", "生成回调ticket")); + if (!ticket) { + console.error(HAC_GetOfflinePlusDebugInfo("下载离线表单", "生成回调ticket失败")); + return; + } + + var manualPdfUrl = getManualPdfUrl(manualAttachmentValue); + patternParam.ticket = ticket; + finalPatternParamJson = JSON.stringify(patternParam, null, 2); - patternParamJson = JSON.stringify(patternParam, null, 2); console.log(patternParam); if (window.offlinePlus && window.offlinePlus.offlinePlusAddPatternAsync) { - window.offlinePlus.offlinePlusAddPatternAsync(patternParamJson, manualPdfUrl || "", signatureBase64 || ""); + window.offlinePlus.offlinePlusAddPatternAsync(finalPatternParamJson, manualPdfUrl || "", signatureBase64 || ""); } else { - HAC_CallFunctionOutOfHAC(HAC_GetOfflinePlusDebugInfo("添加离线表单项目", "调用offlinePlusAddPatternAsync")); + HAC_CallFunctionOutOfHAC(HAC_GetOfflinePlusDebugInfo("下载离线表单", "调用offlinePlusAddPatternAsync")); } }; diff --git a/Resources/Icon_OfflineBuild.png b/Resources/Icon_OfflineBuild.png new file mode 100644 index 0000000000000000000000000000000000000000..9430bea9db1a5a7f715d3ae3259bade60d8e00cb GIT binary patch literal 295 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!9AWXjv*HQ$q5V8E@;P=M{DL^t#^`G!WXMA z(V(*b?>~Qm<|_+dr(W3pUHk&a`eOk-yv Date: Wed, 24 Jun 2026 13:42:24 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E6=94=AF=E6=8C=81=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E5=86=85=E5=AE=B9=E5=85=AC=E5=BC=8F=E6=9E=84=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OfflinePlusBuildPattern.cs:在离线表单步骤上新增“使用页面内容公式”开关,并保留两个“页面内容”输入入口;通过 GetDesignerPropertyVisible 按开关隐藏固定页面内容树或公式输入,满足同一字段语义下切换输入方式的设计器配置需求。 Resources/AndroidPDACommand.js:调整构建步骤 JSON 的 items 来源;未勾选时继续使用原来的 buildNodes(step.Items),勾选时只 evaluate 页面内容公式并直接作为 step.items,避免公式模式再经过固定节点转换。 --- OfflinePlusBuildPattern.cs | 20 ++++++++++++++++++++ Resources/AndroidPDACommand.js | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/OfflinePlusBuildPattern.cs b/OfflinePlusBuildPattern.cs index 853e627..7be725a 100644 --- a/OfflinePlusBuildPattern.cs +++ b/OfflinePlusBuildPattern.cs @@ -57,9 +57,29 @@ namespace AndroidPDACommand [DisplayName("标题")] public object Title { get; set; } + [DisplayName("使用页面内容公式")] + public bool UseItemsFormula { get; set; } + [TreeProperty(NodeType = typeof(OfflineFormNode), DefaultNodeName = "节点")] [DisplayName("页面内容")] public List Items { get; set; } = new List(); + + [FormulaProperty] + [DisplayName("页面内容")] + public object ItemsFormula { get; set; } + + public override bool GetDesignerPropertyVisible(string propertyName) + { + switch (propertyName) + { + case nameof(Items): + return !UseItemsFormula; + case nameof(ItemsFormula): + return UseItemsFormula; + default: + return base.GetDesignerPropertyVisible(propertyName); + } + } } public class OfflineFormNode : ObjectPropertyBase, ITreeNode diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 6b22098..8eb00f1 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -3100,7 +3100,7 @@ var OfflinePlusBuildPattern_Command = (function (_super) { return { stepId: evaluate(step.StepId), title: evaluate(step.Title), - items: buildNodes(step.Items) + items: step.UseItemsFormula ? evaluate(step.ItemsFormula) : buildNodes(step.Items) }; }); } -- Gitee From 4705f60008737b66e23cd482ac1af72239414835 Mon Sep 17 00:00:00 2001 From: Rex Lei Date: Wed, 24 Jun 2026 14:37:18 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=9E=84=E5=BB=BA?= =?UTF-8?q?=E7=A6=BB=E7=BA=BF=E9=A1=B5=E9=9D=A2=E5=86=85=E5=AE=B9=E5=91=BD?= =?UTF-8?q?=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 变更原因: - AndroidPDACommand.csproj:加入 OfflinePlusBuildFormItem.cs 编译项,并把 Icon_OfflineFormItem.png 注册为资源,确保新命令和图标会被插件打包。 - OfflinePlusBuildFormItem.cs:新增“构建离线页面内容”命令,复用 OfflineFormNode 的树形页面内容配置,返回单个页面内容对象供“页面内容”公式组合使用。 - Resources/AndroidPDACommand.js:抽出离线表单节点 JSON 构建逻辑供整表构建和单节点构建复用;新命令在单个根节点时直接返回该节点,多个根节点时自动包一层带时间戳 key/title 的 group,保留 children 支持。 - Resources/Icon_OfflineFormItem.png:新增新命令专用图标,避免和“构建离线表单”命令共用图标导致设计器命令识别不清。 验证: - node --check Resources/AndroidPDACommand.js - dotnet build AndroidPDACommand.csproj - git diff --cached --check --- AndroidPDACommand.csproj | 2 + OfflinePlusBuildFormItem.cs | 25 ++ Resources/AndroidPDACommand.js | 488 ++++++++++++++++------------- Resources/Icon_OfflineFormItem.png | Bin 0 -> 213 bytes 4 files changed, 296 insertions(+), 219 deletions(-) create mode 100644 OfflinePlusBuildFormItem.cs create mode 100644 Resources/Icon_OfflineFormItem.png diff --git a/AndroidPDACommand.csproj b/AndroidPDACommand.csproj index 575c3e8..fba84ea 100644 --- a/AndroidPDACommand.csproj +++ b/AndroidPDACommand.csproj @@ -50,6 +50,7 @@ + @@ -168,6 +169,7 @@ + diff --git a/OfflinePlusBuildFormItem.cs b/OfflinePlusBuildFormItem.cs new file mode 100644 index 0000000..2cf5b47 --- /dev/null +++ b/OfflinePlusBuildFormItem.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using System.ComponentModel; +using GrapeCity.Forguncy.Commands; +using GrapeCity.Forguncy.Plugin; + +namespace AndroidPDACommand +{ + [Icon("pack://application:,,,/AndroidPDACommand;component/Resources/Icon_OfflineFormItem.png")] + [Category("活字格安卓容器(HAC)")] + public class OfflinePlusBuildFormItem : BaseCommand + { + [TreeProperty(NodeType = typeof(OfflineFormNode), DefaultNodeName = "节点")] + [DisplayName("页面内容")] + public List Items { get; set; } = new List(); + + [DisplayName("将页面内容返回到变量")] + [ResultToProperty] + public string ItemResult { get; set; } = "OfflineFormItem"; + + public override string ToString() + { + return "构建离线页面内容"; + } + } +} diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 8eb00f1..e827326 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -2840,277 +2840,327 @@ var Biometric_Available_Async_Command = (function (_super) { Forguncy.CommandFactory.registerCommand("AndroidPDACommand.Biometric_Available_Async, AndroidPDACommand", Biometric_Available_Async_Command); -var OfflinePlusBuildPattern_Command = (function (_super) { - __extends(OfflinePlusBuildPattern_Command, _super); - function OfflinePlusBuildPattern_Command() { - return _super !== null && _super.apply(this, arguments) || this; +function HAC_OfflinePlusCreateFormNodeBuilder(context) { + let me = context; + + function evaluate(value) { + if (value === undefined || value === null) { + return value; + } + return me.evaluateFormula(value); } - OfflinePlusBuildPattern_Command.prototype.execute = function () { + function getList(value) { + return Array.isArray(value) ? value : []; + } - let me = this; - let params = this.CommandParam; + function buildSelectOptions(options) { + return getList(options).map(function (option) { + return { + value: evaluate(option.Value), + label: evaluate(option.Label) + }; + }); + } - function evaluate(value) { - if (value === undefined || value === null) { - return value; - } - return me.evaluateFormula(value); + function buildCheckOptions(options) { + if (!options) { + return undefined; } - function getList(value) { - return Array.isArray(value) ? value : []; + var checkOptions = {}; + var minLength = evaluate(options.MinLength); + var maxLength = evaluate(options.MaxLength); + var regexPattern = evaluate(options.RegexPattern); + if (minLength !== undefined && minLength !== null && minLength !== "") { + checkOptions.minLength = minLength; } - - function buildSelectOptions(options) { - return getList(options).map(function (option) { - return { - value: evaluate(option.Value), - label: evaluate(option.Label) - }; - }); + if (maxLength !== undefined && maxLength !== null && maxLength !== "") { + checkOptions.maxLength = maxLength; } + if (regexPattern !== undefined && regexPattern !== null && regexPattern !== "") { + checkOptions.regexPattern = regexPattern; + } + return Object.keys(checkOptions).length > 0 ? checkOptions : undefined; + } - function buildCheckOptions(options) { - if (!options) { - return undefined; - } + function buildImageCompression(options) { + if (!options) { + return undefined; + } - var checkOptions = {}; - var minLength = evaluate(options.MinLength); - var maxLength = evaluate(options.MaxLength); - var regexPattern = evaluate(options.RegexPattern); - if (minLength !== undefined && minLength !== null && minLength !== "") { - checkOptions.minLength = minLength; - } - if (maxLength !== undefined && maxLength !== null && maxLength !== "") { - checkOptions.maxLength = maxLength; - } - if (regexPattern !== undefined && regexPattern !== null && regexPattern !== "") { - checkOptions.regexPattern = regexPattern; - } - return Object.keys(checkOptions).length > 0 ? checkOptions : undefined; + var compression = {}; + var maxLongEdge = evaluate(options.MaxLongEdge); + var jpegQuality = evaluate(options.JpegQuality); + var maxFileSizeKb = evaluate(options.MaxFileSizeKb); + var minQuality = evaluate(options.MinQuality); + compression.enableCompression = !!options.EnableCompression; + if (maxLongEdge !== undefined && maxLongEdge !== null && maxLongEdge !== "") { + compression.maxLongEdge = maxLongEdge; + } + if (jpegQuality !== undefined && jpegQuality !== null && jpegQuality !== "") { + compression.jpegQuality = jpegQuality; + } + if (maxFileSizeKb !== undefined && maxFileSizeKb !== null && maxFileSizeKb !== "") { + compression.maxFileSizeKb = maxFileSizeKb; + } + if (minQuality !== undefined && minQuality !== null && minQuality !== "") { + compression.minQuality = minQuality; } + return Object.keys(compression).length > 0 ? compression : undefined; + } - function buildImageCompression(options) { - if (!options) { - return undefined; - } + function buildImageWatermark(options) { + if (!options) { + return undefined; + } - var compression = {}; - var maxLongEdge = evaluate(options.MaxLongEdge); - var jpegQuality = evaluate(options.JpegQuality); - var maxFileSizeKb = evaluate(options.MaxFileSizeKb); - var minQuality = evaluate(options.MinQuality); - compression.enableCompression = !!options.EnableCompression; - if (maxLongEdge !== undefined && maxLongEdge !== null && maxLongEdge !== "") { - compression.maxLongEdge = maxLongEdge; - } - if (jpegQuality !== undefined && jpegQuality !== null && jpegQuality !== "") { - compression.jpegQuality = jpegQuality; - } - if (maxFileSizeKb !== undefined && maxFileSizeKb !== null && maxFileSizeKb !== "") { - compression.maxFileSizeKb = maxFileSizeKb; - } - if (minQuality !== undefined && minQuality !== null && minQuality !== "") { - compression.minQuality = minQuality; - } - return Object.keys(compression).length > 0 ? compression : undefined; + var fields = getList(options.Fields); + if (!options.EnableTimestamp && fields.length === 0) { + return undefined; } - function buildImageWatermark(options) { - if (!options) { - return undefined; - } + var watermark = {}; + var items = fields.map(function (field) { + return { + key: field.Key, + value: evaluate(field.Value) + }; + }); - var fields = getList(options.Fields); - if (!options.EnableTimestamp && fields.length === 0) { - return undefined; - } + if (options.EnableTimestamp) { + watermark.enableTimestamp = true; + } + if (items.length > 0) { + watermark.items = items; + } + return Object.keys(watermark).length > 0 ? watermark : undefined; + } - var watermark = {}; - var items = fields.map(function (field) { - return { - key: field.Key, - value: evaluate(field.Value) - }; - }); + function buildFileItemConfig(options) { + if (!options) { + return undefined; + } - if (options.EnableTimestamp) { - watermark.enableTimestamp = true; - } - if (items.length > 0) { - watermark.items = items; - } - return Object.keys(watermark).length > 0 ? watermark : undefined; + var config = {}; + var maxCount = evaluate(options.MaxCount); + var allowedExtensions = evaluate(options.AllowedExtensions); + var maxFileSizeKb = evaluate(options.MaxFileSizeKb); + if (maxCount !== undefined && maxCount !== null && maxCount !== "") { + config.maxCount = maxCount; } + if (allowedExtensions !== undefined && allowedExtensions !== null && allowedExtensions !== "") { + config.allowedExtensions = allowedExtensions; + } + if (maxFileSizeKb !== undefined && maxFileSizeKb !== null && maxFileSizeKb !== "") { + config.maxFileSizeKb = maxFileSizeKb; + } + return Object.keys(config).length > 0 ? config : undefined; + } - function buildFileItemConfig(options) { - if (!options) { - return undefined; + var fieldTypeSpecs = { + textItem: { + apply: function (field, node) { + var checkOptions = buildCheckOptions(node.CheckOptions); + if (checkOptions) { + field.options = checkOptions; + } } - - var config = {}; - var maxCount = evaluate(options.MaxCount); - var allowedExtensions = evaluate(options.AllowedExtensions); - var maxFileSizeKb = evaluate(options.MaxFileSizeKb); - if (maxCount !== undefined && maxCount !== null && maxCount !== "") { - config.maxCount = maxCount; + }, + passwordItem: { + apply: function (field, node) { + var checkOptions = buildCheckOptions(node.CheckOptions); + if (checkOptions) { + field.options = checkOptions; + } } - if (allowedExtensions !== undefined && allowedExtensions !== null && allowedExtensions !== "") { - config.allowedExtensions = allowedExtensions; + }, + selectItem: { + apply: function (field, node) { + var selectOptions = buildSelectOptions(node.SelectOptionsList); + if (selectOptions.length > 0) { + field.options = { + selectOptions: selectOptions + }; + } } - if (maxFileSizeKb !== undefined && maxFileSizeKb !== null && maxFileSizeKb !== "") { - config.maxFileSizeKb = maxFileSizeKb; + }, + timePicker: { + apply: function (field, node) { + if (node.IncludeSeconds) { + field.options = { + includeSeconds: true + }; + } } - return Object.keys(config).length > 0 ? config : undefined; - } - - var fieldTypeSpecs = { - textItem: { - apply: function (field, node) { - var checkOptions = buildCheckOptions(node.CheckOptions); - if (checkOptions) { - field.options = checkOptions; - } + }, + imageItem: { + apply: function (field, node) { + var options = {}; + var maxCount = evaluate(node.MaxCount); + var compression = buildImageCompression(node.CompressionOptions); + var watermark = buildImageWatermark(node.WatermarkOptions); + if (maxCount !== undefined && maxCount !== null && maxCount !== "") { + options.maxCount = maxCount; } - }, - passwordItem: { - apply: function (field, node) { - var checkOptions = buildCheckOptions(node.CheckOptions); - if (checkOptions) { - field.options = checkOptions; - } + if (node.AllowImageUpload) { + options.allowImageUpload = true; } - }, - selectItem: { - apply: function (field, node) { - var selectOptions = buildSelectOptions(node.SelectOptionsList); - if (selectOptions.length > 0) { - field.options = { - selectOptions: selectOptions - }; - } + if (compression) { + options.compression = compression; } - }, - timePicker: { - apply: function (field, node) { - if (node.IncludeSeconds) { - field.options = { - includeSeconds: true - }; - } + if (watermark) { + options.watermark = watermark; } - }, - imageItem: { - apply: function (field, node) { - var options = {}; - var maxCount = evaluate(node.MaxCount); - var compression = buildImageCompression(node.CompressionOptions); - var watermark = buildImageWatermark(node.WatermarkOptions); - if (maxCount !== undefined && maxCount !== null && maxCount !== "") { - options.maxCount = maxCount; - } - if (node.AllowImageUpload) { - options.allowImageUpload = true; - } - if (compression) { - options.compression = compression; - } - if (watermark) { - options.watermark = watermark; - } - if (Object.keys(options).length > 0) { - field.options = options; - } + if (Object.keys(options).length > 0) { + field.options = options; } - }, - fileItem: { - apply: function (field, node) { - var config = buildFileItemConfig(node.FileItemConfig); - if (config) { - field.options = { - fileItemConfig: config - }; - } + } + }, + fileItem: { + apply: function (field, node) { + var config = buildFileItemConfig(node.FileItemConfig); + if (config) { + field.options = { + fileItemConfig: config + }; } } + } + }; + + function applyFieldTypeSpec(field, node) { + var spec = fieldTypeSpecs[node.ItemType]; + if (spec && spec.apply) { + spec.apply(field, node); + } + } + + function buildField(node) { + var field = { + itemId: evaluate(node.ItemId), + itemType: node.ItemType, + title: evaluate(node.Title), + hint: evaluate(node.Hint), + required: !!node.Required }; - function applyFieldTypeSpec(field, node) { - var spec = fieldTypeSpecs[node.ItemType]; - if (spec && spec.apply) { - spec.apply(field, node); - } + var value = evaluate(node.Value); + if (value !== undefined && value !== null && value !== "") { + field.value = value; } + applyFieldTypeSpec(field, node); + return field; + } - function buildField(node) { - var field = { - itemId: evaluate(node.ItemId), - itemType: node.ItemType, - title: evaluate(node.Title), - hint: evaluate(node.Hint), - required: !!node.Required - }; + function buildNode(node) { + var nodeType = node.NodeType || "group"; + var children = getList(node.Children); - var value = evaluate(node.Value); - if (value !== undefined && value !== null && value !== "") { - field.value = value; - } - applyFieldTypeSpec(field, node); - return field; + if (nodeType !== "group" && children.length > 0) { + console.warn("离线表单节点不是分组,但包含子节点。", node); } - function buildNodes(nodes) { - return getList(nodes).map(function (node) { - var nodeType = node.NodeType || "group"; - var children = getList(node.Children); + if (nodeType === "field") { + return { + nodeType: "field", + title: node.Text, + field: buildField(node) + }; + } - if (nodeType !== "group" && children.length > 0) { - console.warn("离线表单节点不是分组,但包含子节点。", node); - } + if (nodeType === "text") { + return { + nodeType: "text", + title: node.Text, + content: evaluate(node.Content) + }; + } - if (nodeType === "field") { - return { - nodeType: "field", - title: node.Text, - field: buildField(node) - }; - } + return { + nodeType: "group", + title: node.Text, + defaultCollapsed: !!node.DefaultCollapsed, + children: buildNodes(children) + }; + } - if (nodeType === "text") { - return { - nodeType: "text", - title: node.Text, - content: evaluate(node.Content) - }; - } + function buildNodes(nodes) { + return getList(nodes).map(function (node) { + return buildNode(node); + }); + } - return { - nodeType: "group", - title: node.Text, - defaultCollapsed: !!node.DefaultCollapsed, - children: buildNodes(children) - }; - }); + function buildFormItem(nodes) { + var items = buildNodes(nodes); + if (items.length <= 1) { + return items[0]; } + var timestamp = new Date().getTime(); + return { + nodeType: "group", + key: "offlineFormItemGroup_" + timestamp, + title: "页面内容分组_" + timestamp, + defaultCollapsed: false, + children: items + }; + } + + return { + evaluate: evaluate, + getList: getList, + buildNode: buildNode, + buildNodes: buildNodes, + buildFormItem: buildFormItem + }; +} + +var OfflinePlusBuildFormItem_Command = (function (_super) { + __extends(OfflinePlusBuildFormItem_Command, _super); + function OfflinePlusBuildFormItem_Command() { + return _super !== null && _super.apply(this, arguments) || this; + } + + OfflinePlusBuildFormItem_Command.prototype.execute = function () { + let params = this.CommandParam; + var formNodeBuilder = HAC_OfflinePlusCreateFormNodeBuilder(this); + var item = formNodeBuilder.buildFormItem(params.Items); + HAC_ReturnToParam(params.ItemResult, item); + }; + + return OfflinePlusBuildFormItem_Command; +}(Forguncy.CommandBase)); + +Forguncy.CommandFactory.registerCommand("AndroidPDACommand.OfflinePlusBuildFormItem, AndroidPDACommand", OfflinePlusBuildFormItem_Command); + +var OfflinePlusBuildPattern_Command = (function (_super) { + __extends(OfflinePlusBuildPattern_Command, _super); + function OfflinePlusBuildPattern_Command() { + return _super !== null && _super.apply(this, arguments) || this; + } + + OfflinePlusBuildPattern_Command.prototype.execute = function () { + + let params = this.CommandParam; + var formNodeBuilder = HAC_OfflinePlusCreateFormNodeBuilder(this); + function buildSteps(steps) { - return getList(steps).map(function (step) { + return formNodeBuilder.getList(steps).map(function (step) { return { - stepId: evaluate(step.StepId), - title: evaluate(step.Title), - items: step.UseItemsFormula ? evaluate(step.ItemsFormula) : buildNodes(step.Items) + stepId: formNodeBuilder.evaluate(step.StepId), + title: formNodeBuilder.evaluate(step.Title), + items: step.UseItemsFormula ? formNodeBuilder.evaluate(step.ItemsFormula) : formNodeBuilder.buildNodes(step.Items) }; }); } const steps = buildSteps(params.Steps); let patternParam = { - patternId: this.evaluateFormula(params.PatternId), - schemaVersion: this.evaluateFormula(params.SchemaVersion), - title: this.evaluateFormula(params.Title), - description: this.evaluateFormula(params.Description), + patternId: formNodeBuilder.evaluate(params.PatternId), + schemaVersion: formNodeBuilder.evaluate(params.SchemaVersion), + title: formNodeBuilder.evaluate(params.Title), + description: formNodeBuilder.evaluate(params.Description), steps: steps }; diff --git a/Resources/Icon_OfflineFormItem.png b/Resources/Icon_OfflineFormItem.png new file mode 100644 index 0000000000000000000000000000000000000000..26e42e6d02f98faf21b2d29902644cb786662b0b GIT binary patch literal 213 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!7NV~#}EtuM-&X4F>C(h#_2e-C|7uXoEEl8fk(~wxw z>muEdXT3}NgH(er^Dc>8UWf1cWmnZDM3dnRUue?m~bf&{hUdS3j3^P6