920 lines
34 KiB
C#
920 lines
34 KiB
C#
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
using SK.Framework;
|
||
using UnityEngine.UI;
|
||
using UnityEngine.EventSystems;
|
||
using System.Linq;
|
||
using System;
|
||
using TMPro;
|
||
using System.Data;
|
||
using System.IO;
|
||
using OfficeOpenXml;
|
||
using System.Text;
|
||
using UnityEditor;
|
||
|
||
/// <summary>
|
||
/// 执行流程仿真
|
||
/// </summary>
|
||
public class ExecuteSimulationView : UIView
|
||
{
|
||
|
||
public Variables variables;
|
||
|
||
public List<Button> leftBtns = new List<Button>();
|
||
[System.Serializable]
|
||
public class ButtonData
|
||
{
|
||
public Sprite normalSprite;
|
||
public Sprite selectedSprite;
|
||
}
|
||
[SerializeField] private List<ButtonData> buttonData = new List<ButtonData>();
|
||
private Dictionary<Button, ButtonData> buttonDictionary = new Dictionary<Button, ButtonData>();
|
||
private Button _currentSelectedButton;
|
||
public List<GameObject> panels = new List<GameObject>();
|
||
// 存储所有Item的RectTransform,便于索引查找
|
||
private List<RectTransform> itemTransforms = new List<RectTransform>();
|
||
// 运行时状态
|
||
private RectTransform draggedItem; // 当前被拖拽的Item
|
||
private GameObject placeholder; // 占位符对象
|
||
private int startDragIndex; // 开始拖拽时Item的索引
|
||
[Header("数据与测试")]
|
||
[Tooltip("示例数据列表,实际项目中应替换为您的数据模型List")]
|
||
[SerializeField] private List<GameObject> dataList = new List<GameObject>();
|
||
|
||
//打字动画协程句柄,防止重复打字导致打字动画卡顿问题
|
||
private Coroutine typingCoroutine;
|
||
//打字动画速度,单位:秒/字符
|
||
private float typingSpeed = 0.05f;
|
||
//延时隐藏时间
|
||
private float hideAlarm = 3f;
|
||
|
||
private DataRecordSheet dataRecordSheet;
|
||
|
||
public List<BreakdownTaskItem> breakdownTaskItems = new List<BreakdownTaskItem>();
|
||
|
||
protected override void OnInit(IViewData data)
|
||
{
|
||
base.OnInit(data);
|
||
variables.Set<ExecuteSimulationView>("my_executeSimulation", this);
|
||
|
||
breakdownTaskItems.Clear();
|
||
breakdownTaskItems.Add(variables.Get<RectTransform>("子任务").GetComponent<BreakdownTaskItem>());
|
||
|
||
PanelInit();
|
||
PanelBtnsInit();
|
||
itemTransforms.Clear();
|
||
}
|
||
|
||
#region Tab页面切换
|
||
|
||
/// <summary>
|
||
/// Tab页初始化
|
||
/// </summary>
|
||
private void PanelInit()
|
||
{
|
||
if (!leftBtns.Count.Equals(panels.Count))
|
||
{
|
||
ShowWarming($"按钮和面板数量{leftBtns.Count}_{panels.Count}不匹配!");
|
||
return;
|
||
}
|
||
|
||
HideAllPanels();
|
||
|
||
InitLeftBtns();
|
||
|
||
SetSelectedButton(leftBtns[0]);
|
||
|
||
if (panels.Count > 0)
|
||
panels[0].Activate();
|
||
|
||
GetTaskList();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 隐藏所有面板信息
|
||
/// </summary>
|
||
private void HideAllPanels()
|
||
{
|
||
foreach (var panel in panels)
|
||
{
|
||
if (panel != null)
|
||
panel.Deactivate();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Tab页点击初始化
|
||
/// </summary>
|
||
/// <param name="index"></param>
|
||
private void OnPanelBtnClick(int index)
|
||
{
|
||
if (index < 0 || index >= panels.Count)
|
||
return;
|
||
|
||
HideAllPanels();
|
||
|
||
panels[index].Activate();
|
||
}
|
||
void InitLeftBtns()
|
||
{
|
||
|
||
// 初始化字典
|
||
for (int i = 0; i < leftBtns.Count; i++)
|
||
{
|
||
buttonDictionary[leftBtns[i]] = buttonData[i];
|
||
|
||
// 设置初始状态
|
||
Image img = leftBtns[i].GetComponent<Image>();
|
||
if (img != null)
|
||
{
|
||
img.sprite = buttonData[i].normalSprite;
|
||
}
|
||
|
||
// 添加点击事件
|
||
int index = i; // 闭包需要
|
||
leftBtns[i].onClick.AddListener(() => OnButtonSelected(leftBtns[index], index));
|
||
}
|
||
|
||
// 设置默认选中
|
||
if (leftBtns.Count > 0)
|
||
{
|
||
SetSelectedButton(leftBtns[0]);
|
||
}
|
||
}
|
||
private void OnButtonSelected(Button selectedButton, int index)
|
||
{
|
||
if (_currentSelectedButton == selectedButton) return;
|
||
|
||
// 取消上一个按钮的选中
|
||
if (_currentSelectedButton != null && buttonDictionary.ContainsKey(_currentSelectedButton))
|
||
{
|
||
Image prevImg = _currentSelectedButton.GetComponent<Image>();
|
||
if (prevImg != null)
|
||
{
|
||
prevImg.sprite = buttonDictionary[_currentSelectedButton].normalSprite;
|
||
}
|
||
}
|
||
HideAllPanels();
|
||
panels[index].Activate();
|
||
// 设置新按钮的选中
|
||
SetSelectedButton(selectedButton);
|
||
}
|
||
public void SetSelectedButton(Button button)
|
||
{
|
||
if (!buttonDictionary.ContainsKey(button))
|
||
{
|
||
Debug.LogWarning($"按钮 {button.name} 不在管理列表中");
|
||
return;
|
||
}
|
||
|
||
_currentSelectedButton = button;
|
||
Image img = button.GetComponent<Image>();
|
||
if (img != null)
|
||
{
|
||
img.sprite = buttonDictionary[button].selectedSprite;
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
/// <summary>
|
||
/// 页面按钮点击初始化
|
||
/// </summary>
|
||
private void PanelBtnsInit()
|
||
{
|
||
variables.Get<Button>("关闭界面").onClick.AddListener(() =>
|
||
{
|
||
breakdownTaskItems.Clear();
|
||
Unload();
|
||
Load<HighEnergyConsumptionSTView>();
|
||
});
|
||
|
||
variables.Get<Button>("确认承接").onClick.AddListener(() =>
|
||
{
|
||
variables.Get<InputField>("起始日期").interactable = false;
|
||
variables.Get<InputField>("起始日期").GetComponent<EventTrigger>().triggers.Clear();
|
||
variables.Get<Button>("起始日期按钮").interactable = false;
|
||
variables.Get<InputField>("终止日期").interactable = false;
|
||
variables.Get<InputField>("终止日期").GetComponent<EventTrigger>().triggers.Clear();
|
||
variables.Get<Button>("终止日期按钮").interactable = false;
|
||
variables.Get<Button>("确认承接").interactable = false;
|
||
});
|
||
|
||
variables.Get<Button>("新增").onClick.AddListener(() =>
|
||
{
|
||
AddItemToScrollView(variables.Get<RectTransform>("子任务"), variables.Get<RectTransform>("子任务Content"));
|
||
//AddItemToScrollView(variables.Get<RectTransform>("准备工作子任务"), variables.Get<RectTransform>("准备工作Content"));
|
||
});
|
||
|
||
variables.Get<Button>("保存").onClick.AddListener(() =>
|
||
{
|
||
if (breakdownTaskItems.Where(a => a.timeInput.text.IsNullOrEmpty()).ToList().Count > 0
|
||
|| breakdownTaskItems.Where(a => a.nameInput.text.IsNullOrEmpty()).ToList().Count > 0
|
||
)
|
||
{
|
||
ShowWarming($"子任务名称或预计耗时未填写!");
|
||
}
|
||
else
|
||
{
|
||
variables.Get<Button>("新增").interactable = false;
|
||
variables.Get<Button>("保存").interactable = false;
|
||
float sum = 0;
|
||
for (int i = 0; i < breakdownTaskItems.Count; i++)
|
||
{
|
||
breakdownTaskItems[i].DisabledAll();
|
||
if (!breakdownTaskItems[i].timeInput.text.IsNullOrEmpty())
|
||
sum += float.Parse(breakdownTaskItems[i].timeInput.text);
|
||
}
|
||
variables.Get<Text>("总耗时").text = $"总耗时:{sum}天";
|
||
AddItemToTaskList();
|
||
AddItemToMaterialsList();
|
||
|
||
}
|
||
|
||
|
||
|
||
});
|
||
|
||
variables.Get<Button>("导出Excel").onClick.AddListener(() =>
|
||
{
|
||
ExportToExcel();
|
||
});
|
||
|
||
variables.Get<Button>("保存数据").onClick.AddListener(() =>
|
||
{
|
||
SaveDataRecordSheet();
|
||
});
|
||
|
||
variables.Get<Button>("保存报告").onClick.AddListener(() =>
|
||
{
|
||
SaveReport();
|
||
});
|
||
|
||
variables.Get<Button>("上传附件").onClick.AddListener(() =>
|
||
{
|
||
UploadFile();
|
||
});
|
||
variables.Get<Button>("导出PDF").onClick.AddListener(() =>
|
||
{
|
||
ExportPDF();
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 承接任务
|
||
/// </summary>
|
||
private void GetTaskList()
|
||
{
|
||
variables.Get<Text>("任务名称").text = UIUtils.Instance.ProjectName;
|
||
variables.Get<Text>("任务ID").text = UIUtils.Instance.GetUuid();
|
||
variables.Get<Text>("负责人").text = UIUtils.Instance.ProjectServiceTarget;
|
||
}
|
||
|
||
|
||
#region ScrollView部分
|
||
|
||
/// <summary>
|
||
/// 向滚动视图添加子项。
|
||
/// </summary>
|
||
/// <param name="item"></param>
|
||
/// <param name="scrollViewContent"></param>
|
||
private void AddItemToScrollView(RectTransform item, RectTransform scrollViewContent)
|
||
{
|
||
GameObject newItem = Instantiate(item.gameObject, scrollViewContent.transform);
|
||
newItem.Activate();
|
||
//AdjustContentLength(scrollViewContent);
|
||
|
||
if (newItem.GetComponent<BreakdownTaskItem>() != null)
|
||
{
|
||
BreakdownTaskItem breakdownTaskItem = newItem.GetComponent<BreakdownTaskItem>();
|
||
breakdownTaskItem.InitData();
|
||
breakdownTaskItems.Add(breakdownTaskItem);
|
||
Refresh();
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 添加子项到任务清单
|
||
/// </summary>
|
||
/// <param name="item"></param>
|
||
/// <param name="scrollViewContent"></param>
|
||
private void AddItemToTaskList()
|
||
{
|
||
BubbleSortList();
|
||
for (int i = 0; i < breakdownTaskItems.Count; i++)
|
||
{
|
||
GameObject newItem = Instantiate(variables.Get<RectTransform>("准备工作子任务").gameObject,
|
||
variables.Get<RectTransform>("准备工作Content").transform);
|
||
newItem.Activate();
|
||
newItem.transform.Find("顺序").GetComponent<Text>().text = (breakdownTaskItems[i].index + 1).ToString();
|
||
newItem.transform.Find("子任务名称输入框").GetComponent<InputField>().text = breakdownTaskItems[i].nameInput.text;
|
||
newItem.transform.Find("预计耗时输入框").GetComponent<InputField>().text = breakdownTaskItems[i].timeInput.text;
|
||
}
|
||
//AdjustContentLength(variables.Get<RectTransform>("准备工作Content"));
|
||
}
|
||
/// <summary>
|
||
/// 准备工作面板-添加物料准备清单
|
||
/// </summary>
|
||
private void AddItemToMaterialsList()
|
||
{
|
||
InventoryData inventoryData = JsonManager.LoadData<InventoryData>("BillofMaterials");
|
||
for (int i = 0; i < inventoryData.inventory.Count; i++)
|
||
{
|
||
GameObject newItem = Instantiate(variables.Get<RectTransform>("物料").gameObject,
|
||
variables.Get<RectTransform>("物料Content").transform);
|
||
newItem.Activate();
|
||
newItem.transform.Find("名称").GetComponent<Text>().text =$"名称:{inventoryData.inventory[i].type}";
|
||
newItem.transform.Find("数量").GetComponent<Text>().text = $"数量:{inventoryData.inventory[i].remaining}";
|
||
}
|
||
}
|
||
|
||
void BubbleSortList()
|
||
{
|
||
for (int i = 0; i < breakdownTaskItems.Count - 1; i++)
|
||
{
|
||
for (int j = 0; j < breakdownTaskItems.Count - 1 - i; j++)
|
||
{
|
||
if (breakdownTaskItems[j].index > breakdownTaskItems[j + 1].index)
|
||
{
|
||
BreakdownTaskItem temp = breakdownTaskItems[j];
|
||
breakdownTaskItems[j] = breakdownTaskItems[j + 1];
|
||
breakdownTaskItems[j + 1] = temp;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 调整内容长度以适应子项数量和布局设置。
|
||
/// 计算内容长度,以便在滚动视图中正确显示所有子项。
|
||
/// </summary>
|
||
/// <param name="contentRect"></param>
|
||
private void AdjustContentLength(RectTransform contentRect)
|
||
{
|
||
GridLayoutGroup gridLayout = contentRect.GetComponent<GridLayoutGroup>();
|
||
int childCount = contentRect.childCount;
|
||
if (childCount == 0) return;
|
||
|
||
Vector2 cellSize = gridLayout.cellSize;
|
||
Vector2 spacing = gridLayout.spacing;
|
||
GridLayoutGroup.Constraint constraint = gridLayout.constraint;
|
||
int constraintCount = gridLayout.constraintCount;
|
||
GridLayoutGroup.Axis startAxis = gridLayout.startAxis;
|
||
|
||
int rows = 1;
|
||
int columns = 1;
|
||
|
||
// 根据Grid Layout Group设置计算行和列
|
||
if (startAxis == GridLayoutGroup.Axis.Vertical) // 垂直排列
|
||
{
|
||
switch (constraint)
|
||
{
|
||
case GridLayoutGroup.Constraint.FixedColumnCount:
|
||
columns = constraintCount;
|
||
rows = Mathf.CeilToInt((float)childCount / columns);
|
||
break;
|
||
case GridLayoutGroup.Constraint.FixedRowCount:
|
||
rows = constraintCount;
|
||
columns = Mathf.CeilToInt((float)childCount / rows);
|
||
break;
|
||
case GridLayoutGroup.Constraint.Flexible: // Flexible模式
|
||
float contentWidth = contentRect.rect.width;
|
||
if (contentWidth > 0)
|
||
{
|
||
columns = Mathf.FloorToInt((contentWidth + spacing.x) / (cellSize.x + spacing.x));
|
||
if (columns < 1) columns = 1;
|
||
rows = Mathf.CeilToInt((float)childCount / columns);
|
||
}
|
||
else
|
||
{
|
||
columns = 1;
|
||
rows = childCount;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
else // 水平排列
|
||
{
|
||
switch (constraint)
|
||
{
|
||
case GridLayoutGroup.Constraint.FixedColumnCount:
|
||
columns = constraintCount;
|
||
rows = Mathf.CeilToInt((float)childCount / columns);
|
||
break;
|
||
case GridLayoutGroup.Constraint.FixedRowCount:
|
||
rows = constraintCount;
|
||
columns = Mathf.CeilToInt((float)childCount / rows);
|
||
break;
|
||
case GridLayoutGroup.Constraint.Flexible: // Flexible模式
|
||
float contentHeight = contentRect.rect.height;
|
||
if (contentHeight > 0)
|
||
{
|
||
rows = Mathf.FloorToInt((contentHeight + spacing.y) / (cellSize.y + spacing.y));
|
||
if (rows < 1) rows = 1;
|
||
columns = Mathf.CeilToInt((float)childCount / rows);
|
||
}
|
||
else
|
||
{
|
||
rows = 1;
|
||
columns = childCount;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 计算所需Content尺寸
|
||
float requiredWidth = columns * cellSize.x + Mathf.Max(0, columns - 1) * spacing.x;
|
||
float requiredHeight = rows * cellSize.y + Mathf.Max(0, rows - 1) * spacing.y;
|
||
|
||
// 更新Content大小
|
||
contentRect.sizeDelta = new Vector2(requiredWidth, requiredHeight);
|
||
}
|
||
|
||
/*
|
||
/// <summary>
|
||
/// 【核心方法】为实例化好的Item GameObject 绑定拖拽功能。
|
||
/// 在您自己的实例化代码中,在Instantiate之后调用此方法。
|
||
/// </summary>
|
||
/// <param name="itemRectTransform">Item的RectTransform组件</param>
|
||
/// <param name="index">该Item在列表中的初始索引</param>
|
||
public void SetupDraggableItem(RectTransform itemRectTransform, int index, RectTransform content, GridLayoutGroup gridLayoutGroup)
|
||
{
|
||
if (itemRectTransform == null) return;
|
||
|
||
// 确保Item有CanvasGroup组件(用于在拖拽时屏蔽射线检测)
|
||
CanvasGroup cg = itemRectTransform.gameObject.GetComponent<CanvasGroup>();
|
||
if (cg == null) cg = itemRectTransform.gameObject.AddComponent<CanvasGroup>();
|
||
|
||
// 添加或获取EventTrigger组件
|
||
EventTrigger eventTrigger = itemRectTransform.gameObject.GetComponent<EventTrigger>();
|
||
if (eventTrigger == null) eventTrigger = itemRectTransform.gameObject.AddComponent<EventTrigger>();
|
||
|
||
// 清除旧的事件(避免重复绑定),然后添加三个必要的事件监听
|
||
eventTrigger.triggers.Clear();
|
||
|
||
// 1. 开始拖拽事件
|
||
EventTrigger.Entry beginDragEntry = new EventTrigger.Entry();
|
||
beginDragEntry.eventID = EventTriggerType.BeginDrag;
|
||
beginDragEntry.callback.AddListener((data) => { OnBeginDrag(itemRectTransform, index, content); });
|
||
eventTrigger.triggers.Add(beginDragEntry);
|
||
|
||
// 2. 拖拽中事件
|
||
EventTrigger.Entry dragEntry = new EventTrigger.Entry();
|
||
dragEntry.eventID = EventTriggerType.Drag;
|
||
dragEntry.callback.AddListener((data) => { OnDrag(content); });
|
||
eventTrigger.triggers.Add(dragEntry);
|
||
|
||
// 3. 结束拖拽事件
|
||
EventTrigger.Entry endDragEntry = new EventTrigger.Entry();
|
||
endDragEntry.eventID = EventTriggerType.EndDrag;
|
||
endDragEntry.callback.AddListener((data) => { OnEndDrag(itemRectTransform, content, gridLayoutGroup); });
|
||
eventTrigger.triggers.Add(endDragEntry);
|
||
|
||
// 将Item添加到跟踪列表
|
||
if (!itemTransforms.Contains(itemRectTransform))
|
||
{
|
||
itemTransforms.Add(itemRectTransform);
|
||
}
|
||
}
|
||
|
||
// --- 事件处理函数 ---
|
||
private void OnBeginDrag(RectTransform item, int index, RectTransform content)
|
||
{
|
||
draggedItem = item;
|
||
startDragIndex = index;
|
||
Debug.Log($"开始拖拽: {item.name}, 起始索引: {startDragIndex}");
|
||
|
||
// 1. 创建占位符,保持原Item的尺寸
|
||
placeholder = new GameObject("Placeholder");
|
||
placeholder.transform.SetParent(content, false);
|
||
LayoutElement le = placeholder.AddComponent<LayoutElement>();
|
||
le.preferredWidth = item.sizeDelta.x;
|
||
le.preferredHeight = item.sizeDelta.y;
|
||
// 将占位符放在被拖拽Item原来的位置
|
||
placeholder.transform.SetSiblingIndex(startDragIndex);
|
||
|
||
// 2. 使被拖拽Item暂时脱离布局控制,并置于顶层
|
||
item.SetParent(content.parent.parent, true); // 通常设为Canvas或ScrollView的父级
|
||
item.GetComponent<CanvasGroup>().blocksRaycasts = false; // 禁止接收射线,防止事件冲突
|
||
}
|
||
|
||
private void OnDrag(RectTransform content)
|
||
{
|
||
if (draggedItem == null || placeholder == null) return;
|
||
|
||
// 1. 让被拖拽的Item跟随鼠标/触摸位置
|
||
RectTransformUtility.ScreenPointToWorldPointInRectangle(
|
||
content,
|
||
Input.mousePosition,
|
||
null,
|
||
out Vector3 worldPoint
|
||
);
|
||
draggedItem.position = worldPoint;
|
||
|
||
// 2. 计算并更新占位符的新位置(决定插入点)
|
||
// 该方法适用于垂直布局。对于水平布局,需比较X轴位置。
|
||
int newSiblingIndex = content.childCount; // 默认放在最后
|
||
|
||
for (int i = 0; i < content.childCount; i++)
|
||
{
|
||
// 跳过占位符自己
|
||
if (content.GetChild(i) == placeholder.transform) continue;
|
||
|
||
// 比较Y坐标(从上到下递减的布局)。可根据您的布局方向调整比较逻辑。
|
||
if (draggedItem.position.y > content.GetChild(i).position.y)
|
||
{
|
||
newSiblingIndex = i;
|
||
// 一个小调整:如果从下往上拖,索引需要修正
|
||
if (placeholder.transform.GetSiblingIndex() < newSiblingIndex)
|
||
{
|
||
newSiblingIndex--;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
// 应用新的位置索引
|
||
placeholder.transform.SetSiblingIndex(newSiblingIndex);
|
||
}
|
||
|
||
private void OnEndDrag(RectTransform item, RectTransform content, GridLayoutGroup contentLayoutGroup)
|
||
{
|
||
if (draggedItem == null || placeholder == null) return;
|
||
|
||
// 1. 恢复被拖拽Item的状态
|
||
item.SetParent(content, true);
|
||
// 将Item放到占位符所在的位置
|
||
item.SetSiblingIndex(placeholder.transform.GetSiblingIndex());
|
||
item.GetComponent<CanvasGroup>().blocksRaycasts = true; // 恢复交互
|
||
|
||
// 2. 销毁占位符
|
||
Destroy(placeholder);
|
||
placeholder = null;
|
||
|
||
// 3. 计算新的数据索引并更新数据列表
|
||
int endDragIndex = item.GetSiblingIndex();
|
||
UpdateDataOrder(startDragIndex, endDragIndex);
|
||
|
||
// 4. 可选:强制布局组件立即重新计算,避免视觉延迟
|
||
if (contentLayoutGroup != null)
|
||
{
|
||
LayoutRebuilder.ForceRebuildLayoutImmediate(content);
|
||
}
|
||
|
||
// 5. 更新itemTransforms列表的顺序,以匹配新的UI顺序
|
||
RefreshItemTransformList(content);
|
||
|
||
Debug.Log($"拖拽结束。Item从索引 {startDragIndex} 移动到 {endDragIndex}");
|
||
Debug.Log("当前数据顺序: " + string.Join(", ", dataList));
|
||
|
||
draggedItem = null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新底层数据列表的顺序,以匹配UI变化。
|
||
/// 这是整个拖拽排序功能的核心,确保数据与UI同步。
|
||
/// </summary>
|
||
private void UpdateDataOrder(int fromIndex, int toIndex)
|
||
{
|
||
if (fromIndex == toIndex) return;
|
||
if (fromIndex < 0 || fromIndex >= dataList.Count) return;
|
||
if (toIndex < 0 || toIndex >= dataList.Count) return;
|
||
|
||
// 移动数据
|
||
GameObject movedData = dataList[fromIndex];
|
||
dataList.RemoveAt(fromIndex);
|
||
dataList.Insert(toIndex, movedData);
|
||
|
||
// 这里可以触发一个自定义事件,通知其他游戏系统数据顺序已改变
|
||
// OnDataOrderChanged?.Invoke(dataList);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据Content下Item当前的顺序,刷新itemTransforms列表。
|
||
/// </summary>
|
||
private void RefreshItemTransformList(RectTransform content)
|
||
{
|
||
itemTransforms.Clear();
|
||
foreach (Transform child in content)
|
||
{
|
||
RectTransform rt = child.GetComponent<RectTransform>();
|
||
if (rt != null && !child.name.Contains("Placeholder")) // 排除占位符
|
||
{
|
||
itemTransforms.Add(rt);
|
||
}
|
||
}
|
||
}*/
|
||
|
||
#endregion
|
||
|
||
/// <summary>
|
||
/// 导出Excel
|
||
/// </summary>
|
||
private void ExportToExcel()
|
||
{
|
||
string defaultFileName = $"{"标准化清单"}_{DateTime.Now:yyyyMMdd_HHmmss}.xlsx";
|
||
string outputPath = EditorUtility.SaveFilePanel("保存Excel文件", "", defaultFileName, "xlsx");
|
||
|
||
if (!string.IsNullOrEmpty(outputPath))
|
||
{
|
||
|
||
FileInfo file = new FileInfo(outputPath);
|
||
ExcelPackage package = new ExcelPackage(file);
|
||
ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("sheet1");
|
||
worksheet.Cells[1, 1, 1, 4].Merge = true;
|
||
worksheet.Cells[1, 1].Value = "任务清单";
|
||
worksheet.Cells[1, 1].Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center;
|
||
worksheet.Cells[1, 1].Style.Font.Bold = true;
|
||
for (int i = 1; i <= breakdownTaskItems.Count; i++)
|
||
{
|
||
Debug.Log(i);
|
||
worksheet.Cells[$"A{i*2}:A{i*2+1}"].Merge = true;
|
||
worksheet.Cells[$"A{i*2}:A{i*2+1}"].Style.VerticalAlignment = OfficeOpenXml.Style.ExcelVerticalAlignment.Center;
|
||
worksheet.Cells[$"A{i*2}:A{i*2+1}"].Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center;
|
||
worksheet.Cells[$"A{i*2}:A{i*2+1}"].Value = i;
|
||
worksheet.Cells[$"B{i*2}"].Value = "子任务名称";
|
||
worksheet.Cells[$"B{i*2+1}"].Value ="预计耗时(天)";
|
||
|
||
worksheet.Cells[$"C{i*2}"].Value = breakdownTaskItems[i-1].nameInput.text;
|
||
worksheet.Cells[$"C{i*2+1}"].Value =breakdownTaskItems[i-1].timeInput.text;
|
||
|
||
}
|
||
|
||
int row = (breakdownTaskItems.Count*2+2);
|
||
worksheet.Cells[row, 1, row, 4].Merge = true;
|
||
worksheet.Cells[row, 1].Value = "诊断方案";
|
||
worksheet.Cells[row, 1].Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center;
|
||
worksheet.Cells[row, 1].Style.Font.Bold = true;
|
||
row++;
|
||
worksheet.Cells[row, 1, row, 4].Merge = true;
|
||
worksheet.Cells[row, 1].Value = variables.Get<Dropdown>("诊断方案").options[variables.Get<Dropdown>("诊断方案").value].text;
|
||
row++;
|
||
|
||
|
||
worksheet.Cells[row, 1, row, 4].Merge = true;
|
||
worksheet.Cells[row, 1].Value = "物料准备清单";
|
||
worksheet.Cells[row, 1].Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center;
|
||
worksheet.Cells[row, 1].Style.Font.Bold = true;
|
||
row++;
|
||
for (int i = 0; i < variables.Get<RectTransform>("物料准备清单").transform.childCount; i++)
|
||
{
|
||
worksheet.Cells[$"A{row}:A{row+1}"].Merge = true;
|
||
worksheet.Cells[$"A{row}:A{row+1}"].Style.VerticalAlignment = OfficeOpenXml.Style.ExcelVerticalAlignment.Center;
|
||
worksheet.Cells[$"A{row}:A{row + 1}"].Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center;
|
||
worksheet.Cells[$"A{row}:A{row + 1}"].Value = i;
|
||
worksheet.Cells[$"B{row}"].Value = variables.Get<RectTransform>("物料准备清单").GetComponentsInChildren<Text>()[0].text;
|
||
worksheet.Cells[$"B{row+1}"].Value = variables.Get<RectTransform>("物料准备清单").GetComponentsInChildren<Text>()[1].text;
|
||
row++;
|
||
}
|
||
|
||
worksheet.Cells.AutoFitColumns();
|
||
package.Save();
|
||
Debug.Log("导出Excel成功");
|
||
}
|
||
|
||
|
||
}
|
||
/// <summary>
|
||
/// 保存数据记录表
|
||
/// </summary>
|
||
private void SaveDataRecordSheet()
|
||
{
|
||
if (!UIUtils.Instance.IsInputCorrect(variables.Get<InputField>("运行时长")) ||
|
||
!UIUtils.Instance.IsInputCorrect(variables.Get<InputField>("当前能耗")) ||
|
||
!UIUtils.Instance.IsInputCorrect(variables.Get<InputField>("功率")) ||
|
||
!UIUtils.Instance.IsInputCorrect(variables.Get<InputField>("温度")))
|
||
{
|
||
ShowWarming("有数据未记录"); return;
|
||
}
|
||
|
||
|
||
dataRecordSheet = new DataRecordSheet
|
||
{
|
||
Model = variables.Get<Dropdown>("设备型号").options[variables.Get<Dropdown>("设备型号").value].text,
|
||
RuntimeDuration = float.Parse(variables.Get<InputField>("运行时长").text),
|
||
CurrentEnergyConsumption = float.Parse(variables.Get<InputField>("当前能耗").text),
|
||
Power = float.Parse(variables.Get<InputField>("功率").text),
|
||
Temperature = float.Parse(variables.Get<InputField>("温度").text)
|
||
};
|
||
|
||
variables.Get<Button>("保存数据").interactable = false;
|
||
variables.Get<Dropdown>("设备型号").interactable = false;
|
||
variables.Get<InputField>("运行时长").interactable = false;
|
||
variables.Get<InputField>("当前能耗").interactable = false;
|
||
variables.Get<InputField>("功率").interactable = false;
|
||
variables.Get<InputField>("温度").interactable = false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 保存报告
|
||
/// </summary>
|
||
private void SaveReport()
|
||
{
|
||
variables.Get<InputField>("设备现状输入框").interactable = false;
|
||
variables.Get<InputField>("数据对比输入框").interactable = false;
|
||
variables.Get<InputField>("问题清单输入框").interactable = false;
|
||
variables.Get<InputField>("节能方案输入框").interactable = false;
|
||
variables.Get<Button>("上传附件").interactable = false;
|
||
//variables.Get<Button>("导出PDF").interactable = false;
|
||
|
||
//-------------------------------------------------------------
|
||
|
||
variables.Get<InputField>("设备现状输入框-解读").text = variables.Get<InputField>("设备现状输入框").text;
|
||
variables.Get<InputField>("数据对比输入框-解读").text = variables.Get<InputField>("数据对比输入框").text;
|
||
variables.Get<InputField>("问题清单输入框-解读").text = variables.Get<InputField>("问题清单输入框").text;
|
||
variables.Get<InputField>("节能方案输入框-解读").text = variables.Get<InputField>("节能方案输入框").text;
|
||
|
||
Transform attachmentContainer = variables.Get<RectTransform>("附件展示框-解读");
|
||
foreach (var item in variables.Get<RectTransform>("附件展示框").GetComponentsInChildren<AttachmentItem>())
|
||
{
|
||
GameObject attachmentGO = Instantiate(item.gameObject, attachmentContainer);
|
||
AttachmentItem attachmentItem = attachmentGO.GetComponent<AttachmentItem>();
|
||
attachmentItem.Initialize(item.filePath, FileUploadManager.Instance.GetFileIcon(item.filePath), OnAttachmentRemoved);
|
||
attachmentItem.removeButton.gameObject.SetActive(false);
|
||
}
|
||
//variables.Get<InputField>("上传附件-解读").interactable = false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 上传附件
|
||
/// </summary>
|
||
private void UploadFile()
|
||
{
|
||
// 使用FileUploadManager选择文件
|
||
FileUploadManager.Instance.SelectAndUploadFile((filePath) =>
|
||
{
|
||
if (!string.IsNullOrEmpty(filePath))
|
||
{
|
||
// 获取文件图标
|
||
Sprite fileIcon = FileUploadManager.Instance.GetFileIcon(filePath);
|
||
|
||
// 创建附件项
|
||
CreateAttachmentItem(filePath, fileIcon);
|
||
}
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 导出PDF
|
||
/// </summary>
|
||
private void ExportPDF()
|
||
{
|
||
string title = "能效诊断报告";
|
||
string content = $@"
|
||
设备现状
|
||
{variables.Get<InputField>("设备现状输入框").text}
|
||
|
||
|
||
数据对比
|
||
{variables.Get<InputField>("数据对比输入框").text}
|
||
|
||
|
||
问题清单
|
||
{variables.Get<InputField>("问题清单输入框").text}
|
||
|
||
|
||
节能方案
|
||
{variables.Get<InputField>("节能方案输入框").text}
|
||
|
||
|
||
|
||
";
|
||
|
||
// 执行PDF导出
|
||
PdfExportManager.Instance.SelectAndExportPdf(title, content, (success, message) =>
|
||
{
|
||
Debug.Log($"PDF导出测试结果: {message}");
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建附件项
|
||
/// </summary>
|
||
/// <param name="filePath">文件路径</param>
|
||
/// <param name="fileIcon">文件图标</param>
|
||
private void CreateAttachmentItem(string filePath, Sprite fileIcon)
|
||
{
|
||
// 获取附件容器
|
||
Transform attachmentContainer = variables.Get<RectTransform>("附件展示框");
|
||
if (attachmentContainer == null)
|
||
{
|
||
Debug.LogError("未找到附件容器,请确保UI中存在名为'附件展示框'的Transform");
|
||
return;
|
||
}
|
||
|
||
// 查找AttachmentItem预制件
|
||
GameObject attachmentPrefab = Resources.Load<GameObject>("Prefabs/AttachmentItem");
|
||
if (attachmentPrefab == null)
|
||
{
|
||
Debug.LogError("未找到预制体路径");
|
||
}
|
||
else
|
||
{
|
||
// 实例化预制件
|
||
GameObject attachmentGO = Instantiate(attachmentPrefab, attachmentContainer);
|
||
AttachmentItem attachmentItem = attachmentGO.GetComponent<AttachmentItem>();
|
||
if (attachmentItem == null)
|
||
{
|
||
attachmentItem = attachmentGO.AddComponent<AttachmentItem>();
|
||
// 创建UI元素
|
||
}
|
||
LayoutRebuilder.ForceRebuildLayoutImmediate(variables.Get<ScrollRect>("报告生成").content);
|
||
|
||
// 初始化附件项
|
||
attachmentItem.Initialize(filePath, fileIcon, OnAttachmentRemoved);
|
||
variables.Get<ScrollRect>("报告生成").verticalNormalizedPosition = 0;
|
||
Canvas.ForceUpdateCanvases();
|
||
PdfExportManager.Instance.AddAttachment(filePath);
|
||
|
||
}
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 附件移除回调
|
||
/// </summary>
|
||
/// <param name="attachmentItem">被移除的附件项</param>
|
||
private void OnAttachmentRemoved(AttachmentItem attachmentItem)
|
||
{
|
||
if (attachmentItem != null)
|
||
{
|
||
PdfExportManager.Instance.RemoveAttachment(attachmentItem.filePath);
|
||
Destroy(attachmentItem.gameObject);
|
||
}
|
||
}
|
||
|
||
|
||
public void Refresh()
|
||
{
|
||
if (breakdownTaskItems.Count == 0) return;
|
||
for (int i = 0; i < breakdownTaskItems.Count; i++)
|
||
{
|
||
int index = i;
|
||
//breakdownTaskItems[i].SetCurrentIndex =index;
|
||
breakdownTaskItems[i].Refresh();
|
||
}
|
||
}
|
||
|
||
#region 警告
|
||
|
||
/// <summary>
|
||
/// 显示警告信息
|
||
/// </summary>
|
||
/// <param name="warmingText"></param>
|
||
public void ShowWarming(string warmingText)
|
||
{
|
||
if (string.IsNullOrEmpty(warmingText.Trim())) return;
|
||
if (!variables.Get<RectTransform>("警告").gameObject.activeSelf)
|
||
variables.Get<RectTransform>("警告").gameObject.Activate();
|
||
// 快速完成打字
|
||
if (typingCoroutine != null)
|
||
StopCoroutine(typingCoroutine);
|
||
//开启打字效果
|
||
typingCoroutine = StartCoroutine(TypeText(warmingText));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 打字效果协程,逐个字符显示文本。
|
||
/// </summary>
|
||
/// <param name="text"></param>
|
||
/// <returns></returns>
|
||
private IEnumerator TypeText(string text)
|
||
{
|
||
variables.Get<Text>("警告文本").text = "";
|
||
|
||
foreach (char letter in text.ToCharArray())
|
||
{
|
||
variables.Get<Text>("警告文本").text += letter;
|
||
yield return new WaitForSeconds(typingSpeed);
|
||
}
|
||
yield return new WaitForSeconds(hideAlarm);
|
||
variables.Get<RectTransform>("警告").gameObject.SetActive(false);
|
||
}
|
||
#endregion
|
||
}
|
||
|
||
/// <summary>
|
||
/// 数据记录表
|
||
/// </summary>
|
||
public class DataRecordSheet
|
||
{
|
||
/// <summary>
|
||
/// 型号
|
||
/// </summary>
|
||
public string Model { get; set; }
|
||
/// <summary>
|
||
/// 运行时长
|
||
/// </summary>
|
||
public float RuntimeDuration { get; set; }
|
||
/// <summary>
|
||
/// 当前能耗
|
||
/// </summary>
|
||
public float CurrentEnergyConsumption { get; set; }
|
||
/// <summary>
|
||
/// 功率
|
||
/// </summary>
|
||
public float Power { get; set; }
|
||
/// <summary>
|
||
/// 温度
|
||
/// </summary>
|
||
public float Temperature { get; set; }
|
||
} |