第一版IM封装

feature/1.0.1-im-ch
ch 3 years ago
parent 990cd56690
commit 649b91d8a1

@ -6,13 +6,13 @@
// * @Description: file content
// */
// import { MsbSkt } from "../utils/webSkt";
// import { createUUID } from '@/common/utils';
// import { CreateUUID } from '@/common/utils';
// /**
// * 系统消息心跳
// */
// export const ApiSktSysHeart = () => MsbSkt.send({
// traceId: createUUID(),
// traceId: CreateUUID(),
// traceType: '0',
// content: { text: "ping" }
// });
@ -22,7 +22,7 @@
// * @param {*} content
// */
// export const ApiSktSysGetSession = (content) => MsbSkt.send({
// traceId: createUUID(),
// traceId: CreateUUID(),
// traceType: '1',
// content
// });
@ -32,7 +32,7 @@
// * @param {*} content
// */
// export const ApiSktSysGetHistory = (content) => MsbSkt.send({
// traceId: createUUID(),
// traceId: CreateUUID(),
// traceType: '2',
// content
// });
@ -42,7 +42,7 @@
// * @param {*} content
// */
// export const ApiSktSysGetHistory = (content) => MsbSkt.send({
// traceId: createUUID(),
// traceId: CreateUUID(),
// traceType: '6',
// content
// });

