2026-07-06 22:18:28 +08:00
|
|
|
|
using Assets.MyGame.Scripts.Net;
|
2026-07-08 20:49:22 +08:00
|
|
|
|
using Assets.MyGame.Scripts.Net.APIResponses.Customer_SubClass;
|
2026-04-15 18:30:37 +08:00
|
|
|
|
using Assets.MyGame.Scripts.Net.WebResponses;
|
|
|
|
|
|
using System;
|
2026-04-14 18:30:34 +08:00
|
|
|
|
using System.Collections;
|
2025-12-13 18:18:28 +08:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using TMPro;
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
using UnityEngine.UI;
|
|
|
|
|
|
|
2025-12-26 11:15:56 +08:00
|
|
|
|
public class UIHome_BY_ServicePanel : SubUIBase
|
2025-12-13 18:18:28 +08:00
|
|
|
|
{
|
2026-04-14 17:28:32 +08:00
|
|
|
|
public Toggle toggle_DefaultQuestion;
|
|
|
|
|
|
public Toggle toggle_YouChangeIChange;
|
|
|
|
|
|
public Toggle toggle_OnlineService;
|
2026-04-15 18:30:37 +08:00
|
|
|
|
|
|
|
|
|
|
[Header("客服")]
|
|
|
|
|
|
public TMP_InputField tMPInput_Text;
|
2026-07-08 20:49:22 +08:00
|
|
|
|
public DialogItem dialogGreenPrefab;
|
|
|
|
|
|
public DialogItem dialogOrangePrefab;
|
2026-04-15 18:30:37 +08:00
|
|
|
|
public Transform dialogPrefabParent;
|
|
|
|
|
|
public Button btn_SendText;
|
|
|
|
|
|
public string conversationId;
|
2026-07-06 22:18:28 +08:00
|
|
|
|
|
|
|
|
|
|
Dictionary<string, DialogItem> dic_dialogItems = new Dictionary<string, DialogItem>();
|
2026-07-08 20:49:22 +08:00
|
|
|
|
private bool _historyLoaded = false;
|
2026-07-06 22:18:28 +08:00
|
|
|
|
|
2026-08-09 17:57:46 +08:00
|
|
|
|
/// <summary>游客模式下生成的临时用户id(登录界面无user时使用)</summary>
|
|
|
|
|
|
private string _guestUserId;
|
|
|
|
|
|
|
2026-07-06 22:18:28 +08:00
|
|
|
|
// ==================== 生命周期 ====================
|
|
|
|
|
|
|
2026-04-14 18:30:34 +08:00
|
|
|
|
public override void Awake()
|
2025-12-13 18:18:28 +08:00
|
|
|
|
{
|
2026-04-23 17:24:31 +08:00
|
|
|
|
base.Awake();
|
|
|
|
|
|
btn_Close.onClick.RemoveAllListeners();
|
2026-07-06 22:18:28 +08:00
|
|
|
|
btn_Close.onClick.AddListener(() => uIManager.Close(UIPanel.ServicePanel));
|
|
|
|
|
|
|
2026-08-09 17:57:46 +08:00
|
|
|
|
// 游客模式(登录界面无user):生成临时身份
|
|
|
|
|
|
if (GameManager.Instance.user == null)
|
|
|
|
|
|
_guestUserId = Guid.NewGuid().ToString();
|
|
|
|
|
|
|
2026-07-08 20:49:22 +08:00
|
|
|
|
// 连接 Socket(仅收发实时消息,不再 StartConversation)
|
|
|
|
|
|
WebSocketManager.Instance.Connect(SocketType.customer, null);
|
2026-04-15 18:30:37 +08:00
|
|
|
|
|
2026-07-08 20:49:22 +08:00
|
|
|
|
toggle_DefaultQuestion.onValueChanged.AddListener((a) => { if (a) { } });
|
2026-07-06 22:18:28 +08:00
|
|
|
|
btn_SendText.onClick.AddListener(SendMessage);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-08 20:49:22 +08:00
|
|
|
|
protected override void OnShow(object args = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
base.OnShow(args);
|
|
|
|
|
|
|
|
|
|
|
|
// 拉取历史消息(只拉一次)
|
|
|
|
|
|
if (!_historyLoaded)
|
|
|
|
|
|
{
|
|
|
|
|
|
_historyLoaded = true;
|
|
|
|
|
|
LoadHistory();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 加载历史 ====================
|
|
|
|
|
|
|
|
|
|
|
|
private void LoadHistory()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 清空旧气泡
|
|
|
|
|
|
for (int i = dialogPrefabParent.childCount - 1; i >= 0; i--)
|
|
|
|
|
|
Destroy(dialogPrefabParent.GetChild(i).gameObject);
|
|
|
|
|
|
dic_dialogItems.Clear();
|
|
|
|
|
|
|
|
|
|
|
|
APIRequestList.GetMyConversations(list =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (list != null && list.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
var conv = list[0];
|
|
|
|
|
|
conversationId = conv.id;
|
|
|
|
|
|
|
|
|
|
|
|
// 显示历史消息(倒序逐一创建气泡)
|
|
|
|
|
|
if (conv.messages != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var msg in conv.messages)
|
|
|
|
|
|
{
|
|
|
|
|
|
AddHistoryBubble(msg);
|
|
|
|
|
|
}
|
|
|
|
|
|
ScrollToBottom();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void AddHistoryBubble(CustomerMessageInfo msg)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (msg.senderType == 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
var green = Instantiate(dialogGreenPrefab, dialogPrefabParent);
|
|
|
|
|
|
green.showAvatar = true;
|
|
|
|
|
|
green.SetMessage(msg.content);
|
2026-07-09 17:21:18 +08:00
|
|
|
|
if (green.waitMessage != null) green.waitMessage.SetActive(false);
|
2026-07-08 20:49:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
var orange = Instantiate(dialogOrangePrefab, dialogPrefabParent);
|
|
|
|
|
|
orange.showAvatar = false;
|
|
|
|
|
|
orange.SetMessage(msg.content);
|
2026-07-09 17:21:18 +08:00
|
|
|
|
if (orange.waitMessage != null) orange.waitMessage.SetActive(false);
|
2026-07-08 20:49:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== WebSocket 回调 ====================
|
|
|
|
|
|
|
|
|
|
|
|
public void OnMessageReceived(CustomerMessageReceived msg)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 首次消息 → 获取 conversationId
|
|
|
|
|
|
if (string.IsNullOrEmpty(conversationId) && !string.IsNullOrEmpty(msg.conversationId))
|
|
|
|
|
|
conversationId = msg.conversationId;
|
|
|
|
|
|
|
|
|
|
|
|
if (msg.senderType == 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 自己发的消息确认 → 隐藏等待图标
|
|
|
|
|
|
if (!string.IsNullOrEmpty(msg.guid) && dic_dialogItems.TryGetValue(msg.guid, out var item))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (item.waitMessage != null)
|
|
|
|
|
|
item.waitMessage.SetActive(false);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// 客服新消息
|
|
|
|
|
|
var orange = Instantiate(dialogOrangePrefab, dialogPrefabParent);
|
|
|
|
|
|
orange.showAvatar = false;
|
|
|
|
|
|
orange.SetMessage(msg.content);
|
|
|
|
|
|
ScrollToBottom();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void OnConversationStarted(CustomerConversationStartedResult result)
|
|
|
|
|
|
{
|
|
|
|
|
|
conversationId = result.conversation.id;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 发送消息 ====================
|
|
|
|
|
|
|
2026-07-06 22:18:28 +08:00
|
|
|
|
private void SendMessage()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(tMPInput_Text.text.Trim()))
|
|
|
|
|
|
{
|
|
|
|
|
|
UIManager.Instance.ShowBoardError("不能发送空白");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var content = tMPInput_Text.text.Trim();
|
|
|
|
|
|
tMPInput_Text.text = "";
|
|
|
|
|
|
|
2026-07-08 20:49:22 +08:00
|
|
|
|
// 绿色气泡
|
2026-07-06 22:18:28 +08:00
|
|
|
|
var green = Instantiate(dialogGreenPrefab, dialogPrefabParent);
|
|
|
|
|
|
green.showAvatar = true;
|
|
|
|
|
|
green.SetMessage(content);
|
|
|
|
|
|
ScrollToBottom();
|
|
|
|
|
|
|
|
|
|
|
|
string guid = Guid.NewGuid().ToString();
|
2026-08-09 17:57:46 +08:00
|
|
|
|
|
|
|
|
|
|
// 身份选择:有user用真实身份,无user(登录界面游客)用临时guid
|
|
|
|
|
|
string userId, userName;
|
|
|
|
|
|
if (GameManager.Instance.user != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
userId = GameManager.Instance.user.id;
|
|
|
|
|
|
userName = GameManager.Instance.user.BaseInfo.userName;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
userId = _guestUserId;
|
|
|
|
|
|
userName = _guestUserId.Substring(_guestUserId.Length - 6);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-06 22:18:28 +08:00
|
|
|
|
WebSocketSendList.Customer_SendMessage(
|
2026-07-08 20:49:22 +08:00
|
|
|
|
conversationId ?? "", // 首次发传空串,服务端自动创建
|
|
|
|
|
|
1,
|
2026-08-09 17:57:46 +08:00
|
|
|
|
userId,
|
|
|
|
|
|
userName,
|
2026-07-06 22:18:28 +08:00
|
|
|
|
null, 1, content, guid
|
|
|
|
|
|
);
|
|
|
|
|
|
dic_dialogItems[guid] = green;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void OnDestroy()
|
|
|
|
|
|
{
|
2026-07-08 20:49:22 +08:00
|
|
|
|
if (!string.IsNullOrEmpty(conversationId))
|
|
|
|
|
|
WebSocketSendList.Customer_LeaveConversation(conversationId);
|
2026-07-06 22:18:28 +08:00
|
|
|
|
WebSocketManager.Instance.Close(SocketType.customer);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-09 16:59:26 +08:00
|
|
|
|
protected override void OnHide()
|
|
|
|
|
|
{
|
|
|
|
|
|
base.OnHide();
|
|
|
|
|
|
_historyLoaded = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-06 22:18:28 +08:00
|
|
|
|
// ==================== 滚动 ====================
|
2026-04-15 18:30:37 +08:00
|
|
|
|
|
|
|
|
|
|
public void ScrollToBottom()
|
|
|
|
|
|
{
|
|
|
|
|
|
StartCoroutine(ScrollBottomCoroutine());
|
2025-12-13 18:18:28 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-15 18:30:37 +08:00
|
|
|
|
IEnumerator ScrollBottomCoroutine()
|
|
|
|
|
|
{
|
|
|
|
|
|
yield return null;
|
2026-07-06 22:18:28 +08:00
|
|
|
|
yield return null;
|
|
|
|
|
|
yield return null;
|
|
|
|
|
|
var scrollRect = dialogPrefabParent.parent.parent.GetComponent<ScrollRect>();
|
|
|
|
|
|
scrollRect.verticalNormalizedPosition = 0;
|
2026-04-15 18:30:37 +08:00
|
|
|
|
Canvas.ForceUpdateCanvases();
|
2026-07-06 22:18:28 +08:00
|
|
|
|
scrollRect.verticalNormalizedPosition = 0;
|
2025-12-13 18:18:28 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|