ConversationItem.class.js 13.4 KB
Newer Older
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1
import {watch,computed} from 'vue'
DCloud_JSON's avatar
DCloud_JSON 已提交
2 3
import $state from '@/uni_modules/uni-im/sdk/state/index.js';
import $utils from '@/uni_modules/uni-im/sdk/utils/index.js';
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
4 5
import $extensions from '@/uni_modules/uni-im/sdk/methods/extensions.js';
import Msg from '@/uni_modules/uni-im/sdk/state/Msg.class.js'
DCloud_JSON's avatar
DCloud_JSON 已提交
6 7 8 9
const db = uniCloud.database();
/**
 * 会话类,实现会话相关的业务逻辑。
 */
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
10
class ConversationItem {
DCloud_JSON's avatar
DCloud_JSON 已提交
11 12 13
  constructor(data) {
    // 检查是否关联用户/群被删除
    if (!data.group_id && !data.user_info) {
14 15 16
      // 删除本地生成的 data.client_create_time 避免错误重复上报
      delete data.client_create_time
      throw new Error('会话列表失效,疑似关联用户/群被删除(请改为软删除避免系统异常)data:'+JSON.stringify(data));
DCloud_JSON's avatar
DCloud_JSON 已提交
17 18 19 20 21
    }
    // 对话框消息内容
    this.chatInputContent = ""
    // @我的消息id列表
    this.call_list = []
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
22 23 24
    
    this.msg = new Msg(data.id)
    
DCloud_JSON's avatar
DCloud_JSON 已提交
25 26 27 28 29 30
    // 客户端创建此会话的时间
    this.client_create_time = Date.now()
    // 是否已离开(退出、被踢出)群聊
    this.leave = false
    // 默认不置顶
    this.pinned = false
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
31 32
    
    this.tags = []
DCloud_JSON's avatar
DCloud_JSON 已提交
33 34

    // 是否已经初始化。 从缓存中取出的会话数据可能已经初始化,这里需要归零
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
35
    data.isInit = true
DCloud_JSON's avatar
DCloud_JSON 已提交
36 37 38 39
    Object.assign(this, data)

    if (this.group_id) {
      // 群聊
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
40 41 42 43
      this.group = $state.group.find(this.group_id)
      if (!this.group) {
        console.error('群聊本地不存在 this.group_id', this.group_id);
        // throw new Error('群聊不存在')
DCloud_JSON's avatar
DCloud_JSON 已提交
44 45 46 47
      }

      // 2. 设置群tag
      // 调用扩展点,扩展程序可以为该会话增加 tag。
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
48 49 50 51 52 53 54 55
      Promise.all($extensions.invokeExts('conversation-tags', this))
        .then(tags => {
          tags = tags.filter(tag => tag)
          if (tags.length === 0) {
            this.tags = ['群聊']
          }else{
            // 需要绕一圈,否则无法触发响应式
            $state.conversation.find(this.id).tags = tags
DCloud_JSON's avatar
DCloud_JSON 已提交
56
          }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
57
        })
DCloud_JSON's avatar
DCloud_JSON 已提交
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76

      // 3. 初始化字段:群简介、群公告、群头像
      const fieldList = [{
          "introduction": ""
        }, {
          "notification": {
            "content": false
          }
        }, {
          "avatar_file": {
            "url": ""
          }
        },
        {
          "mute_all_members": false // 全员禁言
        }
      ]
      fieldList.forEach(item => {
        const key = Object.keys(item)[0]
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
77 78
        if (!this.group[key]) {
          this.group[key] = item[key]
DCloud_JSON's avatar
DCloud_JSON 已提交
79 80 81 82 83 84 85
        }
      })
      // 4. 非单聊,不需要用户信息
      // this.user_info = false
    } else {
      // 单聊
      // 非单聊,不需要群消息
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
86 87 88 89 90
      this.group = false
      const real_name = this.user_info?.realname_auth?.real_name
      if (real_name){
        this.tags = [real_name]
      }
DCloud_JSON's avatar
DCloud_JSON 已提交
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
    }
    
    // 初始化响应式属性
    this.activeProperty().init()
  }
  /**
   * 会话未读消息数清零。
   */
  clearUnreadCount() {
    // console.log('clearUnreadCount');
    setTimeout(() => {
      this.unread_count = 0
    }, 100);
    // console.log('clearUnreadCount this.id', this.id)
    // 触发器会触发消息表的 is_read = true
    uniCloud.database()
      .collection('uni-im-conversation')
      .where({
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
109
        user_id: $state.currentUser._id,
DCloud_JSON's avatar
DCloud_JSON 已提交
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
        id: this.id
      })
      .update({
        "unread_count": 0
      }).then(e => {
        console.log('设置为已读', e.result.updated);
      }).catch(err => {
        console.error('设置为已读失败', err);
      })
  }

