This commit is contained in:
feng0207
2026-08-11 22:22:10 +08:00
commit 5e312c1266
6985 changed files with 1061169 additions and 0 deletions
+41
View File
@@ -0,0 +1,41 @@
import apiSetting from './apiSetting.js';
import login from './apiModel/login.js';
import message from './apiModel/message.js';
import userProgAdministration from "./apiModel/userProgAdministration.js";
import statistics from './apiModel/statistics.js';
import personalCenter from './apiModel/personalCenter.js';
const api = {
...login,
// 聊天列表
...message,
// 客户管理
...userProgAdministration,
// 统计
...statistics,
// 个人中心
...personalCenter
}
if (process.env.NODE_ENV === 'production') {
Object.keys(api).forEach((item) => {
// api[item]['url'] = apiSetting.productionApiUrl + '/api/' + api[item]['url'];
api[item]['url'] = '/api/' + api[item]['url'];
});
} else {
Object.keys(api).forEach((item) => {
// api[item]['url'] = apiSetting.developeApiUrl + '/api/'+ api[item]['url'];
if (api[item]['url'].indexOf('/api/') === -1) {
api[item]['url'] = '/api/' + api[item]['url'];
}
});
}
export default api;
+27
View File
@@ -0,0 +1,27 @@
const api = {
// 客服登录
login: {
url: 'kefu/login',
method: 'post',
loading: true,
noAuth: true
},
// 退出登录
userLogout: {
url: 'kefu/user/logout',
method: 'post'
},
// 发送CID
userClient: {
url: 'kefu/user/client',
method: 'put'
},
// 授权登录
serviceCode: {
url: 'kefu/service/code',
method: 'post'
}
}
export default api;
+106
View File
@@ -0,0 +1,106 @@
// 聊天界面接口
const customerServer = {
pingNetWork:{
url:'kefu/service/ping',
noAuth:true,
method:'get',
timeout:1000
},
kefuServiceList: {
url: 'kefu/service/list',
method: 'get'
},
getSendId: {
url: 'kefu/service/get_send_id',
method: 'get'
},
sendMessage:{
url: 'kefu/service/send_message',
method: 'post'
},
// 获取转接客服列表
serviceTransferList: {
url: 'kefu/service/transfer_list',
method: 'get'
},
// 确认转接
serviceTransfer: {
url: 'kefu/service/transfer',
method: 'post'
},
// 查询客服话术
serviceSpeechcraft: {
url: 'kefu/service/speechcraft',
method: 'get'
},
// 获取话术分类
kefuServiceCate: {
url: 'kefu/service/cate',
method: 'get'
},
// 添加话术
postServiceSpeechcraft: {
url: 'kefu/service/speechcraft',
method: 'post'
},
// 修改话术
putServiceSpeechcraft: {
url: 'kefu/service/speechcraft',
method: 'put',
queryKey: ['id']
},
// 删除话术
deleteServiceSpeechcraft: {
url: 'kefu/service/speechcraft',
method: 'delete',
queryKey: ['id'],
canNotInputQuery: true
},
// 修改分组
putServiceCate: {
url: 'kefu/service/cate',
method: 'put',
queryKey: ['id']
},
// 删除分组
deleteServiceCate: {
url: 'kefu/service/cate',
method: 'delete',
queryKey: ['id']
}
}
const api = {
// 获取客户列表
userList: {
url: 'kefu/user/list',
method: 'get'
},
// 获取聊过天的用户
userRecord: {
url: 'kefu/user/record',
method: 'get'
},
// 获取客服未读条数
userCount: {
url: 'kefu/user/count',
method: 'get'
},
// 获取所有聊天消息id
userRecordAll: {
url: 'kefu/user/recordAll',
method: 'get'
},
// 删除聊天列表用户
deleteUserRecord: {
url: 'kefu/user/record',
method: 'delete',
queryKey: ['id']
},
...customerServer
};
export default api;
@@ -0,0 +1,44 @@
const api = {
// 获取当前登录客服信息
userUserInfo: {
url: 'kefu/user/userInfo',
method: 'get'
},
// 上传头像
kefuUploadAvatar: {
url: 'kefu/upload',
method: 'post',
form: true
},
// 确认信息修改
putKefuUserUserInfo: {
url: 'kefu/user/userInfo',
method: 'put'
},
// 客服信息反馈
userFeedback: {
url: 'kefu/user/feedback',
method: 'post'
},
// 获取投诉列表
userComplain: {
url: 'kefu/user/complain',
method: 'get'
},
// 保存客户投诉
postUserComplain: {
url: 'kefu/user/complain',
method: 'post'
},
// 拉黑用户
putUserStatus: {
url: 'kefu/user/status',
method: 'put',
queryKey: ['userId']
},
appVersion: {
url: 'kefu/version',
method:'post'
}
};
export default api;
+13
View File
@@ -0,0 +1,13 @@
const api = {
// 客户统计
statisticsAll: {
url: 'kefu/statistics/all',
method: 'get'
},
// 获取当前客服统计
statisticsIndex: {
url: 'kefu/statistics/index',
method: 'get'
}
};
export default api;
@@ -0,0 +1,105 @@
const api = {
// 客户列表
userList: {
url: 'kefu/user/list',
method: 'get'
},
// 客户全部标签
userLabe: {
url: 'kefu/user/label/all',
method: 'get'
},
// 客户已有标签,带有选中标识
userLabelSelect: {
url: 'kefu/user/label',
method: 'get'
},
// 设置用户标签
putUserLabel: {
url: 'kefu/user/label',
method: 'put',
queryKey: ['userId']
},
// 客户详细信息
userInfo: {
url: 'kefu/user/info',
method: 'get',
queryKey: ['user_id'],
canInputQuery: true // 有此选项时,并且值为true,代表可以在url上不可以携带参数
},
// 用户分组
UserGroup: {
url: 'kefu/user/group',
method: 'get'
},
// 设置用户分组
setUserGroup: {
url: 'kefu/user/group',
method: 'put',
queryKey: ['userId', 'id'],
canInputQuery: true
},
// 修改用户信息
userUpdateUser: {
url: 'kefu/user/updateUser',
method: 'put',
queryKey: ['userId']
},
// 删除单个用户标签
deleteUserLabel: {
url: 'kefu/user/label',
method: 'delete',
queryKey: ['userId', 'labelId'],
canInputQuery: true
},
// 添加分组
serviceCate: {
url: 'kefu/service/cate',
method: 'post'
},
userAgreement: {
url: 'kefu/agreement',
method: 'get',
noAuth: true
},
getAuthReply: {
url: 'kefu/service/auth_reply',
method: 'get'
},
saveAuthReply: {
url: 'kefu/service/auth_reply',
method: 'post',
queryKey: ['id'],
},
deleteAuthReply: {
url: 'kefu/service/auth_reply',
method: 'delete',
queryKey: ['id'],
canInputQuery: true
},
putAuthReply: {
url: 'kefu/service/auth_reply',
method: 'put',
queryKey: ['value'],
},
// 获取当前登录客服信息
kefuInfoApi: {
url: 'kefu/user/userInfo',
method: 'get',
},
savelog: {
url: 'kefu/user/savelog',
method: 'post'
},
setKefubackstage: {
url: 'kefu/service/backstage',
method: 'put',
queryKey: ['value'],
}
}
export default api;
+13
View File
@@ -0,0 +1,13 @@
import { cache } from 'pages/utils/uniApi.js';
const setting = {
// developeApiUrl: 'http://chat.lfmn.fun',
developeApiUrl: `${cache.get('requestFile')}://${cache.get('dominName')}`,
productionApiUrl: `${cache.get('requestFile')}://${cache.get('dominName')}`,
// productionApiUrl: location.origin + '/api' : '',
wsUrlDevelop: `${cache.get('wsFile')}://${cache.get('dominName')}/`,
wsUrlProduction: `${cache.get('wsFile')}://${cache.get('dominName')}/`,
// wsUrlProduction: `ws:${location.hostname}`
}
export default setting;
+136
View File
@@ -0,0 +1,136 @@
import {
Loading,
hideLoading,
Toast,
navigateTo,
cache
} from 'pages/utils/uniApi.js';
import apiHttp from 'pages/api/api.js';
import store from '../../store/index.js';
//检测是否去登录
async function toLogin() {
if (!store.state.token) {
if (cache.get('accountData')) {
let res = await http(apiHttp.login, cache.get('accountData'));
if (res.token) {
cache.set('userData', res);
cache.remove('pages_login');
store.commit('setToken', res.token);
return false;
}
}
if (!cache.get('pages_login')) {
navigateTo(3, '/pages/view/login/index');
}
return true;
}
return false;
}
function getHttpUrl() {
let requestFile = cache.get('requestFile');
let dominName = cache.get('dominName');
return `${cache.get('requestFile')}://${cache.get('dominName')}`;
}
//检测并执行去设置域名
function checkHttpUrl() {
let requestFile = cache.get('requestFile');
let dominName = cache.get('dominName');
let res = !!requestFile && !!dominName;
if (!res) {
cache.remove('pages_dominName');
if (!cache.get('pages_dominName')) {
navigateTo(1, '/pages/view/dominName/index');
}
}
return res;
}
function http(api, data, base) {
let baseUrl = getHttpUrl();
let url = (base ? base : baseUrl) + api.url;
// 是否在url上挂载单独参数时,也可以传输数据 eg: /api/{12}/ false 代表可传输,true 代表不可传输
let canNotInputQuery = api.canNotInputQuery ? api.canNotInputQuery : false
if (api.queryKey instanceof Array && api.queryKey.length) {
url += api.queryKey.map(item => `/${data[item]}`).join('')
}
let post_data = {
url: url,
data: api.canNotInputQuery ? '' : data,
header: {
'content-type': api.form ? 'application/x-www-form-urlencoded' : 'application/json',
'Authori-zation': 'Bearer ' + store.state.token
},
method: api.method.toUpperCase(),
timeout: api.timeout || 3000,
}
return new Promise(async (reslove, reject) => {
//检测域名是否存在
if (!checkHttpUrl()) {
return reject({
msg: '域名填写错误, 请核实并修改域名'
})
}
if (api.loading) {
Loading();
}
//检测是否登录
if (api.noAuth === undefined && await toLogin()) {
return reject({
msg: '请登录'
})
}
uni.request({
...post_data,
success: (data) => {
switch (data.data.status) {
case 200:
reslove(data.data.data);
break;
case 400:
Toast(data.data.msg)
reject(data.data);
break;
case 410003:
// token失效后,自动登录
if (cache.get('accountData')) {
http(apiHttp.login, cache.get('accountData')).then(res => {
cache.set('userData', res);
store.commit('setToken', res.token);
}).catch(res => {
if (!cache.get('pages_login')) {
navigateTo(2, '/pages/view/login/index');
}
})
} else {
if (!cache.get('pages_login')) {
navigateTo(2, '/pages/view/login/index');
}
}
break;
default:
Toast(data.data.msg)
reject(data.data);
break;
}
},
fail: (rej) => {
reject(rej);
},
complete: () => {
if (api.loading) {
hideLoading();
}
}
});
})
}
export default http;
+59
View File
@@ -0,0 +1,59 @@
import http from '@/pages/api/index.js'
import api from '@/pages/api/api.js'
export function onNetworkStatusChange(onlineFun, offlineFun) {
//#ifdef H5
function addHandler(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent("on" + type, handler);
} else {
element["on" + type] = handler;
}
}
addHandler(window, 'online', () => {
onlineFun()
})
addHandler(window, 'offline', () => {
offlineFun()
});
//#endif
//#ifdef APP-PLUS
uni.onNetworkStatusChange(res => {
if (res.networkType != 'none') {
onlineFun(res);
} else {
offlineFun(res);
}
});
//#endif
}
let NetWork = null;
export function onNetworkStatusChangeV2(onlineFun, offlineFun) {
if (NetWork) {
clearInterval(NetWork);
NetWork = null;
}
let online = null,
offline = null;
NetWork = setInterval(() => {
http(api.pingNetWork).then(() => {
if (online === null) {
onlineFun();
online = true;
}
offline = null;
}).catch(() => {
if (offline === null) {
offlineFun();
offline = true;
}
online = null;
})
}, 1000);
}
+259
View File
@@ -0,0 +1,259 @@
import apiSetting from './apiSetting.js';
import {
cache
} from 'pages/utils/uniApi.js';
import store from '@/store';
import {
onNetworkStatusChange,
onNetworkStatusChangeV2
} from './network.js'
class Socket {
constructor() {
this.socketTask = null; //socket 任务
this.timer = null; //心跳定时器
this.connectStatus = false; //连接状态
this.wsUrl = ''; //ws地址
this.reconnectTimer = 2000; //重连
this.handClse = false; //手动关闭
this.reconnetime = null; //重连 定时器
this.networkStatus = true;
this.connectLing = false; //连接是否进行中
this.defaultEvenv(); //执行默认事件
}
//网络状态变化监听
networkEvent() {
onNetworkStatusChange(() => {
console.log('有网了')
this.networkStatus = true;
uni.$on('timeout', this.timeoutEvent.bind(this))
}, () => {
console.log('断网了')
this.networkStatus = false;
this.connectStatus = false;
clearInterval(this.timer);
this.timer = null;
this.socketTask && this.socketTask.close();
});
}
//开始连接
startConnect() {
console.log('开始链接')
this.networkEvent();
this.handClse = false;
if (!this.connectStatus) {
this.init();
this.connect();
}
}
//默认事件
defaultEvenv() {
uni.$off('success', this.successEvent);
uni.$off('timeout', this.timeoutEvent)
uni.$off('recored', this.recoredEvent);
uni.$off('online', this.onlineEvent);
uni.$on('success', this.successEvent.bind(this));
uni.$on('timeout', this.timeoutEvent.bind(this))
uni.$on('recored', this.recoredEvent.bind(this));
uni.$on('online', this.onlineEvent.bind(this));
}
messageListEvent() {
}
timeoutEvent() {
this.reconne();
}
recoredEvent(data) {
store.commit('setChatInfo', data);
}
successEvent() {
console.log('success默认事件');
this.changOnline();
this.openLaterEvent()
}
onlineEvent(data) {
store.commit('setChatOnline', data);
}
//发送用户状态
changOnline() {
let online = cache.get('kefu_online')
if (online !== undefined && online !== '') {
this.send({
data: {
online: online
},
type: 'online'
});
}
}
//打开连接后的事件
openLaterEvent() {
if (store.state.chatList) {
Object.keys(store.state.chatList).map(item => {
store.state.chatList[item].map(value => {
this.send({
type: 'chat',
data: {
msn: value.msn,
type: value.msn_type,
to_user_id: value.to_user_id,
guid: value.guid
}
}).then(() => {
store.commit('delChatList', {
id: item,
guid: value.guid
})
})
})
})
}
}
//连接websocket
connect() {
this.connectLing = true;
this.socketTask = uni.connectSocket({
url: this.wsUrl,
complete: () => {}
});
this.socketTask.onOpen(this.onOpen.bind(this))
this.socketTask.onError(this.onError.bind(this));
this.socketTask.onMessage(this.onMessage.bind(this))
this.socketTask.onClose(this.onClose.bind(this));
}
init() {
let wsUrl = `${cache.get('wsFile')}://${cache.get('dominName')}/ws`
wsUrl += `?type=kefu&app=1`
this.wsUrl = `${wsUrl}&token=${store.state.token}&form=app&client_id=${cache.get('cid')}`
}
onOpen() {
clearInterval(this.reconnetime);
this.reconnetime = null;
this.connectLing = false;
this.connectStatus = true;
this.ping();
}
onError(error) {
console.log('连接发生错误', error)
this.connectStatus = false;
this.connectLing = false;
this.reconne();
}
//断线重连
reconne() {
if (this.reconnetime || this.connectStatus) {
return;
}
this.reconnetime = setInterval(() => {
if (this.connectStatus) {
return;
}
this.connectLing || this.connect();
}, this.reconnectTimer);
}
onClose() {
console.log('关闭连接')
uni.$emit('close');
//手动关闭不用重新连接
if (this.handClse) {
return;
}
clearInterval(this.timer);
this.timer = null;
this.connectStatus = false;
this.connectLing = false;
this.reconne();
}
ping() {
this.timer = setInterval(() => {
this.send({
type: 'ping'
})
}, 10000)
}
onMessage(response) {
let {
type,
data
} = JSON.parse(response.data);
// console.log(type, data);
uni.$emit(type, data);
}
send(data) {
let that = this;
//没有网络,或者没有连接
if (!this.connectStatus || !this.networkStatus) {
this.reconne();
}
return new Promise((reslove, reject) => {
this.socketTask.send({
data: JSON.stringify(data),
success() {
reslove();
},
fail(res) {
console.log(res)
if (res.errMsg ==
'sendSocketMessage:fail WebSocket is not connected' ||
res.errMsg ==
'sendSocketMessage:fail Error: SocketTask.readyState is not OPEN'
) {
that.reconne();
}
reject(res);
},
complete(res) {
console.log(res)
}
})
});
}
guid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0,
v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
clearPing() {
clearInterval(this.timer);
this.timer = null;
if (this.connectStatus) {
this.socketTask.close();
}
this.handClse = true;
this.connectStatus = false;
this.connectLing = false;
}
setBadgeNumber(count) {
//#ifdef APP-PLUS
plus.runtime.setBadgeNumber(Number(count));
//#endif
}
}
export default Socket;