修复滚动条big
This commit is contained in:
@ -226,10 +226,8 @@ const ChatInput = ((props) => {
|
||||
let msgList = []
|
||||
let newmsg = sendMsg && sendMsg.length>0 ?sendMsg : lodash.cloneDeep(msg);
|
||||
newmsg.map((item)=>{
|
||||
const randomNum = Math.floor(Math.random() * 1000)
|
||||
//const date = dayjs().unix()
|
||||
const date = new Date()
|
||||
const encryption = doEncrypt(`${date}${randomNum}`) //有无更快的加密方法,可以加密图片?这个加密方法加密图片太慢!
|
||||
const encryption = doEncrypt(Math.floor(Math.random() * 1000)+(new Date()).getTime()) //有无更快的加密方法,可以加密图片?这个加密方法加密图片太慢!
|
||||
//console.log('加密生成完毕')
|
||||
let msgData = null
|
||||
if(item.type=='text'){
|
||||
@ -279,12 +277,8 @@ const ChatInput = ((props) => {
|
||||
//发送文件
|
||||
const sendFileHandle = (msg) => {
|
||||
let msgList = []
|
||||
|
||||
const randomNum = Math.floor(Math.random() * 1000)
|
||||
//const date = dayjs().unix()
|
||||
const date = new Date()
|
||||
const encryption = doEncrypt(`${date}${randomNum}`) //有无更快的加密方法,可以加密图片?这个加密方法加密图片太慢!
|
||||
//console.log('加密生成完毕')
|
||||
const encryption = doEncrypt(Math.floor(Math.random() * 1000)+(new Date()).getTime()) //有无更快的加密方法,可以加密图片?这个加密方法加密图片太慢!
|
||||
const msgData = {
|
||||
_id: encryption,
|
||||
date: date,
|
||||
|
@ -26,43 +26,43 @@ const ScrollWrapper = (Comp) => (props) => {
|
||||
const [shadowStyle, setShadowStyle] = useState('')
|
||||
|
||||
let { data, viewH, scrollToBottom, switchFlag, style, isMove, isModalVisible, loading, } = this? this.props : props
|
||||
//let data = props.data
|
||||
const scrollHandle = () => {
|
||||
|
||||
const scrollHandle = () => {
|
||||
if (scrollView.current) {
|
||||
setScrollT(scrollView.current.scrollTop)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const mouseUpHandle = () => {
|
||||
const mouseUpHandle = (e) => {
|
||||
setIsPressing(false)
|
||||
}
|
||||
}
|
||||
|
||||
const mouseDownHandle = () => {
|
||||
const mouseDownHandle = (e) => {
|
||||
setIsPressing(true)
|
||||
}
|
||||
}
|
||||
|
||||
const mouseMovingHandle = (e) => {
|
||||
const mouseMovingHandle = (e) => {
|
||||
e.persist()
|
||||
if (isPressing !== true) return
|
||||
if (scrollT < 0) {
|
||||
setScrollT(0)
|
||||
} else if (scrollT > scrollH - viewPortH) {
|
||||
setScrollT(scrollH - viewPortH)
|
||||
} else {
|
||||
setScrollT((preScrollT) => preScrollT + e.movementY / scrollR) //e.nativeEvent.movementY
|
||||
}
|
||||
setScrollT((preScrollT) => preScrollT + e.movementY / scrollR)
|
||||
}
|
||||
}
|
||||
|
||||
const thumbHeight = () => viewPortH * scrollR
|
||||
const thumbHeight = () => viewPortH * scrollR
|
||||
|
||||
const transH = () => scrollT * scrollR
|
||||
const transH = () => scrollT * scrollR
|
||||
|
||||
useEffect(() => {
|
||||
useEffect(() => {
|
||||
addEventListener('mouseup', mouseUpHandle)
|
||||
|
||||
return () => {
|
||||
removeEventListener('mouseup', mouseUpHandle)
|
||||
}
|
||||
}, [])
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if(isModalVisible){
|
||||
@ -110,13 +110,14 @@ let { data, viewH, scrollToBottom, switchFlag, style, isMove, isModalVisible, lo
|
||||
return (
|
||||
<section
|
||||
style={style}
|
||||
className={cns([styles.customer_service_content_wrapper_content, shadowStyle])}
|
||||
className={cns([styles.customer_service_wrapper_content, shadowStyle])}
|
||||
id={isMove?"section":""}
|
||||
>
|
||||
<div
|
||||
className={styles.list_block}
|
||||
ref={scrollView}
|
||||
onScroll={scrollHandle}>
|
||||
onScroll={scrollHandle}
|
||||
>
|
||||
{useMemo(() => <Comp {...props} />, [data, loading, style])}
|
||||
</div>
|
||||
<aside
|
||||
@ -124,6 +125,7 @@ let { data, viewH, scrollToBottom, switchFlag, style, isMove, isModalVisible, lo
|
||||
style={{ width: showScrollBar ? 5 : 0 }}>
|
||||
<span
|
||||
ref={thumb}
|
||||
datatype="thumb"
|
||||
className={cns([styles.scroll_thumb])}
|
||||
onMouseDown={mouseDownHandle}
|
||||
onMouseMove={mouseMovingHandle}
|
||||
|
@ -1,12 +1,8 @@
|
||||
@import '../../style/common.css';
|
||||
|
||||
.customer_service_content_wrapper_content {
|
||||
.customer_service_wrapper_content {
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
border-top: solid 1px rgb(226, 226, 226);
|
||||
border-bottom: solid 1px rgb(226, 226, 226);
|
||||
}
|
||||
.customer_service_content_wrapper_content .list_block {
|
||||
.customer_service_wrapper_content .list_block {
|
||||
flex: auto;
|
||||
overflow: auto;
|
||||
overflow-x: hidden;
|
||||
@ -14,10 +10,10 @@
|
||||
-ms-overflow-style: none; /* IE 10+ */
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.customer_service_content_wrapper_content .list_block::-webkit-scrollbar {
|
||||
.customer_service_wrapper_content .list_block::-webkit-scrollbar {
|
||||
display: none; /* Chrome Safari */
|
||||
}
|
||||
.customer_service_content_wrapper_content .scroll_bar_block {
|
||||
.customer_service_wrapper_content .scroll_bar_block {
|
||||
width: 8px;
|
||||
/* border-radius: 4px; */
|
||||
overflow: hidden;
|
||||
@ -25,25 +21,25 @@
|
||||
box-sizing: border-box;
|
||||
background-color: rgb(231,229,229);
|
||||
}
|
||||
.customer_service_content_wrapper_content .scroll_bar_block:hover {
|
||||
.customer_service_wrapper_content .scroll_bar_block:hover {
|
||||
background-color: #eee;
|
||||
}
|
||||
.customer_service_content_wrapper_content .scroll_thumb {
|
||||
.customer_service_wrapper_content .scroll_thumb {
|
||||
display: block;
|
||||
width: 100%;
|
||||
background-color: #aaa;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.customer_service_content_wrapper_content .scroll_thumb:hover {
|
||||
.customer_service_wrapper_content .scroll_thumb:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
.customer_service_content_wrapper_content .shadow_top {
|
||||
.customer_service_wrapper_content .shadow_top {
|
||||
box-shadow: inset 0px 5px 10px -5px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
.customer_service_content_wrapper_content .shadow_bottom {
|
||||
.customer_service_wrapper_content .shadow_bottom {
|
||||
box-shadow: inset 0px -5px 10px -5px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
.customer_service_content_wrapper_content .shadow_vertical {
|
||||
.customer_service_wrapper_content .shadow_vertical {
|
||||
box-shadow: inset 0px 5px 10px -5px rgba(0, 0, 0, 0.2),
|
||||
inset 0px -5px 10px -5px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import React, { useState, useEffect, useRef } from 'react'
|
||||
import Chat from './components/Chat/Chat'
|
||||
import ImgPreview from './components/ImgPreview/ImgPreview'
|
||||
import SeactList from './components/SeactList'
|
||||
import {entitiestoUtf16, handleElement } from './utils/utils'
|
||||
import {entitiestoUtf16, handleElement, doEncrypt } from './utils/utils'
|
||||
import user from '@/assets/img/cs_user.png'
|
||||
import client from '@/assets/img/cs_client.png'
|
||||
import { customerserviceAPI as API} from '@/services/customerservice';
|
||||
@ -12,6 +12,35 @@ import { connect } from 'dva'
|
||||
import { disconnect } from 'echarts'
|
||||
import { history } from 'umi'
|
||||
|
||||
//未读消息提醒
|
||||
window.messageAlert = {
|
||||
timeout: null,
|
||||
oldTitle:'招投标系统',
|
||||
time: 0,
|
||||
num: 0,
|
||||
showMessage(msg){
|
||||
window.messageAlert.num++;
|
||||
if(window.messageAlert.num==1){
|
||||
window.messageAlert.timeout = setInterval(function(){
|
||||
window.messageAlert.time ++;
|
||||
let title = '';
|
||||
if(messageAlert.time % 2 === 0){
|
||||
title = '[ ]我的咨询';
|
||||
}else{
|
||||
title = '['+msg+']我的咨询';
|
||||
}
|
||||
document.getElementsByTagName('title')[0].innerText = title;
|
||||
},500);
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
stopMessage(){
|
||||
document.getElementsByTagName('title')[0].innerText = window.messageAlert.oldTitle;
|
||||
window.messageAlert.num = 0;
|
||||
clearInterval(window.messageAlert.timeout);
|
||||
}
|
||||
};
|
||||
const conversation = (props) => {
|
||||
const [msgList, setMsgList] = useState([])
|
||||
const [scrollToBottom, setScrollToBottom] = useState(true)
|
||||
@ -53,6 +82,54 @@ const conversation = (props) => {
|
||||
|
||||
const {isModalVisible, isCloseWs, closeWin, hideWin, msgAlert, supplierNumber, staffId, staffName, optionsModal, projectModal, closeOptionsModal, closeProjectModal, kfType, questionType, openWin, openProjectWin, roleIds} = props
|
||||
|
||||
document.addEventListener('visibilitychange',()=>{ //监听网页是否失焦
|
||||
var isHidden = document.hidden
|
||||
window.isBlurForCustomerService = isHidden
|
||||
if(!isHidden && (window.isConversationURLChanged==undefined || !window.isConversationURLChanged)){
|
||||
stopMsg()
|
||||
}
|
||||
})
|
||||
//项目信息
|
||||
const onChange = () => {
|
||||
setShowLoading(true)
|
||||
getProject({
|
||||
projectName: queryParams.projectName==undefined? null: queryParams.projectName,
|
||||
});
|
||||
}
|
||||
const getProject = (params)=>{
|
||||
API.list(params).then((res)=>{
|
||||
setShowLoading(false)
|
||||
if(res && res.success && res.data){
|
||||
let data = res.data
|
||||
setProjectData(data)
|
||||
setPagination({
|
||||
showQuickJumper: true,
|
||||
showSizeChanger: false,
|
||||
pageSize: params.pageSize,
|
||||
current: params.pageNum,
|
||||
total: res.data.total,
|
||||
showTotal: total => `共 ${total} 条`,
|
||||
})
|
||||
}else{
|
||||
message.warn(res && res.message)
|
||||
}
|
||||
})
|
||||
}
|
||||
const dataList=[
|
||||
{ label: '项目名称', value: 'projectName', type: 'input', },
|
||||
]
|
||||
const onSearch = (param) => {
|
||||
setQueryParams(param)
|
||||
getProject({
|
||||
projectName: param.projectName,
|
||||
});
|
||||
};
|
||||
const onReset = () => {
|
||||
getProject({
|
||||
projectName: null,
|
||||
});
|
||||
setQueryParams({})
|
||||
}
|
||||
const onMsgRender = ()=>{
|
||||
let serverAvatar = user
|
||||
let data = wsMsg
|
||||
@ -87,7 +164,7 @@ const conversation = (props) => {
|
||||
}
|
||||
}
|
||||
let msgData={
|
||||
_id: Math.floor(Math.random() * 1000)+new Date(),
|
||||
_id: doEncrypt(Math.floor(Math.random() * 1000)+ (new Date()).getTime()),
|
||||
date: new Date(),
|
||||
user: {
|
||||
id: data.serverNo,
|
||||
@ -138,7 +215,7 @@ const conversation = (props) => {
|
||||
}
|
||||
}
|
||||
earlierMsg.push({
|
||||
_id: Math.floor(Math.random() * 1000)+new Date(),
|
||||
_id: doEncrypt(Math.floor(Math.random() * 1000)+ (new Date()).getTime()),
|
||||
date: item.sendingTime,
|
||||
user: {
|
||||
id: item.senderUid,
|
||||
@ -150,8 +227,9 @@ const conversation = (props) => {
|
||||
})
|
||||
|
||||
if(data && data.length>0){
|
||||
if(pageNum==-1){
|
||||
setMsgPage(msgPage+1)
|
||||
|
||||
}
|
||||
let count = earlierMsg.length
|
||||
let arr = [...msgList]
|
||||
while(count>0){
|
||||
@ -164,91 +242,16 @@ const conversation = (props) => {
|
||||
setIsSend(true)
|
||||
}
|
||||
} else {
|
||||
message.warn(res && res.message)
|
||||
//message.warn(res && res.message)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
const onChange = () => {
|
||||
setShowLoading(true)
|
||||
getProject({
|
||||
projectName: queryParams.projectName==undefined? null: queryParams.projectName,
|
||||
});
|
||||
}
|
||||
const getProject = (params)=>{
|
||||
API.list(params).then((res)=>{
|
||||
setShowLoading(false)
|
||||
if(res && res.success && res.data){
|
||||
let data = res.data
|
||||
setProjectData(data)
|
||||
setPagination({
|
||||
showQuickJumper: true,
|
||||
showSizeChanger: false,
|
||||
pageSize: params.pageSize,
|
||||
current: params.pageNum,
|
||||
total: res.data.total,
|
||||
showTotal: total => `共 ${total} 条`,
|
||||
})
|
||||
}else{
|
||||
message.warn(res && res.message)
|
||||
}
|
||||
})
|
||||
}
|
||||
const dataList=[
|
||||
{ label: '项目名称', value: 'projectName', type: 'input', },
|
||||
]
|
||||
const onSearch = (param) => {
|
||||
setQueryParams(param)
|
||||
getProject({
|
||||
projectName: param.projectName,
|
||||
});
|
||||
};
|
||||
const onReset = () => {
|
||||
getProject({
|
||||
projectName: null,
|
||||
});
|
||||
setQueryParams({})
|
||||
}
|
||||
//检验连接websocket
|
||||
const checkWebSocket = ()=>{
|
||||
if(window.isCloseChatUIModal!=undefined){ //弹窗没有关闭(弹窗开着或者隐藏,ws不应该断)
|
||||
if(window.webSocketForCustomerService==undefined){
|
||||
console.log('首次创建websocket')
|
||||
//获取当前用户token
|
||||
getToken()
|
||||
}else{
|
||||
let ws = window.webSocketForCustomerService
|
||||
if(ws){
|
||||
//别的路由切过来,ws没断,重新监听
|
||||
let avatar = client
|
||||
console.log('ws没断,重新监听')
|
||||
setShow(true)
|
||||
monitorWebSocket(ws)
|
||||
setCuruser({
|
||||
id: staffId,
|
||||
name: staffName,
|
||||
avatar: avatar,
|
||||
})
|
||||
setLoading(true)
|
||||
getMoreMessage(1)
|
||||
}else{
|
||||
console.log('websocket断开,重新连接')
|
||||
if(isModalVisible){ //断连后,用户打开弹窗再发提醒
|
||||
setConversationId('')
|
||||
disconnectedAlert()
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
delete window.webSocketForCustomerService //释放websocket对象
|
||||
}
|
||||
}
|
||||
//断开连接提醒
|
||||
const disconnectedAlert = () =>{
|
||||
let serverAvatar = user
|
||||
const msg = {
|
||||
_id: Math.floor(Math.random() * 1000)+new Date(),
|
||||
_id: doEncrypt(Math.floor(Math.random() * 1000)+ (new Date()).getTime()),
|
||||
date: new Date(),
|
||||
user: {
|
||||
id: serverNo,
|
||||
@ -259,17 +262,23 @@ const disconnectedAlert = () =>{
|
||||
}
|
||||
setMsgList([...msgList, msg])
|
||||
}
|
||||
//检验连接websocket
|
||||
const checkDisconnected = ()=>{
|
||||
if(window.isCloseChatUIModal!=undefined){ //弹窗没有关闭(弹窗开着或者隐藏,ws不应该断)
|
||||
console.log('websocket断开,重新连接')
|
||||
if(isModalVisible){ //断连后,用户打开弹窗再发提醒
|
||||
setConversationId('')
|
||||
disconnectedAlert()
|
||||
}
|
||||
}else{
|
||||
setConversationId('')
|
||||
setMsgPage(0)
|
||||
delete window.webSocketForCustomerService //释放websocket对象
|
||||
}
|
||||
}
|
||||
|
||||
//获取当前登录者token
|
||||
const getToken = ()=>{
|
||||
//登录人的信息的关键字 顺序是固定的。
|
||||
let avatar = client
|
||||
//当前用户
|
||||
setCuruser({
|
||||
id: staffId,
|
||||
name: staffName,
|
||||
avatar: avatar,
|
||||
})
|
||||
API.check({
|
||||
clientNo: staffId,
|
||||
supplierNo:kfType==1?'EMPTY':agentNumber
|
||||
@ -278,10 +287,20 @@ const getToken = ()=>{
|
||||
websocketInit(staffId)
|
||||
setLoading(true)
|
||||
getMoreMessage(1)
|
||||
}else{
|
||||
if(window.webSocketForCustomerService!=undefined){
|
||||
//别的路由切过来,ws没断,重新监听
|
||||
console.log('ws没断,重新监听')
|
||||
setShow(true)
|
||||
monitorWebSocket(window.webSocketForCustomerService)
|
||||
setLoading(true)
|
||||
getMoreMessage(1)
|
||||
}else{
|
||||
closeWin && closeWin()
|
||||
delete window.isCloseChatUIModal
|
||||
message.warn(res && '您已在别的终端建立会话')
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
//监听websocket
|
||||
@ -292,34 +311,27 @@ const monitorWebSocket = (ws)=>{
|
||||
//记录ws
|
||||
window.webSocketForCustomerService = ws
|
||||
setShow(true) //连接建立后,才可以显示弹窗、收发消息
|
||||
//else{
|
||||
// //发空消息给websocket
|
||||
// let serverAvatar = user
|
||||
// const msg = {
|
||||
// _id: Math.floor(Math.random() * 1000)+new Date(),
|
||||
// date: new Date(),
|
||||
// user: {
|
||||
// id: serverNo,
|
||||
// avatar: serverAvatar,
|
||||
// name: '供应链客服',
|
||||
// },
|
||||
// message: { type: 'text', content: '您好,欢迎使用供应链客服' },
|
||||
// }
|
||||
// setMsgList([...msgList, msg])
|
||||
// }
|
||||
}
|
||||
// 接收服务端数据时触发事件
|
||||
ws.onmessage = function (res) {
|
||||
if(res.data){
|
||||
let data = JSON.parse(res.data)
|
||||
if(window.isConversationURLChanged){//路由变化
|
||||
window.msgAlertForCustomerService = true
|
||||
showMsg()
|
||||
}else {
|
||||
if(window.isBlurForCustomerService){//失焦
|
||||
showMsg()
|
||||
}
|
||||
setWsMsg(data)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 断开 web socket 连接成功触发事件
|
||||
ws.onclose = function () {
|
||||
console.log("连接已关闭...");
|
||||
checkWebSocket()
|
||||
checkDisconnected()
|
||||
};
|
||||
}
|
||||
/*websocket*/
|
||||
@ -329,6 +341,30 @@ const websocketInit = (id)=>{
|
||||
var ws = new WebSocket(addr+id+'/'+no, [sessionStorage.getItem('Authorization')]);
|
||||
monitorWebSocket(ws)
|
||||
}
|
||||
|
||||
//消息闪烁提醒
|
||||
const showMsg = ()=>{
|
||||
messageAlert.showMessage('新消息');
|
||||
}
|
||||
|
||||
const stopMsg = ()=>{
|
||||
messageAlert.stopMessage('新消息');
|
||||
}
|
||||
|
||||
useEffect(()=>{
|
||||
history.listen(location => {
|
||||
// 最新路由的 location 对象,可以通过比较 pathname 是否相同来判断路由的变化情况
|
||||
let isChanged = location.pathname.indexOf('/Dashboard')==-1
|
||||
if(isChanged){
|
||||
window.isConversationURLChanged = isChanged
|
||||
}else{
|
||||
if(window.isConversationURLChanged != undefined){ //路由切换回来
|
||||
//stopMsg()
|
||||
window.isConversationURLChanged = isChanged
|
||||
}
|
||||
}
|
||||
})
|
||||
},[])
|
||||
useEffect(()=>{
|
||||
if(!isCloseWs){
|
||||
if(window.isCloseChatUIModal==undefined){
|
||||
@ -338,6 +374,15 @@ useEffect(()=>{
|
||||
},[isCloseWs])
|
||||
useEffect(() => {
|
||||
if(isModalVisible){
|
||||
stopMsg()
|
||||
//登录人的信息的关键字 顺序是固定的。
|
||||
let avatar = client
|
||||
//当前用户
|
||||
setCuruser({
|
||||
id: staffId,
|
||||
name: staffName,
|
||||
avatar: avatar,
|
||||
})
|
||||
//恢复初始值
|
||||
chatUI.style.width = wid
|
||||
chatUI.style.height = hei
|
||||
@ -345,8 +390,16 @@ useEffect(() => {
|
||||
chatUI.style.top = (document.documentElement.clientHeight - hei)*0.5 +"px"
|
||||
record.style.height = listHeight + "px"
|
||||
chatInput.style.height = textHeight + "px"
|
||||
checkWebSocket()
|
||||
|
||||
//清空全局变量
|
||||
if(window.isConversationURLChanged!=undefined) delete window.isConversationURLChanged
|
||||
if(window.msgAlertForCustomerService!=undefined) delete window.msgAlertForCustomerService
|
||||
//校验登录
|
||||
getToken()
|
||||
}else{
|
||||
if(window.msgAlertForCustomerService){
|
||||
msgAlert && msgAlert() //侧边栏提醒
|
||||
}
|
||||
setMsgList([])
|
||||
}
|
||||
}, [isModalVisible])
|
||||
@ -363,14 +416,14 @@ useEffect(() => {
|
||||
|
||||
useEffect(() => {
|
||||
//实时渲染消息
|
||||
if(wsMsg && wsMsg.clientNo!=undefined){
|
||||
if((!window.isConversationURLChanged || window.isConversationURLChanged== undefined) && wsMsg && wsMsg.clientNo!=undefined){
|
||||
if(isModalVisible){ //弹窗开着才渲染
|
||||
onMsgRender()
|
||||
}else{
|
||||
msgAlert && msgAlert() //只提醒,不渲染
|
||||
msgAlert && msgAlert() //只提醒
|
||||
}
|
||||
}
|
||||
}, [wsMsg])
|
||||
}, [wsMsg])
|
||||
|
||||
const columns=[
|
||||
{ title: '项目名称', dataIndex: 'projectName', align: 'center', ellipsis:true, width:'40%'},
|
||||
@ -453,7 +506,12 @@ useEffect(() => {
|
||||
setImageParams(imageParams)
|
||||
setIsImgPreviewVisible(true)
|
||||
}}
|
||||
reConnect={()=>websocketInit(staffId)}
|
||||
reConnect={()=>{
|
||||
websocketInit(staffId)
|
||||
setLoading(true)
|
||||
getMoreMessage(1)
|
||||
}
|
||||
}
|
||||
onEarlier={()=>{
|
||||
setLoading(true)
|
||||
setScrollToBottom(false)
|
||||
|
Reference in New Issue
Block a user