<?php
|
include_once "/Common/CommFunc.php";
|
include_once "/Common/Logging.php";
|
include_once "/Account/User.php";
|
include_once "/language/lang.php";
|
|
|
$Permission = \User\Permission::P_Chatmonitor;
|
$spid = $_SESSION['spid'];
|
$user = new \User\User($_SESSION['UserAccount']);
|
if (!$user->HavePermission($Permission)) {
|
exit;
|
}
|
|
\CommFunc\GetConfig("Chatmonitor", "SocketHost", $address);
|
\CommFunc\GetConfig("Chatmonitor", "SocketPort", $port);
|
if ($address == "0.0.0.0" || $address == "127.0.0.1" || $address == "localhost") {
|
$address = $_SERVER["SERVER_NAME"];
|
}
|
|
$wordFile0 = "chatmonitor/word_" . $spid . "_0.txt";
|
$wordFile1 = "chatmonitor/word_" . $spid . "_1.txt";
|
$words0 = \CommFunc\GetFileContents($wordFile0);
|
$words1 = \CommFunc\GetFileContents($wordFile1);
|
$SensitiveWords = array(
|
explode(",", $words0),
|
explode(",", $words1)
|
);
|
|
?>
|
|
<!DOCTYPE HTML>
|
<html>
|
|
<head>
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
<title><?php echo \Lang\gettext("聊天监控"), " - ", $spid; ?></title>
|
<link rel="gettext" type="application/x-po" href="../language/<?php echo \Lang\getLang(); ?>/LC_MESSAGES/<?php echo \Lang\getjspodomain(); ?>.po" />
|
<style>
|
html,
|
body {
|
height: 100%;
|
overflow: hidden;
|
}
|
|
.container {
|
display: flex;
|
height: 100%;
|
flex-direction: column;
|
}
|
|
.top {
|
height: 35px;
|
}
|
|
.middle {
|
flex: 1;
|
overflow: auto;
|
}
|
|
.word0 {
|
background-color: red;
|
/* color: blue; */
|
}
|
|
.word1 {
|
background-color: yellow;
|
/* color: blue; */
|
}
|
</style>
|
</head>
|
|
<body>
|
|
<div class="container">
|
<div class="top">
|
<input type="button" value="<?php echo \Lang\gettext("清屏"); ?>" onclick="clearChatContent()" />
|
<input type="button" id="scrolling" value="<?php echo \Lang\gettext("暂停滚屏"); ?>" onclick="changescrolling()" />
|
<input type="button" value="<?php echo \Lang\gettext("敏感词管理"); ?>" onclick="doopen('chatwordmgr.php');" />
|
<span class="word0"><?php echo \Lang\gettext("超级敏感词样式"); ?></span>
|
<span class="word1"><?php echo \Lang\gettext("普通敏感词样式"); ?></span>
|
<br />
|
<hr />
|
</div>
|
<div class="middle">
|
<div id="chatContent"></div>
|
<span id="msgbottom" style="overflow:hidden"></span>
|
</div>
|
</div>
|
|
</body>
|
|
<script type='text/javascript' src="/js/common.js"></script>
|
<script type="text/javascript">
|
var linkType = 1; // 连接方式: 0-默认使用socket;1-长轮询
|
var lastChat = {};
|
var errorCount = 0;
|
var address = "<?php echo $address ?>";
|
var port = "<?php echo $port ?>";
|
var spid = "<?php echo $spid ?>";
|
var SensitiveWords = <?php echo json_encode($SensitiveWords) ?>;
|
var HeartbeatInterval = 2000; //心跳,同时也是拉数据频率
|
var ReconnectInterval = 10000; //重连频率,10秒
|
var lockReconnect = false; //避免重复连接
|
var ws;
|
var tt;
|
var recmsg = "";
|
//-------------------------
|
var msgbottom = document.getElementById('msgbottom'); //隐藏在消息框下面的元素
|
var scrolling = 1; //自动滚屏,默认开启
|
|
window.onload = function() {
|
if (linkType == 0) {
|
createWebSocket();
|
} else {
|
requestChatContent();
|
}
|
}
|
|
function sleep(ms) {
|
return new Promise(resolve => setTimeout(resolve, ms));
|
}
|
|
function requestChatContent() {
|
// console.log("requestChatContent", spid, lastChat);
|
var params = "spid=" + spid;
|
if (lastChat.AccountID) {
|
params += "&AccountID=" + lastChat.AccountID + "&Time=" + lastChat.Time + "&Content=" + lastChat.Content;
|
}
|
ajaxRequest("chatmonitors2.php?" + params,
|
function(xmlhttp) {
|
var sleepSeconds = 1;
|
if (xmlhttp.responseText) {
|
try {
|
var parseData = JSON.parse(xmlhttp.responseText);
|
// console.log(parseData);
|
switch (parseData.MsgType) {
|
case "CHAT":
|
addChatContent(parseData.Msg);
|
break;
|
default:
|
break;
|
}
|
} catch (error) {
|
errorCount += 1;
|
console.error("error:", errorCount, error);
|
// 每错一次多暂停1秒,最高暂停1分钟
|
sleepSeconds = Math.min(errorCount, 60);
|
}
|
}
|
sleep(sleepSeconds * 1000).then(() => {
|
requestChatContent();
|
});
|
}, "POST"
|
);
|
}
|
|
|
// 更新敏感词
|
function updSensitiveWord(words) {
|
SensitiveWords = words;
|
}
|
|
function clearChatContent() {
|
var chatContent = document.getElementById("chatContent");
|
chatContent.innerHTML = "";
|
}
|
|
function changescrolling() {
|
if (scrolling == 1) {
|
scrolling = 0;
|
document.getElementById("scrolling").value = "<?php echo \Lang\gettext("继续滚屏"); ?>";
|
} else {
|
scrolling = 1;
|
document.getElementById("scrolling").value = "<?php echo \Lang\gettext("暂停滚屏"); ?>";
|
scrollTobottom();
|
}
|
}
|
|
function scrollTobottom() {
|
if (scrolling != 1) {
|
return;
|
}
|
msgbottom.scrollIntoView(false); //通过调用隐藏元素的scrollIntoView()方法使其可见
|
}
|
|
function addLogContent(html) {
|
var timestr = (new Date()).toLocaleString();
|
var chatContent = document.getElementById("chatContent");
|
chatContent.insertAdjacentHTML("beforeEnd", timestr + " " + html + "<br/>");
|
scrollTobottom();
|
}
|
|
function addChatContent(chatList) {
|
// console.log('增加聊天内容:', chatList);
|
var chatContent = document.getElementById("chatContent");
|
for (let index = 0; index < chatList.length; index++) {
|
const chat = chatList[index];
|
let html = "";
|
if (chat.OperatorID != spid) {
|
continue;
|
}
|
lastChat = chat;
|
// 替换敏感词样式
|
let content = chat.Content;
|
for (let i = 0; i < SensitiveWords.length; i++) {
|
const words = SensitiveWords[i];
|
for (let j = 0; j < words.length; j++) {
|
const word = words[j];
|
if (!word || content.indexOf(word) == -1) {
|
continue;
|
}
|
content = content.replace(new RegExp(word, "gm"), "<span class='word" + i + "'>" + word + "</span>");
|
// replaceAll 某些浏览器不兼容
|
// content = content.replaceAll(word, "<span class='word" + i + "'>" + word + "</span>");
|
}
|
}
|
accID = chat.AccountID + "@" + spid + "@" + chat.RegionName;
|
html += chat.Time + "【" + chat.ChatChannel + "】" + chat.RegionName + " ";
|
html += "<span title='" + accID + "'>" + chat.RoleID + "</span>";
|
if (chat.ToRoleID) {
|
html += " to " + chat.ToRoleID;
|
}
|
html += " : " + content;
|
chatContent.insertAdjacentHTML("beforeEnd", html + "<br/>");
|
}
|
scrollTobottom();
|
}
|
|
function createWebSocket() {
|
try {
|
addLogContent('<?php echo \Lang\gettext("开始连接监控服务器"); ?>');
|
var url = "ws://" + address + ":" + port;
|
console.log(url);
|
ws = new WebSocket("ws://" + address + ":" + port);
|
init();
|
} catch (e) {
|
console.log('catch');
|
reconnect();
|
}
|
}
|
|
function init() {
|
ws.onclose = function() {
|
addLogContent('<?php echo \Lang\gettext("与监控服务器连接关闭"); ?>');
|
// console.log('连接关闭');
|
reconnect();
|
};
|
ws.onerror = function() {
|
addLogContent('<?php echo \Lang\gettext("与监控服务器连接发生异常"); ?>');
|
// console.log('连接发生异常了');
|
reconnect();
|
};
|
ws.onopen = function() {
|
addLogContent('<?php echo \Lang\gettext("与监控服务器连接成功"); ?>');
|
// console.log('连接onopen', spid);
|
sendMsg("SPID", spid);
|
//心跳检测重置
|
heartCheck.start();
|
};
|
ws.onmessage = function(event) {
|
heartCheck.start(); //拿到任何消息都说明当前连接是正常的
|
// console.log('收到消息:', event.data);
|
recmsg += event.data;
|
if (!recmsg.endsWith("#end#")) {
|
return;
|
}
|
try {
|
// 处理完成消息
|
recmsg = recmsg.slice(0, -5);
|
// console.log('完整消息:', recmsg);
|
let parseData = JSON.parse(recmsg);
|
// console.log('处理消息:', parseData);
|
switch (parseData.MsgType) {
|
case "CHAT":
|
addChatContent(parseData.Msg);
|
break;
|
default:
|
break;
|
}
|
} catch (error) {}
|
recmsg = "";
|
}
|
}
|
|
function reconnect() {
|
if (lockReconnect) {
|
return;
|
};
|
lockReconnect = true;
|
//没连接上会一直重连,设置延迟避免请求过多
|
tt && clearTimeout(tt);
|
tt = setTimeout(function() {
|
console.log('reconnect');
|
createWebSocket();
|
lockReconnect = false;
|
}, ReconnectInterval);
|
}
|
|
//心跳检测
|
var heartCheck = {
|
timeout: HeartbeatInterval,
|
timeoutObj: null,
|
serverTimeoutObj: null,
|
start: function() {
|
// console.log('start');
|
var self = this;
|
this.timeoutObj && clearTimeout(this.timeoutObj);
|
this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);
|
this.timeoutObj = setTimeout(function() {
|
//这里发送一个心跳,后端收到后,返回一个心跳消息,
|
//onmessage拿到返回的心跳就说明连接正常
|
sendMsg("HEARTBEAT", {
|
"spid": spid
|
})
|
self.serverTimeoutObj = setTimeout(function() {
|
ws.close();
|
// createWebSocket();
|
}, 10000); //等待10秒,服务器没回应则视为断开
|
|
}, this.timeout)
|
}
|
}
|
|
function sendMsg(msgType, msg) {
|
if (ws.readyState != 1) {
|
return;
|
}
|
ws.send(JSON.stringify({
|
MsgType: msgType,
|
Msg: msg
|
}))
|
};
|
|
/**
|
*0:未连接
|
*1:连接成功,可通讯
|
*2:正在关闭
|
*3:连接已关闭或无法打开
|
*/
|
function sockState() {
|
var status = ['未连接', '连接成功,可通讯', '正在关闭', '连接已关闭或无法打开'];
|
return status[ws.readyState];
|
}
|
</script>
|
|
</html>
|