using System.Collections.Generic; using System.IO; using MotionFramework; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using UnityEngine; namespace DefaultNamespace { /// /// 任务书信息类,用于存储解析后的任务书字段数据 /// 完全动态,不预定义任何固定字段 /// [System.Serializable] public class TaskBookInfo { /// /// 字段映射字典,存储所有解析出的字段名和对应值 /// public Dictionary FieldMap { get; set; } = new Dictionary(); /// /// 原始任务书字符串 /// public string OriginalText { get; set; } = string.Empty; /// /// 根据字段名获取对应的值 /// /// 字段名称 /// 对应的值,如果不存在则返回空字符串 public string GetValue(string fieldName) { return FieldMap.TryGetValue(fieldName, out string value) ? value : string.Empty; } /// /// 检查是否包含指定字段 /// /// 字段名称 /// 是否包含该字段 public bool HasField(string fieldName) { return FieldMap.ContainsKey(fieldName); } /// /// 获取所有字段名 /// /// 字段名集合 public IEnumerable GetAllFieldNames() { return FieldMap.Keys; } /// /// 获取所有字段和值的键值对 /// /// 所有字段的键值对 public IEnumerable> GetAllFields() { return FieldMap; } /// /// 清空所有字段数据 /// public void Clear() { FieldMap.Clear(); OriginalText = string.Empty; } } /// /// 用于存储全局的考试相关信息以及其他可能的全局数据。 /// public class GlobalDataStorage : ModuleSingleton, IModule { /// /// Info文件,前端传过来的 /// public ExamInfo ExamInfo = new ExamInfo(); /// /// Info文件,前端传过来的 /// public string ExamName { get; set; } public ApiResponse ExamData; /// /// 任务书信息,存储解析后的任务书字段数据 /// public TaskBookInfo TaskBook { get; set; } = new TaskBookInfo(); /// /// 任务书信息,存储解析后的任务书字段数据 /// public object materialTaskObj = null; /// /// 大类题目 /// public string bigName; public List materialCheckInfoList = new List(); /// /// 获取任务书 /// /// public string GetTaskBook() { return TaskBook.OriginalText; } /// /// 根据字段名获取任务书中的值 /// /// 字段名称 /// 对应的值,如果不存在则返回空字符串 public string GetTaskBookValue(string fieldName) { return TaskBook.GetValue(fieldName); } /// /// 检查任务书是否包含指定字段 /// /// 字段名称 /// 是否包含该字段 public bool HasTaskBookField(string fieldName) { return TaskBook.HasField(fieldName); } /// /// 获取物料编码 /// /// 物料编码 public string GetMaterialCode() { return GetTaskBookValue("物料编码"); } /// /// 获取物料描述 /// /// 物料描述 public string GetMaterialDescription() { return GetTaskBookValue("物料描述"); } /// /// 获取工厂代码 /// /// 工厂代码 public string GetFactoryCode() { return GetTaskBookValue("工厂代码"); } /// /// 获取批次号 /// /// 批次号 public string GetBatchNumber() { return GetTaskBookValue("批次"); } /// /// 获取收入数量 /// /// 收入数量 public string GetIncomeQuantity() { return GetTaskBookValue("收入数量"); } /// /// 获取台数(从"已将X台"中提取的数字) /// /// 台数 public string GetQuantity() { return GetTaskBookValue("台"); } /// /// 获取日期 /// /// 日期 public string GetDate() { return GetTaskBookValue("日期"); } /// /// 获取货物交接单号 /// /// 货物交接单号 public string GetHandoverDocument() { return GetTaskBookValue("货物交接单"); } /// /// 获取过账日期前 /// /// 过账日期前 public string GetPostingDateBefore() { return GetTaskBookValue("过账日期前"); } /// /// 获取过账日期后 /// /// 过账日期后 public string GetPostingDateAfter() { return GetTaskBookValue("过账日期后"); } /// /// 获取仓库号 /// /// 过账日期后 public string GetCangKuHao() { return GetTaskBookValue("仓库号"); } /// /// 获取仓位信息 /// /// 仓位信息,如F01-010101 public string GetShelfPosition() { // 优先获取货架区信息 string shelfArea = GetTaskBookValue("货架区"); if (!string.IsNullOrEmpty(shelfArea)) { return shelfArea; } // 其次获取仓位信息 string position = GetTaskBookValue("仓位"); if (!string.IsNullOrEmpty(position)) { return position; } // 最后获取仓位号信息 string positionNumber = GetTaskBookValue("仓位号"); if (!string.IsNullOrEmpty(positionNumber)) { return positionNumber; } return string.Empty; } /// /// 智能字段映射字典,处理字段名的模糊匹配 /// private readonly Dictionary _fieldMapping = new Dictionary { // 完全匹配 {"物料编码", "物料编码"}, {"物料描述", "物料描述"}, {"工厂代码", "工厂代码"}, {"批次", "批次"}, {"库存地点", "库存地点"}, {"库管员", "库管员"}, {"仓库主管", "仓库主管"}, {"物资公司签字", "物资公司签字"}, {"单位签收人", "单位签收人"}, {"供应商交付人", "供应商交付人"}, {"发货方", "发货方"}, {"收货方", "收货方"}, {"收入数量", "收入数量"}, {"结存数量", "结存数量"}, {"发出数量", "发出数量"}, {"期初库存数量", "期初库存数量"}, {"台", "台"}, {"套", "套"}, {"组", "组"}, {"米", "米"}, {"千米", "千米"}, {"只", "只"}, {"片", "片"}, {"付", "付"}, {"日期", "日期"}, {"货物交接单", "货物交接单"}, {"过账起始时间", "过账起始时间"}, {"过账结束时间", "过账结束时间"}, // {"货架区", "货架区"}, // {"仓位", "仓位"}, // {"仓位号", "仓位号"}, // 模糊匹配 {"批次号", "批次"}, {"物料编号", "物料编码"}, {"物资编码", "物料编码"}, {"物资描述", "物料描述"}, {"工厂编号", "工厂代码"}, {"库存位置", "库存地点"}, {"仓库管理员", "库管员"}, {"仓库负责人", "仓库主管"}, {"物资公司负责人", "物资公司签字"}, {"签收人", "单位签收人"}, {"交付人", "供应商交付人"}, {"发货人", "发货方"}, {"收货人", "收货方"}, {"入库数量", "收入数量"}, {"库存数量", "结存数量"}, {"出库数量", "发出数量"}, {"初始库存", "期初库存数量"}, {"已交付数量", "台"}, {"交付台数", "台"}, {"交接单号", "货物交接单"}, {"过账开始日期", "过账日期前"}, {"过账结束日期", "过账日期后"}, {"过账日期开始", "过账日期前"}, {"过账日期结束", "过账日期后"}, {"货架位置", "货架区"}, {"存储位置", "仓位"}, {"位置编号", "仓位号"}, {"上架仓位", "上架仓位"}, {"仓库号", "仓库号"}, }; /// /// 根据字段名获取对应的任务书值,支持模糊匹配 /// /// 字段名称 /// 对应的值,如果不存在则返回空字符串 public string GetTaskBookValueByMapping(string fieldName) { // Debug.Log($"尝试获取字段值: {fieldName}"); // 首先尝试直接匹配 if (_fieldMapping.ContainsKey(fieldName)) { string mappedField = _fieldMapping[fieldName]; string value = GetTaskBookValue(mappedField); Debug.Log($"字段映射成功: {fieldName} -> {mappedField} = {value}"); return value; } // 如果没有找到映射,尝试直接获取 string directValue = GetTaskBookValue(fieldName); Debug.Log($"直接获取字段值: {fieldName} = {directValue}"); return directValue; } /// /// 更新JSON字符串中的JudgmentQuestions字段值 /// /// 原始JSON字符串 /// 更新后的JSON字符串 public string UpdateJsonWithTaskBookValues(string jsonString) { // 输入参数验证 if (string.IsNullOrEmpty(jsonString)) { Debug.LogWarning("JSON字符串为空,无法更新"); return jsonString; } try { Debug.Log("开始更新JSON中的JudgmentQuestions字段值..."); // 解析JSON JArray jsonArray = JArray.Parse(jsonString); // 验证JSON数组是否为空 if (jsonArray == null || jsonArray.Count == 0) { Debug.LogWarning("JSON数组为空或无效,无法更新"); return jsonString; } int updatedCount = 0; // 遍历所有步骤 foreach (JObject step in jsonArray) { // 验证步骤对象是否有效 if (step == null) continue; // 检查步骤是否包含Actions数组 if (step["Actions"] != null && step["Actions"] is JArray actions) { // 验证Actions数组是否为空 if (actions.Count == 0) continue; // 遍历所有动作 foreach (JObject action in actions) { // 验证动作对象是否有效 if (action == null) continue; // 检查动作是否包含JudgmentQuestions且不为null if (action["JudgmentQuestions"] != null && action["JudgmentQuestions"] is JArray judgmentQuestions) { // 验证判断题数组是否为空 if (judgmentQuestions.Count == 0) continue; // 遍历所有判断题 foreach (JObject question in judgmentQuestions) { // 验证问题对象是否有效 if (question == null) continue; // 安全地获取问题文本和正确答案 if (question["Question"] != null && question["CorrectAnswer"] != null) { string questionText = question["Question"].ToString(); string currentAnswer = question["CorrectAnswer"].ToString(); // 验证问题文本和答案是否为空 if (string.IsNullOrEmpty(questionText) || string.IsNullOrEmpty(currentAnswer)) { Debug.LogWarning($"跳过无效的问题或答案: Question='{questionText}', Answer='{currentAnswer}'"); continue; } // 获取对应的任务书值 string taskBookValue = GetTaskBookValueByMapping(questionText); if (!string.IsNullOrEmpty(taskBookValue)) { // 更新CorrectAnswer question["CorrectAnswer"] = taskBookValue; updatedCount++; Debug.Log($"更新字段: {questionText} = {taskBookValue} (原值: {currentAnswer})"); } else { // Debug.Log($"未找到字段对应的任务书值: {questionText}"); } } } } } } } string updatedJson = jsonArray.ToString(Formatting.None); Debug.Log($"JSON更新完成,共更新了 {updatedCount} 个字段"); return updatedJson; } catch (System.Exception ex) { Debug.LogError($"更新JSON时发生错误: {ex.Message}"); Debug.LogError($"错误堆栈: {ex.StackTrace}"); return jsonString; // 返回原始字符串 } } /// /// 设置任务书信息 /// /// 任务书原始文本 public void SetTaskBook(string taskBookText) { TaskBook.Clear(); TaskBook.OriginalText = taskBookText; ParseTaskBook(taskBookText); } /// /// 解析任务书文本,智能提取各种字段信息 /// /// 任务书文本 private void ParseTaskBook(string taskBookText) { if (string.IsNullOrEmpty(taskBookText)) { Debug.LogWarning("任务书文本为空,无法解析"); return; } Debug.Log("开始智能解析任务书文本..."); // 定义字段匹配模式 var fieldPatterns = new Dictionary { // 物料相关信息 {"物料编码", @"物料编码[::]\s*([A-Za-z0-9]+)"}, {"物料描述", @"(([^)]+))|物料描述[::]\s*([^,。;:,.;:\n\r)]+?))"}, // 工厂和批次信息 {"工厂代码", @"工厂代码[::]?\s*([A-Za-z0-9*]+)"}, {"批次", @"批次[::]?\s*([A-Za-z0-9]+)"}, // 库存地点 {"库存地点", @"库存地点[::]\s*[^(]*(([A-Za-z0-9]+))"}, // 人员信息 {"库管员", @"库管员[::]\s*([^,。;:,.;:]+)"}, {"仓库主管", @"仓库主管[::]\s*([^,。;:,.;:]+)"}, {"物资公司签字", @"物资公司签字[::]\s*([^,。;:,.;:]+)"}, {"单位签收人", @"单位签收人[::]\s*([^,。;:,.;:]+)"}, {"供应商交付人", @"供应商交付人[::]\s*([^,。;:,.;:]+)"}, {"发货方", @"发货方[::]\s*([^,。;:,.;:]+)"}, {"收货方", @"收货方[::]\s*([^,。;:,.;:]+)"}, // 数量信息 {"收入数量", @"收入数量[::]\s*(\d+)"}, {"结存数量", @"结存数量[::]\s*(\d+)"}, {"发出数量", @"发出数量[::]\s*(\d+)"}, {"期初库存数量", @"期初库存数量[::]\s*(\d+)"}, {"台", @"已将(\d+)台"}, {"套", @"已将(\d+)套"}, {"组", @"已将(\d+)组"}, {"米", @"已将(\d+)米"}, {"千米", @"已将(\d+)千米"}, {"只", @"已将(\d+)只"}, {"片", @"已将(\d+)片"}, {"付", @"已将(\d+)付"}, // 日期信息 {"日期", @"日期[为]?\s*(\d{4}\.\d{2}\.\d{2})"}, {"过账起始时间", @"过账日期前[::]\s*(\d{4}\.\d{2}月\.\d{2})"}, {"过账结束时间", @"过账日期后[::]\s*(\d{4}\.\d{2}月\.\d{2})"}, // 单据信息 {"货物交接单", @"货物交接单[::]\s*([A-Za-z0-9]+)"}, {"仓库号", @"仓库号[::]?\s*([A-Za-z0-9]+)"}, // //仓位号 // {"货架区", @"货架区[::]\s*([A-Za-z0-9\-]+)"}, // {"仓位", @"仓位[::]\s*([A-Za-z0-9\-]+)"}, // {"仓位号", @"仓位号[::]\s*([A-Za-z0-9\-]+)"}, // 复合格式解析 - 支持"货架区F01-010101仓位"等格式 // {"上架仓位", @"货架区([A-Za-z0-9\-]+)仓位"}, // 直接匹配仓位编号格式 F01-010101 {"上架仓位", @"([A-Z][0-9]{2}-[0-9]{6})"}, }; int parsedFieldsCount = 0; // 遍历所有字段模式进行匹配 foreach (var pattern in fieldPatterns) { string fieldName = pattern.Key; string regexPattern = pattern.Value; try { System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex(regexPattern); System.Text.RegularExpressions.Match match = regex.Match(taskBookText); if (match.Success && match.Groups.Count >= 2) { string value = string.Empty; // 特殊处理物料描述字段,支持两种格式的合并正则 if (fieldName == "物料描述") { // 检查第一个捕获组(括号格式) if (match.Groups[1].Success && !string.IsNullOrEmpty(match.Groups[1].Value.Trim())) { value = match.Groups[1].Value.Trim(); Debug.Log($"成功解析字段: [物料描述] = {value} (括号格式)"); // 如果括号格式解析成功,再次解析物料描述 int materialDescIndex = value.IndexOf("物料描述:"); if (materialDescIndex >= 0) { string materialDescValue = value.Substring(materialDescIndex + 4); // 跳过"物料描述:" materialDescValue = CleanValue(materialDescValue); if (!string.IsNullOrEmpty(materialDescValue)) { value = materialDescValue; Debug.Log($"成功解析字段: [物料描述] = {value} (从括号格式中再次解析)"); } } } // 检查第二个捕获组(冒号格式) else if (match.Groups[2].Success && !string.IsNullOrEmpty(match.Groups[2].Value.Trim())) { value = match.Groups[2].Value.Trim(); Debug.Log($"成功解析字段: [物料描述] = {value} (冒号格式)"); } } else { value = match.Groups[1].Value.Trim(); } // 清理值中的多余字符 value = CleanValue(value); if (!string.IsNullOrEmpty(value)) { TaskBook.FieldMap[fieldName] = value; if (fieldName != "物料描述") // 物料描述已经在上面打印过日志了 { Debug.Log($"成功解析字段: [{fieldName}] = {value}"); } parsedFieldsCount++; } } else { Debug.Log($"未找到字段: {fieldName}"); } } catch (System.Exception ex) { Debug.LogError($"解析字段 {fieldName} 时发生错误: {ex.Message}"); } } Debug.Log($"任务书解析完成,共成功解析出 {parsedFieldsCount} 个字段"); Debug.Log($"解析出的字段列表: {string.Join(", ", TaskBook.FieldMap.Keys)}"); } /// /// 清理值中的多余字符 /// /// 原始值 /// 清理后的值 private string CleanValue(string value) { if (string.IsNullOrEmpty(value)) return value; // 移除开头和结尾的标点符号和空格 value = value.Trim(',', '。', ';', ':', ',', '.', ';', ':', ' ', '\t', '\n', '\r'); // 处理日期格式中的"月"字符,将其替换为"." // 例如:2024.12月.01 -> 2024.12.01 value = value.Replace("月", "."); // 清理重复的点号 while (value.Contains("..")) { value = value.Replace("..", "."); } return value; } // public void OnCreate(object createParam) { } public void OnUpdate() { } public void OnDestroy() { } public void OnGUI() { } } }