123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484 |
- import { mapActions, mapState, mapMutations } from 'vuex'
- import { scrollMsgIntoView } from '@/util/util.js'
- import { emojiList } from '@/util/emoji'
- import { Message } from 'element-ui'
- import ImageMin from '@/util/imageMin.js'
- // 聊天mixin 用于chatRoom组件
- export const chatMixin = {
- watch: {
- '$route' () {
- this.bdHiden = true
- // 切换房间
- this.groupSet = false
- this.lockMore = false
- this.lockEnd = false
- this.enableScroll = false
- this.initRoom()
- },
- unreadNums (val, newval) {
- if (val > 0 && this.isBottom) {
- setTimeout(this.resizeToBottom.bind(this), 150)
- }
- },
- chatList (val) {
- let lastVal = val[val.length - 1]
- if (lastVal && lastVal.msg_type == 4) {
- // 自己发的红包自动滚动到底部
- this.$nextTick(this.resizeToBottom)
- }
- },
- isJoinGroup (val) {
- if (val == 1) setTimeout(this.resizeToBottom.bind(this), 100)
- }
- },
- data () {
- return {
- groupSet: false,
- lockMore: false,
- lockEnd: false,
- enableScroll: false, // 记录滚动条是否激活的状态
- isBottom: true,
- scrollHeight: 100, // 滚动条高度
- isScrollToView: false,
- isShowGroudMgr: false // 是否显示群管理
- }
- },
- computed: {
- ...mapState(['group', 'userId', 'userInfo', '']),
- ...mapState({
- creator: state => state.group.creator,
- isJoin: state => state.group.isJoin,
- pinMsg: state => state.group.pinMsg,
- pinList: state => state.group.pinList,
- atList: state => state.group.atList,
- unreadNums: state => state.group.unreadNums,
- chatList: state => state.group.chatList,
- members: state => state.group.members,
- sessionId: state => state.curSession,
- sessionInfo: state => state.group.sessionInfo
- }),
- isPrivate () {
- return this.$store.getters.isPrivate
- },
- isCreator () {
- return this.userId == this.creator
- },
- isJoinGroup () {
- if (this.group && this.group.groupId) {
- return this.isJoin ? 1 : 0
- } else {
- return 1
- }
- }
- },
- mounted () {
- this.initRoom()
- document.addEventListener('contextmenu', e => e.preventDefault())
- },
- methods: {
- ...mapMutations([
- 'initGroup',
- 'resetUnreadNums',
- 'addChatItem',
- 'deleteChatItem',
- 'initState',
- 'clearAtList',
- 'curSession',
- 'setSessionItemUnread'
- ]),
- ...mapActions([
- 'getGroupInfo',
- 'getUserInfo',
- 'getNewMsg',
- 'getHistoryMsg',
- 'doSendMsg',
- 'getPrivateNewMsg',
- 'getPrivateHistoryMsg',
- 'doSendPrivateMsg'
- ]),
- async initRoom () {
- if (!this.userInfo) {
- await this.getUserInfo()
- }
- this.$store.commit('changeSessionId', this.$route.params.id)
- this.initState(this.userInfo)
- if (this.isPrivate) {
- this.initPersonChat()
- } else {
- this.initGroupChat()
- }
- },
- /**
- * @des 私聊初始化处理
- */
- async initPersonChat () {
- await this.getPrivateNewMsg()
- this.$nextTick(() => {
- this.resizeToBottom()
- this.bdHiden = false
- })
- },
- /**
- * @des 聊天群初始化处理
- */
- async initGroupChat () {
- this.initGroup({
- userId: this.userId,
- groupId: this.sessionId,
- useCache: false
- })
- this.isShowGroudMgr = false
- await this.getGroupInfo()
- await this.getNewMsg()
- this.$nextTick(() => {
- this.resizeToBottom()
- this.bdHiden = false
- })
- },
- /**
- * @des 滚动事件监听
- */
- initScrollEvent () {},
- /**
- * @des 聊天窗体滚动事件处理集
- */
- async handleScroll (e) {
- // 防止切换房间时触发滚动处理
- if (!this.group.chatList.length) {
- return
- }
- // 防止滚动到置顶消息触发滚动
- if (this.isScrollToView) {
- return
- }
- // 激活滚动条
- this.enableScroll = true
- let totalHeight = this.$refs.msgWrap.offsetHeight
- let scrollTop = e.target.scrollTop
- // 差不多滚动到顶部
- if (scrollTop === 0 && !this.lockMore) {
- if (this.group.endHash !== null) {
- this.lockMore = true
- let res
- if (this.isPrivate) {
- res = await this.getPrivateHistoryMsg()
- } else {
- res = await this.getHistoryMsg()
- }
- if (res === 'end') {
- this.lockEnd = true
- } else {
- let scrollBottom = totalHeight - scrollTop
- this.$nextTick(() => {
- e.target.scrollTop =
- this.$refs.msgWrap.offsetHeight - scrollBottom
- setTimeout(() => {
- this.lockMore = false
- }, 800)
- })
- }
- }
- }
- // 滚动到底部清空未读消息状态
- if (scrollTop + e.target.offsetHeight > totalHeight) {
- this.isBottom = true
- if (this.group.unreadNums) {
- this.resetUnreadNums()
- }
- } else {
- this.isBottom = false
- }
- },
- /**
- * @des 聊天窗体滚动到底部
- */
- resizeToBottom () {
- this.$refs.scrollWrap.scrollTop = this.$refs.msgWrap.offsetHeight
- this.resetUnreadNums()
- this.isBottom = true
- },
- /**
- * @des 点击,查看未读消息
- * 直接滚动到聊天列表底部
- */
- doSetRead () {
- this.resizeToBottom()
- },
- /**
- * @des 引用某条消息
- */
- quoteMsg (msg) {
- this.$refs.inputArea.inputMsg = msg
- },
- /**
- * @des 某条消息被删除
- */
- deleteMsg (hash) {
- this.deleteChatItem(hash)
- },
- pinMsgClose () {
- this.pinMsg.visible = false
- },
- scrollToView () {
- if (this.pinList.length) {
- let node = this.$refs.msgWrap.querySelector('.msg-item')
- scrollMsgIntoView(
- this.$refs.scrollWrap,
- node.offsetTop - (this.pinMsg ? 40 : 10),
- node
- )
- } else {
- let hash = this.pinMsg.hash
- let index = this.group.chatList.findIndex(item => item.hash === hash)
- if (index >= 0) {
- let node = this.$refs.msgWrap
- .querySelectorAll('.msg-item')
- .item(index)
- scrollMsgIntoView(
- this.$refs.scrollWrap,
- node.offsetTop - (this.pinMsg ? 40 : 10),
- node
- )
- }
- }
- // 防止加载更多
- this.isScrollToView = true
- setTimeout(() => {
- this.isScrollToView = false
- }, 2000)
- },
- scrollToMsg (index) {
- let hash = this.atList[index].hash
- let eleIndex = this.group.chatList.findIndex(item => item.hash === hash)
- if (eleIndex >= 0) {
- let pinLen = this.group.pinList.length
- let node = this.$refs.msgWrap
- .querySelectorAll('.msg-item')
- .item(eleIndex + pinLen)
- scrollMsgIntoView(
- this.$refs.scrollWrap,
- node.offsetTop - (this.pinMsg ? 40 : 10),
- node
- )
- }
- this.clearAtList()
- },
- joinGroup () {
- this.$store.dispatch('joinGroup')
- },
- // 群管理
- showGroudMgr (flag) {
- this.isShowGroudMgr = flag == 1
- }
- }
- }
- // 聊天输入框mixin
- export const inputMixin = {
- computed: {
- ...mapState(['group', 'userId', 'curSession']),
- ...mapState({
- chatInputFocus: state => state.group.chatInputFocus,
- blockList: state => state.group.blockList
- }),
- isPrivate () {
- return this.$store.getters.isPrivate
- },
- emojiMap () {
- var emojiMap = {}
- for (let i in emojiList) {
- let arr = emojiList[i]
- arr.forEach(v => {
- let names = JSON.stringify(v.names)
- let emoji = v.surrogates
- emojiMap[names] = emoji
- })
- }
- return emojiMap
- }
- },
- data () {
- return {
- emojiShow: false,
- inputMsg: '',
- atInd: 0
- }
- },
- mounted () {
- document.body.addEventListener('click', () => {
- this.emojiShow = false
- })
- },
- methods: {
- ...mapMutations(['updateChatInputFocus', 'addChatItem']),
- ...mapActions(['doSendMsg', 'doSendFile', 'doSendPrivateMsg']),
- addEmoji (val) {
- this.inputMsg += val
- this.emojiShow = false
- this.$refs.chatInput.focus()
- },
- /**
- * @des 处理消息发送
- */
- handleSend (e) {
- // 判断是否被禁言
- if (this.blockList.some(id => id == this.userId)) {
- Message({
- message: '您已被禁言',
- type: 'error'
- })
- return
- }
- // 替换emoji字符串
- let _inputMsg = this.inputMsg
- for (let k in this.emojiMap) {
- if (_inputMsg.indexOf(k) > -1) {
- let reg = new RegExp(k, 'g')
- _inputMsg = _inputMsg.replace(reg, this.emojiMap[k])
- }
- }
- let text = _inputMsg.trim()
- if (text.length === 0) {
- Message({
- message: '聊天内容不能为空',
- type: 'warning'
- })
- return
- }
- let opt = {
- type: 0,
- msg: text
- }
- // 用户不是第一次发言
- if (this.group.members[this.userId]) {
- let createTime = Date.now()
- this.addChatItem({
- from: this.userId,
- content: text,
- hash: `${createTime}`,
- timestamp: createTime,
- createTime,
- msg_type: '0',
- loading: true
- })
- opt.createTime = createTime
- }
- this.$store.commit('setSessionItemUnread', {
- session_id: this.curSession,
- unread: 0,
- curSession: this.curSession,
- cont: this.inputMsg
- })
- this.isPrivate ? this.doSendPrivateMsg(opt) : this.doSendMsg(opt)
- // 滚到底部
- this.$nextTick(function () {
- this.inputMsg = ''
- this.resizeToBottom ? this.resizeToBottom() : this.$emit('toBottom')
- })
- e.preventDefault()
- return false
- },
- /**
- * 文件预处理
- * @return {Object} data 预处理文件信息
- * @param {Number} data.type
- * @param {File} data.res
- */
- async preHandleFile (file) {
- let type = file.type
- let size = file.size
- if (type.match('video')) {
- return size > 3 * 1024 * 1024
- ? Promise.reject(new Error(file))
- : Promise.resolve({
- type: 2,
- res: file
- })
- } else if (type.match('audio')) {
- return size > 2 * 1024 * 1024
- ? Promise.reject(new Error(file))
- : Promise.resolve({
- type: 3,
- res: file
- })
- } else if (type.match('image')) {
- let image = await new ImageMin({
- file: file,
- maxSize: 1024 * 1024
- })
- return {
- type: 1,
- preview: image.base64,
- res: image.res
- }
- }
- },
- /**
- * @des 处理文件发送
- */
- async handleFile (e) {
- let inputfile
- if (e.constructor === File) {
- inputfile = e
- } else {
- inputfile = e.target.files[0]
- }
- try {
- let fileInfo = await this.preHandleFile(inputfile)
- let opt = { res: fileInfo.res }
- if (this.group.members[this.userId]) {
- let createTime = Date.now()
- this.addChatItem({
- content: fileInfo.preview || '',
- from: this.userId,
- hash: `${createTime}`,
- msg_type: fileInfo.type,
- timestamp: createTime,
- res: fileInfo.res,
- loading: true,
- createTime
- })
- opt.createTime = createTime
- }
- this.doSendFile(opt)
- setTimeout(() => {
- if (this.$refs.inputFile) {
- this.$refs.inputFile.value = null
- }
- if (this.$refs.inputFile1) {
- this.$refs.inputFile1.value = null
- }
- if (this.$refs.inputFile2) {
- this.$refs.inputFile2.value = null
- }
- if (this.$refs.inputFile3) {
- this.$refs.inputFile3.value = null
- }
- this.resizeToBottom ? this.resizeToBottom() : this.$emit('toBottom')
- }, 100)
- } catch (error) {
- Message({
- message: '上传文件大小限制:音频2M以内,视频3M以内',
- type: 'warning'
- })
- }
- }
- }
- }
|