  /** 撤回消息。
   * @param {object} msg - 参数对象
   * @param {string} msg._id - 消息id
   * @param {string} msg.msg_id - 消息id和_id二选一
   * @param {string} msg.conversation_id - 所属会话的id
   * @param {number} msg.create_time - 创建时间
   * @param {boolean} [submit=true] -  是否需要提交;操作撤回端需要提交,被动撤回消息端无需提交
   */
  async revokeMsg(msg_id, submit = true) {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
130 131 132 133
    // 处理内存中显示中的数据
    const msg = this.msg.find(msg_id)
    if (!msg) {
      return console.warn('内存中没有找到此消息(当前用户可能还没点开相关会话),无需撤回', msg_id)
DCloud_JSON's avatar
DCloud_JSON 已提交
134
    }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
135
    // 是否为当前用户触发的撤回
DCloud_JSON's avatar
DCloud_JSON 已提交
136
    if (submit) {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
137 138 139 140 141
      // 保存撤回前的消息内容,用于方便点击重新编辑
      msg.before_revoke_body = msg.body
      // ui 界面上显示撤回中
      msg.revoke_ing = true
      // 提交操作到云端
DCloud_JSON's avatar
DCloud_JSON 已提交
142
      try {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
143 144
        const uniImCo = uniCloud.importObject("uni-im-co",{customUI:true})
        await uniImCo.sendMsg({
DCloud_JSON's avatar
DCloud_JSON 已提交
145
          "type": "revoke_msg",
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
146
          "body": {msg_id}
DCloud_JSON's avatar
DCloud_JSON 已提交
147 148 149
        })
      } catch (err) {
        console.log('err', err);
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
150 151 152 153
        // 撤回失败,还原数据
        msg.body = msg.before_revoke_body
        delete msg.before_revoke_body
        delete msg.revoke_ing
DCloud_JSON's avatar
DCloud_JSON 已提交
154 155 156 157 158
        return uni.showToast({
          title: err.message,
          icon: 'none'
        });
      }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
159 160
      // ui 界面上去掉撤回中
      delete msg.revoke_ing
DCloud_JSON's avatar
DCloud_JSON 已提交
161
    }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
162 163
    msg.is_revoke = true
    msg.body = '[此消息已被撤回]'
DCloud_JSON's avatar
DCloud_JSON 已提交
164 165 166 167 168 169 170
  }

