EnergyEfficiencyManagement/Assets/Zion/Scripts/UIView/ManagementSimulationView.cs

775 lines
26 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using SK.Framework;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using UI.Dates;
using Unity.VisualScripting.Antlr3.Runtime.Misc;
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// 管理流程仿真模块
/// </summary>
public class ManagementSimulationView : UIView
{
public Variables variables;
public List<Button> leftBtns = new List<Button>();
public List<GameObject> panels = new List<GameObject>();
public List<string> detectData = new List<string>();
public List<string> researchData = new List<string>();
public List<string> reportData = new List<string>();
[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;
//打字动画协程句柄,防止重复打字导致打字动画卡顿问题
private Coroutine typingCoroutine;
//打字动画速度,单位:秒/字符
private float typingSpeed = 0.05f;
//已完成任务
private List<GameObject> processTask_done = new List<GameObject>();
//进行中任务
private List<GameObject> processTask_doing = new List<GameObject>();
//已逾期任务
private List<GameObject> processTask_dead = new List<GameObject>();
//库存物品列表key为物品名称value为物品对象
private Dictionary<string, GameObject> inventorys = new Dictionary<string, GameObject>();
[Header("评分权重 (0-1)")]
[Tooltip("任务成效的权重")]
[Range(0f, 1f)] public float weightEffectiveness = 0.5f;
[Tooltip("存在问题的负向权重")]
[Range(0f, 1f)] public float weightProblems = 0.3f;
[Tooltip("改进措施的正向权重")]
[Range(0f, 1f)] public float weightImprovements = 0.2f;
protected override void OnInit(IViewData data)
{
base.OnInit(data);
variables.Set<ManagementSimulationView>("my_ManagementSimulation", this);
variables.Get<InputField>("项目ID输入框").text = UIUtils.Instance.GetUuid();
PanelInit();
PanelBtnsInit();
}
#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]);
panels[0].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;
}
}
/// <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();
//leftBtns[index].Set
panels[index].Activate();
}
#endregion
/// <summary>
/// 页面按钮点击初始化
/// </summary>
private void PanelBtnsInit()
{
processTask_dead.Clear();
processTask_doing.Clear();
processTask_done.Clear();
inventorys.Clear();
logString = new StringBuilder();
variables.Get<Button>("关闭界面").onClick.AddListener(() =>
{
Unload();
Load<HighEnergyConsumptionSTView>();
});
variables.Get<Button>("完成").onClick.AddListener(() =>
{
ProjectInitCheck();
});
variables.Get<Button>("完成设定").onClick.AddListener(() =>
{
TargetSetCheck();
});
variables.Get<Button>("新增目标").onClick.AddListener(() =>
{
UIUtils.Instance.AddItemToScrollView(variables.Get<RectTransform>("阶段目标"), variables.Get<RectTransform>("目标分解表"));
});
variables.Get<Button>("分配").onClick.AddListener(() =>
{
PushTaskCheck();
});
variables.Get<Dropdown>("类型").onValueChanged.AddListener(TaskTypeValueChanged);
variables.Get<Dropdown>("任务状态").onValueChanged.AddListener(SeekTask);
variables.Get<Button>("调整日志按钮").onClick.AddListener(LogClick);
InitInventory();
variables.Get<Button>("登记").onClick.AddListener(() =>
{
Regesiter();
});
variables.Get<Button>("计算目标达成率").onClick.AddListener(() =>
{
CalculateAndDisplayAchievementRate();
});
variables.Get<Button>("上传附件").onClick.AddListener(()=>
{
UploadFile();
});
}
/// <summary>
/// 上传附件
/// </summary>
private void UploadFile()
{
// 使用FileUploadManager选择文件
FileUploadManager.Instance.SelectAndUploadFile((filePath) =>
{
if (!string.IsNullOrEmpty(filePath))
{
// 获取文件图标
Sprite fileIcon = FileUploadManager.Instance.GetFileIcon(filePath);
// 创建附件项
CreateAttachmentItem(filePath, fileIcon);
}
});
}
/// <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);
}
}
/// <summary>
/// 立项审批单完成检查
/// </summary>
private void ProjectInitCheck()
{
if (!UIUtils.Instance.IsInputCorrect(variables.Get<InputField>("项目名称输入框")) ||
!UIUtils.Instance.IsInputCorrect(variables.Get<InputField>("服务对象输入框")) ||
!UIUtils.Instance.IsInputCorrect(variables.Get<InputField>("预期目标输入框")) ||
string.IsNullOrEmpty(variables.Get<DatePicker_DateRange>("立项预期周期").FromDate.ToDateString()) ||
string.IsNullOrEmpty(variables.Get<DatePicker_DateRange>("立项预期周期").ToDate.ToDateString()))
{
ShowWarming("请完善信息!");
return;
}
variables.Get<InputField>("项目名称输入框").interactable = false;
variables.Get<InputField>("服务对象输入框").interactable = false;
variables.Get<InputField>("预期目标输入框").interactable = false;
variables.Get<Button>("完成").interactable = false;
//variables.Get<DatePicker_DateRange>("立项预期周期").
//TODO:记录当前数据
}
/// <summary>
/// 目标设定检查
/// </summary>
private void TargetSetCheck()
{
bool isError = false;
foreach (Transform item in variables.Get<RectTransform>("目标分解表"))
{
if (item.gameObject.activeSelf)
{
if (!item.GetComponent<PhaseObjectiveItem>().IsEditDone())
isError = true;
}
}
if (isError)
{
ShowWarming("请完善阶段目标!");
return;
}
for (int i = 0; i < variables.Get<RectTransform>("目标分解表").childCount; i++)
{
//if()
Transform item = variables.Get<RectTransform>("目标分解表").GetChild(i);
if (item.gameObject.activeSelf)
{
item.GetComponent<PhaseObjectiveItem>().CloseEdit();
}
}
foreach (Transform item in variables.Get<RectTransform>("目标分解表"))
{
if (item.gameObject.activeSelf)
{
item.GetComponent<PhaseObjectiveItem>().CloseEdit();
}
///================进度看板================
GameObject temp = Instantiate(variables.Get<ProcessTaskItem>("任务进度").gameObject, variables.Get<RectTransform>("进度看板内容").transform);
temp.Activate();
temp.GetComponent<ProcessTaskItem>().SetName = item.GetComponent<PhaseObjectiveItem>().GetName;
temp.GetComponent<ProcessTaskItem>().SetDate = item.GetComponent<PhaseObjectiveItem>().GetDate;
temp.GetComponent<ProcessTaskItem>().SetRole = item.GetComponent<PhaseObjectiveItem>().GetRole;
int state = UnityEngine.Random.Range(0, 3);
switch (state)
{
case 0:
temp.GetComponent<ProcessTaskItem>().SetState = "已完成";
processTask_done.Add(temp);
break;
case 1:
temp.GetComponent<ProcessTaskItem>().SetState = "进行中...";
processTask_doing.Add(temp);
break;
case 2:
temp.GetComponent<ProcessTaskItem>().SetState = "...逾期...";
processTask_dead.Add(temp);
break;
}
///================进度调整================
GameObject task = Instantiate(item.gameObject, variables.Get<RectTransform>("任务清单").transform);
task.Activate();
task.GetComponent<PhaseObjectiveItem>().OpenFuncBtns();
task.GetComponent<PhaseObjectiveItem>().doneBtn.onClick.AddListener(() =>
{
SetLog(System.DateTime.Now + " " + task.GetComponent<PhaseObjectiveItem>().GetName + ",已修改");
});
}
variables.Get<Button>("完成设定").interactable = false;
variables.Get<Button>("新增目标").interactable = false;
}
/// <summary>
/// 推送任务检查
/// </summary>
private void PushTaskCheck()
{
if (!UIUtils.Instance.IsInputCorrect(variables.Get<InputField>("任务描述输入框")))
{
ShowWarming("请填写任务描述!");
return;
}
if (string.IsNullOrEmpty(variables.Get<DatePicker_DateRange>("任务分配截止日期").FromDate.ToString()) ||
string.IsNullOrEmpty(variables.Get<DatePicker_DateRange>("任务分配截止日期").ToDate.ToString()))
{
ShowWarming("请填写任务截止日期");
return;
}
variables.Get<Dropdown>("任务类型").interactable = false;
variables.Get<Button>("执行人").interactable = false;
variables.Get<InputField>("任务描述输入框").interactable = false;
InputField[] inputs = variables.Get<DatePicker_DateRange>("任务分配截止日期").gameObject.GetComponentsInChildren<InputField>();
Button[] buttons = variables.Get<DatePicker_DateRange>("任务分配截止日期").gameObject.GetComponentsInChildren<Button>();
foreach (var item in inputs)
{
item.interactable = false;
}
foreach (var item in buttons)
{
item.interactable = false;
}
variables.Get<Button>("分配").interactable = false;
}
/// <summary>
/// 任务类型切换
/// </summary>
/// <param name="index"></param>
private void TaskTypeValueChanged(int index)
{
int num = UnityEngine.Random.Range(0, 3);
switch (index)
{
case 0:
variables.Get<InputField>("诊断结果").text = detectData[num].ToString();
break;
case 1:
variables.Get<InputField>("诊断结果").text = researchData[num].ToString();
break;
case 2:
variables.Get<InputField>("诊断结果").text = reportData[num].ToString();
break;
}
}
/// <summary>
/// 检索任务状态
/// </summary>
/// <param name="index"></param>
private void SeekTask(int index)
{
switch (index)
{
case 0:
ObjListCtr(processTask_done, false);
ObjListCtr(processTask_dead, false);
ObjListCtr(processTask_doing, false);
break;
case 1:
ObjListCtr(processTask_done, false);
ObjListCtr(processTask_dead, true);
ObjListCtr(processTask_doing, true);
break;
case 2:
ObjListCtr(processTask_done, true);
ObjListCtr(processTask_dead, true);
ObjListCtr(processTask_doing, false);
break;
case 3:
ObjListCtr(processTask_done, true);
ObjListCtr(processTask_dead, false);
ObjListCtr(processTask_doing, true);
break;
}
}
/// <summary>
/// 批量修改列表
/// </summary>
/// <param name="target"></param>
/// <param name="isClose"></param>
private void ObjListCtr(List<GameObject> target, bool isClose)
{
for (int i = 0; i < target.Count; i++)
{
if (isClose)
target[i].Deactivate();
else
target[i].Activate();
}
}
/// <summary>
/// 点击日志
/// </summary>
private void LogClick()
{
bool isActive = variables.Get<RectTransform>("任务清单").gameObject.activeSelf;
variables.Get<RectTransform>("任务清单").gameObject.SetActive(!isActive);
variables.Get<RectTransform>("日志弹窗").gameObject.SetActive(isActive);
}
StringBuilder logString;
/// <summary>
/// 设置日志
/// </summary>
/// <param name="str"></param>
public void SetLog(string str)
{
logString.AppendLine(str);
variables.Get<InputField>("日志内容").text = logString.ToString();
}
/// <summary>
/// 初始化库存信息
/// </summary>
private void InitInventory()
{
StartCoroutine(WaitForInventory());
// 注册库存更新事件
Dictionary<string, int> stats = InventoryManager.Instance.GetAllItemDetails();
if (stats.Count == 0) return;
foreach (KeyValuePair<string, int> item in stats)
{
GameObject objClone = Instantiate(variables.Get<RectTransform>("资源").gameObject, variables.Get<RectTransform>("资源列表").transform);
objClone.Activate();
objClone.transform.GetChild(0).GetComponent<Text>().text = "类型:" + item.Key;
objClone.transform.GetChild(1).GetComponent<Text>().text = "剩余数量:" + item.Value;
inventorys.Add(item.Key, objClone);
}
}
/// <summary>
/// 登记库存信息
/// </summary>
private void Regesiter()
{
Dictionary<string, int> stats = InventoryManager.Instance.GetAllItemDetails();
if (stats.Count == 0) return;
stats.TryGetValue(variables.Get<Dropdown>("资源类型").options[variables.Get<Dropdown>("资源类型").value].text, out int result);
int num = result - int.Parse(variables.Get<Dropdown>("资源数量").options[variables.Get<Dropdown>("资源数量").value].text);
if (num < 0)
{
ShowWarming("库存不足");
return;
}
InventoryManager.Instance.UpdateItemQuantity(variables.Get<Dropdown>("资源类型").options[variables.Get<Dropdown>("资源类型").value].text, num);
foreach (KeyValuePair<string, GameObject> item in inventorys)
{
if (item.Key == variables.Get<Dropdown>("资源类型").options[variables.Get<Dropdown>("资源类型").value].text)
item.Value.transform.GetChild(1).GetComponent<Text>().text = "剩余数量:" + num;
}
}
/// <summary>
/// 等待库存系统初始化完成并注册事件回调函数。
/// </summary>
/// <returns></returns>
private System.Collections.IEnumerator WaitForInventory()
{
// 等待库存系统初始化完成
while (!InventoryManager.Instance.IsInitialized)
{
yield return null;
}
}
#region
/// <summary>
/// 计算并显示达成率
/// </summary>
public void CalculateAndDisplayAchievementRate()
{
// 1. 获取文本
string effectivenessText = variables.Get<InputField>("成效").text;
string problemsText = variables.Get<InputField>("问题").text;
string improvementsText = variables.Get<InputField>("改进措施").text;
// 2. 计算各部分的基础分 (这里需要您自定义核心逻辑!)
float effectivenessScore = EvaluateEffectiveness(effectivenessText);
float problemsScore = EvaluateProblems(problemsText);
float improvementsScore = EvaluateImprovements(improvementsText);
// 3. 综合计算 (加权平均)
// 公式:达成率 = 成效分*权重 - 问题分*权重 + 改进分*权重
// 注意:问题通常是扣分项,所以用减号
float compositeScore = (effectivenessScore * weightEffectiveness)
- (problemsScore * weightProblems)
+ (improvementsScore * weightImprovements);
// 4. 将分数限制在0-1范围内并转换为百分比
float achievementRate = Mathf.Clamp01(compositeScore) * 100f;
// 5. 更新UI显示
variables.Get<InputField>("达成率").text = $"{achievementRate:F1}%";
Debug.Log($"计算完成:成效{effectivenessScore:F2}, 问题{problemsScore:F2}, 改进{improvementsScore:F2} -> 达成率{achievementRate:F1}%");
}
// --- 以下是需要您根据业务逻辑自定义的评分方法 ---
/// <summary>
/// 评估“任务成效”文本
/// </summary>
private float EvaluateEffectiveness(string text)
{
if (string.IsNullOrWhiteSpace(text))
return 0.2f; // 没填,给个低基础分
// **示例1: 长度粗略评估**
// float score = Mathf.Clamp01(text.Length / 100f); // 假设100字为满分
// **示例2: 关键词匹配 (需在Awake/Start中初始化关键词列表)**
float score = 0f;
string[] positiveKeywords = { "完成", "优秀", "达标", "超出预期", "顺利" ,"很好", "非常好", "非常棒","及时","有效","显著"};
foreach (var keyword in positiveKeywords)
{
if (text.Contains(keyword)) score += 0.1f;
}
score = Mathf.Clamp01(score);
//// **示例3: 查找自评分数 (如“评分8/10”)**
//float score = 0f;
//Regex regex = new Regex(@"(\d+)\s*\/\s*10"); // 匹配 "8/10" 格式
//Match match = regex.Match(text);
//if (match.Success && float.TryParse(match.Groups[1].Value, out float userScore))
//{
// score = userScore / 10f; // 转化为0-1分
//}
//else
//{
// // 如果没有找到自评,使用简单的长度评估作为后备
// score = Mathf.Clamp01(text.Length / 200f);
//}
return Mathf.Clamp01(score); // 确保返回0-1
}
/// <summary>
/// 评估“存在问题”文本 (通常为扣分项)
/// </summary>
private float EvaluateProblems(string text)
{
if (string.IsNullOrWhiteSpace(text))
return 0f; // 没问题填写,不扣分
// 问题越严重、描述越详细,扣分越多
float penaltyScore = 0f;
string[] severeKeywords = { "严重", "失败", "未完成", "阻碍", "错误" };
string[] mediumKeywords = { "不足", "困难", "延迟", "小问题" };
foreach (var kw in severeKeywords)
{
if (text.Contains(kw)) penaltyScore += 0.3f;
}
foreach (var kw in mediumKeywords)
{
if (text.Contains(kw)) penaltyScore += 0.1f;
}
// 也考虑文本长度,描述越详细可能问题越具体
penaltyScore += Mathf.Clamp01(text.Length / 300f) * 0.5f;
return Mathf.Clamp01(penaltyScore); // 返回0-1的扣分程度
}
/// <summary>
/// 评估“改进措施”文本
/// </summary>
private float EvaluateImprovements(string text)
{
if (string.IsNullOrWhiteSpace(text))
return 0f; // 没写改进措施,不加分
// 改进措施越具体、可执行性越高,加分越多
float bonusScore = 0f;
string[] actionableKeywords = { "将", "计划", "步骤", "方案", "优化", "加强" };
foreach (var kw in actionableKeywords)
{
if (text.Contains(kw)) bonusScore += 0.15f;
}
// 措施描述的详细程度也加分
bonusScore += Mathf.Clamp01(text.Length / 150f) * 0.4f;
return Mathf.Clamp01(bonusScore);
}
#endregion
#region
/// <summary>
/// 显示警告信息
/// </summary>
/// <param name="warmingText"></param>
private 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(2f);
variables.Get<Text>("警告文本").text = "";
variables.Get<RectTransform>("警告").gameObject.Deactivate();
typingCoroutine = null;
}
#endregion
}