@ -0,0 +1,238 @@
/*
* @Author: ch
* @Date: 2022-05-18 14:54:47
* @LastEditors: ch
* @LastEditTime: 2022-05-20 11:25:57
* @Description: file content
*/
const connect = Symbol('connect'),
send = Symbol('send');
export default class MsbIm {
option = {
ioKey : 'traceId',
reconnect: true,
}
socket = null;
queue = {};
interceptors = {
dataChangeBefore: null,
dataChangeAfter: null,
onMessage: null,
onResponse: null
};
sessionData = [];
curSession = {};
constructor(option) {
this.option = {
...this.option,
...option
}
}
/**
* 创建连接返回一个Promise 创建成功并成功打开连接算连接成功
* @param {*} option
*/
[connect](option) {
return new Promise((resolve, reject) => {
this.socket = uni.connectSocket({
...option,
fail(e){
reject(e);
}
});
this.socket.onOpen(() => {
this.socket.onMessage((res) => {
const result = JSON.parse(res.data);
// 每次消息推送都会推送至onMessage Hook中
this.interceptors.onMessage && this.interceptors.onMessage(result);
// 查看是否有返回信息处理Hook有的话优先取处理后的结果返回
const responseData = this.interceptors.onResponse ? this.interceptors.onResponse(result) : result;
const isError = responseData.constructor === Promise;
// 如果再消息堆里有此消息回调,则执行回调,并删除
const cbk = this.queue[result[this.option.ioKey]];
if (cbk) {
cbk(isError ? {error:responseData} : {result:responseData});
delete this.queue[result[this.option.ioKey]];
}
})
resolve(this.socket);
});
this.socket.onClose(() => {
if (this.option.reconnect) {
this.connect();
}
});
});
}
/**
* 向服务端发送消息||请求返回一个Promise对象收到ioKey对应的消息会算一个同步完成
* @param {*} data
*/
[send](data) {
return new Promise((resolve, reject) => {
this.queue[data[this.option.ioKey]] = ({ result, error }) => {
if (result) {
resolve(result);
} else {
reject(error);
}
};
this.socket.send({
data : JSON.stringify(data),
fail(e) {
if (this.interceptors.onResponse) {
reject(this.interceptors.onResponse(e))
}
reject(e);
}
});
})
}
/**
* 扩展钩子
* @param {*} hookName
* @param {*} cb
*/
use(hookName, cb){
this.hook[hookName] = cb;
}
init (config) {
return new Promise((resolve, reject) => {
const heart = () => {
setTimeout(async () => {
await this[send]({
traceId: CreateUUID(),
traceType: '0',
content: { text: "ping" }
});
heart();
},5000)
}
this[connect]({
...config,
// url : `wss://you-gateway.mashibing.com/ws?client=${store.state.token}&type=1`
// url : `wss://k8s-horse-gateway.mashibing.cn/ws?client=${store.state.token}&type=1`, // url是websocket连接ip
}).then(() => {
heart();
resolve(this);
});
})
}
/**
* 设置
*/
setSessionData(data) {
this.interceptors.dataChangeBefore && this.interceptors.dataChangeBefore(data, this.sessionData);
this.sessionData = data;
this.interceptors.dataChangeAfter && this.interceptors.dataChangeAfter(this.sessionData);
},
/**
* 设置当前聊天窗口
* Data为Session数据
* @param {*} data
*/
setCurSession(data) {
this.curSession = data;
}
async getSessionList (params) {
let {content} = await this[send]({
traceId: CreateUUID(),
...params
});
content.sessionVOS.forEach(item => {
if (item.lastMessage) {
item.lastMessage.createTimeStamp = FormatDate(item.lastMessage.createTimeStamp, 'mm-dd hh:ii')
item.lastMessage.payload = JSON.parse(item.lastMessage.payload || {});
}
let historyData = this.sessionData;
let hisIndex = historyData.findIndex(i => i.id === item.id);
if(hisIndex >= 0){
historyData[hisIndex].lastMessage = item.lastMessage;
historyData[hisIndex].unreadCount++;
this.interceptors.dataChangeBefore && this.interceptors.dataChangeBefore(historyData, this.sessionData);
this.sessionData = historyData;
this.interceptors.dataChangeAfter && this.interceptors.dataChangeAfter(this.sessionData);
}else{
item.messageList = [];
const newData = [...historyData, item]
this.interceptors.dataChangeBefore && this.interceptors.dataChangeBefore(newData, this.sessionData);
this.sessionData = newData;
this.interceptors.dataChangeAfter && this.interceptors.dataChangeAfter(this.sessionData);
}
});
}
async getHistoryMsg (params){
let { content } = await this[send]({
traceId: CreateUUID(),
traceType : 23,
...params
})
if(!content.length){
return false;
}
// ctx.reverse();
let newData = this.sessionData;
const hisIdx = newData.findIndex(i => i.id === content[0].sessionId);
content.forEach(item => {
item.createTimeStamp = FormatDate(item.createTimeStamp, 'mm-dd hh:ii');
item.payload = JSON.parse(item.payload)
})
newData[hisIdx].messageList = newData[hisIdx].messageList.concat(content);
this.interceptors.dataChangeBefore && this.interceptors.dataChangeBefore(newData, this.sessionData);
this.sessionData = newData;
this.interceptors.dataChangeAfter && this.interceptors.dataChangeAfter(this.sessionData);
return Promise.resolve(content);
}
async setRead (params){
await this[send]({
traceId : CreateUUID(),
traceType : "6",
...params
});
// 计算页头消息数
this.curSession.unreadCount = 0;
}
async sendMsg (params){
const { content } = await this[send]({
traceId: CreateUUID(),
traceType: 20,
...params
});
return Promise.resolve(content)
}
async createSession (params){
const { content } = await this[send]({
traceId : CreateUUID(),
traceType : 21,
...params
});
let historyData = this.sessionData;
let curSession = historyData.find(i => i.id === content.id);
if (!curSession) {
curSession = {
...content,
unreadCount: 0,
messageList : []
}
const newData = [...historyData, curSession];
this.interceptors.dataChangeBefore && this.interceptors.dataChangeBefore(newData, this.sessionData);
this.sessionData = newData;
this.interceptors.dataChangeAfter && this.interceptors.dataChangeAfter(this.sessionData);
}
this.curSession = curSession;
// store.commit('SET_SESSION_DATA',this.sessionData);
// store.commit('SET_SESSION_MSG_ID',curSession.id);
return Promise.resolve(content);
}
}

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-05-18 14:54:47
* @LastEditors: ch
* @LastEditTime: 2022-05-19 15:42:19
* @LastEditTime: 2022-05-19 17:35:21
* @Description: file content
*/
@ -17,8 +17,7 @@ export class MsbWebSktNew{
this.queue = {};
this.hook = {};
this.data = [];
this.count = 0;
this.sessionData = [];
this.curSession = {};
}
/**

@ -0,0 +1,31 @@
/*
* @Author: ch
* @Date: 2022-05-20 11:00:07
* @LastEditors: ch
* @LastEditTime: 2022-05-20 11:36:51
* @Description: file content
*/
import MsbIm from '@/common/plugins/msbIm' ;
import $store from '@/common/store';
const Im = new MsbIm({
reconnect: true,
});
const ImInit = () => {
return Im.init({
url: `wss://k8s-horse-gateway.mashibing.cn/ws?client=${$store.state.token}&type=1`
})
};
Im.interceptors.dataChangeAfter = () => {
$store.commit('SET_SESSION_DATA', Im.sessionData);
let msgCount = 0;
Im.sessionData.forEach(i => {
msgCount += i.unreadCount;
})
$store.commit('SET_SESSION_MSG_COUNT', msgCount);
}
export {
Im,
ImInit
}

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-17 19:15:10
* @LastEditors: ch
* @LastEditTime: 2022-05-07 17:18:50
* @LastEditTime: 2022-05-20 10:02:24
* @Description: 一些无法归类的公共方法容器
*/
@ -79,7 +79,7 @@ const IsDouble = (str) => {
* @param {number|string|Date} d 时间参数能被new Date识别的数字字符串日期
* @param {string} fmt 时间格式参数 字符串类型 默认'yyyy/mm/dd'
*/
const formatDate = (date, fmt = 'yyyy/mm/dd' ) =>{
const FormatDate = (date, fmt = 'yyyy/mm/dd' ) =>{
// 处理不识别的时间表示字符串如2020年01月01日00时00分00秒
if(date.constructor === String){
date = date.replace(/\D+/ig,'/');
@ -118,7 +118,7 @@ const formatDate = (date, fmt = 'yyyy/mm/dd' ) =>{
return fmt;
}
const createUUID = (len,radix) => {
const CreateUUID = (len,radix) => {
const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
let uuid = [],
i=0;
@ -140,7 +140,7 @@ const createUUID = (len,radix) => {
return uuid.join('');
}
const toSearchJson = (search)=>{
const ToSearchJson = (search)=>{
search = search.replace(/\?/g,'&');
let searchArr = search.split('&'),
obj = {};
@ -170,7 +170,7 @@ export {
// 判断是否double或float
IsDouble,
// 时间格式化
formatDate,
createUUID,
toSearchJson
FormatDate,
CreateUUID,
ToSearchJson
}

@ -2,12 +2,12 @@
* @Author: ch
* @Date: 2022-05-18 15:27:02
* @LastEditors: ch
* @LastEditTime: 2022-05-19 15:50:12
* @LastEditTime: 2022-05-19 16:42:44
* @Description: file content
*/
import { MsbWebSktNew } from "../plugins/webSkt";
import { createUUID, formatDate } from '@/common/utils';
import { CreateUUID, FormatDate } from '@/common/utils';
import store from "../store";
const MsbSkt = new MsbWebSktNew();
@ -25,8 +25,8 @@ MsbSkt.use('onMessage', (data) => {
}
ctx = data.content;
ctx.payload = JSON.parse(ctx.payload || {});
ctx.createTimeStamp = formatDate(ctx.createTimeStamp || new Date(), 'mm-dd hh:ii')
let historyData = MsbSkt.data;
ctx.createTimeStamp = FormatDate(ctx.createTimeStamp || new Date(), 'mm-dd hh:ii')
let historyData = MsbSkt.sessionData;
const hisIndex = historyData.findIndex(i => i.id === ctx.sessionId);
// 不在当前会话框则全局消息加1
// if(ctx.sessionId !== store.state.sessionMsgId){
@ -40,10 +40,10 @@ MsbSkt.use('onMessage', (data) => {
// if(ctx.sessionId !== store.state.sessionMsgId){
// curHisData.unreadCount++;
// }
MsbSkt.data = historyData;
MsbSkt.sessionData = historyData;
}else{
// 会话列表不存在,则创建一个会话
MsbSkt.data = [...historyData, {
MsbSkt.sessionData = [...historyData, {
fromAvatar : ctx.fromAvatar,
fromId : ctx.fromId,
fromNickname : ctx.fromNickname,
@ -53,7 +53,7 @@ MsbSkt.use('onMessage', (data) => {
unreadCount : 1
}]
}
store.commit('SET_SESSION_DATA',MsbSkt.data);
store.commit('SET_SESSION_DATA',MsbSkt.sessionData);
});
/**
@ -64,7 +64,7 @@ export const MsbSktInit = () => {
const heart = () => {
setTimeout(async () => {
await MsbSkt.send({
traceId: createUUID(),
traceId: CreateUUID(),
traceType: '0',
content: { text: "ping" }
});
@ -88,23 +88,23 @@ export const MsbSktInit = () => {
*/
export const MsbSktGetSessionList = async (params) => {
let {content} = await MsbSkt.send({
traceId: createUUID(),
traceId: CreateUUID(),
...params
});
content.sessionVOS.forEach(item => {
if (item.lastMessage) {
item.lastMessage.createTimeStamp = formatDate(item.lastMessage.createTimeStamp, 'mm-dd hh:ii')
item.lastMessage.createTimeStamp = FormatDate(item.lastMessage.createTimeStamp, 'mm-dd hh:ii')
item.lastMessage.payload = JSON.parse(item.lastMessage.payload || {});
}
let historyData = MsbSkt.data;
let historyData = MsbSkt.sessionData;
let hisIndex = historyData.findIndex(i => i.id === item.id);
if(hisIndex >= 0){
historyData[hisIndex].lastMessage = item.lastMessage;
historyData[hisIndex].unreadCount++;
MsbSkt.data = historyData
MsbSkt.sessionData = historyData
}else{
item.messageList = [];
MsbSkt.data = [...historyData, item];
MsbSkt.sessionData = [...historyData, item];
}
});
}
@ -113,7 +113,7 @@ export const MsbSktGetSessionList = async (params) => {
*/
export const MsbSktGetHistoryMsg = async (params) => {
let { content } = await MsbSkt.send({
traceId: createUUID(),
traceId: CreateUUID(),
traceType : 23,
...params
})
@ -121,14 +121,14 @@ export const MsbSktGetHistoryMsg = async (params) => {
return false;
}
// ctx.reverse();
let newData = MsbSkt.data;
let newData = MsbSkt.sessionData;
const hisIdx = newData.findIndex(i => i.id === content[0].sessionId);
content.forEach(item => {
item.createTimeStamp = formatDate(item.createTimeStamp, 'mm-dd hh:ii');
item.createTimeStamp = FormatDate(item.createTimeStamp, 'mm-dd hh:ii');
item.payload = JSON.parse(item.payload)
})
newData[hisIdx].messageList = newData[hisIdx].messageList.concat(content);
MsbSkt.data = newData;
MsbSkt.sessionData = newData;
store.commit('SET_SESSION_DATA', newData);
return Promise.resolve(content);
@ -138,7 +138,7 @@ export const MsbSktGetHistoryMsg = async (params) => {
*/
export const MsbSktSetRead = async (params) => {
await MsbSkt.send({
traceId : createUUID(),
traceId : CreateUUID(),
traceType : "6",
...params
});
@ -151,7 +151,7 @@ export const MsbSktSetRead = async (params) => {
*/
export const MsbSktSendMsg = async (params) => {
const { content } = await MsbSkt.send({
traceId: createUUID(),
traceId: CreateUUID(),
traceType: 20,
...params
});
@ -162,11 +162,11 @@ export const MsbSktSendMsg = async (params) => {
*/
export const MsbSktCreateSession = async (params) => {
const { content } = await MsbSkt.send({
traceId : createUUID(),
traceId : CreateUUID(),
traceType : 21,
...params
});
let historyData = MsbSkt.data;
let historyData = MsbSkt.sessionData;
let curSession = historyData.find(i => i.id === content.id);
if (!curSession) {
curSession = {
@ -174,10 +174,10 @@ export const MsbSktCreateSession = async (params) => {
unreadCount: 0,
messageList : []
}
MsbSkt.data = [...historyData, curSession];
MsbSkt.sessionData = [...historyData, curSession];
}
MsbSkt.curSession = curSession;
store.commit('SET_SESSION_DATA',MsbSkt.data);
store.commit('SET_SESSION_DATA',MsbSkt.sessionData);
store.commit('SET_SESSION_MSG_ID',curSession.id);
return Promise.resolve(content);
}

@ -6,14 +6,14 @@
* @Description: file content
*/
import store from "../store";
import {createUUID, formatDate} from '@/common/utils';
import {CreateUUID, FormatDate} from '@/common/utils';
let sessionListFlag = false;
const sessionList = (ctx) => {
sessionListFlag = true;
// 来新消息先查会话列表是否一存在,存在则加消息数。不存在则向会话列表加一个会话框
ctx.sessionVOS.forEach(item => {
if (item.lastMessage) {
item.lastMessage.createTimeStamp = formatDate(item.lastMessage.createTimeStamp, 'mm-dd hh:ii')
item.lastMessage.createTimeStamp = FormatDate(item.lastMessage.createTimeStamp, 'mm-dd hh:ii')
item.lastMessage.payload = JSON.parse(item.lastMessage.payload || {});
}
let historyData = store.state.sessionData;
@ -38,7 +38,7 @@ const historyMsg = (ctx) => {
let newData = store.state.sessionData;
const hisIdx = newData.findIndex(i => i.id === ctx[0].sessionId);
ctx.forEach(item => {
item.createTimeStamp = formatDate(item.createTimeStamp, 'mm-dd hh:ii');
item.createTimeStamp = FormatDate(item.createTimeStamp, 'mm-dd hh:ii');
item.payload = JSON.parse(item.payload)
})
// newData[hisIdx].messageList = ctx.concat(newData[hisIdx].messageList);
@ -55,7 +55,7 @@ const sessionMsg = (ctx)=>{
return
}
ctx.payload = JSON.parse(ctx.payload || {});
ctx.createTimeStamp = formatDate(ctx.createTimeStamp || new Date(), 'mm-dd hh:ii')
ctx.createTimeStamp = FormatDate(ctx.createTimeStamp || new Date(), 'mm-dd hh:ii')
let historyData = store.state.sessionData;
const hisIndex = historyData.findIndex(i => i.id === ctx.sessionId);
// 不在当前会话框则全局消息加1

@ -13,9 +13,9 @@ import uView from 'uview-ui';
import store from '@/common/store';
import Confirm from '@/components/mount/index';
import route from 'uview-ui/libs/util/route';
import {toSearchJson} from '@/common/utils';
import {ToSearchJson} from '@/common/utils';
import {ApiGetOpenId, ApiGetAuthUrl} from '@/common/api/wx';
import {MsbWebSkt, MsbWebSktInit, createUUID} from '@/common/utils';
import {MsbWebSkt, MsbWebSktInit, CreateUUID} from '@/common/utils';
import { MsbSktInit, MsbSktGetSessionList} from './common/utils/webSkt';
import { ApiSktSysGetSession, ApiSktSysHeart } from './common/api/im';
@ -34,7 +34,7 @@ if (store.state.token) {
const ua = navigator ? navigator.userAgent.toLowerCase() : '';
if(ua.includes('micromessenger')) {
if(!store.state.openId){
let query = toSearchJson(window.location.search)
let query = ToSearchJson(window.location.search)
if(query.code){
ApiGetOpenId({
code : query.code

@ -1,926 +0,0 @@
<template>
<view class="chat-list" :class="{'loading':!loading,'isInput':isInput==true,'otherInput':otherInput==true}">
<view v-for="(item,index) in msgData" :key="item.id" :id="item.id" :class="{'nowAt':item.messageId == isNowAit}">
<!-- <view v-if="index>0&&item.sendTime - msgList[index-1].sendTime > 300000">
<view class="chat-item-hint">
<view style="background: none;">{{getTime(item.sendTime)}}</view>
</view>
</view> -->
<!-- 接收的消息 -->
<view class="chat-item-l" v-if="item.fromId != userInfo.id">
<view class="head-img">
<image class="head-img" src="@/static/message/xt.png"></image>
</view>
<view>
<view class="group-user-name clamp" v-if="imObject && imObject.type===2">
{{item.fromNickName||item.nickName}}
</view>
<!-- 文字类型消息 -->
<view v-if="item.type == msgType['txt']" class="chat-item-content" :class="{'jump-box':false}">
<!-- 普通文字消息 -->
<view>{{item.ctx}}</view>
</view>
<!-- 图片类型消息 -->
<view v-if="item.type == msgType['img']" class="chat-item-content-voice" >
<img class="des-img" mode='aspectFit' :src="item.ctx" @click="previewImg(item.ctx)">
</img>
</view>
<!-- 视频类型消息 -->
<view v-if="item.type == msgType['video']" class="chat-item-content-video" @click="clickVideo(item)">
<image class="v-icon" src="@/static/im/ship@2x.png" mode=""></image>
<view class="v-bottom">
<image class="v-b-icon" src="@/static/im/xiazai.png"></image>
</view>
</view>
</view>
</view>
<!-- 发送的消息 -->
<view class="chat-item-r" v-else >
<!-- 文字类型消息 -->
<view v-if="item.type == msgType['txt']" class="chat-item-content" :style="{'maxWidth':Width + 'px'}">
<view v-html="getUrl(item.content)"></view>
</view>
<!-- 图片类型消息 -->
<view v-if="item.type == msgType['img']" class="chat-item-content-voice" :style="{'maxWidth':Width + 'px'}">
<image class="des-img" mode='aspectFit' :src="item.ctx" @click="previewImg(item.ctx)">
</image>
</view>
<!-- 视频类型消息 -->
<view v-if="item.type == msgType['video']" class="chat-item-content-video" @click="clickVideo(item)">
<image class="v-icon" src="@/static/im/ship@2x.png" mode=""></image>
<view class="v-bottom">
<image class="v-b-icon" src="@/static/im/xiazai.png"></image>
</view>
</view>
<!-- 头像 -->
<view class="head-img">
<image class="head-img" src="@/static/message/xt.png"></image>
</view>
</view>
<view v-if="item.type === msgType['tips']">
<view class="chat-item-hint">
<view>{{item.ctx}}</view>
</view>
</view>
</view>
<!-- <view class="ait-jump" @click="aitJump"> -->
<view class="ait-jump" v-if="aitMsgId" @click="aitJump">
<image src="@/static/im/aitbtn1.png"></image>
<text>有人@</text>
<image @click.stop="aitMsgId=''" src="@/static/im/aitbtn2.png"></image>
</view>
<!-- <yinrh-menu-popup v-model="popup" :pop-data="menu" dynamic :x="x" :y="y" direction="row" theme="dark"
:placement="place" @tapPopup="tapPopup" /> -->
</view>
</template>
<script>
import {MSG_TYPE} from '@/common/dicts/im';
export default {
props: {
imObject: {
type: Object,
default: () => {}
},
isInput: {
type: Boolean,
default: false
},
otherInput: {
type: Boolean,
default: false
},
unReadCount: {
type: [String, Number],
default: 0
},
identity: {
type: [String, Number],
default: 0
}
},
data() {
return {
msgType : MSG_TYPE,
msgData :[
{id : 1, fromId : 9, type:1, ctx : 'ype 1文本消息 2语音消息 3图片消息 4视频消息 7提示消息'},
{id : 5, fromId : 3, type:1, ctx: 'ype 1文本消息 2语音消息 3图片消息 4视频消息 7提示消息'},
{id : 2, fromId : 9, type:7, ctx: '给你移动了客服'},
{id : 3, fromId : 2, type:3, ctx : 'https://msb-edu-dev.oss-cn-beijing.aliyuncs.com/mall-product/product2bca55bb5c3adb4d02a7a76039d097eewww800-800.jpg'},
{id : 3, fromId : 2, type:3, ctx : 'https://msb-edu-dev.oss-cn-beijing.aliyuncs.com/uc/account-avatar/aitbtn1.png'},
// {id : 4, formId : 9, type:4},
],
Width: '',
userNo: '',
historyParams: {},
msgList: [],
pullLoad: true,
firstPage: true,
loading: true,
popup: false,
aitMsgId: '',
isNowAit: '',
menu: [{
title: '转发'
}, {
title: '撤回'
}, {
title: '收藏'
}, {
title: '复制'
}],
value: false, // menutrue-
place: 'bottom-end',
x: 0,
y: 0,
selectMsg: {},
//
innerAudioContext: {},
//
audioItem: {}
}
},
created() {
// let app = this;
// uni.getSystemInfo({
// success: function(res) {
// app.Width = res.windowWidth - 116;
// app.Height = res.windowHeight;
// }
// });
// app.innerAudioContext = uni.createInnerAudioContext();
// app.innerAudioContext.autoplay = true;
// app.innerAudioContext.onEnded(() => {
// app.stopAudio()
// })
// //
// app.userNo = uni.getStorageSync('loginToken').userNo
// // app.historyParams = {
// // sessionId: app.imObject.sessionId,
// // msgCount: 100,
// // msgId: '',
// // }
// app.firstPage = true;
// app.msgList = [];
// let msgData = this.imDB.where({
// sessionId: app.imObject.sessionId
// }).limit(100).orderBy('messageId', 'desc').get()
// msgData = msgData.reverse()
// if (app.unReadCount > 0 || msgData.length <= 0) {
// app.getHistoryMsg();
// app.$emit('clearUnReadCount')
// } else {
// app.randerList(msgData)
// app.firstPage = false;
// }
//pushlist
},
beforeDestroy() {
this.chatListOnload()
},
computed: {
imDB: function() {
return this.$store.state.imDB;
},
userInfo (){
return this.$store.state.userInfo
}
},
methods: {
aitJump() {
let app = this;
uni.createSelectorQuery().select(".chat-list").boundingClientRect(data => { //
uni.createSelectorQuery().select("#msg" + app.aitMsgId).boundingClientRect((res) => { //
uni.pageScrollTo({
duration: 0, //0uniapp bug
scrollTop: res.top - data.top, //
})
app.isNowAit = app.aitMsgId
app.aitMsgId = ''
}).exec()
}).exec();
},
chatListOnload() {
uni.$off('scoket')
this.innerAudioContext.stop();
// this.msgList = [];
},
reprot(item) {
},
getUrl(str) {
},
fnThrottle(method, delay, duration) {
},
getHistoryMsg() {
},
randerList(list) {
},
getContent(item) {
},
clickVideo(item) {
let app = this;
uni.showModal({
title: '提示',
content: '暂时无法播放视频,是否下载视频文件?',
success: function(res) {
if (res.confirm) {
app.download(item)
}
}
});
},
download(item) {
if (item.isLoading) {
return false;
}
this.downloadFile(item)
},
scrollTop() {
if (this.pullLoad) {
this.getHistoryMsg();
}
},
tapPopup(e) {
},
copy() {
},
deleteMessage() {
},
forwardMsg() {
},
previewImg(logourl) {
let _this = this;
let imgsArray = [];
imgsArray[0] = logourl
uni.previewImage({
current: 0,
urls: imgsArray
});
},
playAudio(item) {
},
stopAudio() {
},
getSize(num) {
},
getTime(time) {
return dateFormat(time, 'yyyy-MM-dd HH:mm')
},
jumpPages(type, id, flag) {
},
delUnReadCount(res) {
let app = this;
delUnReadCount({
sessionId: res.sessionId,
userId: app.userNo,
platform: 2
})
}
}
}
</script>
<script module="test" lang="renderjs">
export default {
mounted() {
window.addEventListener("click", function(e) {
if (e.target.id == 'isa') {
uni.navigateTo({
url: 'pages/open-url/index?src=' + e.target.innerHTML
})
}
});
},
}
</script>
<style lang="scss" scoped>
.chat-item-content {
color: #0062CC;
position: relative;
.file-loading {
width: 22rpx;
height: 22rpx;
position: absolute;
left: -50rpx;
}
.file-fail {
height: 80rpx;
width: 110rpx;
position: absolute;
left: -110rpx;
background: url('@/static/im/fail.png') no-repeat;
background-position-x: 20rpx;
background-position-y: top;
background-size: 50rpx 50rpx;
&::before {
position: absolute;
content: '发送失败';
font-size: 20rpx;
font-family: PingFang SC;
font-weight: 400;
color: #999999;
width: 200rpx;
top: 52rpx;
}
}
}
.otherInput {
padding-bottom: 500rpx !important;
}
.isInput {
// padding-bottom: 718rpx !important;
}
.loading {
opacity: 0;
}
.chat-list {
padding: 20rpx 32rpx;
height: 100%;
overflow-y: auto;
overflow-x: hidden;
.chat-item-time {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
font-size: 24rpx;
font-family: DIN;
font-weight: 500;
color: #69707F;
margin: 30rpx 0;
}
.chat-item-hint {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20rpx;
view {
background: #EEEEEE;
border-radius: 25rpx;
padding: 12rpx 42rpx;
font-size: 24rpx;
font-family: PingFang SC;
font-weight: 500;
color: #999999;
}
}
.chat-item-l {
display: flex;
align-items: top;
margin: 20rpx 0;
.head-img {
width: 64rpx;
height: 64rpx;
margin-right: 20rpx;
border-radius: 50%;
}
.group-user-name {
font-size: 28rpx;
color: #999999;
padding-bottom: 12rpx;
max-width: 300rpx;
}
.jump-box {
position: relative;
padding-bottom: 56rpx !important;
}
.chat-item-content {
background: #FFFFFF;
border-radius: 2rpx 16rpx 16rpx 16rpx;
margin-right: 84rpx;
background-color: #fff;
box-sizing: border-box;
padding: 20rpx 30rpx;
font-size: 28rpx;
font-family: PingFang SC;
font-weight: 500;
color: #000000;
display: flex;
align-items: center;
word-break: break-all;
white-space: pre-wrap;
.audio-icon {
width: 24rpx;
height: 32rpx;
}
}
.chat-item-content-video {
width: 287rpx;
height: 161rpx;
background: #DCDCDC;
border-radius: 2rpx 16rpx 16rpx 16rpx;
position: relative;
.v-icon {
position: absolute;
left: 120rpx;
top: 48rpx;
width: 46rpx;
height: 46rpx;
}
.v-bottom {
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 40rpx;
background: rgba(0, 0, 0, 0.4);
border-radius: 2rpx 16rpx 16rpx 16rpx;
.v-b-icon {
position: absolute;
width: 23rpx;
height: 22rpx;
right: 20rpx;
bottom: 9rpx;
}
}
}
.chat-item-content-voice {
display: flex;
align-items: center;
width: auto;
max-width: 400rpx;
height: auto;
// height: 320rpx;
// background: #FB3A4E;
border-radius: 2rpx 2rpx 16rpx 16rpx;
font-size: 28rpx;
font-family: DIN;
font-weight: 500;
color: #333333;
// padding: 30rpx;
.des-img,
.des-video {
// width: 100%;
height: 150rpx;
// margin-right: 15rpx;
}
}
.chat-item-content-datum {
width: 465rpx;
display: flex;
align-items: center;
justify-content: space-between;
background: #FFFFFF;
border-radius: 2rpx 16rpx 16rpx 16rpx;
margin-right: 84rpx;
background-color: #fff;
box-sizing: border-box;
padding: 35rpx 30rpx;
.datum-info {
display: flex;
flex-flow: column;
flex: 1;
.datum-title {
flex: 1;
width: 300rpx;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
font-size: 32rpx;
line-height: 32rpx;
font-family: PingFang SC;
font-weight: 500;
color: #333333;
}
.datum-size {
margin-top: 15rpx;
font-size: 28rpx;
font-family: PingFang SC;
font-weight: 500;
color: #999999;
}
}
}
.chat-item-content-picture {
display: flex;
align-items: center;
border-radius: 2rpx 16rpx 16rpx 16rpx;
background-color: #fff;
box-sizing: border-box;
overflow: hidden;
image {
width: 213rpx;
}
}
}
.chat-item-r {
display: flex;
align-items: top;
justify-content: flex-end;
margin: 20rpx 0;
>.head-img {
margin-left: 20rpx;
}
.head-img {
width: 64rpx;
height: 64rpx;
padding: 0;
border-radius: 50%;
}
.chat-item-content {
background: #FB3A4E;
border-radius: 16rpx 2rpx 16rpx 16rpx;
margin-left: 84rpx;
box-sizing: border-box;
padding: 20rpx 30rpx;
font-size: 28rpx;
font-family: PingFang SC;
font-weight: 500;
color: #FFFFFF;
word-break: break-all;
white-space: pre-wrap;
display: flex;
align-items: center;
.audio-icon {
width: 24rpx;
height: 32rpx;
}
}
.chat-item-content-video {
width: 287rpx;
height: 161rpx;
background: #DCDCDC;
border-radius: 16rpx 2rpx 16rpx 16rpx;
position: relative;
.v-icon {
position: absolute;
left: 120rpx;
top: 48rpx;
width: 46rpx;
height: 46rpx;
}
.v-bottom {
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 40rpx;
background: rgba(0, 0, 0, 0.4);
border-radius: 2rpx 2rpx 16rpx 16rpx;
.v-b-icon {
position: absolute;
width: 23rpx;
height: 22rpx;
right: 20rpx;
bottom: 9rpx;
}
}
}
.chat-item-content-voice {
display: flex;
align-items: center;
justify-content: flex-end;
width: auto;
max-width: 400rpx;
height: auto;
// height: 320rpx;
// background: #FB3A4E;
border-radius: 16rpx 2rpx 16rpx 16rpx;
font-size: 28rpx;
font-family: DIN;
font-weight: 500;
color: #333333;
// padding: 30rpx;
.des-img,
.des-video {
// width: 100%;
height: 150rpx;
// margin-right: 15rpx;
}
}
.chat-item-content-datum {
width: 465rpx;
display: flex;
align-items: center;
justify-content: space-between;
background: #FFFFFF;
border-radius: 16rpx 2rpx 16rpx 16rpx;
margin-left: 84rpx;
background-color: #fff;
box-sizing: border-box;
padding: 35rpx 30rpx;
position: relative;
.file-loading {
width: 22rpx;
height: 22rpx;
position: absolute;
left: -50rpx;
}
.file-fail {
height: 80rpx;
width: 110rpx;
position: absolute;
left: -110rpx;
background: url('@/static/im/fail.png') no-repeat;
background-position-x: 15rpx;
background-position-y: top;
background-size: 50rpx 50rpx;
&::before {
position: absolute;
content: '发送失败';
font-size: 20rpx;
font-family: PingFang SC;
font-weight: 400;
color: #999999;
width: 200rpx;
top: 52rpx;
}
}
.datum-info {
display: flex;
flex-flow: column;
flex: 1;
.datum-title {
flex: 1;
width: 300rpx;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
font-size: 32rpx;
line-height: 32rpx;
font-family: PingFang SC;
font-weight: 500;
color: #333333;
}
.datum-size {
margin-top: 15rpx;
font-size: 28rpx;
font-family: PingFang SC;
font-weight: 500;
color: #999999;
}
}
}
.chat-item-content-picture {
display: flex;
align-items: center;
border-radius: 16rpx 2rpx 16rpx 16rpx;
background-color: #fff;
box-sizing: border-box;
overflow: hidden;
image {
width: 213rpx;
}
}
}
}
.datum-type {
image {
width: 74rpx;
height: 77rpx;
}
}
.jump-ques {
color: #00CCFF;
}
.voice-mask {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba($color: #000000, $alpha: 0.6);
z-index: 1003;
.vm-box {
width: 617rpx;
height: 514rpx;
background: #FFFFFF;
border-radius: 16rpx;
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
padding: 40rpx;
.vm-title {
font-size: 32rpx;
font-family: PingFang SC;
font-weight: 500;
color: #333333;
margin-bottom: 25rpx;
}
.vm-user {
display: flex;
align-items: center;
margin-bottom: 20rpx;
.vmu-img {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
margin-right: 20rpx;
}
.vmu-txt {
font-size: 30rpx;
font-family: PingFang SC;
font-weight: bold;
color: #333333;
}
}
.vm-msg {
width: 377rpx;
height: 76rpx;
background: #FB3A4E;
border-radius: 2rpx 16rpx 16rpx 16rpx;
display: flex;
align-items: center;
padding-left: 30rpx;
margin-bottom: 20rpx;
.vmm-img {
width: 24rpx;
height: 32rpx;
transform: rotate(180deg);
}
.vmm-txt {
font-size: 28rpx;
font-family: DIN;
font-weight: 500;
color: #F3F5F6;
}
}
.vm-ipt {
width: 537rpx;
height: 68rpx;
background: #F6F6F6;
border-radius: 8rpx;
font-size: 28rpx;
color: #999;
padding-left: 20rpx;
}
.vm-btm {
height: 106rpx;
width: 100%;
position: absolute;
left: 0;
bottom: 0;
display: flex;
border-top: 1rpx solid #F5F6F6;
.vmb-cel,
.vmb-sub {
width: 50%;
height: 100%;
text-align: center;
line-height: 106rpx;
font-size: 32rpx;
font-family: PingFang SC;
font-weight: 500;
color: #999999;
}
.vmb-cel {
border-right: 1rpx solid #F5F6F6;
}
}
}
}
.chat-item-l {
/deep/.at_span {
&::after {
content: attr(data-name);
color: #FB3A4E;
}
}
}
.chat-item-r {
/deep/.at_span {
&::after {
content: attr(data-name);
color: #ffffff;
}
}
}
.ait-jump {
position: fixed;
right: 0rpx;
bottom: 200rpx;
width: 273rpx;
height: 78rpx;
background: #FFFFFF;
box-shadow: 0rpx 4rpx 30rpx 1rpx rgba(0, 0, 0, 0.06);
border-radius: 100rpx 0rpx 0rpx 100rpx;
z-index: 9999;
display: flex;
align-items: center;
padding: 0 30rpx;
image {
width: 16rpx;
height: 16rpx;
&:nth-child(1) {
margin-right: 20rpx;
}
&:last-child {
margin-left: auto;
}
}
text {
font-size: 28rpx;
font-family: PingFang SC-Regular, PingFang SC;
font-weight: 400;
color: #FB3A4E;
}
}
.nowAt {
animation: isAt 3s 1;
-webkit-animation: isAt 3s 1;
/* Safari 和 Chrome */
}
@keyframes isAt {
0% {
background: #eee;
}
100% {
background: #fff;
}
}
</style>

@ -45,7 +45,7 @@
</view>
</template>
<script>
import {MsbWebSkt, createUUID} from '@/common/utils';
import {MsbWebSkt, CreateUUID} from '@/common/utils';
import {MsbSktSendMsg} from '@/common/utils/webSkt';
import {MSG_TYPE} from '@/common/dicts/im';
import {Request} from '@/common/utils';

@ -1,913 +0,0 @@
<template>
<!-- -->
<view class="chat-bottom" :style="{'bottom':isInput==true?getKeyHeight()+'px':'0px'}" @touchend='endAudio'>
<view class="bottom-operation">
<view class="goVoice" @click="setAudioShow">
<image src="../../../static/im/voice.png" mode=""></image>
</view>
<!-- <u-input type="textarea" maxlength="300" :clearable="false" height="80rpx" v-model="chatInfo" placeholder-style="color:#999;" placeholder="输入文字..." /> -->
<textarea v-if="!isIos()&&!audioShow" class="textarea" :class="{'textarea2':chatInfo}" maxlength="300"
v-model="chatInfo" @focus='onInput' placeholder-style="color:#999;" placeholder="输入文字..."
:auto-height='true' :adjust-position="false" />
<textarea v-if="isIos()&&!audioShow" class="textarea" :class="{'textarea2':chatInfo}" maxlength="300"
v-model="chatInfo" @focus='onInput' placeholder-style="color:#999;" placeholder="输入文字..."
:auto-height='true' />
<!-- <view class="textarea" v-if="audioShow"></view> -->
<view class="goexpression" @click="setEmojiShow">
<image src="../../../static/im/expression.png" mode=""></image>
</view>
<view v-show="chatInfo" class="send-btn" @touchend.prevent="sendMsg">
发送
</view>
<view class="more" v-show="!chatInfo" @click="setMoreShow">
<image src="../../../static/im/more.png" mode=""></image>
</view>
</view>
<view class="bottom-box">
<view v-show="emojiShow" class="emoji-box">
<view class="tools-box">
<text class="emoji" @click="setEmoji(item)"
v-for="(item,index) in getEmoji()">{{entitiestoUtf16(item)}}</text>
</view>
</view>
<view v-show="moreShow" class="operation-box">
<view class="operation-item" @click="goQuick">
<view class="item-btn">
<image src="../../../static/im/reply.png" mode=""></image>
</view>
<view class="item-hint">回复</view>
</view>
<view class="operation-item" @click="chooseImage">
<view class="item-btn">
<image src="../../../static/im/picture.png" mode=""></image>
</view>
<view class="item-hint">相册</view>
</view>
<view class="operation-item" @click="chooseFile">
<view class="item-btn">
<image src="../../../static/im/file.png" mode=""></image>
</view>
<view class="item-hint">文件</view>
</view>
<view class="operation-item" @click="chatCollect">
<view class="item-btn">
<image src="../../../static/im/collect.png"></image>
</view>
<view class="item-hint">收藏</view>
</view>
</view>
</view>
<u-popup v-model="showAitFlag" mode="bottom" border-radius="16" >
<!-- -->
<view class="ait-box" :style="{'height':isInput==true? (425 - keyHeight/2) +'px':'425px'}">
<view class="ab-title" >
<u-icon class='abt-close' name="arrow-down" color="#333333" size="24"></u-icon>
<text class="abt-txt">选择提醒的人</text>
</view>
<view class="ipt-wrp">
<image class="ipt-icon" src="@/static/sousuo.png"></image>
<input type="text" confirm-type="search" v-model="aitKeyword" class="ipt" placeholder="昵称搜索" >
</view>
<view class="ab-item" @click="setAit()">
<view class="abi-all">@</view>
<view class="abi-name">@所有人({{groupPeoList.length}})</view>
</view>
<view class="ab-item" @click="setAit(item)" v-for="(item,index) in groupPeoList" v-if="item.nickName.includes(aitKeyword)">
<image class="abi-img" :src="item.avatar"></image>
<view class="abi-name clamp">{{item.nickName}}</view>
</view>
</view>
</u-popup>
</view>
</template>
<script>
import {
utf16toEntities,
entitiestoUtf16
} from '@/common/js/utils.js'
import emojiData from '@/common/js/emoji.js'
import {
sendMsg,
sendGroupMsg,
sendSpecialMessage,
sendTextMsg,
getUserByGroupId
} from '@/common/api-request/im.js'
import cCircle from "@/components/Your_Exios-Circle/Your_Exios-Circle.vue"
import api from '@/common/js/api.js'
const baseUrl = api.host['local'];
export default {
components: {
cCircle
},
props: {
toUserNo: {
type: [String, Number],
default: ''
},
sendType: {
type: [String, Number],
default: ''
},
isInput: {
type: Boolean,
default: false
},
keyHeight: {
type: Number,
default: 0
},
isScreen: {
type: Boolean,
default: false
}
},
data() {
return {
chatInfo: '',
userNo: '',
moreShow: false,
emojiShow: false,
audioShow: false,
showAitFlag: false,
groupPeoList: [],
recorderManager: {}, //
innerAudioContext: {}, //
voicePath: [], //
timer: null, //
audioText: '长按录音',
audioStart: false,
sendFlag: true, //
voiceCel: false,
stamp: 0, //
txtIndex: 0, //
aitKeyword: '',
isserchinput:false
};
},
created() {
let app = this;
app.userNo = uni.getStorageSync('loginToken').userNo
//
app.recorderManager = uni.getRecorderManager();
console.log('录音对象', app.recorderManager)
app.innerAudioContext = uni.createInnerAudioContext();
app.innerAudioContext.autoplay = true;
app.recorderManager.onStop(function(res) {
console.log('-------停止录音', res)
let now = new Date().getTime()
let obj = {
path: res.tempFilePath,
duration: parseInt((now - app.stamp) / 100) * 100
}
if (obj.duration < 1000) {
uni.showToast({
icon: 'none',
title: '录音太短了!'
})
setTimeout(() => {
app.cancelAudio()
}, 200)
} else {
//
if (!app.voiceCel) {
app.voicePath.push(obj);
app.sendAudio()
}
}
});
if (app.sendType === 2) {
getUserByGroupId(app.toUserNo).then(res => {
console.log('--------------获取群成员', res.data)
app.groupPeoList = res.data
app.groupPeoList.forEach((el, idx) => {
if (el.userNo == app.userNo) {
app.groupPeoList.splice(idx, 1)
}
})
})
}
},
beforeDestroy() {
let app = this;
if (app.innerAudioContext.stop) {
app.innerAudioContext.stop()
}
if (app.timer) {
clearInterval(app.timer)
app.timer = null;
}
},
onShow() {
},
methods: {
getserchInput(){
//
uni.onKeyboardHeightChange(res => {
if (res.height > 0) {
console.log(res.height,'禁停')
// app.keyHeight = res.height
// app.isInput = true;
} else {
// app.isInput = false;
}
})
},
setAit(item) {
let app = this;
app.showAitFlag = false;
//,便
let curEnd = app.chatInfo.slice(app.txtIndex)
let curStr = app.chatInfo.slice(0, app.txtIndex)
if (item) {
app.chatInfo = curStr + item.nickName + '\t' + curEnd
} else {
app.chatInfo = curStr + '所有人' + '\t' + curEnd
}
console.log(item)
},
//
getKeyHeight() {
// if (this.isIos()) {
// if (this.isScreen) {
// return (this.keyHeight - 35)
// } else {
// return (this.keyHeight - 5)
// }
// } else {
// // return this.keyHeight
// return 0
// }
return 0
},
async sendMsg() {
let app = this;
let ids = []
let isAt = false;
if (app.sendType === 2) {
//@\t
let reg = /@.*?\\t/gi;
let result = JSON.stringify(app.chatInfo).match(reg)
if (result) {
for (let i = 0; i < result.length; i++) {
let el = result[i];
let cur = el.slice(1, el.length - 2)
if (cur == '所有人') {
app.groupPeoList.forEach(val => {
ids.push(val.userNo)
})
break;
} else {
app.groupPeoList.forEach(val => {
if (val.nickName == cur) {
ids.push(val.userNo)
}
})
}
console.log(cur)
}
}
isAt = ids.length > 0 ? true : false;
}
if (!app.sendFlag) {
return false;
}
app.sendFlag = false;
let res;
if (!app.chatInfo) {
uni.showToast({
icon: 'none',
title: "请输入聊天内容!"
})
app.sendFlag = true;
return false;
}
if (app.sendType === 1) {
//
res = await sendTextMsg({
content: app.chatInfo,
fromUserNo: app.userNo,
toUserNo: app.toUserNo
})
} else {
//
res = await sendTextMsg({
content: app.chatInfo,
fromUserNo: app.userNo,
groupId: app.toUserNo,
atUsers: ids,
isAt: isAt
})
}
if (res.code === 200) {
app.chatInfo = '';
uni.$emit('scoket', JSON.stringify(res.data))
// app.audioShow = false;
// app.moreShow = false;
// app.emojiShow = false;
} else {
uni.showToast({
icon: 'none',
title: res.msg
})
}
app.sendFlag = true;
},
chooseImage() {
let app = this;
uni.chooseImage({
count: 1, //9
sizeType: ['original', 'compressed'], //
sourceType: ['album', 'camera'], //
success: function(res) {
console.log(res.tempFilePaths[0]);
let filePath = res.tempFilePaths[0]
app.uploadFile(filePath, 1)
}
});
},
chooseFile() {
let app = this;
if (this.isIos()) {
const iOSFileSelect = uni.requireNativePlugin('YangChuan-YCiOSFileSelect');
let params = {
"document-types": ["public.text", "public.zip", "public.movie", "public.data", "com.adobe.pdf",
"com.microsoft.word.doc", "com.adobe.postscript", "com.microsoft.excel.xls",
"com.adobe.encapsulated- postscript", "com.microsoft.powerpoint.ppt",
"com.adobe.photoshop- image", "com.microsoft.word.rtf",
"com.microsoft.advanced- systems-format", "com.microsoft.advanced- stream-redirector"
],
"isBase64": 0
}
iOSFileSelect.show(params, result => {
let filePath = result.url
console.log(result,'result')
let fileName = result.lastName
let fileSize = result.version
app.uploadFile(filePath, 4,fileName,fileSize)
})
} else {
const plugin = uni.requireNativePlugin('GuoWei-SelectFileModule')
plugin.chooseFile({
count: 1
},
result => {
let filePath = result.files[0].url
let fileName = result.files[0].name
let fileSize = result.files[0].size
console.log('-----im文件选择', result)
app.uploadFile(filePath, 4, fileName, fileSize)
}
)
}
},
startAudio() {
console.log('开始录音', this.recorderManager);
let app = this
clearInterval(app.timer)
app.timer = null;
app.stamp = new Date().getTime()
uni.vibrateShort({
success: function() {
console.log('开始录音2', this.recorderManager);
app.timer = setInterval(() => {
uni.showToast({
icon: 'none',
title: '录音时间过长!'
})
app.endAudio()
app.$emit('longStop')
}, 60000)
console.log('开始录音3', this.recorderManager);
app.recorderManager.start();
app.audioText = '松开停止'
}
});
},
endAudio(val = false) {
let app = this;
app.voiceCel = val;
if (app.timer) {
console.log('录音结束');
clearInterval(app.timer)
app.timer = null;
app.recorderManager.stop();
app.audioText = '点击播放'
}
},
playVoice() {
console.log('播放录音');
// console.log('this.voicePath', this.voicePath, this.audioStart);
if (!this.audioStart) {
this.audioStart = true
this.innerAudioContext.src = this.voicePath[0];
this.innerAudioContext.play();
this.audioText = '暂停播放'
} else if (this.audioStart) {
this.audioStart = false
this.innerAudioContext.stop()
this.audioText = '点击播放'
}
},
cancelAudio() {
let app = this;
// app.audioShow = false;
app.moreShow = false;
app.emojiShow = false;
app.timer = null;
app.innerAudioContext.stop()
app.voicePath.length > 0 ? app.voicePath.shift() : app.voicePath = []
app.audioStart = false;
app.audioText = '长按录音'
},
sendAudio() {
let app = this;
if (app.voicePath.length == 1) {
app.uploadFile(app.voicePath[0].path, 2)
}
},
uploadFile(filePath, type, fileName = '', fileSize = 0) {
let header = {}
let app = this;
if (uni.getStorageSync('loginToken')) {
let token = uni.getStorageSync('loginToken');
header['Authorization'] = token.tokenHead + token.token;
header['R-Authorization'] = token.tokenHead + token.refreshToken;
// header['Content-Type'] = 'multipart/form-data'
}
let scoketParams = {
isLoading: 'load',
fromUserNo: app.userNo,
toUserNo: app.sendType == 1 ? app.toUserNo : '',
groupId: app.sendType == 2 ? app.toUserNo : '',
type: type,
fileName: fileName,
fileSize: fileSize,
filePath: filePath,
audioSeconds: app.voicePath && app.voicePath.length > 0 ? app.voicePath[0].duration : ''
}
console.log('ios',scoketParams)
uni.$emit('scoket', JSON.stringify(scoketParams))
uni.uploadFile({
url: baseUrl + '/edu-im/file/upload',
filePath: filePath,
header: header,
name: "file",
success: function(res) {
let resData = JSON.parse(res.data).data
let params = {
content: resData.content,
fileName: resData.filename,
size: resData.size,
fromUserNo: app.userNo,
toUserNo: app.sendType == 1 ? app.toUserNo : '',
groupId: app.sendType == 2 ? app.toUserNo : '',
type: type,
audioSeconds: app.voicePath && app.voicePath.length > 0 ? app.voicePath[0]
.duration : ''
}
sendSpecialMessage(params).then(ret => {
console.log('ret', ret)
if (ret.code === 200) {
console.log('-----------------im发送图片', ret)
app.chatInfo = '';
uni.$emit('scoket', JSON.stringify(ret.data))
app.innerAudioContext.stop()
// app.audioShow = false;
app.moreShow = false;
app.emojiShow = false;
app.audioStart = false;
app.audioText = '长按录音'
if (app.voicePath.length > 1) {
app.voicePath.shift()
setTimeout(() => {
app.sendAudio()
}, 1000)
} else {
app.voicePath = []
}
} else {
uni.showToast({
icon: 'none',
title: ret.msg
})
}
})
},
fail: function(error) {
// uni.showToast({
// title: "", //
// duration: 3000, //
// icon: "none", //"success""loading"
// });
scoketParams.isLoading = 'fail'
uni.$emit('scoket', JSON.stringify(scoketParams))
}
})
},
chatCollect() {
uni.navigateTo({
url: '/pages/im/chat/chatCollect'
})
},
goQuick() {
uni.navigateTo({
url: '/pages/im/quick/index?sendType=' + this.sendType + '&toUserNo=' + this.toUserNo
})
},
getEmoji() {
return [...emojiData[0].list, ...emojiData[1].list, ...emojiData[4].list]
},
setEmoji(data) {
let str = ' ' + this.entitiestoUtf16(data) + ' '
this.chatInfo += str;
},
onInput() {
this.emojiShow = false;
this.audioShow = false;
this.moreShow = false;
this.$emit('setInput', false)
},
setMoreShow() {
this.moreShow = !this.moreShow;
this.emojiShow = false;
this.audioShow = false;
this.$emit('setInput', this.moreShow)
},
setAudioShow() {
this.audioShow = !this.audioShow;
this.emojiShow = false;
this.moreShow = false;
this.$emit('setInput', false)
// this.$emit('setInput', this.audioShow)
},
setEmojiShow() {
// this.chatInfo = '@\t@asdadad1\t2 '
// console.log(JSON.stringify(this.chatInfo))
// return false;
this.emojiShow = !this.emojiShow;
this.moreShow = false;
this.audioShow = false;
this.$emit('setInput', this.emojiShow)
},
utf16toEntities(val) {
return utf16toEntities(val)
},
entitiestoUtf16(val) {
return entitiestoUtf16(val)
},
},
watch: {
audioShow: function(n, o) {
this.$emit('onAudioShow', n)
},
chatInfo: function(n, o) {
let app = this;
if (app.sendType != 2) {
return false;
}
//
uni.getSelectedTextRange({
success: res => {
app.txtIndex = res.end;
//,便
let curEnd = n.slice(res.end)
let curStr = n.slice(0, res.end)
/*
新增艾特相关
*/
let oldStr1 = o.slice(0, res.end)
if (curStr == oldStr1 + '@') {
app.aitKeyword = '';
app.showAitFlag = true;
uni.hideKeyboard()
}
/*
删除艾特相关
*/
//
let oldStr = o.slice(0, res.end + 1)
//\t,
if (curStr.length < oldStr.length && curStr + '\t' == oldStr) {
//
let num = curStr.lastIndexOf('@')
let nowStr = curStr.slice(0, num)
app.chatInfo = nowStr + curEnd;
console.log('删除艾特')
}
}
})
}
}
}
</script>
<style lang="scss">
// .isInput {
// bottom: 570rpx !important;
// }
.chat-bottom {
position: fixed;
bottom: 0;
width: 100%;
min-height: 148rpx;
background-color: #fff;
display: flex;
flex-flow: column;
.bottom-operation {
width: 100%;
display: flex;
align-items: flex-end;
padding: 17px 30rpx;
}
.goVoice {
width: 52rpx;
height: 52rpx;
margin-right: 10rpx;
margin-bottom: 15rpx;
image {
width: 100%;
height: 100%;
}
}
.textarea {
height: 80rpx;
max-height: 200rpx !important;
overflow: auto;
width: 490rpx;
line-height: 80rpx;
background: #F8F8F8;
border-radius: 40rpx;
padding: 0 40rpx;
}
.textarea2 {
width: 420rpx;
line-height: 48rpx;
min-height: 80rpx;
/deep/.uni-textarea-textarea{
padding-top: 16rpx;
}
}
.audio {
flex: 1;
background: #F8F8F8;
border-radius: 39rpx;
font-size: 28rpx;
font-family: PingFang SC;
font-weight: 500;
color: #333;
height: 78rpx;
text-align: center;
line-height: 78rpx;
}
/deep/.u-input {
flex: 1;
background: #F8F8F8;
border-radius: 39rpx;
font-size: 28rpx;
font-family: PingFang SC;
font-weight: 500;
color: #333;
max-height: 200rpx !important;
overflow-y: auto;
.u-input__textarea {
display: flex;
align-items: center;
box-sizing: border-box;
padding: 20rpx 40rpx;
max-height: 200rpx;
}
}
.goexpression {
width: 52rpx;
height: 53rpx;
margin-left: 15rpx;
margin-right: 19rpx;
margin-bottom: 15rpx;
image {
width: 100%;
height: 100%;
}
}
.more {
width: 53rpx;
height: 53rpx;
margin-bottom: 15rpx;
image {
width: 100%;
height: 100%;
}
}
.send-btn {
display: flex;
align-items: center;
justify-content: center;
width: 120rpx;
height: 60rpx;
background-color: #fb3a4e;
color: #fff;
font-size: 28rpx;
border-radius: 10rpx;
margin-bottom: 15rpx;
transition: all .3s;
}
.operation-box {
display: flex;
align-items: center;
flex-wrap: wrap;
justify-content: space-around;
background-color: #f8f8f8;
padding: 0 30rpx;
.operation-item {
width: 120rpx;
padding: 30rpx 0;
.item-btn {
display: flex;
align-items: center;
justify-content: center;
width: 120rpx;
height: 120rpx;
background-color: #fff;
border-radius: 16rpx;
image {
width: 50rpx;
height: 50rpx;
}
}
.item-hint {
text-align: center;
font-size: 24rpx;
font-family: PingFang SC;
font-weight: 500;
color: #999999;
margin-top: 13rpx;
}
}
}
}
.bottom-box {
max-height: 300rpx;
overflow-y: auto;
}
.emoji-box {
padding: 0 30rpx 30rpx;
.emoji {
margin: 10rpx;
font-size: 48rpx;
}
}
.audio-box {
height: 300rpx;
display: flex;
justify-content: center;
align-items: center;
.circle {
margin: 0 100rpx;
width: 150rpx;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.audio-icon {
width: 120rpx;
height: 120rpx;
border-radius: 50%;
margin-bottom: 20rpx;
}
}
}
.ait-box {
width: 750rpx;
height: 850rpx;
background-color: #fff;
z-index: 999;
.ab-title {
position: relative;
display: flex;
justify-content: center;
align-items: center;
margin-top: 40rpx;
.abt-close {
position: absolute;
top: 10rpx;
left: 40rpx;
}
.abt-txt {
font-size: 28rpx;
font-family: PingFang SC-Medium, PingFang SC;
font-weight: 500;
color: #000000;
}
}
.ab-item {
width: 750rpx;
height: 120rpx;
display: flex;
padding: 0 40rpx;
align-items: center;
&:hover {
background-color: #EEEEEE;
}
.abi-all {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
margin-right: 30rpx;
background-color: #FFEBED;
text-align: center;
line-height: 80rpx;
font-size: 36rpx;
font-family: SF Pro Display-Medium, SF Pro Display;
font-weight: 500;
color: #FB3A4E;
}
.abi-img {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
margin-right: 30rpx;
}
.abi-name {
font-size: 28rpx;
font-family: PingFang SC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
}
}
}
.ipt-wrp {
margin: 18rpx auto;
position: relative;
width: 690rpx;
.ipt-icon {
position: absolute;
left: 28rpx;
height: 24rpx;
width: 24rpx;
top: 20rpx;
}
.ipt {
width: 100%;
height: 64rpx;
background: #f6f6f6;
border-radius: 32rpx;
font-size: 28rpx;
color: #999;
padding-left: 76rpx;
}
}
</style>

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-26 14:32:03
* @LastEditors: ch
* @LastEditTime: 2022-05-19 14:05:29
* @LastEditTime: 2022-05-20 10:02:52
* @Description: file content
-->
<template>
@ -47,7 +47,7 @@
</template>
<script>
import {MSG_TYPE} from '@/common/dicts/im';
import {MsbWebSkt, createUUID} from '@/common/utils';
import {MsbWebSkt, CreateUUID} from '@/common/utils';
import {MsbSktCreateSession, MsbSktGetHistoryMsg, MsbSktSetRead} from '@/common/utils/webSkt';
import {ApiGetOrderDetail} from '@/common/api/order';
import {ApiGetGoodsDetail} from '@/common/api/goods';

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-26 14:32:03
* @LastEditors: ch
* @LastEditTime: 2022-05-17 16:22:13
* @LastEditTime: 2022-05-20 10:02:50
* @Description: file content
-->
<template>
@ -21,7 +21,7 @@
</view>
</template>
<script>
import {MsbWebSkt, createUUID} from '@/common/utils';
import {MsbWebSkt, CreateUUID} from '@/common/utils';
export default {
data(){
return {
@ -60,7 +60,7 @@ export default {
const lastMsg = this.msgData[this.msgData.length - 1] || {};
MsbWebSkt.send({
data : JSON.stringify({
traceId : createUUID(),
traceId : CreateUUID(),
traceType : "2",
content: {
sessionId : this.$store.state.sessionMsgId,
@ -75,7 +75,7 @@ export default {
readMsg(){
MsbWebSkt.send({
data : JSON.stringify({
traceId : createUUID(),
traceId : CreateUUID(),
traceType : "6",
content: {
sessionId : this.$store.state.sessionMsgId

@ -36,7 +36,7 @@
</view>
</template>
<script>
import {formatDate} from '@/common/utils';
import {FormatDate} from '@/common/utils';
export default {
props : {
data : {
@ -85,7 +85,7 @@ export default {
return currentTime.getDate() === activityTime.getDate();
},
startDate(){
return formatDate(this.data.activityStartTime, 'm月d日hh:ii')
return FormatDate(this.data.activityStartTime, 'm月d日hh:ii')
}
},
methods:{

@ -47,7 +47,7 @@
</template>
<script>
import {formatDate} from '@/common/utils';
import {FormatDate} from '@/common/utils';
import {ApiGetGoodsDetail, ApiGetGoodsSkus} from '@/common/api/goods';
import SlideImage from './components/SlideImage.vue';
import Service from './components/Service.vue';
@ -107,9 +107,9 @@ export default {
if(seckillVO.isActivity){
seckillVO = {
...seckillVO,
activityStartTime :formatDate(seckillVO.activityStartTime,'yyyy/MM/dd hh:ii:ss'),
activityEndTime : formatDate(seckillVO.activityEndTime,'yyyy/MM/dd hh:ii:ss'),
currentTime : formatDate(seckillVO.currentTime,'yyyy/MM/dd hh:ii:ss'),
activityStartTime :FormatDate(seckillVO.activityStartTime,'yyyy/MM/dd hh:ii:ss'),
activityEndTime : FormatDate(seckillVO.activityEndTime,'yyyy/MM/dd hh:ii:ss'),
currentTime : FormatDate(seckillVO.currentTime,'yyyy/MM/dd hh:ii:ss'),
}
}
//

@ -31,7 +31,7 @@
</view>
</template>
<script>
import { IsPhone,MsbWebSkt, MsbWebSktInit, createUUID } from '@/common/utils';
import { IsPhone,MsbWebSkt, MsbWebSktInit, CreateUUID } from '@/common/utils';
import { MsbSktInit, MsbSktGetSessionList} from '@/common/utils/webSkt';
import { ApiGetCode, ApiPostLogin } from '@/common/api/index';
import { ApiPostThirdInfo } from '@/common/api/wx';

Loading…
Cancel
Save