提交 563cb74e 编写于 作者: guangjun.yang's avatar guangjun.yang

发送返回等

上级 3e82498e
.current-session-wrap {
.component-content {
display: flex;
flex-direction: row;
min-height: 600px;
min-width: 1200px;
font-size: 14px;
.left {
width: 270px;
// padding: 0 25px 15px;
border-right: 2px solid #f5f5f5;
.l-header {
display: flex;
flex-direction: row;
height: 52px;
justify-content: space-between;
align-items: center;
padding: 0 25px;
& > span:first-child {
font-size: 16px;
}
& > span:last-child {
color: #0d9078;
cursor: pointer;
}
}
.c-num {
padding: 0 25px;
height: 40px;
line-height: 40px;
background: #fffbe6;
}
.session-list {
width: 100%;
height: 100%;
overflow: scroll;
& > .item {
width: 100%;
display: flex;
height: 72px;
flex-direction: row;
align-items: center;
padding: 0 25px;
cursor: pointer;
.img-wrapper {
// position: relative;
// top: 0;
// left: 0;
width: 40px;
height: 40px;
margin-right: 10px;
img {
width: 100%;
height: 100%;
border-radius: 20px;
}
}
& > .desc {
flex: 1;
.top {
display: flex;
flex-direction: row;
justify-content: space-between;
.name {
}
}
.bottom {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
font-size: 12px;
color: #999999;
.num {
display: inline-block;
min-width: 16px;
padding: 2px 4px;
border-radius: 8px;
text-align: center;
color: #ffffff;
background: #ff4d4f;
}
& > img {
display: block;
width: 15px;
height: 15px;
padding: 2px 0 2px 4px;
}
}
}
&.current {
background: #f8f9fa;
}
}
}
}
.center {
flex: 1;
.c-header {
padding: 0 25px;
height: 56px;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
border-bottom: 2px solid #f5f5f5;
& > .c-header-l {
flex: 1;
display: flex;
flex-direction: row;
align-items: center;
& > img {
display: inline-block;
width: 24px;
height: 24px;
border-radius: 12px;
margin-right: 8px;
}
& > .name {
margin-right: 25px;
color: #333333;
}
& > .time-tip {
font-size: 12px;
color: #999999;
}
}
.close-btn {
width: 100px;
color: #c7c8c9;
cursor: pointer;
}
}
.msg-content {
// width: 100%;
// height: 650px;
overflow: scroll;
display: flex;
flex-direction: column;
margin: 10px 20px;
.msg-item {
display: flex;
flex-direction: row;
margin: 12px 0;
.msg-item-img {
width: 44px;
height: 44px;
margin-right: 8px;
& > img {
width: 100%;
height: 100%;
border-radius: 22px;
}
}
.msg-item-detail {
display: flex;
flex-direction: column;
text-align: left;
font-size: 13px;
& > :first-child {
color: #999999;
margin-bottom: 8px;
}
.mid-text-wrapper {
display: flex;
flex-direction: row;
align-items: center;
& > img {
width: 18px;
height: 18px;
margin-right: 8px;
cursor: pointer;
}
}
.mid-text {
padding: 12px 24px;
display: inline-block;
max-width: 520px;
border-radius: 8px;
background: #ebf5fc;
text-align: justify;
color: #333333;
&.no-support {
display: flex;
align-items: center;
& > img {
width: 14px;
height: 14px;
margin-right: 3px;
}
}
}
.link {
color: #2f86f6;
}
& > .mid-pdf {
width: 260px;
display: flex;
flex-direction: row;
justify-content: space-between;
text-align: left;
padding: 10px 15px;
background: #f0f1f2;
border-radius: 8px;
min-height: 80px;
cursor: pointer;
.midp-left {
display: flex;
flex-direction: column;
justify-content: space-around;
margin-right: 10px;
.name {
font-size: 13px;
color: #333333;
word-break: break-word;
}
.size {
font-size: 12px;
color: #999999;
}
}
.midp-icon {
width: 36px;
height: 44px;
& > img {
width: 36px;
height: 100%;
border-radius: 3px;
}
}
}
& > .mid-img {
width: 170px;
height: 108px;
cursor: pointer;
& > img {
width: 100%;
height: 100%;
border-radius: 8px;
}
}
}
&.cr {
flex-direction: row-reverse;
.msg-item-img {
margin-right: 0;
margin-left: 8px;
}
.msg-item-detail {
text-align: right;
& > .mid-text {
background: #f0f1f2;
}
}
}
}
.split-line {
width: 100%;
display: flex;
flex-direction: row;
align-items: center;
margin: 15px 0;
font-size: 14px;
color: #999999;
&::before {
flex: 1;
content: '';
height: 1px;
margin-right: 18px;
background: #f0f1f2;
}
&::after {
flex: 1;
content: '';
height: 1px;
margin-left: 18px;
background: #f0f1f2;
}
}
.error-mg {
display: inline-block;
max-width: 520px;
// height: 24px;
max-width: 520px;
line-height: 16px;
text-align: left;
border-radius: 20px;
opacity: 0.45;
margin: -2px 0 10px;
padding: 4px 12px;
color: #FFFFFF;
background: #000000;
margin-left: 50px;
&.mr {
margin-left: 0;
margin-right: 50px;
}
}
}
.c-bottom {
position: relative;
top: 0;
left: 0;
display: flex;
flex-direction: row;
margin: 16px 12px 16px 25px;
.cb-icon-wrapper {
position: absolute;
top: 0;
right: 70px;
display: flex;
align-items: center;
height: 44px;
img {
width: 20px;
height: 20px;
margin-right: 16px;
cursor: pointer;
}
}
.send-btn {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
width: 60px;
height: 44px;
background: #f3f6f7;
margin-left: 12px;
border-radius: 8px;
cursor: pointer;
& > img {
width: 24px;
height: 24px;
}
&.active {
background: #0d9078;
}
}
}
}
.right {
width: 240px;
border-left: 2px solid #f5f5f5;
}
background: #fff;
.time {
color: #999999;
}
.small {
font-size: 12px;
}
}
}
\ No newline at end of file
<template>
<div class="current-session-wrap">
<bread-crumb :curmbFirst="curmbFirst" :curmbSecond="curmbSecond"></bread-crumb>
<section class="component-content screenSet" id="screenSet">
<article class="left">
<div class="l-header">
<span>我的任务({{this.sessionListData.myTaskCount}})</span>
<span @click="fetchOneTask">再来一个</span>
</div>
<p class="c-num">当前等待会话:{{this.sessionListData.waitingTaskCount}}</p>
<ul class="session-list" :style="{'height': containerHeight + 'px'}">
<li
class="item"
:class="{'current': currentTaskLogId == session.taskLogId}"
v-for="(session, index) in sessionListData.sessionList"
:key="index"
@click="selectSession(session, index)"
>
<div class="img-wrapper">
<img :src="session.avatarImageUrl" alt />
</div>
<div class="desc">
<div class="top">
<span class="name">{{session.toName}}</span>
<span class="time small">{{session.timestampStr}}</span>
</div>
<div class="bottom">
<span>{{session.text | shortName}}</span>
<!-- <span>{{session.lastMsgContent}}</span> -->
<span
v-show="session.status !=3 && currentTaskLogId != session.taskLogId && session.unreadCount"
class="num"
>{{session.unreadCount}}</span>
<img
v-show="session.status == 3"
src="../../../assets/image/IM/icon-exit.png"
@click.stop="closeOneTask(session)"
/>
</div>
</div>
</li>
</ul>
</article>
<article class="center">
<section class="c-header">
<div class="c-header-l">
<img :src="currentSession.avatarImageUrl" alt />
<span class="name">{{doctorInfo.name}}</span>
<span class="time-tip">当前会话时长:{{currentContinueTimes | continueTimesFilter}}</span>
</div>
<!-- <span class="close-btn">结束会话</span> -->
</section>
<p class="refreshText"></p>
<section class="msg-content scroll-box" :style="{'height': (containerHeight - 35) + 'px'}">
<article
class="msg-item"
:class="{'cr': item.sendOrReceive}"
v-for="(item, index) in messageList"
:key="index"
>
<div class="msg-item-img">
<img :src="item.avatarImg" alt />
</div>
<div class="msg-item-detail">
<span class="mid-time">{{item.timestampStr}}</span>
<div v-if="item.showType == 1" class="mid-text-wrapper" style="max-width: 520px;">
<img v-show="item.sendFlag" src="../../../assets/image/IM/icon-no-send.png" alt />
<div class="mid-text">{{item.text}}</div>
</div>
<div v-if="item.showType == 2" class="mid-img" v-viewer>
<img :src="item.url" alt />
<!-- <img :src="item.imgUrl" alt /> -->
</div>
<div v-if="item.showType == 3" class="mid-pdf" @click="openPDF(item)">
<div class="midp-left">
<span class="name">{{item.text}}</span>
<span class="size">{{fileSizeChange(item.size)}}</span>
</div>
<div class="midp-icon">
<img src="../../../assets/image/IM/icon-pdf.png" alt />
</div>
</div>
<div v-if="item.showType == 4" class="mid-text">
{{item.suffix}}
<span class="link">{{item.text}}</span>
</div>
<div v-if="item.showType == 5" class="mid-text no-support">
<img src="../../../assets/image/IM/icon-warning-circle.png" alt />
<span>该消息类型PC端暂不支持</span>
</div>
</div>
</article>
</section>
<section class="c-bottom">
<el-input type="textarea" placeholder="请输入内容" v-model="sendText" maxlength=499></el-input>
<div class="cb-icon-wrapper">
<el-upload
class="bg-uploader"
action="#"
accept=".jpg, .png, .pdf"
:show-file-list="false"
:before-upload="beforeUploadFile"
>
<img src="../../../assets/image/IM/icon-folder-open.png" alt />
</el-upload>
<img src="../../../assets/image/IM/icon-link.png" @click="preSendLinkMsg" alt />
</div>
<div class="send-btn" :class="{'active': canSend}" @click="sendTextMsg">
<img v-show="canSend" src="../../../assets/image/IM/send-yes.png" alt />
<img v-show="!canSend" src="../../../assets/image/IM/send-no.png" alt />
</div>
</section>
</article>
<article class="right">
<UserInfo :userInfo="doctorInfo" :taskLogId="currentTaskLogId"></UserInfo>
</article>
</section>
<!-- 选择链接弹窗 -->
<el-dialog
title="选择链接"
:show-close="true"
:visible.sync="showSelectDialog"
:close-on-click-modal="false"
width="500px"
class="link-form"
>
<el-form ref="linkFormRef" :rules="rules" :model="linkForm" label-width="100px">
<el-form-item label="普通文本">
<el-col :span="20">
<el-input v-model="linkForm.remark" size="small" maxlength="300"></el-input>
</el-col>
</el-form-item>
<el-form-item label="链接文案" prop="info">
<el-col :span="20">
<el-input v-model="linkForm.info" size="small" maxlength="100"></el-input>
</el-col>
</el-form-item>
<el-form-item label="链接地址" prop="url">
<el-col :span="20">
<el-select
size="small"
style="width: 300px"
clearable
filterable
v-model="linkForm.url"
placeholder="请选择"
>
<el-option
v-for="item in linkList"
:key="item.id"
:label="item.title"
:value="item.id"
></el-option>
</el-select>
</el-col>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer" style="text-align: right;">
<el-button size="small" @click="showSelectDialog = false">取 消</el-button>
<el-button size="small" type="primary" @click="sendLinkMsg">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { mapGetters, mapMutations } from 'vuex';
import BreadCrumb from "@/components/breadcrumb.vue";
import { doUpload, getFilePath } from "@/utils/qiniu-util";
import { validateWord } from "@/utils/validate.js";
// import { openLoading, closeLoading } from "@/utils/utils";
import { openLoading, closeLoading, betaHandle, timeHandle } from "@/utils/utils";
import * as commonUtil from "@/utils/utils";
import { getPicaKFAccid, getPhomeDemain } from "@/utils";
import UserInfo from "@/components/IM/user-info.vue";
const CONTAINER_HEIGHT = 700;
let forwardMsgIntervalId = null;
let sessionIntervalId = null;
let continueIntervalId = null;
let _this = null;
export default {
components: {
BreadCrumb,
UserInfo
},
data() {
return {
curmbFirst: "云鹊客服",
curmbSecond: "当前会话",
sendText: "",
sessionListData: {
currentTimestamp: 0,
myTaskCount: 0,
sessionList: [],
waitingTaskCount: 0
},
currentContinueTimes: 0,
currentSessionIndex: 0, // 当前会话序号
currentSession: {},
currentTaskLogId: "", // 当前会话ID
currentToAccId: "",
picakfAccId: "",
historyTimestamp: 0,
realTimestamp: 0,
doctorInfo: {
name: "",
mobilePhone: "",
isShowCopyBtn: true
},
containerHeight: CONTAINER_HEIGHT,
showSelectDialog: false,
linkForm: {
remark: "",
info: "",
url: ""
},
linkList: [],
// 消息列表 showType 1: 文本; 2: 图片; 3: PDF; 4: 链接; 5: 不支持类型;
messageList: [],
rules: {
info: [{ required: true, message: "请输入链接文案", trigger: "blur" }],
url: [{ required: true, message: "请选择链接地址", trigger: "change" }]
}
};
},
computed: {
...mapGetters(['isFromAssignTask']),
canSend() {
return !!this.sendText;
}
},
created() {
_this = this;
this.picakfAccId = getPicaKFAccid();
this.kfAvatar = require("../../../assets/image/IM/kf-avatar.png");
this.getSessionList();
sessionIntervalId && clearInterval(sessionIntervalId);
sessionIntervalId = setInterval(() => {
this.getSessionList();
}, 10000);
this.getFiveContentList();
document.onkeydown = function(ev) {
var event = ev || event;
if (event.keyCode == 13) {
_this.sendTextMsg();
event.preventDefault();
}
};
},
mounted: function() {
(function(window) {
var _element = document.querySelector(".scroll-box"),
_refreshText = document.querySelector(".refreshText"),
_startPos = 0,
_transitionHeight = 0,
_isMousedown = false,
_canRefresh = false;
_element.addEventListener(
"mousedown",
function(e) {
var event = e || window.event;
_isMousedown = true;
_canRefresh = false;
console.log("##########", event);
console.log("初始位置:", event.pageX);
_startPos = event.pageX;
_element.style.position = "relative";
_element.style.transition = "transform 0s";
},
false
);
_element.addEventListener(
"mousemove",
function(e) {
if (!_isMousedown) return;
var event = e || window.event;
console.log("##########", event);
console.log("当前位置:", event.pageX);
_transitionHeight = event.pageX - _startPos;
if (_transitionHeight > 0 && _transitionHeight < 40) {
_canRefresh = true;
// _refreshText.innerText = "下拉刷新";
_refreshText.innerText = "";
_element.style.transform =
"translateY(" + _transitionHeight + "px)";
if (_transitionHeight > 20) {
// _refreshText.innerText = "释放更新";
_refreshText.innerText = "";
}
}
},
false
);
_element.addEventListener(
"mouseup",
function(e) {
_isMousedown = false;
_element.style.transition = "transform 0.5s ease 1s";
_element.style.transform = "translateY(0px)";
// _refreshText.innerText = "更新中";
_refreshText.innerText = "";
if (_canRefresh) {
_canRefresh = false;
_this.getOldMSGHistory();
}
},
false
);
})(window);
},
methods: {
//
...mapMutations(['SET_IS_FROM_ASSIGN_TASK']),
// 下拉刷新
loadmore() {
console.log("in loadmore...");
},
// 查询医生和居民的消息历史(下拉刷新时调用)
getOldMSGHistory() {
let session = this.currentSession;
let params = {
doctorAccId: this.currentToAccId,
includeFlag: 0, // 不带本条消息
lastClientIdServer: session.lastMsgIdClient,
lastMsgIdServer: session.lastMsgIdServer,
lastMsgTimestamp: this.historyTimestamp,
limit: 20,
patientAccId: this.picakfAccId,
unionId: ""
};
this.POST("/im/msg/history", params).then(res => {
if (res.code === "000000") {
console.log("res", res);
// 将新消息合并到之前的消息中, 并且重置最后一条消息
this.convertMessageList(res.data, 3);
} else {
this.$message({
message: res.message,
type: "error"
});
}
});
},
// 查询医生和居民的消息历史(第一次进来时就调用)
getMSGHistory(session) {
let params = {
doctorAccId: this.currentToAccId,
includeFlag: 1, // 带本条消息
lastClientIdServer: session.lastMsgIdClient,
lastMsgIdServer: session.lastMsgIdServer,
lastMsgTimestamp: session.lastMsgTime,
limit: 20,
patientAccId: this.picakfAccId,
unionId: ""
};
this.POST("/im/msg/history", params).then(res => {
if (res.code === "000000") {
this.convertMessageList(res.data, 1);
} else {
this.$message({
message: res.message,
type: "error"
});
}
});
},
// 查询医生和居民的消息 - 向前查找
// 将获取消息列表插入到当前消息列表的最后
getMSGForward() {
let session = this.currentSession;
let params = {
doctorAccId: this.currentToAccId,
includeFlag: 0,
lastClientIdServer: session.lastMsgIdClient,
lastMsgIdServer: session.lastMsgIdServer,
lastMsgTimestamp: this.realTimestamp,
limit: 20,
patientAccId: this.picakfAccId,
unionId: ""
};
this.POST("/im/msg/forward", params).then(res => {
if (res.code === "000000") {
this.convertMessageList(res.data, 2);
this.readAllMsg();
} else {
this.$message({
message: res.message,
type: "error"
});
}
});
},
// 转换消息格式
// 处理的消息类型只有5种:
// type == TEXT(showType:1)
// type == image 或 picture(showType:2)
// type == custom时,1 ~ 17: 不支持(showType:5); 18: PDF文件(showType:3); 19: 链接信息(showType:4);
// directFlag 1: 第一次取数据; 2: 拼接实时消息(unshift); 3: 拼接历史消息(push);
convertMessageList(messageList, directFlag = 1) {
console.log('@@@@@@directFlag@@@@@', directFlag);
messageList.sort((a, b) => {
return a.timestamp - b.timestamp;
});
let msg = null,
content = null,
text = "",
suffix = "",
showType = 1,
size = 0,
url = "",
cMessageList = [];
messageList.forEach((rawMsg, index) => {
text = "";
suffix = "";
showType = 1;
size = 0;
url = "";
msg = Object.assign({}, rawMsg);
msg.sendOrReceive = rawMsg.fromAccId !== this.currentToAccId;
msg.avatarImg = msg.sendOrReceive
? this.kfAvatar
: this.currentSession.avatarImageUrl;
if (msg.type.toLowerCase() == "custom") {
content = JSON.parse(msg.content);
text = content.content;
if (content.bizType == -1) {
showType = -1;
text = content.content;
} else if (content.bizType == 18) {
showType = 3;
text = content.name;
size = content.size;
url = content.url;
} else if (content.bizType == 19) {
showType = 4;
suffix = content.suffix;
} else {
showType = 5;
}
} else if (
msg.type.toLowerCase() == "image" ||
msg.type.toLowerCase() == "picture"
) {
content = JSON.parse(msg.content);
url = content.url;
text = content.name;
showType = 2;
} else {
showType = 1;
text = msg.content;
}
msg.text = text;
msg.showType = showType;
msg.suffix = suffix;
msg.size = size;
msg.url = url;
cMessageList.push(msg);
});
if (directFlag === 1) {
this.messageList = cMessageList;
this.$nextTick( () => {
const scrollBoxDom = document.querySelector('.scroll-box')
scrollBoxDom.scrollTop = 200000;
});
this.currentContinueTimes = this.sessionListData.currentTimestamp - this.currentSession.handleStartTime;
continueIntervalId && clearInterval(continueIntervalId);
continueIntervalId = setInterval(() => {
this.currentContinueTimes += 1000;
}, 1000);
} else if (directFlag === 2) {
this.messageList.push(...cMessageList);
} else {
this.messageList.unshift(...cMessageList);
}
// 重新设置历史与实时的时间戳
if (this.messageList.length) {
this.historyTimestamp = this.messageList[0].timestamp;
this.realTimestamp = this.messageList[
this.messageList.length - 1
].timestamp;
}
if (directFlag == 1) {
forwardMsgIntervalId && clearInterval(forwardMsgIntervalId);
forwardMsgIntervalId = setInterval(() => {
this.getMSGForward();
}, 10000);
}
console.log("this.messageList", this.messageList);
},
// 选择一个会话
selectSession(session, index) {
// 点击当前的,不再重新请求数据
if (this.currentTaskLogId == session.taskLogId) return;
console.log("selectSession");
this.currentTaskLogId = session.taskLogId;
this.currentToAccId = session.toAccId;
this.currentSession = session;
this.currentSessionIndex = index;
// 获取当前消息列表(最新的历史消息)
this.getMSGHistory(this.currentSession);
// 获取医生信息
this.getDoctorInfo(this.currentToAccId);
// 调用全部已读
if (session.unreadCount) {
this.readAllMsg();
}
},
// 打开PDF
openPDF(item) {
window.open(item.url, "__blank");
},
// 给我一个任务吧,如果当前没有任务,则要提示
fetchOneTask() {
this.GET("/im/session/kf/fetchOneTask").then(res => {
if (res.code === "000000") {
this.SET_IS_FROM_ASSIGN_TASK(true);
this.currentTaskLogId = "";
this.getSessionList();
} else {
this.$message({
message: res.message,
type: "error"
});
}
});
},
// 获取会话列表
getSessionList() {
this.GET("/im/session/kf/list").then(res => {
if (res.code === "000000") {
console.log("in getSessionList", res);
this.sessionListData = res.data || {
currentTimestamp: 0,
myTaskCount: 0,
sessionList: [],
waitingTaskCount: 0
};
let sLength = this.sessionListData.sessionList.length;
let cIndex = sLength - 1;
if(!this.isFromAssignTask) {
cIndex = 0;
}
// 第一次进入页面
if (sLength && !this.currentTaskLogId) {
// this.currentSession = this.sessionListData.sessionList[0];
// this.currentSessionIndex = 0;
this.currentSession = this.sessionListData.sessionList[cIndex];
this.currentSessionIndex = cIndex;
this.currentTaskLogId = this.currentSession.taskLogId;
this.currentToAccId = this.currentSession.toAccId;
this.getDoctorInfo(this.currentToAccId);
this.getMSGHistory(this.currentSession);
this.SET_IS_FROM_ASSIGN_TASK(false);
}
if (sLength) {
this.convertSessions(this.sessionListData.sessionList);
this.$forceUpdate();
console.log("this.currentSession", this.currentSession);
}
} else {
this.$message({
message: res.message,
type: "error"
});
}
});
},
// 将会话列表的数据进行处理,主要是显示文本(text)字段
convertSessions(sessions) {
let convertSessionList = [];
let text = "",
cc;
sessions.forEach((session, index) => {
if (session.lastMsgType.toLowerCase() == "custom") {
text = "";
cc = JSON.parse(session.lastMsgContent);
if (cc.showType == 1) {
text = cc.title || cc.name;
} else {
text = cc.content || cc.name;
}
} else if (
session.lastMsgType.toLowerCase() == "image" ||
session.lastMsgType.toLowerCase() == "picture"
) {
text = "[图片]";
} else {
text = session.lastMsgContent;
}
session.text = text;
convertSessionList.push(session);
});
this.sessionListData.sessionList = convertSessionList;
},
// 根据云信id获取医生信息
getDoctorInfo(accId) {
this.GET(`/im/account/accid/doctorinfo?accId=${accId}`).then(res => {
if (res.code === "000000") {
this.doctorInfo = res.data || {};
} else {
this.$message({
message: res.message,
type: "error"
});
}
});
},
// 关闭一个任务
closeOneTask(session) {
let params = {
taskLogId: session.taskLogId
};
this.POST(`/im/session/kf/closeOneTask`, params).then(res => {
if (res.code === "000000") {
console.log("in closeOneTask", res);
if (res.data == 1) {
this.currentTaskLogId = "";
this.getSessionList();
}
} else {
this.$message({
message: res.message,
type: "error"
});
}
});
},
// 设置全部消息已读
readAllMsg() {
let fromAccount = this.currentToAccId,
toAccount = this.picakfAccId;
let params = {
fromAccount,
toAccount
};
this.POST(`/im/msg/read/all`, params).then(res => {
if (res.code === "000000") {
let session = this.findItemByKeyAndVal(
this.sessionListData.sessionList,
"id",
this.currentTaskLogId
);
if (session) {
session.unreadCount = 0;
}
} else {
this.$message({
message: res.message,
type: "error"
});
}
});
},
// 根据字段名及其值,从数组中查找对象
findItemByKeyAndVal(arr, key, value, flag = 0) {
if (flag == 0) {
return arr.find(item => {
return item[key] == value;
});
} else if (flag == 1) {
return arr.findIndex(item => {
return item[key] == value;
});
}
},
// 获取积木列表
getFiveContentList() {
this.GET(
"/contents/admin/template/queryTemplate?publishFlag=5&pageNo=1&pageSize=99999"
).then(res => {
if (res.code === "000000") {
console.log("in getFiveContentList", res);
this.linkList = res.data.templateList || [];
} else {
this.$message({
message: res.message,
type: "error"
});
}
});
},
// 上传文件
beforeUploadFile(file) {
console.log("file", file);
let fileSize = file.size / (1024 * 1024);
if(fileSize > 5) {
this.$message({
message: '请上传小于5M的文件',
type: "warning"
});
return;
}
doUpload(
_this,
file,
getFilePath(file, null),
"preview4",
"progress",
""
).then(function(resData) {
let params = {};
params.fileSize = resData.size;
params.fileExt = resData.ext;
params.url = resData.fullPath;
params.info = resData.name;
params.type = 2;
// 如果是图片,则要获取其宽与高
if (
params.fileExt.toLowerCase() === ".jpg" ||
params.fileExt.toLowerCase() === ".png"
) {
params.type = 1;
let image = new Image();
image.src = params.url;
image.onload = function() {
let _img = this;
params.width = _img.width;
params.height = _img.height;
_this.sendCommonMsg(params);
};
} else {
_this.sendCommonMsg(params);
}
});
},
// 打开发送链接弹框
preSendLinkMsg() {
this.linkForm = {
remark: "",
info: "",
url: ""
};
this.showSelectDialog = true;
},
// 发送带链接消息
sendLinkMsg() {
this.$refs["linkFormRef"].validate(valid => {
if (valid) {
let params = this.linkForm;
params.url = getPhomeDemain() + `/template_v2/?id=${params.url}`;
params.type = 3;
this.sendCommonMsg(params);
this.showSelectDialog = false;
}
});
},
// 发送文本消息
sendTextMsg() {
if (!this.canSend) return;
this.sendCommonMsg({ info: this.sendText });
this.sendText = "";
},
// 发送通用消息
sendCommonMsg(params) {
let sendMsgParams = {
fromAccount: this.picakfAccId,
toAccount: this.currentToAccId,
fileExt: "", // 文件扩展名称图片或PDF文件)
fileSize: 0, // 文件大小(图片或PDF文件)
height: 0, // 图片高度(仅图片)
width: 0, // 图片宽度(仅图片)
info: "", // 文本内容,图片的名称,pdf的名称,链接显示内容
md5: "", // 图片或文件MD5 暂时由后台生成
remark: "", // 其他信息(链接中的前缀文案)
type: 0, // 类型 0文本 1图片 2pdf 3链接
url: "" // url地址(图片、pdf,链接)
};
params = Object.assign(sendMsgParams, params);
console.log("sendMsgParams", params);
this.POST("/im/msg/sendMessage", params).then(res => {
if (res.code === "000000") {
// 校验结果:1校验通过 2校验不通过
console.log(res.data.checkFlag);
// this.getSessionList();
} else {
this.$message({
message: res.message,
type: "error"
});
}
});
},
// 文件大小单位转换
fileSizeChange(val) {
return betaHandle(val)
},
},
beforeDestroy() {
console.log("in beforeDestroy", forwardMsgIntervalId);
sessionIntervalId && clearInterval(sessionIntervalId);
forwardMsgIntervalId && clearInterval(forwardMsgIntervalId);
console.log("in beforeDestroy", forwardMsgIntervalId);
}
};
</script>
<style lang="scss" scoped>
@import "./index.scss";
</style>
\ No newline at end of file
...@@ -161,6 +161,15 @@ ...@@ -161,6 +161,15 @@
color: #999999; color: #999999;
margin-bottom: 8px; margin-bottom: 8px;
} }
.send-warpper {
display: flex;
flex-direction: row;
align-items: center;
& > .icon {
width: 20px;
height: 20px;
margin-right: 10px;
}
.mid-text-wrapper { .mid-text-wrapper {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
...@@ -230,15 +239,22 @@ ...@@ -230,15 +239,22 @@
} }
} }
& > .mid-img { & > .mid-img {
display: flex;
flex-direction: row;
align-items: center;
cursor: pointer;
// & > .icon {
// width: 20px;
// height: 20px;
// }
& > .img {
width: 170px; width: 170px;
height: 108px; height: 108px;
cursor: pointer;
& > img {
width: 100%;
height: 100%;
border-radius: 8px; border-radius: 8px;
} }
} }
}
} }
&.cr { &.cr {
flex-direction: row-reverse; flex-direction: row-reverse;
...@@ -254,6 +270,48 @@ ...@@ -254,6 +270,48 @@
} }
} }
} }
.split-line {
width: 100%;
display: flex;
flex-direction: row;
align-items: center;
margin: 15px 0;
font-size: 14px;
color: #999999;
&::before {
flex: 1;
content: '';
height: 1px;
margin-right: 18px;
background: #f0f1f2;
}
&::after {
flex: 1;
content: '';
height: 1px;
margin-left: 18px;
background: #f0f1f2;
}
}
.error-mg {
display: inline-block;
max-width: 520px;
// height: 24px;
max-width: 520px;
line-height: 16px;
text-align: left;
border-radius: 20px;
opacity: 0.45;
margin: -2px 0 10px;
padding: 4px 12px;
color: #FFFFFF;
background: #000000;
margin-left: 50px;
&.mr {
margin-left: 0;
margin-right: 50px;
}
}
} }
.c-bottom { .c-bottom {
position: relative; position: relative;
...@@ -308,5 +366,27 @@ ...@@ -308,5 +366,27 @@
.small { .small {
font-size: 12px; font-size: 12px;
} }
.ld{
-webkit-transition-property: -webkit-transform;
-webkit-transition-duration: 1s;
-moz-transition-property: -moz-transform;
-moz-transition-duration: 1s;
-webkit-animation: rotate 3s linear infinite;
-moz-animation: rotate 3s linear infinite;
-o-animation: rotate 3s linear infinite;
animation: rotate 3s linear infinite;
}
@-webkit-keyframes rotate{from{-webkit-transform: rotate(0deg)}
to{-webkit-transform: rotate(360deg)}
}
@-moz-keyframes rotate{from{-moz-transform: rotate(0deg)}
to{-moz-transform: rotate(359deg)}
}
@-o-keyframes rotate{from{-o-transform: rotate(0deg)}
to{-o-transform: rotate(359deg)}
}
@keyframes rotate{from{transform: rotate(0deg)}
to{transform: rotate(359deg)}
}
} }
} }
\ No newline at end of file
...@@ -53,23 +53,36 @@ ...@@ -53,23 +53,36 @@
<p class="refreshText"></p> <p class="refreshText"></p>
<section class="msg-content scroll-box" :style="{'height': (containerHeight - 35) + 'px'}"> <section class="msg-content scroll-box" :style="{'height': (containerHeight - 35) + 'px'}">
<article <article
class="msg-item"
:class="{'cr': item.sendOrReceive}"
v-for="(item, index) in messageList" v-for="(item, index) in messageList"
:key="index" :key="index"
:style="{'text-align': item.sendOrReceive ? 'right' : 'left'}"
> >
<div class="split-line" v-if="item.sessionFlag">本次会话结束</div>
<div class="msg-item" :class="{'cr': item.sendOrReceive}">
<div class="msg-item-img"> <div class="msg-item-img">
<img :src="item.avatarImg" alt /> <img :src="item.avatarImg" alt />
</div> </div>
<div class="msg-item-detail"> <div class="msg-item-detail">
<span class="mid-time">{{item.timestampStr}}</span> <span class="mid-time">{{item.timestampStr}}</span>
<div class="send-warpper">
<img
v-if="item.sendOrReceive && item.isShowErrorIcon"
class="icon"
src="../../../assets/image/IM/icon-no-send.png"
alt
/>
<img
v-if="item.sendOrReceive && item.isShowLoadingIcon"
class="icon ld"
src="../../../assets/image/IM/icon-fresh-2.png"
alt
/>
<div v-if="item.showType == 1" class="mid-text-wrapper" style="max-width: 520px;"> <div v-if="item.showType == 1" class="mid-text-wrapper" style="max-width: 520px;">
<img v-show="item.sendFlag" src="../../../assets/image/IM/icon-no-send.png" alt /> <!-- <img v-show="item.sendFlag" src="../../../assets/image/IM/icon-no-send.png" alt /> -->
<div class="mid-text">{{item.text}}</div> <div class="mid-text">{{item.text}}</div>
</div> </div>
<div v-if="item.showType == 2" class="mid-img" v-viewer> <div v-if="item.showType == 2" class="mid-img" v-viewer>
<img :src="item.url" alt /> <img class="img" :src="item.url" alt />
<!-- <img :src="item.imgUrl" alt /> --> <!-- <img :src="item.imgUrl" alt /> -->
</div> </div>
<div v-if="item.showType == 3" class="mid-pdf" @click="openPDF(item)"> <div v-if="item.showType == 3" class="mid-pdf" @click="openPDF(item)">
...@@ -90,10 +103,17 @@ ...@@ -90,10 +103,17 @@
<span>该消息类型PC端暂不支持</span> <span>该消息类型PC端暂不支持</span>
</div> </div>
</div> </div>
</div>
</div>
<span
v-if="item.sendOrReceive && item.isShowErrorMsg"
class="error-mg"
:class="{'mr': item.sendOrReceive}"
>{{item.isErrorMsg}}</span>
</article> </article>
</section> </section>
<section class="c-bottom"> <section class="c-bottom">
<el-input type="textarea" placeholder="请输入内容" v-model="sendText" maxlength=499></el-input> <el-input type="textarea" placeholder="请输入内容" v-model="sendText" maxlength="499"></el-input>
<div class="cb-icon-wrapper"> <div class="cb-icon-wrapper">
<el-upload <el-upload
class="bg-uploader" class="bg-uploader"
...@@ -165,12 +185,17 @@ ...@@ -165,12 +185,17 @@
</div> </div>
</template> </template>
<script> <script>
import { mapGetters, mapMutations } from 'vuex'; import { mapGetters, mapMutations } from "vuex";
import BreadCrumb from "@/components/breadcrumb.vue"; import BreadCrumb from "@/components/breadcrumb.vue";
import { doUpload, getFilePath } from "@/utils/qiniu-util"; import { doUpload, getFilePath } from "@/utils/qiniu-util";
import { validateWord } from "@/utils/validate.js"; import { validateWord } from "@/utils/validate.js";
// import { openLoading, closeLoading } from "@/utils/utils"; // import { openLoading, closeLoading } from "@/utils/utils";
import { openLoading, closeLoading, betaHandle, timeHandle } from "@/utils/utils"; import {
openLoading,
closeLoading,
betaHandle,
timeHandle
} from "@/utils/utils";
import * as commonUtil from "@/utils/utils"; import * as commonUtil from "@/utils/utils";
import { getPicaKFAccid, getPhomeDemain } from "@/utils"; import { getPicaKFAccid, getPhomeDemain } from "@/utils";
import UserInfo from "@/components/IM/user-info.vue"; import UserInfo from "@/components/IM/user-info.vue";
...@@ -220,14 +245,16 @@ export default { ...@@ -220,14 +245,16 @@ export default {
// 消息列表 showType 1: 文本; 2: 图片; 3: PDF; 4: 链接; 5: 不支持类型; // 消息列表 showType 1: 文本; 2: 图片; 3: PDF; 4: 链接; 5: 不支持类型;
messageList: [], messageList: [],
rules: { rules: {
info: [{ required: true, message: "请输入链接文案", trigger: "blur" }], info: [
url: [{ required: true, message: "请选择链接地址", trigger: "change" }] { required: true, message: "请填写链接显示文案", trigger: "blur" }
],
url: [{ required: true, message: "请选择链接", trigger: "change" }]
} }
}; };
}, },
computed: { computed: {
...mapGetters(['isFromAssignTask']), ...mapGetters(["isFromAssignTask"]),
canSend() { canSend() {
return !!this.sendText; return !!this.sendText;
} }
...@@ -244,6 +271,7 @@ export default { ...@@ -244,6 +271,7 @@ export default {
}, 10000); }, 10000);
this.getFiveContentList(); this.getFiveContentList();
// 监听键盘的回车按键(回车时发送消息,并阻止其在textarea中的回车换行行为)
document.onkeydown = function(ev) { document.onkeydown = function(ev) {
var event = ev || event; var event = ev || event;
if (event.keyCode == 13) { if (event.keyCode == 13) {
...@@ -309,10 +337,10 @@ export default { ...@@ -309,10 +337,10 @@ export default {
_element.style.transform = "translateY(0px)"; _element.style.transform = "translateY(0px)";
// _refreshText.innerText = "更新中"; // _refreshText.innerText = "更新中";
_refreshText.innerText = ""; _refreshText.innerText = "";
if (_canRefresh) { // if (_canRefresh) {
_canRefresh = false; // _canRefresh = false;
_this.getOldMSGHistory(); _this.getOldMSGHistory();
} // }
}, },
false false
); );
...@@ -320,9 +348,40 @@ export default { ...@@ -320,9 +348,40 @@ export default {
}, },
methods: { methods: {
// 处理发送消息
// 1: 先将消息体直接显示在对话框中
// 2: 设置一个时间戳,以便再次找回
// 3: 保存再次发送的数据
// 4: 设置各种状态(1:isShowErrorIcon; 2:isShowLoadingIcon; 3:isShowErrorMsg)
handleSendMsg(params, sendId) {
let text = "";
let msg = Object.assign({}, params);
msg.fromAccount = this.currentToAccId;
msg.toAccount = this.picakfAccId;
msg.text = params.info;
msg.suffix = params.remark;
msg.size = params.fileSize;
msg.url = params.url;
msg.showType = params.type - 0 + 1;
msg.sessionFlag = false;
msg.isShowLoadingIcon = true;
msg.isShowErrorIcon = false;
msg.isShowErrorMsg = false; // 只有在下次拉取新数据时才有可能是为ture
msg.extData = Object.assign({}, params); // 再将发送时的数据
msg.sendId = sendId; //
msg.sendOrReceive = true;
msg.avatarImg = this.kfAvatar;
msg.timestampStr = new Date().format("hh:mm");
msg.realTimestamp = this.realTimestamp;
console.log("####msg####", msg);
this.messageList.push(msg);
this.$nextTick( () => {
var element = document.querySelector(".scroll-box");
element.scrollTop = element.scrollHeight;
})
},
// //
...mapMutations(['SET_IS_FROM_ASSIGN_TASK']), ...mapMutations(["SET_IS_FROM_ASSIGN_TASK"]),
// 下拉刷新 // 下拉刷新
loadmore() { loadmore() {
...@@ -414,6 +473,7 @@ export default { ...@@ -414,6 +473,7 @@ export default {
// type == custom时,1 ~ 17: 不支持(showType:5); 18: PDF文件(showType:3); 19: 链接信息(showType:4); // type == custom时,1 ~ 17: 不支持(showType:5); 18: PDF文件(showType:3); 19: 链接信息(showType:4);
// directFlag 1: 第一次取数据; 2: 拼接实时消息(unshift); 3: 拼接历史消息(push); // directFlag 1: 第一次取数据; 2: 拼接实时消息(unshift); 3: 拼接历史消息(push);
convertMessageList(messageList, directFlag = 1) { convertMessageList(messageList, directFlag = 1) {
console.log("@@@@@@directFlag@@@@@", directFlag);
messageList.sort((a, b) => { messageList.sort((a, b) => {
return a.timestamp - b.timestamp; return a.timestamp - b.timestamp;
}); });
...@@ -439,7 +499,11 @@ export default { ...@@ -439,7 +499,11 @@ export default {
if (msg.type.toLowerCase() == "custom") { if (msg.type.toLowerCase() == "custom") {
content = JSON.parse(msg.content); content = JSON.parse(msg.content);
text = content.content; text = content.content;
if (content.bizType == 18) { // 系统消息:消息由于违规未发送成功(可以不处理)
if (content.bizType == -1) {
showType = -1;
text = content.content;
} else if (content.bizType == 18) {
showType = 3; showType = 3;
text = content.name; text = content.name;
size = content.size; size = content.size;
...@@ -467,22 +531,35 @@ export default { ...@@ -467,22 +531,35 @@ export default {
msg.suffix = suffix; msg.suffix = suffix;
msg.size = size; msg.size = size;
msg.url = url; msg.url = url;
msg.sessionFlag = false;
// 设置是否是会话结束标志
if (cMessageList.length >= 1) {
if (
cMessageList[cMessageList.length - 1].taskLogId !== msg.taskLogId
) {
msg.sessionFlag = true;
}
}
cMessageList.push(msg); cMessageList.push(msg);
}); });
if (directFlag === 1) { if (directFlag === 1) {
this.messageList = cMessageList; this.messageList = cMessageList;
this.$nextTick( () => { this.$nextTick(() => {
const scrollBoxDom = document.querySelector('.scroll-box') const scrollBoxDom = document.querySelector(".scroll-box");
scrollBoxDom.scrollTop = 200000; scrollBoxDom.scrollTop = 200000;
}); });
this.currentContinueTimes = this.sessionListData.currentTimestamp - this.currentSession.handleStartTime; this.currentContinueTimes =
this.sessionListData.currentTimestamp -
this.currentSession.handleStartTime;
continueIntervalId && clearInterval(continueIntervalId); continueIntervalId && clearInterval(continueIntervalId);
continueIntervalId = setInterval(() => { continueIntervalId = setInterval(() => {
this.currentContinueTimes += 1000; this.currentContinueTimes += 1000;
}, 1000); }, 1000);
// 最新消息,要合并CUSTOM类型中,bizType是-1的数据
} else if (directFlag === 2) { } else if (directFlag === 2) {
this.messageList.push(...cMessageList); this.contactForwardMessage(cMessageList);
// this.messageList.push(...cMessageList);
} else { } else {
this.messageList.unshift(...cMessageList); this.messageList.unshift(...cMessageList);
} }
...@@ -490,9 +567,10 @@ export default { ...@@ -490,9 +567,10 @@ export default {
// 重新设置历史与实时的时间戳 // 重新设置历史与实时的时间戳
if (this.messageList.length) { if (this.messageList.length) {
this.historyTimestamp = this.messageList[0].timestamp; this.historyTimestamp = this.messageList[0].timestamp;
this.realTimestamp = this.messageList[ let timestamp = this.messageList[this.messageList.length - 1].timestamp;
this.messageList.length - 1 if (timestamp) {
].timestamp; this.realTimestamp = timestamp;
}
} }
if (directFlag == 1) { if (directFlag == 1) {
...@@ -504,6 +582,33 @@ export default { ...@@ -504,6 +582,33 @@ export default {
console.log("this.messageList", this.messageList); console.log("this.messageList", this.messageList);
}, },
// 接接数据
contactForwardMessage(cMessageList) {
cMessageList.forEach(item => {
let content = {},
signature = "",
msgIndex = -1;
if (item.type.toLowerCase() == "custom") {
content = JSON.parse(item.content);
if (content.bizType == -1) {
signature = content.signature;
msgIndex = this.messageList.findIndex(m => {
return m.signature == signature;
});
if (msgIndex > -1) {
this.messageList[msgIndex].isErrorMsg = content.content;
this.messageList[msgIndex].isShowErrorMsg = true;
}
this.$forceUpdate();
} else {
this.messageList.push(item);
}
} else {
this.messageList.push(item);
}
});
},
// 选择一个会话 // 选择一个会话
selectSession(session, index) { selectSession(session, index) {
// 点击当前的,不再重新请求数据 // 点击当前的,不再重新请求数据
...@@ -557,7 +662,7 @@ export default { ...@@ -557,7 +662,7 @@ export default {
}; };
let sLength = this.sessionListData.sessionList.length; let sLength = this.sessionListData.sessionList.length;
let cIndex = sLength - 1; let cIndex = sLength - 1;
if(!this.isFromAssignTask) { if (!this.isFromAssignTask) {
cIndex = 0; cIndex = 0;
} }
// 第一次进入页面 // 第一次进入页面
...@@ -709,7 +814,14 @@ export default { ...@@ -709,7 +814,14 @@ export default {
// 上传文件 // 上传文件
beforeUploadFile(file) { beforeUploadFile(file) {
console.log("file", file); console.log("file", file);
let fileSize = file.size / (1024 * 1024);
if (fileSize > 5) {
this.$message({
message: "请上传小于5M的文件",
type: "warning"
});
return;
}
doUpload( doUpload(
_this, _this,
file, file,
...@@ -759,7 +871,7 @@ export default { ...@@ -759,7 +871,7 @@ export default {
sendLinkMsg() { sendLinkMsg() {
this.$refs["linkFormRef"].validate(valid => { this.$refs["linkFormRef"].validate(valid => {
if (valid) { if (valid) {
let params = this.linkForm; let params = Object.assign({}, this.linkForm);
params.url = getPhomeDemain() + `/template_v2/?id=${params.url}`; params.url = getPhomeDemain() + `/template_v2/?id=${params.url}`;
params.type = 3; params.type = 3;
this.sendCommonMsg(params); this.sendCommonMsg(params);
...@@ -791,25 +903,45 @@ export default { ...@@ -791,25 +903,45 @@ export default {
url: "" // url地址(图片、pdf,链接) url: "" // url地址(图片、pdf,链接)
}; };
params = Object.assign(sendMsgParams, params); params = Object.assign(sendMsgParams, params);
// 将获取新数据的定时器关闭
forwardMsgIntervalId && clearInterval(forwardMsgIntervalId);
let sendId = new Date().getTime();
this.handleSendMsg(params, sendId);
console.log("sendMsgParams", params); console.log("sendMsgParams", params);
this.POST("/im/msg/sendMessage", params).then(res => { this.POST("/im/msg/sendMessage", params).then(res => {
if (res.code === "000000") { if (res.code === "000000") {
// 校验结果:1校验通过 2校验不通过 // 校验结果:1校验通过 2校验不通过
console.log(res.data.checkFlag); console.log(res.data.checkFlag);
// this.getSessionList(); let msg = this.messageList[this.messageList.length - 1];
if (res.data.checkFlag == 1) {
this.realTimestamp = res.data.timetag;
msg.isShowLoadingIcon = false;
msg.isShowErrorIcon = false;
msg.isShowErrorMsg = false; // 只有在下次拉取新数据时才有可能是为ture
} else {
msg.signature = res.data.signature;
msg.isShowLoadingIcon = false;
msg.isShowErrorIcon = true;
msg.isShowErrorMsg = false; // 只有在下次拉取新数据时才有可能是为ture
}
this.$forceUpdate();
} else { } else {
this.$message({ this.$message({
message: res.message, message: res.message,
type: "error" type: "error"
}); });
} }
// 重新开启定时器
forwardMsgIntervalId = setInterval(() => {
this.getMSGForward();
}, 10000);
}); });
}, },
// 文件大小单位转换 // 文件大小单位转换
fileSizeChange(val) { fileSizeChange(val) {
return betaHandle(val) return betaHandle(val);
}, }
}, },
beforeDestroy() { beforeDestroy() {
......
...@@ -8,7 +8,11 @@ ...@@ -8,7 +8,11 @@
</div> </div>
<el-table :data="tableData" style="width: 100%" v-loading="loading"> <el-table :data="tableData" style="width: 100%" v-loading="loading">
<el-table-column prop="userName" label="用户名" min-width="50" align="center"></el-table-column> <el-table-column prop="userName" label="用户名" min-width="50" align="center"></el-table-column>
<el-table-column prop="waitTime" label="等待时间" min-width="100" align="center"></el-table-column> <el-table-column prop="waitTime" label="等待时间" min-width="100" align="center">
<template slot-scope="scope">
<span>{{scope.row.waitTime | continueTimesFilter}}</span>
</template>
</el-table-column>
<el-table-column prop="idType" label="用户类型" min-width="50" align="center"> <el-table-column prop="idType" label="用户类型" min-width="50" align="center">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{scope.row.idType | typeFilter}}</span> <span>{{scope.row.idType | typeFilter}}</span>
......
Markdown 格式
0% or
您添加了 0 到此讨论。请谨慎行事。
先完成此消息的编辑!
想要评论请 注册