615 lines
19 KiB
C#
615 lines
19 KiB
C#
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using Unity.VisualScripting;
|
||
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
using AFeijia.UI;
|
||
using TMPro;
|
||
using System;
|
||
using System.IO;
|
||
using UnityEditor;
|
||
using Newtonsoft.Json;
|
||
|
||
public class TrainingManager : UITool
|
||
{
|
||
public static TrainingManager Instance;
|
||
/// <summary>
|
||
/// 已选择的选项
|
||
/// Key:设备信息(名称或者id);Value:选项信息(选项图片id)
|
||
/// </summary>
|
||
[Manual]
|
||
public static Dictionary<string, string> SelectedDeviceOption = new Dictionary<string, string>();
|
||
/// <summary>
|
||
/// 当前选中的设备
|
||
/// </summary>
|
||
[Manual]
|
||
public string CurrentDevice;
|
||
|
||
/// <summary>
|
||
/// 选择对应模型标题
|
||
/// </summary>
|
||
public RectTransform SelectModelTittle;
|
||
/// <summary>
|
||
/// 提交按钮
|
||
/// </summary>
|
||
public Button TrainingSubmit;
|
||
/// <summary>
|
||
/// 训练成绩返回按钮
|
||
/// </summary>
|
||
public Button TrainingScoreBack;
|
||
/// <summary>
|
||
/// 当前是否停留在成绩页面
|
||
/// </summary>
|
||
[Manual]
|
||
public bool IsScorePage;
|
||
/// <summary>
|
||
/// 事件值
|
||
/// </summary>
|
||
public TextMeshProUGUI TimeValue;
|
||
/// <summary>
|
||
/// 正确值
|
||
/// </summary>
|
||
public TextMeshProUGUI CorretValue;
|
||
/// <summary>
|
||
/// 错误值
|
||
/// </summary>
|
||
public TextMeshProUGUI WrongValue;
|
||
|
||
#region 练习UI
|
||
|
||
/// <summary>
|
||
/// 练习设备选项容器
|
||
/// </summary>
|
||
public RectTransform TrainingOptionsContent;
|
||
/// <summary>
|
||
/// 练习设备选项预制体
|
||
/// </summary>
|
||
[Manual]
|
||
public TrainingDeviceItem TrainingDeviceItemPrefab;
|
||
/// <summary>
|
||
/// 练习设备选项列表
|
||
/// </summary>
|
||
[Manual]
|
||
public List<TrainingDeviceItem> TrainingDeviceItemList = new List<TrainingDeviceItem>();
|
||
|
||
/// <summary>
|
||
/// 练习结果容器
|
||
/// </summary>
|
||
public RectTransform TrainingScoreContent;
|
||
/// <summary>
|
||
/// 练习结果预制体
|
||
/// </summary>
|
||
[Manual]
|
||
public TrainingScoreItem TrainingScoreItemPrefab;
|
||
/// <summary>
|
||
/// 训练结果项列表
|
||
/// </summary>
|
||
[Manual]
|
||
public List<TrainingScoreItem> TrainingScoreItemList = new List<TrainingScoreItem>();
|
||
|
||
#endregion
|
||
|
||
#region 练习界面
|
||
|
||
/// <summary>
|
||
/// 练习选项界面
|
||
/// </summary>
|
||
public RectTransform TrainingOptions;
|
||
/// <summary>
|
||
/// 练习分数界面
|
||
/// </summary>
|
||
public RectTransform TrainingScore;
|
||
#endregion
|
||
|
||
#region 考核模式
|
||
/// <summary>
|
||
/// 考核模式部分UI元素
|
||
/// </summary>
|
||
public RectTransform ExaminationElements;
|
||
/// <summary>
|
||
/// 交卷
|
||
/// </summary>
|
||
public Button ExaminationSubmit;
|
||
/// <summary>
|
||
/// 剩余时间
|
||
/// </summary>
|
||
public TextMeshProUGUI RemainingTime;
|
||
/// <summary>
|
||
/// 总时间(秒)
|
||
/// </summary>
|
||
[Manual]
|
||
public int TotalSeconds = 60;
|
||
/// <summary>
|
||
/// 计时器协程
|
||
/// </summary>
|
||
[Manual]
|
||
private Coroutine TimerCoroutine;
|
||
/// <summary>
|
||
/// 退出计时
|
||
/// </summary>
|
||
public TextMeshProUGUI TimerClock;
|
||
/// <summary>
|
||
/// 计时提示文本
|
||
/// </summary>
|
||
public TextMeshProUGUI TimerQuit;
|
||
/// <summary>
|
||
/// 考试结束标题
|
||
/// </summary>
|
||
public TextMeshProUGUI ExamEndTittle;
|
||
/// <summary>
|
||
/// 圆环
|
||
/// </summary>
|
||
public Image ClockRing;
|
||
/// <summary>
|
||
/// 考核退出界面
|
||
/// </summary>
|
||
public RectTransform ExaminationQuit;
|
||
#endregion
|
||
|
||
public bool IsTutorial;
|
||
|
||
protected override void Awake()
|
||
{
|
||
base.Awake();
|
||
Instance = this;
|
||
}
|
||
|
||
private void Start()
|
||
{
|
||
TrainingSubmit.onClick.AddListener(OnTrainingSubmit);
|
||
TrainingScoreBack.onClick.AddListener(OnTrainingBack);
|
||
|
||
ExaminationSubmit.onClick.AddListener(() =>
|
||
{
|
||
OnExaminationSubmit(true);
|
||
});
|
||
#region 本地无数据测试
|
||
Debug.Log("本地测试生成练习选项");
|
||
TrainingDeviceItemPrefab = Resources.Load<TrainingDeviceItem>("Prefabs/UI/TrainingDeviceItem");
|
||
//for (int i = 0; i < 30; i++)
|
||
//{
|
||
// var inst = Instantiate(TrainingDeviceItemPrefab, TrainingOptionsContent);
|
||
// inst.Init(new TrainingDeviceData { id = i.ToString() });
|
||
|
||
// TrainingDeviceItemList.Add(inst);
|
||
//}
|
||
#endregion
|
||
InterfaceManager.GetLocalFiles(Application.streamingAssetsPath + "/结构认知图", (_files) =>
|
||
{
|
||
for (int i = 0; i < _files.Count; i++)
|
||
{
|
||
var _directory = Path.GetFileNameWithoutExtension(_files[i].DirectoryName);
|
||
if (!PictureDic.ContainsKey(_directory))
|
||
{
|
||
PictureDic.Add(_directory, new List<string>() { _files[i].FullName });
|
||
}
|
||
else
|
||
{
|
||
PictureDic[_directory].Add(_files[i].FullName);
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
#region 训练模式内容
|
||
|
||
/// <summary>
|
||
/// 提交训练结果
|
||
/// </summary>
|
||
private void OnTrainingSubmit()
|
||
{
|
||
//隐藏设备列表
|
||
CanvasMain.Instance.DeviceListRoot.gameObject.SetActive(false);
|
||
//隐藏设备选项
|
||
TrainingOptions.gameObject.SetActive(false);
|
||
//展示练习结果
|
||
TrainingScore.gameObject.SetActive(true);
|
||
//隐藏提交按钮
|
||
TrainingSubmit.gameObject.SetActive(false);
|
||
//隐藏标题
|
||
SelectModelTittle.gameObject.SetActive(false);
|
||
//根据设备列表数据和选择内容生成练习结果
|
||
|
||
int trueCount = 0; int falseCount = 0;
|
||
if (TrainingScoreItemPrefab == null)
|
||
TrainingScoreItemPrefab = Resources.Load<TrainingScoreItem>("Prefabs/UI/TrainingScoreItem");
|
||
for (int i = 0; i < DeviceItem.DeviceItemsList.Count; i++)
|
||
{
|
||
var inst = Instantiate(TrainingScoreItemPrefab, TrainingScoreContent);
|
||
var istrue = inst.Init(i + 1, DeviceItem.DeviceItemsList[i].DevicesItemData);
|
||
if (istrue)
|
||
trueCount++;
|
||
else
|
||
falseCount++;
|
||
TrainingScoreItemList.Add(inst);
|
||
}
|
||
MainCoroutine.Instance.StopTimer();
|
||
|
||
//计算时间、得分数量、错误数量
|
||
TimeValue.text = MainCoroutine.Instance.cost_time;
|
||
CorretValue.text = trueCount + "题";
|
||
WrongValue.text = falseCount + "题";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 训练结果返回
|
||
/// </summary>
|
||
private void OnTrainingBack()
|
||
{
|
||
//显示设备列表
|
||
CanvasMain.Instance.DeviceListRoot.gameObject.SetActive(true);
|
||
//隐藏设备选项
|
||
TrainingOptions.gameObject.SetActive(true);
|
||
//展示练习结果
|
||
TrainingScore.gameObject.SetActive(false);
|
||
//显示提交按钮
|
||
TrainingSubmit.gameObject.SetActive(true);
|
||
//显示标题
|
||
SelectModelTittle.gameObject.SetActive(true);
|
||
//清空上次训练选项
|
||
SelectedDeviceOption.Clear();
|
||
//清除已选中的状态
|
||
if (TrainingDeviceItem.SelectedItem != null)
|
||
{
|
||
TrainingDeviceItem.SelectedItem.SetSelectStatus(selected: false, force: true);
|
||
}
|
||
//清除上一次的训练结果
|
||
for (int i = 0; i < TrainingScoreItemList.Count; i++)
|
||
{
|
||
Destroy(TrainingScoreItemList[i].gameObject);
|
||
}
|
||
TrainingScoreItemList.Clear();
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 公共
|
||
/// <summary>
|
||
/// 当前设备改变
|
||
/// </summary>
|
||
/// <param name="_device_item"></param>
|
||
public static void ChangeDevice(DeviceItem _device_item)
|
||
{
|
||
Instance.CurrentDevice = _device_item.DevicesItemData.dev_name;
|
||
|
||
//当设备改变时,先清除已选中的状态
|
||
if (TrainingDeviceItem.SelectedItem != null)
|
||
{
|
||
TrainingDeviceItem.SelectedItem.SetSelectStatus(selected: false, force: true);
|
||
}
|
||
|
||
if (!SelectedDeviceOption.ContainsKey(_device_item.DevicesItemData.dev_name))
|
||
{
|
||
SelectedDeviceOption.Add(_device_item.DevicesItemData.dev_name, "");
|
||
}
|
||
else
|
||
{
|
||
var selected = TrainingDeviceItem.TrainingDeviceItemList.Find(x => x.TrainingDeviceData.id.Equals(SelectedDeviceOption[_device_item.DevicesItemData.dev_name]));
|
||
if (selected != null)
|
||
{
|
||
selected.SetSelectStatus(selected: true, force: true);
|
||
}
|
||
}
|
||
|
||
Instance.Init(_device_item);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新选项值
|
||
/// </summary>
|
||
public void UpdateSelectItem(string _selected_id)
|
||
{
|
||
SelectedDeviceOption[CurrentDevice] = _selected_id;
|
||
}
|
||
#endregion
|
||
|
||
#region 考核模式内容
|
||
|
||
/// <summary>
|
||
/// 切换考核模式
|
||
/// </summary>
|
||
public void SwitchExaminationMode()
|
||
{
|
||
//改变界面元素
|
||
TrainingSubmit.gameObject.SetActive(false);
|
||
ExaminationElements.gameObject.SetActive(true);
|
||
//开始倒计时
|
||
TimerCoroutine = StartCoroutine(Timer(OnExaminationSubmit));
|
||
|
||
//StartCoroutine()
|
||
}
|
||
|
||
/// <summary>
|
||
/// 交卷
|
||
/// </summary>
|
||
/// <param name="tips"> 是否进行二次确认 </param>
|
||
private void OnExaminationSubmit(bool tips)
|
||
{
|
||
if (tips)
|
||
{
|
||
//二次确认
|
||
TipsPanel.Instance.Tips("提示", "确定要交卷吗?", (submit) =>
|
||
{
|
||
if (submit)
|
||
{
|
||
//显示正在提交面板
|
||
TipsPanel.Instance.WaitingSubmit(true);
|
||
try
|
||
{
|
||
//手动交卷确认时,停止倒计时
|
||
StopCoroutine(TimerCoroutine);
|
||
//提交成绩
|
||
OnSubmitScore((_error, _data) =>
|
||
{
|
||
TipsPanel.Instance.WaitingSubmit(false);
|
||
if (!string.IsNullOrEmpty(_error))
|
||
{
|
||
TipsPanel.Instance.ForceTips("ERROR_1", _error, (submit) =>
|
||
{
|
||
|
||
});
|
||
}
|
||
else
|
||
{
|
||
//隐藏其他
|
||
//设备列表
|
||
CanvasMain.Instance.DeviceListRoot.gameObject.SetActive(false);
|
||
//设备选项
|
||
TrainingOptions.gameObject.SetActive(false);
|
||
//提交按钮、考核倒计时
|
||
ExaminationElements.gameObject.SetActive(false);
|
||
|
||
_submited = true;
|
||
//倒计时并退出
|
||
ExaminationQuit.gameObject.SetActive(true);
|
||
StartCoroutine(ExitTimer(() =>
|
||
{
|
||
Debug.Log("退出!");
|
||
Application.Quit();
|
||
}));
|
||
}
|
||
});
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Debug.LogException(ex);
|
||
TipsPanel.Instance.WaitingSubmit(false);
|
||
TipsPanel.Instance.ForceTips("ERROR_2", ex.ToString(), (submit) =>
|
||
{
|
||
|
||
});
|
||
}
|
||
}
|
||
else
|
||
{
|
||
|
||
}
|
||
});
|
||
}
|
||
else
|
||
{
|
||
//显示正在提交面板
|
||
TipsPanel.Instance.WaitingSubmit(true);
|
||
TipsPanel.Instance.WaitingText("考试时间到,正在自动交卷...");
|
||
try
|
||
{
|
||
//提交成绩
|
||
OnSubmitScore((_error, _data) =>
|
||
{
|
||
TipsPanel.Instance.WaitingSubmit(false);
|
||
if (!string.IsNullOrEmpty(_error))
|
||
{
|
||
TipsPanel.Instance.ForceTips("ERROR", _error, (submit) =>
|
||
{
|
||
|
||
});
|
||
}
|
||
else
|
||
{
|
||
//隐藏其他
|
||
//设备列表
|
||
CanvasMain.Instance.DeviceListRoot.gameObject.SetActive(false);
|
||
//设备选项
|
||
TrainingOptions.gameObject.SetActive(false);
|
||
//提交按钮、考核倒计时
|
||
ExaminationElements.gameObject.SetActive(false);
|
||
|
||
_submited = true;
|
||
//倒计时并退出
|
||
ExaminationQuit.gameObject.SetActive(true);
|
||
//变更标题
|
||
ExamEndTittle.text = "考试时间到,已自动交卷,请离开考场";
|
||
StartCoroutine(ExitTimer(() =>
|
||
{
|
||
Debug.Log("退出!");
|
||
Application.Quit();
|
||
}));
|
||
}
|
||
});
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Debug.LogException(ex);
|
||
TipsPanel.Instance.WaitingSubmit(false);
|
||
TipsPanel.Instance.ForceTips("ERROR_2", ex.ToString(), (submit) =>
|
||
{
|
||
|
||
});
|
||
}
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 考试总花费的时间
|
||
/// </summary>
|
||
int cost_time = 0;
|
||
/// <summary>
|
||
/// 考核总时间倒计时
|
||
/// </summary>
|
||
/// <param name="callback"></param>
|
||
/// <returns></returns>
|
||
private IEnumerator Timer(Action<bool> callback)
|
||
{
|
||
int t = (int)GameInit.InfoIni.user_time * 60;
|
||
while (t > 0)
|
||
{
|
||
RemainingTime.text = string.Format("{0:D2}:{1:D2}:{2:D2}", t / 3600, t % 3600 / 60, t % 3600 % 60);
|
||
t--;
|
||
cost_time++;
|
||
yield return new WaitForSeconds(1);
|
||
}
|
||
//考试限时结束,自动交卷
|
||
Debug.Log("考试限时结束,自动交卷");
|
||
callback?.Invoke(false);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 自动退出倒计时
|
||
/// </summary>
|
||
/// <param name="callback"></param>
|
||
/// <returns></returns>
|
||
private IEnumerator ExitTimer(Action callback)
|
||
{
|
||
yield return new WaitUntil(() => _submited == true);
|
||
int t = 10;
|
||
float c = 0;
|
||
TimerClock.text = t.ToString();
|
||
TimerQuit.text = t + "秒后自动退出系统";
|
||
while (t > 0)
|
||
{
|
||
c++;
|
||
if (c == 10)
|
||
{
|
||
t--;
|
||
c = 0;
|
||
TimerClock.text = t.ToString();
|
||
TimerQuit.text = t + "秒后自动退出系统";
|
||
}
|
||
ClockRing.fillAmount -= 0.01f;
|
||
yield return new WaitForSeconds(0.1f);
|
||
}
|
||
|
||
yield return new WaitForSeconds(0.5f);
|
||
callback?.Invoke();
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 读取信息
|
||
|
||
/// <summary>
|
||
/// Key:设备名称;Value:图片地址列表
|
||
/// </summary>
|
||
public Dictionary<string, List<string>> PictureDic = new Dictionary<string, List<string>>();
|
||
/// <summary>
|
||
/// Key:图片地址;Value:精灵
|
||
/// </summary>
|
||
public Dictionary<string, Sprite> Sprites = new Dictionary<string, Sprite>();
|
||
|
||
/// <summary>
|
||
/// 初始化
|
||
/// </summary>
|
||
/// <param name="_device_item"></param>
|
||
public void Init(DeviceItem _device_item)
|
||
{
|
||
if (_device_item == null)
|
||
{
|
||
return;
|
||
}
|
||
if (PictureDic.ContainsKey(_device_item.DevicesItemData.dev_name))
|
||
{
|
||
var _pics = PictureDic[_device_item.DevicesItemData.dev_name];
|
||
for (int i = 0; i < _pics.Count; i++)
|
||
{
|
||
var _id = Path.GetFileNameWithoutExtension(_pics[i]);
|
||
TrainingDeviceItem _inst;
|
||
if (TrainingDeviceItemList.Count > i)
|
||
{
|
||
_inst = TrainingDeviceItemList[i];
|
||
}
|
||
else
|
||
{
|
||
_inst = Instantiate(TrainingDeviceItemPrefab, TrainingOptionsContent);
|
||
TrainingDeviceItemList.Add(_inst);
|
||
}
|
||
|
||
if (Sprites.ContainsKey(_pics[i]))
|
||
{
|
||
var _uuid = System.Guid.NewGuid().ToString();
|
||
var _sprite = Sprites[_pics[i]];
|
||
_inst.Init(new TrainingDeviceData { id = _id, uuid = _uuid }, _sprite);
|
||
_inst.gameObject.SetActive(true);
|
||
}
|
||
else
|
||
{
|
||
var _url = _pics[i];
|
||
StartCoroutine(InterfaceManager.GetSprite(_url, (_sp) =>
|
||
{
|
||
Sprites.Add(_url, _sp);
|
||
_inst.Init(new TrainingDeviceData { id = _id }, _sp);
|
||
_inst.gameObject.SetActive(true);
|
||
}));
|
||
}
|
||
}
|
||
|
||
if (_pics.Count < TrainingDeviceItemList.Count)
|
||
{
|
||
for (int i = _pics.Count; i < TrainingDeviceItemList.Count; i++)
|
||
{
|
||
TrainingDeviceItemList[i].gameObject.SetActive(false);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Debug.Log($"[{_device_item.DevicesItemData.dev_name}]不存在!");
|
||
}
|
||
}
|
||
|
||
//是否完成提交
|
||
bool _submited = false;
|
||
/// <summary>
|
||
/// 提交当前内容
|
||
/// </summary>
|
||
/// <param name="_callback"></param>
|
||
private void OnSubmitScore(Action<string, string> _callback)
|
||
{
|
||
var _post_url = InterfaceManager.IpAddress + InterfaceManager.API_DIC["SUBMIT"];
|
||
|
||
List<StepListItem> stepListItems = new List<StepListItem>();
|
||
|
||
for (int i = 0; i < CanvasMain.Instance.ExamContents.Count; i++)
|
||
{
|
||
StepListItem _step = new StepListItem();
|
||
_step.stepName = CanvasMain.Instance.ExamContents[i].step;
|
||
_step.testPoint = CanvasMain.Instance.ExamContents[i].point;
|
||
|
||
DeviceItem device = DeviceItem.DeviceItemsList.Find(x => x.DevicesItemData.dev_name == CanvasMain.Instance.ExamContents[i].device);
|
||
|
||
_step.score = SelectedDeviceOption.ContainsKey(CanvasMain.Instance.ExamContents[i].device)
|
||
? (SelectedDeviceOption[CanvasMain.Instance.ExamContents[i].device] == device.DevicesItemData.pic_id
|
||
? float.Parse(CanvasMain.Instance.ExamContents[i].score) : 0)
|
||
: 0;
|
||
stepListItems.Add(_step);
|
||
|
||
_step.setScore = float.Parse(CanvasMain.Instance.ExamContents[i].score);
|
||
}
|
||
|
||
ScoreInfo _score_info = new ScoreInfo()
|
||
{
|
||
userName = GameInit.InfoIni.user_name,
|
||
userId = GameInit.InfoIni.user_id,
|
||
examId = GameInit.InfoIni.exam_id,
|
||
classId = GameInit.InfoIni.class_id,
|
||
useTime = cost_time.ToString(),
|
||
examClassId = GameInit.InfoIni.exam_class_id,
|
||
stepList = stepListItems
|
||
};
|
||
|
||
var _json_str = JsonConvert.SerializeObject(_score_info);
|
||
|
||
StartCoroutine(InterfaceManager.Post(_post_url, _json_str, _callback));
|
||
}
|
||
|
||
#endregion
|
||
}
|