Compare commits
No commits in common. "main" and "zhangyuanshan-20250310" have entirely different histories.
main
...
zhangyuans
2
auto-imports.d.ts
vendored
@ -70,6 +70,6 @@ declare global {
|
||||
// for type re-export
|
||||
declare global {
|
||||
// @ts-ignore
|
||||
export type { Component, Slot, Slots, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
|
||||
export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
|
||||
import('vue')
|
||||
}
|
||||
|
6
components.d.ts
vendored
@ -8,8 +8,6 @@ export {}
|
||||
/* prettier-ignore */
|
||||
declare module 'vue' {
|
||||
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']
|
||||
Avatar: typeof import('./src/components/base/Avatar.vue')['default']
|
||||
AvatarCropper: typeof import('./src/components/base/AvatarCropper.vue')['default']
|
||||
@ -38,17 +36,13 @@ declare module 'vue' {
|
||||
RevokeMessage: typeof import('./src/components/talk/message/RevokeMessage.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
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']
|
||||
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']
|
||||
SysGroupMemberCancelMutedMessage: typeof import('./src/components/talk/message/system/SysGroupMemberCancelMutedMessage.vue')['default']
|
||||
SysGroupMemberKickedMessage: typeof import('./src/components/talk/message/system/SysGroupMemberKickedMessage.vue')['default']
|
||||
SysGroupMemberMutedMessage: typeof import('./src/components/talk/message/system/SysGroupMemberMutedMessage.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']
|
||||
SysGroupTransferMessage: typeof import('./src/components/talk/message/system/SysGroupTransferMessage.vue')['default']
|
||||
SysTextMessage: typeof import('./src/components/talk/message/system/SysTextMessage.vue')['default']
|
||||
|
6
env/.env.dev
vendored
@ -5,8 +5,4 @@ VITE_SHOW_CONSOLE = true
|
||||
# 是否开启sourcemap
|
||||
VITE_SHOW_SOURCEMAP = true
|
||||
# baseUrl
|
||||
VITE_BASEURL = 'http://172.16.100.93:8503'
|
||||
#VITE_SOCKET_API
|
||||
VITE_SOCKET_API = 'ws://172.16.100.93:8504'
|
||||
# EPRAPI baseUrl
|
||||
VITE_EPR_BASEURL = 'http://114.218.158.24:9020'
|
||||
VITE_BASEURL = 'http://warehouse.szjixun.cn/oa_backend'
|
||||
|
19
env/.env.prod
vendored
@ -1,21 +1,8 @@
|
||||
# 变量必须以 VITE_ 为前缀才能暴露给外部读取
|
||||
NODE_ENV = 'prod'
|
||||
# 是否显示console
|
||||
VITE_SHOW_CONSOLE = false
|
||||
VITE_SHOW_CONSOLE = true
|
||||
# 是否开启sourcemap
|
||||
VITE_SHOW_SOURCEMAP = false
|
||||
|
||||
VITE_SHOW_SOURCEMAP = true
|
||||
# baseUrl
|
||||
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' #体制内
|
||||
|
||||
VITE_BASEURL = 'https://oa-a.szjixun.cn/api'
|
||||
|
12
env/.env.test
vendored
@ -4,16 +4,10 @@ NODE_ENV = 'test'
|
||||
VITE_SHOW_CONSOLE = true
|
||||
# 是否开启sourcemap
|
||||
VITE_SHOW_SOURCEMAP = true
|
||||
|
||||
# # baseUrl
|
||||
VITE_BASEURL = 'http://172.16.100.93:8503'
|
||||
# #VITE_SOCKET_API
|
||||
VITE_SOCKET_API = 'ws://172.16.100.93:8504'
|
||||
|
||||
# baseUrl
|
||||
# VITE_BASEURL = 'http://192.168.88.21:9503'
|
||||
# VITE_BASEURL = 'https://warehouse.szjixun.cn/oa_backend'
|
||||
VITE_BASEURL = 'http://172.16.100.93:8503'
|
||||
#VITE_SOCKET_API
|
||||
# VITE_SOCKET_API = 'ws://192.168.88.21:9504'
|
||||
|
||||
VITE_SOCKET_API = 'ws://172.16.100.93:8504'
|
||||
# EPRAPI baseUrl
|
||||
VITE_EPR_BASEURL = 'http://114.218.158.24:9020'
|
||||
|
11
package.json
@ -2,15 +2,14 @@
|
||||
"name": "unihelper",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"packageManager": "pnpm@8.14.1",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"test:h5": "uni --mode test --port 2468",
|
||||
"prod:h5": "uni --mode prod",
|
||||
"build:h5:test": "uni build --mode test",
|
||||
"build:h5:prod": "uni build --mode prod",
|
||||
"preview:h5": "uni preview --mode test",
|
||||
"preview:h5:prod": "uni preview --mode prod"
|
||||
"build:h5:prod": "uni build --mode prod"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dcloudio/uni-app": "3.0.0-alpha-4000020240111001",
|
||||
@ -39,9 +38,7 @@
|
||||
"lodash": "^4.17.21",
|
||||
"nzh": "^1.0.13",
|
||||
"pinia-plugin-persistedstate": "^4.1.3",
|
||||
"quill": "^1.3.7",
|
||||
"quill-mention": "^4.1.0",
|
||||
"recorder-core": "^1.3.25011100",
|
||||
"quill-mention": "^6.0.2",
|
||||
"vconsole": "^3.15.1",
|
||||
"vue": "^3.3.8",
|
||||
"vue-i18n": "11.0.0-rc.1"
|
||||
@ -65,7 +62,7 @@
|
||||
"lint-staged": "^15.2.0",
|
||||
"naive-ui": "^2.41.0",
|
||||
"pinia": "2.0.36",
|
||||
"sass": "1.62.1",
|
||||
"sass": "^1.77.8",
|
||||
"simple-git-hooks": "^2.9.0",
|
||||
"typescript": "^5.3.3",
|
||||
"unocss": "^0.58.9",
|
||||
|
5462
pnpm-lock.yaml
23
src/App.vue
@ -1,33 +1,28 @@
|
||||
<script setup>
|
||||
import { useStatus } from '@/store/status'
|
||||
import { useUserStore, useDialogueListStore } from '@/store'
|
||||
import { useUserStore } from '@/store'
|
||||
import { useProvideUserModal } from '@/hooks'
|
||||
import {useAuth} from "@/store/auth";
|
||||
const {token} = useAuth()
|
||||
import ws from '@/connect'
|
||||
import {uniStorage} from "@/utils/uniStorage.js"
|
||||
const { statusBarHeight } = useStatus()
|
||||
const { uid, isShow } = useProvideUserModal()
|
||||
const userStore = useUserStore()
|
||||
const root = document.documentElement
|
||||
root.style.setProperty('--statusBarHeight', `${statusBarHeight.value}px`)
|
||||
const handleWebview = () => {
|
||||
let statusBarHeight_ = window?.plus?.navigator?.getStatusbarHeight()
|
||||
let statusBarHeight = window?.plus?.navigator?.getStatusbarHeight()
|
||||
const webview = plus.webview.currentWebview()
|
||||
// webview.setStyle({
|
||||
// top: statusBarHeight_,
|
||||
// bottom: 0,
|
||||
// })
|
||||
console.log("webview", webview)
|
||||
webview.setStyle({
|
||||
top: statusBarHeight,
|
||||
bottom: 0,
|
||||
})
|
||||
// console.log(webview)
|
||||
token.value = webview.token
|
||||
if(webview?.doClearDialogueList){
|
||||
useDialogueListStore().dialogueList.value = []
|
||||
uniStorage.removeItem('dialogueList')
|
||||
}
|
||||
userStore.loadSetting()
|
||||
ws.connect()
|
||||
}
|
||||
const init = () => {
|
||||
userStore.loadSetting()
|
||||
ws.connect()
|
||||
if (typeof plus !== 'undefined') {
|
||||
handleWebview()
|
||||
} else {
|
||||
|
@ -1,47 +0,0 @@
|
||||
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,6 +1,5 @@
|
||||
import request from '@/service/index.js'
|
||||
import qs from 'qs'
|
||||
import { useTalkStore, useDialogueStore } from '@/store'
|
||||
|
||||
// 获取聊天列表服务接口
|
||||
export const ServeGetTalkList = (data) => {
|
||||
@ -39,31 +38,7 @@ export const ServeTopTalkList = (data) => {
|
||||
}
|
||||
|
||||
// 清除聊天消息未读数服务接口
|
||||
export const ServeClearTalkUnreadNum = (data, unReadNum) => {
|
||||
console.log('=======chatApp==UnreadNum', unReadNum)
|
||||
if (
|
||||
!useTalkStore().items[
|
||||
useTalkStore().findTalkIndex(useDialogueStore().index_name)
|
||||
]?.is_disturb
|
||||
) {
|
||||
if (typeof plus !== 'undefined') {
|
||||
let OAWebView = plus.webview.all()
|
||||
OAWebView.forEach((webview) => {
|
||||
if (webview.id === 'webviewId1') {
|
||||
webview.evalJS(`updateUnreadMsgNumReduce('${unReadNum}')`)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
document.addEventListener('plusready', () => {
|
||||
let OAWebView = plus.webview.all()
|
||||
OAWebView.forEach((webview) => {
|
||||
if (webview.id === 'webviewId1') {
|
||||
webview.evalJS(`updateUnreadMsgNumReduce('${unReadNum}')`)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
export const ServeClearTalkUnreadNum = (data) => {
|
||||
return request({
|
||||
url: '/api/v1/talk/unread/clear',
|
||||
method: 'POST',
|
||||
@ -83,7 +58,7 @@ export const ServeTalkRecords = (data) => {
|
||||
// 获取转发会话记录详情列表服务接口
|
||||
export const ServeGetForwardRecords = (data) => {
|
||||
return request({
|
||||
url: '/api/v1/talk/records/forward/v2',
|
||||
url: '/api/v1/talk/records/forward',
|
||||
method: 'GET',
|
||||
data,
|
||||
})
|
||||
@ -194,58 +169,13 @@ export const ServeConfirmVoteHandle = (data) => {
|
||||
})
|
||||
}
|
||||
|
||||
export const uploadImg = (data, onProgressFn) => {
|
||||
export const uploadImg = (data,onProgressFn) => {
|
||||
return request({
|
||||
url: '/upload/img',
|
||||
method: 'POST',
|
||||
data: data,
|
||||
baseURL: import.meta.env.VITE_EPR_BASEURL,
|
||||
isFormData: true,
|
||||
onUploadProgress: (progressEvent) =>
|
||||
onProgressFn(progressEvent, data.get('file')),
|
||||
data:data,
|
||||
baseURL:import.meta.env.VITE_EPR_BASEURL,
|
||||
isFormData:true,
|
||||
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,
|
||||
})
|
||||
}
|
@ -26,22 +26,6 @@ export const departmentV2TreeAll = (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) => {
|
||||
@ -61,14 +45,6 @@ export const userV2List = (data) => {
|
||||
data,
|
||||
})
|
||||
}
|
||||
// 过滤测试数据的erp用户接口
|
||||
export const userV2List2 = (data) => {
|
||||
return request({
|
||||
url: '/api/v1/group/erp/users',
|
||||
method: 'POST',
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
export const groupCreateDept = (data) => {
|
||||
return request({
|
||||
|
@ -4,7 +4,7 @@ import qs from 'qs'
|
||||
// ES搜索聊天记录-主页搜索什么都有
|
||||
export const ServeSeachQueryAll = (data) => {
|
||||
return request({
|
||||
url: '/api/v1/elasticsearch/query-all/v2',
|
||||
url: '/api/v1/elasticsearch/query-all',
|
||||
method: 'POST',
|
||||
data,
|
||||
})
|
||||
@ -13,7 +13,7 @@ export const ServeSeachQueryAll = (data) => {
|
||||
// ES搜索用户数据
|
||||
export const ServeQueryUser = (data) => {
|
||||
return request({
|
||||
url: '/api/v1/elasticsearch/query-user/v2',
|
||||
url: '/api/v1/elasticsearch/query-user',
|
||||
method: 'POST',
|
||||
data,
|
||||
})
|
||||
@ -45,12 +45,3 @@ export const ServeTalkDate = (data) => {
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
//获取会话Id
|
||||
export const ServeGetSessionId = (data) => {
|
||||
return request({
|
||||
url: '/api/v1/talk/session/getId',
|
||||
method: 'POST',
|
||||
data,
|
||||
})
|
||||
}
|
@ -10,9 +10,10 @@ export const ServeGetUserSetting = (data) => {
|
||||
|
||||
export const userInfoApi = (data) => {
|
||||
return request({
|
||||
url: '/api/v1/users/erp/info',
|
||||
url: '/user/info',
|
||||
method: 'POST',
|
||||
data,
|
||||
baseURL:import.meta.env.VITE_EPR_BASEURL,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1,89 +0,0 @@
|
||||
<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>
|
@ -1,81 +0,0 @@
|
||||
<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>
|
||||
<div class="avatar-module" :style="[customStyle, { background: avatar ? '#fff' : '' }]">
|
||||
<div class="avatar-module" :style="customStyle">
|
||||
<img :src="avatar" v-if="avatar" />
|
||||
<span v-else :style="customTextStyle">{{ text_avatar }}</span>
|
||||
</div>
|
||||
@ -89,7 +89,6 @@ const text_avatar = computed(() => {
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -90,6 +90,8 @@ const onSubmit = () => {
|
||||
ServeUploadAvatar(form).then((res) => {
|
||||
if (res.code == 200) {
|
||||
emit('success', res.data.avatar)
|
||||
} else {
|
||||
message.warning(res.message)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
@ -6,11 +6,7 @@
|
||||
props.subBtnText ? 'apposition-btn-style' : '',
|
||||
]"
|
||||
>
|
||||
<wd-button
|
||||
custom-class="custom-sub-btn-class"
|
||||
v-if="props.subBtnText"
|
||||
@click="clickSubBtn"
|
||||
>
|
||||
<wd-button custom-class="custom-sub-btn-class" v-if="props.subBtnText">
|
||||
{{ props.subBtnText }}
|
||||
</wd-button>
|
||||
<wd-button
|
||||
@ -19,7 +15,6 @@
|
||||
:disabled="props?.disabled"
|
||||
:class="[props?.disabled ? 'custom-btn-class-disabled' : '']"
|
||||
:plain="props?.plain"
|
||||
:loading="props?.isLoading"
|
||||
>
|
||||
{{ props.btnText }}
|
||||
</wd-button>
|
||||
@ -29,22 +24,16 @@
|
||||
import { reactive } from 'vue'
|
||||
import { defineProps, defineEmits } from 'vue'
|
||||
const state = reactive({})
|
||||
const emits = defineEmits(['clickSubBtn', 'clickBtn'])
|
||||
const emits = defineEmits(['clickBtn'])
|
||||
const props = defineProps({
|
||||
isBottom: false, //是否底部按钮
|
||||
btnText: '', //按钮文字
|
||||
subBtnText: '', //次要按钮文字
|
||||
disabled: false, //是否禁用
|
||||
plain: false, //是否镂空
|
||||
isLoading: false, //是否正在加载中
|
||||
})
|
||||
|
||||
//点击副按钮
|
||||
const clickSubBtn = () => {
|
||||
emits('clickSubBtn')
|
||||
}
|
||||
|
||||
//点击主按钮
|
||||
//点击
|
||||
const clickBtn = () => {
|
||||
emits('clickBtn')
|
||||
}
|
||||
|
@ -21,20 +21,9 @@
|
||||
<script setup>
|
||||
import { defineProps, defineEmits, reactive, watch } from 'vue'
|
||||
const props = defineProps({
|
||||
searchText: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
first_talk_record_infos: {
|
||||
type: Object,
|
||||
default(){
|
||||
return {}
|
||||
}
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
searchText: String,
|
||||
first_talk_record_infos: Object,
|
||||
disabled: Boolean,
|
||||
})
|
||||
const state = reactive({
|
||||
searchText: '', //搜索内容
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<tm-navbar
|
||||
:hideBack="props.hideBack"
|
||||
:hideHome="props.hideHome"
|
||||
hideHome
|
||||
:title="props.title"
|
||||
:shadow="props.shadowNum"
|
||||
:fontSize="34"
|
||||
@ -38,10 +38,6 @@ const props = defineProps({
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
hideHome: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
|
@ -25,15 +25,7 @@
|
||||
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.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>
|
||||
</div>
|
||||
<div
|
||||
@click="() => itemClick('multipleChoose')"
|
||||
@ -44,7 +36,7 @@
|
||||
:height="40"
|
||||
:src="multipleChoices"
|
||||
></tm-image>
|
||||
<div class="mt-1">多选</div>
|
||||
<div>多选</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="props.isShowCite"
|
||||
@ -52,7 +44,7 @@
|
||||
class="flex flex-col items-center justify-center"
|
||||
>
|
||||
<tm-image :width="40" :height="40" :src="cite"></tm-image>
|
||||
<div class="mt-1">引用</div>
|
||||
<div>引用</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="props.isShowWithdraw"
|
||||
@ -60,14 +52,14 @@
|
||||
class="flex flex-col items-center justify-center"
|
||||
>
|
||||
<tm-image :width="40" :height="40" :src="withdraw"></tm-image>
|
||||
<div class="mt-1">撤回</div>
|
||||
<div>撤回</div>
|
||||
</div>
|
||||
<div
|
||||
@click="() => itemClick('actionDelete')"
|
||||
class="flex flex-col items-center justify-center"
|
||||
>
|
||||
<tm-image :width="40" :height="40" :src="delete07"></tm-image>
|
||||
<div class="mt-1">删除</div>
|
||||
<div>删除</div>
|
||||
</div>
|
||||
</div>
|
||||
<div :style="data.iconStyle" class="icon"></div>
|
||||
@ -86,8 +78,8 @@
|
||||
// 组件
|
||||
|
||||
// uniapp & vue
|
||||
import { onLoad, onReady } from '@dcloudio/uni-app'
|
||||
import { defineEmits, defineProps } from 'vue'
|
||||
import { onLoad, onReady } from "@dcloudio/uni-app";
|
||||
import { defineEmits, defineProps } from "vue";
|
||||
import {
|
||||
reactive,
|
||||
ref,
|
||||
@ -95,18 +87,18 @@ import {
|
||||
computed,
|
||||
nextTick,
|
||||
getCurrentInstance,
|
||||
onMounted,
|
||||
onBeforeUnmount,
|
||||
} from 'vue'
|
||||
import copy07 from '@/static/image/chatList/copy07@2x.png'
|
||||
import multipleChoices from '@/static/image/chatList/multipleChoices@2x.png'
|
||||
import cite from '@/static/image/chatList/cite@2x.png'
|
||||
import withdraw from '@/static/image/chatList/withdraw@2x.png'
|
||||
import delete07 from '@/static/image/chatList/delete@2x.png'
|
||||
onMounted,
|
||||
onBeforeUnmount
|
||||
} from "vue";
|
||||
import copy07 from "@/static/image/chatList/copy07@2x.png";
|
||||
import multipleChoices from "@/static/image/chatList/multipleChoices@2x.png";
|
||||
import cite from "@/static/image/chatList/cite@2x.png";
|
||||
import withdraw from "@/static/image/chatList/withdraw@2x.png";
|
||||
import delete07 from "@/static/image/chatList/delete@2x.png";
|
||||
|
||||
// pinia
|
||||
const systemInfo = uni.getSystemInfoSync()
|
||||
const bubbleRef = ref(null)
|
||||
const systemInfo = uni.getSystemInfoSync();
|
||||
const bubbleRef = ref(null);
|
||||
|
||||
const props = defineProps({
|
||||
isShowCopy: {
|
||||
@ -121,114 +113,109 @@ const props = defineProps({
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
isShowConvertText: {
|
||||
//是否显示转文字
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
const emits = defineEmits(['clickMenu'])
|
||||
const emits = defineEmits(["clickMenu"]);
|
||||
|
||||
/**
|
||||
* @name 生成UUID
|
||||
*/
|
||||
const uuid = () => {
|
||||
const reg = /[xy]/g
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
|
||||
const reg = /[xy]/g;
|
||||
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
|
||||
.replace(reg, function (c) {
|
||||
var r = (Math.random() * 16) | 0,
|
||||
v = c == 'x' ? r : (r & 0x3) | 0x8
|
||||
return v.toString(16)
|
||||
v = c == "x" ? r : (r & 0x3) | 0x8;
|
||||
return v.toString(16);
|
||||
})
|
||||
.replace(/-/g, '')
|
||||
}
|
||||
.replace(/-/g, "");
|
||||
};
|
||||
|
||||
const popoverBoxId = `ID${uuid()}`
|
||||
const popoverContentId = `ID${uuid()}`
|
||||
const instance = getCurrentInstance()
|
||||
const popoverBoxId = `ID${uuid()}`;
|
||||
const popoverContentId = `ID${uuid()}`;
|
||||
const instance = getCurrentInstance();
|
||||
const data = reactive({
|
||||
popoverShow: false,
|
||||
defaultStyle: {},
|
||||
showStyle: {
|
||||
left: 0,
|
||||
right: '',
|
||||
transform: '',
|
||||
right: "",
|
||||
transform: "",
|
||||
},
|
||||
iconStyle: {
|
||||
left: '',
|
||||
right: '',
|
||||
transform: '',
|
||||
left: "",
|
||||
right: "",
|
||||
transform: "",
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
/**
|
||||
* @name 获取DOM
|
||||
*/
|
||||
const getDom = (dom) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const query = uni.createSelectorQuery().in(instance)
|
||||
let select = query.select(dom)
|
||||
const query = uni.createSelectorQuery().in(instance);
|
||||
let select = query.select(dom);
|
||||
const boundingClientRect = select.boundingClientRect((data) => {
|
||||
resolve(data)
|
||||
})
|
||||
boundingClientRect.exec()
|
||||
})
|
||||
}
|
||||
resolve(data);
|
||||
});
|
||||
boundingClientRect.exec();
|
||||
});
|
||||
};
|
||||
|
||||
const itemClick = (item) => {
|
||||
emits('clickMenu', item)
|
||||
}
|
||||
emits("clickMenu", item);
|
||||
};
|
||||
|
||||
// 弹起 长按5
|
||||
let pressDownTime = 0
|
||||
let time = null
|
||||
let pressDownTime = 0;
|
||||
let time = null;
|
||||
const onTouchstart = () => {
|
||||
time && clearTimeout(time)
|
||||
time = setTimeout(open, 500)
|
||||
}
|
||||
time && clearTimeout(time);
|
||||
time = setTimeout(open, 500);
|
||||
};
|
||||
|
||||
const onTouchend = () => {
|
||||
time && clearTimeout(time)
|
||||
}
|
||||
time && clearTimeout(time);
|
||||
};
|
||||
|
||||
const open = async () => {
|
||||
let popoverContent = await getDom(`#${popoverContentId}`)
|
||||
let popoverBox = await getDom(`#${popoverBoxId}`)
|
||||
let popoverContent = await getDom(`#${popoverContentId}`);
|
||||
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 = {
|
||||
top: isTop ? '60rpx' : 'auto',
|
||||
bottom: !isTop ? '-20rpx' : 'auto',
|
||||
transform: `translateY(${isTop ? '-100%' : '100%'}) scale(.8)`,
|
||||
}
|
||||
top: isTop ? "60rpx" : "auto",
|
||||
bottom: !isTop ? "-20rpx" : "auto",
|
||||
transform: `translateY(${isTop ? "-100%" : "100%"}) scale(.8)`,
|
||||
};
|
||||
// 左边还是右边
|
||||
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
|
||||
}px ${isTop ? '100%' : '0%'}`
|
||||
}px ${isTop ? "100%" : "0%"}`;
|
||||
} else {
|
||||
data.defaultStyle.left = 0
|
||||
data.defaultStyle.left = 0;
|
||||
// 动画缩放中心点
|
||||
data.defaultStyle['transform-origin'] = `${originX}px ${
|
||||
isTop ? '100%' : '0%'
|
||||
}`
|
||||
data.defaultStyle["transform-origin"] = `${originX}px ${
|
||||
isTop ? "100%" : "0%"
|
||||
}`;
|
||||
}
|
||||
data.showStyle = { ...data.defaultStyle }
|
||||
data.showStyle = { ...data.defaultStyle };
|
||||
// icon位置样式
|
||||
let iconDefsultStyle = {
|
||||
transform: `translate(0%, ${isTop ? '20%' : '-20%'})`,
|
||||
'border-top-color': isTop ? '#333333' : '',
|
||||
'border-bottom-color': !isTop ? '#333333' : '',
|
||||
top: !isTop ? '-20rpx' : 'auto',
|
||||
bottom: isTop ? '-20rpx' : 'auto',
|
||||
}
|
||||
transform: `translate(0%, ${isTop ? "20%" : "-20%"})`,
|
||||
"border-top-color": isTop ? "#333333" : "",
|
||||
"border-bottom-color": !isTop ? "#333333" : "",
|
||||
top: !isTop ? "-20rpx" : "auto",
|
||||
bottom: isTop ? "-20rpx" : "auto",
|
||||
};
|
||||
|
||||
setTimeout(() => {
|
||||
if (popoverBox.left > systemInfo.windowWidth - popoverBox.right) {
|
||||
@ -237,55 +224,55 @@ const open = async () => {
|
||||
...data.defaultStyle,
|
||||
// 显示
|
||||
opacity: 1,
|
||||
transform: `translateY(${isTop ? '-100%' : '100%'}) scale(1)`,
|
||||
'pointer-events': 'auto',
|
||||
}
|
||||
transform: `translateY(${isTop ? "-100%" : "100%"}) scale(1)`,
|
||||
"pointer-events": "auto",
|
||||
};
|
||||
data.iconStyle = {
|
||||
right: `${originX}px`,
|
||||
left: 'auto',
|
||||
left: "auto",
|
||||
...iconDefsultStyle,
|
||||
}
|
||||
};
|
||||
} else {
|
||||
data.showStyle = {
|
||||
// 位置
|
||||
...data.defaultStyle,
|
||||
// 显示
|
||||
opacity: 1,
|
||||
transform: `translateY(${isTop ? '-100%' : '100%'}) scale(1)`,
|
||||
'pointer-events': 'auto',
|
||||
}
|
||||
transform: `translateY(${isTop ? "-100%" : "100%"}) scale(1)`,
|
||||
"pointer-events": "auto",
|
||||
};
|
||||
data.iconStyle = {
|
||||
left: `${originX}px`,
|
||||
right: 'auto',
|
||||
right: "auto",
|
||||
...iconDefsultStyle,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (!data.popoverShow) data.popoverShow = true
|
||||
}, 200)
|
||||
}
|
||||
if (!data.popoverShow) data.popoverShow = true;
|
||||
}, 200);
|
||||
};
|
||||
|
||||
const close = (time) => {
|
||||
setTimeout(() => {
|
||||
data.popoverShow = false
|
||||
data.showStyle = data.defaultStyle
|
||||
}, time || 0)
|
||||
}
|
||||
data.popoverShow = false;
|
||||
data.showStyle = data.defaultStyle;
|
||||
}, time || 0);
|
||||
};
|
||||
const handleClickOutside = (event) => {
|
||||
if ((data.popoverShow = false)) {
|
||||
if (data.popoverShow = false) {
|
||||
return false
|
||||
}
|
||||
if (bubbleRef.value && !bubbleRef.value.contains(event.target)) {
|
||||
close()
|
||||
close();
|
||||
}
|
||||
}
|
||||
};
|
||||
onMounted(() => {
|
||||
document.addEventListener('click', handleClickOutside)
|
||||
})
|
||||
document.addEventListener('click', handleClickOutside);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
document.removeEventListener('click', handleClickOutside)
|
||||
})
|
||||
document.removeEventListener('click', handleClickOutside);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -25,130 +25,69 @@ const getFileTypeIMG = computed(() => {
|
||||
let objT = {
|
||||
finishedImg: '',
|
||||
blankImg: '',
|
||||
progressColor: '',
|
||||
}
|
||||
progressColor: ''
|
||||
};
|
||||
|
||||
switch (suffix) {
|
||||
case 'pdf':
|
||||
objT.finishedImg = filePaperPDF
|
||||
objT.blankImg = filePaperPDFBlank
|
||||
objT.progressColor = '#DE4E4E'
|
||||
break
|
||||
break;
|
||||
case 'doc':
|
||||
case 'docx':
|
||||
objT.finishedImg = filePaperWord
|
||||
objT.blankImg = filePaperWordBlank
|
||||
objT.progressColor = '#2750B2'
|
||||
break
|
||||
break;
|
||||
case 'xls':
|
||||
case 'xlsx':
|
||||
objT.finishedImg = filePaperExcel
|
||||
objT.blankImg = filePaperExcelBlank
|
||||
objT.progressColor = '#3C7F4B'
|
||||
break
|
||||
break;
|
||||
case 'ppt':
|
||||
case 'pptx':
|
||||
objT.finishedImg = filePaperPPT
|
||||
objT.blankImg = filePaperPPTBlank
|
||||
objT.progressColor = '#B74B2B'
|
||||
break
|
||||
break;
|
||||
default:
|
||||
objT.finishedImg = filePaperOther
|
||||
objT.blankImg = filePaperOtherBlank
|
||||
objT.progressColor = '#46299d'
|
||||
objT.progressColor = '#747474'
|
||||
}
|
||||
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>
|
||||
|
||||
<template>
|
||||
<section
|
||||
class="file-message"
|
||||
@click="previewPDF"
|
||||
:class="{ left: data.float === 'left', right: data.float === 'right' }"
|
||||
>
|
||||
<div class="flex justify-between">
|
||||
<div
|
||||
class="w-[228rpx] text-[32rpx] text-[#1A1A1A] h-[88rpx] leading-[44rpx] textEllipsis file_name"
|
||||
>
|
||||
<div class="w-[228rpx] text-[32rpx] text-[#1A1A1A] h-[88rpx] leading-[44rpx] textEllipsis">
|
||||
{{ extra.name }}
|
||||
</div>
|
||||
<div
|
||||
v-if="data.uploadStatus === 2 || !data.uploadStatus"
|
||||
class="w-[95rpx]"
|
||||
>
|
||||
<tm-image
|
||||
:width="95"
|
||||
:height="95"
|
||||
:src="getFileTypeIMG.finishedImg"
|
||||
></tm-image>
|
||||
<div v-if="data.uploadStatus === 2 || !data.uploadStatus" class="w-[95rpx]">
|
||||
<tm-image :width="95" :height="95" :src="getFileTypeIMG.finishedImg"></tm-image>
|
||||
</div>
|
||||
<div
|
||||
v-if="data.uploadStatus === 1 || data.uploadStatus === 3"
|
||||
class="w-[95rpx]"
|
||||
>
|
||||
<tm-image
|
||||
:width="95"
|
||||
:height="95"
|
||||
:src="getFileTypeIMG.blankImg"
|
||||
></tm-image>
|
||||
<wd-circle v-if="data.uploadStatus === 1"
|
||||
customClass="circleProgress"
|
||||
:modelValue="data.uploadCurrent"
|
||||
layerColor="#E3E3E3"
|
||||
:color="getFileTypeIMG.progressColor"
|
||||
:strokeWidth="3"
|
||||
:size="20"
|
||||
></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 v-if="data.uploadStatus === 1 || data.uploadStatus === 3" class="w-[95rpx]">
|
||||
<tm-image :width="95" :height="95" :src="getFileTypeIMG.blankImg"></tm-image>
|
||||
<wd-circle
|
||||
customClass="circleProgress"
|
||||
:modelValue="data.uploadCurrent"
|
||||
layerColor="#E3E3E3"
|
||||
:color="getFileTypeIMG.progressColor"
|
||||
:strokeWidth="3"
|
||||
:size="20"
|
||||
></wd-circle>
|
||||
</div>
|
||||
</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="ext">{{ getFileNameSuffix(extra.name) }}</div>
|
||||
<div class="file-box">
|
||||
@ -185,11 +124,6 @@ const downloadAndOpenFile = () => {
|
||||
border-radius: 16rpx 0 16rpx 16rpx;
|
||||
}
|
||||
|
||||
.file_name {
|
||||
word-break: break-all; /* 在任意字符间断行 */
|
||||
word-wrap: break-word; /* 允许长单词换行到下一行 */
|
||||
}
|
||||
|
||||
.main {
|
||||
height: 45px;
|
||||
display: flex;
|
||||
@ -278,7 +212,7 @@ const downloadAndOpenFile = () => {
|
||||
}
|
||||
|
||||
.divider {
|
||||
background-color: #e7e7e7;
|
||||
background-color: #E7E7E7;
|
||||
height: 1rpx;
|
||||
}
|
||||
|
||||
@ -291,20 +225,4 @@ const downloadAndOpenFile = () => {
|
||||
width: 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>
|
||||
|
@ -12,25 +12,19 @@ const props = defineProps<{
|
||||
const isShowRecord = ref(false)
|
||||
|
||||
const title = computed(() => {
|
||||
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('和')
|
||||
return [...new Set(props.extra.records.map((v) => v.nickname))].join('、')
|
||||
})
|
||||
console.log(props.extra.records)
|
||||
|
||||
const onClick = () => {
|
||||
// isShowRecord.value = true
|
||||
uni.navigateTo({
|
||||
url: '/pages/forwardRecord/index?msgId=' + props.data.msg_id + '&created_at=' + props.data?.created_at
|
||||
url: '/pages/forwardRecord/index?msgId=' + props.data.msg_id
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<section class="im-message-forward pointer" :class="{ left: data.float === 'left' }" @click="onClick">
|
||||
<div class="title">{{ extra.forward_name || title}}的会话记录</div>
|
||||
<div class="title">{{ title }} 的会话记录</div>
|
||||
<div class="list" v-for="(record, index) in extra.records" :key="index">
|
||||
<p>
|
||||
<span>{{ record.nickname }}: </span>
|
||||
@ -65,14 +59,13 @@ const onClick = () => {
|
||||
}
|
||||
|
||||
.title {
|
||||
max-height: 88rpx;
|
||||
height: 44rpx;
|
||||
line-height: 44rpx;
|
||||
font-size: 32rpx;
|
||||
color: #1A1A1A;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-weight: 400;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
@ -12,40 +12,40 @@ const img = computed(() => {
|
||||
// console.log(props.extra);
|
||||
let info = {
|
||||
width: 0,
|
||||
height: 0,
|
||||
height: 0
|
||||
}
|
||||
if (props.extra.url.includes('blob:http://')) {
|
||||
info = {
|
||||
width: props.extra.width,
|
||||
height: props.extra.height,
|
||||
height: props.extra.height
|
||||
}
|
||||
} else {
|
||||
}else {
|
||||
info = getImageInfo(props.extra.url)
|
||||
}
|
||||
|
||||
if (info.width == 0 || info.height == 0) {
|
||||
return {
|
||||
width: 450,
|
||||
height: 298,
|
||||
height: 298
|
||||
}
|
||||
}
|
||||
if (info.width < 300) {
|
||||
if(info.width<300){
|
||||
return {
|
||||
width: 300,
|
||||
height: info.height / (info.width / 300),
|
||||
height: info.height / (info.width / 300)
|
||||
}
|
||||
}
|
||||
|
||||
if (info.width < 350) {
|
||||
return {
|
||||
width: info.width,
|
||||
height: info.height,
|
||||
height: info.height
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
width: 350,
|
||||
height: info.height / (info.width / 350),
|
||||
height: info.height / (info.width / 350)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@ -54,30 +54,13 @@ const img = computed(() => {
|
||||
class="im-message-image"
|
||||
:class="{
|
||||
left: data.float === 'left',
|
||||
right: data.float === 'right',
|
||||
right: data.float === 'right'
|
||||
}"
|
||||
>
|
||||
<div class="image-container">
|
||||
<div class="relative">
|
||||
<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 class="image-container">
|
||||
<tm-image preview :width="img.width" :height="img.height" :src="extra.url" />
|
||||
<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>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
<style lang="less" scoped>
|
||||
@ -96,12 +79,12 @@ const img = computed(() => {
|
||||
}
|
||||
|
||||
&.right {
|
||||
background-color: #46299d;
|
||||
background-color: #46299D;
|
||||
border-radius: 16rpx 0 16rpx 16rpx;
|
||||
}
|
||||
}
|
||||
.image-container {
|
||||
position: relative;
|
||||
position: relative;
|
||||
|
||||
.circleProgress {
|
||||
position: absolute;
|
||||
@ -111,18 +94,4 @@ const img = computed(() => {
|
||||
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>
|
||||
|
@ -4,97 +4,34 @@ import { formatTime } from '@/utils/datetime'
|
||||
defineProps({
|
||||
login_uid: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
default: 0
|
||||
},
|
||||
user_id: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
default: 0
|
||||
},
|
||||
talk_type: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
default: 0
|
||||
},
|
||||
nickname: {
|
||||
type: String,
|
||||
default: '',
|
||||
default: ''
|
||||
},
|
||||
datetime: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
msg_id: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
revokeInfo: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
extra:{
|
||||
type: String,
|
||||
default: '',
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<div class="im-message-revoke">
|
||||
<div class="content" v-if="JSON.stringify(revokeInfo) !== '{}'">
|
||||
<span v-if="talk_type === 1 && login_uid === revokeInfo.withdraw_id">
|
||||
你撤回了一条消息 | {{ formatTime(datetime) }}
|
||||
<slot></slot>
|
||||
<!-- 添加插槽用于放置重新编辑按钮 -->
|
||||
</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">
|
||||
你撤回了一条消息 |
|
||||
<div class="content">
|
||||
<span v-if="login_uid == user_id"> 你撤回了一条消息 | {{ formatTime(datetime) }} </span>
|
||||
<span v-else-if="talk_type == 1"> 对方撤回了一条消息 | {{ formatTime(datetime) }} </span>
|
||||
<span v-else>
|
||||
"{{ nickname }}" 撤回了一条消息 |
|
||||
{{ 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>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -2,7 +2,6 @@
|
||||
import { textReplaceEmoji } from '@/utils/emojis'
|
||||
import { textReplaceLink, textReplaceMention } from '@/utils/strings'
|
||||
import { ITalkRecordExtraText, ITalkRecord } from '@/types/chat'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
extra: ITalkRecordExtraText
|
||||
@ -13,14 +12,15 @@ const props = defineProps<{
|
||||
|
||||
const float = props.data.float
|
||||
|
||||
const textContent = computed(() => {
|
||||
let text = props.extra?.content || ''
|
||||
// text = textReplaceLink(text)
|
||||
if (props.data.talk_type == 2) {
|
||||
text = textReplaceMention(text, '#1890ff')
|
||||
}
|
||||
return textReplaceEmoji(text)
|
||||
})
|
||||
let textContent = props.extra?.content || ''
|
||||
|
||||
textContent = textReplaceLink(textContent)
|
||||
|
||||
if (props.data.talk_type == 2) {
|
||||
textContent = textReplaceMention(textContent, '#1890ff')
|
||||
}
|
||||
|
||||
textContent = textReplaceEmoji(textContent)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -1,8 +1,8 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref, nextTick, getCurrentInstance, computed, onMounted } from 'vue'
|
||||
import { getImageInfo } from '@/utils/functions'
|
||||
import playCircle from '@/static/image/chatList/playCircle@2x.png'
|
||||
import { useStatus } from '@/store/status'
|
||||
import playCircle from "@/static/image/chatList/playCircle@2x.png";
|
||||
import { useStatus } from "@/store/status";
|
||||
|
||||
const { statusBarHeight } = useStatus()
|
||||
const instance = getCurrentInstance()
|
||||
@ -20,12 +20,12 @@ const open = ref(false)
|
||||
const img = computed(() => {
|
||||
let info = {
|
||||
width: 0,
|
||||
height: 0,
|
||||
height: 0
|
||||
}
|
||||
if (props.extra.url.includes('blob:http://')) {
|
||||
info = {
|
||||
width: props.extra.width,
|
||||
height: props.extra.height,
|
||||
height: props.extra.height
|
||||
}
|
||||
} else {
|
||||
info = getImageInfo(props.extra.url)
|
||||
@ -34,26 +34,26 @@ const img = computed(() => {
|
||||
if (info.width == 0 || info.height == 0) {
|
||||
return {
|
||||
width: 450,
|
||||
height: 298,
|
||||
height: 298
|
||||
}
|
||||
}
|
||||
if (info.width < 300) {
|
||||
return {
|
||||
width: 300,
|
||||
height: info.height / (info.width / 300),
|
||||
height: info.height / (info.width / 300)
|
||||
}
|
||||
}
|
||||
|
||||
if (info.width < 350) {
|
||||
return {
|
||||
width: info.width,
|
||||
height: info.height,
|
||||
height: info.height
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
width: 350,
|
||||
height: info.height / (info.width / 350),
|
||||
height: info.height / (info.width / 350)
|
||||
}
|
||||
})
|
||||
|
||||
@ -67,98 +67,57 @@ const fullscreenchange = (e) => {
|
||||
|
||||
/* 视频播放 获取第一帧 */
|
||||
const canplay = (e) => {
|
||||
console.log('Video can play:', e)
|
||||
console.log('Video can play:', e);
|
||||
|
||||
if (e.target) {
|
||||
setTimeout(() => {
|
||||
e.target.pause()
|
||||
}, 200)
|
||||
e.target.pause();
|
||||
}, 200);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
async function onPlay() {
|
||||
videoContext.value = uni.createVideoContext(props.extra.url, instance);
|
||||
videoContext.value.requestFullScreen({ direction: 2 });
|
||||
videoContext.value.play()
|
||||
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(() => {
|
||||
videoRef.value = uni.createVideoContext(props.data.msg_id)
|
||||
videoRef.value = uni.createVideoContext(props.data.msg_id);
|
||||
videoRef.value.play()
|
||||
setTimeout(() => {
|
||||
videoRef.value.pause()
|
||||
}, 200)
|
||||
}, 200);
|
||||
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<section
|
||||
class="im-message-video"
|
||||
:class="{ left: data.float === 'left' }"
|
||||
@click="onPlay"
|
||||
>
|
||||
<div
|
||||
class="coverVideo"
|
||||
:style="{
|
||||
width: img.width + '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%"
|
||||
height="100%"
|
||||
playsinline
|
||||
preload="auto"
|
||||
controls="false"
|
||||
x5-playsinline
|
||||
webkit-playsinline
|
||||
style="object-fit: cover; pointer-events: none;"
|
||||
></video>
|
||||
<section class="im-message-video" :class="{ left: data.float === 'left' }" @click="onPlay">
|
||||
<div class="coverVideo" :style="{
|
||||
width: img.width + '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%"
|
||||
height="100%" playsinline preload="auto" controls="false" x5-playsinline
|
||||
webkit-playsinline style="object-fit: cover; pointer-events: none;">
|
||||
</video>
|
||||
</div>
|
||||
<wd-img
|
||||
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',
|
||||
height: img.height + 'rpx',
|
||||
}"
|
||||
>
|
||||
<wd-img 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',
|
||||
height: img.height + 'rpx'
|
||||
}">
|
||||
<tm-image :src="playCircle" :width="80" :height="80" />
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="btn-video"
|
||||
:style="{
|
||||
width: img.width + 'rpx',
|
||||
height: img.height + 'rpx',
|
||||
}"
|
||||
>
|
||||
<div v-else class="btn-video" :style="{
|
||||
width: img.width + 'rpx',
|
||||
height: img.height + 'rpx'
|
||||
}" >
|
||||
<wd-circle
|
||||
v-if="data.uploadStatus === 1"
|
||||
v-model="props.data.uploadCurrent"
|
||||
customClass="circleProgress"
|
||||
color="#46299d"
|
||||
layer-color="#E3E3E3"
|
||||
layerColor="#E3E3E3"
|
||||
color="#FFFFFF"
|
||||
:strokeWidth="6"
|
||||
:size="40"
|
||||
></wd-circle>
|
||||
@ -172,32 +131,18 @@ onMounted(() => {
|
||||
:width="70"
|
||||
:percent="props.data.uploadCurrent">
|
||||
</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>
|
||||
</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>
|
||||
<style lang="less" scoped>
|
||||
.im-message-video {
|
||||
overflow: hidden;
|
||||
padding: 20rpx 18rpx;
|
||||
background: #46299d;
|
||||
background: #46299D;
|
||||
min-width: 30rpx;
|
||||
min-height: 30rpx;
|
||||
display: inline-flex;
|
||||
@ -255,43 +200,10 @@ onMounted(() => {
|
||||
:deep(.uni-video-bar) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
}
|
||||
.circleProgress {
|
||||
width: 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>
|
||||
|
@ -1,25 +0,0 @@
|
||||
<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>
|
@ -1,19 +0,0 @@
|
||||
<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>
|
@ -1,25 +0,0 @@
|
||||
<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>
|
||||
</template>
|
||||
|
||||
<span>移出群聊</span>
|
||||
<span>踢出群聊</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,23 +0,0 @@
|
||||
<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>
|
@ -30,7 +30,6 @@ class Connect {
|
||||
},
|
||||
// Websocket 连接成功回调方法
|
||||
onOpen: () => {
|
||||
console.log("socket已连接")
|
||||
// 更新 WebSocket 连接状态
|
||||
useUserStore().updateSocketStatus(true)
|
||||
// online.value = true;
|
||||
@ -38,7 +37,6 @@ class Connect {
|
||||
},
|
||||
// Websocket 断开连接回调方法
|
||||
onClose: () => {
|
||||
console.log("socket已断开")
|
||||
// 更新 WebSocket 连接状态
|
||||
useUserStore().updateSocketStatus(false)
|
||||
// online.value = false
|
||||
|
@ -17,7 +17,7 @@ export const ChatMsgSysText = 1000 // 系统文本消息
|
||||
export const ChatMsgSysGroupCreate = 1101 // 创建群聊消息
|
||||
export const ChatMsgSysGroupMemberJoin = 1102 // 加入群聊消息
|
||||
export const ChatMsgSysGroupMemberQuit = 1103 // 群成员退出群消息
|
||||
export const ChatMsgSysGroupMemberKicked = 1104 // 移出群成员消息(普通群、项目群被踢)
|
||||
export const ChatMsgSysGroupMemberKicked = 1104 // 踢出群成员消息
|
||||
export const ChatMsgSysGroupMessageRevoke = 1105 // 管理员撤回成员消息
|
||||
export const ChatMsgSysGroupDismissed = 1106 // 群解散
|
||||
export const ChatMsgSysGroupMuted = 1107 // 群禁言
|
||||
@ -26,9 +26,6 @@ export const ChatMsgSysGroupMemberMuted = 1109 // 群成员禁言
|
||||
export const ChatMsgSysGroupMemberCancelMuted = 1110 // 群成员解除禁言
|
||||
export const ChatMsgSysGroupNotice = 1111 // 编辑群公告
|
||||
export const ChatMsgSysGroupTransfer = 1113 // 变更群主
|
||||
export const ChatMsgSysGroupAdmin = 1114 // 设置管理员
|
||||
export const ChatMsgSysGroupMemberRemoved = 1115 // 移出群成员消息(部门群、公司群自动移出)
|
||||
export const ChatMsgSysGroupInfoChange = 1116 // 管理员更新了群信息
|
||||
|
||||
export const ChatMsgTypeMapping = {
|
||||
[ChatMsgTypeText]: '[文本消息]',
|
||||
@ -49,18 +46,14 @@ export const ChatMsgTypeMapping = {
|
||||
[ChatMsgSysGroupCreate]: '[创建群消息]',
|
||||
[ChatMsgSysGroupMemberJoin]: '[加入群消息]',
|
||||
[ChatMsgSysGroupMemberQuit]: '[退出群消息]',
|
||||
[ChatMsgSysGroupMemberKicked]: '[移出群消息]',
|
||||
[ChatMsgSysGroupMemberKicked]: '[踢出群消息]',
|
||||
[ChatMsgSysGroupMessageRevoke]: '[撤回消息]',
|
||||
[ChatMsgSysGroupDismissed]: '[群解散消息]',
|
||||
[ChatMsgSysGroupMuted]: '[群禁言消息]',
|
||||
[ChatMsgSysGroupCancelMuted]: '[群解除禁言消息]',
|
||||
[ChatMsgSysGroupMemberMuted]: '[群成员禁言消息]',
|
||||
[ChatMsgSysGroupMemberCancelMuted]: '[群成员解除禁言消息]',
|
||||
[ChatMsgSysGroupNotice]: '[群公告]',
|
||||
[ChatMsgSysGroupTransfer]: '[转让群主]',
|
||||
[ChatMsgSysGroupAdmin]: '[设置管理员]',
|
||||
[ChatMsgSysGroupMemberRemoved]: '[移出群成员消息]',
|
||||
[ChatMsgSysGroupInfoChange]: '[群信息更新]'
|
||||
[ChatMsgSysGroupNotice]: '[群公告]'
|
||||
}
|
||||
|
||||
// 消息类型 - 消息组件 映射关系
|
||||
@ -85,15 +78,12 @@ export const MessageComponents = {
|
||||
[ChatMsgSysGroupMemberQuit]: 'sys-group-member-quit-message',
|
||||
[ChatMsgSysGroupMemberKicked]: 'sys-group-member-kicked-message',
|
||||
// [ChatMsgSysGroupMessageRevoke]: '[撤回消息]',
|
||||
[ChatMsgSysGroupDismissed]: 'sys-group-dismissed',
|
||||
// [ChatMsgSysGroupDismissed]: '[群解散消息]',
|
||||
[ChatMsgSysGroupMuted]: 'sys-group-muted-message',
|
||||
[ChatMsgSysGroupCancelMuted]: 'sys-group-cancel-muted-message',
|
||||
[ChatMsgSysGroupMemberMuted]: 'sys-group-member-muted-message',
|
||||
[ChatMsgSysGroupMemberCancelMuted]: 'sys-group-member-cancel-muted-message',
|
||||
[ChatMsgSysGroupTransfer]: 'sys-group-transfer-message',
|
||||
[ChatMsgSysGroupAdmin]:'sys-group-admin-message',
|
||||
[ChatMsgSysGroupMemberRemoved]:'sys-group-member-removed-message',
|
||||
[ChatMsgSysGroupInfoChange]:'sys-group-info-change-message'
|
||||
[ChatMsgSysGroupTransfer]: 'sys-group-transfer-message'
|
||||
}
|
||||
|
||||
// 可转发的消息类型
|
||||
|
@ -68,38 +68,20 @@ class Revoke extends Base {
|
||||
}
|
||||
|
||||
handle() {
|
||||
const { updateDialogueRecord } = useDialogueListStore()
|
||||
const {updateDialogueRecord} = useDialogueListStore()
|
||||
useTalkStore().updateItem({
|
||||
index_name: this.getIndexName(),
|
||||
msg_text: this.resource.text,
|
||||
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()),
|
||||
updated_at: parseTime(new Date())
|
||||
})
|
||||
|
||||
useDialogueStore().updateDialogueRecord({
|
||||
msg_id: this.msg_id,
|
||||
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,
|
||||
is_revoke: 1
|
||||
})
|
||||
updateDialogueRecord({
|
||||
msg_id: this.msg_id,
|
||||
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,
|
||||
is_revoke: 1
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -5,16 +5,8 @@ import { parseTime } from '@/utils/datetime'
|
||||
import * as message from '@/constant/message'
|
||||
import { formatTalkItem, palyMusic, formatTalkRecord } from '@/utils/talk'
|
||||
// import { isElectronMode } from '@/utils/common'
|
||||
import {
|
||||
ServeClearTalkUnreadNum,
|
||||
ServeCreateTalkList,
|
||||
} from '@/api/chat/index.js'
|
||||
import {
|
||||
useTalkStore,
|
||||
useDialogueStore,
|
||||
useDialogueListStore,
|
||||
useGroupStore,
|
||||
} from '@/store'
|
||||
import { ServeClearTalkUnreadNum, ServeCreateTalkList } from '@/api/chat/index.js'
|
||||
import { useTalkStore, useDialogueStore,useDialogueListStore } from '@/store'
|
||||
|
||||
/**
|
||||
* 好友状态事件
|
||||
@ -40,11 +32,6 @@ class Talk extends Base {
|
||||
*/
|
||||
talk_type = 0
|
||||
|
||||
/**
|
||||
* 文件上传唯一随机值
|
||||
*/
|
||||
fileNum = ''
|
||||
|
||||
/**
|
||||
* 初始化构造方法
|
||||
*
|
||||
@ -56,10 +43,6 @@ class Talk extends Base {
|
||||
this.sender_id = resource.sender_id
|
||||
this.receiver_id = resource.receiver_id
|
||||
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.handle()
|
||||
@ -106,10 +89,11 @@ class Talk extends Base {
|
||||
play() {
|
||||
// 客户端有消息提示
|
||||
// if (isElectronMode()) return
|
||||
|
||||
// useSettingsStore().isPromptTone && palyMusic()
|
||||
}
|
||||
|
||||
async handle() {
|
||||
handle() {
|
||||
// 不是自己发送的消息则需要播放提示音
|
||||
if (!this.isCurrSender()) {
|
||||
this.play()
|
||||
@ -117,21 +101,7 @@ class Talk extends Base {
|
||||
|
||||
// 判断会话列表是否存在,不存在则创建
|
||||
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()
|
||||
}
|
||||
|
||||
// 判断当前是否正在和好友对话
|
||||
@ -139,37 +109,6 @@ class Talk extends Base {
|
||||
this.insertTalkRecord()
|
||||
} else {
|
||||
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() {
|
||||
if (typeof plus !== 'undefined') {
|
||||
let OAWebView = plus.webview.all()
|
||||
OAWebView.forEach((webview) => {
|
||||
if (webview.id === 'webviewId1') {
|
||||
webview.evalJS(`updateUnreadMsgNumAdd()`)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
document.addEventListener('plusready', () => {
|
||||
let OAWebView = plus.webview.all()
|
||||
OAWebView.forEach((webview) => {
|
||||
if (webview.id === 'webviewId1') {
|
||||
webview.evalJS(`updateUnreadMsgNumAdd()`)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -184,6 +123,7 @@ class Talk extends Base {
|
||||
// lang: 'zh-CN',
|
||||
// body: '您有新的消息请注意查收'
|
||||
// })
|
||||
|
||||
// notification.onclick = () => {
|
||||
// notification.close()
|
||||
// }
|
||||
@ -211,16 +151,12 @@ class Talk extends Base {
|
||||
|
||||
ServeCreateTalkList({
|
||||
talk_type,
|
||||
receiver_id,
|
||||
}).then(async ({ code, data }) => {
|
||||
receiver_id
|
||||
}).then(({ code, data }) => {
|
||||
if (code == 200) {
|
||||
let item = formatTalkItem(data)
|
||||
if (!item?.is_disturb) {
|
||||
item.unread_num = 1
|
||||
this.updateUnreadMsgNumAdd()
|
||||
}
|
||||
item.unread_num = 1
|
||||
useTalkStore().addItem(item)
|
||||
await useTalkStore().loadTalkList()
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -230,76 +166,24 @@ class Talk extends Base {
|
||||
*/
|
||||
insertTalkRecord() {
|
||||
let record = this.resource
|
||||
let newRecord = formatTalkRecord(this.getAccountId(), this.resource)
|
||||
const { addDialogueRecord, addChatRecord } = useDialogueListStore()
|
||||
let newRecord = formatTalkRecord(this.getAccountId(), this.resource);
|
||||
const {addDialogueRecord,addChatRecord} = useDialogueListStore()
|
||||
// 群成员变化的消息,需要更新群成员列表
|
||||
if ([1102, 1103, 1104, 1115].includes(record.msg_type)) {
|
||||
if ([1102, 1103, 1104].includes(record.msg_type)) {
|
||||
useDialogueStore().updateGroupMembers()
|
||||
}
|
||||
|
||||
//群解散时,需要更新群成员权限
|
||||
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)
|
||||
addDialogueRecord([newRecord],'add')
|
||||
addChatRecord(this.getIndexName(),newRecord)
|
||||
useDialogueStore().addDialogueRecord(newRecord)
|
||||
|
||||
if (!this.isCurrSender()) {
|
||||
// 推送已读消息
|
||||
// setTimeout(() => {
|
||||
// ws.emit('im.message.read', {
|
||||
// receiver_id: this.sender_id,
|
||||
// msg_ids: [this.resource.msg_id],
|
||||
// })
|
||||
// }, 1000)
|
||||
setTimeout(() => {
|
||||
ws.emit('im.message.read', {
|
||||
receiver_id: this.sender_id,
|
||||
msg_ids: [this.resource.msg_id]
|
||||
})
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
// 获取聊天面板元素节点
|
||||
@ -307,8 +191,7 @@ class Talk extends Base {
|
||||
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()) {
|
||||
nextTick(() => {
|
||||
@ -321,15 +204,14 @@ class Talk extends Base {
|
||||
useTalkStore().updateItem({
|
||||
index_name: this.getIndexName(),
|
||||
msg_text: this.getTalkText(),
|
||||
updated_at: parseTime(new Date()),
|
||||
updated_at: parseTime(new Date())
|
||||
})
|
||||
|
||||
if (this.talk_type == 1 && this.getAccountId() !== this.sender_id) {
|
||||
//不在此处维护未读消息数量
|
||||
// ServeClearTalkUnreadNum({
|
||||
// talk_type: 1,
|
||||
// receiver_id: this.sender_id,
|
||||
// })
|
||||
ServeClearTalkUnreadNum({
|
||||
talk_type: 1,
|
||||
receiver_id: this.sender_id
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -340,31 +222,8 @@ class Talk extends Base {
|
||||
useTalkStore().updateMessage({
|
||||
index_name: this.getIndexName(),
|
||||
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,12 +11,7 @@ import { reactive, nextTick, computed, h, inject } from 'vue'
|
||||
// EditTwo,
|
||||
// IdCard
|
||||
// } from '@icon-park/vue-next'
|
||||
import {
|
||||
ServeTopTalkList,
|
||||
ServeDeleteTalkList,
|
||||
ServeSetNotDisturb,
|
||||
ServeClearTalkUnreadNum,
|
||||
} from '@/api/chat'
|
||||
import { ServeTopTalkList, ServeDeleteTalkList, ServeSetNotDisturb } from '@/api/chat'
|
||||
import { useDialogueStore, useTalkStore, useDialogueListStore } from '@/store'
|
||||
import { ServeSecedeGroup } from '@/api/group'
|
||||
// import { ServeDeleteContact, ServeEditContactRemark } from '@/api/contact'
|
||||
@ -28,7 +23,7 @@ export function useSessionMenu() {
|
||||
show: false,
|
||||
x: 0,
|
||||
y: 0,
|
||||
item: {},
|
||||
item: {}
|
||||
})
|
||||
|
||||
const dialogueStore = useDialogueStore()
|
||||
@ -123,22 +118,10 @@ export function useSessionMenu() {
|
||||
// 移除会话
|
||||
const onRemoveTalk = (item) => {
|
||||
ServeDeleteTalkList({
|
||||
list_id: item.id,
|
||||
list_id: item.id
|
||||
}).then(({ code }) => {
|
||||
if (code == 200) {
|
||||
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(() => {
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -148,13 +131,13 @@ export function useSessionMenu() {
|
||||
ServeSetNotDisturb({
|
||||
talk_type: item.talk_type,
|
||||
receiver_id: item.receiver_id,
|
||||
is_disturb: item.is_disturb == 0 ? 1 : 0,
|
||||
is_disturb: item.is_disturb == 0 ? 1 : 0
|
||||
}).then(({ code, message }) => {
|
||||
if (code == 200) {
|
||||
message.success('设置成功!')
|
||||
talkStore.updateItem({
|
||||
index_name: item.index_name,
|
||||
is_disturb: item.is_disturb == 0 ? 1 : 0,
|
||||
is_disturb: item.is_disturb == 0 ? 1 : 0
|
||||
})
|
||||
} else {
|
||||
message.error(message)
|
||||
@ -170,12 +153,12 @@ export function useSessionMenu() {
|
||||
|
||||
ServeTopTalkList({
|
||||
list_id: item.id,
|
||||
type: item.is_top == 0 ? 1 : 2,
|
||||
type: item.is_top == 0 ? 1 : 2
|
||||
}).then(({ code, message }) => {
|
||||
if (code == 200) {
|
||||
talkStore.updateItem({
|
||||
index_name: item.index_name,
|
||||
is_top: item.is_top == 0 ? 1 : 0,
|
||||
is_top: item.is_top == 0 ? 1 : 0
|
||||
})
|
||||
} else {
|
||||
message.error(message)
|
||||
@ -218,7 +201,7 @@ export function useSessionMenu() {
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
ServeSecedeGroup({
|
||||
group_id: item.receiver_id,
|
||||
group_id: item.receiver_id
|
||||
}).then(({ code, message }) => {
|
||||
if (code == 200) {
|
||||
message.success('已退出群聊')
|
||||
@ -227,7 +210,7 @@ export function useSessionMenu() {
|
||||
message.error(message)
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -276,18 +259,12 @@ export function useSessionMenu() {
|
||||
disturb: onSetDisturb,
|
||||
signout_group: onSignOutGroup,
|
||||
delete_contact: onDeleteContact,
|
||||
remark: onChangeRemark,
|
||||
remark: onChangeRemark
|
||||
}
|
||||
|
||||
dropdown.show = false
|
||||
evnets[key] && evnets[key](dropdown.item)
|
||||
}
|
||||
|
||||
return {
|
||||
dropdown,
|
||||
onCloseContextMenu,
|
||||
onContextMenuTalkHandle,
|
||||
onToTopTalk,
|
||||
onRemoveTalk,
|
||||
}
|
||||
return { dropdown, onCloseContextMenu, onContextMenuTalkHandle, onToTopTalk, onRemoveTalk }
|
||||
}
|
||||
|
95
src/main.js
@ -10,18 +10,13 @@ import tmui from '@/uni_modules/tmui'
|
||||
import { config } from '@/config/tmui/index.js'
|
||||
import 'dayjs/locale/zh-cn'
|
||||
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 messagePopup from '@/components/x-message/useMessagePopup'
|
||||
import pageAnimation from '@/components/page-animation/index.vue'
|
||||
import * as plugins from './plugins'
|
||||
import { useDialogueStore, useTalkStore, useUserStore, useDialogueListStore } from '@/store'
|
||||
import {uniStorage} from "@/utils/uniStorage.js"
|
||||
|
||||
const { showMessage } = messagePopup()
|
||||
dayjs.locale('zh-cn')
|
||||
if (import.meta.env.VITE_SHOW_CONSOLE === 'true') {
|
||||
if (import.meta.env.VITE_SHOW_CONSOLE) {
|
||||
new VConsole()
|
||||
}
|
||||
export function createApp() {
|
||||
@ -33,8 +28,6 @@ export function createApp() {
|
||||
app.mixin(pageAnimation)
|
||||
app.component('customNavbar', customNavbar)
|
||||
app.component('x-loaderror', xLoaderror)
|
||||
app.component('AsyncLoading', asyncLoading)
|
||||
app.component('AsyncError', asyncError)
|
||||
app.directive('no-space', {
|
||||
mounted(el) {
|
||||
el.addEventListener('input', (e) => {
|
||||
@ -47,92 +40,6 @@ 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('===准备创建本地通知栏消息')
|
||||
let OAWebView = plus.webview.all()
|
||||
OAWebView.forEach((webview, index) => {
|
||||
if (webview.id === 'webviewId1') {
|
||||
webview.evalJS(`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 = () => {
|
||||
let OAWebView = plus.webview.all()
|
||||
OAWebView.forEach((webview, index) => {
|
||||
if (webview.id === 'webviewId1') {
|
||||
webview.evalJS(`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)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
window.message = ['success', 'error', 'warning'].reduce((acc, type) => {
|
||||
acc[type] = (message) => {
|
||||
if (typeof message === 'string') {
|
||||
|
@ -5,7 +5,8 @@
|
||||
"^tm-(.*)": "@/tmui/components/tm-$1/tm-$1.vue"
|
||||
}
|
||||
},
|
||||
"pages": [{
|
||||
"pages": [
|
||||
{
|
||||
"path": "pages/index/index",
|
||||
"type": "page",
|
||||
"style": {
|
||||
@ -177,38 +178,6 @@
|
||||
"navigationStyle": "custom",
|
||||
"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": {
|
||||
|
@ -1,398 +0,0 @@
|
||||
<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>
|
@ -1,950 +0,0 @@
|
||||
<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"
|
||||
@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: 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"
|
||||
@click="toUserDetail(item)"
|
||||
>
|
||||
<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">
|
||||
<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 } 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()
|
||||
let OAWebView = plus.webview.all()
|
||||
OAWebView.forEach((webview) => {
|
||||
if (webview.id === 'webviewId1') {
|
||||
webview.evalJS(`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.error(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 (newVal === '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;
|
||||
|
||||
.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',
|
||||
}"
|
||||
v-for="(memberItem, memberIndex) in sortedMemberList"
|
||||
v-for="(memberItem, memberIndex) in props?.memberList"
|
||||
@click="toUserDetailPage(memberItem)"
|
||||
>
|
||||
<div
|
||||
@ -53,7 +53,7 @@
|
||||
>
|
||||
<div class="group-member-each">
|
||||
<div class="group-member-avatar" :style="{ background: 'unset' }">
|
||||
<img src="@/static/image/chatSettings/add-member.png" />
|
||||
<img src="/src/static/image/chatSettings/add-member.png" />
|
||||
</div>
|
||||
<div class="group-member-name">
|
||||
<span class="text-[24rpx] font-regular">添加</span>
|
||||
@ -71,7 +71,7 @@
|
||||
>
|
||||
<div class="group-member-each">
|
||||
<div class="group-member-avatar" :style="{ background: 'unset' }">
|
||||
<img src="@/static/image/chatSettings/remove-member.png" />
|
||||
<img src="/src/static/image/chatSettings/remove-member.png" />
|
||||
</div>
|
||||
<div class="group-member-name">
|
||||
<span class="text-[24rpx] font-regular">移除</span>
|
||||
@ -81,7 +81,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { defineProps, computed } from 'vue'
|
||||
import { defineProps } from 'vue'
|
||||
const props = defineProps({
|
||||
memberList: Array, //人员列表
|
||||
memberListsLimit: Number, //人员列表数量限制
|
||||
@ -90,36 +90,6 @@ const props = defineProps({
|
||||
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) => {
|
||||
console.log(userItem)
|
||||
|
@ -49,7 +49,7 @@
|
||||
props?.memberItem?.is_mine && props?.manageType === 'removeMembers'
|
||||
"
|
||||
>
|
||||
<img src="@/static/image/chatSettings/is-mine.png" />
|
||||
<img src="/src/static/image/chatSettings/is-mine.png" />
|
||||
</div>
|
||||
<div
|
||||
class="is-admin-tag"
|
||||
|
@ -1,803 +0,0 @@
|
||||
<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,10 +16,9 @@
|
||||
props?.item?.hasPointer &&
|
||||
(props?.isManager ||
|
||||
(!props?.isManager &&
|
||||
(props?.item?.label !== $t('chat.settings.groupName') ||
|
||||
props?.item?.label !== $t('chat.settings.groupType'))))
|
||||
props?.item?.label !== $t('chat.settings.groupName')))
|
||||
"
|
||||
src="@/static/image/chatSettings/pointer.png"
|
||||
src="/src/static/image/chatSettings/pointer.png"
|
||||
/>
|
||||
<tm-switch
|
||||
:width="88"
|
||||
|
@ -22,7 +22,6 @@
|
||||
<customBtn
|
||||
:btnText="$t('button.text.edit')"
|
||||
@click="editAvatar"
|
||||
:isLoading="state.isLoading"
|
||||
></customBtn>
|
||||
</ZPaging>
|
||||
</div>
|
||||
@ -50,10 +49,6 @@ const dialogueParams = reactive({
|
||||
receiver_id: computed(() => dialogueStore.talk.receiver_id),
|
||||
})
|
||||
|
||||
const state = reactive({
|
||||
isLoading: false, //是否正在加载中
|
||||
})
|
||||
|
||||
const onProgressFn = (progress, id) => {
|
||||
console.log((progress.loaded / progress.total) * 100, 'progress')
|
||||
|
||||
@ -74,7 +69,6 @@ const editAvatar = () => {
|
||||
count: 1,
|
||||
success: async (res) => {
|
||||
console.log(res, 'res')
|
||||
state.isLoading = true
|
||||
res.tempFiles.forEach(async (file) => {
|
||||
console.log(file)
|
||||
let image = new Image()
|
||||
@ -99,7 +93,6 @@ const editAvatar = () => {
|
||||
const resp = ServeEditGroup(params)
|
||||
resp.then(({ code }) => {
|
||||
if (code == 200) {
|
||||
state.isLoading = false
|
||||
groupStore.updateGroupInfo({
|
||||
avatar: data.ori_url,
|
||||
})
|
||||
@ -107,18 +100,13 @@ const editAvatar = () => {
|
||||
// delta: 1,
|
||||
// })
|
||||
} else {
|
||||
state.isLoading = false
|
||||
}
|
||||
})
|
||||
resp.catch(() => {
|
||||
state.isLoading = false})
|
||||
resp.catch(() => {})
|
||||
} else {
|
||||
state.isLoading = false
|
||||
}
|
||||
},
|
||||
).catch(() => {
|
||||
state.isLoading = false
|
||||
})
|
||||
)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
@ -29,13 +29,10 @@
|
||||
:placeholder="$t('edit.groupName.placeholder')"
|
||||
placeholder-style="color:#B4B4B4;font-size:28rpx;font-weight:500;line-height:40rpx;"
|
||||
v-model="state.groupName"
|
||||
@input="handleGroupNameInput"
|
||||
maxlength="20"
|
||||
/>
|
||||
<img
|
||||
v-if="state.groupName"
|
||||
class="groupName-input-clearBtn"
|
||||
src="@/static/image/chatSettings/clear-btn.png"
|
||||
src="/src/static/image/chatSettings/clear-btn.png"
|
||||
@click="clearGroupNameInput"
|
||||
/>
|
||||
</div>
|
||||
@ -85,12 +82,7 @@ onLoad((options) => {
|
||||
const clearGroupNameInput = () => {
|
||||
state.groupName = ''
|
||||
}
|
||||
const handleGroupNameInput = (e) => {
|
||||
if (state.groupName.length > 20) {
|
||||
// 截取前20个字符
|
||||
state.groupName = state.groupName.slice(0, 20)
|
||||
}
|
||||
}
|
||||
|
||||
//点击确认修改
|
||||
const confirmEdit = () => {
|
||||
console.log(state.groupName)
|
||||
@ -154,7 +146,7 @@ const confirmEdit = () => {
|
||||
height: 110rpx;
|
||||
box-shadow: 0 6px 12px 2px rgba(188, 188, 188, 0.08);
|
||||
padding: 0 74rpx 0 32rpx;
|
||||
color: #747474;
|
||||
color: #B747474;
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
line-height: 40rpx;
|
||||
|
@ -46,7 +46,7 @@
|
||||
<div class="group-admin-list-each-btns">
|
||||
<img
|
||||
v-if="item.is_mine"
|
||||
src="@/static/image/chatSettings/is-mine.png"
|
||||
src="/src/static/image/chatSettings/is-mine.png"
|
||||
/>
|
||||
<div
|
||||
class="group-admin-list-each-btns-each"
|
||||
@ -67,7 +67,7 @@
|
||||
margin: state?.groupAdminList.length == 0 ? '20rpx 0 0' : '',
|
||||
}"
|
||||
>
|
||||
<img src="@/static/image/chatSettings/add-btn.png" />
|
||||
<img src="/src/static/image/chatSettings/add-btn.png" />
|
||||
<span class="text-[28rpx] font-medium">
|
||||
{{ $t('chat.manage.addAdmin') }}
|
||||
</span>
|
||||
|
@ -1,76 +0,0 @@
|
||||
<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"
|
||||
@click="toSelectMembersPage"
|
||||
>
|
||||
<img src="@/static/image/chatSettings/add-btn.png" />
|
||||
<img src="/src/static/image/chatSettings/add-btn.png" />
|
||||
<span class="text-[28rpx] font-medium">
|
||||
{{ $t('chat.manage.addSilenceMember') }}
|
||||
</span>
|
||||
|
@ -14,7 +14,7 @@
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<template #right v-if="state.isManager === 'true'">
|
||||
<template #right>
|
||||
<div
|
||||
v-if="state.editMode !== 3"
|
||||
class="nav-bar-done-btn"
|
||||
@ -39,7 +39,7 @@
|
||||
</template>
|
||||
<div class="notice-text-area">
|
||||
<div class="notice-view-area">
|
||||
<div class="notice-view-info" v-if="state.editMode !== 1 && state?.groupNoticeObj?.content">
|
||||
<div class="notice-view-info" v-if="state.editMode !== 1">
|
||||
<div class="notice-creater-avatar">
|
||||
<img :src="state?.groupNoticeObj?.avatar" />
|
||||
</div>
|
||||
@ -53,12 +53,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="notice-view-content" v-if="state.editMode === 3">
|
||||
<span class="text-[32rpx] font-regular" v-if="state?.groupNoticeObj?.content">
|
||||
<span class="text-[32rpx] font-regular">
|
||||
{{ state?.groupNoticeObj?.content }}
|
||||
</span>
|
||||
<span class="text-[32rpx] font-regular color-[#898989]" v-else>
|
||||
{{ $t('groupNotice.notice.empty') }}
|
||||
</span>
|
||||
</div>
|
||||
<wd-textarea
|
||||
size="large"
|
||||
@ -80,7 +77,6 @@ import useConfirm from '@/components/x-confirm/useConfirm.js'
|
||||
import ZPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
|
||||
import { reactive, computed, onMounted } from 'vue'
|
||||
import { useGroupStore, useDialogueStore } from '@/store'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import {
|
||||
ServeEditGroupNotice,
|
||||
ServeDeleteGroupNotice,
|
||||
@ -102,8 +98,7 @@ const state = reactive({
|
||||
groupNoticeObj: null, //群公告信息
|
||||
groupNotice: '', //群公告
|
||||
canDoComplete: false, //是否可以点击完成按钮
|
||||
editMode: 3, // 1:新增;2:修改;3:查看
|
||||
isManager: 'false', //是否是群管理员
|
||||
editMode: 1, // 1:新增;2:修改;3:查看
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
@ -112,14 +107,6 @@ onMounted(() => {
|
||||
state.editMode = 3
|
||||
state.groupNoticeObj = groupParams.groupNotice[0]
|
||||
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,45 +11,170 @@
|
||||
@scroll="onScroll"
|
||||
>
|
||||
<template #top>
|
||||
<div id="topArea">
|
||||
<customNavbar :title="pageTitle"></customNavbar>
|
||||
</div>
|
||||
<customNavbar :title="pageTitle" id="topArea"></customNavbar>
|
||||
</template>
|
||||
<selectMemberByAlphabet
|
||||
:manageType="state.manageType"
|
||||
:isCreateDepGroup="state.isCreateDepGroup"
|
||||
ref="selectMemberByAlphabetRef"
|
||||
:selectAreaHeight="state.selectAreaHeight"
|
||||
@updateSelectedMembersNum="updateSelectedMembersNum"
|
||||
></selectMemberByAlphabet>
|
||||
<template #bottom v-if="state.manageType !== 'searchRecord'">
|
||||
<div id="footArea">
|
||||
<customBtn
|
||||
v-if="state.manageType !== 'removeMembers'"
|
||||
:isBottom="true"
|
||||
:btnText="$t('ok')"
|
||||
@clickBtn="confirmSelectMembers"
|
||||
></customBtn>
|
||||
<div
|
||||
class="confirm-btn-area"
|
||||
v-if="state.manageType === 'removeMembers'"
|
||||
>
|
||||
<div class="confirm-btn-area-statistic-text">
|
||||
<span class="text-[28rpx] font-medium">
|
||||
{{
|
||||
$t('select.member.num') +
|
||||
':' +
|
||||
state.selectedMembersNum +
|
||||
$t('statistic.unit.person')
|
||||
}}
|
||||
<div class="select-members">
|
||||
<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>
|
||||
<customBtn
|
||||
:btnText="$t('ok')"
|
||||
@clickBtn="confirmSelectMembers"
|
||||
:disabled="state.selectedMembersNum == 0 ? true : false"
|
||||
></customBtn>
|
||||
</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"
|
||||
:itemStyle="
|
||||
state.manageType === 'searchRecord' ||
|
||||
state.manageType === 'removeMembers'
|
||||
? 'list'
|
||||
: 'card'
|
||||
"
|
||||
>
|
||||
<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'">
|
||||
<customBtn
|
||||
v-if="state.manageType !== 'removeMembers'"
|
||||
:isBottom="true"
|
||||
:btnText="$t('ok')"
|
||||
@clickBtn="confirmSelectMembers"
|
||||
></customBtn>
|
||||
<div
|
||||
class="confirm-btn-area"
|
||||
v-if="state.manageType === 'removeMembers'"
|
||||
>
|
||||
<div class="confirm-btn-area-statistic-text">
|
||||
<span class="text-[28rpx] font-medium">
|
||||
{{
|
||||
$t('select.member.num') +
|
||||
':' +
|
||||
state.selectedMembersNum +
|
||||
$t('statistic.unit.person')
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
<customBtn
|
||||
:btnText="$t('ok')"
|
||||
@clickBtn="confirmSelectMembers"
|
||||
:disabled="state.selectedMembersNum == 0 ? true : false"
|
||||
></customBtn>
|
||||
</div>
|
||||
</template>
|
||||
</ZPaging>
|
||||
@ -57,63 +182,120 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import selectMemberByAlphabet from '../components/selectMemberByAlphabet.vue'
|
||||
import customInput from '@/components/custom-input/custom-input.vue'
|
||||
import selectMemberItem from '../components/select-member-item.vue'
|
||||
import customBtn from '@/components/custom-btn/custom-btn.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 { computed, reactive, ref, onMounted, nextTick } from 'vue'
|
||||
import { computed, onMounted, reactive, ref, watch, nextTick } from 'vue'
|
||||
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'
|
||||
const { t } = useI18n()
|
||||
|
||||
const selectMemberByAlphabetRef = ref(null)
|
||||
|
||||
const zPaging = ref()
|
||||
useZPaging(zPaging)
|
||||
|
||||
const state = reactive({
|
||||
manageType: '', //管理类型
|
||||
selectedMembersNum: 0, //当前选中数量
|
||||
isCreateDepGroup: 0, //是否是创建部门群
|
||||
selectAreaHeight: 0, //选择区域高度
|
||||
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({
|
||||
searchText: '', //搜索内容
|
||||
manageType: '', //管理类型
|
||||
alphabet: [], //A-Z列表
|
||||
resultMemberList: [], //按A-Z整理后的人员列表
|
||||
currentAlphabet: 'A', //当前A-Z位置
|
||||
scrollDirection: '', //当前列表滚动方向
|
||||
isAssign: false, //是否指定view
|
||||
selectedMembersNum: 0, //当前选中数量
|
||||
isCreateDepGroup: 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) => {
|
||||
// console.log(options)
|
||||
console.log(options)
|
||||
if (options.manageType) {
|
||||
state.manageType = options.manageType
|
||||
assembleAlphabetMemberList(dialogueParams?.memberList)
|
||||
}
|
||||
if (options.isCreateDepGroup) {
|
||||
state.isCreateDepGroup = Number(options.isCreateDepGroup)
|
||||
assembleAlphabetMemberList()
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
dialogueParams.memberList.forEach((ele) => {
|
||||
ele.checkArr = []
|
||||
})
|
||||
const options = {
|
||||
root: null, // 使用浏览器窗口作为根容器
|
||||
threshold: 1.0, // 当元素100%离开视口时触发
|
||||
}
|
||||
observer = new IntersectionObserver(handleIntersection, options)
|
||||
nextTick(() => {
|
||||
let selectAreaHeight = uni.getSystemInfoSync().windowHeight
|
||||
// console.log('页面高度:', uni.getSystemInfoSync().windowHeight)
|
||||
const topAreaQuery = uni.createSelectorQuery()
|
||||
topAreaQuery
|
||||
.select('#topArea')
|
||||
.boundingClientRect((res) => {
|
||||
if (res) {
|
||||
// console.log('元素高度:', res.height)
|
||||
selectAreaHeight = selectAreaHeight - res.height
|
||||
watch(
|
||||
alphabetElementRefs,
|
||||
(newAlphabetElementRefs) => {
|
||||
if (Array.isArray(newAlphabetElementRefs)) {
|
||||
newAlphabetElementRefs.forEach((el, index) => {
|
||||
observeElement(el, index)
|
||||
})
|
||||
}
|
||||
})
|
||||
.exec()
|
||||
const footAreaQuery = uni.createSelectorQuery()
|
||||
footAreaQuery
|
||||
.select('#footArea')
|
||||
.boundingClientRect((res) => {
|
||||
if (res) {
|
||||
// console.log('元素高度:', res.height)
|
||||
selectAreaHeight = selectAreaHeight - res.height
|
||||
}
|
||||
})
|
||||
.exec()
|
||||
// console.log(selectAreaHeight)
|
||||
state.selectAreaHeight = selectAreaHeight + 'px'
|
||||
},
|
||||
{ immediate: true, deep: true },
|
||||
)
|
||||
if (alphabetElementRefs.value.length > 0) {
|
||||
alphabetElementRefs.value.forEach((el, index) =>
|
||||
observeElement(el, index),
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@ -132,16 +314,341 @@ const pageTitle = computed(() => {
|
||||
return page_title
|
||||
})
|
||||
|
||||
//确认
|
||||
const confirmSelectMembers = () => {
|
||||
if (selectMemberByAlphabetRef.value) {
|
||||
selectMemberByAlphabetRef.value.confirmSelectMembers()
|
||||
// 观察者函数
|
||||
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 updateSelectedMembersNum = (numChange) => {
|
||||
state.selectedMembersNum = state.selectedMembersNum + numChange
|
||||
//输入搜索文本
|
||||
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 = () => {
|
||||
let selectedUserIds = ''
|
||||
let itemList = dialogueParams.memberList
|
||||
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) => {
|
||||
if (
|
||||
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>
|
||||
<style scoped lang="scss">
|
||||
@ -152,6 +659,48 @@ const updateSelectedMembersNum = (numChange) => {
|
||||
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 {
|
||||
background-color: #fff;
|
||||
padding: 14rpx 32rpx 72rpx;
|
||||
|
@ -17,17 +17,10 @@
|
||||
</div>
|
||||
<div class="avatarImg">
|
||||
<avatarModule
|
||||
:mode="props?.data?.group_type === 0 ? 1 : 2"
|
||||
:mode="2"
|
||||
:avatar="props?.data?.avatar"
|
||||
:groupType="props?.data?.group_type"
|
||||
:userName="props?.data?.name"
|
||||
:customStyle="{ width: '96rpx', height: '96rpx' }"
|
||||
:customTextStyle="{
|
||||
fontSize: '32rpx',
|
||||
fontWeight: 'bold',
|
||||
color: '#fff',
|
||||
lineHeight: '44rpx',
|
||||
}"
|
||||
></avatarModule>
|
||||
</div>
|
||||
<div class="chatInfo">
|
||||
@ -37,18 +30,7 @@
|
||||
class="text-[#171717] text-[32rpx] font-medium leading-[44rpx]"
|
||||
>
|
||||
<span>{{ props.data.name }}</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>
|
||||
<span>({{ props.data.group_member_num }})</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -136,31 +118,16 @@ const cellClick = () => {
|
||||
opacity: 40%;
|
||||
}
|
||||
|
||||
.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 {
|
||||
width: 76rpx;
|
||||
height: 38rpx;
|
||||
border: 1px solid #7a58de;
|
||||
font-size: 24rpx;
|
||||
text-align: center;
|
||||
border-radius: 6rpx;
|
||||
color: #7a58de;
|
||||
}
|
||||
.depTag {
|
||||
border: 1px solid #377ec6;
|
||||
color: #377ec6;
|
||||
}
|
||||
.projectTag {
|
||||
border: 1px solid #c1681c;
|
||||
color: #c1681c;
|
||||
font-weight: bold;
|
||||
margin-left: 12rpx;
|
||||
}
|
||||
|
||||
.textEllipsis {
|
||||
|
@ -58,7 +58,6 @@
|
||||
okColor="#FFFFFF"
|
||||
@ok="handleOk"
|
||||
@cancel="handleCancel"
|
||||
:okText="'发送'"
|
||||
>
|
||||
<template v-slot:title>
|
||||
<div
|
||||
@ -87,7 +86,7 @@
|
||||
<div
|
||||
class="mt-[8rpx] text-[#666666] text-[24rpx] w-[94rpx] truncate"
|
||||
>
|
||||
<span>{{ item.name }}</span>
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="w-full flex items-center justify-start">
|
||||
@ -99,16 +98,6 @@
|
||||
></avatarModule>
|
||||
<div class="ml-[16rpx] text-[#161616] text-[32rpx] font-bold">
|
||||
{{ 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>
|
||||
@ -219,7 +208,7 @@ watch(
|
||||
onMounted(() => {
|
||||
talkStore.loadTalkList()
|
||||
console.log(talkStore.talkItems)
|
||||
items.value = lodash.cloneDeep(talkStore.talkItems).filter(item=>item.is_dismiss === 0 && item.is_quit === 0)
|
||||
items.value = lodash.cloneDeep(talkStore.talkItems)
|
||||
})
|
||||
onUnmounted(() => {
|
||||
dialogueStore.setForwardType('')
|
||||
@ -252,32 +241,7 @@ onUnmounted(() => {
|
||||
margin-top: 20rpx;
|
||||
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 {
|
||||
::v-deep .custom-btn-class {
|
||||
padding: 6rpx 24rpx !important;
|
||||
|
@ -15,7 +15,7 @@
|
||||
</div>
|
||||
<div class="mt-[54rpx] w-full h-[872rpx]">
|
||||
<div
|
||||
@click="groupActiveIndex = 0;depCheckedKeys = []"
|
||||
@click="groupActiveIndex = 0"
|
||||
class="groupCard firstPanel"
|
||||
:class="groupActiveIndex === 0 ? 'activePanel' : ''"
|
||||
>
|
||||
@ -33,7 +33,6 @@
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="isHasPermission"
|
||||
@click="groupActiveIndex = 1"
|
||||
class="groupCard secondPanel"
|
||||
:class="groupActiveIndex === 1 ? 'activePanel' : ''"
|
||||
@ -96,8 +95,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="isCreateProjecy"
|
||||
@click="groupActiveIndex = 2;depCheckedKeys = [];"
|
||||
@click="groupActiveIndex = 2"
|
||||
class="groupCard thirdPanel"
|
||||
:class="groupActiveIndex === 2 ? 'activePanel' : ''"
|
||||
>
|
||||
@ -133,36 +131,13 @@
|
||||
import ZPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
|
||||
import customBtn from '@/components/custom-btn/custom-btn.vue'
|
||||
import { ref, watch, computed } from 'vue'
|
||||
import { onShow, onLoad, onUnload } from '@dcloudio/uni-app'
|
||||
import { onShow, onLoad } from '@dcloudio/uni-app'
|
||||
import { useChatList } from '@/store/chatList/index.js'
|
||||
import { useAuth } from '@/store/auth'
|
||||
import { useTalkStore, useUserStore } from '@/store'
|
||||
import { useGroupTypeStore } from '@/store/groupType'
|
||||
import { userHasPermission } from '@/api/deps/index.js'
|
||||
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 { groupActiveIndex, depCheckedKeys } = useGroupTypeStore()
|
||||
|
||||
const confirmBtnStatus = computed(() => {
|
||||
let disabledT = false
|
||||
@ -233,10 +208,10 @@ const handleConfirm = () => {
|
||||
border-radius: 12rpx;
|
||||
&.firstPanel {
|
||||
background-image: url('@/static/image/chatList/zu6033@2x.png');
|
||||
margin-bottom: 28rpx;
|
||||
}
|
||||
&.secondPanel {
|
||||
background-image: url('@/static/image/chatList/zu6031@2x.png');
|
||||
margin-top: 28rpx;
|
||||
margin-bottom: 28rpx;
|
||||
}
|
||||
&.thirdPanel {
|
||||
|
@ -404,7 +404,7 @@ const getCurrentMembers = async (depItem) => {
|
||||
departmentId: depItem.ID,
|
||||
status: 'notactive',
|
||||
})
|
||||
if (res.code === 200) {
|
||||
if (res.status === 0) {
|
||||
currentMembers.value = res.data.data.length
|
||||
? res.data.data.map((v) => {
|
||||
return {
|
||||
@ -628,7 +628,7 @@ const handleConfirm = async () => {
|
||||
departmentIds: allCheckedList.value.map((v) => v.ID),
|
||||
status: 'notactive',
|
||||
})
|
||||
if (res.code == 200 && res.data?.data?.length) {
|
||||
if (res.status == 0 && res.data?.data?.length) {
|
||||
res.data?.data.forEach((v) => {
|
||||
listT.push(v)
|
||||
})
|
||||
|
@ -1,366 +0,0 @@
|
||||
<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,8 +8,12 @@
|
||||
<div class="group-avatar flex items-center justify-center">
|
||||
<div class="avatar-placeholder" v-if="groupActiveIndex === -1"></div>
|
||||
<div v-else>
|
||||
<avatarModule :mode="2" :avatar="avatarImg" :groupType="groupType"
|
||||
:customStyle="{ width: '192rpx', height: '192rpx' }"></avatarModule>
|
||||
<avatarModule
|
||||
:mode="2"
|
||||
:avatar="avatarImg"
|
||||
:groupType="groupType"
|
||||
:customStyle="{ width: '192rpx', height: '192rpx' }"
|
||||
></avatarModule>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group flex items-center justify-between">
|
||||
@ -17,12 +21,25 @@
|
||||
群名称
|
||||
</div>
|
||||
<div class="input-box">
|
||||
<tm-input v-model="groupName" :followTheme="false" 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>
|
||||
<tm-input
|
||||
v-model="groupName"
|
||||
:followTheme="false"
|
||||
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 class="input-group w-full flex flex-col mt-[20rpx] leading-[40rpx]">
|
||||
<div
|
||||
class="input-group w-full flex flex-col mt-[20rpx] leading-[40rpx]"
|
||||
>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="input-item">
|
||||
群类型
|
||||
@ -35,310 +52,344 @@
|
||||
<span v-else-if="groupActiveIndex === 2">项目群</span>
|
||||
</div>
|
||||
<div class="ml-[32rpx]">
|
||||
<tm-icon :font-size="22" color="#747474" name="tmicon-angle-right"></tm-icon>
|
||||
<tm-icon
|
||||
:font-size="22"
|
||||
color="#747474"
|
||||
name="tmicon-angle-right"
|
||||
></tm-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="depCheckedKeys.length && groupActiveIndex === 1" class="mt-[32rpx]">
|
||||
<div v-for="(item, index) in depCheckedKeys" class="text-[#747474] text-[28rpx] leading-[40rpx] font-bold"
|
||||
<div
|
||||
v-if="depCheckedKeys.length && groupActiveIndex === 1"
|
||||
class="mt-[32rpx]"
|
||||
>
|
||||
<div
|
||||
v-for="(item, index) in depCheckedKeys"
|
||||
class="text-[#747474] text-[28rpx] leading-[40rpx] font-bold"
|
||||
:class="[
|
||||
index !== 0 ? 'mt-[10rpx]' : '',
|
||||
depsNoExpanded_1 && index > 4 ? 'hidden' : '',
|
||||
]">
|
||||
depsNoExpanded && index > 4 ? 'hidden' : '',
|
||||
]"
|
||||
>
|
||||
{{ item.name }}
|
||||
</div>
|
||||
<div 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
|
||||
class="text-[#46299D] text-[28rpx] mt-[20rpx] font-bold flex justify-center"
|
||||
>
|
||||
<div
|
||||
v-if="depCheckedKeys.length > 5"
|
||||
@click="depsNoExpanded = !depsNoExpanded"
|
||||
class="w-[100rpx]"
|
||||
>
|
||||
{{ depsNoExpanded ? '展开' : '收起' }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="groupActiveIndex === 0 || groupActiveIndex === 2"
|
||||
class="input-group w-full flex flex-col mt-[20rpx] leading-[40rpx]">
|
||||
<div
|
||||
v-if="groupActiveIndex === 0 || groupActiveIndex === 2"
|
||||
class="input-group w-full flex flex-col mt-[20rpx] leading-[40rpx]"
|
||||
>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="input-item">
|
||||
群成员
|
||||
</div>
|
||||
<div @click="chooseMembers" class="left-box">
|
||||
<div class="ml-[32rpx] flex items-center">
|
||||
<div class="text-[#B4B4B4] text-[28rpx] font-bold mr-[32rpx]">
|
||||
<div
|
||||
class="text-[#B4B4B4] text-[28rpx] font-bold mr-[32rpx]"
|
||||
>
|
||||
全部({{ allChooseMembers?.length || 0 }})
|
||||
</div>
|
||||
<tm-icon :font-size="22" color="#747474" name="tmicon-angle-right"></tm-icon>
|
||||
<tm-icon
|
||||
:font-size="22"
|
||||
color="#747474"
|
||||
name="tmicon-angle-right"
|
||||
></tm-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<groupMemberList :groupType="3" :is_manager="true" :memberList="allChooseMembers" :memberListsLimit="15"
|
||||
:hideAddRemoveBtns="true"></groupMemberList>
|
||||
<groupMemberList
|
||||
:groupType="3"
|
||||
:is_manager="true"
|
||||
:memberList="allChooseMembers"
|
||||
:memberListsLimit="15"
|
||||
:hideAddRemoveBtns="true"
|
||||
></groupMemberList>
|
||||
</div>
|
||||
|
||||
<div v-if="groupActiveIndex === 1" class="input-group w-full flex flex-col mt-[20rpx] leading-[40rpx]">
|
||||
<div
|
||||
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="input-item">
|
||||
群管理员
|
||||
</div>
|
||||
<div @click="chooseGroupAdmin" class="left-box">
|
||||
<div class="ml-[32rpx] flex items-center">
|
||||
<div v-if="!groupAdmins.length" class="text-[#B4B4B4] text-[28rpx] font-bold mr-[32rpx]">
|
||||
<div
|
||||
v-if="!groupAdmins.length"
|
||||
class="text-[#B4B4B4] text-[28rpx] font-bold mr-[32rpx]"
|
||||
>
|
||||
请选择群管理员
|
||||
</div>
|
||||
<tm-icon :font-size="22" color="#747474" name="tmicon-angle-right"></tm-icon>
|
||||
<tm-icon
|
||||
:font-size="22"
|
||||
color="#747474"
|
||||
name="tmicon-angle-right"
|
||||
></tm-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="groupAdmins.length" class="mt-[32rpx]">
|
||||
<div v-for="(item, index) in groupAdmins" class="text-[#747474] text-[28rpx] leading-[40rpx] font-bold"
|
||||
<div
|
||||
v-for="(item, index) in groupAdmins"
|
||||
class="text-[#747474] text-[28rpx] leading-[40rpx] font-bold"
|
||||
:class="[
|
||||
index !== 0 ? 'mt-[10rpx]' : '',
|
||||
depsNoExpanded_2 && index > 4 ? 'hidden' : '',
|
||||
]">
|
||||
depsNoExpanded && index > 4 ? 'hidden' : '',
|
||||
]"
|
||||
>
|
||||
{{ item.name }}
|
||||
</div>
|
||||
<div 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
|
||||
class="text-[#46299D] text-[28rpx] mt-[20rpx] font-bold flex justify-center"
|
||||
>
|
||||
<div
|
||||
v-if="groupAdmins.length > 5"
|
||||
@click="depsNoExpanded = !depsNoExpanded"
|
||||
class="w-[100rpx]"
|
||||
>
|
||||
{{ depsNoExpanded ? '展开' : '收起' }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<template #bottom>
|
||||
<customBtn :isBottom="true" :btnText="$t('pageTitle.create.group')" @click="handleConfirm"
|
||||
:isLoading="isLoading" :disabled="confirmBtnStatus || isLoading"></customBtn>
|
||||
<customBtn
|
||||
:isBottom="true"
|
||||
:btnText="$t('pageTitle.create.group')"
|
||||
@click="handleConfirm"
|
||||
:disabled="confirmBtnStatus"
|
||||
></customBtn>
|
||||
</template>
|
||||
</zPaging>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import zPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
|
||||
import customBtn from '@/components/custom-btn/custom-btn.vue'
|
||||
import groupMemberList from '../chatSettings/components/groupMembersList.vue'
|
||||
import avatarModule from '@/components/avatar-module/index.vue'
|
||||
import zPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
|
||||
import customBtn from '@/components/custom-btn/custom-btn.vue'
|
||||
import groupMemberList from '../chatSettings/components/groupMembersList.vue'
|
||||
import avatarModule from '@/components/avatar-module/index.vue'
|
||||
|
||||
import {
|
||||
ref,
|
||||
watch,
|
||||
computed,
|
||||
onMounted
|
||||
} from 'vue'
|
||||
import {
|
||||
onShow,
|
||||
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'
|
||||
import { ref, watch, computed } from 'vue'
|
||||
import { onShow, onLoad } 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'
|
||||
|
||||
const {
|
||||
groupName,
|
||||
groupActiveIndex,
|
||||
depCheckedKeys,
|
||||
groupAdmins,
|
||||
createDepGroup,
|
||||
resetGroupInfo,
|
||||
allChooseMembers,
|
||||
} = useGroupTypeStore()
|
||||
const talkStore = useTalkStore()
|
||||
const userStore = useUserStore()
|
||||
const groupStore = useGroupStore()
|
||||
const {
|
||||
userInfo
|
||||
} = useAuth()
|
||||
const {
|
||||
groupName,
|
||||
groupActiveIndex,
|
||||
depCheckedKeys,
|
||||
groupAdmins,
|
||||
createDepGroup,
|
||||
resetGroupInfo,
|
||||
allChooseMembers,
|
||||
} = useGroupTypeStore()
|
||||
const talkStore = useTalkStore()
|
||||
const userStore = useUserStore()
|
||||
const groupStore = useGroupStore()
|
||||
const { userInfo } = useAuth()
|
||||
|
||||
const groupChatType = ref('')
|
||||
const depsNoExpanded_1 = ref(true)
|
||||
const depsNoExpanded_2 = ref(true)
|
||||
const groupChatType = ref('')
|
||||
const depsNoExpanded = ref(true)
|
||||
|
||||
onLoad(()=> {
|
||||
groupStore.$reset()
|
||||
})
|
||||
|
||||
onLoad(() => {
|
||||
groupStore.$reset()
|
||||
})
|
||||
onUnload(() => {
|
||||
resetGroupInfo();
|
||||
})
|
||||
onMounted(() => {
|
||||
handleSetWebviewStyle()
|
||||
//群类型
|
||||
const groupType = computed(() => {
|
||||
let group_type = ''
|
||||
switch (groupActiveIndex.value) {
|
||||
case 0:
|
||||
group_type = 1
|
||||
break
|
||||
case 1:
|
||||
group_type = 2
|
||||
break
|
||||
case 2:
|
||||
group_type = 3
|
||||
break
|
||||
default:
|
||||
group_type = ''
|
||||
}
|
||||
return group_type
|
||||
})
|
||||
|
||||
//点击跳转到选择群类型页面
|
||||
const chooseGroupType = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/chooseGroupType/index',
|
||||
})
|
||||
}
|
||||
|
||||
//群类型
|
||||
const groupType = computed(() => {
|
||||
let group_type = ''
|
||||
switch (groupActiveIndex.value) {
|
||||
case 0:
|
||||
group_type = 1
|
||||
break
|
||||
case 1:
|
||||
group_type = 2
|
||||
break
|
||||
case 2:
|
||||
group_type = 3
|
||||
break
|
||||
default:
|
||||
group_type = ''
|
||||
const chooseGroupAdmin = () => {
|
||||
uni.navigateTo({
|
||||
url:
|
||||
'/pages/chatSettings/groupManage/selectMembers?manageType=admin&isCreateDepGroup=1',
|
||||
})
|
||||
}
|
||||
|
||||
const chooseMembers = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/chooseByDeps/index?chooseMode=2',
|
||||
})
|
||||
}
|
||||
|
||||
//点击发起群聊
|
||||
const handleConfirm = async () => {
|
||||
// console.log(allChooseMembers.value)
|
||||
let erp_ids = ''
|
||||
if (allChooseMembers?.value?.length > 0) {
|
||||
allChooseMembers?.value?.forEach((ele) => {
|
||||
if (!erp_ids) {
|
||||
erp_ids = String(ele.ID)
|
||||
} else {
|
||||
erp_ids += ',' + ele.ID
|
||||
}
|
||||
})
|
||||
}
|
||||
if (groupActiveIndex.value === 0) {
|
||||
//普通群
|
||||
let params = {
|
||||
avatar: '',
|
||||
name: groupName.value,
|
||||
erp_ids: erp_ids,
|
||||
type: 1,
|
||||
profile: '',
|
||||
}
|
||||
return group_type
|
||||
})
|
||||
|
||||
//点击跳转到选择群类型页面
|
||||
const chooseGroupType = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/chooseGroupType/index',
|
||||
})
|
||||
}
|
||||
|
||||
const chooseGroupAdmin = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/chatSettings/groupManage/selectMembers?manageType=admin&isCreateDepGroup=1',
|
||||
})
|
||||
}
|
||||
|
||||
const chooseMembers = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/chooseByDeps/index?chooseMode=2',
|
||||
})
|
||||
}
|
||||
const isLoading = ref(false)
|
||||
|
||||
// 点击发起群聊
|
||||
const handleConfirm = async () => {
|
||||
if (isLoading.value) return
|
||||
isLoading.value = true
|
||||
|
||||
try {
|
||||
let erp_ids = ''
|
||||
if (allChooseMembers?.value?.length > 0) {
|
||||
allChooseMembers.value.forEach((ele) => {
|
||||
if (!erp_ids) {
|
||||
erp_ids = String(ele.ID)
|
||||
} else {
|
||||
erp_ids += ',' + ele.ID
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
let res = null
|
||||
|
||||
if (groupActiveIndex.value === 0) {
|
||||
// 普通群
|
||||
const params = {
|
||||
avatar: '',
|
||||
name: groupName.value,
|
||||
erp_ids: erp_ids,
|
||||
type: 1,
|
||||
profile: '',
|
||||
}
|
||||
console.log('普通群参数:', params)
|
||||
res = await ServeCreateGroup(params)
|
||||
} else if (groupActiveIndex.value === 1) {
|
||||
// 部门群
|
||||
res = await createDepGroup()
|
||||
} else if (groupActiveIndex.value === 2) {
|
||||
// 项目群
|
||||
const params = {
|
||||
avatar: '',
|
||||
name: groupName.value,
|
||||
erp_ids: erp_ids,
|
||||
type: 3,
|
||||
profile: '',
|
||||
}
|
||||
console.log('项目群参数:', params)
|
||||
res = await ServeCreateGroup(params)
|
||||
}
|
||||
|
||||
if (res?.code === 200) {
|
||||
resetGroupInfo()
|
||||
uni.navigateBack()
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
console.log(params)
|
||||
const res = await ServeCreateGroup(params)
|
||||
if (res.code === 200) {
|
||||
resetGroupInfo()
|
||||
uni.navigateBack()
|
||||
}
|
||||
} else if (groupActiveIndex.value === 1) {
|
||||
//部门群
|
||||
const res = await createDepGroup()
|
||||
if (res.code === 200) {
|
||||
resetGroupInfo()
|
||||
uni.navigateBack()
|
||||
}
|
||||
} else if (groupActiveIndex.value === 2) {
|
||||
//项目群
|
||||
let params = {
|
||||
avatar: '',
|
||||
name: groupName.value,
|
||||
erp_ids: erp_ids,
|
||||
type: 3,
|
||||
profile: '',
|
||||
}
|
||||
console.log(params)
|
||||
const res = await ServeCreateGroup(params)
|
||||
if (res.code === 200) {
|
||||
resetGroupInfo()
|
||||
uni.navigateBack()
|
||||
}
|
||||
} else {
|
||||
}
|
||||
//发起群聊按钮可点击状态
|
||||
const confirmBtnStatus = computed(() => {
|
||||
return groupActiveIndex.value === -1;
|
||||
});
|
||||
}
|
||||
|
||||
onShow(() => {
|
||||
depsNoExpanded_1.value = true;
|
||||
depsNoExpanded_2.value = true;
|
||||
})
|
||||
//发起群聊按钮可点击状态
|
||||
const confirmBtnStatus = computed(() => {
|
||||
let disabledT = false
|
||||
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>
|
||||
<style scoped lang="scss">
|
||||
::v-deep .zp-paging-container-content {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
}
|
||||
::v-deep .zp-paging-container-content {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.create-group-chat {
|
||||
background-image: url('@/static/image/clockIn/z3280@3x.png');
|
||||
background-size: cover;
|
||||
background-position: center bottom;
|
||||
width: 100%;
|
||||
padding: 0 32rpx 20rpx;
|
||||
|
||||
.group-avatar {
|
||||
padding: 60rpx 0;
|
||||
|
||||
.avatar-placeholder {
|
||||
width: 192rpx;
|
||||
height: 192rpx;
|
||||
background-color: #e0e0e0;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.create-group-chat {
|
||||
background-image: url('@/static/image/clockIn/z3280@3x.png');
|
||||
background-size: cover;
|
||||
background-position: center bottom;
|
||||
width: 100%;
|
||||
padding: 0 32rpx 20rpx;
|
||||
.group-avatar {
|
||||
padding: 60rpx 0;
|
||||
.avatar-placeholder {
|
||||
width: 192rpx;
|
||||
height: 192rpx;
|
||||
background-color: #e0e0e0;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.divider {
|
||||
height: 1rpx;
|
||||
background-color: #7c7c7c;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.divider {
|
||||
height: 1rpx;
|
||||
background-color: #7c7c7c;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.input-group {
|
||||
background-color: #fff;
|
||||
padding: 38rpx 40rpx 32rpx 32rpx;
|
||||
}
|
||||
|
||||
.input-item {
|
||||
line-height: 40rpx;
|
||||
font-size: 28rpx;
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.input-box {
|
||||
margin-left: 84rpx;
|
||||
line-height: 40rpx;
|
||||
width: 404rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.left-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.input-group {
|
||||
background-color: #fff;
|
||||
padding: 38rpx 40rpx 32rpx 32rpx;
|
||||
}
|
||||
.input-item {
|
||||
line-height: 40rpx;
|
||||
font-size: 28rpx;
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
}
|
||||
.input-box {
|
||||
margin-left: 84rpx;
|
||||
line-height: 40rpx;
|
||||
width: 404rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
.left-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,34 +1,25 @@
|
||||
<template>
|
||||
<div>
|
||||
<zPaging :fixed="false" :height="'210px'" :show-scrollbar="false">
|
||||
<div class="emojiRoot">
|
||||
<div
|
||||
v-for="(img, key) in emojis"
|
||||
v-html="img"
|
||||
:key="key"
|
||||
@click="onSendEmoticon(1, key, img)"
|
||||
class="option pointer flex-center"
|
||||
/>
|
||||
</div>
|
||||
</zPaging>
|
||||
<div class="emojiRoot">
|
||||
<div v-for="(img, key) in emojis" v-html="img" :key="key" @click="onSendEmoticon(1, key, img)"
|
||||
class="option pointer flex-center" />
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import zPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
|
||||
import { ref, reactive, defineProps, defineEmits } from 'vue'
|
||||
import dayjs from 'dayjs'
|
||||
import { ref, reactive, defineProps,defineEmits } from "vue"
|
||||
import dayjs from "dayjs";
|
||||
import { beautifyTime } from '@/utils/datetime'
|
||||
import { useTalkStore } from '@/store'
|
||||
import { useSessionMenu } from '@/hooks'
|
||||
import { emojis } from '@/utils/emojis'
|
||||
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
default: {},
|
||||
required: false,
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
const emit = defineEmits(['on-select'])
|
||||
const onSendEmoticon = (type, value, img = '') => {
|
||||
@ -42,15 +33,21 @@ const onSendEmoticon = (type, value, img = '') => {
|
||||
emit('on-select', { type, value, img })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.emojiRoot {
|
||||
width: 100%;
|
||||
height: 420rpx;
|
||||
padding: 5rpx 32rpx;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.option {
|
||||
|
@ -1,39 +1,25 @@
|
||||
<template>
|
||||
<div class="emojiRoot">
|
||||
<div
|
||||
@click="() => photoActionsSelect(0)"
|
||||
class="flex flex-col items-center"
|
||||
>
|
||||
<div
|
||||
class="w-[106rpx] h-[106rpx] bg-[#F9F9F9] rounded-[60rpx] flex-center"
|
||||
>
|
||||
<div @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>
|
||||
</div>
|
||||
<div class="mt-[6rpx] text-[#666666] text-[24rpx]">照片</div>
|
||||
</div>
|
||||
<div
|
||||
@click="() => photoActionsSelect(1)"
|
||||
class="flex flex-col items-center"
|
||||
>
|
||||
<div
|
||||
class="w-[106rpx] h-[106rpx] bg-[#F9F9F9] rounded-[60rpx] flex-center"
|
||||
>
|
||||
<div @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>
|
||||
</div>
|
||||
<div class="mt-[6rpx] text-[#666666] text-[24rpx]">视频</div>
|
||||
</div>
|
||||
<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>
|
||||
</div>
|
||||
<div class="mt-[6rpx] text-[#666666] text-[24rpx]">拍摄</div>
|
||||
</div>
|
||||
<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>
|
||||
</div>
|
||||
<div class="mt-[6rpx] text-[#666666] text-[24rpx]">文件</div>
|
||||
@ -41,15 +27,10 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref, reactive, defineProps, defineEmits } from 'vue'
|
||||
import dayjs from 'dayjs'
|
||||
import { ref, reactive, defineProps, defineEmits } from "vue"
|
||||
import dayjs from "dayjs";
|
||||
import { beautifyTime } from '@/utils/datetime'
|
||||
import {
|
||||
useDialogueListStore,
|
||||
useDialogueStore,
|
||||
useUserStore,
|
||||
useUploadsStore,
|
||||
} from '@/store'
|
||||
import { useDialogueListStore, useDialogueStore, useUserStore,useUploadsStore } from '@/store'
|
||||
import { useSessionMenu } from '@/hooks'
|
||||
import photoAlbum from '@/static/image/chatList/photoAlbum.png'
|
||||
import photoGraph from '@/static/image/chatList/photoGraph.png'
|
||||
@ -62,167 +43,82 @@ const props = defineProps({
|
||||
sendUserInfo: {
|
||||
type: Object,
|
||||
default: {},
|
||||
required: true,
|
||||
required: true
|
||||
},
|
||||
talkParams: {
|
||||
type: Object,
|
||||
default: {},
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
|
||||
const state = reactive({
|
||||
base64Url: '',
|
||||
})
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
const uploadsStore = useUploadsStore()
|
||||
const {
|
||||
addDialogueRecord,
|
||||
virtualList,
|
||||
updateUploadProgress,
|
||||
} = useDialogueListStore()
|
||||
const { addDialogueRecord, virtualList, updateUploadProgress } = useDialogueListStore()
|
||||
const dialogueStore = useDialogueStore()
|
||||
const userStore = useUserStore()
|
||||
|
||||
const emit = defineEmits(['selectImg'])
|
||||
|
||||
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) => {
|
||||
if (index === 0) {
|
||||
if (typeof plus === 'undefined') {
|
||||
uni.chooseImage({
|
||||
sourceType: ['album'],
|
||||
count: 9,
|
||||
success: async (res) => {
|
||||
console.log(res, 'res')
|
||||
res.tempFiles.forEach(async (file) => {
|
||||
const fileSizeInMB = (file.size / (1024 * 1024)).toFixed(2)
|
||||
if (fileSizeInMB > 100) {
|
||||
plus.nativeUI.toast('图片大小不能超过100MB')
|
||||
return
|
||||
}
|
||||
const result = await onUploadImageVideo(file, 'image')
|
||||
if (result) {
|
||||
emit('selectImg', result, result.file_num)
|
||||
}
|
||||
})
|
||||
},
|
||||
})
|
||||
} 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 {
|
||||
// let OAWebView = plus.webview.all()
|
||||
// OAWebView.forEach((webview, index) => {
|
||||
// if (webview.id === 'webviewId1') {
|
||||
// webview.evalJS(`getPlusVideoPicker()`)
|
||||
// }
|
||||
// })
|
||||
// return
|
||||
uni.chooseImage({
|
||||
sourceType: ['album'],
|
||||
count: 9,
|
||||
success: async (res) => {
|
||||
console.log(res,'res');
|
||||
res.tempFiles.forEach(async (file) => {
|
||||
let data = await onUploadImageVideo(file, 'image')
|
||||
emit('selectImg', data)
|
||||
})
|
||||
}
|
||||
})
|
||||
}else{
|
||||
uni.chooseVideo({
|
||||
sourceType: ['album'],
|
||||
compressed: true,
|
||||
maxDuration: 60,
|
||||
success: async (res) => {
|
||||
console.log(res, 'res')
|
||||
const fileSizeInMB = (res.tempFile.size / (1024 * 1024)).toFixed(2)
|
||||
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)
|
||||
}
|
||||
},
|
||||
console.log(res,'res');
|
||||
let data = await onUploadImageVideo(res.tempFile, 'video',res.tempFilePath)
|
||||
emit('selectImg', data)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const onUploadImageVideo = async (file, type = 'image', fileUrl) => {
|
||||
console.log('开始上传文件:', file.name)
|
||||
uploadsStore.updateUploadStatus(true)
|
||||
const onUploadImageVideo = async (file, type = 'image',fileUrl) => {
|
||||
console.log(file, 'file');
|
||||
return new Promise(async (resolve) => {
|
||||
if (type === 'image') {
|
||||
let image = new Image()
|
||||
image.src = URL.createObjectURL(file)
|
||||
image.onload = async () => {
|
||||
image.onload = () => {
|
||||
const form = new FormData()
|
||||
form.append('file', file)
|
||||
form.append('source', 'fonchain-chat')
|
||||
form.append('urlParam', `width=${image.width}&height=${image.height}`)
|
||||
form.append("source", "fonchain-chat");
|
||||
form.append("urlParam", `width=${image.width}&height=${image.height}`);
|
||||
let randomId = uniqueId()
|
||||
let newItem = {
|
||||
avatar: userStore.avatar,
|
||||
created_at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
|
||||
extra: {
|
||||
height: image.height,
|
||||
name: '',
|
||||
name: "",
|
||||
size: 0,
|
||||
url: image.src,
|
||||
width: image.width,
|
||||
width: image.width
|
||||
},
|
||||
float: 'right',
|
||||
float: "right",
|
||||
isCheck: false,
|
||||
is_mark: 0,
|
||||
is_read: 0,
|
||||
is_revoke: 0,
|
||||
msg_id: randomId,
|
||||
file_num: randomId,
|
||||
msg_type: 3,
|
||||
nickname: userStore.nickname,
|
||||
receiver_id: dialogueStore.talk.receiver_id,
|
||||
@ -230,372 +126,210 @@ const onUploadImageVideo = async (file, type = 'image', fileUrl) => {
|
||||
talk_type: dialogueStore.talk.talk_type,
|
||||
user_id: userStore.uid,
|
||||
uploadCurrent: 0,
|
||||
uploadStatus: 1, // 1 上传中 2 上传成功 3 上传失败
|
||||
uploadStatus: 1, // 1 上传中 2 上传成功 3 上传失败
|
||||
}
|
||||
|
||||
virtualList.value.unshift(newItem)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// 确保返回数据
|
||||
uploadImg(form, (e) => onProgressFn(e, randomId)).then(({ status, data, msg }) => {
|
||||
if (status == 0) {
|
||||
resolve({
|
||||
type: 'image',
|
||||
url: result.data.ori_url,
|
||||
url: data.ori_url,
|
||||
size: file.size,
|
||||
width: image.width,
|
||||
height: image.height,
|
||||
file_num: randomId,
|
||||
height: image.height
|
||||
})
|
||||
} else {
|
||||
uploadsStore.updateUploadStatus(false)
|
||||
// 更新上传状态为失败
|
||||
const index = virtualList.value.findIndex(
|
||||
(item) => item.file_num === randomId,
|
||||
)
|
||||
if (index !== -1) {
|
||||
virtualList.value[index].uploadStatus = 3
|
||||
}
|
||||
message.error(result.msg)
|
||||
resolve('')
|
||||
message.error(msg)
|
||||
}
|
||||
} 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 {
|
||||
uni.getVideoInfo({
|
||||
src: fileUrl,
|
||||
success: async (resp) => {
|
||||
console.log('视频信息:', resp)
|
||||
const form = new FormData()
|
||||
form.append('file', file)
|
||||
form.append('source', 'fonchain-chat')
|
||||
form.append('type', 'video')
|
||||
form.append('urlParam', `width=${resp.width}&height=${resp.height}`)
|
||||
let randomId = uniqueId()
|
||||
let newItem = {
|
||||
avatar: userStore.avatar,
|
||||
created_at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
|
||||
extra: {
|
||||
src:fileUrl,
|
||||
success:(resp)=>{
|
||||
console.log(resp);
|
||||
form.append('file', file)
|
||||
form.append("source", "fonchain-chat");
|
||||
form.append("type", "video");
|
||||
form.append("urlParam", `width=${resp.width}&height=${resp.height}`);
|
||||
let randomId = uniqueId()
|
||||
let newItem = {
|
||||
avatar: userStore.avatar,
|
||||
created_at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
|
||||
extra: {
|
||||
duration: parseInt(resp.duration),
|
||||
height: resp.height,
|
||||
name: "",
|
||||
url: fileUrl,
|
||||
width: resp.width
|
||||
},
|
||||
float: "right",
|
||||
isCheck: false,
|
||||
is_mark: 0,
|
||||
is_read: 0,
|
||||
is_revoke: 0,
|
||||
msg_id: randomId,
|
||||
msg_type: 5,
|
||||
nickname: userStore.nickname,
|
||||
receiver_id: dialogueStore.talk.receiver_id,
|
||||
sequence: -1,
|
||||
talk_type: dialogueStore.talk.talk_type,
|
||||
user_id: userStore.uid,
|
||||
uploadCurrent: 0,
|
||||
uploadStatus: 1, // 1 上传中 2 上传成功 3 上传失败
|
||||
}
|
||||
virtualList.value.unshift(newItem)
|
||||
uploadImg(form, (e) => onProgressFn(e, randomId)).then(({ status, data, msg }) => {
|
||||
if (status == 0) {
|
||||
console.log(data);
|
||||
resolve({
|
||||
type: 'video',
|
||||
url: data.ori_url,
|
||||
cover: data.cover_url,
|
||||
duration: parseInt(resp.duration),
|
||||
height: resp.height,
|
||||
name: '',
|
||||
url: fileUrl,
|
||||
width: resp.width,
|
||||
},
|
||||
float: 'right',
|
||||
isCheck: false,
|
||||
is_mark: 0,
|
||||
is_read: 0,
|
||||
is_revoke: 0,
|
||||
msg_id: randomId,
|
||||
file_num: randomId,
|
||||
msg_type: 5,
|
||||
nickname: userStore.nickname,
|
||||
receiver_id: dialogueStore.talk.receiver_id,
|
||||
sequence: -1,
|
||||
talk_type: dialogueStore.talk.talk_type,
|
||||
user_id: userStore.uid,
|
||||
uploadCurrent: 0,
|
||||
uploadStatus: 1,
|
||||
size: file.size
|
||||
})
|
||||
} else {
|
||||
// resolve('')
|
||||
// message.error(msg)
|
||||
}
|
||||
virtualList.value.unshift(newItem)
|
||||
|
||||
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({
|
||||
type: 'video',
|
||||
url: result.data.ori_url,
|
||||
cover: result.data.cover_url,
|
||||
duration: parseInt(resp.duration),
|
||||
size: file.size,
|
||||
file_num: randomId,
|
||||
})
|
||||
} else {
|
||||
uploadsStore.updateUploadStatus(false)
|
||||
// 更新上传状态为失败
|
||||
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) => {
|
||||
if (!base64) {
|
||||
message.warning('您的系统暂不支持发送原图哦')
|
||||
}
|
||||
// base64转file
|
||||
const [header, base64String] = base64.split(';base64,')
|
||||
const imageType = header.split(':')[1]
|
||||
const byteCharacters = atob(base64String)
|
||||
const [header, base64String] = base64.split(";base64,");
|
||||
const imageType = header.split(":")[1];
|
||||
const byteCharacters = atob(base64String);
|
||||
const byteArray = new Uint8Array(
|
||||
Array.from(byteCharacters, (char) => char.charCodeAt(0)),
|
||||
)
|
||||
return new File([new Blob([byteArray], { type: imageType })], 'example.png', {
|
||||
type: imageType,
|
||||
})
|
||||
Array.from(byteCharacters, (char) => char.charCodeAt(0))
|
||||
);
|
||||
return new File(
|
||||
[new Blob([byteArray], { type: imageType })],
|
||||
"example.png",
|
||||
{ type: imageType }
|
||||
);
|
||||
}
|
||||
|
||||
const choosePhoto = (filter = 'none', maximum = 9, multiple = true) => {
|
||||
window.plus?.gallery.pick(
|
||||
(res) => {
|
||||
console.log(res)
|
||||
res.files.reverse()
|
||||
res.files.forEach(async (filePath) => {
|
||||
const suffix = filePath.split('.').pop()?.toLowerCase() || ''
|
||||
if (['jpg', 'png'].includes(suffix)) {
|
||||
console.log('进入图片')
|
||||
window.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)
|
||||
let data = await onUploadImageVideo(fileObj, 'image')
|
||||
emit('selectImg', data)
|
||||
}
|
||||
})
|
||||
},
|
||||
(err) => {
|
||||
console.log(err)
|
||||
},
|
||||
)
|
||||
}
|
||||
if (['mp4', 'flv'].includes(suffix)) {
|
||||
console.log(filePath, '进入视频')
|
||||
// const localUrl = plus.io.convertLocalFileSystemURL(filePath)
|
||||
// console.log(localUrl);
|
||||
|
||||
plus.io.getVideoInfo({
|
||||
filePath: filePath,
|
||||
success: (event) => {
|
||||
console.log(event)
|
||||
},
|
||||
fail: (err) => {
|
||||
console.log(err)
|
||||
},
|
||||
window.plus?.gallery.pick((res) => {
|
||||
console.log(res);
|
||||
res.files.reverse()
|
||||
res.files.forEach(async (filePath) => {
|
||||
const suffix = filePath.split('.').pop()?.toLowerCase() || ''
|
||||
if (['jpg', 'png'].includes(suffix)) {
|
||||
console.log("进入图片")
|
||||
window.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);
|
||||
let data = await onUploadImageVideo(fileObj, 'image')
|
||||
emit('selectImg', data)
|
||||
};
|
||||
})
|
||||
// window.plus?.io?.resolveLocalFileSystemURL(localUrl, async (entry) => {
|
||||
// entry.file((file) => {
|
||||
// console.log(file,'file');
|
||||
// const fileReader = new plus.io.FileReader();
|
||||
// fileReader.readAsDataURL(file);
|
||||
// fileReader.onloadend = async (e) => {
|
||||
// const base64Url = e.target.result;
|
||||
// const fileObj = base64ToFile(base64Url);
|
||||
// let data = await onUploadImageVideo(fileObj, 'video')
|
||||
// emit('selectImg', data)
|
||||
// };
|
||||
// })
|
||||
// },
|
||||
// (err) => {
|
||||
// console.log(err);
|
||||
// }
|
||||
// )
|
||||
},
|
||||
(err) => {
|
||||
console.log(err);
|
||||
}
|
||||
)
|
||||
}
|
||||
if (['mp4', 'flv'].includes(suffix)) {
|
||||
console.log(filePath,"进入视频")
|
||||
// const localUrl = plus.io.convertLocalFileSystemURL(filePath)
|
||||
// console.log(localUrl);
|
||||
|
||||
plus.io.getVideoInfo({
|
||||
filePath:filePath,
|
||||
success:(event)=>{
|
||||
console.log(event);
|
||||
},
|
||||
fail:(err)=>{
|
||||
console.log(err);
|
||||
}
|
||||
})
|
||||
},
|
||||
(err) => {
|
||||
console.log(err)
|
||||
},
|
||||
});
|
||||
// window.plus?.io?.resolveLocalFileSystemURL(localUrl, async (entry) => {
|
||||
// entry.file((file) => {
|
||||
// console.log(file,'file');
|
||||
// const fileReader = new plus.io.FileReader();
|
||||
// fileReader.readAsDataURL(file);
|
||||
// fileReader.onloadend = async (e) => {
|
||||
// const base64Url = e.target.result;
|
||||
// const fileObj = base64ToFile(base64Url);
|
||||
// let data = await onUploadImageVideo(fileObj, 'video')
|
||||
// emit('selectImg', data)
|
||||
// };
|
||||
// })
|
||||
// },
|
||||
// (err) => {
|
||||
// console.log(err);
|
||||
// }
|
||||
// )
|
||||
}
|
||||
})
|
||||
}, (err) => {
|
||||
console.log(err);
|
||||
},
|
||||
{
|
||||
filter: filter,
|
||||
maximum: maximum,
|
||||
multiple: multiple,
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
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 = () => {
|
||||
uni.chooseFile({
|
||||
count: 1,
|
||||
extension: [''],
|
||||
extension:[''],
|
||||
success: (res) => {
|
||||
const fileSizeInMB = (res.tempFiles[0].size / (1024 * 1024)).toFixed(2)
|
||||
if (fileSizeInMB > 100) {
|
||||
plus.nativeUI.toast('文件大小不能超过100MB')
|
||||
return
|
||||
}
|
||||
let randomId = uniqueId()
|
||||
let newItem = {
|
||||
avatar: userStore.avatar,
|
||||
created_at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
|
||||
extra: {
|
||||
drive: 3,
|
||||
name: res.tempFiles[0].name,
|
||||
size: res.tempFiles[0].size,
|
||||
path: res.tempFilePaths[0],
|
||||
},
|
||||
float: 'right',
|
||||
isCheck: false,
|
||||
is_mark: 0,
|
||||
is_read: 0,
|
||||
is_revoke: 0,
|
||||
msg_id: randomId,
|
||||
file_num: randomId,
|
||||
msg_type: 6,
|
||||
nickname: userStore.nickname,
|
||||
receiver_id: dialogueStore.talk.receiver_id,
|
||||
sequence: -1,
|
||||
talk_type: dialogueStore.talk.talk_type,
|
||||
user_id: userStore.uid,
|
||||
uploadCurrent: 0,
|
||||
uploadStatus: 1, // 1 上传中 2 上传成功 3 上传失败
|
||||
}
|
||||
let newItem = {
|
||||
avatar: userStore.avatar,
|
||||
created_at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
|
||||
extra: {
|
||||
drive: 3,
|
||||
name: res.tempFiles[0].name,
|
||||
size: res.tempFiles[0].size,
|
||||
path: res.tempFilePaths[0],
|
||||
},
|
||||
float: "right",
|
||||
isCheck: false,
|
||||
is_mark: 0,
|
||||
is_read: 0,
|
||||
is_revoke: 0,
|
||||
msg_id: randomId,
|
||||
msg_type: 6,
|
||||
nickname: userStore.nickname,
|
||||
receiver_id: dialogueStore.talk.receiver_id,
|
||||
sequence: -1,
|
||||
talk_type: dialogueStore.talk.talk_type,
|
||||
user_id: userStore.uid,
|
||||
uploadCurrent: 0,
|
||||
uploadStatus: 1, // 1 上传中 2 上传成功 3 上传失败
|
||||
}
|
||||
virtualList.value.unshift(newItem)
|
||||
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)
|
||||
}
|
||||
},
|
||||
)
|
||||
},
|
||||
uploadsStore.initUploadFile(res.tempFiles[0], props.talkParams,randomId)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.emojiRoot {
|
||||
|
@ -37,7 +37,7 @@
|
||||
</div>
|
||||
<div class="user-info-main user-info-card">
|
||||
<div class="user-info-main-title">
|
||||
<img src="@/static/image/mine/ming001@3x.png" />
|
||||
<img src="/src/static/image/mine/ming001@3x.png" />
|
||||
<span class="text-[28rpx] font-medium">
|
||||
{{ $t('index.mine.basic') }}
|
||||
</span>
|
||||
@ -61,48 +61,13 @@
|
||||
<template #bottom>
|
||||
<customBtn
|
||||
:isBottom="true"
|
||||
:btnText="
|
||||
state.canSendMsg
|
||||
? $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"
|
||||
:btnText="$t('user.detail.sendMsg')"
|
||||
:subBtnText="$t('user.detail.ringBell')"
|
||||
@clickBtn="toTalkUser"
|
||||
></customBtn>
|
||||
</template>
|
||||
</ZPaging>
|
||||
</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>
|
||||
</template>
|
||||
<script setup>
|
||||
@ -111,12 +76,10 @@ import ZPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { reactive } from 'vue'
|
||||
|
||||
import { useTalkStore, useUserStore } from '@/store'
|
||||
import { useTalkStore } from '@/store'
|
||||
const talkStore = useTalkStore()
|
||||
const userStore = useUserStore()
|
||||
|
||||
import { getUserInfoByClickAvatar } from '@/api/user/index'
|
||||
import { ServeCheckFriend, ServeAddFriend } from '@/api/addressBook/index'
|
||||
|
||||
import { useI18n } from 'vue-i18n'
|
||||
const { t } = useI18n()
|
||||
@ -125,10 +88,6 @@ const state = reactive({
|
||||
erpUserId: '', //erp用户id
|
||||
userInfo: null, //用户详情
|
||||
userBasicInfos: [], //用户基本信息
|
||||
isShowPhoneCall: false, //是否显示电话拨号弹框
|
||||
phoneNumber: '', //手机号
|
||||
uid: computed(() => userStore.uid), //当前用户id
|
||||
canSendMsg: false, //是否可以发送消息(是好友或同公司别),如果不可以就需要先加好友
|
||||
})
|
||||
|
||||
onLoad((options) => {
|
||||
@ -151,7 +110,6 @@ const getUserInfo = () => {
|
||||
console.log(data)
|
||||
if (code == 200) {
|
||||
state.userInfo = data
|
||||
checkNeedAddFriend()
|
||||
let department = ''
|
||||
let post = ''
|
||||
if (data?.erp_dept_position?.length > 0) {
|
||||
@ -209,7 +167,6 @@ const getUserInfo = () => {
|
||||
value: data.enter_date,
|
||||
},
|
||||
]
|
||||
state.phoneNumber = data.tel_num
|
||||
} else {
|
||||
}
|
||||
})
|
||||
@ -217,71 +174,10 @@ const getUserInfo = () => {
|
||||
resp.catch(() => {})
|
||||
}
|
||||
|
||||
//点击唤起拨号弹框
|
||||
const handleCall = () => {
|
||||
state.isShowPhoneCall = true
|
||||
}
|
||||
|
||||
//点击隐藏拨号弹框
|
||||
const hidePhoneCallPopup = () => {
|
||||
state.isShowPhoneCall = false
|
||||
}
|
||||
|
||||
//点击对用户发起单聊
|
||||
const toTalkUser = () => {
|
||||
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 = () => {
|
||||
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>
|
||||
<style scoped lang="scss">
|
||||
.outer-layer {
|
||||
@ -324,7 +220,6 @@ const doAddFriend = () => {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@ -395,58 +290,4 @@ const doAddFriend = () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.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>
|
||||
|
@ -1,17 +1,14 @@
|
||||
<script lang="ts" setup>
|
||||
import zPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { ServeGetForwardRecords } from '@/api/chat'
|
||||
import { MessageComponents } from '@/constant/message'
|
||||
import { ITalkRecord } from '@/types/chat'
|
||||
import WdLoading from "@/uni_modules/wot-design-uni/components/wd-loading/wd-loading.vue";
|
||||
import { useInject } from '@/hooks'
|
||||
import { parseTime } from '@/utils/datetime'
|
||||
|
||||
const emit = defineEmits(['close'])
|
||||
|
||||
const msgId = ref(null)
|
||||
const createdAt = ref(null)
|
||||
const { showUserInfoModal } = useInject()
|
||||
const isShow = ref(true)
|
||||
const items = ref<ITalkRecord[]>([])
|
||||
@ -23,18 +20,12 @@ const onMaskClick = () => {
|
||||
|
||||
const onLoadData = () => {
|
||||
ServeGetForwardRecords({
|
||||
msg_id: msgId.value,
|
||||
biz_date: createdAt.value
|
||||
msg_id: msgId.value
|
||||
}).then((res) => {
|
||||
if (res.code == 200) {
|
||||
items.value = res.data.items || []
|
||||
// 修复标题逻辑
|
||||
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('和') + '等';
|
||||
}
|
||||
|
||||
title.value = [...new Set(items.value.map((v) => v.nickname))].join('、')
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -44,7 +35,6 @@ onMounted(() => {
|
||||
const page = pages[pages.length - 1]
|
||||
const options = page.$page.options
|
||||
msgId.value = options.msgId
|
||||
createdAt.value = parseTime(new Date((options.created_at as any)), '{y}{m}')
|
||||
console.log(msgId.value,'msgId.value');
|
||||
|
||||
onLoadData()
|
||||
@ -52,12 +42,12 @@ onMounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="forward-record-page">
|
||||
<zPaging ref="zPaging" :show-scrollbar="false">
|
||||
<template #top>
|
||||
<customNavbar :title="`${title}的会话记录`"></customNavbar>
|
||||
</template>
|
||||
<div class="main-box">
|
||||
<div class="outer-layer">
|
||||
<div>
|
||||
<tm-navbar :hideBack="false" hideHome :title="`${title}的会话记录`" >
|
||||
</tm-navbar>
|
||||
</div>
|
||||
<div class="main-box">
|
||||
<div v-if="items.length === 0" class="flex justify-center items-center w-full mt-[200rpx]">
|
||||
<wd-loading />
|
||||
</div>
|
||||
@ -81,15 +71,16 @@ onMounted(() => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</zPaging>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.forward-record-page {
|
||||
.outer-layer {
|
||||
overflow-y: auto;
|
||||
flex: 1;
|
||||
background-image: url("@/static/image/clockIn/z3280@3x.png");
|
||||
background-size: cover;
|
||||
padding: 0 66rpx 20rpx 50rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
@ -100,7 +91,7 @@ onMounted(() => {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: auto;
|
||||
padding: 28rpx 66rpx 20rpx 50rpx;
|
||||
padding-top: 28rpx;
|
||||
}
|
||||
|
||||
.message-item {
|
||||
|
@ -1,50 +1,40 @@
|
||||
<template>
|
||||
<div>
|
||||
<wd-swipe-action class="swipe_action">
|
||||
<div
|
||||
@click="cellClick"
|
||||
:class="['chatItem', props.data.is_top === 1 ? 'isTop' : '']"
|
||||
>
|
||||
<div class="avatarImg">
|
||||
<tm-badge
|
||||
:count="props.data.is_disturb === 0 ? props.data.unread_num : ''"
|
||||
:dot="
|
||||
props.data.is_disturb === 1 && props.data.unread_num
|
||||
? true
|
||||
: false
|
||||
"
|
||||
:maxCount="99"
|
||||
class="badge"
|
||||
color="#D03050"
|
||||
>
|
||||
<avatarModule
|
||||
:mode="props?.data?.group_type === 0 ? 1 : 2"
|
||||
:avatar="props?.data?.avatar"
|
||||
:groupType="props?.data?.group_type"
|
||||
:userName="props?.data?.name"
|
||||
:customStyle="{
|
||||
width: '96rpx',
|
||||
height: '96rpx',
|
||||
}"
|
||||
:customTextStyle="{
|
||||
fontSize: '32rpx',
|
||||
fontWeight: 'bold',
|
||||
color: '#fff',
|
||||
lineHeight: '44rpx',
|
||||
}"
|
||||
></avatarModule>
|
||||
</tm-badge>
|
||||
</div>
|
||||
<div class="chatInfo">
|
||||
<div class="chatInfo_1">
|
||||
<div class="name_center">
|
||||
<div
|
||||
class="text-[#000000] text-[32rpx] font-bold opacity-90 name_text"
|
||||
>
|
||||
<div>
|
||||
<wd-swipe-action class="swipe_action">
|
||||
<div
|
||||
@click="cellClick"
|
||||
:class="['chatItem', props.data.is_top === 1 ? 'isTop' : '']"
|
||||
>
|
||||
<div class="avatarImg">
|
||||
<tm-badge
|
||||
:count="props.data.unread_num"
|
||||
:maxCount="99"
|
||||
color="#D03050"
|
||||
>
|
||||
<avatarModule
|
||||
:mode="props?.data?.group_type === 0 ? 1 : 2"
|
||||
:avatar="props?.data?.avatar"
|
||||
:groupType="props?.data?.group_type"
|
||||
:userName="props?.data?.name"
|
||||
:customStyle="{
|
||||
width: '96rpx',
|
||||
height: '96rpx',
|
||||
}"
|
||||
:customTextStyle="{
|
||||
fontSize: '32rpx',
|
||||
fontWeight: 'bold',
|
||||
color: '#fff',
|
||||
lineHeight: '44rpx',
|
||||
}"
|
||||
></avatarModule>
|
||||
</tm-badge>
|
||||
</div>
|
||||
<div class="chatInfo">
|
||||
<div class="chatInfo_1">
|
||||
<div class="name_center">
|
||||
<div class="text-[#000000] text-[32rpx]
|
||||
font-bold opacity-90 name_text">
|
||||
{{ 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>
|
||||
@ -55,167 +45,153 @@
|
||||
公司
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
style="flex-shrink: 0;"
|
||||
class="text-[#000000] text-[28rpx] font-medium opacity-26 ml-[24rpx] time_right"
|
||||
>
|
||||
{{ beautifyTime(props.data.updated_at) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="chatInfo_2 w-full mr-[6rpx]">
|
||||
<div class="w-full chatInfo_2_1 textEllipsis">
|
||||
<span v-if="props.data.atsign_num" style="color: red;">
|
||||
[有人@你]
|
||||
</span>
|
||||
{{ props.data.msg_text }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<template #right>
|
||||
<div class="flex flex-row flex-row-center-end">
|
||||
<!-- 样式占位 -->
|
||||
<div style="width: 1px;"></div>
|
||||
<div
|
||||
@click="handleTop"
|
||||
class="w-[156rpx] h-[154rpx] text-[#ffffff] bg-[#F09F1F] flex items-center justify-center"
|
||||
>
|
||||
{{ props.data.is_top === 1 ? '取消置顶' : '置顶' }}
|
||||
</div>
|
||||
<div
|
||||
@click="handleDelete"
|
||||
class="w-[156rpx] h-[154rpx] text-[#ffffff] bg-[#CF3050] flex items-center justify-center"
|
||||
>
|
||||
删除
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</wd-swipe-action>
|
||||
<div
|
||||
v-if="props.index !== talkStore.talkItems.length - 1"
|
||||
class="divider"
|
||||
></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div style="flex-shrink: 0;"
|
||||
class="text-[#000000] text-[28rpx] font-medium opacity-26 ml-[24rpx] time_right"
|
||||
>
|
||||
{{ beautifyTime(props.data.updated_at) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="chatInfo_2 w-full mr-[6rpx]">
|
||||
<div class="w-full chatInfo_2_1 textEllipsis">
|
||||
{{ props.data.msg_text }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<template #right>
|
||||
<div class="flex flex-row flex-row-center-end">
|
||||
<!-- 样式占位 -->
|
||||
<div style="width: 1px"></div>
|
||||
<div
|
||||
@click="handleTop"
|
||||
class="w-[156rpx] h-[154rpx] text-[#ffffff] bg-[#F09F1F] flex items-center justify-center"
|
||||
>
|
||||
{{ props.data.is_top === 1 ? "取消置顶" : "置顶" }}
|
||||
</div>
|
||||
<div
|
||||
@click="handleDelete"
|
||||
class="w-[156rpx] h-[154rpx] text-[#ffffff] bg-[#CF3050] flex items-center justify-center"
|
||||
>
|
||||
删除
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</wd-swipe-action>
|
||||
<div
|
||||
v-if="props.index !== talkStore.talkItems.length - 1"
|
||||
class="divider"
|
||||
></div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import avatarModule from '@/components/avatar-module/index.vue'
|
||||
import { ref, reactive, defineProps, computed } from 'vue'
|
||||
import dayjs from 'dayjs'
|
||||
import { beautifyTime } from '@/utils/datetime'
|
||||
import { ServeClearTalkUnreadNum } from '@/api/chat'
|
||||
import { useTalkStore, useDialogueStore } from '@/store'
|
||||
import { useSessionMenu } from '@/hooks'
|
||||
import avatarModule from "@/components/avatar-module/index.vue";
|
||||
import { ref, reactive, defineProps, computed } from "vue";
|
||||
import dayjs from "dayjs";
|
||||
import { beautifyTime } from "@/utils/datetime";
|
||||
import { ServeClearTalkUnreadNum } from "@/api/chat";
|
||||
import { useTalkStore, useDialogueStore } from "@/store";
|
||||
import { useSessionMenu } from "@/hooks";
|
||||
|
||||
const talkStore = useTalkStore()
|
||||
const { onToTopTalk, onRemoveTalk } = useSessionMenu()
|
||||
const dialogueStore = useDialogueStore()
|
||||
const dialogueParams = reactive({
|
||||
unReadNum: computed(() => dialogueStore.unreadNum),
|
||||
})
|
||||
const talkStore = useTalkStore();
|
||||
const { onToTopTalk, onRemoveTalk } = useSessionMenu();
|
||||
const dialogueStore = useDialogueStore();
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
default: {},
|
||||
required: true,
|
||||
},
|
||||
index: {
|
||||
type: Number,
|
||||
default: -1,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
data: {
|
||||
type: Object,
|
||||
default: {},
|
||||
required: true,
|
||||
},
|
||||
index: {
|
||||
type: Number,
|
||||
default: -1,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
// 添加格式化方法
|
||||
const formatNameText = (text, maxLength = 16) => {
|
||||
return text.length > maxLength ? `${text.slice(0, maxLength - 1)}...` : text
|
||||
}
|
||||
const formatNameText = (text, maxLength = 19) => {
|
||||
return text.length > maxLength ? `${text.slice(0, maxLength - 1)}...` : text;
|
||||
};
|
||||
|
||||
const cellClick = () => {
|
||||
console.log(props.data)
|
||||
// 更新编辑信息
|
||||
dialogueStore.setDialogue(props.data)
|
||||
console.log(props.data);
|
||||
// 更新编辑信息
|
||||
dialogueStore.setDialogue(props.data);
|
||||
|
||||
// 清空消息未读数
|
||||
if (props.data.unread_num > 0) {
|
||||
ServeClearTalkUnreadNum(
|
||||
{
|
||||
talk_type: props.data.talk_type,
|
||||
receiver_id: props.data.receiver_id,
|
||||
},
|
||||
dialogueParams.unReadNum,
|
||||
).then(() => {
|
||||
talkStore.updateItem({
|
||||
index_name: props.data.index_name,
|
||||
unread_num: 0,
|
||||
})
|
||||
dialogueStore.clearUnreadNum()
|
||||
})
|
||||
}
|
||||
uni.navigateTo({
|
||||
url: `/pages/dialog/index?sessionId=${props.data.id}`,
|
||||
})
|
||||
}
|
||||
// 清空消息未读数
|
||||
if (props.data.unread_num > 0) {
|
||||
ServeClearTalkUnreadNum({
|
||||
talk_type: props.data.talk_type,
|
||||
receiver_id: props.data.receiver_id,
|
||||
}).then(() => {
|
||||
talkStore.updateItem({
|
||||
index_name: props.data.index_name,
|
||||
unread_num: 0,
|
||||
});
|
||||
});
|
||||
}
|
||||
uni.navigateTo({
|
||||
url: "/pages/dialog/index?sessionId=" + props.data.id,
|
||||
});
|
||||
};
|
||||
|
||||
const handleTop = () => {
|
||||
console.log(props.data, 1)
|
||||
onToTopTalk(props.data)
|
||||
}
|
||||
console.log(props.data, 1);
|
||||
onToTopTalk(props.data);
|
||||
};
|
||||
|
||||
//点击删除会话
|
||||
const handleDelete = () => {
|
||||
console.log(props.data)
|
||||
onRemoveTalk(props.data)
|
||||
}
|
||||
console.log(props.data);
|
||||
onRemoveTalk(props.data);
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
::v-deep .swipe_action {
|
||||
// border: 1px solid #fff;
|
||||
// transform: translate3d(1px, 0px, 0px) !important;
|
||||
}
|
||||
::v-deep .badge .round-6 {
|
||||
min-width: 22rpx;
|
||||
min-height: 22rpx;
|
||||
// border: 1px solid #fff;
|
||||
// transform: translate3d(1px, 0px, 0px) !important;
|
||||
}
|
||||
.chatItem {
|
||||
width: 100%;
|
||||
height: 154rpx;
|
||||
padding: 30rpx 16rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 154rpx;
|
||||
padding: 30rpx 16rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&.isTop {
|
||||
background-color: #f3f3f3;
|
||||
}
|
||||
&.isTop {
|
||||
background-color: #f3f3f3;
|
||||
}
|
||||
}
|
||||
|
||||
.chatInfo {
|
||||
flex: 1;
|
||||
margin-left: 20rpx;
|
||||
flex: 1;
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
|
||||
.chatInfo_1 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.chatInfo_2 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: 6rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: 6rpx;
|
||||
}
|
||||
|
||||
.chatInfo_2_1 {
|
||||
font-size: 28rpx;
|
||||
color: rgba($color: #000000, $alpha: 0.4);
|
||||
font-size: 28rpx;
|
||||
color: rgba($color: #000000, $alpha: 0.4);
|
||||
}
|
||||
.tag {
|
||||
.tag{
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
// margin-left: 10rpx;
|
||||
margin-left: 10rpx;
|
||||
margin-top: 4rpx;
|
||||
vertical-align: top;
|
||||
height: 38rpx;
|
||||
@ -226,22 +202,22 @@ const handleDelete = () => {
|
||||
font-weight: bold;
|
||||
}
|
||||
.companyTag {
|
||||
border: 1px solid #7a58de;
|
||||
color: #7a58de;
|
||||
border: 1px solid #7a58de;
|
||||
color: #7a58de;
|
||||
}
|
||||
.depTag {
|
||||
border: 1px solid #377ec6;
|
||||
color: #377ec6;
|
||||
border: 1px solid #377ec6;
|
||||
color: #377ec6;
|
||||
}
|
||||
.projectTag {
|
||||
border: 1px solid #c1681c;
|
||||
color: #c1681c;
|
||||
border: 1px solid #c1681c;
|
||||
color: #c1681c;
|
||||
}
|
||||
.name_center {
|
||||
.name_center{
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
.name_text {
|
||||
.name_text{
|
||||
display: inline-block;
|
||||
max-height: 88rpx; // 两行文字的高度
|
||||
line-height: 44rpx;
|
||||
@ -253,24 +229,23 @@ const handleDelete = () => {
|
||||
word-break: break-all;
|
||||
}
|
||||
.time_right {
|
||||
/* white-space: nowrap;
|
||||
/* white-space: nowrap;
|
||||
max-width: 146rpx; */
|
||||
flex: 0 0 auto; /* 不伸缩,保持内容宽度 */
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.textEllipsis {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
word-break: break-all;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.divider {
|
||||
background-color: rgba(243, 243, 243, 1);
|
||||
height: 1rpx;
|
||||
margin: 0 18rpx;
|
||||
background-color: rgba(243, 243, 243, 1);
|
||||
height: 1rpx;
|
||||
margin: 0 18rpx;
|
||||
}
|
||||
</style>
|
||||
|
@ -31,25 +31,12 @@
|
||||
>
|
||||
<template v-slot:left>
|
||||
<div class="flex items-center ml-[48rpx]">
|
||||
<!-- <image
|
||||
<image
|
||||
class="w-[72rpx] h-[72rpx]"
|
||||
style="border-radius: 50%;"
|
||||
:src="userStore.avatar"
|
||||
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">
|
||||
{{ userStore.nickname }}
|
||||
</div>
|
||||
@ -66,11 +53,11 @@
|
||||
/>
|
||||
<template v-slot:label>
|
||||
<div
|
||||
class="w-full px-[14rpx]"
|
||||
class="w-full h-[208rpx] pt-[22rpx] pb-[32rpx] pl-[14rpx] pr-[12rpx]"
|
||||
>
|
||||
<div
|
||||
@click="creatGroupChat"
|
||||
class="flex items-center pl-[22rpx] py-[32rpx]"
|
||||
class="flex items-center pl-[22rpx] mb-[32rpx]"
|
||||
>
|
||||
<div class="mr-[26rpx] flex items-center">
|
||||
<tm-image
|
||||
@ -86,27 +73,9 @@
|
||||
</div>
|
||||
</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
|
||||
@click="toAddressBookPage"
|
||||
class="flex items-center pl-[22rpx] py-[32rpx]"
|
||||
class="flex items-center pl-[22rpx] mt-[32rpx]"
|
||||
>
|
||||
<div class="mr-[26rpx] flex items-center">
|
||||
<tm-image
|
||||
@ -156,23 +125,17 @@ import { ref, watch, computed } from 'vue'
|
||||
import { onShow, onLoad } from '@dcloudio/uni-app'
|
||||
import { useChatList } from '@/store/chatList/index.js'
|
||||
import { useAuth } from '@/store/auth'
|
||||
import { ServeClearTalkUnreadNum } from '@/api/chat'
|
||||
import { useTalkStore, useUserStore, useDialogueStore } from '@/store'
|
||||
import chatItem from './components/chatItem.vue'
|
||||
import addCircle from '@/static/image/chatList/addCircle.png'
|
||||
import cahtPopover from '@/static/image/chatList/cahtPopover.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 { handleSetWebviewStyle } from '@/utils/common'
|
||||
const paging = ref()
|
||||
const isEmptyViewShow = ref(false)
|
||||
const talkStore = useTalkStore()
|
||||
const userStore = useUserStore()
|
||||
const dialogueStore = useDialogueStore()
|
||||
const dialogueParams = reactive({
|
||||
unReadNum: computed(() => dialogueStore.unreadNum),
|
||||
})
|
||||
const { userInfo } = useAuth()
|
||||
|
||||
const topItems = computed(() => talkStore.topItems)
|
||||
@ -235,23 +198,10 @@ const toSearchPage = () => {
|
||||
})
|
||||
}
|
||||
|
||||
//点击跳转到添加好友页面
|
||||
const toAddFriendPage = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/addressBook/addFriend/index',
|
||||
})
|
||||
}
|
||||
|
||||
//点击跳转到通讯录页面
|
||||
const toAddressBookPage = () => {
|
||||
// 旧版本-按组织架构树的通讯录
|
||||
// uni.navigateTo({
|
||||
// url: '/pages/chooseByDeps/index?chooseMode=3',
|
||||
// })
|
||||
|
||||
// 新版本-按公司别、好友、群组的通讯录
|
||||
uni.navigateTo({
|
||||
url: '/pages/addressBook/index',
|
||||
url: '/pages/chooseByDeps/index?chooseMode=3',
|
||||
})
|
||||
}
|
||||
|
||||
@ -264,7 +214,6 @@ const toAddressBookPage = () => {
|
||||
); */
|
||||
|
||||
onShow(() => {
|
||||
handleSetWebviewStyle(true)
|
||||
// 页面显示时重新加载数据
|
||||
talkStore
|
||||
.loadTalkList()
|
||||
@ -286,27 +235,21 @@ onLoad((options) => {
|
||||
if (items?.value?.length > 0) {
|
||||
items.value.forEach((openSession) => {
|
||||
if (openSession.index_name === options?.openSessionIndexName) {
|
||||
setTimeout(() => {
|
||||
dialogueStore.setDialogue(openSession)
|
||||
if (openSession.unread_num > 0) {
|
||||
ServeClearTalkUnreadNum(
|
||||
{
|
||||
talk_type: openSession.talk_type,
|
||||
receiver_id: openSession.receiver_id,
|
||||
},
|
||||
dialogueParams.unReadNum,
|
||||
).then(() => {
|
||||
talkStore.updateItem({
|
||||
index_name: openSession.index_name,
|
||||
unread_num: 0,
|
||||
})
|
||||
dialogueStore.clearUnreadNum()
|
||||
dialogueStore.setDialogue(openSession)
|
||||
if (openSession.unread_num > 0) {
|
||||
ServeClearTalkUnreadNum({
|
||||
talk_type: openSession.talk_type,
|
||||
receiver_id: openSession.receiver_id,
|
||||
}).then(() => {
|
||||
talkStore.updateItem({
|
||||
index_name: openSession.index_name,
|
||||
unread_num: 0,
|
||||
})
|
||||
}
|
||||
uni.navigateTo({
|
||||
url: `/pages/dialog/index?sessionId=${openSession.id}`,
|
||||
})
|
||||
}, 500)
|
||||
}
|
||||
uni.navigateTo({
|
||||
url: '/pages/dialog/index?sessionId=' + openSession.id,
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -96,30 +96,14 @@ import {
|
||||
import HighlightText from './highLightText.vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { beautifyTime } from '@/utils/datetime'
|
||||
import { ChatMsgTypeMapping } from '@/constant/message'
|
||||
const { t } = useI18n()
|
||||
const props = defineProps({
|
||||
searchItem: Object | Number,
|
||||
searchResultKey: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
searchText: {
|
||||
type: String,
|
||||
default: '',
|
||||
}, //搜索内容
|
||||
searchRecordDetail: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
}, //是否是搜索聊天记录详情
|
||||
pointerIconSrc: {
|
||||
type: String,
|
||||
default: '',
|
||||
}, //箭头图标
|
||||
conditionType: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
}, //搜索类型
|
||||
searchResultKey: String,
|
||||
searchText: String, //搜索内容
|
||||
searchRecordDetail: Boolean, //是否是搜索聊天记录详情
|
||||
pointerIconSrc: String, //箭头图标
|
||||
conditionType: Number, //搜索类型
|
||||
})
|
||||
// 映射表-查找对应结构下的属性名
|
||||
const keyMapping = {
|
||||
@ -176,13 +160,6 @@ const keyMapping = {
|
||||
name: 'receiver_name',
|
||||
group_num: 'group_num',
|
||||
},
|
||||
search_by_member_condition: {
|
||||
avatar: 'avatar',
|
||||
name: 'nickname',
|
||||
created_at: 'created_at',
|
||||
msg_type: 'msg_type',
|
||||
detailKey: 'chatMessageType',
|
||||
},
|
||||
}
|
||||
//获取key对应值
|
||||
const getKeyValue = (keys) => {
|
||||
@ -216,8 +193,10 @@ const imgText = computed(() => {
|
||||
})
|
||||
// 映射表-根据groupType设置对应值
|
||||
const groupTypeMapping = {
|
||||
0: {},
|
||||
1: {},
|
||||
0: {
|
||||
},
|
||||
1: {
|
||||
},
|
||||
2: {
|
||||
result_type: t('index.mine.department'),
|
||||
result_type_color: '#377EC6',
|
||||
@ -262,12 +241,6 @@ const resultDetail = computed(() => {
|
||||
case 'extra':
|
||||
result_detail = props.searchItem?.extra
|
||||
break
|
||||
case 'chatMessageType':
|
||||
result_detail =
|
||||
props.searchItem?.msg_type === 1
|
||||
? props.searchItem?.extra?.content
|
||||
: ChatMsgTypeMapping[props.searchItem?.msg_type]
|
||||
break
|
||||
default:
|
||||
result_detail = ''
|
||||
}
|
||||
@ -302,7 +275,6 @@ const resultDetail = computed(() => {
|
||||
padding: 2rpx 14rpx;
|
||||
border: 2rpx solid #000;
|
||||
border-radius: 6rpx;
|
||||
flex-shrink: 0;
|
||||
span {
|
||||
line-height: 34rpx;
|
||||
}
|
||||
@ -327,7 +299,6 @@ const resultDetail = computed(() => {
|
||||
.info-detail-searchRecordDetail {
|
||||
span {
|
||||
color: $theme-text;
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
:default-page-size="props.searchResultPageSize"
|
||||
:loading-more-default-as-loading="true"
|
||||
:inside-more="true"
|
||||
:empty-view-img="searchNoData"
|
||||
:empty-view-img="'/src/static//image/search/search-no-data.png'"
|
||||
:empty-view-text="$t('search.hint')"
|
||||
:empty-view-img-style="{ width: '476rpx', height: '261rpx' }"
|
||||
:empty-view-title-style="{
|
||||
@ -19,7 +19,6 @@
|
||||
'font-size': '28rpx',
|
||||
'font-weight': 400,
|
||||
}"
|
||||
:refresher-enabled="false"
|
||||
>
|
||||
<template #top>
|
||||
<div class="searchRoot">
|
||||
@ -36,10 +35,7 @@
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<div
|
||||
class="search-record-detail"
|
||||
v-if="props.searchRecordDetail && !props?.hideFirstRecord"
|
||||
>
|
||||
<div class="search-record-detail" v-if="props.searchRecordDetail">
|
||||
<searchItem
|
||||
@click="
|
||||
clickSearchItem(
|
||||
@ -113,7 +109,6 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import searchNoData from '@/static/image/search/search-no-data.png'
|
||||
import customInput from '@/components/custom-input/custom-input.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'
|
||||
@ -122,10 +117,6 @@ import { useI18n } from 'vue-i18n'
|
||||
import { ref, reactive, defineEmits, defineProps, onMounted } from 'vue'
|
||||
import pointerIconSrc from '@/static/image/search/search-item-pointer.png'
|
||||
|
||||
import lodash from 'lodash'
|
||||
import { useUserStore } from '@/store'
|
||||
const userStore = useUserStore()
|
||||
|
||||
const zPaging = ref()
|
||||
useZPaging(zPaging)
|
||||
|
||||
@ -140,45 +131,17 @@ const state = reactive({
|
||||
searchResultList: [], //搜素结果列表
|
||||
searchResult: null, //搜索结果
|
||||
pageNum: 1, //当前请求数据页数
|
||||
uid: computed(() => userStore.uid), //当前用户id
|
||||
})
|
||||
|
||||
const props = defineProps({
|
||||
searchResultPageSize: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
}, //搜索结果每页数据量
|
||||
listLimit: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
}, //是否限制列表内数据数量
|
||||
apiParams: {
|
||||
type: String,
|
||||
default: '',
|
||||
}, //请求参数
|
||||
searchResultPageSize: Number, //搜索结果每页数据量
|
||||
listLimit: Boolean, //是否限制列表内数据数量
|
||||
apiParams: String, //请求参数
|
||||
apiRequest: Function, //请求
|
||||
searchText: {
|
||||
type: String,
|
||||
default: '',
|
||||
}, //搜索内容
|
||||
isPagination: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
}, //是否分页
|
||||
searchRecordDetail: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
}, //是否是搜索聊天记录的详情
|
||||
first_talk_record_infos: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {}
|
||||
},
|
||||
}, //接受者信息
|
||||
hideFirstRecord: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
}, //是否隐藏前缀及搜索群/用户主体信息
|
||||
searchText: String, //搜索内容
|
||||
isPagination: Boolean, //是否分页
|
||||
searchRecordDetail: Boolean, //是否是搜索聊天记录的详情
|
||||
first_talk_record_infos: Object, //接受者信息
|
||||
})
|
||||
|
||||
const { t } = useI18n()
|
||||
@ -191,14 +154,13 @@ onMounted(() => {
|
||||
|
||||
//输入搜索文本
|
||||
const inputSearchText = (e) => {
|
||||
// console.log(e)
|
||||
if (e.trim() != state.searchText.trim()) {
|
||||
state.pageNum = 1
|
||||
state.searchResult = null // 清空搜索结果
|
||||
emits('lastIdChange', 0, 0, 0)
|
||||
}
|
||||
state.searchText = e.trim()
|
||||
if (!e.trim()) {
|
||||
state.searchResult = null // 清空搜索结果
|
||||
emits('lastIdChange', 0, 0, 0)
|
||||
}
|
||||
zPaging.value?.reload()
|
||||
@ -235,35 +197,15 @@ const queryAllSearch = (pageNum, searchResultPageSize) => {
|
||||
})
|
||||
}
|
||||
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,
|
||||
receiverInfo,
|
||||
data.talk_record_infos[0],
|
||||
)
|
||||
;(data.talk_record_infos || []).forEach((item) => {
|
||||
item.group_type = 0
|
||||
})
|
||||
}
|
||||
|
||||
let tempGeneral_infos = Array.isArray(data.general_infos)
|
||||
? [...data.general_infos]
|
||||
: data.general_infos
|
||||
@ -272,8 +214,6 @@ const queryAllSearch = (pageNum, searchResultPageSize) => {
|
||||
data.group_member_infos || [],
|
||||
)
|
||||
data.general_infos = tempGeneral_infos
|
||||
|
||||
// 检查数据是否为空
|
||||
let isEmpty = true
|
||||
let dataKeys = Object.keys(data)
|
||||
let paginationKey = ''
|
||||
@ -283,147 +223,58 @@ const queryAllSearch = (pageNum, searchResultPageSize) => {
|
||||
isEmpty = false
|
||||
}
|
||||
})
|
||||
|
||||
if (isEmpty) {
|
||||
if (pageNum === 1) {
|
||||
// 第一页请求且为空,清空结果
|
||||
state.searchResult = null
|
||||
if (pageNum == 1) {
|
||||
zPaging.value?.complete([])
|
||||
} else {
|
||||
// 加载更多且为空,保持原列表不变
|
||||
zPaging.value?.complete(
|
||||
state.searchResult ? [state.searchResult] : [],
|
||||
)
|
||||
data = state.searchResult
|
||||
zPaging.value?.complete([data])
|
||||
}
|
||||
} else {
|
||||
if (props.isPagination) {
|
||||
if (pageNum === 1) {
|
||||
// 第一页请求,直接设置新数据
|
||||
state.searchResult = data
|
||||
} else {
|
||||
// 加载更多,合并数据
|
||||
if (
|
||||
paginationKey &&
|
||||
Array.isArray(
|
||||
(state?.searchResult && state?.searchResult[paginationKey]) ||
|
||||
[],
|
||||
)
|
||||
) {
|
||||
data[paginationKey] = state.searchResult[paginationKey].concat(
|
||||
data[paginationKey],
|
||||
)
|
||||
}
|
||||
state.searchResult = data
|
||||
if (
|
||||
paginationKey &&
|
||||
Array.isArray(
|
||||
(state?.searchResult && state?.searchResult[paginationKey]) || [],
|
||||
) &&
|
||||
((state?.searchResult && state?.searchResult[paginationKey]) || [])
|
||||
.length > 0
|
||||
) {
|
||||
data[paginationKey] = state.searchResult[paginationKey].concat(
|
||||
data[paginationKey],
|
||||
)
|
||||
}
|
||||
|
||||
emits(
|
||||
'lastIdChange',
|
||||
data.last_id,
|
||||
data.last_group_id,
|
||||
data.last_member_id,
|
||||
data.last_receiver_user_name,
|
||||
data.last_receiver_group_name,
|
||||
)
|
||||
let total = data.count
|
||||
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
|
||||
}
|
||||
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 {
|
||||
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,
|
||||
)
|
||||
total = data.group_record_count
|
||||
}
|
||||
zPaging.value?.completeByTotal([data], total)
|
||||
} else {
|
||||
state.searchResult = data
|
||||
zPaging.value?.complete([data])
|
||||
}
|
||||
}
|
||||
state.searchResult = data
|
||||
} else {
|
||||
if (pageNum === 1) {
|
||||
// 第一页请求失败,清空结果
|
||||
state.searchResult = null
|
||||
zPaging.value?.complete([])
|
||||
} else {
|
||||
// 加载更多失败,保持原列表不变
|
||||
zPaging.value?.complete(state.searchResult ? [state.searchResult] : [])
|
||||
}
|
||||
zPaging.value?.complete([])
|
||||
}
|
||||
})
|
||||
|
||||
resp.catch(() => {
|
||||
if (pageNum === 1) {
|
||||
// 第一页请求异常,清空结果
|
||||
state.searchResult = null
|
||||
zPaging.value?.complete([])
|
||||
} else {
|
||||
// 加载更多异常,保持原列表不变
|
||||
zPaging.value?.complete(state.searchResult ? [state.searchResult] : [])
|
||||
}
|
||||
zPaging.value?.complete([])
|
||||
})
|
||||
}
|
||||
|
||||
//点击取消搜索
|
||||
const cancelSearch = () => {
|
||||
const pages = getCurrentPages()
|
||||
if (pages.length > 1) {
|
||||
uni.navigateBack({
|
||||
delta: 1,
|
||||
})
|
||||
} else {
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/index',
|
||||
})
|
||||
}
|
||||
uni.navigateBack({
|
||||
delta: 1,
|
||||
})
|
||||
}
|
||||
|
||||
//获取key对应值
|
||||
@ -491,12 +342,6 @@ const getHasMoreResult = (searchResultKey) => {
|
||||
}
|
||||
break
|
||||
case 'general_infos':
|
||||
if (
|
||||
state.searchResult['record_count'] &&
|
||||
state.searchResult['record_count'] >= 3
|
||||
) {
|
||||
has_more_result = t('has_more') + t('chat.type.record')
|
||||
}
|
||||
break
|
||||
default:
|
||||
}
|
||||
@ -510,41 +355,12 @@ const toMoreResultPage = (searchResultKey) => {
|
||||
|
||||
//点击了搜索结果项
|
||||
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(
|
||||
'clickSearchItem',
|
||||
state.searchText,
|
||||
searchResultKey,
|
||||
talk_type,
|
||||
receiver_id,
|
||||
encodeURIComponent(JSON.stringify(searchItem)),
|
||||
searchItem.talk_type,
|
||||
searchItem.receiver_id,
|
||||
)
|
||||
}
|
||||
</script>
|
||||
|
@ -13,19 +13,7 @@
|
||||
</template>
|
||||
<script setup>
|
||||
import searchList from './components/searchList.vue'
|
||||
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()
|
||||
})
|
||||
import { ServeSeachQueryAll } from '@/api/search/index'
|
||||
|
||||
//点击跳转到更多结果页面
|
||||
const toMoreResultPage = (searchResultKey, searchText) => {
|
||||
@ -39,49 +27,14 @@ const toMoreResultPage = (searchResultKey, searchText) => {
|
||||
}
|
||||
|
||||
//点击了搜索结果项
|
||||
const clickSearchItem = async (
|
||||
const clickSearchItem = (
|
||||
searchText,
|
||||
searchResultKey,
|
||||
talk_type,
|
||||
receiver_id,
|
||||
res,
|
||||
) => {
|
||||
console.log(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 (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') {
|
||||
if (searchResultKey === 'general_infos') {
|
||||
uni.navigateTo({
|
||||
url:
|
||||
'/pages/search/moreResult/moreResultDetail?searchText=' +
|
||||
@ -93,25 +46,5 @@ const clickSearchItem = async (
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//获取会话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>
|
||||
<style scoped lang="scss"></style>
|
||||
|
@ -21,21 +21,14 @@ import {
|
||||
ServeQueryUser,
|
||||
ServeQueryGroup,
|
||||
ServeTalkRecord,
|
||||
ServeGetSessionId,
|
||||
} from '@/api/search/index'
|
||||
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({
|
||||
apiRequest: Function,
|
||||
apiParams: '',
|
||||
searchText: '',
|
||||
searchResultKey: '',
|
||||
apiParams: String,
|
||||
searchText: String,
|
||||
searchResultKey: String,
|
||||
})
|
||||
|
||||
onLoad((options) => {
|
||||
@ -64,8 +57,6 @@ onLoad((options) => {
|
||||
receiver_id: 0, //查详情的时候需传入
|
||||
last_group_id: 0, //最后一条群id
|
||||
last_member_id: 0, //最后一条用户id
|
||||
last_receiver_user_name: '', //最后一条用户名
|
||||
last_receiver_group_name: '', //最后一条群名
|
||||
}),
|
||||
)
|
||||
state.apiRequest = ServeTalkRecord
|
||||
@ -77,19 +68,11 @@ onLoad((options) => {
|
||||
})
|
||||
|
||||
//分页查询时,最后一条id变化
|
||||
const lastIdChange = (
|
||||
last_id,
|
||||
last_group_id,
|
||||
last_member_id,
|
||||
last_receiver_user_name,
|
||||
last_receiver_group_name,
|
||||
) => {
|
||||
const lastIdChange = (last_id, last_group_id, last_member_id) => {
|
||||
let idChanges = {
|
||||
last_id,
|
||||
last_group_id,
|
||||
last_member_id,
|
||||
last_receiver_user_name,
|
||||
last_receiver_group_name,
|
||||
}
|
||||
state.apiParams = encodeURIComponent(
|
||||
JSON.stringify(
|
||||
@ -103,79 +86,12 @@ const lastIdChange = (
|
||||
}
|
||||
|
||||
//点击了搜索结果项
|
||||
const clickSearchItem = async (
|
||||
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,
|
||||
})
|
||||
const clickSearchItem = (searchText) => {
|
||||
if (state.searchResultKey === 'general_infos') {
|
||||
uni.navigateTo({
|
||||
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,
|
||||
url: '/pages/search/moreResult/moreResultDetail?searchText=' + searchText,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//获取会话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>
|
||||
<style scoped lang="scss"></style>
|
||||
|
@ -7,11 +7,9 @@
|
||||
:apiRequest="ServeTalkRecord"
|
||||
:apiParams="state.apiParams"
|
||||
:searchText="state.searchText"
|
||||
:hideFirstRecord="state.hideFirstRecord"
|
||||
:isPagination="true"
|
||||
:searchRecordDetail="true"
|
||||
@lastIdChange="lastIdChange"
|
||||
@clickSearchItem="clickSearchItem"
|
||||
></searchList>
|
||||
</div>
|
||||
</div>
|
||||
@ -21,17 +19,10 @@ import searchList from '../components/searchList.vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { ServeTalkRecord } from '@/api/search/index'
|
||||
import { reactive } from 'vue'
|
||||
import { useDialogueStore, useUserStore } from '@/store'
|
||||
import lodash from 'lodash'
|
||||
|
||||
const dialogueStore = useDialogueStore()
|
||||
const userStore = useUserStore()
|
||||
|
||||
const state = reactive({
|
||||
apiParams: '',
|
||||
searchText: '',
|
||||
uid: computed(() => userStore.uid), //当前用户id
|
||||
hideFirstRecord: false, //是否隐藏前缀及搜索群/用户主体信息
|
||||
apiParams: String,
|
||||
searchText: String,
|
||||
})
|
||||
|
||||
onLoad((options) => {
|
||||
@ -57,10 +48,6 @@ onLoad((options) => {
|
||||
}
|
||||
|
||||
console.log(JSON.parse(decodeURIComponent(state.apiParams)))
|
||||
|
||||
if (options.hideFirstRecord) {
|
||||
state.hideFirstRecord = options.hideFirstRecord === '1' ? true : false
|
||||
}
|
||||
})
|
||||
|
||||
//分页查询时,最后一条id变化
|
||||
@ -80,51 +67,5 @@ 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>
|
||||
<style scoped lang="scss"></style>
|
||||
|
@ -9,7 +9,6 @@
|
||||
:auto="false"
|
||||
:loading-more-default-as-loading="true"
|
||||
:inside-more="true"
|
||||
v-model="state.flatList"
|
||||
>
|
||||
<template #top v-if="state.showPageTitle">
|
||||
<customNavbar :title="state.pageTitle"></customNavbar>
|
||||
@ -42,7 +41,7 @@
|
||||
<span class="text-[28rpx] font-regular">
|
||||
{{ state.selectedMonth }}
|
||||
</span>
|
||||
<img src="@/static/image/search/down-pointer.png" />
|
||||
<img src="/src/static/image/search/down-pointer.png" />
|
||||
</div>
|
||||
</tm-time-picker>
|
||||
<tm-calendar-view
|
||||
@ -65,8 +64,7 @@
|
||||
v-if="
|
||||
state.condition === 'imgAndVideo' ||
|
||||
state.condition === 'file' ||
|
||||
state.condition === 'link' ||
|
||||
state.condition === 'member'
|
||||
state.condition === 'link'
|
||||
"
|
||||
:style="{
|
||||
padding: state.condition === 'imgAndVideo' ? '0 27rpx' : '',
|
||||
@ -114,27 +112,11 @@
|
||||
v-for="(item, index) in conditionItem.monthResultList"
|
||||
:key="index"
|
||||
:style="{
|
||||
border:
|
||||
state.condition === 'imgAndVideo' ||
|
||||
state.condition === 'member'
|
||||
? '0'
|
||||
: '',
|
||||
border: state.condition === 'imgAndVideo' ? '0' : '',
|
||||
padding:
|
||||
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
|
||||
class="condition-result-imgAndVideo"
|
||||
v-if="state.condition === 'imgAndVideo'"
|
||||
@ -160,27 +142,17 @@
|
||||
class="condition-result-imgAndVideo-area"
|
||||
v-if="item?.extra?.url"
|
||||
>
|
||||
<template v-if="item?.msg_type === 3">
|
||||
<tm-image
|
||||
preview
|
||||
:src="item?.extra?.url"
|
||||
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>
|
||||
<tm-image
|
||||
preview
|
||||
:src="
|
||||
item?.msg_type === 3
|
||||
? item?.extra?.url
|
||||
: item?.msg_type === 5
|
||||
? item?.extra?.cover
|
||||
: ''
|
||||
"
|
||||
model="aspectFill"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@ -201,7 +173,6 @@
|
||||
</div>
|
||||
<div
|
||||
class="condition-each-result-attachments"
|
||||
@click="previewPDF(item)"
|
||||
v-if="
|
||||
state.condition === 'file' || state.condition === 'link'
|
||||
"
|
||||
@ -212,7 +183,7 @@
|
||||
v-if="state.condition === 'file'"
|
||||
/>
|
||||
<img
|
||||
src="@/static/image/search/result-link-icon.png"
|
||||
src="/src/static/image/search/result-link-icon.png"
|
||||
v-if="state.condition === 'link'"
|
||||
/>
|
||||
</div>
|
||||
@ -267,20 +238,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</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>
|
||||
</template>
|
||||
@ -290,16 +247,15 @@ import fileType_EXCEL from '@/static/image/search/fileType_EXCEL.png'
|
||||
import fileType_WORD from '@/static/image/search/fileType_WORD.png'
|
||||
import fileType_PDF from '@/static/image/search/fileType_PDF.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 searchItem from '../components/searchItem.vue'
|
||||
import customInput from '@/components/custom-input/custom-input.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 { parseTime } from '@/utils/datetime'
|
||||
import { onMounted, reactive, computed, ref, nextTick } from 'vue'
|
||||
import { onMounted, reactive, computed, ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { ServeTalkDate, ServeGetSessionId } from '@/api/search/index'
|
||||
import { ServeTalkDate } from '@/api/search/index'
|
||||
import { ServeFindTalkRecords } from '@/api/chat/index'
|
||||
import { useDialogueStore } from '@/store'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
@ -317,6 +273,7 @@ const dialogueParams = reactive({
|
||||
let nowDay = new Date().setHours(0, 0, 0, 0)
|
||||
|
||||
const state = reactive({
|
||||
receiver_id: '', //目标人id
|
||||
pageTitle: '', //页面标题
|
||||
dateStyle: [], //日期样式
|
||||
nowDate: new Date(nowDay), //当前时间
|
||||
@ -332,53 +289,16 @@ const state = reactive({
|
||||
searchResultList: [], //搜索结果列表
|
||||
cursor: 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) => {
|
||||
console.log(options)
|
||||
if (options.receiver_id) {
|
||||
state.receiver_id = Number(options.receiver_id)
|
||||
}
|
||||
if (options.condition) {
|
||||
state.condition = options.condition
|
||||
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') {
|
||||
if (options.condition === 'date') {
|
||||
state.showPageTitle = true
|
||||
state.pageTitle = t('search.condition.date')
|
||||
ServeQueryTalkDate(parseTime(state.nowDate, '{y}{m}'))
|
||||
@ -431,8 +351,8 @@ onMounted(() => {
|
||||
const ServeQueryTalkDate = (month) => {
|
||||
let params = {
|
||||
month: month,
|
||||
talk_type: dialogueParams.talk_type, //1私聊2群聊
|
||||
receiver_id: dialogueParams.receiver_id, //目标人id
|
||||
talk_type: 2, //1私聊2群聊
|
||||
receiver_id: state.receiver_id, //目标人id
|
||||
}
|
||||
const resp = ServeTalkDate(params)
|
||||
console.log(resp)
|
||||
@ -467,7 +387,7 @@ const ServeQueryTalkDate = (month) => {
|
||||
}
|
||||
|
||||
//点击选择日期
|
||||
const selectDate = async (e) => {
|
||||
const selectDate = (e) => {
|
||||
if (e == parseTime(state.nowDate, '{y}/{m}/{d}')) {
|
||||
console.log('==今日')
|
||||
state.dateStyle = [
|
||||
@ -493,38 +413,6 @@ const selectDate = async (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(() => {})
|
||||
})
|
||||
}
|
||||
|
||||
//点击确认选择月份
|
||||
@ -555,22 +443,13 @@ const getDArray = (dArray) => {
|
||||
//输入搜索内容
|
||||
const inputSearchText = (e) => {
|
||||
state.searchText = e
|
||||
state.cursor = 0
|
||||
queryAllSearch()
|
||||
}
|
||||
|
||||
//点击取消搜索
|
||||
const cancelSearch = () => {
|
||||
const pages = getCurrentPages()
|
||||
if (pages.length > 1) {
|
||||
uni.navigateBack({
|
||||
delta: 1,
|
||||
})
|
||||
} else {
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/index',
|
||||
})
|
||||
}
|
||||
uni.navigateBack({
|
||||
delta: 1,
|
||||
})
|
||||
}
|
||||
|
||||
//查询数据
|
||||
@ -585,8 +464,7 @@ const queryAllSearch = () => {
|
||||
direction: 'up', //down向下查最新,up向上查老数据
|
||||
start_time: '',
|
||||
end_time: '',
|
||||
group_member_user_id: state.group_member_id, //群成员id,当查询群历史消息的时候,需要指定群成员的时候送
|
||||
file_name: state.msg_type === 6 ? state.searchText : '',
|
||||
group_member_user_id: 0, //群成员id,当查询群历史消息的时候,需要指定群成员的时候送
|
||||
}
|
||||
console.log(params)
|
||||
const resp = ServeFindTalkRecords(params)
|
||||
@ -594,20 +472,17 @@ const queryAllSearch = () => {
|
||||
resp.then(({ code, data }) => {
|
||||
console.log(data)
|
||||
if (code == 200) {
|
||||
// 当cursor为0时,清空searchResultList
|
||||
let dateList = state.cursor === 0 ? [] : state.searchResultList
|
||||
let dateList = state.searchResultList
|
||||
let noMore = false
|
||||
if (data?.items?.length > 0) {
|
||||
data.items.forEach((item) => {
|
||||
item.dateTime = parseTime(item?.created_at, '{m}/{d}')
|
||||
if (item?.extra) {
|
||||
item.extra.fileSize = fileFormatSize(item?.extra?.size)
|
||||
item.extra.typeText = item?.extra?.name
|
||||
? fileSuffix(item?.extra?.name)
|
||||
: ''
|
||||
item.extra.file_avatar = fileTypeAvatar(item?.extra?.typeText)
|
||||
console.log(item.extra.type)
|
||||
}
|
||||
item.extra.fileSize = fileFormatSize(item?.extra?.size)
|
||||
item.extra.typeText = item?.extra?.name
|
||||
? fileSuffix(item?.extra?.name)
|
||||
: ''
|
||||
item.extra.file_avatar = fileTypeAvatar(item?.extra?.typeText)
|
||||
console.log(item.extra.type)
|
||||
let year = new Date(item.created_at).getFullYear()
|
||||
let month = new Date(item.created_at).getMonth() + 1
|
||||
let dateMonth =
|
||||
@ -640,35 +515,15 @@ const queryAllSearch = () => {
|
||||
} else {
|
||||
noMore = true
|
||||
}
|
||||
|
||||
// 保存分组数据用于显示
|
||||
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 {
|
||||
zPaging.value?.completeByNoMore(state.flatList, noMore)
|
||||
}
|
||||
console.log(dateList)
|
||||
state.cursor = data?.cursor
|
||||
zPaging.value?.completeByNoMore(dateList, noMore)
|
||||
} else {
|
||||
if (state.cursor === 0) {
|
||||
state.searchResultList = []
|
||||
state.flatList = []
|
||||
}
|
||||
zPaging.value?.complete([])
|
||||
}
|
||||
})
|
||||
|
||||
resp.catch(() => {
|
||||
if (state.cursor === 0) {
|
||||
state.searchResultList = []
|
||||
state.flatList = []
|
||||
}
|
||||
zPaging.value?.complete([])
|
||||
})
|
||||
}
|
||||
@ -691,59 +546,6 @@ const fileTypeAvatar = (fileType) => {
|
||||
}
|
||||
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>
|
||||
<style scoped lang="scss">
|
||||
.search-by-date {
|
||||
@ -850,7 +652,6 @@ body::v-deep .round-3 {
|
||||
span {
|
||||
line-height: 40rpx;
|
||||
color: $theme-text;
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
.attachment-sub-info {
|
||||
@ -897,26 +698,6 @@ body::v-deep .round-3 {
|
||||
width: 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -925,23 +706,4 @@ 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>
|
||||
|
@ -23,7 +23,7 @@ class WsSocket {
|
||||
lockReconnect: false,
|
||||
setTimeout: null, // 计时器对象
|
||||
time: 3000, // 重连间隔时间
|
||||
number: 20 // 重连次数
|
||||
number: 10000000 // 重连次数
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,21 +1,5 @@
|
||||
import Request from '@/service/request/index.js'
|
||||
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()
|
||||
let isRefreshing = false;
|
||||
let refreshSubscribers = [];
|
||||
@ -40,25 +24,19 @@ const request = new Request({
|
||||
},
|
||||
responseInterceptors: async (res) => {
|
||||
if(res.data.status===1){
|
||||
// message.warning(res.data.msg)
|
||||
messageInstance.warning(res.data.msg)
|
||||
message.warning(res.data.msg)
|
||||
}
|
||||
if (res.data.status === 401) {
|
||||
return
|
||||
// return getRefreshToken(res);
|
||||
return getRefreshToken(res);
|
||||
// uni.navigateTo({
|
||||
// url:'/pages/login/index'
|
||||
// })
|
||||
}
|
||||
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;
|
||||
} else {
|
||||
/* message.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.'));
|
||||
return Promise.reject(new Error(res.data.msg || 'An error occurred.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -81,14 +59,13 @@ async function getRefreshToken(response) {
|
||||
})
|
||||
return request.request(response.config);
|
||||
} else {
|
||||
|
||||
messageInstance.error(res.message || res.msg);
|
||||
message.error(res.message || res.msg);
|
||||
throw new Error(res.message || res.msg);
|
||||
}
|
||||
} catch (error) {
|
||||
// uni.navigateTo({
|
||||
// url:'/pages/login/index'
|
||||
// })
|
||||
uni.navigateTo({
|
||||
url:'/pages/login/index'
|
||||
})
|
||||
throw error
|
||||
} finally {
|
||||
isRefreshing = false;
|
||||
@ -96,9 +73,9 @@ async function getRefreshToken(response) {
|
||||
refreshSubscribers = [];
|
||||
}
|
||||
} else {
|
||||
// uni.navigateTo({
|
||||
// url:'/pages/login/index'
|
||||
// })
|
||||
uni.navigateTo({
|
||||
url:'/pages/login/index'
|
||||
})
|
||||
throw new Error('No refresh token available.');
|
||||
}
|
||||
} else {
|
||||
|
Before Width: | Height: | Size: 654 B |
Before Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 752 B |
Before Width: | Height: | Size: 208 B |
Before Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.7 KiB |
@ -5,7 +5,7 @@ import { userInfoApi } from "@/api/user";
|
||||
import {ref} from 'vue'
|
||||
export const useAuth = createGlobalState(() => {
|
||||
const token = useStorage('token', '', uniStorage)
|
||||
// const token = ref("2046c3941ed4959f6d988d3d4a0fe40d4b52f33f3f5fc1001406064554641d9406bb13cacb92939b0ca223c17e2c2f2fe70212ef017dbae8965d5cf86bad48ce4316e605ca187bd9ffd4aa6b56865be4ad4e422701d330b52d60cfe649cd48cf3a21a2a6e9a9cabafff364ee9c311ec634b0afc09db0d3215bedce561e9d50e5a8da6092062e2ebe35f747d77d72a68ad492a4ab218c07887c9cd4867f2c2d28e4ae1fd671144cc20ef0632f9ce067289004d67f6adf41b20d6ef5cdbfb74aadc2d2736ececf07254f1a76552bde4f1161a0fca7bfe32a29685ce1e76366116b81ae2195b3713dbb04285e5ddfd36184fe671c5524d20b4fe74a555db755f8d939b0bc46fb0cb998323d54c9925729d7ca835b7925999a677faa0cbe1cbc67b5203d85317653883aec81d3e71d865b326376bea726cc66d9f7f5a160d43f671c")
|
||||
// const token = ref('79b5c732d96d2b27a48a99dfd4a5566c43aaa5796242e854ebe3ffc198d6876b9628e7b764d9af65ab5dbb2d517ced88170491b74b048c0ba827c0d3741462cb89dc59ed46653a449af837a8262941caaef1334d640773710f8cd96473bacfb190cba595a5d6a9c87d70f0999a3ebb41147213b31b4bdccffca66a56acf3baab5af0154f0dce360079f37709f78e13711036899344bddb0fb4cf0f2890287cb62c3fcbe33368caa5e213624577be8b8420ab75b1f50775ee16142a4321c5d56995f37354a66a969da98d95ba6e65d142ed097e04b411c1ebad2f62866d0ec7e1838420530a9941dbbcd00490199f8b897937e719454eda6de1352a14497a54063c2ae13c2b1418f2689268102faffee874777ce1312eb7d9399eaa8cf58674aa86c9b85ad9300293c0a3369ed429536bbea4fcb092b78466ea53a44a2b2b1c1a')
|
||||
const refreshToken = useStorage('refreshToken', '', uniStorage)
|
||||
const userInfo = useStorage('userInfo', {}, uniStorage)
|
||||
const leaderList = useStorage('leaderList', [], uniStorage)
|
||||
|
@ -10,14 +10,10 @@ import {
|
||||
departmentV2AllPosition,
|
||||
groupCreateDept,
|
||||
departmentV2TreeAll,
|
||||
departmentV2TreeAll2,
|
||||
userHasPermission,
|
||||
userV2List,
|
||||
userV2List2,
|
||||
v2TreePositionByDepartment,
|
||||
} from '@/api/deps/index.js'
|
||||
import { useAuth } from '@/store/auth'
|
||||
const { userInfo } = useAuth()
|
||||
|
||||
export const useGroupTypeStore = createGlobalState(() => {
|
||||
const groupName = ref('')
|
||||
const groupActiveIndex = ref(-1) // 当前激活的分组索引
|
||||
@ -38,40 +34,6 @@ export const useGroupTypeStore = createGlobalState(() => {
|
||||
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) => {
|
||||
@ -89,7 +51,7 @@ export const useGroupTypeStore = createGlobalState(() => {
|
||||
}
|
||||
|
||||
const getDepMembers = async (param) => {
|
||||
const res = await userV2List2(param)
|
||||
const res = await userV2List(param)
|
||||
return res
|
||||
}
|
||||
|
||||
@ -162,7 +124,6 @@ export const useGroupTypeStore = createGlobalState(() => {
|
||||
postTreeList,
|
||||
departmentAllPositions,
|
||||
getDepsTreeMy,
|
||||
getDepsTreeMy2,
|
||||
getPositionByDepartment,
|
||||
getPositionsTree,
|
||||
crumbs,
|
||||
|
@ -15,10 +15,6 @@ import { useAuth } from '../auth/index'
|
||||
// let keyboardTimeout = null
|
||||
|
||||
export const useDialogueStore = defineStore('dialogue', {
|
||||
// 添加持久化配置
|
||||
persist: {
|
||||
paths: ['talk.talk_type', 'talk.receiver_id']
|
||||
},
|
||||
state: () => {
|
||||
return {
|
||||
// 对话索引(聊天对话的唯一索引)
|
||||
@ -52,15 +48,6 @@ export const useDialogueStore = defineStore('dialogue', {
|
||||
// 是否显示会话列表
|
||||
isShowSessionList: true,
|
||||
|
||||
//是否已被解散
|
||||
isDismiss: false,
|
||||
|
||||
//是否退群/移出群
|
||||
isQuit: false,
|
||||
|
||||
//未读消息数量
|
||||
unreadNum:0,
|
||||
|
||||
// 群成员列表
|
||||
members: [],
|
||||
|
||||
@ -97,21 +84,6 @@ export const useDialogueStore = defineStore('dialogue', {
|
||||
this.online = status
|
||||
},
|
||||
|
||||
// 更新未读消息数量-清空未读
|
||||
clearUnreadNum() {
|
||||
this.unreadNum = 0
|
||||
},
|
||||
|
||||
// 更新群解散状态
|
||||
updateDismiss() {
|
||||
this.isDismiss = true
|
||||
},
|
||||
|
||||
// 更新群成员退出状态
|
||||
updateQuit() {
|
||||
this.isQuit = true
|
||||
},
|
||||
|
||||
// 更新对话信息
|
||||
setDialogue(data = {}) {
|
||||
this.online = data.is_online == 1
|
||||
@ -126,13 +98,8 @@ export const useDialogueStore = defineStore('dialogue', {
|
||||
this.unreadBubble = 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 = []
|
||||
if (data.talk_type == 2 && !this.isDismiss && !this.isQuit) {
|
||||
if (data.talk_type == 2) {
|
||||
this.updateGroupMembers()
|
||||
}
|
||||
},
|
||||
@ -242,6 +209,8 @@ export const useDialogueStore = defineStore('dialogue', {
|
||||
if (res.code == 200) {
|
||||
this.batchDelDialogueRecord(msgIds)
|
||||
batchDelDialogueRecord(msgIds)
|
||||
} else {
|
||||
message.warning(res.message)
|
||||
}
|
||||
})
|
||||
},
|
||||
@ -265,6 +234,8 @@ export const useDialogueStore = defineStore('dialogue', {
|
||||
ServeRevokeRecords({ msg_id }).then((res) => {
|
||||
if (res.code == 200) {
|
||||
this.updateDialogueRecord({ msg_id, is_revoke: 1 })
|
||||
} else {
|
||||
message.warning(res.message)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
@ -7,105 +7,7 @@ import { createGlobalState, useStorage } from '@vueuse/core'
|
||||
import { uniStorage } from '@/utils/uniStorage.js'
|
||||
|
||||
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',
|
||||
},
|
||||
}
|
||||
document.addEventListener('plusready', () => {
|
||||
let OAWebView = plus.webview.all()
|
||||
OAWebView.forEach((webview, index) => {
|
||||
if (webview.id === 'webviewId1') {
|
||||
webview.evalJS(
|
||||
`operateSQLite('${encodeURIComponent(
|
||||
JSON.stringify(chatDatabase),
|
||||
)}')`,
|
||||
)
|
||||
webview.evalJS(
|
||||
`operateSQLite('${encodeURIComponent(
|
||||
JSON.stringify(chatDBexecuteSql),
|
||||
)}')`,
|
||||
)
|
||||
webview.evalJS(
|
||||
`operateSQLite('${encodeURIComponent(
|
||||
JSON.stringify(chatDBexecuteSql2),
|
||||
)}')`,
|
||||
)
|
||||
webview.evalJS(
|
||||
`operateSQLite('${encodeURIComponent(
|
||||
JSON.stringify(chatDBSelectSql),
|
||||
)}')`,
|
||||
)
|
||||
webview.evalJS(
|
||||
`operateSQLite('${encodeURIComponent(
|
||||
JSON.stringify(chatDBIsOpenDatabase),
|
||||
)}')`,
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
// testDatabase()
|
||||
|
||||
const dialogueList = useStorage('dialogueList', [], uniStorage)
|
||||
// const dialogueList = ref([])
|
||||
const zpagingRef = ref()
|
||||
const virtualList = ref([])
|
||||
|
||||
@ -116,49 +18,18 @@ export const useDialogueListStore = createGlobalState(() => {
|
||||
const addDialogueRecord = (newRecords, type = 'add') => {
|
||||
console.log(newRecords)
|
||||
|
||||
const dialogue = useDialogueStore()
|
||||
const dialogue = lodash.cloneDeep(useDialogueStore())
|
||||
if (!dialogue || typeof dialogue !== 'object') return
|
||||
// 检查是否已存在相同 index_name 的对话
|
||||
const existingIndex = dialogueList.value.findIndex(
|
||||
(item) => item.index_name === dialogue.index_name,
|
||||
)
|
||||
if (existingIndex === -1) {
|
||||
// 如果不存在,创建新对话,只保存需要的属性
|
||||
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)
|
||||
// 如果不存在,直接添加
|
||||
dialogueList.value.push(dialogue)
|
||||
} else {
|
||||
// 如果对话存在,处理 records 数组
|
||||
const { records = [] } = dialogue
|
||||
newRecords.forEach((newRecord) => {
|
||||
const recordIndex = dialogueList.value[existingIndex].records.findIndex(
|
||||
(record) => record.msg_id === newRecord.msg_id,
|
||||
@ -173,11 +44,18 @@ export const useDialogueListStore = createGlobalState(() => {
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 更新除 records 和 index_name 外的其他属性
|
||||
const { index_name, records: _, ...updateProps } = dialogue
|
||||
dialogueList.value[existingIndex] = {
|
||||
...dialogueList.value[existingIndex],
|
||||
...updateProps,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const updateDialogueRecord = (record) => {
|
||||
const dialogue = useDialogueStore()
|
||||
const dialogue = lodash.cloneDeep(useDialogueStore())
|
||||
const item = getDialogueList(dialogue.index_name)
|
||||
const recordIndex = item.records.findIndex(
|
||||
(item) => item.msg_id === record.msg_id,
|
||||
@ -200,7 +78,7 @@ export const useDialogueListStore = createGlobalState(() => {
|
||||
}
|
||||
|
||||
const deleteDialogueRecord = (record) => {
|
||||
const dialogue = useDialogueStore()
|
||||
const dialogue = lodash.cloneDeep(useDialogueStore())
|
||||
const item = getDialogueList(dialogue.index_name)
|
||||
const recordIndex = item.records.findIndex(
|
||||
(item) => item.msg_id === record.msg_id,
|
||||
@ -226,29 +104,14 @@ export const useDialogueListStore = createGlobalState(() => {
|
||||
}
|
||||
|
||||
const addChatRecord = (indexName, item) => {
|
||||
const dialogue = useDialogueStore()
|
||||
const dialogue = lodash.cloneDeep(useDialogueStore())
|
||||
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)
|
||||
}
|
||||
} else {
|
||||
zpagingRef.value?.addChatRecordData(item, false, false)
|
||||
}
|
||||
zpagingRef.value?.addChatRecordData(item, false, false)
|
||||
}
|
||||
}
|
||||
|
||||
const batchDelDialogueRecord = (msgIds) => {
|
||||
const dialogue = useDialogueStore()
|
||||
const dialogue = lodash.cloneDeep(useDialogueStore())
|
||||
const item = getDialogueList(dialogue.index_name)
|
||||
item.records = item.records.filter((item) => !msgIds.includes(item.msg_id))
|
||||
}
|
||||
@ -266,7 +129,7 @@ export const useDialogueListStore = createGlobalState(() => {
|
||||
|
||||
//清空聊天记录时,同时清空本地保存的聊天记录
|
||||
const clearDialogueRecord = () => {
|
||||
const dialogue = useDialogueStore()
|
||||
const dialogue = lodash.cloneDeep(useDialogueStore())
|
||||
const item = getDialogueList(dialogue.index_name)
|
||||
item.records = []
|
||||
virtualList.value = []
|
||||
|
@ -41,6 +41,8 @@ export const useEditorStore = defineStore('editor', {
|
||||
}).then((res) => {
|
||||
if (res.code == 200) {
|
||||
this.loadUserEmoticon()
|
||||
} else {
|
||||
message.warning(res.message)
|
||||
}
|
||||
})
|
||||
},
|
||||
@ -53,6 +55,8 @@ export const useEditorStore = defineStore('editor', {
|
||||
ServeUploadEmoticon(data).then((res) => {
|
||||
if (res.code == 200) {
|
||||
this.emoticon.items[1].children.unshift(res.data)
|
||||
} else {
|
||||
message.warning(res.message)
|
||||
}
|
||||
})
|
||||
},
|
||||
@ -65,7 +69,9 @@ export const useEditorStore = defineStore('editor', {
|
||||
if (res.code == 200) {
|
||||
this.emoticon.items[1].children.splice(resoure.index, 1)
|
||||
message.success('删除成功')
|
||||
}
|
||||
} else {
|
||||
message.warning(res.message)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -102,24 +102,6 @@ export const useTalkStore = defineStore('talk', {
|
||||
// 返回 Promise 对象,使调用方可以使用 then/catch
|
||||
return resp.then(({ code, data }) => {
|
||||
if (code == 200) {
|
||||
//向OA的webview通信,改变未读消息数量
|
||||
if (typeof plus !== 'undefined') {
|
||||
let OAWebView = plus.webview.all()
|
||||
OAWebView.forEach((webview) => {
|
||||
if (webview.id === 'webviewId1') {
|
||||
webview.evalJS(`doUpdateUnreadNum('${data.unread_num}')`)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
document.addEventListener('plusready', () => {
|
||||
let OAWebView = plus.webview.all()
|
||||
OAWebView.forEach((webview) => {
|
||||
if (webview.id === 'webviewId1') {
|
||||
webview.evalJS(`doUpdateUnreadNum('${data.unread_num}')`)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
this.items = data.items.map((item) => {
|
||||
const value = formatTalkItem(item)
|
||||
|
||||
@ -162,7 +144,6 @@ export const useTalkStore = defineStore('talk', {
|
||||
|
||||
ServeCreateTalkList({
|
||||
talk_type,
|
||||
receiver_id,
|
||||
erp_user_id,
|
||||
}).then(({ code, data, message }) => {
|
||||
if (code == 200) {
|
||||
|
@ -33,9 +33,7 @@ export const useUploadsStore = defineStore('uploads', {
|
||||
state: () => {
|
||||
return {
|
||||
isShow: false,
|
||||
items: [],
|
||||
isUploading: false,//当前是否正在上传
|
||||
uploadingNum: 0//当前正在上传数量
|
||||
items: []
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
@ -77,10 +75,8 @@ export const useUploadsStore = defineStore('uploads', {
|
||||
this.triggerUpload(upload_id,msgId)
|
||||
this.isShow = true
|
||||
} else {
|
||||
this.updateUploadStatus(false)
|
||||
message.error(res.message)
|
||||
}
|
||||
}).catch(()=> {
|
||||
this.updateUploadStatus(false)
|
||||
})
|
||||
},
|
||||
|
||||
@ -97,19 +93,7 @@ export const useUploadsStore = defineStore('uploads', {
|
||||
|
||||
item.status = 1
|
||||
|
||||
// 开始上传时就更新进度
|
||||
const currentPercentage = (item.uploadIndex / item.files.length) * 100
|
||||
item.percentage = currentPercentage.toFixed(1)
|
||||
updateUploadProgress(msgId, currentPercentage)
|
||||
|
||||
ServeFileSubareaUpload(form, (progressEvent) => {
|
||||
// 计算当前分片的进度
|
||||
const currentChunkProgress = (progressEvent.loaded / progressEvent.total) * 100
|
||||
// 计算总体进度:已完成分片 + 当前分片的进度
|
||||
const totalProgress = ((item.uploadIndex + currentChunkProgress / 100) / item.files.length) * 100
|
||||
item.percentage = totalProgress.toFixed(1)
|
||||
updateUploadProgress(msgId, totalProgress)
|
||||
})
|
||||
ServeFileSubareaUpload(form)
|
||||
.then((res) => {
|
||||
if (res.code == 200) {
|
||||
item.uploadIndex++
|
||||
@ -120,81 +104,32 @@ export const useUploadsStore = defineStore('uploads', {
|
||||
console.log(msgId,'msgId');
|
||||
|
||||
updateUploadProgress(msgId,100)
|
||||
this.sendUploadMessage(item, msgId)
|
||||
|
||||
// 更新虚拟列表中的状态
|
||||
const { virtualList } = useDialogueListStore()
|
||||
const index = virtualList.value.findIndex(item => item.file_num === msgId)
|
||||
if (index !== -1) {
|
||||
virtualList.value[index].uploadStatus = 2
|
||||
virtualList.value[index].uploadCurrent = 100
|
||||
}
|
||||
this.sendUploadMessage(item)
|
||||
} else {
|
||||
// 继续上传下一个分片
|
||||
this.triggerUpload(uploadId, msgId)
|
||||
const percentage = (item.uploadIndex / item.files.length) * 100
|
||||
item.percentage = percentage.toFixed(1)
|
||||
console.log(msgId,'msgId');
|
||||
console.log(percentage,'percentage');
|
||||
|
||||
updateUploadProgress(msgId,percentage)
|
||||
this.triggerUpload(uploadId,msgId)
|
||||
}
|
||||
} else {
|
||||
this.updateUploadStatus(false)
|
||||
item.status = 3
|
||||
// 更新虚拟列表中的状态为失败
|
||||
const { virtualList } = useDialogueListStore()
|
||||
const index = virtualList.value.findIndex(item => item.file_num === msgId)
|
||||
if (index !== -1) {
|
||||
virtualList.value[index].uploadStatus = 3
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.updateUploadStatus(false)
|
||||
item.status = 3
|
||||
// 更新虚拟列表中的状态为失败
|
||||
const { virtualList } = useDialogueListStore()
|
||||
const index = virtualList.value.findIndex(item => item.file_num === msgId)
|
||||
if (index !== -1) {
|
||||
virtualList.value[index].uploadStatus = 3
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 发送上传消息
|
||||
sendUploadMessage(item: any, file_num: String) {
|
||||
sendUploadMessage(item: any) {
|
||||
ServeSendTalkFile({
|
||||
upload_id: item.upload_id,
|
||||
receiver_id: item.receiver_id,
|
||||
talk_type: item.talk_type,
|
||||
file_num: file_num
|
||||
}).then((res) => {
|
||||
console.log(res, 'res')
|
||||
if(res.code == 200){
|
||||
this.updateUploadStatus(false)
|
||||
}else{
|
||||
this.updateUploadStatus(false)
|
||||
}
|
||||
}).catch(() => {
|
||||
this.updateUploadStatus(false)
|
||||
talk_type: item.talk_type
|
||||
})
|
||||
},
|
||||
|
||||
//更新资源上传状态
|
||||
updateUploadStatus(isUploading: boolean){
|
||||
if(isUploading){
|
||||
this.uploadingNum++
|
||||
this.isUploading = true
|
||||
}else{
|
||||
this.uploadingNum--
|
||||
if(this.uploadingNum < 0){
|
||||
this.uploadingNum = 0
|
||||
}
|
||||
if(this.uploadingNum === 0){
|
||||
this.isUploading = false
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 清除上传
|
||||
clearUpload(){
|
||||
this.isUploading = false
|
||||
this.uploadingNum = 0
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -1,19 +0,0 @@
|
||||
## 1.0.250331(2025-03-31)
|
||||
增加RecordApp.UniNativeUtsPlugin_OnJsCall接口,App端搭配原生插件使用时,可绑定接收配套原生录音插件事件:原生插件新增PcmPlayer播放器,支持流式播放、完整播放,App端边录音边播放更流畅
|
||||
## 1.0.250111(2025-01-11)
|
||||
修复vue3 Fragments(multi-root 多个根节点)的兼容性问题;修复uniapp Android自带的XXPermissions库在后台无法请求权限的问题(仅限搭配原生录音插件可用)
|
||||
## 1.0.241020(2024-10-20)
|
||||
适配HBuilder4.28 vue3 setup编译环境下$root.$scope无法读取的bug,HBuilder4.29已修复此编译bug,但似乎还是有不能使用的问题。如果setup内不能使用,可尝试新建个vue组件,然后使用选项式api来调用录音功能,页面的setup内使用此vue组件
|
||||
## 1.0.240910(2024-09-10)
|
||||
- 新增RecordApp.UniMainCallBack_Register接口,允许App renderjs层多次回调数据给逻辑层
|
||||
- iOS App请求权限时,会预先检查NSMicrophoneUsageDescription是否声明,避免无声明时调用录音会崩溃
|
||||
- 新增appNativePlugin_sampleRate原生插件录音选项
|
||||
- Android App已提供后台录音保活功能,启用后App在后台或锁屏后可继续正常录音
|
||||
## 1.0.240625(2024-06-25)
|
||||
调整UniWebViewCallAsync调用失败时返回更详细信息。android_audioSource默认值由1改成0,新增ios_categoryOptions原生插件录音选项
|
||||
## 1.0.240409(2024-04-09)
|
||||
增加功能调用,完善demo项目
|
||||
## 1.0.231208(2023-12-08)
|
||||
完善文档,增加asr语音识别示例
|
||||
## 1.0.231201(2023-12-04)
|
||||
第一次发布
|
@ -1,6 +0,0 @@
|
||||
<template>
|
||||
<view>
|
||||
<view style="font-weight: bold;">Recorder-UniCore Vue Component</view>
|
||||
<view style="font-size:14px; color:#f60">无需手动显示本UI组件,只需在script中正常引入 RecordApp + app-uni-support.js 即可实现 H5、iOS Android App、微信小程序 多端录音</view>
|
||||
</view>
|
||||
</template>
|
@ -1,495 +0,0 @@
|
||||
/*
|
||||
Recorder ../app-support-sample/demo_UniApp/uni_modules/Recorder-UniCore/i18n/Template.js
|
||||
https://github.com/xiangyuecn/Recorder
|
||||
|
||||
Usage: Recorder.i18n.lang="Your-Language-Name" or "your-language"
|
||||
|
||||
Desc: This file is a language translation template file. After copying and renaming, translate the text into the corresponding language. 此文件为语言翻译模板文件,复制并改名后,将文本翻译成对应语言即可。
|
||||
|
||||
注意:请勿修改//@@打头的文本行;以下代码结构由/src/package-i18n.js自动生成,只允许在字符串中填写翻译后的文本,请勿改变代码结构;翻译的文本如果需要明确的空值,请填写"=Empty";文本中的变量用{n}表示(n代表第几个变量),所有变量必须都出现至少一次,如果不要某变量用{n!}表示
|
||||
|
||||
Note: Do not modify the text lines starting with //@@; The following code structure is automatically generated by /src/package-i18n.js, only the translated text is allowed to be filled in the string, please do not change the code structure; If the translated text requires an explicit empty value, please fill in "=Empty"; Variables in the text are represented by {n} (n represents the number of variables), all variables must appear at least once, if a variable is not required, it is represented by {n!}
|
||||
*/
|
||||
(function(factory){
|
||||
var browser=typeof window=="object" && !!window.document;
|
||||
var win=browser?window:Object; //非浏览器环境,Recorder挂载在Object下面
|
||||
factory(win.Recorder,browser);
|
||||
}(function(Recorder,isBrowser){
|
||||
"use strict";
|
||||
var i18n=Recorder.i18n;
|
||||
|
||||
//@@User Code-1 Begin 手写代码放这里 Put the handwritten code here @@
|
||||
|
||||
//@@User Code-1 End @@
|
||||
|
||||
//@@Exec i18n.lang="Your-Language-Name";
|
||||
Recorder.CLog('Import Page[Recorder_UniCore] lang="Your-Language-Name"');
|
||||
|
||||
//@@Exec i18n.alias["Your-Language-Name"]="your-language";
|
||||
|
||||
var putSet={lang:"your-language"};
|
||||
|
||||
//@@Exec i18n.data["rtl$your-language"]=false;
|
||||
i18n.data["desc-page-Recorder_UniCore$your-language"]="This file is a language translation template file. After copying and renaming, translate the text into the corresponding language. 此文件为语言翻译模板文件,复制并改名后,将文本翻译成对应语言即可。";
|
||||
//@@Exec i18n.GenerateDisplayEnglish=true;
|
||||
|
||||
|
||||
|
||||
//*************** Begin srcFile=../app-support-sample/demo_UniApp/uni_modules/Recorder-UniCore/app-uni-support.js ***************
|
||||
i18n.put(putSet,
|
||||
[ //@@PutList
|
||||
|
||||
//@@zh="微信小程序中需要:{1}"
|
||||
//@@en="WeChat miniProgram requires: {1}"
|
||||
//@@Put0
|
||||
"RXs7:"+ //args: {1}
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="Recorder-UniCore目前只支持:H5、APP(Android iOS)、MP-WEIXIN,其他平台环境需要自行编写适配文件实现接入"
|
||||
//@@en="Recorder-UniCore currently only supports: H5, APP (Android iOS), MP-WEIXIN, other platform environments need to write their own adaptation files to achieve access"
|
||||
,"4ATo:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="RecordApp.UniWebViewActivate 需要传入当前页面或组件的this对象作为参数"
|
||||
//@@en="RecordApp.UniWebViewActivate needs to pass in the this object of the current page or component as a parameter"
|
||||
,"GwCz:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="RecordApp.UniWebViewActivate 发生不应该出现的错误(可能需要升级插件代码):"
|
||||
//@@en="An error occurred in RecordApp.UniWebViewActivate that should not occur (the plug-in code may need to be upgraded): "
|
||||
,"ipB3:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="RecordApp.UniWebViewActivate 已切换当前页面或组件的renderjs所在的WebView"
|
||||
//@@en="RecordApp.UniWebViewActivate has switched the WebView where the renderjs of the current page or component is located"
|
||||
,"WpKg:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="RecordApp.UniRenderjsRegister 发生不应该出现的错误(可能需要升级插件代码):"
|
||||
//@@en="An error occurred in RecordApp.UniRenderjsRegister that should not occur (the plugin code may need to be upgraded): "
|
||||
,"Uc9E:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="RecordApp.UniRenderjsRegister 重复注册当前页面renderjs模块,一个组件内只允许一个renderjs模块进行注册"
|
||||
//@@en="RecordApp.UniRenderjsRegister repeatedly registers the renderjs module of the current page. Only one renderjs module is allowed to be registered in a component"
|
||||
,"mzKj:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="RecordApp.UniRenderjsRegister 已注册当前页面renderjs模块"
|
||||
//@@en="RecordApp.UniRenderjsRegister has registered the renderjs module of the current page"
|
||||
,"7kJS:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="严重兼容性问题:无法获取页面或组件this.$root.$scope或.$page"
|
||||
//@@en="Serious compatibility issue: Unable to get page or component this.$root.$scope or .$page"
|
||||
,"KpY6:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="需要先调用RecordApp.UniWebViewActivate方法"
|
||||
//@@en="You need to call the RecordApp.UniWebViewActivate method first"
|
||||
,"AGd7:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="需先调用RecordApp.RequestPermission方法"
|
||||
//@@en="You need to call the RecordApp.RequestPermission method first"
|
||||
,"7ot0:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="需重新调用RecordApp.RequestPermission方法"
|
||||
//@@en="The RecordApp.RequestPermission method needs to be called again"
|
||||
,"VsdN:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="检测到有其他页面或组件调用了RecordApp.UniPageOnShow(WvCid={1}),但未调用过RecordApp.UniWebViewActivate(当前WvCid={2}),部分功能会继续使用之前Activate的WebView和组件,请确保这是符合你的业务逻辑,不是因为忘记了调用UniWebViewActivate"
|
||||
//@@en="It is detected that another page or component has called RecordApp.UniPageOnShow (WvCid={1}), but RecordApp.UniWebViewActivate (current WvCid={2}) has not been called. Some functions will continue to use the previously Activated WebView and components. Please make sure This is in line with your business logic, not because you forgot to call UniWebViewActivate"
|
||||
,"SWsy:"+ //args: {1}-{2}
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="{1}未正确查询到节点,将使用传入的当前页面或组件this的$el.parentNode作为组件根节点。如果template下存在多个根节点(vue3 multi-root),尽量在最外面再套一层view来避免兼容性问题"
|
||||
//@@en="{1} does not query the node correctly, and will use the current page or component this's $el.parentNode as the component root node. If there are multiple root nodes under the template (vue3 multi-root), try to add another layer of view on the outermost to avoid compatibility issues"
|
||||
,"dX7B:"+ //args: {1}
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="{1}需在renderjs中调用并且传入当前模块的this"
|
||||
//@@en="{1} needs to be called in renderjs and pass in this of the current module"
|
||||
,"dX5B:"+ //args: {1}
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="{1}需要传入当前页面或组件的this对象作为参数"
|
||||
//@@en="{1} needs to pass in the this object of the current page or component as a parameter"
|
||||
,"dX6B:"+ //args: {1}
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="当前不是App逻辑层"
|
||||
//@@en="Currently it is not the App logic layer"
|
||||
,"TfJX:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="当前还未调用过RecordApp.UniWebViewActivate"
|
||||
//@@en="RecordApp.UniWebViewActivate has not been called yet"
|
||||
,"peIm:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="未找到此页面renderjs所在的WebView"
|
||||
//@@en="The WebView where renderjs for this page is not found"
|
||||
,"qDo1:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh=",不可以调用RecordApp.UniWebViewEval"
|
||||
//@@en=", RecordApp.UniWebViewEval cannot be called"
|
||||
,"igw2:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="当前不是App逻辑层"
|
||||
//@@en="Currently it is not the App logic layer"
|
||||
,"lU1W:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="当前还未调用过RecordApp.UniWebViewActivate"
|
||||
//@@en="RecordApp.UniWebViewActivate has not been called yet"
|
||||
,"mSbR:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="未找到此页面renderjs所在的WebView Cid"
|
||||
//@@en="The WebView Cid where renderjs for this page is not found"
|
||||
,"6Iql:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh=",不可以调用RecordApp.UniWebViewVueCall"
|
||||
//@@en=", RecordApp.UniWebViewVueCall cannot be called"
|
||||
,"TtoS:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="renderjs中未import导入RecordApp"
|
||||
//@@en="RecordApp is not imported in renderjs"
|
||||
,"U1Be:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="renderjs中的mounted内需要调用RecordApp.UniRenderjsRegister"
|
||||
//@@en="RecordApp.UniRenderjsRegister needs to be called in mounted in renderjs"
|
||||
,"Bcgi:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="没有找到组件的renderjs模块"
|
||||
//@@en="The renderjs module for the component was not found"
|
||||
,"URyD:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="{1}连接renderjs超时"
|
||||
//@@en="{1} connection renderjs timeout"
|
||||
,"KQhJ:"+ //args: {1}
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="{1}处理超时"
|
||||
//@@en="{1} processing timeout"
|
||||
,"RDcZ:"+ //args: {1}
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="需要在页面中提供一个renderjs,在里面import导入RecordApp、录音格式编码器、可视化插件等"
|
||||
//@@en="You need to provide a renderjs in the page, and import RecordApp, recording format encoder, visualization plug-in, etc."
|
||||
,"TSmQ:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="需在renderjs中import {1}"
|
||||
//@@en="Need to import {1} in renderjs"
|
||||
,"AN0e:"+ //args: {1}
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="不应该出现的MainReceiveBind重复绑定"
|
||||
//@@en="MainReceiveBind duplicate binding that should not occur"
|
||||
,"vEgr:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="从renderjs发回数据但UniMainCallBack回调不存在:"
|
||||
//@@en="Sending data back from renderjs but UniMainCallBack callback does not exist: "
|
||||
,"kZx6:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="[MainReceive]从renderjs发回未知数据:"
|
||||
//@@en="[MainReceive] Unknown data sent back from renderjs: "
|
||||
,"ZHwv:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="只允许在renderjs中调用RecordApp.UniWebViewSendBigBytesToMain"
|
||||
//@@en="Only allowed to call RecordApp.UniWebViewSendBigBytesToMain in renderjs"
|
||||
,"MujG:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="renderjs中的mounted内需要调用RecordApp.UniRenderjsRegister才能调用RecordApp.UniWebViewSendBigBytesToMain"
|
||||
//@@en="RecordApp.UniRenderjsRegister needs to be called in mounted in renderjs to call RecordApp.UniWebViewSendBigBytesToMain"
|
||||
,"kE91:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="无效的BigBytes回传数据"
|
||||
//@@en="Invalid BigBytes return data"
|
||||
,"CjMb:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="保存文件{1}失败:"
|
||||
//@@en="Failed to save file {1}: "
|
||||
,"UqfI:"+ //args: {1}
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="当前环境未支持保存本地文件"
|
||||
//@@en="The current environment does not support saving local files"
|
||||
,"kxOd:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh=" | RecordApp的uni-app支持文档和示例:{1} "
|
||||
//@@en=" | RecordApp’s uni-app support documentation and examples: {1}"
|
||||
,"1f2V:"+ //args: {1}
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="当前录音由原生录音插件提供支持"
|
||||
//@@en="Current recording is powered by native recording plug-in"
|
||||
,"XSYY:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="当前录音由uts插件提供支持"
|
||||
//@@en="Current recording is powered by uts plugin"
|
||||
,"nnM6:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="当前已配置RecordApp.UniWithoutAppRenderjs,必须提供原生录音插件或uts插件才能录音,请参考RecordApp.UniNativeUtsPlugin配置"
|
||||
//@@en="RecordApp.UniWithoutAppRenderjs is currently configured. A native recording plug-in or uts plug-in must be provided to record. Please refer to the RecordApp.UniNativeUtsPlugin configuration"
|
||||
,"fqhr:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="当前RecordApp运行在逻辑层中(性能会略低一些,可视化等插件不可用)"
|
||||
//@@en="Currently RecordApp runs in the logical layer (performance will be slightly lower, and plug-ins such as visualization are not available) "
|
||||
,"xYRb:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="未找到当前页面renderjs所在的WebView"
|
||||
//@@en="The WebView where renderjs of the current page is located is not found"
|
||||
,"S3eF:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="当前RecordApp运行在renderjs所在的WebView中(逻辑层中只能做有限的实时处理,可视化等插件均需要在renderjs中进行调用)"
|
||||
//@@en="The current RecordApp runs in the WebView where renderjs is located (only limited real-time processing can be done in the logic layer, and visualization and other plug-ins need to be called in renderjs) "
|
||||
,"0hyi:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh=",请检查此页面代码中是否编写了lang=renderjs的module,并且调用了RecordApp.UniRenderjsRegister;如果确实没有renderjs,比如nvue页面,请设置RecordApp.UniWithoutAppRenderjs=true并且搭配配套的原生插件在逻辑层中直接录音"
|
||||
//@@en=", please check whether the module with lang=renderjs is written in the code of this page and RecordApp.UniRenderjsRegister is called; if there is indeed no renderjs, such as nvue page, please set RecordApp.UniWithoutAppRenderjs=true and use the matching native plug-in to record directly in the logic layer"
|
||||
,"e6Mo:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="【在App内使用{1}的授权许可】"
|
||||
//@@en="[License for use of {1} within the App] "
|
||||
,"FabE:"+ //args: {1}
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="已购买原生录音插件,获得授权许可"
|
||||
//@@en="Purchased the native recording plug-in and obtained the license"
|
||||
,"w37G:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="已购买uts插件,获得授权许可"
|
||||
//@@en="Purchased uts plug-in and obtained license"
|
||||
,"e71S:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="UniAppUseLicense填写无效,如果已获取到了商用授权,请填写:{1},否则请使用空字符串"
|
||||
//@@en="UniAppUseLicense is invalid. If you have obtained a commercial license, please fill in: {1}, otherwise please use an empty string"
|
||||
,"aPoj:"+ //args: {1}
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="未找到Canvas:{1},请确保此DOM已挂载(可尝试用$nextTick等待DOM更新)"
|
||||
//@@en="Canvas not found: {1}, please make sure this DOM is mounted (try $nextTick to wait for DOM update) "
|
||||
,"k7im:"+ //args: {1}
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="RecordApp.UniFindCanvas未适配当前环境"
|
||||
//@@en="RecordApp.UniFindCanvas does not adapt to the current environment"
|
||||
,"yI24:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="未配置RecordApp.UniNativeUtsPlugin原生录音插件"
|
||||
//@@en="RecordApp.UniNativeUtsPlugin native recording plug-in is not configured"
|
||||
,"H753:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="renderjs中不支持设置RecordApp.UniNativeUtsPlugin"
|
||||
//@@en="Setting RecordApp.UniNativeUtsPlugin is not supported in renderjs"
|
||||
,"l6sY:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="当前App未打包进双端原生插件[{1}],尝试加载单端[{2}]"
|
||||
//@@en="The current App is not packaged into the dual-end native plug-in [{1}], try to load the single-end [{2}]"
|
||||
,"kSjQ:"+ //args: {1}-{2}
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="已加载原生录音插件[{1}]"
|
||||
//@@en="Native recording plugin loaded [{1}]"
|
||||
,"Xh1W:"+ //args: {1}
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="配置了RecordApp.UniNativeUtsPlugin,但当前App未打包进原生录音插件[{1}]"
|
||||
//@@en="RecordApp.UniNativeUtsPlugin is configured, but the current App is not packaged with the native recording plug-in [{1}]"
|
||||
,"SCW9:"+ //args: {1}
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="提供的RecordApp.UniNativeUtsPlugin值不是RecordApp的uts原生录音插件"
|
||||
//@@en="The provided RecordApp.UniNativeUtsPlugin value is not RecordApp’s uts native recording plug-in"
|
||||
,"TGMm:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="需在App逻辑层中调用原生插件功能"
|
||||
//@@en="The native plug-in function needs to be called in the App logic layer"
|
||||
,"MrBx:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="未开始录音,不可以调用{1}"
|
||||
//@@en="Recording has not started and {1} cannot be called"
|
||||
,"0FGq:"+ //args: {1}
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="需先调用RecordApp.UniWebViewActivate,然后才可以调用RequestPermission"
|
||||
//@@en="RecordApp.UniWebViewActivate needs to be called first, and then RequestPermission can be called"
|
||||
,"PkQ2:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="不应当出现的非H5权限请求"
|
||||
//@@en="Non-H5 permission requests that should not appear"
|
||||
,"Jk72:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="正在调用plus.ios@AVAudioSession请求iOS原生录音权限"
|
||||
//@@en="Calling plus.ios@AVAudioSession to request iOS native recording permissions"
|
||||
,"Y3rC:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="项目配置中未声明iOS录音权限{1}"
|
||||
//@@en="iOS recording permission {1} is not declared in the project configuration"
|
||||
,"9xoE:"+ //args: {1}
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="已获得iOS原生录音权限"
|
||||
//@@en="Obtained iOS native recording permissions"
|
||||
,"j15C:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="plus.ios请求录音权限,状态值: "
|
||||
//@@en="plus.ios requests recording permission, status value: "
|
||||
,"iKhe:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="正在调用plus.android.requestPermissions请求Android原生录音权限"
|
||||
//@@en="Calling plus.android.requestPermissions to request Android native recording permissions"
|
||||
,"7Noe:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="已获得Android原生录音权限:"
|
||||
//@@en="Obtained Android native recording permission: "
|
||||
,"Bgls:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="plus.android请求录音权限:无权限"
|
||||
//@@en="plus.android requests recording permission: No permission"
|
||||
,"Ruxl:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="plus.android请求录音权限出错:"
|
||||
//@@en="plus.android error in requesting recording permission: "
|
||||
,"0JQw:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="调用plus的权限请求出错:"
|
||||
//@@en="An error occurred in the permission request to call plus: "
|
||||
,"Mvl7:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="用户拒绝了录音权限"
|
||||
//@@en="User denied recording permission"
|
||||
,"0caE:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="正在调用原生插件请求录音权限"
|
||||
//@@en="Calling the native plug-in to request recording permission"
|
||||
,"Lx5r:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="已获得录音权限"
|
||||
//@@en="Recording permission obtained"
|
||||
,"Lx6r:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="无录音权限"
|
||||
//@@en="No recording permission"
|
||||
,"Lx7r:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="无法调用RequestPermission:"
|
||||
//@@en="Unable to call RequestPermission: "
|
||||
,"ksoA:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="无法连接到renderjs"
|
||||
//@@en="Unable to connect to renderjs"
|
||||
,"KnF0:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="需先调用RecordApp.UniWebViewActivate,然后才可以调用Start"
|
||||
//@@en="RecordApp.UniWebViewActivate needs to be called first, and then Start can be called"
|
||||
,"XCMU:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="不应当出现的非H5录音Start"
|
||||
//@@en="Start of non-H5 recordings that should not appear"
|
||||
,"rSLO:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="无法调用Start:"
|
||||
//@@en="Unable to call Start: "
|
||||
,"Bjx9:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="未开始录音,但收到renderjs回传的onRecEncodeChunk"
|
||||
//@@en="Recording did not start, but onRecEncodeChunk returned by renderjs was received"
|
||||
,"MTdp:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="未开始录音,但收到Uni Native PCM数据"
|
||||
//@@en="Recording did not start, but Uni Native PCM data was received"
|
||||
,"BjGP:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="未开始录音,但收到UniNativeUtsPlugin PCM数据"
|
||||
//@@en="Recording did not start, but UniNativeUtsPlugin PCM data was received"
|
||||
,"byzO:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="未开始录音"
|
||||
//@@en="Recording not started"
|
||||
,"YP4V:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="不应当出现的非H5录音Stop"
|
||||
//@@en="Stop non-H5 recordings that should not appear"
|
||||
,"TPhg:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="未开始录音"
|
||||
//@@en="Recording not started"
|
||||
,"pP4O:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="无法调用Stop:"
|
||||
//@@en="Unable to call Stop: "
|
||||
,"H6cq:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
//@@zh="不应该出现的renderjs发回的文件数据丢失"
|
||||
//@@en="The file data sent back by renderjs should not be lost"
|
||||
,"gomD:"+ //no args
|
||||
"" /** TODO: translate to your-language **/
|
||||
|
||||
]);
|
||||
//*************** End srcFile=../app-support-sample/demo_UniApp/uni_modules/Recorder-UniCore/app-uni-support.js ***************
|
||||
|
||||
//@@User Code-2 Begin 手写代码放这里 Put the handwritten code here @@
|
||||
|
||||
//@@User Code-2 End @@
|
||||
|
||||
}));
|
@ -1,406 +0,0 @@
|
||||
/*
|
||||
Recorder ../app-support-sample/demo_UniApp/uni_modules/Recorder-UniCore/i18n/en-US.js
|
||||
https://github.com/xiangyuecn/Recorder
|
||||
|
||||
Usage: Recorder.i18n.lang="en-US" or "en"
|
||||
|
||||
Desc: English, 英语。This translation mainly comes from: google translation + Baidu translation, translated from Chinese to English. 此翻译主要来自:google翻译+百度翻译,由中文翻译成英文。
|
||||
|
||||
注意:请勿修改//@@打头的文本行;以下代码结构由/src/package-i18n.js自动生成,只允许在字符串中填写翻译后的文本,请勿改变代码结构;翻译的文本如果需要明确的空值,请填写"=Empty";文本中的变量用{n}表示(n代表第几个变量),所有变量必须都出现至少一次,如果不要某变量用{n!}表示
|
||||
|
||||
Note: Do not modify the text lines starting with //@@; The following code structure is automatically generated by /src/package-i18n.js, only the translated text is allowed to be filled in the string, please do not change the code structure; If the translated text requires an explicit empty value, please fill in "=Empty"; Variables in the text are represented by {n} (n represents the number of variables), all variables must appear at least once, if a variable is not required, it is represented by {n!}
|
||||
*/
|
||||
(function(factory){
|
||||
var browser=typeof window=="object" && !!window.document;
|
||||
var win=browser?window:Object; //非浏览器环境,Recorder挂载在Object下面
|
||||
factory(win.Recorder,browser);
|
||||
}(function(Recorder,isBrowser){
|
||||
"use strict";
|
||||
var i18n=Recorder.i18n;
|
||||
|
||||
//@@User Code-1 Begin 手写代码放这里 Put the handwritten code here @@
|
||||
|
||||
//@@User Code-1 End @@
|
||||
|
||||
//@@Exec i18n.lang="en-US";
|
||||
Recorder.CLog('Import Page[Recorder_UniCore] lang="en-US"');
|
||||
|
||||
//@@Exec i18n.alias["en-US"]="en";
|
||||
|
||||
var putSet={lang:"en"};
|
||||
|
||||
//@@Exec i18n.data["rtl$en"]=false;
|
||||
i18n.data["desc-page-Recorder_UniCore$en"]="English, 英语。This translation mainly comes from: google translation + Baidu translation, translated from Chinese to English. 此翻译主要来自:google翻译+百度翻译,由中文翻译成英文。";
|
||||
//@@Exec i18n.GenerateDisplayEnglish=false;
|
||||
|
||||
|
||||
|
||||
//*************** Begin srcFile=../app-support-sample/demo_UniApp/uni_modules/Recorder-UniCore/app-uni-support.js ***************
|
||||
i18n.put(putSet,
|
||||
[ //@@PutList
|
||||
|
||||
//@@zh="微信小程序中需要:{1}"
|
||||
//@@Put0
|
||||
"RXs7:"+ //args: {1}
|
||||
"WeChat miniProgram requires: {1}"
|
||||
|
||||
//@@zh="Recorder-UniCore目前只支持:H5、APP(Android iOS)、MP-WEIXIN,其他平台环境需要自行编写适配文件实现接入"
|
||||
,"4ATo:"+ //no args
|
||||
"Recorder-UniCore currently only supports: H5, APP (Android iOS), MP-WEIXIN, other platform environments need to write their own adaptation files to achieve access"
|
||||
|
||||
//@@zh="RecordApp.UniWebViewActivate 需要传入当前页面或组件的this对象作为参数"
|
||||
,"GwCz:"+ //no args
|
||||
"RecordApp.UniWebViewActivate needs to pass in the this object of the current page or component as a parameter"
|
||||
|
||||
//@@zh="RecordApp.UniWebViewActivate 发生不应该出现的错误(可能需要升级插件代码):"
|
||||
,"ipB3:"+ //no args
|
||||
"An error occurred in RecordApp.UniWebViewActivate that should not occur (the plug-in code may need to be upgraded): "
|
||||
|
||||
//@@zh="RecordApp.UniWebViewActivate 已切换当前页面或组件的renderjs所在的WebView"
|
||||
,"WpKg:"+ //no args
|
||||
"RecordApp.UniWebViewActivate has switched the WebView where the renderjs of the current page or component is located"
|
||||
|
||||
//@@zh="RecordApp.UniRenderjsRegister 发生不应该出现的错误(可能需要升级插件代码):"
|
||||
,"Uc9E:"+ //no args
|
||||
"An error occurred in RecordApp.UniRenderjsRegister that should not occur (the plugin code may need to be upgraded): "
|
||||
|
||||
//@@zh="RecordApp.UniRenderjsRegister 重复注册当前页面renderjs模块,一个组件内只允许一个renderjs模块进行注册"
|
||||
,"mzKj:"+ //no args
|
||||
"RecordApp.UniRenderjsRegister repeatedly registers the renderjs module of the current page. Only one renderjs module is allowed to be registered in a component"
|
||||
|
||||
//@@zh="RecordApp.UniRenderjsRegister 已注册当前页面renderjs模块"
|
||||
,"7kJS:"+ //no args
|
||||
"RecordApp.UniRenderjsRegister has registered the renderjs module of the current page"
|
||||
|
||||
//@@zh="严重兼容性问题:无法获取页面或组件this.$root.$scope或.$page"
|
||||
,"KpY6:"+ //no args
|
||||
"Serious compatibility issue: Unable to get page or component this.$root.$scope or .$page"
|
||||
|
||||
//@@zh="需要先调用RecordApp.UniWebViewActivate方法"
|
||||
,"AGd7:"+ //no args
|
||||
"You need to call the RecordApp.UniWebViewActivate method first"
|
||||
|
||||
//@@zh="需先调用RecordApp.RequestPermission方法"
|
||||
,"7ot0:"+ //no args
|
||||
"You need to call the RecordApp.RequestPermission method first"
|
||||
|
||||
//@@zh="需重新调用RecordApp.RequestPermission方法"
|
||||
,"VsdN:"+ //no args
|
||||
"The RecordApp.RequestPermission method needs to be called again"
|
||||
|
||||
//@@zh="检测到有其他页面或组件调用了RecordApp.UniPageOnShow(WvCid={1}),但未调用过RecordApp.UniWebViewActivate(当前WvCid={2}),部分功能会继续使用之前Activate的WebView和组件,请确保这是符合你的业务逻辑,不是因为忘记了调用UniWebViewActivate"
|
||||
,"SWsy:"+ //args: {1}-{2}
|
||||
"It is detected that another page or component has called RecordApp.UniPageOnShow (WvCid={1}), but RecordApp.UniWebViewActivate (current WvCid={2}) has not been called. Some functions will continue to use the previously Activated WebView and components. Please make sure This is in line with your business logic, not because you forgot to call UniWebViewActivate"
|
||||
|
||||
//@@zh="{1}未正确查询到节点,将使用传入的当前页面或组件this的$el.parentNode作为组件根节点。如果template下存在多个根节点(vue3 multi-root),尽量在最外面再套一层view来避免兼容性问题"
|
||||
,"dX7B:"+ //args: {1}
|
||||
"{1} does not query the node correctly, and will use the current page or component this's $el.parentNode as the component root node. If there are multiple root nodes under the template (vue3 multi-root), try to add another layer of view on the outermost to avoid compatibility issues"
|
||||
|
||||
//@@zh="{1}需在renderjs中调用并且传入当前模块的this"
|
||||
,"dX5B:"+ //args: {1}
|
||||
"{1} needs to be called in renderjs and pass in this of the current module"
|
||||
|
||||
//@@zh="{1}需要传入当前页面或组件的this对象作为参数"
|
||||
,"dX6B:"+ //args: {1}
|
||||
"{1} needs to pass in the this object of the current page or component as a parameter"
|
||||
|
||||
//@@zh="当前不是App逻辑层"
|
||||
,"TfJX:"+ //no args
|
||||
"Currently it is not the App logic layer"
|
||||
|
||||
//@@zh="当前还未调用过RecordApp.UniWebViewActivate"
|
||||
,"peIm:"+ //no args
|
||||
"RecordApp.UniWebViewActivate has not been called yet"
|
||||
|
||||
//@@zh="未找到此页面renderjs所在的WebView"
|
||||
,"qDo1:"+ //no args
|
||||
"The WebView where renderjs for this page is not found"
|
||||
|
||||
//@@zh=",不可以调用RecordApp.UniWebViewEval"
|
||||
,"igw2:"+ //no args
|
||||
", RecordApp.UniWebViewEval cannot be called"
|
||||
|
||||
//@@zh="当前不是App逻辑层"
|
||||
,"lU1W:"+ //no args
|
||||
"Currently it is not the App logic layer"
|
||||
|
||||
//@@zh="当前还未调用过RecordApp.UniWebViewActivate"
|
||||
,"mSbR:"+ //no args
|
||||
"RecordApp.UniWebViewActivate has not been called yet"
|
||||
|
||||
//@@zh="未找到此页面renderjs所在的WebView Cid"
|
||||
,"6Iql:"+ //no args
|
||||
"The WebView Cid where renderjs for this page is not found"
|
||||
|
||||
//@@zh=",不可以调用RecordApp.UniWebViewVueCall"
|
||||
,"TtoS:"+ //no args
|
||||
", RecordApp.UniWebViewVueCall cannot be called"
|
||||
|
||||
//@@zh="renderjs中未import导入RecordApp"
|
||||
,"U1Be:"+ //no args
|
||||
"RecordApp is not imported in renderjs"
|
||||
|
||||
//@@zh="renderjs中的mounted内需要调用RecordApp.UniRenderjsRegister"
|
||||
,"Bcgi:"+ //no args
|
||||
"RecordApp.UniRenderjsRegister needs to be called in mounted in renderjs"
|
||||
|
||||
//@@zh="没有找到组件的renderjs模块"
|
||||
,"URyD:"+ //no args
|
||||
"The renderjs module for the component was not found"
|
||||
|
||||
//@@zh="{1}连接renderjs超时"
|
||||
,"KQhJ:"+ //args: {1}
|
||||
"{1} connection renderjs timeout"
|
||||
|
||||
//@@zh="{1}处理超时"
|
||||
,"RDcZ:"+ //args: {1}
|
||||
"{1} processing timeout"
|
||||
|
||||
//@@zh="需要在页面中提供一个renderjs,在里面import导入RecordApp、录音格式编码器、可视化插件等"
|
||||
,"TSmQ:"+ //no args
|
||||
"You need to provide a renderjs in the page, and import RecordApp, recording format encoder, visualization plug-in, etc."
|
||||
|
||||
//@@zh="需在renderjs中import {1}"
|
||||
,"AN0e:"+ //args: {1}
|
||||
"Need to import {1} in renderjs"
|
||||
|
||||
//@@zh="不应该出现的MainReceiveBind重复绑定"
|
||||
,"vEgr:"+ //no args
|
||||
"MainReceiveBind duplicate binding that should not occur"
|
||||
|
||||
//@@zh="从renderjs发回数据但UniMainCallBack回调不存在:"
|
||||
,"kZx6:"+ //no args
|
||||
"Sending data back from renderjs but UniMainCallBack callback does not exist: "
|
||||
|
||||
//@@zh="[MainReceive]从renderjs发回未知数据:"
|
||||
,"ZHwv:"+ //no args
|
||||
"[MainReceive] Unknown data sent back from renderjs: "
|
||||
|
||||
//@@zh="只允许在renderjs中调用RecordApp.UniWebViewSendBigBytesToMain"
|
||||
,"MujG:"+ //no args
|
||||
"Only allowed to call RecordApp.UniWebViewSendBigBytesToMain in renderjs"
|
||||
|
||||
//@@zh="renderjs中的mounted内需要调用RecordApp.UniRenderjsRegister才能调用RecordApp.UniWebViewSendBigBytesToMain"
|
||||
,"kE91:"+ //no args
|
||||
"RecordApp.UniRenderjsRegister needs to be called in mounted in renderjs to call RecordApp.UniWebViewSendBigBytesToMain"
|
||||
|
||||
//@@zh="无效的BigBytes回传数据"
|
||||
,"CjMb:"+ //no args
|
||||
"Invalid BigBytes return data"
|
||||
|
||||
//@@zh="保存文件{1}失败:"
|
||||
,"UqfI:"+ //args: {1}
|
||||
"Failed to save file {1}: "
|
||||
|
||||
//@@zh="当前环境未支持保存本地文件"
|
||||
,"kxOd:"+ //no args
|
||||
"The current environment does not support saving local files"
|
||||
|
||||
//@@zh=" | RecordApp的uni-app支持文档和示例:{1} "
|
||||
,"1f2V:"+ //args: {1}
|
||||
" | RecordApp’s uni-app support documentation and examples: {1}"
|
||||
|
||||
//@@zh="当前录音由原生录音插件提供支持"
|
||||
,"XSYY:"+ //no args
|
||||
"Current recording is powered by native recording plug-in"
|
||||
|
||||
//@@zh="当前录音由uts插件提供支持"
|
||||
,"nnM6:"+ //no args
|
||||
"Current recording is powered by uts plugin"
|
||||
|
||||
//@@zh="当前已配置RecordApp.UniWithoutAppRenderjs,必须提供原生录音插件或uts插件才能录音,请参考RecordApp.UniNativeUtsPlugin配置"
|
||||
,"fqhr:"+ //no args
|
||||
"RecordApp.UniWithoutAppRenderjs is currently configured. A native recording plug-in or uts plug-in must be provided to record. Please refer to the RecordApp.UniNativeUtsPlugin configuration"
|
||||
|
||||
//@@zh="当前RecordApp运行在逻辑层中(性能会略低一些,可视化等插件不可用)"
|
||||
,"xYRb:"+ //no args
|
||||
"Currently RecordApp runs in the logical layer (performance will be slightly lower, and plug-ins such as visualization are not available) "
|
||||
|
||||
//@@zh="未找到当前页面renderjs所在的WebView"
|
||||
,"S3eF:"+ //no args
|
||||
"The WebView where renderjs of the current page is located is not found"
|
||||
|
||||
//@@zh="当前RecordApp运行在renderjs所在的WebView中(逻辑层中只能做有限的实时处理,可视化等插件均需要在renderjs中进行调用)"
|
||||
,"0hyi:"+ //no args
|
||||
"The current RecordApp runs in the WebView where renderjs is located (only limited real-time processing can be done in the logic layer, and visualization and other plug-ins need to be called in renderjs) "
|
||||
|
||||
//@@zh=",请检查此页面代码中是否编写了lang=renderjs的module,并且调用了RecordApp.UniRenderjsRegister;如果确实没有renderjs,比如nvue页面,请设置RecordApp.UniWithoutAppRenderjs=true并且搭配配套的原生插件在逻辑层中直接录音"
|
||||
,"e6Mo:"+ //no args
|
||||
", please check whether the module with lang=renderjs is written in the code of this page and RecordApp.UniRenderjsRegister is called; if there is indeed no renderjs, such as nvue page, please set RecordApp.UniWithoutAppRenderjs=true and use the matching native plug-in to record directly in the logic layer"
|
||||
|
||||
//@@zh="【在App内使用{1}的授权许可】"
|
||||
,"FabE:"+ //args: {1}
|
||||
"[License for use of {1} within the App] "
|
||||
|
||||
//@@zh="已购买原生录音插件,获得授权许可"
|
||||
,"w37G:"+ //no args
|
||||
"Purchased the native recording plug-in and obtained the license"
|
||||
|
||||
//@@zh="已购买uts插件,获得授权许可"
|
||||
,"e71S:"+ //no args
|
||||
"Purchased uts plug-in and obtained license"
|
||||
|
||||
//@@zh="UniAppUseLicense填写无效,如果已获取到了商用授权,请填写:{1},否则请使用空字符串"
|
||||
,"aPoj:"+ //args: {1}
|
||||
"UniAppUseLicense is invalid. If you have obtained a commercial license, please fill in: {1}, otherwise please use an empty string"
|
||||
|
||||
//@@zh="未找到Canvas:{1},请确保此DOM已挂载(可尝试用$nextTick等待DOM更新)"
|
||||
,"k7im:"+ //args: {1}
|
||||
"Canvas not found: {1}, please make sure this DOM is mounted (try $nextTick to wait for DOM update) "
|
||||
|
||||
//@@zh="RecordApp.UniFindCanvas未适配当前环境"
|
||||
,"yI24:"+ //no args
|
||||
"RecordApp.UniFindCanvas does not adapt to the current environment"
|
||||
|
||||
//@@zh="未配置RecordApp.UniNativeUtsPlugin原生录音插件"
|
||||
,"H753:"+ //no args
|
||||
"RecordApp.UniNativeUtsPlugin native recording plug-in is not configured"
|
||||
|
||||
//@@zh="renderjs中不支持设置RecordApp.UniNativeUtsPlugin"
|
||||
,"l6sY:"+ //no args
|
||||
"Setting RecordApp.UniNativeUtsPlugin is not supported in renderjs"
|
||||
|
||||
//@@zh="当前App未打包进双端原生插件[{1}],尝试加载单端[{2}]"
|
||||
,"kSjQ:"+ //args: {1}-{2}
|
||||
"The current App is not packaged into the dual-end native plug-in [{1}], try to load the single-end [{2}]"
|
||||
|
||||
//@@zh="已加载原生录音插件[{1}]"
|
||||
,"Xh1W:"+ //args: {1}
|
||||
"Native recording plugin loaded [{1}]"
|
||||
|
||||
//@@zh="配置了RecordApp.UniNativeUtsPlugin,但当前App未打包进原生录音插件[{1}]"
|
||||
,"SCW9:"+ //args: {1}
|
||||
"RecordApp.UniNativeUtsPlugin is configured, but the current App is not packaged with the native recording plug-in [{1}]"
|
||||
|
||||
//@@zh="提供的RecordApp.UniNativeUtsPlugin值不是RecordApp的uts原生录音插件"
|
||||
,"TGMm:"+ //no args
|
||||
"The provided RecordApp.UniNativeUtsPlugin value is not RecordApp’s uts native recording plug-in"
|
||||
|
||||
//@@zh="需在App逻辑层中调用原生插件功能"
|
||||
,"MrBx:"+ //no args
|
||||
"The native plug-in function needs to be called in the App logic layer"
|
||||
|
||||
//@@zh="未开始录音,不可以调用{1}"
|
||||
,"0FGq:"+ //args: {1}
|
||||
"Recording has not started and {1} cannot be called"
|
||||
|
||||
//@@zh="需先调用RecordApp.UniWebViewActivate,然后才可以调用RequestPermission"
|
||||
,"PkQ2:"+ //no args
|
||||
"RecordApp.UniWebViewActivate needs to be called first, and then RequestPermission can be called"
|
||||
|
||||
//@@zh="不应当出现的非H5权限请求"
|
||||
,"Jk72:"+ //no args
|
||||
"Non-H5 permission requests that should not appear"
|
||||
|
||||
//@@zh="正在调用plus.ios@AVAudioSession请求iOS原生录音权限"
|
||||
,"Y3rC:"+ //no args
|
||||
"Calling plus.ios@AVAudioSession to request iOS native recording permissions"
|
||||
|
||||
//@@zh="项目配置中未声明iOS录音权限{1}"
|
||||
,"9xoE:"+ //args: {1}
|
||||
"iOS recording permission {1} is not declared in the project configuration"
|
||||
|
||||
//@@zh="已获得iOS原生录音权限"
|
||||
,"j15C:"+ //no args
|
||||
"Obtained iOS native recording permissions"
|
||||
|
||||
//@@zh="plus.ios请求录音权限,状态值: "
|
||||
,"iKhe:"+ //no args
|
||||
"plus.ios requests recording permission, status value: "
|
||||
|
||||
//@@zh="正在调用plus.android.requestPermissions请求Android原生录音权限"
|
||||
,"7Noe:"+ //no args
|
||||
"Calling plus.android.requestPermissions to request Android native recording permissions"
|
||||
|
||||
//@@zh="已获得Android原生录音权限:"
|
||||
,"Bgls:"+ //no args
|
||||
"Obtained Android native recording permission: "
|
||||
|
||||
//@@zh="plus.android请求录音权限:无权限"
|
||||
,"Ruxl:"+ //no args
|
||||
"plus.android requests recording permission: No permission"
|
||||
|
||||
//@@zh="plus.android请求录音权限出错:"
|
||||
,"0JQw:"+ //no args
|
||||
"plus.android error in requesting recording permission: "
|
||||
|
||||
//@@zh="调用plus的权限请求出错:"
|
||||
,"Mvl7:"+ //no args
|
||||
"An error occurred in the permission request to call plus: "
|
||||
|
||||
//@@zh="用户拒绝了录音权限"
|
||||
,"0caE:"+ //no args
|
||||
"User denied recording permission"
|
||||
|
||||
//@@zh="正在调用原生插件请求录音权限"
|
||||
,"Lx5r:"+ //no args
|
||||
"Calling the native plug-in to request recording permission"
|
||||
|
||||
//@@zh="已获得录音权限"
|
||||
,"Lx6r:"+ //no args
|
||||
"Recording permission obtained"
|
||||
|
||||
//@@zh="无录音权限"
|
||||
,"Lx7r:"+ //no args
|
||||
"No recording permission"
|
||||
|
||||
//@@zh="无法调用RequestPermission:"
|
||||
,"ksoA:"+ //no args
|
||||
"Unable to call RequestPermission: "
|
||||
|
||||
//@@zh="无法连接到renderjs"
|
||||
,"KnF0:"+ //no args
|
||||
"Unable to connect to renderjs"
|
||||
|
||||
//@@zh="需先调用RecordApp.UniWebViewActivate,然后才可以调用Start"
|
||||
,"XCMU:"+ //no args
|
||||
"RecordApp.UniWebViewActivate needs to be called first, and then Start can be called"
|
||||
|
||||
//@@zh="不应当出现的非H5录音Start"
|
||||
,"rSLO:"+ //no args
|
||||
"Start of non-H5 recordings that should not appear"
|
||||
|
||||
//@@zh="无法调用Start:"
|
||||
,"Bjx9:"+ //no args
|
||||
"Unable to call Start: "
|
||||
|
||||
//@@zh="未开始录音,但收到renderjs回传的onRecEncodeChunk"
|
||||
,"MTdp:"+ //no args
|
||||
"Recording did not start, but onRecEncodeChunk returned by renderjs was received"
|
||||
|
||||
//@@zh="未开始录音,但收到Uni Native PCM数据"
|
||||
,"BjGP:"+ //no args
|
||||
"Recording did not start, but Uni Native PCM data was received"
|
||||
|
||||
//@@zh="未开始录音,但收到UniNativeUtsPlugin PCM数据"
|
||||
,"byzO:"+ //no args
|
||||
"Recording did not start, but UniNativeUtsPlugin PCM data was received"
|
||||
|
||||
//@@zh="未开始录音"
|
||||
,"YP4V:"+ //no args
|
||||
"Recording not started"
|
||||
|
||||
//@@zh="不应当出现的非H5录音Stop"
|
||||
,"TPhg:"+ //no args
|
||||
"Stop non-H5 recordings that should not appear"
|
||||
|
||||
//@@zh="未开始录音"
|
||||
,"pP4O:"+ //no args
|
||||
"Recording not started"
|
||||
|
||||
//@@zh="无法调用Stop:"
|
||||
,"H6cq:"+ //no args
|
||||
"Unable to call Stop: "
|
||||
|
||||
//@@zh="不应该出现的renderjs发回的文件数据丢失"
|
||||
,"gomD:"+ //no args
|
||||
"The file data sent back by renderjs should not be lost"
|
||||
|
||||
]);
|
||||
//*************** End srcFile=../app-support-sample/demo_UniApp/uni_modules/Recorder-UniCore/app-uni-support.js ***************
|
||||
|
||||
//@@User Code-2 Begin 手写代码放这里 Put the handwritten code here @@
|
||||
|
||||
//@@User Code-2 End @@
|
||||
|
||||
}));
|
@ -1,19 +0,0 @@
|
||||
《许可及服务协议》
|
||||
|
||||
**您(以下称“用户”)下载、使用我(以下称“作者”)提供的Recorder-UniCore组件(含原生录音插件、uts插件,以下统称“本组件”),应当阅读并遵守本许可协议。请用户务必审慎阅读、充分理解各条款内容,特别是免除或者限制责任的条款,并选择接受或不接受。除非用户已阅读并接受本协议所有条款,否则用户无权下载、使用本组件及相关服务,用户的下载、使用等行为即视为用户已阅读并同意本许可协议的约束。**
|
||||
|
||||
1. 用户应当直接从作者许可的途径,如作者的GitHub、Gitee仓库、已上架的DCloud插件市场、QQ群等途径中获取本组件;其他途径获取到的组件代码是未经过作者授权的,存在安全隐患,可能会导致你的程序、资产受到侵害,作者对因此给用户造成的损失不予负责。
|
||||
|
||||
2. 作者将积极并采取措施保护用户的信息和隐私;组件本身不会搜集存储任何用户信息。
|
||||
|
||||
3. 除法律法规有明确规定外,作者将尽最大努力确保本组件及其所涉及的技术及信息安全、有效、准确、可靠,但受限于现有技术,用户理解作者不能对此进行担保。
|
||||
|
||||
4. 用户理解,对于不可抗力及第三方原因导致的您的直接或间接损失,作者无法承担责任。
|
||||
|
||||
5. 用户因使用本组件进行生成、处理数据,由此引起或与有关的包括但不限于利润损失、资料损失、业务中断的损害赔偿或其它商业损害赔偿或损失,需由用户自行承担。
|
||||
|
||||
6. 如若发生赔偿、退款等行为,赔偿、退款等累计金额不得超过用户实际支付给作者的总金额。
|
||||
|
||||
7. 已授予的授权许可,包括免费授权,和已购买的原生录音插件、uts插件,均仅限在授权指定的uni-app的应用标识(AppID)对应的项目上使用,不可在其他项目上使用;用户不得对本组件及其中的相关信息擅自出租、出借、销售、逆向工程、破解,不得在未取得作者授权的情况下借助本组件发展与本组件有关联的衍生软件产品、服务、插件、外挂等。
|
||||
|
||||
8. 用户不得使用本组件从事违反法律法规政策、破坏公序良俗、损害公共利益的行为。
|