index.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. import api from '@/api'
  2. import { getLanguage, getUserOpt, setUserOpt, mobileInputBlur } from '@/util/util'
  3. import { mapState } from 'vuex'
  4. import _ from 'lodash'
  5. // 搜索mixin
  6. export const searchUserMixin = {
  7. data () {
  8. return {
  9. isSearch: false, // 搜索展示
  10. searchList: null // 搜索结果
  11. }
  12. },
  13. methods: {
  14. searchUser (e, originList) {
  15. let val = e.target.value.toLocaleLowerCase()
  16. if (!val) {
  17. this.isSearch = false
  18. return
  19. }
  20. this.searchList = originList.filter(item => {
  21. let inName, inNick
  22. let name = (item.name || item.user_name || '').toLocaleLowerCase()
  23. let nickName = (item.nick_name || '').toLocaleLowerCase()
  24. inName = name ? name.indexOf(val) > -1 : false
  25. inNick = nickName ? nickName.indexOf(val) > -1 : false
  26. return inName || inNick
  27. })
  28. this.isSearch = true
  29. }
  30. }
  31. }
  32. // 群搜索mixin
  33. export const searchGroupUserMixin = {
  34. data () {
  35. return {
  36. showNum: 0,
  37. isSearchGroup: false,
  38. searchUserTimer: null,
  39. searchGroupList: []
  40. }
  41. },
  42. methods: {
  43. async searchUser (e, originList) {
  44. if (!e) return
  45. clearTimeout(this.searchUserTimer)
  46. this.searchUserTimer = setTimeout(async () => {
  47. let val = e.target.value.toLocaleLowerCase()
  48. let inviteType = this.inviteType
  49. this.isSearchGroup = true
  50. if (!val.trim()) {
  51. originList.forEach(item => {
  52. this.$set(item, 'isShow', true)
  53. })
  54. this.$nextTick(() => {
  55. this.isSearchGroup = false
  56. this.showNum = originList.length
  57. originList = this.originListCache
  58. })
  59. return
  60. }
  61. // 当前数据搜索
  62. originList.forEach(item => {
  63. let inName, inNick
  64. let name = (item.user_name || '').toLocaleLowerCase()
  65. let nickName = (item.nick_name || '').toLocaleLowerCase()
  66. inName = name ? name.indexOf(val) > -1 : false
  67. inNick = nickName ? nickName.indexOf(val) > -1 : false
  68. this.$set(item, 'isShow', inName || inNick)
  69. })
  70. // 接口搜索
  71. if (!(originList.length + 1 >= this.membersNum || inviteType == 1 || inviteType == 2)) {
  72. await api.group.searchMember({
  73. group_id: this.group.groupId,
  74. keyword: val
  75. }).then(({ data }) => {
  76. let list = data.data
  77. list.forEach(item => {
  78. item.isChecked = false
  79. item.isChoosed = false
  80. item.isShow = true
  81. })
  82. originList = _.unionBy([...originList, ...list], 'user_id')
  83. })
  84. }
  85. this.searchGroupList = originList
  86. this.$nextTick(() => {
  87. this.showNum = originList.filter(item => {
  88. return item.isShow
  89. }).length
  90. })
  91. }, 200)
  92. }
  93. }
  94. }
  95. // @人
  96. export const chatAtMixin = {
  97. data () {
  98. return {
  99. atInd: 0 // @人索引
  100. }
  101. },
  102. methods: {
  103. atPerson (name, nickName = name) {
  104. let el = this.$refs.chatInput
  105. let selectionStart = el.selectionStart
  106. let realStart = selectionStart - this.keyAfterAt.length
  107. this.inputMsg = this.inputMsg.slice(0, realStart) + `${name} ` + this.inputMsg.slice(selectionStart)
  108. this.atInd = 0
  109. el.focus()
  110. this.$nextTick(() => {
  111. el.setSelectionRange(realStart + name.length + 1, realStart + name.length + 1)
  112. })
  113. this.$store.commit('updateIsNewAt', {
  114. isNewAt: this.group.isNewAt,
  115. isNewAtFound: true
  116. })
  117. this.$store.commit('updateGroupSearchList', [])
  118. },
  119. handleUp (event) {
  120. if (this.atInd > 0) {
  121. this.atInd--
  122. }
  123. this.atShow && event.preventDefault()
  124. return true
  125. },
  126. handleDown (event) {
  127. let membersLen = this.filterMembers.length
  128. this.atInd < membersLen - 1 ? this.atInd++ : this.atInd = 0
  129. this.atShow && event.preventDefault()
  130. return true
  131. }
  132. }
  133. }
  134. // 聊天输入框
  135. export const chatInputMixin = {
  136. data () {
  137. return {
  138. selectionAfterAt: false, // 光标在@后面
  139. keyAfterAt: '', // 光标后的搜索字
  140. keyAfterAtTimer: '', // 光标后的搜索字触发定时器
  141. lastKeyAfterAt: '',
  142. isIOS: !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/),
  143. isShowContextmenu: false,
  144. menuTop: 0, // 右键菜单-top
  145. menuLeft: 0 // 右键菜单-left
  146. }
  147. },
  148. mounted () {
  149. },
  150. computed: {
  151. ...mapState([
  152. 'copyText'
  153. ]),
  154. filterMembers () {
  155. if (!this.group.groupId) return []
  156. let members = this.group.membersArray
  157. let resArr = []
  158. if (this.keyAfterAt !== '') {
  159. resArr = this.group.searchList
  160. } else {
  161. for (let k = 0; k < members.length; k++) {
  162. if (members[k].user_id == this.userId) continue
  163. resArr.push(members[k])
  164. }
  165. }
  166. return resArr.slice(0, 100)
  167. },
  168. atShow () {
  169. this.atInd = 0
  170. return this.selectionAfterAt && this.filterMembers.length
  171. }
  172. },
  173. watch: {
  174. keyAfterAt (val) {
  175. clearTimeout(this.keyAfterAtTimer)
  176. this.keyAfterAtTimer = setTimeout(() => {
  177. this.handleKeyAfterAt(val)
  178. }, 200)
  179. },
  180. inputMsg (val, newval) {
  181. this.handleSelectionChange()
  182. }
  183. },
  184. methods: {
  185. handleKeyAfterAt (val) {
  186. if (!this.group.groupId || val.trim() == '') return
  187. if (this.group.isNewAtFound) return
  188. if (this.group.membersArray.length < this.group.membersNum) {
  189. api.group.searchMember({
  190. group_id: this.group.groupId,
  191. keyword: val
  192. }).then(({ data }) => {
  193. this.$store.commit('updateGroupSearchList', data.data)
  194. })
  195. } else {
  196. let searchList = this.group.membersArray.filter(item => {
  197. let inName, inNick
  198. inName = item.user_name ? item.user_name.indexOf(val) > -1 : false
  199. inNick = item.nick_name ? item.nick_name.indexOf(val) > -1 : false
  200. return inName || inNick
  201. })
  202. this.$store.commit('updateGroupSearchList', searchList)
  203. }
  204. },
  205. getStrBeforeSelection () {
  206. let el = this.$refs.chatInput
  207. if (!el) return ''
  208. let selectionStart = el.selectionStart
  209. let prevStr = this.inputMsg.slice(0, selectionStart)
  210. return prevStr
  211. },
  212. getStrAfterSelection () {
  213. let el = this.$refs.chatInput
  214. if (!el) return ''
  215. let selectionStart = el.selectionStart
  216. let prevStr = this.inputMsg.slice(selectionStart)
  217. return prevStr
  218. },
  219. handleClick () {
  220. this.isShowContextmenu = false
  221. },
  222. handleLeft (event) {
  223. let el = this.$refs.chatInput
  224. let selectionStart = el.selectionStart
  225. if (selectionStart === 0) return true
  226. let prevStr = this.getStrBeforeSelection()
  227. let members = this.group.members
  228. for (let k in members) {
  229. let name = members[k].user_name
  230. let reg = new RegExp(`@${name} $`)
  231. if (reg.test(prevStr)) {
  232. event.preventDefault()
  233. el.setSelectionRange(selectionStart - name.length - 2, selectionStart - name.length - 2)
  234. return true
  235. }
  236. }
  237. },
  238. handleRight (event) {
  239. let el = this.$refs.chatInput
  240. let selectionStart = el.selectionStart
  241. let afterStr = this.getStrAfterSelection()
  242. let members = this.group.members
  243. for (let k in members) {
  244. let name = members[k].user_name
  245. let reg = new RegExp(`^@${name} `)
  246. if (reg.test(afterStr)) {
  247. event.preventDefault()
  248. el.setSelectionRange(selectionStart + name.length + 2, selectionStart + name.length + 2)
  249. return true
  250. }
  251. }
  252. return true
  253. },
  254. handleDel (event) {
  255. let el = this.$refs.chatInput
  256. let selectionStart = el.selectionStart
  257. if (selectionStart === 0) return
  258. let prevStr = this.getStrBeforeSelection()
  259. let members = this.group.members
  260. for (let k in members) {
  261. let name = members[k].user_name
  262. let reg = new RegExp(`@${name} $`)
  263. if (reg.test(prevStr)) {
  264. event.preventDefault()
  265. this.inputMsg = this.inputMsg.slice(0, selectionStart - name.length - 2) + this.inputMsg.slice(selectionStart)
  266. this.$nextTick(() => {
  267. el.setSelectionRange(selectionStart - name.length - 2, selectionStart - name.length - 2)
  268. })
  269. return
  270. }
  271. }
  272. },
  273. handleKeyDown (event) {
  274. if (this.atShow) {
  275. event.preventDefault()
  276. let item = this.filterMembers[this.atInd]
  277. this.atPerson(item.user_name, item.nick_name)
  278. return
  279. }
  280. if (event.altKey || event.ctrlKey) {
  281. let beforeStr = this.getStrBeforeSelection()
  282. let afterStr = this.getStrAfterSelection()
  283. // 单纯换行
  284. this.inputMsg = beforeStr + '\n' + afterStr
  285. this.$nextTick(() => {
  286. this.$refs.chatInput.setSelectionRange(beforeStr.length + 1, beforeStr.length + 1)
  287. })
  288. } else {
  289. this.handleSend(event)
  290. event.preventDefault()
  291. }
  292. return true
  293. },
  294. handleFocus () {
  295. this.$emit('handleFocus') // 针对完整版
  296. this.updateChatInputFocus(true)
  297. document.addEventListener('selectionchange', this.handleSelectionChange)
  298. if (this.isIOS) {
  299. setTimeout(() => {
  300. this.$root.$el.addEventListener('click', this.fixIOS)
  301. }, 0)
  302. }
  303. },
  304. handleBlur () {
  305. document.removeEventListener('selectionchange', this.handleSelectionChange)
  306. this.updateChatInputFocus(false)
  307. // 定时防止@列表/右键粘贴点击前消失
  308. if (this.selectionAfterAt || this.isShowContextmenu) {
  309. setTimeout(() => {
  310. this.selectionAfterAt = false
  311. this.isShowContextmenu = false
  312. }, 200)
  313. }
  314. if (this.isIOS) {
  315. let scrollTop = document.body.scrollTop
  316. document.body.scrollTop = scrollTop
  317. this.$root.$el.removeEventListener('click', this.fixIOS)
  318. }
  319. mobileInputBlur()
  320. },
  321. handleEsc () {
  322. this.selectionAfterAt = false
  323. },
  324. /**
  325. * 监听光标位置
  326. */
  327. handleSelectionChange () {
  328. let el = this.$refs.chatInput
  329. if (!el) return
  330. let selectionStart = el.selectionStart
  331. let selectionEnd = this.$refs.chatInput.selectionEnd
  332. if (selectionStart !== selectionEnd) return
  333. let prevStr = this.getStrBeforeSelection()
  334. this.selectionAfterAt = /@/.test(prevStr)
  335. if (this.selectionAfterAt) {
  336. this.keyAfterAt = prevStr.slice(prevStr.lastIndexOf('@') + 1)
  337. let isNewAt = this.keyAfterAt.indexOf(this.lastKeyAfterAt) < 0
  338. this.$store.commit('updateIsNewAt', {
  339. isNewAt: isNewAt,
  340. isNewAtFound: isNewAt ? false : this.group.isNewAtFound
  341. })
  342. if (isNewAt) this.$store.commit('updateGroupSearchList', [])
  343. this.lastKeyAfterAt = this.keyAfterAt
  344. }
  345. },
  346. // 监听右键
  347. handleContextmenu (ev) {
  348. if (!this.copyText) return
  349. this.isShowContextmenu = !this.isShowContextmenu
  350. if (this.isShowContextmenu) {
  351. this.menuTop = ev.offsetY
  352. this.menuLeft = ev.offsetX > 100 ? ev.offsetX - 30 : ev.offsetX
  353. }
  354. },
  355. // 监听粘贴
  356. handlePaste () {
  357. this.isShowContextmenu = false
  358. this.inputMsg += this.copyText
  359. },
  360. // 关闭emoji面板
  361. closeEmojiList () {
  362. this.emojiShow = false
  363. },
  364. fixIOS (event) {
  365. setTimeout(() => {
  366. if (this.$refs.chatInput === document.activeElement) {
  367. document.activeElement.blur()
  368. }
  369. }, 0)
  370. }
  371. }
  372. }
  373. //
  374. export const addPanelSessionMixin = {
  375. methods: {
  376. addPanelSession (serverId, sessionId) {
  377. // 先判断serverId有没有在sessionList
  378. let isInSession = this.sessionList.some(v => {
  379. return v.session_id == sessionId
  380. })
  381. if (!isInSession) {
  382. // 没有就加入一个会话
  383. api.user.getOtherInfo({
  384. target_id: serverId
  385. }).then(({ data }) => {
  386. let userInfo = data.data
  387. let obj = {
  388. cover_photo: userInfo.cover_photo,
  389. is_group: '0',
  390. name: userInfo.nick_name,
  391. session_id: sessionId,
  392. unread: 0
  393. }
  394. this.$store.commit('addSessionItem', obj)
  395. })
  396. }
  397. }
  398. }
  399. }
  400. // 切换语言
  401. export const changeLangMixin = {
  402. data () {
  403. return {
  404. curLang: getUserOpt('lang') || getLanguage()
  405. }
  406. },
  407. methods: {
  408. changeLang () {
  409. let changeLang = this.curLang == 'en' ? 'zh' : 'en'
  410. this.$i18n.locale = changeLang
  411. this.curLang = changeLang
  412. // localStorage.setItem('lang', changeLang)
  413. setUserOpt('lang', changeLang)
  414. }
  415. }
  416. }