diff --git a/AndroidPDACommand.csproj b/AndroidPDACommand.csproj index 9d634e0b7a162561b05fff49cf80c450bef5c0ec..fba84ea341ed0b7ffabbd4cd0d55f7e6892fb42d 100644 --- a/AndroidPDACommand.csproj +++ b/AndroidPDACommand.csproj @@ -1,76 +1,38 @@ - - - + - Debug - AnyCPU - {8414FB54-B60D-4F9A-9505-B5E0B2D86C43} + net8.0-windows Library - Properties AndroidPDACommand AndroidPDACommand - v4.7.2 - 512 SAK SAK SAK SAK - true + true + true + true + false + false + false + false + bin\ true full false - bin\ DEBUG;TRACE prompt 4 - MinimumRecommendedRules.ruleset pdbonly true - bin\ TRACE prompt 4 - - - false - - - D:\ForguncyOtherVersion\8.0.6.0\Website\designerBin\Forguncy.Commands.dll - - - D:\ForguncyOtherVersion\8.0.6.0\Website\designerBin\Forguncy.Commands.Design.dll - - - D:\ForguncyOtherVersion\8.0.6.0\Website\designerBin\GrapeCity.Forguncy.Plugin.dll - - - False - D:\ForguncyOtherVersion\8.0.6.0\Website\bin\GrapeCity.Forguncy.ServerApi.dll - - - packages\Jiguang.JPush.1.2.5\lib\net45\Jiguang.JPush.dll - - - packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll - - - - - - - - - - - - - @@ -87,6 +49,10 @@ + + + + @@ -117,6 +83,7 @@ + @@ -141,77 +108,72 @@ - + + + + + E:\forAgentA\forguncy\Forguncy.Server2\designerBin\Forguncy.Commands.dll + False + + + E:\forAgentA\forguncy\Forguncy.Server2\designerBin\Forguncy.Commands.Design.dll + False + + + E:\forAgentA\forguncy\Forguncy.Server2\designerBin\GrapeCity.Forguncy.Plugin.dll + False + + + E:\forAgentA\forguncy\Forguncy.Server2\bin\GrapeCity.Forguncy.ServerApi.dll + False + + + + + - + PreserveNewest - - - + PreserveNewest - - + Always - - - + PreserveNewest + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "D:\ForguncyCode\puglin\PluginTools\PluginPackageTool\bin\Release\PluginPackageTool.exe" "$(ProjectDir)\" "$(ConfigurationName)" - - \ No newline at end of file + + + + + + + + + diff --git a/Device_Info_Json.cs b/Device_Info_Json.cs new file mode 100644 index 0000000000000000000000000000000000000000..2c3c05a21f737c6dcbbd5e400adc1895889ab671 --- /dev/null +++ b/Device_Info_Json.cs @@ -0,0 +1,27 @@ +using GrapeCity.Forguncy.Commands; +using GrapeCity.Forguncy.Plugin; +using System.ComponentModel; + +namespace AndroidPDACommand +{ + [Icon("pack://application:,,,/AndroidPDACommand;component/Resources/Icon_Phone.png")] + [Category("活字格安卓容器(HAC)")] + [OrderWeight(903)] + public class Device_Info_Json : BaseCommand + { + [DisplayName("将设备信息JSON返回到变量")] + [Description("读取设备唯一标识、品牌、型号、Android版本、APP版本、WebView版本等基础信息。")] + [SearchableProperty] + [ResultToProperty] + public string DeviceInfoJson { get; set; } + + public override string ToString() + { + if (string.IsNullOrEmpty(DeviceInfoJson)) + { + return "读取设备信息"; + } + return "读取设备信息:" + DeviceInfoJson; + } + } +} diff --git a/JPushServerCommand.cs b/JPushServerCommand.cs index 317c421e4e5fcecbd923cda3079c40bddbd97a5b..c6ff1b64f1e62cb1d9dc9a7742601d86c755cdc8 100644 --- a/JPushServerCommand.cs +++ b/JPushServerCommand.cs @@ -12,7 +12,6 @@ using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; using System.Windows.Markup; -using System.Xml.Serialization.Configuration; namespace AndroidPDACommand { @@ -66,7 +65,7 @@ namespace AndroidPDACommand if (!string.IsNullOrEmpty(url)) { - intentObj.Add("url", "intent:#Intent;action=com.huozige.lab.container.navigate;component=com.huozige.lab.container/com.huozige.lab.container.MainActivity;S.url=" + System.Web.HttpUtility.UrlEncode(url) + ";end"); + intentObj.Add("url", "intent:#Intent;action=com.huozige.lab.container.navigate;component=com.huozige.lab.container/com.huozige.lab.container.MainActivity;S.url=" + WebUtility.UrlEncode(url) + ";end"); } else { diff --git a/OfflinePlusAddPattern_Async.cs b/OfflinePlusAddPattern_Async.cs new file mode 100644 index 0000000000000000000000000000000000000000..8f7612d8c4a69afc31bd1faebb4cc5de4ad3fd1a --- /dev/null +++ b/OfflinePlusAddPattern_Async.cs @@ -0,0 +1,33 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using GrapeCity.Forguncy.Commands; +using GrapeCity.Forguncy.Plugin; + +namespace AndroidPDACommand +{ + [Icon("pack://application:,,,/AndroidPDACommand;component/Resources/Icon_OfflineDownload.png")] + [Category("活字格安卓容器(HAC)")] + public class OfflinePlusAddPattern_Async : BaseAsyncCommand + { + [Required] + [FormulaProperty] + [DisplayName("离线表单JSON")] + [Description("由“构建离线表单”命令生成的表单JSON。")] + public object PatternJson { get; set; } + + [FormulaProperty] + [DisplayName("手册附件单元格")] + [Description("选择保存 PDF 手册附件的单元格。下载离线表单时会把 PDF 手册随表单一起保存到离线设备。")] + public object ManualAttachmentCell { get; set; } + + [FormulaProperty] + [DisplayName("员工签名单元格")] + [Description("选择保存员工签名附件的单元格。下载离线表单时会把签名文件随表单一起保存到离线设备。")] + public object SignatureAttachmentCell { get; set; } + + public override string ToString() + { + return "下载离线表单"; + } + } +} diff --git a/OfflinePlusBuildFormItem.cs b/OfflinePlusBuildFormItem.cs new file mode 100644 index 0000000000000000000000000000000000000000..2cf5b47d46f3e5be256bd651c33add4845f4601f --- /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/OfflinePlusBuildPattern.cs b/OfflinePlusBuildPattern.cs new file mode 100644 index 0000000000000000000000000000000000000000..7be725adf0e3bd00bb963cca7466f87ac4276954 --- /dev/null +++ b/OfflinePlusBuildPattern.cs @@ -0,0 +1,352 @@ +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; } + + [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 + { + 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/OfflinePlusGetPatterns_Async.cs b/OfflinePlusGetPatterns_Async.cs new file mode 100644 index 0000000000000000000000000000000000000000..3061322c7574372e22a659ae441e5fbba8a2d8ff --- /dev/null +++ b/OfflinePlusGetPatterns_Async.cs @@ -0,0 +1,103 @@ +using System.ComponentModel; +using System; +using GrapeCity.Forguncy.Commands; +using GrapeCity.Forguncy.Plugin; + +namespace AndroidPDACommand +{ + [Icon("pack://application:,,,/AndroidPDACommand;component/Resources/Icon_OfflineUpload.png")] + [Category("活字格安卓容器(HAC)")] + public class OfflinePlusGetPatterns_Async : BaseAsyncCommand + { + [DisplayName("动作")] + [ComboProperty(ValueList = "GetPatterns|ExportRecords|MarkRecordExported|DeleteReadRecords|DeleteProject", DisplayList = "获取设备上的离线表单项目编号列表|导出离线表单数据|标记离线记录已导出|删除已读离线记录|删除离线表单项目")] + public string Action { get; set; } = "GetPatterns"; + + [FormulaProperty] + [DisplayName("项目编号")] + public object ProjectId { get; set; } + + [FormulaProperty] + [DisplayName("记录编号")] + [Description("多个记录编号用英文逗号分隔。标记离线记录已导出时必填;删除已读离线记录时不填,则删除项目下所有已读记录。")] + public object RecordIds { get; set; } + + [DisplayName("将离线表单项目编号列表返回到变量")] + [ResultToProperty] + public string ProjectsResult { get; set; } + + [DisplayName("将离线表单数据返回到变量")] + [Description("导出离线记录数据。图片和文件字段会先按统一附件模型读取本地附件并上传,再把上传结果写回对应字段值。")] + [ResultToProperty] + public string ExportResult { get; set; } + + [ServerProperty] + [Browsable(false)] + [PageMetadataJsonIgnore] + [SaveJsonIgnore] + public UploadLimit FileUploadLimit { get; set; } = new UploadLimit(); + + [DisplayName("将操作结果返回到变量")] + [ResultToProperty] + public string OperationResult { get; set; } + + public override string ToString() + { + return "上传离线表单"; + } + + public override bool GetDesignerPropertyVisible(string propertyName, CommandScope commandScope) + { + if (propertyName == nameof(ProjectId)) + { + return Action == "ExportRecords" || Action == "MarkRecordExported" || Action == "DeleteReadRecords" || Action == "DeleteProject"; + } + if (propertyName == nameof(RecordIds)) + { + return Action == "MarkRecordExported" || Action == "DeleteReadRecords"; + } + if (propertyName == nameof(OperationResult)) + { + return Action == "MarkRecordExported" || Action == "DeleteReadRecords" || Action == "DeleteProject"; + } + if (propertyName == nameof(ExportResult)) + { + return Action == "ExportRecords"; + } + if (propertyName == nameof(ProjectsResult)) + { + return Action == "GetPatterns"; + } + return base.GetDesignerPropertyVisible(propertyName, commandScope); + } + } + + public class UploadLimit : ICloneable, IUploadLimit, ISupportDeclareObjectEmpty + { + public UploadLimit() + { + ExtensionFilter = ""; + SizeLimit = 0; + MaxUploadFileCount = 0; + } + + [DefaultValue("")] + public string ExtensionFilter { get; set; } + + [DefaultValue(0d)] + public double SizeLimit { get; set; } + + [DefaultValue(0)] + public int MaxUploadFileCount { get; set; } + + public object Clone() + { + return MemberwiseClone(); + } + + public bool IsObjectEmpty() + { + return SizeLimit == 0 && MaxUploadFileCount == 0 && ExtensionFilter == ""; + } + } +} diff --git a/PluginConfig.json b/PluginConfig.json index df57b62c3dfab828bc263c68db06d2c89de59e9c..2ac37f60d2099891ed71e9d72ff8a8b48fdd08f9 100644 --- a/PluginConfig.json +++ b/PluginConfig.json @@ -12,7 +12,7 @@ "name": "PDA(Android)交互命令", "pluginType": "command", "guid": "{16B8DF69-1379-41C1-9194-BE89BAF8BB32}", - "version": "1.21.0.0", + "version": "1.22.0.0", "dependenceVersion": "8.0.0.0", "bundleJavaScript": true, "bundleCSS": true diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index dafc0e1f72b985330c379b7f58b7daca460cb38e..e827326cdacd2208cb5a87c82dbf9ed3744754fb 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -1,10 +1,29 @@  var ERROR_NOT_RUN_IN_HAC = "当前APP不支持该命令,这通常是因为APP版本过低。您可以通过在葡萄城技术社区搜索“HAC”下载最新版APP。"; -var HAC_CallFunctionOutOfHAC = function () { - alert(ERROR_NOT_RUN_IN_HAC); +var HAC_CallFunctionOutOfHAC = function (debugInfo) { + var message = ERROR_NOT_RUN_IN_HAC; + if (debugInfo) { + message += "\r\n\r\n诊断信息:\r\n" + debugInfo; + } + alert(message); } +var HAC_GetOfflinePlusDebugInfo = function (commandName, stage) { + var offlinePlus = window.offlinePlus; + var hac = window.HAC; + return [ + "命令:" + commandName, + "阶段:" + stage, + "window.HAC:" + (hac ? typeof hac : "undefined"), + "window.HAC.registryCallback:" + (hac && hac.registryCallback ? typeof hac.registryCallback : "undefined"), + "window.offlinePlus:" + (offlinePlus ? typeof offlinePlus : "undefined"), + "window.offlinePlus.offlinePlusAddPatternAsync:" + (offlinePlus && offlinePlus.offlinePlusAddPatternAsync ? typeof offlinePlus.offlinePlusAddPatternAsync : "undefined"), + "window.offlinePlus.offlinePlusGetPatternsAsync:" + (offlinePlus && offlinePlus.offlinePlusGetPatternsAsync ? typeof offlinePlus.offlinePlusGetPatternsAsync : "undefined"), + "location:" + window.location.href + ].join("\r\n"); +}; + var HAC_GenerateCellInfo = function (context, formula) { var cellLocation = context.getCellLocation(formula); @@ -18,9 +37,9 @@ var HAC_GenerateCellInfo = function (context, formula) { return JSON.stringify(cellLocation); }; -var HAC_GenerateCallbackTicket = function (context, onSuccess) { +var HAC_GenerateCallbackTicket = function (context, onSuccess, debugInfo) { if (!window.HAC) { - HAC_CallFunctionOutOfHAC(); + HAC_CallFunctionOutOfHAC(debugInfo || "window.HAC is undefined."); } else { var ticket = { @@ -54,6 +73,239 @@ var HAC_ReturnToParam = function (OutParamaterName, data) { console.log("OutParamaterName was not set, the value is: " + JSON.stringify(data)); } }; +/** + * 将DataURL转换为File对象 + * @param {*} dataUrl + * @param {*} fileName + * @returns File对象,或转换失败时返回null + */ +var HAC_DataUrlToFile = function (dataUrl, fileName) { + var parts = (dataUrl || "").split(","); + if (parts.length < 2) { + return null; + } + var header = parts[0]; + var mimeMatch = header.match(/data:([^;]+);base64/i); + var mimeType = mimeMatch ? mimeMatch[1] : "application/octet-stream"; + var binary = atob(parts.slice(1).join(",")); + var bytes = new Uint8Array(binary.length); + for (var i = 0; i < binary.length; i++) { + bytes[i] = binary.charCodeAt(i); + } + return new File([bytes], fileName || "offlineAttachment", { type: mimeType }); +}; + +/** + * 将字节数格式化为MB字符串 + */ +var HAC_FormatBytesAsMb = function (bytes) { + return (bytes / 1024 / 1024).toFixed(2) + " MB"; +}; +/** + * 离线附件上传进度显示组件 + */ +var HAC_OfflineUploadProgress = { + element: null, + fill: null, + title: null, + detail: null, + speed: null, + preventScrollHandler: null, + bodyOverflow: null, + documentOverflow: null, + ensure: function () { + if (this.element) { + return; + } + var root = document.createElement("div"); + root.style.cssText = "position:fixed;left:0;top:0;right:0;bottom:0;z-index:2147483647;background:rgba(0,0,0,.28);display:flex;align-items:center;justify-content:center;font-family:Arial,'Microsoft YaHei',sans-serif;touch-action:none;overscroll-behavior:contain;"; + root.innerHTML = "
" + + "
正在上传离线附件
" + + "
" + + "
" + + "
" + + "
"; + this.bodyOverflow = document.body.style.overflow; + this.documentOverflow = document.documentElement.style.overflow; + document.body.style.overflow = "hidden"; + document.documentElement.style.overflow = "hidden"; + this.preventScrollHandler = function (event) { + event.preventDefault(); + }; + root.addEventListener("touchmove", this.preventScrollHandler, { passive: false }); + document.body.appendChild(root); + this.element = root; + this.fill = root.querySelector("[data-role='fill']"); + this.title = root.querySelector("[data-role='title']"); + this.detail = root.querySelector("[data-role='detail']"); + this.speed = root.querySelector("[data-role='speed']"); + }, + update: function (options) { + this.ensure(); + var percent = Math.max(0, Math.min(100, options.percent || 0)); + this.fill.style.width = percent.toFixed(1) + "%"; + this.title.textContent = options.title || "正在上传离线附件"; + this.detail.textContent = options.detail || ""; + this.speed.textContent = options.speed || ""; + }, + close: function () { + if (this.element && this.preventScrollHandler) { + this.element.removeEventListener("touchmove", this.preventScrollHandler); + } + if (this.element && this.element.parentNode) { + this.element.parentNode.removeChild(this.element); + } + document.body.style.overflow = this.bodyOverflow || ""; + document.documentElement.style.overflow = this.documentOverflow || ""; + this.element = null; + this.fill = null; + this.title = null; + this.detail = null; + this.speed = null; + this.preventScrollHandler = null; + this.bodyOverflow = null; + this.documentOverflow = null; + } +}; +/** + * 将文件上传到服务器临时目录,并返回服务器上的文件标识 + * @param {*} file + * @param {*} uploadLimitId + * @param {*} onProgress + * @returns Promise,成功时返回服务器上的文件标识,失败时返回错误信息 + */ +function HAC_UploadFileToTemp(file, uploadLimitId, onProgress) { + return new Promise(function (resolve, reject) { + var formData = new FormData(); + formData.append("file", file); + formData.append("uploadLimitId", uploadLimitId); + formData.append("uploadFolder", ""); + + var startTime = new Date().valueOf(); + var xhr = new XMLHttpRequest(); + xhr.open("POST", Forguncy.Common.uploadUrl, true); + xhr.setRequestHeader("Accept", "application/json"); + xhr.upload.onprogress = function (event) { + if (onProgress && event.lengthComputable) { + var elapsedSeconds = Math.max((new Date().valueOf() - startTime) / 1000, 0.1); + onProgress(event.loaded, event.total, event.loaded / elapsedSeconds); + } + }; + xhr.onload = function () { + if (xhr.status >= 200 && xhr.status < 300) { + resolve(xhr.responseText); + } else { + reject(xhr.responseText || xhr.statusText || "上传离线附件失败。"); + } + }; + xhr.onerror = function () { + reject("上传离线附件失败。"); + }; + xhr.send(formData); + }); +} +/** + * 将上传后的附件值应用到记录中,并更新记录的字段值 + */ +function HAC_ApplyUploadedAttachmentValue(record, attachment, attachmentValue, uploadedValues) { + if (!record || !record.values || !attachment) { + return; + } + + var recordId = HAC_GetOfflineAttachmentRecordId(attachment); + var fieldId = HAC_GetOfflineAttachmentFieldId(attachment); + if (!recordId || !fieldId) { + return; + } + + var key = recordId + "|" + fieldId; + if (!uploadedValues[key]) { + uploadedValues[key] = []; + } + uploadedValues[key].push(attachmentValue); + record.values[fieldId] = uploadedValues[key].join("|"); +} + +function HAC_GetOfflineAttachmentRecordId(attachment) { + return attachment && attachment.recordId || attachment && attachment.path && attachment.path[0] || ""; +} + +function HAC_GetOfflineAttachmentFieldId(attachment) { + return attachment && attachment.fieldId || attachment && attachment.path && attachment.path[1] || ""; +} + +function HAC_GetOfflineAttachmentUploadFileName(attachment) { + return attachment && (attachment.originalName || attachment.fileName || attachment.localName) || "offlineAttachment"; +} + +/** + * 处理离线导出附件 + * @param {*} projectId + * @param {*} exportData + * @param {*} uploadLimitId + * @returns Promise,成功时返回处理后的导出数据,失败时返回错误信息 + */ +async function HAC_ProcessOfflineExportAttachments(projectId, exportData, uploadLimitId) { + if (!exportData) { + return exportData; + } + var records = exportData.records || []; + if (!exportData.attachments || exportData.attachments.length === 0) { + delete exportData.attachments; + return exportData; + } + if (!uploadLimitId) { + throw "请设置文件上传限制ID。"; + } + if (!window.offlinePlus || !window.offlinePlus.offlinePlusLoadAttachment) { + HAC_CallFunctionOutOfHAC(HAC_GetOfflinePlusDebugInfo("上传离线表单", "调用offlinePlusLoadAttachment")); + throw "当前APP不支持读取离线附件。"; + } + + var uploadedValues = {}; + HAC_OfflineUploadProgress.update({ + percent: 0, + detail: "准备上传 " + exportData.attachments.length + " 个离线附件", + speed: "" + }); + for (var i = 0; i < exportData.attachments.length; i++) { + var attachment = exportData.attachments[i]; + if (!attachment || !attachment.localName || !HAC_GetOfflineAttachmentRecordId(attachment) || !HAC_GetOfflineAttachmentFieldId(attachment)) { + continue; + } + + var fileIndexText = (i + 1) + " / " + exportData.attachments.length; + HAC_OfflineUploadProgress.update({ + percent: exportData.attachments.length === 0 ? 0 : i / exportData.attachments.length * 100, + detail: "正在读取离线文件:" + fileIndexText + " " + attachment.localName, + speed: "" + }); + var dataUrl = window.offlinePlus.offlinePlusLoadAttachment(projectId, attachment.localName); + var file = HAC_DataUrlToFile(dataUrl, HAC_GetOfflineAttachmentUploadFileName(attachment)); + if (!file) { + throw "读取离线附件失败:" + attachment.localName; + } + + var attachmentValue = await HAC_UploadFileToTemp(file, uploadLimitId, function (loaded, total, bytesPerSecond) { + HAC_OfflineUploadProgress.update({ + percent: (i + (total > 0 ? loaded / total : 0)) / exportData.attachments.length * 100, + detail: "正在上传:" + fileIndexText + " " + file.name + "," + HAC_FormatBytesAsMb(loaded) + " / " + HAC_FormatBytesAsMb(total), + speed: "速度:" + HAC_FormatBytesAsMb(bytesPerSecond) + "/s" + }); + }); + var record = records.find(function (record) { + return record && record.recordId === HAC_GetOfflineAttachmentRecordId(attachment); + }); + HAC_ApplyUploadedAttachmentValue(record, attachment, attachmentValue, uploadedValues); + } + HAC_OfflineUploadProgress.update({ + percent: 100, + detail: "正在生成导出数据", + speed: "" + }); + delete exportData.attachments; + return exportData; +} var HAC_DothanPrinterOp = function (callback) { if (window.dothanPrinter) { @@ -1386,6 +1638,31 @@ var Device_Info_Command = (function (_super) { Forguncy.CommandFactory.registerCommand("AndroidPDACommand.Device_Info, AndroidPDACommand", Device_Info_Command); +var Device_Info_Json_Command = (function (_super) { + __extends(Device_Info_Json_Command, _super); + function Device_Info_Json_Command() { + return _super !== null && _super.apply(this, arguments) || this; + } + + Device_Info_Json_Command.prototype.execute = function () { + var params = this.CommandParam; + var pName = params.DeviceInfoJson; + + if (window.device && window.device.getDeviceInfo) { + var value = window.device.getDeviceInfo(); + + HAC_ReturnToParam(pName, value); + } else { + HAC_CallFunctionOutOfHAC(); + HAC_ReturnToParam(pName, ""); + } + }; + + return Device_Info_Json_Command; +}(Forguncy.CommandBase)); + +Forguncy.CommandFactory.registerCommand("AndroidPDACommand.Device_Info_Json, AndroidPDACommand", Device_Info_Json_Command); + var BLE_Scan_Command = (function (_super) { __extends(BLE_Scan_Command, _super); function BLE_Scan_Command() { @@ -2347,7 +2624,7 @@ var GenericBroadcast_Stop_Command = (function (_super) { var params = this.CommandParam; var uuid = this.evaluateFormula(params.HandlerID); - + if (window.broadcast && window.broadcast.stopReceiving) { window.broadcast.stopReceiving(uuid); @@ -2428,14 +2705,14 @@ var OnKeyDown_Listen_Start_Async_Command = (function (_super) { locationString: "执行window.onKeyDownListen.startOnKeyDownListenAsync的回调" }); }); - + if (window.onKeyDownListen && window.onKeyDownListen.startOnKeyDownListenAsync) { window.onKeyDownListen.startOnKeyDownListenAsync(ticket, theKey, isCover); } else { HAC_CallFunctionOutOfHAC(); } } - + return OnKeyDown_Listen_Start_Async_Command; }(Forguncy.CommandBase)); @@ -2451,14 +2728,14 @@ var OnKeyDown_Listen_Stop_Command = (function (_super) { var params = this.CommandParam; var theKey = this.evaluateFormula(params.TheKey); - + if (window.onKeyDownListen && window.onKeyDownListen.stopOnKeyDownListen) { window.onKeyDownListen.stopOnKeyDownListen(theKey); } else { HAC_CallFunctionOutOfHAC(); } }; - + return OnKeyDown_Listen_Stop_Command; }(Forguncy.CommandBase)); @@ -2561,4 +2838,595 @@ var Biometric_Available_Async_Command = (function (_super) { return Biometric_Available_Async_Command; }(Forguncy.CommandBase)); -Forguncy.CommandFactory.registerCommand("AndroidPDACommand.Biometric_Available_Async, AndroidPDACommand", Biometric_Available_Async_Command); \ No newline at end of file +Forguncy.CommandFactory.registerCommand("AndroidPDACommand.Biometric_Available_Async, AndroidPDACommand", Biometric_Available_Async_Command); + +function HAC_OfflinePlusCreateFormNodeBuilder(context) { + let me = context; + + function evaluate(value) { + if (value === undefined || value === null) { + return value; + } + return me.evaluateFormula(value); + } + + function getList(value) { + return Array.isArray(value) ? value : []; + } + + function buildSelectOptions(options) { + return getList(options).map(function (option) { + return { + value: evaluate(option.Value), + label: evaluate(option.Label) + }; + }); + } + + function buildCheckOptions(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; + } + + function buildImageCompression(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; + } + + function buildImageWatermark(options) { + if (!options) { + return undefined; + } + + var fields = getList(options.Fields); + if (!options.EnableTimestamp && fields.length === 0) { + return undefined; + } + + var watermark = {}; + var items = fields.map(function (field) { + return { + key: field.Key, + value: evaluate(field.Value) + }; + }); + + if (options.EnableTimestamp) { + watermark.enableTimestamp = true; + } + if (items.length > 0) { + watermark.items = items; + } + return Object.keys(watermark).length > 0 ? watermark : undefined; + } + + function buildFileItemConfig(options) { + if (!options) { + return 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; + } + + var fieldTypeSpecs = { + textItem: { + apply: function (field, node) { + var checkOptions = buildCheckOptions(node.CheckOptions); + if (checkOptions) { + field.options = checkOptions; + } + } + }, + passwordItem: { + apply: function (field, node) { + var checkOptions = buildCheckOptions(node.CheckOptions); + if (checkOptions) { + field.options = checkOptions; + } + } + }, + selectItem: { + apply: function (field, node) { + var selectOptions = buildSelectOptions(node.SelectOptionsList); + if (selectOptions.length > 0) { + field.options = { + selectOptions: selectOptions + }; + } + } + }, + timePicker: { + apply: function (field, node) { + if (node.IncludeSeconds) { + field.options = { + includeSeconds: true + }; + } + } + }, + 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; + } + } + }, + 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 + }; + + var value = evaluate(node.Value); + if (value !== undefined && value !== null && value !== "") { + field.value = value; + } + applyFieldTypeSpec(field, node); + return field; + } + + function buildNode(node) { + var nodeType = node.NodeType || "group"; + var children = getList(node.Children); + + if (nodeType !== "group" && children.length > 0) { + console.warn("离线表单节点不是分组,但包含子节点。", node); + } + + if (nodeType === "field") { + return { + nodeType: "field", + title: node.Text, + field: buildField(node) + }; + } + + if (nodeType === "text") { + return { + nodeType: "text", + title: node.Text, + content: evaluate(node.Content) + }; + } + + return { + nodeType: "group", + title: node.Text, + defaultCollapsed: !!node.DefaultCollapsed, + children: buildNodes(children) + }; + } + + function buildNodes(nodes) { + return getList(nodes).map(function (node) { + return buildNode(node); + }); + } + + 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 formNodeBuilder.getList(steps).map(function (step) { + return { + 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: formNodeBuilder.evaluate(params.PatternId), + schemaVersion: formNodeBuilder.evaluate(params.SchemaVersion), + title: formNodeBuilder.evaluate(params.Title), + description: formNodeBuilder.evaluate(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); + } + + function getManualPdfUrl(manualValue) { + if (!manualValue) { + return ""; + } + + var fileId = (manualValue + "").split("|")[0]; + if (!fileId) { + console.warn("手册附件单元格没有文件标识。", manualValue); + return ""; + } + + return Forguncy.Helper.SpecialPath.getFileDownloadUrl(fileId); + } + + 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(), + initParams: { + "IsSuccess": true, + "Error": "" + }, + locationString: "执行window.offlinePlus.offlinePlusAddPattern" + }); + }, HAC_GetOfflinePlusDebugInfo("下载离线表单", "生成回调ticket")); + if (!ticket) { + console.error(HAC_GetOfflinePlusDebugInfo("下载离线表单", "生成回调ticket失败")); + return; + } + + var manualPdfUrl = getManualPdfUrl(manualAttachmentValue); + patternParam.ticket = ticket; + finalPatternParamJson = JSON.stringify(patternParam, null, 2); + + console.log(patternParam); + if (window.offlinePlus && window.offlinePlus.offlinePlusAddPatternAsync) { + window.offlinePlus.offlinePlusAddPatternAsync(finalPatternParamJson, manualPdfUrl || "", signatureBase64 || ""); + } else { + HAC_CallFunctionOutOfHAC(HAC_GetOfflinePlusDebugInfo("下载离线表单", "调用offlinePlusAddPatternAsync")); + } + }; + + + return OfflinePlusAddPattern_Async_Command; +}(Forguncy.CommandBase)); + +Forguncy.CommandFactory.registerCommand("AndroidPDACommand.OfflinePlusAddPattern_Async, AndroidPDACommand", OfflinePlusAddPattern_Async_Command); + +var OfflinePlusGetPatterns_Async_Command = (function (_super) { + __extends(OfflinePlusGetPatterns_Async_Command, _super); + function OfflinePlusGetPatterns_Async_Command() { + return _super !== null && _super.apply(this, arguments) || this; + } + + OfflinePlusGetPatterns_Async_Command.prototype.execute = function () { + var params = this.CommandParam; + var action = params.Action || "GetPatterns"; + + if (action === "ExportRecords") { + var projectId = this.evaluateFormula(params.ProjectId); + var fileUploadLimit = (params.ServerPropertiesId && params.ServerPropertiesId.FileUploadLimit) || ""; + let me = this; + let ticket = HAC_GenerateCallbackTicket(me, async function (payload, payload2) { + try { + var exportData = JSON.parse(payload); + if (exportData) { + exportData = await HAC_ProcessOfflineExportAttachments(projectId, exportData, fileUploadLimit); + payload = JSON.stringify(exportData); + } + HAC_ReturnToParam(params.ExportResult, payload); + me.CommandExecutor.excuteCommand(me.CommandParam.CommandList, { + runTimePageName: me.CommandExecutingInfo.runTimePageName, + commandID: new Date().valueOf().toString(), + initParams: { + "ExportResult": payload, + "IsSuccess": true, + "Error": "" + }, + locationString: "执行window.offlinePlus.offlinePlusExportRecordsAsync" + }); + } catch (e) { + me.CommandExecutor.excuteCommand(me.CommandParam.CommandList, { + runTimePageName: me.CommandExecutingInfo.runTimePageName, + commandID: new Date().valueOf().toString(), + initParams: { + "ExportResult": payload, + "IsSuccess": false, + "Error": e ? e.toString() : "导出离线附件失败。" + }, + locationString: "处理离线附件上传时出错" + }); + } finally { + HAC_OfflineUploadProgress.close(); + } + }, HAC_GetOfflinePlusDebugInfo("上传离线表单", "生成导出数据回调ticket")); + + if (window.offlinePlus && window.offlinePlus.offlinePlusExportRecordsAsync) { + window.offlinePlus.offlinePlusExportRecordsAsync(projectId, ticket); + } else { + HAC_CallFunctionOutOfHAC(HAC_GetOfflinePlusDebugInfo("上传离线表单", "调用offlinePlusExportRecordsAsync")); + } + return; + } + + if (action === "MarkRecordExported") { + var projectId = this.evaluateFormula(params.ProjectId); + var recordIds = this.evaluateFormula(params.RecordIds); + let me = this; + let ticket = HAC_GenerateCallbackTicket(me, function (payload, payload2) { + HAC_ReturnToParam(params.OperationResult, payload); + me.CommandExecutor.excuteCommand(me.CommandParam.CommandList, { + runTimePageName: me.CommandExecutingInfo.runTimePageName, + commandID: new Date().valueOf().toString(), + initParams: { + "OperationResult": payload, + "IsSuccess": true, + "Error": "" + }, + locationString: "执行window.offlinePlus.offlinePlusMarkRecordExportedAsync" + }); + }, HAC_GetOfflinePlusDebugInfo("上传离线表单", "生成标记导出回调ticket")); + + if (window.offlinePlus && window.offlinePlus.offlinePlusMarkRecordExportedAsync) { + window.offlinePlus.offlinePlusMarkRecordExportedAsync(projectId, recordIds, ticket); + } else { + HAC_CallFunctionOutOfHAC(HAC_GetOfflinePlusDebugInfo("上传离线表单", "调用offlinePlusMarkRecordExportedAsync")); + } + return; + } + + if (action === "DeleteReadRecords") { + var projectId = this.evaluateFormula(params.ProjectId); + var recordIds = this.evaluateFormula(params.RecordIds); + let me = this; + let ticket = HAC_GenerateCallbackTicket(me, function (payload, payload2) { + HAC_ReturnToParam(params.OperationResult, payload); + me.CommandExecutor.excuteCommand(me.CommandParam.CommandList, { + runTimePageName: me.CommandExecutingInfo.runTimePageName, + commandID: new Date().valueOf().toString(), + initParams: { + "OperationResult": payload, + "IsSuccess": true, + "Error": "" + }, + locationString: "执行window.offlinePlus.offlinePlusDeleteReadRecordsAsync" + }); + }, HAC_GetOfflinePlusDebugInfo("上传离线表单", "生成删除已读记录回调ticket")); + + if (window.offlinePlus && window.offlinePlus.offlinePlusDeleteReadRecordsAsync) { + window.offlinePlus.offlinePlusDeleteReadRecordsAsync(projectId, recordIds, ticket); + } else { + HAC_CallFunctionOutOfHAC(HAC_GetOfflinePlusDebugInfo("上传离线表单", "调用offlinePlusDeleteReadRecordsAsync")); + } + return; + } + + if (action === "DeleteProject") { + var projectId = this.evaluateFormula(params.ProjectId); + let me = this; + let ticket = HAC_GenerateCallbackTicket(me, function (payload, payload2) { + HAC_ReturnToParam(params.OperationResult, payload); + me.CommandExecutor.excuteCommand(me.CommandParam.CommandList, { + runTimePageName: me.CommandExecutingInfo.runTimePageName, + commandID: new Date().valueOf().toString(), + initParams: { + "OperationResult": payload, + "IsSuccess": true, + "Error": "" + }, + locationString: "执行window.offlinePlus.offlinePlusDeleteProjectAsync" + }); + }, HAC_GetOfflinePlusDebugInfo("上传离线表单", "生成删除离线表单项目回调ticket")); + + if (window.offlinePlus && window.offlinePlus.offlinePlusDeleteProjectAsync) { + window.offlinePlus.offlinePlusDeleteProjectAsync(projectId, ticket); + } else { + HAC_CallFunctionOutOfHAC(HAC_GetOfflinePlusDebugInfo("上传离线表单", "调用offlinePlusDeleteProjectAsync")); + } + return; + } + + if (action !== "GetPatterns") { + alert("不支持的离线表单上传动作:" + action); + return; + } + + let me = this; + + let ticket = HAC_GenerateCallbackTicket(me, function (payload, payload2) { + HAC_ReturnToParam(params.ProjectsResult, payload); + me.CommandExecutor.excuteCommand(me.CommandParam.CommandList, { + runTimePageName: me.CommandExecutingInfo.runTimePageName, + commandID: new Date().valueOf().toString(), + initParams: { + "ProjectsResult": payload, + "IsSuccess": true, + "Error": "" + }, + locationString: "执行window.offlinePlus.offlinePlusGetPatternsAsync" + }); + }, HAC_GetOfflinePlusDebugInfo("上传离线表单", "生成回调ticket")); + + if (window.offlinePlus && window.offlinePlus.offlinePlusGetPatternsAsync) { + window.offlinePlus.offlinePlusGetPatternsAsync(ticket); + } else { + HAC_CallFunctionOutOfHAC(HAC_GetOfflinePlusDebugInfo("上传离线表单", "调用offlinePlusGetPatternsAsync")); + } + }; + + return OfflinePlusGetPatterns_Async_Command; +}(Forguncy.CommandBase)); + +Forguncy.CommandFactory.registerCommand("AndroidPDACommand.OfflinePlusGetPatterns_Async, AndroidPDACommand", OfflinePlusGetPatterns_Async_Command); + diff --git a/Resources/Icon_OfflineBuild.png b/Resources/Icon_OfflineBuild.png new file mode 100644 index 0000000000000000000000000000000000000000..9430bea9db1a5a7f715d3ae3259bade60d8e00cb Binary files /dev/null and b/Resources/Icon_OfflineBuild.png differ diff --git a/Resources/Icon_OfflineDownload.png b/Resources/Icon_OfflineDownload.png new file mode 100644 index 0000000000000000000000000000000000000000..1295a66c444353576d3580da122e425f19b457b9 Binary files /dev/null and b/Resources/Icon_OfflineDownload.png differ diff --git a/Resources/Icon_OfflineFormItem.png b/Resources/Icon_OfflineFormItem.png new file mode 100644 index 0000000000000000000000000000000000000000..26e42e6d02f98faf21b2d29902644cb786662b0b Binary files /dev/null and b/Resources/Icon_OfflineFormItem.png differ diff --git a/Resources/Icon_OfflineUpload.png b/Resources/Icon_OfflineUpload.png new file mode 100644 index 0000000000000000000000000000000000000000..cb7876aa0535f3281c9228c20470eeb39031e1e6 Binary files /dev/null and b/Resources/Icon_OfflineUpload.png differ