From c29273c855e3d62f84b447ee8632de7d89e0be3e Mon Sep 17 00:00:00 2001 From: NathanGuo Date: Mon, 30 Mar 2026 15:55:57 +0800 Subject: [PATCH 01/71] add class and method --- AndroidPDACommand.csproj | 2 + OfflinePlusAddPattern_Async.cs | 109 ++++++++++++++++++++++++++++++++ OfflinePlusGetPatterns_Async.cs | 18 ++++++ PluginConfig.json | 2 +- Resources/AndroidPDACommand.js | 86 ++++++++++++++++++++++++- 5 files changed, 215 insertions(+), 2 deletions(-) create mode 100644 OfflinePlusAddPattern_Async.cs create mode 100644 OfflinePlusGetPatterns_Async.cs diff --git a/AndroidPDACommand.csproj b/AndroidPDACommand.csproj index 9d634e0..c53bcc5 100644 --- a/AndroidPDACommand.csproj +++ b/AndroidPDACommand.csproj @@ -87,6 +87,8 @@ + + diff --git a/OfflinePlusAddPattern_Async.cs b/OfflinePlusAddPattern_Async.cs new file mode 100644 index 0000000..dfbe591 --- /dev/null +++ b/OfflinePlusAddPattern_Async.cs @@ -0,0 +1,109 @@ +using System.Collections.Generic; +using System.ComponentModel; +using GrapeCity.Forguncy.Commands; +using GrapeCity.Forguncy.Plugin; + +namespace AndroidPDACommand +{ + 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; } + + [DisplayName("表单项")] + [ObjectListProperty(ItemType = typeof(OfflineFormItem))] + public List FormItems { get; set; } + + public override string ToString() + { + return "添加项目"; + } + } + + public class OfflineFormItem : ObjectPropertyBase, INamedObject + { + public string Name { get; set; } + + [FormulaProperty] + [DisplayName("编号")] + [Description("该表单项的唯一标识,全局唯一,无论是同一项目内,还是跨项目,都必须唯一,更建议使用项目编号作为前缀拼接;例如项目为Project01,则该表单项编号为Project01_Name")] + public object ItemId { get; set; } + + [DisplayName("类型")] + [ComboProperty(ValueList = "textItem|passwordItem|selectItem", 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; } + + + [ObjectProperty(ObjType = typeof(CheckOptions))] + [DisplayName("校验规则")] + public CheckOptions CheckOptions { get; set; } + + [ListProperty] + [DisplayName("选则项")] + public List SelectOptionsList { get; set; } + + public override bool GetDesignerPropertyVisible(string propertyName) + { + switch (propertyName) + { + case nameof(SelectOptionsList): + return ItemType == "selectItem"; + case nameof(CheckOptions): + return ItemType == "textItem" || ItemType == "passwordItem"; + default: + return base.GetDesignerPropertyVisible(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; } + } +} \ No newline at end of file diff --git a/OfflinePlusGetPatterns_Async.cs b/OfflinePlusGetPatterns_Async.cs new file mode 100644 index 0000000..b3257de --- /dev/null +++ b/OfflinePlusGetPatterns_Async.cs @@ -0,0 +1,18 @@ +using System.ComponentModel; +using GrapeCity.Forguncy.Commands; + +namespace AndroidPDACommand +{ + public class OfflinePlusGetPatterns_Async : BaseAsyncCommand + { + + [Browsable(false)] + [ResultToProperty] + public string ProjectsResult { get; set; } = "projects"; + + public override string ToString() + { + return "获取已保存项目"; + } + } +} \ No newline at end of file diff --git a/PluginConfig.json b/PluginConfig.json index df57b62..2ac37f6 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 dafc0e1..0555f00 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -2561,4 +2561,88 @@ 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); + +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 = function () { + + let me = this; + let params = this.CommandParam; + + let _ticket = HAC_GenerateCallbackTicket(me, function (payload, payload2) { + me.CommandExecutor.excuteCommand(me.CommandParam.CommandList, { + runTimePageName: me.CommandExecutingInfo.runTimePageName, + commandID: new Date().valueOf().toString(), + initParams: { + "IsSuccess": true, + "Error": "" + }, + locationString: "执行window.offlinePlus.offlinePlusAddPattern" + }); + }); + + let patternParam = { + ticket: _ticket, + patternId: this.evaluateFormula(params.PatternId), + title: this.evaluateFormula(params.Title), + description: this.evaluateFormula(params.Description), + formItems: params.FormItems + }; + + console.log(patternParam); + if (window.offlinePlus && window.offlinePlus.offlinePlusAddPattern) { + + window.offlinePlus.offlinePlusAddPatternAsync(JSON.stringify(patternParam)); + } else { + HAC_CallFunctionOutOfHAC(); + } + }; + + + 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 () { + + let me = this; + + let ticket = HAC_GenerateCallbackTicket(me, function (payload, payload2) { + 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" + }); + }); + + if (window.offlinePlus && window.offlinePlus.offlinePlusGetPatternsAsync) { + window.offlinePlus.offlinePlusGetPatternsAsync(ticket); + } else { + HAC_CallFunctionOutOfHAC(); + } + + }; + + + return OfflinePlusGetPatterns_Async_Command; +}(Forguncy.CommandBase)); + +Forguncy.CommandFactory.registerCommand("AndroidPDACommand.OfflinePlusGetPatterns_Async, AndroidPDACommand", OfflinePlusGetPatterns_Async_Command); + -- Gitee From 8dc864d908fd015609277f380c7d7198088e37b5 Mon Sep 17 00:00:00 2001 From: NathanGuo Date: Thu, 4 Jun 2026 12:04:02 +0800 Subject: [PATCH 02/71] add async --- Resources/AndroidPDACommand.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 0555f00..795ce02 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -2595,7 +2595,7 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { }; console.log(patternParam); - if (window.offlinePlus && window.offlinePlus.offlinePlusAddPattern) { + if (window.offlinePlus && window.offlinePlus.offlinePlusAddPatternAsync) { window.offlinePlus.offlinePlusAddPatternAsync(JSON.stringify(patternParam)); } else { -- Gitee From 8a1a8b517e52a276b5f5d42a24ba16abc0156948 Mon Sep 17 00:00:00 2001 From: Rex Lei Date: Thu, 4 Jun 2026 13:51:11 +0800 Subject: [PATCH 03/71] chore: migrate HAC plugin to net8 and add offline diagnostics Migrate the plugin project to SDK-style net8.0-windows so it can reference Forguncy v12 assemblies. Add offline form command diagnostics and a success alert showing the JSON payload used by OfflinePlusAddPattern_Async. --- AndroidPDACommand.csproj | 131 +++++++++++---------------------- JPushServerCommand.cs | 3 +- OfflinePlusAddPattern_Async.cs | 3 +- Resources/AndroidPDACommand.js | 40 +++++++--- 4 files changed, 76 insertions(+), 101 deletions(-) diff --git a/AndroidPDACommand.csproj b/AndroidPDACommand.csproj index c53bcc5..376c9ec 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 - - - - - - - - - - - - - @@ -143,77 +105,68 @@ - + + + + + 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/JPushServerCommand.cs b/JPushServerCommand.cs index 317c421..c6ff1b6 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 index dfbe591..1e6a3bc 100644 --- a/OfflinePlusAddPattern_Async.cs +++ b/OfflinePlusAddPattern_Async.cs @@ -5,6 +5,7 @@ using GrapeCity.Forguncy.Plugin; namespace AndroidPDACommand { + [Category("活字格安卓容器(HAC)")] public class OfflinePlusAddPattern_Async : BaseAsyncCommand { [FormulaProperty] @@ -26,7 +27,7 @@ namespace AndroidPDACommand public override string ToString() { - return "添加项目"; + return "添加离线表单项目"; } } diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 795ce02..0eb19e1 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 = { @@ -2573,8 +2592,10 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { let me = this; let params = this.CommandParam; + let patternParamJson = ""; let _ticket = HAC_GenerateCallbackTicket(me, function (payload, payload2) { + alert("离线表单项目设置成功\r\n\r\nJSON Schema:\r\n" + patternParamJson); me.CommandExecutor.excuteCommand(me.CommandParam.CommandList, { runTimePageName: me.CommandExecutingInfo.runTimePageName, commandID: new Date().valueOf().toString(), @@ -2584,7 +2605,7 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { }, locationString: "执行window.offlinePlus.offlinePlusAddPattern" }); - }); + }, HAC_GetOfflinePlusDebugInfo("添加离线表单项目", "生成回调ticket")); let patternParam = { ticket: _ticket, @@ -2594,12 +2615,13 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { formItems: params.FormItems }; + patternParamJson = JSON.stringify(patternParam, null, 2); console.log(patternParam); if (window.offlinePlus && window.offlinePlus.offlinePlusAddPatternAsync) { - window.offlinePlus.offlinePlusAddPatternAsync(JSON.stringify(patternParam)); + window.offlinePlus.offlinePlusAddPatternAsync(patternParamJson); } else { - HAC_CallFunctionOutOfHAC(); + HAC_CallFunctionOutOfHAC(HAC_GetOfflinePlusDebugInfo("添加离线表单项目", "调用offlinePlusAddPatternAsync")); } }; @@ -2630,12 +2652,12 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { }, locationString: "执行window.offlinePlus.offlinePlusGetPatternsAsync" }); - }); + }, HAC_GetOfflinePlusDebugInfo("获取已保存项目", "生成回调ticket")); if (window.offlinePlus && window.offlinePlus.offlinePlusGetPatternsAsync) { window.offlinePlus.offlinePlusGetPatternsAsync(ticket); } else { - HAC_CallFunctionOutOfHAC(); + HAC_CallFunctionOutOfHAC(HAC_GetOfflinePlusDebugInfo("获取已保存项目", "调用offlinePlusGetPatternsAsync")); } }; -- Gitee From 5f3d38bbe9ef4268b49ac2a5b2f4c4c8bcf51cef Mon Sep 17 00:00:00 2001 From: Rex Lei Date: Thu, 4 Jun 2026 16:31:13 +0800 Subject: [PATCH 04/71] feat: add SchemaVersion property to OfflinePlusAddPattern and update command to include it --- OfflinePlusAddPattern_Async.cs | 9 ++++++++- Resources/AndroidPDACommand.js | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/OfflinePlusAddPattern_Async.cs b/OfflinePlusAddPattern_Async.cs index 1e6a3bc..af41d9c 100644 --- a/OfflinePlusAddPattern_Async.cs +++ b/OfflinePlusAddPattern_Async.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.ComponentModel; +using System.ComponentModel.DataAnnotations; using GrapeCity.Forguncy.Commands; using GrapeCity.Forguncy.Plugin; @@ -21,6 +22,12 @@ namespace AndroidPDACommand [FormulaProperty] public object Description { get; set; } + [Required] + [FormulaProperty] + [DisplayName("版本号")] + [Description("同一项目编号下的表单定义版本,用于区分表单结构变更。")] + public string SchemaVersion { get; set; } = "1.0"; + [DisplayName("表单项")] [ObjectListProperty(ItemType = typeof(OfflineFormItem))] public List FormItems { get; set; } @@ -107,4 +114,4 @@ namespace AndroidPDACommand [DisplayName("显示文本")] public object Label { get; set; } } -} \ No newline at end of file +} diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 0eb19e1..dd474d9 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -2610,6 +2610,7 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { let patternParam = { ticket: _ticket, patternId: this.evaluateFormula(params.PatternId), + schemaVersion: this.evaluateFormula(params.SchemaVersion), title: this.evaluateFormula(params.Title), description: this.evaluateFormula(params.Description), formItems: params.FormItems -- Gitee From eabb098ab7c0b0240a71fc83672644afc50329b5 Mon Sep 17 00:00:00 2001 From: Rex Lei Date: Mon, 8 Jun 2026 11:47:44 +0800 Subject: [PATCH 05/71] feat(offline): support stepped form schema Replace the flat offline FormItems command model with a Steps list so each offline pattern can describe multiple pages or tabs. Add tree-backed offline form nodes for step content. Nodes can represent collapsible groups, static text, or leaf field items; designer property visibility now follows the selected node type and field item type. Update the HAC command runtime serializer to emit the new steps JSON shape, evaluate nested formula-backed fields, serialize validation/options data, and keep field/text nodes as leaf output structures. --- OfflinePlusAddPattern_Async.cs | 81 ++++++++++++++++++++-- Resources/AndroidPDACommand.js | 121 ++++++++++++++++++++++++++++++++- 2 files changed, 195 insertions(+), 7 deletions(-) diff --git a/OfflinePlusAddPattern_Async.cs b/OfflinePlusAddPattern_Async.cs index af41d9c..9cbc110 100644 --- a/OfflinePlusAddPattern_Async.cs +++ b/OfflinePlusAddPattern_Async.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.DataAnnotations; +using System.Linq; using GrapeCity.Forguncy.Commands; using GrapeCity.Forguncy.Plugin; @@ -28,9 +29,9 @@ namespace AndroidPDACommand [Description("同一项目编号下的表单定义版本,用于区分表单结构变更。")] public string SchemaVersion { get; set; } = "1.0"; - [DisplayName("表单项")] - [ObjectListProperty(ItemType = typeof(OfflineFormItem))] - public List FormItems { get; set; } + [DisplayName("步骤")] + [ObjectListProperty(ItemType = typeof(OfflineFormStep))] + public List Steps { get; set; } public override string ToString() { @@ -38,10 +39,43 @@ namespace AndroidPDACommand } } - public class OfflineFormItem : ObjectPropertyBase, INamedObject + 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 + { + [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")] @@ -77,16 +111,51 @@ namespace AndroidPDACommand 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; + case nameof(ItemId): + case nameof(ItemType): + case nameof(Title): + case nameof(Hint): + case nameof(Required): + case nameof(Value): + return isField; case nameof(SelectOptionsList): - return ItemType == "selectItem"; + return isField && ItemType == "selectItem"; case nameof(CheckOptions): - return ItemType == "textItem" || ItemType == "passwordItem"; + return isField && (ItemType == "textItem" || ItemType == "passwordItem"); default: 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, + CheckOptions = CheckOptions, + SelectOptionsList = SelectOptionsList + }; + } } public class CheckOptions : ObjectPropertyBase diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index dd474d9..96b794a 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -2594,6 +2594,125 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { let params = this.CommandParam; let patternParamJson = ""; + function evaluate(value) { + if (value === undefined || value === null) { + return value; + } + return me.evaluateFormula(value); + } + + function getValue(obj, pascalName, camelName) { + if (!obj) { + return undefined; + } + if (obj[pascalName] !== undefined) { + return obj[pascalName]; + } + return obj[camelName]; + } + + function getList(value) { + return Array.isArray(value) ? value : []; + } + + function buildSelectOptions(options) { + return getList(options).map(function (option) { + return { + value: evaluate(getValue(option, "Value", "value")), + label: evaluate(getValue(option, "Label", "label")) + }; + }); + } + + function buildCheckOptions(options) { + if (!options) { + return undefined; + } + + var checkOptions = {}; + var minLength = evaluate(getValue(options, "MinLength", "minLength")); + var maxLength = evaluate(getValue(options, "MaxLength", "maxLength")); + var regexPattern = evaluate(getValue(options, "RegexPattern", "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 buildField(node) { + var field = { + itemId: evaluate(getValue(node, "ItemId", "itemId")), + itemType: getValue(node, "ItemType", "itemType"), + title: evaluate(getValue(node, "Title", "title")), + hint: evaluate(getValue(node, "Hint", "hint")), + required: !!getValue(node, "Required", "required") + }; + + var value = evaluate(getValue(node, "Value", "value")); + var checkOptions = buildCheckOptions(getValue(node, "CheckOptions", "checkOptions")); + var selectOptions = buildSelectOptions(getValue(node, "SelectOptionsList", "selectOptionsList")); + + if (value !== undefined && value !== null && value !== "") { + field.value = value; + } + if (checkOptions) { + field.checkOptions = checkOptions; + } + if (selectOptions.length > 0) { + field.options = selectOptions; + } + return field; + } + + function buildNodes(nodes) { + return getList(nodes).map(function (node) { + var nodeType = getValue(node, "NodeType", "nodeType") || "group"; + var children = getList(getValue(node, "Children", "children")); + + if (nodeType !== "group" && children.length > 0) { + console.warn("离线表单节点不是分组,但包含子节点。", node); + } + + if (nodeType === "field") { + return { + nodeType: "field", + field: buildField(node) + }; + } + + if (nodeType === "text") { + return { + nodeType: "text", + title: getValue(node, "Text", "text"), + content: evaluate(getValue(node, "Content", "content")) + }; + } + + return { + nodeType: "group", + title: getValue(node, "Text", "text"), + defaultCollapsed: !!getValue(node, "DefaultCollapsed", "defaultCollapsed"), + children: buildNodes(children) + }; + }); + } + + function buildSteps(steps) { + return getList(steps).map(function (step) { + return { + stepId: evaluate(getValue(step, "StepId", "stepId")), + title: evaluate(getValue(step, "Title", "title")), + items: buildNodes(getValue(step, "Items", "items")) + }; + }); + } + let _ticket = HAC_GenerateCallbackTicket(me, function (payload, payload2) { alert("离线表单项目设置成功\r\n\r\nJSON Schema:\r\n" + patternParamJson); me.CommandExecutor.excuteCommand(me.CommandParam.CommandList, { @@ -2613,7 +2732,7 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { schemaVersion: this.evaluateFormula(params.SchemaVersion), title: this.evaluateFormula(params.Title), description: this.evaluateFormula(params.Description), - formItems: params.FormItems + steps: buildSteps(params.Steps) }; patternParamJson = JSON.stringify(patternParam, null, 2); -- Gitee From 8631f8d7c29cca8e9b6828a1cdcd5faa681a1ecb Mon Sep 17 00:00:00 2001 From: Rex Lei Date: Mon, 8 Jun 2026 15:18:23 +0800 Subject: [PATCH 06/71] refactor: simplify value retrieval in OfflinePlusAddPattern_Async_Command --- Resources/AndroidPDACommand.js | 70 +++++++++++++++------------------- 1 file changed, 30 insertions(+), 40 deletions(-) diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 96b794a..802d9ca 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -2366,7 +2366,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); @@ -2447,14 +2447,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)); @@ -2470,14 +2470,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)); @@ -2601,16 +2601,6 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { return me.evaluateFormula(value); } - function getValue(obj, pascalName, camelName) { - if (!obj) { - return undefined; - } - if (obj[pascalName] !== undefined) { - return obj[pascalName]; - } - return obj[camelName]; - } - function getList(value) { return Array.isArray(value) ? value : []; } @@ -2618,8 +2608,8 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { function buildSelectOptions(options) { return getList(options).map(function (option) { return { - value: evaluate(getValue(option, "Value", "value")), - label: evaluate(getValue(option, "Label", "label")) + value: evaluate(option.Value), + label: evaluate(option.Label) }; }); } @@ -2630,9 +2620,9 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { } var checkOptions = {}; - var minLength = evaluate(getValue(options, "MinLength", "minLength")); - var maxLength = evaluate(getValue(options, "MaxLength", "maxLength")); - var regexPattern = evaluate(getValue(options, "RegexPattern", "regexPattern")); + var minLength = evaluate(options.MinLength); + var maxLength = evaluate(options.MaxLength); + var regexPattern = evaluate(options.RegexPattern); if (minLength !== undefined && minLength !== null && minLength !== "") { checkOptions.minLength = minLength; } @@ -2647,16 +2637,16 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { function buildField(node) { var field = { - itemId: evaluate(getValue(node, "ItemId", "itemId")), - itemType: getValue(node, "ItemType", "itemType"), - title: evaluate(getValue(node, "Title", "title")), - hint: evaluate(getValue(node, "Hint", "hint")), - required: !!getValue(node, "Required", "required") + itemId: evaluate(node.ItemId), + itemType: node.ItemType, + title: evaluate(node.Title), + hint: evaluate(node.Hint), + required: !!node.Required }; - var value = evaluate(getValue(node, "Value", "value")); - var checkOptions = buildCheckOptions(getValue(node, "CheckOptions", "checkOptions")); - var selectOptions = buildSelectOptions(getValue(node, "SelectOptionsList", "selectOptionsList")); + var value = evaluate(node.Value); + var checkOptions = buildCheckOptions(node.CheckOptions); + var selectOptions = buildSelectOptions(node.SelectOptionsList); if (value !== undefined && value !== null && value !== "") { field.value = value; @@ -2672,8 +2662,8 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { function buildNodes(nodes) { return getList(nodes).map(function (node) { - var nodeType = getValue(node, "NodeType", "nodeType") || "group"; - var children = getList(getValue(node, "Children", "children")); + var nodeType = node.NodeType || "group"; + var children = getList(node.Children); if (nodeType !== "group" && children.length > 0) { console.warn("离线表单节点不是分组,但包含子节点。", node); @@ -2689,15 +2679,15 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { if (nodeType === "text") { return { nodeType: "text", - title: getValue(node, "Text", "text"), - content: evaluate(getValue(node, "Content", "content")) + title: node.Text, + content: evaluate(node.Content) }; } return { nodeType: "group", - title: getValue(node, "Text", "text"), - defaultCollapsed: !!getValue(node, "DefaultCollapsed", "defaultCollapsed"), + title: node.Text, + defaultCollapsed: !!node.DefaultCollapsed, children: buildNodes(children) }; }); @@ -2706,9 +2696,9 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { function buildSteps(steps) { return getList(steps).map(function (step) { return { - stepId: evaluate(getValue(step, "StepId", "stepId")), - title: evaluate(getValue(step, "Title", "title")), - items: buildNodes(getValue(step, "Items", "items")) + stepId: evaluate(step.StepId), + title: evaluate(step.Title), + items: buildNodes(step.Items) }; }); } @@ -2725,20 +2715,20 @@ 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: buildSteps(params.Steps) + steps: steps }; patternParamJson = JSON.stringify(patternParam, null, 2); console.log(patternParam); if (window.offlinePlus && window.offlinePlus.offlinePlusAddPatternAsync) { - + window.offlinePlus.offlinePlusAddPatternAsync(patternParamJson); } else { HAC_CallFunctionOutOfHAC(HAC_GetOfflinePlusDebugInfo("添加离线表单项目", "调用offlinePlusAddPatternAsync")); -- Gitee From 20c8c8e95d3d892f205abf5dbc488bde7b0d36f3 Mon Sep 17 00:00:00 2001 From: Rex Lei Date: Thu, 11 Jun 2026 10:37:57 +0800 Subject: [PATCH 07/71] =?UTF-8?q?feat(offline-form):=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E6=97=A5=E6=9C=9F=E6=97=B6=E9=97=B4=E5=9B=BE=E7=89=87=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E9=A1=B9=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 本次提交补齐离线填报新增表单项在活字格插件侧的配置生成能力,使命令设计器能够产出 Android 端已支持的 datePicker、timePicker 和 imageItem schema。 OfflinePlusAddPattern_Async.cs:扩展离线表单项类型下拉选项,新增 datePicker、timePicker、imageItem;为 imageItem 增加最大图片数量和压缩参数配置;按表单项类型控制属性面板显示,避免选择框、校验项、图片配置在不适用的类型上暴露。 Resources/AndroidPDACommand.js:生成离线表单 JSON 时按 itemType 输出类型专属字段;textItem/passwordItem 只输出 checkOptions,selectItem 只输出 options,imageItem 输出 maxCount 与 compression,并保持 Android 端需要的小驼峰字段名。 验证:已执行 git diff --check;已执行 node --check Resources\\AndroidPDACommand.js;已执行 dotnet build AndroidPDACommand.sln --no-restore,结果 0 Warning(s)、0 Error(s)。 --- OfflinePlusAddPattern_Async.cs | 40 +++++++++++++++++++++++++++++++--- Resources/AndroidPDACommand.js | 37 +++++++++++++++++++++++++++++-- 2 files changed, 72 insertions(+), 5 deletions(-) diff --git a/OfflinePlusAddPattern_Async.cs b/OfflinePlusAddPattern_Async.cs index 9cbc110..a196909 100644 --- a/OfflinePlusAddPattern_Async.cs +++ b/OfflinePlusAddPattern_Async.cs @@ -82,7 +82,7 @@ namespace AndroidPDACommand public object ItemId { get; set; } [DisplayName("类型")] - [ComboProperty(ValueList = "textItem|passwordItem|selectItem", DisplayList = "文本框|密码框|选择框")] + [ComboProperty(ValueList = "textItem|passwordItem|selectItem|datePicker|timePicker|imageItem", DisplayList = "文本框|密码框|选择框|日期选择|时间选择|图片列表")] public string ItemType { get; set; } = "textItem"; [FormulaProperty] @@ -109,6 +109,14 @@ namespace AndroidPDACommand [DisplayName("选则项")] public List SelectOptionsList { get; set; } + [FormulaProperty] + [DisplayName("图片最大数量")] + public object MaxCount { get; set; } = 9; + + [ObjectProperty(ObjType = typeof(ImageCompressionOptions))] + [DisplayName("图片压缩设置")] + public ImageCompressionOptions CompressionOptions { get; set; } = new ImageCompressionOptions(); + public override bool GetDesignerPropertyVisible(string propertyName) { var isField = NodeType == "field"; @@ -126,12 +134,16 @@ namespace AndroidPDACommand case nameof(Title): case nameof(Hint): case nameof(Required): - case nameof(Value): return isField; + case nameof(Value): + return isField && ItemType != "imageItem"; case nameof(SelectOptionsList): return isField && ItemType == "selectItem"; case nameof(CheckOptions): return isField && (ItemType == "textItem" || ItemType == "passwordItem"); + case nameof(MaxCount): + case nameof(CompressionOptions): + return isField && ItemType == "imageItem"; default: return base.GetDesignerPropertyVisible(propertyName); } @@ -153,7 +165,9 @@ namespace AndroidPDACommand Required = Required, Value = Value, CheckOptions = CheckOptions, - SelectOptionsList = SelectOptionsList + SelectOptionsList = SelectOptionsList, + MaxCount = MaxCount, + CompressionOptions = CompressionOptions }; } } @@ -183,4 +197,24 @@ namespace AndroidPDACommand [DisplayName("显示文本")] public object Label { get; set; } } + + public class ImageCompressionOptions : ObjectPropertyBase + { + [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; + } } diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 802d9ca..59ae86b 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -2635,6 +2635,31 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { 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); + 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 buildField(node) { var field = { itemId: evaluate(node.ItemId), @@ -2645,8 +2670,10 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { }; var value = evaluate(node.Value); - var checkOptions = buildCheckOptions(node.CheckOptions); - var selectOptions = buildSelectOptions(node.SelectOptionsList); + var checkOptions = node.ItemType === "textItem" || node.ItemType === "passwordItem" ? buildCheckOptions(node.CheckOptions) : undefined; + var selectOptions = node.ItemType === "selectItem" ? buildSelectOptions(node.SelectOptionsList) : []; + var maxCount = node.ItemType === "imageItem" ? evaluate(node.MaxCount) : undefined; + var compression = node.ItemType === "imageItem" ? buildImageCompression(node.CompressionOptions) : undefined; if (value !== undefined && value !== null && value !== "") { field.value = value; @@ -2657,6 +2684,12 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { if (selectOptions.length > 0) { field.options = selectOptions; } + if (maxCount !== undefined && maxCount !== null && maxCount !== "") { + field.maxCount = maxCount; + } + if (compression) { + field.compression = compression; + } return field; } -- Gitee From 831ac11ec1501de6815ddab4a1c189a6a002b443 Mon Sep 17 00:00:00 2001 From: Rex Lei Date: Thu, 11 Jun 2026 15:25:18 +0800 Subject: [PATCH 08/71] feat(offline): add title property to field node in OfflinePlusAddPattern_Async_Command --- Resources/AndroidPDACommand.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 59ae86b..44b0882 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -2705,6 +2705,7 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { if (nodeType === "field") { return { nodeType: "field", + title: node.Text, field: buildField(node) }; } -- Gitee From 0d491fdb985041384a0b4ea7020cc421f86d57bf Mon Sep 17 00:00:00 2001 From: Rex Lei Date: Thu, 11 Jun 2026 16:31:23 +0800 Subject: [PATCH 09/71] =?UTF-8?q?=E9=85=8D=E7=BD=AE=E7=A6=BB=E7=BA=BF?= =?UTF-8?q?=E8=A1=A8=E5=8D=95=E6=97=B6=E9=97=B4=E5=AD=97=E6=AE=B5=E7=A7=92?= =?UTF-8?q?=E6=95=B0=E9=80=89=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OfflinePlusAddPattern_Async.cs:在时间选择字段上增加包含秒配置,并用字段类型到属性集合的映射统一控制各表单类型可见属性,减少 AndroidPDACommand.js 与设计器属性可见性之间继续堆 if/else 的成本,同时保持 OfflineFormNode 属性平铺。 Resources/AndroidPDACommand.js:用 fieldTypeSpecs 按表单类型集中生成专属 JSON 属性,让 timePicker 仅在启用包含秒时输出 includeSeconds,同时保留文本、密码、选择和图片字段原有配置输出规则。 --- OfflinePlusAddPattern_Async.cs | 73 +++++++++++++++++++++++++++------- Resources/AndroidPDACommand.js | 71 +++++++++++++++++++++++++-------- 2 files changed, 112 insertions(+), 32 deletions(-) diff --git a/OfflinePlusAddPattern_Async.cs b/OfflinePlusAddPattern_Async.cs index a196909..87c9cfc 100644 --- a/OfflinePlusAddPattern_Async.cs +++ b/OfflinePlusAddPattern_Async.cs @@ -59,6 +59,35 @@ namespace AndroidPDACommand 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(CompressionOptions) + }; + + 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(CompressionOptions)) } + }; + [DisplayName("节点名称")] public string Text { get; set; } @@ -99,6 +128,10 @@ namespace AndroidPDACommand [FormulaProperty] [DisplayName("默认值")] public object Value { get; set; } + + [DisplayName("包含秒")] + [Description("仅时间选择类型生效。启用后可选择时分秒;关闭时使用系统原生时分选择器。")] + public bool IncludeSeconds { get; set; } [ObjectProperty(ObjType = typeof(CheckOptions))] @@ -129,22 +162,11 @@ namespace AndroidPDACommand return isText; case nameof(DefaultCollapsed): return isGroup; - case nameof(ItemId): - case nameof(ItemType): - case nameof(Title): - case nameof(Hint): - case nameof(Required): - return isField; - case nameof(Value): - return isField && ItemType != "imageItem"; - case nameof(SelectOptionsList): - return isField && ItemType == "selectItem"; - case nameof(CheckOptions): - return isField && (ItemType == "textItem" || ItemType == "passwordItem"); - case nameof(MaxCount): - case nameof(CompressionOptions): - return isField && ItemType == "imageItem"; default: + if (isField && FieldTypeControlledProperties.Contains(propertyName)) + { + return IsFieldPropertyVisible(ItemType, propertyName); + } return base.GetDesignerPropertyVisible(propertyName); } } @@ -164,12 +186,33 @@ namespace AndroidPDACommand Hint = Hint, Required = Required, Value = Value, + IncludeSeconds = IncludeSeconds, CheckOptions = CheckOptions, SelectOptionsList = SelectOptionsList, MaxCount = MaxCount, CompressionOptions = CompressionOptions }; } + + 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 diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 44b0882..64321d4 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -2660,6 +2660,59 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { return Object.keys(compression).length > 0 ? compression : undefined; } + var fieldTypeSpecs = { + textItem: { + apply: function (field, node) { + var checkOptions = buildCheckOptions(node.CheckOptions); + if (checkOptions) { + field.checkOptions = checkOptions; + } + } + }, + passwordItem: { + apply: function (field, node) { + var checkOptions = buildCheckOptions(node.CheckOptions); + if (checkOptions) { + field.checkOptions = checkOptions; + } + } + }, + selectItem: { + apply: function (field, node) { + var selectOptions = buildSelectOptions(node.SelectOptionsList); + if (selectOptions.length > 0) { + field.options = selectOptions; + } + } + }, + timePicker: { + apply: function (field, node) { + if (node.IncludeSeconds) { + field.includeSeconds = true; + } + } + }, + imageItem: { + apply: function (field, node) { + var maxCount = evaluate(node.MaxCount); + var compression = buildImageCompression(node.CompressionOptions); + if (maxCount !== undefined && maxCount !== null && maxCount !== "") { + field.maxCount = maxCount; + } + if (compression) { + field.compression = compression; + } + } + } + }; + + 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), @@ -2670,26 +2723,10 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { }; var value = evaluate(node.Value); - var checkOptions = node.ItemType === "textItem" || node.ItemType === "passwordItem" ? buildCheckOptions(node.CheckOptions) : undefined; - var selectOptions = node.ItemType === "selectItem" ? buildSelectOptions(node.SelectOptionsList) : []; - var maxCount = node.ItemType === "imageItem" ? evaluate(node.MaxCount) : undefined; - var compression = node.ItemType === "imageItem" ? buildImageCompression(node.CompressionOptions) : undefined; - if (value !== undefined && value !== null && value !== "") { field.value = value; } - if (checkOptions) { - field.checkOptions = checkOptions; - } - if (selectOptions.length > 0) { - field.options = selectOptions; - } - if (maxCount !== undefined && maxCount !== null && maxCount !== "") { - field.maxCount = maxCount; - } - if (compression) { - field.compression = compression; - } + applyFieldTypeSpec(field, node); return field; } -- Gitee From 28672e4cdf76f72b6b14114b736e38ee8859437d Mon Sep 17 00:00:00 2001 From: Rex Lei Date: Fri, 12 Jun 2026 11:39:12 +0800 Subject: [PATCH 10/71] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=A6=BB=E7=BA=BF?= =?UTF-8?q?=E5=9B=BE=E7=89=87=E5=88=97=E8=A1=A8=E8=AE=BE=E8=AE=A1=E6=97=B6?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OfflinePlusAddPattern_Async.cs:在图片列表表单项中补充允许图片上传、图片压缩开关和拍照水印配置,使设计器能够按图片项展示这些配置;新增拍照水印配置对象和自定义字段列表,默认提供用户名、姓名两个字段,并把这些属性纳入克隆逻辑,避免设计器复制节点时丢失配置。 Resources/AndroidPDACommand.js:在生成离线表单 JSON 时输出 allowImageUpload、compression.enableCompression 和 watermark 配置;watermark 使用 enableTimestamp 与 key/value 字段列表,供 Android 端后续按字段顺序用横线拼接生成拍照水印。 --- OfflinePlusAddPattern_Async.cs | 46 +++++++++++++++++++++++++++++++--- Resources/AndroidPDACommand.js | 32 +++++++++++++++++++++++ 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/OfflinePlusAddPattern_Async.cs b/OfflinePlusAddPattern_Async.cs index 87c9cfc..f0e9034 100644 --- a/OfflinePlusAddPattern_Async.cs +++ b/OfflinePlusAddPattern_Async.cs @@ -75,7 +75,9 @@ namespace AndroidPDACommand nameof(SelectOptionsList), nameof(IncludeSeconds), nameof(MaxCount), - nameof(CompressionOptions) + nameof(AllowImageUpload), + nameof(CompressionOptions), + nameof(WatermarkOptions) }; private static readonly Dictionary> FieldVisiblePropertiesByType = new Dictionary> @@ -85,7 +87,7 @@ namespace AndroidPDACommand { "selectItem", CreateFieldVisibleProperties(nameof(Value), nameof(SelectOptionsList)) }, { "datePicker", CreateFieldVisibleProperties(nameof(Value)) }, { "timePicker", CreateFieldVisibleProperties(nameof(Value), nameof(IncludeSeconds)) }, - { "imageItem", CreateFieldVisibleProperties(nameof(MaxCount), nameof(CompressionOptions)) } + { "imageItem", CreateFieldVisibleProperties(nameof(MaxCount), nameof(AllowImageUpload), nameof(CompressionOptions), nameof(WatermarkOptions)) } }; [DisplayName("节点名称")] @@ -146,10 +148,18 @@ namespace AndroidPDACommand [DisplayName("图片最大数量")] public object MaxCount { get; set; } = 9; + [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(); + public override bool GetDesignerPropertyVisible(string propertyName) { var isField = NodeType == "field"; @@ -190,7 +200,9 @@ namespace AndroidPDACommand CheckOptions = CheckOptions, SelectOptionsList = SelectOptionsList, MaxCount = MaxCount, - CompressionOptions = CompressionOptions + AllowImageUpload = AllowImageUpload, + CompressionOptions = CompressionOptions, + WatermarkOptions = WatermarkOptions }; } @@ -243,6 +255,10 @@ namespace AndroidPDACommand public class ImageCompressionOptions : ObjectPropertyBase { + [DisplayName("启用压缩")] + [Description("默认关闭,关闭时按原图保存。启用后才使用下面的压缩参数。")] + public bool EnableCompression { get; set; } + [FormulaProperty] [DisplayName("最长边像素")] public object MaxLongEdge { get; set; } = 1600; @@ -260,4 +276,28 @@ namespace AndroidPDACommand [DisplayName("最低JPEG质量")] public object MinQuality { get; set; } = 60; } + + public class ImageWatermarkOptions : ObjectPropertyBase + { + [DisplayName("时间戳水印")] + public bool EnableTimestamp { get; set; } = true; + + [ListProperty] + [DisplayName("自定义字段")] + public List Fields { get; set; } = new List + { + new ImageWatermarkField { Key = "用户名", Value = "用户名" }, + new ImageWatermarkField { Key = "姓名", Value = "姓名" } + }; + } + + public class ImageWatermarkField : ObjectPropertyBase + { + [DisplayName("Key")] + public string Key { get; set; } + + [FormulaProperty] + [DisplayName("Value")] + public object Value { get; set; } + } } diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 64321d4..330ecbb 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -2645,6 +2645,7 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { 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; } @@ -2660,6 +2661,30 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { return Object.keys(compression).length > 0 ? compression : undefined; } + function buildImageWatermark(options) { + if (!options) { + return undefined; + } + + var watermark = {}; + var items = getList(options.Fields).map(function (field) { + return { + key: field.Key, + value: evaluate(field.Value) + }; + }).filter(function (field) { + return field.value !== undefined && field.value !== null && field.value !== ""; + }); + + if (options.EnableTimestamp) { + watermark.enableTimestamp = true; + } + if (items.length > 0) { + watermark.items = items; + } + return Object.keys(watermark).length > 0 ? watermark : undefined; + } + var fieldTypeSpecs = { textItem: { apply: function (field, node) { @@ -2696,12 +2721,19 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { apply: function (field, node) { var maxCount = evaluate(node.MaxCount); var compression = buildImageCompression(node.CompressionOptions); + var watermark = buildImageWatermark(node.WatermarkOptions); if (maxCount !== undefined && maxCount !== null && maxCount !== "") { field.maxCount = maxCount; } + if (node.AllowImageUpload) { + field.allowImageUpload = true; + } if (compression) { field.compression = compression; } + if (watermark) { + field.watermark = watermark; + } } } }; -- Gitee From 76a8c8f3f2e738fcb398df38c556c10882ea74f4 Mon Sep 17 00:00:00 2001 From: Rex Lei Date: Fri, 12 Jun 2026 12:05:23 +0800 Subject: [PATCH 11/71] feat(watermark): disable timestamp by default and update field handling logic --- OfflinePlusAddPattern_Async.cs | 4 +--- Resources/AndroidPDACommand.js | 9 ++++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/OfflinePlusAddPattern_Async.cs b/OfflinePlusAddPattern_Async.cs index f0e9034..08b1ee2 100644 --- a/OfflinePlusAddPattern_Async.cs +++ b/OfflinePlusAddPattern_Async.cs @@ -280,14 +280,12 @@ namespace AndroidPDACommand public class ImageWatermarkOptions : ObjectPropertyBase { [DisplayName("时间戳水印")] - public bool EnableTimestamp { get; set; } = true; + public bool EnableTimestamp { get; set; } = false; [ListProperty] [DisplayName("自定义字段")] public List Fields { get; set; } = new List { - new ImageWatermarkField { Key = "用户名", Value = "用户名" }, - new ImageWatermarkField { Key = "姓名", Value = "姓名" } }; } diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 330ecbb..762e79e 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -2666,14 +2666,17 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { return undefined; } + var fields = getList(options.Fields); + if (!options.EnableTimestamp && fields.length === 0) { + return undefined; + } + var watermark = {}; - var items = getList(options.Fields).map(function (field) { + var items = fields.map(function (field) { return { key: field.Key, value: evaluate(field.Value) }; - }).filter(function (field) { - return field.value !== undefined && field.value !== null && field.value !== ""; }); if (options.EnableTimestamp) { -- Gitee From fa1641062a7419d6a3bd46e8d9cef45ae2dda5d2 Mon Sep 17 00:00:00 2001 From: Rex Lei Date: Fri, 12 Jun 2026 17:45:19 +0800 Subject: [PATCH 12/71] =?UTF-8?q?=E6=94=AF=E6=8C=81=E7=A6=BB=E7=BA=BF?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E4=B8=8A=E4=BC=A0=E8=AE=BE=E8=AE=A1=E6=97=B6?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OfflinePlusAddPattern_Async.cs:在离线表单节点类型中增加 fileItem,并新增 FileItemConfig 配置对象,让设计时可以配置最大数量、允许扩展名和单文件大小限制;同时把文件上传配置纳入字段类型属性可见性控制,只在 fileItem 类型下显示。 Resources/AndroidPDACommand.js:为 fileItem 增加运行时 JSON 输出逻辑,将设计时 FileItemConfig 转换成 field.fileItemConfig;扩展名字符串按用户输入原样输出,Android 运行时再根据扩展名做选择器 MIME 推断和保存前校验。 --- OfflinePlusAddPattern_Async.cs | 33 +++++++++++++++++++++++++++++---- Resources/AndroidPDACommand.js | 29 +++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/OfflinePlusAddPattern_Async.cs b/OfflinePlusAddPattern_Async.cs index 08b1ee2..f791b8b 100644 --- a/OfflinePlusAddPattern_Async.cs +++ b/OfflinePlusAddPattern_Async.cs @@ -77,7 +77,8 @@ namespace AndroidPDACommand nameof(MaxCount), nameof(AllowImageUpload), nameof(CompressionOptions), - nameof(WatermarkOptions) + nameof(WatermarkOptions), + nameof(FileItemConfig) }; private static readonly Dictionary> FieldVisiblePropertiesByType = new Dictionary> @@ -87,7 +88,8 @@ namespace AndroidPDACommand { "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)) } + { "imageItem", CreateFieldVisibleProperties(nameof(MaxCount), nameof(AllowImageUpload), nameof(CompressionOptions), nameof(WatermarkOptions)) }, + { "fileItem", CreateFieldVisibleProperties(nameof(FileItemConfig)) } }; [DisplayName("节点名称")] @@ -113,7 +115,7 @@ namespace AndroidPDACommand public object ItemId { get; set; } [DisplayName("类型")] - [ComboProperty(ValueList = "textItem|passwordItem|selectItem|datePicker|timePicker|imageItem", DisplayList = "文本框|密码框|选择框|日期选择|时间选择|图片列表")] + [ComboProperty(ValueList = "textItem|passwordItem|selectItem|datePicker|timePicker|imageItem|fileItem", DisplayList = "文本框|密码框|选择框|日期选择|时间选择|图片列表|文件上传")] public string ItemType { get; set; } = "textItem"; [FormulaProperty] @@ -160,6 +162,10 @@ namespace AndroidPDACommand [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"; @@ -202,7 +208,8 @@ namespace AndroidPDACommand MaxCount = MaxCount, AllowImageUpload = AllowImageUpload, CompressionOptions = CompressionOptions, - WatermarkOptions = WatermarkOptions + WatermarkOptions = WatermarkOptions, + FileItemConfig = FileItemConfig }; } @@ -298,4 +305,22 @@ namespace AndroidPDACommand [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 762e79e..1d82cad 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -2688,6 +2688,27 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { 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) { @@ -2738,6 +2759,14 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { field.watermark = watermark; } } + }, + fileItem: { + apply: function (field, node) { + var config = buildFileItemConfig(node.FileItemConfig); + if (config) { + field.fileItemConfig = config; + } + } } }; -- Gitee From fc5e4d7b95280df450abff481eaf62ef8626333c Mon Sep 17 00:00:00 2001 From: Rex Lei Date: Sat, 13 Jun 2026 11:56:04 +0800 Subject: [PATCH 13/71] =?UTF-8?q?=E6=94=AF=E6=8C=81=E7=A6=BB=E7=BA=BF?= =?UTF-8?q?=E8=A1=A8=E5=8D=95=E6=89=8B=E5=86=8C=E4=B8=8E=E5=91=98=E5=B7=A5?= =?UTF-8?q?=E7=AD=BE=E5=90=8D=E8=AE=BE=E8=AE=A1=E6=97=B6=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OfflinePlusAddPattern_Async.cs:新增手册附件单元格配置,让设计人员可以指定保存 PDF 手册附件的单元格,后续下载离线表单时可把手册随表单传给安卓端保存。新增员工签名单元格配置,用于接收签名单元格直接产出的 Base64 字符串,使员工签名能跟随离线表单一起下发到离线设备。 Resources/AndroidPDACommand.js:将添加离线表单项目命令改为 async 执行,以便在提交表单定义前先通过手册附件单元格生成下载地址并读取 PDF Base64。保留表单定义 JSON 本身不包含手册和签名内容,改为调用 offlinePlusAddPatternAsync 时把手册 Base64 作为第二个参数、签名 Base64 作为第三个参数传给安卓端,避免把大附件内容拼进 definition JSON。 --- OfflinePlusAddPattern_Async.cs | 10 +++++++ Resources/AndroidPDACommand.js | 53 ++++++++++++++++++++++++++++++++-- 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/OfflinePlusAddPattern_Async.cs b/OfflinePlusAddPattern_Async.cs index f791b8b..16a2886 100644 --- a/OfflinePlusAddPattern_Async.cs +++ b/OfflinePlusAddPattern_Async.cs @@ -29,6 +29,16 @@ namespace AndroidPDACommand [Description("同一项目编号下的表单定义版本,用于区分表单结构变更。")] public string SchemaVersion { get; set; } = "1.0"; + [FormulaProperty] + [DisplayName("手册附件单元格")] + [Description("选择保存 PDF 手册附件的单元格。下载离线表单时会把 PDF 手册随表单一起保存到离线设备。")] + public object ManualAttachmentCell { get; set; } + + [FormulaProperty] + [DisplayName("员工签名单元格")] + [Description("选择保存员工签名附件的单元格。下载离线表单时会把签名文件随表单一起保存到离线设备。")] + public object SignatureAttachmentCell { get; set; } + [DisplayName("步骤")] [ObjectListProperty(ItemType = typeof(OfflineFormStep))] public List Steps { get; set; } diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 1d82cad..14f71b4 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -2588,7 +2588,7 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { return _super !== null && _super.apply(this, arguments) || this; } - OfflinePlusAddPattern_Async_Command.prototype.execute = function () { + OfflinePlusAddPattern_Async_Command.prototype.execute = async function () { let me = this; let params = this.CommandParam; @@ -2838,6 +2838,47 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { }); } + function readBlobAsBase64(blob) { + return new Promise(function (resolve, reject) { + var reader = new FileReader(); + reader.onload = function () { + var dataUrl = reader.result || ""; + var commaIndex = dataUrl.indexOf(","); + resolve(commaIndex >= 0 ? dataUrl.substring(commaIndex + 1) : dataUrl); + }; + reader.onerror = reject; + reader.readAsDataURL(blob); + }); + } + + async function loadManualPdfBase64() { + if (params.ManualAttachmentCell === undefined || params.ManualAttachmentCell === null || params.ManualAttachmentCell === "") { + return undefined; + } + + var manualValue = evaluate(params.ManualAttachmentCell); + if (!manualValue) { + return undefined; + } + + var fileId = (manualValue + "").split("|")[0]; + if (!fileId) { + console.warn("手册附件单元格没有文件标识。", manualValue); + return undefined; + } + + var manualDownloadUrl = Forguncy.Helper.SpecialPath.getFileDownloadUrl(fileId); + var response = await fetch(manualDownloadUrl); + if (!response.ok) { + throw new Error("下载手册 PDF 失败:" + response.status); + } + + var blob = await response.blob(); + var base64 = await readBlobAsBase64(blob); + console.log("Manual PDF Base64", base64); + return base64; + } + let _ticket = HAC_GenerateCallbackTicket(me, function (payload, payload2) { alert("离线表单项目设置成功\r\n\r\nJSON Schema:\r\n" + patternParamJson); me.CommandExecutor.excuteCommand(me.CommandParam.CommandList, { @@ -2859,12 +2900,18 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { description: this.evaluateFormula(params.Description), steps: steps }; + const signatureBase64 = this.evaluateFormula(params.SignatureAttachmentCell); + var manualPdfBase64; + try { + manualPdfBase64 = await loadManualPdfBase64(); + } catch (error) { + console.error("读取手册 PDF Base64 失败:", error); + } patternParamJson = JSON.stringify(patternParam, null, 2); console.log(patternParam); if (window.offlinePlus && window.offlinePlus.offlinePlusAddPatternAsync) { - - window.offlinePlus.offlinePlusAddPatternAsync(patternParamJson); + window.offlinePlus.offlinePlusAddPatternAsync(patternParamJson, manualPdfBase64, signatureBase64); } else { HAC_CallFunctionOutOfHAC(HAC_GetOfflinePlusDebugInfo("添加离线表单项目", "调用offlinePlusAddPatternAsync")); } -- Gitee From 7af7e61a13f00474603d3516c31d1ba7fdd5e934 Mon Sep 17 00:00:00 2001 From: Rex Lei Date: Sat, 13 Jun 2026 12:31:43 +0800 Subject: [PATCH 14/71] refactor(offline-plus): simplify manual PDF handling and improve URL retrieval --- Resources/AndroidPDACommand.js | 39 ++++++---------------------------- 1 file changed, 7 insertions(+), 32 deletions(-) diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 14f71b4..c7c9dc8 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -2838,20 +2838,7 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { }); } - function readBlobAsBase64(blob) { - return new Promise(function (resolve, reject) { - var reader = new FileReader(); - reader.onload = function () { - var dataUrl = reader.result || ""; - var commaIndex = dataUrl.indexOf(","); - resolve(commaIndex >= 0 ? dataUrl.substring(commaIndex + 1) : dataUrl); - }; - reader.onerror = reject; - reader.readAsDataURL(blob); - }); - } - - async function loadManualPdfBase64() { + function getManualPdfUrl() { if (params.ManualAttachmentCell === undefined || params.ManualAttachmentCell === null || params.ManualAttachmentCell === "") { return undefined; } @@ -2867,16 +2854,7 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { return undefined; } - var manualDownloadUrl = Forguncy.Helper.SpecialPath.getFileDownloadUrl(fileId); - var response = await fetch(manualDownloadUrl); - if (!response.ok) { - throw new Error("下载手册 PDF 失败:" + response.status); - } - - var blob = await response.blob(); - var base64 = await readBlobAsBase64(blob); - console.log("Manual PDF Base64", base64); - return base64; + return Forguncy.Helper.SpecialPath.getFileDownloadUrl(fileId); } let _ticket = HAC_GenerateCallbackTicket(me, function (payload, payload2) { @@ -2900,18 +2878,15 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { description: this.evaluateFormula(params.Description), steps: steps }; - const signatureBase64 = this.evaluateFormula(params.SignatureAttachmentCell); - var manualPdfBase64; - try { - manualPdfBase64 = await loadManualPdfBase64(); - } catch (error) { - console.error("读取手册 PDF Base64 失败:", error); - } + const signatureBase64 = params.SignatureAttachmentCell === undefined || params.SignatureAttachmentCell === null || params.SignatureAttachmentCell === "" + ? "" + : this.evaluateFormula(params.SignatureAttachmentCell); + var manualPdfUrl = getManualPdfUrl(); patternParamJson = JSON.stringify(patternParam, null, 2); console.log(patternParam); if (window.offlinePlus && window.offlinePlus.offlinePlusAddPatternAsync) { - window.offlinePlus.offlinePlusAddPatternAsync(patternParamJson, manualPdfBase64, signatureBase64); + window.offlinePlus.offlinePlusAddPatternAsync(patternParamJson, manualPdfUrl || "", signatureBase64 || ""); } else { HAC_CallFunctionOutOfHAC(HAC_GetOfflinePlusDebugInfo("添加离线表单项目", "调用offlinePlusAddPatternAsync")); } -- Gitee From 2b0f5ca487e7a35a457a1f2cd85a80eacb25846f Mon Sep 17 00:00:00 2001 From: Rex Lei Date: Sat, 13 Jun 2026 15:24:45 +0800 Subject: [PATCH 15/71] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=AF=BB=E5=8F=96?= =?UTF-8?q?=E5=AE=8C=E6=95=B4=E8=AE=BE=E5=A4=87=E4=BF=A1=E6=81=AF=E5=91=BD?= =?UTF-8?q?=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Device_Info_Json.cs:新增读取设备信息命令,作为旧 Device_Info 唯一标识命令的并列新命令,避免改变现有命令的行为和兼容性。 Device_Info_Json.cs:命令结果属性 DeviceInfoJson 使用 ResultToProperty 返回完整设备信息 JSON,设计器显示文案明确包含唯一标识、品牌、型号、Android 版本、APP 版本和 WebView 版本。 Resources/AndroidPDACommand.js:注册 AndroidPDACommand.Device_Info_Json 命令,并按 C# 属性名直接读取 DeviceInfoJson,运行时调用 window.device.getDeviceInfo(),HAC 外环境仍按现有模式返回空字符串。 AndroidPDACommand.csproj:加入 Device_Info_Json.cs 编译项,确保新命令随插件工程一起编译和安装。 --- AndroidPDACommand.csproj | 1 + Device_Info_Json.cs | 27 +++++++++++++++++++++++++++ Resources/AndroidPDACommand.js | 25 +++++++++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 Device_Info_Json.cs diff --git a/AndroidPDACommand.csproj b/AndroidPDACommand.csproj index 376c9ec..6892606 100644 --- a/AndroidPDACommand.csproj +++ b/AndroidPDACommand.csproj @@ -81,6 +81,7 @@ + diff --git a/Device_Info_Json.cs b/Device_Info_Json.cs new file mode 100644 index 0000000..2c3c05a --- /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/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index c7c9dc8..e7f0bbd 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -1405,6 +1405,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() { -- Gitee From 501db334a3e7c85ffc1b929ce935098142a710a3 Mon Sep 17 00:00:00 2001 From: Rex Lei Date: Sat, 13 Jun 2026 16:46:40 +0800 Subject: [PATCH 16/71] =?UTF-8?q?=E8=B0=83=E6=95=B4=E7=A6=BB=E7=BA=BF?= =?UTF-8?q?=E8=A1=A8=E5=8D=95=E4=B8=8A=E4=BC=A0=E4=B8=8B=E8=BD=BD=E5=91=BD?= =?UTF-8?q?=E4=BB=A4=E5=85=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OfflinePlusAddPattern_Async.cs:仅调整设计器展示名称为“下载离线表单”,保留原 OfflinePlusAddPattern_Async 类名和运行时注册名,使下载动作与上传动作在设计器中形成对应关系。 OfflinePlusGetPatterns_Async.cs:保留原类名作为上传命令入口,将展示名称改为“上传离线表单”;新增动作属性,当前只提供“获取设备上的离线表单项目编号列表”,为后续上传数据、删除记录等 action 预留同一命令入口。 OfflinePlusGetPatterns_Async.cs:将 ProjectsResult 改为设计器可见的结果变量配置,确保项目编号列表 JSON 能由活字格开发人员明确指定返回变量。 Resources/AndroidPDACommand.js:在原 OfflinePlusGetPatterns_Async_Command 内部直接增加 action 判断,不新增额外 helper,不改变原 JS 构造函数名和命令注册名;Android 回调后同时写入 ProjectsResult 变量并保留子命令 initParams。 Resources/AndroidPDACommand.js:调用 window.offlinePlus.offlinePlusGetPatternsAsync(ticket),与 Android bridge 方法名保持一致,并将诊断文案调整为上传离线表单。 AndroidPDACommand.csproj:新增下载/上传两个离线表单图标资源的嵌入配置,保证设计器命令图标可加载。 Resources/Icon_OfflineDownload.png、Resources/Icon_OfflineUpload.png:新增一组方向相反的离线表单图标,用于表达下载离线表单和上传离线表单的对应关系。 --- AndroidPDACommand.csproj | 2 ++ OfflinePlusAddPattern_Async.cs | 3 ++- OfflinePlusGetPatterns_Async.cs | 18 ++++++++++++------ Resources/AndroidPDACommand.js | 14 ++++++++++---- Resources/Icon_OfflineDownload.png | Bin 0 -> 290 bytes Resources/Icon_OfflineUpload.png | Bin 0 -> 279 bytes 6 files changed, 26 insertions(+), 11 deletions(-) create mode 100644 Resources/Icon_OfflineDownload.png create mode 100644 Resources/Icon_OfflineUpload.png diff --git a/AndroidPDACommand.csproj b/AndroidPDACommand.csproj index 6892606..13b436e 100644 --- a/AndroidPDACommand.csproj +++ b/AndroidPDACommand.csproj @@ -166,6 +166,8 @@ + + diff --git a/OfflinePlusAddPattern_Async.cs b/OfflinePlusAddPattern_Async.cs index 16a2886..308192d 100644 --- a/OfflinePlusAddPattern_Async.cs +++ b/OfflinePlusAddPattern_Async.cs @@ -7,6 +7,7 @@ using GrapeCity.Forguncy.Plugin; namespace AndroidPDACommand { + [Icon("pack://application:,,,/AndroidPDACommand;component/Resources/Icon_OfflineDownload.png")] [Category("活字格安卓容器(HAC)")] public class OfflinePlusAddPattern_Async : BaseAsyncCommand { @@ -45,7 +46,7 @@ namespace AndroidPDACommand public override string ToString() { - return "添加离线表单项目"; + return "下载离线表单"; } } diff --git a/OfflinePlusGetPatterns_Async.cs b/OfflinePlusGetPatterns_Async.cs index b3257de..cc1b509 100644 --- a/OfflinePlusGetPatterns_Async.cs +++ b/OfflinePlusGetPatterns_Async.cs @@ -1,18 +1,24 @@ using System.ComponentModel; 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 { - - [Browsable(false)] + [DisplayName("动作")] + [ComboProperty(ValueList = "GetPatterns", DisplayList = "获取设备上的离线表单项目编号列表")] + public string Action { get; set; } = "GetPatterns"; + + [DisplayName("将离线表单项目编号列表返回到变量")] [ResultToProperty] - public string ProjectsResult { get; set; } = "projects"; - + public string ProjectsResult { get; set; } + public override string ToString() { - return "获取已保存项目"; + return "上传离线表单"; } } -} \ No newline at end of file +} diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index e7f0bbd..40ff061 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -2930,10 +2930,18 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { } OfflinePlusGetPatterns_Async_Command.prototype.execute = function () { + var params = this.CommandParam; + var action = params.Action || "GetPatterns"; + + 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(), @@ -2944,17 +2952,15 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { }, locationString: "执行window.offlinePlus.offlinePlusGetPatternsAsync" }); - }, HAC_GetOfflinePlusDebugInfo("获取已保存项目", "生成回调ticket")); + }, HAC_GetOfflinePlusDebugInfo("上传离线表单", "生成回调ticket")); if (window.offlinePlus && window.offlinePlus.offlinePlusGetPatternsAsync) { window.offlinePlus.offlinePlusGetPatternsAsync(ticket); } else { - HAC_CallFunctionOutOfHAC(HAC_GetOfflinePlusDebugInfo("获取已保存项目", "调用offlinePlusGetPatternsAsync")); + HAC_CallFunctionOutOfHAC(HAC_GetOfflinePlusDebugInfo("上传离线表单", "调用offlinePlusGetPatternsAsync")); } - }; - return OfflinePlusGetPatterns_Async_Command; }(Forguncy.CommandBase)); diff --git a/Resources/Icon_OfflineDownload.png b/Resources/Icon_OfflineDownload.png new file mode 100644 index 0000000000000000000000000000000000000000..1295a66c444353576d3580da122e425f19b457b9 GIT binary patch literal 290 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!R?+djv*HQ$q5oy9QN4Va@=IMi_vBAX+c(p zS*p@W|C%#OEO`=yuNU05*z(BUDD3p9U;IW4Kn0Cg7E3S){rUBnpDXYFX0{xL4!7yd zE01R#xZQvMzkS_T&YsuX^w^~t79}PrRNj(uFxEeiqn2^tqV@IzQVuuL!<26@2;AM1 zta?K=UGCoDd*#ZQ#1h+ZS|H`Di)2F%$F8(BY%^R#YS}m!C7-=w!(%AG gw$k0OA%=lL^u#J-k=mV=Krb+Oy85}Sb4q9e01!22OaK4? literal 0 HcmV?d00001 diff --git a/Resources/Icon_OfflineUpload.png b/Resources/Icon_OfflineUpload.png new file mode 100644 index 0000000000000000000000000000000000000000..cb7876aa0535f3281c9228c20470eeb39031e1e6 GIT binary patch literal 279 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!8M*Pjv*HQ$q5TgZ@kZ6*P!QSa^rFSybbyX z{@8c8O;_efn3XtVfudO<@Ah72?SIV$RRv5j%0_IRhp#kTSuDXI^yk;(^Z)(x@BiPw zGet~d{<>2v*(?_g3@6xl$a>g@G2g5E^Y8!1)&2=JiSI%-Fe*r?u}xaOmhptdlavWS zUM$~o#vL&Xn`eGw3wXnt^5@Z=%nfM*y?X9b7=IYFF{TNI&Ub7&k~E=8g!u$3!xpDA V52S>6s(|ih@O1TaS?83{1OO1XWwZbQ literal 0 HcmV?d00001 -- Gitee From db356877e20c1ed86c0b40f1fc964da871785d1f Mon Sep 17 00:00:00 2001 From: Rex Lei Date: Sat, 13 Jun 2026 17:33:03 +0800 Subject: [PATCH 17/71] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E7=A6=BB=E7=BA=BF=E8=A1=A8=E5=8D=95=E6=95=B0=E6=8D=AE=E5=AF=BC?= =?UTF-8?q?=E5=87=BA=E5=8A=A8=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OfflinePlusGetPatterns_Async.cs:在保留原 OfflinePlusGetPatterns_Async 类名和命令注册名的前提下,为上传离线表单命令新增 ExportRecords 动作,设计器显示为“导出离线表单数据”。 OfflinePlusGetPatterns_Async.cs:新增 ProjectId 输入和 ExportResult 输出,只在 ExportRecords 动作下显示;ProjectsResult 继续只在 GetPatterns 动作下显示,避免两个 action 的参数混在一起误用。 Resources/AndroidPDACommand.js:在原 OfflinePlusGetPatterns_Async_Command 内直接增加 ExportRecords 分支,使用 HAC_GenerateCallbackTicket 生成回调并调用 window.offlinePlus.offlinePlusExportRecordsAsync(projectId, ticket)。 Resources/AndroidPDACommand.js:导出回调返回后写入 ExportResult 变量,并继续通过子命令 initParams 传递 ExportResult、IsSuccess 和 Error,保持与现有异步命令执行模式一致。 --- OfflinePlusGetPatterns_Async.cs | 23 ++++++++++++++++++++++- Resources/AndroidPDACommand.js | 25 +++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/OfflinePlusGetPatterns_Async.cs b/OfflinePlusGetPatterns_Async.cs index cc1b509..0dd3b6f 100644 --- a/OfflinePlusGetPatterns_Async.cs +++ b/OfflinePlusGetPatterns_Async.cs @@ -9,16 +9,37 @@ namespace AndroidPDACommand public class OfflinePlusGetPatterns_Async : BaseAsyncCommand { [DisplayName("动作")] - [ComboProperty(ValueList = "GetPatterns", DisplayList = "获取设备上的离线表单项目编号列表")] + [ComboProperty(ValueList = "GetPatterns|ExportRecords", DisplayList = "获取设备上的离线表单项目编号列表|导出离线表单数据")] public string Action { get; set; } = "GetPatterns"; + [FormulaProperty] + [DisplayName("项目编号")] + public object ProjectId { get; set; } + [DisplayName("将离线表单项目编号列表返回到变量")] [ResultToProperty] public string ProjectsResult { get; set; } + [DisplayName("将离线表单数据返回到变量")] + [ResultToProperty] + public string ExportResult { get; set; } + public override string ToString() { return "上传离线表单"; } + + public override bool GetDesignerPropertyVisible(string propertyName, CommandScope commandScope) + { + if (propertyName == nameof(ProjectId) || propertyName == nameof(ExportResult)) + { + return Action == "ExportRecords"; + } + if (propertyName == nameof(ProjectsResult)) + { + return Action == "GetPatterns"; + } + return base.GetDesignerPropertyVisible(propertyName, commandScope); + } } } diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 40ff061..eecd4d7 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -2933,6 +2933,31 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { var params = this.CommandParam; var action = params.Action || "GetPatterns"; + if (action === "ExportRecords") { + var projectId = this.evaluateFormula(params.ProjectId); + let me = this; + let ticket = HAC_GenerateCallbackTicket(me, function (payload, payload2) { + 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" + }); + }, HAC_GetOfflinePlusDebugInfo("上传离线表单", "生成导出数据回调ticket")); + + if (window.offlinePlus && window.offlinePlus.offlinePlusExportRecordsAsync) { + window.offlinePlus.offlinePlusExportRecordsAsync(projectId, ticket); + } else { + HAC_CallFunctionOutOfHAC(HAC_GetOfflinePlusDebugInfo("上传离线表单", "调用offlinePlusExportRecordsAsync")); + } + return; + } + if (action !== "GetPatterns") { alert("不支持的离线表单上传动作:" + action); return; -- Gitee From 4e662aba3c50fca81764bac1e71254d66dae50cf Mon Sep 17 00:00:00 2001 From: Rex Lei Date: Sat, 13 Jun 2026 17:48:29 +0800 Subject: [PATCH 18/71] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E7=A6=BB=E7=BA=BF?= =?UTF-8?q?=E8=A1=A8=E5=8D=95=E6=94=AF=E6=8C=81=E6=A0=87=E8=AE=B0=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=E5=B7=B2=E5=AF=BC=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OfflinePlusGetPatterns_Async.cs:在上传离线表单命令中新增“标记离线记录已导出”动作,增加项目编号、记录编号和操作结果的设计时可见性控制;记录编号参数改为 RecordIds,并补充“多个记录编号用英文逗号分隔”的设计时备注,明确运行时输入格式。Resources/AndroidPDACommand.js:为 MarkRecordExported 动作生成 HAC 异步回调 ticket,调用 window.offlinePlus.offlinePlusMarkRecordExportedAsync(projectId, recordIds, ticket),并将安卓端返回的操作结果写回 OperationResult;JS 只传递逗号分隔字符串,不在前端拆分,保持拆分和逐条标记逻辑在安卓端完成。 --- OfflinePlusGetPatterns_Async.cs | 21 +++++++++++++++++++-- Resources/AndroidPDACommand.js | 26 ++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/OfflinePlusGetPatterns_Async.cs b/OfflinePlusGetPatterns_Async.cs index 0dd3b6f..4584c67 100644 --- a/OfflinePlusGetPatterns_Async.cs +++ b/OfflinePlusGetPatterns_Async.cs @@ -9,13 +9,18 @@ namespace AndroidPDACommand public class OfflinePlusGetPatterns_Async : BaseAsyncCommand { [DisplayName("动作")] - [ComboProperty(ValueList = "GetPatterns|ExportRecords", DisplayList = "获取设备上的离线表单项目编号列表|导出离线表单数据")] + [ComboProperty(ValueList = "GetPatterns|ExportRecords|MarkRecordExported", 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; } @@ -24,6 +29,10 @@ namespace AndroidPDACommand [ResultToProperty] public string ExportResult { get; set; } + [DisplayName("将操作结果返回到变量")] + [ResultToProperty] + public string OperationResult { get; set; } + public override string ToString() { return "上传离线表单"; @@ -31,7 +40,15 @@ namespace AndroidPDACommand public override bool GetDesignerPropertyVisible(string propertyName, CommandScope commandScope) { - if (propertyName == nameof(ProjectId) || propertyName == nameof(ExportResult)) + if (propertyName == nameof(ProjectId)) + { + return Action == "ExportRecords" || Action == "MarkRecordExported"; + } + if (propertyName == nameof(RecordIds) || propertyName == nameof(OperationResult)) + { + return Action == "MarkRecordExported"; + } + if (propertyName == nameof(ExportResult)) { return Action == "ExportRecords"; } diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index eecd4d7..cadb2cd 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -2958,6 +2958,32 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { 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 !== "GetPatterns") { alert("不支持的离线表单上传动作:" + action); return; -- Gitee From a926e1e0f366ea04e76f72f4d4ca3b48af031983 Mon Sep 17 00:00:00 2001 From: Rex Lei Date: Sat, 13 Jun 2026 18:06:01 +0800 Subject: [PATCH 19/71] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E7=A6=BB=E7=BA=BF?= =?UTF-8?q?=E8=A1=A8=E5=8D=95=E6=94=AF=E6=8C=81=E5=88=A0=E9=99=A4=E5=B7=B2?= =?UTF-8?q?=E8=AF=BB=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OfflinePlusGetPatterns_Async.cs:在上传离线表单命令中新增“删除已读离线记录”动作,复用项目编号、记录编号和操作结果参数;记录编号备注说明多个值用英文逗号分隔,并明确不填时删除项目下所有已读记录,方便设计时理解参数语义。Resources/AndroidPDACommand.js:新增 DeleteReadRecords action,使用 HAC_GenerateCallbackTicket 调用 window.offlinePlus.offlinePlusDeleteReadRecordsAsync(projectId, recordIds, ticket),并把安卓端返回结果写回 OperationResult;JS 仅传递 recordIds 字符串,不在前端拆分,保持拆分和删除逻辑在安卓端完成。 --- OfflinePlusGetPatterns_Async.cs | 8 ++++---- Resources/AndroidPDACommand.js | 26 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/OfflinePlusGetPatterns_Async.cs b/OfflinePlusGetPatterns_Async.cs index 4584c67..4652452 100644 --- a/OfflinePlusGetPatterns_Async.cs +++ b/OfflinePlusGetPatterns_Async.cs @@ -9,7 +9,7 @@ namespace AndroidPDACommand public class OfflinePlusGetPatterns_Async : BaseAsyncCommand { [DisplayName("动作")] - [ComboProperty(ValueList = "GetPatterns|ExportRecords|MarkRecordExported", DisplayList = "获取设备上的离线表单项目编号列表|导出离线表单数据|标记离线记录已导出")] + [ComboProperty(ValueList = "GetPatterns|ExportRecords|MarkRecordExported|DeleteReadRecords", DisplayList = "获取设备上的离线表单项目编号列表|导出离线表单数据|标记离线记录已导出|删除已读离线记录")] public string Action { get; set; } = "GetPatterns"; [FormulaProperty] @@ -18,7 +18,7 @@ namespace AndroidPDACommand [FormulaProperty] [DisplayName("记录编号")] - [Description("多个记录编号用英文逗号分隔。")] + [Description("多个记录编号用英文逗号分隔。删除已读离线记录时不填,则删除项目下所有已读记录。")] public object RecordIds { get; set; } [DisplayName("将离线表单项目编号列表返回到变量")] @@ -42,11 +42,11 @@ namespace AndroidPDACommand { if (propertyName == nameof(ProjectId)) { - return Action == "ExportRecords" || Action == "MarkRecordExported"; + return Action == "ExportRecords" || Action == "MarkRecordExported" || Action == "DeleteReadRecords"; } if (propertyName == nameof(RecordIds) || propertyName == nameof(OperationResult)) { - return Action == "MarkRecordExported"; + return Action == "MarkRecordExported" || Action == "DeleteReadRecords"; } if (propertyName == nameof(ExportResult)) { diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index cadb2cd..fbec884 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -2984,6 +2984,32 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { 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 !== "GetPatterns") { alert("不支持的离线表单上传动作:" + action); return; -- Gitee From a8b7381a62a63f971aa5a022b083f7bed593c4d2 Mon Sep 17 00:00:00 2001 From: Rex Lei Date: Sat, 13 Jun 2026 18:12:58 +0800 Subject: [PATCH 20/71] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E7=A6=BB=E7=BA=BF?= =?UTF-8?q?=E8=A1=A8=E5=8D=95=E6=94=AF=E6=8C=81=E5=88=A0=E9=99=A4=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OfflinePlusGetPatterns_Async.cs:在上传离线表单命令中新增“删除离线表单项目”动作,并将设计时可见参数限制为项目编号和操作结果,避免展示无关的记录编号参数。Resources/AndroidPDACommand.js:新增 DeleteProject action,使用 HAC_GenerateCallbackTicket 调用 window.offlinePlus.offlinePlusDeleteProjectAsync(projectId, ticket),并将安卓端返回结果写回 OperationResult,保持删除项目流程与其它上传离线表单动作一致。 --- OfflinePlusGetPatterns_Async.cs | 10 +++++++--- Resources/AndroidPDACommand.js | 25 +++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/OfflinePlusGetPatterns_Async.cs b/OfflinePlusGetPatterns_Async.cs index 4652452..1a597ef 100644 --- a/OfflinePlusGetPatterns_Async.cs +++ b/OfflinePlusGetPatterns_Async.cs @@ -9,7 +9,7 @@ namespace AndroidPDACommand public class OfflinePlusGetPatterns_Async : BaseAsyncCommand { [DisplayName("动作")] - [ComboProperty(ValueList = "GetPatterns|ExportRecords|MarkRecordExported|DeleteReadRecords", DisplayList = "获取设备上的离线表单项目编号列表|导出离线表单数据|标记离线记录已导出|删除已读离线记录")] + [ComboProperty(ValueList = "GetPatterns|ExportRecords|MarkRecordExported|DeleteReadRecords|DeleteProject", DisplayList = "获取设备上的离线表单项目编号列表|导出离线表单数据|标记离线记录已导出|删除已读离线记录|删除离线表单项目")] public string Action { get; set; } = "GetPatterns"; [FormulaProperty] @@ -42,12 +42,16 @@ namespace AndroidPDACommand { if (propertyName == nameof(ProjectId)) { - return Action == "ExportRecords" || Action == "MarkRecordExported" || Action == "DeleteReadRecords"; + return Action == "ExportRecords" || Action == "MarkRecordExported" || Action == "DeleteReadRecords" || Action == "DeleteProject"; } - if (propertyName == nameof(RecordIds) || propertyName == nameof(OperationResult)) + 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"; diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index fbec884..6d0d91b 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -3010,6 +3010,31 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { 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; -- Gitee From 70cdf7ba70f00914ea0edc78cf271c8dbf29389b Mon Sep 17 00:00:00 2001 From: Rex Lei Date: Mon, 15 Jun 2026 09:53:51 +0800 Subject: [PATCH 21/71] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E7=A6=BB=E7=BA=BF=E8=A1=A8=E5=8D=95=E8=AE=B0=E5=BD=95=E7=BC=96?= =?UTF-8?q?=E5=8F=B7=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OfflinePlusGetPatterns_Async.cs:修正 RecordIds 参数的设计时备注,明确该参数在“标记离线记录已导出”动作下必填,在“删除已读离线记录”动作下可不填并表示删除项目下所有已读记录,避免设计时误解参数是否可选。 --- OfflinePlusGetPatterns_Async.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OfflinePlusGetPatterns_Async.cs b/OfflinePlusGetPatterns_Async.cs index 1a597ef..01dbc68 100644 --- a/OfflinePlusGetPatterns_Async.cs +++ b/OfflinePlusGetPatterns_Async.cs @@ -18,7 +18,7 @@ namespace AndroidPDACommand [FormulaProperty] [DisplayName("记录编号")] - [Description("多个记录编号用英文逗号分隔。删除已读离线记录时不填,则删除项目下所有已读记录。")] + [Description("多个记录编号用英文逗号分隔。标记离线记录已导出时必填;删除已读离线记录时不填,则删除项目下所有已读记录。")] public object RecordIds { get; set; } [DisplayName("将离线表单项目编号列表返回到变量")] -- Gitee From 86b41cb9f28130db7ee2cae0302cf81112131843 Mon Sep 17 00:00:00 2001 From: Rex Lei Date: Mon, 15 Jun 2026 12:04:28 +0800 Subject: [PATCH 22/71] =?UTF-8?q?=E6=94=AF=E6=8C=81=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E7=A6=BB=E7=BA=BF=E8=A1=A8=E5=8D=95=E9=99=84=E4=BB=B6=E6=95=B0?= =?UTF-8?q?=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OfflinePlusGetPatterns_Async.cs:为上传离线表单命令增加隐藏的 FileUploadLimit 服务端属性,让运行时 JS 可以通过 ServerPropertiesId.FileUploadLimit 拿到文件上传限制 ID,并复用本体临时文件上传能力。 Resources/AndroidPDACommand.js:导出离线表单数据时解析 Android 返回的 attachments,逐个从 HAC 读取离线本地文件并上传到 Forguncy 临时目录,再把 records 中对应图片/附件字段替换为竖线分隔的临时文件名字符串;增加上传进度遮罩,显示文件数量、MB 进度和上传速度。空图片/附件占位值已改由 Android 导出阶段处理,因此删除前端 "[]"/"{}" 兜底归一化代码,避免两端职责重复。 --- OfflinePlusGetPatterns_Async.cs | 36 +++++ Resources/AndroidPDACommand.js | 236 ++++++++++++++++++++++++++++++-- 2 files changed, 260 insertions(+), 12 deletions(-) diff --git a/OfflinePlusGetPatterns_Async.cs b/OfflinePlusGetPatterns_Async.cs index 01dbc68..6b82b0c 100644 --- a/OfflinePlusGetPatterns_Async.cs +++ b/OfflinePlusGetPatterns_Async.cs @@ -1,4 +1,5 @@ using System.ComponentModel; +using System; using GrapeCity.Forguncy.Commands; using GrapeCity.Forguncy.Plugin; @@ -29,6 +30,12 @@ namespace AndroidPDACommand [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; } @@ -63,4 +70,33 @@ namespace AndroidPDACommand 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/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 6d0d91b..c38aa82 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -74,6 +74,197 @@ var HAC_ReturnToParam = function (OutParamaterName, data) { } }; +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 }); +}; + +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, + 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;"; + root.innerHTML = "
" + + "
正在上传离线附件
" + + "
" + + "
" + + "
" + + "
"; + 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.element.parentNode) { + this.element.parentNode.removeChild(this.element); + } + this.element = null; + this.fill = null; + this.title = null; + this.detail = null; + this.speed = null; + } +}; + +var HAC_UploadFileToTemp = function (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); + }); +}; + +var HAC_ParseJsonValue = function (value, fallback) { + if (value === undefined || value === null || value === "") { + return fallback; + } + try { + return JSON.parse(value); + } catch (e) { + return fallback; + } +}; + +var HAC_FindOfflineRecord = function (records, recordId) { + for (var i = 0; i < records.length; i++) { + if (records[i] && records[i].recordId === recordId) { + return records[i]; + } + } + return null; +}; + +var HAC_ApplyUploadedAttachmentValue = function (record, attachment, attachmentValue, uploadedValues) { + if (!record || !record.values || !attachment || !attachment.path || attachment.path.length < 3) { + return; + } + + var fieldId = attachment.path[1]; + var key = attachment.path[0] + "|" + fieldId; + if (!uploadedValues[key]) { + uploadedValues[key] = []; + } + uploadedValues[key].push(attachmentValue); + record.values[fieldId] = uploadedValues[key].join("|"); +}; + +var HAC_ProcessOfflineExportAttachments = async function (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 || !attachment.path || attachment.path.length < 3) { + 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 fileName = attachment.type === "image" ? attachment.localName : attachment.path[2]; + var file = HAC_DataUrlToFile(dataUrl, fileName); + 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 = HAC_FindOfflineRecord(records, attachment.path[0]); + 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) { var status = window.dothanPrinter.getStatus(); @@ -2935,19 +3126,40 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { if (action === "ExportRecords") { var projectId = this.evaluateFormula(params.ProjectId); + var fileUploadLimit = (params.ServerPropertiesId && params.ServerPropertiesId.FileUploadLimit) || ""; let me = this; - let ticket = HAC_GenerateCallbackTicket(me, function (payload, payload2) { - 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" - }); + let ticket = HAC_GenerateCallbackTicket(me, async function (payload, payload2) { + try { + var exportData = HAC_ParseJsonValue(payload, null); + 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) { -- Gitee From d6e115e24bde15ff7567a0d67e3eafc408ab43ec Mon Sep 17 00:00:00 2001 From: Rex Lei Date: Mon, 15 Jun 2026 14:55:45 +0800 Subject: [PATCH 23/71] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=87=BD=E6=95=B0?= =?UTF-8?q?=E6=B3=A8=E9=87=8A=EF=BC=8C=E5=A2=9E=E5=8A=A0=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91=E7=9A=84=E5=8F=AF=E8=AF=BB?= =?UTF-8?q?=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Resources/AndroidPDACommand.js | 71 +++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 32 deletions(-) diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index c38aa82..c58bb27 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -73,7 +73,12 @@ 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) { @@ -90,10 +95,15 @@ var HAC_DataUrlToFile = function (dataUrl, fileName) { 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, @@ -138,8 +148,14 @@ var HAC_OfflineUploadProgress = { this.speed = null; } }; - -var HAC_UploadFileToTemp = function (file, uploadLimitId, onProgress) { +/** + * 将文件上传到服务器临时目录,并返回服务器上的文件标识 + * @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); @@ -168,29 +184,11 @@ var HAC_UploadFileToTemp = function (file, uploadLimitId, onProgress) { }; xhr.send(formData); }); -}; - -var HAC_ParseJsonValue = function (value, fallback) { - if (value === undefined || value === null || value === "") { - return fallback; - } - try { - return JSON.parse(value); - } catch (e) { - return fallback; - } -}; - -var HAC_FindOfflineRecord = function (records, recordId) { - for (var i = 0; i < records.length; i++) { - if (records[i] && records[i].recordId === recordId) { - return records[i]; - } - } - return null; -}; - -var HAC_ApplyUploadedAttachmentValue = function (record, attachment, attachmentValue, uploadedValues) { +} +/** + * 将上传后的附件值应用到记录中,并更新记录的字段值 + */ +function HAC_ApplyUploadedAttachmentValue(record, attachment, attachmentValue, uploadedValues) { if (!record || !record.values || !attachment || !attachment.path || attachment.path.length < 3) { return; } @@ -202,9 +200,16 @@ var HAC_ApplyUploadedAttachmentValue = function (record, attachment, attachmentV } uploadedValues[key].push(attachmentValue); record.values[fieldId] = uploadedValues[key].join("|"); -}; +} -var HAC_ProcessOfflineExportAttachments = async function (projectId, exportData, uploadLimitId) { +/** + * 处理离线导出附件 + * @param {*} projectId + * @param {*} exportData + * @param {*} uploadLimitId + * @returns Promise,成功时返回处理后的导出数据,失败时返回错误信息 + */ +async function HAC_ProcessOfflineExportAttachments(projectId, exportData, uploadLimitId) { if (!exportData) { return exportData; } @@ -253,7 +258,9 @@ var HAC_ProcessOfflineExportAttachments = async function (projectId, exportData, speed: "速度:" + HAC_FormatBytesAsMb(bytesPerSecond) + "/s" }); }); - var record = HAC_FindOfflineRecord(records, attachment.path[0]); + var record = records.find(function (record) { + return record && record.recordId === attachment.path[0]; + }); HAC_ApplyUploadedAttachmentValue(record, attachment, attachmentValue, uploadedValues); } HAC_OfflineUploadProgress.update({ @@ -263,7 +270,7 @@ var HAC_ProcessOfflineExportAttachments = async function (projectId, exportData, }); delete exportData.attachments; return exportData; -}; +} var HAC_DothanPrinterOp = function (callback) { if (window.dothanPrinter) { @@ -3130,7 +3137,7 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { let me = this; let ticket = HAC_GenerateCallbackTicket(me, async function (payload, payload2) { try { - var exportData = HAC_ParseJsonValue(payload, null); + var exportData = JSON.parse(payload); if (exportData) { exportData = await HAC_ProcessOfflineExportAttachments(projectId, exportData, fileUploadLimit); payload = JSON.stringify(exportData); -- Gitee From f7f0cd1ea51ad34723ceba6eae885e4aecf753d9 Mon Sep 17 00:00:00 2001 From: Rex Lei Date: Tue, 16 Jun 2026 10:38:00 +0800 Subject: [PATCH 24/71] =?UTF-8?q?=EF=BB=BFfix(offline):=20=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E7=A6=BB=E7=BA=BF=E9=99=84=E4=BB=B6=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E5=8D=8F=E8=AE=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 配合 Android 侧图片和文件附件值统一为 AttachmentFormItemValue 列表,调整插件运行时导出处理逻辑。 按文件说明: - Resources/AndroidPDACommand.js:导出附件上传时改用 recordId/fieldId/fileName/originalName 统一字段;移除图片和文件文件名策略分支;上传遮罩拦截 touchmove 并锁定 body/html 滚动,避免移动端拖动穿透到底层页面;添加离线表单项目时将各控件类型专属配置统一写入 field.options。 - OfflinePlusGetPatterns_Async.cs:补充导出结果说明,说明图片和文件字段会按统一附件模型上传并回写字段值。 验证: - node --check Resources/AndroidPDACommand.js - git diff --cached --check --- OfflinePlusGetPatterns_Async.cs | 1 + Resources/AndroidPDACommand.js | 79 ++++++++++++++++++++++++++------- 2 files changed, 63 insertions(+), 17 deletions(-) diff --git a/OfflinePlusGetPatterns_Async.cs b/OfflinePlusGetPatterns_Async.cs index 6b82b0c..3061322 100644 --- a/OfflinePlusGetPatterns_Async.cs +++ b/OfflinePlusGetPatterns_Async.cs @@ -27,6 +27,7 @@ namespace AndroidPDACommand public string ProjectsResult { get; set; } [DisplayName("将离线表单数据返回到变量")] + [Description("导出离线记录数据。图片和文件字段会先按统一附件模型读取本地附件并上传,再把上传结果写回对应字段值。")] [ResultToProperty] public string ExportResult { get; set; } diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index c58bb27..6022923 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -110,18 +110,29 @@ var HAC_OfflineUploadProgress = { 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;"; + 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']"); @@ -138,14 +149,22 @@ var HAC_OfflineUploadProgress = { 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; } }; /** @@ -189,12 +208,17 @@ function HAC_UploadFileToTemp(file, uploadLimitId, onProgress) { * 将上传后的附件值应用到记录中,并更新记录的字段值 */ function HAC_ApplyUploadedAttachmentValue(record, attachment, attachmentValue, uploadedValues) { - if (!record || !record.values || !attachment || !attachment.path || attachment.path.length < 3) { + if (!record || !record.values || !attachment) { + return; + } + + var recordId = HAC_GetOfflineAttachmentRecordId(attachment); + var fieldId = HAC_GetOfflineAttachmentFieldId(attachment); + if (!recordId || !fieldId) { return; } - var fieldId = attachment.path[1]; - var key = attachment.path[0] + "|" + fieldId; + var key = recordId + "|" + fieldId; if (!uploadedValues[key]) { uploadedValues[key] = []; } @@ -202,6 +226,18 @@ function HAC_ApplyUploadedAttachmentValue(record, attachment, attachmentValue, u 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 @@ -234,7 +270,7 @@ async function HAC_ProcessOfflineExportAttachments(projectId, exportData, upload }); for (var i = 0; i < exportData.attachments.length; i++) { var attachment = exportData.attachments[i]; - if (!attachment || !attachment.localName || !attachment.path || attachment.path.length < 3) { + if (!attachment || !attachment.localName || !HAC_GetOfflineAttachmentRecordId(attachment) || !HAC_GetOfflineAttachmentFieldId(attachment)) { continue; } @@ -245,8 +281,7 @@ async function HAC_ProcessOfflineExportAttachments(projectId, exportData, upload speed: "" }); var dataUrl = window.offlinePlus.offlinePlusLoadAttachment(projectId, attachment.localName); - var fileName = attachment.type === "image" ? attachment.localName : attachment.path[2]; - var file = HAC_DataUrlToFile(dataUrl, fileName); + var file = HAC_DataUrlToFile(dataUrl, HAC_GetOfflineAttachmentUploadFileName(attachment)); if (!file) { throw "读取离线附件失败:" + attachment.localName; } @@ -259,7 +294,7 @@ async function HAC_ProcessOfflineExportAttachments(projectId, exportData, upload }); }); var record = records.find(function (record) { - return record && record.recordId === attachment.path[0]; + return record && record.recordId === HAC_GetOfflineAttachmentRecordId(attachment); }); HAC_ApplyUploadedAttachmentValue(record, attachment, attachmentValue, uploadedValues); } @@ -2937,7 +2972,7 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { apply: function (field, node) { var checkOptions = buildCheckOptions(node.CheckOptions); if (checkOptions) { - field.checkOptions = checkOptions; + field.options = checkOptions; } } }, @@ -2945,7 +2980,7 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { apply: function (field, node) { var checkOptions = buildCheckOptions(node.CheckOptions); if (checkOptions) { - field.checkOptions = checkOptions; + field.options = checkOptions; } } }, @@ -2953,33 +2988,41 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { apply: function (field, node) { var selectOptions = buildSelectOptions(node.SelectOptionsList); if (selectOptions.length > 0) { - field.options = selectOptions; + field.options = { + selectOptions: selectOptions + }; } } }, timePicker: { apply: function (field, node) { if (node.IncludeSeconds) { - field.includeSeconds = true; + 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 !== "") { - field.maxCount = maxCount; + options.maxCount = maxCount; } if (node.AllowImageUpload) { - field.allowImageUpload = true; + options.allowImageUpload = true; } if (compression) { - field.compression = compression; + options.compression = compression; } if (watermark) { - field.watermark = watermark; + options.watermark = watermark; + } + if (Object.keys(options).length > 0) { + field.options = options; } } }, @@ -2987,7 +3030,9 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { apply: function (field, node) { var config = buildFileItemConfig(node.FileItemConfig); if (config) { - field.fileItemConfig = config; + field.options = { + fileItemConfig: config + }; } } } -- Gitee From fd347305f8f1d6ea84edadc954215928f7687f53 Mon Sep 17 00:00:00 2001 From: Rex Lei Date: Tue, 16 Jun 2026 14:30:38 +0800 Subject: [PATCH 25/71] feat(offline): update MaxCount property to allow unlimited image uploads --- OfflinePlusAddPattern_Async.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OfflinePlusAddPattern_Async.cs b/OfflinePlusAddPattern_Async.cs index 308192d..751a119 100644 --- a/OfflinePlusAddPattern_Async.cs +++ b/OfflinePlusAddPattern_Async.cs @@ -159,7 +159,8 @@ namespace AndroidPDACommand [FormulaProperty] [DisplayName("图片最大数量")] - public object MaxCount { get; set; } = 9; + [Description("0表示不限制图片数量。")] + public object MaxCount { get; set; } = 0; [DisplayName("允许图片上传")] [Description("仅图片列表类型生效。启用后填报时除拍照外还可以从本地选择图片。")] -- Gitee From 3cbf0ebf430dac04e32b7b0adbcdb4fc8c556897 Mon Sep 17 00:00:00 2001 From: Rex Lei Date: Wed, 17 Jun 2026 09:29:34 +0800 Subject: [PATCH 26/71] fix(offline): hide field options for non-field nodes OfflinePlusAddPattern_Async.cs: keep field-type controlled designer properties hidden unless the selected offline form node is a form field. This prevents group and text nodes from showing image, file, time, and other field-specific configuration panels. --- OfflinePlusAddPattern_Async.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OfflinePlusAddPattern_Async.cs b/OfflinePlusAddPattern_Async.cs index 751a119..fd5a6e7 100644 --- a/OfflinePlusAddPattern_Async.cs +++ b/OfflinePlusAddPattern_Async.cs @@ -191,9 +191,9 @@ namespace AndroidPDACommand case nameof(DefaultCollapsed): return isGroup; default: - if (isField && FieldTypeControlledProperties.Contains(propertyName)) + if (FieldTypeControlledProperties.Contains(propertyName)) { - return IsFieldPropertyVisible(ItemType, propertyName); + return isField && IsFieldPropertyVisible(ItemType, propertyName); } return base.GetDesignerPropertyVisible(propertyName); } -- Gitee From d018c787892307f7d17cfeb2bb8eed10e1f4e061 Mon Sep 17 00:00:00 2001 From: Rex Lei Date: Wed, 24 Jun 2026 12:16:07 +0800 Subject: [PATCH 27/71] =?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 28/71] =?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 29/71] =?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 Date: Wed, 1 Jul 2026 17:41:35 +0800 Subject: [PATCH 30/71] build with V12.0.2 --- AndroidPDACommand.csproj | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/AndroidPDACommand.csproj b/AndroidPDACommand.csproj index fba84ea..c9cd4d7 100644 --- a/AndroidPDACommand.csproj +++ b/AndroidPDACommand.csproj @@ -113,19 +113,19 @@ - E:\forAgentA\forguncy\Forguncy.Server2\designerBin\Forguncy.Commands.dll + D:\Forguncy 12\WebSite\designerBin\Forguncy.Commands.dll False - E:\forAgentA\forguncy\Forguncy.Server2\designerBin\Forguncy.Commands.Design.dll + D:\Forguncy 12\WebSite\designerBin\Forguncy.Commands.Design.dll False - E:\forAgentA\forguncy\Forguncy.Server2\designerBin\GrapeCity.Forguncy.Plugin.dll + D:\Forguncy 12\WebSite\designerBin\GrapeCity.Forguncy.Plugin.dll False - E:\forAgentA\forguncy\Forguncy.Server2\bin\GrapeCity.Forguncy.ServerApi.dll + D:\Forguncy 12\WebSite\bin\GrapeCity.Forguncy.ServerApi.dll False @@ -174,6 +174,6 @@ - + -- Gitee From 1ac63c8114c61943ac5eba89608177d16ea8e1ab Mon Sep 17 00:00:00 2001 From: NathanGuo Date: Fri, 3 Jul 2026 17:57:03 +0800 Subject: [PATCH 31/71] =?UTF-8?q?=E6=B3=A8=E9=87=8A=E4=B8=8B=E8=BD=BD?= =?UTF-8?q?=E8=A1=A8=E5=8D=95=E5=BC=B9=E7=AA=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Resources/AndroidPDACommand.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index e827326..54597d5 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -3230,7 +3230,7 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { : evaluate(params.SignatureAttachmentCell); let ticket = HAC_GenerateCallbackTicket(me, function (payload, payload2) { - alert("离线表单项目设置成功\r\n\r\nJSON Schema:\r\n" + finalPatternParamJson); + // alert("离线表单项目设置成功\r\n\r\nJSON Schema:\r\n" + finalPatternParamJson); me.CommandExecutor.excuteCommand(me.CommandParam.CommandList, { runTimePageName: me.CommandExecutingInfo.runTimePageName, commandID: new Date().valueOf().toString(), -- Gitee From 1a6d8706ae41a78af952072ba0192363f45722d5 Mon Sep 17 00:00:00 2001 From: NathanGuo Date: Tue, 7 Jul 2026 12:24:58 +0800 Subject: [PATCH 32/71] =?UTF-8?q?=E6=89=B9=E9=87=8F=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E5=9F=BA=E7=A1=80=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- OfflinePlusGetPatterns_Async.cs | 4 ++-- Resources/AndroidPDACommand.js | 37 +++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/OfflinePlusGetPatterns_Async.cs b/OfflinePlusGetPatterns_Async.cs index 3061322..0b73171 100644 --- a/OfflinePlusGetPatterns_Async.cs +++ b/OfflinePlusGetPatterns_Async.cs @@ -10,7 +10,7 @@ namespace AndroidPDACommand public class OfflinePlusGetPatterns_Async : BaseAsyncCommand { [DisplayName("动作")] - [ComboProperty(ValueList = "GetPatterns|ExportRecords|MarkRecordExported|DeleteReadRecords|DeleteProject", DisplayList = "获取设备上的离线表单项目编号列表|导出离线表单数据|标记离线记录已导出|删除已读离线记录|删除离线表单项目")] + [ComboProperty(ValueList = "GetPatterns|ExportRecords|MarkRecordExported|DeleteReadRecords|DeleteProject|BatchExportRecords", DisplayList = "获取设备上的离线表单项目编号列表|导出离线表单数据|标记离线记录已导出|删除已读离线记录|删除离线表单项目|批量导出离线表单数据")] public string Action { get; set; } = "GetPatterns"; [FormulaProperty] @@ -62,7 +62,7 @@ namespace AndroidPDACommand } if (propertyName == nameof(ExportResult)) { - return Action == "ExportRecords"; + return Action == "ExportRecords" || Action == "BatchExportRecords"; } if (propertyName == nameof(ProjectsResult)) { diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 54597d5..c8871ff 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -3397,6 +3397,43 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { return; } + if (action === "BatchExportRecords") { + let me = this; + let ticket = HAC_GenerateCallbackTicket(me, async function (payload, payload2) { + try { + 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.offlinePlusBatchExportRecordsAsync" + }); + } 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: "批量导出离线表单数据时出错" + }); + } + }, HAC_GetOfflinePlusDebugInfo("批量导出离线表单", "生成批量导出回调ticket")); + + if (window.offlinePlus && window.offlinePlus.offlinePlusExportMultipleRecordsAsync) { + window.offlinePlus.offlinePlusExportMultipleRecordsAsync(ticket); + } else { + HAC_CallFunctionOutOfHAC(HAC_GetOfflinePlusDebugInfo("批量导出离线表单", "offlinePlusExportMultipleRecordsAsync")); + } + return; + } + if (action !== "GetPatterns") { alert("不支持的离线表单上传动作:" + action); return; -- Gitee From f7eec639e7bb37c90f66f33a5cedee474e4c8afe Mon Sep 17 00:00:00 2001 From: NathanGuo Date: Wed, 8 Jul 2026 14:12:55 +0800 Subject: [PATCH 33/71] =?UTF-8?q?=E8=BF=9B=E5=BA=A6=E6=9D=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Resources/AndroidPDACommand.js | 284 ++++++++++++++++++++++++++++++++- 1 file changed, 278 insertions(+), 6 deletions(-) diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index c8871ff..113f4b1 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -167,6 +167,155 @@ var HAC_OfflineUploadProgress = { this.documentOverflow = null; } }; + +/** + * 批量离线附件上传进度显示组件 - 支持多行显示多个表单状态 + */ +var HAC_BatchUploadProgress = { + element: null, + title: null, + listContainer: null, + itemMap: {}, + preventScrollHandler: null, + bodyOverflow: null, + documentOverflow: null, + ensure: function (itemCount) { + 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;padding:20px;box-sizing:border-box;"; + 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) { + if (event.target === root.querySelector("[data-role='list']")) { + return; + } + event.preventDefault(); + }; + root.addEventListener("touchmove", this.preventScrollHandler, { passive: false }); + document.body.appendChild(root); + this.element = root; + this.title = root.querySelector("[data-role='title']"); + this.listContainer = root.querySelector("[data-role='list']"); + }, + /** + * 初始化表单项 + * @param {*} itemKey 表单项唯一标识 + * @param {*} itemTitle 表单显示标题 + */ + initItem: function (itemKey, itemTitle) { + this.ensure(); + if (this.itemMap[itemKey]) { + return; + } + + var itemDiv = document.createElement("div"); + itemDiv.style.cssText = "display:flex;align-items:center;padding:12px;margin-bottom:8px;background:#f5f7fa;border-radius:6px;"; + itemDiv.innerHTML = "
⏳
" + + "
" + + "
" + + "
" + + "
"; + + this.listContainer.appendChild(itemDiv); + this.itemMap[itemKey] = { + element: itemDiv, + statusIcon: itemDiv.querySelector("[data-role='status']"), + title: itemDiv.querySelector("[data-role='title']"), + progress: itemDiv.querySelector("[data-role='progress']"), + state: 'pending' + }; + this.itemMap[itemKey].title.textContent = itemTitle || "离线表单"; + this.itemMap[itemKey].progress.textContent = "等待处理..."; + }, + /** + * 更新表单项状态 + * @param {*} itemKey 表单项唯一标识 + * @param {*} options 状态选项 { state, progress, detail, titleSuffix } + */ + updateItem: function (itemKey, options) { + this.ensure(); + var item = this.itemMap[itemKey]; + if (!item) { + return; + } + + if (options.state) { + item.state = options.state; + switch (options.state) { + case 'processing': + item.statusIcon.textContent = "⏳"; + item.statusIcon.style.color = "#2f7df6"; + break; + case 'completed': + item.statusIcon.textContent = "✓"; + item.statusIcon.style.color = "#52c41a"; + item.element.style.background = "#f6ffed"; + break; + case 'error': + item.statusIcon.textContent = "✗"; + item.statusIcon.style.color = "#ff4d4f"; + item.element.style.background = "#fff1f0"; + break; + } + } + + if (options.detail !== undefined) { + item.progress.textContent = options.detail; + } + + if (options.titleSuffix !== undefined) { + var baseTitle = item.baseTitle || item.title.textContent.split(" (")[0]; + item.baseTitle = baseTitle; + item.title.textContent = baseTitle + options.titleSuffix; + } + + if (options.progress !== undefined) { + if (item.state !== 'completed' && item.state !== 'error') { + item.progress.textContent = "处理中: " + Math.floor(options.progress) + "%"; + } + } + }, + /** + * 标记表单项完成 + * @param {*} itemKey 表单项唯一标识 + */ + completeItem: function (itemKey) { + this.updateItem(itemKey, { state: 'completed', detail: '已完成' }); + }, + /** + * 标记表单项错误 + * @param {*} itemKey 表单项唯一标识 + * @param {*} error 错误信息 + */ + errorItem: function (itemKey, error) { + this.updateItem(itemKey, { state: 'error', detail: error || '处理失败' }); + }, + 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.title = null; + this.listContainer = null; + this.itemMap = {}; + this.preventScrollHandler = null; + this.bodyOverflow = null; + this.documentOverflow = null; + } +}; /** * 将文件上传到服务器临时目录,并返回服务器上的文件标识 * @param {*} file @@ -240,10 +389,10 @@ function HAC_GetOfflineAttachmentUploadFileName(attachment) { /** * 处理离线导出附件 - * @param {*} projectId - * @param {*} exportData - * @param {*} uploadLimitId - * @returns Promise,成功时返回处理后的导出数据,失败时返回错误信息 + * @param {*} projectId + * @param {*} exportData + * @param {*} uploadLimitId + * @returns Promise,成功时返回处理后的导出数据,失败时返回错误信息 */ async function HAC_ProcessOfflineExportAttachments(projectId, exportData, uploadLimitId) { if (!exportData) { @@ -307,6 +456,121 @@ async function HAC_ProcessOfflineExportAttachments(projectId, exportData, upload return exportData; } +/** + * 处理批量导出多条记录的附件 + * @param {*} exportDataArray 批量导出的数据数组,每项包含 { projectId, patternTitle, records, attachments } + * @param {*} uploadLimitId 上传限制ID + * @returns Promise,成功时返回处理后的导出数据数组 + */ +async function HAC_ProcessBatchExportAttachments(exportDataArray, uploadLimitId) { + if (!exportDataArray || !Array.isArray(exportDataArray) || exportDataArray.length === 0) { + return exportDataArray; + } + + if (!uploadLimitId) { + throw "请设置文件上传限制ID。"; + } + if (!window.offlinePlus || !window.offlinePlus.offlinePlusLoadAttachment) { + HAC_CallFunctionOutOfHAC(HAC_GetOfflinePlusDebugInfo("批量导出离线表单", "调用offlinePlusLoadAttachment")); + throw "当前APP不支持读取离线附件。"; + } + + // 统计所有附件总数并初始化进度显示 + var totalAttachments = 0; + exportDataArray.forEach(function (item, index) { + if (item && item.attachments) { + totalAttachments += item.attachments.length; + } + // 初始化每个表单项的进度显示 + var itemKey = "item_" + index; + var itemTitle = item.patternTitle || ("离线表单 " + (index + 1)); + HAC_BatchUploadProgress.initItem(itemKey, itemTitle); + }); + + if (totalAttachments === 0) { + // 没有附件,直接标记所有项为完成 + exportDataArray.forEach(function (item, index) { + if (item) { + delete item.attachments; + HAC_BatchUploadProgress.completeItem("item_" + index); + } + }); + return exportDataArray; + } + + var uploadedValues = {}; + var currentAttachmentIndex = 0; + + HAC_BatchUploadProgress.updateItem("header", { detail: "共 " + totalAttachments + " 个附件待上传" }); + + for (var itemIndex = 0; itemIndex < exportDataArray.length; itemIndex++) { + var exportItem = exportDataArray[itemIndex]; + if (!exportItem) { + continue; + } + + var itemKey = "item_" + itemIndex; + var projectId = exportItem.projectId; + var records = exportItem.records || []; + var attachments = exportItem.attachments || []; + + // 更新标题显示进度(如 1/4) + HAC_BatchUploadProgress.updateItem(itemKey, { titleSuffix: " (" + (itemIndex + 1) + "/" + exportDataArray.length + ")" }); + + if (!attachments || attachments.length === 0) { + delete exportItem.attachments; + HAC_BatchUploadProgress.completeItem(itemKey); + continue; + } + + HAC_BatchUploadProgress.updateItem(itemKey, { state: 'processing', detail: '准备处理 ' + attachments.length + ' 个附件...' }); + + for (var i = 0; i < attachments.length; i++) { + var attachment = attachments[i]; + if (!attachment || !attachment.localName || !HAC_GetOfflineAttachmentRecordId(attachment) || !HAC_GetOfflineAttachmentFieldId(attachment)) { + continue; + } + + currentAttachmentIndex++; + var progressPercent = ((currentAttachmentIndex - 1) / totalAttachments) * 100; + + HAC_BatchUploadProgress.updateItem(itemKey, { + progress: progressPercent, + detail: "正在上传 " + currentAttachmentIndex + "/" + totalAttachments + ":" + (attachment.localName || "附件") + }); + + try { + 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) { + var itemProgress = ((currentAttachmentIndex - 1 + (total > 0 ? loaded / total : 0)) / totalAttachments) * 100; + HAC_BatchUploadProgress.updateItem(itemKey, { + progress: itemProgress, + detail: "正在上传 " + HAC_FormatBytesAsMb(loaded) + "/" + HAC_FormatBytesAsMb(total) + ",速度:" + HAC_FormatBytesAsMb(bytesPerSecond) + "/s" + }); + }); + + var record = records.find(function (record) { + return record && record.recordId === HAC_GetOfflineAttachmentRecordId(attachment); + }); + HAC_ApplyUploadedAttachmentValue(record, attachment, attachmentValue, uploadedValues); + } catch (e) { + HAC_BatchUploadProgress.errorItem(itemKey, "附件上传失败: " + (attachment.localName || "未知")); + throw e; + } + } + + delete exportItem.attachments; + HAC_BatchUploadProgress.completeItem(itemKey); + } + + return exportDataArray; +} + var HAC_DothanPrinterOp = function (callback) { if (window.dothanPrinter) { var status = window.dothanPrinter.getStatus(); @@ -3398,9 +3662,15 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { } if (action === "BatchExportRecords") { + var fileUploadLimit = (params.ServerPropertiesId && params.ServerPropertiesId.FileUploadLimit) || ""; let me = this; let ticket = HAC_GenerateCallbackTicket(me, async function (payload, payload2) { try { + var exportDataArray = JSON.parse(payload); + if (exportDataArray && Array.isArray(exportDataArray)) { + exportDataArray = await HAC_ProcessBatchExportAttachments(exportDataArray, fileUploadLimit); + payload = JSON.stringify(exportDataArray); + } HAC_ReturnToParam(params.ExportResult, payload); me.CommandExecutor.excuteCommand(me.CommandParam.CommandList, { runTimePageName: me.CommandExecutingInfo.runTimePageName, @@ -3410,7 +3680,7 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { "IsSuccess": true, "Error": "" }, - locationString: "执行window.offlinePlus.offlinePlusBatchExportRecordsAsync" + locationString: "执行window.offlinePlus.offlinePlusExportMultipleRecordsAsync" }); } catch (e) { me.CommandExecutor.excuteCommand(me.CommandParam.CommandList, { @@ -3423,13 +3693,15 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { }, locationString: "批量导出离线表单数据时出错" }); + } finally { + HAC_BatchUploadProgress.close(); } }, HAC_GetOfflinePlusDebugInfo("批量导出离线表单", "生成批量导出回调ticket")); if (window.offlinePlus && window.offlinePlus.offlinePlusExportMultipleRecordsAsync) { window.offlinePlus.offlinePlusExportMultipleRecordsAsync(ticket); } else { - HAC_CallFunctionOutOfHAC(HAC_GetOfflinePlusDebugInfo("批量导出离线表单", "offlinePlusExportMultipleRecordsAsync")); + HAC_CallFunctionOutOfHAC(HAC_GetOfflinePlusDebugInfo("批量导出离线表单", "调用offlinePlusExportMultipleRecordsAsync")); } return; } -- Gitee From 3b4a2fc678dd1125ea002001c7d5d78e6d73e4ba Mon Sep 17 00:00:00 2001 From: NathanGuo Date: Wed, 8 Jul 2026 17:44:43 +0800 Subject: [PATCH 34/71] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=AE=BE=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Resources/AndroidPDACommand.js | 269 ++++++++++++++++++++++++++++----- 1 file changed, 228 insertions(+), 41 deletions(-) diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 113f4b1..aec3dcb 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -174,9 +174,18 @@ var HAC_OfflineUploadProgress = { var HAC_BatchUploadProgress = { element: null, title: null, + countLabel: null, listContainer: null, + summaryLabel: null, + currentTitle: null, + percentLabel: null, + fill: null, + metaLeft: null, + metaRight: null, + confirmButton: null, itemMap: {}, preventScrollHandler: null, + buttonClickHandler: null, bodyOverflow: null, documentOverflow: null, ensure: function (itemCount) { @@ -184,17 +193,47 @@ var HAC_BatchUploadProgress = { 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;padding:20px;box-sizing:border-box;"; - root.innerHTML = "
" + - "
正在导出离线表单数据
" + - "
" + + root.style.cssText = "position:fixed;left:0;top:0;right:0;bottom:0;z-index:2147483647;background:#fff;display:flex;align-items:stretch;justify-content:center;font-family:Arial,'Microsoft YaHei',sans-serif;touch-action:none;overscroll-behavior:contain;box-sizing:border-box;"; + root.innerHTML = "" + + "
" + + "
" + + "
" + + "
批量导出离线表单
" + + "
批量上传已开始,状态会按处理进度实时更新。
" + + "
" + + "
" + + "
" + + "
" + + "正在导出:" + + "" + + "
" + + "0%" + + "
" + + "
" + + "
" + + "" + + "" + + "
" + + "
" + + "
" + + "
" + + "

单据列表

" + + "" + + "
" + + "
" + + "
" + + "
" + + "" + + "
" + + "
" + "
"; 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) { - if (event.target === root.querySelector("[data-role='list']")) { + var list = root.querySelector("[data-role='list']"); + if (list && list.contains(event.target)) { return; } event.preventDefault(); @@ -203,7 +242,109 @@ var HAC_BatchUploadProgress = { document.body.appendChild(root); this.element = root; this.title = root.querySelector("[data-role='title']"); + this.countLabel = root.querySelector("[data-role='count']"); this.listContainer = root.querySelector("[data-role='list']"); + this.summaryLabel = root.querySelector("[data-role='summary-label']"); + this.currentTitle = root.querySelector("[data-role='current-title']"); + this.percentLabel = root.querySelector("[data-role='percent']"); + this.fill = root.querySelector("[data-role='fill']"); + this.metaLeft = root.querySelector("[data-role='meta-left']"); + this.metaRight = root.querySelector("[data-role='meta-right']"); + this.confirmButton = root.querySelector("[data-role='confirm']"); + this.buttonClickHandler = function () { + if (!this.confirmButton || this.confirmButton.disabled) { + return; + } + this.close(); + }.bind(this); + this.confirmButton.addEventListener("click", this.buttonClickHandler); + this.refreshCount(itemCount || 0); + this.updateSummary({ + percent: 0, + title: "准备导出", + metaLeft: "正在准备附件", + metaRight: "" + }); + }, + refreshCount: function (itemCount) { + if (!this.countLabel) { + return; + } + var count = itemCount || Object.keys(this.itemMap).length; + this.countLabel.textContent = "共 " + count + " 项"; + }, + renderStatus: function (statusIcon, state) { + if (!statusIcon) { + return; + } + switch (state) { + case 'processing': + statusIcon.style.color = "#2f7df6"; + statusIcon.innerHTML = ""; + break; + case 'completed': + statusIcon.style.color = "#52c41a"; + statusIcon.innerHTML = ""; + break; + case 'error': + statusIcon.style.color = "#ff4d4f"; + statusIcon.innerHTML = ""; + break; + default: + statusIcon.style.color = "#98a2b3"; + statusIcon.innerHTML = ""; + break; + } + }, + updateSummary: function (options) { + this.ensure(); + options = options || {}; + if (options.percent !== undefined) { + var percent = Math.max(0, Math.min(100, options.percent || 0)); + this.fill.style.width = percent.toFixed(1) + "%"; + this.percentLabel.textContent = Math.floor(percent) + "%"; + } + if (options.title !== undefined) { + this.currentTitle.textContent = options.title || "离线表单"; + } + if (options.metaLeft !== undefined) { + this.metaLeft.textContent = options.metaLeft || ""; + } + if (options.metaRight !== undefined) { + this.metaRight.textContent = options.metaRight || ""; + } + if (options.label !== undefined) { + this.summaryLabel.textContent = options.label || ""; + } + }, + finish: function (options) { + if (!this.element) { + return; + } + options = options || {}; + if (options.success === false) { + this.updateSummary({ + label: "导出结果:", + title: "处理完成", + metaLeft: "处理失败", + metaRight: options.error || "请查看失败项" + }); + } else { + this.updateSummary({ + label: "导出结果:", + percent: 100, + title: "处理完成", + metaLeft: "已完成全部动作", + metaRight: "可以关闭页面" + }); + } + if (this.confirmButton) { + this.confirmButton.disabled = false; + this.confirmButton.textContent = "确认"; + this.confirmButton.style.background = "#2f7df6"; + this.confirmButton.style.opacity = "1"; + this.confirmButton.style.cursor = "pointer"; + } }, /** * 初始化表单项 @@ -217,12 +358,12 @@ var HAC_BatchUploadProgress = { } var itemDiv = document.createElement("div"); - itemDiv.style.cssText = "display:flex;align-items:center;padding:12px;margin-bottom:8px;background:#f5f7fa;border-radius:6px;"; - itemDiv.innerHTML = "
⏳
" + - "
" + - "
" + - "
" + - "
"; + itemDiv.style.cssText = "display:flex;align-items:center;justify-content:space-between;gap:14px;padding:14px 2px;border-bottom:1px solid #e4e8f0;background:#fff;"; + itemDiv.innerHTML = "
" + + "" + + "" + + "
" + + "
"; this.listContainer.appendChild(itemDiv); this.itemMap[itemKey] = { @@ -230,10 +371,13 @@ var HAC_BatchUploadProgress = { statusIcon: itemDiv.querySelector("[data-role='status']"), title: itemDiv.querySelector("[data-role='title']"), progress: itemDiv.querySelector("[data-role='progress']"), + baseTitle: itemTitle || "离线表单", state: 'pending' }; this.itemMap[itemKey].title.textContent = itemTitle || "离线表单"; this.itemMap[itemKey].progress.textContent = "等待处理..."; + this.renderStatus(this.itemMap[itemKey].statusIcon, 'pending'); + this.refreshCount(); }, /** * 更新表单项状态 @@ -249,22 +393,7 @@ var HAC_BatchUploadProgress = { if (options.state) { item.state = options.state; - switch (options.state) { - case 'processing': - item.statusIcon.textContent = "⏳"; - item.statusIcon.style.color = "#2f7df6"; - break; - case 'completed': - item.statusIcon.textContent = "✓"; - item.statusIcon.style.color = "#52c41a"; - item.element.style.background = "#f6ffed"; - break; - case 'error': - item.statusIcon.textContent = "✗"; - item.statusIcon.style.color = "#ff4d4f"; - item.element.style.background = "#fff1f0"; - break; - } + this.renderStatus(item.statusIcon, options.state); } if (options.detail !== undefined) { @@ -272,9 +401,7 @@ var HAC_BatchUploadProgress = { } if (options.titleSuffix !== undefined) { - var baseTitle = item.baseTitle || item.title.textContent.split(" (")[0]; - item.baseTitle = baseTitle; - item.title.textContent = baseTitle + options.titleSuffix; + item.title.textContent = item.baseTitle + options.titleSuffix; } if (options.progress !== undefined) { @@ -302,6 +429,9 @@ var HAC_BatchUploadProgress = { if (this.element && this.preventScrollHandler) { this.element.removeEventListener("touchmove", this.preventScrollHandler); } + if (this.confirmButton && this.buttonClickHandler) { + this.confirmButton.removeEventListener("click", this.buttonClickHandler); + } if (this.element && this.element.parentNode) { this.element.parentNode.removeChild(this.element); } @@ -309,9 +439,18 @@ var HAC_BatchUploadProgress = { document.documentElement.style.overflow = this.documentOverflow || ""; this.element = null; this.title = null; + this.countLabel = null; this.listContainer = null; + this.summaryLabel = null; + this.currentTitle = null; + this.percentLabel = null; + this.fill = null; + this.metaLeft = null; + this.metaRight = null; + this.confirmButton = null; this.itemMap = {}; this.preventScrollHandler = null; + this.buttonClickHandler = null; this.bodyOverflow = null; this.documentOverflow = null; } @@ -477,15 +616,22 @@ async function HAC_ProcessBatchExportAttachments(exportDataArray, uploadLimitId) // 统计所有附件总数并初始化进度显示 var totalAttachments = 0; + HAC_BatchUploadProgress.ensure(exportDataArray.length); exportDataArray.forEach(function (item, index) { if (item && item.attachments) { totalAttachments += item.attachments.length; } // 初始化每个表单项的进度显示 var itemKey = "item_" + index; - var itemTitle = item.patternTitle || ("离线表单 " + (index + 1)); + var itemTitle = (item && item.projectId) || ("离线表单 " + (index + 1)); HAC_BatchUploadProgress.initItem(itemKey, itemTitle); }); + HAC_BatchUploadProgress.updateSummary({ + percent: 0, + title: "准备导出", + metaLeft: "已上传文件0/" + totalAttachments, + metaRight: totalAttachments > 0 ? ("共 " + totalAttachments + " 个附件待上传") : "无需上传附件" + }); if (totalAttachments === 0) { // 没有附件,直接标记所有项为完成 @@ -495,13 +641,25 @@ async function HAC_ProcessBatchExportAttachments(exportDataArray, uploadLimitId) HAC_BatchUploadProgress.completeItem("item_" + index); } }); + HAC_BatchUploadProgress.updateSummary({ + percent: 100, + title: "导出数据", + metaLeft: "无需上传附件", + metaRight: "共 " + exportDataArray.length + " 项" + }); return exportDataArray; } var uploadedValues = {}; var currentAttachmentIndex = 0; + var completedAttachmentCount = 0; - HAC_BatchUploadProgress.updateItem("header", { detail: "共 " + totalAttachments + " 个附件待上传" }); + HAC_BatchUploadProgress.updateSummary({ + percent: 0, + title: "准备上传附件", + metaLeft: "已上传文件0/" + totalAttachments, + metaRight: "共 " + totalAttachments + " 个附件待上传" + }); for (var itemIndex = 0; itemIndex < exportDataArray.length; itemIndex++) { var exportItem = exportDataArray[itemIndex]; @@ -513,9 +671,7 @@ async function HAC_ProcessBatchExportAttachments(exportDataArray, uploadLimitId) var projectId = exportItem.projectId; var records = exportItem.records || []; var attachments = exportItem.attachments || []; - - // 更新标题显示进度(如 1/4) - HAC_BatchUploadProgress.updateItem(itemKey, { titleSuffix: " (" + (itemIndex + 1) + "/" + exportDataArray.length + ")" }); + var currentItemTitle = exportItem.projectId || ("离线表单 " + (itemIndex + 1)); if (!attachments || attachments.length === 0) { delete exportItem.attachments; @@ -524,6 +680,12 @@ async function HAC_ProcessBatchExportAttachments(exportDataArray, uploadLimitId) } HAC_BatchUploadProgress.updateItem(itemKey, { state: 'processing', detail: '准备处理 ' + attachments.length + ' 个附件...' }); + HAC_BatchUploadProgress.updateSummary({ + percent: completedAttachmentCount / totalAttachments * 100, + title: currentItemTitle, + metaLeft: "已上传文件" + completedAttachmentCount + "/" + totalAttachments, + metaRight: "准备处理 " + attachments.length + " 个附件" + }); for (var i = 0; i < attachments.length; i++) { var attachment = attachments[i]; @@ -532,11 +694,18 @@ async function HAC_ProcessBatchExportAttachments(exportDataArray, uploadLimitId) } currentAttachmentIndex++; - var progressPercent = ((currentAttachmentIndex - 1) / totalAttachments) * 100; + var progressPercent = (completedAttachmentCount / totalAttachments) * 100; + var attachmentName = attachment.localName || "附件"; HAC_BatchUploadProgress.updateItem(itemKey, { progress: progressPercent, - detail: "正在上传 " + currentAttachmentIndex + "/" + totalAttachments + ":" + (attachment.localName || "附件") + detail: "正在上传 " + currentAttachmentIndex + "/" + totalAttachments + ":" + attachmentName + }); + HAC_BatchUploadProgress.updateSummary({ + percent: progressPercent, + title: currentItemTitle, + metaLeft: "已上传文件" + completedAttachmentCount + "/" + totalAttachments, + metaRight: attachmentName }); try { @@ -547,19 +716,32 @@ async function HAC_ProcessBatchExportAttachments(exportDataArray, uploadLimitId) } var attachmentValue = await HAC_UploadFileToTemp(file, uploadLimitId, function (loaded, total, bytesPerSecond) { - var itemProgress = ((currentAttachmentIndex - 1 + (total > 0 ? loaded / total : 0)) / totalAttachments) * 100; + var itemProgress = ((completedAttachmentCount + (total > 0 ? loaded / total : 0)) / totalAttachments) * 100; HAC_BatchUploadProgress.updateItem(itemKey, { progress: itemProgress, detail: "正在上传 " + HAC_FormatBytesAsMb(loaded) + "/" + HAC_FormatBytesAsMb(total) + ",速度:" + HAC_FormatBytesAsMb(bytesPerSecond) + "/s" }); + HAC_BatchUploadProgress.updateSummary({ + percent: itemProgress, + title: currentItemTitle, + metaLeft: "已上传文件" + completedAttachmentCount + "/" + totalAttachments, + metaRight: attachmentName + " · " + HAC_FormatBytesAsMb(bytesPerSecond) + "/s" + }); }); var record = records.find(function (record) { return record && record.recordId === HAC_GetOfflineAttachmentRecordId(attachment); }); HAC_ApplyUploadedAttachmentValue(record, attachment, attachmentValue, uploadedValues); + completedAttachmentCount++; + HAC_BatchUploadProgress.updateSummary({ + percent: completedAttachmentCount / totalAttachments * 100, + title: currentItemTitle, + metaLeft: "已上传文件" + completedAttachmentCount + "/" + totalAttachments, + metaRight: attachmentName + " 已上传" + }); } catch (e) { - HAC_BatchUploadProgress.errorItem(itemKey, "附件上传失败: " + (attachment.localName || "未知")); + HAC_BatchUploadProgress.errorItem(itemKey, "附件上传失败: " + (attachmentName || "未知")); throw e; } } @@ -3665,6 +3847,7 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { var fileUploadLimit = (params.ServerPropertiesId && params.ServerPropertiesId.FileUploadLimit) || ""; let me = this; let ticket = HAC_GenerateCallbackTicket(me, async function (payload, payload2) { + var batchExportError = ""; try { var exportDataArray = JSON.parse(payload); if (exportDataArray && Array.isArray(exportDataArray)) { @@ -3683,18 +3866,22 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { locationString: "执行window.offlinePlus.offlinePlusExportMultipleRecordsAsync" }); } catch (e) { + batchExportError = e ? e.toString() : "批量导出离线表单数据失败。"; me.CommandExecutor.excuteCommand(me.CommandParam.CommandList, { runTimePageName: me.CommandExecutingInfo.runTimePageName, commandID: new Date().valueOf().toString(), initParams: { "ExportResult": payload, "IsSuccess": false, - "Error": e ? e.toString() : "批量导出离线表单数据失败。" + "Error": batchExportError }, locationString: "批量导出离线表单数据时出错" }); } finally { - HAC_BatchUploadProgress.close(); + HAC_BatchUploadProgress.finish({ + success: !batchExportError, + error: batchExportError + }); } }, HAC_GetOfflinePlusDebugInfo("批量导出离线表单", "生成批量导出回调ticket")); -- Gitee From 6cc9229771a783d0d84b139a3e5bbecd70f9309f Mon Sep 17 00:00:00 2001 From: NathanGuo Date: Wed, 8 Jul 2026 18:08:40 +0800 Subject: [PATCH 35/71] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E7=AA=97=E5=8F=A3?= =?UTF-8?q?=E7=BB=93=E6=9E=84=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Resources/AndroidPDACommand.js | 74 +++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 28 deletions(-) diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index aec3dcb..164eabb 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -186,6 +186,7 @@ var HAC_BatchUploadProgress = { itemMap: {}, preventScrollHandler: null, buttonClickHandler: null, + confirmHandler: null, bodyOverflow: null, documentOverflow: null, ensure: function (itemCount) { @@ -255,7 +256,11 @@ var HAC_BatchUploadProgress = { if (!this.confirmButton || this.confirmButton.disabled) { return; } + var confirmHandler = this.confirmHandler; this.close(); + if (confirmHandler) { + confirmHandler(); + } }.bind(this); this.confirmButton.addEventListener("click", this.buttonClickHandler); this.refreshCount(itemCount || 0); @@ -318,10 +323,14 @@ var HAC_BatchUploadProgress = { } }, finish: function (options) { + options = options || {}; if (!this.element) { + if (options.onConfirm) { + options.onConfirm(); + } return; } - options = options || {}; + this.confirmHandler = options.onConfirm || null; if (options.success === false) { this.updateSummary({ label: "导出结果:", @@ -451,6 +460,7 @@ var HAC_BatchUploadProgress = { this.itemMap = {}; this.preventScrollHandler = null; this.buttonClickHandler = null; + this.confirmHandler = null; this.bodyOverflow = null; this.documentOverflow = null; } @@ -3848,41 +3858,49 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { let me = this; let ticket = HAC_GenerateCallbackTicket(me, async function (payload, payload2) { var batchExportError = ""; + var batchExportPayload = payload; + var batchExportSuccess = false; try { var exportDataArray = JSON.parse(payload); if (exportDataArray && Array.isArray(exportDataArray)) { exportDataArray = await HAC_ProcessBatchExportAttachments(exportDataArray, fileUploadLimit); - payload = JSON.stringify(exportDataArray); + batchExportPayload = JSON.stringify(exportDataArray); } - 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.offlinePlusExportMultipleRecordsAsync" - }); + batchExportSuccess = true; } catch (e) { batchExportError = e ? e.toString() : "批量导出离线表单数据失败。"; - me.CommandExecutor.excuteCommand(me.CommandParam.CommandList, { - runTimePageName: me.CommandExecutingInfo.runTimePageName, - commandID: new Date().valueOf().toString(), - initParams: { - "ExportResult": payload, - "IsSuccess": false, - "Error": batchExportError - }, - locationString: "批量导出离线表单数据时出错" - }); - } finally { - HAC_BatchUploadProgress.finish({ - success: !batchExportError, - error: batchExportError - }); } + var continueBatchExport = function () { + if (batchExportSuccess) { + HAC_ReturnToParam(params.ExportResult, batchExportPayload); + me.CommandExecutor.excuteCommand(me.CommandParam.CommandList, { + runTimePageName: me.CommandExecutingInfo.runTimePageName, + commandID: new Date().valueOf().toString(), + initParams: { + "ExportResult": batchExportPayload, + "IsSuccess": true, + "Error": "" + }, + locationString: "执行window.offlinePlus.offlinePlusExportMultipleRecordsAsync" + }); + } else { + me.CommandExecutor.excuteCommand(me.CommandParam.CommandList, { + runTimePageName: me.CommandExecutingInfo.runTimePageName, + commandID: new Date().valueOf().toString(), + initParams: { + "ExportResult": batchExportPayload, + "IsSuccess": false, + "Error": batchExportError + }, + locationString: "批量导出离线表单数据时出错" + }); + } + }; + HAC_BatchUploadProgress.finish({ + success: batchExportSuccess, + error: batchExportError, + onConfirm: continueBatchExport + }); }, HAC_GetOfflinePlusDebugInfo("批量导出离线表单", "生成批量导出回调ticket")); if (window.offlinePlus && window.offlinePlus.offlinePlusExportMultipleRecordsAsync) { -- Gitee From e061d1f161e0113b6c05d6c86dded0d58bb0e7a0 Mon Sep 17 00:00:00 2001 From: NathanGuo Date: Fri, 17 Jul 2026 09:28:11 +0800 Subject: [PATCH 36/71] =?UTF-8?q?=E7=A6=BB=E7=BA=BF=E8=A1=A8=E5=8D=95?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0List=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- OfflinePlusBuildPattern.cs | 83 ++++++++++++++++++++++++++++++++-- Resources/AndroidPDACommand.js | 46 ++++++++++++++++++- 2 files changed, 123 insertions(+), 6 deletions(-) diff --git a/OfflinePlusBuildPattern.cs b/OfflinePlusBuildPattern.cs index 7be725a..e9ab83b 100644 --- a/OfflinePlusBuildPattern.cs +++ b/OfflinePlusBuildPattern.cs @@ -84,6 +84,11 @@ namespace AndroidPDACommand public class OfflineFormNode : ObjectPropertyBase, ITreeNode { + public const string BaseItemTypeValueList = "textItem|passwordItem|selectItem|datePicker|timePicker|imageItem|fileItem"; + public const string BaseItemTypeDisplayList = "文本框|密码框|选择框|日期选择|时间选择|图片列表|文件上传"; + public const string ItemTypeValueList = BaseItemTypeValueList + "|listItem"; + public const string ItemTypeDisplayList = BaseItemTypeDisplayList + "|列表"; + private static readonly string[] CommonFieldVisibleProperties = { nameof(ItemId), @@ -103,7 +108,8 @@ namespace AndroidPDACommand nameof(AllowImageUpload), nameof(CompressionOptions), nameof(WatermarkOptions), - nameof(FileItemConfig) + nameof(FileItemConfig), + nameof(ListItemOptions) }; private static readonly Dictionary> FieldVisiblePropertiesByType = new Dictionary> @@ -114,7 +120,8 @@ namespace AndroidPDACommand { "datePicker", CreateFieldVisibleProperties(nameof(Value)) }, { "timePicker", CreateFieldVisibleProperties(nameof(Value), nameof(IncludeSeconds)) }, { "imageItem", CreateFieldVisibleProperties(nameof(MaxCount), nameof(AllowImageUpload), nameof(CompressionOptions), nameof(WatermarkOptions)) }, - { "fileItem", CreateFieldVisibleProperties(nameof(FileItemConfig)) } + { "fileItem", CreateFieldVisibleProperties(nameof(FileItemConfig)) }, + { "listItem", CreateFieldVisibleProperties(nameof(ListItemOptions)) } }; [DisplayName("节点名称")] @@ -140,8 +147,8 @@ namespace AndroidPDACommand public object ItemId { get; set; } [DisplayName("类型")] - [ComboProperty(ValueList = "textItem|passwordItem|selectItem|datePicker|timePicker|imageItem|fileItem", DisplayList = "文本框|密码框|选择框|日期选择|时间选择|图片列表|文件上传")] - public string ItemType { get; set; } = "textItem"; + [ComboProperty(ValueList = ItemTypeValueList, DisplayList = ItemTypeDisplayList)] + public virtual string ItemType { get; set; } = "textItem"; [FormulaProperty] [DisplayName("标题")] @@ -192,6 +199,10 @@ namespace AndroidPDACommand [DisplayName("文件上传配置")] public FileItemConfig FileItemConfig { get; set; } = new FileItemConfig(); + [ObjectProperty(ObjType = typeof(ListItemOptions))] + [DisplayName("列表配置")] + public ListItemOptions ListItemOptions { get; set; } = new ListItemOptions(); + public override bool GetDesignerPropertyVisible(string propertyName) { var isField = NodeType == "field"; @@ -235,7 +246,8 @@ namespace AndroidPDACommand AllowImageUpload = AllowImageUpload, CompressionOptions = CompressionOptions, WatermarkOptions = WatermarkOptions, - FileItemConfig = FileItemConfig + FileItemConfig = FileItemConfig, + ListItemOptions = ListItemOptions }; } @@ -260,6 +272,40 @@ namespace AndroidPDACommand } } + public class OfflineListFormNode : OfflineFormNode + { + [DisplayName("类型")] + [ComboProperty(ValueList = BaseItemTypeValueList, DisplayList = BaseItemTypeDisplayList)] + public override string ItemType { get; set; } = "textItem"; + + public override object Clone() + { + return new OfflineListFormNode + { + 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, + ListItemOptions = ListItemOptions + }; + } + } + public class CheckOptions : ObjectPropertyBase { [FormulaProperty] @@ -349,4 +395,31 @@ namespace AndroidPDACommand [Description("0表示不限制单文件大小。")] public object MaxFileSizeKb { get; set; } = 0; } + + public class ListItemOptions : ObjectPropertyBase + { + [FormulaProperty] + [DisplayName("最小数量")] + public object MinCount { get; set; } + + [FormulaProperty] + [DisplayName("最大数量")] + public object MaxCount { get; set; } + + [FormulaProperty] + [DisplayName("默认数量")] + public object DefaultCount { get; set; } + + [FormulaProperty] + [DisplayName("添加按钮文本")] + public object AddButtonText { get; set; } + + [FormulaProperty] + [DisplayName("列表项标题")] + public object ItemTitle { get; set; } + + [TreeProperty(NodeType = typeof(OfflineListFormNode), DefaultNodeName = "节点")] + [DisplayName("列表子项")] + public List Children { get; set; } = new List(); + } } diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 164eabb..7be13e6 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -3414,6 +3414,41 @@ function HAC_OfflinePlusCreateFormNodeBuilder(context) { return Object.keys(config).length > 0 ? config : undefined; } + function buildListItemOptions(node) { + var options = {}; + var listOptions = node.ListItemOptions || {}; + var minCount = evaluate(listOptions.MinCount); + var maxCount = evaluate(listOptions.MaxCount); + var defaultCount = evaluate(listOptions.DefaultCount); + var addButtonText = evaluate(listOptions.AddButtonText); + var itemTitle = evaluate(listOptions.ItemTitle); + var children = buildNodes(listOptions.Children); + + if (children.length === 0 && getList(node.Children).length > 0) { + children = buildNodes(node.Children); + } + + if (minCount !== undefined && minCount !== null && minCount !== "") { + options.minCount = minCount; + } + if (maxCount !== undefined && maxCount !== null && maxCount !== "") { + options.maxCount = maxCount; + } + if (defaultCount !== undefined && defaultCount !== null && defaultCount !== "") { + options.defaultCount = defaultCount; + } + if (addButtonText !== undefined && addButtonText !== null && addButtonText !== "") { + options.addButtonText = addButtonText; + } + if (itemTitle !== undefined && itemTitle !== null && itemTitle !== "") { + options.itemTitle = itemTitle; + } + if (children.length > 0) { + options.children = children; + } + return Object.keys(options).length > 0 ? options : undefined; + } + var fieldTypeSpecs = { textItem: { apply: function (field, node) { @@ -3482,6 +3517,14 @@ function HAC_OfflinePlusCreateFormNodeBuilder(context) { }; } } + }, + listItem: { + apply: function (field, node) { + var options = buildListItemOptions(node); + if (options) { + field.options = options; + } + } } }; @@ -3512,8 +3555,9 @@ function HAC_OfflinePlusCreateFormNodeBuilder(context) { function buildNode(node) { var nodeType = node.NodeType || "group"; var children = getList(node.Children); + var isListField = nodeType === "field" && node.ItemType === "listItem"; - if (nodeType !== "group" && children.length > 0) { + if (nodeType !== "group" && !isListField && children.length > 0) { console.warn("离线表单节点不是分组,但包含子节点。", node); } -- Gitee From 4aa3774bff069401501033e45ee7670814eacc87 Mon Sep 17 00:00:00 2001 From: NathanGuo Date: Thu, 23 Jul 2026 14:09:24 +0800 Subject: [PATCH 37/71] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=A6=BB=E7=BA=BFjson?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C=E5=91=BD=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AndroidPDACommand.csproj | 1 + OfflinePlusValidatePatternJson.cs | 32 +++++ Resources/AndroidPDACommand.js | 216 ++++++++++++++++++++++++++++-- 3 files changed, 239 insertions(+), 10 deletions(-) create mode 100644 OfflinePlusValidatePatternJson.cs diff --git a/AndroidPDACommand.csproj b/AndroidPDACommand.csproj index c9cd4d7..5a89361 100644 --- a/AndroidPDACommand.csproj +++ b/AndroidPDACommand.csproj @@ -53,6 +53,7 @@ + diff --git a/OfflinePlusValidatePatternJson.cs b/OfflinePlusValidatePatternJson.cs new file mode 100644 index 0000000..b96687b --- /dev/null +++ b/OfflinePlusValidatePatternJson.cs @@ -0,0 +1,32 @@ +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 OfflinePlusValidatePatternJson : BaseCommand + { + [Required] + [FormulaProperty] + [DisplayName("离线表单JSON")] + [Description("需要检测的JSON字符串或JSON对象。结构要求与“下载离线表单”命令的“离线表单JSON”参数一致。")] + public object PatternJson { get; set; } + + [DisplayName("将是否有效返回到变量")] + [ResultToProperty] + public string IsValidResult { get; set; } = "OfflinePatternJsonIsValid"; + + [DisplayName("将错误点返回到变量")] + [Description("校验成功时返回空字符串;失败时返回第一个错误的JSON路径和错误原因。")] + [ResultToProperty] + public string ErrorResult { get; set; } = "OfflinePatternJsonError"; + + public override string ToString() + { + return "检测离线表单JSON"; + } + } +} diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 7be13e6..cc9858f 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -3675,6 +3675,208 @@ var OfflinePlusBuildPattern_Command = (function (_super) { Forguncy.CommandFactory.registerCommand("AndroidPDACommand.OfflinePlusBuildPattern, AndroidPDACommand", OfflinePlusBuildPattern_Command); +function HAC_OfflinePlusValidatePatternJson(patternJson) { + function fail(path, message) { + return { isValid: false, error: path + ":" + message }; + } + + function isObject(value) { + return value !== null && typeof value === "object" && !Array.isArray(value); + } + + function isBlank(value) { + return value === undefined || value === null || (typeof value === "string" && value.trim() === ""); + } + + function validateNonNegativeNumber(value, path) { + if (value !== undefined && value !== null && value !== "" && + (typeof value !== "number" || !isFinite(value) || value < 0)) { + return fail(path, "必须是大于或等于0的数字"); + } + return null; + } + + function validateNode(node, path, itemIds) { + if (!isObject(node)) { + return fail(path, "必须是对象"); + } + + var nodeType = node.nodeType; + if (["group", "text", "field"].indexOf(nodeType) < 0) { + return fail(path + ".nodeType", "必须是group、text或field"); + } + + if (nodeType === "group") { + if (!Array.isArray(node.children)) { + return fail(path + ".children", "必须是数组"); + } + for (var groupIndex = 0; groupIndex < node.children.length; groupIndex++) { + var groupError = validateNode(node.children[groupIndex], path + ".children[" + groupIndex + "]", itemIds); + if (groupError) { + return groupError; + } + } + return null; + } + + if (nodeType === "text") { + if (node.content === undefined || node.content === null) { + return fail(path + ".content", "缺少说明内容"); + } + return null; + } + + if (!isObject(node.field)) { + return fail(path + ".field", "必须是对象"); + } + + var field = node.field; + if (isBlank(field.itemId)) { + return fail(path + ".field.itemId", "不能为空"); + } + var itemIdKey = String(field.itemId); + if (itemIds[itemIdKey]) { + return fail(path + ".field.itemId", "与" + itemIds[itemIdKey] + "重复"); + } + itemIds[itemIdKey] = path + ".field.itemId"; + + var itemTypes = ["textItem", "passwordItem", "selectItem", "datePicker", "timePicker", "imageItem", "fileItem", "listItem"]; + if (itemTypes.indexOf(field.itemType) < 0) { + return fail(path + ".field.itemType", "是不支持的表单项类型"); + } + if (isBlank(field.title)) { + return fail(path + ".field.title", "不能为空"); + } + if (field.required !== undefined && typeof field.required !== "boolean") { + return fail(path + ".field.required", "必须是布尔值"); + } + if (field.options !== undefined && !isObject(field.options)) { + return fail(path + ".field.options", "必须是对象"); + } + + var options = field.options || {}; + var numberError; + if (field.itemType === "selectItem") { + if (!Array.isArray(options.selectOptions) || options.selectOptions.length === 0) { + return fail(path + ".field.options.selectOptions", "必须是非空数组"); + } + for (var optionIndex = 0; optionIndex < options.selectOptions.length; optionIndex++) { + var optionPath = path + ".field.options.selectOptions[" + optionIndex + "]"; + if (!isObject(options.selectOptions[optionIndex])) { + return fail(optionPath, "必须是对象"); + } + if (isBlank(options.selectOptions[optionIndex].value)) { + return fail(optionPath + ".value", "不能为空"); + } + if (isBlank(options.selectOptions[optionIndex].label)) { + return fail(optionPath + ".label", "不能为空"); + } + } + } else if (field.itemType === "listItem") { + if (!Array.isArray(options.children) || options.children.length === 0) { + return fail(path + ".field.options.children", "必须是非空数组"); + } + numberError = validateNonNegativeNumber(options.minCount, path + ".field.options.minCount") || + validateNonNegativeNumber(options.maxCount, path + ".field.options.maxCount") || + validateNonNegativeNumber(options.defaultCount, path + ".field.options.defaultCount"); + if (numberError) { + return numberError; + } + for (var listIndex = 0; listIndex < options.children.length; listIndex++) { + var listError = validateNode(options.children[listIndex], path + ".field.options.children[" + listIndex + "]", itemIds); + if (listError) { + return listError; + } + } + } else if (field.itemType === "imageItem") { + numberError = validateNonNegativeNumber(options.maxCount, path + ".field.options.maxCount"); + if (numberError) { + return numberError; + } + } + + return null; + } + + if (patternJson === undefined || patternJson === null || patternJson === "") { + return fail("$", "离线表单JSON不能为空"); + } + + var pattern; + try { + pattern = typeof patternJson === "string" ? JSON.parse(patternJson) : patternJson; + } catch (e) { + return fail("$", "JSON格式不正确" + (e && e.message ? "(" + e.message + ")" : "")); + } + + if (!isObject(pattern)) { + return fail("$", "根节点必须是对象"); + } + if (isBlank(pattern.patternId)) { + return fail("$.patternId", "不能为空"); + } + if (isBlank(pattern.schemaVersion)) { + return fail("$.schemaVersion", "不能为空"); + } + if (isBlank(pattern.title)) { + return fail("$.title", "不能为空"); + } + if (!Array.isArray(pattern.steps) || pattern.steps.length === 0) { + return fail("$.steps", "必须是非空数组"); + } + + var stepIds = Object.create(null); + var itemIds = Object.create(null); + for (var stepIndex = 0; stepIndex < pattern.steps.length; stepIndex++) { + var step = pattern.steps[stepIndex]; + var stepPath = "$.steps[" + stepIndex + "]"; + if (!isObject(step)) { + return fail(stepPath, "必须是对象"); + } + if (isBlank(step.stepId)) { + return fail(stepPath + ".stepId", "不能为空"); + } + var stepIdKey = String(step.stepId); + if (stepIds[stepIdKey]) { + return fail(stepPath + ".stepId", "与" + stepIds[stepIdKey] + "重复"); + } + stepIds[stepIdKey] = stepPath + ".stepId"; + if (isBlank(step.title)) { + return fail(stepPath + ".title", "不能为空"); + } + if (!Array.isArray(step.items) || step.items.length === 0) { + return fail(stepPath + ".items", "必须是非空数组"); + } + for (var itemIndex = 0; itemIndex < step.items.length; itemIndex++) { + var itemError = validateNode(step.items[itemIndex], stepPath + ".items[" + itemIndex + "]", itemIds); + if (itemError) { + return itemError; + } + } + } + + return { isValid: true, error: "", value: pattern }; +} + +var OfflinePlusValidatePatternJson_Command = (function (_super) { + __extends(OfflinePlusValidatePatternJson_Command, _super); + function OfflinePlusValidatePatternJson_Command() { + return _super !== null && _super.apply(this, arguments) || this; + } + + OfflinePlusValidatePatternJson_Command.prototype.execute = function () { + var params = this.CommandParam; + var patternJson = this.evaluateFormula(params.PatternJson); + var result = HAC_OfflinePlusValidatePatternJson(patternJson); + HAC_ReturnToParam(params.IsValidResult, result.isValid); + HAC_ReturnToParam(params.ErrorResult, result.error); + }; + + return OfflinePlusValidatePatternJson_Command; +}(Forguncy.CommandBase)); + +Forguncy.CommandFactory.registerCommand("AndroidPDACommand.OfflinePlusValidatePatternJson, AndroidPDACommand", OfflinePlusValidatePatternJson_Command); + var OfflinePlusAddPattern_Async_Command = (function (_super) { __extends(OfflinePlusAddPattern_Async_Command, _super); function OfflinePlusAddPattern_Async_Command() { @@ -3709,18 +3911,12 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { } 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 : "")); + var validationResult = HAC_OfflinePlusValidatePatternJson(patternJson); + if (!validationResult.isValid) { + alert("离线表单JSON不正确:" + validationResult.error); return; } + var patternParam = validationResult.value; var manualAttachmentValue = params.ManualAttachmentCell === undefined || params.ManualAttachmentCell === null || params.ManualAttachmentCell === "" ? "" -- Gitee From bd86bcd70115c1011436b5a4e37e606a1e26aaf3 Mon Sep 17 00:00:00 2001 From: NathanGuo Date: Mon, 10 Aug 2026 10:36:41 +0800 Subject: [PATCH 38/71] change version --- PluginConfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PluginConfig.json b/PluginConfig.json index 2ac37f6..db67877 100644 --- a/PluginConfig.json +++ b/PluginConfig.json @@ -12,7 +12,7 @@ "name": "PDA(Android)交互命令", "pluginType": "command", "guid": "{16B8DF69-1379-41C1-9194-BE89BAF8BB32}", - "version": "1.22.0.0", + "version": "1.23.0.0", "dependenceVersion": "8.0.0.0", "bundleJavaScript": true, "bundleCSS": true -- Gitee From 59672fb1320cea9202c227757ffca09cb123cdc4 Mon Sep 17 00:00:00 2001 From: NathanGuo Date: Tue, 18 Aug 2026 15:35:04 +0800 Subject: [PATCH 39/71] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E5=BC=82=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AndroidPDACommand.csproj | 3 + PluginConfig.json | 3 +- Resources/AndroidPDACommand.js | 439 ++++----------------- Resources/OfflinePlusExportProgress.js | 504 +++++++++++++++++++++++++ 4 files changed, 579 insertions(+), 370 deletions(-) create mode 100644 Resources/OfflinePlusExportProgress.js diff --git a/AndroidPDACommand.csproj b/AndroidPDACommand.csproj index fe1c5dd..0ec5be3 100644 --- a/AndroidPDACommand.csproj +++ b/AndroidPDACommand.csproj @@ -139,6 +139,9 @@ + + PreserveNewest + PreserveNewest diff --git a/PluginConfig.json b/PluginConfig.json index db67877..1775e55 100644 --- a/PluginConfig.json +++ b/PluginConfig.json @@ -3,6 +3,7 @@ "AndroidPDACommand.dll" ], "javascript": [ + "Resources/OfflinePlusExportProgress.js", "Resources/AndroidPDACommand.js", "Resources/LPAPI-0.4.20181022.js" ], @@ -16,4 +17,4 @@ "dependenceVersion": "8.0.0.0", "bundleJavaScript": true, "bundleCSS": true -} \ No newline at end of file +} diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 406049b..d313aff 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -37,7 +37,7 @@ var HAC_GenerateCellInfo = function (context, formula) { return JSON.stringify(cellLocation); }; -var HAC_GenerateCallbackTicket = function (context, onSuccess, debugInfo) { +var HAC_GenerateCallbackTicket = function (context, onSuccess, debugInfo, onError) { if (!window.HAC) { HAC_CallFunctionOutOfHAC(debugInfo || "window.HAC is undefined."); } else { @@ -51,6 +51,9 @@ var HAC_GenerateCallbackTicket = function (context, onSuccess, debugInfo) { } window.HAC.registryCallback(ticket, onSuccess, function (error) { + if (onError) { + onError(error); + } context.CommandExecutor.excuteCommand(context.CommandParam.CommandList, { runTimePageName: context.CommandExecutingInfo.runTimePageName, commandID: new Date().valueOf().toString(), @@ -101,370 +104,7 @@ var HAC_DataUrlToFile = function (dataUrl, fileName) { 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; - } -}; - -/** - * 批量离线附件上传进度显示组件 - 支持多行显示多个表单状态 - */ -var HAC_BatchUploadProgress = { - element: null, - title: null, - countLabel: null, - listContainer: null, - summaryLabel: null, - currentTitle: null, - percentLabel: null, - fill: null, - metaLeft: null, - metaRight: null, - confirmButton: null, - itemMap: {}, - preventScrollHandler: null, - buttonClickHandler: null, - confirmHandler: null, - bodyOverflow: null, - documentOverflow: null, - ensure: function (itemCount) { - 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:#fff;display:flex;align-items:stretch;justify-content:center;font-family:Arial,'Microsoft YaHei',sans-serif;touch-action:none;overscroll-behavior:contain;box-sizing:border-box;"; - root.innerHTML = "" + - "
" + - "
" + - "
" + - "
批量导出离线表单
" + - "
批量上传已开始,状态会按处理进度实时更新。
" + - "
" + - "
" + - "
" + - "
" + - "正在导出:" + - "" + - "
" + - "0%" + - "
" + - "
" + - "
" + - "" + - "" + - "
" + - "
" + - "
" + - "
" + - "

单据列表

" + - "" + - "
" + - "
" + - "
" + - "
" + - "" + - "
" + - "
" + - "
"; - 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) { - var list = root.querySelector("[data-role='list']"); - if (list && list.contains(event.target)) { - return; - } - event.preventDefault(); - }; - root.addEventListener("touchmove", this.preventScrollHandler, { passive: false }); - document.body.appendChild(root); - this.element = root; - this.title = root.querySelector("[data-role='title']"); - this.countLabel = root.querySelector("[data-role='count']"); - this.listContainer = root.querySelector("[data-role='list']"); - this.summaryLabel = root.querySelector("[data-role='summary-label']"); - this.currentTitle = root.querySelector("[data-role='current-title']"); - this.percentLabel = root.querySelector("[data-role='percent']"); - this.fill = root.querySelector("[data-role='fill']"); - this.metaLeft = root.querySelector("[data-role='meta-left']"); - this.metaRight = root.querySelector("[data-role='meta-right']"); - this.confirmButton = root.querySelector("[data-role='confirm']"); - this.buttonClickHandler = function () { - if (!this.confirmButton || this.confirmButton.disabled) { - return; - } - var confirmHandler = this.confirmHandler; - this.close(); - if (confirmHandler) { - confirmHandler(); - } - }.bind(this); - this.confirmButton.addEventListener("click", this.buttonClickHandler); - this.refreshCount(itemCount || 0); - this.updateSummary({ - percent: 0, - title: "准备导出", - metaLeft: "正在准备附件", - metaRight: "" - }); - }, - refreshCount: function (itemCount) { - if (!this.countLabel) { - return; - } - var count = itemCount || Object.keys(this.itemMap).length; - this.countLabel.textContent = "共 " + count + " 项"; - }, - renderStatus: function (statusIcon, state) { - if (!statusIcon) { - return; - } - switch (state) { - case 'processing': - statusIcon.style.color = "#2f7df6"; - statusIcon.innerHTML = ""; - break; - case 'completed': - statusIcon.style.color = "#52c41a"; - statusIcon.innerHTML = ""; - break; - case 'error': - statusIcon.style.color = "#ff4d4f"; - statusIcon.innerHTML = ""; - break; - default: - statusIcon.style.color = "#98a2b3"; - statusIcon.innerHTML = ""; - break; - } - }, - updateSummary: function (options) { - this.ensure(); - options = options || {}; - if (options.percent !== undefined) { - var percent = Math.max(0, Math.min(100, options.percent || 0)); - this.fill.style.width = percent.toFixed(1) + "%"; - this.percentLabel.textContent = Math.floor(percent) + "%"; - } - if (options.title !== undefined) { - this.currentTitle.textContent = options.title || "离线表单"; - } - if (options.metaLeft !== undefined) { - this.metaLeft.textContent = options.metaLeft || ""; - } - if (options.metaRight !== undefined) { - this.metaRight.textContent = options.metaRight || ""; - } - if (options.label !== undefined) { - this.summaryLabel.textContent = options.label || ""; - } - }, - finish: function (options) { - options = options || {}; - if (!this.element) { - if (options.onConfirm) { - options.onConfirm(); - } - return; - } - this.confirmHandler = options.onConfirm || null; - if (options.success === false) { - this.updateSummary({ - label: "导出结果:", - title: "处理完成", - metaLeft: "处理失败", - metaRight: options.error || "请查看失败项" - }); - } else { - this.updateSummary({ - label: "导出结果:", - percent: 100, - title: "处理完成", - metaLeft: "已完成全部动作", - metaRight: "可以关闭页面" - }); - } - if (this.confirmButton) { - this.confirmButton.disabled = false; - this.confirmButton.textContent = "确认"; - this.confirmButton.style.background = "#2f7df6"; - this.confirmButton.style.opacity = "1"; - this.confirmButton.style.cursor = "pointer"; - } - }, - /** - * 初始化表单项 - * @param {*} itemKey 表单项唯一标识 - * @param {*} itemTitle 表单显示标题 - */ - initItem: function (itemKey, itemTitle) { - this.ensure(); - if (this.itemMap[itemKey]) { - return; - } - - var itemDiv = document.createElement("div"); - itemDiv.style.cssText = "display:flex;align-items:center;justify-content:space-between;gap:14px;padding:14px 2px;border-bottom:1px solid #e4e8f0;background:#fff;"; - itemDiv.innerHTML = "
" + - "" + - "" + - "
" + - "
"; - - this.listContainer.appendChild(itemDiv); - this.itemMap[itemKey] = { - element: itemDiv, - statusIcon: itemDiv.querySelector("[data-role='status']"), - title: itemDiv.querySelector("[data-role='title']"), - progress: itemDiv.querySelector("[data-role='progress']"), - baseTitle: itemTitle || "离线表单", - state: 'pending' - }; - this.itemMap[itemKey].title.textContent = itemTitle || "离线表单"; - this.itemMap[itemKey].progress.textContent = "等待处理..."; - this.renderStatus(this.itemMap[itemKey].statusIcon, 'pending'); - this.refreshCount(); - }, - /** - * 更新表单项状态 - * @param {*} itemKey 表单项唯一标识 - * @param {*} options 状态选项 { state, progress, detail, titleSuffix } - */ - updateItem: function (itemKey, options) { - this.ensure(); - var item = this.itemMap[itemKey]; - if (!item) { - return; - } - - if (options.state) { - item.state = options.state; - this.renderStatus(item.statusIcon, options.state); - } - if (options.detail !== undefined) { - item.progress.textContent = options.detail; - } - - if (options.titleSuffix !== undefined) { - item.title.textContent = item.baseTitle + options.titleSuffix; - } - - if (options.progress !== undefined) { - if (item.state !== 'completed' && item.state !== 'error') { - item.progress.textContent = "处理中: " + Math.floor(options.progress) + "%"; - } - } - }, - /** - * 标记表单项完成 - * @param {*} itemKey 表单项唯一标识 - */ - completeItem: function (itemKey) { - this.updateItem(itemKey, { state: 'completed', detail: '已完成' }); - }, - /** - * 标记表单项错误 - * @param {*} itemKey 表单项唯一标识 - * @param {*} error 错误信息 - */ - errorItem: function (itemKey, error) { - this.updateItem(itemKey, { state: 'error', detail: error || '处理失败' }); - }, - close: function () { - if (this.element && this.preventScrollHandler) { - this.element.removeEventListener("touchmove", this.preventScrollHandler); - } - if (this.confirmButton && this.buttonClickHandler) { - this.confirmButton.removeEventListener("click", this.buttonClickHandler); - } - 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.title = null; - this.countLabel = null; - this.listContainer = null; - this.summaryLabel = null; - this.currentTitle = null; - this.percentLabel = null; - this.fill = null; - this.metaLeft = null; - this.metaRight = null; - this.confirmButton = null; - this.itemMap = {}; - this.preventScrollHandler = null; - this.buttonClickHandler = null; - this.confirmHandler = null; - this.bodyOverflow = null; - this.documentOverflow = null; - } -}; /** * 将文件上传到服务器临时目录,并返回服务器上的文件标识 * @param {*} file @@ -3757,7 +3397,7 @@ function HAC_OfflinePlusValidatePatternJson(patternJson) { function validateNonNegativeNumber(value, path) { if (value !== undefined && value !== null && value !== "" && (typeof value !== "number" || !isFinite(value) || value < 0)) { - return fail(path, "必须是大于或等于0的数字"); + return fail(path, "必须是大于或等于0的数字:" + value); } return null; } @@ -3911,6 +3551,7 @@ function HAC_OfflinePlusValidatePatternJson(patternJson) { return fail(stepPath + ".title", "不能为空"); } if (!Array.isArray(step.items) || step.items.length === 0) { + console.log(Array.isArray(step.items) + "-" + step.items.length) return fail(stepPath + ".items", "必须是非空数组"); } for (var itemIndex = 0; itemIndex < step.items.length; itemIndex++) { @@ -4037,9 +3678,18 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { var action = params.Action || "GetPatterns"; if (action === "ExportRecords") { + if (!HAC_OfflineExportExecution.begin()) { + return; + } var projectId = this.evaluateFormula(params.ProjectId); var fileUploadLimit = (params.ServerPropertiesId && params.ServerPropertiesId.FileUploadLimit) || ""; let me = this; + HAC_OfflineUploadProgress.update({ + percent: 0, + title: "正在上传离线附件", + detail: "正在读取设备上的离线数据", + speed: "" + }); let ticket = HAC_GenerateCallbackTicket(me, async function (payload, payload2) { try { var exportData = JSON.parse(payload); @@ -4071,13 +3721,31 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { }); } finally { HAC_OfflineUploadProgress.close(); + HAC_OfflineExportExecution.complete(); } - }, HAC_GetOfflinePlusDebugInfo("上传离线表单", "生成导出数据回调ticket")); + }, HAC_GetOfflinePlusDebugInfo("上传离线表单", "生成导出数据回调ticket"), function () { + HAC_OfflineUploadProgress.close(); + HAC_OfflineExportExecution.complete(); + }); + + if (!ticket) { + HAC_OfflineUploadProgress.close(); + HAC_OfflineExportExecution.complete(); + return; + } if (window.offlinePlus && window.offlinePlus.offlinePlusExportRecordsAsync) { - window.offlinePlus.offlinePlusExportRecordsAsync(projectId, ticket); + try { + window.offlinePlus.offlinePlusExportRecordsAsync(projectId, ticket); + } catch (e) { + HAC_OfflineUploadProgress.close(); + HAC_OfflineExportExecution.complete(); + throw e; + } } else { HAC_CallFunctionOutOfHAC(HAC_GetOfflinePlusDebugInfo("上传离线表单", "调用offlinePlusExportRecordsAsync")); + HAC_OfflineUploadProgress.close(); + HAC_OfflineExportExecution.complete(); } return; } @@ -4160,8 +3828,18 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { } if (action === "BatchExportRecords") { + if (!HAC_OfflineExportExecution.begin()) { + return; + } var fileUploadLimit = (params.ServerPropertiesId && params.ServerPropertiesId.FileUploadLimit) || ""; let me = this; + HAC_BatchUploadProgress.ensure(0); + HAC_BatchUploadProgress.updateSummary({ + percent: 0, + title: "准备导出", + metaLeft: "正在读取设备数据", + metaRight: "" + }); let ticket = HAC_GenerateCallbackTicket(me, async function (payload, payload2) { var batchExportError = ""; var batchExportPayload = payload; @@ -4177,6 +3855,7 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { batchExportError = e ? e.toString() : "批量导出离线表单数据失败。"; } var continueBatchExport = function () { + HAC_OfflineExportExecution.complete(); if (batchExportSuccess) { HAC_ReturnToParam(params.ExportResult, batchExportPayload); me.CommandExecutor.excuteCommand(me.CommandParam.CommandList, { @@ -4207,12 +3886,34 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { error: batchExportError, onConfirm: continueBatchExport }); - }, HAC_GetOfflinePlusDebugInfo("批量导出离线表单", "生成批量导出回调ticket")); + }, HAC_GetOfflinePlusDebugInfo("批量导出离线表单", "生成批量导出回调ticket"), function (error) { + HAC_BatchUploadProgress.finish({ + success: false, + error: error, + onConfirm: function () { + HAC_OfflineExportExecution.complete(); + } + }); + }); + + if (!ticket) { + HAC_BatchUploadProgress.close(); + HAC_OfflineExportExecution.complete(); + return; + } if (window.offlinePlus && window.offlinePlus.offlinePlusExportMultipleRecordsAsync) { - window.offlinePlus.offlinePlusExportMultipleRecordsAsync(ticket); + try { + window.offlinePlus.offlinePlusExportMultipleRecordsAsync(ticket); + } catch (e) { + HAC_BatchUploadProgress.close(); + HAC_OfflineExportExecution.complete(); + throw e; + } } else { HAC_CallFunctionOutOfHAC(HAC_GetOfflinePlusDebugInfo("批量导出离线表单", "调用offlinePlusExportMultipleRecordsAsync")); + HAC_BatchUploadProgress.close(); + HAC_OfflineExportExecution.complete(); } return; } diff --git a/Resources/OfflinePlusExportProgress.js b/Resources/OfflinePlusExportProgress.js new file mode 100644 index 0000000..2012c63 --- /dev/null +++ b/Resources/OfflinePlusExportProgress.js @@ -0,0 +1,504 @@ +/** + * 离线表单导出进度与执行状态组件。 + * 此文件必须先于 AndroidPDACommand.js 加载。 + */ +var HAC_OfflineExportExecution = { + isRunning: false, + begin: function () { + if (this.isRunning) { + alert("上一个导出动作尚未完成,请等待上一个导出完成。"); + return false; + } + this.isRunning = true; + return true; + }, + complete: function () { + this.isRunning = false; + } +}; +/** + * 离线附件上传进度显示组件 + */ +var HAC_OfflineUploadProgress = { + element: null, + panel: null, + collapseButton: null, + collapsedButton: null, + fill: null, + title: null, + detail: null, + speed: null, + preventScrollHandler: null, + collapseButtonHandler: null, + collapsedButtonHandler: null, + collapsed: false, + 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) { + if (this.collapsed) { + return; + } + event.preventDefault(); + }.bind(this); + root.addEventListener("touchmove", this.preventScrollHandler, { passive: false }); + document.body.appendChild(root); + this.element = root; + this.panel = root.querySelector("[data-role='panel']"); + this.collapseButton = root.querySelector("[data-role='collapse']"); + this.collapsedButton = root.querySelector("[data-role='collapsed']"); + 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']"); + this.collapseButtonHandler = function () { + this.collapse(); + }.bind(this); + this.collapsedButtonHandler = function () { + this.expand(); + }.bind(this); + this.collapseButton.addEventListener("click", this.collapseButtonHandler); + this.collapsedButton.addEventListener("click", this.collapsedButtonHandler); + }, + lockPage: function () { + document.body.style.overflow = "hidden"; + document.documentElement.style.overflow = "hidden"; + }, + unlockPage: function () { + document.body.style.overflow = this.bodyOverflow || ""; + document.documentElement.style.overflow = this.documentOverflow || ""; + }, + collapse: function () { + this.ensure(); + this.collapsed = true; + this.panel.style.display = "none"; + this.collapsedButton.style.display = "block"; + this.element.style.background = "transparent"; + this.element.style.pointerEvents = "none"; + this.unlockPage(); + }, + expand: function () { + this.ensure(); + this.collapsed = false; + this.panel.style.display = "block"; + this.collapsedButton.style.display = "none"; + this.element.style.background = "rgba(0,0,0,.28)"; + this.element.style.pointerEvents = "auto"; + this.lockPage(); + }, + 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 || ""; + this.collapsedButton.querySelector("[data-role='collapsed-title']").textContent = options.title || "正在上传离线附件"; + this.collapsedButton.querySelector("[data-role='collapsed-percent']").textContent = Math.floor(percent) + "%"; + }, + close: function () { + if (this.element && this.preventScrollHandler) { + this.element.removeEventListener("touchmove", this.preventScrollHandler); + } + if (this.collapseButton && this.collapseButtonHandler) { + this.collapseButton.removeEventListener("click", this.collapseButtonHandler); + } + if (this.collapsedButton && this.collapsedButtonHandler) { + this.collapsedButton.removeEventListener("click", this.collapsedButtonHandler); + } + if (this.element && this.element.parentNode) { + this.element.parentNode.removeChild(this.element); + } + this.unlockPage(); + this.element = null; + this.panel = null; + this.collapseButton = null; + this.collapsedButton = null; + this.fill = null; + this.title = null; + this.detail = null; + this.speed = null; + this.preventScrollHandler = null; + this.collapseButtonHandler = null; + this.collapsedButtonHandler = null; + this.collapsed = false; + this.bodyOverflow = null; + this.documentOverflow = null; + } +}; + +/** + * 批量离线附件上传进度显示组件 - 支持多行显示多个表单状态 + */ +var HAC_BatchUploadProgress = { + element: null, + panel: null, + collapseButton: null, + collapsedButton: null, + title: null, + countLabel: null, + listContainer: null, + summaryLabel: null, + currentTitle: null, + percentLabel: null, + fill: null, + metaLeft: null, + metaRight: null, + confirmButton: null, + itemMap: {}, + preventScrollHandler: null, + buttonClickHandler: null, + collapseButtonHandler: null, + collapsedButtonHandler: null, + confirmHandler: null, + collapsed: false, + bodyOverflow: null, + documentOverflow: null, + ensure: function (itemCount) { + 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:#fff;display:flex;align-items:stretch;justify-content:center;font-family:Arial,'Microsoft YaHei',sans-serif;touch-action:none;overscroll-behavior:contain;box-sizing:border-box;"; + root.innerHTML = "" + + "
" + + "
" + + "
" + + "
批量导出离线表单
" + + "
批量上传已开始,状态会按处理进度实时更新。
" + + "
" + + "
" + + "
" + + "
" + + "正在导出:" + + "" + + "
" + + "0%" + + "
" + + "
" + + "
" + + "" + + "" + + "
" + + "
" + + "
" + + "
" + + "

单据列表

" + + "" + + "
" + + "
" + + "
" + + "
" + + "" + + "
" + + "
" + + "
" + + ""; + 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) { + if (this.collapsed) { + return; + } + var list = root.querySelector("[data-role='list']"); + if (list && list.contains(event.target)) { + return; + } + event.preventDefault(); + }.bind(this); + root.addEventListener("touchmove", this.preventScrollHandler, { passive: false }); + document.body.appendChild(root); + this.element = root; + this.panel = root.querySelector("[data-role='panel']"); + this.collapseButton = root.querySelector("[data-role='collapse']"); + this.collapsedButton = root.querySelector("[data-role='collapsed']"); + this.title = root.querySelector("[data-role='title']"); + this.countLabel = root.querySelector("[data-role='count']"); + this.listContainer = root.querySelector("[data-role='list']"); + this.summaryLabel = root.querySelector("[data-role='summary-label']"); + this.currentTitle = root.querySelector("[data-role='current-title']"); + this.percentLabel = root.querySelector("[data-role='percent']"); + this.fill = root.querySelector("[data-role='fill']"); + this.metaLeft = root.querySelector("[data-role='meta-left']"); + this.metaRight = root.querySelector("[data-role='meta-right']"); + this.confirmButton = root.querySelector("[data-role='confirm']"); + this.buttonClickHandler = function () { + if (!this.confirmButton || this.confirmButton.disabled) { + return; + } + var confirmHandler = this.confirmHandler; + this.close(); + if (confirmHandler) { + confirmHandler(); + } + }.bind(this); + this.confirmButton.addEventListener("click", this.buttonClickHandler); + this.collapseButtonHandler = function () { + this.collapse(); + }.bind(this); + this.collapsedButtonHandler = function () { + this.expand(); + }.bind(this); + this.collapseButton.addEventListener("click", this.collapseButtonHandler); + this.collapsedButton.addEventListener("click", this.collapsedButtonHandler); + this.refreshCount(itemCount || 0); + this.updateSummary({ + percent: 0, + title: "准备导出", + metaLeft: "正在准备附件", + metaRight: "" + }); + }, + lockPage: function () { + document.body.style.overflow = "hidden"; + document.documentElement.style.overflow = "hidden"; + }, + unlockPage: function () { + document.body.style.overflow = this.bodyOverflow || ""; + document.documentElement.style.overflow = this.documentOverflow || ""; + }, + collapse: function () { + this.ensure(); + this.collapsed = true; + this.panel.style.display = "none"; + this.collapsedButton.style.display = "block"; + this.element.style.background = "transparent"; + this.element.style.pointerEvents = "none"; + this.unlockPage(); + }, + expand: function () { + this.ensure(); + this.collapsed = false; + this.panel.style.display = "flex"; + this.collapsedButton.style.display = "none"; + this.element.style.background = "#fff"; + this.element.style.pointerEvents = "auto"; + this.lockPage(); + }, + refreshCount: function (itemCount) { + if (!this.countLabel) { + return; + } + var count = itemCount || Object.keys(this.itemMap).length; + this.countLabel.textContent = "共 " + count + " 项"; + }, + renderStatus: function (statusIcon, state) { + if (!statusIcon) { + return; + } + switch (state) { + case 'processing': + statusIcon.style.color = "#2f7df6"; + statusIcon.innerHTML = ""; + break; + case 'completed': + statusIcon.style.color = "#52c41a"; + statusIcon.innerHTML = ""; + break; + case 'error': + statusIcon.style.color = "#ff4d4f"; + statusIcon.innerHTML = ""; + break; + default: + statusIcon.style.color = "#98a2b3"; + statusIcon.innerHTML = ""; + break; + } + }, + updateSummary: function (options) { + this.ensure(); + options = options || {}; + if (options.percent !== undefined) { + var percent = Math.max(0, Math.min(100, options.percent || 0)); + this.fill.style.width = percent.toFixed(1) + "%"; + this.percentLabel.textContent = Math.floor(percent) + "%"; + } + if (options.title !== undefined) { + this.currentTitle.textContent = options.title || "离线表单"; + this.collapsedButton.querySelector("[data-role='collapsed-title']").textContent = options.title || "离线表单"; + } + if (options.metaLeft !== undefined) { + this.metaLeft.textContent = options.metaLeft || ""; + } + if (options.metaRight !== undefined) { + this.metaRight.textContent = options.metaRight || ""; + } + if (options.label !== undefined) { + this.summaryLabel.textContent = options.label || ""; + } + if (options.percent !== undefined) { + this.collapsedButton.querySelector("[data-role='collapsed-percent']").textContent = Math.floor(percent) + "%"; + } + }, + finish: function (options) { + options = options || {}; + if (!this.element) { + if (options.onConfirm) { + options.onConfirm(); + } + return; + } + this.confirmHandler = options.onConfirm || null; + if (options.success === false) { + this.updateSummary({ + label: "导出结果:", + title: "处理完成", + metaLeft: "处理失败", + metaRight: options.error || "请查看失败项" + }); + } else { + this.updateSummary({ + label: "导出结果:", + percent: 100, + title: "处理完成", + metaLeft: "已完成全部动作", + metaRight: "可以关闭页面" + }); + } + if (this.confirmButton) { + this.confirmButton.disabled = false; + this.confirmButton.textContent = "确认"; + this.confirmButton.style.background = "#2f7df6"; + this.confirmButton.style.opacity = "1"; + this.confirmButton.style.cursor = "pointer"; + } + }, + /** + * 初始化表单项 + * @param {*} itemKey 表单项唯一标识 + * @param {*} itemTitle 表单显示标题 + */ + initItem: function (itemKey, itemTitle) { + this.ensure(); + if (this.itemMap[itemKey]) { + return; + } + + var itemDiv = document.createElement("div"); + itemDiv.style.cssText = "display:flex;align-items:center;justify-content:space-between;gap:18px;padding:17px 4px;border-bottom:1px solid #e4e8f0;background:#fff;"; + itemDiv.innerHTML = "
" + + "" + + "" + + "
" + + "
"; + + this.listContainer.appendChild(itemDiv); + this.itemMap[itemKey] = { + element: itemDiv, + statusIcon: itemDiv.querySelector("[data-role='status']"), + title: itemDiv.querySelector("[data-role='title']"), + progress: itemDiv.querySelector("[data-role='progress']"), + baseTitle: itemTitle || "离线表单", + state: 'pending' + }; + this.itemMap[itemKey].title.textContent = itemTitle || "离线表单"; + this.itemMap[itemKey].progress.textContent = "等待处理..."; + this.renderStatus(this.itemMap[itemKey].statusIcon, 'pending'); + this.refreshCount(); + }, + /** + * 更新表单项状态 + * @param {*} itemKey 表单项唯一标识 + * @param {*} options 状态选项 { state, progress, detail, titleSuffix } + */ + updateItem: function (itemKey, options) { + this.ensure(); + var item = this.itemMap[itemKey]; + if (!item) { + return; + } + + if (options.state) { + item.state = options.state; + this.renderStatus(item.statusIcon, options.state); + } + + if (options.detail !== undefined) { + item.progress.textContent = options.detail; + } + + if (options.titleSuffix !== undefined) { + item.title.textContent = item.baseTitle + options.titleSuffix; + } + + if (options.progress !== undefined) { + if (item.state !== 'completed' && item.state !== 'error') { + item.progress.textContent = "处理中: " + Math.floor(options.progress) + "%"; + } + } + }, + /** + * 标记表单项完成 + * @param {*} itemKey 表单项唯一标识 + */ + completeItem: function (itemKey) { + this.updateItem(itemKey, { state: 'completed', detail: '已完成' }); + }, + /** + * 标记表单项错误 + * @param {*} itemKey 表单项唯一标识 + * @param {*} error 错误信息 + */ + errorItem: function (itemKey, error) { + this.updateItem(itemKey, { state: 'error', detail: error || '处理失败' }); + }, + close: function () { + if (this.element && this.preventScrollHandler) { + this.element.removeEventListener("touchmove", this.preventScrollHandler); + } + if (this.confirmButton && this.buttonClickHandler) { + this.confirmButton.removeEventListener("click", this.buttonClickHandler); + } + if (this.collapseButton && this.collapseButtonHandler) { + this.collapseButton.removeEventListener("click", this.collapseButtonHandler); + } + if (this.collapsedButton && this.collapsedButtonHandler) { + this.collapsedButton.removeEventListener("click", this.collapsedButtonHandler); + } + if (this.element && this.element.parentNode) { + this.element.parentNode.removeChild(this.element); + } + this.unlockPage(); + this.element = null; + this.panel = null; + this.collapseButton = null; + this.collapsedButton = null; + this.title = null; + this.countLabel = null; + this.listContainer = null; + this.summaryLabel = null; + this.currentTitle = null; + this.percentLabel = null; + this.fill = null; + this.metaLeft = null; + this.metaRight = null; + this.confirmButton = null; + this.itemMap = {}; + this.preventScrollHandler = null; + this.buttonClickHandler = null; + this.collapseButtonHandler = null; + this.collapsedButtonHandler = null; + this.confirmHandler = null; + this.collapsed = false; + this.bodyOverflow = null; + this.documentOverflow = null; + } +}; -- Gitee From 23bbf072d668b37e6f709035790566566fa2f146 Mon Sep 17 00:00:00 2001 From: NathanGuo Date: Wed, 19 Aug 2026 10:17:31 +0800 Subject: [PATCH 40/71] =?UTF-8?q?=E7=AD=BE=E5=90=8D=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- OfflinePlusBuildPattern.cs | 8 +++++--- Resources/AndroidPDACommand.js | 16 +++++++++++++--- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/OfflinePlusBuildPattern.cs b/OfflinePlusBuildPattern.cs index e9ab83b..101e58e 100644 --- a/OfflinePlusBuildPattern.cs +++ b/OfflinePlusBuildPattern.cs @@ -84,8 +84,8 @@ namespace AndroidPDACommand public class OfflineFormNode : ObjectPropertyBase, ITreeNode { - public const string BaseItemTypeValueList = "textItem|passwordItem|selectItem|datePicker|timePicker|imageItem|fileItem"; - public const string BaseItemTypeDisplayList = "文本框|密码框|选择框|日期选择|时间选择|图片列表|文件上传"; + public const string BaseItemTypeValueList = "textItem|passwordItem|selectItem|datePicker|timePicker|imageItem|fileItem|signatureItem"; + public const string BaseItemTypeDisplayList = "文本框|密码框|选择框|日期选择|时间选择|图片列表|文件上传|签名"; public const string ItemTypeValueList = BaseItemTypeValueList + "|listItem"; public const string ItemTypeDisplayList = BaseItemTypeDisplayList + "|列表"; @@ -121,6 +121,7 @@ namespace AndroidPDACommand { "timePicker", CreateFieldVisibleProperties(nameof(Value), nameof(IncludeSeconds)) }, { "imageItem", CreateFieldVisibleProperties(nameof(MaxCount), nameof(AllowImageUpload), nameof(CompressionOptions), nameof(WatermarkOptions)) }, { "fileItem", CreateFieldVisibleProperties(nameof(FileItemConfig)) }, + { "signatureItem", CreateFieldVisibleProperties(nameof(Value), nameof(WatermarkOptions)) }, { "listItem", CreateFieldVisibleProperties(nameof(ListItemOptions)) } }; @@ -192,7 +193,8 @@ namespace AndroidPDACommand public ImageCompressionOptions CompressionOptions { get; set; } = new ImageCompressionOptions(); [ObjectProperty(ObjType = typeof(ImageWatermarkOptions))] - [DisplayName("拍照水印配置")] + [DisplayName("图片/签名水印配置")] + [Description("仅图片列表和签名类型生效。")] public ImageWatermarkOptions WatermarkOptions { get; set; } = new ImageWatermarkOptions(); [ObjectProperty(ObjType = typeof(FileItemConfig))] diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index d313aff..584d57e 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -3072,7 +3072,7 @@ function HAC_OfflinePlusCreateFormNodeBuilder(context) { return Object.keys(compression).length > 0 ? compression : undefined; } - function buildImageWatermark(options) { + function buildWatermark(options) { if (!options) { return undefined; } @@ -3196,7 +3196,7 @@ function HAC_OfflinePlusCreateFormNodeBuilder(context) { var options = {}; var maxCount = evaluate(node.MaxCount); var compression = buildImageCompression(node.CompressionOptions); - var watermark = buildImageWatermark(node.WatermarkOptions); + var watermark = buildWatermark(node.WatermarkOptions); if (maxCount !== undefined && maxCount !== null && maxCount !== "") { options.maxCount = maxCount; } @@ -3224,6 +3224,16 @@ function HAC_OfflinePlusCreateFormNodeBuilder(context) { } } }, + signatureItem: { + apply: function (field, node) { + var watermark = buildWatermark(node.WatermarkOptions); + if (watermark) { + field.options = { + watermark: watermark + }; + } + } + }, listItem: { apply: function (field, node) { var options = buildListItemOptions(node); @@ -3446,7 +3456,7 @@ function HAC_OfflinePlusValidatePatternJson(patternJson) { } itemIds[itemIdKey] = path + ".field.itemId"; - var itemTypes = ["textItem", "passwordItem", "selectItem", "datePicker", "timePicker", "imageItem", "fileItem", "listItem"]; + var itemTypes = ["textItem", "passwordItem", "selectItem", "datePicker", "timePicker", "imageItem", "fileItem", "signatureItem", "listItem"]; if (itemTypes.indexOf(field.itemType) < 0) { return fail(path + ".field.itemType", "是不支持的表单项类型"); } -- Gitee From 00f3ba3cc4c24fbb335bdf88609237c6b199d4d5 Mon Sep 17 00:00:00 2001 From: NathanGuo Date: Thu, 20 Aug 2026 11:11:16 +0800 Subject: [PATCH 41/71] =?UTF-8?q?=E6=9C=80=E5=B0=8F=E5=8D=95=E4=BD=8D?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Resources/AndroidPDACommand.js | 38 ++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 584d57e..f3538cd 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -3627,6 +3627,43 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { return Forguncy.Helper.SpecialPath.getFileDownloadUrl(fileId); } + function applyFieldUpdateTime(pattern) { + var now = new Date(); + var updateTime = (now.getTime() - now.getTimezoneOffset() * 60000) / 86400000 + 25569; + + function applyToNodes(nodes) { + if (!Array.isArray(nodes)) { + return; + } + + nodes.forEach(function (node) { + if (!node || typeof node !== "object") { + return; + } + + if (node.nodeType === "field" && node.field && typeof node.field === "object") { + node.field.updateTime = updateTime; + if (node.field.itemType === "listItem" && node.field.options) { + applyToNodes(node.field.options.children); + } + return; + } + + if (node.nodeType === "group") { + applyToNodes(node.children); + } + }); + } + + if (pattern && Array.isArray(pattern.steps)) { + pattern.steps.forEach(function (step) { + if (step && typeof step === "object") { + applyToNodes(step.items); + } + }); + } + } + var patternJson = evaluate(params.PatternJson); var validationResult = HAC_OfflinePlusValidatePatternJson(patternJson); if (!validationResult.isValid) { @@ -3660,6 +3697,7 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { } var manualPdfUrl = getManualPdfUrl(manualAttachmentValue); + applyFieldUpdateTime(patternParam); patternParam.ticket = ticket; finalPatternParamJson = JSON.stringify(patternParam, null, 2); -- Gitee From 3026dd6224fd823e8bbabfbf5e2fd969fe0bf6be Mon Sep 17 00:00:00 2001 From: NathanGuo Date: Thu, 20 Aug 2026 16:10:55 +0800 Subject: [PATCH 42/71] =?UTF-8?q?=E7=AD=BE=E5=90=8D=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- OfflinePlusBuildPattern.cs | 27 ++++++- Resources/AndroidPDACommand.js | 125 ++++++++++++++++++++++++++++++--- 2 files changed, 141 insertions(+), 11 deletions(-) diff --git a/OfflinePlusBuildPattern.cs b/OfflinePlusBuildPattern.cs index 101e58e..da8ea32 100644 --- a/OfflinePlusBuildPattern.cs +++ b/OfflinePlusBuildPattern.cs @@ -109,6 +109,7 @@ namespace AndroidPDACommand nameof(CompressionOptions), nameof(WatermarkOptions), nameof(FileItemConfig), + nameof(SignatureOptions), nameof(ListItemOptions) }; @@ -121,7 +122,7 @@ namespace AndroidPDACommand { "timePicker", CreateFieldVisibleProperties(nameof(Value), nameof(IncludeSeconds)) }, { "imageItem", CreateFieldVisibleProperties(nameof(MaxCount), nameof(AllowImageUpload), nameof(CompressionOptions), nameof(WatermarkOptions)) }, { "fileItem", CreateFieldVisibleProperties(nameof(FileItemConfig)) }, - { "signatureItem", CreateFieldVisibleProperties(nameof(Value), nameof(WatermarkOptions)) }, + { "signatureItem", CreateFieldVisibleProperties(nameof(Value), nameof(SignatureOptions)) }, { "listItem", CreateFieldVisibleProperties(nameof(ListItemOptions)) } }; @@ -193,14 +194,17 @@ namespace AndroidPDACommand public ImageCompressionOptions CompressionOptions { get; set; } = new ImageCompressionOptions(); [ObjectProperty(ObjType = typeof(ImageWatermarkOptions))] - [DisplayName("图片/签名水印配置")] - [Description("仅图片列表和签名类型生效。")] + [DisplayName("拍照水印配置")] public ImageWatermarkOptions WatermarkOptions { get; set; } = new ImageWatermarkOptions(); [ObjectProperty(ObjType = typeof(FileItemConfig))] [DisplayName("文件上传配置")] public FileItemConfig FileItemConfig { get; set; } = new FileItemConfig(); + [ObjectProperty(ObjType = typeof(SignatureItemOptions))] + [DisplayName("签名配置")] + public SignatureItemOptions SignatureOptions { get; set; } = new SignatureItemOptions(); + [ObjectProperty(ObjType = typeof(ListItemOptions))] [DisplayName("列表配置")] public ListItemOptions ListItemOptions { get; set; } = new ListItemOptions(); @@ -249,6 +253,7 @@ namespace AndroidPDACommand CompressionOptions = CompressionOptions, WatermarkOptions = WatermarkOptions, FileItemConfig = FileItemConfig, + SignatureOptions = SignatureOptions, ListItemOptions = ListItemOptions }; } @@ -303,6 +308,7 @@ namespace AndroidPDACommand CompressionOptions = CompressionOptions, WatermarkOptions = WatermarkOptions, FileItemConfig = FileItemConfig, + SignatureOptions = SignatureOptions, ListItemOptions = ListItemOptions }; } @@ -398,6 +404,21 @@ namespace AndroidPDACommand public object MaxFileSizeKb { get; set; } = 0; } + public class SignatureItemOptions : ObjectPropertyBase + { + [ListProperty] + [DisplayName("签名人员")] + [Description("按签名顺序配置人员,生成JSON中的options.users字符串数组。")] + public List Users { get; set; } = new List(); + } + + public class SignatureUser : ObjectPropertyBase + { + [FormulaProperty] + [DisplayName("人员")] + public object Name { get; set; } + } + public class ListItemOptions : ObjectPropertyBase { [FormulaProperty] diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index f3538cd..f6a624f 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -142,8 +142,88 @@ function HAC_UploadFileToTemp(file, uploadLimitId, onProgress) { xhr.send(formData); }); } +function HAC_GetOfflineRecordFieldValue(record, fieldId) { + var fieldValue = record && record.values && record.values[fieldId]; + if (fieldValue && typeof fieldValue === "object" && !Array.isArray(fieldValue) && + Object.prototype.hasOwnProperty.call(fieldValue, "value")) { + return fieldValue.value; + } + return fieldValue; +} + +function HAC_SetOfflineRecordFieldValue(record, fieldId, value) { + var fieldValue = record && record.values && record.values[fieldId]; + if (fieldValue && typeof fieldValue === "object" && !Array.isArray(fieldValue) && + Object.prototype.hasOwnProperty.call(fieldValue, "value")) { + // 只替换实际值,保留图片等字段的整体更新时间和其它元数据。 + fieldValue.value = value; + } else { + record.values[fieldId] = value; + } +} + +function HAC_ParseOfflineSignatureValues(record, fieldId) { + var fieldValue = HAC_GetOfflineRecordFieldValue(record, fieldId); + if (Array.isArray(fieldValue)) { + return fieldValue.slice(); + } + if (typeof fieldValue !== "string" || fieldValue.trim() === "") { + return []; + } + + try { + var values = JSON.parse(fieldValue); + return Array.isArray(values) ? values : []; + } catch (e) { + return []; + } +} + +function HAC_GetOfflineSignatureAttachmentIndex(record, attachment, fieldId) { + var path = attachment && attachment.path; + if (!Array.isArray(path) || path.length < 3) { + return -1; + } + + var signatureIndex = Number(path[2]); + if (!isFinite(signatureIndex) || signatureIndex < 0 || Math.floor(signatureIndex) !== signatureIndex) { + return -1; + } + + var signatureValues = HAC_ParseOfflineSignatureValues(record, fieldId); + var signatureValue = signatureValues[signatureIndex]; + var hasSignatureValue = signatureValue && typeof signatureValue === "object" && !Array.isArray(signatureValue) && + (Object.prototype.hasOwnProperty.call(signatureValue, "userName") || + Object.prototype.hasOwnProperty.call(signatureValue, "updateTime")); + var hasSignatureMetadata = attachment && attachment.updateTime !== undefined && attachment.updateTime !== null; + return hasSignatureValue || hasSignatureMetadata ? signatureIndex : -1; +} + +function HAC_ApplyUploadedSignatureValue(record, attachment, attachmentValue, fieldId, signatureIndex) { + var signatureValues = HAC_ParseOfflineSignatureValues(record, fieldId); + var oldSignatureValue = signatureValues[signatureIndex]; + var signatureValue = {}; + + if (oldSignatureValue && typeof oldSignatureValue === "object" && !Array.isArray(oldSignatureValue)) { + Object.keys(oldSignatureValue).forEach(function (key) { + signatureValue[key] = oldSignatureValue[key]; + }); + } + + if (!signatureValue.userName && attachment.originalName) { + signatureValue.userName = attachment.originalName; + } + signatureValue.fileName = attachmentValue; + if (attachment.updateTime !== undefined && attachment.updateTime !== null) { + signatureValue.updateTime = attachment.updateTime; + } + + signatureValues[signatureIndex] = signatureValue; + HAC_SetOfflineRecordFieldValue(record, fieldId, JSON.stringify(signatureValues)); +} + /** - * 将上传后的附件值应用到记录中,并更新记录的字段值 + * 将上传后的附件值应用到记录中。普通附件保留字段整体更新时间;签名附件额外保留每张签名的更新时间。 */ function HAC_ApplyUploadedAttachmentValue(record, attachment, attachmentValue, uploadedValues) { if (!record || !record.values || !attachment) { @@ -156,12 +236,18 @@ function HAC_ApplyUploadedAttachmentValue(record, attachment, attachmentValue, u return; } + var signatureIndex = HAC_GetOfflineSignatureAttachmentIndex(record, attachment, fieldId); + if (signatureIndex >= 0) { + HAC_ApplyUploadedSignatureValue(record, attachment, attachmentValue, fieldId, signatureIndex); + return; + } + var key = recordId + "|" + fieldId; if (!uploadedValues[key]) { uploadedValues[key] = []; } uploadedValues[key].push(attachmentValue); - record.values[fieldId] = uploadedValues[key].join("|"); + HAC_SetOfflineRecordFieldValue(record, fieldId, uploadedValues[key].join("|")); } function HAC_GetOfflineAttachmentRecordId(attachment) { @@ -300,7 +386,6 @@ async function HAC_ProcessBatchExportAttachments(exportDataArray, uploadLimitId) return exportDataArray; } - var uploadedValues = {}; var currentAttachmentIndex = 0; var completedAttachmentCount = 0; @@ -321,6 +406,7 @@ async function HAC_ProcessBatchExportAttachments(exportDataArray, uploadLimitId) var projectId = exportItem.projectId; var records = exportItem.records || []; var attachments = exportItem.attachments || []; + var uploadedValues = {}; var currentItemTitle = exportItem.projectId || ("离线表单 " + (itemIndex + 1)); if (!attachments || attachments.length === 0) { @@ -3072,7 +3158,7 @@ function HAC_OfflinePlusCreateFormNodeBuilder(context) { return Object.keys(compression).length > 0 ? compression : undefined; } - function buildWatermark(options) { + function buildImageWatermark(options) { if (!options) { return undefined; } @@ -3120,6 +3206,20 @@ function HAC_OfflinePlusCreateFormNodeBuilder(context) { return Object.keys(config).length > 0 ? config : undefined; } + function buildSignatureUsers(options) { + if (!options) { + return []; + } + + return getList(options.Users).map(function (user) { + return evaluate(user && user.Name); + }).filter(function (userName) { + return userName !== undefined && userName !== null && String(userName).trim() !== ""; + }).map(function (userName) { + return String(userName); + }); + } + function buildListItemOptions(node) { var options = {}; var listOptions = node.ListItemOptions || {}; @@ -3196,7 +3296,7 @@ function HAC_OfflinePlusCreateFormNodeBuilder(context) { var options = {}; var maxCount = evaluate(node.MaxCount); var compression = buildImageCompression(node.CompressionOptions); - var watermark = buildWatermark(node.WatermarkOptions); + var watermark = buildImageWatermark(node.WatermarkOptions); if (maxCount !== undefined && maxCount !== null && maxCount !== "") { options.maxCount = maxCount; } @@ -3226,10 +3326,10 @@ function HAC_OfflinePlusCreateFormNodeBuilder(context) { }, signatureItem: { apply: function (field, node) { - var watermark = buildWatermark(node.WatermarkOptions); - if (watermark) { + var users = buildSignatureUsers(node.SignatureOptions); + if (users.length > 0) { field.options = { - watermark: watermark + users: users }; } } @@ -3488,6 +3588,15 @@ function HAC_OfflinePlusValidatePatternJson(patternJson) { return fail(optionPath + ".label", "不能为空"); } } + } else if (field.itemType === "signatureItem") { + if (!Array.isArray(options.users) || options.users.length === 0) { + return fail(path + ".field.options.users", "必须是非空数组"); + } + for (var userIndex = 0; userIndex < options.users.length; userIndex++) { + if (typeof options.users[userIndex] !== "string" || isBlank(options.users[userIndex])) { + return fail(path + ".field.options.users[" + userIndex + "]", "必须是非空字符串"); + } + } } else if (field.itemType === "listItem") { if (!Array.isArray(options.children) || options.children.length === 0) { return fail(path + ".field.options.children", "必须是非空数组"); -- Gitee From 77d72abada00b6bc150767ceb8184beac2267aa6 Mon Sep 17 00:00:00 2001 From: NathanGuo Date: Fri, 21 Aug 2026 10:17:34 +0800 Subject: [PATCH 43/71] =?UTF-8?q?=E6=8A=BD=E7=A6=BB=E4=B8=8B=E8=BD=BD?= =?UTF-8?q?=E7=A6=BB=E7=BA=BF=E8=A1=A8=E5=8D=95=E8=AF=B4=E6=98=8EPDF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AndroidPDACommand.csproj | 1 + OfflinePlusAddPattern_Async.cs | 5 -- OfflinePlusDownloadManualPdf_Async.cs | 29 ++++++++++ Resources/AndroidPDACommand.js | 76 ++++++++++++++++++++------- 4 files changed, 87 insertions(+), 24 deletions(-) create mode 100644 OfflinePlusDownloadManualPdf_Async.cs diff --git a/AndroidPDACommand.csproj b/AndroidPDACommand.csproj index 0ec5be3..06ad00e 100644 --- a/AndroidPDACommand.csproj +++ b/AndroidPDACommand.csproj @@ -50,6 +50,7 @@ + diff --git a/OfflinePlusAddPattern_Async.cs b/OfflinePlusAddPattern_Async.cs index 8f7612d..75e7dc3 100644 --- a/OfflinePlusAddPattern_Async.cs +++ b/OfflinePlusAddPattern_Async.cs @@ -15,11 +15,6 @@ namespace AndroidPDACommand [Description("由“构建离线表单”命令生成的表单JSON。")] public object PatternJson { get; set; } - [FormulaProperty] - [DisplayName("手册附件单元格")] - [Description("选择保存 PDF 手册附件的单元格。下载离线表单时会把 PDF 手册随表单一起保存到离线设备。")] - public object ManualAttachmentCell { get; set; } - [FormulaProperty] [DisplayName("员工签名单元格")] [Description("选择保存员工签名附件的单元格。下载离线表单时会把签名文件随表单一起保存到离线设备。")] diff --git a/OfflinePlusDownloadManualPdf_Async.cs b/OfflinePlusDownloadManualPdf_Async.cs new file mode 100644 index 0000000..1c127ab --- /dev/null +++ b/OfflinePlusDownloadManualPdf_Async.cs @@ -0,0 +1,29 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using GrapeCity.Forguncy.Commands; +using GrapeCity.Forguncy.Plugin; + +namespace AndroidPDACommand +{ + [Icon("pack://application:,,,/AndroidPDACommand;component/Resources/Icon_PDF.png")] + [Category("活字格安卓容器(HAC)")] + public class OfflinePlusDownloadManualPdf_Async : BaseAsyncCommand + { + [Required] + [FormulaProperty] + [DisplayName("项目编号")] + [Description("需要绑定说明 PDF 的离线表单项目编号。")] + public object PatternId { get; set; } + + [Required] + [FormulaProperty] + [DisplayName("说明 PDF 附件单元格")] + [Description("选择保存说明 PDF 附件的单元格。APP 会下载该 PDF 并绑定到指定的离线表单项目。")] + public object ManualAttachmentCell { get; set; } + + public override string ToString() + { + return "下载离线表单说明PDF"; + } + } +} diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index f6a624f..d0f9f95 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -19,6 +19,7 @@ var HAC_GetOfflinePlusDebugInfo = function (commandName, stage) { "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.offlinePlusDownloadManualPdfAsync:" + (offlinePlus && offlinePlus.offlinePlusDownloadManualPdfAsync ? typeof offlinePlus.offlinePlusDownloadManualPdfAsync : "undefined"), "window.offlinePlus.offlinePlusGetPatternsAsync:" + (offlinePlus && offlinePlus.offlinePlusGetPatternsAsync ? typeof offlinePlus.offlinePlusGetPatternsAsync : "undefined"), "location:" + window.location.href ].join("\r\n"); @@ -76,6 +77,20 @@ var HAC_ReturnToParam = function (OutParamaterName, data) { console.log("OutParamaterName was not set, the value is: " + JSON.stringify(data)); } }; + +var HAC_GetOfflinePlusManualPdfUrl = function (manualAttachmentValue) { + if (!manualAttachmentValue) { + return ""; + } + + var fileId = (manualAttachmentValue + "").split("|")[0]; + if (!fileId) { + console.warn("说明 PDF 附件单元格没有文件标识。", manualAttachmentValue); + return ""; + } + + return Forguncy.Helper.SpecialPath.getFileDownloadUrl(fileId); +}; /** * 将DataURL转换为File对象 * @param {*} dataUrl @@ -3722,20 +3737,6 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { 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); - } - function applyFieldUpdateTime(pattern) { var now = new Date(); var updateTime = (now.getTime() - now.getTimezoneOffset() * 60000) / 86400000 + 25569; @@ -3781,9 +3782,6 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { } var patternParam = validationResult.value; - 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); @@ -3805,14 +3803,13 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { return; } - var manualPdfUrl = getManualPdfUrl(manualAttachmentValue); applyFieldUpdateTime(patternParam); patternParam.ticket = ticket; finalPatternParamJson = JSON.stringify(patternParam, null, 2); console.log(patternParam); if (window.offlinePlus && window.offlinePlus.offlinePlusAddPatternAsync) { - window.offlinePlus.offlinePlusAddPatternAsync(finalPatternParamJson, manualPdfUrl || "", signatureBase64 || ""); + window.offlinePlus.offlinePlusAddPatternAsync(finalPatternParamJson, "", signatureBase64 || ""); } else { HAC_CallFunctionOutOfHAC(HAC_GetOfflinePlusDebugInfo("下载离线表单", "调用offlinePlusAddPatternAsync")); } @@ -3824,6 +3821,47 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { Forguncy.CommandFactory.registerCommand("AndroidPDACommand.OfflinePlusAddPattern_Async, AndroidPDACommand", OfflinePlusAddPattern_Async_Command); +var OfflinePlusDownloadManualPdf_Async_Command = (function (_super) { + __extends(OfflinePlusDownloadManualPdf_Async_Command, _super); + function OfflinePlusDownloadManualPdf_Async_Command() { + return _super !== null && _super.apply(this, arguments) || this; + } + + OfflinePlusDownloadManualPdf_Async_Command.prototype.execute = function () { + var me = this; + var params = this.CommandParam; + var patternId = this.evaluateFormula(params.PatternId); + var manualAttachmentValue = this.evaluateFormula(params.ManualAttachmentCell); + var manualPdfUrl = HAC_GetOfflinePlusManualPdfUrl(manualAttachmentValue); + + var ticket = HAC_GenerateCallbackTicket(me, function (payload, payload2) { + me.CommandExecutor.excuteCommand(me.CommandParam.CommandList, { + runTimePageName: me.CommandExecutingInfo.runTimePageName, + commandID: new Date().valueOf().toString(), + initParams: { + "IsSuccess": true, + "Error": "" + }, + locationString: "执行window.offlinePlus.offlinePlusDownloadManualPdfAsync" + }); + }, HAC_GetOfflinePlusDebugInfo("下载绑定说明PDF", "生成回调ticket")); + if (!ticket) { + console.error(HAC_GetOfflinePlusDebugInfo("下载绑定说明PDF", "生成回调ticket失败")); + return; + } + + if (window.offlinePlus && window.offlinePlus.offlinePlusDownloadManualPdfAsync) { + window.offlinePlus.offlinePlusDownloadManualPdfAsync(patternId, manualPdfUrl, ticket); + } else { + HAC_CallFunctionOutOfHAC(HAC_GetOfflinePlusDebugInfo("下载绑定说明PDF", "调用offlinePlusDownloadManualPdfAsync")); + } + }; + + return OfflinePlusDownloadManualPdf_Async_Command; +}(Forguncy.CommandBase)); + +Forguncy.CommandFactory.registerCommand("AndroidPDACommand.OfflinePlusDownloadManualPdf_Async, AndroidPDACommand", OfflinePlusDownloadManualPdf_Async_Command); + var OfflinePlusGetPatterns_Async_Command = (function (_super) { __extends(OfflinePlusGetPatterns_Async_Command, _super); function OfflinePlusGetPatterns_Async_Command() { -- Gitee From 2a482e2b37e530d2c5878d704b72f45f9fccfb45 Mon Sep 17 00:00:00 2001 From: NathanGuo Date: Fri, 21 Aug 2026 14:21:09 +0800 Subject: [PATCH 44/71] radio --- OfflinePlusBuildPattern.cs | 12 +++++- Resources/AndroidPDACommand.js | 75 ++++++++++++++++++++++++++-------- 2 files changed, 67 insertions(+), 20 deletions(-) diff --git a/OfflinePlusBuildPattern.cs b/OfflinePlusBuildPattern.cs index da8ea32..0497b77 100644 --- a/OfflinePlusBuildPattern.cs +++ b/OfflinePlusBuildPattern.cs @@ -84,8 +84,8 @@ namespace AndroidPDACommand public class OfflineFormNode : ObjectPropertyBase, ITreeNode { - public const string BaseItemTypeValueList = "textItem|passwordItem|selectItem|datePicker|timePicker|imageItem|fileItem|signatureItem"; - public const string BaseItemTypeDisplayList = "文本框|密码框|选择框|日期选择|时间选择|图片列表|文件上传|签名"; + public const string BaseItemTypeValueList = "textItem|passwordItem|selectItem|radioItem|datePicker|timePicker|imageItem|fileItem|signatureItem"; + public const string BaseItemTypeDisplayList = "文本框|密码框|选择框|单选框|日期选择|时间选择|图片列表|文件上传|签名"; public const string ItemTypeValueList = BaseItemTypeValueList + "|listItem"; public const string ItemTypeDisplayList = BaseItemTypeDisplayList + "|列表"; @@ -103,6 +103,7 @@ namespace AndroidPDACommand nameof(Value), nameof(CheckOptions), nameof(SelectOptionsList), + nameof(RadioDirection), nameof(IncludeSeconds), nameof(MaxCount), nameof(AllowImageUpload), @@ -118,6 +119,7 @@ namespace AndroidPDACommand { "textItem", CreateFieldVisibleProperties(nameof(Value), nameof(CheckOptions)) }, { "passwordItem", CreateFieldVisibleProperties(nameof(Value), nameof(CheckOptions)) }, { "selectItem", CreateFieldVisibleProperties(nameof(Value), nameof(SelectOptionsList)) }, + { "radioItem", CreateFieldVisibleProperties(nameof(Value), nameof(RadioDirection), nameof(SelectOptionsList)) }, { "datePicker", CreateFieldVisibleProperties(nameof(Value)) }, { "timePicker", CreateFieldVisibleProperties(nameof(Value), nameof(IncludeSeconds)) }, { "imageItem", CreateFieldVisibleProperties(nameof(MaxCount), nameof(AllowImageUpload), nameof(CompressionOptions), nameof(WatermarkOptions)) }, @@ -180,6 +182,10 @@ namespace AndroidPDACommand [DisplayName("选则项")] public List SelectOptionsList { get; set; } + [DisplayName("排列方向")] + [ComboProperty(ValueList = "vertical|horizontal", DisplayList = "垂直|水平")] + public string RadioDirection { get; set; } = "horizontal"; + [FormulaProperty] [DisplayName("图片最大数量")] [Description("0表示不限制图片数量。")] @@ -248,6 +254,7 @@ namespace AndroidPDACommand IncludeSeconds = IncludeSeconds, CheckOptions = CheckOptions, SelectOptionsList = SelectOptionsList, + RadioDirection = RadioDirection, MaxCount = MaxCount, AllowImageUpload = AllowImageUpload, CompressionOptions = CompressionOptions, @@ -303,6 +310,7 @@ namespace AndroidPDACommand IncludeSeconds = IncludeSeconds, CheckOptions = CheckOptions, SelectOptionsList = SelectOptionsList, + RadioDirection = RadioDirection, MaxCount = MaxCount, AllowImageUpload = AllowImageUpload, CompressionOptions = CompressionOptions, diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index d0f9f95..5716550 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -3297,6 +3297,22 @@ function HAC_OfflinePlusCreateFormNodeBuilder(context) { } } }, + radioItem: { + apply: function (field, node) { + var options = {}; + var direction = node.RadioDirection || "horizontal"; + var selectOptions = buildSelectOptions(node.SelectOptionsList); + if (direction) { + options.direction = direction; + } + if (selectOptions.length > 0) { + options.selectOptions = selectOptions; + } + if (Object.keys(options).length > 0) { + field.options = options; + } + } + }, timePicker: { apply: function (field, node) { if (node.IncludeSeconds) { @@ -3527,7 +3543,30 @@ function HAC_OfflinePlusValidatePatternJson(patternJson) { return null; } - function validateNode(node, path, itemIds) { + function validateSelectOptions(selectOptions, path) { + if (!Array.isArray(selectOptions) || selectOptions.length === 0) { + return fail(path, "必须是非空数组"); + } + for (var optionIndex = 0; optionIndex < selectOptions.length; optionIndex++) { + var optionPath = path + "[" + optionIndex + "]"; + if (!isObject(selectOptions[optionIndex])) { + return fail(optionPath, "必须是对象"); + } + if (isBlank(selectOptions[optionIndex].value)) { + return fail(optionPath + ".value", "不能为空"); + } + if (isBlank(selectOptions[optionIndex].label)) { + return fail(optionPath + ".label", "不能为空"); + } + } + return null; + } + + function validateNode(node, path, itemIds, allowListItem) { + if (allowListItem === undefined) { + allowListItem = true; + } + if (!isObject(node)) { return fail(path, "必须是对象"); } @@ -3542,7 +3581,7 @@ function HAC_OfflinePlusValidatePatternJson(patternJson) { return fail(path + ".children", "必须是数组"); } for (var groupIndex = 0; groupIndex < node.children.length; groupIndex++) { - var groupError = validateNode(node.children[groupIndex], path + ".children[" + groupIndex + "]", itemIds); + var groupError = validateNode(node.children[groupIndex], path + ".children[" + groupIndex + "]", itemIds, allowListItem); if (groupError) { return groupError; } @@ -3571,7 +3610,10 @@ function HAC_OfflinePlusValidatePatternJson(patternJson) { } itemIds[itemIdKey] = path + ".field.itemId"; - var itemTypes = ["textItem", "passwordItem", "selectItem", "datePicker", "timePicker", "imageItem", "fileItem", "signatureItem", "listItem"]; + var itemTypes = ["textItem", "passwordItem", "selectItem", "radioItem", "datePicker", "timePicker", "imageItem", "fileItem", "signatureItem"]; + if (allowListItem) { + itemTypes.push("listItem"); + } if (itemTypes.indexOf(field.itemType) < 0) { return fail(path + ".field.itemType", "是不支持的表单项类型"); } @@ -3588,20 +3630,17 @@ function HAC_OfflinePlusValidatePatternJson(patternJson) { var options = field.options || {}; var numberError; if (field.itemType === "selectItem") { - if (!Array.isArray(options.selectOptions) || options.selectOptions.length === 0) { - return fail(path + ".field.options.selectOptions", "必须是非空数组"); + var selectError = validateSelectOptions(options.selectOptions, path + ".field.options.selectOptions"); + if (selectError) { + return selectError; } - for (var optionIndex = 0; optionIndex < options.selectOptions.length; optionIndex++) { - var optionPath = path + ".field.options.selectOptions[" + optionIndex + "]"; - if (!isObject(options.selectOptions[optionIndex])) { - return fail(optionPath, "必须是对象"); - } - if (isBlank(options.selectOptions[optionIndex].value)) { - return fail(optionPath + ".value", "不能为空"); - } - if (isBlank(options.selectOptions[optionIndex].label)) { - return fail(optionPath + ".label", "不能为空"); - } + } else if (field.itemType === "radioItem") { + if (options.direction !== undefined && ["horizontal", "vertical"].indexOf(options.direction) < 0) { + return fail(path + ".field.options.direction", "必须是horizontal或vertical"); + } + var radioError = validateSelectOptions(options.selectOptions, path + ".field.options.selectOptions"); + if (radioError) { + return radioError; } } else if (field.itemType === "signatureItem") { if (!Array.isArray(options.users) || options.users.length === 0) { @@ -3623,7 +3662,7 @@ function HAC_OfflinePlusValidatePatternJson(patternJson) { return numberError; } for (var listIndex = 0; listIndex < options.children.length; listIndex++) { - var listError = validateNode(options.children[listIndex], path + ".field.options.children[" + listIndex + "]", itemIds); + var listError = validateNode(options.children[listIndex], path + ".field.options.children[" + listIndex + "]", itemIds, false); if (listError) { return listError; } @@ -3689,7 +3728,7 @@ function HAC_OfflinePlusValidatePatternJson(patternJson) { return fail(stepPath + ".items", "必须是非空数组"); } for (var itemIndex = 0; itemIndex < step.items.length; itemIndex++) { - var itemError = validateNode(step.items[itemIndex], stepPath + ".items[" + itemIndex + "]", itemIds); + var itemError = validateNode(step.items[itemIndex], stepPath + ".items[" + itemIndex + "]", itemIds, true); if (itemError) { return itemError; } -- Gitee From ab93e01940ea1fb31708f2e9581c62b767322ff6 Mon Sep 17 00:00:00 2001 From: NathanGuo Date: Fri, 21 Aug 2026 17:38:13 +0800 Subject: [PATCH 45/71] 1.23.1build --- PluginConfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PluginConfig.json b/PluginConfig.json index 1775e55..5829942 100644 --- a/PluginConfig.json +++ b/PluginConfig.json @@ -13,7 +13,7 @@ "name": "PDA(Android)交互命令", "pluginType": "command", "guid": "{16B8DF69-1379-41C1-9194-BE89BAF8BB32}", - "version": "1.23.0.0", + "version": "1.23.1.0", "dependenceVersion": "8.0.0.0", "bundleJavaScript": true, "bundleCSS": true -- Gitee From a9467c2b6d07a1a83b98f5509a56bf8d9c272c9c Mon Sep 17 00:00:00 2001 From: NathanGuo Date: Tue, 1 Sep 2026 13:50:43 +0800 Subject: [PATCH 46/71] =?UTF-8?q?=E7=AD=BE=E5=90=8D=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- OfflinePlusBuildPattern.cs | 27 +++++++++++++++++++++++++++ PluginConfig.json | 2 +- Resources/AndroidPDACommand.js | 23 ++++++++++++++++++++++- 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/OfflinePlusBuildPattern.cs b/OfflinePlusBuildPattern.cs index 0497b77..83339f7 100644 --- a/OfflinePlusBuildPattern.cs +++ b/OfflinePlusBuildPattern.cs @@ -414,10 +414,37 @@ namespace AndroidPDACommand public class SignatureItemOptions : ObjectPropertyBase { + [DisplayName("使用人员数组公式")] + [Description("启用后直接使用下面公式返回的字符串数组作为签名人员。")] + public bool UseUsersFormula { get; set; } + [ListProperty] [DisplayName("签名人员")] [Description("按签名顺序配置人员,生成JSON中的options.users字符串数组。")] public List Users { get; set; } = new List(); + + [FormulaProperty] + [DisplayName("人员数组公式")] + [Description("返回签名人员字符串数组,例如:[\"张三\",\"李四\"]。")] + public object UsersFormula { get; set; } + + [FormulaProperty] + [DisplayName("免责声明")] + [Description("签名前展示的确认说明,生成JSON中的options.disclaimer。")] + public object Disclaimer { get; set; } + + public override bool GetDesignerPropertyVisible(string propertyName) + { + switch (propertyName) + { + case nameof(Users): + return !UseUsersFormula; + case nameof(UsersFormula): + return UseUsersFormula; + default: + return base.GetDesignerPropertyVisible(propertyName); + } + } } public class SignatureUser : ObjectPropertyBase diff --git a/PluginConfig.json b/PluginConfig.json index 5829942..85f3a6f 100644 --- a/PluginConfig.json +++ b/PluginConfig.json @@ -13,7 +13,7 @@ "name": "PDA(Android)交互命令", "pluginType": "command", "guid": "{16B8DF69-1379-41C1-9194-BE89BAF8BB32}", - "version": "1.23.1.0", + "version": "1.23.2.0", "dependenceVersion": "8.0.0.0", "bundleJavaScript": true, "bundleCSS": true diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 5716550..a8a36ad 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -3226,6 +3226,19 @@ function HAC_OfflinePlusCreateFormNodeBuilder(context) { return []; } + if (options.UseUsersFormula) { + return getList(evaluate(options.UsersFormula)).map(function (user) { + if (user && typeof user === "object" && !Array.isArray(user)) { + return evaluate(user.Name); + } + return evaluate(user); + }).filter(function (userName) { + return userName !== undefined && userName !== null && String(userName).trim() !== ""; + }).map(function (userName) { + return String(userName); + }); + } + return getList(options.Users).map(function (user) { return evaluate(user && user.Name); }).filter(function (userName) { @@ -3357,11 +3370,16 @@ function HAC_OfflinePlusCreateFormNodeBuilder(context) { }, signatureItem: { apply: function (field, node) { - var users = buildSignatureUsers(node.SignatureOptions); + var signatureOptions = node.SignatureOptions || {}; + var users = buildSignatureUsers(signatureOptions); + var disclaimer = evaluate(signatureOptions.Disclaimer); if (users.length > 0) { field.options = { users: users }; + if (disclaimer !== undefined && disclaimer !== null) { + field.options.disclaimer = String(disclaimer); + } } } }, @@ -3651,6 +3669,9 @@ function HAC_OfflinePlusValidatePatternJson(patternJson) { return fail(path + ".field.options.users[" + userIndex + "]", "必须是非空字符串"); } } + if (options.disclaimer !== undefined && typeof options.disclaimer !== "string") { + return fail(path + ".field.options.disclaimer", "必须是字符串"); + } } else if (field.itemType === "listItem") { if (!Array.isArray(options.children) || options.children.length === 0) { return fail(path + ".field.options.children", "必须是非空数组"); -- Gitee From 9fe9afdd4e743e869662e3837cd40f9315fd9480 Mon Sep 17 00:00:00 2001 From: NathanGuo Date: Thu, 3 Sep 2026 16:23:27 +0800 Subject: [PATCH 47/71] =?UTF-8?q?=E5=A1=AB=E6=8A=A5=E8=BF=9B=E5=BA=A6?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- OfflinePlusBuildPattern.cs | 16 ++++++++++++ Resources/AndroidPDACommand.js | 48 ++++++++++++++++++++++------------ 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/OfflinePlusBuildPattern.cs b/OfflinePlusBuildPattern.cs index 83339f7..43313cd 100644 --- a/OfflinePlusBuildPattern.cs +++ b/OfflinePlusBuildPattern.cs @@ -145,6 +145,14 @@ namespace AndroidPDACommand [DisplayName("默认折叠")] public bool DefaultCollapsed { get; set; } + [DisplayName("启用填报进度")] + [Description("仅步骤中的最外层节点生效。启用后该节点作为一个填报进度统计单位。")] + public bool EnableProgress { get; set; } + + [DisplayName("填报进度标识项")] + [Description("仅最外层分组的直接表单项生效。启用后该表单项作为该填报单位的完成标识。")] + public bool ProgressIdentifier { get; set; } + [FormulaProperty] [DisplayName("编号")] [Description("该表单项的唯一标识,全局唯一,无论是同一项目内,还是跨项目,都必须唯一,更建议使用项目编号作为前缀拼接;例如项目为Project01,则该表单项编号为Project01_Name")] @@ -227,6 +235,10 @@ namespace AndroidPDACommand return isText; case nameof(DefaultCollapsed): return isGroup; + case nameof(EnableProgress): + return isGroup; + case nameof(ProgressIdentifier): + return isField; default: if (FieldTypeControlledProperties.Contains(propertyName)) { @@ -245,6 +257,8 @@ namespace AndroidPDACommand NodeType = NodeType, Content = Content, DefaultCollapsed = DefaultCollapsed, + EnableProgress = EnableProgress, + ProgressIdentifier = ProgressIdentifier, ItemId = ItemId, ItemType = ItemType, Title = Title, @@ -301,6 +315,8 @@ namespace AndroidPDACommand NodeType = NodeType, Content = Content, DefaultCollapsed = DefaultCollapsed, + EnableProgress = EnableProgress, + ProgressIdentifier = ProgressIdentifier, ItemId = ItemId, ItemType = ItemType, Title = Title, diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index a8a36ad..cc739f4 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -3417,7 +3417,8 @@ function HAC_OfflinePlusCreateFormNodeBuilder(context) { return field; } - function buildNode(node) { + function buildNode(node, options) { + options = options || {}; var nodeType = node.NodeType || "group"; var children = getList(node.Children); var isListField = nodeType === "field" && node.ItemType === "listItem"; @@ -3426,38 +3427,47 @@ function HAC_OfflinePlusCreateFormNodeBuilder(context) { console.warn("离线表单节点不是分组,但包含子节点。", node); } + var result; if (nodeType === "field") { - return { + result = { nodeType: "field", title: node.Text, field: buildField(node) }; - } - - if (nodeType === "text") { - return { + } else if (nodeType === "text") { + result = { nodeType: "text", title: node.Text, content: evaluate(node.Content) }; + } else { + result = { + nodeType: "group", + title: node.Text, + defaultCollapsed: !!node.DefaultCollapsed, + children: buildNodes(children, { + allowProgressIdentifier: !!options.isStepRoot && !!node.EnableProgress + }) + }; } - return { - nodeType: "group", - title: node.Text, - defaultCollapsed: !!node.DefaultCollapsed, - children: buildNodes(children) - }; + if (options.isStepRoot && nodeType === "group" && node.EnableProgress) { + result.enableProgress = true; + } + if (nodeType === "field" && (options.isStepRoot || options.allowProgressIdentifier) && node.ProgressIdentifier) { + result.progressIdentifier = true; + } + return result; } - function buildNodes(nodes) { + function buildNodes(nodes, options) { return getList(nodes).map(function (node) { - return buildNode(node); + return buildNode(node, options); }); } function buildFormItem(nodes) { - var items = buildNodes(nodes); + var items = buildNodes(nodes, { isStepRoot: true }); if (items.length <= 1) { return items[0]; } @@ -3515,7 +3525,7 @@ var OfflinePlusBuildPattern_Command = (function (_super) { return { stepId: formNodeBuilder.evaluate(step.StepId), title: formNodeBuilder.evaluate(step.Title), - items: step.UseItemsFormula ? formNodeBuilder.evaluate(step.ItemsFormula) : formNodeBuilder.buildNodes(step.Items) + items: step.UseItemsFormula ? formNodeBuilder.evaluate(step.ItemsFormula) : formNodeBuilder.buildNodes(step.Items, { isStepRoot: true }) }; }); } @@ -3593,6 +3603,12 @@ function HAC_OfflinePlusValidatePatternJson(patternJson) { if (["group", "text", "field"].indexOf(nodeType) < 0) { return fail(path + ".nodeType", "必须是group、text或field"); } + if (node.enableProgress !== undefined && typeof node.enableProgress !== "boolean") { + return fail(path + ".enableProgress", "必须是布尔值"); + } + if (node.progressIdentifier !== undefined && typeof node.progressIdentifier !== "boolean") { + return fail(path + ".progressIdentifier", "必须是布尔值"); + } if (nodeType === "group") { if (!Array.isArray(node.children)) { -- Gitee From 41d2bfa22f49a4a03f350ac20a07a833e37daf1e Mon Sep 17 00:00:00 2001 From: NathanGuo Date: Fri, 4 Sep 2026 10:59:18 +0800 Subject: [PATCH 48/71] =?UTF-8?q?=E5=A1=AB=E6=8A=A5=E8=BF=9B=E5=BA=A6?= =?UTF-8?q?=E5=8F=AF=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- OfflinePlusBuildPattern.cs | 37 +++++++++++++++++++++++- Resources/AndroidPDACommand.js | 52 ++++++++++++++++++++++++++++++---- 2 files changed, 83 insertions(+), 6 deletions(-) diff --git a/OfflinePlusBuildPattern.cs b/OfflinePlusBuildPattern.cs index 43313cd..a31350c 100644 --- a/OfflinePlusBuildPattern.cs +++ b/OfflinePlusBuildPattern.cs @@ -142,6 +142,25 @@ namespace AndroidPDACommand [DisplayName("说明内容")] public object Content { get; set; } + [DisplayName("文本类型")] + [ComboProperty(ValueList = "plain|progress|document", DisplayList = "普通文本|填报进度|说明文档")] + public string TextMode { get; set; } = "plain"; + + [DefaultValue(true)] + [BoolProperty(IndentLevel = 1)] + [DisplayName("总填报项")] + public bool ShowProgressTotal { get; set; } = true; + + [DefaultValue(true)] + [BoolProperty(IndentLevel = 1)] + [DisplayName("已填报项")] + public bool ShowProgressCompleted { get; set; } = true; + + [DefaultValue(true)] + [BoolProperty(IndentLevel = 1)] + [DisplayName("完成率")] + public bool ShowProgressCompletionRate { get; set; } = true; + [DisplayName("默认折叠")] public bool DefaultCollapsed { get; set; } @@ -228,11 +247,19 @@ namespace AndroidPDACommand var isField = NodeType == "field"; var isText = NodeType == "text"; var isGroup = NodeType == "group"; + var isTextProgress = isText && TextMode == "progress"; + var isTextPlain = isText && TextMode != "progress" && TextMode != "document"; switch (propertyName) { - case nameof(Content): + case nameof(TextMode): return isText; + case nameof(Content): + return isTextPlain; + case nameof(ShowProgressTotal): + case nameof(ShowProgressCompleted): + case nameof(ShowProgressCompletionRate): + return isTextProgress; case nameof(DefaultCollapsed): return isGroup; case nameof(EnableProgress): @@ -256,6 +283,10 @@ namespace AndroidPDACommand Children = Children == null ? new List() : Children.ToList(), NodeType = NodeType, Content = Content, + TextMode = TextMode, + ShowProgressTotal = ShowProgressTotal, + ShowProgressCompleted = ShowProgressCompleted, + ShowProgressCompletionRate = ShowProgressCompletionRate, DefaultCollapsed = DefaultCollapsed, EnableProgress = EnableProgress, ProgressIdentifier = ProgressIdentifier, @@ -314,6 +345,10 @@ namespace AndroidPDACommand Children = Children == null ? new List() : Children.ToList(), NodeType = NodeType, Content = Content, + TextMode = TextMode, + ShowProgressTotal = ShowProgressTotal, + ShowProgressCompleted = ShowProgressCompleted, + ShowProgressCompletionRate = ShowProgressCompletionRate, DefaultCollapsed = DefaultCollapsed, EnableProgress = EnableProgress, ProgressIdentifier = ProgressIdentifier, diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index cc739f4..251544d 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -3435,11 +3435,32 @@ function HAC_OfflinePlusCreateFormNodeBuilder(context) { field: buildField(node) }; } else if (nodeType === "text") { - result = { - nodeType: "text", - title: node.Text, - content: evaluate(node.Content) - }; + var textMode = node.TextMode || "plain"; + if (textMode === "progress") { + result = { + nodeType: "text", + title: node.Text, + textMode: "progress", + progressDisplay: { + total: !!node.ShowProgressTotal, + completed: !!node.ShowProgressCompleted, + completionRate: !!node.ShowProgressCompletionRate + } + }; + } else if (textMode === "document") { + result = { + nodeType: "text", + title: node.Text, + textMode: "document" + }; + } else { + // Preserve the existing JSON shape for the default text mode. + result = { + nodeType: "text", + title: node.Text, + content: evaluate(node.Content) + }; + } } else { result = { nodeType: "group", @@ -3624,6 +3645,27 @@ function HAC_OfflinePlusValidatePatternJson(patternJson) { } if (nodeType === "text") { + var textMode = node.textMode || "plain"; + if (["plain", "progress", "document"].indexOf(textMode) < 0) { + return fail(path + ".textMode", "必须是plain、progress或document"); + } + if (textMode === "progress") { + if (!isObject(node.progressDisplay)) { + return fail(path + ".progressDisplay", "必须是对象"); + } + var progressDisplay = node.progressDisplay; + var progressDisplayProperties = ["total", "completed", "completionRate"]; + for (var progressDisplayIndex = 0; progressDisplayIndex < progressDisplayProperties.length; progressDisplayIndex++) { + var progressDisplayProperty = progressDisplayProperties[progressDisplayIndex]; + if (typeof progressDisplay[progressDisplayProperty] !== "boolean") { + return fail(path + ".progressDisplay." + progressDisplayProperty, "必须是布尔值"); + } + } + return null; + } + if (textMode === "document") { + return null; + } if (node.content === undefined || node.content === null) { return fail(path + ".content", "缺少说明内容"); } -- Gitee From ea126600f06db81ba7bd17a33bd78063b8499cde Mon Sep 17 00:00:00 2001 From: NathanGuo Date: Mon, 7 Sep 2026 09:08:35 +0800 Subject: [PATCH 49/71] =?UTF-8?q?=E6=97=A5=E6=9C=9F=E6=97=B6=E9=97=B4?= =?UTF-8?q?=E9=80=89=E6=8B=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- OfflinePlusBuildPattern.cs | 9 ++++++++- Resources/AndroidPDACommand.js | 17 ++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/OfflinePlusBuildPattern.cs b/OfflinePlusBuildPattern.cs index a31350c..5cc270f 100644 --- a/OfflinePlusBuildPattern.cs +++ b/OfflinePlusBuildPattern.cs @@ -104,6 +104,7 @@ namespace AndroidPDACommand nameof(CheckOptions), nameof(SelectOptionsList), nameof(RadioDirection), + nameof(IncludeTime), nameof(IncludeSeconds), nameof(MaxCount), nameof(AllowImageUpload), @@ -120,7 +121,7 @@ namespace AndroidPDACommand { "passwordItem", CreateFieldVisibleProperties(nameof(Value), nameof(CheckOptions)) }, { "selectItem", CreateFieldVisibleProperties(nameof(Value), nameof(SelectOptionsList)) }, { "radioItem", CreateFieldVisibleProperties(nameof(Value), nameof(RadioDirection), nameof(SelectOptionsList)) }, - { "datePicker", CreateFieldVisibleProperties(nameof(Value)) }, + { "datePicker", CreateFieldVisibleProperties(nameof(Value), nameof(IncludeTime)) }, { "timePicker", CreateFieldVisibleProperties(nameof(Value), nameof(IncludeSeconds)) }, { "imageItem", CreateFieldVisibleProperties(nameof(MaxCount), nameof(AllowImageUpload), nameof(CompressionOptions), nameof(WatermarkOptions)) }, { "fileItem", CreateFieldVisibleProperties(nameof(FileItemConfig)) }, @@ -196,6 +197,10 @@ namespace AndroidPDACommand [DisplayName("默认值")] public object Value { get; set; } + [DisplayName("包含时间")] + [Description("仅日期选择类型生效。启用后可同时选择日期和时间。")] + public bool IncludeTime { get; set; } + [DisplayName("包含秒")] [Description("仅时间选择类型生效。启用后可选择时分秒;关闭时使用系统原生时分选择器。")] public bool IncludeSeconds { get; set; } @@ -296,6 +301,7 @@ namespace AndroidPDACommand Hint = Hint, Required = Required, Value = Value, + IncludeTime = IncludeTime, IncludeSeconds = IncludeSeconds, CheckOptions = CheckOptions, SelectOptionsList = SelectOptionsList, @@ -358,6 +364,7 @@ namespace AndroidPDACommand Hint = Hint, Required = Required, Value = Value, + IncludeTime = IncludeTime, IncludeSeconds = IncludeSeconds, CheckOptions = CheckOptions, SelectOptionsList = SelectOptionsList, diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 251544d..ea28336 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -3326,6 +3326,13 @@ function HAC_OfflinePlusCreateFormNodeBuilder(context) { } } }, + datePicker: { + apply: function (field, node) { + field.options = { + includeTime: !!node.IncludeTime + }; + } + }, timePicker: { apply: function (field, node) { if (node.IncludeSeconds) { @@ -3705,7 +3712,15 @@ function HAC_OfflinePlusValidatePatternJson(patternJson) { var options = field.options || {}; var numberError; - if (field.itemType === "selectItem") { + if (field.itemType === "datePicker") { + if (options.includeTime !== undefined && typeof options.includeTime !== "boolean") { + return fail(path + ".field.options.includeTime", "必须是布尔值"); + } + } else if (field.itemType === "timePicker") { + if (options.includeSeconds !== undefined && typeof options.includeSeconds !== "boolean") { + return fail(path + ".field.options.includeSeconds", "必须是布尔值"); + } + } else if (field.itemType === "selectItem") { var selectError = validateSelectOptions(options.selectOptions, path + ".field.options.selectOptions"); if (selectError) { return selectError; -- Gitee From 5e8c07094c634fec91f6a12f683930fd97fed990 Mon Sep 17 00:00:00 2001 From: NathanGuo Date: Tue, 8 Sep 2026 10:43:01 +0800 Subject: [PATCH 50/71] =?UTF-8?q?=E5=A4=9A=E8=AF=B4=E6=98=8E=E6=96=87?= =?UTF-8?q?=E6=A1=A3=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- OfflinePlusDownloadManualPdf_Async.cs | 2 +- Resources/AndroidPDACommand.js | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/OfflinePlusDownloadManualPdf_Async.cs b/OfflinePlusDownloadManualPdf_Async.cs index 1c127ab..2930c44 100644 --- a/OfflinePlusDownloadManualPdf_Async.cs +++ b/OfflinePlusDownloadManualPdf_Async.cs @@ -18,7 +18,7 @@ namespace AndroidPDACommand [Required] [FormulaProperty] [DisplayName("说明 PDF 附件单元格")] - [Description("选择保存说明 PDF 附件的单元格。APP 会下载该 PDF 并绑定到指定的离线表单项目。")] + [Description("选择保存说明 PDF 附件的单元格。多个附件名称请使用英文竖线(|)分隔,APP 会下载全部 PDF 并绑定到指定的离线表单项目。")] public object ManualAttachmentCell { get; set; } public override string ToString() diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index ea28336..bd75ca9 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -80,16 +80,16 @@ var HAC_ReturnToParam = function (OutParamaterName, data) { var HAC_GetOfflinePlusManualPdfUrl = function (manualAttachmentValue) { if (!manualAttachmentValue) { - return ""; - } - - var fileId = (manualAttachmentValue + "").split("|")[0]; - if (!fileId) { - console.warn("说明 PDF 附件单元格没有文件标识。", manualAttachmentValue); - return ""; + return []; } - return Forguncy.Helper.SpecialPath.getFileDownloadUrl(fileId); + return (manualAttachmentValue + "").split("|").map(function (fileId) { + return fileId.trim(); + }).filter(function (fileId) { + return fileId !== ""; + }).map(function (fileId) { + return Forguncy.Helper.SpecialPath.getFileDownloadUrl(fileId); + }); }; /** * 将DataURL转换为File对象 -- Gitee From 88987d609b41db80577acb4597ff4180a3edbb2f Mon Sep 17 00:00:00 2001 From: NathanGuo Date: Tue, 8 Sep 2026 13:31:49 +0800 Subject: [PATCH 51/71] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=85=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- OfflinePlusAddPattern_Async.cs | 5 ----- OfflinePlusDownloadManualPdf_Async.cs | 2 +- Resources/AndroidPDACommand.js | 7 +------ 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/OfflinePlusAddPattern_Async.cs b/OfflinePlusAddPattern_Async.cs index 75e7dc3..e43cbe2 100644 --- a/OfflinePlusAddPattern_Async.cs +++ b/OfflinePlusAddPattern_Async.cs @@ -15,11 +15,6 @@ namespace AndroidPDACommand [Description("由“构建离线表单”命令生成的表单JSON。")] public object PatternJson { get; set; } - [FormulaProperty] - [DisplayName("员工签名单元格")] - [Description("选择保存员工签名附件的单元格。下载离线表单时会把签名文件随表单一起保存到离线设备。")] - public object SignatureAttachmentCell { get; set; } - public override string ToString() { return "下载离线表单"; diff --git a/OfflinePlusDownloadManualPdf_Async.cs b/OfflinePlusDownloadManualPdf_Async.cs index 2930c44..0e6bd74 100644 --- a/OfflinePlusDownloadManualPdf_Async.cs +++ b/OfflinePlusDownloadManualPdf_Async.cs @@ -17,7 +17,7 @@ namespace AndroidPDACommand [Required] [FormulaProperty] - [DisplayName("说明 PDF 附件单元格")] + [DisplayName("说明 PDF 附件")] [Description("选择保存说明 PDF 附件的单元格。多个附件名称请使用英文竖线(|)分隔,APP 会下载全部 PDF 并绑定到指定的离线表单项目。")] public object ManualAttachmentCell { get; set; } diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index bd75ca9..920a28c 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -3915,10 +3915,6 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { } var patternParam = validationResult.value; - 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, { @@ -3942,7 +3938,7 @@ var OfflinePlusAddPattern_Async_Command = (function (_super) { console.log(patternParam); if (window.offlinePlus && window.offlinePlus.offlinePlusAddPatternAsync) { - window.offlinePlus.offlinePlusAddPatternAsync(finalPatternParamJson, "", signatureBase64 || ""); + window.offlinePlus.offlinePlusAddPatternAsync(finalPatternParamJson); } else { HAC_CallFunctionOutOfHAC(HAC_GetOfflinePlusDebugInfo("下载离线表单", "调用offlinePlusAddPatternAsync")); } @@ -4278,4 +4274,3 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { }(Forguncy.CommandBase)); Forguncy.CommandFactory.registerCommand("AndroidPDACommand.OfflinePlusGetPatterns_Async, AndroidPDACommand", OfflinePlusGetPatterns_Async_Command); - -- Gitee From a9a74ab269e7aef1d33a0545bf60426ba711393d Mon Sep 17 00:00:00 2001 From: NathanGuo Date: Thu, 10 Sep 2026 16:42:16 +0800 Subject: [PATCH 52/71] =?UTF-8?q?=E5=88=97=E8=A1=A8=E5=8D=A1=E7=89=87?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AndroidPDACommand.csproj | 8 +++--- OfflinePlusBuildPattern.cs | 50 ++++++++++++++++++++++++++++++++++ Resources/AndroidPDACommand.js | 22 +++++++++++++++ 3 files changed, 76 insertions(+), 4 deletions(-) diff --git a/AndroidPDACommand.csproj b/AndroidPDACommand.csproj index 06ad00e..14e9019 100644 --- a/AndroidPDACommand.csproj +++ b/AndroidPDACommand.csproj @@ -117,19 +117,19 @@
- D:\Forguncy 12\WebSite\designerBin\Forguncy.Commands.dll + D:\Forguncy 12.0.3\WebSite\designerBin\Forguncy.Commands.dll False - D:\Forguncy 12\WebSite\designerBin\Forguncy.Commands.Design.dll + D:\Forguncy 12.0.3\WebSite\designerBin\Forguncy.Commands.Design.dll False - D:\Forguncy 12\WebSite\designerBin\GrapeCity.Forguncy.Plugin.dll + D:\Forguncy 12.0.3\WebSite\designerBin\GrapeCity.Forguncy.Plugin.dll False - D:\Forguncy 12\WebSite\bin\GrapeCity.Forguncy.ServerApi.dll + D:\Forguncy 12.0.3\WebSite\bin\GrapeCity.Forguncy.ServerApi.dll False diff --git a/OfflinePlusBuildPattern.cs b/OfflinePlusBuildPattern.cs index 5cc270f..ede1938 100644 --- a/OfflinePlusBuildPattern.cs +++ b/OfflinePlusBuildPattern.cs @@ -34,6 +34,10 @@ namespace AndroidPDACommand [ObjectListProperty(ItemType = typeof(OfflineFormStep))] public List Steps { get; set; } + [DisplayName("卡片样式")] + [ObjectListProperty(ItemType = typeof(OfflineFormCardItem))] + public List CardStyle { get; set; } = new List(); + [DisplayName("将离线表单JSON返回到变量")] [ResultToProperty] public string PatternJson { get; set; } = "OfflinePatternJson"; @@ -44,6 +48,52 @@ namespace AndroidPDACommand } } + public class OfflineFormCardItem : ObjectPropertyBase, INamedObject + { + public string Name { get; set; } + + [DisplayName("类型")] + [ComboProperty(ValueList = "text|form|system", DisplayList = "固定文本|表单属性|系统属性")] + public string Type { get; set; } = "text"; + + [FormulaProperty] + [DisplayName("固定文本")] + public object Content { get; set; } + + [DisplayName("表单属性")] + [ComboProperty(ValueList = "patternId|title|description|schemaVersion", DisplayList = "项目编号|项目名称|项目描述|版本号")] + public string FormProperty { get; set; } = "title"; + + [DisplayName("系统属性")] + [ComboProperty(ValueList = "progress|delete", DisplayList = "填报进度|删除按钮")] + public string SystemProperty { get; set; } = "progress"; + + [DisplayName("字体大小")] + [ComboProperty(ValueList = "small|medium|large", DisplayList = "小|中|大")] + public string FontSize { get; set; } = "medium"; + + [DisplayName("加粗")] + public bool Bold { get; set; } + + public override bool GetDesignerPropertyVisible(string propertyName) + { + switch (propertyName) + { + case nameof(Content): + return Type == "text"; + case nameof(FormProperty): + return Type == "form"; + case nameof(SystemProperty): + return Type == "system"; + case nameof(FontSize): + case nameof(Bold): + return Type == "text" || Type == "form"; + default: + return base.GetDesignerPropertyVisible(propertyName); + } + } + } + public class OfflineFormStep : ObjectPropertyBase, INamedObject { public string Name { get; set; } diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 920a28c..3343772 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -3567,6 +3567,28 @@ var OfflinePlusBuildPattern_Command = (function (_super) { steps: steps }; + var cardStyle = formNodeBuilder.getList(params.CardStyle); + if (cardStyle.length > 0) { + patternParam.cardStyle = cardStyle.map(function (item) { + var type = item.Type || "text"; + if (type === "system") { + return { type: type, property: item.SystemProperty || "progress" }; + } + + var result = { + type: type, + fontSize: item.FontSize || "medium", + bold: !!item.Bold + }; + if (type === "form") { + result.property = item.FormProperty || "title"; + } else { + result.content = formNodeBuilder.evaluate(item.Content); + } + return result; + }); + } + var patternParamJson = JSON.stringify(patternParam, null, 2); console.log(patternParam); HAC_ReturnToParam(params.PatternJson, patternParamJson); -- Gitee From 11784faf0dcf8e64d5b0162c8e5e4590a7f0859f Mon Sep 17 00:00:00 2001 From: NathanGuo Date: Wed, 16 Sep 2026 11:43:23 +0800 Subject: [PATCH 53/71] =?UTF-8?q?=E5=BC=82=E6=AD=A5=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E5=9B=9E=E8=B0=83=E5=8F=98=E9=87=8F=E6=A8=A1=E5=BC=8Ffix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- OfflinePlusGetPatterns_Async.cs | 46 ++++++++++++++++++--------------- PluginConfig.json | 2 +- Resources/AndroidPDACommand.js | 6 ----- 3 files changed, 26 insertions(+), 28 deletions(-) diff --git a/OfflinePlusGetPatterns_Async.cs b/OfflinePlusGetPatterns_Async.cs index 0b73171..36c907d 100644 --- a/OfflinePlusGetPatterns_Async.cs +++ b/OfflinePlusGetPatterns_Async.cs @@ -22,14 +22,14 @@ namespace AndroidPDACommand [Description("多个记录编号用英文逗号分隔。标记离线记录已导出时必填;删除已读离线记录时不填,则删除项目下所有已读记录。")] public object RecordIds { get; set; } - [DisplayName("将离线表单项目编号列表返回到变量")] - [ResultToProperty] - public string ProjectsResult { get; set; } + [Browsable(false)] + [OfflinePlusActionResultToProperty("GetPatterns")] + public string SubCommandParam1 { get; set; } = "ProjectsResult"; - [DisplayName("将离线表单数据返回到变量")] + [Browsable(false)] [Description("导出离线记录数据。图片和文件字段会先按统一附件模型读取本地附件并上传,再把上传结果写回对应字段值。")] - [ResultToProperty] - public string ExportResult { get; set; } + [OfflinePlusActionResultToProperty("ExportRecords", "BatchExportRecords")] + public string SubCommandParam2 { get; set; } = "ExportResult"; [ServerProperty] [Browsable(false)] @@ -37,9 +37,9 @@ namespace AndroidPDACommand [SaveJsonIgnore] public UploadLimit FileUploadLimit { get; set; } = new UploadLimit(); - [DisplayName("将操作结果返回到变量")] - [ResultToProperty] - public string OperationResult { get; set; } + [Browsable(false)] + [OfflinePlusActionResultToProperty("MarkRecordExported", "DeleteReadRecords", "DeleteProject")] + public string SubCommandParam3 { get; set; } = "OperationResult"; public override string ToString() { @@ -56,22 +56,26 @@ namespace AndroidPDACommand { return Action == "MarkRecordExported" || Action == "DeleteReadRecords"; } - if (propertyName == nameof(OperationResult)) - { - return Action == "MarkRecordExported" || Action == "DeleteReadRecords" || Action == "DeleteProject"; - } - if (propertyName == nameof(ExportResult)) - { - return Action == "ExportRecords" || Action == "BatchExportRecords"; - } - if (propertyName == nameof(ProjectsResult)) - { - return Action == "GetPatterns"; - } return base.GetDesignerPropertyVisible(propertyName, commandScope); } } + internal sealed class OfflinePlusActionResultToPropertyAttribute : ResultToPropertyAttribute + { + private readonly string[] actions; + + public OfflinePlusActionResultToPropertyAttribute(params string[] actions) + { + this.actions = actions; + } + + public override bool NeedGenerateParam(Command command) + { + return command is OfflinePlusGetPatterns_Async offlineCommand + && Array.IndexOf(actions, offlineCommand.Action) >= 0; + } + } + public class UploadLimit : ICloneable, IUploadLimit, ISupportDeclareObjectEmpty { public UploadLimit() diff --git a/PluginConfig.json b/PluginConfig.json index 85f3a6f..ebf0a26 100644 --- a/PluginConfig.json +++ b/PluginConfig.json @@ -13,7 +13,7 @@ "name": "PDA(Android)交互命令", "pluginType": "command", "guid": "{16B8DF69-1379-41C1-9194-BE89BAF8BB32}", - "version": "1.23.2.0", + "version": "1.23.3.0", "dependenceVersion": "8.0.0.0", "bundleJavaScript": true, "bundleCSS": true diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 3343772..02bbc63 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -4043,7 +4043,6 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { 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(), @@ -4101,7 +4100,6 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { 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(), @@ -4127,7 +4125,6 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { 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(), @@ -4152,7 +4149,6 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { 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(), @@ -4203,7 +4199,6 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { var continueBatchExport = function () { HAC_OfflineExportExecution.complete(); if (batchExportSuccess) { - HAC_ReturnToParam(params.ExportResult, batchExportPayload); me.CommandExecutor.excuteCommand(me.CommandParam.CommandList, { runTimePageName: me.CommandExecutingInfo.runTimePageName, commandID: new Date().valueOf().toString(), @@ -4272,7 +4267,6 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { 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(), -- Gitee From e33fdfd88c6e507dc44a37e927d53ac8b99d819d Mon Sep 17 00:00:00 2001 From: NathanGuo Date: Thu, 17 Sep 2026 09:27:05 +0800 Subject: [PATCH 54/71] =?UTF-8?q?=E6=AD=A3=E6=96=87=E5=8A=A0=E7=B2=97?= =?UTF-8?q?=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- OfflinePlusBuildPattern.cs | 5 +++++ Resources/AndroidPDACommand.js | 1 + 2 files changed, 6 insertions(+) diff --git a/OfflinePlusBuildPattern.cs b/OfflinePlusBuildPattern.cs index ede1938..e8f0ff1 100644 --- a/OfflinePlusBuildPattern.cs +++ b/OfflinePlusBuildPattern.cs @@ -72,6 +72,10 @@ namespace AndroidPDACommand [ComboProperty(ValueList = "small|medium|large", DisplayList = "小|中|大")] public string FontSize { get; set; } = "medium"; + [DisplayName("颜色")] + [ComboProperty(ValueList = "primary|secondary", DisplayList = "标题|正文")] + public string Color { get; set; } = "secondary"; + [DisplayName("加粗")] public bool Bold { get; set; } @@ -85,6 +89,7 @@ namespace AndroidPDACommand return Type == "form"; case nameof(SystemProperty): return Type == "system"; + case nameof(Color): case nameof(FontSize): case nameof(Bold): return Type == "text" || Type == "form"; diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 02bbc63..c1953e8 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -3578,6 +3578,7 @@ var OfflinePlusBuildPattern_Command = (function (_super) { var result = { type: type, fontSize: item.FontSize || "medium", + color: item.Color || "secondary", bold: !!item.Bold }; if (type === "form") { -- Gitee From dffd2b46a2e9289c018c142885c30c77189fc9a8 Mon Sep 17 00:00:00 2001 From: GerZhang Date: Tue, 13 Oct 2026 14:30:46 +0800 Subject: [PATCH 55/71] =?UTF-8?q?chore:=20=E5=BF=BD=E7=95=A5=20OpenCode=20?= =?UTF-8?q?=E6=9C=AC=E5=9C=B0=E9=85=8D=E7=BD=AE=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 9491a2f..60ef307 100644 --- a/.gitignore +++ b/.gitignore @@ -360,4 +360,9 @@ MigrationBackup/ .ionide/ # Fody - auto-generated XML schema -FodyWeavers.xsd \ No newline at end of file +FodyWeavers.xsd + +# OpenCode AI Agent 本地配置(专属本机,不纳入版本库) +opencode.json +opencode.jsonc +.opencode/ -- Gitee From 2969d2af787edf60dfe96f66b9f3ec0f2154a63c Mon Sep 17 00:00:00 2001 From: GerZhang Date: Tue, 13 Oct 2026 15:10:43 +0800 Subject: [PATCH 56/71] =?UTF-8?q?build:=20=E5=B0=86=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E6=89=93=E5=8C=85=E5=B7=A5=E5=85=B7=E7=BA=B3=E5=85=A5=E5=B7=A5?= =?UTF-8?q?=E7=A8=8B=E5=B9=B6=E6=94=AF=E6=8C=81=20macOS=20=E8=B7=A8?= =?UTF-8?q?=E5=B9=B3=E5=8F=B0=E7=BC=96=E8=AF=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AndroidPDACommand.csproj | 44 ++- .../ForguncyPluginPackageTool.deps.json | 41 +++ PackageTools/ForguncyPluginPackageTool.dll | Bin 0 -> 22016 bytes PackageTools/ForguncyPluginPackageTool.exe | Bin 0 -> 150528 bytes ...rguncyPluginPackageTool.runtimeconfig.json | 12 + PackageTools/Newtonsoft.Json.dll | Bin 0 -> 712464 bytes PackageTools/PluginAnalyzer.deps.json | 315 ++++++++++++++++++ PackageTools/PluginAnalyzer.dll | Bin 0 -> 24064 bytes 8 files changed, 406 insertions(+), 6 deletions(-) create mode 100755 PackageTools/ForguncyPluginPackageTool.deps.json create mode 100755 PackageTools/ForguncyPluginPackageTool.dll create mode 100755 PackageTools/ForguncyPluginPackageTool.exe create mode 100755 PackageTools/ForguncyPluginPackageTool.runtimeconfig.json create mode 100755 PackageTools/Newtonsoft.Json.dll create mode 100755 PackageTools/PluginAnalyzer.deps.json create mode 100755 PackageTools/PluginAnalyzer.dll diff --git a/AndroidPDACommand.csproj b/AndroidPDACommand.csproj index 14e9019..8d18736 100644 --- a/AndroidPDACommand.csproj +++ b/AndroidPDACommand.csproj @@ -18,6 +18,25 @@ false bin\ + + + D:\Forguncy 12.0.3\WebSite\designerBin + $(HOME)/Develop/Library/forguncy/designerBin/12.0.3.0 + D:\Forguncy 12.0.3\WebSite\bin + $(ForguncyDesignerBin) + + true + + $(MSBuildProjectDirectory)/PackageTools/ForguncyPluginPackageTool.exe + $(MSBuildProjectDirectory)/PackageTools/ForguncyPluginPackageTool.dll + + false + true full @@ -117,19 +136,19 @@ - D:\Forguncy 12.0.3\WebSite\designerBin\Forguncy.Commands.dll + $(ForguncyDesignerBin)/Forguncy.Commands.dll False - D:\Forguncy 12.0.3\WebSite\designerBin\Forguncy.Commands.Design.dll + $(ForguncyDesignerBin)/Forguncy.Commands.Design.dll False - D:\Forguncy 12.0.3\WebSite\designerBin\GrapeCity.Forguncy.Plugin.dll + $(ForguncyDesignerBin)/GrapeCity.Forguncy.Plugin.dll False - D:\Forguncy 12.0.3\WebSite\bin\GrapeCity.Forguncy.ServerApi.dll + $(ForguncyServerApiDir)/GrapeCity.Forguncy.ServerApi.dll False @@ -180,7 +199,20 @@ - - + + + + + diff --git a/PackageTools/ForguncyPluginPackageTool.deps.json b/PackageTools/ForguncyPluginPackageTool.deps.json new file mode 100755 index 0000000..1f5bca9 --- /dev/null +++ b/PackageTools/ForguncyPluginPackageTool.deps.json @@ -0,0 +1,41 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v8.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v8.0": { + "ForguncyPluginPackageTool/1.0.0": { + "dependencies": { + "Newtonsoft.Json": "13.0.3" + }, + "runtime": { + "ForguncyPluginPackageTool.dll": {} + } + }, + "Newtonsoft.Json/13.0.3": { + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "assemblyVersion": "13.0.0.0", + "fileVersion": "13.0.3.27908" + } + } + } + } + }, + "libraries": { + "ForguncyPluginPackageTool/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "path": "newtonsoft.json/13.0.3", + "hashPath": "newtonsoft.json.13.0.3.nupkg.sha512" + } + } +} \ No newline at end of file diff --git a/PackageTools/ForguncyPluginPackageTool.dll b/PackageTools/ForguncyPluginPackageTool.dll new file mode 100755 index 0000000000000000000000000000000000000000..7ca0b0d0f310c6a09248f095acb3d42bec0c3b98 GIT binary patch literal 22016 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 H_rU)L1*1Kp literal 0 HcmV?d00001 diff --git a/PackageTools/ForguncyPluginPackageTool.exe b/PackageTools/ForguncyPluginPackageTool.exe new file mode 100755 index 0000000000000000000000000000000000000000..9f1ac12a8ae7ec6002af5248e872cade03bbeb6f GIT binary patch literal 150528 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 B$UOi6 literal 0 HcmV?d00001 diff --git a/PackageTools/ForguncyPluginPackageTool.runtimeconfig.json b/PackageTools/ForguncyPluginPackageTool.runtimeconfig.json new file mode 100755 index 0000000..becfaea --- /dev/null +++ b/PackageTools/ForguncyPluginPackageTool.runtimeconfig.json @@ -0,0 +1,12 @@ +{ + "runtimeOptions": { + "tfm": "net8.0", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "8.0.0" + }, + "configProperties": { + "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false + } + } +} \ No newline at end of file diff --git a/PackageTools/Newtonsoft.Json.dll b/PackageTools/Newtonsoft.Json.dll new file mode 100755 index 0000000000000000000000000000000000000000..d035c38b4edec5c10d4bc421a2dce19f5f998677 GIT binary patch literal 712464 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≀-~gC8dflab=g^w4(KOPXwpOyk)f1V4 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

a}WImGl=81hq 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

E8M**(dU{S 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%0DMqEZz0aTJh&9-MMO!Y0F0 zG-lfFh6rQB3bu9pc;B(M1xl}xdKOS&-k(u^8)8BCcmt4D6{AYA2NG4RQx6BrvDQ#m zw&2Li12o;vwJHaaLZ4}saN_0VkEG{%Y^2vfpgx(rpDqED5>r}fK`-yaXLFxdR?N3g zgPb9sLMW8H1UN^6YGqRnFOeJ?myz`{L0)%6{5QqpM)AM z6t}Mh(lWzcAP^o~Dx+j6xK?iUU}#=!joO(}>Ku-lm$WxRX3G*iokm?BaOihDMF3nGbK6xoVb$CK=pGKAv`kf&4ZK1HN1y_i~k&tyJ{zg*fMDgTX28Yo5W{XNQ27kSf4h? zygkZ1JY+(xYWi*&;d;8LB9aE<4JB)3CCeX9#Y0avmbw2HbtO?4rY%0$DcL>3{5Y?m zGyqUr3d&=a2YchAg4pv36(m-Ua=C~W@A~h9goQI(*GSBuBOd2c) z4#CQMQb%DJL8_5b$`sqnT#546#k=Xh89x|r*^8jce{4N+t_%A;xEe-ziOvwB$Ly^6 zN2Y}@nNVUcZNHFUGGUmsbQc>ue04TE^kDHM%jS{8;%Sxy5S8{+3SyJvDuP|)ae57S z(9RV-jIDjNeB=>RSIxtdasVIuaYYnv@NlQvU*)F}W1~fai=R|Vv8sGXP(d;{u8Lw3 z6&2JVS!AxZ>8X^aeLuqF~gUQ z1$hdbn%IyTk}ns9j&uH7L-H#;b06Av9bSUEB#$Co zL0VIp-yK?)qY#HvO`KZ{81M2Jv%QMVX{t@?Fe$|)^ZzB)OR5jj{U(IFxfdx^wu)$R z;88%GpxXGdy;*Bn#)+q8JP7d&-2&-?lv=#7lL!@`=QA$u$bl=6`Hc{5PTr0zVZ8L# zhVklTnP(@zE`kZbVa6&c`Ff)xOX{!0{cLy~4T zMNB@%m3us^O6`$vP%(zqVNZCx!lk~qfA~Y*>r3$;wc|=PEQLHSg_L6W%6-fgHWI7g zY{3upDvTa0z@>t_fUcUMJDC3zv4>x|@XBg^*1Wi&ZtFL)FU=O~9f_Q@!9?~uNy=g1 z_M^U;f2~n-c6u%hCNfd!iT2rq+HYO+iVV4f0~zE*7uicceoX^KYra;2$v?r>F?>U7 zwvW?CCF*8??SiqXOu$yAvDKlp8NZe_>z1+030wuQgF_2K3NVBKxMU-<`MCpHlJy<|0?>6koNla{_q5al_bS%U&kV1G(2(x9~OMop0*jdV| zp{;adLiq?^p|dl(yaZA*;}dnZ*?9^nvzS8u5arHFqr}-T9xkEyyE?{mT?k1SiUVP_ z1pkfuzDpgjbz)s;gtHKg!wRHVD6Auw@!~N`K8m-VuFm%end%4Qgi;sZ&MVvpFt7G1 z+{!F=sbcrMcPQVDO%S}{hp+8{CeamtGefSKVOCO%nw0m*tw(U&&e(3CwhXM7+DkD%g}Q}0<#MAB&KMF%6>4WDpxGHs`A8t51JNb{IN=q5IdIEwY|lWZY&(#l z+aR!$T+bxA$E7lCK1I|)DlrMf^a^kgPU?B3m>E|uXY@xGbkc#SYVnGcjg_}ROMPuF zD!LAtH^RcvN|SK0sfMxE8iMx&%wsYs9zf4J2PYKNB(=pEFXQTdrX(pN8|wl0wb+x5 z&4PA8{^WfspFAgMH4wC{1|$z<3G^#?`e^RaG}sazPjlY**2FQlO$PA&`JYCrL zBrJ8ZWrEa6qUXQA%IbCITSG8WNAu-95yLw7PxJJNzWeSm8zh{Ucpb_?MC{EP1c&r8 zhb^pW)Hp5u#@!j(1CujgDE8G%uQ!=fb~S9@?st*|{gmjF{RXKFhXyPH+` zMZ~To5Vx}FF)-f3ud*`K`IeXg5BwW8i~uk1%_jG=t&&?D(kIh6Jrb1h90#tC3t~=X zpyB+C5kPb2)E@1TT*AE<$`|ZMEW?VmotxFs#6uXxo#TjrKybP|sZA~%Y%5Wd2MOb= z7I3=4BYwMVd8r?sqBlG{Pc$b=Bw?hJq8f7g?fKrlBw}TB)sw+DnD}sJS@1;|WW>Dc zzNcN{q#({04(F3OI(0~Uo5G+N^bieFMWRuh_m13-MH%pt*^sbKw+K#NRDXaS`ZcRm^rs5J;^w8H2Y=^!p;I5hq3)qIcj?f?$_NWtBc>DL zJUH6mVTea;+#WV=%QFNJdjAlTr^H8( zJWA^3!JPfp(m{5#=3(^KL)bnZB9?j35W&Mh2O2>lMcoFTe>i(Y`|tJ=+YDsQZr|XV z${5Fu0HBm9oj`NM4F6?iYbN`1g1F4vM`IY283V=_u_JwuhPq|*xof3XAi~^n5!SLq zj8ADtm`&K#`w|cr$^*7Dlbe&_`C@W3Q>(80!jcFlb<=}|ei2ct5erIV;|w5r62WVW z2lJ!l!m4(&etgJww$vBZnd1V z1jteKqPU%Rr1PBf^|v1Gx}KCw?wlQ7gELQ!4BVu@-);;b#8Wg3q^(-qPkUjmwLE@I){d;guCct#n%F7M_@56XZwOdPq*%gCt>)D5Ii zqBHvDuP4WS|41UE7)T1OBC_HuGvKiEh}tlEB}n5w{laDA%zPjf2SR-!smrxw$I&`D z7X0k^V)gbifTneFz+i;GVAFKa zthi%~pVDbG6Z>Hgs1oHl%I4hiwc9NUR%gh^`cmE<6USJ}F#3ogSOxI8YuKrUqZTrh zv=HP?O|h~RYO^I*Qi8H<<4Q_oP6s~%m@FaMC4kMOf-9@9XKy7Ie!A^dU)buMITPAF zortSf0fD|WU1IEn!RTWeaspD|2VzrJOmAdH+(aQIP)3lVE5xN@QES96 zH48~P{PI8^$Z&3XCo;3QwRyyI8e2vURjAzN>U84x;|<=DnCeQ2!rmM8mgm~_`V zOEG(OqmK)MEF6qEi#Amj7;(1j7Dhb%WMIjW7L4y~S|ru2!o`>=YqMsR1e>r}x=m*> zoT($n2q&NT**4X~hM*7xMFnuNeS*th+qhu{<%D`9w&&%?itQSVI|AS4I)SESe{sOi z2(G13eZoU!_*62zww3_eZiGYfqYBFHVa9|C%Dnd4&uDRoqRdo8=LSr9&|;Oz<4orZ zuvXdvB(E0mtw9B)`P}|8vjyan%Lhq#(wx%L69)#d{=inh5ByM`NfiS^TR!)5P}nqf z3+^n~u)VosvjTKGj*dncmTP>Ok!RDM$oq0ByoA4r%J4VYgINhjA~(s%!Pkc?$aP#q z;N}0QBY1NKoRv8YJ$ZhZK6h>%4)*6QMLkjPVup{FcsDT`9$FWcRhxr}rxVkx%KHzR zk8Y120)=oa3+s&0IRX+nTeE?uQy{#(wLm+NdD_N%3mLGv$l;xF%6FFf&2bGaoFOll z!R!?55hJ&j56!TJQ%B#N3?Y?2ya}-juQ00I15Xz1xg{U#03OJ=s>LydyPVhM3)mlb`t??5>hN= zbfuYL3ln=hQ=D=IrB220hGhyf#h};`1sH?Qc{mRH6d+t^RYNw?D~{~&Sx`8*t?39! z;vDZQHLXB@GF`$b-G4O3r#Zks`*W#7{b>hOO*+l;pgm|g8Uf0gI3g|uWofhhY^+ooJ?T$?+R>9;Gozx0 zAhx>{AKSQ1;krG8Mg$w-1V{%1gJCLvLDKkhU7y|KXh<-4wodSI5f&LD6obGErabp$ z4Bp55+0K?O%L5h#R=Z*ttj#ixAMpp)Pd?O~4;=|a`!!&id@Y%5TEl$=INI9(N)n54 ze~1CV|Gme}FK2hhcPVbPvTiNlE7Su|0!u4D{G42FX(gb$WY#82w33|7x1fucCHF}TV(cHai8NoS5^M^kr%+Qt1X%^dMY(R_E3IFvnkxX45c$=h_`*Ko56`vF!Qy6Bw+kd63680UbGZXNEM*?SYrXw$#($= zURZz<11w-{Gk;XENZ4K$k))RvFyjK8`~s$Y+woDuB4uZqXUDD*i=t4owL| z4|{P9+{?I?0x_q$LTG7u)XGAB2d01bWc3&yV8T=2ctY4tUHzG0ol?yr#zyEfb8B|| z?vI6&IC3)Q4LDsvcP{K!P$j3bYr1<7Dr!!W6__3cw1$j8@C@N?t0kMTeJ?ELn( zP4m+IX4X7znisC(-)+Qy*j#FU*fcNN-_Nchb-$T62l#i4@KJLS;ge>C*u~~9AQzi4 z{^1gQgAeE-FCk0IH^uJ>@(A`7!b_{;Qq#OK?bO>m`Csp#iWRaQ;y+fw2B)a*7#%!B z_%9Lu9Xj_{=;FoZ4)U_Gm005M9#S}n zD8EEke*@SAkT)&gN2qJFxrIDOfFIglwu!IMqb^t{t-VXlg;yR}YbQu+p8VSlbb5-! z$iR-UnOXA)e=jz>D0YHMI5f`M#U?kzd1dE0mz>#ME5}*iHRv22yO+{Ai|kN2+$dWP z2Q&UM>$MKPvTL1Xx#r~sVEg#5c|$##c{`l==JgT!5$$pjnm68R+OP{R-9ml0Fz~Oh z*nB*&4h6DIkhs8qT>6X6L+dKjh%#K$2?oO^w9RCQ)}E8bRpgowspb}% z0wTbNxFZ7tnf5leP4k0K zQO~~NL3baQrMQS_duQ7>SIio5O`GE;YI@X=J{)?_@FB<4i;F17?Is$*Eprh$A7Qy? z_>XwY1-o#K>qQLYUI-+qXDJYYqa@;R+a6V}6q6!^pi#jA5|>PhfKiVgqAXCPp6 z+kBKuI0>1_he!~lZD!ST2toz2xG|c$k48oMCtzu0NSq`}J*6l{p^k*|1b@3ssM|># zJfcTro(r@g!I6{4+NZ@*H5<2(%GM~3mlF~bK@lO>A0#&~c5`zh^^Ds?f?u0ChV&Iv z-)=4B^XA%Zt3y3y-`PHUO(}gJJ=8qb@}U%p5K6f;|KW;FSTq+x`<4~YLVgy3$Jp*DGhNpnpcUkc;FbZ zW5|@hv8BLQ*#Qgfu6e6}zh`vM2*c(1Z%C z9;K2febPUei3z9pd;)6IUK-k85=eqF9NP4SsvEnEN>$a5FW9Q;rP{neDaI%$wS~KD z9Wj(kRV&<8-M_eu+E`Pb5$-4=6~$ShB();Vd#h(J{JLp2N9a*WAK2Tu%`4mHOq^EV zuTg*6=lA>PnC*vXI5dCfYZ>VFu)nS6wVtFq2Szel3dWOvxdCz*sM1D*OaeLWL1RuZ z0bK&$*VUjg{adA4{?FQrN4m7MrKh=sG>KeLn+&Qy1p_t9=&C;^b$86Y+3e|C)pL=s!Z=xkt9J zFGw7z;`Y_?RFnM@5#wPqqz;{Be4>J)CMQP4DD+^549r>IYEo$%+L`_Jm#fp<>|dRl zKCh>rLBr7R7k>y!*lckf4jm&(T6qy{P88=&tb^=7Arj>6CjqeB#V|44c^-An(JyX) z86Qw9gwwDM)@fmeiC$77q#cXaN3q^8kFKygXpEt8Fof0+PuSYK%{yGt=hA#q zy}hob-V$%J{Zba|*Uv;3gRN&(rEI@z&fNn>QTPwBg?g;$3y*kUEAKYm$MkA4oS7<7 zzAaOb)qiS4O{92zZf;c)MaoPh>+Bp^^`D}97rw!6^Sq?ePH{R2HOQX!R&lO77%}9iS&{ll6&^JVH2> zg$q}N9g>p;jh16g+Qf(TNIfIbM_(ql(GGhM2S07WjE6}jZcz!Ne$1Lks&@@P*wfN5 zlh+AtyvTKFW*df8?eP&eI1e0UjDffsXB%vrYr@kao|UqtvP_(l@I(e}EzjPH1RvUn z;~+D(v=q%VwfET;dY;c1OTp^2QLtssp-!Ueaadn~~X{cwY{p^F~Zp`>PROM-dt!wEF*7W7R^;FKl zm6=W60t-P(MjA*i(k5!b>cX~MlkzSyXM)TL>2oiT z0q+2v#wu)nfT1i6(Vq_r|2O>={ue;sU-k9m`JnEZ23aHA?+IeO(GGwYt=;t+Tz4`<{cyVn~Dt7H(Wl1h?3oa;S zseGKHT~3KA`zBCIrEAhY@=3N4Wm358V^)Go=>nT_;0!&+BneK^Xt>F+ZcqC87j+!*oCjL zCHWGuG(E{Q_U2U{Ver=&ovAWvrbb{X{ZWsaF6X~xtUc_2diK#g+LTtO+C+Gqv~uc-HMn)W_YyX>}h zLS*@vYo3z>FDB2sh1=-a0s2TGZUa3;8#~Xt4UR%9V)Z}wS;`p6RmTXP{Oz_WsI{FU zBUcb1q6EpR1m{4nQZyH_eX}2sM%m-|T~K!^oyk5q*_RR}u>!r8g!~I*3 z_xqS{lHukT{p%J&ML0_R(({+p2P=1Fgj!00EnK>Y(_%ByA8p(3bx@mQtPa@* zsUQRdPoXPHE9KiNa}_CMfuuuK$!{o~Ofu84#!G3wWZ0}qeJ4supkS@cOZ+5_HlYB< zQ}(*7qxr62q-td3Oy4wC&HW$Dx$)Y$)`NMzshTtwY{La2hifJZ__vh5oQERy#chng zdG!i<6n68b*9DSXg?mtxLX<0?!e%il(dL)b!{+9C6|5_WP$`pLhxAhIa-PXvFTAAj z(fyfwnr6l>R*8`g9{4XLDW?q_RxXzRYx>r#+mgqC;Tirw(qL`&iKSke?1`rb^{K{-7 zAv3RJ`%I4cC1*&`KgRqLwnwpNM4ZaJp0kqEHNU*W!XuCN43aKqv-^b+#X_oQ6s1`s z$DAoqU01k~#CmW%C+LYe+P_NinR3w*@#bamQ&8AHYAbc@J4-gNb3AM{?d6Rw_MQ)8 zn>TdRgYN#Rou{Z(SQh)Bxp@=wNIwm_ds2p^c>4j)=XE@Fh#2RQ*jS4Hb)LYo=Cu)O zA=MEMG=HqUn<11t*aOVo=JROzQ`G0O!`qzUnJFujMClnbEBZnSY|q9*RoH0$U#u^| zai_dLUY}RgU$~m7S+n)DW9-gYTJx80p;yGn<|U1(`D4;#-O-Ajlvd;ot-uFZ5%RC; z8E2m3X{&ssL^o{LkwbDXP!>WzUZG+~diqtOy0@{}jgS=2y>Bce}l+ z<~zTSnwu}5rPl6Te1iF!**}|&XPW8uY_#geF0 zt}~MBem0!$;s~k0v1ViEd9LAy*rzo374<(?{HyD4CeO3)TcBNWAGhfLbDf`V8_z}w z+k0pOBang7F#Wk=W3Ic|dzN|cV&heCinb1DJZ1JQ?X>4+u$A%eyOrjv=h;GuLxW>F z`1@?JdGXhvCj7gwzu@l(@7mwH_7^_+uhOIbhxqRwH9z*)JBYo5xY88+ndRr@;9tW@ zs(Im0aHte^gJEryQgB%2WME^JIZQ23aAg%q@T&U5Y|~~4rTdu$28ft zG64mVKEZ3~#Ax?ew%Zcjw%I#sJNY<@l5u$ibcVX0{Hy+fvGMTJdX@(IP9Z7kW#zAQ z_iQ%Vn-JE*fGgKU4wWK3@8-+MIJ}^7O4IzshE1egNNU9}l)+?zcmW9WdkV;s85bGSuZ8F5l`Z{hZceQNX6aCHlDRV%^7M~ zSudq6c1J|(NgMBF$(Un?;z0}UmawxCCu#XDp9|=-yTE$#Wk34WwH-rFyS zZ{@6Xp?Lw6<;S!N+Tf^JW&c>$YJXMQhuT(%?zsu)LNiDN)sd#ql_|1= zbAMyZZ`J*|0&FAw!54M=`tiy6`XLQb&Tj+l|2*`@bte;~Ms3{?mYZ+&SzM#O=1evB z)qtAK{t_6}Jo$GwF&Po%l5x4a=B)OCSXP0f4CzbTEK{akGxH%AFQ6pkJUURya{*?*zWFWds*(QmnT~lIn(YfGr?=TQ zS3ZYUUmn@0ahUQQ8qe!lR$s$l3en?Lkrf#^n-^fh`r}NtDcFaJ%nT8)&=^EQ4l?s9 zQ%DerGtFz6X;{vdSwTX{82GRW(?mR~L;Q%8OcsPU*BsAC49hZYH73eGUCqKu8qPQt z;;g9xc9p5km&rETz6-=V%}HEn)(U340s;JrCTICA&<}%zyaZF6W@%{TzIB5|1uqPcPyUkzNaQW$?<@~x6fW5i z39incC@so)x=n0@Fm|OTotl)SS!X6BR6P5Tw*?6`x1(H;*pK9n{p7zQXA*^y2Vj@R zT|!lt(K!iZ`G0;Sp3NcJDs4deNC{cIbx4|g;KAmMAF5NfkFlUv5~=*Ks~w6rN~7!Ot* zED8U5l7NthxgpB+c4hI~JkSgEwLM#qDBsv}^F`cy$3f?tHBBBtwxA3`OeI-Ma_@Kh z@=@9*|4zAn(3gw+fV~ZqhMXNJXEm#B^qBl#s!wS4w*iwEXGkH0@aVGrEDGl>JWKmr z-6Zc)`Q(g0#@L!)kkGePd|d|Mo|Y=6xt7N&(NOyh>-wv{(%C{$BXsOiN<~98CsO_j zXOeRc57KYn!tX|CRr0trizU^;NIxlS zqslr|TXv~BrN*Dt*g@Tgj}TmfI|3OU=k8;pucVAY9gUm+QOV7#L$z;F|DvXIWb4Zs z_u#ea{~87o;f@w0jBQ^OUxPD4ZY( z0G!n9#)F}KqfIlJqxp>ErKutO!DCsvYp`3cO_VwQlRjkZWMZ0Pe zCw3vo06ku5lVSs5$tt^+*P9qaGAU%_;DTRM7@?nz2p`3jaE&L7DZ;DrnuT%)-VuLt z8444%S{8;4Vir9C!t+3;*!IMiA`M&S*w`zMT7BdmdE}$+Dt2v>RVo7613)|JL#sFY zAIgJ;>ZGi1SgObMrDu9@<++QEPZJ4uYni5*?n53DWU*fEI+ZS2U+-CACsVE zj#gx%Z_XX6FY94XxZ2m&^izFnV;9dM$l%cSn`LPd#`Y>{?VInE`3CafiDO(wdFz&q zI$zt#b0hMvd@_}OI$Rfyv3!?_bD{G_F(A!urf%gPxbV`S0e2vHg1U+B?)YvP({+{*qe<&7gwG?S2sqvVg$Hma#OtptaVO`p;xWV|CfiNSNA zLsNr+ZQjOIW)mZqx$KijbbG2x@n4H9ssy3=weqQM93yugd5^Y&BWE-!jUTipu`kS3 z&S7pDZGE|&Hr@HkQc}*oZzM0A>F60-M(scC&P?uW?guvlw?&$Plc(=ht&*IkHLwp! zGr%q1u6ef}Rk>xm{nsYs94!3MGn)r78(+WpyjW{V4@*k@MN5DWIxLzK)V1t5Db(LL z3;lZAR{IZ|g$g5w*bi4aV{&Fa{pYUC-Ouv4H!0RwjE<>~xgw+K~BWhFLR4 z_VRhL#f)?%Q`|t`Wr_L2W{G9*ngG6@}KuvbC1S<*0Rsfc$}Kb3=Ik zhcdMPt6ncstgNVZwYfj=;mqsN3`uw0$(MZ9uh|8LRoWa*EIAh;d)L-QN}y4yBxhkC zXtv6km6%3>i2e~FdXy%h5RpVWGkL6->}-Uc(LGJhM;Y9UrSD>SiX!nW1OVn z#o_c7Hn7?!|1}M=VTgXQ;>n@Jx+aVN@b94x-;RT#(@Mv6GH z%ljin+N@4*gD8BumG2yFzPn|s5Esz;kLLo#)YIn2AK19L8Z@{Nz5BLStJK$c{h<#z zC@lwBX)BbasH&aWZz849fof`=)RO3w=jJ4OT&zGU_9?ed;ue!v6TDK{4ik=$EQT3G zNH(Z$kIMat{r9W>BO}&Qo*A5O!!GMJi?uz>Db%E{Ei%uS@((dKE)-!j0&3~95rLzR z6Jkn@L~Sw%Iz~Xxef+$7oKK6nnshDTw$bUVYyw%xvJrjK-}3p+Y;v6#%h!J$2vGBv zegVGkn?`X26)z(8(UZPip-Cq-$cQ79S=S2la=}VPVMuptn`HG`8yAv&4DT4y;PUh? z+&{F9$VrLb>a9?LO2?M@`Y%i238<(SW#uD|*R*Kt5&o-P)3xj!)a`K>?&%|HFZ)QcO*Obp{N9MsoW<483 zs8J8XtM@^l*=wF}VmHs&7p9hOva!8FEG@U(dPF83iMCg_DbGxW+Ow=4=+mxQ*2E_G z`mfe?BrkZ$22XnyMh(#6K}LtZp^*J?^O42XM;xRIZP)Sj`+mLT6UGNhdSq*)I9siS z$~1|KPWdQHX_QVR=^=rR2&SKBMreezNi$(dT49%JlYByOVnE*7hd=U z*~GqWbFOoFeiodauJ`>~P4i}6g>`d#;X5T699XX}Xz$(v`{K9i4xJ52wC$5Oh&}!N z7U9oxjNLL)-TjiwxoY}?Pa5lNm28sxKl`ZlpFv8#JcHe-G6aTAELP$4c4B8{<^UYR zg^!vcaNi-3P@D8@kGZ-IwZ)-^|eI2v!M+a?PGMdwo?*K^S178 zDGd6_fB%QjrBim^o%3VT8E|N$U2EQL;kj6=;(;|G=3KCk>yXohTDpGy%bhI_8dfIa zSr$wheD;F4T$;0>!`ZQ8 zt3_O%v-mI>K@jOX)gVoHP9n;mbl3T)ez3APM{GMHee+3ukBWjFwLJ-%)QZYm)7?}F zg5@?kUyT$SN=B~dIBUJ8edGQ!+nm&TA7Uo?uqcHzeT+wfp)SPa_Yby^Bfgx_)8mKd znS*!}VI%R8tgW&)H!&izv9N5#e%}C;nk&C@q^Cxk@3iygcN(Hpb3GoqKK~cW`HihN zF}wWl!V7!2&e1P6Q+Nz7Ff*=xr@J>gdGIv~nwxmHag4{YZsCm)VRpV(*}VK4tPe4% zdGVja52bkl&uk;~Lxlc0{(T3Zpyg_`HOaajidDI#ez7G}Qi{FTI=3!rfuwZ2mzJI_ zuXS5xIjUbF_(}kQu=c_i`1d77Me7Q`7DI81UX0B*snoGHt~l=_%9!1JqZU5(^_>Ra z7aTWxf*!plOAGBl ze2R?m@_T#DpHOk&iJA;*qy{%JUNTTG(VL^H;|V=Wczb>%BY2?%o) z5X^o1n__$=r+J<5@_UQTYh0zQdN;4~YMgvCfwk!q_gn?K05-4HGuph&-fB){ePZ06 z%>5?SviNpm(YLR<*tvn#iK|N#z{|s)p-)CfyQQSM>i^vBUw2#FtQ3K>wps6uK0NN- zBjXzHc$yFfSeij371y^yDaCMvI-HWJKr#$hx~2%&g=6{ME?p}{{r&IO zK2%p0U}Z>RZ>f0Y8SZUi)otPI{eQ|fe?CIrO3UzRW0Glvx6t_|B5^W~u6ebjl8t@8 zh!lsny!i%__6JuKvDfO0KFuq6oXtzr%&^D4{&%$2)l7iwhxeiR@gv>;qrA>MweXOY zwLC2)bBHGdb@VmIFyz@QGQj1MDo7-g1`|3*Sio|<<>>*H$FPl+o9hP&T5j^Ll`N2y zHy4O3BywaK6z=KP#7&c5dShCsthqnxZ`rHpGv~7$;S_>tW~nUqA=)X=cDwc`FxItS za3Mm3b4B#2K$$!2!>q%YBd08y>|?*im-BHolYj0TYE?Ej5)8im$yOTJin7R863NnW zUCNTyZaWcP5R@O(IyqN?D4z)z*Qn4J*LvZ61j}$H@cC>#@Z~l}O-9ZQg0`RhhijHy zhDV|}6N8eRuQIwhlrK$XBrO}I_9^LuA=2Z}CW#cZj70Z~1>GyryleUrwT@{b)wqP3 z>fUoqoL06XkDoSza610G4J0y|FCVDdx|(b~W7o3KzTP z!vE5@3PTm=8Gg1E;l3%)Fi4f?MnH6xIDPu+*h@cJo&OJX_p|kTe`o}!6P5q%_fzq+ z6PTg1th_gySMp;W4UP;;RINQ8LaeM`mx%MO?)9>|bbOYW2f@v+NDX4wQ;8A%*VYIc zLkg4qIw;yu=%@Hkey-z4`Fz|k!fG}DMOm}REfq$+vPzCEqWeSk;*)M(8Id3l%WtF}H+S`TCV@ zvpkT3QTLK;8CiMMLfR#9fJ;#?6D<;93nI;~`Ir`Dcrv4tya+Z%&GaG-eq#^nd?bv^bgQVjnKgMLdfS0daTq*fBb=X01WhRuUAEst& zLLTYU97Wa%N*SNM5C7XN9tR}ZM(}DW`^!2_FuS&n1jW|P^EMzJ4LC{GGg!Awp@4cl z@q+&C{8V?As8WAlfPOL$%<5~MQckuX=h+rfh_%t$h7KPq+L@gv|GKLd2VK$bWoI*s z&RPr+pjMYDl@M|DrelrnZP&m4C53eV?nZ~(wuM0=L?tJGc~(RU53wv6#1@bVD`I(+ z=+R%_!h+GSEQ_b2c$#pPECo$2dzZ?$sW)@2dp9H@#Ostdvu_*>VY7ZMhQvnS>MS>B z-**l3TOv`0t3?w*tP8gEH;Bx7^Pf7E$V>C&KZ^Bbyo;%;Eit8iCFE~;9QB=0c2SP@ zF?Oy*zV!$v%r7Yf2Jz%?`y|Gi*k){aHaW4bwL2Yo7xl^S|31s_bwz&=-RpcZ?v}4l zQ@zmF)f4NnoJv=p{M|b8+-8%fRrl<2AsOAWFjE%t;Jh9hcWLP*P*Q~0%YBUg49e%I zmNsLSwFmHgB{I)lKbKcAlPAuw(fZHM*Z(WP4r&WeJ8LvuJ#E>yG3O|I z&hg%HqnVdJ=XiN0$31)gK5yAqFTCtI`@Dtq zK2KeIPq+UdCeED;e*24$u~M{A=%_7TgqMKT6*p##NqWNim`yZuS z9JH#ihq`Jcy&1K=HB>H-e%q}Q$o+;^if0Q^Tl0%rY;3EAZB0G)%NKa~5Hy0d9#N0GL?w`k;lbEboFE9ZrDev%6?92~PHv2EMt4k3x5t#x4(~l_0s-CnT@_+qKuO8WV&VBR_nF?8pCRImfiseexCP( zN@^!$9a`SMl;zl$+y|7!*W=<8txWAbQnH)nZB&ECH74)etp2L+a_zk z2Oj_NX=4-L%&SGyS;1Kgy4SzX?eg3gJf43;4c-9PQCJ0uxVBlbA!Mt*Cq^;L-Q#?*(#^#uU(dzyTRvCV7b z4|(r310MMTz9uk2NB&mg!H2`{Bi4F~K0-CKqa_2lMzrmT%vVqQ{RCJ}aI38aB9 z!?PC~Xd9RyOY<=PoC#M3nAfxStJr2QQ*qz~Hm~xg29NyA>GBgz-3b;U`~yOmk!KiF zNK`V*4sw`n#964v8N>$nV$?-P#AvJSM)*{?D|K$S-Pa+^&*MZ- zee7i|-8S;LbJ^0+PjQMV_EzH^&F0h8SkF{d>y!Vq?Hs7@^fnhPX(YF7*QzHcIZ6SU ztM%1cPlJ4?yPl<#_v5oEvd86tV|phyvH0ADbU>l5z~l7tOEUVZ9qENaJYv%MFu4Y6 zya|-Z*9A9FgQSjhAK)d~BAZt}MNWEC1HpgZC1iOk)gxp7t3Lm! zn}2zFS0z;BVx=IkZW!BWSd1#KB0HaVf#8$?n>(@@g``+7A4%D;ge6SRwNgud;DnzwbfRQ0`Uz+XZ4EnAZ*4n=P>KaBL&p!>zEEnz0S&Zl+-VUcc+a62F z1e#a!95mk*>(w3?0&DZ_fjT9-#g!4p&h=nB6kba_i^H|H!$MdFTxPN_!gocca=S%M zdG$DsQq<O?7a<)oaL48`BwEu zRezPM$~H7fwbR@+iu(489cFr$(RI)6Pyg(g$?cQGI-*z*v*8NV5h#i4ZHCQ z>te}hv1G5vm1h?ua}`!(FS!eQLF=rXdyQmt9f@cit&w0vw6G$(L`yXL`=9eZ^;WfQ z>`a*1JJQlf+PqxYy2$_~ zjLR>n&MGf_vN~w5!~Yj_cRRdgcz1~o{kz7}8lrnUUQQ23x3&u8LIV4+B!QwqOdwvO zSfk3pE93A2e}muP$AjY>@I*QlDiC!znRd)VC3;_<$(7^R6Z>#lXH> z(tABIYp{h|+dJ7Lp{=}$NYl=R4fxd`1h$VBZ@{l!at}22)`_m&K)jzb5Z%>(suiQY z4ZP!B@{2amcD{BiJ3qp|9|fv>vW%n8Z7^uTA`q0jExpVd`X;nGcw}7t%zHK@p3avYOJHG z{tsCJ3CyJ{p_ulHsGVfUwBrL)f8%lrI&30MjFa~Eb#@m-DMb^#!u8|HJ@tr ziMV!3`IMZa;e39v3Q||Lk-y7fCsZ~ko7^9Zi7Y^_jV((KCD#sf^N=(cvu4vuj zG;7kSxlSp-O{7?;G|HIZPPcX*3(A%WjPJKwO0K#EaW^nSH`;15w5rrm9Se>v$E2U-5*QiO8N$w`EUhXbl?r$e@!pmWL?{adJEWEeMjL75q%eU#bLzg@$)^%o(5trZA zsd1MOHxYak6F6HFQmtLfKaSL0Zn-IJ^ho%*)vQwe7D{-~?b0`jH&$D)80Lz-bt$a9 z`->J_ydKi~J9M4VRSc7p9%$jh*jF)&zKPK&{NhEiiH+8B-)xy(y4{#R;RM&wqjvT( zY`kCq5Fa$x5)3BTmo6>rZrVwdTgvQPPHQ`*qJia5Q$8)2UamzFD6K8AaC#)v?owyZ ztwk;~F(jqqieyr+SHd@T6YoLX7YV2C0r~;8i0lM^r!<(Tlwv!*353DgHXr654EO?*4+;Cz2m-f z!@KvJkO(2`J^{ZHG^J^`z1G`4a!r2vpHkdPi8^Q@)mdiWjb;M0Lq=k~(?*!=EohTUls7Ks_wzGOGd zG??;A326OTGNe!8xK5SihBGLVP{CaI{S%kwE0O9ZAo}RY)BliC_rW!-YG#`9-E0;i z5{xCGsp`O$i}<9rZRG-Kt=41yw^OX_;(tPIUcL4oo*ZAJ#U>$?f9B~*<^3lj4As6X zA^OQWpp{Qr^}#<$Vl4i11Xf>EY*}kxeD}p+*CzXpG_cnYT^((-RGW0X+nzy-`dlwN zfg~{AgL+5fww`P+^|I2{t>2=))VzeJX&u8$-6m+dmh$iJv>GVwBRHQ^@If^?qVmQ+ zHe$(iMAFx)XW5JBs4~G&zMV-FDYYwLY4O$tgs`fZEQE`F)PK0;);??H<1ViS z)thXuosT3SVLT8ld|`I6g@DnrOQTHh-DYS2Em-(2zKdb{1?9s0 z($Ly>Nrj1&Rvu1$&r7=)wrJ*G+_)TUnH{o;)&B~IOTzzBtHGAcLxeiD;j;R6U%V#KhHD46y>Tw; z7>-h%!>LrZi$`IpoH;$xUBl^AE@z?T%+g}zXQ|?ruHmRq`L)7|v)y`DQ`x1(>UB8I z5m&4pC2O|CBVAJdYzgpbfm2v1n<1=NJ(MN11k7qRwK&rIe%?x7vSefh)X(gBxQFN; zq!&kvQ#s49v{3z4(|doa)mu9%?=g$*H>eg{D#>%FCshg2;s~g<-==fL+E_Pn52s3C zrhH(L%C4B!pf7{N*N-b=I4;L!fZ=D#0el!~*KXmY6Ni6+6c1TJcgnEZk#)K;X5 zwet#(X&r})b1VTUF!)tl*;C_*-WR0K-(-b&>CPyX9_Wrba{TLx2+MV5ctS|U_C#s&9p~4TNfoM{2uN`jXR&g`o=;^B zZn5&LacAWXLF`Q}i_*)YOoS#VG}eGmvGP>0@(eN#FkB7gt$zfI)0kUn+P>iqK%QI- zrcZTcByEd^yX0#WXBS7x1iPh+vl*c?%NtS16)UfLp|2MzKaVT_O8kB;exL0G?MDEa zbSj0|uKrbn=LSv(+T@mAP%9<)GB36E#jr0Wlj$TwLL5+K8q(XIRW+atL<(EZW zy%q+oE5Eb&troI1(~F{_#ryLq#Y-Q3}i|UU$X}8AhgypjXnJ#6d)qf8+F3ynS zM4|HZP*-k_GR)^waRT@q*F>D4>VWh6->uIXGpeNCoY=%Y{KEYd8MS7Y`# zY%HND7>F1_=!a&N!z!6qu7wnMRn3lkrn68v2vkoqN3Us#=cExUbC!QD4zm0JE!3aR z6IZZ`N1#h1}Y4@e>nK*1r#5@M%=eDCcrr~Z-rjB zas=5ZA{Evd+nZ2HiD>$A{C+EbpLQTiV(-smAk}w9JY@2k}kxTh`fv?X}O^LJR#D;9Ld+-J;v(%dJ_eZ<`A zb_$J#xz&vn8ZVn$WGytFH20I{e#+c*CxrjV+&?n+GvlbY`JqU# ze=@^zXR}?{JbKbxn|d;x;zqK|Jn6t3k}v0$jnq{U{omMR1nQ99P3KBjI7-x)=>bf( zqoX6;L1x)h9Vx+=mg>N2>Y$*G4p})J9o@3PFoYHm zC9D_!0J!(&vZ_H2i%crI12xCXe;(8e0t3CK(htd+qGWKeDt>G<``FwcnfoKT=f>pb zi6nd9KX;3T++wlg<{qaOCZcnl=I^vPYnVAB;9TCq^AKLzNX9}U3yI9#Z|?qVrenzd_eR)`)kESfnlqP8Glojj?sWcUMieSX z)ge}2ux{}vw98qu_x0JUr>775wDz+9fQ>_z`|YXX+~)O}oufBMdJt4@?MN@3D#DG^=ugj;fvaBabUX$4WQe7nYT!xaX-w`?ar5Ulc!md1F)->^=O`L8q zAX{J>uq7A{ArnNFt%h?~TCQ_H5)W*wWeEj;&`d_d8g)({Y;%Tm3)A$P7e3*2!w{TPutr9zOs|<^ zDkselsOairrwuc9m;mj>ASujk;b&51eaqZ58dipN&^-@X(uYj5Q~2S5ezQ0=EJVet zJj*;|$*ilGd&Jz24lN_31%J z1yS^%K!3$%X>1xl?SV)AbtqOUhdu+>N&1GUVDqmp+ehWP888tF2gmW9@>)f<1pCrE zGga9uJkU>PMpH62S3iT{tRcEcWlDrzO!jNm#>R!Y`>fvg8OVFgeUG`fntQ9cA29a= zHiE70DpWp@q{?h%;JmarSK*zNHKv&wIS8@&u#mz=e*?63oCXLsnEjm(W`CFK8D`l1 zJL`UjG0jPD-7KRdby!4Yd!w%Gkaxz0Qo~ScP<&$tg=rM&t~ewmlD%)TQm}%VfLScL zlDd&ixg@QqA;1kdMiZY!UO}4 zq2laynD(>9>f8{2S^h|armQ|uoMrw_frZ+RZU$onNgC1Y?yy8cktF<_fXkx(SSnR6 z^EM)v1xhP9HUn5BO;1)%(|$Cq=s*^D7QIIYQNrSZ1(!u=0+NlU!0#YGG0mHhgD_@b zvu15kc^e`OX_`sQ+Cjo>*2!Qw4-GIbKv9xQ!~k{msk1|vYiiao85@B_40>_Y*$otr zSJx&8arRR{ZR?q;0aQOcJ}CFF(aq~dHZIqqdn2amXtxgFCjM`bSc zXF7{>KT=q+dR(2|F`NA9=!PM>VUJ;OJkDgQvdGB~?q(<}qLoU843^rVTt9>P!`a@R zK8#6}X}^zf8A7L0y?XTM(bvU;S%M6Mcbkwv(H#OI^o3pm)C1-|`KMHcxyP@|^niC| z&gLI-q+o8;et)A%7H4xB`}5ZPaf*42hw&+~%548| zXQ|kDj4>bpdWQk$9!TD((rm@qxROhGKP$m-+Qgw*2$IVetAEo2on;Qo?2cW%t20YI ztgjCSL$kV8#x#`&Sn;DJGB$Dh!ZZcaCvC`7f^6C>J&_f>5RHC_Y7y#@=zEHdIh#{G z3e}kN>=j{p3s`2@jMWzq@?MGdoSKstzd_9W>L3nMEy0kpP@YG-G3u$5W??LzASIDD z^)$4RVDt=kD;@u6cER!2z@n%N{GH~S5Lw_qC_IkBf5OfIS|2Q&VtmPy>4Gl|Crf0+ zVLry|NYbNTKkQH0#0Sm#cS;`hE?qUTaxi3#_;`Sd{yN$l&&(XnqE}6EXX6>!bg*&I zSACi~jMrCew&rJr>g#4%zmA2|IGDt0f~aJ}i|XqXKKGQNQItlSMCxB}f)SE&Y>t`# z0G%X-i_+$L+p^{j{dh4!?1ham_hhGB`YSl+h4}R1j^3drd@C{9ZRwN&&5_Q<>lD?uyCeF6S}OQ|50tqhr25=&7Yi9Mn;JqU zKQdtv@yknjIW9$SmGWCXe%~h@_j`PT5V?8<0R7GH2ZuWqcrjRq_eu;;Z-M$%!0T5_ zni+*|8xpU@nekHF^DG`93#HpMMuEkFA0r8g((aSlbEo?vAxDHwN!V;=)Z_Qr$I*^SPxZ1Cd8H} zgOg%|^)0$xI*ekCIq_M=SAU<^kXYj#4GR@u@dNZ;SR_~%1jgnL4!W!w%WOSTzDivy z82Ezvb70cy>Za+li;brZ+VOx)K4O*bTb9Ri&K88x(KvcQG_y(;fGLzz|0Y&Kz|gbl z8gdt4CB7inoNRd;$`c-ysa}6j2n$7u|Y99Ed>^(WQiC_Ju(4r&BK*G>`^Kzk zj8>>ubF_U+JBQeB6=XpT<@n#nJX*1~KBsxcW3uvU_rX3xGzjG@0=yy55FF~$3inHy zY69Z^TsJJwON(Mn`?W8h>da!!GKiAp3&ix&48ybHY+tduiL9ff&Gz|N>%819V&Eb1 zIxnF_x%WW}O6f~uSN56Jys0l+BrGwxYWD%Khn~`l%Vn~vj+PPAeYVPqE6a?N%-u9y zcUO8aqZ*S)mKHOWSYa56GEvN2#1v(cFxwY(Gqspwj9I%^CEAQcOd3jLd@m|7dy^7% z8!yTyi61a_{xRc-I9^GGsstXD+AM0WSF}ktu%K5 zK9CBSyO5E9qZGtOjC|%UF!m}oehQbVAoDy;8S*S@k$(9lvyG!(Yz(h9AUO1oR)Uuq zLk1~J@9~DB_oEr+lIGr_`K*&^kF)JcJMXgDn%IGRKerBasWx^QwS_0Rz zI6^nqcvTRcn!ZG3LIOpI0SEK3gl73gUi(ch&QM?y#&{&Ir-*<%ZZeVGH1F%m<`^F5 z4d5BfCgfKp%up#u0XC)qDE}FtpnfHywFymLmo&OamGWr`2>KNPF{|u29@7`leHPX) zl>|zi_lGt)MeE2Wb5DAi?fqbiu~^$>(V1AgQ5+eUF#MetapyiVEDWDm^5#A=Nu2x0 z$G;5FiW11`aaRb(Ew7lcHE-P3b02jrEsm!&RS`D0@Gh!wBr~4aVwS#x0C-I=IILsP zn#TsH1ZbQZzYtGLbHBgtOtB0gySO8VSa$SgI)}9TVW`7av*&GgoF`WKyv>^Pl-p*O z=lidPtB_2agJO6}`R;UFdV7c2dEx)0Hs_a^p)fxPHngF=>CbClP^UhJ&O(O{F?j)r z=Sy*#@E*pmv=hp>Joc=YX9XUO*caPgsQHz6v8o4{6wL4xww1#WPctCssVwW-7@`{7 z=QOx4)E+~Fh`}e&ooX27I*ZkYTt6@uWuVJTr4`KoRx9426|0XAp>c|}DoJU_LQT^i zPZa0Jiu2W~wnxRN?wChimzkLFAa9cuB~YrL1qM##6XW=ze zR?~gJP;8aHj@B~w;b!RJB((ZO2-Q4RTDc&%bw+ep)&b{o$PD7+J(MvLEu^^`NjSMO zGBbG#ui2%;;$blariHbojEjL`ARC{^=;)yu@M2(^^^4Sh;RB>pxiP7_^Y!U#oNu$jbYIbliWH)V_Sn?vhPxScSecF=;0Ib<(RnAF~3;KbxR zv>BqxRtiS!O!z*nk$R-PZ8Q+ug|y6sWJQehnDl_jp3V)GY&0~#HDMUZth_zaRFjN% z>G743os!Hebz~wI8=1`MH~A>cZ^^PciEhZk<@aWXwfPE%PjPAZiWKP8ht`liBsX&@ zKFuSKD*3Dh+c;kZT43#XGca~8^6n(Yidh($o7y1)8?l6Dt;Mb#^fXD}SD4c#CTSGw zk`zScsv6r^<(`#76H%KE=GqoV*Jqf$chgOf?oFnoinS&DN@)%0+k@ljA)gD5nG4=u zBImPa1TGoN^r7QkB0yY%e7jf|YtIKKQ6^@__!c=sW|Z2dXL(w>F|qTEs;dOjF;(WBP4fZQL|UxWxyVv92UXS21wFD1RTTOqDG>Li zBrQ~|`gyeN{B-dlQ91rU{}5`kSnDs&?-VYzyij<^yVN;GGeDqvhNXxO6_|()fy|-? zC&6yvG5;*dWb>*9fYmu!CAD$I#o2Yyq^$F@I zsIZ|Yr}|z>aQHm7rD40E>N^N_&}@FM@?$o^-_?&|5?N1Etc@5ERxo*9tSu)B<<6i^ zHd?Jj?s=_d6>E1Oi6FRHp6ZVW(KpMXrXwO=<2P1Zu9;KSBvJNbSzjM)yq)L>nyRH! z8Dq5?eK(fglqnjV7vR~Pk@Y@xwJ$osy)72Dg5s>PeAaM<^$$Bm*T%a>-51sS&p!ek z;o{m)wY?huqrwn#(Ur9s2)7h#n?>OFSw8gba&j@L#R|06PSn*+x-cU$v+~AcA9b#`w=tTfX+Y}#Pgh{Vd9QsVn2!*pvv2F&)B zQZH`qm0q<5W3eT6Bw?EOwn*2D2}B9oy%&;UZg&!#U5E=oPLK`o&=16DNQV(SfxvOU{zV#cTz zfHM)gxI_KNVk09Psv%K*kZlz#q11juhX+T|JKFOwmi7RD-Td|P*U4W$e;NLIR%oSP z3$vF-W1q?Ni}IKHFD97l^6l%R zKni+bOx>dF+u9fgjo|VJ8?c(0yVfn7LM0Zc@Df{8&*n5(QP*Q?;vf(PnM0ScO3)UT zeJZa?TI!v}I_7={PwijFMxx)=Hq;Z)tWeX^WpPV!%Z(YLXGzgdPP9pFIdRCsN}MAk z26_qb6gh#Lr0+$Em#PN1~1WjspJexZOFvLbJ2T;gEvCI_48uW43CJDLntAS+Mg@x=_vk zC}#8dCn?kMxIRN>^?RhvdBLicQK?XQ1^32`@JFO-V_=xYmO3HvFjOnAh$5==(n9Tb zaT2uew_>N~i6@s$mYZ&1eIehWW#@aDLRcm%B_54?4~O3z>AqgcVFD>&qLnBWD!s!z zShIKwj~AH;Z{kwYhGnx+7Q9wa14L6T0K*`E(7p1ijDRg-c#~tK4}!;g(HVu=u!aK@ zu)rBa*7o+Xm%8?Q7GiDnRpV%;bK?mqLxYJKtH=`Z3Dt{NmQe3PQgSXUH>blG=3guY zw9@Gu@Rnk&t-L0~{+-IlEWy&VSw6|f+iWP&GM;w8s|GgzqG2#AaO&(?7A#g?M+>ka z4F+DKZnWOR6Yo%_A7CPLf*txn_yB3Swq;(V8>FT~APEgA$!}GwdN~t)@-A|{V56gf zevJ+_63|=(YB%m$YtKtgPg1q#;{k5%1<8~RxD@16uJO;}FD47UVs$ zr)BVmKmnX&ve)LN=a2bl2bi;($zdGKFn1Q^tZ6?D5qW1aJ_lH}A!DryiU6L|9@Zke z-6;`_s@Ag=TC8^~Bo;ux(^u4&Y6_)OTCkL+qv5?M(_O;$cw=dyejN+-Y^;HIaq9Gn z1*t76Z&;TzA@*S62KBEEI4GffE^k}$=ATvR^C#Rav29;fJ6%z%Jg44+m2{P+(+^Vf zwT6;co{fdRW^*^1#i=z!9d#JZ=^PKz*tVhi;spl1My*dYPvz*1zEx}z|69W#w=C&-2sVC6xrpm>@&S*=DTHNDN9i4E=HpfgkFRcm}! z^R+>A)T6~2i0uhk>Yam@%Bo|jRTZmEb2wxHF=gtV*Vz6S>-QVY47Cd^82R2!ED_5P z%#+%4?cpY*1lFF5U22Znb7BjC;$r%=I8P*kEwA%W(~FLaD{h%WDrKj=2#ecm{-iO$ zNqMOpUfRl^b3-L%tfHY0mUX)byK#FD#m;~ zf6_(+8?Fz7L({)v00UQfE!aRShBRik5|Tm^m$WKWsbV5~A9K=H1;Z{_v8bw|ak)8U z@HOJ|KR%GGJ*N&sD*srK4WyVYxRl3|dbavdoZl?LW7owa-X($XA1EA)x3|d{ zjavay*xX@5lZa}H^IAf*fU|&6igO|090A%?t@*z5h7-naR;zfjdQF9y*Q8c+ zC-qL|*8Q!iule&fH!I-O$4EYZ#)32(hBKZGn}5p!bD3^z6pd+k%=%P3$4zazK7JQC zBukfp+|R!ws_~Tj0u9XhhGOlE1zwN<*Uo4rS{nKcKN~fY85BwD4$Jz!<#^xR?*%Yt zE$}@9bCyAn*7hvL#}@Iixj!=ZM{F0i1`FDY*+QMI9aZM~`q+27`EHAScVcuv5|oQ^ zioMw)#OTk%!gfC)tBkb|k?0UfAU{DW%zc3!lO4QoC~;m-D%(JL3Z6Y|Nm3*xk%?<4 z&`_mXicGdA8(i7pC7t1OqX%1<6TZwp-BPTb(@00er18(vNO&>j=r;J<*C_`(5GJUr#* zT(paj8WFFGWy|KI5kPi<)RXL*dZ)zsVI9sepY2tf+i0>pl2PHFDsi}GZow58MzITN zj0w~8MvuaQ;edom<$+-%&lAPUv&EW8XypUL^_DmpxrFO21j0wlR5*P|;Zec2BCsC{ zkCGVO{3r&j&bhjhQsYzv*wi_UT+a(sJ#VeXM#e)Wtt23nK*D=4r|D(AwXP5c+F8^z zYYcH3@3!aI&)OAd@{ohgB$k7vKo)vEj~{1k_jZ)nQNiI`ogiS)&e4b{#mGS3Zh3iY z`ANZywY2M%H4(+K6LkS{*>=d??cPkgx2xUTi2{a$Rr&Ua-ga-lj?^;jUr=<9YSH6} z^;{I&r%Zhc){wtGsI9q&N{m)GBoWwrezm1hMJ#_Gaf(#97pK;fk4J)q@d z$#7=|VP~gFNlRNL9R%WVleoBYBA&TBVd~F9bl|$4XJUqB*vfHJy8VDy&iu)iY_B#( z!*PBfgk%mT9L5Mx>UoD-M>T3&>tSUXu$~VNQwQkl*8}63rJS{)ENcgbK@`c)_s3dM zDoxw4?Wbua|1na@_S!K#9l+0~9jLZP0b8e;c|DD0nY%5;j5JCd2il*dH_bqL{861I zj3GOQy>^VPp7+Wc-UmettM)*Ddu7#LmEVUZ8HBx+6y{Jwwd~rXSl^(NBJ7psfFcXz z>9iL8R%QyOMm&vgxQ+wFCcY`y_8Ks1gSE9f|Fn9b`exuT?IPQ@zM;hY9zn(W9ZcEQ zHx=t!aPkX9Z|2M;is_BqKyT|Ic6JXdw1W*2m;r#woX(HsdA!yL%o(DxG`%AUA&L^{Gvkly)V1w{P^p~a zft`}@;(@(!Lm${nUtXJFRi=1gM%c`fglMH|E~*~b=_3NdZG!Q@-r-Dd@xUYai?uUD z+Ac)fV4D*Uc66x|Oo&L$GD&x!}=GeFI2xm4Zn+ zs|Kz<4wB8PS0B%_#R6Ov?h|&3qpk`u6?YVd5K^_rOnP5NL~@wvkD1-Vn;QAfe4I^Y zA~C(ZvZRZ<*g9dgQD4;BHWSGjMV2ol`YYD;Qw9S@+%Z*^4q0Ti!B_7J95zz1at%)s;WMQ_vQmns5 zVJ#&wGhuDbP{?|L(`hp@e_5=f9#2cut-Y{bCG!CGeYCL_Cj9rAC|jcj{!Z{2&vG6Skk;WpYyy;HPufwi3lbv zs>SFj(Ft|F>QqR=g8+8s#Q0G@i(diT>oUEzs6;>HbDTs2jvSja*AyCK#fD}wX#U0s zKZ90mEKyks>$e|=xBRyphol@`c(B-5!N(E0ij9?GDg!{jmf{ObsZ>`8>hBru(jH(= zY1(HDx;Xg5MyjqHOKDzsNU75KWYm&ud(q1=d{ua?6b?L^7LOfx zlmIyzoA|L4Q(k#kPdZQ$#fGD%Z!y7V$w-JC*u|wp8^?7?n`}sGX&t6h7!h4Y7p`OMOPm7|*_^CA=H`A*5g8 z+Q_pdvM0+yO~5ta(rS-}?bR-Ajy!=5)=qzUb^Or7{ls~XdV5daJCeqJ)@Nx_eRg&m z5QWBO=s`-x!^RP*p_7q!NVBYi3S=K4~ zcV*Npt+{Bo>iR;}RvTKfJOIXovgwTP9js?gK&cuJ-0XlbtrtLXAO_el?}G5{2u%kd z)2I!O5D#&LR>bso5AXh%V1hnf!eEP0hBpkb)K3>C56dD3L7(hVfRnxyurC!F54Gjy zls8mLahj5m!EAPy)XjPqa7S;~~T2&U|ed+LQjs z8T}cpID%RXv^~v}0T(#(sTG;tg(zIQRxO#11UHpA5^y_m2}n+oHhAr*JQH$1(*p7t z9iN0OO@f9*$KuMBKB02Y20&EqM2q{m8!|f3@eK3$7q!`CNJZ^VhN4flfI2zE=V>kj zs-=2l|4GRH6P7PM%SDxXDWrKht{t|>Wt;Amm^a%h(O%|jYq2UWgIz0N2XV1%g7&F^ z(y5kOH{D2i(+!bN2aa>8i-n;br!#RH4UQ9mX-{*urL1!Sfpf8-wUMMr!j>Fwg&a-C z`8F}WBw7~&#apq0cFkS^TD-H;6)&}J*WQkW<-C}P(B-{=(R%?+K)kmuvq+88p;>{1 z66TI&)!RkSu2jcGRRyE>13U_O-}N!)CM>z@nvRfw4=%kQuxQQoVF>&%qy)7Ou@^w? z*+TU;K5SU1ZiEij6>apc=r+rATcN?KhQyPE>b*!6pnV)W=9t2=UTaQM+DbN;4UYcc z$Op%g;1~=JChTHNRDjwe#0&?=^59qz94mukBsj)`V>~!+362fHu_+!V+joKPXWm*< z@JDj~eKlJuz^>DZfedc;6EoPx>P)w;9+N&6y9rY~91o$Gek2PH1UiGj9ue@sTYB462TkA{#Zr z-%PngYqxQ(X6&_>OB{c+s11Tp`Otv+Zt^FX&`6AxxUJ{2c^$TLcEGSt+IK#P>^$?p zMUF;UB{>G=Z%wr+e0luVVv_tTc{8EnTfaG0;pYvsJgvQP^Y<7+*0S-20O3r`fs+&g=K{# zOWGdumKB`tW=}Vt(Ewj(JF?rVwV&iDvL0=i#z+~?tYs^V-bDFqMZs5*eU{Yn50cUW z5-8p+#<|P}tet6-%b-~kv0)k8Rp~r?V$hDYGu~9K4fT$LVy9YS`CUT3=R?ml|DJ<7 zdoif@SvX+gQ0ux{gVh*q{=?PkyA;Hl=fb64fiRWRT6hZ+ebiEwj~vf)tw}G1XXsDn zKc?X{!B@NB3i?9M5kG$s;s>;!SBPs9f){iC3dOJh?36u__Y4=Vlp%Cf2L?@zvqBi! zD?loF#QPUT3^VVq`B)M3zzVpKWgR}cBjZqeGfFy^)6pFtHMBT=X^}YA=`D|)csO8( zKMsul3pEInySKDqtgWCh05ssOJ@!rk+AQ`vudxIW`<-DRSnR(*yCuzafE87Z8iC_R zRP3-42I5f-VXU==gl9rRb131NB;lEsgl9uSb1322B;nbXgtm!8buot$UPuyNAR$^o zt2LZcXAWN^UIAfzCdXIhMDR_haK)_@)v%SA3v;S&*6u9DUx?SnpW57NoOfVJ_T*Q-_t%9td%s*c7A=pW&Po(L#kB$5X&(5$ zefP%Es56RE{QvFb|Mta4clO=>*tREE{Ura3|FB~B-H&$t`SSn!?~Yw_>uvwnm;P*e z_=f*@qW|B0>(CS5S@ol@zx7{sKK}Xt34KF|Vt$#Ul*MEO>|7|b*t9|#pckLU+fB&<8^RNHg>gLD({onpSN9+IH zzg)B`|CN6`bVK2*|Jmy^8`A#^Xn?Ei z7r8X>i_vEOe~~K~zsRK~yJDBF*tjYBTHF6`M4cOeng0FXbv{ZloqzXtfA^J6mDIp8KzX^1_$XQRj-Rt@XDxDH#%MOwJ5ng z&2J8RfcwV=TZ8Y2@6Av|Tlzb>9%OIy0GDk3i@Rw`-L0V;Xl}CGhZo)>BNT5pgmpPu zxc5o10sEs>Ioh-q_FWRgV3qN}P7k!hHK5L!67X^`)*pQ>XC2A5+Xi z`Mgvi)Bn%~s1`dv%|cok^-?w3`;S?eYL~uV<_}-7;KOJ`xWqhF;}l&dbkVeTjp1xD!?x}6#loHT2XXf1o;6) z?l96!NB>OMz|C0vJ}y#gzdX#LuecP*OC?+Ye1DYNMLE0qQ*XUX-buT_%)P_9&1?$v z9tN=;G)o!dur>W96SP9eJN%aFc?n5CuDyCikH3SWbitl3<|9aDwgzPtD}=2=s=e-7 z+X)BtimEd>%h5HuwN5vvi%Iqp=;ZGAEAdp$OqBEc@+JYM%XN!>pRQj(>9;NdMK#x* zZaeIH-7**a&PM&Z0#G)xQstFqzcJ!YF!^DWOD;g1CZbbGuhEUcJFIETE$!W#Fng~q zO4Sv4JEP9O#(KV~op(1G#*-MhvLbc^Dcm(YNfl?K+*Zm??5wOVMcfax{;!c-K!wWM z%fY-2h)%oN`1at|i!{6aLg8$w+p#nFgQd0OC`^K1rFXt z-M{@1fMx*m<>+Sq|0Upbk)?(Ux+?L9#EFHzZw^5v{$M-#h0Q|Jt@8&m+DUqq;hqW8uY21BV`S413e)83~t=HZD)42+{+W*JZy0sl8gAbZ|ausqr%<@m`V(98M z|M1lKr+5`|wfEDbORJpxQ=|n`&t2*6u8!`)68;AHEAcn1F9SC=;99}oO8!Rp8%uYm z_1(Msx|vDkaJwcNb>`qqaGckA2OnQ5a)lRXR9*_fR-lwwK9QsGQg1Ej>=_aYm0<^f;x*YkIuQ$0Y9~XZ3;} z@9Qz7$9szWxm@qW2*RkAnPQcEE@VA2Fba4DU z&blN7yo|&4I&TT|s=gy!ZU9jANj;u|3i{9@=-68?jF)b8Gx}z<*Wc+04GiH8>ru@$WA@_`-B-sfAwL1`#N;? z8igd^P4&b6d;oydaLf=#H@ef^d;q>!g++$?_{%MB&tjiiRf3=Bafel2pUjkRs~*RB z@L4nE(ggqk^|_A}xl`daee}@2nf3!#)vFEYvfMsQ-u`7WebR7?RU!Tk8CceK2+Ap& zGjI6>l44#}xqJta#Sf)9Ycyf|yMn1(Q8cUB=hG@Wi`;3gB^Td(HC(w)kEG)M~iPKIXi+pGZS%Rt;ip&nC&U$&LlLewe{1XC#>w$j6mhUrdnadLET$^>{*$lK__-a2nYh1EDo)jVAp$ z?5wK6U3IvoSUaJ|`4CN3(d{Q8&HPDupHrD+VKXpqwW4ur?OFRsb~tPDOs<*rqqfsRO;)At#8!hHl;((InAlZ4|p6{Vn}dU(U1^euK{%YQb4UcoRg{DWYfmxN`NY5BkZa;X^KuTR>6L`m?Qvhi zodLC_UQpWOdi+?AzfsupO-QE|_M#p?RRk_J_R9M!J${Xs{k*u|4ml1~ z2y4J(Y!xO#UbfkPYSm`kSXODLmFq{bG|bcN#rda_B)RaBd;45P;vtJtJ|q5;R%h=9-j|vg8>-#> zE3qH_U>Lqu@Z_iyvI(0D08pc`piG9Ex`f)9X4qMI&!Vbt!EqqlEdBz54QShWg|nGn z28u(wpqvTt_d`USSnJK6SS~M6uCta-F6H&(DxH9;uh0XDVX0YcrFCX`M)VkKU9gRH z&Vj9p8IRM77HzJm(dIfyb&VwKsdR4-|si501?7 zsXIG3GFTYqi)cDZQW)&wOi6JU+k|rZ_G_+NkBlBYp6QU>+=tVd>&L8R3bQLWkdsS6 z19EUEl^`YS(nHr90b0kb_3Ci%QTHA-FDgM^ULDGu>)_5Yp4fx}z`cW_klrT^9 zHCnv5ECf^8LfFt0y9#5tI3}qxdggA%KLtF_=JC0C3OfQ^-m~14$7aP`mb1jXxbMYo z>ct^=9;i~?LPWfv*&wT@YN>@3+VCmAVjnky1@{Eg9t zGs#QldBr`inCCV3yk;JKumfH?+ojhdeBGEDyrCnfdEI2nfsse@)YF8ldHuEOOEE0L z7gkt4o|JgXL7lSe?qxjFzu7Ul-{DxKU3&ytUxwelz=B^Vqd(wYn`WdPz*!K&S;7S& zhZlexSm5XI(+2?$81n-m$Utd0>JZk$hV`(VCUJ$5oFf)Gl3^no9WEaWL8Roc%AMfJ z2uoGuMM^%EpiGaD%u?}TEDje)8Fj@F2I8mzPWu_ibR57pmpwp-zdbvyByg@7IF|$- zYz7{*^Np3qo!lqX{0s*9#6BN4;hoNa+#|S*FZk9WZ@S(k@DF!^pm4C~IaF4xJkBU7 z$63_aMKH&x<)LjunkSoS%oWl+8K;57w4C3MEdo{FF#=WJG0*kxx!yeQx#vCeyzid( z%`@blAv}fZ7v$k3PvtH1RNgYrY4@BK)%j2ysr0!x2C*LgGT}ujOGdK_;bqZ3_voK1 z+n8k=lXK9VgL1AkCr^N#^VH|MB3k>YtmOGA(+V8dG?x*zdPB+He0Y)c$Y3MO7x5XP zay)lL`X+=(M8C+XSNzD-yLoX+Vc1_Ke~s8Ho6lYE=}6|O?8!!Ya*XK7cUyI6w0dKy z$D|ZRz%?SsDG-g9^_{hz#)6p z;>EoZOHCs{Gl+mgM5OFvTp_8;mE%qt>zuBd8t~+$7AKA9TX~$j9y$P^lZf<<#COP< zRw9J)n9Jm`j;z)EafwyjKcPuF0BkThdkXuIoQqo>-xJ`Ax(9dN#z}?cq>8Grd%Vsu z9Tn`!^E|R|KCVh2l_~BdLQNL1 zpTo@;+G9|z&_kS5d25{fAp#2EVOz z`8~VHoYbb>C)x!FoZpReh}}FdXZu_7%ID!4;3Y8S3s5*X--d_$o`;XXwB%{`spT93 z#uRSt;*kAxW^SUEVlB)KOPDk;l(9bT-5(rwHE%aOoXR*4>uV#h z^3(p}ibCmt6XR62CJ;wLNnyF-_+N6!=HoFF~$u=uilWu}id(we5l&mI& zMVNU^d*L|}`boaIN31KV+7Y1Gp%ilHO}+JEkmQ`H&JPmAB4fTlwFWUkei~wvrevu# zb6nvjdNvrI;$5WP5HF`aIu*^vN1H0Nj>5h;rKI|7m}f!Q;oSy9T#hBt~uJ!|p7k#TYN_R9p(q-IR=`rG4{KZJ$;^(Sgy4W}fQ(KBcSa7U5 zuTQ(B&4Fo5xQ<#2s(TztC&PoZ9$7tf>Yi5Bsr%AE_*6?(eYZY4WULl$I?#ttckl<-%E+ZX(C|rp;mMd<0w;Q zd7Z2`mpWVe&{R54_29I;b*Ow|$nZrT73;fm-LE3aPw^;olAcTvrRrw!Gn{}j2o2dV4ho7Edc`Xt`g;R4QpXI@pdXc_8!E@ zW)$p64{}$a!Rsa8Q3UY?8cYFM`4Iye>_#9K29;qcm#0B1{ALyM`IYJmg+T}&hcZZ) z*}@ITY|yrZM+<{ZAPoNngyMyF9#V;BVu=^yD@$HY>(GvQ!d`kj$q_7!t5kB|Xtr;- zlMKb`FSz=+m-dkRjeH52Gv}LJDANr8CBswNM@fDa68yR~!P`m3cNHEI{YIWp(g%Dz z8I#w*{I&`EcX_^r2H+96rdYe)M(+|*4Jvi}1-Copu*zXvyU@@sdqPxn?b8j}ev84> zMbu`g1(HB8pY8D+`rbDHxTXgg(Si1p2g+D6Z@9;PD4#Ss%8Ay9oLO&qf1 z)9v08Z~N=Fy>u$+p*~%xw+Q7~)j?Ymx7vNW5Rj_4f{{Ql36Rd`XmYujFUo5UfmI;R zc34(B7S>nlWgETfb{|%sz7U}Sh2WznYxlw=7BZyqA%3H0C6D&38KKC>=eY;^hWY$A z0T4;1D&H{>O*u&+Hu4)Ws#|?2NXQVVr7l)fg)N;-2WA_ZF(CQWD(X15d~!6Y57!HBPisHY2w zih_1|fl*Z3~w+!#0tc%ICOa(L8GV z-h2*u!F%Ra&ba|V&pnQc8+7K)Aix@(D5FP8f}RWEaOVFc+j^txA0%P!*OHr&jqek>J#-^s(gQ zo#s+o>(}v6D3^q66k;tt{?Y1F~mr|6SZ zTXllurSq%tHA=~e9B8Jl*agA)M3DueGUAj&(i2QbW+A+Ua;eSWf_;n8#AIZ|b^ut6 zn{&jLIi!?==nK_MwCIm<=#;D)0{WLx_NEwE8BiOk={Uqa{Z{@%ku0h2j(wE+v*9ln*s-Dd=F0EY`dz6Hm zq7 zf|#-4i%VKafGG`UJJ08a{Whc$v-vPTEuyJx7~E>MS<=a|TtcK0ARMXbeQjyN~!B&CpEqWLj*6tLWE8_ z2cRSj`KF3OVa#fc6FhX*Jcf~zq=G>JNgKtv`ObiDWJ)h_s^LS$gxir~Qri5Os=8Pj zU+bB*5#eThl7uBpvY2WhFKWpa0R!{}H;Jb8U~!g5U{useUUiHM zzaw_Gqhxh6$kz<(`<8$+A3%*Y5KqiE3qo!L3W8e?ESDnLcgfFP=UJ_X?v`u|h{Z^A z#jFKYpB6I*8Z<+hw@E@ncFpD}lxvlm6>UitGS}%L#4(Oy2(8^_H@C&1MTjWGTId=Q z!meC06|!T~8TCk+*K(qe&N`QzB$28A+AXGcY8(8u2`dMckmu&9jJgtT(6yfA1$y1A zrea=_o*`xnZKC_-SimL=<5RgT%YDVob_XFH4dZ_L07kwVrDOi;&BaGFD&NU8S-;Qh zr0aYTLJ&m0&QL&jY7IqS&_JFruffV>>_oT7(-1~_v0V_BF|Mecuxzyx zQofctc5pL|hs1!n4MA2>j1}d`8dVR&EjlET;rpCMIJ&mS7J*Urn8u*SK17ufzjSX8 z=+2)siw+GUyOe@aKH%U^>@v&?52K%uc}Ew`vl+o=0^D}X4%fC+&XQARWo>0}EFXY1 zV*Gs4UWj5Co;8e~bBvy|ju4__Da7PQxiyJ@q?Pzbgm&%7fGDY(d}P!#AgH{!j9PM- zy?Ko7lDLy(si(`t-^fgom)jk*_a%02|;4 z6BpHEy9~oyTyTb4VW6{gfZ9Mh;X@NffiYo}gX|`ZXIvQ1&@6F)tEMyba+p;nogf21 zk6}vpd`3O|c7NT;3rRmGd<*`~rrwd}H8EZb*w&O>U4ievi5O8 zuJa4YrGOT4)pvPie&BUIuewIo`W9Zh(5y%80wI*CsSLf`d2PlISe>#wKw= z#wO>TP0lyj11xC};+RxL4%291PbMCpcoz=I z#JgdXHz@JK&&LQG^df zQ@OmL+ItD)_Z_lR`F#iWegLLO$!6^p#q%;jwb2dR%PrVPmtYaO%R_`> z9Ma;9H4Te+A(A#}^{^b5#2ijw3^>$oe`Wl|+CWHb6N^HKCBYEZn>hPbD@C_}>`tOH ziL)nh_IW9B(f#g|;RYma(B)-oI^1~4w7I+xE);aMwIWADD0fXLoiiirr_#exPhIdj zY(8R^G#lNRUcpB59d9NjlKLPno=s|wbSWw3k2FWB@0%+TdsO|+4(~oJPctzH_Bk`_ zEV$X(<^bJ8It*<~N2#5lk^(~9MWFZ`+Y{CcX%dWksVZ(2>w={d)}<0?>P0uJscWZ} zgG{utII6X17D>6Rrlk2`%`daYT4%;RZ!^jD!JG;IAZ943tS}NosKiH&K?k`X1hibd zkg~x+ZD*6&25Ay2iTd<_fsM6UQf0Sv7LvpPj5M(kWenCgFhwBy#oSp|5P-aa%XLM) z4IMVE$Xl8}p0cfP(7fWbv{ZdF#y0a3rVKYNZo|W{i9XAxv|`*s8IC6C(T_IWSyp|5 zN3{^~3iVA4=|MvQ);s}cW`W|0fPxHAk}?ywuzbj;?4lUiy*-36AJu1&hy9&chZ!Sx5%Dt!Jt3*y&?)q_m z*+x{(AGz;u?8QAG&1ODr!gsn@dEOfCv{{^7uMp?6OF1e(^=#&;|I9)C%+mYZblqm8 z>#uvv>lX8K_xwD-f6-ysyepSwZal#ZNjRDmJ;;c zUj~+9W4Tz!O_gkmQL%Qr4gaY~?S89%4WSzliL?-8uep!hH^+-)wkXEp&=VF~)6fJ9 za)N~l?+=Fd*>zyp1tVo> zyJJLn4lB7@KCqW*X>Gos-URY96c6l8@TWoW#I1nG>|9&jAt`uV=vcv5QCD!|;fg5N zxq>+{9vmCO#d)C>Y_2G3N3f5ZY_vga%Ie9fL`$;l}W8ZN?5vkRGvT#hzQOoU&)N z%`OH`J6tTRrtJz@g=x!5C|BpSL4OEZv+2YD86|2vgkSAd0cAmwXZ5TVu!Pi{iUN+t z8iH&ij5AHw`K0Qdi8E^@+u~k~7M&W9YU9m}uQXj}o37U^O}{lDH+vab&I~hqvqz%NNhS zS*m#UP40O1O%**RptUFaRv^bdFQx`X5z@pIR`QpzMSYDS@C6UbdD#rt9YeS;#?2&% zF{>~Xr5LQ*bGe1w8){xTs&-|VDFn_L5I6o3=Vr_Iv{KYhnfv)9^0Wo}^F_HUKedpb z+0&S#{<^t;ZqGOE`36rqAu(5%oOB~(ZKy5PZOAP=i}fYeUe+}zuKGGz_^3DJ3#v^4 zCKJB4oJ~bpJMXv*lRes+zUD9XP42yG&+gkEnJVv{*|BH$)`#}(`Qd&(59G%sqv}Jc zsJiX0@(*YB?B2g;`^-&W-@j+~O?OW{RNghYa(K(b+jj1l`bK$n{m96wu@U_n8@Jbl z`$k6Aj;ykPIDXBlHLJ%)SC1;Ch0Dd?_BCrqr?;M3rnavhFHf$U-ZnD5Zq>xpD4IsxQuQ)|}&b@jTjvGU|L3Zmp~@JvzE-s=RG_+qP}1CRdG*j*YLIo+_6ox07~!_2lHl>XGfMSB;LW-oC9o zI=yOQbaZUhnr%~SfCuTO)ZhZUN)oaUBV{2DUZJ(H0wPtK$Via~LuU%W-wrz9` z3_QMO?dtK#HKXgs$JfD^+s5I=sclo+N2b?It=YbP-L~@hn#r~B>O^_n+BMT7lT+)a zrs3bU7;bcQWMcd1nz6}kqhpg3W1~}J6XY0Ovu0{~bb4(2 z)V9fy?UUP(IK*k&SQ$ZEGqHNx$mp7>$!)mSO;4^K9bLC-JDj_A-So&rd3t(sY-DWP zILr^{uHHVfcGYBg-RShlwpHb^vDM?-){RX~jgC%F@u}z=Qqgh*Z1tM)$;lg6kFMKx zIuZCh{Mv#-2y@7|T)E$`cpI$Hl% zYj0w9VQX&5*Y-{BD*tfLzVC0^v48K*$=SQ`MvGEWZ_ilV$&~r@!$VJ9a-fjA|N>qFYnZpP5>t{NWw@hbM>k?%DhB z&dGhl50Ul8z2$w|_w3s>xqGTS{PnxPdDrmvfXXo8!@@d>3aO}nboEUmH?6*D)w&5m z9ZN+wd&rkYCRdedspwA@q_U*nE>BLE_kHP>yT89<@5cSJyQlta z`g`A76-9rRiY7iOz30<&E=`}ddk%`~&q(i>CJEmz9Eao@hl+1q!|?D^{KOxZk5 z2y3HgLn`{yD?->kednIPDsSC$>z>^+<=qJeqoDBTspzYp1fVVF*Y@q%MGtuqoHfR@ zBbS1+wfx9Tpx&lEMu|W_N~ih8uas-c$D-&fsp!jB%B>QG z_Sbgo-m(9oGK~P>KuC(E$^JAIt-Y#Zzq#!%%Tq0^N^@N`%D3*>wX2QK z5tOUpwA&_U{^Fq>Gv)nzC#PB}Op9MN+TL(Um1*-Yr=m4is`8zaGgA+>bIT}A{moSL z^{dbN7ihe#`zCkngmvyN@15K?iB4>yvI=c^HPtXw&{lVs6Y8&mVJ@d>S_Ryg9__Gy zX5Yh8ZH3c(m(!IO0l4eoUE9k0?wY(S!JP*DMk@N+m1tq*dv+AYj+q^QRla@qb|imh zHi1QR{(-RWDnB@RX;?Jx)zGvBuLKX;_iC8Z@*>Z4y)Cs^O^a+wMPIoRMI?nzkV`0& z)rj&{X%p82KX`c0OnLfZRM6vBBbtuN&Ye;UO)9KLCtQtyY@Xaby|aAR!#j5-S+7zh zsN9RR|7tkuYP%1Y>2~Q{4HsQ)ey9I}{BX|I^z(KF&+|4 zJVwLco{BbI4flv|G&0^>p58jUx4b|vkJ0#7qZtAobfx93J9Z`7b&OX0S}NLjB~%sy z_~!QQ`&%^B*j2Vi6HIw($F9kQnZ}UDt5HzR{CgPgC$(6EI9`n~hwKn_^{OT(uYrhv zNZ|`QnKh7bZ7LeQ90~toAAK6e>!v-o?%cCKLHY{zNXTZHzUpSk?r9Hgq7KX1^^-cK1t_#L#ai(H`)B@R zN?u0`{Jl$_KnMQ)Gb71Y!#=GfpJ^jGvn!w6r!AoQMOM0``43>5Z%_WPz1c=(rhYvY z-F7Kq4u#)6yMLy<>&DwnZZvsLQP#RH#`iWHaWd_j$w-zB-3n;KkBm51#1-n!@e<-{70HF!CBxj5V1jDTenF-&NpEmQDvv~PpZ zBJb+U6998XrL=ls|0FGD*DDBf!McMFkn!!`#}L*Er6FY1-~=HNN#3FdH+pc zWe#uc*loKt4yPY?N0aiJ#VMzv2Noif$5~0NwLW)9p z=RQ0|>HGb@zxVz9{(0Z)GoE|z%$zxM=FB-~&di+wM%~ZIb+ZBH%!RfY8fz{fr4FOc@~^W6?_VCaJlFY#6PE1Rez5XX=R zKaAsYecA@)Z{zM_4+eK$o+xJ$|^MSpKA|gjXp9H?(-`r}yWdeQDAB+w$xy0dIVn~G0wnb@SY=#X6F!uVv zLqOUA*E0WK=F#y2Ud$hYYI`RT1~sisGGg1Jwv%w%t2+Q5^s#gBw72o}#WW*4&=f%;1hyybx&g*7 z_iI)EOd)IzP||)+KMx0tlLu~jNzk{p8`G`hh|RX%^|3Agi{u5e<~X!2djE_7R!aZg zvVcf`X1t%-w$v3M{b$Al8lGQH1?{j|&w!SMXA`z3C#K=od0&8{ow4towBa0isLa#@AU0BOqYS8K~ysju|%Y4|K5e^L1E% z#MEEj$XDtz}w{u6z+QG2eXiN>nhFxjS2wv z32M9SU`!4>zI}m2bZ`n1Ky82n&S;<#fc|wyBAkBZF(U^sKjQ9k4AZ-WfSF+fI2Kj_ zXd62)Z3WN(ij{vu(1Kxts*4?LE7+ie)?H%gBcl9rzlmbNMBBMl*XjL35NcuXbX&!BQ1?Baa_DcjF*I9GEEui@@PHIOWEk-dpaGn{$Bs zjT|@t+UEQiXq4;gVn7VIV1VRE1OW^legcmM;E-lxXV6T(z#aJ0YO;4YigvIAw6{mO zc%por9Z<^f1hLOi;AwMo0TF<1LMRg-@ZJR`AV`I68F<|AKZ0oD=K`0Cg||UAn0D9= z&S8>m>|G9%a8m@h|GB9-s3tcO5$OhK4ps#1P;z(o3c#{7ctNb`=?pjq)DcdmL-Y5^ z7{R9McyQDF1`WiZFpaidOcpqKdiy+~0N?Fn$o^PPDDk#=hyiYzU@(k8(1Iz&4O})= zF*E^*2#vzDBGAF`a1jN(@TdSl0Qml2v6uav9DIem&`!b|CbiFRid-2;lkKeMjW&fD z8G8#b#&!^JyU~a+OK)ab3c%b2hdyAjaa~sU|h9T@W6b!ML1v+{a`XeH=V&-GkKNwGqC*L)tzaW=;d9w!>f|Wq1qZ{)-zk`N5 z+HdKBWbt=_>+~ZZ7|j58Ii_1`{+3)8j)U9ON9eb>AE4w>ynHD6eJJ#XR74;`uL5KX zHiYH@KmagaG;**(+c~Sb+c^1b#nspgjH~Qj9D^`8c&w)e<*v(LjL^VzEwG}*%LDZX zNsQq?FggRX+V&0@KtT5XXeJ<^H?Tl?IQTkyZ59dANQBsWZD9vN5P;+E4o0q^W!6WoK>XUE9R0wQzXJ-;3LaUayc|*3)iXd90;hdeE|XYG ztvR`>`ss6tfg^|3wEMm+u@r|&`QEB^t){+OR_rZCasP8eTJdD6kd?zS|G!H&L#`NL^fx7&ySNSbvnYn6o zIdU{DZhi8*5Vf3aKd zpd%1KvLnbrpa5Yf2w0kM0IJC$_93{zJNSZW3No_8?4v^Fb&<5IjJDukG-Jae!$7Uw?{+>A0DGLI@O~lrVw=aR_0B;6?BO>W~1+l7Uo~h$sXv ziVuZ_2gAhH6TaUZu;wMW zfN&I~K8k>kgod$3A>d<(oxp!V@D@IE{O1YM@af0|>h_;6!S&^vTDa>DVt7zpd95@U}GhTrSJdzSpDzbZ)e`w`c0 zy5H;fv!;>&6PPx#p#6TrG6k^E0NPL5iy*`>DTOeVz@(15&fOJYxc zhR-qoS%dBH7utlCJxC3!CRYR}fCC@y?F4G?j-kj=Knu8~VVe7bG;r%}eTPC6W2lZj z#Tm7QUV;d1kQ?R`6gZh3=7)8h_kfZ%m$lAy@EP9lY2a{M!JM&v>0|1rw}A%?4aN@3 z!SEB@#@n~kcJ&km(hRwAdb>T~E%-F)pVa!jycgdQka#(|kPbw@ z=?w)$jEh9%;N{_jBEZ*TTl3%?d2z#WC_r=Ikl=&^ z=jJUjpU@Y!xJPLOcCyGEK7RdpL^SJnZebm+YYFcotcz>q53Q1>>)@zE({H{{Plz9K zJY2W8PoQx3+9~tO;rB0(^YyFgqls8OpE8rYVr$QcTc)7!X?mT->L=Rnb^hfZ*R%@v zR^qPrq`@cX2{bcidxu6^jC!s&2h2y`==L-}8!oJ>mta zSpAnf3*u>Lo*LmHPAs^pGJMxRDoV(5q8PYPf~7|+j4maj|xOD>v*OWo2lF> zrRrT%nCVlYchl*(*pytdwoIviAwT(G@AxUo>zC-5Iwe?7_W94mXGs+CRu@^ZuR>C< zhKLyTXq(3iUnZ-cUP?96Ic@(26Bz+S#Lr+YV^yCg>*`@aTE<2x*UV#~kvxT9zy1Yq7(Ywng=KcJ-IKhe%6(4@lYF7!|KqB}HIC5JofK zk(!-x=Dnyzhm*V~p5rw#J;8jTrHh{fvzJJ|g(SUIjyE}1JAX+^aP^{f+V@io%&Vur zX(yNU;W|^O5Ye(cx_*&7$9dhA%M48Z}eOFSi$6VpTje;{7Uxc1&A+tZnQq9&`>~uBPGk3Fa zT1dJ{O;P_sSe_SsmGR`x6Rw9YrHxzPPSu;=mus;m_#}InCm>1GhsBA+e_`3Oysnn@ z9vN?D#UpwrQZb4L_ap~bYLrP!W+ETh_D0ebmlL`bdwyu{9J`^)*Em;c6S^nCtDDAh zcZ{+9LV-?0?w2CB_ut>kt_BT|Ck-|)wD!0UO-AINX62Y}m90Po5AH2eW;!{TP`p$A zbWuIZ%Zk`aMRhF6@k#L^!ui?EW8{^_uT#H~3pA(nnSAq3m#8MzT5IOx6<9PB9H3!1 z%kzdVSwB66)%4|UrXNN zvzcW`|4njMO5~@U1>f>Y{gktZwn}vdhz=IsB-9k}M|>zXFF&w`0iLrF0Urj!F}T!x zzr>(`Zy5ea#|Jo0fjid7#R*>1gi=uw1>*Iu#coFs-y^b!uQ=IzOQ`DSG%2zKx$2yJ zICe*R>wK&#Gs;jViQxMzg@_AoL`BCDzb#Mn_Ud*ladtK=YYLS(c!~5rA^zMm9P8G{ zQH3&d-usi5o_*UBztnThU(teUrl8lVmb7>E;lFMD6ArNWoE=zU~|*RyJ_)nbQ5_NBHn&s%Os?NJgYzAEQ5(~uA?8-Y8xZ(L$h zo96mzx|Ym1!?UzOUl+A(gq}~6QoG`klf;vK5e*t?=0)$Uo_N7Ymo^Xbf6MLABW7g2|jny`ZT*Z_&fM z_NRrPmyK5vPjrq&t)}L^DigFcNpo>IM@Ami&^dEm+*{xBiS;0|E|yT?S~aU{y-nT- z>-($&1(#z#OwozWrki-ryIQ(b48PT}4?C9AXsl7in4$YfA4+X$A-r9X^wxEyP8=snb`G?&zS9Y^msjv6L@+O)N~`)V8VzYtc37EIyMj48p&BvW%l3mwzY2stOVY1aY?WG=V zlG&q;k+Bh4c}lYv_&*lhVb@$BqT=Va;;gx@UQ1=LE_TC_R!}(79HROmONk%?AWMPh z+$4^9$#vpbGS1J3%_R{H9i-B(tq$yj*x)Rjcz|m||Czj|hBNHOBZEi?h=6s4k57n; z3k6~Ckw`ob$PMDcK10Z826&+t_>R=e&gZC*J+O4_fTaU}P70~~NQDzEwUNpWd@+Xh z_1Th87;6Tp7;P9qunnXxA!LX4h4#bvu;J~4z1DdB1wbmD3F)3+XX<$<<9;8V4eJo~)EV3|ZtSjB=H%u~t#p4_Tzvaz?SlO^ZitrIX}`5w{RM@R7lT!+{LD}F36!23 z=6JLpckWFXuj-^YGPH1@bkH_tV=3&ReH@G50ZQJZK5y zde5I$PK;aPC7b-r%TQ)H{n*V8+{Q|NZRG)mk6ur&oCsm9v0t(1+v&?Iq!2cE)$WF4 zyu$gfC05tyd=p=0X$13`$H*HMT(GiDv$PaG)6U%2Xa7X;?9AAdJZbo|@#{jF55z=T zTvpo#Odb(h=VZ6t@ElrG(`?O=e7NUH&?Bt~m6Bm@*Oy70iXubSjD$zLm8NIU+~;!} zneNzm)82LB>D1w)M|#S;(&*ZDpw7F;)29fCb!d~^WpP|=T?`xi^!+>Un}x1jwf1u@ z%LyJm@7aQ@Q|XMqXj{+-qNU`ZjMSGx-l`3+Ula4j6G zz4`2W`!GRrn6)X5@vuaNmNLVfra4{a%zpuM7kl~I@3iT%C5Ni+T4#-YHjkS z+wGG#%YVozSnRpGDc$Xws1A{Iv0a0?!G|-;Y?ODRW@nqyo7yC^v46YBA9s7@a>abpM$U5=^vFqeoj(tgn&xv;phcRGM*Xs^3I zwZ&&6a#!Q82K}Xpr#|e>Frr|%hU-T8-R;eoTcN_t1-sDtk@(KexA9uj$AnEXY*MTR zO}&#>+LB0;hYX4HaJ?opK4|Vvn3dy7nUW8@)@UR4y3?#xcLH5hE#S+3BI0-?SyWi8 ziSwm_;YVzdq#njaqY|?96dA=r<4P~=yvz@A^~Ec*M;xAc$X51x+Nm+dE78?kaxYi^ z!li&NW)r$Q%%@q7l@arel$2G7<~%!H~^$l;2gh3K;WXh~b|~&KYwm%mmg}`TY@q|jT?aqaPDD8ArSnY8*SyN; zeYBx1ai{>NkZ)0a+v>)jBbnU3%K7tEJ+!ZivzCRf4_jN_lXrr|VU@8HPY~kI;lpY& zBHSF%)5sW2j06uV8EI(hsvGO+3U2BlTgN|yq0qMaG%OQ_&4w420)-_*YB{Po%F&8{ z)N8=b{Ap%lZAsXa+^{5pAqiBa`|ohXx9Z1#3P&DB4uvNPcH0rf>PkL{2TKDSBpvex zuJGFK%_?75Mc)Vti^8S^)Z1?Oj(@4y*zCU-$kYIq&KJZBpr$-^H-o0C7& zw*SrA&{vzd68;l2ICSi94g0KRsF*%TC^d6ZMy4NLGKtIRlNotz@U@pv^`r_Lf#FNB z<5yH&PDU8aHb~RX=HM*zybT|-x!A;WM5fmd*xl_=Bs)T%cx06i`E;6mZNaBbd`7aS+wsF}1Nag4Qx8yJVsz_I>+)I&AmV zhMHb2z5YUBOSie=yAt_j-=&<1eY76urjT^V?@}b{r4eIXLbJLksM%H?$~AWwD^3bA zn&V$aa<^qhNxa23Wj*`BTpxGl+O@cSRBDfNMjQ+UR!>Gx>qko?f>vLenK zj;K+ugLkx<5AQL%n;Ny)hD`oqLVc>jgz#O>K$2**saW7*Uxh8R&?F*=mcCffOq#iW z#OfUr+nF)bCz2xJOes(}Qxb44LSFw?4UR*(o&B)MmzfiG6DVV>H<1`uglv;16AxIg zKRunKBIJOze?HSf!ap3^KaD!L_tJCE!o15?RkHa_HMeCc zNFa?(*~vs?A?X~dP|8gcSeR+UT#nGc`-WqS2Nbvr@xpNsR8Fr?T`7#YA=UG>A2Aqk z*#GvmRGpqLtUcEPM>s-HSG=qK{I)L@gJk+!h)p#0sH zNd{Y1^0p+;FXmd0-zUU)v~_ETw~CMLkS!@1ZTBlS;Q!e4jMe3dGMNT+B*x`!JM9a@ zYNs%(Op(kl%uTk990cMy`eqYjJHW~UlQ8pQMHi|YCbg@1&8D_8olzd%(z=zw&7axT zO+r!1m5~>HyTX(Q5AQfWrzA@B?GsllgA;O5ZG@v@dGRS%3s>JfxhuC~RD(sAZzKoq zkqOEy4+|fg_a~m`f4XHWSWSE)ebsQXVSN04?*lS(os*v#Cn53rXvOU1rwRHJL~ctg zP8Xl!bc~)vB#wPoj!1b>OlxH%IOs8FKgH?jcdOtV4e>l$vrKnRDlTVDJkx^q=44>N zQcBw~KDwoV4BH~i|vl)$s^g69M|fKIyZ{g3|UPKeybq5o04 zBiz>GT3flrkwSqYCCYQIjjtDNC(9f7bu@Mvy)Xs`pnj5ti-iPsf+(`{;w~hLcw4DgAX1(j;{NOFmnN-kPMg)z+7N1 zKn(1#B`Sg)0H|$6VkgGy3M_6SY+2jQIlzVZz=ePEe4VIX&cCdyZgiMzCm#bnnmNsrpICS*3BvWWxaY0nV}yV)0fBZ#2uJ9Ac=MFi*E z3cCEftVx;Jv`zeEA@4x4o#nkaqY+ubQ!&cdxeMOi4Gg?;av>{C zJvu6AAK78YQ%odW_p`2cXWd%T^9*d_Rmf+d&?k_pA?lYXtlIT5(2P}P;)~81%5xzH zUcYL*b~)sWAT!%EzZye6z4K21xwBnsJ=5`*8Yo@SP`4)Pxrr0%w|ITW)xY z20bD*k4S9(@LAw^@aZ=DxcTy?>T#pP)+XI282QX`b(gK)@AqMe4C(85(<2*zbw?!t zcT~)8rtVgQ3wD#T?uH%zn|(<{5Nh4JWQ6E{IACxf(#?H)v(KuAuHWN8l&}w<{{>;c zQ?96_i!EN8d|tNkLtQqjNg^~e=Skb;_oUJc8)iWka0zU9MvwudmvbOTJ6aQKPX5tl zw9ysS#Wx&K>-}(ZH&ju=*w|soSThwEw_y=bSm-}AZ_TjzfO)Hf#b-P77Tab2Axgf# z2qcVUYjSlD(}LPU;6W*9)$grdZxrYJ>en=x%-v&4==k&p0X_Dsv@4R0ng#-av34fJ zYBGpbm!8L&d@K11^{t3ZYStU+af5*$+mA=J8)cW-zOix4r`fYVMk`&JUw@Uk>LL+D zy!=kEk2o&qEAd!t#|h?Y*SyRIqa(x<`PJEd*VtI9r_+_@7Rf_b-mML1Qx;7jYOJ-A zm}CuazON(Jq?M2~zd&K!UBP@Z9oi#njZY!QaLp&H9WhNB%xWGR_j@M^8O=Yp(C6_UvLW+_p6U~RO2eEPbf)x z2VDD>H*wxqSLo#~)>9TOyDmI$oNMN|qL+E^1f zb+$3>g7!|Fmhh}rCj8?y-c`ECGTc8+TH>CGc1xc}b}Puf935R8%Nz_5c(O*Xa{!U|q8CYCo$z671Z@&0 zz{6;>7=Szlbl7#E!_IB!FhWVG+g!%SU#ORU<8|C~_|Pvb1KDm>AHYcpt11#|GAu8` z^VTAu$HK2ksVRRQ_KC1#2HQZnG5pAZRc`Ck+2R{2Obn>oA1VxNW(c;M+?dY(kLc0A z({ErBfZ;?7)ET4n2k*ahe1 z6AM{!q$ji4E>eiG=~I((`<(Oma_|byiEk=5BVX>E_bIRZz#keJ&%rP}^-{ix{$vRw z|32kGr_=8ZJ?o!#8SYPxQ9}d|s4B$`9(O%>Y)&fZ zl2vKjM5O&q!;k*zOEwXVudHtxld?N|O0nNnEVZr}(mK)cS%%7Kmi)4v`@6!2tnHFJ zET4}tUum%SRV=DUKdjMZE3Yy;5cIt-$tR^$K<3S5jo!H%BGknP`OfhOeU2$i()Fh` z;XazqeKLnh9i{SC#V$11&y#0&a=NVa&dSBbi(`8aO@|F}(DaAzd33feXXx#|JfG!p zHVgOEkA`VG`OSP4c}sj$I)=4!S=@kgbm8&Ub3V$>mu{(5X3OS3#~rDg%aePoJjkGN zl1990;Q~o=7wf&xDKVB}S8Ra_sEJsa4{Z9r9l9~q+P~8FtC4%^`EbKp0%b94l zG-xxF@?EC>YXx*!r*AS{%WU5>+}Q7xNzV>z`%@XDw4Nf{dnlgcN&`31R~kwx+!NNE zckSQWjTFA#x7g@gp|FeCf4am<&F{^Td^2Js*g8GZ_(R8}Rm)+B>Ym!gs%QRpy2;%# z$hyUDwwGh|+dr9Z*;X@cR$bG5Z^OI2t?YG%g`5<|YtpZ?Q2ahUzKwf`2nxXJ3ZP@$ zAeVorVU)1BfQFIyZ)h0IWQ#avvPETGbAqWBFea4D5swzd!udPR`2&diKTz=7_+n0& zpRP~2<&|En%7F}V?0vzm{Q3ri5aj{tPROXEj$!4IzSSFTzLlf#JFfD%thzLGvJy`2 zJJRxkbky=tpGVAcBx<*~h*SG5s&igV`Z~6(WJKXt=nO?b*()duY$p;>GfyjIeyu=n|6s zt;0=;IpgUoD}~wUvZhB34X)n(&D5d9O}8$!$HZ{m)yvns6X1Ae9-TF*jbm6O6_R39 zx|fwmlOnZU=Gd#X-F6u~0`dxOMe~jil-l)fDQ2>>D|X$c=4u~g4U~O%@!F`k_t`#f zw|CM$C51@6dkT94ujyP{X-W&8A+Z*diBSqXCOw(;`W5FlR^DfizD~@iTd(lH2>Ga% z?I*B{M}T|4i#B){V}fLLO3&Cw`V8~ON9UyK(hSg(&Z=~n& z&!j2cmVHi}E^^bBn1bY9SU>gmx`L+*2m5RBmcxfchwO>*r7ES+aQFgY&s$Nfc6@>z z(}#6iQogX;WQtGWHy@rp#8f-g+Sy(zu4r9;%<)4&i^dhlg9k4eo1G@(zpYmU^_zZp z9BlRWTC3jSQHgPpwwEb~2Tv!3zPxoNT`@W6LExiX!0o~Z*HaR9}{=p<(S6YNFEil;|1TxL)yE>$?dL>^~|0< zD|=CX5bQira+jvZg^*Jfg_Jv|k;|O2hyFI2-z))QnfP77nO2*DwVa&HX&V7{J&_Lby zK6mLYCBLC#rPhfGt+mgTc2XT0rPQAidH5Jj$3Z-NT*ptrZkpY?31#5sRbCREpx4;D z-#Qz$n!D>^eNtX|2nlz_=XWl`>8ygE`->}BN13rYOBRgDB!6FS^>dPATYa=yVeOyF zEBkb|EnGyKU(vV2R(VRLJOOtVF>zsUFX8BumeM@x*3GZDf&5aS5jyhb-beH2x z43mp7$4o(NfX6*1norbP$AkrMOV55<3%&Ctcj+T~h^y8Rw?(&W&(N}OYTV3d%hoF*z@-l0QSBK&IbnWfu1=V=aPp(L-1HLeqnIn* zI*N=EYOXHEH>z_@Pfr&-m!Bvf{KoR)Q-Fn~@hPv_Tz&afe`4pzOJ0u$P>B*pSa5LL zP&Z1=a>y0!9;S0NRG5D@aqHwMarf`=;uQQ8;_b@m#<50KZ7j$W@l*XF%Fps3&aG0RWW!p3o#rAqQ%0`N))Ho-b*?+`JLss z&u=buBCVM-2(`FscJKIm{PNqaO`nZA`rRy`0)<{@>dL#m2a+t? zKk%kJz4~^%u9=n+7TiF!)-SS^tF^m8I3zWyW5dZ)H literal 0 HcmV?d00001 diff --git a/PackageTools/PluginAnalyzer.deps.json b/PackageTools/PluginAnalyzer.deps.json new file mode 100755 index 0000000..64e2368 --- /dev/null +++ b/PackageTools/PluginAnalyzer.deps.json @@ -0,0 +1,315 @@ +{ + "runtimeTarget": { + "name": ".NETStandard,Version=v2.0/", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETStandard,Version=v2.0": {}, + ".NETStandard,Version=v2.0/": { + "PluginAnalyzer/1.0.0": { + "dependencies": { + "Microsoft.CodeAnalysis.Analyzers": "2.9.8", + "Microsoft.CodeAnalysis.CSharp": "3.3.1", + "NETStandard.Library": "2.0.3" + }, + "runtime": { + "PluginAnalyzer.dll": {} + } + }, + "Microsoft.CodeAnalysis.Analyzers/2.9.8": {}, + "Microsoft.CodeAnalysis.Common/3.3.1": { + "dependencies": { + "Microsoft.CodeAnalysis.Analyzers": "2.9.8", + "System.Collections.Immutable": "1.5.0", + "System.Memory": "4.5.3", + "System.Reflection.Metadata": "1.6.0", + "System.Runtime.CompilerServices.Unsafe": "4.5.2", + "System.Text.Encoding.CodePages": "4.5.1", + "System.Threading.Tasks.Extensions": "4.5.3" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.CodeAnalysis.dll": { + "assemblyVersion": "3.3.0.0", + "fileVersion": "3.300.119.46211" + } + }, + "resources": { + "lib/netstandard2.0/cs/Microsoft.CodeAnalysis.resources.dll": { + "locale": "cs" + }, + "lib/netstandard2.0/de/Microsoft.CodeAnalysis.resources.dll": { + "locale": "de" + }, + "lib/netstandard2.0/es/Microsoft.CodeAnalysis.resources.dll": { + "locale": "es" + }, + "lib/netstandard2.0/fr/Microsoft.CodeAnalysis.resources.dll": { + "locale": "fr" + }, + "lib/netstandard2.0/it/Microsoft.CodeAnalysis.resources.dll": { + "locale": "it" + }, + "lib/netstandard2.0/ja/Microsoft.CodeAnalysis.resources.dll": { + "locale": "ja" + }, + "lib/netstandard2.0/ko/Microsoft.CodeAnalysis.resources.dll": { + "locale": "ko" + }, + "lib/netstandard2.0/pl/Microsoft.CodeAnalysis.resources.dll": { + "locale": "pl" + }, + "lib/netstandard2.0/pt-BR/Microsoft.CodeAnalysis.resources.dll": { + "locale": "pt-BR" + }, + "lib/netstandard2.0/ru/Microsoft.CodeAnalysis.resources.dll": { + "locale": "ru" + }, + "lib/netstandard2.0/tr/Microsoft.CodeAnalysis.resources.dll": { + "locale": "tr" + }, + "lib/netstandard2.0/zh-Hans/Microsoft.CodeAnalysis.resources.dll": { + "locale": "zh-Hans" + }, + "lib/netstandard2.0/zh-Hant/Microsoft.CodeAnalysis.resources.dll": { + "locale": "zh-Hant" + } + } + }, + "Microsoft.CodeAnalysis.CSharp/3.3.1": { + "dependencies": { + "Microsoft.CodeAnalysis.Common": "3.3.1" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.CodeAnalysis.CSharp.dll": { + "assemblyVersion": "3.3.0.0", + "fileVersion": "3.300.119.46211" + } + }, + "resources": { + "lib/netstandard2.0/cs/Microsoft.CodeAnalysis.CSharp.resources.dll": { + "locale": "cs" + }, + "lib/netstandard2.0/de/Microsoft.CodeAnalysis.CSharp.resources.dll": { + "locale": "de" + }, + "lib/netstandard2.0/es/Microsoft.CodeAnalysis.CSharp.resources.dll": { + "locale": "es" + }, + "lib/netstandard2.0/fr/Microsoft.CodeAnalysis.CSharp.resources.dll": { + "locale": "fr" + }, + "lib/netstandard2.0/it/Microsoft.CodeAnalysis.CSharp.resources.dll": { + "locale": "it" + }, + "lib/netstandard2.0/ja/Microsoft.CodeAnalysis.CSharp.resources.dll": { + "locale": "ja" + }, + "lib/netstandard2.0/ko/Microsoft.CodeAnalysis.CSharp.resources.dll": { + "locale": "ko" + }, + "lib/netstandard2.0/pl/Microsoft.CodeAnalysis.CSharp.resources.dll": { + "locale": "pl" + }, + "lib/netstandard2.0/pt-BR/Microsoft.CodeAnalysis.CSharp.resources.dll": { + "locale": "pt-BR" + }, + "lib/netstandard2.0/ru/Microsoft.CodeAnalysis.CSharp.resources.dll": { + "locale": "ru" + }, + "lib/netstandard2.0/tr/Microsoft.CodeAnalysis.CSharp.resources.dll": { + "locale": "tr" + }, + "lib/netstandard2.0/zh-Hans/Microsoft.CodeAnalysis.CSharp.resources.dll": { + "locale": "zh-Hans" + }, + "lib/netstandard2.0/zh-Hant/Microsoft.CodeAnalysis.CSharp.resources.dll": { + "locale": "zh-Hant" + } + } + }, + "Microsoft.NETCore.Platforms/1.1.0": {}, + "NETStandard.Library/2.0.3": { + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0" + } + }, + "System.Buffers/4.4.0": { + "runtime": { + "lib/netstandard2.0/System.Buffers.dll": { + "assemblyVersion": "4.0.2.0", + "fileVersion": "4.6.25519.3" + } + } + }, + "System.Collections.Immutable/1.5.0": { + "runtime": { + "lib/netstandard2.0/System.Collections.Immutable.dll": { + "assemblyVersion": "1.2.3.0", + "fileVersion": "4.6.26515.6" + } + } + }, + "System.Memory/4.5.3": { + "dependencies": { + "System.Buffers": "4.4.0", + "System.Numerics.Vectors": "4.4.0", + "System.Runtime.CompilerServices.Unsafe": "4.5.2" + }, + "runtime": { + "lib/netstandard2.0/System.Memory.dll": { + "assemblyVersion": "4.0.1.1", + "fileVersion": "4.6.27617.2" + } + } + }, + "System.Numerics.Vectors/4.4.0": { + "runtime": { + "lib/netstandard2.0/System.Numerics.Vectors.dll": { + "assemblyVersion": "4.1.3.0", + "fileVersion": "4.6.25519.3" + } + } + }, + "System.Reflection.Metadata/1.6.0": { + "dependencies": { + "System.Collections.Immutable": "1.5.0" + }, + "runtime": { + "lib/netstandard2.0/System.Reflection.Metadata.dll": { + "assemblyVersion": "1.4.3.0", + "fileVersion": "4.6.26515.6" + } + } + }, + "System.Runtime.CompilerServices.Unsafe/4.5.2": { + "runtime": { + "lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.dll": { + "assemblyVersion": "4.0.4.1", + "fileVersion": "4.6.26919.2" + } + } + }, + "System.Text.Encoding.CodePages/4.5.1": { + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "4.5.2" + }, + "runtime": { + "lib/netstandard2.0/System.Text.Encoding.CodePages.dll": { + "assemblyVersion": "4.1.1.0", + "fileVersion": "4.6.27129.4" + } + } + }, + "System.Threading.Tasks.Extensions/4.5.3": { + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "4.5.2" + }, + "runtime": { + "lib/netstandard2.0/System.Threading.Tasks.Extensions.dll": { + "assemblyVersion": "4.2.0.1", + "fileVersion": "4.6.27818.1" + } + } + } + } + }, + "libraries": { + "PluginAnalyzer/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "Microsoft.CodeAnalysis.Analyzers/2.9.8": { + "type": "package", + "serviceable": true, + "sha512": "sha512-7ZFIPFQRcL9VEkhm2v7bsIV5Klz/NwvLzhzB/1bEXjvsuTiQA3I9vSS9DOQOMt+iGhT6jxa+djBc6PmSXgIvNw==", + "path": "microsoft.codeanalysis.analyzers/2.9.8", + "hashPath": "microsoft.codeanalysis.analyzers.2.9.8.nupkg.sha512" + }, + "Microsoft.CodeAnalysis.Common/3.3.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-N5yQdGy+M4kimVG7hwCeGTCfgYjK2o5b/Shumkb/rCC+/SAkvP1HUAYK+vxPFS7dLJNtXLRsmPHKj3fnyNWnrw==", + "path": "microsoft.codeanalysis.common/3.3.1", + "hashPath": "microsoft.codeanalysis.common.3.3.1.nupkg.sha512" + }, + "Microsoft.CodeAnalysis.CSharp/3.3.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-WDUIhTHem38H6VJ98x2Ssq0fweakJHnHYl7vbG8ARnsAwLoJKCQCy78EeY1oRrCKG42j0v6JVljKkeqSDA28UA==", + "path": "microsoft.codeanalysis.csharp/3.3.1", + "hashPath": "microsoft.codeanalysis.csharp.3.3.1.nupkg.sha512" + }, + "Microsoft.NETCore.Platforms/1.1.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==", + "path": "microsoft.netcore.platforms/1.1.0", + "hashPath": "microsoft.netcore.platforms.1.1.0.nupkg.sha512" + }, + "NETStandard.Library/2.0.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-st47PosZSHrjECdjeIzZQbzivYBJFv6P2nv4cj2ypdI204DO+vZ7l5raGMiX4eXMJ53RfOIg+/s4DHVZ54Nu2A==", + "path": "netstandard.library/2.0.3", + "hashPath": "netstandard.library.2.0.3.nupkg.sha512" + }, + "System.Buffers/4.4.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-AwarXzzoDwX6BgrhjoJsk6tUezZEozOT5Y9QKF94Gl4JK91I4PIIBkBco9068Y9/Dra8Dkbie99kXB8+1BaYKw==", + "path": "system.buffers/4.4.0", + "hashPath": "system.buffers.4.4.0.nupkg.sha512" + }, + "System.Collections.Immutable/1.5.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-EXKiDFsChZW0RjrZ4FYHu9aW6+P4MCgEDCklsVseRfhoO0F+dXeMSsMRAlVXIo06kGJ/zv+2w1a2uc2+kxxSaQ==", + "path": "system.collections.immutable/1.5.0", + "hashPath": "system.collections.immutable.1.5.0.nupkg.sha512" + }, + "System.Memory/4.5.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3oDzvc/zzetpTKWMShs1AADwZjQ/36HnsufHRPcOjyRAAMLDlu2iD33MBI2opxnezcVUtXyqDXXjoFMOU9c7SA==", + "path": "system.memory/4.5.3", + "hashPath": "system.memory.4.5.3.nupkg.sha512" + }, + "System.Numerics.Vectors/4.4.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-UiLzLW+Lw6HLed1Hcg+8jSRttrbuXv7DANVj0DkL9g6EnnzbL75EB7EWsw5uRbhxd/4YdG8li5XizGWepmG3PQ==", + "path": "system.numerics.vectors/4.4.0", + "hashPath": "system.numerics.vectors.4.4.0.nupkg.sha512" + }, + "System.Reflection.Metadata/1.6.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-COC1aiAJjCoA5GBF+QKL2uLqEBew4JsCkQmoHKbN3TlOZKa2fKLz5CpiRQKDz0RsAOEGsVKqOD5bomsXq/4STQ==", + "path": "system.reflection.metadata/1.6.0", + "hashPath": "system.reflection.metadata.1.6.0.nupkg.sha512" + }, + "System.Runtime.CompilerServices.Unsafe/4.5.2": { + "type": "package", + "serviceable": true, + "sha512": "sha512-wprSFgext8cwqymChhrBLu62LMg/1u92bU+VOwyfBimSPVFXtsNqEWC92Pf9ofzJFlk4IHmJA75EDJn1b2goAQ==", + "path": "system.runtime.compilerservices.unsafe/4.5.2", + "hashPath": "system.runtime.compilerservices.unsafe.4.5.2.nupkg.sha512" + }, + "System.Text.Encoding.CodePages/4.5.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-4J2JQXbftjPMppIHJ7IC+VXQ9XfEagN92vZZNoG12i+zReYlim5dMoXFC1Zzg7tsnKDM7JPo5bYfFK4Jheq44w==", + "path": "system.text.encoding.codepages/4.5.1", + "hashPath": "system.text.encoding.codepages.4.5.1.nupkg.sha512" + }, + "System.Threading.Tasks.Extensions/4.5.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-+MvhNtcvIbqmhANyKu91jQnvIRVSTiaOiFNfKWwXGHG48YAb4I/TyH8spsySiPYla7gKal5ZnF3teJqZAximyQ==", + "path": "system.threading.tasks.extensions/4.5.3", + "hashPath": "system.threading.tasks.extensions.4.5.3.nupkg.sha512" + } + } +} \ No newline at end of file diff --git a/PackageTools/PluginAnalyzer.dll b/PackageTools/PluginAnalyzer.dll new file mode 100755 index 0000000000000000000000000000000000000000..d6ce2be19b887a53489139782b789105d2a21783 GIT binary patch literal 24064 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 G@P7b}&W}U@ literal 0 HcmV?d00001 -- Gitee From 007608923795913459a620264b15112e43fac7de Mon Sep 17 00:00:00 2001 From: GerZhang Date: Tue, 13 Oct 2026 15:47:46 +0800 Subject: [PATCH 57/71] =?UTF-8?q?feat(offline-upload):=20=E4=B8=8A?= =?UTF-8?q?=E4=BC=A0=E6=94=AF=E6=8C=81=E6=96=87=E4=BB=B6=E7=BA=A7=E8=BF=9B?= =?UTF-8?q?=E5=BA=A6=E3=80=81=E5=A4=B1=E8=B4=A5=E9=9A=94=E7=A6=BB=E4=B8=8E?= =?UTF-8?q?=E7=AA=97=E5=8F=A3=E5=86=85=E9=87=8D=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 上传增加超时、错误分类与瞬时重试 - 新增上传会话:清单→逐文件→失败隔离→保序收敛 - 确认时只提交成功项并剔除失败项(含签名) - 新增文件级进度组件,替换旧的整体/表单级进度 --- Resources/AndroidPDACommand.js | 670 +++++++++++++------------ Resources/OfflinePlusExportProgress.js | 594 ++++++++++------------ 2 files changed, 601 insertions(+), 663 deletions(-) diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index c1953e8..2b78bcf 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -121,13 +121,35 @@ var HAC_FormatBytesAsMb = function (bytes) { }; /** - * 将文件上传到服务器临时目录,并返回服务器上的文件标识 - * @param {*} file - * @param {*} uploadLimitId - * @param {*} onProgress - * @returns Promise,成功时返回服务器上的文件标识,失败时返回错误信息 + * 离线附件上传配置(弱网增强): + * - TIMEOUT:单次请求超时,避免长时间无响应; + * - MAX_ATTEMPTS:瞬时错误(网络/超时/5xx/408/429)的最大尝试次数; + * - RETRY_DELAY:重试退避基数。 */ -function HAC_UploadFileToTemp(file, uploadLimitId, onProgress) { +var HAC_OFFLINE_UPLOAD_TIMEOUT_MS = 60000; +var HAC_OFFLINE_UPLOAD_MAX_ATTEMPTS = 2; +var HAC_OFFLINE_UPLOAD_RETRY_DELAY_MS = 600; + +function HAC_Delay(ms) { + return new Promise(function (resolve) { + setTimeout(resolve, ms); + }); +} + +/** 构造上传错误对象,标记是否可重试(其它 4xx 不可重试)。 */ +function HAC_CreateUploadError(message, status) { + var error = new Error(message); + error.status = status || 0; + error.retryable = !(status >= 400 && status < 500 && status !== 408 && status !== 429); + return error; +} + +function HAC_IsRetryableUploadError(error) { + return !error || error.retryable !== false; +} + +/** 单次上传尝试。失败时 reject 的 Error 带 status / retryable 供上层分类。 */ +function HAC_UploadFileOnce(file, uploadLimitId, onProgress) { return new Promise(function (resolve, reject) { var formData = new FormData(); formData.append("file", file); @@ -137,6 +159,7 @@ function HAC_UploadFileToTemp(file, uploadLimitId, onProgress) { var startTime = new Date().valueOf(); var xhr = new XMLHttpRequest(); xhr.open("POST", Forguncy.Common.uploadUrl, true); + xhr.timeout = HAC_OFFLINE_UPLOAD_TIMEOUT_MS; xhr.setRequestHeader("Accept", "application/json"); xhr.upload.onprogress = function (event) { if (onProgress && event.lengthComputable) { @@ -148,15 +171,39 @@ function HAC_UploadFileToTemp(file, uploadLimitId, onProgress) { if (xhr.status >= 200 && xhr.status < 300) { resolve(xhr.responseText); } else { - reject(xhr.responseText || xhr.statusText || "上传离线附件失败。"); + reject(HAC_CreateUploadError(xhr.responseText || xhr.statusText || "上传离线附件失败。", xhr.status)); } }; xhr.onerror = function () { - reject("上传离线附件失败。"); + reject(HAC_CreateUploadError("上传离线附件失败(网络错误)。", 0)); + }; + xhr.ontimeout = function () { + reject(HAC_CreateUploadError("上传离线附件超时。", 0)); }; xhr.send(formData); }); } + +/** + * 将文件上传到服务器临时目录,返回服务端文件标识(guid)。 + * 瞬时错误按退避重试,直到达到最大尝试次数;4xx(除 408/429)直接失败。 + * @returns Promise + */ +async function HAC_UploadFileToTemp(file, uploadLimitId, onProgress) { + var lastError = null; + for (var attempt = 1; attempt <= HAC_OFFLINE_UPLOAD_MAX_ATTEMPTS; attempt++) { + try { + return await HAC_UploadFileOnce(file, uploadLimitId, onProgress); + } catch (error) { + lastError = error; + if (!HAC_IsRetryableUploadError(error) || attempt >= HAC_OFFLINE_UPLOAD_MAX_ATTEMPTS) { + throw error; + } + await HAC_Delay(HAC_OFFLINE_UPLOAD_RETRY_DELAY_MS * attempt); + } + } + throw lastError || HAC_CreateUploadError("上传离线附件失败。", 0); +} function HAC_GetOfflineRecordFieldValue(record, fieldId) { var fieldValue = record && record.values && record.values[fieldId]; if (fieldValue && typeof fieldValue === "object" && !Array.isArray(fieldValue) && @@ -214,55 +261,215 @@ function HAC_GetOfflineSignatureAttachmentIndex(record, attachment, fieldId) { return hasSignatureValue || hasSignatureMetadata ? signatureIndex : -1; } -function HAC_ApplyUploadedSignatureValue(record, attachment, attachmentValue, fieldId, signatureIndex) { - var signatureValues = HAC_ParseOfflineSignatureValues(record, fieldId); - var oldSignatureValue = signatureValues[signatureIndex]; - var signatureValue = {}; - - if (oldSignatureValue && typeof oldSignatureValue === "object" && !Array.isArray(oldSignatureValue)) { - Object.keys(oldSignatureValue).forEach(function (key) { - signatureValue[key] = oldSignatureValue[key]; +/** + * 构建上传会话:把导出数据中的附件摊平成文件条目,保持原始顺序并关联记录。 + * 状态仅存在于本次导出(含窗口内重试)期间:PENDING / UPLOADING / SUCCESS / FAILED。 + */ +function HAC_CreateUploadSession(exportDataArray) { + var session = { items: [], entries: [], total: 0 }; + (exportDataArray || []).forEach(function (exportItem, itemIndex) { + if (!exportItem) { + return; + } + var item = { + itemIndex: itemIndex, + exportItem: exportItem, + projectId: exportItem.projectId, + title: exportItem.patternTitle || exportItem.projectId || ("离线表单 " + (itemIndex + 1)), + records: exportItem.records || [], + entries: [] + }; + var groupOrders = {}; + (exportItem.attachments || []).forEach(function (attachment) { + if (!attachment || !attachment.localName + || !HAC_GetOfflineAttachmentRecordId(attachment) + || !HAC_GetOfflineAttachmentFieldId(attachment)) { + return; + } + var recordId = HAC_GetOfflineAttachmentRecordId(attachment); + var fieldId = HAC_GetOfflineAttachmentFieldId(attachment); + var record = HAC_FindOfflineRecord(item.records, recordId); + var signatureIndex = record ? HAC_GetOfflineSignatureAttachmentIndex(record, attachment, fieldId) : -1; + var groupKey = itemIndex + "|" + recordId + "|" + fieldId; + var order = groupOrders[groupKey] || 0; + groupOrders[groupKey] = order + 1; + + var entry = { + key: "f" + session.total, + itemIndex: itemIndex, + attachment: attachment, + record: record, + recordId: recordId, + fieldId: fieldId, + kind: signatureIndex >= 0 ? "signature" : "normal", + signatureIndex: signatureIndex, + groupKey: groupKey, + order: order, + displayName: attachment.originalName || attachment.fileName || attachment.localName, + state: "PENDING", + serverId: null, + error: null + }; + item.entries.push(entry); + session.entries.push(entry); + session.total++; }); + session.items.push(item); + }); + return session; +} + +function HAC_FindOfflineRecord(records, recordId) { + for (var i = 0; i < (records || []).length; i++) { + if (records[i] && records[i].recordId === recordId) { + return records[i]; + } } + return null; +} - if (!signatureValue.userName && attachment.originalName) { - signatureValue.userName = attachment.originalName; +function HAC_GetUploadErrorMessage(error) { + if (!error) { + return "上传失败"; } - signatureValue.fileName = attachmentValue; - if (attachment.updateTime !== undefined && attachment.updateTime !== null) { - signatureValue.updateTime = attachment.updateTime; + if (error.message) { + return error.message; } + return (error.toString && error.toString()) || "上传失败"; +} - signatureValues[signatureIndex] = signatureValue; - HAC_SetOfflineRecordFieldValue(record, fieldId, JSON.stringify(signatureValues)); +/** 统计会话中各状态的条目数。 */ +function HAC_GetUploadStats(session) { + var stats = { total: session.total, success: 0, failed: 0, uploading: 0, pending: 0 }; + session.entries.forEach(function (entry) { + if (entry.state === "SUCCESS") { + stats.success++; + } else if (entry.state === "FAILED") { + stats.failed++; + } else if (entry.state === "UPLOADING") { + stats.uploading++; + } else { + stats.pending++; + } + }); + return stats; } /** - * 将上传后的附件值应用到记录中。普通附件保留字段整体更新时间;签名附件额外保留每张签名的更新时间。 + * 执行一轮上传:已成功的条目跳过,PENDING / FAILED 重新尝试。 + * 单个文件失败只标记,不中断其余文件。 + * hooks 可选:{ onFileStart(entry, stats), onFileProgress(entry, loaded, total, bps, stats), onFileEnd(entry, stats) } */ -function HAC_ApplyUploadedAttachmentValue(record, attachment, attachmentValue, uploadedValues) { - if (!record || !record.values || !attachment) { - return; +async function HAC_RunUploadPass(session, uploadLimitId, hooks) { + hooks = hooks || {}; + for (var i = 0; i < session.items.length; i++) { + var item = session.items[i]; + for (var j = 0; j < item.entries.length; j++) { + var entry = item.entries[j]; + if (entry.state === "SUCCESS") { + continue; + } + entry.state = "UPLOADING"; + entry.error = null; + if (hooks.onFileStart) { + hooks.onFileStart(entry, HAC_GetUploadStats(session)); + } + try { + var dataUrl = window.offlinePlus.offlinePlusLoadAttachment(item.projectId, entry.attachment.localName); + var file = HAC_DataUrlToFile(dataUrl, HAC_GetOfflineAttachmentUploadFileName(entry.attachment)); + if (!file) { + throw new Error("读取离线附件失败:" + entry.attachment.localName); + } + var currentEntry = entry; + entry.serverId = await HAC_UploadFileToTemp(file, uploadLimitId, function (loaded, total, bytesPerSecond) { + if (hooks.onFileProgress) { + hooks.onFileProgress(currentEntry, loaded, total, bytesPerSecond, HAC_GetUploadStats(session)); + } + }); + entry.state = "SUCCESS"; + } catch (error) { + entry.state = "FAILED"; + entry.error = HAC_GetUploadErrorMessage(error); + } + if (hooks.onFileEnd) { + hooks.onFileEnd(entry, HAC_GetUploadStats(session)); + } + } } + HAC_ApplyUploadSession(session); + return HAC_GetUploadStats(session); +} - var recordId = HAC_GetOfflineAttachmentRecordId(attachment); - var fieldId = HAC_GetOfflineAttachmentFieldId(attachment); - if (!recordId || !fieldId) { - return; - } +/** + * 把会话结果写回记录:只采纳成功项,失败项从提交数据中剔除。 + * - 普通附件字段:成功 serverId 按原始顺序以 "|" 连接。 + * - 签名字段:保留成功的签名并写入 serverId,失败的签名移除(避免本地文件名泄漏到提交数据)。 + */ +function HAC_ApplyUploadSession(session) { + session.items.forEach(function (item) { + var groups = {}; + item.entries.forEach(function (entry) { + var group = groups[entry.groupKey]; + if (!group) { + group = groups[entry.groupKey] = { kind: entry.kind, fieldId: entry.fieldId, record: entry.record, entries: [] }; + } + group.entries.push(entry); + }); + Object.keys(groups).forEach(function (groupKey) { + var group = groups[groupKey]; + if (!group.record) { + return; + } + if (group.kind === "signature") { + HAC_ApplyUploadedSignatureGroup(group); + } else { + HAC_ApplyUploadedNormalGroup(group); + } + }); + }); +} - var signatureIndex = HAC_GetOfflineSignatureAttachmentIndex(record, attachment, fieldId); - if (signatureIndex >= 0) { - HAC_ApplyUploadedSignatureValue(record, attachment, attachmentValue, fieldId, signatureIndex); - return; - } +function HAC_ApplyUploadedNormalGroup(group) { + var values = []; + group.entries.slice().sort(function (a, b) { + return a.order - b.order; + }).forEach(function (entry) { + if (entry.state === "SUCCESS" && entry.serverId) { + values.push(entry.serverId); + } + }); + HAC_SetOfflineRecordFieldValue(group.record, group.fieldId, values.join("|")); +} + +function HAC_ApplyUploadedSignatureGroup(group) { + var signatureValues = HAC_ParseOfflineSignatureValues(group.record, group.fieldId); + var successEntries = {}; + group.entries.forEach(function (entry) { + if (entry.state === "SUCCESS" && entry.serverId && entry.signatureIndex >= 0) { + successEntries[entry.signatureIndex] = entry; + } + }); - var key = recordId + "|" + fieldId; - if (!uploadedValues[key]) { - uploadedValues[key] = []; + var result = []; + for (var i = 0; i < signatureValues.length; i++) { + if (!Object.prototype.hasOwnProperty.call(successEntries, i)) { + continue; + } + var entry = successEntries[i]; + var value = {}; + var source = signatureValues[i]; + if (source && typeof source === "object" && !Array.isArray(source)) { + Object.keys(source).forEach(function (key) { + value[key] = source[key]; + }); + } + if (!value.userName && entry.attachment.originalName) { + value.userName = entry.attachment.originalName; + } + value.fileName = entry.serverId; + result.push(value); } - uploadedValues[key].push(attachmentValue); - HAC_SetOfflineRecordFieldValue(record, fieldId, uploadedValues[key].join("|")); + HAC_SetOfflineRecordFieldValue(group.record, group.fieldId, JSON.stringify(result)); } function HAC_GetOfflineAttachmentRecordId(attachment) { @@ -278,230 +485,64 @@ function HAC_GetOfflineAttachmentUploadFileName(attachment) { } /** - * 处理离线导出附件 - * @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; -} - -/** - * 处理批量导出多条记录的附件 - * @param {*} exportDataArray 批量导出的数据数组,每项包含 { projectId, patternTitle, records, attachments } - * @param {*} uploadLimitId 上传限制ID - * @returns Promise,成功时返回处理后的导出数据数组 + * 离线附件上传主流程:清单 → 逐文件 → 失败隔离 → 窗口内重试 → 收敛。 + * 通过 HAC_FileUploadProgress 展示文件级进度;返回 Promise,resolve 时本轮结束(可能含失败)。 + * 失败项在收敛阶段从记录值中剔除(只提交成功部分)。 + * + * @param {Array} exportDataArray 导出数据数组(单表单时也包装为数组) + * @param {String} uploadLimitId 文件上传限制ID + * @param {Object} options { autoConfirmOnSuccess: 全部成功时是否免确认直接继续 } */ -async function HAC_ProcessBatchExportAttachments(exportDataArray, uploadLimitId) { +async function HAC_ProcessOfflineAttachments(exportDataArray, uploadLimitId, options) { + options = options || {}; if (!exportDataArray || !Array.isArray(exportDataArray) || exportDataArray.length === 0) { - return exportDataArray; - } - - if (!uploadLimitId) { - throw "请设置文件上传限制ID。"; + return { stats: { total: 0, success: 0, failed: 0, uploading: 0, pending: 0 } }; } if (!window.offlinePlus || !window.offlinePlus.offlinePlusLoadAttachment) { - HAC_CallFunctionOutOfHAC(HAC_GetOfflinePlusDebugInfo("批量导出离线表单", "调用offlinePlusLoadAttachment")); - throw "当前APP不支持读取离线附件。"; + HAC_CallFunctionOutOfHAC(HAC_GetOfflinePlusDebugInfo("上传离线表单", "调用offlinePlusLoadAttachment")); + throw new Error("当前APP不支持读取离线附件。"); } - // 统计所有附件总数并初始化进度显示 - var totalAttachments = 0; - HAC_BatchUploadProgress.ensure(exportDataArray.length); - exportDataArray.forEach(function (item, index) { - if (item && item.attachments) { - totalAttachments += item.attachments.length; - } - // 初始化每个表单项的进度显示 - var itemKey = "item_" + index; - var itemTitle = (item && item.projectId) || ("离线表单 " + (index + 1)); - HAC_BatchUploadProgress.initItem(itemKey, itemTitle); - }); - HAC_BatchUploadProgress.updateSummary({ - percent: 0, - title: "准备导出", - metaLeft: "已上传文件0/" + totalAttachments, - metaRight: totalAttachments > 0 ? ("共 " + totalAttachments + " 个附件待上传") : "无需上传附件" - }); - - if (totalAttachments === 0) { - // 没有附件,直接标记所有项为完成 - exportDataArray.forEach(function (item, index) { + var session = HAC_CreateUploadSession(exportDataArray); + if (session.total === 0) { + exportDataArray.forEach(function (item) { if (item) { delete item.attachments; - HAC_BatchUploadProgress.completeItem("item_" + index); } }); - HAC_BatchUploadProgress.updateSummary({ - percent: 100, - title: "导出数据", - metaLeft: "无需上传附件", - metaRight: "共 " + exportDataArray.length + " 项" - }); - return exportDataArray; + return { stats: HAC_GetUploadStats(session), session: session }; } - var currentAttachmentIndex = 0; - var completedAttachmentCount = 0; - - HAC_BatchUploadProgress.updateSummary({ - percent: 0, - title: "准备上传附件", - metaLeft: "已上传文件0/" + totalAttachments, - metaRight: "共 " + totalAttachments + " 个附件待上传" - }); - - for (var itemIndex = 0; itemIndex < exportDataArray.length; itemIndex++) { - var exportItem = exportDataArray[itemIndex]; - if (!exportItem) { - continue; - } + if (!uploadLimitId) { + throw new Error("请设置文件上传限制ID。"); + } - var itemKey = "item_" + itemIndex; - var projectId = exportItem.projectId; - var records = exportItem.records || []; - var attachments = exportItem.attachments || []; - var uploadedValues = {}; - var currentItemTitle = exportItem.projectId || ("离线表单 " + (itemIndex + 1)); + HAC_FileUploadProgress.begin(session); + var hooks = HAC_FileUploadProgress.createHooks(); - if (!attachments || attachments.length === 0) { - delete exportItem.attachments; - HAC_BatchUploadProgress.completeItem(itemKey); - continue; + var stats = await HAC_RunUploadPass(session, uploadLimitId, hooks); + while (stats.failed > 0) { + var decision = await HAC_FileUploadProgress.showResultAndWait(stats, true); + if (decision !== "retry") { + break; } + HAC_FileUploadProgress.markRetrying(); + stats = await HAC_RunUploadPass(session, uploadLimitId, hooks); + } - HAC_BatchUploadProgress.updateItem(itemKey, { state: 'processing', detail: '准备处理 ' + attachments.length + ' 个附件...' }); - HAC_BatchUploadProgress.updateSummary({ - percent: completedAttachmentCount / totalAttachments * 100, - title: currentItemTitle, - metaLeft: "已上传文件" + completedAttachmentCount + "/" + totalAttachments, - metaRight: "准备处理 " + attachments.length + " 个附件" - }); - - for (var i = 0; i < attachments.length; i++) { - var attachment = attachments[i]; - if (!attachment || !attachment.localName || !HAC_GetOfflineAttachmentRecordId(attachment) || !HAC_GetOfflineAttachmentFieldId(attachment)) { - continue; - } - - currentAttachmentIndex++; - var progressPercent = (completedAttachmentCount / totalAttachments) * 100; - var attachmentName = attachment.localName || "附件"; - - HAC_BatchUploadProgress.updateItem(itemKey, { - progress: progressPercent, - detail: "正在上传 " + currentAttachmentIndex + "/" + totalAttachments + ":" + attachmentName - }); - HAC_BatchUploadProgress.updateSummary({ - percent: progressPercent, - title: currentItemTitle, - metaLeft: "已上传文件" + completedAttachmentCount + "/" + totalAttachments, - metaRight: attachmentName - }); - - try { - var dataUrl = window.offlinePlus.offlinePlusLoadAttachment(projectId, attachment.localName); - var file = HAC_DataUrlToFile(dataUrl, HAC_GetOfflineAttachmentUploadFileName(attachment)); - if (!file) { - throw "读取离线附件失败:" + attachment.localName; - } + if (stats.failed === 0 && !options.autoConfirmOnSuccess) { + // 全部成功但仍需用户确认(批量导出保留确认步骤) + await HAC_FileUploadProgress.showResultAndWait(stats, false); + } - var attachmentValue = await HAC_UploadFileToTemp(file, uploadLimitId, function (loaded, total, bytesPerSecond) { - var itemProgress = ((completedAttachmentCount + (total > 0 ? loaded / total : 0)) / totalAttachments) * 100; - HAC_BatchUploadProgress.updateItem(itemKey, { - progress: itemProgress, - detail: "正在上传 " + HAC_FormatBytesAsMb(loaded) + "/" + HAC_FormatBytesAsMb(total) + ",速度:" + HAC_FormatBytesAsMb(bytesPerSecond) + "/s" - }); - HAC_BatchUploadProgress.updateSummary({ - percent: itemProgress, - title: currentItemTitle, - metaLeft: "已上传文件" + completedAttachmentCount + "/" + totalAttachments, - metaRight: attachmentName + " · " + HAC_FormatBytesAsMb(bytesPerSecond) + "/s" - }); - }); + HAC_FileUploadProgress.finishUploading(stats); - var record = records.find(function (record) { - return record && record.recordId === HAC_GetOfflineAttachmentRecordId(attachment); - }); - HAC_ApplyUploadedAttachmentValue(record, attachment, attachmentValue, uploadedValues); - completedAttachmentCount++; - HAC_BatchUploadProgress.updateSummary({ - percent: completedAttachmentCount / totalAttachments * 100, - title: currentItemTitle, - metaLeft: "已上传文件" + completedAttachmentCount + "/" + totalAttachments, - metaRight: attachmentName + " 已上传" - }); - } catch (e) { - HAC_BatchUploadProgress.errorItem(itemKey, "附件上传失败: " + (attachmentName || "未知")); - throw e; - } + exportDataArray.forEach(function (item) { + if (item) { + delete item.attachments; } - - delete exportItem.attachments; - HAC_BatchUploadProgress.completeItem(itemKey); - } - - return exportDataArray; + }); + return { stats: stats, session: session }; } var HAC_DothanPrinterOp = function (callback) { @@ -4031,51 +4072,43 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { var projectId = this.evaluateFormula(params.ProjectId); var fileUploadLimit = (params.ServerPropertiesId && params.ServerPropertiesId.FileUploadLimit) || ""; let me = this; - HAC_OfflineUploadProgress.update({ - percent: 0, - title: "正在上传离线附件", - detail: "正在读取设备上的离线数据", - speed: "" - }); + HAC_FileUploadProgress.showBusy("正在读取设备上的离线数据"); let ticket = HAC_GenerateCallbackTicket(me, async function (payload, payload2) { + var exportResult = payload; + var success = true; + var errorMessage = ""; try { var exportData = JSON.parse(payload); if (exportData) { - exportData = await HAC_ProcessOfflineExportAttachments(projectId, exportData, fileUploadLimit); - payload = JSON.stringify(exportData); + await HAC_ProcessOfflineAttachments([exportData], fileUploadLimit, { autoConfirmOnSuccess: true }); + exportResult = JSON.stringify(exportData); } - 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: "处理离线附件上传时出错" - }); + success = false; + errorMessage = e ? e.toString() : "导出离线附件失败。"; } finally { - HAC_OfflineUploadProgress.close(); + HAC_FileUploadProgress.close(); HAC_OfflineExportExecution.complete(); } + me.CommandExecutor.excuteCommand(me.CommandParam.CommandList, { + runTimePageName: me.CommandExecutingInfo.runTimePageName, + commandID: new Date().valueOf().toString(), + initParams: { + "ExportResult": exportResult, + "IsSuccess": success, + "Error": errorMessage + }, + locationString: success + ? "执行window.offlinePlus.offlinePlusExportRecordsAsync" + : "处理离线附件上传时出错" + }); }, HAC_GetOfflinePlusDebugInfo("上传离线表单", "生成导出数据回调ticket"), function () { - HAC_OfflineUploadProgress.close(); + HAC_FileUploadProgress.close(); HAC_OfflineExportExecution.complete(); }); if (!ticket) { - HAC_OfflineUploadProgress.close(); + HAC_FileUploadProgress.close(); HAC_OfflineExportExecution.complete(); return; } @@ -4084,13 +4117,13 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { try { window.offlinePlus.offlinePlusExportRecordsAsync(projectId, ticket); } catch (e) { - HAC_OfflineUploadProgress.close(); + HAC_FileUploadProgress.close(); HAC_OfflineExportExecution.complete(); throw e; } } else { HAC_CallFunctionOutOfHAC(HAC_GetOfflinePlusDebugInfo("上传离线表单", "调用offlinePlusExportRecordsAsync")); - HAC_OfflineUploadProgress.close(); + HAC_FileUploadProgress.close(); HAC_OfflineExportExecution.complete(); } return; @@ -4176,70 +4209,43 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { } var fileUploadLimit = (params.ServerPropertiesId && params.ServerPropertiesId.FileUploadLimit) || ""; let me = this; - HAC_BatchUploadProgress.ensure(0); - HAC_BatchUploadProgress.updateSummary({ - percent: 0, - title: "准备导出", - metaLeft: "正在读取设备数据", - metaRight: "" - }); + HAC_FileUploadProgress.showBusy("正在读取设备数据"); let ticket = HAC_GenerateCallbackTicket(me, async function (payload, payload2) { - var batchExportError = ""; var batchExportPayload = payload; - var batchExportSuccess = false; + var batchExportSuccess = true; + var batchExportError = ""; try { var exportDataArray = JSON.parse(payload); if (exportDataArray && Array.isArray(exportDataArray)) { - exportDataArray = await HAC_ProcessBatchExportAttachments(exportDataArray, fileUploadLimit); + await HAC_ProcessOfflineAttachments(exportDataArray, fileUploadLimit, { autoConfirmOnSuccess: false }); batchExportPayload = JSON.stringify(exportDataArray); } - batchExportSuccess = true; } catch (e) { + batchExportSuccess = false; batchExportError = e ? e.toString() : "批量导出离线表单数据失败。"; - } - var continueBatchExport = function () { + } finally { + HAC_FileUploadProgress.close(); HAC_OfflineExportExecution.complete(); - if (batchExportSuccess) { - me.CommandExecutor.excuteCommand(me.CommandParam.CommandList, { - runTimePageName: me.CommandExecutingInfo.runTimePageName, - commandID: new Date().valueOf().toString(), - initParams: { - "ExportResult": batchExportPayload, - "IsSuccess": true, - "Error": "" - }, - locationString: "执行window.offlinePlus.offlinePlusExportMultipleRecordsAsync" - }); - } else { - me.CommandExecutor.excuteCommand(me.CommandParam.CommandList, { - runTimePageName: me.CommandExecutingInfo.runTimePageName, - commandID: new Date().valueOf().toString(), - initParams: { - "ExportResult": batchExportPayload, - "IsSuccess": false, - "Error": batchExportError - }, - locationString: "批量导出离线表单数据时出错" - }); - } - }; - HAC_BatchUploadProgress.finish({ - success: batchExportSuccess, - error: batchExportError, - onConfirm: continueBatchExport - }); - }, HAC_GetOfflinePlusDebugInfo("批量导出离线表单", "生成批量导出回调ticket"), function (error) { - HAC_BatchUploadProgress.finish({ - success: false, - error: error, - onConfirm: function () { - HAC_OfflineExportExecution.complete(); - } + } + me.CommandExecutor.excuteCommand(me.CommandParam.CommandList, { + runTimePageName: me.CommandExecutingInfo.runTimePageName, + commandID: new Date().valueOf().toString(), + initParams: { + "ExportResult": batchExportPayload, + "IsSuccess": batchExportSuccess, + "Error": batchExportError + }, + locationString: batchExportSuccess + ? "执行window.offlinePlus.offlinePlusExportMultipleRecordsAsync" + : "批量导出离线表单数据时出错" }); + }, HAC_GetOfflinePlusDebugInfo("批量导出离线表单", "生成批量导出回调ticket"), function () { + HAC_FileUploadProgress.close(); + HAC_OfflineExportExecution.complete(); }); if (!ticket) { - HAC_BatchUploadProgress.close(); + HAC_FileUploadProgress.close(); HAC_OfflineExportExecution.complete(); return; } @@ -4248,13 +4254,13 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { try { window.offlinePlus.offlinePlusExportMultipleRecordsAsync(ticket); } catch (e) { - HAC_BatchUploadProgress.close(); + HAC_FileUploadProgress.close(); HAC_OfflineExportExecution.complete(); throw e; } } else { HAC_CallFunctionOutOfHAC(HAC_GetOfflinePlusDebugInfo("批量导出离线表单", "调用offlinePlusExportMultipleRecordsAsync")); - HAC_BatchUploadProgress.close(); + HAC_FileUploadProgress.close(); HAC_OfflineExportExecution.complete(); } return; diff --git a/Resources/OfflinePlusExportProgress.js b/Resources/OfflinePlusExportProgress.js index 2012c63..e22eef5 100644 --- a/Resources/OfflinePlusExportProgress.js +++ b/Resources/OfflinePlusExportProgress.js @@ -16,204 +16,78 @@ var HAC_OfflineExportExecution = { this.isRunning = false; } }; -/** - * 离线附件上传进度显示组件 - */ -var HAC_OfflineUploadProgress = { - element: null, - panel: null, - collapseButton: null, - collapsedButton: null, - fill: null, - title: null, - detail: null, - speed: null, - preventScrollHandler: null, - collapseButtonHandler: null, - collapsedButtonHandler: null, - collapsed: false, - 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) { - if (this.collapsed) { - return; - } - event.preventDefault(); - }.bind(this); - root.addEventListener("touchmove", this.preventScrollHandler, { passive: false }); - document.body.appendChild(root); - this.element = root; - this.panel = root.querySelector("[data-role='panel']"); - this.collapseButton = root.querySelector("[data-role='collapse']"); - this.collapsedButton = root.querySelector("[data-role='collapsed']"); - 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']"); - this.collapseButtonHandler = function () { - this.collapse(); - }.bind(this); - this.collapsedButtonHandler = function () { - this.expand(); - }.bind(this); - this.collapseButton.addEventListener("click", this.collapseButtonHandler); - this.collapsedButton.addEventListener("click", this.collapsedButtonHandler); - }, - lockPage: function () { - document.body.style.overflow = "hidden"; - document.documentElement.style.overflow = "hidden"; - }, - unlockPage: function () { - document.body.style.overflow = this.bodyOverflow || ""; - document.documentElement.style.overflow = this.documentOverflow || ""; - }, - collapse: function () { - this.ensure(); - this.collapsed = true; - this.panel.style.display = "none"; - this.collapsedButton.style.display = "block"; - this.element.style.background = "transparent"; - this.element.style.pointerEvents = "none"; - this.unlockPage(); - }, - expand: function () { - this.ensure(); - this.collapsed = false; - this.panel.style.display = "block"; - this.collapsedButton.style.display = "none"; - this.element.style.background = "rgba(0,0,0,.28)"; - this.element.style.pointerEvents = "auto"; - this.lockPage(); - }, - 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 || ""; - this.collapsedButton.querySelector("[data-role='collapsed-title']").textContent = options.title || "正在上传离线附件"; - this.collapsedButton.querySelector("[data-role='collapsed-percent']").textContent = Math.floor(percent) + "%"; - }, - close: function () { - if (this.element && this.preventScrollHandler) { - this.element.removeEventListener("touchmove", this.preventScrollHandler); - } - if (this.collapseButton && this.collapseButtonHandler) { - this.collapseButton.removeEventListener("click", this.collapseButtonHandler); - } - if (this.collapsedButton && this.collapsedButtonHandler) { - this.collapsedButton.removeEventListener("click", this.collapsedButtonHandler); - } - if (this.element && this.element.parentNode) { - this.element.parentNode.removeChild(this.element); - } - this.unlockPage(); - this.element = null; - this.panel = null; - this.collapseButton = null; - this.collapsedButton = null; - this.fill = null; - this.title = null; - this.detail = null; - this.speed = null; - this.preventScrollHandler = null; - this.collapseButtonHandler = null; - this.collapsedButtonHandler = null; - this.collapsed = false; - this.bodyOverflow = null; - this.documentOverflow = null; - } -}; /** - * 批量离线附件上传进度显示组件 - 支持多行显示多个表单状态 + * 离线附件上传进度组件(文件级)。 + * 由 AndroidPDACommand.js 的一次导出流程(含窗口内重试)驱动: + * showBusy(message) + * begin(session) -> createHooks()(逐文件更新) + * -> showResultAndWait(stats, hasFailures) => Promise<"retry" | "confirm"> + * -> markRetrying() / finishUploading(stats) -> close() */ -var HAC_BatchUploadProgress = { +var HAC_FileUploadProgress = { element: null, panel: null, + title: null, + subtitle: null, collapseButton: null, collapsedButton: null, - title: null, - countLabel: null, - listContainer: null, - summaryLabel: null, - currentTitle: null, - percentLabel: null, fill: null, + percentLabel: null, metaLeft: null, metaRight: null, + countLabel: null, + listSection: null, + listContainer: null, + footer: null, + retryButton: null, confirmButton: null, itemMap: {}, - preventScrollHandler: null, - buttonClickHandler: null, + decisionResolver: null, collapseButtonHandler: null, collapsedButtonHandler: null, - confirmHandler: null, + retryClickHandler: null, + confirmClickHandler: null, + preventScrollHandler: null, collapsed: false, bodyOverflow: null, documentOverflow: null, - ensure: function (itemCount) { + + 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:#fff;display:flex;align-items:stretch;justify-content:center;font-family:Arial,'Microsoft YaHei',sans-serif;touch-action:none;overscroll-behavior:contain;box-sizing:border-box;"; - root.innerHTML = "" + + root.innerHTML = + "" + "
" + "
" + "
" + - "
批量导出离线表单
" + - "
批量上传已开始,状态会按处理进度实时更新。
" + + "
上传离线附件
" + + "
正在准备附件
" + "
" + "
" + - "
" + - "
" + - "正在导出:" + - "" + - "
" + - "0%" + - "
" + - "
" + - "
" + - "" + - "" + - "
" + - "
" + - "
" + - "
" + - "

单据列表

" + - "" + + "
0%
" + + "
" + + "
" + "
" + + "
" + + "

附件列表

" + "
" + "
" + - "
" + - "" + + "
" + + "" + + "" + "
" + "
" + "
" + - ""; + ""; + 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) { if (this.collapsed) { return; @@ -226,55 +100,54 @@ var HAC_BatchUploadProgress = { }.bind(this); root.addEventListener("touchmove", this.preventScrollHandler, { passive: false }); document.body.appendChild(root); + this.element = root; this.panel = root.querySelector("[data-role='panel']"); + this.title = root.querySelector("[data-role='title']"); + this.subtitle = root.querySelector("[data-role='subtitle']"); this.collapseButton = root.querySelector("[data-role='collapse']"); this.collapsedButton = root.querySelector("[data-role='collapsed']"); - this.title = root.querySelector("[data-role='title']"); - this.countLabel = root.querySelector("[data-role='count']"); - this.listContainer = root.querySelector("[data-role='list']"); - this.summaryLabel = root.querySelector("[data-role='summary-label']"); - this.currentTitle = root.querySelector("[data-role='current-title']"); - this.percentLabel = root.querySelector("[data-role='percent']"); this.fill = root.querySelector("[data-role='fill']"); + this.percentLabel = root.querySelector("[data-role='percent']"); this.metaLeft = root.querySelector("[data-role='meta-left']"); this.metaRight = root.querySelector("[data-role='meta-right']"); + this.countLabel = root.querySelector("[data-role='count']"); + this.listSection = root.querySelector("[data-role='list-section']"); + this.listContainer = root.querySelector("[data-role='list']"); + this.footer = root.querySelector("[data-role='footer']"); + this.retryButton = root.querySelector("[data-role='retry']"); this.confirmButton = root.querySelector("[data-role='confirm']"); - this.buttonClickHandler = function () { - if (!this.confirmButton || this.confirmButton.disabled) { - return; - } - var confirmHandler = this.confirmHandler; - this.close(); - if (confirmHandler) { - confirmHandler(); - } - }.bind(this); - this.confirmButton.addEventListener("click", this.buttonClickHandler); + this.collapseButtonHandler = function () { this.collapse(); }.bind(this); this.collapsedButtonHandler = function () { this.expand(); }.bind(this); + this.retryClickHandler = function () { + this.resolveDecision("retry"); + }.bind(this); + this.confirmClickHandler = function () { + this.resolveDecision("confirm"); + }.bind(this); this.collapseButton.addEventListener("click", this.collapseButtonHandler); this.collapsedButton.addEventListener("click", this.collapsedButtonHandler); - this.refreshCount(itemCount || 0); - this.updateSummary({ - percent: 0, - title: "准备导出", - metaLeft: "正在准备附件", - metaRight: "" - }); + this.retryButton.addEventListener("click", this.retryClickHandler); + this.confirmButton.addEventListener("click", this.confirmClickHandler); + + this.lockPage(); }, + lockPage: function () { document.body.style.overflow = "hidden"; document.documentElement.style.overflow = "hidden"; }, + unlockPage: function () { document.body.style.overflow = this.bodyOverflow || ""; document.documentElement.style.overflow = this.documentOverflow || ""; }, + collapse: function () { this.ensure(); this.collapsed = true; @@ -284,6 +157,7 @@ var HAC_BatchUploadProgress = { this.element.style.pointerEvents = "none"; this.unlockPage(); }, + expand: function () { this.ensure(); this.collapsed = false; @@ -293,27 +167,153 @@ var HAC_BatchUploadProgress = { this.element.style.pointerEvents = "auto"; this.lockPage(); }, - refreshCount: function (itemCount) { - if (!this.countLabel) { + + /** 仅显示忙碌提示(文件清单尚未拿到时)。 */ + showBusy: function (message) { + this.ensure(); + this.expand(); + this.title.textContent = "上传离线附件"; + this.subtitle.textContent = message || "正在读取设备上的离线数据"; + this.listSection.style.display = "none"; + this.footer.style.display = "none"; + this.hideButtons(); + this.setPercent(0); + this.metaLeft.textContent = ""; + this.metaRight.textContent = ""; + }, + + /** 渲染文件清单(第一步先拿到"上传情况"),并初始化汇总。 */ + begin: function (session) { + this.ensure(); + this.expand(); + this.title.textContent = "上传离线附件"; + this.subtitle.textContent = session.total > 0 + ? ("共 " + session.total + " 个附件待上传") + : "无待上传附件"; + this.listSection.style.display = "flex"; + this.footer.style.display = "block"; + this.hideButtons(); + + this.itemMap = {}; + this.listContainer.innerHTML = ""; + var self = this; + session.entries.forEach(function (entry) { + var row = document.createElement("div"); + row.style.cssText = "display:flex;align-items:center;justify-content:space-between;gap:12px;padding:14px 4px;border-bottom:1px solid #e4e8f0;"; + + var left = document.createElement("div"); + left.style.cssText = "flex:1;min-width:0;"; + var titleEl = document.createElement("strong"); + titleEl.style.cssText = "display:block;font-size:14px;font-weight:500;line-height:20px;color:#222;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;"; + titleEl.textContent = entry.displayName || entry.attachment.localName; + var metaEl = document.createElement("span"); + metaEl.style.cssText = "display:block;margin-top:3px;font-size:12px;line-height:18px;color:#667085;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;"; + metaEl.textContent = "等待上传"; + left.appendChild(titleEl); + left.appendChild(metaEl); + + var statusIcon = document.createElement("div"); + statusIcon.style.cssText = "width:28px;height:28px;border-radius:999px;flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;color:#98a2b3;"; + + row.appendChild(left); + row.appendChild(statusIcon); + self.listContainer.appendChild(row); + + self.itemMap[entry.key] = { title: titleEl, meta: metaEl, statusIcon: statusIcon }; + self.renderStatus(statusIcon, "pending"); + }); + + this.countLabel.textContent = "共 " + session.total + " 项"; + this.updateSummary({ total: session.total, success: 0, failed: 0, uploading: 0, pending: session.total }); + this.metaRight.textContent = ""; + }, + + /** 生成上传流程使用的进度回调。 */ + createHooks: function () { + var self = this; + return { + onFileStart: function (entry, stats) { + self.updateEntry(entry, "uploading", stats); + }, + onFileProgress: function (entry, loaded, total, bytesPerSecond, stats) { + self.updateEntryProgress(entry, loaded, total, bytesPerSecond, stats); + }, + onFileEnd: function (entry, stats) { + self.updateEntry(entry, entry.state, stats); + } + }; + }, + + updateEntry: function (entry, state, stats) { + var item = this.itemMap[entry.key]; + if (item) { + if (state === "uploading") { + this.renderStatus(item.statusIcon, "processing"); + item.meta.textContent = "上传中…"; + } else if (state === "SUCCESS") { + this.renderStatus(item.statusIcon, "completed"); + item.meta.textContent = "已上传"; + } else if (state === "FAILED") { + this.renderStatus(item.statusIcon, "error"); + item.meta.textContent = entry.error || "上传失败"; + } else { + this.renderStatus(item.statusIcon, "pending"); + item.meta.textContent = "等待上传"; + } + } + this.updateSummary(stats); + }, + + updateEntryProgress: function (entry, loaded, total, bytesPerSecond, stats) { + var item = this.itemMap[entry.key]; + if (item) { + var text = "上传中 " + HAC_FormatBytesAsMb(loaded) + " / " + HAC_FormatBytesAsMb(total); + if (bytesPerSecond > 0) { + text += " · " + HAC_FormatBytesAsMb(bytesPerSecond) + "/s"; + } + item.meta.textContent = text; + } + this.updateSummary(stats, entry.displayName + " · " + HAC_FormatBytesAsMb(bytesPerSecond) + "/s"); + }, + + updateSummary: function (stats, currentText) { + if (!stats) { return; } - var count = itemCount || Object.keys(this.itemMap).length; - this.countLabel.textContent = "共 " + count + " 项"; + var total = stats.total || 0; + var done = (stats.success || 0) + (stats.failed || 0); + this.setPercent(total === 0 ? 0 : done / total * 100); + this.metaLeft.textContent = "已成功 " + (stats.success || 0) + "/" + total + + (stats.failed ? (",失败 " + stats.failed) : ""); + if (currentText !== undefined && currentText !== null) { + this.metaRight.textContent = currentText; + } }, + + setPercent: function (percent) { + percent = Math.max(0, Math.min(100, percent || 0)); + this.fill.style.width = percent.toFixed(1) + "%"; + this.percentLabel.textContent = Math.floor(percent) + "%"; + var collapsedPercent = this.collapsedButton.querySelector("[data-role='collapsed-percent']"); + if (collapsedPercent) { + collapsedPercent.textContent = Math.floor(percent) + "%"; + } + }, + renderStatus: function (statusIcon, state) { if (!statusIcon) { return; } switch (state) { - case 'processing': + case "processing": statusIcon.style.color = "#2f7df6"; - statusIcon.innerHTML = ""; + statusIcon.innerHTML = ""; break; - case 'completed': + case "completed": statusIcon.style.color = "#52c41a"; statusIcon.innerHTML = ""; break; - case 'error': + case "error": statusIcon.style.color = "#ff4d4f"; statusIcon.innerHTML = ""; break; @@ -323,180 +323,112 @@ var HAC_BatchUploadProgress = { break; } }, - updateSummary: function (options) { - this.ensure(); - options = options || {}; - if (options.percent !== undefined) { - var percent = Math.max(0, Math.min(100, options.percent || 0)); - this.fill.style.width = percent.toFixed(1) + "%"; - this.percentLabel.textContent = Math.floor(percent) + "%"; - } - if (options.title !== undefined) { - this.currentTitle.textContent = options.title || "离线表单"; - this.collapsedButton.querySelector("[data-role='collapsed-title']").textContent = options.title || "离线表单"; - } - if (options.metaLeft !== undefined) { - this.metaLeft.textContent = options.metaLeft || ""; - } - if (options.metaRight !== undefined) { - this.metaRight.textContent = options.metaRight || ""; - } - if (options.label !== undefined) { - this.summaryLabel.textContent = options.label || ""; - } - if (options.percent !== undefined) { - this.collapsedButton.querySelector("[data-role='collapsed-percent']").textContent = Math.floor(percent) + "%"; - } - }, - finish: function (options) { - options = options || {}; - if (!this.element) { - if (options.onConfirm) { - options.onConfirm(); - } - return; - } - this.confirmHandler = options.onConfirm || null; - if (options.success === false) { - this.updateSummary({ - label: "导出结果:", - title: "处理完成", - metaLeft: "处理失败", - metaRight: options.error || "请查看失败项" - }); - } else { - this.updateSummary({ - label: "导出结果:", - percent: 100, - title: "处理完成", - metaLeft: "已完成全部动作", - metaRight: "可以关闭页面" - }); + + hideButtons: function () { + if (this.retryButton) { + this.retryButton.style.display = "none"; } if (this.confirmButton) { - this.confirmButton.disabled = false; - this.confirmButton.textContent = "确认"; - this.confirmButton.style.background = "#2f7df6"; - this.confirmButton.style.opacity = "1"; - this.confirmButton.style.cursor = "pointer"; + this.confirmButton.style.display = "none"; } }, - /** - * 初始化表单项 - * @param {*} itemKey 表单项唯一标识 - * @param {*} itemTitle 表单显示标题 - */ - initItem: function (itemKey, itemTitle) { - this.ensure(); - if (this.itemMap[itemKey]) { - return; - } - var itemDiv = document.createElement("div"); - itemDiv.style.cssText = "display:flex;align-items:center;justify-content:space-between;gap:18px;padding:17px 4px;border-bottom:1px solid #e4e8f0;background:#fff;"; - itemDiv.innerHTML = "
" + - "" + - "" + - "
" + - "
"; - - this.listContainer.appendChild(itemDiv); - this.itemMap[itemKey] = { - element: itemDiv, - statusIcon: itemDiv.querySelector("[data-role='status']"), - title: itemDiv.querySelector("[data-role='title']"), - progress: itemDiv.querySelector("[data-role='progress']"), - baseTitle: itemTitle || "离线表单", - state: 'pending' - }; - this.itemMap[itemKey].title.textContent = itemTitle || "离线表单"; - this.itemMap[itemKey].progress.textContent = "等待处理..."; - this.renderStatus(this.itemMap[itemKey].statusIcon, 'pending'); - this.refreshCount(); - }, /** - * 更新表单项状态 - * @param {*} itemKey 表单项唯一标识 - * @param {*} options 状态选项 { state, progress, detail, titleSuffix } + * 显示结果并等待用户选择。返回 Promise: + * - "retry":重试失败项 + * - "confirm":确认(放弃失败项或结束) */ - updateItem: function (itemKey, options) { + showResultAndWait: function (stats, hasFailures) { this.ensure(); - var item = this.itemMap[itemKey]; - if (!item) { - return; - } - - if (options.state) { - item.state = options.state; - this.renderStatus(item.statusIcon, options.state); - } + var self = this; + return new Promise(function (resolve) { + self.decisionResolver = resolve; + if (hasFailures) { + self.retryButton.textContent = "重试失败项(" + stats.failed + ")"; + self.retryButton.style.display = "block"; + self.confirmButton.textContent = "确认(放弃 " + stats.failed + " 个失败项)"; + self.subtitle.textContent = "部分附件上传失败,可重试或确认放弃失败项"; + self.metaRight.textContent = "失败 " + stats.failed + " 个"; + } else { + self.retryButton.style.display = "none"; + self.confirmButton.textContent = "确认"; + self.subtitle.textContent = "附件上传完成"; + self.metaRight.textContent = "已全部上传"; + } + self.confirmButton.style.display = "block"; + self.updateSummary(stats); + }); + }, - if (options.detail !== undefined) { - item.progress.textContent = options.detail; + resolveDecision: function (decision) { + this.hideButtons(); + var resolver = this.decisionResolver; + this.decisionResolver = null; + if (resolver) { + resolver(decision); } + }, - if (options.titleSuffix !== undefined) { - item.title.textContent = item.baseTitle + options.titleSuffix; - } + markRetrying: function () { + this.hideButtons(); + this.subtitle.textContent = "正在重试失败项…"; + }, - if (options.progress !== undefined) { - if (item.state !== 'completed' && item.state !== 'error') { - item.progress.textContent = "处理中: " + Math.floor(options.progress) + "%"; - } + finishUploading: function (stats) { + this.updateSummary(stats); + if (stats && stats.failed > 0) { + this.subtitle.textContent = "已完成,仍有 " + stats.failed + " 个失败已放弃"; + } else { + this.subtitle.textContent = "已全部完成"; } }, - /** - * 标记表单项完成 - * @param {*} itemKey 表单项唯一标识 - */ - completeItem: function (itemKey) { - this.updateItem(itemKey, { state: 'completed', detail: '已完成' }); - }, - /** - * 标记表单项错误 - * @param {*} itemKey 表单项唯一标识 - * @param {*} error 错误信息 - */ - errorItem: function (itemKey, error) { - this.updateItem(itemKey, { state: 'error', detail: error || '处理失败' }); - }, + close: function () { + var hadElement = !!this.element; if (this.element && this.preventScrollHandler) { this.element.removeEventListener("touchmove", this.preventScrollHandler); } - if (this.confirmButton && this.buttonClickHandler) { - this.confirmButton.removeEventListener("click", this.buttonClickHandler); - } if (this.collapseButton && this.collapseButtonHandler) { this.collapseButton.removeEventListener("click", this.collapseButtonHandler); } if (this.collapsedButton && this.collapsedButtonHandler) { this.collapsedButton.removeEventListener("click", this.collapsedButtonHandler); } + if (this.retryButton && this.retryClickHandler) { + this.retryButton.removeEventListener("click", this.retryClickHandler); + } + if (this.confirmButton && this.confirmClickHandler) { + this.confirmButton.removeEventListener("click", this.confirmClickHandler); + } if (this.element && this.element.parentNode) { this.element.parentNode.removeChild(this.element); } - this.unlockPage(); + if (hadElement) { + this.unlockPage(); + } this.element = null; this.panel = null; + this.title = null; + this.subtitle = null; this.collapseButton = null; this.collapsedButton = null; - this.title = null; - this.countLabel = null; - this.listContainer = null; - this.summaryLabel = null; - this.currentTitle = null; - this.percentLabel = null; this.fill = null; + this.percentLabel = null; this.metaLeft = null; this.metaRight = null; + this.countLabel = null; + this.listSection = null; + this.listContainer = null; + this.footer = null; + this.retryButton = null; this.confirmButton = null; this.itemMap = {}; - this.preventScrollHandler = null; - this.buttonClickHandler = null; + this.decisionResolver = null; this.collapseButtonHandler = null; this.collapsedButtonHandler = null; - this.confirmHandler = null; + this.retryClickHandler = null; + this.confirmClickHandler = null; + this.preventScrollHandler = null; this.collapsed = false; this.bodyOverflow = null; this.documentOverflow = null; -- Gitee From f86084ec046b87af1fa2f08ab5434e313a3f30a8 Mon Sep 17 00:00:00 2001 From: GerZhang Date: Tue, 13 Oct 2026 16:08:30 +0800 Subject: [PATCH 58/71] =?UTF-8?q?feat(offline-upload):=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E2=80=9C=E8=8E=B7=E5=8F=96=E7=BD=91=E7=BB=9C=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E2=80=9D=E5=91=BD=E4=BB=A4=E5=B9=B6=E6=8E=A5=E5=85=A5?= =?UTF-8?q?=20window.network?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AndroidPDACommand.csproj | 1 + Network_Status.cs | 46 +++++++++++ Resources/AndroidPDACommand.js | 145 +++++++++++++++++++++++++++++++++ 3 files changed, 192 insertions(+) create mode 100644 Network_Status.cs diff --git a/AndroidPDACommand.csproj b/AndroidPDACommand.csproj index 8d18736..b07d546 100644 --- a/AndroidPDACommand.csproj +++ b/AndroidPDACommand.csproj @@ -107,6 +107,7 @@ + diff --git a/Network_Status.cs b/Network_Status.cs new file mode 100644 index 0000000..e592b05 --- /dev/null +++ b/Network_Status.cs @@ -0,0 +1,46 @@ +using GrapeCity.Forguncy.Commands; +using GrapeCity.Forguncy.Plugin; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace AndroidPDACommand +{ + /// + /// 读取当前网络状态到变量,供 H5 页面直接使用。 + /// 仅支持网络类型与是否计量网络,不含信号强度(见弱网增强一期)。 + /// + [Icon("pack://application:,,,/AndroidPDACommand;component/Resources/Icon_Info.png")] + [Category("活字格安卓容器(HAC)")] + [OrderWeight(905)] + public class Network_Status : BaseCommand + { + [ResultToProperty] + [DisplayName("网络信息(JSON)到变量")] + [Description("形如 {\"connected\":true,\"transport\":\"wifi\",\"metered\":false,\"validated\":true,\"timestamp\":0}。")] + public string NetworkInfo { get; set; } = "NetworkStatus"; + + [ResultToProperty] + [DisplayName("是否已连接网络到变量")] + public string IsConnected { get; set; } = "NetworkConnected"; + + [ResultToProperty] + [DisplayName("连接类型到变量")] + [Description("wifi / cellular / ethernet / vpn / other / none。")] + public string Transport { get; set; } = "NetworkTransport"; + + [ResultToProperty] + [DisplayName("是否移动数据(流量)到变量")] + [Description("以系统是否计量网络为准,WiFi 热点也可能是 true。")] + public string IsMetered { get; set; } = "NetworkMetered"; + + public override string ToString() + { + return "获取网络状态"; + } + } +} diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 2b78bcf..1fa21ac 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -204,6 +204,108 @@ async function HAC_UploadFileToTemp(file, uploadLimitId, onProgress) { } throw lastError || HAC_CreateUploadError("上传离线附件失败。", 0); } + +/** + * 查询当前网络状态(一期 HAC 原生 network 代理)。 + * 旧版 APP 无该能力时返回 null(视为未知,不阻断上传)。 + * @returns Promise<{connected, transport, metered, validated} | null> + */ +function HAC_QueryNetworkStatus() { + return new Promise(function (resolve) { + if (!window.HAC || !window.HAC.registryCallback + || !window.network || !window.network.getStatusAsync) { + resolve(null); + return; + } + + var ticket = { functionName: "hac_network_status_" + new Date().valueOf().toString() }; + if (window.parent) { + ticket.iFrameName = window.name; + } + + var settled = false; + var timer = null; + var finish = function (status) { + if (settled) { + return; + } + settled = true; + if (timer) { + clearTimeout(timer); + } + resolve(status); + }; + // 兜底:网络桥若未回传,3 秒后按未知处理,避免阻塞上传。 + timer = setTimeout(function () { + finish(null); + }, 3000); + + try { + window.HAC.registryCallback(ticket, function (payload) { + var status = null; + try { + status = JSON.parse(payload); + } catch (e) { + status = null; + } + finish(status); + }, function () { + finish(null); + }); + window.network.getStatusAsync(JSON.stringify(ticket)); + } catch (e) { + finish(null); + } + }); +} + +/** + * 上传前的弱网前置检查: + * - 无网络:直接失败,避免逐个文件等待超时; + * - 计量网络(流量/热点):提示用户确认,可能产生流量费用。 + * 网络状态不可用(旧版 APP)时不阻断。 + * @returns Promise,不通过时 reject + */ +async function HAC_EnsureNetworkReadyForUpload(attachmentCount) { + var status = await HAC_QueryNetworkStatus(); + if (!status) { + return; + } + if (status.connected === false) { + throw new Error("当前没有网络连接,无法上传离线附件,请检查网络后重试。"); + } + if (status.metered === true) { + var confirmed = window.confirm("当前为移动数据网络,本次将上传 " + attachmentCount + " 个离线附件,可能产生流量费用。是否继续?"); + if (!confirmed) { + throw new Error("用户取消了上传。"); + } + } +} + +/** + * 把网络状态写入命令的输出变量:完整 JSON + 是否连接 + 连接类型 + 是否计量。 + * jsonText 为空或解析失败时,除 JSON 外均置为空/否。 + */ +function HAC_ApplyNetworkStatus(infoVar, connectedVar, transportVar, meteredVar, jsonText) { + var status = null; + try { + status = jsonText ? JSON.parse(jsonText) : null; + } catch (e) { + status = null; + } + if (!status) { + HAC_ReturnToParam(infoVar, jsonText || ""); + HAC_ReturnToParam(connectedVar, false); + HAC_ReturnToParam(transportVar, ""); + HAC_ReturnToParam(meteredVar, false); + return; + } + HAC_ReturnToParam(infoVar, jsonText); + HAC_ReturnToParam(connectedVar, status.connected === true); + HAC_ReturnToParam(transportVar, status.transport || "none"); + HAC_ReturnToParam(meteredVar, status.metered === true); +} + function HAC_GetOfflineRecordFieldValue(record, fieldId) { var fieldValue = record && record.values && record.values[fieldId]; if (fieldValue && typeof fieldValue === "object" && !Array.isArray(fieldValue) && @@ -517,6 +619,9 @@ async function HAC_ProcessOfflineAttachments(exportDataArray, uploadLimitId, opt throw new Error("请设置文件上传限制ID。"); } + // 弱网前置检查:无网络直接失败,计量网络提示确认。 + await HAC_EnsureNetworkReadyForUpload(session.total); + HAC_FileUploadProgress.begin(session); var hooks = HAC_FileUploadProgress.createHooks(); @@ -1876,6 +1981,46 @@ var Device_Info_Command = (function (_super) { Forguncy.CommandFactory.registerCommand("AndroidPDACommand.Device_Info, AndroidPDACommand", Device_Info_Command); +/** + * 获取网络状态:将当前网络信息写入变量,供页面直接使用。 + * 优先使用同步接口 window.network.getStatus();旧版 APP 退化到 getStatusAsync。 + */ +var Network_Status_Command = (function (_super) { + __extends(Network_Status_Command, _super); + function Network_Status_Command() { + return _super !== null && _super.apply(this, arguments) || this; + } + + Network_Status_Command.prototype.execute = function () { + var params = this.CommandParam; + var infoVar = params.NetworkInfo; + var connectedVar = params.IsConnected; + var transportVar = params.Transport; + var meteredVar = params.IsMetered; + + if (window.network && typeof window.network.getStatus === "function") { + // 同步接口:可直接在后续命令中读取变量 + HAC_ApplyNetworkStatus(infoVar, connectedVar, transportVar, meteredVar, window.network.getStatus()); + return; + } + + if (window.network && window.network.getStatusAsync) { + // 兼容旧版 APP:异步获取,回调后再写入变量 + HAC_QueryNetworkStatus().then(function (status) { + HAC_ApplyNetworkStatus(infoVar, connectedVar, transportVar, meteredVar, status ? JSON.stringify(status) : ""); + }); + return; + } + + HAC_CallFunctionOutOfHAC("当前APP不支持获取网络状态,请升级HAC到最新版本。"); + HAC_ApplyNetworkStatus(infoVar, connectedVar, transportVar, meteredVar, ""); + }; + + return Network_Status_Command; +}(Forguncy.CommandBase)); + +Forguncy.CommandFactory.registerCommand("AndroidPDACommand.Network_Status, AndroidPDACommand", Network_Status_Command); + var BLE_Scan_Command = (function (_super) { __extends(BLE_Scan_Command, _super); function BLE_Scan_Command() { -- Gitee From 6886d01b014374d4806d9dc62ddf809f1885811a Mon Sep 17 00:00:00 2001 From: GerZhang Date: Tue, 13 Oct 2026 18:14:00 +0800 Subject: [PATCH 59/71] =?UTF-8?q?refactor(network-status):=20=E4=BB=85?= =?UTF-8?q?=E4=BF=9D=E7=95=99=E7=BD=91=E7=BB=9C=E7=8A=B6=E6=80=81=20JSON?= =?UTF-8?q?=20=E8=BE=93=E5=87=BA=E5=B9=B6=E8=A1=A5=E5=85=85=E5=AF=B9?= =?UTF-8?q?=E8=B1=A1=E4=B8=8E=E6=9E=9A=E4=B8=BE=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Network_Status.cs | 31 ++++++++++++++++--------------- Resources/AndroidPDACommand.js | 33 +++------------------------------ 2 files changed, 19 insertions(+), 45 deletions(-) diff --git a/Network_Status.cs b/Network_Status.cs index e592b05..b270b2b 100644 --- a/Network_Status.cs +++ b/Network_Status.cs @@ -17,27 +17,28 @@ namespace AndroidPDACommand [Icon("pack://application:,,,/AndroidPDACommand;component/Resources/Icon_Info.png")] [Category("活字格安卓容器(HAC)")] [OrderWeight(905)] + [Description( + "读取当前网络状态,写入一个 JSON 对象的变量;未连接或旧版 APP 时为空字符串。\r\n" + + "对象字段说明:\r\n" + + " connected:是否已连接网络,true/false。\r\n" + + " transport:连接类型,取值见下方连接类型枚举。\r\n" + + " metered:是否为计量网络(移动数据/热点,可能产生流量费用),true/false,以系统判定为准。\r\n" + + " validated:系统是否已验证该网络可访问互联网,true/false。\r\n" + + " timestamp:状态采集时间戳。\r\n" + + "连接类型(transport)枚举说明:\r\n" + + " wifi:Wi-Fi 无线网络。\r\n" + + " cellular:蜂窝移动数据网络(2G/3G/4G/5G)。\r\n" + + " ethernet:有线以太网。\r\n" + + " vpn:VPN 虚拟专用网络。\r\n" + + " other:其它未知类型。\r\n" + + " none:没有可用网络连接。")] public class Network_Status : BaseCommand { [ResultToProperty] [DisplayName("网络信息(JSON)到变量")] - [Description("形如 {\"connected\":true,\"transport\":\"wifi\",\"metered\":false,\"validated\":true,\"timestamp\":0}。")] + [Description("形如 {\"connected\":true,\"transport\":\"wifi\",\"metered\":false,\"validated\":true,\"timestamp\":0},字段含义见命令下方说明。")] public string NetworkInfo { get; set; } = "NetworkStatus"; - [ResultToProperty] - [DisplayName("是否已连接网络到变量")] - public string IsConnected { get; set; } = "NetworkConnected"; - - [ResultToProperty] - [DisplayName("连接类型到变量")] - [Description("wifi / cellular / ethernet / vpn / other / none。")] - public string Transport { get; set; } = "NetworkTransport"; - - [ResultToProperty] - [DisplayName("是否移动数据(流量)到变量")] - [Description("以系统是否计量网络为准,WiFi 热点也可能是 true。")] - public string IsMetered { get; set; } = "NetworkMetered"; - public override string ToString() { return "获取网络状态"; diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 1fa21ac..1d20e7f 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -282,30 +282,6 @@ async function HAC_EnsureNetworkReadyForUpload(attachmentCount) { } } -/** - * 把网络状态写入命令的输出变量:完整 JSON + 是否连接 + 连接类型 + 是否计量。 - * jsonText 为空或解析失败时,除 JSON 外均置为空/否。 - */ -function HAC_ApplyNetworkStatus(infoVar, connectedVar, transportVar, meteredVar, jsonText) { - var status = null; - try { - status = jsonText ? JSON.parse(jsonText) : null; - } catch (e) { - status = null; - } - if (!status) { - HAC_ReturnToParam(infoVar, jsonText || ""); - HAC_ReturnToParam(connectedVar, false); - HAC_ReturnToParam(transportVar, ""); - HAC_ReturnToParam(meteredVar, false); - return; - } - HAC_ReturnToParam(infoVar, jsonText); - HAC_ReturnToParam(connectedVar, status.connected === true); - HAC_ReturnToParam(transportVar, status.transport || "none"); - HAC_ReturnToParam(meteredVar, status.metered === true); -} - function HAC_GetOfflineRecordFieldValue(record, fieldId) { var fieldValue = record && record.values && record.values[fieldId]; if (fieldValue && typeof fieldValue === "object" && !Array.isArray(fieldValue) && @@ -1994,26 +1970,23 @@ var Network_Status_Command = (function (_super) { Network_Status_Command.prototype.execute = function () { var params = this.CommandParam; var infoVar = params.NetworkInfo; - var connectedVar = params.IsConnected; - var transportVar = params.Transport; - var meteredVar = params.IsMetered; if (window.network && typeof window.network.getStatus === "function") { // 同步接口:可直接在后续命令中读取变量 - HAC_ApplyNetworkStatus(infoVar, connectedVar, transportVar, meteredVar, window.network.getStatus()); + HAC_ReturnToParam(infoVar, window.network.getStatus() || ""); return; } if (window.network && window.network.getStatusAsync) { // 兼容旧版 APP:异步获取,回调后再写入变量 HAC_QueryNetworkStatus().then(function (status) { - HAC_ApplyNetworkStatus(infoVar, connectedVar, transportVar, meteredVar, status ? JSON.stringify(status) : ""); + HAC_ReturnToParam(infoVar, status ? JSON.stringify(status) : ""); }); return; } HAC_CallFunctionOutOfHAC("当前APP不支持获取网络状态,请升级HAC到最新版本。"); - HAC_ApplyNetworkStatus(infoVar, connectedVar, transportVar, meteredVar, ""); + HAC_ReturnToParam(infoVar, ""); }; return Network_Status_Command; -- Gitee From bbd5cde32744d0272258b5686a4c09a4798409fe Mon Sep 17 00:00:00 2001 From: GerZhang Date: Tue, 13 Oct 2026 21:18:37 +0800 Subject: [PATCH 60/71] =?UTF-8?q?feat(offline-build):=20=E8=A1=A8=E5=8D=95?= =?UTF-8?q?=E9=A1=B9=E6=96=B0=E5=A2=9E=E2=80=9C=E6=98=BE=E7=A4=BA=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E6=97=B6=E9=97=B4=E2=80=9D=E9=85=8D=E7=BD=AE=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- OfflinePlusBuildPattern.cs | 9 ++++++++- Resources/AndroidPDACommand.js | 6 +++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/OfflinePlusBuildPattern.cs b/OfflinePlusBuildPattern.cs index e8f0ff1..46d8ab2 100644 --- a/OfflinePlusBuildPattern.cs +++ b/OfflinePlusBuildPattern.cs @@ -150,7 +150,8 @@ namespace AndroidPDACommand nameof(ItemType), nameof(Title), nameof(Hint), - nameof(Required) + nameof(Required), + nameof(ShowFieldUpdateTime) }; private static readonly HashSet FieldTypeControlledProperties = new HashSet(CommonFieldVisibleProperties) @@ -248,6 +249,10 @@ namespace AndroidPDACommand [DisplayName("必填")] public bool Required { get; set; } + [DisplayName("显示更新时间")] + [Description("启用后,填报页会在该字段下方显示其最近更新时间。")] + public bool ShowFieldUpdateTime { get; set; } + [FormulaProperty] [DisplayName("默认值")] public object Value { get; set; } @@ -355,6 +360,7 @@ namespace AndroidPDACommand Title = Title, Hint = Hint, Required = Required, + ShowFieldUpdateTime = ShowFieldUpdateTime, Value = Value, IncludeTime = IncludeTime, IncludeSeconds = IncludeSeconds, @@ -418,6 +424,7 @@ namespace AndroidPDACommand Title = Title, Hint = Hint, Required = Required, + ShowFieldUpdateTime = ShowFieldUpdateTime, Value = Value, IncludeTime = IncludeTime, IncludeSeconds = IncludeSeconds, diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 1d20e7f..0dad350 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -3572,7 +3572,8 @@ function HAC_OfflinePlusCreateFormNodeBuilder(context) { itemType: node.ItemType, title: evaluate(node.Title), hint: evaluate(node.Hint), - required: !!node.Required + required: !!node.Required, + showFieldUpdateTime: !!node.ShowFieldUpdateTime }; var value = evaluate(node.Value); @@ -3888,6 +3889,9 @@ function HAC_OfflinePlusValidatePatternJson(patternJson) { if (field.required !== undefined && typeof field.required !== "boolean") { return fail(path + ".field.required", "必须是布尔值"); } + if (field.showFieldUpdateTime !== undefined && typeof field.showFieldUpdateTime !== "boolean") { + return fail(path + ".field.showFieldUpdateTime", "必须是布尔值"); + } if (field.options !== undefined && !isObject(field.options)) { return fail(path + ".field.options", "必须是对象"); } -- Gitee From 193b933d7067648d1b5a42483e45b8ce6fe88af6 Mon Sep 17 00:00:00 2001 From: GerZhang Date: Tue, 13 Oct 2026 22:06:09 +0800 Subject: [PATCH 61/71] =?UTF-8?q?build:=20macOS/Linux=20=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E6=89=A7=E8=A1=8C=E6=8F=92=E4=BB=B6=E6=89=93=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AndroidPDACommand.csproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/AndroidPDACommand.csproj b/AndroidPDACommand.csproj index b07d546..e41090c 100644 --- a/AndroidPDACommand.csproj +++ b/AndroidPDACommand.csproj @@ -34,8 +34,8 @@ $(MSBuildProjectDirectory)/PackageTools/ForguncyPluginPackageTool.exe $(MSBuildProjectDirectory)/PackageTools/ForguncyPluginPackageTool.dll - - false + + true true @@ -204,8 +204,8 @@ 插件打包:编译后在 bin 下生成 zip 插件包。 - 打包工具随工程放在 PackageTools/,不再依赖任何机器上的私有路径。 - Windows:直接运行 ForguncyPluginPackageTool.exe。 - - macOS / Linux:用 dotnet 运行跨平台的 ForguncyPluginPackageTool.dll(默认关闭, - 需要时用 -p:ForguncyPackageOnMac=true 开启)。工具定位的“自动安装”目录在非 Windows + - macOS / Linux:用 dotnet 运行跨平台的 ForguncyPluginPackageTool.dll(默认开启, + 可用 -p:ForguncyPackageOnMac=false 关闭)。工具定位的“自动安装”目录在非 Windows 上以工作目录为基准,这里把工作目录指向 obj,避免污染工程根目录。 --> -- Gitee From 95d2380314d6d48dee6b4e92ea5186adc92bd09d Mon Sep 17 00:00:00 2001 From: GerZhang Date: Tue, 13 Oct 2026 23:24:28 +0800 Subject: [PATCH 62/71] =?UTF-8?q?chore:=20=E7=89=88=E6=9C=AC=E5=8F=B7?= =?UTF-8?q?=E5=8D=87=E8=87=B3=201.24.0.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PluginConfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PluginConfig.json b/PluginConfig.json index ebf0a26..7ab27e9 100644 --- a/PluginConfig.json +++ b/PluginConfig.json @@ -13,7 +13,7 @@ "name": "PDA(Android)交互命令", "pluginType": "command", "guid": "{16B8DF69-1379-41C1-9194-BE89BAF8BB32}", - "version": "1.23.3.0", + "version": "1.24.0.0", "dependenceVersion": "8.0.0.0", "bundleJavaScript": true, "bundleCSS": true -- Gitee From 1b202815b76fa2deb09553a3b36f245b0c3ad780 Mon Sep 17 00:00:00 2001 From: GerZhang Date: Wed, 14 Oct 2026 14:03:46 +0800 Subject: [PATCH 63/71] =?UTF-8?q?chore:=20=E7=89=88=E6=9C=AC=E5=8F=B7?= =?UTF-8?q?=E8=B0=83=E6=95=B4=E4=B8=BA=201.23.4.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PluginConfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PluginConfig.json b/PluginConfig.json index 7ab27e9..bedf068 100644 --- a/PluginConfig.json +++ b/PluginConfig.json @@ -13,7 +13,7 @@ "name": "PDA(Android)交互命令", "pluginType": "command", "guid": "{16B8DF69-1379-41C1-9194-BE89BAF8BB32}", - "version": "1.24.0.0", + "version": "1.23.4.0", "dependenceVersion": "8.0.0.0", "bundleJavaScript": true, "bundleCSS": true -- Gitee From 83ed61aa62d1c2a3afde6811d77072263b320724 Mon Sep 17 00:00:00 2001 From: GerZhang Date: Thu, 15 Oct 2026 11:28:29 +0800 Subject: [PATCH 64/71] =?UTF-8?q?feat(offline-form):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E2=80=9C=E6=89=93=E5=BC=80=E7=A6=BB=E7=BA=BF=E5=A1=AB=E6=8A=A5?= =?UTF-8?q?=E2=80=9D=E5=91=BD=E4=BB=A4=EF=BC=8C=E6=94=AF=E6=8C=81=20H5=20?= =?UTF-8?q?=E7=9B=B4=E6=8E=A5=E8=B7=B3=E8=BD=AC=20HAC=20=E7=A6=BB=E7=BA=BF?= =?UTF-8?q?=E5=A1=AB=E6=8A=A5=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AndroidPDACommand.csproj | 1 + OfflinePlusOpenForm.cs | 20 ++++++++++++++++++++ Resources/AndroidPDACommand.js | 20 ++++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 OfflinePlusOpenForm.cs diff --git a/AndroidPDACommand.csproj b/AndroidPDACommand.csproj index e41090c..18eb459 100644 --- a/AndroidPDACommand.csproj +++ b/AndroidPDACommand.csproj @@ -74,6 +74,7 @@ + diff --git a/OfflinePlusOpenForm.cs b/OfflinePlusOpenForm.cs new file mode 100644 index 0000000..6dbb930 --- /dev/null +++ b/OfflinePlusOpenForm.cs @@ -0,0 +1,20 @@ +using GrapeCity.Forguncy.Commands; +using GrapeCity.Forguncy.Plugin; +using System.ComponentModel; + +namespace AndroidPDACommand +{ + /// + /// 打开HAC内置的“离线填报”页面,效果等同于点击APP右上角菜单中的“离线填报入口”。 + /// 用于在H5页面中直接跳转到离线填报页面,不依赖顶部菜单是否可见,也不受离线模式导航限制。 + /// + [Icon("pack://application:,,,/AndroidPDACommand;component/Resources/Icon_OfflineFormItem.png")] + [Category("活字格安卓容器(HAC)")] + public class OfflinePlusOpenForm : BaseCommand + { + public override string ToString() + { + return "打开离线填报"; + } + } +} diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 0dad350..61e4142 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -21,6 +21,7 @@ var HAC_GetOfflinePlusDebugInfo = function (commandName, stage) { "window.offlinePlus.offlinePlusAddPatternAsync:" + (offlinePlus && offlinePlus.offlinePlusAddPatternAsync ? typeof offlinePlus.offlinePlusAddPatternAsync : "undefined"), "window.offlinePlus.offlinePlusDownloadManualPdfAsync:" + (offlinePlus && offlinePlus.offlinePlusDownloadManualPdfAsync ? typeof offlinePlus.offlinePlusDownloadManualPdfAsync : "undefined"), "window.offlinePlus.offlinePlusGetPatternsAsync:" + (offlinePlus && offlinePlus.offlinePlusGetPatternsAsync ? typeof offlinePlus.offlinePlusGetPatternsAsync : "undefined"), + "window.offlinePlus.offlinePlusOpenFormList:" + (offlinePlus && offlinePlus.offlinePlusOpenFormList ? typeof offlinePlus.offlinePlusOpenFormList : "undefined"), "location:" + window.location.href ].join("\r\n"); }; @@ -4037,6 +4038,25 @@ var OfflinePlusValidatePatternJson_Command = (function (_super) { Forguncy.CommandFactory.registerCommand("AndroidPDACommand.OfflinePlusValidatePatternJson, AndroidPDACommand", OfflinePlusValidatePatternJson_Command); +var OfflinePlusOpenForm_Command = (function (_super) { + __extends(OfflinePlusOpenForm_Command, _super); + function OfflinePlusOpenForm_Command() { + return _super !== null && _super.apply(this, arguments) || this; + } + + OfflinePlusOpenForm_Command.prototype.execute = function () { + if (window.offlinePlus && window.offlinePlus.offlinePlusOpenFormList) { + window.offlinePlus.offlinePlusOpenFormList(); + } else { + HAC_CallFunctionOutOfHAC(HAC_GetOfflinePlusDebugInfo("打开离线填报", "调用offlinePlusOpenFormList")); + } + }; + + return OfflinePlusOpenForm_Command; +}(Forguncy.CommandBase)); + +Forguncy.CommandFactory.registerCommand("AndroidPDACommand.OfflinePlusOpenForm, AndroidPDACommand", OfflinePlusOpenForm_Command); + var OfflinePlusAddPattern_Async_Command = (function (_super) { __extends(OfflinePlusAddPattern_Async_Command, _super); function OfflinePlusAddPattern_Async_Command() { -- Gitee From 280c68bb4c6430a7fd93c98f6cf77f5ad4ea4d04 Mon Sep 17 00:00:00 2001 From: GerZhang Date: Thu, 15 Oct 2026 12:03:20 +0800 Subject: [PATCH 65/71] =?UTF-8?q?feat(offline-build):=20=E8=A1=A8=E5=8D=95?= =?UTF-8?q?=E9=A1=B9=E6=96=B0=E5=A2=9E=E2=80=9C=E4=BF=AE=E6=94=B9=E5=89=8D?= =?UTF-8?q?=E7=A1=AE=E8=AE=A4=E2=80=9D=E9=85=8D=E7=BD=AE=EF=BC=88=E4=B8=8B?= =?UTF-8?q?=E6=8B=89=E9=80=89=E6=8B=A9/=E5=8D=95=E9=80=89=E6=A1=86?= =?UTF-8?q?=EF=BC=89=EF=BC=8C=E6=94=AF=E6=8C=81=E8=87=AA=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E5=BC=B9=E7=AA=97=E6=96=87=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- OfflinePlusBuildPattern.cs | 60 +++++++++++++++++++++++++++++++--- Resources/AndroidPDACommand.js | 33 +++++++++++++++++++ 2 files changed, 88 insertions(+), 5 deletions(-) diff --git a/OfflinePlusBuildPattern.cs b/OfflinePlusBuildPattern.cs index 46d8ab2..0eea582 100644 --- a/OfflinePlusBuildPattern.cs +++ b/OfflinePlusBuildPattern.cs @@ -168,15 +168,16 @@ namespace AndroidPDACommand nameof(WatermarkOptions), nameof(FileItemConfig), nameof(SignatureOptions), - nameof(ListItemOptions) + nameof(ListItemOptions), + nameof(ConfirmOptions) }; 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)) }, - { "radioItem", CreateFieldVisibleProperties(nameof(Value), nameof(RadioDirection), nameof(SelectOptionsList)) }, + { "selectItem", CreateFieldVisibleProperties(nameof(Value), nameof(SelectOptionsList), nameof(ConfirmOptions)) }, + { "radioItem", CreateFieldVisibleProperties(nameof(Value), nameof(RadioDirection), nameof(SelectOptionsList), nameof(ConfirmOptions)) }, { "datePicker", CreateFieldVisibleProperties(nameof(Value), nameof(IncludeTime)) }, { "timePicker", CreateFieldVisibleProperties(nameof(Value), nameof(IncludeSeconds)) }, { "imageItem", CreateFieldVisibleProperties(nameof(MaxCount), nameof(AllowImageUpload), nameof(CompressionOptions), nameof(WatermarkOptions)) }, @@ -253,6 +254,11 @@ namespace AndroidPDACommand [Description("启用后,填报页会在该字段下方显示其最近更新时间。")] public bool ShowFieldUpdateTime { get; set; } + [ObjectProperty(ObjType = typeof(ConfirmOptions))] + [DisplayName("修改前确认")] + [Description("仅下拉选择和单选框生效。启用后,用户修改该组件时先弹出二次确认;确认后才会写入新值并更新更新时间。")] + public ConfirmOptions ConfirmOptions { get; set; } + [FormulaProperty] [DisplayName("默认值")] public object Value { get; set; } @@ -373,7 +379,8 @@ namespace AndroidPDACommand WatermarkOptions = WatermarkOptions, FileItemConfig = FileItemConfig, SignatureOptions = SignatureOptions, - ListItemOptions = ListItemOptions + ListItemOptions = ListItemOptions, + ConfirmOptions = ConfirmOptions }; } @@ -404,6 +411,16 @@ namespace AndroidPDACommand [ComboProperty(ValueList = BaseItemTypeValueList, DisplayList = BaseItemTypeDisplayList)] public override string ItemType { get; set; } = "textItem"; + public override bool GetDesignerPropertyVisible(string propertyName) + { + // 首版“修改前确认”仅支持顶层字段:列表子字段同 id 可能有多行,按字段 id 持久化锁定会产生歧义,故不开放。 + if (propertyName == nameof(ConfirmOptions)) + { + return false; + } + return base.GetDesignerPropertyVisible(propertyName); + } + public override object Clone() { return new OfflineListFormNode @@ -437,7 +454,8 @@ namespace AndroidPDACommand WatermarkOptions = WatermarkOptions, FileItemConfig = FileItemConfig, SignatureOptions = SignatureOptions, - ListItemOptions = ListItemOptions + ListItemOptions = ListItemOptions, + ConfirmOptions = ConfirmOptions }; } } @@ -600,4 +618,36 @@ namespace AndroidPDACommand [DisplayName("列表子项")] public List Children { get; set; } = new List(); } + + public class ConfirmOptions : ObjectPropertyBase + { + [DisplayName("启用二次确认")] + [Description("启用后,修改该组件前会弹出二次确认弹窗。")] + public bool Enabled { get; set; } + + [FormulaProperty] + [DisplayName("弹窗标题")] + [Description("留空则使用默认标题。")] + public object Title { get; set; } + + [FormulaProperty] + [DisplayName("弹窗内容")] + [Description("留空则使用默认内容。支持占位符:{title} 字段标题、{value} 新值、{oldValue} 原值。")] + public object Message { get; set; } + + [FormulaProperty] + [DisplayName("确定按钮文字")] + [Description("留空则使用默认文案“确定”。")] + public object ConfirmButtonText { get; set; } + + [FormulaProperty] + [DisplayName("取消按钮文字")] + [Description("留空则使用默认文案“取消”。")] + public object CancelButtonText { get; set; } + + [DefaultValue(true)] + [DisplayName("确认后禁用")] + [Description("启用后,二次确认通过后该组件将被禁用,不可再次修改(默认启用)。")] + public bool DisableAfterConfirm { get; set; } = true; + } } diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 61e4142..f5e3edf 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -3567,6 +3567,34 @@ function HAC_OfflinePlusCreateFormNodeBuilder(context) { } } + function buildConfirmOptions(options) { + if (!options || !options.Enabled) { + return undefined; + } + + var confirm = { + enabled: true, + disableAfterConfirm: options.DisableAfterConfirm !== false + }; + var title = evaluate(options.Title); + var message = evaluate(options.Message); + var confirmButtonText = evaluate(options.ConfirmButtonText); + var cancelButtonText = evaluate(options.CancelButtonText); + if (title !== undefined && title !== null && title !== "") { + confirm.title = title; + } + if (message !== undefined && message !== null && message !== "") { + confirm.message = message; + } + if (confirmButtonText !== undefined && confirmButtonText !== null && confirmButtonText !== "") { + confirm.confirmButtonText = confirmButtonText; + } + if (cancelButtonText !== undefined && cancelButtonText !== null && cancelButtonText !== "") { + confirm.cancelButtonText = cancelButtonText; + } + return confirm; + } + function buildField(node) { var field = { itemId: evaluate(node.ItemId), @@ -3582,6 +3610,11 @@ function HAC_OfflinePlusCreateFormNodeBuilder(context) { field.value = value; } applyFieldTypeSpec(field, node); + + var confirm = buildConfirmOptions(node.ConfirmOptions); + if (confirm) { + field.confirm = confirm; + } return field; } -- Gitee From f400bb7b19ab65638d59e38be72510645a57d816 Mon Sep 17 00:00:00 2001 From: GerZhang Date: Thu, 15 Oct 2026 14:26:17 +0800 Subject: [PATCH 66/71] =?UTF-8?q?feat(offline-build):=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E5=89=8D=E7=A1=AE=E8=AE=A4=E6=96=B0=E5=A2=9E=E2=80=9C=E9=A6=96?= =?UTF-8?q?=E6=AC=A1=E5=A1=AB=E5=86=99=E5=86=85=E5=AE=B9=E2=80=9D=E9=85=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- OfflinePlusBuildPattern.cs | 5 +++++ Resources/AndroidPDACommand.js | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/OfflinePlusBuildPattern.cs b/OfflinePlusBuildPattern.cs index 0eea582..fe5773e 100644 --- a/OfflinePlusBuildPattern.cs +++ b/OfflinePlusBuildPattern.cs @@ -635,6 +635,11 @@ namespace AndroidPDACommand [Description("留空则使用默认内容。支持占位符:{title} 字段标题、{value} 新值、{oldValue} 原值。")] public object Message { get; set; } + [FormulaProperty] + [DisplayName("首次填写内容")] + [Description("当字段当前无值(首次填写)时使用的弹窗内容;留空则使用上面的“弹窗内容”。同样支持占位符。")] + public object FirstFillMessage { get; set; } + [FormulaProperty] [DisplayName("确定按钮文字")] [Description("留空则使用默认文案“确定”。")] diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index f5e3edf..835eb20 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -3578,6 +3578,7 @@ function HAC_OfflinePlusCreateFormNodeBuilder(context) { }; var title = evaluate(options.Title); var message = evaluate(options.Message); + var firstFillMessage = evaluate(options.FirstFillMessage); var confirmButtonText = evaluate(options.ConfirmButtonText); var cancelButtonText = evaluate(options.CancelButtonText); if (title !== undefined && title !== null && title !== "") { @@ -3586,6 +3587,9 @@ function HAC_OfflinePlusCreateFormNodeBuilder(context) { if (message !== undefined && message !== null && message !== "") { confirm.message = message; } + if (firstFillMessage !== undefined && firstFillMessage !== null && firstFillMessage !== "") { + confirm.firstFillMessage = firstFillMessage; + } if (confirmButtonText !== undefined && confirmButtonText !== null && confirmButtonText !== "") { confirm.confirmButtonText = confirmButtonText; } -- Gitee From 25ed6c4aae3136e506e4194ac131cfc07ba3be9c Mon Sep 17 00:00:00 2001 From: GerZhang Date: Thu, 15 Oct 2026 17:12:13 +0800 Subject: [PATCH 67/71] =?UTF-8?q?fix(offline-export):=20=E6=89=B9=E9=87=8F?= =?UTF-8?q?=E5=AF=BC=E5=87=BA=E5=85=88=E8=B7=B3=E8=BD=AC=20APP=20=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E9=80=89=E6=8B=A9=EF=BC=8C=E8=BF=94=E5=9B=9E=E5=90=8E?= =?UTF-8?q?=E5=86=8D=E5=BC=B9=E5=87=BA=E4=B8=8A=E4=BC=A0=E7=AA=97=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Resources/AndroidPDACommand.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 835eb20..e8175a4 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -4388,7 +4388,7 @@ var OfflinePlusGetPatterns_Async_Command = (function (_super) { } var fileUploadLimit = (params.ServerPropertiesId && params.ServerPropertiesId.FileUploadLimit) || ""; let me = this; - HAC_FileUploadProgress.showBusy("正在读取设备数据"); + // 先直接跳到 APP 的列表选择页;选好导出项、回到 H5 后,由回调里的附件上传流程再弹出上传窗口。 let ticket = HAC_GenerateCallbackTicket(me, async function (payload, payload2) { var batchExportPayload = payload; var batchExportSuccess = true; -- Gitee From bcf2283bd62ba5d630c2d1ce73a2fafef4d14871 Mon Sep 17 00:00:00 2001 From: GerZhang Date: Thu, 15 Oct 2026 19:04:11 +0800 Subject: [PATCH 68/71] =?UTF-8?q?feat(offline-build):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=BC=80=E5=85=B3=E7=B1=BB=E5=9E=8B=E8=A1=A8=E5=8D=95=E9=A1=B9?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- OfflinePlusBuildPattern.cs | 23 +++++++++++++++++------ Resources/AndroidPDACommand.js | 9 ++++++++- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/OfflinePlusBuildPattern.cs b/OfflinePlusBuildPattern.cs index fe5773e..bc9f1ff 100644 --- a/OfflinePlusBuildPattern.cs +++ b/OfflinePlusBuildPattern.cs @@ -139,8 +139,8 @@ namespace AndroidPDACommand public class OfflineFormNode : ObjectPropertyBase, ITreeNode { - public const string BaseItemTypeValueList = "textItem|passwordItem|selectItem|radioItem|datePicker|timePicker|imageItem|fileItem|signatureItem"; - public const string BaseItemTypeDisplayList = "文本框|密码框|选择框|单选框|日期选择|时间选择|图片列表|文件上传|签名"; + public const string BaseItemTypeValueList = "textItem|passwordItem|selectItem|radioItem|datePicker|timePicker|imageItem|fileItem|signatureItem|switchItem"; + public const string BaseItemTypeDisplayList = "文本框|密码框|选择框|单选框|日期选择|时间选择|图片列表|文件上传|签名|开关"; public const string ItemTypeValueList = BaseItemTypeValueList + "|listItem"; public const string ItemTypeDisplayList = BaseItemTypeDisplayList + "|列表"; @@ -169,7 +169,8 @@ namespace AndroidPDACommand nameof(FileItemConfig), nameof(SignatureOptions), nameof(ListItemOptions), - nameof(ConfirmOptions) + nameof(ConfirmOptions), + nameof(SwitchStyle) }; private static readonly Dictionary> FieldVisiblePropertiesByType = new Dictionary> @@ -183,6 +184,7 @@ namespace AndroidPDACommand { "imageItem", CreateFieldVisibleProperties(nameof(MaxCount), nameof(AllowImageUpload), nameof(CompressionOptions), nameof(WatermarkOptions)) }, { "fileItem", CreateFieldVisibleProperties(nameof(FileItemConfig)) }, { "signatureItem", CreateFieldVisibleProperties(nameof(Value), nameof(SignatureOptions)) }, + { "switchItem", CreateFieldVisibleProperties(nameof(Value), nameof(SwitchStyle), nameof(ConfirmOptions)) }, { "listItem", CreateFieldVisibleProperties(nameof(ListItemOptions)) } }; @@ -248,6 +250,7 @@ namespace AndroidPDACommand public object Hint { get; set; } [DisplayName("必填")] + [Description("是否必填。普通类型:必填 = 值不能为空;开关类型:必填 = 必须打开(值由 false 变为 true)。")] public bool Required { get; set; } [DisplayName("显示更新时间")] @@ -256,11 +259,17 @@ namespace AndroidPDACommand [ObjectProperty(ObjType = typeof(ConfirmOptions))] [DisplayName("修改前确认")] - [Description("仅下拉选择和单选框生效。启用后,用户修改该组件时先弹出二次确认;确认后才会写入新值并更新更新时间。")] + [Description("启用后,用户修改该组件时先弹出二次确认;确认后才写入新值并更新更新时间,取消则不改动。")] public ConfirmOptions ConfirmOptions { get; set; } + [DisplayName("呈现样式")] + [Description("选择该开关的呈现方式,两者的取值与“空值”语义不同:\n“开关”:始终有值(开=true、关=false),未选中也算已填;\n“标准复选框”:未选中表示“未填(空)”,不计入已填。")] + [ComboProperty(ValueList = "switch|checkbox", DisplayList = "开关|标准复选框")] + public string SwitchStyle { get; set; } = "switch"; + [FormulaProperty] [DisplayName("默认值")] + [Description("新建填报时的初始值。开关可填 1(开)或 0(关),也支持 true/false、是/否;留空按“未选中”处理。其它类型无默认值。")] public object Value { get; set; } [DisplayName("包含时间")] @@ -380,7 +389,8 @@ namespace AndroidPDACommand FileItemConfig = FileItemConfig, SignatureOptions = SignatureOptions, ListItemOptions = ListItemOptions, - ConfirmOptions = ConfirmOptions + ConfirmOptions = ConfirmOptions, + SwitchStyle = SwitchStyle }; } @@ -455,7 +465,8 @@ namespace AndroidPDACommand FileItemConfig = FileItemConfig, SignatureOptions = SignatureOptions, ListItemOptions = ListItemOptions, - ConfirmOptions = ConfirmOptions + ConfirmOptions = ConfirmOptions, + SwitchStyle = SwitchStyle }; } } diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index e8175a4..3296237 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -3557,6 +3557,13 @@ function HAC_OfflinePlusCreateFormNodeBuilder(context) { field.options = options; } } + }, + switchItem: { + apply: function (field, node) { + field.options = { + style: node.SwitchStyle || "switch" + }; + } } }; @@ -3914,7 +3921,7 @@ function HAC_OfflinePlusValidatePatternJson(patternJson) { } itemIds[itemIdKey] = path + ".field.itemId"; - var itemTypes = ["textItem", "passwordItem", "selectItem", "radioItem", "datePicker", "timePicker", "imageItem", "fileItem", "signatureItem"]; + var itemTypes = ["textItem", "passwordItem", "selectItem", "radioItem", "datePicker", "timePicker", "imageItem", "fileItem", "signatureItem", "switchItem"]; if (allowListItem) { itemTypes.push("listItem"); } -- Gitee From f4ef4857173b1d107dba8561434eb1e69ee95c09 Mon Sep 17 00:00:00 2001 From: GerZhang Date: Thu, 15 Oct 2026 19:42:21 +0800 Subject: [PATCH 69/71] =?UTF-8?q?docs(offline-build):=20=E5=BC=80=E5=85=B3?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E6=B3=A8=E9=87=8A=E7=A7=BB=E9=99=A4=E5=8E=9F?= =?UTF-8?q?=E5=85=88=E9=80=BB=E8=BE=91=E4=B8=8D=E4=B8=80=E8=87=B4=E7=9A=84?= =?UTF-8?q?=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- OfflinePlusBuildPattern.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OfflinePlusBuildPattern.cs b/OfflinePlusBuildPattern.cs index bc9f1ff..a5b1d0e 100644 --- a/OfflinePlusBuildPattern.cs +++ b/OfflinePlusBuildPattern.cs @@ -250,7 +250,7 @@ namespace AndroidPDACommand public object Hint { get; set; } [DisplayName("必填")] - [Description("是否必填。普通类型:必填 = 值不能为空;开关类型:必填 = 必须打开(值由 false 变为 true)。")] + [Description("是否必填。普通类型:必填 = 值不能为空;开关类型:必填 = 必须选中/打开。")] public bool Required { get; set; } [DisplayName("显示更新时间")] @@ -263,7 +263,7 @@ namespace AndroidPDACommand public ConfirmOptions ConfirmOptions { get; set; } [DisplayName("呈现样式")] - [Description("选择该开关的呈现方式,两者的取值与“空值”语义不同:\n“开关”:始终有值(开=true、关=false),未选中也算已填;\n“标准复选框”:未选中表示“未填(空)”,不计入已填。")] + [Description("选择该开关的呈现方式(仅外观不同,取值/校验/进度口径一致):\n“开关”:右侧可左右拨动的滑动开关;\n“标准复选框”:左侧可打勾的方形选择框。\n未选中(false)一律视为“未填”。")] [ComboProperty(ValueList = "switch|checkbox", DisplayList = "开关|标准复选框")] public string SwitchStyle { get; set; } = "switch"; -- Gitee From b9d1e7f83a8fd00bc95ab890bb541e24632063bf Mon Sep 17 00:00:00 2001 From: GerZhang Date: Fri, 16 Oct 2026 10:04:19 +0800 Subject: [PATCH 70/71] =?UTF-8?q?chore:=20=E7=89=88=E6=9C=AC=E5=8F=B7?= =?UTF-8?q?=E5=8D=87=E8=87=B3=201.23.5.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PluginConfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PluginConfig.json b/PluginConfig.json index bedf068..ca0dd69 100644 --- a/PluginConfig.json +++ b/PluginConfig.json @@ -13,7 +13,7 @@ "name": "PDA(Android)交互命令", "pluginType": "command", "guid": "{16B8DF69-1379-41C1-9194-BE89BAF8BB32}", - "version": "1.23.4.0", + "version": "1.23.5.0", "dependenceVersion": "8.0.0.0", "bundleJavaScript": true, "bundleCSS": true -- Gitee From 8a4cb0f7b77dd2bef09a071839d081be1067d8b0 Mon Sep 17 00:00:00 2001 From: GerZhang Date: Fri, 16 Oct 2026 19:13:06 +0800 Subject: [PATCH 71/71] =?UTF-8?q?fix(offline-export):=20=E7=A6=BB=E7=BA=BF?= =?UTF-8?q?=E9=99=84=E4=BB=B6=E5=9B=9E=E5=86=99=E6=8C=89=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=20path=20=E5=AE=9A=E4=BD=8D=EF=BC=8C=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E5=86=85=E7=AD=BE=E5=90=8D=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E6=AE=8B=E7=95=99=E6=9C=AC=E5=9C=B0=E6=97=B6=E9=97=B4=E6=88=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Resources/AndroidPDACommand.js | 145 +++++++++++++++++++++++---------- 1 file changed, 100 insertions(+), 45 deletions(-) diff --git a/Resources/AndroidPDACommand.js b/Resources/AndroidPDACommand.js index 3296237..0c67a3c 100644 --- a/Resources/AndroidPDACommand.js +++ b/Resources/AndroidPDACommand.js @@ -283,28 +283,101 @@ async function HAC_EnsureNetworkReadyForUpload(attachmentCount) { } } -function HAC_GetOfflineRecordFieldValue(record, fieldId) { - var fieldValue = record && record.values && record.values[fieldId]; - if (fieldValue && typeof fieldValue === "object" && !Array.isArray(fieldValue) && - Object.prototype.hasOwnProperty.call(fieldValue, "value")) { - return fieldValue.value; +function HAC_IsOfflineFieldEntry(value) { + return value && typeof value === "object" && !Array.isArray(value) && + Object.prototype.hasOwnProperty.call(value, "value"); +} + +function HAC_UnwrapOfflineFieldValue(value) { + return HAC_IsOfflineFieldEntry(value) ? value.value : value; +} + +/** 判断 path 段是否为列表行下标 / 签名下标(App 导出时以 JSON 数字写入)。 */ +function HAC_IsOfflinePathIndex(value) { + return typeof value === "number" && isFinite(value) && value >= 0 && Math.floor(value) === value; +} + +/** + * 解析附件的 path,定位它在记录中的嵌套位置(支持列表内、嵌套列表内的附件与签名)。 + * path 由 App 导出生成,形如: + * [recordId, fieldId] 顶层图片/附件 + * [recordId, fieldId, sigIndex] 顶层签名 + * [recordId, listFieldId, rowIndex, fieldId] 列表行内图片/附件 + * [recordId, listFieldId, rowIndex, fieldId, sigIndex] 列表行内签名 + * 规则:紧跟字段后的数字段,非末段为列表行下标(进入该行继续解析),末段为签名下标。 + * 返回 { container, fieldId, signatureIndex, key }: + * container 为字段所在的键值容器(顶层为 record.values,列表行为该行对象); + * key 为该位置的身份串(不含签名下标),用于把同一字段/同一行的附件归为一组。 + */ +function HAC_ResolveOfflineAttachmentLocation(record, attachment) { + if (!record || !record.values || !attachment) { + return null; + } + var path = attachment.path; + if (Array.isArray(path) && path.length >= 2) { + var container = record.values; + var consumed = [path[0]]; + var i = 1; + while (i < path.length) { + var key = path[i]; + consumed.push(key); + i++; + var next = i < path.length ? path[i] : null; + if (HAC_IsOfflinePathIndex(next)) { + if (i < path.length - 1) { + // 非末段数字 = 列表行下标:进入该行继续解析。 + var rows = HAC_UnwrapOfflineFieldValue(container ? container[key] : undefined); + if (!Array.isArray(rows)) { + return null; + } + consumed.push(next); + container = rows[next]; + i++; + continue; + } + // 末段数字 = 签名下标。 + return { + container: container, + fieldId: String(key), + signatureIndex: next, + key: consumed.join("/") + }; + } + // 末段为字段 id:普通附件字段。 + return { + container: container, + fieldId: String(key), + signatureIndex: -1, + key: consumed.join("/") + }; + } + return null; + } + + // 兜底:旧版导出可能没有 path,退化为顶层字段。 + var fieldId = attachment.fieldId; + if (!fieldId) { + return null; } - return fieldValue; + return { container: record.values, fieldId: fieldId, signatureIndex: -1, key: String(fieldId) }; } -function HAC_SetOfflineRecordFieldValue(record, fieldId, value) { - var fieldValue = record && record.values && record.values[fieldId]; - if (fieldValue && typeof fieldValue === "object" && !Array.isArray(fieldValue) && - Object.prototype.hasOwnProperty.call(fieldValue, "value")) { +function HAC_SetOfflineLocationValue(location, value) { + if (!location || !location.container) { + return; + } + var entry = location.container[location.fieldId]; + if (HAC_IsOfflineFieldEntry(entry)) { // 只替换实际值,保留图片等字段的整体更新时间和其它元数据。 - fieldValue.value = value; + entry.value = value; } else { - record.values[fieldId] = value; + location.container[location.fieldId] = value; } } -function HAC_ParseOfflineSignatureValues(record, fieldId) { - var fieldValue = HAC_GetOfflineRecordFieldValue(record, fieldId); +function HAC_ParseOfflineSignatureValues(location) { + var entry = location && location.container ? location.container[location.fieldId] : undefined; + var fieldValue = HAC_UnwrapOfflineFieldValue(entry); if (Array.isArray(fieldValue)) { return fieldValue.slice(); } @@ -320,26 +393,6 @@ function HAC_ParseOfflineSignatureValues(record, fieldId) { } } -function HAC_GetOfflineSignatureAttachmentIndex(record, attachment, fieldId) { - var path = attachment && attachment.path; - if (!Array.isArray(path) || path.length < 3) { - return -1; - } - - var signatureIndex = Number(path[2]); - if (!isFinite(signatureIndex) || signatureIndex < 0 || Math.floor(signatureIndex) !== signatureIndex) { - return -1; - } - - var signatureValues = HAC_ParseOfflineSignatureValues(record, fieldId); - var signatureValue = signatureValues[signatureIndex]; - var hasSignatureValue = signatureValue && typeof signatureValue === "object" && !Array.isArray(signatureValue) && - (Object.prototype.hasOwnProperty.call(signatureValue, "userName") || - Object.prototype.hasOwnProperty.call(signatureValue, "updateTime")); - var hasSignatureMetadata = attachment && attachment.updateTime !== undefined && attachment.updateTime !== null; - return hasSignatureValue || hasSignatureMetadata ? signatureIndex : -1; -} - /** * 构建上传会话:把导出数据中的附件摊平成文件条目,保持原始顺序并关联记录。 * 状态仅存在于本次导出(含窗口内重试)期间:PENDING / UPLOADING / SUCCESS / FAILED。 @@ -360,16 +413,17 @@ function HAC_CreateUploadSession(exportDataArray) { }; var groupOrders = {}; (exportItem.attachments || []).forEach(function (attachment) { - if (!attachment || !attachment.localName - || !HAC_GetOfflineAttachmentRecordId(attachment) - || !HAC_GetOfflineAttachmentFieldId(attachment)) { + if (!attachment || !attachment.localName) { return; } var recordId = HAC_GetOfflineAttachmentRecordId(attachment); - var fieldId = HAC_GetOfflineAttachmentFieldId(attachment); var record = HAC_FindOfflineRecord(item.records, recordId); - var signatureIndex = record ? HAC_GetOfflineSignatureAttachmentIndex(record, attachment, fieldId) : -1; - var groupKey = itemIndex + "|" + recordId + "|" + fieldId; + var location = HAC_ResolveOfflineAttachmentLocation(record, attachment); + if (!record || !location) { + return; + } + var signatureIndex = location.signatureIndex; + var groupKey = itemIndex + "|" + location.key; var order = groupOrders[groupKey] || 0; groupOrders[groupKey] = order + 1; @@ -379,7 +433,8 @@ function HAC_CreateUploadSession(exportDataArray) { attachment: attachment, record: record, recordId: recordId, - fieldId: fieldId, + fieldId: location.fieldId, + location: location, kind: signatureIndex >= 0 ? "signature" : "normal", signatureIndex: signatureIndex, groupKey: groupKey, @@ -490,7 +545,7 @@ function HAC_ApplyUploadSession(session) { item.entries.forEach(function (entry) { var group = groups[entry.groupKey]; if (!group) { - group = groups[entry.groupKey] = { kind: entry.kind, fieldId: entry.fieldId, record: entry.record, entries: [] }; + group = groups[entry.groupKey] = { kind: entry.kind, location: entry.location, record: entry.record, entries: [] }; } group.entries.push(entry); }); @@ -517,11 +572,11 @@ function HAC_ApplyUploadedNormalGroup(group) { values.push(entry.serverId); } }); - HAC_SetOfflineRecordFieldValue(group.record, group.fieldId, values.join("|")); + HAC_SetOfflineLocationValue(group.location, values.join("|")); } function HAC_ApplyUploadedSignatureGroup(group) { - var signatureValues = HAC_ParseOfflineSignatureValues(group.record, group.fieldId); + var signatureValues = HAC_ParseOfflineSignatureValues(group.location); var successEntries = {}; group.entries.forEach(function (entry) { if (entry.state === "SUCCESS" && entry.serverId && entry.signatureIndex >= 0) { @@ -548,7 +603,7 @@ function HAC_ApplyUploadedSignatureGroup(group) { value.fileName = entry.serverId; result.push(value); } - HAC_SetOfflineRecordFieldValue(group.record, group.fieldId, JSON.stringify(result)); + HAC_SetOfflineLocationValue(group.location, JSON.stringify(result)); } function HAC_GetOfflineAttachmentRecordId(attachment) { -- Gitee