Compare commits
190 Commits
zhangyuans
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| df588d379a | |||
| 455a1716b8 | |||
| fa4c67e20b | |||
| e2b41dcd8a | |||
| b046388c86 | |||
| 227d8c7524 | |||
| d76ec030e6 | |||
| 82e14bb969 | |||
| 6ae597c7f4 | |||
| 94ef829509 | |||
| 16c881acfd | |||
| d3164014ee | |||
| d81bfad19d | |||
| d816e9a244 | |||
| 8afcfb73bd | |||
| c8c0df1e75 | |||
| 0a83555976 | |||
| 9a739e7402 | |||
| 468b89fa5c | |||
| 64f76df2ef | |||
| 98aa8e8fdb | |||
| 7f50f09bbe | |||
| 580439fec8 | |||
| 454b9ddbbd | |||
| 079db90021 | |||
| 3719c162c3 | |||
| eb2473df6f | |||
| f056ebd176 | |||
| 033cf16ae7 | |||
| f19660c03c | |||
| e0e3cfdd12 | |||
| 0a15ae5463 | |||
| d5df575aac | |||
| bc99d083c9 | |||
| 68c867eee9 | |||
| d137f39471 | |||
| dd31ad21be | |||
| c139828e71 | |||
| 11bb78cc5e | |||
| b97219565e | |||
| 65dc8002db | |||
| dd42b26d1f | |||
| eb1523516c | |||
| 02999dc782 | |||
| dd0ccb9818 | |||
| 71d97f069f | |||
| 7be32e930c | |||
| 885707f328 | |||
| f76198b674 | |||
| 66828a254c | |||
| 3898c637b4 | |||
| 29dcfac775 | |||
| e4aa6181a8 | |||
| 676ad46ab5 | |||
| 3b70cafff6 | |||
| 9e2daf8b2e | |||
| 651c920b7a | |||
| 4090ee0547 | |||
| 251cf7d66f | |||
| b7eea81200 | |||
| df1cc68b59 | |||
| a5d9009910 | |||
| bbb5dd99fc | |||
| 2953d50e4b | |||
| 4381520f3c | |||
| 4a5d005600 | |||
| ec17da2e2c | |||
| 041692afe8 | |||
| 9536ce98a6 | |||
| 30412b109e | |||
| 87ca206b2b | |||
| d494d514b5 | |||
| f6038e95a0 | |||
| 3183ff5049 | |||
| e0305ab496 | |||
| 21ebbf92d5 | |||
| f8c3689588 | |||
|
|
31dcd0ebca | ||
|
|
c374154f0f | ||
|
|
dd3e217bb1 | ||
|
|
96c4fbaad9 | ||
| e7ec387735 | |||
| 6140c625e4 | |||
| 99ffb6ec05 | |||
| f17250f236 | |||
| e904dae8a0 | |||
| 66e95da62e | |||
| fea7504a91 | |||
| 2676e70c0c | |||
| f9f7e6e45d | |||
|
|
fdf71eb4da | ||
| 1f4c5ba6df | |||
|
|
687cc0ec38 | ||
| 3642d3e2fa | |||
| 8ed2bf7113 | |||
| 17d9ed737d | |||
| 04dcbdf331 | |||
| fa2098c565 | |||
| 383abed2e8 | |||
| 3a15ec6c00 | |||
|
|
2fa381bea1 | ||
|
|
988912de2f | ||
|
|
47d5cab23a | ||
|
|
ed2d6dfbd5 | ||
|
|
e780d44255 | ||
|
|
f6d66fa71c | ||
|
|
5822c80f6a | ||
|
|
fe857f1e81 | ||
|
|
4a670201c6 | ||
| a06f0b2489 | |||
| 84cca43b52 | |||
|
|
b771a3c910 | ||
|
|
0b542e2e63 | ||
| c2a9676b09 | |||
| 7595af1d33 | |||
| d781a94a89 | |||
|
|
d0063bf11f | ||
|
|
11ff75f0d3 | ||
|
|
8d82024a1e | ||
|
|
982adc3f4b | ||
|
|
efc9ffea12 | ||
|
|
d66aa108d8 | ||
|
|
165f960d14 | ||
| d13ae03355 | |||
| ce9f977efd | |||
|
|
32e8428f46 | ||
|
|
cb123c6331 | ||
| 2f64cda0d4 | |||
| 9e8e3aeba3 | |||
|
|
1f64ffd8aa | ||
| 8034a303e7 | |||
|
|
8eb0f0b4f2 | ||
| 92a7d74c6c | |||
| d7c813977d | |||
| 2642a885f0 | |||
|
|
ba52f9a576 | ||
|
|
33106bfa80 | ||
| 026e4fa3e6 | |||
|
|
92cda98ca9 | ||
|
|
a9febca5e5 | ||
|
|
b8fd50394c | ||
| a6810d4f12 | |||
|
|
b4b614b545 | ||
| b0abca9bf2 | |||
|
|
505bb9b9f8 | ||
|
|
ad2b7d42e3 | ||
|
|
16300b68bf | ||
|
|
4b24e7a269 | ||
|
|
0e640c7ad6 | ||
|
|
010528e52e | ||
|
|
baa05faa24 | ||
| 380b0120bc | |||
| 894bb9bf28 | |||
| 11ef845e9c | |||
| cba592b87d | |||
| 3fe60616a5 | |||
|
|
28625c7943 | ||
|
|
566bba5308 | ||
|
|
feee532366 | ||
|
|
67f923b516 | ||
|
|
4abd2d8047 | ||
| 98e3a0710a | |||
| 747653f54a | |||
|
|
e6075849fe | ||
|
|
c7343a012a | ||
|
|
2d28872a12 | ||
|
|
659c2c3e12 | ||
| 2304ddfc45 | |||
| 3414fb63b8 | |||
| 55e13e6024 | |||
|
|
be047f30c1 | ||
|
|
f6ce053787 | ||
|
|
382c3fed39 | ||
| e4c2b7cdcb | |||
| adb57bda88 | |||
|
|
d303c8e94e | ||
| 4b3062eefa | |||
| 36342b4dd9 | |||
|
|
0cb90fcc3b | ||
|
|
7d2cde3b65 | ||
|
|
4be1c7c9a4 | ||
|
|
c408b97b1e | ||
| ae2a447fa4 | |||
| f2abedd88e | |||
| 9b904b4fda | |||
| 8b61369006 | |||
|
|
93428be5df | ||
| 8c9b9d0f2c | |||
| ada0bc0ee9 | |||
| 78756431b7 |
2
auto-imports.d.ts
vendored
@ -70,6 +70,6 @@ declare global {
|
|||||||
// for type re-export
|
// for type re-export
|
||||||
declare global {
|
declare global {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
|
export type { Component, Slot, Slots, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
|
||||||
import('vue')
|
import('vue')
|
||||||
}
|
}
|
||||||
|
|||||||
7
components.d.ts
vendored
@ -8,6 +8,8 @@ export {}
|
|||||||
/* prettier-ignore */
|
/* prettier-ignore */
|
||||||
declare module 'vue' {
|
declare module 'vue' {
|
||||||
export interface GlobalComponents {
|
export interface GlobalComponents {
|
||||||
|
AsyncError: typeof import('./src/components/async-error/index.vue')['default']
|
||||||
|
AsyncLoading: typeof import('./src/components/async-loading/index.vue')['default']
|
||||||
AudioMessage: typeof import('./src/components/talk/message/AudioMessage.vue')['default']
|
AudioMessage: typeof import('./src/components/talk/message/AudioMessage.vue')['default']
|
||||||
Avatar: typeof import('./src/components/base/Avatar.vue')['default']
|
Avatar: typeof import('./src/components/base/Avatar.vue')['default']
|
||||||
AvatarCropper: typeof import('./src/components/base/AvatarCropper.vue')['default']
|
AvatarCropper: typeof import('./src/components/base/AvatarCropper.vue')['default']
|
||||||
@ -36,15 +38,20 @@ declare module 'vue' {
|
|||||||
RevokeMessage: typeof import('./src/components/talk/message/RevokeMessage.vue')['default']
|
RevokeMessage: typeof import('./src/components/talk/message/RevokeMessage.vue')['default']
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
|
SysGroupAdminMessage: typeof import('./src/components/talk/message/system/SysGroupAdminMessage.vue')['default']
|
||||||
SysGroupCancelMutedMessage: typeof import('./src/components/talk/message/system/SysGroupCancelMutedMessage.vue')['default']
|
SysGroupCancelMutedMessage: typeof import('./src/components/talk/message/system/SysGroupCancelMutedMessage.vue')['default']
|
||||||
SysGroupCreateMessage: typeof import('./src/components/talk/message/system/SysGroupCreateMessage.vue')['default']
|
SysGroupCreateMessage: typeof import('./src/components/talk/message/system/SysGroupCreateMessage.vue')['default']
|
||||||
|
SysGroupDismissed: typeof import('./src/components/talk/message/system/SysGroupDismissed.vue')['default']
|
||||||
|
SysGroupInfoChangeMessage: typeof import('./src/components/talk/message/system/SysGroupInfoChangeMessage.vue')['default']
|
||||||
SysGroupJoinMessage: typeof import('./src/components/talk/message/system/SysGroupJoinMessage.vue')['default']
|
SysGroupJoinMessage: typeof import('./src/components/talk/message/system/SysGroupJoinMessage.vue')['default']
|
||||||
SysGroupMemberCancelMutedMessage: typeof import('./src/components/talk/message/system/SysGroupMemberCancelMutedMessage.vue')['default']
|
SysGroupMemberCancelMutedMessage: typeof import('./src/components/talk/message/system/SysGroupMemberCancelMutedMessage.vue')['default']
|
||||||
SysGroupMemberKickedMessage: typeof import('./src/components/talk/message/system/SysGroupMemberKickedMessage.vue')['default']
|
SysGroupMemberKickedMessage: typeof import('./src/components/talk/message/system/SysGroupMemberKickedMessage.vue')['default']
|
||||||
SysGroupMemberMutedMessage: typeof import('./src/components/talk/message/system/SysGroupMemberMutedMessage.vue')['default']
|
SysGroupMemberMutedMessage: typeof import('./src/components/talk/message/system/SysGroupMemberMutedMessage.vue')['default']
|
||||||
SysGroupMemberQuitMessage: typeof import('./src/components/talk/message/system/SysGroupMemberQuitMessage.vue')['default']
|
SysGroupMemberQuitMessage: typeof import('./src/components/talk/message/system/SysGroupMemberQuitMessage.vue')['default']
|
||||||
|
SysGroupMemberRemovedMessage: typeof import('./src/components/talk/message/system/SysGroupMemberRemovedMessage.vue')['default']
|
||||||
SysGroupMutedMessage: typeof import('./src/components/talk/message/system/SysGroupMutedMessage.vue')['default']
|
SysGroupMutedMessage: typeof import('./src/components/talk/message/system/SysGroupMutedMessage.vue')['default']
|
||||||
SysGroupTransferMessage: typeof import('./src/components/talk/message/system/SysGroupTransferMessage.vue')['default']
|
SysGroupTransferMessage: typeof import('./src/components/talk/message/system/SysGroupTransferMessage.vue')['default']
|
||||||
|
SysPushMessage: typeof import('./src/components/talk/message/system/sysPushMessage.vue')['default']
|
||||||
SysTextMessage: typeof import('./src/components/talk/message/system/SysTextMessage.vue')['default']
|
SysTextMessage: typeof import('./src/components/talk/message/system/SysTextMessage.vue')['default']
|
||||||
TabbarItem: typeof import('./src/components/x-tabbar/components/tabbar-item/index.vue')['default']
|
TabbarItem: typeof import('./src/components/x-tabbar/components/tabbar-item/index.vue')['default']
|
||||||
TextMessage: typeof import('./src/components/talk/message/TextMessage.vue')['default']
|
TextMessage: typeof import('./src/components/talk/message/TextMessage.vue')['default']
|
||||||
|
|||||||
8
env/.env.dev
vendored
@ -5,4 +5,10 @@ VITE_SHOW_CONSOLE = true
|
|||||||
# 是否开启sourcemap
|
# 是否开启sourcemap
|
||||||
VITE_SHOW_SOURCEMAP = true
|
VITE_SHOW_SOURCEMAP = true
|
||||||
# baseUrl
|
# baseUrl
|
||||||
VITE_BASEURL = 'http://warehouse.szjixun.cn/oa_backend'
|
# VITE_BASEURL = 'http://172.16.100.93:8503'
|
||||||
|
VITE_BASEURL = 'http://192.168.88.47:9503'
|
||||||
|
#VITE_SOCKET_API
|
||||||
|
# VITE_SOCKET_API = 'ws://172.16.100.93:8504'
|
||||||
|
VITE_SOCKET_API = 'ws://192.168.88.47:9504'
|
||||||
|
# EPRAPI baseUrl
|
||||||
|
VITE_EPR_BASEURL = 'http://114.218.158.24:9020'
|
||||||
|
|||||||
19
env/.env.prod
vendored
@ -1,8 +1,21 @@
|
|||||||
# 变量必须以 VITE_ 为前缀才能暴露给外部读取
|
# 变量必须以 VITE_ 为前缀才能暴露给外部读取
|
||||||
NODE_ENV = 'prod'
|
NODE_ENV = 'prod'
|
||||||
# 是否显示console
|
# 是否显示console
|
||||||
VITE_SHOW_CONSOLE = true
|
VITE_SHOW_CONSOLE = false
|
||||||
# 是否开启sourcemap
|
# 是否开启sourcemap
|
||||||
VITE_SHOW_SOURCEMAP = true
|
VITE_SHOW_SOURCEMAP = false
|
||||||
|
|
||||||
# baseUrl
|
# baseUrl
|
||||||
VITE_BASEURL = 'https://oa-a.szjixun.cn/api'
|
VITE_BASEURL = 'https://chat-out.szjixun.cn' #体制外
|
||||||
|
#VITE_SOCKET_API
|
||||||
|
VITE_SOCKET_API = 'wss://chat-out.szjixun.cn' #体制外
|
||||||
|
# EPRAPI baseUrl
|
||||||
|
VITE_EPR_BASEURL = 'https://erpapi-out.szjixun.cn' #体制外
|
||||||
|
|
||||||
|
# # baseUrl
|
||||||
|
# VITE_BASEURL = 'https://chat.szjixun.cn' #体制内
|
||||||
|
# #VITE_SOCKET_API
|
||||||
|
# VITE_SOCKET_API = 'wss://chat.szjixun.cn' #体制内
|
||||||
|
# # EPRAPI baseUrl
|
||||||
|
# VITE_EPR_BASEURL = 'https://erpapi.fontree.cn' #体制内
|
||||||
|
|
||||||
|
|||||||
12
env/.env.test
vendored
@ -4,10 +4,16 @@ NODE_ENV = 'test'
|
|||||||
VITE_SHOW_CONSOLE = true
|
VITE_SHOW_CONSOLE = true
|
||||||
# 是否开启sourcemap
|
# 是否开启sourcemap
|
||||||
VITE_SHOW_SOURCEMAP = true
|
VITE_SHOW_SOURCEMAP = true
|
||||||
# baseUrl
|
|
||||||
# VITE_BASEURL = 'https://warehouse.szjixun.cn/oa_backend'
|
# # baseUrl
|
||||||
VITE_BASEURL = 'http://172.16.100.93:8503'
|
VITE_BASEURL = 'http://172.16.100.93:8503'
|
||||||
#VITE_SOCKET_API
|
# #VITE_SOCKET_API
|
||||||
VITE_SOCKET_API = 'ws://172.16.100.93:8504'
|
VITE_SOCKET_API = 'ws://172.16.100.93:8504'
|
||||||
|
|
||||||
|
# baseUrl
|
||||||
|
# VITE_BASEURL = 'http://192.168.88.21:9503'
|
||||||
|
#VITE_SOCKET_API
|
||||||
|
# VITE_SOCKET_API = 'ws://192.168.88.21:9504'
|
||||||
|
|
||||||
# EPRAPI baseUrl
|
# EPRAPI baseUrl
|
||||||
VITE_EPR_BASEURL = 'http://114.218.158.24:9020'
|
VITE_EPR_BASEURL = 'http://114.218.158.24:9020'
|
||||||
|
|||||||
12
package.json
@ -2,14 +2,16 @@
|
|||||||
"name": "unihelper",
|
"name": "unihelper",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
|
||||||
"packageManager": "pnpm@8.14.1",
|
"packageManager": "pnpm@8.14.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"dev:h5": "uni --mode dev --port 2468",
|
||||||
"test:h5": "uni --mode test --port 2468",
|
"test:h5": "uni --mode test --port 2468",
|
||||||
"prod:h5": "uni --mode prod",
|
"prod:h5": "uni --mode prod",
|
||||||
"build:h5:test": "uni build --mode test",
|
"build:h5:test": "uni build --mode test",
|
||||||
"build:h5:prod": "uni build --mode prod"
|
"build:h5:prod": "uni build --mode prod",
|
||||||
|
"preview:h5": "uni preview --mode test",
|
||||||
|
"preview:h5:prod": "uni preview --mode prod"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@dcloudio/uni-app": "3.0.0-alpha-4000020240111001",
|
"@dcloudio/uni-app": "3.0.0-alpha-4000020240111001",
|
||||||
@ -38,7 +40,9 @@
|
|||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"nzh": "^1.0.13",
|
"nzh": "^1.0.13",
|
||||||
"pinia-plugin-persistedstate": "^4.1.3",
|
"pinia-plugin-persistedstate": "^4.1.3",
|
||||||
"quill-mention": "^6.0.2",
|
"quill": "^1.3.7",
|
||||||
|
"quill-mention": "^4.1.0",
|
||||||
|
"recorder-core": "^1.3.25011100",
|
||||||
"vconsole": "^3.15.1",
|
"vconsole": "^3.15.1",
|
||||||
"vue": "^3.3.8",
|
"vue": "^3.3.8",
|
||||||
"vue-i18n": "11.0.0-rc.1"
|
"vue-i18n": "11.0.0-rc.1"
|
||||||
@ -62,7 +66,7 @@
|
|||||||
"lint-staged": "^15.2.0",
|
"lint-staged": "^15.2.0",
|
||||||
"naive-ui": "^2.41.0",
|
"naive-ui": "^2.41.0",
|
||||||
"pinia": "2.0.36",
|
"pinia": "2.0.36",
|
||||||
"sass": "^1.77.8",
|
"sass": "1.62.1",
|
||||||
"simple-git-hooks": "^2.9.0",
|
"simple-git-hooks": "^2.9.0",
|
||||||
"typescript": "^5.3.3",
|
"typescript": "^5.3.3",
|
||||||
"unocss": "^0.58.9",
|
"unocss": "^0.58.9",
|
||||||
|
|||||||
5454
pnpm-lock.yaml
23
src/App.vue
@ -1,28 +1,33 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { useStatus } from '@/store/status'
|
import { useStatus } from '@/store/status'
|
||||||
import { useUserStore } from '@/store'
|
import { useUserStore, useDialogueListStore } from '@/store'
|
||||||
import { useProvideUserModal } from '@/hooks'
|
import { useProvideUserModal } from '@/hooks'
|
||||||
import {useAuth} from "@/store/auth";
|
import {useAuth} from "@/store/auth";
|
||||||
const {token} = useAuth()
|
const {token} = useAuth()
|
||||||
import ws from '@/connect'
|
import ws from '@/connect'
|
||||||
|
import {uniStorage} from "@/utils/uniStorage.js"
|
||||||
const { statusBarHeight } = useStatus()
|
const { statusBarHeight } = useStatus()
|
||||||
const { uid, isShow } = useProvideUserModal()
|
const { uid, isShow } = useProvideUserModal()
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const root = document.documentElement
|
const root = document.documentElement
|
||||||
root.style.setProperty('--statusBarHeight', `${statusBarHeight.value}px`)
|
root.style.setProperty('--statusBarHeight', `${statusBarHeight.value}px`)
|
||||||
const handleWebview = () => {
|
const handleWebview = () => {
|
||||||
let statusBarHeight = window?.plus?.navigator?.getStatusbarHeight()
|
let statusBarHeight_ = window?.plus?.navigator?.getStatusbarHeight()
|
||||||
const webview = plus.webview.currentWebview()
|
const webview = plus.webview.currentWebview()
|
||||||
webview.setStyle({
|
// webview.setStyle({
|
||||||
top: statusBarHeight,
|
// top: statusBarHeight_,
|
||||||
bottom: 0,
|
// bottom: 0,
|
||||||
})
|
// })
|
||||||
// console.log(webview)
|
console.log("webview", webview)
|
||||||
token.value = webview.token
|
token.value = webview.token
|
||||||
}
|
if(webview?.doClearDialogueList){
|
||||||
const init = () => {
|
useDialogueListStore().dialogueList.value = []
|
||||||
|
uniStorage.removeItem('dialogueList')
|
||||||
|
}
|
||||||
userStore.loadSetting()
|
userStore.loadSetting()
|
||||||
ws.connect()
|
ws.connect()
|
||||||
|
}
|
||||||
|
const init = () => {
|
||||||
if (typeof plus !== 'undefined') {
|
if (typeof plus !== 'undefined') {
|
||||||
handleWebview()
|
handleWebview()
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
47
src/api/addressBook/index.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import request from '@/service/index.js'
|
||||||
|
|
||||||
|
// 查询用户是否需要添加好友
|
||||||
|
export const ServeCheckFriend = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/api/v1/contact/friend/check',
|
||||||
|
method: 'POST',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 主动添加好友(单向好友)
|
||||||
|
export const ServeAddFriend = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/api/v1/contact/friend/add',
|
||||||
|
method: 'POST',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询我的好友列表
|
||||||
|
export const ServeQueryFriendsList = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/api/v1/contact/friend/list',
|
||||||
|
method: 'POST',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除好友(单向好友)
|
||||||
|
export const ServeDeleteFriend = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/api/v1/contact/friend/delete',
|
||||||
|
method: 'POST',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//添加我的好友时候的搜索接口
|
||||||
|
export const ServeFriendSearch = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/api/v1/contact/friend/search',
|
||||||
|
method: 'POST',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
@ -1,5 +1,7 @@
|
|||||||
import request from '@/service/index.js'
|
import request from '@/service/index.js'
|
||||||
import qs from 'qs'
|
import qs from 'qs'
|
||||||
|
import { useTalkStore, useDialogueStore } from '@/store'
|
||||||
|
import { handleFindWebview } from '@/utils/common'
|
||||||
|
|
||||||
// 获取聊天列表服务接口
|
// 获取聊天列表服务接口
|
||||||
export const ServeGetTalkList = (data) => {
|
export const ServeGetTalkList = (data) => {
|
||||||
@ -38,7 +40,15 @@ export const ServeTopTalkList = (data) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 清除聊天消息未读数服务接口
|
// 清除聊天消息未读数服务接口
|
||||||
export const ServeClearTalkUnreadNum = (data) => {
|
export const ServeClearTalkUnreadNum = (data, unReadNum) => {
|
||||||
|
console.log('=======chatApp==UnreadNum', unReadNum)
|
||||||
|
if (
|
||||||
|
!useTalkStore().items[
|
||||||
|
useTalkStore().findTalkIndex(useDialogueStore().index_name)
|
||||||
|
]?.is_disturb
|
||||||
|
) {
|
||||||
|
handleFindWebview(`updateUnreadMsgNumReduce('${unReadNum}')`)
|
||||||
|
}
|
||||||
return request({
|
return request({
|
||||||
url: '/api/v1/talk/unread/clear',
|
url: '/api/v1/talk/unread/clear',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@ -58,6 +68,7 @@ export const ServeTalkRecords = (data) => {
|
|||||||
// 获取转发会话记录详情列表服务接口
|
// 获取转发会话记录详情列表服务接口
|
||||||
export const ServeGetForwardRecords = (data) => {
|
export const ServeGetForwardRecords = (data) => {
|
||||||
return request({
|
return request({
|
||||||
|
// url: '/api/v1/talk/records/forward/v2',
|
||||||
url: '/api/v1/talk/records/forward',
|
url: '/api/v1/talk/records/forward',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
data,
|
data,
|
||||||
@ -169,13 +180,77 @@ export const ServeConfirmVoteHandle = (data) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const uploadImg = (data,onProgressFn) => {
|
export const uploadImg = (data, onProgressFn) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/upload/img',
|
url: '/upload/img',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data:data,
|
data: data,
|
||||||
baseURL:import.meta.env.VITE_EPR_BASEURL,
|
baseURL: import.meta.env.VITE_EPR_BASEURL,
|
||||||
isFormData:true,
|
isFormData: true,
|
||||||
onUploadProgress:(progressEvent)=>onProgressFn(progressEvent,data.get('file'))
|
onUploadProgress: (progressEvent) =>
|
||||||
|
onProgressFn(progressEvent, data.get('file')),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// 根据msg_id获取消息
|
||||||
|
export const detailGetRecordsContext = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/api/v1/talk/record/detail',
|
||||||
|
method: 'GET',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取自己消息已读回执列表
|
||||||
|
export const ServeReadConditionList = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/api/v1/talk/my-records/read/condition',
|
||||||
|
method: 'POST',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取消息已读未读详情
|
||||||
|
export const ServeMessageReadDetail = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/api/v1/talk/my-records/read/condition',
|
||||||
|
method: 'POST',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 语音转文字
|
||||||
|
export const ServeConvertText = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/api/v1/talk/message/voice-to-text',
|
||||||
|
method: 'POST',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取用户所在群聊列表(我的群聊)
|
||||||
|
export const ServeUserGroupChatList = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/api/v1/group/user/list',
|
||||||
|
method: 'POST',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//查询聊天助手是否开启
|
||||||
|
export const ServeContactRobotQuery = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/api/v1/contact/robot/query',
|
||||||
|
method: 'POST',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//开关聊天助手
|
||||||
|
export const ServeContactRobotUpdate = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/api/v1/contact/robot/update',
|
||||||
|
method: 'POST',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -26,6 +26,22 @@ export const departmentV2TreeAll = (data) => {
|
|||||||
data,
|
data,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// 通讯录过滤测试部门
|
||||||
|
export const departmentV2TreeAll2 = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/api/v1/contact/department/v2/tree/all',
|
||||||
|
method: 'POST',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 查询是否有权限
|
||||||
|
export const userHasPermission = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/api/v1/contact/check/erp/rule',
|
||||||
|
method: 'POST',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
//获取指定部门下的所有岗位
|
//获取指定部门下的所有岗位
|
||||||
export const v2TreePositionByDepartment = (data) => {
|
export const v2TreePositionByDepartment = (data) => {
|
||||||
@ -45,6 +61,14 @@ export const userV2List = (data) => {
|
|||||||
data,
|
data,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// 过滤测试数据的erp用户接口
|
||||||
|
export const userV2List2 = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/api/v1/group/erp/users',
|
||||||
|
method: 'POST',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export const groupCreateDept = (data) => {
|
export const groupCreateDept = (data) => {
|
||||||
return request({
|
return request({
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import qs from 'qs'
|
|||||||
// ES搜索聊天记录-主页搜索什么都有
|
// ES搜索聊天记录-主页搜索什么都有
|
||||||
export const ServeSeachQueryAll = (data) => {
|
export const ServeSeachQueryAll = (data) => {
|
||||||
return request({
|
return request({
|
||||||
|
// url: '/api/v1/elasticsearch/query-all/v2',
|
||||||
url: '/api/v1/elasticsearch/query-all',
|
url: '/api/v1/elasticsearch/query-all',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data,
|
data,
|
||||||
@ -13,6 +14,7 @@ export const ServeSeachQueryAll = (data) => {
|
|||||||
// ES搜索用户数据
|
// ES搜索用户数据
|
||||||
export const ServeQueryUser = (data) => {
|
export const ServeQueryUser = (data) => {
|
||||||
return request({
|
return request({
|
||||||
|
// url: '/api/v1/elasticsearch/query-user/v2',
|
||||||
url: '/api/v1/elasticsearch/query-user',
|
url: '/api/v1/elasticsearch/query-user',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data,
|
data,
|
||||||
@ -45,3 +47,12 @@ export const ServeTalkDate = (data) => {
|
|||||||
data,
|
data,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//获取会话Id
|
||||||
|
export const ServeGetSessionId = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/api/v1/talk/session/getId',
|
||||||
|
method: 'POST',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
@ -10,10 +10,9 @@ export const ServeGetUserSetting = (data) => {
|
|||||||
|
|
||||||
export const userInfoApi = (data) => {
|
export const userInfoApi = (data) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/user/info',
|
url: '/api/v1/users/erp/info',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data,
|
data,
|
||||||
baseURL:import.meta.env.VITE_EPR_BASEURL,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
89
src/components/async-error/index.vue
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
<template>
|
||||||
|
<div class="chat-app-error-page">
|
||||||
|
<div class="error-container">
|
||||||
|
<div class="error-icon">
|
||||||
|
<i class="iconfont icon-wifi"></i>
|
||||||
|
</div>
|
||||||
|
<div class="error-message">
|
||||||
|
<span>您的网络好像波动了一下~</span>
|
||||||
|
</div>
|
||||||
|
<div class="reload-button" @click="handleReload">
|
||||||
|
<span>重新加载</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { onMounted, ref, computed, nextTick } from 'vue'
|
||||||
|
|
||||||
|
const handleReload = () => {
|
||||||
|
location.reload(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (typeof plus !== 'undefined') {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
document.addEventListener('plusready', () => {
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.chat-app-error-page {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100vh;
|
||||||
|
background-image: url('@/static/image/clockIn/z3280@3x.png');
|
||||||
|
background-size: cover;
|
||||||
|
background-position: bottom center;
|
||||||
|
|
||||||
|
.error-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 32px;
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 16px;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
|
||||||
|
max-width: 80%;
|
||||||
|
width: 320px;
|
||||||
|
|
||||||
|
.error-icon {
|
||||||
|
font-size: 48px;
|
||||||
|
color: #ff6b6b;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-message {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #333333;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reload-button {
|
||||||
|
padding: 12px 32px;
|
||||||
|
background: $theme-primary;
|
||||||
|
color: #ffffff;
|
||||||
|
border-radius: 24px;
|
||||||
|
font-size: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 0.9;
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
81
src/components/async-loading/index.vue
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="loader">
|
||||||
|
<p class="heading">加载中</p>
|
||||||
|
<div class="loading">
|
||||||
|
<div class="load"></div>
|
||||||
|
<div class="load"></div>
|
||||||
|
<div class="load"></div>
|
||||||
|
<div class="load"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.loader {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100vh;
|
||||||
|
background-image: url('@/static/image/clockIn/z3280@3x.png');
|
||||||
|
background-size: cover;
|
||||||
|
background-position: bottom center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading {
|
||||||
|
color: black;
|
||||||
|
letter-spacing: 0.2em;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading {
|
||||||
|
display: flex;
|
||||||
|
width: 5em;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.load {
|
||||||
|
width: 23px;
|
||||||
|
height: 3px;
|
||||||
|
background-color: limegreen;
|
||||||
|
animation: 1s move_5011 infinite;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin: 0.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.load:nth-child(1) {
|
||||||
|
animation-delay: 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.load:nth-child(2) {
|
||||||
|
animation-delay: 0.4s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.load:nth-child(3) {
|
||||||
|
animation-delay: 0.6s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes move_5011 {
|
||||||
|
0% {
|
||||||
|
width: 0.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
25% {
|
||||||
|
width: 0.7em;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
width: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
width: 0.2em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="avatar-module" :style="customStyle">
|
<div class="avatar-module" :style="[customStyle, { background: avatar ? '#fff' : '' }]">
|
||||||
<img :src="avatar" v-if="avatar" />
|
<img :src="avatar" v-if="avatar" />
|
||||||
<span v-else :style="customTextStyle">{{ text_avatar }}</span>
|
<span v-else :style="customTextStyle">{{ text_avatar }}</span>
|
||||||
</div>
|
</div>
|
||||||
@ -89,6 +89,7 @@ const text_avatar = computed(() => {
|
|||||||
img {
|
img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -90,8 +90,6 @@ const onSubmit = () => {
|
|||||||
ServeUploadAvatar(form).then((res) => {
|
ServeUploadAvatar(form).then((res) => {
|
||||||
if (res.code == 200) {
|
if (res.code == 200) {
|
||||||
emit('success', res.data.avatar)
|
emit('success', res.data.avatar)
|
||||||
} else {
|
|
||||||
message.warning(res.message)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -6,7 +6,11 @@
|
|||||||
props.subBtnText ? 'apposition-btn-style' : '',
|
props.subBtnText ? 'apposition-btn-style' : '',
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
<wd-button custom-class="custom-sub-btn-class" v-if="props.subBtnText">
|
<wd-button
|
||||||
|
custom-class="custom-sub-btn-class"
|
||||||
|
v-if="props.subBtnText"
|
||||||
|
@click="clickSubBtn"
|
||||||
|
>
|
||||||
{{ props.subBtnText }}
|
{{ props.subBtnText }}
|
||||||
</wd-button>
|
</wd-button>
|
||||||
<wd-button
|
<wd-button
|
||||||
@ -15,6 +19,7 @@
|
|||||||
:disabled="props?.disabled"
|
:disabled="props?.disabled"
|
||||||
:class="[props?.disabled ? 'custom-btn-class-disabled' : '']"
|
:class="[props?.disabled ? 'custom-btn-class-disabled' : '']"
|
||||||
:plain="props?.plain"
|
:plain="props?.plain"
|
||||||
|
:loading="props?.isLoading"
|
||||||
>
|
>
|
||||||
{{ props.btnText }}
|
{{ props.btnText }}
|
||||||
</wd-button>
|
</wd-button>
|
||||||
@ -24,16 +29,22 @@
|
|||||||
import { reactive } from 'vue'
|
import { reactive } from 'vue'
|
||||||
import { defineProps, defineEmits } from 'vue'
|
import { defineProps, defineEmits } from 'vue'
|
||||||
const state = reactive({})
|
const state = reactive({})
|
||||||
const emits = defineEmits(['clickBtn'])
|
const emits = defineEmits(['clickSubBtn', 'clickBtn'])
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
isBottom: false, //是否底部按钮
|
isBottom: false, //是否底部按钮
|
||||||
btnText: '', //按钮文字
|
btnText: '', //按钮文字
|
||||||
subBtnText: '', //次要按钮文字
|
subBtnText: '', //次要按钮文字
|
||||||
disabled: false, //是否禁用
|
disabled: false, //是否禁用
|
||||||
plain: false, //是否镂空
|
plain: false, //是否镂空
|
||||||
|
isLoading: false, //是否正在加载中
|
||||||
})
|
})
|
||||||
|
|
||||||
//点击
|
//点击副按钮
|
||||||
|
const clickSubBtn = () => {
|
||||||
|
emits('clickSubBtn')
|
||||||
|
}
|
||||||
|
|
||||||
|
//点击主按钮
|
||||||
const clickBtn = () => {
|
const clickBtn = () => {
|
||||||
emits('clickBtn')
|
emits('clickBtn')
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,9 +21,20 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { defineProps, defineEmits, reactive, watch } from 'vue'
|
import { defineProps, defineEmits, reactive, watch } from 'vue'
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
searchText: String,
|
searchText: {
|
||||||
first_talk_record_infos: Object,
|
type: String,
|
||||||
disabled: Boolean,
|
default: ''
|
||||||
|
},
|
||||||
|
first_talk_record_infos: {
|
||||||
|
type: Object,
|
||||||
|
default(){
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
})
|
})
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
searchText: '', //搜索内容
|
searchText: '', //搜索内容
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<tm-navbar
|
<tm-navbar
|
||||||
:hideBack="props.hideBack"
|
:hideBack="props.hideBack"
|
||||||
hideHome
|
:hideHome="props.hideHome"
|
||||||
:title="props.title"
|
:title="props.title"
|
||||||
:shadow="props.shadowNum"
|
:shadow="props.shadowNum"
|
||||||
:fontSize="34"
|
:fontSize="34"
|
||||||
@ -38,6 +38,10 @@ const props = defineProps({
|
|||||||
type: Number,
|
type: Number,
|
||||||
default: 1,
|
default: 1,
|
||||||
},
|
},
|
||||||
|
hideHome: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -25,9 +25,18 @@
|
|||||||
class="flex flex-col items-center justify-center"
|
class="flex flex-col items-center justify-center"
|
||||||
>
|
>
|
||||||
<tm-image :width="40" :height="40" :src="copy07"></tm-image>
|
<tm-image :width="40" :height="40" :src="copy07"></tm-image>
|
||||||
<div>复制</div>
|
<div class="mt-1">复制</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
v-if="props.isShowConvertText"
|
||||||
|
@click="() => itemClick('convertText')"
|
||||||
|
class="flex flex-col items-center justify-center"
|
||||||
|
>
|
||||||
|
<tm-image :width="40" :height="40" :src="copy07"></tm-image>
|
||||||
|
<div class="mt-1">转文字</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="props.isShowMultipleChoose && !props.isChatRobot"
|
||||||
@click="() => itemClick('multipleChoose')"
|
@click="() => itemClick('multipleChoose')"
|
||||||
class="flex flex-col items-center justify-center"
|
class="flex flex-col items-center justify-center"
|
||||||
>
|
>
|
||||||
@ -36,15 +45,15 @@
|
|||||||
:height="40"
|
:height="40"
|
||||||
:src="multipleChoices"
|
:src="multipleChoices"
|
||||||
></tm-image>
|
></tm-image>
|
||||||
<div>多选</div>
|
<div class="mt-1">多选</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="props.isShowCite"
|
v-if="props.isShowCite && !props.isChatRobot"
|
||||||
@click="() => itemClick('actionCite')"
|
@click="() => itemClick('actionCite')"
|
||||||
class="flex flex-col items-center justify-center"
|
class="flex flex-col items-center justify-center"
|
||||||
>
|
>
|
||||||
<tm-image :width="40" :height="40" :src="cite"></tm-image>
|
<tm-image :width="40" :height="40" :src="cite"></tm-image>
|
||||||
<div>引用</div>
|
<div class="mt-1">引用</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="props.isShowWithdraw"
|
v-if="props.isShowWithdraw"
|
||||||
@ -52,14 +61,15 @@
|
|||||||
class="flex flex-col items-center justify-center"
|
class="flex flex-col items-center justify-center"
|
||||||
>
|
>
|
||||||
<tm-image :width="40" :height="40" :src="withdraw"></tm-image>
|
<tm-image :width="40" :height="40" :src="withdraw"></tm-image>
|
||||||
<div>撤回</div>
|
<div class="mt-1">撤回</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
:class="{ 'w-full': props.isChatRobot }"
|
||||||
@click="() => itemClick('actionDelete')"
|
@click="() => itemClick('actionDelete')"
|
||||||
class="flex flex-col items-center justify-center"
|
class="flex flex-col items-center justify-center"
|
||||||
>
|
>
|
||||||
<tm-image :width="40" :height="40" :src="delete07"></tm-image>
|
<tm-image :width="40" :height="40" :src="delete07"></tm-image>
|
||||||
<div>删除</div>
|
<div class="mt-1">删除</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div :style="data.iconStyle" class="icon"></div>
|
<div :style="data.iconStyle" class="icon"></div>
|
||||||
@ -78,8 +88,8 @@
|
|||||||
// 组件
|
// 组件
|
||||||
|
|
||||||
// uniapp & vue
|
// uniapp & vue
|
||||||
import { onLoad, onReady } from "@dcloudio/uni-app";
|
import { onLoad, onReady } from '@dcloudio/uni-app'
|
||||||
import { defineEmits, defineProps } from "vue";
|
import { defineEmits, defineProps } from 'vue'
|
||||||
import {
|
import {
|
||||||
reactive,
|
reactive,
|
||||||
ref,
|
ref,
|
||||||
@ -88,134 +98,152 @@ import {
|
|||||||
nextTick,
|
nextTick,
|
||||||
getCurrentInstance,
|
getCurrentInstance,
|
||||||
onMounted,
|
onMounted,
|
||||||
onBeforeUnmount
|
onBeforeUnmount,
|
||||||
} from "vue";
|
} from 'vue'
|
||||||
import copy07 from "@/static/image/chatList/copy07@2x.png";
|
import copy07 from '@/static/image/chatList/copy07@2x.png'
|
||||||
import multipleChoices from "@/static/image/chatList/multipleChoices@2x.png";
|
import multipleChoices from '@/static/image/chatList/multipleChoices@2x.png'
|
||||||
import cite from "@/static/image/chatList/cite@2x.png";
|
import cite from '@/static/image/chatList/cite@2x.png'
|
||||||
import withdraw from "@/static/image/chatList/withdraw@2x.png";
|
import withdraw from '@/static/image/chatList/withdraw@2x.png'
|
||||||
import delete07 from "@/static/image/chatList/delete@2x.png";
|
import delete07 from '@/static/image/chatList/delete@2x.png'
|
||||||
|
|
||||||
// pinia
|
// pinia
|
||||||
const systemInfo = uni.getSystemInfoSync();
|
const systemInfo = uni.getSystemInfoSync()
|
||||||
const bubbleRef = ref(null);
|
const bubbleRef = ref(null)
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
isShowCopy: {
|
isShowCopy: {
|
||||||
|
//是否显示复制
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
isShowCite: {
|
isShowCite: {
|
||||||
|
//是否显示引用
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
isShowWithdraw: {
|
isShowWithdraw: {
|
||||||
|
//是否显示撤回
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
});
|
isShowConvertText: {
|
||||||
|
//是否显示转文字
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
isShowMultipleChoose: {
|
||||||
|
//是否显示多选
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
isChatRobot: {
|
||||||
|
//是否是智能助手
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const emits = defineEmits(["clickMenu"]);
|
const emits = defineEmits(['clickMenu'])
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @name 生成UUID
|
* @name 生成UUID
|
||||||
*/
|
*/
|
||||||
const uuid = () => {
|
const uuid = () => {
|
||||||
const reg = /[xy]/g;
|
const reg = /[xy]/g
|
||||||
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
|
||||||
.replace(reg, function (c) {
|
.replace(reg, function (c) {
|
||||||
var r = (Math.random() * 16) | 0,
|
var r = (Math.random() * 16) | 0,
|
||||||
v = c == "x" ? r : (r & 0x3) | 0x8;
|
v = c == 'x' ? r : (r & 0x3) | 0x8
|
||||||
return v.toString(16);
|
return v.toString(16)
|
||||||
})
|
})
|
||||||
.replace(/-/g, "");
|
.replace(/-/g, '')
|
||||||
};
|
}
|
||||||
|
|
||||||
const popoverBoxId = `ID${uuid()}`;
|
const popoverBoxId = `ID${uuid()}`
|
||||||
const popoverContentId = `ID${uuid()}`;
|
const popoverContentId = `ID${uuid()}`
|
||||||
const instance = getCurrentInstance();
|
const instance = getCurrentInstance()
|
||||||
const data = reactive({
|
const data = reactive({
|
||||||
popoverShow: false,
|
popoverShow: false,
|
||||||
defaultStyle: {},
|
defaultStyle: {},
|
||||||
showStyle: {
|
showStyle: {
|
||||||
left: 0,
|
left: 0,
|
||||||
right: "",
|
right: '',
|
||||||
transform: "",
|
transform: '',
|
||||||
},
|
},
|
||||||
iconStyle: {
|
iconStyle: {
|
||||||
left: "",
|
left: '',
|
||||||
right: "",
|
right: '',
|
||||||
transform: "",
|
transform: '',
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @name 获取DOM
|
* @name 获取DOM
|
||||||
*/
|
*/
|
||||||
const getDom = (dom) => {
|
const getDom = (dom) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const query = uni.createSelectorQuery().in(instance);
|
const query = uni.createSelectorQuery().in(instance)
|
||||||
let select = query.select(dom);
|
let select = query.select(dom)
|
||||||
const boundingClientRect = select.boundingClientRect((data) => {
|
const boundingClientRect = select.boundingClientRect((data) => {
|
||||||
resolve(data);
|
resolve(data)
|
||||||
});
|
})
|
||||||
boundingClientRect.exec();
|
boundingClientRect.exec()
|
||||||
});
|
})
|
||||||
};
|
}
|
||||||
|
|
||||||
const itemClick = (item) => {
|
const itemClick = (item) => {
|
||||||
emits("clickMenu", item);
|
emits('clickMenu', item)
|
||||||
};
|
}
|
||||||
|
|
||||||
// 弹起 长按5
|
// 弹起 长按5
|
||||||
let pressDownTime = 0;
|
let pressDownTime = 0
|
||||||
let time = null;
|
let time = null
|
||||||
const onTouchstart = () => {
|
const onTouchstart = () => {
|
||||||
time && clearTimeout(time);
|
time && clearTimeout(time)
|
||||||
time = setTimeout(open, 500);
|
time = setTimeout(open, 500)
|
||||||
};
|
}
|
||||||
|
|
||||||
const onTouchend = () => {
|
const onTouchend = () => {
|
||||||
time && clearTimeout(time);
|
time && clearTimeout(time)
|
||||||
};
|
}
|
||||||
|
|
||||||
const open = async () => {
|
const open = async () => {
|
||||||
let popoverContent = await getDom(`#${popoverContentId}`);
|
let popoverContent = await getDom(`#${popoverContentId}`)
|
||||||
let popoverBox = await getDom(`#${popoverBoxId}`);
|
let popoverBox = await getDom(`#${popoverBoxId}`)
|
||||||
|
|
||||||
// 缩放中心点
|
// 缩放中心点
|
||||||
let originX = popoverBox.width / 2;
|
let originX = popoverBox.width / 2
|
||||||
// 根据距离 初始化位置 判断是顶部还是底部
|
// 根据距离 初始化位置 判断是顶部还是底部
|
||||||
let isTop = popoverBox.top - 50 > popoverContent.height;
|
let isTop = popoverBox.top - 50 > popoverContent.height
|
||||||
// 上面还是下面
|
// 上面还是下面
|
||||||
data.defaultStyle = {
|
data.defaultStyle = {
|
||||||
top: isTop ? "60rpx" : "auto",
|
top: isTop ? '60rpx' : 'auto',
|
||||||
bottom: !isTop ? "-20rpx" : "auto",
|
bottom: !isTop ? '-20rpx' : 'auto',
|
||||||
transform: `translateY(${isTop ? "-100%" : "100%"}) scale(.8)`,
|
transform: `translateY(${isTop ? '-100%' : '100%'}) scale(.8)`,
|
||||||
};
|
}
|
||||||
// 左边还是右边
|
// 左边还是右边
|
||||||
if (popoverBox.left > systemInfo.windowWidth - popoverBox.right) {
|
if (popoverBox.left > systemInfo.windowWidth - popoverBox.right) {
|
||||||
data.defaultStyle.right = 0;
|
data.defaultStyle.right = 0
|
||||||
// 动画缩放中心点
|
// 动画缩放中心点
|
||||||
data.defaultStyle["transform-origin"] = `${
|
data.defaultStyle['transform-origin'] = `${
|
||||||
popoverContent.width - originX
|
popoverContent.width - originX
|
||||||
}px ${isTop ? "100%" : "0%"}`;
|
}px ${isTop ? '100%' : '0%'}`
|
||||||
} else {
|
} else {
|
||||||
data.defaultStyle.left = 0;
|
data.defaultStyle.left = 0
|
||||||
// 动画缩放中心点
|
// 动画缩放中心点
|
||||||
data.defaultStyle["transform-origin"] = `${originX}px ${
|
data.defaultStyle['transform-origin'] = `${originX}px ${
|
||||||
isTop ? "100%" : "0%"
|
isTop ? '100%' : '0%'
|
||||||
}`;
|
}`
|
||||||
}
|
}
|
||||||
data.showStyle = { ...data.defaultStyle };
|
data.showStyle = { ...data.defaultStyle }
|
||||||
// icon位置样式
|
// icon位置样式
|
||||||
let iconDefsultStyle = {
|
let iconDefsultStyle = {
|
||||||
transform: `translate(0%, ${isTop ? "20%" : "-20%"})`,
|
transform: `translate(0%, ${isTop ? '20%' : '-20%'})`,
|
||||||
"border-top-color": isTop ? "#333333" : "",
|
'border-top-color': isTop ? '#333333' : '',
|
||||||
"border-bottom-color": !isTop ? "#333333" : "",
|
'border-bottom-color': !isTop ? '#333333' : '',
|
||||||
top: !isTop ? "-20rpx" : "auto",
|
top: !isTop ? '-20rpx' : 'auto',
|
||||||
bottom: isTop ? "-20rpx" : "auto",
|
bottom: isTop ? '-20rpx' : 'auto',
|
||||||
};
|
}
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (popoverBox.left > systemInfo.windowWidth - popoverBox.right) {
|
if (popoverBox.left > systemInfo.windowWidth - popoverBox.right) {
|
||||||
@ -224,55 +252,55 @@ const open = async () => {
|
|||||||
...data.defaultStyle,
|
...data.defaultStyle,
|
||||||
// 显示
|
// 显示
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
transform: `translateY(${isTop ? "-100%" : "100%"}) scale(1)`,
|
transform: `translateY(${isTop ? '-100%' : '100%'}) scale(1)`,
|
||||||
"pointer-events": "auto",
|
'pointer-events': 'auto',
|
||||||
};
|
}
|
||||||
data.iconStyle = {
|
data.iconStyle = {
|
||||||
right: `${originX}px`,
|
right: `${originX}px`,
|
||||||
left: "auto",
|
left: 'auto',
|
||||||
...iconDefsultStyle,
|
...iconDefsultStyle,
|
||||||
};
|
}
|
||||||
} else {
|
} else {
|
||||||
data.showStyle = {
|
data.showStyle = {
|
||||||
// 位置
|
// 位置
|
||||||
...data.defaultStyle,
|
...data.defaultStyle,
|
||||||
// 显示
|
// 显示
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
transform: `translateY(${isTop ? "-100%" : "100%"}) scale(1)`,
|
transform: `translateY(${isTop ? '-100%' : '100%'}) scale(1)`,
|
||||||
"pointer-events": "auto",
|
'pointer-events': 'auto',
|
||||||
};
|
}
|
||||||
data.iconStyle = {
|
data.iconStyle = {
|
||||||
left: `${originX}px`,
|
left: `${originX}px`,
|
||||||
right: "auto",
|
right: 'auto',
|
||||||
...iconDefsultStyle,
|
...iconDefsultStyle,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data.popoverShow) data.popoverShow = true;
|
if (!data.popoverShow) data.popoverShow = true
|
||||||
}, 200);
|
}, 200)
|
||||||
};
|
}
|
||||||
|
|
||||||
const close = (time) => {
|
const close = (time) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
data.popoverShow = false;
|
data.popoverShow = false
|
||||||
data.showStyle = data.defaultStyle;
|
data.showStyle = data.defaultStyle
|
||||||
}, time || 0);
|
}, time || 0)
|
||||||
};
|
}
|
||||||
const handleClickOutside = (event) => {
|
const handleClickOutside = (event) => {
|
||||||
if (data.popoverShow = false) {
|
if ((data.popoverShow = false)) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (bubbleRef.value && !bubbleRef.value.contains(event.target)) {
|
if (bubbleRef.value && !bubbleRef.value.contains(event.target)) {
|
||||||
close();
|
close()
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
document.addEventListener('click', handleClickOutside);
|
document.addEventListener('click', handleClickOutside)
|
||||||
});
|
})
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
document.removeEventListener('click', handleClickOutside);
|
document.removeEventListener('click', handleClickOutside)
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@ -1,109 +1,155 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, reactive, onMounted } from "vue";
|
import { ref, reactive, onMounted, onUnmounted, computed } from 'vue'
|
||||||
import { PlayOne, PauseOne } from "@icon-park/vue-next";
|
import { PlayOne, PauseOne } from '@icon-park/vue-next'
|
||||||
import { ITalkRecordExtraAudio, ITalkRecord } from "@/types/chat";
|
import { ITalkRecordExtraAudio, ITalkRecord } from '@/types/chat'
|
||||||
|
import { onHide } from '@dcloudio/uni-app'
|
||||||
|
import aTrumpet from '@/uni_modules/a-trumpet/components/a-trumpet/a-trumpet.vue'
|
||||||
|
import { useUserStore } from '@/store'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
extra: ITalkRecordExtraAudio;
|
extra: ITalkRecordExtraAudio
|
||||||
data: ITalkRecord;
|
data: ITalkRecord
|
||||||
maxWidth?: Boolean;
|
maxWidth?: Boolean
|
||||||
}>();
|
}>()
|
||||||
|
|
||||||
const audioRef = ref();
|
const userStore = useUserStore()
|
||||||
const audioContext = ref<any>(null);
|
const talkParams = reactive({
|
||||||
|
uid: computed(() => userStore.uid),
|
||||||
const durationDesc = ref("-");
|
})
|
||||||
|
|
||||||
|
const audioContext = ref<any>(null)
|
||||||
|
const durationDesc = ref('-')
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
isAudioPlay: false,
|
isAudioPlay: false,
|
||||||
progress: 0,
|
progress: 0,
|
||||||
duration: 0,
|
duration: 0,
|
||||||
currentTime: 0,
|
currentTime: 0,
|
||||||
loading: true,
|
loading: true,
|
||||||
});
|
})
|
||||||
|
|
||||||
|
// 监听其它音频播放事件
|
||||||
|
function onOtherAudioPlay(e) {
|
||||||
|
if (e.detail !== props.data.msg_id && state.isAudioPlay) {
|
||||||
|
audioContext.value.pause()
|
||||||
|
state.isAudioPlay = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 使用uni-app的方式创建内部音频上下文
|
audioContext.value = uni.createInnerAudioContext()
|
||||||
audioContext.value = uni.createInnerAudioContext();
|
audioContext.value.src = props.extra.url
|
||||||
audioContext.value.src = props.extra.url;
|
|
||||||
|
|
||||||
audioContext.value.onCanplay(() => {
|
audioContext.value.onCanplay(() => {
|
||||||
state.duration = audioContext.value.duration;
|
state.duration = audioContext.value.duration
|
||||||
durationDesc.value = formatTime(parseInt(audioContext.value.duration));
|
durationDesc.value = formatTime(parseInt(audioContext.value.duration))
|
||||||
state.loading = false;
|
state.loading = false
|
||||||
});
|
})
|
||||||
|
|
||||||
audioContext.value.onTimeUpdate(() => {
|
audioContext.value.onTimeUpdate(() => {
|
||||||
if (audioContext.value.duration == 0) {
|
if (audioContext.value.duration == 0) {
|
||||||
state.progress = 0;
|
state.progress = 0
|
||||||
} else {
|
} else {
|
||||||
state.currentTime = audioContext.value.currentTime;
|
state.currentTime = audioContext.value.currentTime
|
||||||
state.progress =
|
state.progress =
|
||||||
(audioContext.value.currentTime / audioContext.value.duration) * 100;
|
(audioContext.value.currentTime / audioContext.value.duration) * 100
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
audioContext.value.onEnded(() => {
|
audioContext.value.onEnded(() => {
|
||||||
state.isAudioPlay = false;
|
state.isAudioPlay = false
|
||||||
state.progress = 0;
|
state.progress = 0
|
||||||
});
|
})
|
||||||
|
|
||||||
audioContext.value.onError((e) => {
|
audioContext.value.onError((e) => {
|
||||||
console.log("音频播放异常===>", e);
|
console.log('音频播放异常===>', e)
|
||||||
});
|
})
|
||||||
});
|
|
||||||
|
window.addEventListener('audio-play', onOtherAudioPlay)
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
window.removeEventListener('audio-play', onOtherAudioPlay)
|
||||||
|
audioContext.value &&
|
||||||
|
audioContext.value.destroy &&
|
||||||
|
audioContext.value.destroy()
|
||||||
|
})
|
||||||
|
|
||||||
|
onHide(() => {
|
||||||
|
if (audioContext.value && audioContext.value.pause) {
|
||||||
|
audioContext.value.pause()
|
||||||
|
state.isAudioPlay = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const onPlay = () => {
|
const onPlay = () => {
|
||||||
if (state.isAudioPlay) {
|
if (state.isAudioPlay) {
|
||||||
audioContext.value.pause();
|
audioContext.value.pause()
|
||||||
|
state.isAudioPlay = false
|
||||||
} else {
|
} else {
|
||||||
audioContext.value.play();
|
// 通知其它音频暂停
|
||||||
|
window.dispatchEvent(
|
||||||
|
new CustomEvent('audio-play', { detail: props.data.msg_id }),
|
||||||
|
)
|
||||||
|
audioContext.value.play()
|
||||||
|
state.isAudioPlay = true
|
||||||
}
|
}
|
||||||
|
}
|
||||||
state.isAudioPlay = !state.isAudioPlay;
|
|
||||||
};
|
|
||||||
|
|
||||||
const onPlayEnd = () => {
|
|
||||||
state.isAudioPlay = false;
|
|
||||||
state.progress = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
const formatTime = (value: number = 0) => {
|
const formatTime = (value: number = 0) => {
|
||||||
if (value == 0) {
|
if (value == 0) {
|
||||||
return "-";
|
return '-'
|
||||||
}
|
}
|
||||||
|
const minutes = Math.floor(value / 60)
|
||||||
const minutes = Math.floor(value / 60);
|
let seconds = value
|
||||||
let seconds = value;
|
|
||||||
if (minutes > 0) {
|
if (minutes > 0) {
|
||||||
seconds = Math.floor(value - minutes * 60);
|
seconds = Math.floor(value - minutes * 60)
|
||||||
}
|
}
|
||||||
|
return `${minutes}'${seconds}"`
|
||||||
return `${minutes}'${seconds}"`;
|
}
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="im-message-audio">
|
<div
|
||||||
<div class="play">
|
class="audio-message"
|
||||||
<div class="btn pointer" @click.stop="onPlay">
|
@click.stop="onPlay"
|
||||||
<n-icon
|
:class="
|
||||||
:size="18"
|
props?.data?.user_id == talkParams.uid
|
||||||
:component="state.isAudioPlay ? PauseOne : PlayOne"
|
? 'justify-end py-[22rpx] pl-[30rpx] pr-[16rpx]'
|
||||||
/>
|
: 'justify-start py-[22rpx] pr-[30rpx] pl-[16rpx]'
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<a-trumpet
|
||||||
|
v-if="props?.data?.user_id != talkParams.uid"
|
||||||
|
:isPlay="state.isAudioPlay"
|
||||||
|
color="#C1C1C1"
|
||||||
|
:size="30"
|
||||||
|
></a-trumpet>
|
||||||
|
<div
|
||||||
|
:class="
|
||||||
|
props?.data?.user_id == talkParams.uid ? 'mr-[8rpx]' : 'ml-[8rpx]'
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ Math.ceil(props?.extra?.duration / 1000) }}s
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<a-trumpet
|
||||||
<div class="desc">
|
v-if="props?.data?.user_id == talkParams.uid"
|
||||||
<span class="line" v-for="i in 23" :key="i"></span>
|
:isPlay="state.isAudioPlay"
|
||||||
<span
|
color="#C1C1C1"
|
||||||
class="indicator"
|
:size="30"
|
||||||
:style="{ left: state.progress + '%' }"
|
direction="left"
|
||||||
v-show="state.progress > 0"
|
></a-trumpet>
|
||||||
></span>
|
|
||||||
</div>
|
|
||||||
<div class="time">{{ durationDesc }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
.audio-message {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.im-message-audio {
|
.im-message-audio {
|
||||||
--audio-bg-color: #f5f5f5;
|
--audio-bg-color: #f5f5f5;
|
||||||
--audio-btn-bg-color: #ffffff;
|
--audio-btn-bg-color: #ffffff;
|
||||||
@ -245,7 +291,7 @@ const formatTime = (value: number = 0) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
html[theme-mode="dark"] {
|
html[theme-mode='dark'] {
|
||||||
.im-message-audio {
|
.im-message-audio {
|
||||||
--audio-bg-color: #2c2c32;
|
--audio-bg-color: #2c2c32;
|
||||||
--audio-btn-bg-color: rgb(78, 75, 75);
|
--audio-btn-bg-color: rgb(78, 75, 75);
|
||||||
|
|||||||
@ -25,58 +25,114 @@ const getFileTypeIMG = computed(() => {
|
|||||||
let objT = {
|
let objT = {
|
||||||
finishedImg: '',
|
finishedImg: '',
|
||||||
blankImg: '',
|
blankImg: '',
|
||||||
progressColor: ''
|
progressColor: '',
|
||||||
};
|
}
|
||||||
|
|
||||||
switch (suffix) {
|
switch (suffix) {
|
||||||
case 'pdf':
|
case 'pdf':
|
||||||
objT.finishedImg = filePaperPDF
|
objT.finishedImg = filePaperPDF
|
||||||
objT.blankImg = filePaperPDFBlank
|
objT.blankImg = filePaperPDFBlank
|
||||||
objT.progressColor = '#DE4E4E'
|
objT.progressColor = '#DE4E4E'
|
||||||
break;
|
break
|
||||||
case 'doc':
|
case 'doc':
|
||||||
case 'docx':
|
case 'docx':
|
||||||
objT.finishedImg = filePaperWord
|
objT.finishedImg = filePaperWord
|
||||||
objT.blankImg = filePaperWordBlank
|
objT.blankImg = filePaperWordBlank
|
||||||
objT.progressColor = '#2750B2'
|
objT.progressColor = '#2750B2'
|
||||||
break;
|
break
|
||||||
case 'xls':
|
case 'xls':
|
||||||
case 'xlsx':
|
case 'xlsx':
|
||||||
objT.finishedImg = filePaperExcel
|
objT.finishedImg = filePaperExcel
|
||||||
objT.blankImg = filePaperExcelBlank
|
objT.blankImg = filePaperExcelBlank
|
||||||
objT.progressColor = '#3C7F4B'
|
objT.progressColor = '#3C7F4B'
|
||||||
break;
|
break
|
||||||
case 'ppt':
|
case 'ppt':
|
||||||
case 'pptx':
|
case 'pptx':
|
||||||
objT.finishedImg = filePaperPPT
|
objT.finishedImg = filePaperPPT
|
||||||
objT.blankImg = filePaperPPTBlank
|
objT.blankImg = filePaperPPTBlank
|
||||||
objT.progressColor = '#B74B2B'
|
objT.progressColor = '#B74B2B'
|
||||||
break;
|
break
|
||||||
default:
|
default:
|
||||||
objT.finishedImg = filePaperOther
|
objT.finishedImg = filePaperOther
|
||||||
objT.blankImg = filePaperOtherBlank
|
objT.blankImg = filePaperOtherBlank
|
||||||
objT.progressColor = '#747474'
|
objT.progressColor = '#46299d'
|
||||||
}
|
}
|
||||||
return objT
|
return objT
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const previewPDF = () => {
|
||||||
|
if (typeof plus !== 'undefined') {
|
||||||
|
downloadAndOpenFile()
|
||||||
|
} else {
|
||||||
|
document.addEventListener('plusready', () => {
|
||||||
|
downloadAndOpenFile()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const downloadAndOpenFile = () => {
|
||||||
|
uni.showLoading({ title: '加载中...', mask: true })
|
||||||
|
const downloadUrl = props?.extra?.path
|
||||||
|
if (!downloadUrl) {
|
||||||
|
uni.hideLoading()
|
||||||
|
uni.showToast({ title: '文件路径无效', icon: 'none' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const options = {
|
||||||
|
filename: '_doc/downloads/', // 保存路径
|
||||||
|
}
|
||||||
|
const dtask = plus.downloader.createDownload(downloadUrl, options, function (
|
||||||
|
d,
|
||||||
|
status,
|
||||||
|
) {
|
||||||
|
if (status === 200) {
|
||||||
|
uni.hideLoading()
|
||||||
|
const filePath = d.filename
|
||||||
|
if (filePath) {
|
||||||
|
plus.runtime.openFile(filePath, {}, function () {})
|
||||||
|
} else {
|
||||||
|
uni.showToast({ title: '文件路径无效', icon: 'none' })
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uni.hideLoading()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
dtask.start()
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<section
|
<section
|
||||||
class="file-message"
|
class="file-message"
|
||||||
|
@click="previewPDF"
|
||||||
:class="{ left: data.float === 'left', right: data.float === 'right' }"
|
:class="{ left: data.float === 'left', right: data.float === 'right' }"
|
||||||
>
|
>
|
||||||
<div class="flex justify-between">
|
<div class="flex justify-between">
|
||||||
<div class="w-[228rpx] text-[32rpx] text-[#1A1A1A] h-[88rpx] leading-[44rpx] textEllipsis">
|
<div
|
||||||
|
class="w-[228rpx] text-[32rpx] text-[#1A1A1A] h-[88rpx] leading-[44rpx] textEllipsis file_name"
|
||||||
|
>
|
||||||
{{ extra.name }}
|
{{ extra.name }}
|
||||||
</div>
|
</div>
|
||||||
<div v-if="data.uploadStatus === 2 || !data.uploadStatus" class="w-[95rpx]">
|
<div
|
||||||
<tm-image :width="95" :height="95" :src="getFileTypeIMG.finishedImg"></tm-image>
|
v-if="data.uploadStatus === 2 || !data.uploadStatus"
|
||||||
|
class="w-[95rpx]"
|
||||||
|
>
|
||||||
|
<tm-image
|
||||||
|
:width="95"
|
||||||
|
:height="95"
|
||||||
|
:src="getFileTypeIMG.finishedImg"
|
||||||
|
></tm-image>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="data.uploadStatus === 1 || data.uploadStatus === 3" class="w-[95rpx]">
|
<div
|
||||||
<tm-image :width="95" :height="95" :src="getFileTypeIMG.blankImg"></tm-image>
|
v-if="data.uploadStatus === 1 || data.uploadStatus === 3"
|
||||||
<wd-circle
|
class="w-[95rpx]"
|
||||||
|
>
|
||||||
|
<tm-image
|
||||||
|
:width="95"
|
||||||
|
:height="95"
|
||||||
|
:src="getFileTypeIMG.blankImg"
|
||||||
|
></tm-image>
|
||||||
|
<wd-circle v-if="data.uploadStatus === 1"
|
||||||
customClass="circleProgress"
|
customClass="circleProgress"
|
||||||
:modelValue="data.uploadCurrent"
|
:modelValue="data.uploadCurrent"
|
||||||
layerColor="#E3E3E3"
|
layerColor="#E3E3E3"
|
||||||
@ -84,10 +140,15 @@ const getFileTypeIMG = computed(() => {
|
|||||||
:strokeWidth="3"
|
:strokeWidth="3"
|
||||||
:size="20"
|
:size="20"
|
||||||
></wd-circle>
|
></wd-circle>
|
||||||
|
<div class="upload-failed" v-if="data.uploadStatus === 3">
|
||||||
|
<tm-icon :font-size="20" name="tmicon-times" color="#fff"></tm-icon>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="divider mt-[28rpx]"></div>
|
<div class="divider mt-[28rpx]"></div>
|
||||||
<div class="text-[24rpx] text-[#747474] mt-[10rpx]">{{ fileFormatSize(extra.size) }}</div>
|
<div class="text-[24rpx] text-[#747474] mt-[10rpx]">
|
||||||
|
{{ fileFormatSize(extra.size) }}
|
||||||
|
</div>
|
||||||
<!-- <div class="main">
|
<!-- <div class="main">
|
||||||
<div class="ext">{{ getFileNameSuffix(extra.name) }}</div>
|
<div class="ext">{{ getFileNameSuffix(extra.name) }}</div>
|
||||||
<div class="file-box">
|
<div class="file-box">
|
||||||
@ -124,6 +185,11 @@ const getFileTypeIMG = computed(() => {
|
|||||||
border-radius: 16rpx 0 16rpx 16rpx;
|
border-radius: 16rpx 0 16rpx 16rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.file_name {
|
||||||
|
word-break: break-all; /* 在任意字符间断行 */
|
||||||
|
word-wrap: break-word; /* 允许长单词换行到下一行 */
|
||||||
|
}
|
||||||
|
|
||||||
.main {
|
.main {
|
||||||
height: 45px;
|
height: 45px;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -212,7 +278,7 @@ const getFileTypeIMG = computed(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.divider {
|
.divider {
|
||||||
background-color: #E7E7E7;
|
background-color: #e7e7e7;
|
||||||
height: 1rpx;
|
height: 1rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,4 +291,20 @@ const getFileTypeIMG = computed(() => {
|
|||||||
width: 40rpx !important;
|
width: 40rpx !important;
|
||||||
height: 40rpx !important;
|
height: 40rpx !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.upload-failed {
|
||||||
|
position: absolute;
|
||||||
|
top: 120rpx;
|
||||||
|
right: 52rpx;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
z-index: 1;
|
||||||
|
width: 40rpx;
|
||||||
|
height: 40rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: #ff4d4f;
|
||||||
|
background: #ff4d4f;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -12,19 +12,25 @@ const props = defineProps<{
|
|||||||
const isShowRecord = ref(false)
|
const isShowRecord = ref(false)
|
||||||
|
|
||||||
const title = computed(() => {
|
const title = computed(() => {
|
||||||
return [...new Set(props.extra.records.map((v) => v.nickname))].join('、')
|
const uniqueNames = [...new Set(props.extra.records.map(v => v.nickname))];
|
||||||
|
if (uniqueNames.length <= 2) {
|
||||||
|
return uniqueNames.join('和');
|
||||||
|
} else {
|
||||||
|
return uniqueNames.slice(0, 2).join('和') + '等';
|
||||||
|
}
|
||||||
|
// return [...new Set(props.extra.records.map((v) => v.nickname))].join('和')
|
||||||
})
|
})
|
||||||
|
console.log(props.extra.records)
|
||||||
const onClick = () => {
|
const onClick = () => {
|
||||||
// isShowRecord.value = true
|
// isShowRecord.value = true
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: '/pages/forwardRecord/index?msgId=' + props.data.msg_id
|
url: '/pages/forwardRecord/index?msgId=' + props.data.msg_id + '&created_at=' + props.data?.created_at
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<section class="im-message-forward pointer" :class="{ left: data.float === 'left' }" @click="onClick">
|
<section class="im-message-forward pointer" :class="{ left: data.float === 'left' }" @click="onClick">
|
||||||
<div class="title">{{ title }} 的会话记录</div>
|
<div class="title">{{ extra.forward_name || title}}的会话记录</div>
|
||||||
<div class="list" v-for="(record, index) in extra.records" :key="index">
|
<div class="list" v-for="(record, index) in extra.records" :key="index">
|
||||||
<p>
|
<p>
|
||||||
<span>{{ record.nickname }}: </span>
|
<span>{{ record.nickname }}: </span>
|
||||||
@ -59,13 +65,14 @@ const onClick = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
height: 44rpx;
|
max-height: 88rpx;
|
||||||
line-height: 44rpx;
|
line-height: 44rpx;
|
||||||
font-size: 32rpx;
|
font-size: 32rpx;
|
||||||
color: #1A1A1A;
|
color: #1A1A1A;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
margin-bottom: 8rpx;
|
margin-bottom: 8rpx;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,40 +12,40 @@ const img = computed(() => {
|
|||||||
// console.log(props.extra);
|
// console.log(props.extra);
|
||||||
let info = {
|
let info = {
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0
|
height: 0,
|
||||||
}
|
}
|
||||||
if (props.extra.url.includes('blob:http://')) {
|
if (props.extra.url.includes('blob:http://')) {
|
||||||
info = {
|
info = {
|
||||||
width: props.extra.width,
|
width: props.extra.width,
|
||||||
height: props.extra.height
|
height: props.extra.height,
|
||||||
}
|
}
|
||||||
}else {
|
} else {
|
||||||
info = getImageInfo(props.extra.url)
|
info = getImageInfo(props.extra.url)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.width == 0 || info.height == 0) {
|
if (info.width == 0 || info.height == 0) {
|
||||||
return {
|
return {
|
||||||
width: 450,
|
width: 450,
|
||||||
height: 298
|
height: 298,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(info.width<300){
|
if (info.width < 300) {
|
||||||
return {
|
return {
|
||||||
width: 300,
|
width: 300,
|
||||||
height: info.height / (info.width / 300)
|
height: info.height / (info.width / 300),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.width < 350) {
|
if (info.width < 350) {
|
||||||
return {
|
return {
|
||||||
width: info.width,
|
width: info.width,
|
||||||
height: info.height
|
height: info.height,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
width: 350,
|
width: 350,
|
||||||
height: info.height / (info.width / 350)
|
height: info.height / (info.width / 350),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
@ -54,12 +54,29 @@ const img = computed(() => {
|
|||||||
class="im-message-image"
|
class="im-message-image"
|
||||||
:class="{
|
:class="{
|
||||||
left: data.float === 'left',
|
left: data.float === 'left',
|
||||||
right: data.float === 'right'
|
right: data.float === 'right',
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<div class="image-container">
|
<div class="image-container">
|
||||||
<tm-image preview :width="img.width" :height="img.height" :src="extra.url" />
|
<div class="relative">
|
||||||
<wd-circle custom-class="circleProgress" v-if="props.data.uploadCurrent && props.data.uploadCurrent<100" v-model="props.data.uploadCurrent" color="#ffffff" layer-color="#E3E3E3"></wd-circle>
|
<tm-image
|
||||||
|
preview
|
||||||
|
:width="img.width"
|
||||||
|
:height="img.height"
|
||||||
|
:src="extra.url"
|
||||||
|
model="aspectFill"
|
||||||
|
/>
|
||||||
|
<wd-circle
|
||||||
|
custom-class="circleProgress"
|
||||||
|
v-if="data.uploadStatus === 1"
|
||||||
|
v-model="props.data.uploadCurrent"
|
||||||
|
color="#46299d"
|
||||||
|
layer-color="#E3E3E3"
|
||||||
|
></wd-circle>
|
||||||
|
<div class="upload-failed" v-if="data.uploadStatus === 3">
|
||||||
|
<tm-icon :font-size="20" name="tmicon-times" color="#fff"></tm-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
@ -79,7 +96,7 @@ const img = computed(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.right {
|
&.right {
|
||||||
background-color: #46299D;
|
background-color: #46299d;
|
||||||
border-radius: 16rpx 0 16rpx 16rpx;
|
border-radius: 16rpx 0 16rpx 16rpx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,4 +111,18 @@ const img = computed(() => {
|
|||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.upload-failed {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
z-index: 1;
|
||||||
|
width: 40rpx;
|
||||||
|
height: 40rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: #ff4d4f;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -4,34 +4,97 @@ import { formatTime } from '@/utils/datetime'
|
|||||||
defineProps({
|
defineProps({
|
||||||
login_uid: {
|
login_uid: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 0
|
default: 0,
|
||||||
},
|
},
|
||||||
user_id: {
|
user_id: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 0
|
default: 0,
|
||||||
},
|
},
|
||||||
talk_type: {
|
talk_type: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 0
|
default: 0,
|
||||||
},
|
},
|
||||||
nickname: {
|
nickname: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: '',
|
||||||
},
|
},
|
||||||
datetime: {
|
datetime: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: '',
|
||||||
|
},
|
||||||
|
msg_id: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
revokeInfo: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
extra:{
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="im-message-revoke">
|
<div class="im-message-revoke">
|
||||||
<div class="content">
|
<div class="content" v-if="JSON.stringify(revokeInfo) !== '{}'">
|
||||||
<span v-if="login_uid == user_id"> 你撤回了一条消息 | {{ formatTime(datetime) }} </span>
|
<span v-if="talk_type === 1 && login_uid === revokeInfo.withdraw_id">
|
||||||
<span v-else-if="talk_type == 1"> 对方撤回了一条消息 | {{ formatTime(datetime) }} </span>
|
你撤回了一条消息 | {{ formatTime(datetime) }}
|
||||||
<span v-else>
|
<slot></slot>
|
||||||
"{{ nickname }}" 撤回了一条消息 |
|
<!-- 添加插槽用于放置重新编辑按钮 -->
|
||||||
|
</span>
|
||||||
|
<span v-if="talk_type === 1 && login_uid !== revokeInfo.withdraw_id">
|
||||||
|
{{revokeInfo.withdraw_name}}撤回了一条消息 | {{ formatTime(datetime) }}
|
||||||
|
</span>
|
||||||
|
<span v-if="talk_type === 2 && login_uid === revokeInfo.withdraw_id && login_uid === revokeInfo.retracted_id">
|
||||||
|
你撤回了一条消息 |
|
||||||
{{ formatTime(datetime) }}
|
{{ formatTime(datetime) }}
|
||||||
|
<slot></slot>
|
||||||
|
</span>
|
||||||
|
<span v-if="talk_type === 2 && login_uid === revokeInfo.withdraw_id && login_uid !== revokeInfo.retracted_id">
|
||||||
|
你撤回了{{revokeInfo.retracted_name}}一条消息 |
|
||||||
|
{{ formatTime(datetime) }}
|
||||||
|
</span>
|
||||||
|
<span v-if="talk_type === 2 && login_uid !== revokeInfo.withdraw_id && revokeInfo.withdraw_id === revokeInfo.retracted_id">
|
||||||
|
{{revokeInfo.withdraw_name}}撤回了一条消息 |
|
||||||
|
{{ formatTime(datetime) }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span v-if="talk_type === 2 && login_uid !== revokeInfo.withdraw_id && login_uid === revokeInfo.retracted_id && revokeInfo.withdraw_id !== revokeInfo.retracted_id">
|
||||||
|
{{revokeInfo.withdraw_name}}撤回了你一条消息 |
|
||||||
|
{{ formatTime(datetime) }}
|
||||||
|
</span>
|
||||||
|
<span v-if="talk_type === 2 && login_uid !== revokeInfo.withdraw_id && login_uid !== revokeInfo.retracted_id && revokeInfo.withdraw_id !== revokeInfo.retracted_id">
|
||||||
|
{{revokeInfo.withdraw_name}}撤回了{{revokeInfo.retracted_name}}一条消息 |
|
||||||
|
{{ formatTime(datetime) }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<!-- <span v-if="login_uid == user_idA"> 你撤回B了一条消息 | {{ formatTime(datetime) }} </span>
|
||||||
|
<span v-else-if="login_uid == user_idB"> A撤回你了一条消息 | {{ formatTime(datetime) }} </span>
|
||||||
|
<span v-else> A撤回B了一条消息 | {{ formatTime(datetime) }} </span> -->
|
||||||
|
</div>
|
||||||
|
<div class="content" v-if="JSON.stringify(revokeInfo) === '{}'">
|
||||||
|
<span v-if="talk_type === 1 && login_uid === user_id">
|
||||||
|
你撤回了一条消息 | {{ formatTime(datetime) }}
|
||||||
|
<slot></slot>
|
||||||
|
<!-- 添加插槽用于放置重新编辑按钮 -->
|
||||||
|
</span>
|
||||||
|
<span v-if="talk_type === 1 && login_uid !== user_id">
|
||||||
|
{{nickname}}撤回了一条消息 | {{ formatTime(datetime) }}
|
||||||
|
</span>
|
||||||
|
<span v-if="talk_type === 2 && !extra && login_uid === user_id">
|
||||||
|
你撤回了一条消息 | {{ formatTime(datetime) }}
|
||||||
|
<slot></slot>
|
||||||
|
<!-- 添加插槽用于放置重新编辑按钮 -->
|
||||||
|
</span>
|
||||||
|
<span v-if="talk_type === 2 && !extra && login_uid !== user_id">
|
||||||
|
{{nickname}}撤回了一条消息 | {{ formatTime(datetime) }}
|
||||||
|
</span>
|
||||||
|
<span v-if="talk_type === 2 && extra">
|
||||||
|
{{extra}} | {{ formatTime(datetime) }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
import { textReplaceEmoji } from '@/utils/emojis'
|
import { textReplaceEmoji } from '@/utils/emojis'
|
||||||
import { textReplaceLink, textReplaceMention } from '@/utils/strings'
|
import { textReplaceLink, textReplaceMention } from '@/utils/strings'
|
||||||
import { ITalkRecordExtraText, ITalkRecord } from '@/types/chat'
|
import { ITalkRecordExtraText, ITalkRecord } from '@/types/chat'
|
||||||
|
import { computed } from 'vue'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
extra: ITalkRecordExtraText
|
extra: ITalkRecordExtraText
|
||||||
@ -12,15 +13,14 @@ const props = defineProps<{
|
|||||||
|
|
||||||
const float = props.data.float
|
const float = props.data.float
|
||||||
|
|
||||||
let textContent = props.extra?.content || ''
|
const textContent = computed(() => {
|
||||||
|
let text = props.extra?.content || ''
|
||||||
textContent = textReplaceLink(textContent)
|
// text = textReplaceLink(text)
|
||||||
|
if (props.data.talk_type == 2) {
|
||||||
if (props.data.talk_type == 2) {
|
text = textReplaceMention(text, '#1890ff')
|
||||||
textContent = textReplaceMention(textContent, '#1890ff')
|
}
|
||||||
}
|
return textReplaceEmoji(text)
|
||||||
|
})
|
||||||
textContent = textReplaceEmoji(textContent)
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, nextTick, getCurrentInstance, computed, onMounted } from 'vue'
|
import { ref, nextTick, getCurrentInstance, computed, onMounted } from 'vue'
|
||||||
import { getImageInfo } from '@/utils/functions'
|
import { getImageInfo } from '@/utils/functions'
|
||||||
import playCircle from "@/static/image/chatList/playCircle@2x.png";
|
import playCircle from '@/static/image/chatList/playCircle@2x.png'
|
||||||
import { useStatus } from "@/store/status";
|
import { useStatus } from '@/store/status'
|
||||||
|
|
||||||
const { statusBarHeight } = useStatus()
|
const { statusBarHeight } = useStatus()
|
||||||
const instance = getCurrentInstance()
|
const instance = getCurrentInstance()
|
||||||
@ -20,12 +20,12 @@ const open = ref(false)
|
|||||||
const img = computed(() => {
|
const img = computed(() => {
|
||||||
let info = {
|
let info = {
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0
|
height: 0,
|
||||||
}
|
}
|
||||||
if (props.extra.url.includes('blob:http://')) {
|
if (props.extra.url.includes('blob:http://')) {
|
||||||
info = {
|
info = {
|
||||||
width: props.extra.width,
|
width: props.extra.width,
|
||||||
height: props.extra.height
|
height: props.extra.height,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
info = getImageInfo(props.extra.url)
|
info = getImageInfo(props.extra.url)
|
||||||
@ -34,26 +34,26 @@ const img = computed(() => {
|
|||||||
if (info.width == 0 || info.height == 0) {
|
if (info.width == 0 || info.height == 0) {
|
||||||
return {
|
return {
|
||||||
width: 450,
|
width: 450,
|
||||||
height: 298
|
height: 298,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (info.width < 300) {
|
if (info.width < 300) {
|
||||||
return {
|
return {
|
||||||
width: 300,
|
width: 300,
|
||||||
height: info.height / (info.width / 300)
|
height: info.height / (info.width / 300),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.width < 350) {
|
if (info.width < 350) {
|
||||||
return {
|
return {
|
||||||
width: info.width,
|
width: info.width,
|
||||||
height: info.height
|
height: info.height,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
width: 350,
|
width: 350,
|
||||||
height: info.height / (info.width / 350)
|
height: info.height / (info.width / 350),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -67,57 +67,98 @@ const fullscreenchange = (e) => {
|
|||||||
|
|
||||||
/* 视频播放 获取第一帧 */
|
/* 视频播放 获取第一帧 */
|
||||||
const canplay = (e) => {
|
const canplay = (e) => {
|
||||||
console.log('Video can play:', e);
|
console.log('Video can play:', e)
|
||||||
|
|
||||||
if (e.target) {
|
if (e.target) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
e.target.pause();
|
e.target.pause()
|
||||||
}, 200);
|
}, 200)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
async function onPlay() {
|
async function onPlay() {
|
||||||
videoContext.value = uni.createVideoContext(props.extra.url, instance);
|
|
||||||
videoContext.value.requestFullScreen({ direction: 2 });
|
|
||||||
videoContext.value.play()
|
|
||||||
open.value = true
|
open.value = true
|
||||||
|
await nextTick()
|
||||||
|
videoContext.value = uni.createVideoContext(props.extra.url, instance)
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
// 先请求全屏
|
||||||
|
videoContext.value.requestFullScreen({ direction: 2 })
|
||||||
|
|
||||||
|
// 延迟一下再播放,确保全屏已经完成
|
||||||
|
setTimeout(() => {
|
||||||
|
videoContext.value.play()
|
||||||
|
}, 100)
|
||||||
|
}, 200)
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
videoRef.value = uni.createVideoContext(props.data.msg_id);
|
videoRef.value = uni.createVideoContext(props.data.msg_id)
|
||||||
videoRef.value.play()
|
videoRef.value.play()
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
videoRef.value.pause()
|
videoRef.value.pause()
|
||||||
}, 200);
|
}, 200)
|
||||||
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<section class="im-message-video" :class="{ left: data.float === 'left' }" @click="onPlay">
|
<section
|
||||||
<div class="coverVideo" :style="{
|
class="im-message-video"
|
||||||
|
:class="{ left: data.float === 'left' }"
|
||||||
|
@click="onPlay"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="coverVideo"
|
||||||
|
:style="{
|
||||||
width: img.width + 'rpx',
|
width: img.width + 'rpx',
|
||||||
height: img.height + 'rpx'
|
height: img.height + 'rpx',
|
||||||
}" v-if="props.extra.url.includes('blob:http://')">
|
}"
|
||||||
<video :id="data.msg_id" :autoplay="false" disablepictureinpicture muted :src="props.extra.url" width="100%"
|
v-if="props.extra.url.includes('blob:http://')"
|
||||||
height="100%" playsinline preload="auto" controls="false" x5-playsinline
|
>
|
||||||
webkit-playsinline style="object-fit: cover; pointer-events: none;">
|
<video
|
||||||
</video>
|
:id="data.msg_id"
|
||||||
|
:autoplay="false"
|
||||||
|
disablepictureinpicture
|
||||||
|
muted
|
||||||
|
:src="props.extra.url"
|
||||||
|
width="100%"
|
||||||
|
height="100%"
|
||||||
|
playsinline
|
||||||
|
preload="auto"
|
||||||
|
controls="false"
|
||||||
|
x5-playsinline
|
||||||
|
webkit-playsinline
|
||||||
|
style="object-fit: cover; pointer-events: none;"
|
||||||
|
></video>
|
||||||
</div>
|
</div>
|
||||||
<wd-img v-else :width="`${img.width}rpx`" :height="`${img.height}rpx`" :src="data.extra.cover" />
|
<wd-img
|
||||||
<div v-if="data.uploadStatus === 2 || !data.uploadStatus" class="btn-video" :style="{
|
v-else
|
||||||
|
:width="`${img.width}rpx`"
|
||||||
|
:height="`${img.height}rpx`"
|
||||||
|
:src="data.extra.cover"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
v-if="data.uploadStatus === 2 || !data.uploadStatus"
|
||||||
|
class="btn-video"
|
||||||
|
:style="{
|
||||||
width: img.width + 'rpx',
|
width: img.width + 'rpx',
|
||||||
height: img.height + 'rpx'
|
height: img.height + 'rpx',
|
||||||
}">
|
}"
|
||||||
|
>
|
||||||
<tm-image :src="playCircle" :width="80" :height="80" />
|
<tm-image :src="playCircle" :width="80" :height="80" />
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="btn-video" :style="{
|
<div
|
||||||
|
v-else
|
||||||
|
class="btn-video"
|
||||||
|
:style="{
|
||||||
width: img.width + 'rpx',
|
width: img.width + 'rpx',
|
||||||
height: img.height + 'rpx'
|
height: img.height + 'rpx',
|
||||||
}" >
|
}"
|
||||||
|
>
|
||||||
<wd-circle
|
<wd-circle
|
||||||
|
v-if="data.uploadStatus === 1"
|
||||||
v-model="props.data.uploadCurrent"
|
v-model="props.data.uploadCurrent"
|
||||||
customClass="circleProgress"
|
customClass="circleProgress"
|
||||||
layerColor="#E3E3E3"
|
color="#46299d"
|
||||||
color="#FFFFFF"
|
layer-color="#E3E3E3"
|
||||||
:strokeWidth="6"
|
:strokeWidth="6"
|
||||||
:size="40"
|
:size="40"
|
||||||
></wd-circle>
|
></wd-circle>
|
||||||
@ -131,18 +172,32 @@ onMounted(() => {
|
|||||||
:width="70"
|
:width="70"
|
||||||
:percent="props.data.uploadCurrent">
|
:percent="props.data.uploadCurrent">
|
||||||
</tm-progress> -->
|
</tm-progress> -->
|
||||||
|
<div class="upload-failed" v-if="data.uploadStatus === 3">
|
||||||
|
<tm-icon :font-size="20" name="tmicon-times" color="#fff"></tm-icon>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="open">
|
|
||||||
<video :src="props.extra.url" controls @fullscreenchange="fullscreenchange" :id="props.extra.url">
|
|
||||||
</video>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<teleport to="body">
|
||||||
|
<div v-show="open" class="video-container">
|
||||||
|
<video
|
||||||
|
:src="props.extra.url"
|
||||||
|
controls
|
||||||
|
@fullscreenchange="fullscreenchange"
|
||||||
|
:id="props.extra.url"
|
||||||
|
playsinline
|
||||||
|
webkit-playsinline
|
||||||
|
x5-playsinline
|
||||||
|
class="fullscreen-video"
|
||||||
|
></video>
|
||||||
|
</div>
|
||||||
|
</teleport>
|
||||||
</template>
|
</template>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.im-message-video {
|
.im-message-video {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding: 20rpx 18rpx;
|
padding: 20rpx 18rpx;
|
||||||
background: #46299D;
|
background: #46299d;
|
||||||
min-width: 30rpx;
|
min-width: 30rpx;
|
||||||
min-height: 30rpx;
|
min-height: 30rpx;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
@ -200,10 +255,43 @@ onMounted(() => {
|
|||||||
:deep(.uni-video-bar) {
|
:deep(.uni-video-bar) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
.circleProgress {
|
.circleProgress {
|
||||||
width: 80rpx !important;
|
width: 80rpx !important;
|
||||||
height: 80rpx !important;
|
height: 80rpx !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.video-container {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
background: #000;
|
||||||
|
z-index: 9999;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fullscreen-video {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-failed {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
z-index: 1;
|
||||||
|
width: 40rpx;
|
||||||
|
height: 40rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: #ff4d4f;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
25
src/components/talk/message/system/SysGroupAdminMessage.vue
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<script setup>
|
||||||
|
import './sys-message.less'
|
||||||
|
import { useInject } from '@/hooks'
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
extra: Object,
|
||||||
|
data: Object
|
||||||
|
})
|
||||||
|
|
||||||
|
const { showUserInfoModal } = useInject()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="im-message-sys-text">
|
||||||
|
<div class="sys-text">
|
||||||
|
|
||||||
|
<template v-for="(user, index) in extra.members" :key="index">
|
||||||
|
<a @click="showUserInfoModal(user.user_id)">{{ user.nickname }}</a>
|
||||||
|
<em v-show="index < extra.members.length - 1">、</em>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<span>已成为管理员</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
19
src/components/talk/message/system/SysGroupDismissed.vue
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<script setup>
|
||||||
|
import './sys-message.less'
|
||||||
|
import { useInject } from '@/hooks'
|
||||||
|
|
||||||
|
const { showUserInfoModal } = useInject()
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
extra: Object,
|
||||||
|
data: Object
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="im-message-sys-text">
|
||||||
|
<div class="sys-text">
|
||||||
|
<span>{{ extra.content }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
<script setup>
|
||||||
|
import './sys-message.less'
|
||||||
|
import { useInject } from '@/hooks'
|
||||||
|
|
||||||
|
const { showUserInfoModal } = useInject()
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
extra: Object,
|
||||||
|
data: Object
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="im-message-sys-text">
|
||||||
|
<div class="sys-text">
|
||||||
|
<a @click="showUserInfoModal(data.user_id)">
|
||||||
|
<!-- {{ data.nickname }} -->
|
||||||
|
管理员
|
||||||
|
</a>
|
||||||
|
<!-- <span>修改群名为</span>
|
||||||
|
<span>"{{ extra.group_name }}"</span> -->
|
||||||
|
<span>修改了群信息</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@ -24,7 +24,7 @@ const { showUserInfoModal } = useInject()
|
|||||||
<em v-show="index < extra.members.length - 1">、</em>
|
<em v-show="index < extra.members.length - 1">、</em>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<span>踢出群聊</span>
|
<span>移出群聊</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -0,0 +1,23 @@
|
|||||||
|
<script setup>
|
||||||
|
import './sys-message.less'
|
||||||
|
import { useInject } from '@/hooks'
|
||||||
|
|
||||||
|
const { showUserInfoModal } = useInject()
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
extra: Object,
|
||||||
|
data: Object,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="im-message-sys-text">
|
||||||
|
<div class="sys-text">
|
||||||
|
<template v-for="(user, index) in extra?.members" :key="index">
|
||||||
|
<a @click="showUserInfoModal(user.user_id)">{{ user.nickname }}</a>
|
||||||
|
<em v-show="index < extra.members.length - 1">、</em>
|
||||||
|
</template>
|
||||||
|
<span>已离开此群</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
153
src/components/talk/message/system/sysPushMessage.vue
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
<script setup>
|
||||||
|
import { handleFindWebview } from '@/utils/common'
|
||||||
|
import noClockAfterWork from '@/static/image/chatBotMessageCard/noClockAfterWork.png'
|
||||||
|
import noClockBeforeWork from '@/static/image/chatBotMessageCard/noClockBeforeWork.png'
|
||||||
|
import copy from '@/static/image/chatBotMessageCard/copy.png'
|
||||||
|
import errorClock from '@/static/image/chatBotMessageCard/errorClock.png'
|
||||||
|
import prompt from '@/static/image/chatBotMessageCard/prompt.png'
|
||||||
|
|
||||||
|
const emits = defineEmits(['openPromptDrawer'])
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
extra: Object,
|
||||||
|
data: Object,
|
||||||
|
})
|
||||||
|
|
||||||
|
//聊天助手发送的系统消息卡片图片
|
||||||
|
const getMessageCard = computed(() => {
|
||||||
|
switch (props.data.msg_type) {
|
||||||
|
case 1117: //催办提醒
|
||||||
|
return prompt
|
||||||
|
case 1118: //上班未打卡
|
||||||
|
return noClockBeforeWork
|
||||||
|
case 1119: //下班未打卡
|
||||||
|
return noClockAfterWork
|
||||||
|
case 1120: //待审批
|
||||||
|
return prompt
|
||||||
|
case 1121: //抄送
|
||||||
|
return copy
|
||||||
|
case 1122: //缺卡
|
||||||
|
return errorClock
|
||||||
|
case 1123: //迟到
|
||||||
|
return errorClock
|
||||||
|
case 1124: //早退
|
||||||
|
return errorClock
|
||||||
|
default:
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
//聊天助手发送的系统消息文字颜色
|
||||||
|
const getTextColor = computed(() => {
|
||||||
|
const msgType = props.data.msg_type
|
||||||
|
//审批催办、审批
|
||||||
|
if ([1117, 1120].includes(msgType)) return '#2668BF'
|
||||||
|
//上班未打卡、下班未打卡
|
||||||
|
if ([1118, 1119].includes(msgType)) return '#46299D'
|
||||||
|
//抄送
|
||||||
|
if (msgType === 1121) return '#2099BE'
|
||||||
|
//缺卡、迟到、早退
|
||||||
|
if ([1122, 1123, 1124].includes(msgType)) return '#933BA3'
|
||||||
|
return ''
|
||||||
|
})
|
||||||
|
|
||||||
|
//聊天助手发送的系统消息文字内容
|
||||||
|
const getTextContent = computed(() => {
|
||||||
|
const msgType = props.data.msg_type
|
||||||
|
//审批催办、审批
|
||||||
|
if ([1117, 1120].includes(msgType)) return '立即审批'
|
||||||
|
//上班未打卡、下班未打卡
|
||||||
|
if ([1118, 1119].includes(msgType)) return '立即打卡'
|
||||||
|
//抄送、缺卡、迟到、早退
|
||||||
|
if ([1121, 1122, 1123, 1124].includes(msgType)) return '立即查看'
|
||||||
|
return ''
|
||||||
|
})
|
||||||
|
|
||||||
|
//点击向webview通信,处理智能助手系统消息
|
||||||
|
const handleSysMessagePush = () => {
|
||||||
|
if (props?.extra?.url) {
|
||||||
|
//直接返回地址的,直接在当前页面弹出抽屉打开
|
||||||
|
emits('openPromptDrawer', encodeURIComponent(props?.extra?.url))
|
||||||
|
} else {
|
||||||
|
handleFindWebview(
|
||||||
|
`handleChatRobotSysMessagePush('${encodeURIComponent(
|
||||||
|
JSON.stringify({
|
||||||
|
url: props?.extra?.url,
|
||||||
|
msg_type: props?.data?.msg_type,
|
||||||
|
}),
|
||||||
|
)}')`,
|
||||||
|
)
|
||||||
|
uni.reLaunch({
|
||||||
|
url: '/pages/index/index',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="sys-message-push" @click="handleSysMessagePush">
|
||||||
|
<div class="sys-message-push-card">
|
||||||
|
<span class="sys-message-push-card-title">{{ props.extra.title }}</span>
|
||||||
|
<span
|
||||||
|
class="sys-message-push-card-message"
|
||||||
|
v-html="props.extra.message"
|
||||||
|
></span>
|
||||||
|
<img :src="getMessageCard" alt="" />
|
||||||
|
</div>
|
||||||
|
<div class="sys-message-push-card-btn">
|
||||||
|
<span :style="{ color: getTextColor }">{{ getTextContent }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.sys-message-push {
|
||||||
|
border-radius: 0 16rpx 16rpx 16rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 6px 12px 2px rgba(188, 188, 188, 0.08);
|
||||||
|
.sys-message-push-card {
|
||||||
|
position: relative;
|
||||||
|
width: 486rpx;
|
||||||
|
height: 270rpx;
|
||||||
|
.sys-message-push-card-title {
|
||||||
|
position: absolute;
|
||||||
|
top: 28rpx;
|
||||||
|
left: 30rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
line-height: 34rpx;
|
||||||
|
color: rgba(255, 255, 255, 0.73);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.sys-message-push-card-message {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 44rpx;
|
||||||
|
left: 30rpx;
|
||||||
|
font-size: 40rpx;
|
||||||
|
line-height: 58rpx;
|
||||||
|
color: #fff;
|
||||||
|
font-weight: bold;
|
||||||
|
min-width: 326rpx;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.sys-message-push-card-btn {
|
||||||
|
background-color: #fff;
|
||||||
|
width: 486rpx;
|
||||||
|
height: 78rpx;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
text {
|
||||||
|
color: #000;
|
||||||
|
font-size: 28rpx;
|
||||||
|
line-height: 40rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -30,6 +30,7 @@ class Connect {
|
|||||||
},
|
},
|
||||||
// Websocket 连接成功回调方法
|
// Websocket 连接成功回调方法
|
||||||
onOpen: () => {
|
onOpen: () => {
|
||||||
|
console.log("socket已连接")
|
||||||
// 更新 WebSocket 连接状态
|
// 更新 WebSocket 连接状态
|
||||||
useUserStore().updateSocketStatus(true)
|
useUserStore().updateSocketStatus(true)
|
||||||
// online.value = true;
|
// online.value = true;
|
||||||
@ -37,6 +38,7 @@ class Connect {
|
|||||||
},
|
},
|
||||||
// Websocket 断开连接回调方法
|
// Websocket 断开连接回调方法
|
||||||
onClose: () => {
|
onClose: () => {
|
||||||
|
console.log("socket已断开")
|
||||||
// 更新 WebSocket 连接状态
|
// 更新 WebSocket 连接状态
|
||||||
useUserStore().updateSocketStatus(false)
|
useUserStore().updateSocketStatus(false)
|
||||||
// online.value = false
|
// online.value = false
|
||||||
|
|||||||
@ -17,7 +17,7 @@ export const ChatMsgSysText = 1000 // 系统文本消息
|
|||||||
export const ChatMsgSysGroupCreate = 1101 // 创建群聊消息
|
export const ChatMsgSysGroupCreate = 1101 // 创建群聊消息
|
||||||
export const ChatMsgSysGroupMemberJoin = 1102 // 加入群聊消息
|
export const ChatMsgSysGroupMemberJoin = 1102 // 加入群聊消息
|
||||||
export const ChatMsgSysGroupMemberQuit = 1103 // 群成员退出群消息
|
export const ChatMsgSysGroupMemberQuit = 1103 // 群成员退出群消息
|
||||||
export const ChatMsgSysGroupMemberKicked = 1104 // 踢出群成员消息
|
export const ChatMsgSysGroupMemberKicked = 1104 // 移出群成员消息(普通群、项目群被踢)
|
||||||
export const ChatMsgSysGroupMessageRevoke = 1105 // 管理员撤回成员消息
|
export const ChatMsgSysGroupMessageRevoke = 1105 // 管理员撤回成员消息
|
||||||
export const ChatMsgSysGroupDismissed = 1106 // 群解散
|
export const ChatMsgSysGroupDismissed = 1106 // 群解散
|
||||||
export const ChatMsgSysGroupMuted = 1107 // 群禁言
|
export const ChatMsgSysGroupMuted = 1107 // 群禁言
|
||||||
@ -26,6 +26,17 @@ export const ChatMsgSysGroupMemberMuted = 1109 // 群成员禁言
|
|||||||
export const ChatMsgSysGroupMemberCancelMuted = 1110 // 群成员解除禁言
|
export const ChatMsgSysGroupMemberCancelMuted = 1110 // 群成员解除禁言
|
||||||
export const ChatMsgSysGroupNotice = 1111 // 编辑群公告
|
export const ChatMsgSysGroupNotice = 1111 // 编辑群公告
|
||||||
export const ChatMsgSysGroupTransfer = 1113 // 变更群主
|
export const ChatMsgSysGroupTransfer = 1113 // 变更群主
|
||||||
|
export const ChatMsgSysGroupAdmin = 1114 // 设置管理员
|
||||||
|
export const ChatMsgSysGroupMemberRemoved = 1115 // 移出群成员消息(部门群、公司群自动移出)
|
||||||
|
export const ChatMsgSysGroupInfoChange = 1116 // 管理员更新了群信息
|
||||||
|
export const ChatMsgSysPush_PromptReminder = 1117 // 系统推送消息-催办提醒
|
||||||
|
export const ChatMsgSysPush_NoClockReminderBeforeWork = 1118 // 系统推送消息-上班未打卡
|
||||||
|
export const ChatMsgSysPush_NoClockReminderAfterWork = 1119 // 系统推送消息-下班未打卡
|
||||||
|
export const ChatMsgSysPush_ApprovalReminder = 1120 // 系统推送消息-待审批提醒
|
||||||
|
export const ChatMsgSysPush_CopyReminder = 1121 // 系统推送消息-抄送提醒
|
||||||
|
export const ChatMsgSysPush_AbsentReminder = 1122 // 系统推送消息-缺卡提醒
|
||||||
|
export const ChatMsgSysPush_LateReminder = 1123 // 系统推送消息-迟到提醒
|
||||||
|
export const ChatMsgSysPush_EarlyReminder = 1124 // 系统推送消息-早退提醒
|
||||||
|
|
||||||
export const ChatMsgTypeMapping = {
|
export const ChatMsgTypeMapping = {
|
||||||
[ChatMsgTypeText]: '[文本消息]',
|
[ChatMsgTypeText]: '[文本消息]',
|
||||||
@ -46,14 +57,26 @@ export const ChatMsgTypeMapping = {
|
|||||||
[ChatMsgSysGroupCreate]: '[创建群消息]',
|
[ChatMsgSysGroupCreate]: '[创建群消息]',
|
||||||
[ChatMsgSysGroupMemberJoin]: '[加入群消息]',
|
[ChatMsgSysGroupMemberJoin]: '[加入群消息]',
|
||||||
[ChatMsgSysGroupMemberQuit]: '[退出群消息]',
|
[ChatMsgSysGroupMemberQuit]: '[退出群消息]',
|
||||||
[ChatMsgSysGroupMemberKicked]: '[踢出群消息]',
|
[ChatMsgSysGroupMemberKicked]: '[移出群消息]',
|
||||||
[ChatMsgSysGroupMessageRevoke]: '[撤回消息]',
|
[ChatMsgSysGroupMessageRevoke]: '[撤回消息]',
|
||||||
[ChatMsgSysGroupDismissed]: '[群解散消息]',
|
[ChatMsgSysGroupDismissed]: '[群解散消息]',
|
||||||
[ChatMsgSysGroupMuted]: '[群禁言消息]',
|
[ChatMsgSysGroupMuted]: '[群禁言消息]',
|
||||||
[ChatMsgSysGroupCancelMuted]: '[群解除禁言消息]',
|
[ChatMsgSysGroupCancelMuted]: '[群解除禁言消息]',
|
||||||
[ChatMsgSysGroupMemberMuted]: '[群成员禁言消息]',
|
[ChatMsgSysGroupMemberMuted]: '[群成员禁言消息]',
|
||||||
[ChatMsgSysGroupMemberCancelMuted]: '[群成员解除禁言消息]',
|
[ChatMsgSysGroupMemberCancelMuted]: '[群成员解除禁言消息]',
|
||||||
[ChatMsgSysGroupNotice]: '[群公告]'
|
[ChatMsgSysGroupNotice]: '[群公告]',
|
||||||
|
[ChatMsgSysGroupTransfer]: '[转让群主]',
|
||||||
|
[ChatMsgSysGroupAdmin]: '[设置管理员]',
|
||||||
|
[ChatMsgSysGroupMemberRemoved]: '[移出群成员消息]',
|
||||||
|
[ChatMsgSysGroupInfoChange]: '[群信息更新]',
|
||||||
|
[ChatMsgSysPush_PromptReminder]: '[催办提醒]',
|
||||||
|
[ChatMsgSysPush_NoClockReminderBeforeWork]: '[未打卡提醒]',
|
||||||
|
[ChatMsgSysPush_NoClockReminderAfterWork]: '[未打卡提醒]',
|
||||||
|
[ChatMsgSysPush_ApprovalReminder]: '[审批提醒]',
|
||||||
|
[ChatMsgSysPush_CopyReminder]: '[抄送提醒]',
|
||||||
|
[ChatMsgSysPush_AbsentReminder]: '[异常卡提醒]',
|
||||||
|
[ChatMsgSysPush_LateReminder]: '[异常卡提醒]',
|
||||||
|
[ChatMsgSysPush_EarlyReminder]: '[异常卡提醒]'
|
||||||
}
|
}
|
||||||
|
|
||||||
// 消息类型 - 消息组件 映射关系
|
// 消息类型 - 消息组件 映射关系
|
||||||
@ -78,12 +101,24 @@ export const MessageComponents = {
|
|||||||
[ChatMsgSysGroupMemberQuit]: 'sys-group-member-quit-message',
|
[ChatMsgSysGroupMemberQuit]: 'sys-group-member-quit-message',
|
||||||
[ChatMsgSysGroupMemberKicked]: 'sys-group-member-kicked-message',
|
[ChatMsgSysGroupMemberKicked]: 'sys-group-member-kicked-message',
|
||||||
// [ChatMsgSysGroupMessageRevoke]: '[撤回消息]',
|
// [ChatMsgSysGroupMessageRevoke]: '[撤回消息]',
|
||||||
// [ChatMsgSysGroupDismissed]: '[群解散消息]',
|
[ChatMsgSysGroupDismissed]: 'sys-group-dismissed',
|
||||||
[ChatMsgSysGroupMuted]: 'sys-group-muted-message',
|
[ChatMsgSysGroupMuted]: 'sys-group-muted-message',
|
||||||
[ChatMsgSysGroupCancelMuted]: 'sys-group-cancel-muted-message',
|
[ChatMsgSysGroupCancelMuted]: 'sys-group-cancel-muted-message',
|
||||||
[ChatMsgSysGroupMemberMuted]: 'sys-group-member-muted-message',
|
[ChatMsgSysGroupMemberMuted]: 'sys-group-member-muted-message',
|
||||||
[ChatMsgSysGroupMemberCancelMuted]: 'sys-group-member-cancel-muted-message',
|
[ChatMsgSysGroupMemberCancelMuted]: 'sys-group-member-cancel-muted-message',
|
||||||
[ChatMsgSysGroupTransfer]: 'sys-group-transfer-message'
|
[ChatMsgSysGroupTransfer]: 'sys-group-transfer-message',
|
||||||
|
[ChatMsgSysGroupAdmin]:'sys-group-admin-message',
|
||||||
|
[ChatMsgSysGroupMemberRemoved]:'sys-group-member-removed-message',
|
||||||
|
[ChatMsgSysGroupInfoChange]:'sys-group-info-change-message',
|
||||||
|
// 智能助手推送的系统消息采用相同的模版
|
||||||
|
[ChatMsgSysPush_PromptReminder]:'sys-push-message',
|
||||||
|
[ChatMsgSysPush_NoClockReminderBeforeWork]:'sys-push-message',
|
||||||
|
[ChatMsgSysPush_NoClockReminderAfterWork]:'sys-push-message',
|
||||||
|
[ChatMsgSysPush_ApprovalReminder]:'sys-push-message',
|
||||||
|
[ChatMsgSysPush_CopyReminder]:'sys-push-message',
|
||||||
|
[ChatMsgSysPush_AbsentReminder]:'sys-push-message',
|
||||||
|
[ChatMsgSysPush_LateReminder]:'sys-push-message',
|
||||||
|
[ChatMsgSysPush_EarlyReminder]:'sys-push-message'
|
||||||
}
|
}
|
||||||
|
|
||||||
// 可转发的消息类型
|
// 可转发的消息类型
|
||||||
@ -91,10 +126,11 @@ export const ForwardableMessageType = [
|
|||||||
ChatMsgTypeText,
|
ChatMsgTypeText,
|
||||||
ChatMsgTypeCode,
|
ChatMsgTypeCode,
|
||||||
ChatMsgTypeImage,
|
ChatMsgTypeImage,
|
||||||
ChatMsgTypeAudio,
|
// ChatMsgTypeAudio,
|
||||||
ChatMsgTypeVideo,
|
ChatMsgTypeVideo,
|
||||||
ChatMsgTypeFile,
|
ChatMsgTypeFile,
|
||||||
ChatMsgTypeLocation,
|
ChatMsgTypeLocation,
|
||||||
ChatMsgTypeCard,
|
ChatMsgTypeCard,
|
||||||
ChatMsgTypeLink
|
ChatMsgTypeLink,
|
||||||
|
ChatMsgTypeForward
|
||||||
]
|
]
|
||||||
|
|||||||
@ -68,20 +68,38 @@ class Revoke extends Base {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handle() {
|
handle() {
|
||||||
const {updateDialogueRecord} = useDialogueListStore()
|
const { updateDialogueRecord } = useDialogueListStore()
|
||||||
useTalkStore().updateItem({
|
useTalkStore().updateItem({
|
||||||
index_name: this.getIndexName(),
|
index_name: this.getIndexName(),
|
||||||
msg_text: this.resource.text,
|
msg_text: this.resource.text,
|
||||||
updated_at: parseTime(new Date())
|
revokeInfo: {
|
||||||
|
retracted_id: this.resource.retracted_id,
|
||||||
|
retracted_name: this.resource.retracted_name,
|
||||||
|
withdraw_id: this.resource.withdraw_id,
|
||||||
|
withdraw_name: this.resource.withdraw_name,
|
||||||
|
},
|
||||||
|
updated_at: parseTime(new Date()),
|
||||||
})
|
})
|
||||||
|
|
||||||
useDialogueStore().updateDialogueRecord({
|
useDialogueStore().updateDialogueRecord({
|
||||||
msg_id: this.msg_id,
|
msg_id: this.msg_id,
|
||||||
is_revoke: 1
|
revokeInfo: {
|
||||||
|
retracted_id: this.resource.retracted_id,
|
||||||
|
retracted_name: this.resource.retracted_name,
|
||||||
|
withdraw_id: this.resource.withdraw_id,
|
||||||
|
withdraw_name: this.resource.withdraw_name,
|
||||||
|
},
|
||||||
|
is_revoke: 1,
|
||||||
})
|
})
|
||||||
updateDialogueRecord({
|
updateDialogueRecord({
|
||||||
msg_id: this.msg_id,
|
msg_id: this.msg_id,
|
||||||
is_revoke: 1
|
revokeInfo: {
|
||||||
|
retracted_id: this.resource.retracted_id,
|
||||||
|
retracted_name: this.resource.retracted_name,
|
||||||
|
withdraw_id: this.resource.withdraw_id,
|
||||||
|
withdraw_name: this.resource.withdraw_name,
|
||||||
|
},
|
||||||
|
is_revoke: 1,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,8 +5,17 @@ import { parseTime } from '@/utils/datetime'
|
|||||||
import * as message from '@/constant/message'
|
import * as message from '@/constant/message'
|
||||||
import { formatTalkItem, palyMusic, formatTalkRecord } from '@/utils/talk'
|
import { formatTalkItem, palyMusic, formatTalkRecord } from '@/utils/talk'
|
||||||
// import { isElectronMode } from '@/utils/common'
|
// import { isElectronMode } from '@/utils/common'
|
||||||
import { ServeClearTalkUnreadNum, ServeCreateTalkList } from '@/api/chat/index.js'
|
import {
|
||||||
import { useTalkStore, useDialogueStore,useDialogueListStore } from '@/store'
|
ServeClearTalkUnreadNum,
|
||||||
|
ServeCreateTalkList,
|
||||||
|
} from '@/api/chat/index.js'
|
||||||
|
import {
|
||||||
|
useTalkStore,
|
||||||
|
useDialogueStore,
|
||||||
|
useDialogueListStore,
|
||||||
|
useGroupStore,
|
||||||
|
} from '@/store'
|
||||||
|
import { handleFindWebview } from '@/utils/common'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 好友状态事件
|
* 好友状态事件
|
||||||
@ -32,6 +41,11 @@ class Talk extends Base {
|
|||||||
*/
|
*/
|
||||||
talk_type = 0
|
talk_type = 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件上传唯一随机值
|
||||||
|
*/
|
||||||
|
fileNum = ''
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化构造方法
|
* 初始化构造方法
|
||||||
*
|
*
|
||||||
@ -43,6 +57,10 @@ class Talk extends Base {
|
|||||||
this.sender_id = resource.sender_id
|
this.sender_id = resource.sender_id
|
||||||
this.receiver_id = resource.receiver_id
|
this.receiver_id = resource.receiver_id
|
||||||
this.talk_type = resource.talk_type
|
this.talk_type = resource.talk_type
|
||||||
|
// this.fileNum = resource.file_num
|
||||||
|
if (resource.file_num) {
|
||||||
|
resource.data.file_num = resource.file_num
|
||||||
|
}
|
||||||
this.resource = resource.data
|
this.resource = resource.data
|
||||||
|
|
||||||
this.handle()
|
this.handle()
|
||||||
@ -76,7 +94,11 @@ class Talk extends Base {
|
|||||||
*/
|
*/
|
||||||
getTalkText() {
|
getTalkText() {
|
||||||
let text = ''
|
let text = ''
|
||||||
if (this.resource.msg_type != message.ChatMsgTypeText) {
|
if (
|
||||||
|
this.resource.msg_type != message.ChatMsgTypeText &&
|
||||||
|
//智能助手发送的系统消息,也直接显示内容
|
||||||
|
this.resource.user_id !== 2
|
||||||
|
) {
|
||||||
text = message.ChatMsgTypeMapping[this.resource.msg_type]
|
text = message.ChatMsgTypeMapping[this.resource.msg_type]
|
||||||
} else {
|
} else {
|
||||||
text = this.resource.extra.content.replace(/<img .*?>/g, '')
|
text = this.resource.extra.content.replace(/<img .*?>/g, '')
|
||||||
@ -89,11 +111,10 @@ class Talk extends Base {
|
|||||||
play() {
|
play() {
|
||||||
// 客户端有消息提示
|
// 客户端有消息提示
|
||||||
// if (isElectronMode()) return
|
// if (isElectronMode()) return
|
||||||
|
|
||||||
// useSettingsStore().isPromptTone && palyMusic()
|
// useSettingsStore().isPromptTone && palyMusic()
|
||||||
}
|
}
|
||||||
|
|
||||||
handle() {
|
async handle() {
|
||||||
// 不是自己发送的消息则需要播放提示音
|
// 不是自己发送的消息则需要播放提示音
|
||||||
if (!this.isCurrSender()) {
|
if (!this.isCurrSender()) {
|
||||||
this.play()
|
this.play()
|
||||||
@ -101,16 +122,45 @@ class Talk extends Base {
|
|||||||
|
|
||||||
// 判断会话列表是否存在,不存在则创建
|
// 判断会话列表是否存在,不存在则创建
|
||||||
if (useTalkStore().findTalkIndex(this.getIndexName()) == -1) {
|
if (useTalkStore().findTalkIndex(this.getIndexName()) == -1) {
|
||||||
|
if (this.resource.msg_type == 1102) {
|
||||||
|
//被邀请进入群聊时,需要热更新会话列表
|
||||||
|
await useTalkStore().loadTalkList()
|
||||||
|
} else if (this.resource.msg_type == 1106) {
|
||||||
|
//群解散时,需要热更新会话列表
|
||||||
|
await useTalkStore().loadTalkList()
|
||||||
|
} else if (
|
||||||
|
this.resource.msg_type == 1104 ||
|
||||||
|
this.resource.msg_type == 1115
|
||||||
|
) {
|
||||||
|
//群成员被移出时,需要热更新会话列表
|
||||||
|
await useTalkStore().loadTalkList()
|
||||||
|
} else {
|
||||||
return this.addTalkItem()
|
return this.addTalkItem()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 判断当前是否正在和好友对话
|
// 判断当前是否正在和好友对话
|
||||||
if (this.isTalk(this.talk_type, this.receiver_id, this.sender_id)) {
|
if (this.isTalk(this.talk_type, this.receiver_id, this.sender_id)) {
|
||||||
this.insertTalkRecord()
|
this.insertTalkRecord()
|
||||||
} else {
|
} else {
|
||||||
this.updateTalkItem()
|
this.updateTalkItem()
|
||||||
|
if (
|
||||||
|
!useTalkStore().items[useTalkStore().findTalkIndex(this.getIndexName())]
|
||||||
|
?.is_disturb &&
|
||||||
|
!(
|
||||||
|
useTalkStore().findTalkIndex(this.getIndexName()) == -1 &&
|
||||||
|
(this.resource.msg_type == 1104 || this.resource.msg_type == 1115)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
this.updateUnreadMsgNumAdd()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//更新未读数量+1
|
||||||
|
updateUnreadMsgNumAdd() {
|
||||||
|
handleFindWebview(`updateUnreadMsgNumAdd()`)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 显示消息提示
|
* 显示消息提示
|
||||||
@ -123,7 +173,6 @@ class Talk extends Base {
|
|||||||
// lang: 'zh-CN',
|
// lang: 'zh-CN',
|
||||||
// body: '您有新的消息请注意查收'
|
// body: '您有新的消息请注意查收'
|
||||||
// })
|
// })
|
||||||
|
|
||||||
// notification.onclick = () => {
|
// notification.onclick = () => {
|
||||||
// notification.close()
|
// notification.close()
|
||||||
// }
|
// }
|
||||||
@ -151,12 +200,16 @@ class Talk extends Base {
|
|||||||
|
|
||||||
ServeCreateTalkList({
|
ServeCreateTalkList({
|
||||||
talk_type,
|
talk_type,
|
||||||
receiver_id
|
receiver_id,
|
||||||
}).then(({ code, data }) => {
|
}).then(async ({ code, data }) => {
|
||||||
if (code == 200) {
|
if (code == 200) {
|
||||||
let item = formatTalkItem(data)
|
let item = formatTalkItem(data)
|
||||||
|
if (!item?.is_disturb) {
|
||||||
item.unread_num = 1
|
item.unread_num = 1
|
||||||
|
this.updateUnreadMsgNumAdd()
|
||||||
|
}
|
||||||
useTalkStore().addItem(item)
|
useTalkStore().addItem(item)
|
||||||
|
await useTalkStore().loadTalkList()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -166,24 +219,76 @@ class Talk extends Base {
|
|||||||
*/
|
*/
|
||||||
insertTalkRecord() {
|
insertTalkRecord() {
|
||||||
let record = this.resource
|
let record = this.resource
|
||||||
let newRecord = formatTalkRecord(this.getAccountId(), this.resource);
|
let newRecord = formatTalkRecord(this.getAccountId(), this.resource)
|
||||||
const {addDialogueRecord,addChatRecord} = useDialogueListStore()
|
const { addDialogueRecord, addChatRecord } = useDialogueListStore()
|
||||||
// 群成员变化的消息,需要更新群成员列表
|
// 群成员变化的消息,需要更新群成员列表
|
||||||
if ([1102, 1103, 1104].includes(record.msg_type)) {
|
if ([1102, 1103, 1104, 1115].includes(record.msg_type)) {
|
||||||
useDialogueStore().updateGroupMembers()
|
useDialogueStore().updateGroupMembers()
|
||||||
}
|
}
|
||||||
addDialogueRecord([newRecord],'add')
|
|
||||||
addChatRecord(this.getIndexName(),newRecord)
|
//群解散时,需要更新群成员权限
|
||||||
|
if ([1106].includes(record.msg_type)) {
|
||||||
|
useDialogueStore().updateDismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
//群成员被移出时,需要更新群成员权限
|
||||||
|
if ([1104, 1115].includes(record.msg_type)) {
|
||||||
|
console.error(this.resource.extra.members, 'this.resource.extra.members')
|
||||||
|
if (this.resource?.extra?.members?.length > 0) {
|
||||||
|
const isMeQuit = this.resource.extra.members.find(
|
||||||
|
(item) => item.user_id === this.getAccountId(),
|
||||||
|
)
|
||||||
|
if (isMeQuit) {
|
||||||
|
useDialogueStore().updateQuit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//群禁言变化时,需要更新群禁言状态——即更新群成员列表
|
||||||
|
if ([1107, 1108, 1109, 1110].includes(record.msg_type)) {
|
||||||
|
useDialogueStore().updateGroupMembers()
|
||||||
|
}
|
||||||
|
//群公告变化时,需要更新群公告(新增和修改有热更新,删除没有)
|
||||||
|
if ([13].includes(record.msg_type)) {
|
||||||
|
useGroupStore().ServeGetGroupNotices()
|
||||||
|
}
|
||||||
|
//群管理员变化时,需要更新群管理员列表——即更新群成员列表,同时更新群信息
|
||||||
|
if ([1114].includes(record.msg_type)) {
|
||||||
|
useDialogueStore().updateGroupMembers()
|
||||||
|
useGroupStore().ServeGroupDetail()
|
||||||
|
}
|
||||||
|
if ([1116].includes(record.msg_type)) {
|
||||||
|
// 更新会话信息
|
||||||
|
useDialogueStore().setDialogue({
|
||||||
|
name: record.extra.group_name,
|
||||||
|
talk_type: record.talk_type,
|
||||||
|
receiver_id: record.receiver_id,
|
||||||
|
})
|
||||||
|
// 更新群聊信息
|
||||||
|
useGroupStore().updateGroupInfo({
|
||||||
|
group_name: record.extra.group_name,
|
||||||
|
avatar: record.extra.group_avatar,
|
||||||
|
})
|
||||||
|
// 更新会话列表中的会话信息
|
||||||
|
const dialogue = useDialogueListStore().getDialogueList(
|
||||||
|
`${record.talk_type}_${record.receiver_id}`,
|
||||||
|
)
|
||||||
|
if (dialogue) {
|
||||||
|
dialogue.talk.username = record.extra.group_name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addDialogueRecord([newRecord], 'add')
|
||||||
|
addChatRecord(this.getIndexName(), newRecord)
|
||||||
useDialogueStore().addDialogueRecord(newRecord)
|
useDialogueStore().addDialogueRecord(newRecord)
|
||||||
|
|
||||||
if (!this.isCurrSender()) {
|
if (!this.isCurrSender()) {
|
||||||
// 推送已读消息
|
// 推送已读消息
|
||||||
setTimeout(() => {
|
// setTimeout(() => {
|
||||||
ws.emit('im.message.read', {
|
// ws.emit('im.message.read', {
|
||||||
receiver_id: this.sender_id,
|
// receiver_id: this.sender_id,
|
||||||
msg_ids: [this.resource.msg_id]
|
// msg_ids: [this.resource.msg_id],
|
||||||
})
|
// })
|
||||||
}, 1000)
|
// }, 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取聊天面板元素节点
|
// 获取聊天面板元素节点
|
||||||
@ -191,7 +296,8 @@ class Talk extends Base {
|
|||||||
if (!el) return
|
if (!el) return
|
||||||
|
|
||||||
// 判断的滚动条是否在底部
|
// 判断的滚动条是否在底部
|
||||||
const isBottom = Math.ceil(el.scrollTop) + el.clientHeight >= el.scrollHeight
|
const isBottom =
|
||||||
|
Math.ceil(el.scrollTop) + el.clientHeight >= el.scrollHeight
|
||||||
|
|
||||||
if (isBottom || record.user_id == this.getAccountId()) {
|
if (isBottom || record.user_id == this.getAccountId()) {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
@ -204,14 +310,15 @@ class Talk extends Base {
|
|||||||
useTalkStore().updateItem({
|
useTalkStore().updateItem({
|
||||||
index_name: this.getIndexName(),
|
index_name: this.getIndexName(),
|
||||||
msg_text: this.getTalkText(),
|
msg_text: this.getTalkText(),
|
||||||
updated_at: parseTime(new Date())
|
updated_at: parseTime(new Date()),
|
||||||
})
|
})
|
||||||
|
|
||||||
if (this.talk_type == 1 && this.getAccountId() !== this.sender_id) {
|
if (this.talk_type == 1 && this.getAccountId() !== this.sender_id) {
|
||||||
ServeClearTalkUnreadNum({
|
//不在此处维护未读消息数量
|
||||||
talk_type: 1,
|
// ServeClearTalkUnreadNum({
|
||||||
receiver_id: this.sender_id
|
// talk_type: 1,
|
||||||
})
|
// receiver_id: this.sender_id,
|
||||||
|
// })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,8 +329,31 @@ class Talk extends Base {
|
|||||||
useTalkStore().updateMessage({
|
useTalkStore().updateMessage({
|
||||||
index_name: this.getIndexName(),
|
index_name: this.getIndexName(),
|
||||||
msg_text: this.getTalkText(),
|
msg_text: this.getTalkText(),
|
||||||
updated_at: parseTime(new Date())
|
updated_at: parseTime(new Date()),
|
||||||
})
|
})
|
||||||
|
//收到新消息时,同时判断是否有人@我
|
||||||
|
if (
|
||||||
|
this.resource.msg_type === 1 &&
|
||||||
|
this.resource?.extra?.mentions?.length > 0
|
||||||
|
) {
|
||||||
|
const findMention = this.resource?.extra?.mentions?.find(
|
||||||
|
(mention) => mention === this.getAccountId(),
|
||||||
|
)
|
||||||
|
//有人@我或者@所有人,则更新会话列表
|
||||||
|
if (findMention || this.resource?.extra?.mentions?.includes(0)) {
|
||||||
|
useTalkStore().loadTalkList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.resource.msg_type == 1116) {
|
||||||
|
// 更新会话列表中的会话信息
|
||||||
|
const dialogue = useDialogueListStore().getDialogueList(
|
||||||
|
`${this.resource.talk_type}_${this.resource.receiver_id}`,
|
||||||
|
)
|
||||||
|
if (dialogue) {
|
||||||
|
dialogue.talk.username = this.resource.extra.group_name
|
||||||
|
}
|
||||||
|
useTalkStore().loadTalkList()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -11,7 +11,12 @@ import { reactive, nextTick, computed, h, inject } from 'vue'
|
|||||||
// EditTwo,
|
// EditTwo,
|
||||||
// IdCard
|
// IdCard
|
||||||
// } from '@icon-park/vue-next'
|
// } from '@icon-park/vue-next'
|
||||||
import { ServeTopTalkList, ServeDeleteTalkList, ServeSetNotDisturb } from '@/api/chat'
|
import {
|
||||||
|
ServeTopTalkList,
|
||||||
|
ServeDeleteTalkList,
|
||||||
|
ServeSetNotDisturb,
|
||||||
|
ServeClearTalkUnreadNum,
|
||||||
|
} from '@/api/chat'
|
||||||
import { useDialogueStore, useTalkStore, useDialogueListStore } from '@/store'
|
import { useDialogueStore, useTalkStore, useDialogueListStore } from '@/store'
|
||||||
import { ServeSecedeGroup } from '@/api/group'
|
import { ServeSecedeGroup } from '@/api/group'
|
||||||
// import { ServeDeleteContact, ServeEditContactRemark } from '@/api/contact'
|
// import { ServeDeleteContact, ServeEditContactRemark } from '@/api/contact'
|
||||||
@ -23,7 +28,7 @@ export function useSessionMenu() {
|
|||||||
show: false,
|
show: false,
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
item: {}
|
item: {},
|
||||||
})
|
})
|
||||||
|
|
||||||
const dialogueStore = useDialogueStore()
|
const dialogueStore = useDialogueStore()
|
||||||
@ -118,10 +123,22 @@ export function useSessionMenu() {
|
|||||||
// 移除会话
|
// 移除会话
|
||||||
const onRemoveTalk = (item) => {
|
const onRemoveTalk = (item) => {
|
||||||
ServeDeleteTalkList({
|
ServeDeleteTalkList({
|
||||||
list_id: item.id
|
list_id: item.id,
|
||||||
}).then(({ code }) => {
|
}).then(({ code }) => {
|
||||||
if (code == 200) {
|
if (code == 200) {
|
||||||
onDeleteTalk(item.index_name)
|
onDeleteTalk(item.index_name)
|
||||||
|
console.error(item, 'item')
|
||||||
|
if (item.unread_num > 0) {
|
||||||
|
//同时已读
|
||||||
|
ServeClearTalkUnreadNum(
|
||||||
|
{
|
||||||
|
talk_type: item.talk_type,
|
||||||
|
receiver_id: item.receiver_id,
|
||||||
|
},
|
||||||
|
item.unread_num,
|
||||||
|
).then(() => {
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -131,13 +148,13 @@ export function useSessionMenu() {
|
|||||||
ServeSetNotDisturb({
|
ServeSetNotDisturb({
|
||||||
talk_type: item.talk_type,
|
talk_type: item.talk_type,
|
||||||
receiver_id: item.receiver_id,
|
receiver_id: item.receiver_id,
|
||||||
is_disturb: item.is_disturb == 0 ? 1 : 0
|
is_disturb: item.is_disturb == 0 ? 1 : 0,
|
||||||
}).then(({ code, message }) => {
|
}).then(({ code, message }) => {
|
||||||
if (code == 200) {
|
if (code == 200) {
|
||||||
message.success('设置成功!')
|
message.success('设置成功!')
|
||||||
talkStore.updateItem({
|
talkStore.updateItem({
|
||||||
index_name: item.index_name,
|
index_name: item.index_name,
|
||||||
is_disturb: item.is_disturb == 0 ? 1 : 0
|
is_disturb: item.is_disturb == 0 ? 1 : 0,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
message.error(message)
|
message.error(message)
|
||||||
@ -153,12 +170,12 @@ export function useSessionMenu() {
|
|||||||
|
|
||||||
ServeTopTalkList({
|
ServeTopTalkList({
|
||||||
list_id: item.id,
|
list_id: item.id,
|
||||||
type: item.is_top == 0 ? 1 : 2
|
type: item.is_top == 0 ? 1 : 2,
|
||||||
}).then(({ code, message }) => {
|
}).then(({ code, message }) => {
|
||||||
if (code == 200) {
|
if (code == 200) {
|
||||||
talkStore.updateItem({
|
talkStore.updateItem({
|
||||||
index_name: item.index_name,
|
index_name: item.index_name,
|
||||||
is_top: item.is_top == 0 ? 1 : 0
|
is_top: item.is_top == 0 ? 1 : 0,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
message.error(message)
|
message.error(message)
|
||||||
@ -201,7 +218,7 @@ export function useSessionMenu() {
|
|||||||
negativeText: '取消',
|
negativeText: '取消',
|
||||||
onPositiveClick: () => {
|
onPositiveClick: () => {
|
||||||
ServeSecedeGroup({
|
ServeSecedeGroup({
|
||||||
group_id: item.receiver_id
|
group_id: item.receiver_id,
|
||||||
}).then(({ code, message }) => {
|
}).then(({ code, message }) => {
|
||||||
if (code == 200) {
|
if (code == 200) {
|
||||||
message.success('已退出群聊')
|
message.success('已退出群聊')
|
||||||
@ -210,7 +227,7 @@ export function useSessionMenu() {
|
|||||||
message.error(message)
|
message.error(message)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,12 +276,18 @@ export function useSessionMenu() {
|
|||||||
disturb: onSetDisturb,
|
disturb: onSetDisturb,
|
||||||
signout_group: onSignOutGroup,
|
signout_group: onSignOutGroup,
|
||||||
delete_contact: onDeleteContact,
|
delete_contact: onDeleteContact,
|
||||||
remark: onChangeRemark
|
remark: onChangeRemark,
|
||||||
}
|
}
|
||||||
|
|
||||||
dropdown.show = false
|
dropdown.show = false
|
||||||
evnets[key] && evnets[key](dropdown.item)
|
evnets[key] && evnets[key](dropdown.item)
|
||||||
}
|
}
|
||||||
|
|
||||||
return { dropdown, onCloseContextMenu, onContextMenuTalkHandle, onToTopTalk, onRemoveTalk }
|
return {
|
||||||
|
dropdown,
|
||||||
|
onCloseContextMenu,
|
||||||
|
onContextMenuTalkHandle,
|
||||||
|
onToTopTalk,
|
||||||
|
onRemoveTalk,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
103
src/main.js
@ -10,13 +10,24 @@ import tmui from '@/uni_modules/tmui'
|
|||||||
import { config } from '@/config/tmui/index.js'
|
import { config } from '@/config/tmui/index.js'
|
||||||
import 'dayjs/locale/zh-cn'
|
import 'dayjs/locale/zh-cn'
|
||||||
import xLoaderror from '@/components/x-loaderror/index.vue'
|
import xLoaderror from '@/components/x-loaderror/index.vue'
|
||||||
|
import asyncLoading from '@/components/async-loading/index.vue'
|
||||||
|
import asyncError from '@/components/async-error/index.vue'
|
||||||
import { vLoading } from '@/components/x-loading/index.js'
|
import { vLoading } from '@/components/x-loading/index.js'
|
||||||
import messagePopup from '@/components/x-message/useMessagePopup'
|
import messagePopup from '@/components/x-message/useMessagePopup'
|
||||||
import pageAnimation from '@/components/page-animation/index.vue'
|
import pageAnimation from '@/components/page-animation/index.vue'
|
||||||
import * as plugins from './plugins'
|
import * as plugins from './plugins'
|
||||||
|
import {
|
||||||
|
useDialogueStore,
|
||||||
|
useTalkStore,
|
||||||
|
useUserStore,
|
||||||
|
useDialogueListStore,
|
||||||
|
} from '@/store'
|
||||||
|
import { uniStorage } from '@/utils/uniStorage.js'
|
||||||
|
import { handleFindWebview } from '@/utils/common'
|
||||||
|
|
||||||
const { showMessage } = messagePopup()
|
const { showMessage } = messagePopup()
|
||||||
dayjs.locale('zh-cn')
|
dayjs.locale('zh-cn')
|
||||||
if (import.meta.env.VITE_SHOW_CONSOLE) {
|
if (import.meta.env.VITE_SHOW_CONSOLE === 'true') {
|
||||||
new VConsole()
|
new VConsole()
|
||||||
}
|
}
|
||||||
export function createApp() {
|
export function createApp() {
|
||||||
@ -28,6 +39,8 @@ export function createApp() {
|
|||||||
app.mixin(pageAnimation)
|
app.mixin(pageAnimation)
|
||||||
app.component('customNavbar', customNavbar)
|
app.component('customNavbar', customNavbar)
|
||||||
app.component('x-loaderror', xLoaderror)
|
app.component('x-loaderror', xLoaderror)
|
||||||
|
app.component('AsyncLoading', asyncLoading)
|
||||||
|
app.component('AsyncError', asyncError)
|
||||||
app.directive('no-space', {
|
app.directive('no-space', {
|
||||||
mounted(el) {
|
mounted(el) {
|
||||||
el.addEventListener('input', (e) => {
|
el.addEventListener('input', (e) => {
|
||||||
@ -40,6 +53,94 @@ export function createApp() {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
//获取当前聊天页面所在页面,并通过当前的receiver_id判断是否要创建本地通知栏消息
|
||||||
|
window.getCurrentChatRoute = (msg) => {
|
||||||
|
let pushMsg = JSON.parse(decodeURIComponent(msg))
|
||||||
|
//当前所在聊天会话的receiver_id
|
||||||
|
const receiver_id = pushMsg?.payload?.receiver_id
|
||||||
|
// 获取当前页面路径
|
||||||
|
const pages = getCurrentPages()
|
||||||
|
const page = pages[pages.length - 1]
|
||||||
|
console.log(page.route)
|
||||||
|
|
||||||
|
const dialogueStore = useDialogueStore()
|
||||||
|
console.log(dialogueStore?.talk?.receiver_id)
|
||||||
|
if (
|
||||||
|
page?.route === 'pages/dialog/index' &&
|
||||||
|
receiver_id === dialogueStore?.talk?.receiver_id
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
console.log('===准备创建本地通知栏消息')
|
||||||
|
handleFindWebview(`doCreatePushMessage('${msg}')`)
|
||||||
|
}
|
||||||
|
|
||||||
|
//处理聊天推送弹窗点开
|
||||||
|
window.openUniPushMsg = (msg) => {
|
||||||
|
console.log('=====点击通知栏消息')
|
||||||
|
let pushMsg = JSON.parse(decodeURIComponent(msg))
|
||||||
|
console.log('=====pushMsg', pushMsg)
|
||||||
|
//由于弹窗前处理了不该弹窗的场景,因此这里弹窗可以一并处理
|
||||||
|
//也就是都跳转到聊天页面
|
||||||
|
const talkStore = useTalkStore()
|
||||||
|
talkStore.toTalk(pushMsg?.payload?.talk_type, pushMsg?.payload?.receiver_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
//处理当用户信息发生变化时,更新用户信息
|
||||||
|
window.updateUserInfo = () => {
|
||||||
|
useUserStore().loadSetting()
|
||||||
|
}
|
||||||
|
// 通讯录跳转
|
||||||
|
window.handleContacts = () => {
|
||||||
|
// 旧版本-按组织架构树的通讯录
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages/chooseByDeps/index?chooseMode=3&type=true'
|
||||||
|
});
|
||||||
|
|
||||||
|
// 新版本-按公司别、好友、群组的通讯录
|
||||||
|
// uni.navigateTo({
|
||||||
|
// url: '/pages/addressBook/index?type=true',
|
||||||
|
// })
|
||||||
|
}
|
||||||
|
|
||||||
|
//处理OA、墨册强制刷新时,聊天同步强制刷新
|
||||||
|
window.doLocationRefresh = () => {
|
||||||
|
uniStorage.removeItem('dialogueList')
|
||||||
|
uniStorage.removeItem('dialogue')
|
||||||
|
useUserStore().loadSetting()
|
||||||
|
useDialogueListStore().dialogueList.value = []
|
||||||
|
// location.reload(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
//检查聊天页面是否可用
|
||||||
|
window.checkChatWebviewAvailable = () => {
|
||||||
|
handleFindWebview(`doneCheckChatWebviewAvailable()`)
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取从base传来的多选视频列表
|
||||||
|
window.getBaseMulVideo = (videoList) => {
|
||||||
|
const videos = JSON.parse(decodeURIComponent(videoList))
|
||||||
|
console.error('=====videos', videos)
|
||||||
|
if (videos.length > 0) {
|
||||||
|
const videoUri = videos[0]
|
||||||
|
console.error('=====videoUri', videoUri)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//检查是否是特殊测试用户,开启控制台
|
||||||
|
const checkTestUser = () => {
|
||||||
|
const userStore = useUserStore()
|
||||||
|
if (
|
||||||
|
import.meta.env.VITE_SHOW_CONSOLE === 'false' &&
|
||||||
|
userStore.mobile == '18100591363'
|
||||||
|
) {
|
||||||
|
new VConsole()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkTestUser()
|
||||||
|
|
||||||
window.message = ['success', 'error', 'warning'].reduce((acc, type) => {
|
window.message = ['success', 'error', 'warning'].reduce((acc, type) => {
|
||||||
acc[type] = (message) => {
|
acc[type] = (message) => {
|
||||||
if (typeof message === 'string') {
|
if (typeof message === 'string') {
|
||||||
|
|||||||
@ -5,8 +5,7 @@
|
|||||||
"^tm-(.*)": "@/tmui/components/tm-$1/tm-$1.vue"
|
"^tm-(.*)": "@/tmui/components/tm-$1/tm-$1.vue"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"pages": [
|
"pages": [{
|
||||||
{
|
|
||||||
"path": "pages/index/index",
|
"path": "pages/index/index",
|
||||||
"type": "page",
|
"type": "page",
|
||||||
"style": {
|
"style": {
|
||||||
@ -178,6 +177,38 @@
|
|||||||
"navigationStyle": "custom",
|
"navigationStyle": "custom",
|
||||||
"enablePullDownRefresh": false
|
"enablePullDownRefresh": false
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/chatSettings/groupManage/manageGroupDeps",
|
||||||
|
"type": "page",
|
||||||
|
"style": {
|
||||||
|
"navigationStyle": "custom",
|
||||||
|
"enablePullDownRefresh": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/complaintReport/index",
|
||||||
|
"type": "page",
|
||||||
|
"style": {
|
||||||
|
"navigationStyle": "custom",
|
||||||
|
"enablePullDownRefresh": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/addressBook/index",
|
||||||
|
"type": "page",
|
||||||
|
"style": {
|
||||||
|
"navigationStyle": "custom",
|
||||||
|
"enablePullDownRefresh": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/addressBook/addFriend/index",
|
||||||
|
"type": "page",
|
||||||
|
"style": {
|
||||||
|
"navigationStyle": "custom",
|
||||||
|
"enablePullDownRefresh": false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"globalStyle": {
|
"globalStyle": {
|
||||||
|
|||||||
398
src/pages/addressBook/addFriend/index.vue
Normal file
@ -0,0 +1,398 @@
|
|||||||
|
<template>
|
||||||
|
<div class="add-friend-page">
|
||||||
|
<zPaging ref="zPaging" :show-scrollbar="false" @scrolltolower="doLoadMore">
|
||||||
|
<template #top>
|
||||||
|
<div :class="'top_bg'">
|
||||||
|
<customNavbar
|
||||||
|
:class="'index_top_navbar'"
|
||||||
|
:title="$t('addFriend.pageTitle')"
|
||||||
|
></customNavbar>
|
||||||
|
<div class="pl-[32rpx] pr-[32rpx] pt-[32rpx] pb-[32rpx]">
|
||||||
|
<customInput
|
||||||
|
:searchText="searchVal"
|
||||||
|
@inputSearchText="inputSearchText"
|
||||||
|
></customInput>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div class="add-friend">
|
||||||
|
<div class="add-friend-list" v-if="state.friendsList.length > 0">
|
||||||
|
<div
|
||||||
|
class="members-list-each"
|
||||||
|
v-for="(item, index) in state.friendsList"
|
||||||
|
:key="index"
|
||||||
|
@click="toUserDetail(item)"
|
||||||
|
>
|
||||||
|
<div class="members-info">
|
||||||
|
<avatarModule
|
||||||
|
:mode="1"
|
||||||
|
:avatar="item.avatar"
|
||||||
|
:groupType="0"
|
||||||
|
:userName="item.nickname"
|
||||||
|
:customStyle="{ width: '72rpx', height: '72rpx' }"
|
||||||
|
:customTextStyle="{
|
||||||
|
fontSize: '32rpx',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
color: '#fff',
|
||||||
|
lineHeight: '44rpx',
|
||||||
|
}"
|
||||||
|
></avatarModule>
|
||||||
|
<div class="members-info-area">
|
||||||
|
<div
|
||||||
|
class="members-info-basic"
|
||||||
|
:style="{ padding: item.company_name ? 0 : '0 0 24rpx' }"
|
||||||
|
>
|
||||||
|
<span class="members-name">
|
||||||
|
{{ item.nickname }}
|
||||||
|
</span>
|
||||||
|
<span class="members-jobNum">
|
||||||
|
{{ item.job_num }}
|
||||||
|
</span>
|
||||||
|
<!-- <span class="members-company">{{ item.company_name }}</span> -->
|
||||||
|
</div>
|
||||||
|
<div class="members-positions-area">
|
||||||
|
<tm-popover position="bc">
|
||||||
|
<tm-scrolly :refresher="false" :height="84">
|
||||||
|
<div class="members-positions">
|
||||||
|
<div
|
||||||
|
class="members-positions-each"
|
||||||
|
v-for="(postionItem,
|
||||||
|
positionIndex) in item.user_position"
|
||||||
|
:key="positionIndex"
|
||||||
|
>
|
||||||
|
{{ postionItem.position_name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</tm-scrolly>
|
||||||
|
<template v-slot:label>
|
||||||
|
<tm-scrolly
|
||||||
|
:refresher="false"
|
||||||
|
:height="
|
||||||
|
item.user_position.length >= 4
|
||||||
|
? 180
|
||||||
|
: item.user_position.length === 3
|
||||||
|
? 140
|
||||||
|
: item.user_position.length === 2
|
||||||
|
? 100
|
||||||
|
: item.user_position.length === 1
|
||||||
|
? 60
|
||||||
|
: 0
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<div class="members-positions-popover-box">
|
||||||
|
<div
|
||||||
|
class="members-positions-popover"
|
||||||
|
v-for="(postionItem,
|
||||||
|
positionIndex) in item.user_position"
|
||||||
|
:key="positionIndex"
|
||||||
|
>
|
||||||
|
{{ postionItem.position_name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</tm-scrolly>
|
||||||
|
</template>
|
||||||
|
</tm-popover>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="company-infos" v-if="item.company_name">
|
||||||
|
<div class="company-each">
|
||||||
|
<span>{{ item.company_name }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="addressBook-noData" v-if="state.friendsList.length === 0">
|
||||||
|
<img src="@/static/image/search/search-no-data.png" />
|
||||||
|
<span>
|
||||||
|
{{
|
||||||
|
searchVal
|
||||||
|
? $t('addFriend.message.notFindData')
|
||||||
|
: $t('search.hint')
|
||||||
|
}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</zPaging>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import customInput from '@/components/custom-input/custom-input.vue'
|
||||||
|
import zPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
|
||||||
|
import avatarModule from '@/components/avatar-module/index.vue'
|
||||||
|
import { ServeFriendSearch } from '@/api/addressBook/index'
|
||||||
|
import { handleSetWebviewStyle } from '@/utils/common'
|
||||||
|
|
||||||
|
import { ref, onMounted, reactive } from 'vue'
|
||||||
|
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
const searchVal = ref('')
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
friendsListPage: 1, //当前查询的可添加好友列表分页
|
||||||
|
friendsListPageSize: 10, //可添加好友列表单页数量
|
||||||
|
friendsList: [], //可添加好友列表
|
||||||
|
hasMoreFriends: true, //是否还有更多可添加好友数据
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getFriendsList()
|
||||||
|
handleSetWebviewStyle()
|
||||||
|
})
|
||||||
|
|
||||||
|
//输入搜索内容
|
||||||
|
const inputSearchText = (e) => {
|
||||||
|
searchVal.value = e
|
||||||
|
}
|
||||||
|
|
||||||
|
//搜索可添加好友(精确搜索)
|
||||||
|
const getFriendsList = () => {
|
||||||
|
let params = {
|
||||||
|
name: searchVal.value,
|
||||||
|
}
|
||||||
|
ServeFriendSearch(params)
|
||||||
|
.then((res) => {
|
||||||
|
console.error(res)
|
||||||
|
if (res?.code === 200) {
|
||||||
|
if (state.friendsListPage === 1) {
|
||||||
|
state.friendsList = res.data?.user_list || []
|
||||||
|
} else {
|
||||||
|
state.friendsList = state.friendsList.concat(
|
||||||
|
res.data?.user_list || [],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (state.friendsList.length < res.data?.count) {
|
||||||
|
state.hasMoreFriends = true
|
||||||
|
} else {
|
||||||
|
state.hasMoreFriends = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//点击进入用户详情页面
|
||||||
|
const toUserDetail = (userInfo) => {
|
||||||
|
uni.navigateTo({
|
||||||
|
url:
|
||||||
|
'/pages/dialog/dialogDetail/userDetail??erpUserId=' +
|
||||||
|
userInfo.erp_user_id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//加载更多数据
|
||||||
|
const doLoadMore = (e) => {
|
||||||
|
state.friendsListPage += 1
|
||||||
|
getFriendsList()
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => searchVal.value,
|
||||||
|
(newVal) => {
|
||||||
|
state.friendsListPage = 1
|
||||||
|
getFriendsList()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
</script>
|
||||||
|
<style scoped lang="scss">
|
||||||
|
::v-deep .zp-paging-container-content {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .index_top_navbar .tmicon-angle-left {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .index_top_navbar .text-weight-b {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .index_top_navbar .statusHeightTop > .noNvueBorder:first-child {
|
||||||
|
background: transparent !important;
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top_bg {
|
||||||
|
background: url('@/static/image/mine/page_top.png') no-repeat;
|
||||||
|
background-size: cover;
|
||||||
|
background-position: bottom center;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.animateAll_tabs_tmui) {
|
||||||
|
width: 120rpx !important;
|
||||||
|
height: 10rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-friend-page {
|
||||||
|
.add-friend {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background-image: url('@/static/image/clockIn/z3280@3x.png');
|
||||||
|
background-size: cover;
|
||||||
|
background-position: bottom center;
|
||||||
|
background-attachment: fixed;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.add-friend-list {
|
||||||
|
margin: 30rpx 24rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
flex: 1;
|
||||||
|
gap: 30rpx 0;
|
||||||
|
|
||||||
|
.members-list-each {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: #fff;
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
|
||||||
|
.swipe-action {
|
||||||
|
width: 100%;
|
||||||
|
overflow: visible !important;
|
||||||
|
|
||||||
|
:deep(.wd-swipe-action__right) {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: #cf3050;
|
||||||
|
padding: 0 48rpx;
|
||||||
|
border-radius: 0 8rpx 8rpx 0;
|
||||||
|
span {
|
||||||
|
color: #fff;
|
||||||
|
line-height: 1;
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.members-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: flex-start;
|
||||||
|
gap: 16rpx;
|
||||||
|
padding: 24rpx 24rpx 0;
|
||||||
|
|
||||||
|
.members-info-area {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: flex-start;
|
||||||
|
gap: 16rpx;
|
||||||
|
|
||||||
|
.members-info-basic {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.members-name {
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
width: 150rpx;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.members-jobNum {
|
||||||
|
font-size: 26rpx;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #999;
|
||||||
|
word-break: break-all;
|
||||||
|
margin: 10rpx 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.members-company {
|
||||||
|
font-size: 24rpx;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.members-positions-area {
|
||||||
|
.members-positions {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10rpx;
|
||||||
|
padding: 4rpx 0 0;
|
||||||
|
max-height: 84rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
line-clamp: 2;
|
||||||
|
|
||||||
|
.members-positions-each {
|
||||||
|
background-color: #eee9f8;
|
||||||
|
line-height: 1;
|
||||||
|
font-size: 24rpx;
|
||||||
|
padding: 4rpx 16rpx;
|
||||||
|
color: #46299d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.members-positions-popover-box {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 10rpx 0;
|
||||||
|
|
||||||
|
.members-positions-popover {
|
||||||
|
background-color: #eee9f8;
|
||||||
|
line-height: 1;
|
||||||
|
font-size: 24rpx;
|
||||||
|
padding: 8rpx 16rpx;
|
||||||
|
color: #46299d;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.company-infos {
|
||||||
|
margin: 0 0 0 88rpx;
|
||||||
|
padding: 0 0 24rpx 24rpx;
|
||||||
|
.company-each {
|
||||||
|
span {
|
||||||
|
font-size: 24rpx;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.addressBook-noData {
|
||||||
|
margin: 30rpx 24rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
flex: 1;
|
||||||
|
gap: 30rpx 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
img {
|
||||||
|
width: 500rpx;
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
944
src/pages/addressBook/index.vue
Normal file
@ -0,0 +1,944 @@
|
|||||||
|
<template>
|
||||||
|
<div class="address-book-page">
|
||||||
|
<zPaging ref="zPaging" :show-scrollbar="false" @scrolltolower="doLoadMore">
|
||||||
|
<template #top>
|
||||||
|
<div :class="'top_bg'">
|
||||||
|
<customNavbar
|
||||||
|
:class="'index_top_navbar'"
|
||||||
|
:title="$t('index.mine.addressBook')"
|
||||||
|
:hideHome="navshow"
|
||||||
|
:hideBack="navshow"
|
||||||
|
>
|
||||||
|
<template #left>
|
||||||
|
<tm-icon
|
||||||
|
@click="goWebHome"
|
||||||
|
v-if="navshow"
|
||||||
|
name="tmicon-angle-left"
|
||||||
|
style="padding-left: 30rpx;"
|
||||||
|
></tm-icon>
|
||||||
|
</template>
|
||||||
|
</customNavbar>
|
||||||
|
<div class="pl-[32rpx] pr-[32rpx] pt-[32rpx] pb-[32rpx]">
|
||||||
|
<customInput
|
||||||
|
:searchText="searchVal"
|
||||||
|
@inputSearchText="inputSearchText"
|
||||||
|
></customInput>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<tm-tabs
|
||||||
|
:list="state.addressBookTabs"
|
||||||
|
align="center"
|
||||||
|
:width="750"
|
||||||
|
:height="300"
|
||||||
|
:itemWidth="250"
|
||||||
|
default-name="company"
|
||||||
|
activeColor="#46299d"
|
||||||
|
activeFontColor="#46299d"
|
||||||
|
tabs-line-ani-color="#46299d"
|
||||||
|
:showTabsLineAni="true"
|
||||||
|
:showTabsLine="false"
|
||||||
|
:activeFontSize="32"
|
||||||
|
:itemFontSize="30"
|
||||||
|
@update:activeName="updateAddressBookTab"
|
||||||
|
></tm-tabs>
|
||||||
|
</template>
|
||||||
|
<div class="address-book">
|
||||||
|
<div class="address-book-tabs-panes-list">
|
||||||
|
<div
|
||||||
|
class="tabs-panes-each address-book-company"
|
||||||
|
v-if="
|
||||||
|
state.addressBookActiveTab === 'company' &&
|
||||||
|
state.myContractList.length > 0
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<div class="address-book-company-name">
|
||||||
|
<span>{{ state.myCompany }}</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="members-list-each"
|
||||||
|
v-for="(item, index) in state.myContractList"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
|
<div class="members-info" @click="toUserDetail(item)">
|
||||||
|
<avatarModule
|
||||||
|
:mode="1"
|
||||||
|
:avatar="item.avatar"
|
||||||
|
:groupType="0"
|
||||||
|
:userName="item.nickname"
|
||||||
|
:customStyle="{ width: '72rpx', height: '72rpx' }"
|
||||||
|
:customTextStyle="{
|
||||||
|
fontSize: '32rpx',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
color: '#fff',
|
||||||
|
lineHeight: '44rpx',
|
||||||
|
}"
|
||||||
|
></avatarModule>
|
||||||
|
<div class="members-info-area">
|
||||||
|
<div class="members-info-basic" style="padding: 0 0 24rpx;">
|
||||||
|
<span class="members-name">
|
||||||
|
{{ item.nickname }}
|
||||||
|
</span>
|
||||||
|
<span class="members-jobNum">
|
||||||
|
{{ item.job_num }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="members-positions-area">
|
||||||
|
<tm-popover position="bc">
|
||||||
|
<tm-scrolly :refresher="false" :height="84">
|
||||||
|
<div class="members-positions">
|
||||||
|
<div
|
||||||
|
class="members-positions-each"
|
||||||
|
v-for="(postionItem,
|
||||||
|
positionIndex) in item.user_position"
|
||||||
|
:key="positionIndex"
|
||||||
|
>
|
||||||
|
{{ postionItem.position_name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</tm-scrolly>
|
||||||
|
<template v-slot:label>
|
||||||
|
<tm-scrolly
|
||||||
|
:refresher="false"
|
||||||
|
:height="
|
||||||
|
item.user_position.length >= 4
|
||||||
|
? 180
|
||||||
|
: item.user_position.length === 3
|
||||||
|
? 140
|
||||||
|
: item.user_position.length === 2
|
||||||
|
? 100
|
||||||
|
: item.user_position.length === 1
|
||||||
|
? 60
|
||||||
|
: 0
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<div class="members-positions-popover-box">
|
||||||
|
<div
|
||||||
|
class="members-positions-popover"
|
||||||
|
v-for="(postionItem,
|
||||||
|
positionIndex) in item.user_position"
|
||||||
|
:key="positionIndex"
|
||||||
|
>
|
||||||
|
{{ postionItem.position_name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</tm-scrolly>
|
||||||
|
</template>
|
||||||
|
</tm-popover>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="tabs-panes-each address-book-friends"
|
||||||
|
v-if="
|
||||||
|
state.addressBookActiveTab === 'friends' &&
|
||||||
|
state.myFriendsList.length > 0
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="members-list-each"
|
||||||
|
v-for="(item, index) in state.myFriendsList"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
|
<wd-swipe-action
|
||||||
|
class="swipe-action"
|
||||||
|
@click="showDeleteModal(item, index)"
|
||||||
|
v-if="
|
||||||
|
!item.company_name ||
|
||||||
|
(item.company_name && item.company_name !== state.myCompany)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<div class="members-info" @click="toUserDetail(item)">
|
||||||
|
<avatarModule
|
||||||
|
:mode="1"
|
||||||
|
:avatar="item.avatar"
|
||||||
|
:groupType="0"
|
||||||
|
:userName="item.nickname"
|
||||||
|
:customStyle="{ width: '72rpx', height: '72rpx' }"
|
||||||
|
:customTextStyle="{
|
||||||
|
fontSize: '32rpx',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
color: '#fff',
|
||||||
|
lineHeight: '44rpx',
|
||||||
|
}"
|
||||||
|
></avatarModule>
|
||||||
|
<div class="members-info-area">
|
||||||
|
<div
|
||||||
|
class="members-info-basic"
|
||||||
|
:style="{ padding: item.company_name ? 0 : '0 0 24rpx' }"
|
||||||
|
>
|
||||||
|
<span class="members-name">
|
||||||
|
{{ item.nickname }}
|
||||||
|
</span>
|
||||||
|
<span class="members-jobNum">
|
||||||
|
{{ item.job_num }}
|
||||||
|
</span>
|
||||||
|
<!-- <span class="members-company">{{ item.company_name }}</span> -->
|
||||||
|
</div>
|
||||||
|
<div class="members-positions-area">
|
||||||
|
<tm-popover position="bc">
|
||||||
|
<tm-scrolly :refresher="false" :height="84">
|
||||||
|
<div class="members-positions">
|
||||||
|
<div
|
||||||
|
class="members-positions-each"
|
||||||
|
v-for="(postionItem,
|
||||||
|
positionIndex) in item.user_position"
|
||||||
|
:key="positionIndex"
|
||||||
|
>
|
||||||
|
{{ postionItem.position_name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</tm-scrolly>
|
||||||
|
<template v-slot:label>
|
||||||
|
<tm-scrolly
|
||||||
|
:refresher="false"
|
||||||
|
:height="
|
||||||
|
item.user_position.length >= 4
|
||||||
|
? 180
|
||||||
|
: item.user_position.length === 3
|
||||||
|
? 140
|
||||||
|
: item.user_position.length === 2
|
||||||
|
? 100
|
||||||
|
: item.user_position.length === 1
|
||||||
|
? 60
|
||||||
|
: 0
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<div class="members-positions-popover-box">
|
||||||
|
<div
|
||||||
|
class="members-positions-popover"
|
||||||
|
v-for="(postionItem,
|
||||||
|
positionIndex) in item.user_position"
|
||||||
|
:key="positionIndex"
|
||||||
|
>
|
||||||
|
{{ postionItem.position_name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</tm-scrolly>
|
||||||
|
</template>
|
||||||
|
</tm-popover>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="company-infos" v-if="item.company_name">
|
||||||
|
<div class="company-each">
|
||||||
|
<span>{{ item.company_name }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<template #right>
|
||||||
|
<div
|
||||||
|
v-for="(swipeActionItem,
|
||||||
|
swipeActionIndex) in state.swipeAction"
|
||||||
|
:key="swipeActionIndex"
|
||||||
|
>
|
||||||
|
<span>{{ swipeActionItem.text }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</wd-swipe-action>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="tabs-panes-each address-book-groups"
|
||||||
|
v-if="
|
||||||
|
state.addressBookActiveTab === 'groups' &&
|
||||||
|
state.myGroupsList.length > 0
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="groups-list-each"
|
||||||
|
v-for="(item, index) in state.myGroupsList"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
|
<div class="groups-info">
|
||||||
|
<avatarModule
|
||||||
|
:mode="2"
|
||||||
|
:avatar="item?.avatar"
|
||||||
|
:groupType="Number(item?.group_type)"
|
||||||
|
:customStyle="{ width: '72rpx', height: '72rpx' }"
|
||||||
|
></avatarModule>
|
||||||
|
<span class="groups-name">
|
||||||
|
{{ item?.group_name }}
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="groups-type"
|
||||||
|
:style="{
|
||||||
|
color:
|
||||||
|
groupTypeMapping[item?.group_type]?.result_type_color,
|
||||||
|
border:
|
||||||
|
'1px solid' +
|
||||||
|
groupTypeMapping[item?.group_type]?.result_type_color,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ groupTypeMapping[item?.group_type]?.result_type }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="groups-btns">
|
||||||
|
<div class="groups-btns-each" @click="toGroupChat(item)">
|
||||||
|
<span>{{ $t('addressBook.btns.enterGroup') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="addressBook-noData"
|
||||||
|
v-if="
|
||||||
|
!state.isLoadingData &&
|
||||||
|
((state.addressBookActiveTab === 'company' &&
|
||||||
|
state.myContractList.length === 0) ||
|
||||||
|
(state.addressBookActiveTab === 'friends' &&
|
||||||
|
state.myFriendsList.length === 0) ||
|
||||||
|
(state.addressBookActiveTab === 'groups' &&
|
||||||
|
state.myGroupsList.length === 0))
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<img src="@/static/image/search/search-no-data.png" />
|
||||||
|
<span>
|
||||||
|
{{
|
||||||
|
searchVal
|
||||||
|
? $t('addFriend.message.notFindData')
|
||||||
|
: $t('search.hint')
|
||||||
|
}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<tm-modal
|
||||||
|
class="friendDeleteModal"
|
||||||
|
ref="friendDeleteModalRef"
|
||||||
|
:mask="true"
|
||||||
|
:okText="$t('ok')"
|
||||||
|
okColor="#46299d"
|
||||||
|
cancelColor="#999"
|
||||||
|
@ok="doDeleteFriend"
|
||||||
|
@cancel="hideDeleteModal"
|
||||||
|
:teleport="false"
|
||||||
|
titleStyle="font-size: 40rpx;font-weight: 600;line-height: 1;"
|
||||||
|
:height="300"
|
||||||
|
:round="4"
|
||||||
|
>
|
||||||
|
<div class="friendDeleteModal-content">
|
||||||
|
<span>{{ $t('addressBook.message.doOrNotDeleteFriend') }}</span>
|
||||||
|
</div>
|
||||||
|
</tm-modal>
|
||||||
|
</zPaging>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import customInput from '@/components/custom-input/custom-input.vue'
|
||||||
|
import zPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
|
||||||
|
import avatarModule from '@/components/avatar-module/index.vue'
|
||||||
|
|
||||||
|
import { ref, onMounted, reactive, watch } from 'vue'
|
||||||
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
|
import { handleSetWebviewStyle, handleFindWebview } from '@/utils/common'
|
||||||
|
import { ServeUserGroupChatList, ServeCreateTalkList } from '@/api/chat/index'
|
||||||
|
import { ServeGetSessionId } from '@/api/search/index'
|
||||||
|
import { formatTalkItem } from '@/utils/talk'
|
||||||
|
import { useDialogueStore, useTalkStore } from '@/store'
|
||||||
|
import {
|
||||||
|
ServeQueryFriendsList,
|
||||||
|
ServeDeleteFriend,
|
||||||
|
} from '@/api/addressBook/index'
|
||||||
|
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
const navshow = ref(false)
|
||||||
|
const searchVal = ref('')
|
||||||
|
const friendDeleteModalRef = ref(null)
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
addressBookTabs: [], //tab页
|
||||||
|
addressBookActiveTab: 'company', //当前选中的通讯录tab
|
||||||
|
myContractListPage: 1, //当前查询的我的组织架构通讯录列表分页
|
||||||
|
myContractListPageSize: 10, //我的组织架构通讯录列表单页数量
|
||||||
|
myContractList: [], //我的组织架构通讯录列表
|
||||||
|
hasMoreContracts: true, //是否还有更多我的组织架构通讯录数据
|
||||||
|
myFriendsListPage: 1, //当前查询的我的好友列表分页
|
||||||
|
myFriendsListPageSize: 10, //我的好友列表单页数量
|
||||||
|
myFriendsList: [], //我的好友列表
|
||||||
|
hasMoreFriends: true, //是否还有更多我的好友数据
|
||||||
|
myGroupsListPage: 1, //当前查询的群组列表分页
|
||||||
|
myGroupsListPageSize: 10, //群组列表单页数量
|
||||||
|
myGroupsList: [], //我的群组列表
|
||||||
|
hasMoreGroups: true, //是否还有更多我的群组数据
|
||||||
|
myCompany: '', //当前登录人公司别
|
||||||
|
swipeAction: [], //左滑操作栏按钮组
|
||||||
|
isLoadingData: true, //是否正在加载数据
|
||||||
|
})
|
||||||
|
|
||||||
|
onLoad((options) => {
|
||||||
|
if (options.type) {
|
||||||
|
navshow.value = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const goWebHome = () => {
|
||||||
|
uni.navigateBack()
|
||||||
|
handleFindWebview(`handleBackHost()`)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
state.swipeAction = [
|
||||||
|
{
|
||||||
|
text: t('addressBook.btns.delete'), //操作按钮的文本,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
state.addressBookTabs = [
|
||||||
|
{
|
||||||
|
key: 'company',
|
||||||
|
title: t('addressBook.tabs.company'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'friends',
|
||||||
|
title: t('addressBook.tabs.friends'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'groups',
|
||||||
|
title: t('addressBook.tabs.groups'),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
handleSetWebviewStyle()
|
||||||
|
getMyContractList()
|
||||||
|
})
|
||||||
|
|
||||||
|
//输入搜索内容
|
||||||
|
const inputSearchText = (e) => {
|
||||||
|
searchVal.value = e
|
||||||
|
}
|
||||||
|
|
||||||
|
//切换通讯录tab
|
||||||
|
const updateAddressBookTab = (e) => {
|
||||||
|
state.addressBookActiveTab = e
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取“组织架构”通讯录列表
|
||||||
|
const getMyContractList = () => {
|
||||||
|
let params = {
|
||||||
|
type: 'addressBook', //查我的通讯录的时候写死addressBook
|
||||||
|
page: state.myContractListPage,
|
||||||
|
page_size: state.myContractListPageSize,
|
||||||
|
name: searchVal.value,
|
||||||
|
}
|
||||||
|
// console.log(params)
|
||||||
|
state.isLoadingData = true
|
||||||
|
ServeQueryFriendsList(params)
|
||||||
|
.then((res) => {
|
||||||
|
// console.log(res)
|
||||||
|
state.isLoadingData = false
|
||||||
|
if (res?.code === 200) {
|
||||||
|
state.myCompany = res.data?.company_name
|
||||||
|
if (state.myContractListPage === 1) {
|
||||||
|
state.myContractList = res.data?.user_list || []
|
||||||
|
} else {
|
||||||
|
state.myContractList = state.myContractList.concat(
|
||||||
|
res.data?.user_list || [],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (state.myContractList.length < res.data?.count) {
|
||||||
|
state.hasMoreContracts = true
|
||||||
|
} else {
|
||||||
|
state.hasMoreContracts = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
state.isLoadingData = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取“我的好友”列表
|
||||||
|
const getMyFriendsList = () => {
|
||||||
|
let params = {
|
||||||
|
type: 'myFriends', //查我得好友的时候写死myFriends
|
||||||
|
page: state.myFriendsListPage,
|
||||||
|
page_size: state.myFriendsListPageSize,
|
||||||
|
name: searchVal.value,
|
||||||
|
}
|
||||||
|
console.error(params)
|
||||||
|
state.isLoadingData = true
|
||||||
|
ServeQueryFriendsList(params)
|
||||||
|
.then((res) => {
|
||||||
|
console.log(res)
|
||||||
|
state.isLoadingData = false
|
||||||
|
if (res?.code === 200) {
|
||||||
|
if (state.myFriendsListPage === 1) {
|
||||||
|
state.myFriendsList = res.data?.user_list || []
|
||||||
|
} else {
|
||||||
|
state.myFriendsList = state.myFriendsList.concat(
|
||||||
|
res.data?.user_list || [],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (state.myFriendsList.length < res.data?.count) {
|
||||||
|
state.hasMoreFriends = true
|
||||||
|
} else {
|
||||||
|
state.hasMoreFriends = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
state.isLoadingData = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//点击进入用户详情页面
|
||||||
|
const toUserDetail = (userInfo) => {
|
||||||
|
uni.navigateTo({
|
||||||
|
url:
|
||||||
|
'/pages/dialog/dialogDetail/userDetail??erpUserId=' +
|
||||||
|
userInfo.erp_user_id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取“我的群组”列表
|
||||||
|
const getMyGroupsList = () => {
|
||||||
|
let params = {
|
||||||
|
page: state.myGroupsListPage,
|
||||||
|
page_size: state.myGroupsListPageSize,
|
||||||
|
group_name: searchVal.value,
|
||||||
|
}
|
||||||
|
state.isLoadingData = true
|
||||||
|
ServeUserGroupChatList(params)
|
||||||
|
.then((res) => {
|
||||||
|
console.log(res)
|
||||||
|
state.isLoadingData = false
|
||||||
|
if (res?.code === 200) {
|
||||||
|
if (state.myGroupsListPage === 1) {
|
||||||
|
state.myGroupsList = res.data?.items || []
|
||||||
|
} else {
|
||||||
|
state.myGroupsList = state.myGroupsList.concat(res.data?.items || [])
|
||||||
|
}
|
||||||
|
if (state.myGroupsList.length < res.data?.total) {
|
||||||
|
state.hasMoreGroups = true
|
||||||
|
} else {
|
||||||
|
state.hasMoreGroups = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
state.isLoadingData = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//加载更多数据
|
||||||
|
const doLoadMore = (e) => {
|
||||||
|
if (state.addressBookActiveTab === 'company' && state.hasMoreContracts) {
|
||||||
|
state.myContractListPage += 1
|
||||||
|
getMyContractList()
|
||||||
|
} else if (state.addressBookActiveTab === 'friends' && state.hasMoreFriends) {
|
||||||
|
state.myFriendsListPage += 1
|
||||||
|
getMyFriendsList()
|
||||||
|
} else if (state.addressBookActiveTab === 'groups' && state.hasMoreGroups) {
|
||||||
|
state.myGroupsListPage += 1
|
||||||
|
getMyGroupsList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取会话Id
|
||||||
|
const getSessionId = (talk_type, receiver_id) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let params = {
|
||||||
|
talkType: talk_type,
|
||||||
|
receiverId: receiver_id,
|
||||||
|
}
|
||||||
|
const resp = ServeGetSessionId(params)
|
||||||
|
console.log(resp)
|
||||||
|
resp.then(({ code, data }) => {
|
||||||
|
console.log(data)
|
||||||
|
if (code == 200) {
|
||||||
|
resolve(data?.sessionId)
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
})
|
||||||
|
resp.catch(() => {})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//点击跳转进入我的指定群聊
|
||||||
|
const toGroupChat = async (groupInfo) => {
|
||||||
|
let talk_type = 2
|
||||||
|
let receiver_id = groupInfo.id
|
||||||
|
const sessionId = await getSessionId(talk_type, receiver_id)
|
||||||
|
if (useTalkStore().findTalkIndex(`${talk_type}_${receiver_id}`) === -1) {
|
||||||
|
ServeCreateTalkList({
|
||||||
|
talk_type,
|
||||||
|
receiver_id,
|
||||||
|
}).then(async ({ code, data }) => {
|
||||||
|
if (code == 200) {
|
||||||
|
let item = formatTalkItem(data)
|
||||||
|
useTalkStore().addItem(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
useDialogueStore().setDialogue({
|
||||||
|
name: groupInfo.group_name,
|
||||||
|
talk_type: 2,
|
||||||
|
receiver_id: receiver_id,
|
||||||
|
})
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages/dialog/index?sessionId=' + sessionId,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//显示删除好友确认框
|
||||||
|
const showDeleteModal = (userInfo, friendIndex) => {
|
||||||
|
friendDeleteModalRef.value.open({
|
||||||
|
userInfo,
|
||||||
|
friendIndex,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//关闭删除好友确认框
|
||||||
|
const hideDeleteModal = () => {
|
||||||
|
friendDeleteModalRef.value.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
//删除好友
|
||||||
|
const doDeleteFriend = (args) => {
|
||||||
|
console.log(args.userInfo, args.friendIndex)
|
||||||
|
let params = {
|
||||||
|
receiver_id: args.userInfo.id, //聊天的用户id
|
||||||
|
talk_type: 1,
|
||||||
|
}
|
||||||
|
ServeDeleteFriend(params).then((res) => {
|
||||||
|
console.log(res)
|
||||||
|
if (res?.code === 200) {
|
||||||
|
message.success(t('addressBook.message.deleteSuccess') + ' !')
|
||||||
|
state.myFriendsList.splice(args.friendIndex, 1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 映射表-根据groupType设置对应值
|
||||||
|
const groupTypeMapping = {
|
||||||
|
0: {},
|
||||||
|
1: {},
|
||||||
|
2: {
|
||||||
|
result_type: t('index.mine.department'),
|
||||||
|
result_type_color: '#377EC6',
|
||||||
|
},
|
||||||
|
3: {
|
||||||
|
result_type: t('index.mine.project'),
|
||||||
|
result_type_color: '#C1681C',
|
||||||
|
},
|
||||||
|
4: {
|
||||||
|
result_type: t('index.type.company'),
|
||||||
|
result_type_color: '#7A58DE',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => state.addressBookActiveTab,
|
||||||
|
(newVal) => {
|
||||||
|
if (newVal === 'company') {
|
||||||
|
state.myContractListPage = 1
|
||||||
|
getMyContractList()
|
||||||
|
} else if (newVal === 'friends') {
|
||||||
|
state.myFriendsListPage = 1
|
||||||
|
getMyFriendsList()
|
||||||
|
} else if (newVal === 'groups') {
|
||||||
|
state.myGroupsListPage = 1
|
||||||
|
getMyGroupsList()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => searchVal.value,
|
||||||
|
(newVal) => {
|
||||||
|
if (state.addressBookActiveTab === 'company') {
|
||||||
|
state.myContractListPage = 1
|
||||||
|
getMyContractList()
|
||||||
|
} else if (state.addressBookActiveTab === 'friends') {
|
||||||
|
state.myFriendsListPage = 1
|
||||||
|
getMyFriendsList()
|
||||||
|
} else if (state.addressBookActiveTab === 'groups') {
|
||||||
|
state.myGroupsListPage = 1
|
||||||
|
getMyGroupsList()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
</script>
|
||||||
|
<style scoped lang="scss">
|
||||||
|
::v-deep .zp-paging-container-content {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .index_top_navbar .tmicon-angle-left {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .index_top_navbar .text-weight-b {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .index_top_navbar .statusHeightTop > .noNvueBorder:first-child {
|
||||||
|
background: transparent !important;
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top_bg {
|
||||||
|
background: url('@/static/image/mine/page_top.png') no-repeat;
|
||||||
|
background-size: cover;
|
||||||
|
background-position: bottom center;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.animateAll_tabs_tmui) {
|
||||||
|
width: 120rpx !important;
|
||||||
|
height: 10rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.address-book-page {
|
||||||
|
.address-book {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background-image: url('@/static/image/clockIn/z3280@3x.png');
|
||||||
|
background-size: cover;
|
||||||
|
background-position: bottom center;
|
||||||
|
background-attachment: fixed;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.address-book-tabs-panes-list {
|
||||||
|
margin: 30rpx 24rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.tabs-panes-each {
|
||||||
|
gap: 30rpx 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.address-book-company,
|
||||||
|
.address-book-friends {
|
||||||
|
.address-book-company-name {
|
||||||
|
margin: 0 0 -16rpx;
|
||||||
|
span {
|
||||||
|
font-size: 26rpx;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.members-list-each {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: #fff;
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
|
||||||
|
.swipe-action {
|
||||||
|
width: 100%;
|
||||||
|
overflow: visible !important;
|
||||||
|
|
||||||
|
:deep(.wd-swipe-action__right) {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: #cf3050;
|
||||||
|
padding: 0 48rpx;
|
||||||
|
border-radius: 0 8rpx 8rpx 0;
|
||||||
|
span {
|
||||||
|
color: #fff;
|
||||||
|
line-height: 1;
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.members-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: flex-start;
|
||||||
|
gap: 16rpx;
|
||||||
|
padding: 24rpx 24rpx 0;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.members-info-area {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: flex-start;
|
||||||
|
gap: 16rpx;
|
||||||
|
|
||||||
|
.members-info-basic {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.members-name {
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
width: 150rpx;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.members-jobNum {
|
||||||
|
font-size: 26rpx;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #999;
|
||||||
|
word-break: break-all;
|
||||||
|
margin: 10rpx 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.members-company {
|
||||||
|
font-size: 24rpx;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.members-positions-area {
|
||||||
|
.members-positions {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10rpx;
|
||||||
|
padding: 4rpx 0 0;
|
||||||
|
max-height: 84rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
line-clamp: 2;
|
||||||
|
|
||||||
|
.members-positions-each {
|
||||||
|
background-color: #eee9f8;
|
||||||
|
line-height: 1;
|
||||||
|
font-size: 24rpx;
|
||||||
|
padding: 4rpx 16rpx;
|
||||||
|
color: #46299d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.members-positions-popover-box {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 10rpx 0;
|
||||||
|
|
||||||
|
.members-positions-popover {
|
||||||
|
background-color: #eee9f8;
|
||||||
|
line-height: 1;
|
||||||
|
font-size: 24rpx;
|
||||||
|
padding: 8rpx 16rpx;
|
||||||
|
color: #46299d;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.company-infos {
|
||||||
|
margin: 0 0 0 88rpx;
|
||||||
|
padding: 0 0 24rpx 24rpx;
|
||||||
|
.company-each {
|
||||||
|
span {
|
||||||
|
font-size: 24rpx;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.address-book-groups {
|
||||||
|
.groups-list-each {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
background-color: #fff;
|
||||||
|
width: 100%;
|
||||||
|
padding: 24rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
|
||||||
|
.groups-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
gap: 16rpx;
|
||||||
|
.groups-name {
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.groups-type {
|
||||||
|
font-size: 24rpx;
|
||||||
|
border-radius: 6rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 6rpx 12rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.groups-btns {
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin: 0 0 0 16rpx;
|
||||||
|
.groups-btns-each {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: #46299d;
|
||||||
|
padding: 16rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 24rpx;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.addressBook-noData {
|
||||||
|
margin: 30rpx 24rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
flex: 1;
|
||||||
|
gap: 30rpx 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
img {
|
||||||
|
width: 500rpx;
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.friendDeleteModal {
|
||||||
|
:deep(.overlay) {
|
||||||
|
height: 100vh !important;
|
||||||
|
}
|
||||||
|
.friendDeleteModal-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -9,7 +9,7 @@
|
|||||||
? ''
|
? ''
|
||||||
: '0',
|
: '0',
|
||||||
}"
|
}"
|
||||||
v-for="(memberItem, memberIndex) in props?.memberList"
|
v-for="(memberItem, memberIndex) in sortedMemberList"
|
||||||
@click="toUserDetailPage(memberItem)"
|
@click="toUserDetailPage(memberItem)"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -53,7 +53,7 @@
|
|||||||
>
|
>
|
||||||
<div class="group-member-each">
|
<div class="group-member-each">
|
||||||
<div class="group-member-avatar" :style="{ background: 'unset' }">
|
<div class="group-member-avatar" :style="{ background: 'unset' }">
|
||||||
<img src="/src/static/image/chatSettings/add-member.png" />
|
<img src="@/static/image/chatSettings/add-member.png" />
|
||||||
</div>
|
</div>
|
||||||
<div class="group-member-name">
|
<div class="group-member-name">
|
||||||
<span class="text-[24rpx] font-regular">添加</span>
|
<span class="text-[24rpx] font-regular">添加</span>
|
||||||
@ -71,7 +71,7 @@
|
|||||||
>
|
>
|
||||||
<div class="group-member-each">
|
<div class="group-member-each">
|
||||||
<div class="group-member-avatar" :style="{ background: 'unset' }">
|
<div class="group-member-avatar" :style="{ background: 'unset' }">
|
||||||
<img src="/src/static/image/chatSettings/remove-member.png" />
|
<img src="@/static/image/chatSettings/remove-member.png" />
|
||||||
</div>
|
</div>
|
||||||
<div class="group-member-name">
|
<div class="group-member-name">
|
||||||
<span class="text-[24rpx] font-regular">移除</span>
|
<span class="text-[24rpx] font-regular">移除</span>
|
||||||
@ -81,7 +81,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { defineProps } from 'vue'
|
import { defineProps, computed } from 'vue'
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
memberList: Array, //人员列表
|
memberList: Array, //人员列表
|
||||||
memberListsLimit: Number, //人员列表数量限制
|
memberListsLimit: Number, //人员列表数量限制
|
||||||
@ -90,6 +90,36 @@ const props = defineProps({
|
|||||||
hideAddRemoveBtns: Boolean, //是否隐藏添加移除按钮
|
hideAddRemoveBtns: Boolean, //是否隐藏添加移除按钮
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 对成员列表进行排序
|
||||||
|
const sortedMemberList = computed(() => {
|
||||||
|
if (!props.memberList || props.memberList.length === 0) return [];
|
||||||
|
|
||||||
|
// 创建一个新数组,保留原始索引
|
||||||
|
const indexedList = props.memberList.map((item, index) => ({ item, index }));
|
||||||
|
|
||||||
|
// 按照leader属性和原始顺序排序
|
||||||
|
return indexedList.sort((a, b) => {
|
||||||
|
const leaderA = a.item.leader || 0;
|
||||||
|
const leaderB = b.item.leader || 0;
|
||||||
|
|
||||||
|
// 如果leader状态不同,优先按leader排序
|
||||||
|
if ((leaderA === 1 || leaderA === 2) && (leaderB !== 1 && leaderB !== 2)) {
|
||||||
|
return -1; // a排在前面
|
||||||
|
}
|
||||||
|
if ((leaderB === 1 || leaderB === 2) && (leaderA !== 1 && leaderA !== 2)) {
|
||||||
|
return 1; // b排在前面
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果都是管理员,按照leader值大小排序
|
||||||
|
if ((leaderA === 1 || leaderA === 2) && (leaderB === 1 || leaderB === 2)) {
|
||||||
|
return leaderB - leaderA; // leader值大的排前面
|
||||||
|
}
|
||||||
|
|
||||||
|
// 其他情况保持原始顺序
|
||||||
|
return a.index - b.index;
|
||||||
|
}).map(item => item.item); // 返回排序后的原始对象
|
||||||
|
})
|
||||||
|
|
||||||
//点击跳转到用户详情页面
|
//点击跳转到用户详情页面
|
||||||
const toUserDetailPage = (userItem) => {
|
const toUserDetailPage = (userItem) => {
|
||||||
console.log(userItem)
|
console.log(userItem)
|
||||||
|
|||||||
@ -49,7 +49,7 @@
|
|||||||
props?.memberItem?.is_mine && props?.manageType === 'removeMembers'
|
props?.memberItem?.is_mine && props?.manageType === 'removeMembers'
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<img src="/src/static/image/chatSettings/is-mine.png" />
|
<img src="@/static/image/chatSettings/is-mine.png" />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="is-admin-tag"
|
class="is-admin-tag"
|
||||||
|
|||||||
803
src/pages/chatSettings/components/selectMemberByAlphabet.vue
Normal file
@ -0,0 +1,803 @@
|
|||||||
|
<template>
|
||||||
|
<div class="select-member-by-alphabet">
|
||||||
|
<ZPaging ref="zPaging" :show-scrollbar="false" :use-virtual-list="true" :virtual-list-col="5"
|
||||||
|
:refresher-enabled="false" :loading-more-enabled="false" @scroll="onScroll" :fixed="false"
|
||||||
|
:height="props?.selectAreaHeight">
|
||||||
|
<div class="select-members">
|
||||||
|
<div class="search-member" v-if="
|
||||||
|
props?.manageType !== 'removeMembers' &&
|
||||||
|
!(
|
||||||
|
props?.manageType === 'admin' &&
|
||||||
|
(groupParams.groupInfo.group_type === 2 ||
|
||||||
|
groupParams.groupInfo.group_type === 4)
|
||||||
|
)
|
||||||
|
">
|
||||||
|
<customInput :searchText="state.searchText" @inputSearchText="inputSearchText"></customInput>
|
||||||
|
</div>
|
||||||
|
<div v-show="props?.manageType == 'removeMembers'" class="my-self">
|
||||||
|
<div class="my-self-left">
|
||||||
|
<image style="width: 72rpx;border-radius: 50%;height: 72rpx;" :src="mySelfMember.avatar" mode=""></image>
|
||||||
|
<div style="padding: 0 20rpx;">{{mySelfMember.nickname}}</div>
|
||||||
|
<img style="width: 45rpx;" src="@/static/image/chatSettings/is-mine.png" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="my-self-right">
|
||||||
|
{{ $t('group.identify.admin') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="member-list" :style="{
|
||||||
|
padding: props?.manageType === 'searchRecord' ? '20rpx 0 0' : '',
|
||||||
|
}">
|
||||||
|
<div class="member-list-alphabet-anchor-point" :style="{
|
||||||
|
top: props?.manageType === 'mention' ? '90rpx' : '',
|
||||||
|
}">
|
||||||
|
<div class="member-list-alphabet-anchor-point-each" v-for="(alphabetItem, alphabetIndex) in state?.alphabet"
|
||||||
|
:key="alphabetIndex" :style="{
|
||||||
|
margin: state?.alphabet?.length > 17 ? '0' : '',
|
||||||
|
}" @click.stop="scrollToView(alphabetItem)">
|
||||||
|
<span class="text-[32rpx] font-regular" :style="{
|
||||||
|
color:
|
||||||
|
state.currentAlphabet === alphabetItem ? '#7A58DE' : '',
|
||||||
|
}">
|
||||||
|
{{ alphabetItem }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="member-list-alphabet" v-for="(alphabetItem, alphabetIndex) in state.resultMemberList"
|
||||||
|
:key="alphabetIndex">
|
||||||
|
<div class="member-list-alphabet-key" :style="{
|
||||||
|
padding:
|
||||||
|
props?.manageType === 'searchRecord' ||
|
||||||
|
props?.manageType === 'removeMembers' ||
|
||||||
|
props?.manageType === 'mention'
|
||||||
|
? '10rpx 30rpx'
|
||||||
|
: '',
|
||||||
|
}" v-if="
|
||||||
|
alphabetItem?.memberList?.length > 0 &&
|
||||||
|
alphabetItem?.key !== '0'
|
||||||
|
" :id="alphabetItem.key === '#' ? 'special-hash' : alphabetItem.key" :ref="
|
||||||
|
(el) => {
|
||||||
|
if (el) alphabetElementRefs[alphabetIndex] = el
|
||||||
|
}
|
||||||
|
">
|
||||||
|
<span class="text-[32rpx] font-regular">
|
||||||
|
{{ alphabetItem.key }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div v-if="alphabetItem?.memberList?.length > 0">
|
||||||
|
<div class="member-list-each" v-for="(item, index) in alphabetItem?.memberList" :key="index">
|
||||||
|
<tm-checkbox-group v-model="item.checkArr">
|
||||||
|
<selectMemberItem :groupType="groupParams.groupInfo.group_type" :memberItem="item"
|
||||||
|
@clickItem="handleClickItem(item)" :manageType="props?.manageType" :itemStyle="
|
||||||
|
props?.manageType === 'searchRecord' ||
|
||||||
|
props?.manageType === 'removeMembers' ||
|
||||||
|
props?.manageType === 'mention'
|
||||||
|
? 'list'
|
||||||
|
: 'card'
|
||||||
|
">
|
||||||
|
<template #left v-if="props?.manageType !== 'searchRecord'">
|
||||||
|
<div v-if="
|
||||||
|
props?.manageType === 'removeMembers' && item?.is_mine
|
||||||
|
">
|
||||||
|
<tm-checkbox color="#fff" :transprent="true" :border="0" :disabled="true"></tm-checkbox>
|
||||||
|
</div>
|
||||||
|
<tm-checkbox v-if="
|
||||||
|
!(
|
||||||
|
props?.manageType === 'removeMembers' &&
|
||||||
|
item?.is_mine
|
||||||
|
) && props?.isMulSelect
|
||||||
|
" :round="10" :color="
|
||||||
|
item?.checkArr?.length > 0 ? '#46299d' : '#B4B4B4'
|
||||||
|
" :outlined="
|
||||||
|
item?.checkArr?.length > 0 ||
|
||||||
|
(props?.manageType === 'silence' &&
|
||||||
|
item.is_mute === 1) ||
|
||||||
|
(props?.manageType === 'admin' &&
|
||||||
|
(item.leader === 1 || item.leader === 2))
|
||||||
|
? false
|
||||||
|
: true
|
||||||
|
" :value="item.id" :disabled="
|
||||||
|
(props?.manageType === 'silence' &&
|
||||||
|
item.is_mute === 1) ||
|
||||||
|
(props?.manageType === 'admin' &&
|
||||||
|
(item.leader === 1 || item.leader === 2))
|
||||||
|
" @change="checkBoxChange"></tm-checkbox>
|
||||||
|
</template>
|
||||||
|
</selectMemberItem>
|
||||||
|
</tm-checkbox-group>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ZPaging>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import customInput from '@/components/custom-input/custom-input.vue'
|
||||||
|
import selectMemberItem from '../components/select-member-item.vue'
|
||||||
|
import ZPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
|
||||||
|
import useZPaging from '@/uni_modules/z-paging/components/z-paging/js/hooks/useZPaging.js'
|
||||||
|
import groupAllMember from '@/static/image/chatList/groupAllMember.png'
|
||||||
|
import {
|
||||||
|
computed,
|
||||||
|
onMounted,
|
||||||
|
reactive,
|
||||||
|
ref,
|
||||||
|
watch,
|
||||||
|
nextTick,
|
||||||
|
defineProps,
|
||||||
|
defineEmits,
|
||||||
|
} from 'vue'
|
||||||
|
import {
|
||||||
|
ServeGroupNoSpeak,
|
||||||
|
ServeEditGroupAdmin,
|
||||||
|
ServeGroupAssignAdmin,
|
||||||
|
ServeRemoveMembersGroup,
|
||||||
|
} from '@/api/group/index.js'
|
||||||
|
import {
|
||||||
|
useDialogueStore,
|
||||||
|
useGroupStore,
|
||||||
|
useGroupTypeStore
|
||||||
|
} from '@/store'
|
||||||
|
|
||||||
|
const emits = defineEmits([
|
||||||
|
'updateSelectedMembersNum',
|
||||||
|
'getSelectResult',
|
||||||
|
'getMentionSelectLists',
|
||||||
|
])
|
||||||
|
|
||||||
|
const zPaging = ref()
|
||||||
|
useZPaging(zPaging)
|
||||||
|
|
||||||
|
const groupStore = useGroupStore()
|
||||||
|
const groupParams = reactive({
|
||||||
|
groupInfo: computed(() => groupStore.groupInfo),
|
||||||
|
})
|
||||||
|
|
||||||
|
const groupTypeStore = useGroupTypeStore()
|
||||||
|
const groupTypeParams = reactive({
|
||||||
|
departmentAllPositions: computed(() => groupTypeStore.departmentAllPositions),
|
||||||
|
})
|
||||||
|
|
||||||
|
const dialogueStore = useDialogueStore()
|
||||||
|
const dialogueParams = reactive({
|
||||||
|
memberList: computed(() => {
|
||||||
|
const lowerCaseSearchText = state?.searchText.toLowerCase()
|
||||||
|
return dialogueStore.members.filter((item) =>
|
||||||
|
state?.searchText ?
|
||||||
|
item.nickname.toLowerCase().includes(lowerCaseSearchText) :
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
receiverId: computed(() => dialogueStore.talk.receiver_id),
|
||||||
|
})
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
manageType: {
|
||||||
|
//管理类型
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
isCreateDepGroup: {
|
||||||
|
//是否是创建部门群
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
selectAreaHeight: {
|
||||||
|
//选择区域高度
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
isMulSelect: {
|
||||||
|
//是否开启多选
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
searchText: '', //搜索内容
|
||||||
|
alphabet: [], //A-Z列表
|
||||||
|
currentAlphabet: 'A', //当前A-Z位置
|
||||||
|
resultMemberList: [], //按A-Z整理后的人员列表
|
||||||
|
isAssign: false, //是否指定view
|
||||||
|
scrollDirection: '', //当前列表滚动方向
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => dialogueParams?.memberList,
|
||||||
|
(newMemberList) => {
|
||||||
|
assembleAlphabetMemberList(newMemberList)
|
||||||
|
}, {
|
||||||
|
deep: true
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => groupParams?.groupInfo,
|
||||||
|
(newGroupInfo) => {
|
||||||
|
assembleAlphabetMemberList(dialogueParams?.memberList)
|
||||||
|
}, {
|
||||||
|
deep: true
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props?.isMulSelect,
|
||||||
|
(newIsMulSelect) => {
|
||||||
|
if (props?.manageType === 'mention') {
|
||||||
|
if (!newIsMulSelect) {
|
||||||
|
state.resultMemberList.unshift({
|
||||||
|
key: '0',
|
||||||
|
memberList: [{
|
||||||
|
avatar: groupAllMember,
|
||||||
|
erp_user_id: 0,
|
||||||
|
gender: 0,
|
||||||
|
is_mute: 0,
|
||||||
|
key: '0',
|
||||||
|
leader: 0,
|
||||||
|
nickname: '所有人',
|
||||||
|
remark: '',
|
||||||
|
user_id: 0,
|
||||||
|
}, ],
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
if (state.resultMemberList[0].key === '0') {
|
||||||
|
state.resultMemberList.splice(0, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
deep: true,
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
//获取A-Z tag元素
|
||||||
|
const alphabetElementRefs = ref([])
|
||||||
|
//观察者
|
||||||
|
let observer
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (props?.manageType) {
|
||||||
|
assembleAlphabetMemberList(dialogueParams?.memberList)
|
||||||
|
}
|
||||||
|
if (props?.isCreateDepGroup) {
|
||||||
|
assembleAlphabetMemberList()
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogueParams.memberList.forEach((ele) => {
|
||||||
|
ele.checkArr = []
|
||||||
|
})
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
root: null, // 使用浏览器窗口作为根容器
|
||||||
|
threshold: 1.0, // 当元素100%离开视口时触发
|
||||||
|
}
|
||||||
|
observer = new IntersectionObserver(handleIntersection, options)
|
||||||
|
nextTick(() => {
|
||||||
|
watch(
|
||||||
|
alphabetElementRefs,
|
||||||
|
(newAlphabetElementRefs) => {
|
||||||
|
if (Array.isArray(newAlphabetElementRefs)) {
|
||||||
|
newAlphabetElementRefs.forEach((el, index) => {
|
||||||
|
observeElement(el, index)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
immediate: true,
|
||||||
|
deep: true
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if (alphabetElementRefs.value.length > 0) {
|
||||||
|
alphabetElementRefs.value.forEach((el, index) =>
|
||||||
|
observeElement(el, index),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
//观察元素
|
||||||
|
const observeElement = (el, index) => {
|
||||||
|
if (el && observer) {
|
||||||
|
observer.observe(el)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 观察者函数
|
||||||
|
const handleIntersection = (entries) => {
|
||||||
|
if (state.isAssign) {
|
||||||
|
state.isAssign = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
entries.forEach((entry) => {
|
||||||
|
if (!entry.isIntersecting && state.scrollDirection === 'down') {
|
||||||
|
state.currentAlphabet = entry.target.id
|
||||||
|
} else if (entry.isIntersecting && state.scrollDirection === 'up') {
|
||||||
|
if (state?.alphabet?.length > 1) {
|
||||||
|
state?.alphabet.forEach((item, index) => {
|
||||||
|
if (item === entry.target.id && index > 0) {
|
||||||
|
state.currentAlphabet = state?.alphabet[index - 1]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
state.currentAlphabet = entry.target.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//输入搜索文本
|
||||||
|
const inputSearchText = (e) => {
|
||||||
|
// console.log(e)
|
||||||
|
state.searchText = e
|
||||||
|
}
|
||||||
|
|
||||||
|
//点击item
|
||||||
|
const handleClickItem = (item) => {
|
||||||
|
if (
|
||||||
|
(props?.manageType === 'silence' && item.is_mute === 1) ||
|
||||||
|
(props?.manageType === 'admin' &&
|
||||||
|
(item.leader === 1 || item.leader === 2)) ||
|
||||||
|
(props?.manageType === 'removeMembers' && item.is_mine) ||
|
||||||
|
(props?.manageType === 'mention' && !props?.isMulSelect)
|
||||||
|
) {
|
||||||
|
if (props?.manageType === 'mention' && !props?.isMulSelect) {
|
||||||
|
emits('getMentionSelectLists', [item])
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (props?.manageType === 'searchRecord') {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages/search/searchByCondition/index?condition=member&groupMemberId=' +
|
||||||
|
item.id,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let itemList = dialogueParams.memberList
|
||||||
|
if (
|
||||||
|
props?.manageType === 'admin' &&
|
||||||
|
(groupParams.groupInfo.group_type == 2 ||
|
||||||
|
groupParams.groupInfo.group_type == 4 ||
|
||||||
|
props?.isCreateDepGroup === 1)
|
||||||
|
) {
|
||||||
|
itemList = state.resultMemberList[0].memberList
|
||||||
|
}
|
||||||
|
itemList.forEach((ele) => {
|
||||||
|
if (ele.id == item.id) {
|
||||||
|
ele.checkArr = ele.checkArr?.length > 0 ? [] : [item.id]
|
||||||
|
if (ele.checkArr?.length > 0) {
|
||||||
|
emits('updateSelectedMembersNum', 1)
|
||||||
|
} else {
|
||||||
|
emits('updateSelectedMembersNum', -1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const mySelfMember = ref({})
|
||||||
|
//组装A-Z排序的人员列表
|
||||||
|
const assembleAlphabetMemberList = async (newMemberList) => {
|
||||||
|
if (props?.manageType === 'removeMembers' && Array.isArray(newMemberList)) {
|
||||||
|
// 只遍历一次,找到第一个 is_mine 为 true 的成员并移除
|
||||||
|
for (let i = 0; i < newMemberList.length; i++) {
|
||||||
|
const item = newMemberList[i];
|
||||||
|
if (item?.is_mine === true) {
|
||||||
|
mySelfMember.value = item;
|
||||||
|
newMemberList.splice(i, 1); // 删除该成员
|
||||||
|
break; // 找到后立即跳出
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
props?.manageType === 'searchRecord' ||
|
||||||
|
props?.manageType === 'removeMembers' ||
|
||||||
|
props?.manageType === 'mention'
|
||||||
|
) {
|
||||||
|
const resultMemberList = ref([])
|
||||||
|
const alphabet = Array.from({
|
||||||
|
length: 26
|
||||||
|
}, (_, i) =>
|
||||||
|
String.fromCharCode(i + 65),
|
||||||
|
)
|
||||||
|
let tempAlphabet = []
|
||||||
|
|
||||||
|
// 创建一个对象来存储所有分组的数据
|
||||||
|
let groupedData = {
|
||||||
|
'#': [],
|
||||||
|
}
|
||||||
|
alphabet.forEach((letter) => {
|
||||||
|
groupedData[letter] = []
|
||||||
|
})
|
||||||
|
|
||||||
|
// 对数据进行分组
|
||||||
|
if (newMemberList) {
|
||||||
|
newMemberList.forEach((item) => {
|
||||||
|
const key = item.key?.toUpperCase()
|
||||||
|
if (alphabet.includes(key)) {
|
||||||
|
groupedData[key].push(item)
|
||||||
|
} else {
|
||||||
|
groupedData['#'].push(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将分组数据转换为最终格式
|
||||||
|
alphabet.forEach((letter) => {
|
||||||
|
if (groupedData[letter].length > 0) {
|
||||||
|
tempAlphabet.push(letter)
|
||||||
|
}
|
||||||
|
resultMemberList.value.push({
|
||||||
|
key: letter,
|
||||||
|
memberList: groupedData[letter],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// 添加#分组(如果有数据)
|
||||||
|
if (groupedData['#'].length > 0) {
|
||||||
|
tempAlphabet.push('#')
|
||||||
|
resultMemberList.value.push({
|
||||||
|
key: '#',
|
||||||
|
memberList: groupedData['#'],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
state.alphabet = tempAlphabet
|
||||||
|
if (props?.manageType === 'mention' && !props?.isMulSelect) {
|
||||||
|
resultMemberList.value.unshift({
|
||||||
|
key: '0',
|
||||||
|
memberList: [{
|
||||||
|
avatar: groupAllMember,
|
||||||
|
erp_user_id: 0,
|
||||||
|
gender: 0,
|
||||||
|
is_mute: 0,
|
||||||
|
key: '0',
|
||||||
|
leader: 0,
|
||||||
|
nickname: '所有人',
|
||||||
|
remark: '',
|
||||||
|
user_id: 0,
|
||||||
|
}, ],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
state.resultMemberList = resultMemberList
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
(groupParams.groupInfo.group_type == 2 ||
|
||||||
|
groupParams.groupInfo.group_type == 4) &&
|
||||||
|
props?.manageType === 'admin'
|
||||||
|
) {
|
||||||
|
let departmentIdsArr = []
|
||||||
|
if (groupParams?.groupInfo?.deptInfos?.length > 0) {
|
||||||
|
groupParams.groupInfo.deptInfos.forEach((item) => {
|
||||||
|
departmentIdsArr.push(item.dept_id)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
getPosiByDep(departmentIdsArr)
|
||||||
|
} else if (props?.isCreateDepGroup === 1) {
|
||||||
|
let departmentIdsArr = []
|
||||||
|
if (groupTypeStore?.depCheckedKeys?.value?.length > 0) {
|
||||||
|
groupTypeStore.depCheckedKeys.value.forEach((item) => {
|
||||||
|
departmentIdsArr.push(item.ID)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
getPosiByDep(departmentIdsArr)
|
||||||
|
} else {
|
||||||
|
state.resultMemberList = [{
|
||||||
|
key: '',
|
||||||
|
memberList: newMemberList,
|
||||||
|
}, ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//按部门获取岗位
|
||||||
|
const getPosiByDep = async (departmentIdsArr) => {
|
||||||
|
await groupTypeStore.getPositionByDepartment({
|
||||||
|
IDs: departmentIdsArr,
|
||||||
|
})
|
||||||
|
let departmentAllPositions = []
|
||||||
|
if (groupTypeParams?.departmentAllPositions?.value?.length > 0) {
|
||||||
|
groupTypeParams?.departmentAllPositions?.value?.forEach((item) => {
|
||||||
|
item?.AllPositions?.forEach((positionItem) => {
|
||||||
|
departmentAllPositions.push({
|
||||||
|
nickname: item.name + '-' + positionItem.name,
|
||||||
|
id: item.ID + '-' + positionItem.ID,
|
||||||
|
checkArr: [],
|
||||||
|
positionInfo: {
|
||||||
|
dept_id: item.ID,
|
||||||
|
dept_name: item.name,
|
||||||
|
position_id: positionItem.ID,
|
||||||
|
position_name: positionItem.name,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (groupParams?.groupInfo?.groupAdminList?.length > 0) {
|
||||||
|
groupParams?.groupInfo?.groupAdminList.forEach((item) => {
|
||||||
|
departmentAllPositions.forEach((idsItem) => {
|
||||||
|
if (item.dept_id + '-' + item.position_id == idsItem.id) {
|
||||||
|
idsItem.leader = 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
props?.isCreateDepGroup === 1 &&
|
||||||
|
groupTypeStore?.groupAdmins?.value?.length > 0
|
||||||
|
) {
|
||||||
|
departmentAllPositions.forEach((allPos) => {
|
||||||
|
groupTypeStore.groupAdmins.value.forEach((admin) => {
|
||||||
|
if (allPos.id === admin.id) {
|
||||||
|
allPos.checkArr = [allPos.id]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (state?.searchText) {
|
||||||
|
const lowerCaseSearchText = state?.searchText.toLowerCase()
|
||||||
|
departmentAllPositions = departmentAllPositions.filter((item) =>
|
||||||
|
state?.searchText ?
|
||||||
|
item.nickname.toLowerCase().includes(lowerCaseSearchText) :
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
state.resultMemberList = [{
|
||||||
|
key: '',
|
||||||
|
memberList: departmentAllPositions,
|
||||||
|
}, ]
|
||||||
|
}
|
||||||
|
|
||||||
|
//滚动到指定的view
|
||||||
|
const scrollToView = (alphabet) => {
|
||||||
|
state.currentAlphabet = alphabet
|
||||||
|
state.isAssign = true
|
||||||
|
|
||||||
|
// 计算偏移高度
|
||||||
|
const offsetHeight = document.getElementById('topArea')?.clientHeight ?
|
||||||
|
document.getElementById('topArea').clientHeight - 1 :
|
||||||
|
props?.manageType === 'mention' ?
|
||||||
|
140 :
|
||||||
|
80
|
||||||
|
|
||||||
|
// 使用scrollIntoViewById处理所有情况
|
||||||
|
const targetId = alphabet === '#' ? 'special-hash' : alphabet
|
||||||
|
zPaging.value?.scrollIntoViewById(targetId, offsetHeight)
|
||||||
|
}
|
||||||
|
|
||||||
|
//监听列表滚动
|
||||||
|
const onScroll = (e) => {
|
||||||
|
if (e.detail.deltaY < 0) {
|
||||||
|
state.scrollDirection = 'down'
|
||||||
|
} else if (e.detail.deltaY > 0) {
|
||||||
|
state.scrollDirection = 'up'
|
||||||
|
} else {
|
||||||
|
state.scrollDirection = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//选中的人员改变
|
||||||
|
const checkBoxChange = (e) => {
|
||||||
|
if (e) {
|
||||||
|
emits('updateSelectedMembersNum', 1)
|
||||||
|
} else {
|
||||||
|
emits('updateSelectedMembersNum', -1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//点击确认选择的成员
|
||||||
|
const confirmSelectMembers = () => {
|
||||||
|
let selectedUserIds = ''
|
||||||
|
let itemList = dialogueStore.members
|
||||||
|
let positionInfos = []
|
||||||
|
let selectUserInfos = []
|
||||||
|
if (
|
||||||
|
props?.manageType === 'admin' &&
|
||||||
|
(groupParams.groupInfo.group_type == 2 ||
|
||||||
|
groupParams.groupInfo.group_type == 4 ||
|
||||||
|
props?.isCreateDepGroup === 1)
|
||||||
|
) {
|
||||||
|
itemList = state.resultMemberList[0].memberList
|
||||||
|
}
|
||||||
|
itemList.forEach((ele) => {
|
||||||
|
if (ele.checkArr?.length > 0) {
|
||||||
|
if (!selectedUserIds) {
|
||||||
|
selectedUserIds = String(ele.checkArr[0])
|
||||||
|
} else {
|
||||||
|
selectedUserIds += ',' + ele.checkArr[0]
|
||||||
|
}
|
||||||
|
selectUserInfos.push(ele)
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
ele.checkArr?.length > 0 ||
|
||||||
|
(ele.leader && (ele.leader == 1 || ele.leader == 2))
|
||||||
|
) {
|
||||||
|
if (props?.isCreateDepGroup === 1) {
|
||||||
|
let posInfo = Object.assign({}, ele.positionInfo, {
|
||||||
|
name: ele.nickname,
|
||||||
|
id: ele.id,
|
||||||
|
})
|
||||||
|
positionInfos.push(posInfo)
|
||||||
|
} else {
|
||||||
|
positionInfos.push(ele.positionInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
console.log(selectedUserIds)
|
||||||
|
if (selectedUserIds) {
|
||||||
|
if (props?.manageType === 'silence') {
|
||||||
|
let params = {
|
||||||
|
mode: 1, //1禁言2解禁
|
||||||
|
group_id: dialogueParams.receiverId, //群id
|
||||||
|
user_ids: selectedUserIds, //用户ids
|
||||||
|
}
|
||||||
|
console.log(params)
|
||||||
|
const resp = ServeGroupNoSpeak(params)
|
||||||
|
resp.then(({
|
||||||
|
code,
|
||||||
|
data
|
||||||
|
}) => {
|
||||||
|
console.log(data)
|
||||||
|
if (code == 200) {
|
||||||
|
useDialogueStore().updateGroupMembers()
|
||||||
|
} else {}
|
||||||
|
})
|
||||||
|
resp.catch(() => {})
|
||||||
|
} else if (props?.manageType === 'admin') {
|
||||||
|
if (props?.isCreateDepGroup === 1) {
|
||||||
|
// console.log(positionInfos)
|
||||||
|
groupTypeStore.groupAdmins.value = positionInfos
|
||||||
|
uni.navigateBack({
|
||||||
|
delta: 1,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
groupParams.groupInfo.group_type == 1 ||
|
||||||
|
groupParams.groupInfo.group_type == 3
|
||||||
|
) {
|
||||||
|
let params = {
|
||||||
|
mode: 1, //1管理员,2不是管理员
|
||||||
|
group_id: dialogueParams.receiverId, //群id
|
||||||
|
user_ids: selectedUserIds,
|
||||||
|
}
|
||||||
|
console.log(params)
|
||||||
|
const resp = ServeGroupAssignAdmin(params)
|
||||||
|
resp.then(({
|
||||||
|
code,
|
||||||
|
data
|
||||||
|
}) => {
|
||||||
|
console.log(data)
|
||||||
|
if (code == 200) {
|
||||||
|
useDialogueStore().updateGroupMembers()
|
||||||
|
} else {}
|
||||||
|
})
|
||||||
|
resp.catch(() => {})
|
||||||
|
} else if (
|
||||||
|
groupParams.groupInfo.group_type == 2 ||
|
||||||
|
groupParams.groupInfo.group_type == 4
|
||||||
|
) {
|
||||||
|
let params = {
|
||||||
|
source: 'app',
|
||||||
|
id: dialogueParams.receiverId,
|
||||||
|
deptInfos: groupParams.groupInfo.deptInfos,
|
||||||
|
positionInfos: positionInfos,
|
||||||
|
}
|
||||||
|
console.log(params)
|
||||||
|
const resp = ServeEditGroupAdmin(params)
|
||||||
|
resp.then(({
|
||||||
|
code,
|
||||||
|
data
|
||||||
|
}) => {
|
||||||
|
console.log(data)
|
||||||
|
if (code == 200) {
|
||||||
|
groupStore.ServeGroupDetail()
|
||||||
|
} else {}
|
||||||
|
})
|
||||||
|
resp.catch(() => {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (props?.manageType === 'removeMembers') {
|
||||||
|
let params = {
|
||||||
|
group_id: dialogueParams.receiverId, //群id
|
||||||
|
members_ids: selectedUserIds, //群成员id,批量的话逗号分割
|
||||||
|
}
|
||||||
|
console.log(params)
|
||||||
|
const resp = ServeRemoveMembersGroup(params)
|
||||||
|
resp.then(({
|
||||||
|
code,
|
||||||
|
data
|
||||||
|
}) => {
|
||||||
|
console.log(data)
|
||||||
|
if (code == 200) {
|
||||||
|
// console.error(-selectedUserIds.split(',').length)
|
||||||
|
emits('updateSelectedMembersNum', -selectedUserIds.split(',').length)
|
||||||
|
useDialogueStore().updateGroupMembers()
|
||||||
|
groupStore.ServeGroupDetail()
|
||||||
|
} else {}
|
||||||
|
})
|
||||||
|
resp.catch(() => {})
|
||||||
|
} else if (props?.manageType === 'mention') {
|
||||||
|
emits('getSelectResult', selectUserInfos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 暴露确认方法
|
||||||
|
defineExpose({
|
||||||
|
confirmSelectMembers,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.my-self {
|
||||||
|
padding: 10rpx 60rpx;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
background-color: #fff;
|
||||||
|
|
||||||
|
|
||||||
|
.my-self-left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-left: 8%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.my-self-right {
|
||||||
|
color: #b4b4b4;
|
||||||
|
padding: 0.1875rem 0.375rem;
|
||||||
|
border: #b4b4b4 1px solid;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-member-by-alphabet {
|
||||||
|
.select-members {
|
||||||
|
padding: 20rpx 32rpx;
|
||||||
|
|
||||||
|
.search-member {
|
||||||
|
padding: 22rpx 16rpx;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-list {
|
||||||
|
.member-list-alphabet-anchor-point {
|
||||||
|
position: fixed;
|
||||||
|
right: 32rpx;
|
||||||
|
top: 0;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.member-list-alphabet-anchor-point-each {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin: 0 0 14rpx;
|
||||||
|
|
||||||
|
span {
|
||||||
|
width: 52rpx;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 44rpx;
|
||||||
|
color: $theme-text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-list-alphabet {
|
||||||
|
.member-list-alphabet-key {
|
||||||
|
background-color: #f3f3f3;
|
||||||
|
|
||||||
|
span {
|
||||||
|
line-height: 44rpx;
|
||||||
|
color: $theme-text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -16,9 +16,10 @@
|
|||||||
props?.item?.hasPointer &&
|
props?.item?.hasPointer &&
|
||||||
(props?.isManager ||
|
(props?.isManager ||
|
||||||
(!props?.isManager &&
|
(!props?.isManager &&
|
||||||
props?.item?.label !== $t('chat.settings.groupName')))
|
(props?.item?.label !== $t('chat.settings.groupName') ||
|
||||||
|
props?.item?.label !== $t('chat.settings.groupType'))))
|
||||||
"
|
"
|
||||||
src="/src/static/image/chatSettings/pointer.png"
|
src="@/static/image/chatSettings/pointer.png"
|
||||||
/>
|
/>
|
||||||
<tm-switch
|
<tm-switch
|
||||||
:width="88"
|
:width="88"
|
||||||
@ -27,8 +28,8 @@
|
|||||||
barIcon=""
|
barIcon=""
|
||||||
color="#46299D"
|
color="#46299D"
|
||||||
unCheckedColor="#EEEEEE"
|
unCheckedColor="#EEEEEE"
|
||||||
:modelValue="modelValue"
|
:modelValue="props?.item?.label === t('chat.settings.openReminder') ? openReminderStatus : modelValue"
|
||||||
:defaultValue="modelValue"
|
:defaultValue="props?.item?.label === t('chat.settings.openReminder') ? openReminderStatus : modelValue"
|
||||||
@change="changeSwitch($event, props?.item)"
|
@change="changeSwitch($event, props?.item)"
|
||||||
></tm-switch>
|
></tm-switch>
|
||||||
</div>
|
</div>
|
||||||
@ -45,8 +46,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { defineProps, defineEmits, computed } from 'vue'
|
import { defineProps, defineEmits, computed, ref, onMounted, watch } from 'vue'
|
||||||
|
import { ServeContactRobotQuery } from '@/api/chat'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
@ -102,6 +103,32 @@ const modelValue = computed(() => {
|
|||||||
return switchStatus
|
return switchStatus
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 仅用于“拒收消息”场景的本地状态
|
||||||
|
const openReminderStatus = ref(false)
|
||||||
|
const loadRefuseStatus = async () => {
|
||||||
|
try {
|
||||||
|
const res = await ServeContactRobotQuery()
|
||||||
|
openReminderStatus.value = !!(res?.data?.Result)
|
||||||
|
} catch (err) {
|
||||||
|
openReminderStatus.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (props?.item?.label === t('chat.settings.openReminder')) {
|
||||||
|
loadRefuseStatus()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props?.item?.label,
|
||||||
|
(newLabel) => {
|
||||||
|
if (newLabel === t('chat.settings.openReminder')) {
|
||||||
|
loadRefuseStatus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
//切换开关选择
|
//切换开关选择
|
||||||
const changeSwitch = (e, item) => {
|
const changeSwitch = (e, item) => {
|
||||||
emits('changeSwitch', e, item.label)
|
emits('changeSwitch', e, item.label)
|
||||||
|
|||||||
@ -22,6 +22,7 @@
|
|||||||
<customBtn
|
<customBtn
|
||||||
:btnText="$t('button.text.edit')"
|
:btnText="$t('button.text.edit')"
|
||||||
@click="editAvatar"
|
@click="editAvatar"
|
||||||
|
:isLoading="state.isLoading"
|
||||||
></customBtn>
|
></customBtn>
|
||||||
</ZPaging>
|
</ZPaging>
|
||||||
</div>
|
</div>
|
||||||
@ -49,6 +50,10 @@ const dialogueParams = reactive({
|
|||||||
receiver_id: computed(() => dialogueStore.talk.receiver_id),
|
receiver_id: computed(() => dialogueStore.talk.receiver_id),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
isLoading: false, //是否正在加载中
|
||||||
|
})
|
||||||
|
|
||||||
const onProgressFn = (progress, id) => {
|
const onProgressFn = (progress, id) => {
|
||||||
console.log((progress.loaded / progress.total) * 100, 'progress')
|
console.log((progress.loaded / progress.total) * 100, 'progress')
|
||||||
|
|
||||||
@ -69,6 +74,7 @@ const editAvatar = () => {
|
|||||||
count: 1,
|
count: 1,
|
||||||
success: async (res) => {
|
success: async (res) => {
|
||||||
console.log(res, 'res')
|
console.log(res, 'res')
|
||||||
|
state.isLoading = true
|
||||||
res.tempFiles.forEach(async (file) => {
|
res.tempFiles.forEach(async (file) => {
|
||||||
console.log(file)
|
console.log(file)
|
||||||
let image = new Image()
|
let image = new Image()
|
||||||
@ -93,6 +99,7 @@ const editAvatar = () => {
|
|||||||
const resp = ServeEditGroup(params)
|
const resp = ServeEditGroup(params)
|
||||||
resp.then(({ code }) => {
|
resp.then(({ code }) => {
|
||||||
if (code == 200) {
|
if (code == 200) {
|
||||||
|
state.isLoading = false
|
||||||
groupStore.updateGroupInfo({
|
groupStore.updateGroupInfo({
|
||||||
avatar: data.ori_url,
|
avatar: data.ori_url,
|
||||||
})
|
})
|
||||||
@ -100,13 +107,18 @@ const editAvatar = () => {
|
|||||||
// delta: 1,
|
// delta: 1,
|
||||||
// })
|
// })
|
||||||
} else {
|
} else {
|
||||||
|
state.isLoading = false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
resp.catch(() => {})
|
resp.catch(() => {
|
||||||
|
state.isLoading = false})
|
||||||
} else {
|
} else {
|
||||||
|
state.isLoading = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
).catch(() => {
|
||||||
|
state.isLoading = false
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|||||||
@ -29,10 +29,13 @@
|
|||||||
:placeholder="$t('edit.groupName.placeholder')"
|
:placeholder="$t('edit.groupName.placeholder')"
|
||||||
placeholder-style="color:#B4B4B4;font-size:28rpx;font-weight:500;line-height:40rpx;"
|
placeholder-style="color:#B4B4B4;font-size:28rpx;font-weight:500;line-height:40rpx;"
|
||||||
v-model="state.groupName"
|
v-model="state.groupName"
|
||||||
|
@input="handleGroupNameInput"
|
||||||
|
maxlength="20"
|
||||||
/>
|
/>
|
||||||
<img
|
<img
|
||||||
|
v-if="state.groupName"
|
||||||
class="groupName-input-clearBtn"
|
class="groupName-input-clearBtn"
|
||||||
src="/src/static/image/chatSettings/clear-btn.png"
|
src="@/static/image/chatSettings/clear-btn.png"
|
||||||
@click="clearGroupNameInput"
|
@click="clearGroupNameInput"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -82,7 +85,12 @@ onLoad((options) => {
|
|||||||
const clearGroupNameInput = () => {
|
const clearGroupNameInput = () => {
|
||||||
state.groupName = ''
|
state.groupName = ''
|
||||||
}
|
}
|
||||||
|
const handleGroupNameInput = (e) => {
|
||||||
|
if (state.groupName.length > 20) {
|
||||||
|
// 截取前20个字符
|
||||||
|
state.groupName = state.groupName.slice(0, 20)
|
||||||
|
}
|
||||||
|
}
|
||||||
//点击确认修改
|
//点击确认修改
|
||||||
const confirmEdit = () => {
|
const confirmEdit = () => {
|
||||||
console.log(state.groupName)
|
console.log(state.groupName)
|
||||||
@ -146,7 +154,7 @@ const confirmEdit = () => {
|
|||||||
height: 110rpx;
|
height: 110rpx;
|
||||||
box-shadow: 0 6px 12px 2px rgba(188, 188, 188, 0.08);
|
box-shadow: 0 6px 12px 2px rgba(188, 188, 188, 0.08);
|
||||||
padding: 0 74rpx 0 32rpx;
|
padding: 0 74rpx 0 32rpx;
|
||||||
color: #B747474;
|
color: #747474;
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
line-height: 40rpx;
|
line-height: 40rpx;
|
||||||
|
|||||||
@ -46,7 +46,7 @@
|
|||||||
<div class="group-admin-list-each-btns">
|
<div class="group-admin-list-each-btns">
|
||||||
<img
|
<img
|
||||||
v-if="item.is_mine"
|
v-if="item.is_mine"
|
||||||
src="/src/static/image/chatSettings/is-mine.png"
|
src="@/static/image/chatSettings/is-mine.png"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
class="group-admin-list-each-btns-each"
|
class="group-admin-list-each-btns-each"
|
||||||
@ -67,7 +67,7 @@
|
|||||||
margin: state?.groupAdminList.length == 0 ? '20rpx 0 0' : '',
|
margin: state?.groupAdminList.length == 0 ? '20rpx 0 0' : '',
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<img src="/src/static/image/chatSettings/add-btn.png" />
|
<img src="@/static/image/chatSettings/add-btn.png" />
|
||||||
<span class="text-[28rpx] font-medium">
|
<span class="text-[28rpx] font-medium">
|
||||||
{{ $t('chat.manage.addAdmin') }}
|
{{ $t('chat.manage.addAdmin') }}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
76
src/pages/chatSettings/groupManage/manageGroupDeps.vue
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
<template>
|
||||||
|
<div class="outer-layer manage-group-deps-page">
|
||||||
|
<div class="root">
|
||||||
|
<ZPaging
|
||||||
|
ref="zPaging"
|
||||||
|
:show-scrollbar="false"
|
||||||
|
:use-virtual-list="true"
|
||||||
|
:virtual-list-col="5"
|
||||||
|
:auto="false"
|
||||||
|
:refresher-enabled="false"
|
||||||
|
:loading-more-enabled="false"
|
||||||
|
>
|
||||||
|
<template #top>
|
||||||
|
<customNavbar :title="$t('pageTitle.view.deps')"></customNavbar>
|
||||||
|
</template>
|
||||||
|
<div class="group-deps-list">
|
||||||
|
<div
|
||||||
|
class="group-deps-list-each"
|
||||||
|
v-for="item in groupParams.groupInfo.deptInfos"
|
||||||
|
:key="item.dept_id"
|
||||||
|
>
|
||||||
|
<span>{{ item.dept_name }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ZPaging>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import settingFormItem from '../components/settingFormItem.vue'
|
||||||
|
import ZPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
|
||||||
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
|
import { computed, onMounted, reactive } from 'vue'
|
||||||
|
|
||||||
|
import { useGroupStore } from '@/store'
|
||||||
|
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
const groupStore = useGroupStore()
|
||||||
|
const groupParams = reactive({
|
||||||
|
groupInfo: computed(() => groupStore.groupInfo),
|
||||||
|
})
|
||||||
|
|
||||||
|
const state = reactive({})
|
||||||
|
|
||||||
|
onLoad((options) => {
|
||||||
|
console.log(options)
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
console.log(groupParams.groupInfo.deptInfos)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.outer-layer {
|
||||||
|
flex: 1;
|
||||||
|
background-image: url('@/static/image/clockIn/z3280@3x.png');
|
||||||
|
background-size: cover;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
.group-deps-list {
|
||||||
|
margin: 20rpx 32rpx;
|
||||||
|
background-color: #fff;
|
||||||
|
.group-deps-list-each {
|
||||||
|
padding: 34rpx 32rpx;
|
||||||
|
border-bottom: 1px solid $theme-border-color;
|
||||||
|
span {
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333;
|
||||||
|
line-height: 40rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -42,7 +42,7 @@
|
|||||||
class="add-silence-member-btn chat-settings-card"
|
class="add-silence-member-btn chat-settings-card"
|
||||||
@click="toSelectMembersPage"
|
@click="toSelectMembersPage"
|
||||||
>
|
>
|
||||||
<img src="/src/static/image/chatSettings/add-btn.png" />
|
<img src="@/static/image/chatSettings/add-btn.png" />
|
||||||
<span class="text-[28rpx] font-medium">
|
<span class="text-[28rpx] font-medium">
|
||||||
{{ $t('chat.manage.addSilenceMember') }}
|
{{ $t('chat.manage.addSilenceMember') }}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #right>
|
<template #right v-if="state.isManager === 'true'">
|
||||||
<div
|
<div
|
||||||
v-if="state.editMode !== 3"
|
v-if="state.editMode !== 3"
|
||||||
class="nav-bar-done-btn"
|
class="nav-bar-done-btn"
|
||||||
@ -39,7 +39,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<div class="notice-text-area">
|
<div class="notice-text-area">
|
||||||
<div class="notice-view-area">
|
<div class="notice-view-area">
|
||||||
<div class="notice-view-info" v-if="state.editMode !== 1">
|
<div class="notice-view-info" v-if="state.editMode !== 1 && state?.groupNoticeObj?.content">
|
||||||
<div class="notice-creater-avatar">
|
<div class="notice-creater-avatar">
|
||||||
<img :src="state?.groupNoticeObj?.avatar" />
|
<img :src="state?.groupNoticeObj?.avatar" />
|
||||||
</div>
|
</div>
|
||||||
@ -53,9 +53,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="notice-view-content" v-if="state.editMode === 3">
|
<div class="notice-view-content" v-if="state.editMode === 3">
|
||||||
<span class="text-[32rpx] font-regular">
|
<span class="text-[32rpx] font-regular" v-if="state?.groupNoticeObj?.content">
|
||||||
{{ state?.groupNoticeObj?.content }}
|
{{ state?.groupNoticeObj?.content }}
|
||||||
</span>
|
</span>
|
||||||
|
<span class="text-[32rpx] font-regular color-[#898989]" v-else>
|
||||||
|
{{ $t('groupNotice.notice.empty') }}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<wd-textarea
|
<wd-textarea
|
||||||
size="large"
|
size="large"
|
||||||
@ -77,6 +80,7 @@ import useConfirm from '@/components/x-confirm/useConfirm.js'
|
|||||||
import ZPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
|
import ZPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
|
||||||
import { reactive, computed, onMounted } from 'vue'
|
import { reactive, computed, onMounted } from 'vue'
|
||||||
import { useGroupStore, useDialogueStore } from '@/store'
|
import { useGroupStore, useDialogueStore } from '@/store'
|
||||||
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
import {
|
import {
|
||||||
ServeEditGroupNotice,
|
ServeEditGroupNotice,
|
||||||
ServeDeleteGroupNotice,
|
ServeDeleteGroupNotice,
|
||||||
@ -98,7 +102,8 @@ const state = reactive({
|
|||||||
groupNoticeObj: null, //群公告信息
|
groupNoticeObj: null, //群公告信息
|
||||||
groupNotice: '', //群公告
|
groupNotice: '', //群公告
|
||||||
canDoComplete: false, //是否可以点击完成按钮
|
canDoComplete: false, //是否可以点击完成按钮
|
||||||
editMode: 1, // 1:新增;2:修改;3:查看
|
editMode: 3, // 1:新增;2:修改;3:查看
|
||||||
|
isManager: 'false', //是否是群管理员
|
||||||
})
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@ -107,6 +112,14 @@ onMounted(() => {
|
|||||||
state.editMode = 3
|
state.editMode = 3
|
||||||
state.groupNoticeObj = groupParams.groupNotice[0]
|
state.groupNoticeObj = groupParams.groupNotice[0]
|
||||||
inputGroupNotice(groupParams?.groupNotice[0]?.content)
|
inputGroupNotice(groupParams?.groupNotice[0]?.content)
|
||||||
|
} else if( state.isManager === 'true'){
|
||||||
|
state.editMode = 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
onLoad((options) => {
|
||||||
|
console.log(options)
|
||||||
|
if (options?.is_manager) {
|
||||||
|
state.isManager = options?.is_manager
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -11,145 +11,19 @@
|
|||||||
@scroll="onScroll"
|
@scroll="onScroll"
|
||||||
>
|
>
|
||||||
<template #top>
|
<template #top>
|
||||||
<customNavbar :title="pageTitle" id="topArea"></customNavbar>
|
<div id="topArea">
|
||||||
|
<customNavbar :title="pageTitle"></customNavbar>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div class="select-members">
|
<selectMemberByAlphabet
|
||||||
<div
|
|
||||||
class="search-member"
|
|
||||||
v-if="state.manageType !== 'removeMembers'"
|
|
||||||
>
|
|
||||||
<customInput
|
|
||||||
:searchText="state.searchText"
|
|
||||||
@inputSearchText="inputSearchText"
|
|
||||||
></customInput>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="member-list"
|
|
||||||
:style="{
|
|
||||||
padding: state.manageType === 'searchRecord' ? '20rpx 0 0' : '',
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<div class="member-list-alphabet-anchor-point">
|
|
||||||
<div
|
|
||||||
class="member-list-alphabet-anchor-point-each"
|
|
||||||
v-for="(alphabetItem, alphabetIndex) in state?.alphabet"
|
|
||||||
:key="alphabetIndex"
|
|
||||||
:style="{
|
|
||||||
margin: state?.alphabet?.length > 17 ? '0' : '',
|
|
||||||
}"
|
|
||||||
@click.stop="scrollToView(alphabetItem)"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
class="text-[32rpx] font-regular"
|
|
||||||
:style="{
|
|
||||||
color:
|
|
||||||
state.currentAlphabet === alphabetItem ? '#7A58DE' : '',
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
{{ alphabetItem }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="member-list-alphabet"
|
|
||||||
v-for="(alphabetItem, alphabetIndex) in state.resultMemberList"
|
|
||||||
:key="alphabetIndex"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="member-list-alphabet-key"
|
|
||||||
:style="{
|
|
||||||
padding:
|
|
||||||
state.manageType === 'searchRecord' ||
|
|
||||||
state.manageType === 'removeMembers'
|
|
||||||
? '10rpx 30rpx'
|
|
||||||
: '',
|
|
||||||
}"
|
|
||||||
v-if="alphabetItem?.memberList?.length > 0"
|
|
||||||
:id="alphabetItem.key"
|
|
||||||
:ref="
|
|
||||||
(el) => {
|
|
||||||
if (el) alphabetElementRefs[alphabetIndex] = el
|
|
||||||
}
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<span class="text-[32rpx] font-regular">
|
|
||||||
{{ alphabetItem.key }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div v-if="alphabetItem?.memberList?.length > 0">
|
|
||||||
<div
|
|
||||||
class="member-list-each"
|
|
||||||
v-for="(item, index) in alphabetItem?.memberList"
|
|
||||||
:key="index"
|
|
||||||
>
|
|
||||||
<tm-checkbox-group v-model="item.checkArr">
|
|
||||||
<selectMemberItem
|
|
||||||
:groupType="groupParams.groupInfo.group_type"
|
|
||||||
:memberItem="item"
|
|
||||||
@clickItem="handleClickItem(item)"
|
|
||||||
:manageType="state.manageType"
|
:manageType="state.manageType"
|
||||||
:itemStyle="
|
:isCreateDepGroup="state.isCreateDepGroup"
|
||||||
state.manageType === 'searchRecord' ||
|
ref="selectMemberByAlphabetRef"
|
||||||
state.manageType === 'removeMembers'
|
:selectAreaHeight="state.selectAreaHeight"
|
||||||
? 'list'
|
@updateSelectedMembersNum="updateSelectedMembersNum"
|
||||||
: 'card'
|
></selectMemberByAlphabet>
|
||||||
"
|
|
||||||
>
|
|
||||||
<template
|
|
||||||
#left
|
|
||||||
v-if="state.manageType !== 'searchRecord'"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-if="
|
|
||||||
state.manageType === 'removeMembers' &&
|
|
||||||
item?.is_mine
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<tm-checkbox
|
|
||||||
color="#fff"
|
|
||||||
:transprent="true"
|
|
||||||
:border="0"
|
|
||||||
:disabled="true"
|
|
||||||
></tm-checkbox>
|
|
||||||
</div>
|
|
||||||
<tm-checkbox
|
|
||||||
v-if="
|
|
||||||
!(
|
|
||||||
state.manageType === 'removeMembers' &&
|
|
||||||
item?.is_mine
|
|
||||||
)
|
|
||||||
"
|
|
||||||
:round="10"
|
|
||||||
:color="
|
|
||||||
item?.checkArr?.length > 0 ? '#46299d' : '#B4B4B4'
|
|
||||||
"
|
|
||||||
:outlined="
|
|
||||||
item?.checkArr?.length > 0 ||
|
|
||||||
(state.manageType === 'silence' &&
|
|
||||||
item.is_mute === 1) ||
|
|
||||||
(state.manageType === 'admin' &&
|
|
||||||
(item.leader === 1 || item.leader === 2))
|
|
||||||
? false
|
|
||||||
: true
|
|
||||||
"
|
|
||||||
:value="item.id"
|
|
||||||
:disabled="
|
|
||||||
(state.manageType === 'silence' &&
|
|
||||||
item.is_mute === 1) ||
|
|
||||||
(state.manageType === 'admin' &&
|
|
||||||
(item.leader === 1 || item.leader === 2))
|
|
||||||
"
|
|
||||||
@change="checkBoxChange"
|
|
||||||
></tm-checkbox>
|
|
||||||
</template>
|
|
||||||
</selectMemberItem>
|
|
||||||
</tm-checkbox-group>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<template #bottom v-if="state.manageType !== 'searchRecord'">
|
<template #bottom v-if="state.manageType !== 'searchRecord'">
|
||||||
|
<div id="footArea">
|
||||||
<customBtn
|
<customBtn
|
||||||
v-if="state.manageType !== 'removeMembers'"
|
v-if="state.manageType !== 'removeMembers'"
|
||||||
:isBottom="true"
|
:isBottom="true"
|
||||||
@ -176,126 +50,70 @@
|
|||||||
:disabled="state.selectedMembersNum == 0 ? true : false"
|
:disabled="state.selectedMembersNum == 0 ? true : false"
|
||||||
></customBtn>
|
></customBtn>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</ZPaging>
|
</ZPaging>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import customInput from '@/components/custom-input/custom-input.vue'
|
import selectMemberByAlphabet from '../components/selectMemberByAlphabet.vue'
|
||||||
import selectMemberItem from '../components/select-member-item.vue'
|
|
||||||
import customBtn from '@/components/custom-btn/custom-btn.vue'
|
import customBtn from '@/components/custom-btn/custom-btn.vue'
|
||||||
import ZPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
|
import ZPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
|
||||||
import useZPaging from '@/uni_modules/z-paging/components/z-paging/js/hooks/useZPaging.js'
|
import useZPaging from '@/uni_modules/z-paging/components/z-paging/js/hooks/useZPaging.js'
|
||||||
import { computed, onMounted, reactive, ref, watch, nextTick } from 'vue'
|
import { computed, reactive, ref, onMounted, nextTick } from 'vue'
|
||||||
import { onLoad } from '@dcloudio/uni-app'
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
import {
|
|
||||||
ServeGroupNoSpeak,
|
|
||||||
ServeEditGroupAdmin,
|
|
||||||
ServeGroupAssignAdmin,
|
|
||||||
ServeRemoveMembersGroup,
|
|
||||||
} from '@/api/group/index.js'
|
|
||||||
import { useDialogueStore, useGroupStore, useGroupTypeStore } from '@/store'
|
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
const selectMemberByAlphabetRef = ref(null)
|
||||||
|
|
||||||
const zPaging = ref()
|
const zPaging = ref()
|
||||||
useZPaging(zPaging)
|
useZPaging(zPaging)
|
||||||
|
|
||||||
const groupStore = useGroupStore()
|
|
||||||
const groupParams = reactive({
|
|
||||||
groupInfo: computed(() => groupStore.groupInfo),
|
|
||||||
})
|
|
||||||
|
|
||||||
const groupTypeStore = useGroupTypeStore()
|
|
||||||
const groupTypeParams = reactive({
|
|
||||||
departmentAllPositions: computed(() => groupTypeStore.departmentAllPositions),
|
|
||||||
})
|
|
||||||
|
|
||||||
const dialogueStore = useDialogueStore()
|
|
||||||
const dialogueParams = reactive({
|
|
||||||
memberList: computed(() => {
|
|
||||||
const lowerCaseSearchText = state?.searchText.toLowerCase()
|
|
||||||
return dialogueStore.members.filter((item) =>
|
|
||||||
state?.searchText
|
|
||||||
? item.nickname.toLowerCase().includes(lowerCaseSearchText)
|
|
||||||
: true,
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
receiverId: computed(() => dialogueStore.talk.receiver_id),
|
|
||||||
})
|
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
searchText: '', //搜索内容
|
|
||||||
manageType: '', //管理类型
|
manageType: '', //管理类型
|
||||||
alphabet: [], //A-Z列表
|
|
||||||
resultMemberList: [], //按A-Z整理后的人员列表
|
|
||||||
currentAlphabet: 'A', //当前A-Z位置
|
|
||||||
scrollDirection: '', //当前列表滚动方向
|
|
||||||
isAssign: false, //是否指定view
|
|
||||||
selectedMembersNum: 0, //当前选中数量
|
selectedMembersNum: 0, //当前选中数量
|
||||||
isCreateDepGroup: 0, //是否是创建部门群
|
isCreateDepGroup: 0, //是否是创建部门群
|
||||||
|
selectAreaHeight: 0, //选择区域高度
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(
|
|
||||||
() => dialogueParams?.memberList,
|
|
||||||
(newMemberList) => {
|
|
||||||
assembleAlphabetMemberList(newMemberList)
|
|
||||||
},
|
|
||||||
{ deep: true },
|
|
||||||
)
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => groupParams?.groupInfo,
|
|
||||||
(newGroupInfo) => {
|
|
||||||
assembleAlphabetMemberList(dialogueParams?.memberList)
|
|
||||||
},
|
|
||||||
{ deep: true },
|
|
||||||
)
|
|
||||||
|
|
||||||
//获取A-Z tag元素
|
|
||||||
const alphabetElementRefs = ref([])
|
|
||||||
//观察者
|
|
||||||
let observer
|
|
||||||
|
|
||||||
onLoad((options) => {
|
onLoad((options) => {
|
||||||
console.log(options)
|
// console.log(options)
|
||||||
if (options.manageType) {
|
if (options.manageType) {
|
||||||
state.manageType = options.manageType
|
state.manageType = options.manageType
|
||||||
assembleAlphabetMemberList(dialogueParams?.memberList)
|
|
||||||
}
|
}
|
||||||
if (options.isCreateDepGroup) {
|
if (options.isCreateDepGroup) {
|
||||||
state.isCreateDepGroup = Number(options.isCreateDepGroup)
|
state.isCreateDepGroup = Number(options.isCreateDepGroup)
|
||||||
assembleAlphabetMemberList()
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
dialogueParams.memberList.forEach((ele) => {
|
|
||||||
ele.checkArr = []
|
|
||||||
})
|
|
||||||
const options = {
|
|
||||||
root: null, // 使用浏览器窗口作为根容器
|
|
||||||
threshold: 1.0, // 当元素100%离开视口时触发
|
|
||||||
}
|
|
||||||
observer = new IntersectionObserver(handleIntersection, options)
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
watch(
|
let selectAreaHeight = uni.getSystemInfoSync().windowHeight
|
||||||
alphabetElementRefs,
|
// console.log('页面高度:', uni.getSystemInfoSync().windowHeight)
|
||||||
(newAlphabetElementRefs) => {
|
const topAreaQuery = uni.createSelectorQuery()
|
||||||
if (Array.isArray(newAlphabetElementRefs)) {
|
topAreaQuery
|
||||||
newAlphabetElementRefs.forEach((el, index) => {
|
.select('#topArea')
|
||||||
observeElement(el, index)
|
.boundingClientRect((res) => {
|
||||||
|
if (res) {
|
||||||
|
// console.log('元素高度:', res.height)
|
||||||
|
selectAreaHeight = selectAreaHeight - res.height
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
.exec()
|
||||||
|
const footAreaQuery = uni.createSelectorQuery()
|
||||||
|
footAreaQuery
|
||||||
|
.select('#footArea')
|
||||||
|
.boundingClientRect((res) => {
|
||||||
|
if (res) {
|
||||||
|
// console.log('元素高度:', res.height)
|
||||||
|
selectAreaHeight = selectAreaHeight - res.height
|
||||||
}
|
}
|
||||||
},
|
})
|
||||||
{ immediate: true, deep: true },
|
.exec()
|
||||||
)
|
// console.log(selectAreaHeight)
|
||||||
if (alphabetElementRefs.value.length > 0) {
|
state.selectAreaHeight = selectAreaHeight + 'px'
|
||||||
alphabetElementRefs.value.forEach((el, index) =>
|
|
||||||
observeElement(el, index),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -314,341 +132,16 @@ const pageTitle = computed(() => {
|
|||||||
return page_title
|
return page_title
|
||||||
})
|
})
|
||||||
|
|
||||||
// 观察者函数
|
//确认
|
||||||
const handleIntersection = (entries) => {
|
|
||||||
if (state.isAssign) {
|
|
||||||
state.isAssign = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
entries.forEach((entry) => {
|
|
||||||
if (!entry.isIntersecting && state.scrollDirection === 'down') {
|
|
||||||
state.currentAlphabet = entry.target.id
|
|
||||||
} else if (entry.isIntersecting && state.scrollDirection === 'up') {
|
|
||||||
if (state?.alphabet?.length > 1) {
|
|
||||||
state?.alphabet.forEach((item, index) => {
|
|
||||||
if (item === entry.target.id && index > 0) {
|
|
||||||
state.currentAlphabet = state?.alphabet[index - 1]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
state.currentAlphabet = entry.target.id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
//观察元素
|
|
||||||
const observeElement = (el, index) => {
|
|
||||||
if (el && observer) {
|
|
||||||
observer.observe(el)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//输入搜索文本
|
|
||||||
const inputSearchText = (e) => {
|
|
||||||
// console.log(e)
|
|
||||||
state.searchText = e
|
|
||||||
}
|
|
||||||
|
|
||||||
//点击item
|
|
||||||
const handleClickItem = (item) => {
|
|
||||||
if (
|
|
||||||
(state.manageType === 'silence' && item.is_mute === 1) ||
|
|
||||||
(state.manageType === 'admin' &&
|
|
||||||
(item.leader === 1 || item.leader === 2)) ||
|
|
||||||
(state.manageType === 'removeMembers' && item.is_mine)
|
|
||||||
) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let itemList = dialogueParams.memberList
|
|
||||||
if (
|
|
||||||
state.manageType === 'admin' &&
|
|
||||||
(groupParams.groupInfo.group_type == 2 ||
|
|
||||||
groupParams.groupInfo.group_type == 4 ||
|
|
||||||
state.isCreateDepGroup === 1)
|
|
||||||
) {
|
|
||||||
itemList = state.resultMemberList[0].memberList
|
|
||||||
}
|
|
||||||
itemList.forEach((ele) => {
|
|
||||||
if (ele.id == item.id) {
|
|
||||||
ele.checkArr = ele.checkArr?.length > 0 ? [] : [item.id]
|
|
||||||
if (ele.checkArr?.length > 0) {
|
|
||||||
state.selectedMembersNum += 1
|
|
||||||
} else {
|
|
||||||
state.selectedMembersNum -= 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
//点击确认选择的成员
|
|
||||||
const confirmSelectMembers = () => {
|
const confirmSelectMembers = () => {
|
||||||
let selectedUserIds = ''
|
if (selectMemberByAlphabetRef.value) {
|
||||||
let itemList = dialogueParams.memberList
|
selectMemberByAlphabetRef.value.confirmSelectMembers()
|
||||||
let positionInfos = []
|
|
||||||
if (
|
|
||||||
state.manageType === 'admin' &&
|
|
||||||
(groupParams.groupInfo.group_type == 2 ||
|
|
||||||
groupParams.groupInfo.group_type == 4 ||
|
|
||||||
state.isCreateDepGroup === 1)
|
|
||||||
) {
|
|
||||||
itemList = state.resultMemberList[0].memberList
|
|
||||||
}
|
|
||||||
itemList.forEach((ele) => {
|
|
||||||
if (ele.checkArr?.length > 0) {
|
|
||||||
if (!selectedUserIds) {
|
|
||||||
selectedUserIds = String(ele.checkArr[0])
|
|
||||||
} else {
|
|
||||||
selectedUserIds += ',' + ele.checkArr[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
ele.checkArr?.length > 0 ||
|
|
||||||
(ele.leader && (ele.leader == 1 || ele.leader == 2))
|
|
||||||
) {
|
|
||||||
if (state.isCreateDepGroup === 1) {
|
|
||||||
let posInfo = Object.assign({}, ele.positionInfo, {
|
|
||||||
name: ele.nickname,
|
|
||||||
id: ele.id,
|
|
||||||
})
|
|
||||||
positionInfos.push(posInfo)
|
|
||||||
} else {
|
|
||||||
positionInfos.push(ele.positionInfo)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
console.log(selectedUserIds)
|
|
||||||
if (selectedUserIds) {
|
|
||||||
if (state.manageType === 'silence') {
|
|
||||||
let params = {
|
|
||||||
mode: 1, //1禁言2解禁
|
|
||||||
group_id: dialogueParams.receiverId, //群id
|
|
||||||
user_ids: selectedUserIds, //用户ids
|
|
||||||
}
|
|
||||||
console.log(params)
|
|
||||||
const resp = ServeGroupNoSpeak(params)
|
|
||||||
resp.then(({ code, data }) => {
|
|
||||||
console.log(data)
|
|
||||||
if (code == 200) {
|
|
||||||
useDialogueStore().updateGroupMembers()
|
|
||||||
} else {
|
|
||||||
}
|
|
||||||
})
|
|
||||||
resp.catch(() => {})
|
|
||||||
} else if (state.manageType === 'admin') {
|
|
||||||
if (state.isCreateDepGroup === 1) {
|
|
||||||
// console.log(positionInfos)
|
|
||||||
groupTypeStore.groupAdmins.value = positionInfos
|
|
||||||
uni.navigateBack({
|
|
||||||
delta: 1,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
if (
|
|
||||||
groupParams.groupInfo.group_type == 1 ||
|
|
||||||
groupParams.groupInfo.group_type == 3
|
|
||||||
) {
|
|
||||||
let params = {
|
|
||||||
mode: 1, //1管理员,2不是管理员
|
|
||||||
group_id: dialogueParams.receiverId, //群id
|
|
||||||
user_ids: selectedUserIds,
|
|
||||||
}
|
|
||||||
console.log(params)
|
|
||||||
const resp = ServeGroupAssignAdmin(params)
|
|
||||||
resp.then(({ code, data }) => {
|
|
||||||
console.log(data)
|
|
||||||
if (code == 200) {
|
|
||||||
useDialogueStore().updateGroupMembers()
|
|
||||||
} else {
|
|
||||||
}
|
|
||||||
})
|
|
||||||
resp.catch(() => {})
|
|
||||||
} else if (
|
|
||||||
groupParams.groupInfo.group_type == 2 ||
|
|
||||||
groupParams.groupInfo.group_type == 4
|
|
||||||
) {
|
|
||||||
let params = {
|
|
||||||
source: 'app',
|
|
||||||
id: dialogueParams.receiverId,
|
|
||||||
deptInfos: groupParams.groupInfo.deptInfos,
|
|
||||||
positionInfos: positionInfos,
|
|
||||||
}
|
|
||||||
console.log(params)
|
|
||||||
const resp = ServeEditGroupAdmin(params)
|
|
||||||
resp.then(({ code, data }) => {
|
|
||||||
console.log(data)
|
|
||||||
if (code == 200) {
|
|
||||||
groupStore.ServeGroupDetail()
|
|
||||||
} else {
|
|
||||||
}
|
|
||||||
})
|
|
||||||
resp.catch(() => {})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (state.manageType === 'removeMembers') {
|
|
||||||
let params = {
|
|
||||||
group_id: dialogueParams.receiverId, //群id
|
|
||||||
members_ids: selectedUserIds, //群成员id,批量的话逗号分割
|
|
||||||
}
|
|
||||||
console.log(params)
|
|
||||||
const resp = ServeRemoveMembersGroup(params)
|
|
||||||
resp.then(({ code, data }) => {
|
|
||||||
console.log(data)
|
|
||||||
if (code == 200) {
|
|
||||||
useDialogueStore().updateGroupMembers()
|
|
||||||
groupStore.ServeGroupDetail()
|
|
||||||
} else {
|
|
||||||
}
|
|
||||||
})
|
|
||||||
resp.catch(() => {})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//组装A-Z排序的人员列表
|
//更新选中的人数
|
||||||
const assembleAlphabetMemberList = async (newMemberList) => {
|
const updateSelectedMembersNum = (numChange) => {
|
||||||
if (
|
state.selectedMembersNum = state.selectedMembersNum + numChange
|
||||||
state.manageType === 'searchRecord' ||
|
|
||||||
state.manageType === 'removeMembers'
|
|
||||||
) {
|
|
||||||
const resultMemberList = ref([])
|
|
||||||
const alphabet = Array.from({ length: 26 }, (_, i) =>
|
|
||||||
String.fromCharCode(i + 65),
|
|
||||||
)
|
|
||||||
let tempAlphabet = []
|
|
||||||
alphabet.forEach((letter) => {
|
|
||||||
const matchedItems = newMemberList.filter((item) => item.key === letter)
|
|
||||||
if (matchedItems.length > 0) {
|
|
||||||
tempAlphabet.push(letter)
|
|
||||||
}
|
|
||||||
resultMemberList.value.push({
|
|
||||||
key: letter,
|
|
||||||
memberList: matchedItems.length ? matchedItems : [],
|
|
||||||
})
|
|
||||||
})
|
|
||||||
state.alphabet = tempAlphabet
|
|
||||||
state.resultMemberList = resultMemberList
|
|
||||||
} else {
|
|
||||||
if (
|
|
||||||
(groupParams.groupInfo.group_type == 2 ||
|
|
||||||
groupParams.groupInfo.group_type == 4) &&
|
|
||||||
state.manageType === 'admin'
|
|
||||||
) {
|
|
||||||
let departmentIdsArr = []
|
|
||||||
if (groupParams?.groupInfo?.deptInfos?.length > 0) {
|
|
||||||
groupParams.groupInfo.deptInfos.forEach((item) => {
|
|
||||||
departmentIdsArr.push(item.dept_id)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
getPosiByDep(departmentIdsArr)
|
|
||||||
} else if (state.isCreateDepGroup === 1) {
|
|
||||||
let departmentIdsArr = []
|
|
||||||
if (groupTypeStore?.depCheckedKeys?.value?.length > 0) {
|
|
||||||
groupTypeStore.depCheckedKeys.value.forEach((item) => {
|
|
||||||
departmentIdsArr.push(item.ID)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
getPosiByDep(departmentIdsArr)
|
|
||||||
} else {
|
|
||||||
state.resultMemberList = [
|
|
||||||
{
|
|
||||||
key: '',
|
|
||||||
memberList: newMemberList,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const getPosiByDep = async (departmentIdsArr) => {
|
|
||||||
await groupTypeStore.getPositionByDepartment({
|
|
||||||
IDs: departmentIdsArr,
|
|
||||||
})
|
|
||||||
let departmentAllPositions = []
|
|
||||||
if (groupTypeParams?.departmentAllPositions?.value?.length > 0) {
|
|
||||||
groupTypeParams?.departmentAllPositions?.value?.forEach((item) => {
|
|
||||||
item?.AllPositions?.forEach((positionItem) => {
|
|
||||||
departmentAllPositions.push({
|
|
||||||
nickname: item.name + '-' + positionItem.name,
|
|
||||||
id: item.ID + '-' + positionItem.ID,
|
|
||||||
checkArr: [],
|
|
||||||
positionInfo: {
|
|
||||||
dept_id: item.ID,
|
|
||||||
dept_name: item.name,
|
|
||||||
position_id: positionItem.ID,
|
|
||||||
position_name: positionItem.name,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (groupParams?.groupInfo?.groupAdminList?.length > 0) {
|
|
||||||
groupParams?.groupInfo?.groupAdminList.forEach((item) => {
|
|
||||||
departmentAllPositions.forEach((idsItem) => {
|
|
||||||
if (item.dept_id + '-' + item.position_id == idsItem.id) {
|
|
||||||
idsItem.leader = 1
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
state.isCreateDepGroup === 1 &&
|
|
||||||
groupTypeStore?.groupAdmins?.value?.length > 0
|
|
||||||
) {
|
|
||||||
departmentAllPositions.forEach((allPos) => {
|
|
||||||
groupTypeStore.groupAdmins.value.forEach((admin) => {
|
|
||||||
if (allPos.id === admin.id) {
|
|
||||||
allPos.checkArr = [allPos.id]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if(state?.searchText){
|
|
||||||
const lowerCaseSearchText = state?.searchText.toLowerCase()
|
|
||||||
departmentAllPositions = departmentAllPositions.filter((item) =>
|
|
||||||
state?.searchText
|
|
||||||
? item.nickname.toLowerCase().includes(lowerCaseSearchText)
|
|
||||||
: true,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
state.resultMemberList = [
|
|
||||||
{
|
|
||||||
key: '',
|
|
||||||
memberList: departmentAllPositions,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
//滚动到指定的view
|
|
||||||
const scrollToView = (alphabet) => {
|
|
||||||
state.currentAlphabet = alphabet
|
|
||||||
state.isAssign = true
|
|
||||||
console.log()
|
|
||||||
zPaging.value?.scrollIntoViewById(
|
|
||||||
alphabet,
|
|
||||||
document.getElementById('topArea').clientHeight
|
|
||||||
? document.getElementById('topArea').clientHeight - 1
|
|
||||||
: 80,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
//监听列表滚动
|
|
||||||
const onScroll = (e) => {
|
|
||||||
if (e.detail.deltaY < 0) {
|
|
||||||
state.scrollDirection = 'down'
|
|
||||||
} else if (e.detail.deltaY > 0) {
|
|
||||||
state.scrollDirection = 'up'
|
|
||||||
} else {
|
|
||||||
state.scrollDirection = ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//选中的人员改变
|
|
||||||
const checkBoxChange = (e) => {
|
|
||||||
if (e) {
|
|
||||||
state.selectedMembersNum += 1
|
|
||||||
} else {
|
|
||||||
state.selectedMembersNum -= 1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@ -659,48 +152,6 @@ const checkBoxChange = (e) => {
|
|||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
.select-members {
|
|
||||||
padding: 20rpx 32rpx;
|
|
||||||
.search-member {
|
|
||||||
padding: 22rpx 16rpx;
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
.member-list {
|
|
||||||
.member-list-alphabet-anchor-point {
|
|
||||||
position: fixed;
|
|
||||||
right: 32rpx;
|
|
||||||
top: 0;
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
.member-list-alphabet-anchor-point-each {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
margin: 0 0 14rpx;
|
|
||||||
span {
|
|
||||||
width: 52rpx;
|
|
||||||
text-align: center;
|
|
||||||
line-height: 44rpx;
|
|
||||||
color: $theme-text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.member-list-alphabet {
|
|
||||||
.member-list-alphabet-key {
|
|
||||||
background-color: #f3f3f3;
|
|
||||||
span {
|
|
||||||
line-height: 44rpx;
|
|
||||||
color: $theme-text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.confirm-btn-area {
|
.confirm-btn-area {
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
padding: 14rpx 32rpx 72rpx;
|
padding: 14rpx 32rpx 72rpx;
|
||||||
|
|||||||
@ -6,71 +6,42 @@
|
|||||||
<customNavbar :title="$t('index.chat.settings')"></customNavbar>
|
<customNavbar :title="$t('index.chat.settings')"></customNavbar>
|
||||||
</template>
|
</template>
|
||||||
<div class="chat-settings">
|
<div class="chat-settings">
|
||||||
<div
|
<div class="chat-group-base-infos chat-settings-card" v-if="dialogueParams.type === 2">
|
||||||
class="chat-group-base-infos chat-settings-card"
|
|
||||||
v-if="dialogueParams.type === 2"
|
|
||||||
>
|
|
||||||
<div class="base-info-avatar" @click="toEditAvatarPage">
|
<div class="base-info-avatar" @click="toEditAvatarPage">
|
||||||
<avatarModule
|
<avatarModule :mode="2" :avatar="groupParams?.groupInfo?.avatar"
|
||||||
:mode="2"
|
:groupType="groupParams?.groupInfo?.group_type" :customStyle="{ width: '96rpx', height: '96rpx' }">
|
||||||
:avatar="groupParams?.groupInfo?.avatar"
|
</avatarModule>
|
||||||
:groupType="groupParams?.groupInfo?.group_type"
|
|
||||||
:customStyle="{ width: '96rpx', height: '96rpx' }"
|
|
||||||
></avatarModule>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="base-info">
|
<div class="base-info">
|
||||||
<div class="base-info-name">
|
<div class="base-info-name">
|
||||||
<span class="text-[32rpx] font-medium">{{ groupName }}</span>
|
<span class="text-[32rpx] font-medium">{{ groupName }}</span>
|
||||||
<span
|
<span class="base-info_num text-[32rpx] font-medium" v-if="groupNum">
|
||||||
class="base-info_num text-[32rpx] font-medium"
|
|
||||||
v-if="groupNum"
|
|
||||||
>
|
|
||||||
{{ '(' + groupNum + ')' }}
|
{{ '(' + groupNum + ')' }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div v-if="groupParams?.groupInfo?.group_type !== 1 && groupType" class="base-info-tag" :style="{
|
||||||
v-if="groupParams?.groupInfo?.group_type !== 1 && groupType"
|
|
||||||
class="base-info-tag"
|
|
||||||
:style="{
|
|
||||||
borderColor:
|
borderColor:
|
||||||
groupTypeMapping[groupParams?.groupInfo?.group_type]
|
groupTypeMapping[groupParams?.groupInfo?.group_type]
|
||||||
?.result_type_color,
|
?.result_type_color,
|
||||||
}"
|
}">
|
||||||
>
|
<span class="text-[24rpx] font-medium" :style="{
|
||||||
<span
|
|
||||||
class="text-[24rpx] font-medium"
|
|
||||||
:style="{
|
|
||||||
color:
|
color:
|
||||||
groupTypeMapping[groupParams?.groupInfo?.group_type]
|
groupTypeMapping[groupParams?.groupInfo?.group_type]
|
||||||
?.result_type_color,
|
?.result_type_color,
|
||||||
}"
|
}">
|
||||||
>
|
|
||||||
{{ groupType }}
|
{{ groupType }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div class="base-info-edit" @click="toEditGroupInfoPage" v-if="groupParams?.groupInfo?.is_manager">
|
||||||
class="base-info-edit"
|
<img src="@/static/image/chatSettings/edit-btn.png" />
|
||||||
@click="toEditGroupInfoPage"
|
|
||||||
v-if="groupParams?.groupInfo?.is_manager"
|
|
||||||
>
|
|
||||||
<img src="/src/static/image/chatSettings/edit-btn.png" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="chat-group-members chat-group-infos chat-settings-card">
|
<div class="chat-group-members chat-group-infos chat-settings-card">
|
||||||
<div
|
<div class="chat-group-infos-each" v-for="(item, index) in state.chatGroupMembers" :key="index">
|
||||||
class="chat-group-infos-each"
|
<settingFormItem :item="item" @toManagePage="toManagePage"></settingFormItem>
|
||||||
v-for="(item, index) in state.chatGroupMembers"
|
<groupMemberList :groupType="groupParams?.groupInfo?.group_type"
|
||||||
:key="index"
|
:is_manager="groupParams?.groupInfo?.is_manager" :memberList="dialogueParams?.memberList"
|
||||||
>
|
|
||||||
<settingFormItem
|
|
||||||
:item="item"
|
|
||||||
@toManagePage="toManagePage"
|
|
||||||
></settingFormItem>
|
|
||||||
<groupMemberList
|
|
||||||
:groupType="groupParams?.groupInfo?.group_type"
|
|
||||||
:is_manager="groupParams?.groupInfo?.is_manager"
|
|
||||||
:memberList="dialogueParams?.memberList"
|
|
||||||
:memberListsLimit="
|
:memberListsLimit="
|
||||||
groupParams?.groupInfo?.group_type == 1 ||
|
groupParams?.groupInfo?.group_type == 1 ||
|
||||||
groupParams?.groupInfo?.group_type == 3
|
groupParams?.groupInfo?.group_type == 3
|
||||||
@ -78,93 +49,64 @@
|
|||||||
? 13
|
? 13
|
||||||
: 14
|
: 14
|
||||||
: 15
|
: 15
|
||||||
"
|
"></groupMemberList>
|
||||||
></groupMemberList>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="chat-group-infos chat-settings-card">
|
<div class="chat-group-infos chat-settings-card">
|
||||||
<div
|
<div class="chat-group-infos-each" v-for="(item, index) in state.chatGroupInfos" :key="index">
|
||||||
class="chat-group-infos-each"
|
<settingFormItem :item="item" @toManagePage="toManagePage"
|
||||||
v-for="(item, index) in state.chatGroupInfos"
|
:isManager="groupParams?.groupInfo?.is_manager"></settingFormItem>
|
||||||
:key="index"
|
|
||||||
>
|
|
||||||
<settingFormItem
|
|
||||||
:item="item"
|
|
||||||
@toManagePage="toManagePage"
|
|
||||||
:isManager="groupParams?.groupInfo?.is_manager"
|
|
||||||
></settingFormItem>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="chat-records-search chat-settings-card">
|
<div class="chat-records-search chat-settings-card" v-if="dialogueParams.type !== 1 || (dialogueParams.type === 1 && dialogueParams?.receiver_id !== 2)">
|
||||||
|
<div @click="toSearchPage">
|
||||||
<customInput :disabled="true"></customInput>
|
<customInput :disabled="true"></customInput>
|
||||||
|
</div>
|
||||||
<div class="record-search-types">
|
<div class="record-search-types">
|
||||||
<div
|
<div class="record-search-types-each" v-for="(item, index) in state.recordSearchTypeList" :key="index"
|
||||||
class="record-search-types-each"
|
@click="toSearchByConditionPage(index)">
|
||||||
v-for="(item, index) in state.recordSearchTypeList"
|
|
||||||
:key="index"
|
|
||||||
@click="toSearchByConditionPage(index)"
|
|
||||||
>
|
|
||||||
<img class="record-search-types-icon" :src="item.typeIcon" />
|
<img class="record-search-types-icon" :src="item.typeIcon" />
|
||||||
<span class="text-[24rpx] font-regular">{{ item.value }}</span>
|
<span class="text-[24rpx] font-regular">{{ item.value }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="chat-group-infos chat-settings-card">
|
<div class="chat-group-infos chat-settings-card">
|
||||||
<div
|
<div class="chat-group-infos-each" v-for="(item, index) in state.chatSettings" :key="index">
|
||||||
class="chat-group-infos-each"
|
<settingFormItem :item="item" @toManagePage="toManagePage" :sessionInfo="state?.sessionInfo"
|
||||||
v-for="(item, index) in state.chatSettings"
|
@changeSwitch="changeSwitch"></settingFormItem>
|
||||||
:key="index"
|
|
||||||
>
|
|
||||||
<settingFormItem
|
|
||||||
:item="item"
|
|
||||||
@toManagePage="toManagePage"
|
|
||||||
:sessionInfo="state?.sessionInfo"
|
|
||||||
@changeSwitch="changeSwitch"
|
|
||||||
></settingFormItem>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div class="chat-group-infos chat-settings-card" v-if="groupParams?.groupInfo?.is_manager">
|
||||||
class="chat-group-infos chat-settings-card"
|
<div class="chat-group-infos-each" v-for="(item, index) in state.chatManagement" :key="index">
|
||||||
v-if="groupParams?.groupInfo?.is_manager"
|
<settingFormItem :item="item" @toManagePage="toManagePage"></settingFormItem>
|
||||||
>
|
</div>
|
||||||
<div
|
</div>
|
||||||
class="chat-group-infos-each"
|
<div class="chat-group-infos chat-settings-card" v-if="dialogueParams.type !== 1 || (dialogueParams.type === 1 && dialogueParams?.receiver_id !== 2)">
|
||||||
v-for="(item, index) in state.chatManagement"
|
<div class="chat-group-infos-each" v-for="(item, index) in state.chatReport" :key="index">
|
||||||
:key="index"
|
<settingFormItem :item="item" @toManagePage="toManagePage"></settingFormItem>
|
||||||
>
|
|
||||||
<settingFormItem
|
|
||||||
:item="item"
|
|
||||||
@toManagePage="toManagePage"
|
|
||||||
></settingFormItem>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="clear-chat-record-btn chat-settings-card">
|
<div class="clear-chat-record-btn chat-settings-card">
|
||||||
<div
|
<div @click="showConfirmPrompt(1)" class="clear-chat-record-btn-each">
|
||||||
@click="showConfirmPrompt(1)"
|
|
||||||
class="clear-chat-record-btn-each"
|
|
||||||
>
|
|
||||||
<span class="text-[32rpx] font-regular">
|
<span class="text-[32rpx] font-regular">
|
||||||
{{ $t('chat.settings.clearChatRecord') }}
|
{{ $t('chat.settings.clearChatRecord') }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div @click="showConfirmPrompt(2)" class="clear-chat-record-btn-each" v-if="
|
||||||
@click="showConfirmPrompt(2)"
|
groupParams?.groupInfo?.is_manager &&
|
||||||
class="clear-chat-record-btn-each"
|
dialogueParams.type === 2 &&
|
||||||
v-if="
|
(groupParams?.groupInfo?.group_type === 1 ||
|
||||||
groupParams?.groupInfo?.is_manager && dialogueParams.type === 2
|
groupParams?.groupInfo?.group_type === 3)
|
||||||
"
|
">
|
||||||
>
|
|
||||||
<span class="text-[32rpx] font-regular">
|
<span class="text-[32rpx] font-regular">
|
||||||
{{ $t('group.disband.btn') }}
|
{{ $t('group.disband.btn') }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div @click="showConfirmPrompt(3)" class="clear-chat-record-btn-each" v-if="
|
||||||
@click="showConfirmPrompt(3)"
|
dialogueParams.type === 2 &&
|
||||||
class="clear-chat-record-btn-each"
|
(groupParams?.groupInfo?.group_type === 1 ||
|
||||||
v-if="
|
groupParams?.groupInfo?.group_type === 3)
|
||||||
groupParams?.groupInfo?.is_manager && dialogueParams.type === 2
|
">
|
||||||
"
|
|
||||||
>
|
|
||||||
<span class="text-[32rpx] font-regular">
|
<span class="text-[32rpx] font-regular">
|
||||||
{{ $t('group.quit.btn') }}
|
{{ $t('group.quit.btn') }}
|
||||||
</span>
|
</span>
|
||||||
@ -176,39 +118,56 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import avatarModule from '@/components/avatar-module/index.vue'
|
import avatarModule from '@/components/avatar-module/index.vue'
|
||||||
import useConfirm from '@/components/x-confirm/useConfirm.js'
|
import useConfirm from '@/components/x-confirm/useConfirm.js'
|
||||||
import recordSearchTypeIcon_groupMember from '@/static/image/chatSettings/recordSearchTypeGroupMembers.png'
|
import recordSearchTypeIcon_groupMember from '@/static/image/chatSettings/recordSearchTypeGroupMembers.png'
|
||||||
import recordSearchTypeIcon_date from '@/static/image/chatSettings/recordSearchTypeDate.png'
|
import recordSearchTypeIcon_date from '@/static/image/chatSettings/recordSearchTypeDate.png'
|
||||||
import recordSearchTypeIcon_imgAndVideo from '@/static/image/chatSettings/recordSearchTypeImgAndVideo.png'
|
import recordSearchTypeIcon_imgAndVideo from '@/static/image/chatSettings/recordSearchTypeImgAndVideo.png'
|
||||||
import recordSearchTypeIcon_files from '@/static/image/chatSettings/recordSearchTypeFiles.png'
|
import recordSearchTypeIcon_files from '@/static/image/chatSettings/recordSearchTypeFiles.png'
|
||||||
import recordSearchTypeIcon_link from '@/static/image/chatSettings/recordSearchTypeLink.png'
|
import recordSearchTypeIcon_link from '@/static/image/chatSettings/recordSearchTypeLink.png'
|
||||||
import ZPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
|
import ZPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
|
||||||
import settingFormItem from './components/settingFormItem.vue'
|
import settingFormItem from './components/settingFormItem.vue'
|
||||||
import groupMemberList from './components/groupMembersList.vue'
|
import groupMemberList from './components/groupMembersList.vue'
|
||||||
import { computed, onMounted, reactive, watch } from 'vue'
|
import {
|
||||||
import {
|
computed,
|
||||||
|
onMounted,
|
||||||
|
reactive,
|
||||||
|
watch
|
||||||
|
} from 'vue'
|
||||||
|
import {
|
||||||
useUserStore,
|
useUserStore,
|
||||||
useTalkStore,
|
useTalkStore,
|
||||||
useDialogueStore,
|
useDialogueStore,
|
||||||
useGroupStore,
|
useGroupStore,
|
||||||
useGroupTypeStore,
|
useGroupTypeStore,
|
||||||
} from '@/store'
|
} from '@/store'
|
||||||
import { onLoad } from '@dcloudio/uni-app'
|
import {
|
||||||
import {
|
onLoad
|
||||||
|
} from '@dcloudio/uni-app'
|
||||||
|
import {
|
||||||
ServeInviteGroup,
|
ServeInviteGroup,
|
||||||
ServeDismissGroup,
|
ServeDismissGroup,
|
||||||
ServeSecedeGroup,
|
ServeSecedeGroup,
|
||||||
} from '@/api/group/index'
|
} from '@/api/group/index'
|
||||||
import { ServeTopTalkList, ServeSetNotDisturb } from '@/api/chat/index'
|
import {
|
||||||
import { useI18n } from 'vue-i18n'
|
ServeTopTalkList,
|
||||||
const { t } = useI18n()
|
ServeSetNotDisturb,
|
||||||
import customInput from '@/components/custom-input/custom-input.vue'
|
ServeContactRobotUpdate
|
||||||
const { showConfirm } = useConfirm()
|
} from '@/api/chat/index'
|
||||||
const userStore = useUserStore()
|
import {
|
||||||
const talkStore = useTalkStore()
|
useI18n
|
||||||
const dialogueStore = useDialogueStore()
|
} from 'vue-i18n'
|
||||||
const dialogueParams = reactive({
|
const {
|
||||||
|
t
|
||||||
|
} = useI18n()
|
||||||
|
import customInput from '@/components/custom-input/custom-input.vue'
|
||||||
|
const {
|
||||||
|
showConfirm
|
||||||
|
} = useConfirm()
|
||||||
|
const userStore = useUserStore()
|
||||||
|
const talkStore = useTalkStore()
|
||||||
|
const dialogueStore = useDialogueStore()
|
||||||
|
const dialogueParams = reactive({
|
||||||
uid: computed(() => userStore.uid),
|
uid: computed(() => userStore.uid),
|
||||||
index_name: computed(() => dialogueStore.index_name),
|
index_name: computed(() => dialogueStore.index_name),
|
||||||
type: computed(() => dialogueStore.talk.talk_type),
|
type: computed(() => dialogueStore.talk.talk_type),
|
||||||
@ -218,50 +177,55 @@ const dialogueParams = reactive({
|
|||||||
keyboard: computed(() => dialogueStore.keyboard),
|
keyboard: computed(() => dialogueStore.keyboard),
|
||||||
num: computed(() => dialogueStore.members.length),
|
num: computed(() => dialogueStore.members.length),
|
||||||
memberList: computed(() => dialogueStore.members),
|
memberList: computed(() => dialogueStore.members),
|
||||||
})
|
adminList: computed(() => dialogueStore.getAdminList),
|
||||||
const talkParams = reactive({
|
})
|
||||||
|
const talkParams = reactive({
|
||||||
topItems: computed(() => talkStore.topItems),
|
topItems: computed(() => talkStore.topItems),
|
||||||
disturbItems: computed(() => talkStore.disturbItems),
|
disturbItems: computed(() => talkStore.disturbItems),
|
||||||
})
|
})
|
||||||
const groupStore = useGroupStore()
|
const groupStore = useGroupStore()
|
||||||
const groupParams = reactive({
|
const groupParams = reactive({
|
||||||
groupInfo: computed(() => groupStore.groupInfo),
|
groupInfo: computed(() => groupStore.groupInfo),
|
||||||
groupNotice: computed(() => groupStore.groupNotice),
|
groupNotice: computed(() => groupStore.groupNotice),
|
||||||
})
|
})
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
chatGroupMembers: [], //群成员form-item
|
chatGroupMembers: [], //群成员form-item
|
||||||
chatGroupInfos: [], //群聊信息
|
chatGroupInfos: [], //群聊信息
|
||||||
recordSearchTypeList: [], //聊天记录搜索类型
|
recordSearchTypeList: [], //聊天记录搜索类型
|
||||||
chatSettings: [], //群聊设置
|
chatSettings: [], //群聊设置
|
||||||
chatManagement: [], //群聊管理
|
chatManagement: [], //群聊管理
|
||||||
|
chatReport: [], //聊天举报
|
||||||
groupId: '', //群id
|
groupId: '', //群id
|
||||||
sessionId: '', //会话id
|
sessionId: '', //会话id
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
[() => groupParams.groupInfo, () => groupParams.groupNotice],
|
[() => groupParams.groupInfo, () => groupParams.groupNotice],
|
||||||
([newGroupInfo, newGroupNotice]) => {
|
([newGroupInfo, newGroupNotice]) => {
|
||||||
updateGroupInfos()
|
updateGroupInfos()
|
||||||
|
}, {
|
||||||
|
deep: true
|
||||||
},
|
},
|
||||||
{ deep: true },
|
)
|
||||||
)
|
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => useGroupTypeStore()?.allChooseMembers?.value,
|
() => useGroupTypeStore()?.allChooseMembers?.value,
|
||||||
(newMembers) => {
|
(newMembers) => {
|
||||||
// console.log(newMembers)
|
// console.log(newMembers)
|
||||||
inviteMembersInGroup(newMembers)
|
inviteMembersInGroup(newMembers)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
onLoad(async (options) => {
|
onLoad(async (options) => {
|
||||||
console.log(dialogueParams)
|
console.log(dialogueParams)
|
||||||
if (options.groupId) {
|
if (options.groupId) {
|
||||||
console.log(options.groupId)
|
console.log(options.groupId)
|
||||||
state.groupId = Number(options.groupId)
|
state.groupId = Number(options.groupId)
|
||||||
|
if (dialogueParams.type === 2) {
|
||||||
await groupStore.ServeGroupDetail()
|
await groupStore.ServeGroupDetail()
|
||||||
await groupStore.ServeGetGroupNotices()
|
await groupStore.ServeGetGroupNotices()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (options.sessionId) {
|
if (options.sessionId) {
|
||||||
state.sessionId = Number(options.sessionId)
|
state.sessionId = Number(options.sessionId)
|
||||||
if (talkParams.topItems.length > 0) {
|
if (talkParams.topItems.length > 0) {
|
||||||
@ -279,11 +243,10 @@ onLoad(async (options) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
state.recordSearchTypeList = [
|
state.recordSearchTypeList = [{
|
||||||
{
|
|
||||||
value: t('record.searchType.date'),
|
value: t('record.searchType.date'),
|
||||||
typeIcon: recordSearchTypeIcon_date,
|
typeIcon: recordSearchTypeIcon_date,
|
||||||
},
|
},
|
||||||
@ -306,8 +269,7 @@ onMounted(() => {
|
|||||||
typeIcon: recordSearchTypeIcon_groupMember,
|
typeIcon: recordSearchTypeIcon_groupMember,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
state.chatSettings = [
|
state.chatSettings = [{
|
||||||
{
|
|
||||||
label: t('chat.settings.topSession'),
|
label: t('chat.settings.topSession'),
|
||||||
hasPointer: false,
|
hasPointer: false,
|
||||||
value: '',
|
value: '',
|
||||||
@ -322,20 +284,33 @@ onMounted(() => {
|
|||||||
customInfo: 'switch',
|
customInfo: 'switch',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
})
|
if(dialogueParams.type === 1 && dialogueParams?.receiver_id === 2){
|
||||||
|
state.chatSettings.push({
|
||||||
|
label: t('chat.settings.openReminder'),
|
||||||
|
hasPointer: false,
|
||||||
|
value: '',
|
||||||
|
subValue: '',
|
||||||
|
customInfo: 'switch',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
state.chatReport = [{
|
||||||
|
label: t('chat.settings.report'),
|
||||||
|
hasPointer: true,
|
||||||
|
}, ]
|
||||||
|
})
|
||||||
|
|
||||||
//群名称
|
//群名称
|
||||||
const groupName = computed(() => {
|
const groupName = computed(() => {
|
||||||
return groupParams?.groupInfo?.group_name
|
return groupParams?.groupInfo?.group_name
|
||||||
})
|
})
|
||||||
|
|
||||||
//群人数
|
//群人数
|
||||||
const groupNum = computed(() => {
|
const groupNum = computed(() => {
|
||||||
return groupParams?.groupInfo?.group_num || 0
|
return groupParams?.groupInfo?.group_num || 0
|
||||||
})
|
})
|
||||||
|
|
||||||
// 映射表-根据groupType设置对应值
|
// 映射表-根据groupType设置对应值
|
||||||
const groupTypeMapping = {
|
const groupTypeMapping = {
|
||||||
0: {},
|
0: {},
|
||||||
1: {
|
1: {
|
||||||
result_type: t('index.mine.normal'),
|
result_type: t('index.mine.normal'),
|
||||||
@ -352,28 +327,25 @@ const groupTypeMapping = {
|
|||||||
result_type: t('index.type.company'),
|
result_type: t('index.type.company'),
|
||||||
result_type_color: '#7A58DE',
|
result_type_color: '#7A58DE',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
//群类型
|
//群类型
|
||||||
const groupType = computed(() => {
|
const groupType = computed(() => {
|
||||||
return groupTypeMapping[groupParams?.groupInfo?.group_type]?.result_type || ''
|
return groupTypeMapping[groupParams?.groupInfo?.group_type]?.result_type || ''
|
||||||
})
|
})
|
||||||
|
|
||||||
//更新群信息
|
//更新群信息
|
||||||
const updateGroupInfos = () => {
|
const updateGroupInfos = () => {
|
||||||
state.chatGroupMembers = [
|
state.chatGroupMembers = [{
|
||||||
{
|
|
||||||
label: t('chat.settings.groupMember'),
|
label: t('chat.settings.groupMember'),
|
||||||
hasPointer: true,
|
hasPointer: true,
|
||||||
value: '全部(' + groupNum.value + ')',
|
value: '全部(' + groupNum.value + ')',
|
||||||
subValue: '',
|
subValue: '',
|
||||||
customInfo: '',
|
customInfo: '',
|
||||||
},
|
}, ]
|
||||||
]
|
state.chatGroupInfos = [{
|
||||||
state.chatGroupInfos = [
|
|
||||||
{
|
|
||||||
label: t('chat.settings.groupName'),
|
label: t('chat.settings.groupName'),
|
||||||
hasPointer: true,
|
hasPointer: groupParams?.groupInfo?.is_manager ? true : false,
|
||||||
value: groupName.value,
|
value: groupName.value,
|
||||||
subValue: '',
|
subValue: '',
|
||||||
customInfo: '',
|
customInfo: '',
|
||||||
@ -387,7 +359,7 @@ const updateGroupInfos = () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('chat.settings.groupType'),
|
label: t('chat.settings.groupType'),
|
||||||
hasPointer: false,
|
hasPointer: groupParams?.groupInfo?.group_type === 2 ? true : false,
|
||||||
value: groupType.value + '群',
|
value: groupType.value + '群',
|
||||||
subValue: '',
|
subValue: '',
|
||||||
customInfo: '',
|
customInfo: '',
|
||||||
@ -403,8 +375,7 @@ const updateGroupInfos = () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
state.chatManagement = [
|
state.chatManagement = [{
|
||||||
{
|
|
||||||
label: t('chat.settings.groupGag'),
|
label: t('chat.settings.groupGag'),
|
||||||
hasPointer: true,
|
hasPointer: true,
|
||||||
value: '',
|
value: '',
|
||||||
@ -419,27 +390,27 @@ const updateGroupInfos = () => {
|
|||||||
customInfo: '',
|
customInfo: '',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
//点击跳转到修改群信息页面
|
//点击跳转到修改群信息页面
|
||||||
const toEditGroupInfoPage = () => {
|
const toEditGroupInfoPage = () => {
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: '/pages/chatSettings/groupManage/editGroupName',
|
url: '/pages/chatSettings/groupManage/editGroupName',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//点击跳转到修改头像页面
|
//点击跳转到修改头像页面
|
||||||
const toEditAvatarPage = () => {
|
const toEditAvatarPage = () => {
|
||||||
if (!groupParams?.groupInfo?.is_manager) {
|
if (!groupParams?.groupInfo?.is_manager) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: '/pages/chatSettings/groupManage/editAvatar',
|
url: '/pages/chatSettings/groupManage/editAvatar',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//点击跳转到管理页面
|
//点击跳转到管理页面
|
||||||
const toManagePage = (label) => {
|
const toManagePage = (label) => {
|
||||||
console.log(label)
|
console.log(label)
|
||||||
if (label) {
|
if (label) {
|
||||||
if (label === t('chat.settings.groupName')) {
|
if (label === t('chat.settings.groupName')) {
|
||||||
@ -451,12 +422,15 @@ const toManagePage = (label) => {
|
|||||||
})
|
})
|
||||||
} else if (label === t('chat.settings.groupNotice')) {
|
} else if (label === t('chat.settings.groupNotice')) {
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: '/pages/chatSettings/groupManage/manageNotice',
|
url: `/pages/chatSettings/groupManage/manageNotice?is_manager=${groupParams?.groupInfo?.is_manager}`,
|
||||||
|
})
|
||||||
|
} else if (label === t('chat.settings.groupType')) {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/chatSettings/groupManage/manageGroupDeps`,
|
||||||
})
|
})
|
||||||
} else if (label === t('chat.settings.groupMember')) {
|
} else if (label === t('chat.settings.groupMember')) {
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url:
|
url: '/pages/chatSettings/groupManage/manageGroupMembers?groupId=' +
|
||||||
'/pages/chatSettings/groupManage/manageGroupMembers?groupId=' +
|
|
||||||
state.groupId,
|
state.groupId,
|
||||||
})
|
})
|
||||||
} else if (label === t('chat.settings.groupGag')) {
|
} else if (label === t('chat.settings.groupGag')) {
|
||||||
@ -467,12 +441,16 @@ const toManagePage = (label) => {
|
|||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: '/pages/chatSettings/groupManage/manageGroupAdmin',
|
url: '/pages/chatSettings/groupManage/manageGroupAdmin',
|
||||||
})
|
})
|
||||||
|
} else if (label === t('chat.settings.report')) {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages/complaintReport/index',
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
//点击跳转到按条件搜索页
|
//点击跳转到按条件搜索页
|
||||||
const toSearchByConditionPage = (flag) => {
|
const toSearchByConditionPage = (flag) => {
|
||||||
let condition = ''
|
let condition = ''
|
||||||
let flagIndex = 0
|
let flagIndex = 0
|
||||||
if (dialogueParams.type === 1) {
|
if (dialogueParams.type === 1) {
|
||||||
@ -480,8 +458,7 @@ const toSearchByConditionPage = (flag) => {
|
|||||||
}
|
}
|
||||||
if (flag == flagIndex) {
|
if (flag == flagIndex) {
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url:
|
url: '/pages/chatSettings/groupManage/selectMembers?manageType=searchRecord',
|
||||||
'/pages/chatSettings/groupManage/selectMembers?manageType=searchRecord',
|
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
if (flag == flagIndex + 1) {
|
if (flag == flagIndex + 1) {
|
||||||
@ -494,17 +471,13 @@ const toSearchByConditionPage = (flag) => {
|
|||||||
condition = 'link'
|
condition = 'link'
|
||||||
}
|
}
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url:
|
url: '/pages/search/searchByCondition/index?condition=' + condition,
|
||||||
'/pages/search/searchByCondition/index?condition=' +
|
|
||||||
condition +
|
|
||||||
'&receiver_id=' +
|
|
||||||
state.groupId,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//切换开关选择
|
//切换开关选择
|
||||||
const changeSwitch = (switchStatus, label) => {
|
const changeSwitch = (switchStatus, label) => {
|
||||||
let params
|
let params
|
||||||
let resp
|
let resp
|
||||||
if (label == t('chat.settings.topSession')) {
|
if (label == t('chat.settings.topSession')) {
|
||||||
@ -520,9 +493,17 @@ const changeSwitch = (switchStatus, label) => {
|
|||||||
is_disturb: switchStatus ? 1 : 0, //是否开启免打扰,0不免打扰,1免打扰
|
is_disturb: switchStatus ? 1 : 0, //是否开启免打扰,0不免打扰,1免打扰
|
||||||
}
|
}
|
||||||
resp = ServeSetNotDisturb(params)
|
resp = ServeSetNotDisturb(params)
|
||||||
|
} else if (label == t('chat.settings.openReminder')) {
|
||||||
|
params = {
|
||||||
|
status: switchStatus,
|
||||||
|
}
|
||||||
|
resp = ServeContactRobotUpdate(params)
|
||||||
}
|
}
|
||||||
console.log(resp)
|
console.log(resp)
|
||||||
resp.then(({ code, data }) => {
|
resp.then(({
|
||||||
|
code,
|
||||||
|
data
|
||||||
|
}) => {
|
||||||
console.log(data)
|
console.log(data)
|
||||||
if (code == 200) {
|
if (code == 200) {
|
||||||
if (label == t('chat.settings.topSession')) {
|
if (label == t('chat.settings.topSession')) {
|
||||||
@ -535,16 +516,17 @@ const changeSwitch = (switchStatus, label) => {
|
|||||||
index_name: dialogueParams.index_name,
|
index_name: dialogueParams.index_name,
|
||||||
is_disturb: switchStatus ? 1 : 0,
|
is_disturb: switchStatus ? 1 : 0,
|
||||||
})
|
})
|
||||||
|
} else if (label == t('chat.settings.openReminder')) {
|
||||||
|
console.log("开关聊天助手")
|
||||||
}
|
}
|
||||||
} else {
|
} else {}
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
resp.catch(() => {})
|
resp.catch(() => {})
|
||||||
}
|
}
|
||||||
|
|
||||||
//点击显示确认提示悬窗
|
//点击显示确认提示悬窗
|
||||||
const showConfirmPrompt = (flag) => {
|
const showConfirmPrompt = (flag) => {
|
||||||
let confirmContent = ''
|
let confirmContent = ''
|
||||||
let subContent = ''
|
let subContent = ''
|
||||||
let subContentColor = ''
|
let subContentColor = ''
|
||||||
@ -552,16 +534,25 @@ const showConfirmPrompt = (flag) => {
|
|||||||
//清空聊天记录
|
//清空聊天记录
|
||||||
confirmContent = t('ok') + t('chat.settings.clearChatRecord')
|
confirmContent = t('ok') + t('chat.settings.clearChatRecord')
|
||||||
} else if (flag === 2) {
|
} else if (flag === 2) {
|
||||||
|
//解散群聊
|
||||||
|
confirmContent = t('group.dismiss.confirm')
|
||||||
|
} else if (flag === 3) {
|
||||||
|
//最后一个管理员退群就解散群聊
|
||||||
|
if (
|
||||||
|
dialogueParams.adminList.length === 1 &&
|
||||||
|
dialogueParams.adminList[0].id === dialogueParams.uid
|
||||||
|
) {
|
||||||
//解散群聊
|
//解散群聊
|
||||||
confirmContent = t('ok') + t('group.quit.btn')
|
confirmContent = t('ok') + t('group.quit.btn')
|
||||||
subContent = t('groupManage.disband.hint')
|
subContent = t('groupManage.disband.hint')
|
||||||
subContentColor = '#CF3050'
|
subContentColor = '#CF3050'
|
||||||
} else if (flag === 3) {
|
} else {
|
||||||
//退出群聊
|
//退出群聊
|
||||||
confirmContent = t('ok') + t('group.quit.btn')
|
confirmContent = t('ok') + t('group.quit.btn')
|
||||||
subContent = t('groupManage.quit.hint')
|
subContent = t('groupManage.quit.hint')
|
||||||
subContentColor = '#B4B4B4'
|
subContentColor = '#B4B4B4'
|
||||||
}
|
}
|
||||||
|
}
|
||||||
showConfirm({
|
showConfirm({
|
||||||
subContent: subContent,
|
subContent: subContent,
|
||||||
subContentColor: subContentColor,
|
subContentColor: subContentColor,
|
||||||
@ -587,22 +578,47 @@ const showConfirmPrompt = (flag) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else if (flag === 3) {
|
} else if (flag === 3) {
|
||||||
|
//最后一个管理员退群就解散群聊
|
||||||
|
if (
|
||||||
|
dialogueParams.adminList.length === 1 &&
|
||||||
|
dialogueParams.adminList[0].id === dialogueParams.uid
|
||||||
|
) {
|
||||||
|
//解散群聊
|
||||||
|
let params = {
|
||||||
|
group_id: dialogueParams.receiver_id, //群id
|
||||||
|
}
|
||||||
|
console.log(params)
|
||||||
|
const res = await ServeDismissGroup(params)
|
||||||
|
if (res.code === 200) {
|
||||||
|
dialogueStore.updateGroupMembers()
|
||||||
|
groupStore.ServeGroupDetail()
|
||||||
|
uni.navigateBack({
|
||||||
|
delta: 2,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//退出群聊
|
||||||
ServeSecedeGroup({
|
ServeSecedeGroup({
|
||||||
group_id: dialogueParams.receiver_id,
|
group_id: dialogueParams.receiver_id,
|
||||||
}).then(({ code, message }) => {
|
}).then(({
|
||||||
|
code,
|
||||||
|
message
|
||||||
|
}) => {
|
||||||
if (code == 200) {
|
if (code == 200) {
|
||||||
// dialogueStore.apiClearRecord()
|
uni.navigateBack({
|
||||||
} else {
|
delta: 2,
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
} else {}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onCancel: () => {},
|
onCancel: () => {},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//普通群/项目群拉人
|
//普通群/项目群拉人
|
||||||
const inviteMembersInGroup = async (memberList) => {
|
const inviteMembersInGroup = async (memberList) => {
|
||||||
if (memberList?.length > 0) {
|
if (memberList?.length > 0) {
|
||||||
let erp_ids = ''
|
let erp_ids = ''
|
||||||
memberList.forEach((item) => {
|
memberList.forEach((item) => {
|
||||||
@ -624,17 +640,32 @@ const inviteMembersInGroup = async (memberList) => {
|
|||||||
useGroupTypeStore()?.resetGroupInfo()
|
useGroupTypeStore()?.resetGroupInfo()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//点击跳转到搜索页面
|
||||||
|
const toSearchPage = () => {
|
||||||
|
// uni.navigateTo({
|
||||||
|
// url:
|
||||||
|
// '/pages/search/searchByCondition/index?condition=text'
|
||||||
|
// })
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages/search/moreResult/moreResultDetail?talk_type=' +
|
||||||
|
dialogueParams.type +
|
||||||
|
'&receiver_id=' +
|
||||||
|
dialogueParams.receiver_id +
|
||||||
|
'&hideFirstRecord=1',
|
||||||
|
})
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.outer-layer {
|
.outer-layer {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
background-image: url('@/static/image/clockIn/z3280@3x.png');
|
background-image: url('@/static/image/clockIn/z3280@3x.png');
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-settings-page {
|
.chat-settings-page {
|
||||||
.navBar-title {
|
.navBar-title {
|
||||||
span {
|
span {
|
||||||
line-height: 48rpx;
|
line-height: 48rpx;
|
||||||
@ -663,22 +694,27 @@ const inviteMembersInGroup = async (memberList) => {
|
|||||||
.base-info-avatar {
|
.base-info-avatar {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.base-info {
|
.base-info {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0 30rpx;
|
margin: 0 30rpx;
|
||||||
|
|
||||||
.base-info-name {
|
.base-info-name {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
|
|
||||||
span {
|
span {
|
||||||
line-height: 44rpx;
|
line-height: 44rpx;
|
||||||
color: $theme-text;
|
color: $theme-text;
|
||||||
}
|
}
|
||||||
|
|
||||||
.base-info_num {
|
.base-info_num {
|
||||||
line-height: 44rpx;
|
line-height: 44rpx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.base-info-tag {
|
.base-info-tag {
|
||||||
border: 2rpx solid #7a58de;
|
border: 2rpx solid #7a58de;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -689,6 +725,7 @@ const inviteMembersInGroup = async (memberList) => {
|
|||||||
margin: 10rpx 0 0;
|
margin: 10rpx 0 0;
|
||||||
border-radius: 8rpx;
|
border-radius: 8rpx;
|
||||||
width: 80rpx;
|
width: 80rpx;
|
||||||
|
|
||||||
span {
|
span {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
color: #7a58de;
|
color: #7a58de;
|
||||||
@ -696,10 +733,12 @@ const inviteMembersInGroup = async (memberList) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.base-info-edit {
|
.base-info-edit {
|
||||||
width: 36rpx;
|
width: 36rpx;
|
||||||
height: 36rpx;
|
height: 36rpx;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@ -707,15 +746,16 @@ const inviteMembersInGroup = async (memberList) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-group-members {
|
.chat-group-members {}
|
||||||
}
|
|
||||||
|
|
||||||
.chat-group-infos {
|
.chat-group-infos {
|
||||||
padding: 0 16rpx;
|
padding: 0 16rpx;
|
||||||
|
|
||||||
.chat-group-infos-each {
|
.chat-group-infos-each {
|
||||||
padding: 32rpx 14rpx;
|
padding: 32rpx 14rpx;
|
||||||
border-bottom: 1px solid $theme-border-color;
|
border-bottom: 1px solid $theme-border-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-group-infos-each:last-child {
|
.chat-group-infos-each:last-child {
|
||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
}
|
}
|
||||||
@ -730,6 +770,7 @@ const inviteMembersInGroup = async (memberList) => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|
||||||
.record-search-types-each {
|
.record-search-types-each {
|
||||||
width: calc(100% / 4);
|
width: calc(100% / 4);
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -737,12 +778,14 @@ const inviteMembersInGroup = async (memberList) => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin: 36rpx 0 0;
|
margin: 36rpx 0 0;
|
||||||
|
|
||||||
.record-search-types-icon {
|
.record-search-types-icon {
|
||||||
width: 106rpx;
|
width: 106rpx;
|
||||||
height: 106rpx;
|
height: 106rpx;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background-color: #f9f9f9;
|
background-color: #f9f9f9;
|
||||||
}
|
}
|
||||||
|
|
||||||
span {
|
span {
|
||||||
line-height: 34px;
|
line-height: 34px;
|
||||||
color: #666666;
|
color: #666666;
|
||||||
@ -756,6 +799,7 @@ const inviteMembersInGroup = async (memberList) => {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
.clear-chat-record-btn-each {
|
.clear-chat-record-btn-each {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
@ -770,10 +814,11 @@ const inviteMembersInGroup = async (memberList) => {
|
|||||||
color: #cf3050;
|
color: #cf3050;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.clear-chat-record-btn-each:last-child {
|
.clear-chat-record-btn-each:last-child {
|
||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -17,10 +17,17 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="avatarImg">
|
<div class="avatarImg">
|
||||||
<avatarModule
|
<avatarModule
|
||||||
:mode="2"
|
:mode="props?.data?.group_type === 0 ? 1 : 2"
|
||||||
:avatar="props?.data?.avatar"
|
:avatar="props?.data?.avatar"
|
||||||
:groupType="props?.data?.group_type"
|
:groupType="props?.data?.group_type"
|
||||||
|
:userName="props?.data?.name"
|
||||||
:customStyle="{ width: '96rpx', height: '96rpx' }"
|
:customStyle="{ width: '96rpx', height: '96rpx' }"
|
||||||
|
:customTextStyle="{
|
||||||
|
fontSize: '32rpx',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
color: '#fff',
|
||||||
|
lineHeight: '44rpx',
|
||||||
|
}"
|
||||||
></avatarModule>
|
></avatarModule>
|
||||||
</div>
|
</div>
|
||||||
<div class="chatInfo">
|
<div class="chatInfo">
|
||||||
@ -30,7 +37,18 @@
|
|||||||
class="text-[#171717] text-[32rpx] font-medium leading-[44rpx]"
|
class="text-[#171717] text-[32rpx] font-medium leading-[44rpx]"
|
||||||
>
|
>
|
||||||
<span>{{ props.data.name }}</span>
|
<span>{{ props.data.name }}</span>
|
||||||
<span>({{ props.data.group_member_num }})</span>
|
<span v-if="props.data.talk_type === 2">
|
||||||
|
({{ props.data.group_member_num }})
|
||||||
|
</span>
|
||||||
|
<span v-if="props.data.group_type === 2" class="depTag tag">
|
||||||
|
部门
|
||||||
|
</span>
|
||||||
|
<span v-if="props.data.group_type === 3" class="projectTag tag">
|
||||||
|
项目
|
||||||
|
</span>
|
||||||
|
<span v-if="props.data.group_type === 4" class="companyTag tag">
|
||||||
|
公司
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -118,16 +136,31 @@ const cellClick = () => {
|
|||||||
opacity: 40%;
|
opacity: 40%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.companyTag {
|
.tag {
|
||||||
width: 76rpx;
|
display: inline-flex;
|
||||||
height: 38rpx;
|
align-items: center;
|
||||||
border: 1px solid #7a58de;
|
|
||||||
font-size: 24rpx;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
// margin-left: 10rpx;
|
||||||
|
margin-top: 4rpx;
|
||||||
|
vertical-align: top;
|
||||||
|
height: 38rpx;
|
||||||
|
line-height: 38rpx;
|
||||||
|
padding: 0 10rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
border-radius: 6rpx;
|
border-radius: 6rpx;
|
||||||
color: #7a58de;
|
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin-left: 12rpx;
|
}
|
||||||
|
.companyTag {
|
||||||
|
border: 1px solid #7a58de;
|
||||||
|
color: #7a58de;
|
||||||
|
}
|
||||||
|
.depTag {
|
||||||
|
border: 1px solid #377ec6;
|
||||||
|
color: #377ec6;
|
||||||
|
}
|
||||||
|
.projectTag {
|
||||||
|
border: 1px solid #c1681c;
|
||||||
|
color: #c1681c;
|
||||||
}
|
}
|
||||||
|
|
||||||
.textEllipsis {
|
.textEllipsis {
|
||||||
|
|||||||
@ -58,6 +58,7 @@
|
|||||||
okColor="#FFFFFF"
|
okColor="#FFFFFF"
|
||||||
@ok="handleOk"
|
@ok="handleOk"
|
||||||
@cancel="handleCancel"
|
@cancel="handleCancel"
|
||||||
|
:okText="'发送'"
|
||||||
>
|
>
|
||||||
<template v-slot:title>
|
<template v-slot:title>
|
||||||
<div
|
<div
|
||||||
@ -86,7 +87,7 @@
|
|||||||
<div
|
<div
|
||||||
class="mt-[8rpx] text-[#666666] text-[24rpx] w-[94rpx] truncate"
|
class="mt-[8rpx] text-[#666666] text-[24rpx] w-[94rpx] truncate"
|
||||||
>
|
>
|
||||||
{{ item.name }}
|
<span>{{ item.name }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="w-full flex items-center justify-start">
|
<div v-else class="w-full flex items-center justify-start">
|
||||||
@ -98,6 +99,16 @@
|
|||||||
></avatarModule>
|
></avatarModule>
|
||||||
<div class="ml-[16rpx] text-[#161616] text-[32rpx] font-bold">
|
<div class="ml-[16rpx] text-[#161616] text-[32rpx] font-bold">
|
||||||
{{ selectItemsModal[0].name }}
|
{{ selectItemsModal[0].name }}
|
||||||
|
<span v-if="selectItemsModal[0].talk_type === 2">({{ selectItemsModal[0].group_member_num }})</span>
|
||||||
|
<span v-if="selectItemsModal[0].group_type === 2" class="depTag tag">
|
||||||
|
部门
|
||||||
|
</span>
|
||||||
|
<span v-if="selectItemsModal[0].group_type === 3" class="projectTag tag">
|
||||||
|
项目
|
||||||
|
</span>
|
||||||
|
<span v-if="selectItemsModal[0].group_type === 4" class="companyTag tag">
|
||||||
|
公司
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -208,7 +219,7 @@ watch(
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
talkStore.loadTalkList()
|
talkStore.loadTalkList()
|
||||||
console.log(talkStore.talkItems)
|
console.log(talkStore.talkItems)
|
||||||
items.value = lodash.cloneDeep(talkStore.talkItems)
|
items.value = lodash.cloneDeep(talkStore.talkItems).filter(item=>item.is_dismiss === 0 && item.is_quit === 0 && ((item.talk_type === 1 && item.receiver_id !== 2) || item.talk_type !== 1))
|
||||||
})
|
})
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
dialogueStore.setForwardType('')
|
dialogueStore.setForwardType('')
|
||||||
@ -241,7 +252,32 @@ onUnmounted(() => {
|
|||||||
margin-top: 20rpx;
|
margin-top: 20rpx;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
}
|
}
|
||||||
|
.tag{
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
// margin-left: 10rpx;
|
||||||
|
margin-top: 4rpx;
|
||||||
|
vertical-align: top;
|
||||||
|
height: 38rpx;
|
||||||
|
line-height: 38rpx;
|
||||||
|
padding: 0 10rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
border-radius: 6rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.companyTag {
|
||||||
|
border: 1px solid #7a58de;
|
||||||
|
color: #7a58de;
|
||||||
|
}
|
||||||
|
.depTag {
|
||||||
|
border: 1px solid #377ec6;
|
||||||
|
color: #377ec6;
|
||||||
|
}
|
||||||
|
.projectTag {
|
||||||
|
border: 1px solid #c1681c;
|
||||||
|
color: #c1681c;
|
||||||
|
}
|
||||||
.btnBox {
|
.btnBox {
|
||||||
::v-deep .custom-btn-class {
|
::v-deep .custom-btn-class {
|
||||||
padding: 6rpx 24rpx !important;
|
padding: 6rpx 24rpx !important;
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="mt-[54rpx] w-full h-[872rpx]">
|
<div class="mt-[54rpx] w-full h-[872rpx]">
|
||||||
<div
|
<div
|
||||||
@click="groupActiveIndex = 0"
|
@click="groupActiveIndex = 0;depCheckedKeys = []"
|
||||||
class="groupCard firstPanel"
|
class="groupCard firstPanel"
|
||||||
:class="groupActiveIndex === 0 ? 'activePanel' : ''"
|
:class="groupActiveIndex === 0 ? 'activePanel' : ''"
|
||||||
>
|
>
|
||||||
@ -33,6 +33,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
v-if="isHasPermission"
|
||||||
@click="groupActiveIndex = 1"
|
@click="groupActiveIndex = 1"
|
||||||
class="groupCard secondPanel"
|
class="groupCard secondPanel"
|
||||||
:class="groupActiveIndex === 1 ? 'activePanel' : ''"
|
:class="groupActiveIndex === 1 ? 'activePanel' : ''"
|
||||||
@ -95,7 +96,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@click="groupActiveIndex = 2"
|
v-if="isCreateProjecy"
|
||||||
|
@click="groupActiveIndex = 2;depCheckedKeys = [];"
|
||||||
class="groupCard thirdPanel"
|
class="groupCard thirdPanel"
|
||||||
:class="groupActiveIndex === 2 ? 'activePanel' : ''"
|
:class="groupActiveIndex === 2 ? 'activePanel' : ''"
|
||||||
>
|
>
|
||||||
@ -131,13 +133,36 @@
|
|||||||
import ZPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
|
import ZPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
|
||||||
import customBtn from '@/components/custom-btn/custom-btn.vue'
|
import customBtn from '@/components/custom-btn/custom-btn.vue'
|
||||||
import { ref, watch, computed } from 'vue'
|
import { ref, watch, computed } from 'vue'
|
||||||
import { onShow, onLoad } from '@dcloudio/uni-app'
|
import { onShow, onLoad, onUnload } from '@dcloudio/uni-app'
|
||||||
import { useChatList } from '@/store/chatList/index.js'
|
import { useChatList } from '@/store/chatList/index.js'
|
||||||
import { useAuth } from '@/store/auth'
|
import { useAuth } from '@/store/auth'
|
||||||
import { useTalkStore, useUserStore } from '@/store'
|
import { useTalkStore, useUserStore } from '@/store'
|
||||||
import { useGroupTypeStore } from '@/store/groupType'
|
import { useGroupTypeStore } from '@/store/groupType'
|
||||||
|
import { userHasPermission } from '@/api/deps/index.js'
|
||||||
const { groupActiveIndex, depCheckedKeys } = useGroupTypeStore()
|
const { groupActiveIndex, depCheckedKeys } = useGroupTypeStore()
|
||||||
|
const { userInfo } = useAuth()
|
||||||
|
onUnload(()=> {
|
||||||
|
|
||||||
|
})
|
||||||
|
const isHasPermission = ref(false)
|
||||||
|
const isCreateProjecy = ref(false)
|
||||||
|
onShow( async() =>{
|
||||||
|
const isHasRes = await userHasPermission({
|
||||||
|
erpUserId: userInfo?.value?.ID,
|
||||||
|
ruleUrl: [
|
||||||
|
"auth_chat_app_create_all_dept",
|
||||||
|
"auth_chat_app_create_limit_dept"
|
||||||
|
]
|
||||||
|
})
|
||||||
|
if (isHasRes.code === 200) {
|
||||||
|
if (isHasRes.data.auth_chat_app_create_all_dept || isHasRes.data.auth_chat_app_create_limit_dept) {
|
||||||
|
isHasPermission.value = true
|
||||||
|
} else{
|
||||||
|
isHasPermission.value = false
|
||||||
|
}
|
||||||
|
isCreateProjecy.value = isHasRes.data.btn_rule_create_project_group
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const confirmBtnStatus = computed(() => {
|
const confirmBtnStatus = computed(() => {
|
||||||
let disabledT = false
|
let disabledT = false
|
||||||
@ -208,10 +233,10 @@ const handleConfirm = () => {
|
|||||||
border-radius: 12rpx;
|
border-radius: 12rpx;
|
||||||
&.firstPanel {
|
&.firstPanel {
|
||||||
background-image: url('@/static/image/chatList/zu6033@2x.png');
|
background-image: url('@/static/image/chatList/zu6033@2x.png');
|
||||||
|
margin-bottom: 28rpx;
|
||||||
}
|
}
|
||||||
&.secondPanel {
|
&.secondPanel {
|
||||||
background-image: url('@/static/image/chatList/zu6031@2x.png');
|
background-image: url('@/static/image/chatList/zu6031@2x.png');
|
||||||
margin-top: 28rpx;
|
|
||||||
margin-bottom: 28rpx;
|
margin-bottom: 28rpx;
|
||||||
}
|
}
|
||||||
&.thirdPanel {
|
&.thirdPanel {
|
||||||
|
|||||||
@ -404,7 +404,7 @@ const getCurrentMembers = async (depItem) => {
|
|||||||
departmentId: depItem.ID,
|
departmentId: depItem.ID,
|
||||||
status: 'notactive',
|
status: 'notactive',
|
||||||
})
|
})
|
||||||
if (res.status === 0) {
|
if (res.code === 200) {
|
||||||
currentMembers.value = res.data.data.length
|
currentMembers.value = res.data.data.length
|
||||||
? res.data.data.map((v) => {
|
? res.data.data.map((v) => {
|
||||||
return {
|
return {
|
||||||
@ -628,7 +628,7 @@ const handleConfirm = async () => {
|
|||||||
departmentIds: allCheckedList.value.map((v) => v.ID),
|
departmentIds: allCheckedList.value.map((v) => v.ID),
|
||||||
status: 'notactive',
|
status: 'notactive',
|
||||||
})
|
})
|
||||||
if (res.status == 0 && res.data?.data?.length) {
|
if (res.code == 200 && res.data?.data?.length) {
|
||||||
res.data?.data.forEach((v) => {
|
res.data?.data.forEach((v) => {
|
||||||
listT.push(v)
|
listT.push(v)
|
||||||
})
|
})
|
||||||
|
|||||||
366
src/pages/complaintReport/index.vue
Normal file
@ -0,0 +1,366 @@
|
|||||||
|
<template>
|
||||||
|
<div class="outer-layer user-detail-page">
|
||||||
|
<div class="root">
|
||||||
|
<ZPaging ref="zPaging" :show-scrollbar="false">
|
||||||
|
<template #top>
|
||||||
|
<customNavbar :title="$t('complaint.title')"></customNavbar>
|
||||||
|
</template>
|
||||||
|
<!-- 投诉主体内容 -->
|
||||||
|
<view class="complaint-container">
|
||||||
|
<!-- 投诉类型选择 -->
|
||||||
|
<view class="form-item">
|
||||||
|
<text class="form-label">{{ $t('complaint.selectType') }}</text>
|
||||||
|
<picker mode="selector" :range="complaintTypes" range-key="label" @change="handleTypeChange">
|
||||||
|
<view class="picker">
|
||||||
|
{{ selectedType.label || $t('complaint.selectPlaceholder') }}
|
||||||
|
<uni-icons type="arrowright" size="16" color="#999"></uni-icons>
|
||||||
|
</view>
|
||||||
|
</picker>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 图片证据上传 -->
|
||||||
|
<view class="form-item">
|
||||||
|
<text class="form-label">{{ $t('complaint.imageEvidence') }}</text>
|
||||||
|
<view class="upload-area">
|
||||||
|
<view v-for="(img, index) in imageList" :key="index" class="image-wrapper">
|
||||||
|
<image :src="img" mode="aspectFill" class="uploaded-image" @click="previewImage(index)" />
|
||||||
|
<uni-icons type="close" size="18" color="#fff" class="delete-icon"
|
||||||
|
@click="removeImage(index)"></uni-icons>
|
||||||
|
</view>
|
||||||
|
<view v-if="imageList.length < 9" class="upload-btn" @click="chooseImage">
|
||||||
|
<uni-icons type="plusempty" size="28" color="#999"></uni-icons>
|
||||||
|
<text class="upload-text">{{ $t('complaint.addImage') }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 投诉内容 -->
|
||||||
|
<view class="form-item">
|
||||||
|
<text class="form-label">{{ $t('complaint.complaintContent') }}</text>
|
||||||
|
<textarea v-model="complaintContent" :placeholder="$t('complaint.contentPlaceholder')"
|
||||||
|
class="content-textarea"></textarea>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 投诉须知 -->
|
||||||
|
<view class="notice-box">
|
||||||
|
<view class="notice-header" @click="toggleNotice">
|
||||||
|
<text class="notice-title">{{ $t('complaint.noticeTitle') }}</text>
|
||||||
|
<text class="toggle-btn">
|
||||||
|
{{ isNoticeExpanded ? $t('complaint.collapse') : $t('complaint.expand') }}
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 折叠状态只显示前两项 -->
|
||||||
|
<view class="notice-content" v-if="!isNoticeExpanded">
|
||||||
|
<view class="notice-item">
|
||||||
|
<text>{{ $t('complaint.noticeone') }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="notice-item">
|
||||||
|
<text>{{ $t('complaint.noticetwo') }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 展开状态显示全部 -->
|
||||||
|
<view class="notice-content" v-else>
|
||||||
|
<view class="notice-item">
|
||||||
|
<text>{{ $t('complaint.noticeone') }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="notice-item">
|
||||||
|
<text>{{ $t('complaint.noticetwo') }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="notice-item">
|
||||||
|
<text>{{ $t('complaint.noticethree') }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="notice-item">
|
||||||
|
<text>{{ $t('complaint.noticefour') }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="notice-item">
|
||||||
|
<text>{{ $t('complaint.noticefive') }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="notice-item">
|
||||||
|
<text>{{ $t('complaint.noticenoticeContent') }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<button class="submit-btn" :disabled="!selectedType.value" @click="handleSubmit">
|
||||||
|
{{ $t('complaint.submit') }}
|
||||||
|
</button>
|
||||||
|
</view>
|
||||||
|
</ZPaging>
|
||||||
|
|
||||||
|
<!-- 固定在底部的提交按钮 -->
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import ZPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
|
||||||
|
import {
|
||||||
|
ref
|
||||||
|
} from 'vue';
|
||||||
|
import {
|
||||||
|
onLoad
|
||||||
|
} from '@dcloudio/uni-app';
|
||||||
|
import {
|
||||||
|
useI18n
|
||||||
|
} from 'vue-i18n';
|
||||||
|
|
||||||
|
const {
|
||||||
|
t
|
||||||
|
} = useI18n();
|
||||||
|
|
||||||
|
|
||||||
|
// 投诉类型选项
|
||||||
|
const complaintTypes = computed(() => [{
|
||||||
|
label: t('complaint.typeOptions.porn'),
|
||||||
|
value: 'porn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('complaint.typeOptions.illegal'),
|
||||||
|
value: 'illegal'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('complaint.typeOptions.gambling'),
|
||||||
|
value: 'gambling'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('complaint.typeOptions.violence'),
|
||||||
|
value: 'violence'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('complaint.typeOptions.selfHarm'),
|
||||||
|
value: 'selfHarm'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('complaint.typeOptions.other'),
|
||||||
|
value: 'other'
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 表单数据
|
||||||
|
const selectedType = ref({});
|
||||||
|
const imageList = ref([]);
|
||||||
|
const complaintContent = ref('');
|
||||||
|
const isNoticeExpanded = ref(false);
|
||||||
|
|
||||||
|
// 切换投诉须知展开状态
|
||||||
|
const toggleNotice = () => {
|
||||||
|
isNoticeExpanded.value = !isNoticeExpanded.value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 选择投诉类型
|
||||||
|
const handleTypeChange = (e) => {
|
||||||
|
selectedType.value = complaintTypes.value[e.detail.value];
|
||||||
|
};
|
||||||
|
|
||||||
|
// 选择图片
|
||||||
|
const chooseImage = () => {
|
||||||
|
uni.chooseImage({
|
||||||
|
count: 9 - imageList.value.length,
|
||||||
|
sizeType: ['compressed'],
|
||||||
|
sourceType: ['album', 'camera'],
|
||||||
|
success: (res) => {
|
||||||
|
imageList.value = [...imageList.value, ...res.tempFilePaths];
|
||||||
|
if (imageList.value.length > 9) {
|
||||||
|
uni.showToast({
|
||||||
|
title: `最多只能选择9张图片`,
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 删除图片
|
||||||
|
const removeImage = (index) => {
|
||||||
|
imageList.value.splice(index, 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 预览图片
|
||||||
|
const previewImage = (index) => {
|
||||||
|
uni.previewImage({
|
||||||
|
current: index,
|
||||||
|
urls: imageList.value
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 提交投诉
|
||||||
|
const handleSubmit = () => {
|
||||||
|
const formData = {
|
||||||
|
type: selectedType.value,
|
||||||
|
images: imageList.value,
|
||||||
|
content: complaintContent.value
|
||||||
|
};
|
||||||
|
uni.showLoading({
|
||||||
|
title: t('complaint.toast.submitting') // 使用国际化文本
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
uni.hideLoading();
|
||||||
|
uni.showToast({
|
||||||
|
title: t('complaint.toast.success'),
|
||||||
|
icon: 'success'
|
||||||
|
});
|
||||||
|
selectedType.value = {};
|
||||||
|
imageList.value = [];
|
||||||
|
complaintContent.value = '';
|
||||||
|
// 返回上一页
|
||||||
|
setTimeout(() => {
|
||||||
|
uni.navigateBack();
|
||||||
|
}, 1500);
|
||||||
|
}, 2000);
|
||||||
|
};
|
||||||
|
|
||||||
|
onLoad(() => {
|
||||||
|
// 页面加载时初始化
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
::v-deep .uni-picker-action-confirm {
|
||||||
|
color: #452aa1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outer-layer {
|
||||||
|
flex: 1;
|
||||||
|
background-image: url('@/static/image/mine/1111.png');
|
||||||
|
background-size: cover;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.complaint-container {
|
||||||
|
padding: 20rpx 30rpx;
|
||||||
|
background-color: rgba(255, 255, 255, 0.9);
|
||||||
|
margin: 20rpx;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item {
|
||||||
|
margin-bottom: 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-label {
|
||||||
|
display: block;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.picker {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 24rpx;
|
||||||
|
background-color: #f7f7f7;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-area {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-btn {
|
||||||
|
width: 160rpx;
|
||||||
|
height: 160rpx;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: #f7f7f7;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
border: 1rpx dashed #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-text {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #999;
|
||||||
|
margin-top: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-wrapper {
|
||||||
|
width: 160rpx;
|
||||||
|
height: 160rpx;
|
||||||
|
position: relative;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uploaded-image {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-icon {
|
||||||
|
position: absolute;
|
||||||
|
top: 8rpx;
|
||||||
|
right: 8rpx;
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
border-radius: 50%;
|
||||||
|
padding: 4rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-textarea {
|
||||||
|
width: 100%;
|
||||||
|
height: 200rpx;
|
||||||
|
padding: 20rpx;
|
||||||
|
background-color: #f7f7f7;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-box {
|
||||||
|
padding: 20rpx;
|
||||||
|
background-color: #f0f7ff;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
margin: 40rpx 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-title {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #452aa1;
|
||||||
|
font-weight: bold;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 20rpx 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-btn {
|
||||||
|
color: #452aa1;
|
||||||
|
font-size: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-content {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #666;
|
||||||
|
line-height: 1.6;
|
||||||
|
padding-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-btn {
|
||||||
|
margin-top: 40rpx;
|
||||||
|
background-color: #452aa1;
|
||||||
|
color: white;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
height: 90rpx;
|
||||||
|
line-height: 90rpx;
|
||||||
|
font-size: 32rpx;
|
||||||
|
|
||||||
|
&[disabled] {
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -8,12 +8,8 @@
|
|||||||
<div class="group-avatar flex items-center justify-center">
|
<div class="group-avatar flex items-center justify-center">
|
||||||
<div class="avatar-placeholder" v-if="groupActiveIndex === -1"></div>
|
<div class="avatar-placeholder" v-if="groupActiveIndex === -1"></div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<avatarModule
|
<avatarModule :mode="2" :avatar="avatarImg" :groupType="groupType"
|
||||||
:mode="2"
|
:customStyle="{ width: '192rpx', height: '192rpx' }"></avatarModule>
|
||||||
:avatar="avatarImg"
|
|
||||||
:groupType="groupType"
|
|
||||||
:customStyle="{ width: '192rpx', height: '192rpx' }"
|
|
||||||
></avatarModule>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-group flex items-center justify-between">
|
<div class="input-group flex items-center justify-between">
|
||||||
@ -21,25 +17,12 @@
|
|||||||
群名称
|
群名称
|
||||||
</div>
|
</div>
|
||||||
<div class="input-box">
|
<div class="input-box">
|
||||||
<tm-input
|
<tm-input v-model="groupName" :followTheme="false" fontColor="#747474" placeholderStyle="color: #B4B4B4"
|
||||||
v-model="groupName"
|
focusColor="#FFF" :fontSize="28" :maxlength="20" :height="40" :transprent="true"
|
||||||
:followTheme="false"
|
placeholder="请输入群名称(1~20个字)" :padding="[0, 0]" align="right"></tm-input>
|
||||||
fontColor="#747474"
|
|
||||||
placeholderStyle="color: #B4B4B4"
|
|
||||||
focusColor="#FFF"
|
|
||||||
:fontSize="28"
|
|
||||||
:maxlength="20"
|
|
||||||
:height="40"
|
|
||||||
:transprent="true"
|
|
||||||
placeholder="请输入群名称(1~20个字)"
|
|
||||||
:padding="[0, 0]"
|
|
||||||
align="right"
|
|
||||||
></tm-input>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div class="input-group w-full flex flex-col mt-[20rpx] leading-[40rpx]">
|
||||||
class="input-group w-full flex flex-col mt-[20rpx] leading-[40rpx]"
|
|
||||||
>
|
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div class="input-item">
|
<div class="input-item">
|
||||||
群类型
|
群类型
|
||||||
@ -52,151 +35,123 @@
|
|||||||
<span v-else-if="groupActiveIndex === 2">项目群</span>
|
<span v-else-if="groupActiveIndex === 2">项目群</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="ml-[32rpx]">
|
<div class="ml-[32rpx]">
|
||||||
<tm-icon
|
<tm-icon :font-size="22" color="#747474" name="tmicon-angle-right"></tm-icon>
|
||||||
:font-size="22"
|
|
||||||
color="#747474"
|
|
||||||
name="tmicon-angle-right"
|
|
||||||
></tm-icon>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div v-if="depCheckedKeys.length && groupActiveIndex === 1" class="mt-[32rpx]">
|
||||||
v-if="depCheckedKeys.length && groupActiveIndex === 1"
|
<div v-for="(item, index) in depCheckedKeys" class="text-[#747474] text-[28rpx] leading-[40rpx] font-bold"
|
||||||
class="mt-[32rpx]"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-for="(item, index) in depCheckedKeys"
|
|
||||||
class="text-[#747474] text-[28rpx] leading-[40rpx] font-bold"
|
|
||||||
:class="[
|
:class="[
|
||||||
index !== 0 ? 'mt-[10rpx]' : '',
|
index !== 0 ? 'mt-[10rpx]' : '',
|
||||||
depsNoExpanded && index > 4 ? 'hidden' : '',
|
depsNoExpanded_1 && index > 4 ? 'hidden' : '',
|
||||||
]"
|
]">
|
||||||
>
|
|
||||||
{{ item.name }}
|
{{ item.name }}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div class="text-[#46299D] text-[28rpx] mt-[20rpx] font-bold flex justify-center">
|
||||||
class="text-[#46299D] text-[28rpx] mt-[20rpx] font-bold flex justify-center"
|
<div v-if="depCheckedKeys.length > 5" @click="depsNoExpanded_1 = !depsNoExpanded_1" class="w-[100rpx]">
|
||||||
>
|
{{ depsNoExpanded_1 ? '展开' : '收起' }}
|
||||||
<div
|
|
||||||
v-if="depCheckedKeys.length > 5"
|
|
||||||
@click="depsNoExpanded = !depsNoExpanded"
|
|
||||||
class="w-[100rpx]"
|
|
||||||
>
|
|
||||||
{{ depsNoExpanded ? '展开' : '收起' }}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div v-if="groupActiveIndex === 0 || groupActiveIndex === 2"
|
||||||
v-if="groupActiveIndex === 0 || groupActiveIndex === 2"
|
class="input-group w-full flex flex-col mt-[20rpx] leading-[40rpx]">
|
||||||
class="input-group w-full flex flex-col mt-[20rpx] leading-[40rpx]"
|
|
||||||
>
|
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div class="input-item">
|
<div class="input-item">
|
||||||
群成员
|
群成员
|
||||||
</div>
|
</div>
|
||||||
<div @click="chooseMembers" class="left-box">
|
<div @click="chooseMembers" class="left-box">
|
||||||
<div class="ml-[32rpx] flex items-center">
|
<div class="ml-[32rpx] flex items-center">
|
||||||
<div
|
<div class="text-[#B4B4B4] text-[28rpx] font-bold mr-[32rpx]">
|
||||||
class="text-[#B4B4B4] text-[28rpx] font-bold mr-[32rpx]"
|
|
||||||
>
|
|
||||||
全部({{ allChooseMembers?.length || 0 }})
|
全部({{ allChooseMembers?.length || 0 }})
|
||||||
</div>
|
</div>
|
||||||
<tm-icon
|
<tm-icon :font-size="22" color="#747474" name="tmicon-angle-right"></tm-icon>
|
||||||
:font-size="22"
|
|
||||||
color="#747474"
|
|
||||||
name="tmicon-angle-right"
|
|
||||||
></tm-icon>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<groupMemberList
|
<groupMemberList :groupType="3" :is_manager="true" :memberList="allChooseMembers" :memberListsLimit="15"
|
||||||
:groupType="3"
|
:hideAddRemoveBtns="true"></groupMemberList>
|
||||||
:is_manager="true"
|
|
||||||
:memberList="allChooseMembers"
|
|
||||||
:memberListsLimit="15"
|
|
||||||
:hideAddRemoveBtns="true"
|
|
||||||
></groupMemberList>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div v-if="groupActiveIndex === 1" class="input-group w-full flex flex-col mt-[20rpx] leading-[40rpx]">
|
||||||
v-if="groupActiveIndex === 1"
|
|
||||||
class="input-group w-full flex flex-col mt-[20rpx] leading-[40rpx]"
|
|
||||||
>
|
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div class="input-item">
|
<div class="input-item">
|
||||||
群管理员
|
群管理员
|
||||||
</div>
|
</div>
|
||||||
<div @click="chooseGroupAdmin" class="left-box">
|
<div @click="chooseGroupAdmin" class="left-box">
|
||||||
<div class="ml-[32rpx] flex items-center">
|
<div class="ml-[32rpx] flex items-center">
|
||||||
<div
|
<div v-if="!groupAdmins.length" class="text-[#B4B4B4] text-[28rpx] font-bold mr-[32rpx]">
|
||||||
v-if="!groupAdmins.length"
|
|
||||||
class="text-[#B4B4B4] text-[28rpx] font-bold mr-[32rpx]"
|
|
||||||
>
|
|
||||||
请选择群管理员
|
请选择群管理员
|
||||||
</div>
|
</div>
|
||||||
<tm-icon
|
<tm-icon :font-size="22" color="#747474" name="tmicon-angle-right"></tm-icon>
|
||||||
:font-size="22"
|
|
||||||
color="#747474"
|
|
||||||
name="tmicon-angle-right"
|
|
||||||
></tm-icon>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="groupAdmins.length" class="mt-[32rpx]">
|
<div v-if="groupAdmins.length" class="mt-[32rpx]">
|
||||||
<div
|
<div v-for="(item, index) in groupAdmins" class="text-[#747474] text-[28rpx] leading-[40rpx] font-bold"
|
||||||
v-for="(item, index) in groupAdmins"
|
|
||||||
class="text-[#747474] text-[28rpx] leading-[40rpx] font-bold"
|
|
||||||
:class="[
|
:class="[
|
||||||
index !== 0 ? 'mt-[10rpx]' : '',
|
index !== 0 ? 'mt-[10rpx]' : '',
|
||||||
depsNoExpanded && index > 4 ? 'hidden' : '',
|
depsNoExpanded_2 && index > 4 ? 'hidden' : '',
|
||||||
]"
|
]">
|
||||||
>
|
|
||||||
{{ item.name }}
|
{{ item.name }}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div class="text-[#46299D] text-[28rpx] mt-[20rpx] font-bold flex justify-center">
|
||||||
class="text-[#46299D] text-[28rpx] mt-[20rpx] font-bold flex justify-center"
|
<div v-if="groupAdmins.length > 5" @click="depsNoExpanded_2 = !depsNoExpanded_2" class="w-[100rpx]">
|
||||||
>
|
{{ depsNoExpanded_2 ? '展开' : '收起' }}
|
||||||
<div
|
|
||||||
v-if="groupAdmins.length > 5"
|
|
||||||
@click="depsNoExpanded = !depsNoExpanded"
|
|
||||||
class="w-[100rpx]"
|
|
||||||
>
|
|
||||||
{{ depsNoExpanded ? '展开' : '收起' }}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<template #bottom>
|
<template #bottom>
|
||||||
<customBtn
|
<customBtn :isBottom="true" :btnText="$t('pageTitle.create.group')" @click="handleConfirm"
|
||||||
:isBottom="true"
|
:isLoading="isLoading" :disabled="confirmBtnStatus || isLoading"></customBtn>
|
||||||
:btnText="$t('pageTitle.create.group')"
|
|
||||||
@click="handleConfirm"
|
|
||||||
:disabled="confirmBtnStatus"
|
|
||||||
></customBtn>
|
|
||||||
</template>
|
</template>
|
||||||
</zPaging>
|
</zPaging>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import zPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
|
import zPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
|
||||||
import customBtn from '@/components/custom-btn/custom-btn.vue'
|
import customBtn from '@/components/custom-btn/custom-btn.vue'
|
||||||
import groupMemberList from '../chatSettings/components/groupMembersList.vue'
|
import groupMemberList from '../chatSettings/components/groupMembersList.vue'
|
||||||
import avatarModule from '@/components/avatar-module/index.vue'
|
import avatarModule from '@/components/avatar-module/index.vue'
|
||||||
|
|
||||||
import { ref, watch, computed } from 'vue'
|
import {
|
||||||
import { onShow, onLoad } from '@dcloudio/uni-app'
|
ref,
|
||||||
import { useChatList } from '@/store/chatList/index.js'
|
watch,
|
||||||
import { useAuth } from '@/store/auth'
|
computed,
|
||||||
import { useTalkStore, useUserStore, useGroupStore } from '@/store'
|
onMounted
|
||||||
import addCircle from '@/static/image/chatList/addCircle.png'
|
} from 'vue'
|
||||||
import cahtPopover from '@/static/image/chatList/cahtPopover.png'
|
import {
|
||||||
import { ServeCreateGroup } from '@/api/group/index'
|
onShow,
|
||||||
import { useGroupTypeStore } from '@/store/groupType'
|
onLoad,
|
||||||
|
onUnload
|
||||||
|
} from '@dcloudio/uni-app'
|
||||||
|
import {
|
||||||
|
useChatList
|
||||||
|
} from '@/store/chatList/index.js'
|
||||||
|
import {
|
||||||
|
useAuth
|
||||||
|
} from '@/store/auth'
|
||||||
|
import {
|
||||||
|
useTalkStore,
|
||||||
|
useUserStore,
|
||||||
|
useGroupStore
|
||||||
|
} from '@/store'
|
||||||
|
import addCircle from '@/static/image/chatList/addCircle.png'
|
||||||
|
import cahtPopover from '@/static/image/chatList/cahtPopover.png'
|
||||||
|
import {
|
||||||
|
ServeCreateGroup
|
||||||
|
} from '@/api/group/index'
|
||||||
|
import {
|
||||||
|
useGroupTypeStore
|
||||||
|
} from '@/store/groupType'
|
||||||
|
import {
|
||||||
|
handleSetWebviewStyle
|
||||||
|
} from '@/utils/common'
|
||||||
|
|
||||||
const {
|
const {
|
||||||
groupName,
|
groupName,
|
||||||
groupActiveIndex,
|
groupActiveIndex,
|
||||||
depCheckedKeys,
|
depCheckedKeys,
|
||||||
@ -204,21 +159,31 @@ const {
|
|||||||
createDepGroup,
|
createDepGroup,
|
||||||
resetGroupInfo,
|
resetGroupInfo,
|
||||||
allChooseMembers,
|
allChooseMembers,
|
||||||
} = useGroupTypeStore()
|
} = useGroupTypeStore()
|
||||||
const talkStore = useTalkStore()
|
const talkStore = useTalkStore()
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const groupStore = useGroupStore()
|
const groupStore = useGroupStore()
|
||||||
const { userInfo } = useAuth()
|
const {
|
||||||
|
userInfo
|
||||||
|
} = useAuth()
|
||||||
|
|
||||||
const groupChatType = ref('')
|
const groupChatType = ref('')
|
||||||
const depsNoExpanded = ref(true)
|
const depsNoExpanded_1 = ref(true)
|
||||||
|
const depsNoExpanded_2 = ref(true)
|
||||||
|
|
||||||
onLoad(()=> {
|
|
||||||
|
onLoad(() => {
|
||||||
groupStore.$reset()
|
groupStore.$reset()
|
||||||
})
|
})
|
||||||
|
onUnload(() => {
|
||||||
|
resetGroupInfo();
|
||||||
|
})
|
||||||
|
onMounted(() => {
|
||||||
|
handleSetWebviewStyle()
|
||||||
|
})
|
||||||
|
|
||||||
//群类型
|
//群类型
|
||||||
const groupType = computed(() => {
|
const groupType = computed(() => {
|
||||||
let group_type = ''
|
let group_type = ''
|
||||||
switch (groupActiveIndex.value) {
|
switch (groupActiveIndex.value) {
|
||||||
case 0:
|
case 0:
|
||||||
@ -234,34 +199,37 @@ const groupType = computed(() => {
|
|||||||
group_type = ''
|
group_type = ''
|
||||||
}
|
}
|
||||||
return group_type
|
return group_type
|
||||||
})
|
})
|
||||||
|
|
||||||
//点击跳转到选择群类型页面
|
//点击跳转到选择群类型页面
|
||||||
const chooseGroupType = () => {
|
const chooseGroupType = () => {
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: '/pages/chooseGroupType/index',
|
url: '/pages/chooseGroupType/index',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const chooseGroupAdmin = () => {
|
const chooseGroupAdmin = () => {
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url:
|
url: '/pages/chatSettings/groupManage/selectMembers?manageType=admin&isCreateDepGroup=1',
|
||||||
'/pages/chatSettings/groupManage/selectMembers?manageType=admin&isCreateDepGroup=1',
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const chooseMembers = () => {
|
const chooseMembers = () => {
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: '/pages/chooseByDeps/index?chooseMode=2',
|
url: '/pages/chooseByDeps/index?chooseMode=2',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
const isLoading = ref(false)
|
||||||
|
|
||||||
//点击发起群聊
|
// 点击发起群聊
|
||||||
const handleConfirm = async () => {
|
const handleConfirm = async () => {
|
||||||
// console.log(allChooseMembers.value)
|
if (isLoading.value) return
|
||||||
|
isLoading.value = true
|
||||||
|
|
||||||
|
try {
|
||||||
let erp_ids = ''
|
let erp_ids = ''
|
||||||
if (allChooseMembers?.value?.length > 0) {
|
if (allChooseMembers?.value?.length > 0) {
|
||||||
allChooseMembers?.value?.forEach((ele) => {
|
allChooseMembers.value.forEach((ele) => {
|
||||||
if (!erp_ids) {
|
if (!erp_ids) {
|
||||||
erp_ids = String(ele.ID)
|
erp_ids = String(ele.ID)
|
||||||
} else {
|
} else {
|
||||||
@ -269,95 +237,72 @@ const handleConfirm = async () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let res = null
|
||||||
|
|
||||||
if (groupActiveIndex.value === 0) {
|
if (groupActiveIndex.value === 0) {
|
||||||
//普通群
|
// 普通群
|
||||||
let params = {
|
const params = {
|
||||||
avatar: '',
|
avatar: '',
|
||||||
name: groupName.value,
|
name: groupName.value,
|
||||||
erp_ids: erp_ids,
|
erp_ids: erp_ids,
|
||||||
type: 1,
|
type: 1,
|
||||||
profile: '',
|
profile: '',
|
||||||
}
|
}
|
||||||
console.log(params)
|
console.log('普通群参数:', params)
|
||||||
const res = await ServeCreateGroup(params)
|
res = await ServeCreateGroup(params)
|
||||||
if (res.code === 200) {
|
|
||||||
resetGroupInfo()
|
|
||||||
uni.navigateBack()
|
|
||||||
}
|
|
||||||
} else if (groupActiveIndex.value === 1) {
|
} else if (groupActiveIndex.value === 1) {
|
||||||
//部门群
|
// 部门群
|
||||||
const res = await createDepGroup()
|
res = await createDepGroup()
|
||||||
if (res.code === 200) {
|
|
||||||
resetGroupInfo()
|
|
||||||
uni.navigateBack()
|
|
||||||
}
|
|
||||||
} else if (groupActiveIndex.value === 2) {
|
} else if (groupActiveIndex.value === 2) {
|
||||||
//项目群
|
// 项目群
|
||||||
let params = {
|
const params = {
|
||||||
avatar: '',
|
avatar: '',
|
||||||
name: groupName.value,
|
name: groupName.value,
|
||||||
erp_ids: erp_ids,
|
erp_ids: erp_ids,
|
||||||
type: 3,
|
type: 3,
|
||||||
profile: '',
|
profile: '',
|
||||||
}
|
}
|
||||||
console.log(params)
|
console.log('项目群参数:', params)
|
||||||
const res = await ServeCreateGroup(params)
|
res = await ServeCreateGroup(params)
|
||||||
if (res.code === 200) {
|
}
|
||||||
|
|
||||||
|
if (res?.code === 200) {
|
||||||
resetGroupInfo()
|
resetGroupInfo()
|
||||||
uni.navigateBack()
|
uni.navigateBack()
|
||||||
}
|
}
|
||||||
} else {
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
} finally {
|
||||||
|
isLoading.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//发起群聊按钮可点击状态
|
||||||
|
const confirmBtnStatus = computed(() => {
|
||||||
|
return groupActiveIndex.value === -1;
|
||||||
|
});
|
||||||
|
|
||||||
//发起群聊按钮可点击状态
|
onShow(() => {
|
||||||
const confirmBtnStatus = computed(() => {
|
depsNoExpanded_1.value = true;
|
||||||
let disabledT = false
|
depsNoExpanded_2.value = true;
|
||||||
console.log(groupActiveIndex.value !== -1)
|
})
|
||||||
if (
|
|
||||||
groupName.value === '' ||
|
|
||||||
(groupActiveIndex.value && groupActiveIndex.value === -1) ||
|
|
||||||
(!groupActiveIndex.value && groupActiveIndex.value !== 0)
|
|
||||||
) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
switch (groupActiveIndex.value) {
|
|
||||||
case 0:
|
|
||||||
break
|
|
||||||
case 1:
|
|
||||||
if (!depCheckedKeys.value.length) {
|
|
||||||
disabledT = true
|
|
||||||
}
|
|
||||||
if (!groupAdmins.value.length) {
|
|
||||||
disabledT = true
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case 2:
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
return disabledT
|
|
||||||
})
|
|
||||||
|
|
||||||
onShow(() => {
|
|
||||||
depsNoExpanded.value = true
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
::v-deep .zp-paging-container-content {
|
::v-deep .zp-paging-container-content {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
.create-group-chat {
|
.create-group-chat {
|
||||||
background-image: url('@/static/image/clockIn/z3280@3x.png');
|
background-image: url('@/static/image/clockIn/z3280@3x.png');
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-position: center bottom;
|
background-position: center bottom;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0 32rpx 20rpx;
|
padding: 0 32rpx 20rpx;
|
||||||
|
|
||||||
.group-avatar {
|
.group-avatar {
|
||||||
padding: 60rpx 0;
|
padding: 60rpx 0;
|
||||||
|
|
||||||
.avatar-placeholder {
|
.avatar-placeholder {
|
||||||
width: 192rpx;
|
width: 192rpx;
|
||||||
height: 192rpx;
|
height: 192rpx;
|
||||||
@ -365,31 +310,35 @@ onShow(() => {
|
|||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.divider {
|
|
||||||
|
.divider {
|
||||||
height: 1rpx;
|
height: 1rpx;
|
||||||
background-color: #7c7c7c;
|
background-color: #7c7c7c;
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-group {
|
.input-group {
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
padding: 38rpx 40rpx 32rpx 32rpx;
|
padding: 38rpx 40rpx 32rpx 32rpx;
|
||||||
}
|
}
|
||||||
.input-item {
|
|
||||||
|
.input-item {
|
||||||
line-height: 40rpx;
|
line-height: 40rpx;
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
color: #000;
|
color: #000;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
.input-box {
|
|
||||||
|
.input-box {
|
||||||
margin-left: 84rpx;
|
margin-left: 84rpx;
|
||||||
line-height: 40rpx;
|
line-height: 40rpx;
|
||||||
width: 404rpx;
|
width: 404rpx;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
.left-box {
|
|
||||||
|
.left-box {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,25 +1,34 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<div>
|
||||||
|
<zPaging :fixed="false" :height="'210px'" :show-scrollbar="false">
|
||||||
<div class="emojiRoot">
|
<div class="emojiRoot">
|
||||||
<div v-for="(img, key) in emojis" v-html="img" :key="key" @click="onSendEmoticon(1, key, img)"
|
<div
|
||||||
class="option pointer flex-center" />
|
v-for="(img, key) in emojis"
|
||||||
|
v-html="img"
|
||||||
|
:key="key"
|
||||||
|
@click="onSendEmoticon(1, key, img)"
|
||||||
|
class="option pointer flex-center"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</zPaging>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, defineProps,defineEmits } from "vue"
|
import zPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
|
||||||
import dayjs from "dayjs";
|
import { ref, reactive, defineProps, defineEmits } from 'vue'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
import { beautifyTime } from '@/utils/datetime'
|
import { beautifyTime } from '@/utils/datetime'
|
||||||
import { useTalkStore } from '@/store'
|
import { useTalkStore } from '@/store'
|
||||||
import { useSessionMenu } from '@/hooks'
|
import { useSessionMenu } from '@/hooks'
|
||||||
import { emojis } from '@/utils/emojis'
|
import { emojis } from '@/utils/emojis'
|
||||||
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: {
|
data: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: {},
|
default: {},
|
||||||
required: false,
|
required: false,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
||||||
const emit = defineEmits(['on-select'])
|
const emit = defineEmits(['on-select'])
|
||||||
const onSendEmoticon = (type, value, img = '') => {
|
const onSendEmoticon = (type, value, img = '') => {
|
||||||
@ -33,21 +42,15 @@ const onSendEmoticon = (type, value, img = '') => {
|
|||||||
emit('on-select', { type, value, img })
|
emit('on-select', { type, value, img })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.emojiRoot {
|
.emojiRoot {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 420rpx;
|
|
||||||
padding: 5rpx 32rpx;
|
padding: 5rpx 32rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
overflow: auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.option {
|
.option {
|
||||||
|
|||||||
@ -1,25 +1,39 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="emojiRoot">
|
<div class="emojiRoot">
|
||||||
<div @click="()=>photoActionsSelect(0)" class="flex flex-col items-center">
|
<div
|
||||||
<div class="w-[106rpx] h-[106rpx] bg-[#F9F9F9] rounded-[60rpx] flex-center">
|
@click="() => photoActionsSelect(0)"
|
||||||
|
class="flex flex-col items-center"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="w-[106rpx] h-[106rpx] bg-[#F9F9F9] rounded-[60rpx] flex-center"
|
||||||
|
>
|
||||||
<tm-image :width="53" :height="44" :src="photoAlbum"></tm-image>
|
<tm-image :width="53" :height="44" :src="photoAlbum"></tm-image>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-[6rpx] text-[#666666] text-[24rpx]">照片</div>
|
<div class="mt-[6rpx] text-[#666666] text-[24rpx]">照片</div>
|
||||||
</div>
|
</div>
|
||||||
<div @click="()=>photoActionsSelect(1)" class="flex flex-col items-center">
|
<div
|
||||||
<div class="w-[106rpx] h-[106rpx] bg-[#F9F9F9] rounded-[60rpx] flex-center">
|
@click="() => photoActionsSelect(1)"
|
||||||
|
class="flex flex-col items-center"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="w-[106rpx] h-[106rpx] bg-[#F9F9F9] rounded-[60rpx] flex-center"
|
||||||
|
>
|
||||||
<tm-image :width="53" :height="44" :src="videoImg"></tm-image>
|
<tm-image :width="53" :height="44" :src="videoImg"></tm-image>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-[6rpx] text-[#666666] text-[24rpx]">视频</div>
|
<div class="mt-[6rpx] text-[#666666] text-[24rpx]">视频</div>
|
||||||
</div>
|
</div>
|
||||||
<div @click="takePhoto" class="flex flex-col items-center">
|
<div @click="takePhoto" class="flex flex-col items-center">
|
||||||
<div class="w-[106rpx] h-[106rpx] bg-[#F9F9F9] rounded-[60rpx] flex-center">
|
<div
|
||||||
|
class="w-[106rpx] h-[106rpx] bg-[#F9F9F9] rounded-[60rpx] flex-center"
|
||||||
|
>
|
||||||
<tm-image :width="53" :height="44" :src="photoGraph"></tm-image>
|
<tm-image :width="53" :height="44" :src="photoGraph"></tm-image>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-[6rpx] text-[#666666] text-[24rpx]">拍摄</div>
|
<div class="mt-[6rpx] text-[#666666] text-[24rpx]">拍摄</div>
|
||||||
</div>
|
</div>
|
||||||
<div @click="chooseFile" class="flex flex-col items-center">
|
<div @click="chooseFile" class="flex flex-col items-center">
|
||||||
<div class="w-[106rpx] h-[106rpx] bg-[#F9F9F9] rounded-[60rpx] flex-center">
|
<div
|
||||||
|
class="w-[106rpx] h-[106rpx] bg-[#F9F9F9] rounded-[60rpx] flex-center"
|
||||||
|
>
|
||||||
<tm-image :width="53" :height="44" :src="folder"></tm-image>
|
<tm-image :width="53" :height="44" :src="folder"></tm-image>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-[6rpx] text-[#666666] text-[24rpx]">文件</div>
|
<div class="mt-[6rpx] text-[#666666] text-[24rpx]">文件</div>
|
||||||
@ -27,10 +41,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, defineProps, defineEmits } from "vue"
|
import { ref, reactive, defineProps, defineEmits } from 'vue'
|
||||||
import dayjs from "dayjs";
|
import dayjs from 'dayjs'
|
||||||
import { beautifyTime } from '@/utils/datetime'
|
import { beautifyTime } from '@/utils/datetime'
|
||||||
import { useDialogueListStore, useDialogueStore, useUserStore,useUploadsStore } from '@/store'
|
import {
|
||||||
|
useDialogueListStore,
|
||||||
|
useDialogueStore,
|
||||||
|
useUserStore,
|
||||||
|
useUploadsStore,
|
||||||
|
} from '@/store'
|
||||||
import { useSessionMenu } from '@/hooks'
|
import { useSessionMenu } from '@/hooks'
|
||||||
import photoAlbum from '@/static/image/chatList/photoAlbum.png'
|
import photoAlbum from '@/static/image/chatList/photoAlbum.png'
|
||||||
import photoGraph from '@/static/image/chatList/photoGraph.png'
|
import photoGraph from '@/static/image/chatList/photoGraph.png'
|
||||||
@ -38,87 +57,168 @@ import videoImg from '@/static/image/chatList/video@2x.png'
|
|||||||
import folder from '@/static/image/chatList/folder.png'
|
import folder from '@/static/image/chatList/folder.png'
|
||||||
import { uploadImg } from '@/api/chat'
|
import { uploadImg } from '@/api/chat'
|
||||||
import { uniqueId } from '@/utils'
|
import { uniqueId } from '@/utils'
|
||||||
|
import { handleFindWebview } from '@/utils/common'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
sendUserInfo: {
|
sendUserInfo: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: {},
|
default: {},
|
||||||
required: true
|
required: true,
|
||||||
},
|
},
|
||||||
talkParams: {
|
talkParams: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: {},
|
default: {},
|
||||||
required: true
|
required: true,
|
||||||
}
|
},
|
||||||
});
|
})
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
base64Url: '',
|
||||||
|
})
|
||||||
|
|
||||||
const uploadsStore = useUploadsStore()
|
const uploadsStore = useUploadsStore()
|
||||||
const { addDialogueRecord, virtualList, updateUploadProgress } = useDialogueListStore()
|
const {
|
||||||
|
addDialogueRecord,
|
||||||
|
virtualList,
|
||||||
|
updateUploadProgress,
|
||||||
|
} = useDialogueListStore()
|
||||||
const dialogueStore = useDialogueStore()
|
const dialogueStore = useDialogueStore()
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
|
|
||||||
const emit = defineEmits(['selectImg'])
|
const emit = defineEmits(['selectImg'])
|
||||||
|
|
||||||
const onProgressFn = (progress, id) => {
|
const onProgressFn = (progress, id) => {
|
||||||
console.log(progress.loaded / progress.total * 100, 'progress');
|
console.log((progress.loaded / progress.total) * 100, 'progress')
|
||||||
|
|
||||||
updateUploadProgress(id, progress.loaded / progress.total * 100)
|
updateUploadProgress(id, (progress.loaded / progress.total) * 100)
|
||||||
}
|
}
|
||||||
|
|
||||||
const photoActionsSelect = (index) => {
|
const photoActionsSelect = (index) => {
|
||||||
if (index === 0) {
|
if (index === 0) {
|
||||||
|
if (typeof plus === 'undefined') {
|
||||||
uni.chooseImage({
|
uni.chooseImage({
|
||||||
sourceType: ['album'],
|
sourceType: ['album'],
|
||||||
count: 9,
|
count: 9,
|
||||||
success: async (res) => {
|
success: async (res) => {
|
||||||
console.log(res,'res');
|
console.log(res, 'res')
|
||||||
res.tempFiles.forEach(async (file) => {
|
res.tempFiles.forEach(async (file) => {
|
||||||
let data = await onUploadImageVideo(file, 'image')
|
const fileSizeInMB = (file.size / (1024 * 1024)).toFixed(2)
|
||||||
emit('selectImg', data)
|
if (fileSizeInMB > 100) {
|
||||||
})
|
plus.nativeUI.toast('图片大小不能超过100MB')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const result = await onUploadImageVideo(file, 'image')
|
||||||
|
if (result) {
|
||||||
|
emit('selectImg', result, result.file_num)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}else{
|
},
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
plus?.gallery.pick(
|
||||||
|
(res) => {
|
||||||
|
console.log(res, 'res')
|
||||||
|
res.files.reverse()
|
||||||
|
res.files.forEach(async (filePath) => {
|
||||||
|
plus?.io?.resolveLocalFileSystemURL(
|
||||||
|
filePath,
|
||||||
|
async (entry) => {
|
||||||
|
entry.file((file) => {
|
||||||
|
const fileReader = new plus.io.FileReader()
|
||||||
|
fileReader.readAsDataURL(file)
|
||||||
|
fileReader.onloadend = async (e) => {
|
||||||
|
const base64Url = e.target.result
|
||||||
|
const fileObj = base64ToFile(base64Url)
|
||||||
|
const fileSizeInMB = (fileObj.size / (1024 * 1024)).toFixed(
|
||||||
|
2,
|
||||||
|
)
|
||||||
|
if (fileSizeInMB > 100) {
|
||||||
|
plus.nativeUI.toast('图片大小不能超过100MB')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let data = await onUploadImageVideo(fileObj, 'image')
|
||||||
|
if (data) {
|
||||||
|
emit('selectImg', data, data.file_num)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
console.log(err)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
console.log(err)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
filter: 'image',
|
||||||
|
maximum: 9,
|
||||||
|
multiple: true,
|
||||||
|
onmaxed: () => {
|
||||||
|
plus.nativeUI.toast('最多只能选择9张图片')
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// handleFindWebview(`getPlusVideoPicker()`)
|
||||||
|
// return
|
||||||
uni.chooseVideo({
|
uni.chooseVideo({
|
||||||
sourceType: ['album'],
|
sourceType: ['album'],
|
||||||
|
compressed: true,
|
||||||
|
maxDuration: 60,
|
||||||
success: async (res) => {
|
success: async (res) => {
|
||||||
console.log(res,'res');
|
console.log(res, 'res')
|
||||||
let data = await onUploadImageVideo(res.tempFile, 'video',res.tempFilePath)
|
const fileSizeInMB = (res.tempFile.size / (1024 * 1024)).toFixed(2)
|
||||||
emit('selectImg', data)
|
if (fileSizeInMB > 100) {
|
||||||
|
plus.nativeUI.toast('视频大小不能超过100MB')
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
let data = await onUploadImageVideo(
|
||||||
|
res.tempFile,
|
||||||
|
'video',
|
||||||
|
res.tempFilePath,
|
||||||
|
)
|
||||||
|
if (data) {
|
||||||
|
emit('selectImg', data, data.file_num)
|
||||||
|
}
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const onUploadImageVideo = async (file, type = 'image',fileUrl) => {
|
const onUploadImageVideo = async (file, type = 'image', fileUrl) => {
|
||||||
console.log(file, 'file');
|
console.log('开始上传文件:', file.name)
|
||||||
|
uploadsStore.updateUploadStatus(true)
|
||||||
return new Promise(async (resolve) => {
|
return new Promise(async (resolve) => {
|
||||||
if (type === 'image') {
|
if (type === 'image') {
|
||||||
let image = new Image()
|
let image = new Image()
|
||||||
image.src = URL.createObjectURL(file)
|
image.src = URL.createObjectURL(file)
|
||||||
image.onload = () => {
|
image.onload = async () => {
|
||||||
const form = new FormData()
|
const form = new FormData()
|
||||||
form.append('file', file)
|
form.append('file', file)
|
||||||
form.append("source", "fonchain-chat");
|
form.append('source', 'fonchain-chat')
|
||||||
form.append("urlParam", `width=${image.width}&height=${image.height}`);
|
form.append('urlParam', `width=${image.width}&height=${image.height}`)
|
||||||
let randomId = uniqueId()
|
let randomId = uniqueId()
|
||||||
let newItem = {
|
let newItem = {
|
||||||
avatar: userStore.avatar,
|
avatar: userStore.avatar,
|
||||||
created_at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
|
created_at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
|
||||||
extra: {
|
extra: {
|
||||||
height: image.height,
|
height: image.height,
|
||||||
name: "",
|
name: '',
|
||||||
size: 0,
|
size: 0,
|
||||||
url: image.src,
|
url: image.src,
|
||||||
width: image.width
|
width: image.width,
|
||||||
},
|
},
|
||||||
float: "right",
|
float: 'right',
|
||||||
isCheck: false,
|
isCheck: false,
|
||||||
is_mark: 0,
|
is_mark: 0,
|
||||||
is_read: 0,
|
is_read: 0,
|
||||||
is_revoke: 0,
|
is_revoke: 0,
|
||||||
msg_id: randomId,
|
msg_id: randomId,
|
||||||
|
file_num: randomId,
|
||||||
msg_type: 3,
|
msg_type: 3,
|
||||||
nickname: userStore.nickname,
|
nickname: userStore.nickname,
|
||||||
receiver_id: dialogueStore.talk.receiver_id,
|
receiver_id: dialogueStore.talk.receiver_id,
|
||||||
@ -130,30 +230,66 @@ const onUploadImageVideo = async (file, type = 'image',fileUrl) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtualList.value.unshift(newItem)
|
virtualList.value.unshift(newItem)
|
||||||
uploadImg(form, (e) => onProgressFn(e, randomId)).then(({ status, data, msg }) => {
|
|
||||||
if (status == 0) {
|
try {
|
||||||
|
const result = await uploadImg(form, (e) => onProgressFn(e, randomId))
|
||||||
|
console.log('上传完成,结果:', result)
|
||||||
|
|
||||||
|
if (result.status === 0) {
|
||||||
|
// 更新上传状态为成功
|
||||||
|
const index = virtualList.value.findIndex(
|
||||||
|
(item) => item.file_num === randomId,
|
||||||
|
)
|
||||||
|
if (index !== -1) {
|
||||||
|
virtualList.value[index].uploadStatus = 2
|
||||||
|
virtualList.value[index].uploadCurrent = 100
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保返回数据
|
||||||
resolve({
|
resolve({
|
||||||
type: 'image',
|
type: 'image',
|
||||||
url: data.ori_url,
|
url: result.data.ori_url,
|
||||||
size: file.size,
|
size: file.size,
|
||||||
width: image.width,
|
width: image.width,
|
||||||
height: image.height
|
height: image.height,
|
||||||
|
file_num: randomId,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
resolve('')
|
uploadsStore.updateUploadStatus(false)
|
||||||
message.error(msg)
|
// 更新上传状态为失败
|
||||||
|
const index = virtualList.value.findIndex(
|
||||||
|
(item) => item.file_num === randomId,
|
||||||
|
)
|
||||||
|
if (index !== -1) {
|
||||||
|
virtualList.value[index].uploadStatus = 3
|
||||||
|
}
|
||||||
|
message.error(result.msg)
|
||||||
|
resolve('')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('上传出错:', error)
|
||||||
|
uploadsStore.updateUploadStatus(false)
|
||||||
|
// 更新上传状态为失败
|
||||||
|
const index = virtualList.value.findIndex(
|
||||||
|
(item) => item.file_num === randomId,
|
||||||
|
)
|
||||||
|
if (index !== -1) {
|
||||||
|
virtualList.value[index].uploadStatus = 3
|
||||||
|
}
|
||||||
|
message.error('上传失败')
|
||||||
|
resolve('')
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
uni.getVideoInfo({
|
uni.getVideoInfo({
|
||||||
src:fileUrl,
|
src: fileUrl,
|
||||||
success:(resp)=>{
|
success: async (resp) => {
|
||||||
console.log(resp);
|
console.log('视频信息:', resp)
|
||||||
|
const form = new FormData()
|
||||||
form.append('file', file)
|
form.append('file', file)
|
||||||
form.append("source", "fonchain-chat");
|
form.append('source', 'fonchain-chat')
|
||||||
form.append("type", "video");
|
form.append('type', 'video')
|
||||||
form.append("urlParam", `width=${resp.width}&height=${resp.height}`);
|
form.append('urlParam', `width=${resp.width}&height=${resp.height}`)
|
||||||
let randomId = uniqueId()
|
let randomId = uniqueId()
|
||||||
let newItem = {
|
let newItem = {
|
||||||
avatar: userStore.avatar,
|
avatar: userStore.avatar,
|
||||||
@ -161,16 +297,17 @@ const onUploadImageVideo = async (file, type = 'image',fileUrl) => {
|
|||||||
extra: {
|
extra: {
|
||||||
duration: parseInt(resp.duration),
|
duration: parseInt(resp.duration),
|
||||||
height: resp.height,
|
height: resp.height,
|
||||||
name: "",
|
name: '',
|
||||||
url: fileUrl,
|
url: fileUrl,
|
||||||
width: resp.width
|
width: resp.width,
|
||||||
},
|
},
|
||||||
float: "right",
|
float: 'right',
|
||||||
isCheck: false,
|
isCheck: false,
|
||||||
is_mark: 0,
|
is_mark: 0,
|
||||||
is_read: 0,
|
is_read: 0,
|
||||||
is_revoke: 0,
|
is_revoke: 0,
|
||||||
msg_id: randomId,
|
msg_id: randomId,
|
||||||
|
file_num: randomId,
|
||||||
msg_type: 5,
|
msg_type: 5,
|
||||||
nickname: userStore.nickname,
|
nickname: userStore.nickname,
|
||||||
receiver_id: dialogueStore.talk.receiver_id,
|
receiver_id: dialogueStore.talk.receiver_id,
|
||||||
@ -178,85 +315,129 @@ const onUploadImageVideo = async (file, type = 'image',fileUrl) => {
|
|||||||
talk_type: dialogueStore.talk.talk_type,
|
talk_type: dialogueStore.talk.talk_type,
|
||||||
user_id: userStore.uid,
|
user_id: userStore.uid,
|
||||||
uploadCurrent: 0,
|
uploadCurrent: 0,
|
||||||
uploadStatus: 1, // 1 上传中 2 上传成功 3 上传失败
|
uploadStatus: 1,
|
||||||
}
|
}
|
||||||
virtualList.value.unshift(newItem)
|
virtualList.value.unshift(newItem)
|
||||||
uploadImg(form, (e) => onProgressFn(e, randomId)).then(({ status, data, msg }) => {
|
|
||||||
if (status == 0) {
|
try {
|
||||||
console.log(data);
|
const result = await uploadImg(form, (e) =>
|
||||||
|
onProgressFn(e, randomId),
|
||||||
|
)
|
||||||
|
console.log('视频上传完成,结果:', result)
|
||||||
|
|
||||||
|
if (result.status === 0) {
|
||||||
|
// 更新上传状态为成功
|
||||||
|
const index = virtualList.value.findIndex(
|
||||||
|
(item) => item.file_num === randomId,
|
||||||
|
)
|
||||||
|
if (index !== -1) {
|
||||||
|
virtualList.value[index].uploadStatus = 2
|
||||||
|
virtualList.value[index].uploadCurrent = 100
|
||||||
|
}
|
||||||
|
|
||||||
resolve({
|
resolve({
|
||||||
type: 'video',
|
type: 'video',
|
||||||
url: data.ori_url,
|
url: result.data.ori_url,
|
||||||
cover: data.cover_url,
|
cover: result.data.cover_url,
|
||||||
duration: parseInt(resp.duration),
|
duration: parseInt(resp.duration),
|
||||||
size: file.size
|
size: file.size,
|
||||||
|
file_num: randomId,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
// resolve('')
|
uploadsStore.updateUploadStatus(false)
|
||||||
// message.error(msg)
|
// 更新上传状态为失败
|
||||||
|
const index = virtualList.value.findIndex(
|
||||||
|
(item) => item.file_num === randomId,
|
||||||
|
)
|
||||||
|
if (index !== -1) {
|
||||||
|
virtualList.value[index].uploadStatus = 3
|
||||||
}
|
}
|
||||||
})
|
message.error(result.msg)
|
||||||
|
resolve('')
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('视频上传出错:', error)
|
||||||
|
uploadsStore.updateUploadStatus(false)
|
||||||
|
// 更新上传状态为失败
|
||||||
|
const index = virtualList.value.findIndex(
|
||||||
|
(item) => item.file_num === randomId,
|
||||||
|
)
|
||||||
|
if (index !== -1) {
|
||||||
|
virtualList.value[index].uploadStatus = 3
|
||||||
|
}
|
||||||
|
message.error('上传失败')
|
||||||
|
resolve('')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail: (error) => {
|
||||||
|
console.error('获取视频信息失败:', error)
|
||||||
|
uploadsStore.updateUploadStatus(false)
|
||||||
|
message.error('获取视频信息失败')
|
||||||
|
resolve('')
|
||||||
|
},
|
||||||
})
|
})
|
||||||
const form = new FormData()
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const base64ToFile = (base64) => {
|
const base64ToFile = (base64) => {
|
||||||
|
if (!base64) {
|
||||||
|
message.warning('您的系统暂不支持发送原图哦')
|
||||||
|
}
|
||||||
// base64转file
|
// base64转file
|
||||||
const [header, base64String] = base64.split(";base64,");
|
const [header, base64String] = base64.split(';base64,')
|
||||||
const imageType = header.split(":")[1];
|
const imageType = header.split(':')[1]
|
||||||
const byteCharacters = atob(base64String);
|
const byteCharacters = atob(base64String)
|
||||||
const byteArray = new Uint8Array(
|
const byteArray = new Uint8Array(
|
||||||
Array.from(byteCharacters, (char) => char.charCodeAt(0))
|
Array.from(byteCharacters, (char) => char.charCodeAt(0)),
|
||||||
);
|
)
|
||||||
return new File(
|
return new File([new Blob([byteArray], { type: imageType })], 'example.png', {
|
||||||
[new Blob([byteArray], { type: imageType })],
|
type: imageType,
|
||||||
"example.png",
|
})
|
||||||
{ type: imageType }
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const choosePhoto = (filter = 'none', maximum = 9, multiple = true) => {
|
const choosePhoto = (filter = 'none', maximum = 9, multiple = true) => {
|
||||||
window.plus?.gallery.pick((res) => {
|
window.plus?.gallery.pick(
|
||||||
console.log(res);
|
(res) => {
|
||||||
|
console.log(res)
|
||||||
res.files.reverse()
|
res.files.reverse()
|
||||||
res.files.forEach(async (filePath) => {
|
res.files.forEach(async (filePath) => {
|
||||||
const suffix = filePath.split('.').pop()?.toLowerCase() || ''
|
const suffix = filePath.split('.').pop()?.toLowerCase() || ''
|
||||||
if (['jpg', 'png'].includes(suffix)) {
|
if (['jpg', 'png'].includes(suffix)) {
|
||||||
console.log("进入图片")
|
console.log('进入图片')
|
||||||
window.plus?.io?.resolveLocalFileSystemURL(filePath, async (entry) => {
|
window.plus?.io?.resolveLocalFileSystemURL(
|
||||||
|
filePath,
|
||||||
|
async (entry) => {
|
||||||
entry.file((file) => {
|
entry.file((file) => {
|
||||||
const fileReader = new plus.io.FileReader();
|
const fileReader = new plus.io.FileReader()
|
||||||
fileReader.readAsDataURL(file);
|
fileReader.readAsDataURL(file)
|
||||||
fileReader.onloadend = async (e) => {
|
fileReader.onloadend = async (e) => {
|
||||||
const base64Url = e.target.result;
|
const base64Url = e.target.result
|
||||||
const fileObj = base64ToFile(base64Url);
|
const fileObj = base64ToFile(base64Url)
|
||||||
let data = await onUploadImageVideo(fileObj, 'image')
|
let data = await onUploadImageVideo(fileObj, 'image')
|
||||||
emit('selectImg', data)
|
emit('selectImg', data)
|
||||||
};
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
(err) => {
|
(err) => {
|
||||||
console.log(err);
|
console.log(err)
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (['mp4', 'flv'].includes(suffix)) {
|
if (['mp4', 'flv'].includes(suffix)) {
|
||||||
console.log(filePath,"进入视频")
|
console.log(filePath, '进入视频')
|
||||||
// const localUrl = plus.io.convertLocalFileSystemURL(filePath)
|
// const localUrl = plus.io.convertLocalFileSystemURL(filePath)
|
||||||
// console.log(localUrl);
|
// console.log(localUrl);
|
||||||
|
|
||||||
plus.io.getVideoInfo({
|
plus.io.getVideoInfo({
|
||||||
filePath:filePath,
|
filePath: filePath,
|
||||||
success:(event)=>{
|
success: (event) => {
|
||||||
console.log(event);
|
console.log(event)
|
||||||
},
|
},
|
||||||
fail:(err)=>{
|
fail: (err) => {
|
||||||
console.log(err);
|
console.log(err)
|
||||||
}
|
},
|
||||||
});
|
})
|
||||||
// window.plus?.io?.resolveLocalFileSystemURL(localUrl, async (entry) => {
|
// window.plus?.io?.resolveLocalFileSystemURL(localUrl, async (entry) => {
|
||||||
// entry.file((file) => {
|
// entry.file((file) => {
|
||||||
// console.log(file,'file');
|
// console.log(file,'file');
|
||||||
@ -276,27 +457,83 @@ const choosePhoto = (filter = 'none', maximum = 9, multiple = true) => {
|
|||||||
// )
|
// )
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, (err) => {
|
},
|
||||||
console.log(err);
|
(err) => {
|
||||||
|
console.log(err)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
filter: filter,
|
filter: filter,
|
||||||
maximum: maximum,
|
maximum: maximum,
|
||||||
multiple: multiple,
|
multiple: multiple,
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const takePhoto = () => {
|
const takePhoto = () => {
|
||||||
|
if (typeof plus !== 'undefined') {
|
||||||
|
getCamera()
|
||||||
|
} else {
|
||||||
|
document.addEventListener('plusready', () => {
|
||||||
|
getCamera()
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getCamera = () => {
|
||||||
|
const cmr = plus.camera.getCamera()
|
||||||
|
cmr.captureImage(
|
||||||
|
(p) => {
|
||||||
|
plus.io.resolveLocalFileSystemURL(
|
||||||
|
p,
|
||||||
|
(entry) => {
|
||||||
|
compressAndShowImage(entry.toLocalURL(), entry.name)
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
console.log(err)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
() => {},
|
||||||
|
{ index: '2' },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const compressAndShowImage = (url, filename) => {
|
||||||
|
const dst = `_doc/upload/${filename}`
|
||||||
|
plus.zip.compressImage(
|
||||||
|
{ src: url, dst, quality: 10, overwrite: true },
|
||||||
|
(zip) => displayImage(zip.target),
|
||||||
|
(err) => {
|
||||||
|
console.log(err)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const displayImage = (url) => {
|
||||||
|
plus.io.resolveLocalFileSystemURL(url, (entry) => {
|
||||||
|
entry.file((file) => {
|
||||||
|
const fileReader = new plus.io.FileReader()
|
||||||
|
fileReader.readAsDataURL(file)
|
||||||
|
fileReader.onloadend = async (e) => {
|
||||||
|
state.base64Url = e.target.result
|
||||||
|
const imageFile = base64ToFile(state.base64Url)
|
||||||
|
let data = await onUploadImageVideo(imageFile, 'image')
|
||||||
|
emit('selectImg', data, data.file_num)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const chooseFile = () => {
|
const chooseFile = () => {
|
||||||
uni.chooseFile({
|
uni.chooseFile({
|
||||||
count: 1,
|
count: 1,
|
||||||
extension:[''],
|
extension: [''],
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
|
const fileSizeInMB = (res.tempFiles[0].size / (1024 * 1024)).toFixed(2)
|
||||||
|
if (fileSizeInMB > 100) {
|
||||||
|
plus.nativeUI.toast('文件大小不能超过100MB')
|
||||||
|
return
|
||||||
|
}
|
||||||
let randomId = uniqueId()
|
let randomId = uniqueId()
|
||||||
let newItem = {
|
let newItem = {
|
||||||
avatar: userStore.avatar,
|
avatar: userStore.avatar,
|
||||||
@ -307,12 +544,13 @@ const chooseFile = () => {
|
|||||||
size: res.tempFiles[0].size,
|
size: res.tempFiles[0].size,
|
||||||
path: res.tempFilePaths[0],
|
path: res.tempFilePaths[0],
|
||||||
},
|
},
|
||||||
float: "right",
|
float: 'right',
|
||||||
isCheck: false,
|
isCheck: false,
|
||||||
is_mark: 0,
|
is_mark: 0,
|
||||||
is_read: 0,
|
is_read: 0,
|
||||||
is_revoke: 0,
|
is_revoke: 0,
|
||||||
msg_id: randomId,
|
msg_id: randomId,
|
||||||
|
file_num: randomId,
|
||||||
msg_type: 6,
|
msg_type: 6,
|
||||||
nickname: userStore.nickname,
|
nickname: userStore.nickname,
|
||||||
receiver_id: dialogueStore.talk.receiver_id,
|
receiver_id: dialogueStore.talk.receiver_id,
|
||||||
@ -323,13 +561,37 @@ const chooseFile = () => {
|
|||||||
uploadStatus: 1, // 1 上传中 2 上传成功 3 上传失败
|
uploadStatus: 1, // 1 上传中 2 上传成功 3 上传失败
|
||||||
}
|
}
|
||||||
virtualList.value.unshift(newItem)
|
virtualList.value.unshift(newItem)
|
||||||
uploadsStore.initUploadFile(res.tempFiles[0], props.talkParams,randomId)
|
uploadsStore.updateUploadStatus(true)
|
||||||
|
uploadsStore.initUploadFile(
|
||||||
|
res.tempFiles[0],
|
||||||
|
props.talkParams,
|
||||||
|
randomId,
|
||||||
|
(status, data, msg) => {
|
||||||
|
if (status === 0) {
|
||||||
|
// 更新上传状态为成功
|
||||||
|
const index = virtualList.value.findIndex(
|
||||||
|
(item) => item.file_num === randomId,
|
||||||
|
)
|
||||||
|
if (index !== -1) {
|
||||||
|
virtualList.value[index].uploadStatus = 2
|
||||||
|
virtualList.value[index].uploadCurrent = 100
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
uploadsStore.updateUploadStatus(false)
|
||||||
|
// 更新上传状态为失败
|
||||||
|
const index = virtualList.value.findIndex(
|
||||||
|
(item) => item.file_num === randomId,
|
||||||
|
)
|
||||||
|
if (index !== -1) {
|
||||||
|
virtualList.value[index].uploadStatus = 3
|
||||||
|
}
|
||||||
|
message.error(msg)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.emojiRoot {
|
.emojiRoot {
|
||||||
|
|||||||
@ -37,7 +37,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="user-info-main user-info-card">
|
<div class="user-info-main user-info-card">
|
||||||
<div class="user-info-main-title">
|
<div class="user-info-main-title">
|
||||||
<img src="/src/static/image/mine/ming001@3x.png" />
|
<img src="@/static/image/mine/ming001@3x.png" />
|
||||||
<span class="text-[28rpx] font-medium">
|
<span class="text-[28rpx] font-medium">
|
||||||
{{ $t('index.mine.basic') }}
|
{{ $t('index.mine.basic') }}
|
||||||
</span>
|
</span>
|
||||||
@ -61,13 +61,48 @@
|
|||||||
<template #bottom>
|
<template #bottom>
|
||||||
<customBtn
|
<customBtn
|
||||||
:isBottom="true"
|
:isBottom="true"
|
||||||
:btnText="$t('user.detail.sendMsg')"
|
:btnText="
|
||||||
:subBtnText="$t('user.detail.ringBell')"
|
state.canSendMsg
|
||||||
@clickBtn="toTalkUser"
|
? $t('user.detail.sendMsg')
|
||||||
|
: $t('addressBook.btns.addFriend')
|
||||||
|
"
|
||||||
|
:subBtnText="
|
||||||
|
!state.canSendMsg || state.userInfo.sys_id === state.uid
|
||||||
|
? ''
|
||||||
|
: $t('user.detail.ringBell')
|
||||||
|
"
|
||||||
|
@clickBtn="checkSendPermission"
|
||||||
|
@clickSubBtn="handleCall"
|
||||||
></customBtn>
|
></customBtn>
|
||||||
</template>
|
</template>
|
||||||
</ZPaging>
|
</ZPaging>
|
||||||
</div>
|
</div>
|
||||||
|
<tm-drawer
|
||||||
|
placement="bottom"
|
||||||
|
v-model:show="state.isShowPhoneCall"
|
||||||
|
:hideHeader="true"
|
||||||
|
:height="416"
|
||||||
|
:round="6"
|
||||||
|
>
|
||||||
|
<div class="do-phone-call">
|
||||||
|
<div class="do-phone-call-header">
|
||||||
|
<span>{{ $t('popup.title.phone') }}</span>
|
||||||
|
<img
|
||||||
|
src="@/static/image/login/check-circle-filled@3x.png"
|
||||||
|
@click="hidePhoneCallPopup"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="do-phone-call-number">
|
||||||
|
<span>{{ state.phoneNumber }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="do-phone-call-btn">
|
||||||
|
<customBtn
|
||||||
|
:btnText="$t('do.phone.call')"
|
||||||
|
@clickBtn="doPhoneCall"
|
||||||
|
></customBtn>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</tm-drawer>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
@ -76,10 +111,12 @@ import ZPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
|
|||||||
import { onLoad } from '@dcloudio/uni-app'
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
import { reactive } from 'vue'
|
import { reactive } from 'vue'
|
||||||
|
|
||||||
import { useTalkStore } from '@/store'
|
import { useTalkStore, useUserStore } from '@/store'
|
||||||
const talkStore = useTalkStore()
|
const talkStore = useTalkStore()
|
||||||
|
const userStore = useUserStore()
|
||||||
|
|
||||||
import { getUserInfoByClickAvatar } from '@/api/user/index'
|
import { getUserInfoByClickAvatar } from '@/api/user/index'
|
||||||
|
import { ServeCheckFriend, ServeAddFriend } from '@/api/addressBook/index'
|
||||||
|
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
@ -88,6 +125,10 @@ const state = reactive({
|
|||||||
erpUserId: '', //erp用户id
|
erpUserId: '', //erp用户id
|
||||||
userInfo: null, //用户详情
|
userInfo: null, //用户详情
|
||||||
userBasicInfos: [], //用户基本信息
|
userBasicInfos: [], //用户基本信息
|
||||||
|
isShowPhoneCall: false, //是否显示电话拨号弹框
|
||||||
|
phoneNumber: '', //手机号
|
||||||
|
uid: computed(() => userStore.uid), //当前用户id
|
||||||
|
canSendMsg: false, //是否可以发送消息(是好友或同公司别),如果不可以就需要先加好友
|
||||||
})
|
})
|
||||||
|
|
||||||
onLoad((options) => {
|
onLoad((options) => {
|
||||||
@ -110,6 +151,7 @@ const getUserInfo = () => {
|
|||||||
console.log(data)
|
console.log(data)
|
||||||
if (code == 200) {
|
if (code == 200) {
|
||||||
state.userInfo = data
|
state.userInfo = data
|
||||||
|
checkNeedAddFriend()
|
||||||
let department = ''
|
let department = ''
|
||||||
let post = ''
|
let post = ''
|
||||||
if (data?.erp_dept_position?.length > 0) {
|
if (data?.erp_dept_position?.length > 0) {
|
||||||
@ -167,6 +209,7 @@ const getUserInfo = () => {
|
|||||||
value: data.enter_date,
|
value: data.enter_date,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
state.phoneNumber = data.tel_num
|
||||||
} else {
|
} else {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -174,10 +217,72 @@ const getUserInfo = () => {
|
|||||||
resp.catch(() => {})
|
resp.catch(() => {})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//点击唤起拨号弹框
|
||||||
|
const handleCall = () => {
|
||||||
|
state.isShowPhoneCall = true
|
||||||
|
}
|
||||||
|
|
||||||
|
//点击隐藏拨号弹框
|
||||||
|
const hidePhoneCallPopup = () => {
|
||||||
|
state.isShowPhoneCall = false
|
||||||
|
}
|
||||||
|
|
||||||
//点击对用户发起单聊
|
//点击对用户发起单聊
|
||||||
const toTalkUser = () => {
|
const toTalkUser = () => {
|
||||||
talkStore.toTalk(1, state.userInfo.sys_id, state.erpUserId)
|
talkStore.toTalk(1, state.userInfo.sys_id, state.erpUserId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//点击拨打唤起拨号
|
||||||
|
const doPhoneCall = () => {
|
||||||
|
uni.makePhoneCall({
|
||||||
|
phoneNumber: state.phoneNumber,
|
||||||
|
success: () => {
|
||||||
|
console.log('拨号成功')
|
||||||
|
},
|
||||||
|
fail: (err) => {
|
||||||
|
console.error('失败:', err)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//检查是否可以发送消息,如果不可以要先添加好友
|
||||||
|
const checkSendPermission = () => {
|
||||||
|
if (state.canSendMsg) {
|
||||||
|
toTalkUser()
|
||||||
|
} else {
|
||||||
|
doAddFriend()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//校验是否需要加好友
|
||||||
|
const checkNeedAddFriend = () => {
|
||||||
|
state.canSendMsg = true
|
||||||
|
// let params = {
|
||||||
|
// receiver_id: state.userInfo.sys_id, //聊天的用户id
|
||||||
|
// talk_type: 1,
|
||||||
|
// }
|
||||||
|
// ServeCheckFriend(params).then((res) => {
|
||||||
|
// console.log(res)
|
||||||
|
// if (res?.code === 200) {
|
||||||
|
// state.canSendMsg = res.data?.is_friend || false
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
}
|
||||||
|
|
||||||
|
//主动加好友(单向好友)
|
||||||
|
const doAddFriend = () => {
|
||||||
|
let params = {
|
||||||
|
receiver_id: state.userInfo.sys_id, //聊天的用户id
|
||||||
|
talk_type: 1,
|
||||||
|
}
|
||||||
|
ServeAddFriend(params).then((res) => {
|
||||||
|
console.log(res)
|
||||||
|
if (res?.code === 200) {
|
||||||
|
message.success(t('addressBook.message.addSuccess') + ' !')
|
||||||
|
state.canSendMsg = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.outer-layer {
|
.outer-layer {
|
||||||
@ -220,6 +325,7 @@ const toTalkUser = () => {
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
flex-shrink: 0;
|
||||||
img {
|
img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@ -290,4 +396,58 @@ const toTalkUser = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.do-phone-call {
|
||||||
|
.do-phone-call-header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 42rpx 0;
|
||||||
|
position: relative;
|
||||||
|
span {
|
||||||
|
font-size: 28rpx;
|
||||||
|
line-height: 40rpx;
|
||||||
|
color: #747474;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
position: absolute;
|
||||||
|
top: 44rpx;
|
||||||
|
right: 30rpx;
|
||||||
|
width: 36rpx;
|
||||||
|
height: 36rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.do-phone-call-number {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 32rpx 0;
|
||||||
|
border-top: 2rpx solid #e7e7e7;
|
||||||
|
border-bottom: 2rpx solid #e7e7e7;
|
||||||
|
span {
|
||||||
|
font-size: 32rpx;
|
||||||
|
line-height: 44rpx;
|
||||||
|
color: #1a1a1a;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.do-phone-call-btn {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 50rpx 0;
|
||||||
|
:deep(.custom-btn-class) {
|
||||||
|
width: 690rpx;
|
||||||
|
font-size: 32rpx;
|
||||||
|
line-height: 44rpx;
|
||||||
|
padding: 18rpx 0;
|
||||||
|
height: 80rpx;
|
||||||
|
background: linear-gradient(to right, #674bbc, #46299d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,14 +1,17 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import zPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
import { ServeGetForwardRecords } from '@/api/chat'
|
import { ServeGetForwardRecords } from '@/api/chat'
|
||||||
import { MessageComponents } from '@/constant/message'
|
import { MessageComponents } from '@/constant/message'
|
||||||
import { ITalkRecord } from '@/types/chat'
|
import { ITalkRecord } from '@/types/chat'
|
||||||
import WdLoading from "@/uni_modules/wot-design-uni/components/wd-loading/wd-loading.vue";
|
import WdLoading from "@/uni_modules/wot-design-uni/components/wd-loading/wd-loading.vue";
|
||||||
import { useInject } from '@/hooks'
|
import { useInject } from '@/hooks'
|
||||||
|
import { parseTime } from '@/utils/datetime'
|
||||||
|
|
||||||
const emit = defineEmits(['close'])
|
const emit = defineEmits(['close'])
|
||||||
|
|
||||||
const msgId = ref(null)
|
const msgId = ref(null)
|
||||||
|
const createdAt = ref(null)
|
||||||
const { showUserInfoModal } = useInject()
|
const { showUserInfoModal } = useInject()
|
||||||
const isShow = ref(true)
|
const isShow = ref(true)
|
||||||
const items = ref<ITalkRecord[]>([])
|
const items = ref<ITalkRecord[]>([])
|
||||||
@ -20,12 +23,18 @@ const onMaskClick = () => {
|
|||||||
|
|
||||||
const onLoadData = () => {
|
const onLoadData = () => {
|
||||||
ServeGetForwardRecords({
|
ServeGetForwardRecords({
|
||||||
msg_id: msgId.value
|
msg_id: msgId.value,
|
||||||
|
biz_date: createdAt.value
|
||||||
}).then((res) => {
|
}).then((res) => {
|
||||||
if (res.code == 200) {
|
if (res.code == 200) {
|
||||||
items.value = res.data.items || []
|
items.value = res.data.items || []
|
||||||
|
// 修复标题逻辑
|
||||||
title.value = [...new Set(items.value.map((v) => v.nickname))].join('、')
|
const uniqueNames = [...new Set(items.value.map(v => v.nickname))];
|
||||||
|
if (uniqueNames.length <= 2) {
|
||||||
|
title.value = uniqueNames.join('和');
|
||||||
|
} else {
|
||||||
|
title.value = uniqueNames.slice(0, 2).join('和') + '等';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -35,6 +44,7 @@ onMounted(() => {
|
|||||||
const page = pages[pages.length - 1]
|
const page = pages[pages.length - 1]
|
||||||
const options = page.$page.options
|
const options = page.$page.options
|
||||||
msgId.value = options.msgId
|
msgId.value = options.msgId
|
||||||
|
createdAt.value = parseTime(new Date((options.created_at as any)), '{y}{m}')
|
||||||
console.log(msgId.value,'msgId.value');
|
console.log(msgId.value,'msgId.value');
|
||||||
|
|
||||||
onLoadData()
|
onLoadData()
|
||||||
@ -42,11 +52,11 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="outer-layer">
|
<div class="forward-record-page">
|
||||||
<div>
|
<zPaging ref="zPaging" :show-scrollbar="false">
|
||||||
<tm-navbar :hideBack="false" hideHome :title="`${title}的会话记录`" >
|
<template #top>
|
||||||
</tm-navbar>
|
<customNavbar :title="`${title}的会话记录`"></customNavbar>
|
||||||
</div>
|
</template>
|
||||||
<div class="main-box">
|
<div class="main-box">
|
||||||
<div v-if="items.length === 0" class="flex justify-center items-center w-full mt-[200rpx]">
|
<div v-if="items.length === 0" class="flex justify-center items-center w-full mt-[200rpx]">
|
||||||
<wd-loading />
|
<wd-loading />
|
||||||
@ -71,16 +81,15 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</zPaging>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.outer-layer {
|
.forward-record-page {
|
||||||
overflow-y: auto;
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
background-image: url("@/static/image/clockIn/z3280@3x.png");
|
background-image: url("@/static/image/clockIn/z3280@3x.png");
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
padding: 0 66rpx 20rpx 50rpx;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
@ -91,7 +100,7 @@ onMounted(() => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
padding-top: 28rpx;
|
padding: 28rpx 66rpx 20rpx 50rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-item {
|
.message-item {
|
||||||
|
|||||||
@ -7,8 +7,14 @@
|
|||||||
>
|
>
|
||||||
<div class="avatarImg">
|
<div class="avatarImg">
|
||||||
<tm-badge
|
<tm-badge
|
||||||
:count="props.data.unread_num"
|
:count="props.data.is_disturb === 0 ? props.data.unread_num : ''"
|
||||||
|
:dot="
|
||||||
|
props.data.is_disturb === 1 && props.data.unread_num
|
||||||
|
? true
|
||||||
|
: false
|
||||||
|
"
|
||||||
:maxCount="99"
|
:maxCount="99"
|
||||||
|
class="badge"
|
||||||
color="#D03050"
|
color="#D03050"
|
||||||
>
|
>
|
||||||
<avatarModule
|
<avatarModule
|
||||||
@ -32,9 +38,13 @@
|
|||||||
<div class="chatInfo">
|
<div class="chatInfo">
|
||||||
<div class="chatInfo_1">
|
<div class="chatInfo_1">
|
||||||
<div class="name_center">
|
<div class="name_center">
|
||||||
<div class="text-[#000000] text-[32rpx]
|
<div
|
||||||
font-bold opacity-90 name_text">
|
class="text-[#000000] text-[32rpx] font-bold opacity-90 name_text"
|
||||||
|
>
|
||||||
{{ formatNameText(props.data.name) }}
|
{{ formatNameText(props.data.name) }}
|
||||||
|
<span v-if="props.data.talk_type === 2">
|
||||||
|
({{ props.data.group_member_num }})
|
||||||
|
</span>
|
||||||
<span v-if="props.data.group_type === 2" class="depTag tag">
|
<span v-if="props.data.group_type === 2" class="depTag tag">
|
||||||
部门
|
部门
|
||||||
</span>
|
</span>
|
||||||
@ -45,9 +55,9 @@
|
|||||||
公司
|
公司
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div style="flex-shrink: 0;"
|
<div
|
||||||
|
style="flex-shrink: 0;"
|
||||||
class="text-[#000000] text-[28rpx] font-medium opacity-26 ml-[24rpx] time_right"
|
class="text-[#000000] text-[28rpx] font-medium opacity-26 ml-[24rpx] time_right"
|
||||||
>
|
>
|
||||||
{{ beautifyTime(props.data.updated_at) }}
|
{{ beautifyTime(props.data.updated_at) }}
|
||||||
@ -55,6 +65,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="chatInfo_2 w-full mr-[6rpx]">
|
<div class="chatInfo_2 w-full mr-[6rpx]">
|
||||||
<div class="w-full chatInfo_2_1 textEllipsis">
|
<div class="w-full chatInfo_2_1 textEllipsis">
|
||||||
|
<span v-if="props.data.atsign_num" style="color: red;">
|
||||||
|
[有人@你]
|
||||||
|
</span>
|
||||||
{{ props.data.msg_text }}
|
{{ props.data.msg_text }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -63,12 +76,12 @@
|
|||||||
<template #right>
|
<template #right>
|
||||||
<div class="flex flex-row flex-row-center-end">
|
<div class="flex flex-row flex-row-center-end">
|
||||||
<!-- 样式占位 -->
|
<!-- 样式占位 -->
|
||||||
<div style="width: 1px"></div>
|
<div style="width: 1px;"></div>
|
||||||
<div
|
<div
|
||||||
@click="handleTop"
|
@click="handleTop"
|
||||||
class="w-[156rpx] h-[154rpx] text-[#ffffff] bg-[#F09F1F] flex items-center justify-center"
|
class="w-[156rpx] h-[154rpx] text-[#ffffff] bg-[#F09F1F] flex items-center justify-center"
|
||||||
>
|
>
|
||||||
{{ props.data.is_top === 1 ? "取消置顶" : "置顶" }}
|
{{ props.data.is_top === 1 ? '取消置顶' : '置顶' }}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@click="handleDelete"
|
@click="handleDelete"
|
||||||
@ -86,17 +99,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import avatarModule from "@/components/avatar-module/index.vue";
|
import avatarModule from '@/components/avatar-module/index.vue'
|
||||||
import { ref, reactive, defineProps, computed } from "vue";
|
import { ref, reactive, defineProps, computed } from 'vue'
|
||||||
import dayjs from "dayjs";
|
import dayjs from 'dayjs'
|
||||||
import { beautifyTime } from "@/utils/datetime";
|
import { beautifyTime } from '@/utils/datetime'
|
||||||
import { ServeClearTalkUnreadNum } from "@/api/chat";
|
import { ServeClearTalkUnreadNum } from '@/api/chat'
|
||||||
import { useTalkStore, useDialogueStore } from "@/store";
|
import { useTalkStore, useDialogueStore } from '@/store'
|
||||||
import { useSessionMenu } from "@/hooks";
|
import { useSessionMenu } from '@/hooks'
|
||||||
|
|
||||||
const talkStore = useTalkStore();
|
const talkStore = useTalkStore()
|
||||||
const { onToTopTalk, onRemoveTalk } = useSessionMenu();
|
const { onToTopTalk, onRemoveTalk } = useSessionMenu()
|
||||||
const dialogueStore = useDialogueStore();
|
const dialogueStore = useDialogueStore()
|
||||||
|
const dialogueParams = reactive({
|
||||||
|
unReadNum: computed(() => dialogueStore.unreadNum),
|
||||||
|
})
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: {
|
data: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@ -108,51 +124,59 @@ const props = defineProps({
|
|||||||
default: -1,
|
default: -1,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
||||||
// 添加格式化方法
|
// 添加格式化方法
|
||||||
const formatNameText = (text, maxLength = 19) => {
|
const formatNameText = (text, maxLength = 16) => {
|
||||||
return text.length > maxLength ? `${text.slice(0, maxLength - 1)}...` : text;
|
return text.length > maxLength ? `${text.slice(0, maxLength - 1)}...` : text
|
||||||
};
|
}
|
||||||
|
|
||||||
const cellClick = () => {
|
const cellClick = () => {
|
||||||
console.log(props.data);
|
console.log(props.data)
|
||||||
// 更新编辑信息
|
// 更新编辑信息
|
||||||
dialogueStore.setDialogue(props.data);
|
dialogueStore.setDialogue(props.data)
|
||||||
|
|
||||||
// 清空消息未读数
|
// 清空消息未读数
|
||||||
if (props.data.unread_num > 0) {
|
if (props.data.unread_num > 0) {
|
||||||
ServeClearTalkUnreadNum({
|
ServeClearTalkUnreadNum(
|
||||||
|
{
|
||||||
talk_type: props.data.talk_type,
|
talk_type: props.data.talk_type,
|
||||||
receiver_id: props.data.receiver_id,
|
receiver_id: props.data.receiver_id,
|
||||||
}).then(() => {
|
},
|
||||||
|
dialogueParams.unReadNum,
|
||||||
|
).then(() => {
|
||||||
talkStore.updateItem({
|
talkStore.updateItem({
|
||||||
index_name: props.data.index_name,
|
index_name: props.data.index_name,
|
||||||
unread_num: 0,
|
unread_num: 0,
|
||||||
});
|
})
|
||||||
});
|
dialogueStore.clearUnreadNum()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: "/pages/dialog/index?sessionId=" + props.data.id,
|
url: `/pages/dialog/index?sessionId=${props.data.id}`,
|
||||||
});
|
})
|
||||||
};
|
}
|
||||||
|
|
||||||
const handleTop = () => {
|
const handleTop = () => {
|
||||||
console.log(props.data, 1);
|
console.log(props.data, 1)
|
||||||
onToTopTalk(props.data);
|
onToTopTalk(props.data)
|
||||||
};
|
}
|
||||||
|
|
||||||
//点击删除会话
|
//点击删除会话
|
||||||
const handleDelete = () => {
|
const handleDelete = () => {
|
||||||
console.log(props.data);
|
console.log(props.data)
|
||||||
onRemoveTalk(props.data);
|
onRemoveTalk(props.data)
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
::v-deep .swipe_action {
|
::v-deep .swipe_action {
|
||||||
// border: 1px solid #fff;
|
// border: 1px solid #fff;
|
||||||
// transform: translate3d(1px, 0px, 0px) !important;
|
// transform: translate3d(1px, 0px, 0px) !important;
|
||||||
}
|
}
|
||||||
|
::v-deep .badge .round-6 {
|
||||||
|
min-width: 22rpx;
|
||||||
|
min-height: 22rpx;
|
||||||
|
}
|
||||||
.chatItem {
|
.chatItem {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 154rpx;
|
height: 154rpx;
|
||||||
@ -187,11 +211,11 @@ const handleDelete = () => {
|
|||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
color: rgba($color: #000000, $alpha: 0.4);
|
color: rgba($color: #000000, $alpha: 0.4);
|
||||||
}
|
}
|
||||||
.tag{
|
.tag {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-left: 10rpx;
|
// margin-left: 10rpx;
|
||||||
margin-top: 4rpx;
|
margin-top: 4rpx;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
height: 38rpx;
|
height: 38rpx;
|
||||||
@ -213,11 +237,11 @@ const handleDelete = () => {
|
|||||||
border: 1px solid #c1681c;
|
border: 1px solid #c1681c;
|
||||||
color: #c1681c;
|
color: #c1681c;
|
||||||
}
|
}
|
||||||
.name_center{
|
.name_center {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
.name_text{
|
.name_text {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
max-height: 88rpx; // 两行文字的高度
|
max-height: 88rpx; // 两行文字的高度
|
||||||
line-height: 44rpx;
|
line-height: 44rpx;
|
||||||
@ -241,6 +265,7 @@ const handleDelete = () => {
|
|||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
-webkit-line-clamp: 1;
|
-webkit-line-clamp: 1;
|
||||||
-webkit-box-orient: vertical;
|
-webkit-box-orient: vertical;
|
||||||
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
.divider {
|
.divider {
|
||||||
|
|||||||
@ -31,12 +31,25 @@
|
|||||||
>
|
>
|
||||||
<template v-slot:left>
|
<template v-slot:left>
|
||||||
<div class="flex items-center ml-[48rpx]">
|
<div class="flex items-center ml-[48rpx]">
|
||||||
<image
|
<!-- <image
|
||||||
class="w-[72rpx] h-[72rpx]"
|
class="w-[72rpx] h-[72rpx]"
|
||||||
style="border-radius: 50%;"
|
style="border-radius: 50%;"
|
||||||
:src="userStore.avatar"
|
:src="userStore.avatar"
|
||||||
mode="scaleToFill"
|
mode="scaleToFill"
|
||||||
/>
|
/> -->
|
||||||
|
<avatarModule
|
||||||
|
:mode="1"
|
||||||
|
:avatar="userStore.avatar"
|
||||||
|
:groupType="0"
|
||||||
|
:userName="userStore.nickname"
|
||||||
|
:customStyle="{ width: '72rpx', height: '72rpx' }"
|
||||||
|
:customTextStyle="{
|
||||||
|
fontSize: '32rpx',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
color: '#fff',
|
||||||
|
lineHeight: '44rpx',
|
||||||
|
}"
|
||||||
|
></avatarModule>
|
||||||
<div class="ml-[24rpx] text-[36rpx] font-bold">
|
<div class="ml-[24rpx] text-[36rpx] font-bold">
|
||||||
{{ userStore.nickname }}
|
{{ userStore.nickname }}
|
||||||
</div>
|
</div>
|
||||||
@ -53,11 +66,11 @@
|
|||||||
/>
|
/>
|
||||||
<template v-slot:label>
|
<template v-slot:label>
|
||||||
<div
|
<div
|
||||||
class="w-full h-[208rpx] pt-[22rpx] pb-[32rpx] pl-[14rpx] pr-[12rpx]"
|
class="w-full px-[14rpx]"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@click="creatGroupChat"
|
@click="creatGroupChat"
|
||||||
class="flex items-center pl-[22rpx] mb-[32rpx]"
|
class="flex items-center pl-[22rpx] py-[32rpx]"
|
||||||
>
|
>
|
||||||
<div class="mr-[26rpx] flex items-center">
|
<div class="mr-[26rpx] flex items-center">
|
||||||
<tm-image
|
<tm-image
|
||||||
@ -73,9 +86,27 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
|
<!-- <div
|
||||||
|
@click="toAddFriendPage"
|
||||||
|
class="flex items-center pl-[22rpx] py-[32rpx]"
|
||||||
|
>
|
||||||
|
<div class="mr-[26rpx] flex items-center">
|
||||||
|
<tm-image
|
||||||
|
:width="40"
|
||||||
|
:height="44"
|
||||||
|
:src="addFriend"
|
||||||
|
></tm-image>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="leading-[54rpx] text-[32rpx] text-[#FFFFFF] font-bold"
|
||||||
|
>
|
||||||
|
添加好友
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="divider"></div> -->
|
||||||
<div
|
<div
|
||||||
@click="toAddressBookPage"
|
@click="toAddressBookPage"
|
||||||
class="flex items-center pl-[22rpx] mt-[32rpx]"
|
class="flex items-center pl-[22rpx] py-[32rpx]"
|
||||||
>
|
>
|
||||||
<div class="mr-[26rpx] flex items-center">
|
<div class="mr-[26rpx] flex items-center">
|
||||||
<tm-image
|
<tm-image
|
||||||
@ -125,17 +156,23 @@ import { ref, watch, computed } from 'vue'
|
|||||||
import { onShow, onLoad } from '@dcloudio/uni-app'
|
import { onShow, onLoad } from '@dcloudio/uni-app'
|
||||||
import { useChatList } from '@/store/chatList/index.js'
|
import { useChatList } from '@/store/chatList/index.js'
|
||||||
import { useAuth } from '@/store/auth'
|
import { useAuth } from '@/store/auth'
|
||||||
|
import { ServeClearTalkUnreadNum } from '@/api/chat'
|
||||||
import { useTalkStore, useUserStore, useDialogueStore } from '@/store'
|
import { useTalkStore, useUserStore, useDialogueStore } from '@/store'
|
||||||
import chatItem from './components/chatItem.vue'
|
import chatItem from './components/chatItem.vue'
|
||||||
import addCircle from '@/static/image/chatList/addCircle.png'
|
import addCircle from '@/static/image/chatList/addCircle.png'
|
||||||
import cahtPopover from '@/static/image/chatList/cahtPopover.png'
|
import cahtPopover from '@/static/image/chatList/cahtPopover.png'
|
||||||
import zu3289 from '@/static/image/chatList/zu3289@2x.png'
|
import zu3289 from '@/static/image/chatList/zu3289@2x.png'
|
||||||
|
import addFriend from '@/static/image/chatList/addFriend.png'
|
||||||
import ZPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
|
import ZPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
|
||||||
|
import { handleSetWebviewStyle } from '@/utils/common'
|
||||||
const paging = ref()
|
const paging = ref()
|
||||||
const isEmptyViewShow = ref(false)
|
const isEmptyViewShow = ref(false)
|
||||||
const talkStore = useTalkStore()
|
const talkStore = useTalkStore()
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const dialogueStore = useDialogueStore()
|
const dialogueStore = useDialogueStore()
|
||||||
|
const dialogueParams = reactive({
|
||||||
|
unReadNum: computed(() => dialogueStore.unreadNum),
|
||||||
|
})
|
||||||
const { userInfo } = useAuth()
|
const { userInfo } = useAuth()
|
||||||
|
|
||||||
const topItems = computed(() => talkStore.topItems)
|
const topItems = computed(() => talkStore.topItems)
|
||||||
@ -198,11 +235,24 @@ const toSearchPage = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//点击跳转到添加好友页面
|
||||||
|
const toAddFriendPage = () => {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages/addressBook/addFriend/index',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
//点击跳转到通讯录页面
|
//点击跳转到通讯录页面
|
||||||
const toAddressBookPage = () => {
|
const toAddressBookPage = () => {
|
||||||
|
// 旧版本-按组织架构树的通讯录
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: '/pages/chooseByDeps/index?chooseMode=3',
|
url: '/pages/chooseByDeps/index?chooseMode=3',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 新版本-按公司别、好友、群组的通讯录
|
||||||
|
// uni.navigateTo({
|
||||||
|
// url: '/pages/addressBook/index',
|
||||||
|
// })
|
||||||
}
|
}
|
||||||
|
|
||||||
/* watch(
|
/* watch(
|
||||||
@ -214,6 +264,7 @@ const toAddressBookPage = () => {
|
|||||||
); */
|
); */
|
||||||
|
|
||||||
onShow(() => {
|
onShow(() => {
|
||||||
|
handleSetWebviewStyle(true)
|
||||||
// 页面显示时重新加载数据
|
// 页面显示时重新加载数据
|
||||||
talkStore
|
talkStore
|
||||||
.loadTalkList()
|
.loadTalkList()
|
||||||
@ -235,21 +286,27 @@ onLoad((options) => {
|
|||||||
if (items?.value?.length > 0) {
|
if (items?.value?.length > 0) {
|
||||||
items.value.forEach((openSession) => {
|
items.value.forEach((openSession) => {
|
||||||
if (openSession.index_name === options?.openSessionIndexName) {
|
if (openSession.index_name === options?.openSessionIndexName) {
|
||||||
|
setTimeout(() => {
|
||||||
dialogueStore.setDialogue(openSession)
|
dialogueStore.setDialogue(openSession)
|
||||||
if (openSession.unread_num > 0) {
|
if (openSession.unread_num > 0) {
|
||||||
ServeClearTalkUnreadNum({
|
ServeClearTalkUnreadNum(
|
||||||
|
{
|
||||||
talk_type: openSession.talk_type,
|
talk_type: openSession.talk_type,
|
||||||
receiver_id: openSession.receiver_id,
|
receiver_id: openSession.receiver_id,
|
||||||
}).then(() => {
|
},
|
||||||
|
dialogueParams.unReadNum,
|
||||||
|
).then(() => {
|
||||||
talkStore.updateItem({
|
talkStore.updateItem({
|
||||||
index_name: openSession.index_name,
|
index_name: openSession.index_name,
|
||||||
unread_num: 0,
|
unread_num: 0,
|
||||||
})
|
})
|
||||||
|
dialogueStore.clearUnreadNum()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: '/pages/dialog/index?sessionId=' + openSession.id,
|
url: `/pages/dialog/index?sessionId=${openSession.id}`,
|
||||||
})
|
})
|
||||||
|
}, 500)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -96,14 +96,30 @@ import {
|
|||||||
import HighlightText from './highLightText.vue'
|
import HighlightText from './highLightText.vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { beautifyTime } from '@/utils/datetime'
|
import { beautifyTime } from '@/utils/datetime'
|
||||||
|
import { ChatMsgTypeMapping } from '@/constant/message'
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
searchItem: Object | Number,
|
searchItem: Object | Number,
|
||||||
searchResultKey: String,
|
searchResultKey: {
|
||||||
searchText: String, //搜索内容
|
type: String,
|
||||||
searchRecordDetail: Boolean, //是否是搜索聊天记录详情
|
default: '',
|
||||||
pointerIconSrc: String, //箭头图标
|
},
|
||||||
conditionType: Number, //搜索类型
|
searchText: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
}, //搜索内容
|
||||||
|
searchRecordDetail: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
}, //是否是搜索聊天记录详情
|
||||||
|
pointerIconSrc: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
}, //箭头图标
|
||||||
|
conditionType: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
}, //搜索类型
|
||||||
})
|
})
|
||||||
// 映射表-查找对应结构下的属性名
|
// 映射表-查找对应结构下的属性名
|
||||||
const keyMapping = {
|
const keyMapping = {
|
||||||
@ -160,6 +176,13 @@ const keyMapping = {
|
|||||||
name: 'receiver_name',
|
name: 'receiver_name',
|
||||||
group_num: 'group_num',
|
group_num: 'group_num',
|
||||||
},
|
},
|
||||||
|
search_by_member_condition: {
|
||||||
|
avatar: 'avatar',
|
||||||
|
name: 'nickname',
|
||||||
|
created_at: 'created_at',
|
||||||
|
msg_type: 'msg_type',
|
||||||
|
detailKey: 'chatMessageType',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
//获取key对应值
|
//获取key对应值
|
||||||
const getKeyValue = (keys) => {
|
const getKeyValue = (keys) => {
|
||||||
@ -193,10 +216,8 @@ const imgText = computed(() => {
|
|||||||
})
|
})
|
||||||
// 映射表-根据groupType设置对应值
|
// 映射表-根据groupType设置对应值
|
||||||
const groupTypeMapping = {
|
const groupTypeMapping = {
|
||||||
0: {
|
0: {},
|
||||||
},
|
1: {},
|
||||||
1: {
|
|
||||||
},
|
|
||||||
2: {
|
2: {
|
||||||
result_type: t('index.mine.department'),
|
result_type: t('index.mine.department'),
|
||||||
result_type_color: '#377EC6',
|
result_type_color: '#377EC6',
|
||||||
@ -241,6 +262,12 @@ const resultDetail = computed(() => {
|
|||||||
case 'extra':
|
case 'extra':
|
||||||
result_detail = props.searchItem?.extra
|
result_detail = props.searchItem?.extra
|
||||||
break
|
break
|
||||||
|
case 'chatMessageType':
|
||||||
|
result_detail =
|
||||||
|
props.searchItem?.msg_type === 1
|
||||||
|
? props.searchItem?.extra?.content
|
||||||
|
: ChatMsgTypeMapping[props.searchItem?.msg_type]
|
||||||
|
break
|
||||||
default:
|
default:
|
||||||
result_detail = ''
|
result_detail = ''
|
||||||
}
|
}
|
||||||
@ -275,6 +302,7 @@ const resultDetail = computed(() => {
|
|||||||
padding: 2rpx 14rpx;
|
padding: 2rpx 14rpx;
|
||||||
border: 2rpx solid #000;
|
border: 2rpx solid #000;
|
||||||
border-radius: 6rpx;
|
border-radius: 6rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
span {
|
span {
|
||||||
line-height: 34rpx;
|
line-height: 34rpx;
|
||||||
}
|
}
|
||||||
@ -299,6 +327,7 @@ const resultDetail = computed(() => {
|
|||||||
.info-detail-searchRecordDetail {
|
.info-detail-searchRecordDetail {
|
||||||
span {
|
span {
|
||||||
color: $theme-text;
|
color: $theme-text;
|
||||||
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
:default-page-size="props.searchResultPageSize"
|
:default-page-size="props.searchResultPageSize"
|
||||||
:loading-more-default-as-loading="true"
|
:loading-more-default-as-loading="true"
|
||||||
:inside-more="true"
|
:inside-more="true"
|
||||||
:empty-view-img="'/src/static//image/search/search-no-data.png'"
|
:empty-view-img="searchNoData"
|
||||||
:empty-view-text="$t('search.hint')"
|
:empty-view-text="$t('search.hint')"
|
||||||
:empty-view-img-style="{ width: '476rpx', height: '261rpx' }"
|
:empty-view-img-style="{ width: '476rpx', height: '261rpx' }"
|
||||||
:empty-view-title-style="{
|
:empty-view-title-style="{
|
||||||
@ -19,6 +19,7 @@
|
|||||||
'font-size': '28rpx',
|
'font-size': '28rpx',
|
||||||
'font-weight': 400,
|
'font-weight': 400,
|
||||||
}"
|
}"
|
||||||
|
:refresher-enabled="false"
|
||||||
>
|
>
|
||||||
<template #top>
|
<template #top>
|
||||||
<div class="searchRoot">
|
<div class="searchRoot">
|
||||||
@ -35,7 +36,10 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div class="search-record-detail" v-if="props.searchRecordDetail">
|
<div
|
||||||
|
class="search-record-detail"
|
||||||
|
v-if="props.searchRecordDetail && !props?.hideFirstRecord"
|
||||||
|
>
|
||||||
<searchItem
|
<searchItem
|
||||||
@click="
|
@click="
|
||||||
clickSearchItem(
|
clickSearchItem(
|
||||||
@ -109,6 +113,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import searchNoData from '@/static/image/search/search-no-data.png'
|
||||||
import customInput from '@/components/custom-input/custom-input.vue'
|
import customInput from '@/components/custom-input/custom-input.vue'
|
||||||
import ZPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
|
import ZPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
|
||||||
import useZPaging from '@/uni_modules/z-paging/components/z-paging/js/hooks/useZPaging.js'
|
import useZPaging from '@/uni_modules/z-paging/components/z-paging/js/hooks/useZPaging.js'
|
||||||
@ -117,6 +122,10 @@ import { useI18n } from 'vue-i18n'
|
|||||||
import { ref, reactive, defineEmits, defineProps, onMounted } from 'vue'
|
import { ref, reactive, defineEmits, defineProps, onMounted } from 'vue'
|
||||||
import pointerIconSrc from '@/static/image/search/search-item-pointer.png'
|
import pointerIconSrc from '@/static/image/search/search-item-pointer.png'
|
||||||
|
|
||||||
|
import lodash from 'lodash'
|
||||||
|
import { useUserStore } from '@/store'
|
||||||
|
const userStore = useUserStore()
|
||||||
|
|
||||||
const zPaging = ref()
|
const zPaging = ref()
|
||||||
useZPaging(zPaging)
|
useZPaging(zPaging)
|
||||||
|
|
||||||
@ -131,17 +140,45 @@ const state = reactive({
|
|||||||
searchResultList: [], //搜素结果列表
|
searchResultList: [], //搜素结果列表
|
||||||
searchResult: null, //搜索结果
|
searchResult: null, //搜索结果
|
||||||
pageNum: 1, //当前请求数据页数
|
pageNum: 1, //当前请求数据页数
|
||||||
|
uid: computed(() => userStore.uid), //当前用户id
|
||||||
})
|
})
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
searchResultPageSize: Number, //搜索结果每页数据量
|
searchResultPageSize: {
|
||||||
listLimit: Boolean, //是否限制列表内数据数量
|
type: Number,
|
||||||
apiParams: String, //请求参数
|
default: 0,
|
||||||
|
}, //搜索结果每页数据量
|
||||||
|
listLimit: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
}, //是否限制列表内数据数量
|
||||||
|
apiParams: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
}, //请求参数
|
||||||
apiRequest: Function, //请求
|
apiRequest: Function, //请求
|
||||||
searchText: String, //搜索内容
|
searchText: {
|
||||||
isPagination: Boolean, //是否分页
|
type: String,
|
||||||
searchRecordDetail: Boolean, //是否是搜索聊天记录的详情
|
default: '',
|
||||||
first_talk_record_infos: Object, //接受者信息
|
}, //搜索内容
|
||||||
|
isPagination: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
}, //是否分页
|
||||||
|
searchRecordDetail: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
}, //是否是搜索聊天记录的详情
|
||||||
|
first_talk_record_infos: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
}, //接受者信息
|
||||||
|
hideFirstRecord: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
}, //是否隐藏前缀及搜索群/用户主体信息
|
||||||
})
|
})
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
@ -154,13 +191,14 @@ onMounted(() => {
|
|||||||
|
|
||||||
//输入搜索文本
|
//输入搜索文本
|
||||||
const inputSearchText = (e) => {
|
const inputSearchText = (e) => {
|
||||||
// console.log(e)
|
|
||||||
if (e.trim() != state.searchText.trim()) {
|
if (e.trim() != state.searchText.trim()) {
|
||||||
state.pageNum = 1
|
state.pageNum = 1
|
||||||
|
state.searchResult = null // 清空搜索结果
|
||||||
emits('lastIdChange', 0, 0, 0)
|
emits('lastIdChange', 0, 0, 0)
|
||||||
}
|
}
|
||||||
state.searchText = e.trim()
|
state.searchText = e.trim()
|
||||||
if (!e.trim()) {
|
if (!e.trim()) {
|
||||||
|
state.searchResult = null // 清空搜索结果
|
||||||
emits('lastIdChange', 0, 0, 0)
|
emits('lastIdChange', 0, 0, 0)
|
||||||
}
|
}
|
||||||
zPaging.value?.reload()
|
zPaging.value?.reload()
|
||||||
@ -197,15 +235,35 @@ const queryAllSearch = (pageNum, searchResultPageSize) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
if ((data.talk_record_infos || []).length > 0) {
|
if ((data.talk_record_infos || []).length > 0) {
|
||||||
|
let receiverInfo = lodash.cloneDeep(data.talk_record_infos[0])
|
||||||
|
if (receiverInfo.talk_type === 1) {
|
||||||
|
//单聊才需此判断
|
||||||
|
if (receiverInfo.user_id === state.uid) {
|
||||||
|
//发送人是自己,接收人不需要变
|
||||||
|
}
|
||||||
|
if (receiverInfo.receiver_id === state.uid) {
|
||||||
|
//接收人是自己,这里需要变成对方
|
||||||
|
let temp_id = receiverInfo.receiver_id
|
||||||
|
let temp_name = receiverInfo.receiver_name
|
||||||
|
let temp_avatar = receiverInfo.receiver_avatar
|
||||||
|
receiverInfo.receiver_id = receiverInfo.user_id
|
||||||
|
receiverInfo.receiver_name = receiverInfo.user_name
|
||||||
|
receiverInfo.receiver_avatar = receiverInfo.user_avatar
|
||||||
|
receiverInfo.user_id = temp_id
|
||||||
|
receiverInfo.user_name = temp_name
|
||||||
|
receiverInfo.user_avatar = temp_avatar
|
||||||
|
}
|
||||||
|
}
|
||||||
state.first_talk_record_infos = Object.assign(
|
state.first_talk_record_infos = Object.assign(
|
||||||
{},
|
{},
|
||||||
state.first_talk_record_infos,
|
state.first_talk_record_infos,
|
||||||
data.talk_record_infos[0],
|
receiverInfo,
|
||||||
)
|
)
|
||||||
;(data.talk_record_infos || []).forEach((item) => {
|
;(data.talk_record_infos || []).forEach((item) => {
|
||||||
item.group_type = 0
|
item.group_type = 0
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let tempGeneral_infos = Array.isArray(data.general_infos)
|
let tempGeneral_infos = Array.isArray(data.general_infos)
|
||||||
? [...data.general_infos]
|
? [...data.general_infos]
|
||||||
: data.general_infos
|
: data.general_infos
|
||||||
@ -214,6 +272,8 @@ const queryAllSearch = (pageNum, searchResultPageSize) => {
|
|||||||
data.group_member_infos || [],
|
data.group_member_infos || [],
|
||||||
)
|
)
|
||||||
data.general_infos = tempGeneral_infos
|
data.general_infos = tempGeneral_infos
|
||||||
|
|
||||||
|
// 检查数据是否为空
|
||||||
let isEmpty = true
|
let isEmpty = true
|
||||||
let dataKeys = Object.keys(data)
|
let dataKeys = Object.keys(data)
|
||||||
let paginationKey = ''
|
let paginationKey = ''
|
||||||
@ -223,58 +283,147 @@ const queryAllSearch = (pageNum, searchResultPageSize) => {
|
|||||||
isEmpty = false
|
isEmpty = false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
if (isEmpty) {
|
if (isEmpty) {
|
||||||
if (pageNum == 1) {
|
if (pageNum === 1) {
|
||||||
|
// 第一页请求且为空,清空结果
|
||||||
|
state.searchResult = null
|
||||||
zPaging.value?.complete([])
|
zPaging.value?.complete([])
|
||||||
} else {
|
} else {
|
||||||
data = state.searchResult
|
// 加载更多且为空,保持原列表不变
|
||||||
zPaging.value?.complete([data])
|
zPaging.value?.complete(
|
||||||
|
state.searchResult ? [state.searchResult] : [],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (props.isPagination) {
|
if (props.isPagination) {
|
||||||
|
if (pageNum === 1) {
|
||||||
|
// 第一页请求,直接设置新数据
|
||||||
|
state.searchResult = data
|
||||||
|
} else {
|
||||||
|
// 加载更多,合并数据
|
||||||
if (
|
if (
|
||||||
paginationKey &&
|
paginationKey &&
|
||||||
Array.isArray(
|
Array.isArray(
|
||||||
(state?.searchResult && state?.searchResult[paginationKey]) || [],
|
(state?.searchResult && state?.searchResult[paginationKey]) ||
|
||||||
) &&
|
[],
|
||||||
((state?.searchResult && state?.searchResult[paginationKey]) || [])
|
)
|
||||||
.length > 0
|
|
||||||
) {
|
) {
|
||||||
data[paginationKey] = state.searchResult[paginationKey].concat(
|
data[paginationKey] = state.searchResult[paginationKey].concat(
|
||||||
data[paginationKey],
|
data[paginationKey],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
state.searchResult = data
|
||||||
|
}
|
||||||
|
|
||||||
emits(
|
emits(
|
||||||
'lastIdChange',
|
'lastIdChange',
|
||||||
data.last_id,
|
data.last_id,
|
||||||
data.last_group_id,
|
data.last_group_id,
|
||||||
data.last_member_id,
|
data.last_member_id,
|
||||||
|
data.last_receiver_user_name,
|
||||||
|
data.last_receiver_group_name,
|
||||||
)
|
)
|
||||||
let total = data.count
|
let total = data.count
|
||||||
if (props.searchRecordDetail) {
|
if (props.searchRecordDetail) {
|
||||||
|
if (state?.first_talk_record_infos?.talk_type === 1) {
|
||||||
|
total = data.user_record_count
|
||||||
|
} else if (state?.first_talk_record_infos?.talk_type === 2) {
|
||||||
total = data.group_record_count
|
total = data.group_record_count
|
||||||
}
|
}
|
||||||
zPaging.value?.completeByTotal([data], total)
|
let noMoreSearchResultRecord = true
|
||||||
|
if (
|
||||||
|
Object.keys(data).includes('talk_record_infos') &&
|
||||||
|
state.searchResult['talk_record_infos']?.length > 0
|
||||||
|
) {
|
||||||
|
//搜聊天记录详情
|
||||||
|
if (state.searchResult['talk_record_infos']?.length < total) {
|
||||||
|
noMoreSearchResultRecord = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
zPaging.value?.completeByNoMore([data], noMoreSearchResultRecord)
|
||||||
} else {
|
} else {
|
||||||
|
let noMoreSearchResultUser = true
|
||||||
|
let noMoreSearchResultGroup = true
|
||||||
|
let noMoreSearchResultGeneral = true
|
||||||
|
if (
|
||||||
|
Object.keys(data).includes('user_infos') &&
|
||||||
|
state.searchResult['user_infos']?.length > 0
|
||||||
|
) {
|
||||||
|
//搜人
|
||||||
|
if (state.searchResult['user_infos']?.length < total) {
|
||||||
|
noMoreSearchResultUser = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
Object.keys(data).includes(
|
||||||
|
'group_member_infos' || 'group_infos',
|
||||||
|
) &&
|
||||||
|
state.searchResult['combinedGroup']?.length > 0
|
||||||
|
) {
|
||||||
|
//搜群
|
||||||
|
if (state.searchResult['combinedGroup']?.length < total) {
|
||||||
|
noMoreSearchResultGroup = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
Object.keys(data).includes('general_infos') &&
|
||||||
|
state.searchResult['general_infos']?.length > 0
|
||||||
|
) {
|
||||||
|
//搜聊天记录
|
||||||
|
if (state.searchResult['general_infos']?.length < total) {
|
||||||
|
noMoreSearchResultGeneral = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// zPaging.value?.completeByTotal([data], total)
|
||||||
|
zPaging.value?.completeByNoMore(
|
||||||
|
[data],
|
||||||
|
noMoreSearchResultUser &&
|
||||||
|
noMoreSearchResultGroup &&
|
||||||
|
noMoreSearchResultGeneral,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
state.searchResult = data
|
||||||
zPaging.value?.complete([data])
|
zPaging.value?.complete([data])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
state.searchResult = data
|
|
||||||
} else {
|
} else {
|
||||||
|
if (pageNum === 1) {
|
||||||
|
// 第一页请求失败,清空结果
|
||||||
|
state.searchResult = null
|
||||||
zPaging.value?.complete([])
|
zPaging.value?.complete([])
|
||||||
|
} else {
|
||||||
|
// 加载更多失败,保持原列表不变
|
||||||
|
zPaging.value?.complete(state.searchResult ? [state.searchResult] : [])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
resp.catch(() => {
|
resp.catch(() => {
|
||||||
|
if (pageNum === 1) {
|
||||||
|
// 第一页请求异常,清空结果
|
||||||
|
state.searchResult = null
|
||||||
zPaging.value?.complete([])
|
zPaging.value?.complete([])
|
||||||
|
} else {
|
||||||
|
// 加载更多异常,保持原列表不变
|
||||||
|
zPaging.value?.complete(state.searchResult ? [state.searchResult] : [])
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//点击取消搜索
|
//点击取消搜索
|
||||||
const cancelSearch = () => {
|
const cancelSearch = () => {
|
||||||
|
const pages = getCurrentPages()
|
||||||
|
if (pages.length > 1) {
|
||||||
uni.navigateBack({
|
uni.navigateBack({
|
||||||
delta: 1,
|
delta: 1,
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
uni.reLaunch({
|
||||||
|
url: '/pages/index/index',
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取key对应值
|
//获取key对应值
|
||||||
@ -342,6 +491,12 @@ const getHasMoreResult = (searchResultKey) => {
|
|||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 'general_infos':
|
case 'general_infos':
|
||||||
|
if (
|
||||||
|
state.searchResult['record_count'] &&
|
||||||
|
state.searchResult['record_count'] >= 3
|
||||||
|
) {
|
||||||
|
has_more_result = t('has_more') + t('chat.type.record')
|
||||||
|
}
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
@ -355,12 +510,41 @@ const toMoreResultPage = (searchResultKey) => {
|
|||||||
|
|
||||||
//点击了搜索结果项
|
//点击了搜索结果项
|
||||||
const clickSearchItem = (searchResultKey, searchItem) => {
|
const clickSearchItem = (searchResultKey, searchItem) => {
|
||||||
|
console.log(searchResultKey, searchItem)
|
||||||
|
let talk_type = searchItem.talk_type
|
||||||
|
let receiver_id = searchItem.receiver_id
|
||||||
|
if (searchResultKey === 'user_infos') {
|
||||||
|
talk_type = 1
|
||||||
|
receiver_id = searchItem.id
|
||||||
|
} else if (searchResultKey === 'combinedGroup') {
|
||||||
|
talk_type = searchItem.type || 2
|
||||||
|
receiver_id = searchItem.group_id || searchItem.id
|
||||||
|
} else if (searchResultKey === 'general_infos') {
|
||||||
|
if (searchItem.talk_type === 1) {
|
||||||
|
if (searchItem.user_id === state.uid) {
|
||||||
|
//发送人是自己,接收人不需要变
|
||||||
|
}
|
||||||
|
if (searchItem.receiver_id === state.uid) {
|
||||||
|
//接收人是自己,这里需要变成对方
|
||||||
|
let temp_id = searchItem.receiver_id
|
||||||
|
let temp_name = searchItem.receiver_name
|
||||||
|
let temp_avatar = searchItem.receiver_avatar
|
||||||
|
searchItem.receiver_id = searchItem.user_id
|
||||||
|
searchItem.receiver_name = searchItem.user_name
|
||||||
|
searchItem.receiver_avatar = searchItem.user_avatar
|
||||||
|
searchItem.user_id = temp_id
|
||||||
|
searchItem.user_name = temp_name
|
||||||
|
searchItem.user_avatar = temp_avatar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
emits(
|
emits(
|
||||||
'clickSearchItem',
|
'clickSearchItem',
|
||||||
state.searchText,
|
state.searchText,
|
||||||
searchResultKey,
|
searchResultKey,
|
||||||
searchItem.talk_type,
|
talk_type,
|
||||||
searchItem.receiver_id,
|
receiver_id,
|
||||||
|
encodeURIComponent(JSON.stringify(searchItem)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -13,7 +13,19 @@
|
|||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import searchList from './components/searchList.vue'
|
import searchList from './components/searchList.vue'
|
||||||
import { ServeSeachQueryAll } from '@/api/search/index'
|
import { ServeSeachQueryAll, ServeGetSessionId } from '@/api/search/index'
|
||||||
|
import { onMounted } from 'vue'
|
||||||
|
import { handleSetWebviewStyle } from '@/utils/common'
|
||||||
|
|
||||||
|
import { useDialogueStore, useTalkStore } from '@/store'
|
||||||
|
import { ServeCreateTalkList } from '@/api/chat/index.js'
|
||||||
|
import { formatTalkItem } from '@/utils/talk'
|
||||||
|
|
||||||
|
const dialogueStore = useDialogueStore()
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
handleSetWebviewStyle()
|
||||||
|
})
|
||||||
|
|
||||||
//点击跳转到更多结果页面
|
//点击跳转到更多结果页面
|
||||||
const toMoreResultPage = (searchResultKey, searchText) => {
|
const toMoreResultPage = (searchResultKey, searchText) => {
|
||||||
@ -27,14 +39,49 @@ const toMoreResultPage = (searchResultKey, searchText) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//点击了搜索结果项
|
//点击了搜索结果项
|
||||||
const clickSearchItem = (
|
const clickSearchItem = async (
|
||||||
searchText,
|
searchText,
|
||||||
searchResultKey,
|
searchResultKey,
|
||||||
talk_type,
|
talk_type,
|
||||||
receiver_id,
|
receiver_id,
|
||||||
|
res,
|
||||||
) => {
|
) => {
|
||||||
console.log(searchResultKey)
|
console.log(searchResultKey)
|
||||||
if (searchResultKey === 'general_infos') {
|
const result = JSON.parse(decodeURIComponent(res))
|
||||||
|
console.log(result)
|
||||||
|
console.log(talk_type, receiver_id)
|
||||||
|
const sessionId = await getSessionId(talk_type, receiver_id)
|
||||||
|
if (searchResultKey === 'user_infos') {
|
||||||
|
if (useTalkStore().findTalkIndex(`${talk_type}_${receiver_id}`) === -1) {
|
||||||
|
ServeCreateTalkList({
|
||||||
|
talk_type,
|
||||||
|
receiver_id,
|
||||||
|
erp_user_id: result.erp_user_id,
|
||||||
|
}).then(async ({ code, data }) => {
|
||||||
|
if (code == 200) {
|
||||||
|
let item = formatTalkItem(data)
|
||||||
|
useTalkStore().addItem(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
dialogueStore.setDialogue({
|
||||||
|
name: result.nickname,
|
||||||
|
talk_type: 1,
|
||||||
|
receiver_id: receiver_id,
|
||||||
|
})
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages/dialog/index?sessionId=' + sessionId,
|
||||||
|
})
|
||||||
|
} else if (searchResultKey === 'combinedGroup') {
|
||||||
|
dialogueStore.setDialogue({
|
||||||
|
name: result.name || result.group_name,
|
||||||
|
talk_type: result.type || 2,
|
||||||
|
receiver_id: result.group_id || result.id,
|
||||||
|
})
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages/dialog/index?sessionId=' + sessionId,
|
||||||
|
})
|
||||||
|
} else if (searchResultKey === 'general_infos') {
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url:
|
url:
|
||||||
'/pages/search/moreResult/moreResultDetail?searchText=' +
|
'/pages/search/moreResult/moreResultDetail?searchText=' +
|
||||||
@ -46,5 +93,25 @@ const clickSearchItem = (
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//获取会话Id
|
||||||
|
const getSessionId = (talk_type, receiver_id) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let params = {
|
||||||
|
talkType: talk_type,
|
||||||
|
receiverId: receiver_id,
|
||||||
|
}
|
||||||
|
const resp = ServeGetSessionId(params)
|
||||||
|
console.log(resp)
|
||||||
|
resp.then(({ code, data }) => {
|
||||||
|
console.log(data)
|
||||||
|
if (code == 200) {
|
||||||
|
resolve(data?.sessionId)
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
})
|
||||||
|
resp.catch(() => {})
|
||||||
|
})
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss"></style>
|
<style scoped lang="scss"></style>
|
||||||
|
|||||||
@ -21,14 +21,21 @@ import {
|
|||||||
ServeQueryUser,
|
ServeQueryUser,
|
||||||
ServeQueryGroup,
|
ServeQueryGroup,
|
||||||
ServeTalkRecord,
|
ServeTalkRecord,
|
||||||
|
ServeGetSessionId,
|
||||||
} from '@/api/search/index'
|
} from '@/api/search/index'
|
||||||
import { reactive } from 'vue'
|
import { reactive } from 'vue'
|
||||||
|
|
||||||
|
import { useDialogueStore, useTalkStore } from '@/store'
|
||||||
|
import { ServeCreateTalkList } from '@/api/chat/index.js'
|
||||||
|
import { formatTalkItem } from '@/utils/talk'
|
||||||
|
|
||||||
|
const dialogueStore = useDialogueStore()
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
apiRequest: Function,
|
apiRequest: Function,
|
||||||
apiParams: String,
|
apiParams: '',
|
||||||
searchText: String,
|
searchText: '',
|
||||||
searchResultKey: String,
|
searchResultKey: '',
|
||||||
})
|
})
|
||||||
|
|
||||||
onLoad((options) => {
|
onLoad((options) => {
|
||||||
@ -57,6 +64,8 @@ onLoad((options) => {
|
|||||||
receiver_id: 0, //查详情的时候需传入
|
receiver_id: 0, //查详情的时候需传入
|
||||||
last_group_id: 0, //最后一条群id
|
last_group_id: 0, //最后一条群id
|
||||||
last_member_id: 0, //最后一条用户id
|
last_member_id: 0, //最后一条用户id
|
||||||
|
last_receiver_user_name: '', //最后一条用户名
|
||||||
|
last_receiver_group_name: '', //最后一条群名
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
state.apiRequest = ServeTalkRecord
|
state.apiRequest = ServeTalkRecord
|
||||||
@ -68,11 +77,19 @@ onLoad((options) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
//分页查询时,最后一条id变化
|
//分页查询时,最后一条id变化
|
||||||
const lastIdChange = (last_id, last_group_id, last_member_id) => {
|
const lastIdChange = (
|
||||||
|
last_id,
|
||||||
|
last_group_id,
|
||||||
|
last_member_id,
|
||||||
|
last_receiver_user_name,
|
||||||
|
last_receiver_group_name,
|
||||||
|
) => {
|
||||||
let idChanges = {
|
let idChanges = {
|
||||||
last_id,
|
last_id,
|
||||||
last_group_id,
|
last_group_id,
|
||||||
last_member_id,
|
last_member_id,
|
||||||
|
last_receiver_user_name,
|
||||||
|
last_receiver_group_name,
|
||||||
}
|
}
|
||||||
state.apiParams = encodeURIComponent(
|
state.apiParams = encodeURIComponent(
|
||||||
JSON.stringify(
|
JSON.stringify(
|
||||||
@ -86,12 +103,79 @@ const lastIdChange = (last_id, last_group_id, last_member_id) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//点击了搜索结果项
|
//点击了搜索结果项
|
||||||
const clickSearchItem = (searchText) => {
|
const clickSearchItem = async (
|
||||||
if (state.searchResultKey === 'general_infos') {
|
searchText,
|
||||||
|
searchResultKey,
|
||||||
|
talk_type,
|
||||||
|
receiver_id,
|
||||||
|
res,
|
||||||
|
) => {
|
||||||
|
console.log(state.searchResultKey)
|
||||||
|
const result = JSON.parse(decodeURIComponent(res))
|
||||||
|
console.log(result)
|
||||||
|
console.log(talk_type, receiver_id)
|
||||||
|
const sessionId = await getSessionId(talk_type, receiver_id)
|
||||||
|
if (state.searchResultKey === 'user_infos') {
|
||||||
|
if (useTalkStore().findTalkIndex(`${talk_type}_${receiver_id}`) === -1) {
|
||||||
|
ServeCreateTalkList({
|
||||||
|
talk_type,
|
||||||
|
receiver_id,
|
||||||
|
erp_user_id: result.erp_user_id,
|
||||||
|
}).then(async ({ code, data }) => {
|
||||||
|
if (code == 200) {
|
||||||
|
let item = formatTalkItem(data)
|
||||||
|
useTalkStore().addItem(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
dialogueStore.setDialogue({
|
||||||
|
name: result.nickname,
|
||||||
|
talk_type: 1,
|
||||||
|
receiver_id: receiver_id,
|
||||||
|
})
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: '/pages/search/moreResult/moreResultDetail?searchText=' + searchText,
|
url: '/pages/dialog/index?sessionId=' + sessionId,
|
||||||
|
})
|
||||||
|
} else if (state.searchResultKey === 'combinedGroup') {
|
||||||
|
dialogueStore.setDialogue({
|
||||||
|
name: result.name || result.group_name,
|
||||||
|
talk_type: result.type || 2,
|
||||||
|
receiver_id: result.group_id || result.id,
|
||||||
|
})
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages/dialog/index?sessionId=' + sessionId,
|
||||||
|
})
|
||||||
|
} else if (state.searchResultKey === 'general_infos') {
|
||||||
|
uni.navigateTo({
|
||||||
|
url:
|
||||||
|
'/pages/search/moreResult/moreResultDetail?searchText=' +
|
||||||
|
searchText +
|
||||||
|
'&talk_type=' +
|
||||||
|
talk_type +
|
||||||
|
'&receiver_id=' +
|
||||||
|
receiver_id,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//获取会话Id
|
||||||
|
const getSessionId = (talk_type, receiver_id) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let params = {
|
||||||
|
talkType: talk_type,
|
||||||
|
receiverId: receiver_id,
|
||||||
|
}
|
||||||
|
const resp = ServeGetSessionId(params)
|
||||||
|
console.log(resp)
|
||||||
|
resp.then(({ code, data }) => {
|
||||||
|
console.log(data)
|
||||||
|
if (code == 200) {
|
||||||
|
resolve(data?.sessionId)
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
})
|
||||||
|
resp.catch(() => {})
|
||||||
|
})
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss"></style>
|
<style scoped lang="scss"></style>
|
||||||
|
|||||||
@ -7,9 +7,11 @@
|
|||||||
:apiRequest="ServeTalkRecord"
|
:apiRequest="ServeTalkRecord"
|
||||||
:apiParams="state.apiParams"
|
:apiParams="state.apiParams"
|
||||||
:searchText="state.searchText"
|
:searchText="state.searchText"
|
||||||
|
:hideFirstRecord="state.hideFirstRecord"
|
||||||
:isPagination="true"
|
:isPagination="true"
|
||||||
:searchRecordDetail="true"
|
:searchRecordDetail="true"
|
||||||
@lastIdChange="lastIdChange"
|
@lastIdChange="lastIdChange"
|
||||||
|
@clickSearchItem="clickSearchItem"
|
||||||
></searchList>
|
></searchList>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -19,10 +21,17 @@ import searchList from '../components/searchList.vue'
|
|||||||
import { onLoad } from '@dcloudio/uni-app'
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
import { ServeTalkRecord } from '@/api/search/index'
|
import { ServeTalkRecord } from '@/api/search/index'
|
||||||
import { reactive } from 'vue'
|
import { reactive } from 'vue'
|
||||||
|
import { useDialogueStore, useUserStore } from '@/store'
|
||||||
|
import lodash from 'lodash'
|
||||||
|
|
||||||
|
const dialogueStore = useDialogueStore()
|
||||||
|
const userStore = useUserStore()
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
apiParams: String,
|
apiParams: '',
|
||||||
searchText: String,
|
searchText: '',
|
||||||
|
uid: computed(() => userStore.uid), //当前用户id
|
||||||
|
hideFirstRecord: false, //是否隐藏前缀及搜索群/用户主体信息
|
||||||
})
|
})
|
||||||
|
|
||||||
onLoad((options) => {
|
onLoad((options) => {
|
||||||
@ -48,6 +57,10 @@ onLoad((options) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
console.log(JSON.parse(decodeURIComponent(state.apiParams)))
|
console.log(JSON.parse(decodeURIComponent(state.apiParams)))
|
||||||
|
|
||||||
|
if (options.hideFirstRecord) {
|
||||||
|
state.hideFirstRecord = options.hideFirstRecord === '1' ? true : false
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
//分页查询时,最后一条id变化
|
//分页查询时,最后一条id变化
|
||||||
@ -67,5 +80,51 @@ const lastIdChange = (last_id, last_group_id, last_member_id) => {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//点击了搜索结果项
|
||||||
|
const clickSearchItem = (
|
||||||
|
searchText,
|
||||||
|
searchResultKey,
|
||||||
|
talk_type,
|
||||||
|
receiver_id,
|
||||||
|
res,
|
||||||
|
) => {
|
||||||
|
console.log(searchResultKey)
|
||||||
|
let result = JSON.parse(decodeURIComponent(res))
|
||||||
|
console.log(result)
|
||||||
|
let receiverInfo = lodash.cloneDeep(result)
|
||||||
|
if (receiverInfo.talk_type === 1) {
|
||||||
|
//单聊才需此判断
|
||||||
|
if (receiverInfo.user_id === state.uid) {
|
||||||
|
//发送人是自己,接收人不需要变
|
||||||
|
}
|
||||||
|
if (receiverInfo.receiver_id === state.uid) {
|
||||||
|
//接收人是自己,这里需要变成对方
|
||||||
|
let temp_id = receiverInfo.receiver_id
|
||||||
|
let temp_name = receiverInfo.receiver_name
|
||||||
|
let temp_avatar = receiverInfo.receiver_avatar
|
||||||
|
receiverInfo.receiver_id = receiverInfo.user_id
|
||||||
|
receiverInfo.receiver_name = receiverInfo.user_name
|
||||||
|
receiverInfo.receiver_avatar = receiverInfo.user_avatar
|
||||||
|
receiverInfo.user_id = temp_id
|
||||||
|
receiverInfo.user_name = temp_name
|
||||||
|
receiverInfo.user_avatar = temp_avatar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dialogueStore.setDialogue({
|
||||||
|
name: receiverInfo.receiver_name,
|
||||||
|
talk_type: talk_type,
|
||||||
|
receiver_id: receiverInfo.receiver_id,
|
||||||
|
})
|
||||||
|
if (searchResultKey === 'talk_record_infos_receiver') {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages/dialog/index',
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages/dialog/index?msgInfo=' + res + '&keepDialogInfo=1',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss"></style>
|
<style scoped lang="scss"></style>
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
:auto="false"
|
:auto="false"
|
||||||
:loading-more-default-as-loading="true"
|
:loading-more-default-as-loading="true"
|
||||||
:inside-more="true"
|
:inside-more="true"
|
||||||
|
v-model="state.flatList"
|
||||||
>
|
>
|
||||||
<template #top v-if="state.showPageTitle">
|
<template #top v-if="state.showPageTitle">
|
||||||
<customNavbar :title="state.pageTitle"></customNavbar>
|
<customNavbar :title="state.pageTitle"></customNavbar>
|
||||||
@ -41,7 +42,7 @@
|
|||||||
<span class="text-[28rpx] font-regular">
|
<span class="text-[28rpx] font-regular">
|
||||||
{{ state.selectedMonth }}
|
{{ state.selectedMonth }}
|
||||||
</span>
|
</span>
|
||||||
<img src="/src/static/image/search/down-pointer.png" />
|
<img src="@/static/image/search/down-pointer.png" />
|
||||||
</div>
|
</div>
|
||||||
</tm-time-picker>
|
</tm-time-picker>
|
||||||
<tm-calendar-view
|
<tm-calendar-view
|
||||||
@ -64,7 +65,8 @@
|
|||||||
v-if="
|
v-if="
|
||||||
state.condition === 'imgAndVideo' ||
|
state.condition === 'imgAndVideo' ||
|
||||||
state.condition === 'file' ||
|
state.condition === 'file' ||
|
||||||
state.condition === 'link'
|
state.condition === 'link' ||
|
||||||
|
state.condition === 'member'
|
||||||
"
|
"
|
||||||
:style="{
|
:style="{
|
||||||
padding: state.condition === 'imgAndVideo' ? '0 27rpx' : '',
|
padding: state.condition === 'imgAndVideo' ? '0 27rpx' : '',
|
||||||
@ -112,11 +114,27 @@
|
|||||||
v-for="(item, index) in conditionItem.monthResultList"
|
v-for="(item, index) in conditionItem.monthResultList"
|
||||||
:key="index"
|
:key="index"
|
||||||
:style="{
|
:style="{
|
||||||
border: state.condition === 'imgAndVideo' ? '0' : '',
|
border:
|
||||||
|
state.condition === 'imgAndVideo' ||
|
||||||
|
state.condition === 'member'
|
||||||
|
? '0'
|
||||||
|
: '',
|
||||||
padding:
|
padding:
|
||||||
state.condition === 'imgAndVideo' ? '0 0 10rpx' : '',
|
state.condition === 'imgAndVideo' ? '0 0 10rpx' : '',
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
|
<div
|
||||||
|
class="condition-result-member"
|
||||||
|
v-if="state.condition === 'member'"
|
||||||
|
>
|
||||||
|
<searchItem
|
||||||
|
@click="toDialogueByMember(item)"
|
||||||
|
:searchResultKey="'search_by_member_condition'"
|
||||||
|
:searchItem="item"
|
||||||
|
:searchText="state.searchText"
|
||||||
|
:searchRecordDetail="true"
|
||||||
|
></searchItem>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
class="condition-result-imgAndVideo"
|
class="condition-result-imgAndVideo"
|
||||||
v-if="state.condition === 'imgAndVideo'"
|
v-if="state.condition === 'imgAndVideo'"
|
||||||
@ -142,17 +160,27 @@
|
|||||||
class="condition-result-imgAndVideo-area"
|
class="condition-result-imgAndVideo-area"
|
||||||
v-if="item?.extra?.url"
|
v-if="item?.extra?.url"
|
||||||
>
|
>
|
||||||
|
<template v-if="item?.msg_type === 3">
|
||||||
<tm-image
|
<tm-image
|
||||||
preview
|
preview
|
||||||
:src="
|
:src="item?.extra?.url"
|
||||||
item?.msg_type === 3
|
|
||||||
? item?.extra?.url
|
|
||||||
: item?.msg_type === 5
|
|
||||||
? item?.extra?.cover
|
|
||||||
: ''
|
|
||||||
"
|
|
||||||
model="aspectFill"
|
model="aspectFill"
|
||||||
/>
|
/>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="item?.msg_type === 5">
|
||||||
|
<div
|
||||||
|
class="video-preview"
|
||||||
|
@click="onPlay(item?.extra?.url)"
|
||||||
|
>
|
||||||
|
<tm-image
|
||||||
|
:src="item?.extra?.cover"
|
||||||
|
model="aspectFill"
|
||||||
|
/>
|
||||||
|
<div class="play-icon">
|
||||||
|
<img :src="playCircle" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@ -173,6 +201,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="condition-each-result-attachments"
|
class="condition-each-result-attachments"
|
||||||
|
@click="previewPDF(item)"
|
||||||
v-if="
|
v-if="
|
||||||
state.condition === 'file' || state.condition === 'link'
|
state.condition === 'file' || state.condition === 'link'
|
||||||
"
|
"
|
||||||
@ -183,7 +212,7 @@
|
|||||||
v-if="state.condition === 'file'"
|
v-if="state.condition === 'file'"
|
||||||
/>
|
/>
|
||||||
<img
|
<img
|
||||||
src="/src/static/image/search/result-link-icon.png"
|
src="@/static/image/search/result-link-icon.png"
|
||||||
v-if="state.condition === 'link'"
|
v-if="state.condition === 'link'"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -238,6 +267,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ZPaging>
|
</ZPaging>
|
||||||
|
<teleport to="body">
|
||||||
|
<div v-show="open" class="video-container">
|
||||||
|
<video
|
||||||
|
:src="currentVideoUrl"
|
||||||
|
controls
|
||||||
|
@fullscreenchange="fullscreenchange"
|
||||||
|
:id="currentVideoUrl"
|
||||||
|
playsinline
|
||||||
|
webkit-playsinline
|
||||||
|
x5-playsinline
|
||||||
|
class="fullscreen-video"
|
||||||
|
></video>
|
||||||
|
</div>
|
||||||
|
</teleport>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -247,15 +290,16 @@ import fileType_EXCEL from '@/static/image/search/fileType_EXCEL.png'
|
|||||||
import fileType_WORD from '@/static/image/search/fileType_WORD.png'
|
import fileType_WORD from '@/static/image/search/fileType_WORD.png'
|
||||||
import fileType_PDF from '@/static/image/search/fileType_PDF.png'
|
import fileType_PDF from '@/static/image/search/fileType_PDF.png'
|
||||||
import fileType_Files from '@/static/image/search/fileType_Files.png'
|
import fileType_Files from '@/static/image/search/fileType_Files.png'
|
||||||
|
import playCircle from '@/static/image/chatList/playCircle@2x.png'
|
||||||
import { fileFormatSize, fileSuffix } from '@/utils/strings'
|
import { fileFormatSize, fileSuffix } from '@/utils/strings'
|
||||||
import searchItem from '../components/searchItem.vue'
|
import searchItem from '../components/searchItem.vue'
|
||||||
import customInput from '@/components/custom-input/custom-input.vue'
|
import customInput from '@/components/custom-input/custom-input.vue'
|
||||||
import ZPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
|
import ZPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
|
||||||
import useZPaging from '@/uni_modules/z-paging/components/z-paging/js/hooks/useZPaging.js'
|
import useZPaging from '@/uni_modules/z-paging/components/z-paging/js/hooks/useZPaging.js'
|
||||||
import { parseTime } from '@/utils/datetime'
|
import { parseTime } from '@/utils/datetime'
|
||||||
import { onMounted, reactive, computed, ref } from 'vue'
|
import { onMounted, reactive, computed, ref, nextTick } from 'vue'
|
||||||
import { onLoad } from '@dcloudio/uni-app'
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
import { ServeTalkDate } from '@/api/search/index'
|
import { ServeTalkDate, ServeGetSessionId } from '@/api/search/index'
|
||||||
import { ServeFindTalkRecords } from '@/api/chat/index'
|
import { ServeFindTalkRecords } from '@/api/chat/index'
|
||||||
import { useDialogueStore } from '@/store'
|
import { useDialogueStore } from '@/store'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
@ -273,7 +317,6 @@ const dialogueParams = reactive({
|
|||||||
let nowDay = new Date().setHours(0, 0, 0, 0)
|
let nowDay = new Date().setHours(0, 0, 0, 0)
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
receiver_id: '', //目标人id
|
|
||||||
pageTitle: '', //页面标题
|
pageTitle: '', //页面标题
|
||||||
dateStyle: [], //日期样式
|
dateStyle: [], //日期样式
|
||||||
nowDate: new Date(nowDay), //当前时间
|
nowDate: new Date(nowDay), //当前时间
|
||||||
@ -289,16 +332,53 @@ const state = reactive({
|
|||||||
searchResultList: [], //搜索结果列表
|
searchResultList: [], //搜索结果列表
|
||||||
cursor: 0, //上次查询的游标
|
cursor: 0, //上次查询的游标
|
||||||
msg_type: 0, //查询的消息类型
|
msg_type: 0, //查询的消息类型
|
||||||
|
group_member_id: 0, //群成员id
|
||||||
|
flatList: [], // 用于存储扁平化的数据
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const videoContext = ref()
|
||||||
|
const open = ref(false)
|
||||||
|
const currentVideoUrl = ref('')
|
||||||
|
|
||||||
|
const fullscreenchange = (e) => {
|
||||||
|
if (!e.detail.fullScreen) {
|
||||||
|
videoContext.value.stop()
|
||||||
|
videoContext.value.seek(0)
|
||||||
|
open.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onPlay(url) {
|
||||||
|
currentVideoUrl.value = url
|
||||||
|
open.value = true
|
||||||
|
|
||||||
|
// 等待 DOM 更新
|
||||||
|
await nextTick()
|
||||||
|
|
||||||
|
// 创建新的视频上下文
|
||||||
|
videoContext.value = uni.createVideoContext(url, getCurrentInstance())
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
// 先请求全屏
|
||||||
|
videoContext.value.requestFullScreen({ direction: 2 })
|
||||||
|
|
||||||
|
// 延迟一下再播放,确保全屏已经完成
|
||||||
|
setTimeout(() => {
|
||||||
|
videoContext.value.play()
|
||||||
|
}, 100)
|
||||||
|
}, 200)
|
||||||
|
}
|
||||||
|
|
||||||
onLoad((options) => {
|
onLoad((options) => {
|
||||||
console.log(options)
|
console.log(options)
|
||||||
if (options.receiver_id) {
|
|
||||||
state.receiver_id = Number(options.receiver_id)
|
|
||||||
}
|
|
||||||
if (options.condition) {
|
if (options.condition) {
|
||||||
state.condition = options.condition
|
state.condition = options.condition
|
||||||
if (options.condition === 'date') {
|
if (options.condition === 'member') {
|
||||||
|
state.showPageTitle = true
|
||||||
|
state.pageTitle = t('search.condition.member')
|
||||||
|
state.group_member_id = options.groupMemberId
|
||||||
|
queryAllSearch()
|
||||||
|
} else if (options.condition === 'date') {
|
||||||
state.showPageTitle = true
|
state.showPageTitle = true
|
||||||
state.pageTitle = t('search.condition.date')
|
state.pageTitle = t('search.condition.date')
|
||||||
ServeQueryTalkDate(parseTime(state.nowDate, '{y}{m}'))
|
ServeQueryTalkDate(parseTime(state.nowDate, '{y}{m}'))
|
||||||
@ -351,8 +431,8 @@ onMounted(() => {
|
|||||||
const ServeQueryTalkDate = (month) => {
|
const ServeQueryTalkDate = (month) => {
|
||||||
let params = {
|
let params = {
|
||||||
month: month,
|
month: month,
|
||||||
talk_type: 2, //1私聊2群聊
|
talk_type: dialogueParams.talk_type, //1私聊2群聊
|
||||||
receiver_id: state.receiver_id, //目标人id
|
receiver_id: dialogueParams.receiver_id, //目标人id
|
||||||
}
|
}
|
||||||
const resp = ServeTalkDate(params)
|
const resp = ServeTalkDate(params)
|
||||||
console.log(resp)
|
console.log(resp)
|
||||||
@ -387,7 +467,7 @@ const ServeQueryTalkDate = (month) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//点击选择日期
|
//点击选择日期
|
||||||
const selectDate = (e) => {
|
const selectDate = async (e) => {
|
||||||
if (e == parseTime(state.nowDate, '{y}/{m}/{d}')) {
|
if (e == parseTime(state.nowDate, '{y}/{m}/{d}')) {
|
||||||
console.log('==今日')
|
console.log('==今日')
|
||||||
state.dateStyle = [
|
state.dateStyle = [
|
||||||
@ -413,6 +493,38 @@ const selectDate = (e) => {
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
const sessionId = await getSessionId(
|
||||||
|
dialogueParams.talk_type,
|
||||||
|
dialogueParams.receiver_id,
|
||||||
|
)
|
||||||
|
uni.navigateTo({
|
||||||
|
url:
|
||||||
|
'/pages/dialog/index?sessionId=' +
|
||||||
|
sessionId +
|
||||||
|
'&keepDialogInfo=1' +
|
||||||
|
'&recordDate=' +
|
||||||
|
parseTime(e, '{y}-{m}-{d}'),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取会话Id
|
||||||
|
const getSessionId = (talk_type, receiver_id) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let params = {
|
||||||
|
talkType: talk_type,
|
||||||
|
receiverId: receiver_id,
|
||||||
|
}
|
||||||
|
const resp = ServeGetSessionId(params)
|
||||||
|
console.log(resp)
|
||||||
|
resp.then(({ code, data }) => {
|
||||||
|
console.log(data)
|
||||||
|
if (code == 200) {
|
||||||
|
resolve(data?.sessionId)
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
})
|
||||||
|
resp.catch(() => {})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//点击确认选择月份
|
//点击确认选择月份
|
||||||
@ -443,13 +555,22 @@ const getDArray = (dArray) => {
|
|||||||
//输入搜索内容
|
//输入搜索内容
|
||||||
const inputSearchText = (e) => {
|
const inputSearchText = (e) => {
|
||||||
state.searchText = e
|
state.searchText = e
|
||||||
|
state.cursor = 0
|
||||||
|
queryAllSearch()
|
||||||
}
|
}
|
||||||
|
|
||||||
//点击取消搜索
|
//点击取消搜索
|
||||||
const cancelSearch = () => {
|
const cancelSearch = () => {
|
||||||
|
const pages = getCurrentPages()
|
||||||
|
if (pages.length > 1) {
|
||||||
uni.navigateBack({
|
uni.navigateBack({
|
||||||
delta: 1,
|
delta: 1,
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
uni.reLaunch({
|
||||||
|
url: '/pages/index/index',
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//查询数据
|
//查询数据
|
||||||
@ -464,7 +585,8 @@ const queryAllSearch = () => {
|
|||||||
direction: 'up', //down向下查最新,up向上查老数据
|
direction: 'up', //down向下查最新,up向上查老数据
|
||||||
start_time: '',
|
start_time: '',
|
||||||
end_time: '',
|
end_time: '',
|
||||||
group_member_user_id: 0, //群成员id,当查询群历史消息的时候,需要指定群成员的时候送
|
group_member_user_id: state.group_member_id, //群成员id,当查询群历史消息的时候,需要指定群成员的时候送
|
||||||
|
file_name: state.msg_type === 6 ? state.searchText : '',
|
||||||
}
|
}
|
||||||
console.log(params)
|
console.log(params)
|
||||||
const resp = ServeFindTalkRecords(params)
|
const resp = ServeFindTalkRecords(params)
|
||||||
@ -472,17 +594,20 @@ const queryAllSearch = () => {
|
|||||||
resp.then(({ code, data }) => {
|
resp.then(({ code, data }) => {
|
||||||
console.log(data)
|
console.log(data)
|
||||||
if (code == 200) {
|
if (code == 200) {
|
||||||
let dateList = state.searchResultList
|
// 当cursor为0时,清空searchResultList
|
||||||
|
let dateList = state.cursor === 0 ? [] : state.searchResultList
|
||||||
let noMore = false
|
let noMore = false
|
||||||
if (data?.items?.length > 0) {
|
if (data?.items?.length > 0) {
|
||||||
data.items.forEach((item) => {
|
data.items.forEach((item) => {
|
||||||
item.dateTime = parseTime(item?.created_at, '{m}/{d}')
|
item.dateTime = parseTime(item?.created_at, '{m}/{d}')
|
||||||
|
if (item?.extra) {
|
||||||
item.extra.fileSize = fileFormatSize(item?.extra?.size)
|
item.extra.fileSize = fileFormatSize(item?.extra?.size)
|
||||||
item.extra.typeText = item?.extra?.name
|
item.extra.typeText = item?.extra?.name
|
||||||
? fileSuffix(item?.extra?.name)
|
? fileSuffix(item?.extra?.name)
|
||||||
: ''
|
: ''
|
||||||
item.extra.file_avatar = fileTypeAvatar(item?.extra?.typeText)
|
item.extra.file_avatar = fileTypeAvatar(item?.extra?.typeText)
|
||||||
console.log(item.extra.type)
|
console.log(item.extra.type)
|
||||||
|
}
|
||||||
let year = new Date(item.created_at).getFullYear()
|
let year = new Date(item.created_at).getFullYear()
|
||||||
let month = new Date(item.created_at).getMonth() + 1
|
let month = new Date(item.created_at).getMonth() + 1
|
||||||
let dateMonth =
|
let dateMonth =
|
||||||
@ -515,15 +640,35 @@ const queryAllSearch = () => {
|
|||||||
} else {
|
} else {
|
||||||
noMore = true
|
noMore = true
|
||||||
}
|
}
|
||||||
console.log(dateList)
|
|
||||||
state.cursor = data?.cursor
|
// 保存分组数据用于显示
|
||||||
zPaging.value?.completeByNoMore(dateList, noMore)
|
state.searchResultList = dateList
|
||||||
|
|
||||||
|
// 将分组数据扁平化,用于z-paging分页
|
||||||
|
state.flatList = dateList.reduce((acc, group) => {
|
||||||
|
return acc.concat(group.monthResultList)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
if (state.cursor === 0) {
|
||||||
|
zPaging.value?.complete(state.flatList)
|
||||||
} else {
|
} else {
|
||||||
|
zPaging.value?.completeByNoMore(state.flatList, noMore)
|
||||||
|
}
|
||||||
|
state.cursor = data?.cursor
|
||||||
|
} else {
|
||||||
|
if (state.cursor === 0) {
|
||||||
|
state.searchResultList = []
|
||||||
|
state.flatList = []
|
||||||
|
}
|
||||||
zPaging.value?.complete([])
|
zPaging.value?.complete([])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
resp.catch(() => {
|
resp.catch(() => {
|
||||||
|
if (state.cursor === 0) {
|
||||||
|
state.searchResultList = []
|
||||||
|
state.flatList = []
|
||||||
|
}
|
||||||
zPaging.value?.complete([])
|
zPaging.value?.complete([])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -546,6 +691,59 @@ const fileTypeAvatar = (fileType) => {
|
|||||||
}
|
}
|
||||||
return file_type_avatar
|
return file_type_avatar
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const previewPDF = (item) => {
|
||||||
|
console.log(item)
|
||||||
|
if (typeof plus !== 'undefined') {
|
||||||
|
downloadAndOpenFile(item)
|
||||||
|
} else {
|
||||||
|
document.addEventListener('plusready', () => {
|
||||||
|
downloadAndOpenFile(item)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const downloadAndOpenFile = (item) => {
|
||||||
|
uni.showLoading({ title: '加载中...', mask: true })
|
||||||
|
const downloadUrl = item?.extra?.path
|
||||||
|
const options = {
|
||||||
|
filename: '_doc/downloads/', // 保存路径
|
||||||
|
}
|
||||||
|
const dtask = plus.downloader.createDownload(downloadUrl, options, function (
|
||||||
|
d,
|
||||||
|
status,
|
||||||
|
) {
|
||||||
|
if (status === 200) {
|
||||||
|
uni.hideLoading()
|
||||||
|
const filePath = d.filename
|
||||||
|
plus.runtime.openFile(
|
||||||
|
filePath,
|
||||||
|
{},
|
||||||
|
function () {},
|
||||||
|
function (error) {},
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
uni.hideLoading()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
dtask.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
//跳转到对应的记录位置
|
||||||
|
const toDialogueByMember = async (msgInfo) => {
|
||||||
|
const sessionId = await getSessionId(
|
||||||
|
dialogueParams.talk_type,
|
||||||
|
dialogueParams.receiver_id,
|
||||||
|
)
|
||||||
|
uni.navigateTo({
|
||||||
|
url:
|
||||||
|
'/pages/dialog/index?sessionId=' +
|
||||||
|
sessionId +
|
||||||
|
'&keepDialogInfo=1' +
|
||||||
|
'&msgInfo=' +
|
||||||
|
encodeURIComponent(JSON.stringify(msgInfo)),
|
||||||
|
})
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.search-by-date {
|
.search-by-date {
|
||||||
@ -652,6 +850,7 @@ body::v-deep .round-3 {
|
|||||||
span {
|
span {
|
||||||
line-height: 40rpx;
|
line-height: 40rpx;
|
||||||
color: $theme-text;
|
color: $theme-text;
|
||||||
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.attachment-sub-info {
|
.attachment-sub-info {
|
||||||
@ -698,6 +897,26 @@ body::v-deep .round-3 {
|
|||||||
width: 164rpx !important;
|
width: 164rpx !important;
|
||||||
height: 164rpx !important;
|
height: 164rpx !important;
|
||||||
}
|
}
|
||||||
|
.video-preview {
|
||||||
|
position: relative;
|
||||||
|
width: 164rpx;
|
||||||
|
height: 164rpx;
|
||||||
|
cursor: pointer;
|
||||||
|
.play-icon {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 80rpx !important;
|
||||||
|
height: 80rpx !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -706,4 +925,23 @@ body::v-deep .round-3 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.video-container {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
background: #000;
|
||||||
|
z-index: 9999;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fullscreen-video {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -23,7 +23,7 @@ class WsSocket {
|
|||||||
lockReconnect: false,
|
lockReconnect: false,
|
||||||
setTimeout: null, // 计时器对象
|
setTimeout: null, // 计时器对象
|
||||||
time: 3000, // 重连间隔时间
|
time: 3000, // 重连间隔时间
|
||||||
number: 10000000 // 重连次数
|
number: 20 // 重连次数
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,21 @@
|
|||||||
import Request from '@/service/request/index.js'
|
import Request from '@/service/request/index.js'
|
||||||
import {useAuth} from "@/store/auth";
|
import {useAuth} from "@/store/auth";
|
||||||
|
import { createApp } from 'vue';
|
||||||
|
import XMessage from '@/components/x-message/index.vue';
|
||||||
|
|
||||||
|
// 创建消息提示实例
|
||||||
|
const messageInstance = (() => {
|
||||||
|
const messageNode = document.createElement('div');
|
||||||
|
document.body.appendChild(messageNode);
|
||||||
|
const app = createApp(XMessage);
|
||||||
|
const instance = app.mount(messageNode);
|
||||||
|
return {
|
||||||
|
warning: (msg) => instance.showMessage({ type: 'warning', message: msg }),
|
||||||
|
error: (msg) => instance.showMessage({ type: 'error', message: msg }),
|
||||||
|
success: (msg) => instance.showMessage({ type: 'success', message: msg }),
|
||||||
|
info: (msg) => instance.showMessage({ type: 'info', message: msg })
|
||||||
|
};
|
||||||
|
})();
|
||||||
const { token ,refreshToken,userInfo}=useAuth()
|
const { token ,refreshToken,userInfo}=useAuth()
|
||||||
let isRefreshing = false;
|
let isRefreshing = false;
|
||||||
let refreshSubscribers = [];
|
let refreshSubscribers = [];
|
||||||
@ -24,19 +40,25 @@ const request = new Request({
|
|||||||
},
|
},
|
||||||
responseInterceptors: async (res) => {
|
responseInterceptors: async (res) => {
|
||||||
if(res.data.status===1){
|
if(res.data.status===1){
|
||||||
message.warning(res.data.msg)
|
// message.warning(res.data.msg)
|
||||||
|
messageInstance.warning(res.data.msg)
|
||||||
}
|
}
|
||||||
if (res.data.status === 401) {
|
if (res.data.status === 401) {
|
||||||
return getRefreshToken(res);
|
return
|
||||||
|
// return getRefreshToken(res);
|
||||||
// uni.navigateTo({
|
// uni.navigateTo({
|
||||||
// url:'/pages/login/index'
|
// url:'/pages/login/index'
|
||||||
// })
|
// })
|
||||||
}
|
}
|
||||||
if ([200, 201, 204].includes(res.status)) {
|
if ([200, 201, 204].includes(res.status)) {
|
||||||
|
if(res.data.code !== 200 && res.data.code!== 0) {
|
||||||
|
messageInstance.error(res.data.message || res.data.msg || 'An error occurred.');
|
||||||
|
}
|
||||||
return res.config.responseType === 'blob' ? res : res;
|
return res.config.responseType === 'blob' ? res : res;
|
||||||
} else {
|
} else {
|
||||||
/* message.error(res.data.msg || 'An error occurred.');*/
|
/* message.error(res.data.msg || 'An error occurred.');*/
|
||||||
return Promise.reject(new Error(res.data.msg || 'An error occurred.'));
|
messageInstance.error(res.data.message || res.data.msg || 'An error occurred.');
|
||||||
|
return Promise.reject(new Error(res.data.message || res.data.msg || 'An error occurred.'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -59,13 +81,14 @@ async function getRefreshToken(response) {
|
|||||||
})
|
})
|
||||||
return request.request(response.config);
|
return request.request(response.config);
|
||||||
} else {
|
} else {
|
||||||
message.error(res.message || res.msg);
|
|
||||||
|
messageInstance.error(res.message || res.msg);
|
||||||
throw new Error(res.message || res.msg);
|
throw new Error(res.message || res.msg);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
uni.navigateTo({
|
// uni.navigateTo({
|
||||||
url:'/pages/login/index'
|
// url:'/pages/login/index'
|
||||||
})
|
// })
|
||||||
throw error
|
throw error
|
||||||
} finally {
|
} finally {
|
||||||
isRefreshing = false;
|
isRefreshing = false;
|
||||||
@ -73,9 +96,9 @@ async function getRefreshToken(response) {
|
|||||||
refreshSubscribers = [];
|
refreshSubscribers = [];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
uni.navigateTo({
|
// uni.navigateTo({
|
||||||
url:'/pages/login/index'
|
// url:'/pages/login/index'
|
||||||
})
|
// })
|
||||||
throw new Error('No refresh token available.');
|
throw new Error('No refresh token available.');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
BIN
src/static/image/chatBotMessageCard/copy.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
src/static/image/chatBotMessageCard/errorClock.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
src/static/image/chatBotMessageCard/noClockAfterWork.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
src/static/image/chatBotMessageCard/noClockBeforeWork.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
src/static/image/chatBotMessageCard/prompt.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
src/static/image/chatList/addFriend.png
Normal file
|
After Width: | Height: | Size: 654 B |
BIN
src/static/image/chatList/groupAllMember.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
src/static/image/chatList/mention_select_hide_bg.png
Normal file
|
After Width: | Height: | Size: 752 B |
BIN
src/static/image/chatList/mention_select_hide_icon.png
Normal file
|
After Width: | Height: | Size: 208 B |
BIN
src/static/image/record/chat-voice-animation-bg-blue.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
src/static/image/record/chat-voice-animation-bg-red.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
src/static/image/record/chat-voice-cancel-blue.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
src/static/image/record/chat-voice-cancel-grey.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
src/static/image/record/chat-voice-icon-blue.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
src/static/image/record/chat-voice-icon-white.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
src/static/image/record/keyboardIcon.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
src/static/image/record/voiceIcon.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
@ -5,7 +5,7 @@ import { userInfoApi } from "@/api/user";
|
|||||||
import {ref} from 'vue'
|
import {ref} from 'vue'
|
||||||
export const useAuth = createGlobalState(() => {
|
export const useAuth = createGlobalState(() => {
|
||||||
const token = useStorage('token', '', uniStorage)
|
const token = useStorage('token', '', uniStorage)
|
||||||
// const token = ref('79b5c732d96d2b27a48a99dfd4a5566c43aaa5796242e854ebe3ffc198d6876b9628e7b764d9af65ab5dbb2d517ced88170491b74b048c0ba827c0d3741462cb89dc59ed46653a449af837a8262941caaef1334d640773710f8cd96473bacfb190cba595a5d6a9c87d70f0999a3ebb41147213b31b4bdccffca66a56acf3baab5af0154f0dce360079f37709f78e13711036899344bddb0fb4cf0f2890287cb62c3fcbe33368caa5e213624577be8b8420ab75b1f50775ee16142a4321c5d56995f37354a66a969da98d95ba6e65d142ed097e04b411c1ebad2f62866d0ec7e1838420530a9941dbbcd00490199f8b897937e719454eda6de1352a14497a54063c2ae13c2b1418f2689268102faffee874777ce1312eb7d9399eaa8cf58674aa86c9b85ad9300293c0a3369ed429536bbea4fcb092b78466ea53a44a2b2b1c1a')
|
// const token = ref("2046c3941ed4959f6d988d3d4a0fe40d4b52f33f3f5fc1001406064554641d9406bb13cacb92939b0ca223c17e2c2f2fe70212ef017dbae8965d5cf86bad48ce4316e605ca187bd9ffd4aa6b56865be4ad4e422701d330b52d60cfe649cd48cf3a21a2a6e9a9cabafff364ee9c311ec634b0afc09db0d3215bedce561e9d50e5a8da6092062e2ebe35f747d77d72a68ad492a4ab218c07887c9cd4867f2c2d28e4ae1fd671144cc20ef0632f9ce067289004d67f6adf41b20d6ef5cdbfb74aadc2d2736ececf07254f1a76552bde4f1161a0fca7bfe32a29685ce1e76366116b81ae2195b3713dbb04285e5ddfd36184fe671c5524d20b4fe74a555db755f8d939b0bc46fb0cb998323d54c9925729d7ca835b7925999a677faa0cbe1cbc67b5203d85317653883aec81d3e71d865b326376bea726cc66d9f7f5a160d43f671c")
|
||||||
const refreshToken = useStorage('refreshToken', '', uniStorage)
|
const refreshToken = useStorage('refreshToken', '', uniStorage)
|
||||||
const userInfo = useStorage('userInfo', {}, uniStorage)
|
const userInfo = useStorage('userInfo', {}, uniStorage)
|
||||||
const leaderList = useStorage('leaderList', [], uniStorage)
|
const leaderList = useStorage('leaderList', [], uniStorage)
|
||||||
|
|||||||
@ -10,10 +10,14 @@ import {
|
|||||||
departmentV2AllPosition,
|
departmentV2AllPosition,
|
||||||
groupCreateDept,
|
groupCreateDept,
|
||||||
departmentV2TreeAll,
|
departmentV2TreeAll,
|
||||||
|
departmentV2TreeAll2,
|
||||||
|
userHasPermission,
|
||||||
userV2List,
|
userV2List,
|
||||||
|
userV2List2,
|
||||||
v2TreePositionByDepartment,
|
v2TreePositionByDepartment,
|
||||||
} from '@/api/deps/index.js'
|
} from '@/api/deps/index.js'
|
||||||
|
import { useAuth } from '@/store/auth'
|
||||||
|
const { userInfo } = useAuth()
|
||||||
export const useGroupTypeStore = createGlobalState(() => {
|
export const useGroupTypeStore = createGlobalState(() => {
|
||||||
const groupName = ref('')
|
const groupName = ref('')
|
||||||
const groupActiveIndex = ref(-1) // 当前激活的分组索引
|
const groupActiveIndex = ref(-1) // 当前激活的分组索引
|
||||||
@ -34,6 +38,40 @@ export const useGroupTypeStore = createGlobalState(() => {
|
|||||||
depTreeMyList.value = res.data.nodes
|
depTreeMyList.value = res.data.nodes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// userInfo?.value?.ID
|
||||||
|
const getDepsTreeMy2 = async (chooseMode) => {
|
||||||
|
let params = { nowUserId: 0 }
|
||||||
|
if (chooseMode === 1) {
|
||||||
|
const isHasRes = await userHasPermission({
|
||||||
|
erpUserId: userInfo?.value?.ID,
|
||||||
|
ruleUrl: [
|
||||||
|
'auth_chat_app_create_all_dept',
|
||||||
|
'auth_chat_app_create_limit_dept',
|
||||||
|
],
|
||||||
|
})
|
||||||
|
if (isHasRes.code === 200) {
|
||||||
|
if (isHasRes.data.auth_chat_app_create_all_dept) {
|
||||||
|
params = {
|
||||||
|
nowUserId: 0,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (isHasRes.data.auth_chat_app_create_limit_dept) {
|
||||||
|
params = {
|
||||||
|
nowUserId: userInfo?.value?.ID,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
params = {
|
||||||
|
nowUserId: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const res = await departmentV2TreeAll2(params)
|
||||||
|
if (res.status === 0) {
|
||||||
|
depTreeMyList.value = res.data.nodes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//获取指定部门下的所有岗位
|
//获取指定部门下的所有岗位
|
||||||
const getPositionByDepartment = async (params) => {
|
const getPositionByDepartment = async (params) => {
|
||||||
@ -51,7 +89,7 @@ export const useGroupTypeStore = createGlobalState(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getDepMembers = async (param) => {
|
const getDepMembers = async (param) => {
|
||||||
const res = await userV2List(param)
|
const res = await userV2List2(param)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,6 +162,7 @@ export const useGroupTypeStore = createGlobalState(() => {
|
|||||||
postTreeList,
|
postTreeList,
|
||||||
departmentAllPositions,
|
departmentAllPositions,
|
||||||
getDepsTreeMy,
|
getDepsTreeMy,
|
||||||
|
getDepsTreeMy2,
|
||||||
getPositionByDepartment,
|
getPositionByDepartment,
|
||||||
getPositionsTree,
|
getPositionsTree,
|
||||||
crumbs,
|
crumbs,
|
||||||
|
|||||||
@ -15,6 +15,10 @@ import { useAuth } from '../auth/index'
|
|||||||
// let keyboardTimeout = null
|
// let keyboardTimeout = null
|
||||||
|
|
||||||
export const useDialogueStore = defineStore('dialogue', {
|
export const useDialogueStore = defineStore('dialogue', {
|
||||||
|
// 添加持久化配置
|
||||||
|
persist: {
|
||||||
|
paths: ['talk.talk_type', 'talk.receiver_id']
|
||||||
|
},
|
||||||
state: () => {
|
state: () => {
|
||||||
return {
|
return {
|
||||||
// 对话索引(聊天对话的唯一索引)
|
// 对话索引(聊天对话的唯一索引)
|
||||||
@ -48,6 +52,15 @@ export const useDialogueStore = defineStore('dialogue', {
|
|||||||
// 是否显示会话列表
|
// 是否显示会话列表
|
||||||
isShowSessionList: true,
|
isShowSessionList: true,
|
||||||
|
|
||||||
|
//是否已被解散
|
||||||
|
isDismiss: false,
|
||||||
|
|
||||||
|
//是否退群/移出群
|
||||||
|
isQuit: false,
|
||||||
|
|
||||||
|
//未读消息数量
|
||||||
|
unreadNum:0,
|
||||||
|
|
||||||
// 群成员列表
|
// 群成员列表
|
||||||
members: [],
|
members: [],
|
||||||
|
|
||||||
@ -84,6 +97,21 @@ export const useDialogueStore = defineStore('dialogue', {
|
|||||||
this.online = status
|
this.online = status
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 更新未读消息数量-清空未读
|
||||||
|
clearUnreadNum() {
|
||||||
|
this.unreadNum = 0
|
||||||
|
},
|
||||||
|
|
||||||
|
// 更新群解散状态
|
||||||
|
updateDismiss() {
|
||||||
|
this.isDismiss = true
|
||||||
|
},
|
||||||
|
|
||||||
|
// 更新群成员退出状态
|
||||||
|
updateQuit() {
|
||||||
|
this.isQuit = true
|
||||||
|
},
|
||||||
|
|
||||||
// 更新对话信息
|
// 更新对话信息
|
||||||
setDialogue(data = {}) {
|
setDialogue(data = {}) {
|
||||||
this.online = data.is_online == 1
|
this.online = data.is_online == 1
|
||||||
@ -98,8 +126,13 @@ export const useDialogueStore = defineStore('dialogue', {
|
|||||||
this.unreadBubble = 0
|
this.unreadBubble = 0
|
||||||
this.isShowEditor = data?.is_robot === 0
|
this.isShowEditor = data?.is_robot === 0
|
||||||
|
|
||||||
|
this.isDismiss = data?.is_dismiss === 1 ? true : false
|
||||||
|
this.isQuit = data?.is_quit === 1 ? true : false
|
||||||
|
|
||||||
|
this.unreadNum = data?.unread_num || 0
|
||||||
|
|
||||||
this.members = []
|
this.members = []
|
||||||
if (data.talk_type == 2) {
|
if (data.talk_type == 2 && !this.isDismiss && !this.isQuit) {
|
||||||
this.updateGroupMembers()
|
this.updateGroupMembers()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -209,8 +242,6 @@ export const useDialogueStore = defineStore('dialogue', {
|
|||||||
if (res.code == 200) {
|
if (res.code == 200) {
|
||||||
this.batchDelDialogueRecord(msgIds)
|
this.batchDelDialogueRecord(msgIds)
|
||||||
batchDelDialogueRecord(msgIds)
|
batchDelDialogueRecord(msgIds)
|
||||||
} else {
|
|
||||||
message.warning(res.message)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@ -234,8 +265,6 @@ export const useDialogueStore = defineStore('dialogue', {
|
|||||||
ServeRevokeRecords({ msg_id }).then((res) => {
|
ServeRevokeRecords({ msg_id }).then((res) => {
|
||||||
if (res.code == 200) {
|
if (res.code == 200) {
|
||||||
this.updateDialogueRecord({ msg_id, is_revoke: 1 })
|
this.updateDialogueRecord({ msg_id, is_revoke: 1 })
|
||||||
} else {
|
|
||||||
message.warning(res.message)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|||||||
@ -5,9 +5,111 @@ import lodash from 'lodash'
|
|||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { createGlobalState, useStorage } from '@vueuse/core'
|
import { createGlobalState, useStorage } from '@vueuse/core'
|
||||||
import { uniStorage } from '@/utils/uniStorage.js'
|
import { uniStorage } from '@/utils/uniStorage.js'
|
||||||
|
import { handleFindWebview } from '@/utils/common'
|
||||||
|
|
||||||
export const useDialogueListStore = createGlobalState(() => {
|
export const useDialogueListStore = createGlobalState(() => {
|
||||||
|
const testDatabase = async () => {
|
||||||
|
// 初始化数据库
|
||||||
|
let chatDatabase = {
|
||||||
|
eventType: 'openDatabase',
|
||||||
|
eventParams: {
|
||||||
|
name: 'chat',
|
||||||
|
path: '_doc/chat.db',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
let chatDBexecuteSql = {
|
||||||
|
eventType: 'executeSql',
|
||||||
|
eventParams: {
|
||||||
|
name: 'chat',
|
||||||
|
sql: `CREATE TABLE IF NOT EXISTS talk_records (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
msg_id TEXT NOT NULL,
|
||||||
|
sequence INTEGER NOT NULL,
|
||||||
|
talk_type INTEGER NOT NULL DEFAULT 1,
|
||||||
|
msg_type INTEGER NOT NULL DEFAULT 1,
|
||||||
|
user_id INTEGER NOT NULL DEFAULT 0,
|
||||||
|
receiver_id INTEGER NOT NULL DEFAULT 0,
|
||||||
|
is_revoke INTEGER NOT NULL DEFAULT 0,
|
||||||
|
is_mark INTEGER NOT NULL DEFAULT 0,
|
||||||
|
quote_id TEXT NOT NULL,
|
||||||
|
extra TEXT NOT NULL,
|
||||||
|
created_at TEXT NOT NULL,
|
||||||
|
updated_at TEXT NOT NULL,
|
||||||
|
biz_date TEXT
|
||||||
|
)`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const content = {
|
||||||
|
content: '我试试传送文件和图片是不是一个接口',
|
||||||
|
name: '测试excel1.xlsx',
|
||||||
|
path:
|
||||||
|
'https://cdn-test.szjixun.cn/fonchain-chat/chat/file/multipart/20250307/727a2371-ffc4-46da-b953-a7d449ff82ff-测试excel1.xlsx',
|
||||||
|
size: 9909,
|
||||||
|
drive: 3,
|
||||||
|
}
|
||||||
|
const extra = JSON.stringify(content)
|
||||||
|
|
||||||
|
let chatDBexecuteSql2 = {
|
||||||
|
eventType: 'executeSql',
|
||||||
|
eventParams: {
|
||||||
|
name: 'chat',
|
||||||
|
sql:
|
||||||
|
'INSERT INTO talk_records (msg_id, sequence, talk_type, msg_type, user_id, receiver_id, is_revoke, is_mark, quote_id, extra, created_at, updated_at, biz_date) VALUES ("' +
|
||||||
|
'77b715fb30f54f739a255a915ef72445' +
|
||||||
|
'", 166, 2, 1, 1774, 888890, 0, 0, "' +
|
||||||
|
'' +
|
||||||
|
'", "' +
|
||||||
|
extra +
|
||||||
|
'", "' +
|
||||||
|
'2025-03-06T15:57:07.000Z' +
|
||||||
|
'", "' +
|
||||||
|
'2025-03-06T15:57:07.000Z' +
|
||||||
|
'", "' +
|
||||||
|
'20250306' +
|
||||||
|
'")',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
let chatDBSelectSql = {
|
||||||
|
eventType: 'selectSql',
|
||||||
|
eventParams: {
|
||||||
|
name: 'chat',
|
||||||
|
sql: `SELECT * FROM talk_records ORDER BY sequence DESC LIMIT 20`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
let chatDBIsOpenDatabase = {
|
||||||
|
eventType: 'isOpenDatabase',
|
||||||
|
eventParams: {
|
||||||
|
name: 'chat',
|
||||||
|
path: '_doc/chat.db',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
// handleFindWebview(
|
||||||
|
// `operateSQLite('${encodeURIComponent(JSON.stringify(chatDatabase))}')`,
|
||||||
|
// )
|
||||||
|
// handleFindWebview(
|
||||||
|
// `operateSQLite('${encodeURIComponent(
|
||||||
|
// JSON.stringify(chatDBexecuteSql),
|
||||||
|
// )}')`,
|
||||||
|
// )
|
||||||
|
// handleFindWebview(
|
||||||
|
// `operateSQLite('${encodeURIComponent(
|
||||||
|
// JSON.stringify(chatDBexecuteSql2),
|
||||||
|
// )}')`,
|
||||||
|
// )
|
||||||
|
// handleFindWebview(
|
||||||
|
// `operateSQLite('${encodeURIComponent(JSON.stringify(chatDBSelectSql))}')`,
|
||||||
|
// )
|
||||||
|
// handleFindWebview(
|
||||||
|
// `operateSQLite('${encodeURIComponent(
|
||||||
|
// JSON.stringify(chatDBIsOpenDatabase),
|
||||||
|
// )}')`,
|
||||||
|
// )
|
||||||
|
}
|
||||||
|
// testDatabase()
|
||||||
|
|
||||||
const dialogueList = useStorage('dialogueList', [], uniStorage)
|
const dialogueList = useStorage('dialogueList', [], uniStorage)
|
||||||
|
// const dialogueList = ref([])
|
||||||
const zpagingRef = ref()
|
const zpagingRef = ref()
|
||||||
const virtualList = ref([])
|
const virtualList = ref([])
|
||||||
|
|
||||||
@ -18,18 +120,49 @@ export const useDialogueListStore = createGlobalState(() => {
|
|||||||
const addDialogueRecord = (newRecords, type = 'add') => {
|
const addDialogueRecord = (newRecords, type = 'add') => {
|
||||||
console.log(newRecords)
|
console.log(newRecords)
|
||||||
|
|
||||||
const dialogue = lodash.cloneDeep(useDialogueStore())
|
const dialogue = useDialogueStore()
|
||||||
if (!dialogue || typeof dialogue !== 'object') return
|
if (!dialogue || typeof dialogue !== 'object') return
|
||||||
// 检查是否已存在相同 index_name 的对话
|
// 检查是否已存在相同 index_name 的对话
|
||||||
const existingIndex = dialogueList.value.findIndex(
|
const existingIndex = dialogueList.value.findIndex(
|
||||||
(item) => item.index_name === dialogue.index_name,
|
(item) => item.index_name === dialogue.index_name,
|
||||||
)
|
)
|
||||||
if (existingIndex === -1) {
|
if (existingIndex === -1) {
|
||||||
// 如果不存在,直接添加
|
// 如果不存在,创建新对话,只保存需要的属性
|
||||||
dialogueList.value.push(dialogue)
|
const newDialogue = {
|
||||||
|
index_name: dialogue.index_name,
|
||||||
|
talk: {
|
||||||
|
username: dialogue.talk.username,
|
||||||
|
talk_type: dialogue.talk.talk_type,
|
||||||
|
receiver_id: dialogue.talk.receiver_id,
|
||||||
|
},
|
||||||
|
online: dialogue.online,
|
||||||
|
records: dialogue.records || [],
|
||||||
|
unreadBubble: dialogue.unreadBubble,
|
||||||
|
isOpenMultiSelect: dialogue.isOpenMultiSelect,
|
||||||
|
isShowEditor: dialogue.isShowEditor,
|
||||||
|
isShowSessionList: dialogue.isShowSessionList,
|
||||||
|
isDismiss: dialogue.isDismiss,
|
||||||
|
isQuit: dialogue.isQuit,
|
||||||
|
unreadNum: dialogue.unreadNum,
|
||||||
|
members: dialogue.members.map((member) => ({
|
||||||
|
id: member.id,
|
||||||
|
nickname: member.nickname,
|
||||||
|
avatar: member.avatar,
|
||||||
|
gender: member.gender,
|
||||||
|
leader: member.leader,
|
||||||
|
remark: member.remark,
|
||||||
|
online: member.online,
|
||||||
|
value: member.value,
|
||||||
|
key: member.key,
|
||||||
|
erp_user_id: member.erp_user_id,
|
||||||
|
is_mute: member.is_mute,
|
||||||
|
is_mine: member.is_mine,
|
||||||
|
})),
|
||||||
|
forwardType: dialogue.forwardType,
|
||||||
|
}
|
||||||
|
dialogueList.value.push(newDialogue)
|
||||||
} else {
|
} else {
|
||||||
// 如果对话存在,处理 records 数组
|
// 如果对话存在,处理 records 数组
|
||||||
const { records = [] } = dialogue
|
|
||||||
newRecords.forEach((newRecord) => {
|
newRecords.forEach((newRecord) => {
|
||||||
const recordIndex = dialogueList.value[existingIndex].records.findIndex(
|
const recordIndex = dialogueList.value[existingIndex].records.findIndex(
|
||||||
(record) => record.msg_id === newRecord.msg_id,
|
(record) => record.msg_id === newRecord.msg_id,
|
||||||
@ -44,18 +177,11 @@ export const useDialogueListStore = createGlobalState(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 更新除 records 和 index_name 外的其他属性
|
|
||||||
const { index_name, records: _, ...updateProps } = dialogue
|
|
||||||
dialogueList.value[existingIndex] = {
|
|
||||||
...dialogueList.value[existingIndex],
|
|
||||||
...updateProps,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateDialogueRecord = (record) => {
|
const updateDialogueRecord = (record) => {
|
||||||
const dialogue = lodash.cloneDeep(useDialogueStore())
|
const dialogue = useDialogueStore()
|
||||||
const item = getDialogueList(dialogue.index_name)
|
const item = getDialogueList(dialogue.index_name)
|
||||||
const recordIndex = item.records.findIndex(
|
const recordIndex = item.records.findIndex(
|
||||||
(item) => item.msg_id === record.msg_id,
|
(item) => item.msg_id === record.msg_id,
|
||||||
@ -78,7 +204,7 @@ export const useDialogueListStore = createGlobalState(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const deleteDialogueRecord = (record) => {
|
const deleteDialogueRecord = (record) => {
|
||||||
const dialogue = lodash.cloneDeep(useDialogueStore())
|
const dialogue = useDialogueStore()
|
||||||
const item = getDialogueList(dialogue.index_name)
|
const item = getDialogueList(dialogue.index_name)
|
||||||
const recordIndex = item.records.findIndex(
|
const recordIndex = item.records.findIndex(
|
||||||
(item) => item.msg_id === record.msg_id,
|
(item) => item.msg_id === record.msg_id,
|
||||||
@ -104,14 +230,29 @@ export const useDialogueListStore = createGlobalState(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const addChatRecord = (indexName, item) => {
|
const addChatRecord = (indexName, item) => {
|
||||||
const dialogue = lodash.cloneDeep(useDialogueStore())
|
const dialogue = useDialogueStore()
|
||||||
if (dialogue?.index_name === indexName) {
|
if (dialogue?.index_name === indexName) {
|
||||||
|
if (item?.file_num) {
|
||||||
|
const index = virtualList.value.findIndex(
|
||||||
|
(v) => v?.file_num === item?.file_num,
|
||||||
|
)
|
||||||
|
if (index > -1) {
|
||||||
|
// 保持响应性的同时替换整个对象
|
||||||
|
virtualList.value.splice(index, 1, {
|
||||||
|
...virtualList.value[index], // 保留原有不需要修改的字段
|
||||||
|
...item, // 覆盖需要更新的字段
|
||||||
|
})
|
||||||
|
} else {
|
||||||
zpagingRef.value?.addChatRecordData(item, false, false)
|
zpagingRef.value?.addChatRecordData(item, false, false)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
zpagingRef.value?.addChatRecordData(item, false, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const batchDelDialogueRecord = (msgIds) => {
|
const batchDelDialogueRecord = (msgIds) => {
|
||||||
const dialogue = lodash.cloneDeep(useDialogueStore())
|
const dialogue = useDialogueStore()
|
||||||
const item = getDialogueList(dialogue.index_name)
|
const item = getDialogueList(dialogue.index_name)
|
||||||
item.records = item.records.filter((item) => !msgIds.includes(item.msg_id))
|
item.records = item.records.filter((item) => !msgIds.includes(item.msg_id))
|
||||||
}
|
}
|
||||||
@ -129,7 +270,7 @@ export const useDialogueListStore = createGlobalState(() => {
|
|||||||
|
|
||||||
//清空聊天记录时,同时清空本地保存的聊天记录
|
//清空聊天记录时,同时清空本地保存的聊天记录
|
||||||
const clearDialogueRecord = () => {
|
const clearDialogueRecord = () => {
|
||||||
const dialogue = lodash.cloneDeep(useDialogueStore())
|
const dialogue = useDialogueStore()
|
||||||
const item = getDialogueList(dialogue.index_name)
|
const item = getDialogueList(dialogue.index_name)
|
||||||
item.records = []
|
item.records = []
|
||||||
virtualList.value = []
|
virtualList.value = []
|
||||||
|
|||||||
@ -41,8 +41,6 @@ export const useEditorStore = defineStore('editor', {
|
|||||||
}).then((res) => {
|
}).then((res) => {
|
||||||
if (res.code == 200) {
|
if (res.code == 200) {
|
||||||
this.loadUserEmoticon()
|
this.loadUserEmoticon()
|
||||||
} else {
|
|
||||||
message.warning(res.message)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@ -55,8 +53,6 @@ export const useEditorStore = defineStore('editor', {
|
|||||||
ServeUploadEmoticon(data).then((res) => {
|
ServeUploadEmoticon(data).then((res) => {
|
||||||
if (res.code == 200) {
|
if (res.code == 200) {
|
||||||
this.emoticon.items[1].children.unshift(res.data)
|
this.emoticon.items[1].children.unshift(res.data)
|
||||||
} else {
|
|
||||||
message.warning(res.message)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@ -69,8 +65,6 @@ export const useEditorStore = defineStore('editor', {
|
|||||||
if (res.code == 200) {
|
if (res.code == 200) {
|
||||||
this.emoticon.items[1].children.splice(resoure.index, 1)
|
this.emoticon.items[1].children.splice(resoure.index, 1)
|
||||||
message.success('删除成功')
|
message.success('删除成功')
|
||||||
} else {
|
|
||||||
message.warning(res.message)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { defineStore } from 'pinia'
|
|||||||
import { ServeGetTalkList, ServeCreateTalkList } from '@/api/chat/index'
|
import { ServeGetTalkList, ServeCreateTalkList } from '@/api/chat/index'
|
||||||
import { formatTalkItem, ttime, KEY_INDEX_NAME } from '@/utils/talk'
|
import { formatTalkItem, ttime, KEY_INDEX_NAME } from '@/utils/talk'
|
||||||
import { useEditorDraftStore } from './editor-draft'
|
import { useEditorDraftStore } from './editor-draft'
|
||||||
|
import { handleFindWebview } from '@/utils/common'
|
||||||
// import { ISession } from '@/types/chat'
|
// import { ISession } from '@/types/chat'
|
||||||
|
|
||||||
export const useTalkStore = defineStore('talk', {
|
export const useTalkStore = defineStore('talk', {
|
||||||
@ -102,6 +103,8 @@ export const useTalkStore = defineStore('talk', {
|
|||||||
// 返回 Promise 对象,使调用方可以使用 then/catch
|
// 返回 Promise 对象,使调用方可以使用 then/catch
|
||||||
return resp.then(({ code, data }) => {
|
return resp.then(({ code, data }) => {
|
||||||
if (code == 200) {
|
if (code == 200) {
|
||||||
|
//向OA的webview通信,改变未读消息数量
|
||||||
|
handleFindWebview(`doUpdateUnreadNum('${data.unread_num}')`)
|
||||||
this.items = data.items.map((item) => {
|
this.items = data.items.map((item) => {
|
||||||
const value = formatTalkItem(item)
|
const value = formatTalkItem(item)
|
||||||
|
|
||||||
@ -144,6 +147,7 @@ export const useTalkStore = defineStore('talk', {
|
|||||||
|
|
||||||
ServeCreateTalkList({
|
ServeCreateTalkList({
|
||||||
talk_type,
|
talk_type,
|
||||||
|
receiver_id,
|
||||||
erp_user_id,
|
erp_user_id,
|
||||||
}).then(({ code, data, message }) => {
|
}).then(({ code, data, message }) => {
|
||||||
if (code == 200) {
|
if (code == 200) {
|
||||||
|
|||||||