  /**
   * 获取用户信息。
   */
  getUsersInfo() {
    // 群会话返回群成员信息,单聊返回对方用户信息
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
171
    return this.group_id ? this.group.member.dataList : {
DCloud_JSON's avatar
DCloud_JSON 已提交
172 173 174 175 176 177 178 179 180 181
      [this.user_info._id]: this.user_info
    }
  }
  /**
   * changeMute
   */
  changeMute() {
    this.mute = !this.mute
    const db = uniCloud.database();
    db.collection('uni-im-conversation')
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
182 183 184 185 186
      // 因为本地创建的会话没有_id,需通过user_id和id指定要操作的会话
      .where({
        user_id: this.user_id,
        id: this.id
      })
DCloud_JSON's avatar
DCloud_JSON 已提交
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
      .update({
        "mute": this.mute
      })
      .then((e) => {
        console.log('updated 消息免打扰设置', e.result.updated, this._id)
      })
      .catch(() => {
        uni.showToast({
          title: '服务端错误,消息免打扰设置失败,请稍后重试',
          icon: 'none'
        });
        this.mute = !this.mute
      })
  }
  /**
   * 设置响应式属性。
   * @param {Object} data
   */
  activeProperty(data) {
    this._leave = this.leave
    this._update_time = this.update_time || this.create_time
    const _conversation = this
    const activeProperty = {
      title() {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
211
        return _conversation.group_id ? _conversation.group.name : _conversation.user_info.nickname
DCloud_JSON's avatar
DCloud_JSON 已提交
212 213
      },
      avatar_file() {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
214
        return _conversation.group_id ? _conversation.group.avatar_file : _conversation.user_info.avatar_file
DCloud_JSON's avatar
DCloud_JSON 已提交
215 216 217
      },
      leave:{
        get() {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
218
          if (_conversation.msg.dataList.length === 0) {
DCloud_JSON's avatar
DCloud_JSON 已提交
219 220
            return _conversation._leave
          } else {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
221
            let last_msg = _conversation.msg.dataList[_conversation.msg.dataList.length - 1]
DCloud_JSON's avatar
DCloud_JSON 已提交
222
            //群被解散,或者被踢出
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
223
            return "group-dissolved" === last_msg.action || ["group-exit", "group-expel"].includes(last_msg.action) && last_msg.body.user_id_list.includes($state.currentUser._id)
DCloud_JSON's avatar
DCloud_JSON 已提交
224 225 226
          }
        },
        set(value){
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
227
          // console.log('set leave value',value)
DCloud_JSON's avatar
DCloud_JSON 已提交
228 229 230 231
          _conversation._leave = value
        }
      },
      isMuteAllMembers() {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
        try{
          if (!_conversation.group_id) return false
          const member = _conversation.group.member.find($state.currentUser._id)
          // console.log('member',member)
          return member && !member.role.includes('admin') && _conversation.group.mute_all_members
        }catch(e){
          console.error('isMuteAllMembers',e,_conversation)
          console.error('isMuteAllMembers',1,_conversation.group)
          console.error('isMuteAllMembers',2,_conversation.group.member)
          console.error('isMuteAllMembers',3,_conversation.group.member.find)
          console.error('isMuteAllMembers',4,typeof _conversation.group.member.find)
        }
      },
      // 最后一条可见消息
      _last_visible_msg() {
        // 拿到内存中的
        const visibleMsgList = _conversation.msg.visibleDataList()
        const vml = visibleMsgList.length
        return vml > 0 ? visibleMsgList[vml - 1] : false
DCloud_JSON's avatar
DCloud_JSON 已提交
251
      },
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
252
      // 最后一条可见消息的时间,也被用于排序会话
DCloud_JSON's avatar
DCloud_JSON 已提交
253
      time() {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
254 255 256 257 258
        // 如果存在最后一条可见消息,就用它的时间,否则用会话的更新时间 (注意:不能取最大值,因为消息被已读也会更新会话时间,此时会话无需重新排序)
       const last_visible_msg = _conversation._last_visible_msg
       let time = last_visible_msg ? (last_visible_msg.create_time || last_visible_msg.client_create_time) : _conversation.update_time
       // time 和本地自定义排序时间比较,取最大值。说明:customSortTime 是临时将会话排序提升到最前的时间。比如:在群成员列表/消息列表等 与某个用户起会话,临时将会话提升到最前等
       return Math.max(time, _conversation.customSortTime || 0)
DCloud_JSON's avatar
DCloud_JSON 已提交
259 260 261
      },
      // 最后一条可见消息的内容
      note() {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
262
        let note = _conversation.last_msg_note || '暂无聊天记录'
DCloud_JSON's avatar
DCloud_JSON 已提交
263 264 265 266 267 268 269 270 271
        // 如果输入框有文本未发出(草稿),直接覆盖消息
        let chatInputContent = _conversation.chatInputContent
        if (typeof chatInputContent === 'object') {
          chatInputContent = chatInputContent.text || '[富文本消息]'
        } else {
          // 把this.chatInputContent中的 变成空格,再把头尾的空格去掉
          chatInputContent = chatInputContent.replace(/ /g, ' ').trim()
        }
        _conversation.hasDraft = chatInputContent && $state.currentConversationId != _conversation.id
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
272
        let last_visible_msg = _conversation._last_visible_msg
DCloud_JSON's avatar
DCloud_JSON 已提交
273 274 275 276 277 278 279 280 281 282
        if (_conversation.hasDraft) {
          note = chatInputContent
          last_visible_msg = {
            body: chatInputContent,
            type: 'text'
          }
        }
        if (last_visible_msg) { // 如果存在最后一条消息
          const _last_visible_msg = JSON.parse(JSON.stringify(last_visible_msg))
          // console.error('last_visible_msg',_last_visible_msg)
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
283
          note = $utils.getMsgNote(last_visible_msg)
DCloud_JSON's avatar
DCloud_JSON 已提交
284
        }
285 286
        // 替换\\n \\r \n \r   < > & 为 空格
        note = note.replace(/\\n|\\r|\n|\r| |<|>|&/g, ' ')
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
287 288 289 290 291 292
        // 拿到发送消息的用户昵称
        const {nickname} =last_visible_msg
        if(_conversation.group_id && nickname){
          note = nickname + ': ' + note
        }
        
293
        return note.trim()
DCloud_JSON's avatar
DCloud_JSON 已提交
294 295 296 297 298 299 300
      },
      // 刷新会话的更新时间
      update_time:{
        get() {
          // console.log('refreshUpdateTime');
          // 拿到最后一条消息
          let update_time = _conversation._update_time
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
301
          let msgLength = _conversation.msg.dataList.length
DCloud_JSON's avatar
DCloud_JSON 已提交
302
          if (msgLength > 0) {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
303
            let last_msg = _conversation.msg.dataList[msgLength - 1]
DCloud_JSON's avatar
DCloud_JSON 已提交
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
            // 拿到最后一条消息的创建时间,消息发送成功之前没有create_time,用client_create_time
            let last_msg_time = last_msg.create_time || last_msg.client_create_time
            if (last_msg_time > update_time) {
              update_time = last_msg_time
            }
          }
          return update_time
        },
        set(value) {
          _conversation._update_time = value
        }
      }
    }
    
    let res = {
      init() {
        Object.keys(activeProperty).forEach(key => {
          let item = activeProperty[key];
          if (typeof activeProperty[key] != 'function') {
            item = activeProperty[key].get
          }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
325
          _conversation[key] = item()
DCloud_JSON's avatar
DCloud_JSON 已提交
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
        })
      },
      ...activeProperty
    }
    
    Object.defineProperty(res, 'init', {
      // 设置init方法不可枚举
      enumerable: false
    })
    return res
  }
  // 隐藏会话
  async hide() {
    console.log('hidden######');
    this.hidden = true
    let res = await db.collection('uni-im-conversation')
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
342 343 344 345 346
      // 因为本地创建的会话没有_id,需通过user_id和id指定要操作的会话
      .where({
        user_id: this.user_id,
        id: this.id
      })
DCloud_JSON's avatar
DCloud_JSON 已提交
347 348 349 350 351 352
      .update({
        "hidden": true
      })
    console.log('updated hidden', res)
    return res
  }
353 354 355 356 357 358
  // 设置未读消息数
  async setUnreadCount(count) {
    // console.log('setUnreadCount', count);
    const oldCount = this.unread_count
    this.unread_count = count
    let res = await db.collection('uni-im-conversation')
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
359 360 361 362 363
      // 因为本地创建的会话没有_id,需通过user_id和id指定要操作的会话
      .where({
        user_id: this.user_id,
        id: this.id
      })
364 365 366 367 368 369 370 371 372 373 374 375
      .update({
        "unread_count": count
      })
      .catch(err => {
        console.error('setUnreadCount err', err);
        this.unread_count = oldCount
      })
      .then(e => {
        // console.log('setUnreadCount updated', e.result.updated);
      })
    return res
  }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
  async changeIsStar() {
    const oldIsStar = this.is_star
    console.log('setIsStar', oldIsStar);
    this.is_star = !oldIsStar
    let res = await db.collection('uni-im-conversation')
      // 因为本地创建的会话没有_id,需通过user_id和id指定要操作的会话
      .where({
        user_id: this.user_id,
        id: this.id
      })
      .update({
        "is_star": this.is_star
      })
      .catch(err => {
        console.error('setIsStar err', err);
        this.is_star = oldIsStar
      })
      .then(e => {
        console.log('setUnreadCount updated', e.result.updated);
      })
    return res
  }
DCloud_JSON's avatar
DCloud_JSON 已提交
398 399
}

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
400
export default ConversationItem