$(function(){
var index = 0;
var debug = true; // 生产环境可改为false
var reconnectTimer = null; // 重连定时器
// 1. 自动适配协议的BOSH服务地址(解决HTTPS环境问题)
var protocol = window.location.protocol;
var BOSH_SERVICE = protocol + '//124.71.230.244:7070/http-bind/';
// 2. 获取页面参数(与后端模板配合)
var fromId = $("#from").val();
var password = $("#password").val();
var toId = $("#to").val();
var username = $("#username").val() || "访客";
var customername = $("#customername").val() || username;
// 提取基础URL用于商品/订单链接
var url = window.location.href;
url = url.substring(0, url.indexOf("chat.php"));
// 3. 初始化连接(添加跨域支持参数)
var connection = new Strophe.Connection(BOSH_SERVICE, {
'withCredentials': true, // 允许跨域携带认证信息
'sync': false, // 禁用同步请求避免浏览器限制
'timeout': 30000 // 超时时间30秒
});
/**
* 日志记录函数
*/
Strophe.log = function(level, msg) {
if(debug) $('#log').append('<div></div>').append(document.createTextNode(`[${new Date().toLocaleTimeString()}] ${msg}`));
};
function log(msg) {
if(debug) $('#log').append('<div></div>').append(document.createTextNode(`[${new Date().toLocaleTimeString()}] ${msg}`));
}
/**
* 播放提示音
* @param {Number} type 2-客服消息 3-系统消息
*/
function playSound(type){
if($("#sound").size() == 0){
$("body").append("<div id='sound'></div>");
}
let soundFile = type === 2 ? "sound/msg.wav" : "sound/notice.wav";
let soundHtml = '';
// 兼容不同浏览器
if(navigator.userAgent.indexOf("MSIE 8.0") > -1){
soundHtml = `<embed src="${soundFile}" autostart="true" hidden="true" />`;
}else{
soundHtml = `<audio autoplay="autoplay" hidden="true">
<source src="${soundFile}" type="audio/wav">
</audio>`;
}
$("#sound").html(soundHtml);
}
/**
* 添加消息到聊天窗口
* @param {String} showname 显示名称
* @param {String} message 消息内容
* @param {Number} type 1-用户 2-客服 3-系统
*/
function appendMessage(showname, message, type) {
index++;
var message_id = "message_" + index;
var html = "";
// 选择对应的消息模板
if(type === 1){
html = $("#from_html").html().replace('script_from_id', message_id);
}else if(type === 2){
html = $("#to_html").html().replace('script_to_id', message_id);
}else if(type === 3){
html = $("#notice_html").html().replace('script_notice_id', message_id);
}
$(html).appendTo('.scroll_inner');
// 填充消息内容
if(type === 1 || type === 2){
$("#"+message_id).find(".msg_owner").html(showname);
$("#"+message_id).find(".send_time").html(new Date().toLocaleTimeString());
}
// 处理空消息
if(!message || message.length === 0){
message = "<br>";
}
// 防止XSS攻击
message = message.replace(/</g, '<').replace(/>/g, '>');
// 保留换行
message = message.replace(/\n/g, '<br>');
$("#"+message_id).find(".msg_content").html(`<p>${message}</p>`);
// 滚动到底部
$("#scroll_div").scrollTop($(".scroll_inner").height());
// 播放提示音
playSound(type);
}
/**
* 发送消息
*/
function sendMessage(){
var message = getContent().trim();
if(message.length > 0){
// 创建消息XML
var reply = $msg({
to: toId,
from: fromId,
type: 'chat'
}).cnode(Strophe.xmlElement('body', '', message));
// 发送消息
connection.send(reply.tree());
// 本地显示
appendMessage(username, message, 1);
}
setContent("");
}
/**
* 发送用户状态消息(系统通知)
* @param {String} message 状态消息
*/
function sendUserStatusMessage(message){
var statusMsg = $msg({
to: toId,
from: fromId,
type: 'chat'
}).cnode(Strophe.xmlElement('body', '', message));
connection.send(statusMsg.tree());
}
/**
* 加载历史消息
* @param {String} targetJID 目标用户JID
*/
function loadChatHistory(targetJID) {
if(!targetJID) return;
var historyIQ = $iq({
type: 'get',
id: 'history_' + new Date().getTime()
})
.c('query', {xmlns: 'urn:xmpp:mam:2', with: targetJID})
.c('set', {xmlns: 'http://jabber.org/protocol/rsm'})
.c('max').t('20'); // 加载最近20条
connection.sendIQ(historyIQ,
function(result) {
$(result).find('message').each(function() {
var msg = $(this);
var from = msg.attr('from');
var body = msg.find('body').text();
var timestamp = msg.find('archived').attr('ts');
if (body && timestamp) {
var time = new Date(timestamp).toLocaleTimeString();
var isUser = from === fromId;
var displayName = isUser ? username : from.split('@')[0];
// 临时保存当前index,避免历史消息影响最新消息排序
var tempIndex = index;
appendMessage(displayName, body, isUser ? 1 : 2);
index = tempIndex;
}
});
appendMessage("系统", "历史消息加载完成", 3);
},
function(error) {
console.error("加载历史消息失败:", error);
appendMessage("系统", "无法加载历史消息", 3);
}
);
}
/**
* 开始连接XMPP服务器
*/
function startConnection(){
// 清除现有定时器
if(reconnectTimer) clearTimeout(reconnectTimer);
// 调试日志输出
connection.rawInput = function (data) {
if(debug) log('RECV: ' + data);
};
connection.rawOutput = function (data) {
if(debug) log('SENT: ' + data);
};
// 连接处理
connection.connect(fromId, password, function(status){
switch(status) {
case Strophe.Status.CONNECTING:
appendMessage("系统", '正在连接客服系统...', 3);
break;
case Strophe.Status.CONNFAIL:
appendMessage("系统", '连接失败,5秒后重试...', 3);
// 检测CORS错误
var isCORSError = connection._xmlHttpRequest &&
connection._xmlHttpRequest.status === 0;
if(isCORSError) {
console.error("跨域错误: 请检查OpenFire的CORS配置是否包含 " + window.location.origin);
appendMessage("系统", "跨域配置错误,请联系管理员", 3);
}
// 设置重连
reconnectTimer = setTimeout(startConnection, 5000);
break;
case Strophe.Status.AUTHENTICATING:
if(debug) appendMessage("系统", '正在认证...', 3);
break;
case Strophe.Status.AUTHFAIL:
appendMessage("系统", '认证失败,请刷新页面重新登录', 3);
console.error("认证失败: 用户名或密码错误");
// 通知后端认证失败
$.get('chat.php?act=authfail', function(data){
try {
var res = $.parseJSON(data);
if(res && res.message) {
appendMessage("系统", res.message, 3);
}
} catch(e) {
console.error("解析认证失败响应错误:", e);
}
});
break;
case Strophe.Status.DISCONNECTING:
if(debug) appendMessage("系统", '正在断开连接...', 3);
break;
case Strophe.Status.DISCONNECTED:
appendMessage("系统", '连接已断开,5秒后重试...', 3);
reconnectTimer = setTimeout(startConnection, 5000);
break;
case Strophe.Status.CONNECTED:
appendMessage("系统", '连接成功,正在加载历史消息...', 3);
// 发送在线状态
var presence = $pres()
.c("status").t("在线").up()
.c("priority").t("1");
connection.send(presence.tree());
// 注册消息处理handler
connection.addHandler(function(msg) {
var to = msg.getAttribute('to');
var from = msg.getAttribute('from');
var type = msg.getAttribute('type');
var elems = msg.getElementsByTagName('body');
if (type === "chat" && elems.length > 0) {
// 提取发送者名称
var senderName = from;
if(from.indexOf("@") !== -1){
senderName = from.substring(0, from.indexOf("@"));
}
// 显示消息
var bodyText = Strophe.getText(elems[0]);
appendMessage(senderName, bodyText, 2);
// 更新页面标题提示新消息
document.title = "在线客服聊天:您收到了一条新消息!";
}
return true; // 保持handler有效
}, null, 'message', null, null, null);
// 发送用户接入信息
var joinMessage = `用户【${username}】接入聊天系统!`;
// 添加商品信息
var chatGoodsId = $("#chat_goods_id").val();
if(chatGoodsId.length > 0){
var goodsUrl = url + "goods.php?id=" + chatGoodsId;
joinMessage += "\n正在浏览的商品:" + goodsUrl;
}
// 添加订单信息
var chatOrderId = $("#chat_order_id").val();
if(chatOrderId.length > 0){
joinMessage += "\n可能需要咨询的订单ID:" + chatOrderId;
}
var chatOrderSn = $("#chat_order_sn").val();
if(chatOrderSn.length > 0){
joinMessage += "\n可能需要咨询的订单号:" + chatOrderSn;
}
sendUserStatusMessage(joinMessage);
// 加载历史消息
loadChatHistory(toId);
break;
}
});
}
/**
* 获取输入框内容
*/
function getContent(){
return $.trim($('#editor').val());
}
/**
* 设置输入框内容
* @param {String} msg 要设置的内容
*/
function setContent(msg){
$('#editor').val(msg);
}
/**
* 绑定事件
*/
function bindEvents(){
// 回车发送消息(支持Shift+Enter换行)
$("#editor").keydown(function(e) {
if (e.which === 13 && !e.shiftKey) {
e.preventDefault(); // 阻止默认换行
sendMessage();
}
});
// 发送按钮点击事件
$('#btn_send').click(function(){
sendMessage();
});
// 窗口获得焦点时重置标题
$(window).focus(function() {
document.title = "在线客服聊天";
});
}
/**
* 初始化检查
*/
function initCheck(){
if(!toId || toId.length === 0){
var notice = $("#system_notice").html() || "未指定客服,请刷新页面重试";
appendMessage("系统", notice, 3);
return false;
}
if(!fromId || fromId.length === 0){
appendMessage("系统", "用户信息不完整,请重新登录", 3);
return false;
}
if(!password || password.length === 0){
appendMessage("系统", "认证信息不完整,请重新登录", 3);
return false;
}
return true;
}
// 初始化执行
bindEvents();
if(initCheck()){
startConnection();
}
// 页面关闭时发送离线状态
window.addEventListener('beforeunload', function() {
if(connection.connected) {
var presence = $pres({type: "unavailable"})
.c("status").t("离线");
connection.send(presence.tree());
}
});
}); 客服如何配置 这个
最新发布