Compare commits
No commits in common. "main" and "wyfMain-dev" have entirely different histories.
main
...
wyfMain-de
@ -68,7 +68,6 @@
|
|||||||
"@types/node": "^18.18.5",
|
"@types/node": "^18.18.5",
|
||||||
"@types/vue": "^2.0.0",
|
"@types/vue": "^2.0.0",
|
||||||
"@unocss/reset": "^66.1.1",
|
"@unocss/reset": "^66.1.1",
|
||||||
"@vicons/tabler": "^0.13.0",
|
|
||||||
"@vitejs/plugin-vue": "^4.4.0",
|
"@vitejs/plugin-vue": "^4.4.0",
|
||||||
"@vitejs/plugin-vue-jsx": "^3.0.2",
|
"@vitejs/plugin-vue-jsx": "^3.0.2",
|
||||||
"@vue/tsconfig": "^0.4.0",
|
"@vue/tsconfig": "^0.4.0",
|
||||||
|
@ -159,9 +159,6 @@ importers:
|
|||||||
'@unocss/reset':
|
'@unocss/reset':
|
||||||
specifier: ^66.1.1
|
specifier: ^66.1.1
|
||||||
version: 66.3.0
|
version: 66.3.0
|
||||||
'@vicons/tabler':
|
|
||||||
specifier: ^0.13.0
|
|
||||||
version: 0.13.0
|
|
||||||
'@vitejs/plugin-vue':
|
'@vitejs/plugin-vue':
|
||||||
specifier: ^4.4.0
|
specifier: ^4.4.0
|
||||||
version: 4.6.2(vite@6.3.5(@types/node@18.19.112)(jiti@1.21.7)(less@4.3.0)(sass@1.89.2)(terser@5.43.1))(vue@3.5.17(typescript@5.2.2))
|
version: 4.6.2(vite@6.3.5(@types/node@18.19.112)(jiti@1.21.7)(less@4.3.0)(sass@1.89.2)(terser@5.43.1))(vue@3.5.17(typescript@5.2.2))
|
||||||
@ -1253,9 +1250,6 @@ packages:
|
|||||||
'@vicons/ionicons5@0.13.0':
|
'@vicons/ionicons5@0.13.0':
|
||||||
resolution: {integrity: sha512-zvZKBPjEXKN7AXNo2Na2uy+nvuv6SP4KAMQxpKL2vfHMj0fSvuw7JZcOPCjQC3e7ayssKnaoFVAhbYcW6v41qQ==}
|
resolution: {integrity: sha512-zvZKBPjEXKN7AXNo2Na2uy+nvuv6SP4KAMQxpKL2vfHMj0fSvuw7JZcOPCjQC3e7ayssKnaoFVAhbYcW6v41qQ==}
|
||||||
|
|
||||||
'@vicons/tabler@0.13.0':
|
|
||||||
resolution: {integrity: sha512-AykuhiqjszkIoAL/7knIFm6RDOBS1ZmQdJfQ+RNLEah0fVsxykUFCfMBSNZh8lOzC85EtdD1k5g/sv5GYk0Ohg==}
|
|
||||||
|
|
||||||
'@vitejs/plugin-vue-jsx@3.1.0':
|
'@vitejs/plugin-vue-jsx@3.1.0':
|
||||||
resolution: {integrity: sha512-w9M6F3LSEU5kszVb9An2/MmXNxocAnUb3WhRr8bHlimhDrXNt6n6D2nJQR3UXpGlZHh/EsgouOHCsM8V3Ln+WA==}
|
resolution: {integrity: sha512-w9M6F3LSEU5kszVb9An2/MmXNxocAnUb3WhRr8bHlimhDrXNt6n6D2nJQR3UXpGlZHh/EsgouOHCsM8V3Ln+WA==}
|
||||||
engines: {node: ^14.18.0 || >=16.0.0}
|
engines: {node: ^14.18.0 || >=16.0.0}
|
||||||
@ -5015,8 +5009,6 @@ snapshots:
|
|||||||
|
|
||||||
'@vicons/ionicons5@0.13.0': {}
|
'@vicons/ionicons5@0.13.0': {}
|
||||||
|
|
||||||
'@vicons/tabler@0.13.0': {}
|
|
||||||
|
|
||||||
'@vitejs/plugin-vue-jsx@3.1.0(vite@6.3.5(@types/node@18.19.112)(jiti@1.21.7)(less@4.3.0)(sass@1.89.2)(terser@5.43.1))(vue@3.5.17(typescript@5.2.2))':
|
'@vitejs/plugin-vue-jsx@3.1.0(vite@6.3.5(@types/node@18.19.112)(jiti@1.21.7)(less@4.3.0)(sass@1.89.2)(terser@5.43.1))(vue@3.5.17(typescript@5.2.2))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.27.4
|
'@babel/core': 7.27.4
|
||||||
|
@ -1,173 +1,46 @@
|
|||||||
<script lang="js" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, computed, onMounted, watch, reactive, nextTick, getCurrentInstance, h } from 'vue'
|
import { ref, computed, onMounted, watch } from 'vue'
|
||||||
import { ServeGetTalkList } from '@/api/chat.js'
|
import { ServeGetTalkList } from '@/api/chat.js'
|
||||||
import { ServeGetGroups } from '@/api/group'
|
import { ServeGetGroups } from '@/api/group'
|
||||||
import XNModal from '@/components/x-naive-ui/x-n-modal/index.vue'
|
import XNModal from '@/components/x-naive-ui/x-n-modal/index.vue'
|
||||||
import { Plus } from '@vicons/tabler'
|
|
||||||
import { CloseCircle } from '@vicons/ionicons5'
|
|
||||||
import customModal from '@/components/common/customModal.vue'
|
|
||||||
import xSearchForm from '@/components/x-naive-ui/x-search-form/index.vue'
|
|
||||||
import xNDataTable from '@/components/x-naive-ui/x-n-data-table/index.vue'
|
|
||||||
import flTree from '@/components/flnlayout/tree/flnindex.vue'
|
|
||||||
import { processError, processSuccess } from '@/utils/helper/message.js'
|
|
||||||
import { ServeUserGroupChatList } from '@/api/search'
|
|
||||||
import { GetContactFriendList } from '@/api/chat'
|
|
||||||
import { getUserInfoByERPUserId } from '@/api/user'
|
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
import { useUtil } from '@/hooks/useUtil'
|
|
||||||
import { NButton } from 'naive-ui'
|
|
||||||
|
|
||||||
const emit = defineEmits(['close', 'on-submit'])
|
const emit = defineEmits(['close', 'on-submit'])
|
||||||
|
import { CloseCircle } from '@vicons/ionicons5'
|
||||||
const { useMessage } = useUtil()
|
interface Item {
|
||||||
const router = useRouter()
|
id: number
|
||||||
|
type: number
|
||||||
const currentInstance = getCurrentInstance()
|
name: string
|
||||||
const $request = currentInstance?.appContext.config.globalProperties?.$request
|
avatar: string
|
||||||
|
remark: string
|
||||||
|
checked: boolean
|
||||||
|
keyword: string
|
||||||
|
}
|
||||||
|
|
||||||
const isShowBox = defineModel('show')
|
const isShowBox = defineModel('show')
|
||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
const items = ref([])
|
const items = ref<Item[]>([])
|
||||||
const keywords = ref('')
|
const keywords = ref('')
|
||||||
const loadGroupStatus = ref(false)
|
const loadGroupStatus = ref(false)
|
||||||
const props = defineProps({
|
defineProps<{
|
||||||
'forwardMode': {
|
forwardMode: number
|
||||||
type: Number,
|
}>()
|
||||||
default: 0
|
// 搜索过滤器:不再按类型过滤,将好友和群组融合在一起
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// 通讯录弹窗相关状态
|
|
||||||
const state = reactive({
|
|
||||||
selectedGroupRowKeys: [],
|
|
||||||
isShowAddressBookModal: false,
|
|
||||||
customModalStyle: {
|
|
||||||
width: '1288px',
|
|
||||||
height: '846px',
|
|
||||||
backgroundColor: '#F9F9FD'
|
|
||||||
},
|
|
||||||
addressBookSearchConfig: [
|
|
||||||
{
|
|
||||||
label: '姓名',
|
|
||||||
key: 'nickName',
|
|
||||||
type: 'input',
|
|
||||||
valueType: 'string'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
groupChatListSearchConfig: [
|
|
||||||
{
|
|
||||||
label: '群聊名称',
|
|
||||||
key: 'groupName',
|
|
||||||
type: 'input',
|
|
||||||
valueType: 'string'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
treeData: [],
|
|
||||||
expandedKeys: [],
|
|
||||||
clickKey: 3,
|
|
||||||
treeRefreshCount: 0,
|
|
||||||
treeSelectData: {},
|
|
||||||
addressBookColumns: [
|
|
||||||
{
|
|
||||||
type: 'selection'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '姓名 【工号】',
|
|
||||||
field: 'nickname',
|
|
||||||
width: 200,
|
|
||||||
ellipsis: {
|
|
||||||
tooltip: true
|
|
||||||
},
|
|
||||||
render(row, index) {
|
|
||||||
return row.nickName + '【' + row.jobNum + '】'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '岗位名称',
|
|
||||||
field: 'user_position',
|
|
||||||
width: 400,
|
|
||||||
ellipsis: {
|
|
||||||
tooltip: true
|
|
||||||
},
|
|
||||||
render(row, index) {
|
|
||||||
let positionNames = Array.isArray(row.depPositions)
|
|
||||||
? row.depPositions.flatMap((dep) =>
|
|
||||||
Array.isArray(dep.positions) ? dep.positions.map((pos) => pos.name) : []
|
|
||||||
)
|
|
||||||
: []
|
|
||||||
return positionNames.join(' , ')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
groupChatListColumns: [
|
|
||||||
{
|
|
||||||
type: 'selection'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '群聊名称',
|
|
||||||
field: 'groupName',
|
|
||||||
width: 400,
|
|
||||||
ellipsis: {
|
|
||||||
tooltip: true
|
|
||||||
},
|
|
||||||
render(row, index) {
|
|
||||||
return row.group_name
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '群类型',
|
|
||||||
field: 'groupType',
|
|
||||||
width: 200,
|
|
||||||
ellipsis: true,
|
|
||||||
render(row, index) {
|
|
||||||
let groupType = row.group_type
|
|
||||||
if (groupType == 1) {
|
|
||||||
return '普通群'
|
|
||||||
} else if (groupType == 2) {
|
|
||||||
return '部门群'
|
|
||||||
} else if (groupType == 3) {
|
|
||||||
return '项目群'
|
|
||||||
} else if (groupType == 4) {
|
|
||||||
return '公司群'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
addressBookData: [],
|
|
||||||
company_name: '',
|
|
||||||
groupChatListData: [],
|
|
||||||
addressBookTableHeight: 500,
|
|
||||||
addressBookTableWidth: 800,
|
|
||||||
addressBookPage: 1,
|
|
||||||
addressBookPageSize: 10,
|
|
||||||
addressBookTotal: 0,
|
|
||||||
addressBookSearchNickName: '',
|
|
||||||
addressBookCurrentTab: 'employeeAddressBook',
|
|
||||||
groupChatListPage: 1,
|
|
||||||
groupChatListPageSize: 10,
|
|
||||||
groupChatListTotal: 0,
|
|
||||||
groupChatListSearchGroupName: '',
|
|
||||||
selectedRowKeys: []
|
|
||||||
})
|
|
||||||
|
|
||||||
// 原有转发功能的过滤器
|
|
||||||
const searchFilter = computed(() => {
|
const searchFilter = computed(() => {
|
||||||
return items.value.filter((item) => {
|
return items.value.filter((item: Item) => {
|
||||||
return item.name.toLowerCase().includes(keywords.value.toLowerCase())
|
return item.name.toLowerCase().includes(keywords.value.toLowerCase())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
const checkedFilter = computed(() => {
|
const checkedFilter = computed(() => {
|
||||||
return items.value.filter((item) => item.checked)
|
return items.value.filter((item: Item) => item.checked)
|
||||||
})
|
})
|
||||||
|
|
||||||
const isCanSubmit = computed(() => {
|
const isCanSubmit = computed(() => {
|
||||||
return !checkedFilter.value.length
|
return !checkedFilter.value.length
|
||||||
})
|
})
|
||||||
|
|
||||||
// 原有加载数据函数
|
|
||||||
const onLoad = () => {
|
const onLoad = () => {
|
||||||
onLoadContact()
|
onLoadContact()
|
||||||
|
// onLoadGroup()
|
||||||
}
|
}
|
||||||
|
|
||||||
const onLoadContact = () => {
|
const onLoadContact = () => {
|
||||||
@ -177,7 +50,7 @@ const onLoadContact = () => {
|
|||||||
if (res.code == 200) {
|
if (res.code == 200) {
|
||||||
let list = res.data.items || []
|
let list = res.data.items || []
|
||||||
|
|
||||||
items.value = list.filter((item) => ((item.talk_type === 1 && item.receiver_id !== 2) || item.talk_type !== 1)).map((item) => {
|
items.value = list.filter((item: any) => ((item.talk_type === 1 && item.receiver_id !== 2) || item.talk_type !== 1)).map((item: any) => {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
checked: false
|
checked: false
|
||||||
@ -190,30 +63,57 @@ const onLoadContact = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 原有转发功能函数
|
// const onLoadGroup = async () => {
|
||||||
|
// if (loadGroupStatus.value) {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
// loading.value = true
|
||||||
|
// let { code, data } = await ServeGetGroups()
|
||||||
|
// if (code != 200) {
|
||||||
|
// loading.value = false
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
// let list = data.items.map((item: any) => {
|
||||||
|
// return {
|
||||||
|
// id: item.id,
|
||||||
|
// avatar: item.avatar,
|
||||||
|
// type: 2,
|
||||||
|
// name: item.group_name,
|
||||||
|
// keyword: item.group_name,
|
||||||
|
// remark: '',
|
||||||
|
// checked: false
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
|
||||||
|
// items.value.push(...list)
|
||||||
|
|
||||||
|
// loading.value = false
|
||||||
|
// loadGroupStatus.value = true
|
||||||
|
// }
|
||||||
|
|
||||||
const onMaskClick = () => {
|
const onMaskClick = () => {
|
||||||
emit('close')
|
emit('close')
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectType = ref(2)
|
const onTriggerContact = (item: any) => {
|
||||||
|
// 如果是单选模式,先取消所有选中
|
||||||
|
if (selectType.value === 1) {
|
||||||
|
items.value.forEach(contact => {
|
||||||
|
contact.checked = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const onTriggerContact = (item) => {
|
let data = items.value.find((val: any) => val.id === item.id)
|
||||||
const clicked = items.value.find((val) => val.id === item.id)
|
|
||||||
if (!clicked) return
|
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
data.checked = !data.checked
|
||||||
// 多选:限制同一类型选择
|
|
||||||
if (!clicked.checked) {
|
|
||||||
|
|
||||||
clicked.checked = true
|
|
||||||
} else {
|
|
||||||
clicked.checked = false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const onRemoveContact = (item) => {
|
const onRemoveContact = (item: any) => {
|
||||||
let data = items.value.find((val) => val.id === item.id)
|
let data = items.value.find((val: any) => val.id === item.id)
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
data.checked = false
|
data.checked = false
|
||||||
@ -225,7 +125,7 @@ const onCancel = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const onSubmit = () => {
|
const onSubmit = () => {
|
||||||
let data = checkedFilter.value.map((item) => {
|
let data = checkedFilter.value.map((item: any) => {
|
||||||
return {
|
return {
|
||||||
receiver_id: item.receiver_id,
|
receiver_id: item.receiver_id,
|
||||||
talk_type: item.talk_type
|
talk_type: item.talk_type
|
||||||
@ -234,204 +134,17 @@ const onSubmit = () => {
|
|||||||
emit('on-submit', data)
|
emit('on-submit', data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 通讯录弹窗功能函数
|
// 1 单选 2 多选
|
||||||
const onCreateContact = () => {
|
const selectType = ref(1)
|
||||||
state.isShowAddressBookModal = true
|
const changeSelectType = () => {
|
||||||
getTreeData()
|
selectType.value = selectType.value == 1 ? 2 : 1
|
||||||
getDepPoisUser()
|
|
||||||
getUserGroupChatList()
|
|
||||||
}
|
|
||||||
|
|
||||||
const closeAddressBookModal = () => {
|
// 切换选择模式时清空已选择的联系人
|
||||||
state.isShowAddressBookModal = false
|
items.value.forEach(item => {
|
||||||
resetAddressBookModal()
|
item.checked = false
|
||||||
}
|
|
||||||
|
|
||||||
const calcTreeData = (data) => {
|
|
||||||
for (let item of data) {
|
|
||||||
item.key = item.ID
|
|
||||||
item.label = item.name
|
|
||||||
item.title = item.name
|
|
||||||
if (item.sons) {
|
|
||||||
item.children = item.sons
|
|
||||||
calcTreeData(item.children)
|
|
||||||
}
|
|
||||||
delete item.ID
|
|
||||||
delete item.name
|
|
||||||
delete item.sons
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const getTreeData = () => {
|
|
||||||
let url = '/department/v2/tree/filter'
|
|
||||||
let params = {}
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
if (res.status === 0 && Array.isArray(res.data.nodes)) {
|
|
||||||
let data = res.data.nodes
|
|
||||||
calcTreeData(data)
|
|
||||||
state.treeData = data
|
|
||||||
state.treeRefreshCount++
|
|
||||||
getDepPoisUser()
|
|
||||||
} else {
|
|
||||||
processError(res.msg || '获取失败!')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError('获取失败!')
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError('获取失败!')
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const getDepPoisUser = () => {
|
|
||||||
let url = '/user/v2/list'
|
|
||||||
let params = {
|
|
||||||
departmentId: state.addressBookSearchNickName ? undefined : state.clickKey,
|
|
||||||
page: state.addressBookPage,
|
|
||||||
pageSize: state.addressBookPageSize,
|
|
||||||
status: 'notactive',
|
|
||||||
nickName: state.addressBookSearchNickName
|
|
||||||
}
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then((res) => {
|
|
||||||
if (res.code === 200) {
|
|
||||||
state.addressBookData = res?.data?.data || []
|
|
||||||
state.addressBookTotal = res?.data?.count || 0
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const getUserGroupChatList = () => {
|
|
||||||
let params = {
|
|
||||||
page: state.groupChatListPage,
|
|
||||||
page_size: state.groupChatListPageSize,
|
|
||||||
group_name: state.groupChatListSearchGroupName
|
|
||||||
}
|
|
||||||
ServeUserGroupChatList(params).then((res) => {
|
|
||||||
if (res.code === 200) {
|
|
||||||
state.groupChatListData = res?.data?.items || []
|
|
||||||
state.groupChatListTotal = res?.data?.total || 0
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleTreeClick = ({ selectedKey, tree }) => {
|
|
||||||
state.clickKey = tree.key
|
|
||||||
state.treeSelectData = tree
|
|
||||||
state.addressBookPage = 1
|
|
||||||
getDepPoisUser()
|
|
||||||
}
|
|
||||||
|
|
||||||
const resetAddressBookModal = () => {
|
|
||||||
nextTick(() => {
|
|
||||||
state.addressBookCurrentTab = 'employeeAddressBook'
|
|
||||||
state.addressBookSearchNickName = ''
|
|
||||||
state.groupChatListSearchGroupName = ''
|
|
||||||
state.addressBookTableWidth = 800
|
|
||||||
state.clickKey = 3
|
|
||||||
state.treeRefreshCount++
|
|
||||||
state.addressBookPage = 1
|
|
||||||
state.addressBookPageSize = 10
|
|
||||||
state.groupChatListPage = 1
|
|
||||||
state.groupChatListPageSize = 10
|
|
||||||
state.selectedRowKeys = []
|
|
||||||
getDepPoisUser()
|
|
||||||
getUserGroupChatList()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleAddressBookPagination = (page) => {
|
|
||||||
state.addressBookPage = page
|
|
||||||
getDepPoisUser()
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleAddressBookPaginationSize = (pageSize) => {
|
|
||||||
state.addressBookPageSize = pageSize
|
|
||||||
state.addressBookPage = 1
|
|
||||||
getDepPoisUser()
|
|
||||||
}
|
|
||||||
|
|
||||||
const changeAddressBookSearch = (value) => {
|
|
||||||
if (!value.nickName?.trim()) {
|
|
||||||
state.addressBookSearchNickName = ''
|
|
||||||
} else {
|
|
||||||
state.addressBookSearchNickName = value.nickName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleAddressBookTabChange = (value) => {
|
|
||||||
state.addressBookCurrentTab = value
|
|
||||||
// 切换时清空另一类选项
|
|
||||||
if (value === 'employeeAddressBook') {
|
|
||||||
state.selectedGroupRowKeys = []
|
|
||||||
} else if (value === 'groupChatList') {
|
|
||||||
state.selectedRowKeys = []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const changeGroupChatListSearch = (value) => {
|
|
||||||
if (!value.groupName?.trim()) {
|
|
||||||
state.groupChatListSearchGroupName = ''
|
|
||||||
} else {
|
|
||||||
state.groupChatListSearchGroupName = value.groupName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleGroupChatListPagination = (page) => {
|
|
||||||
state.groupChatListPage = page
|
|
||||||
getUserGroupChatList()
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleGroupChatListPaginationSize = (pageSize) => {
|
|
||||||
state.groupChatListPageSize = pageSize
|
|
||||||
state.groupChatListPage = 1
|
|
||||||
getUserGroupChatList()
|
|
||||||
}
|
|
||||||
|
|
||||||
const onAddressBookCancel = () => {
|
|
||||||
state.isShowAddressBookModal = false
|
|
||||||
}
|
|
||||||
|
|
||||||
const onAddressBookSubmit = async () => {
|
|
||||||
if (state.addressBookCurrentTab === 'employeeAddressBook') {
|
|
||||||
if (!Array.isArray(state.selectedRowKeys) || state.selectedRowKeys.length === 0) {
|
|
||||||
processError('请选择联系人')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const results = await Promise.all(
|
|
||||||
state.selectedRowKeys.map((erpId) => getUserInfoByERPUserId({ erp_user_id: erpId }))
|
|
||||||
)
|
|
||||||
|
|
||||||
const data = results
|
|
||||||
.filter((res) => res && res.code === 200 && res.data && res.data.sys_id)
|
|
||||||
.map((res) => ({ receiver_id: res.data.sys_id, talk_type: 1 }))
|
|
||||||
|
|
||||||
if (data.length === 0) {
|
|
||||||
processError('未获取到有效联系人')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
emit('on-submit', data)
|
|
||||||
state.isShowAddressBookModal = false
|
|
||||||
} catch (e) {
|
|
||||||
processError('发送失败,请稍后重试')
|
|
||||||
}
|
|
||||||
} else if (state.addressBookCurrentTab === 'groupChatList') {
|
|
||||||
if (!Array.isArray(state.selectedGroupRowKeys) || state.selectedGroupRowKeys.length === 0) {
|
|
||||||
processError('请选择群聊')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = state.selectedGroupRowKeys.map((gid) => ({ receiver_id: gid, talk_type: 2 }))
|
|
||||||
emit('on-submit', data)
|
|
||||||
state.isShowAddressBookModal = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(()=>{
|
watch(()=>{
|
||||||
return isShowBox.value
|
return isShowBox.value
|
||||||
},(newVal)=>{
|
},(newVal)=>{
|
||||||
@ -439,42 +152,12 @@ watch(() => {
|
|||||||
onLoad()
|
onLoad()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(() => state.addressBookSearchNickName, (newValue, oldValue) => {
|
|
||||||
if (newValue) {
|
|
||||||
state.addressBookTableWidth = 1142
|
|
||||||
state.addressBookPage = 1
|
|
||||||
} else {
|
|
||||||
state.addressBookTableWidth = 800
|
|
||||||
state.clickKey = 3
|
|
||||||
state.treeRefreshCount++
|
|
||||||
state.addressBookPage = 1
|
|
||||||
}
|
|
||||||
getDepPoisUser()
|
|
||||||
})
|
|
||||||
|
|
||||||
watch(() => state.groupChatListSearchGroupName, (newValue, oldValue) => {
|
|
||||||
if (newValue) {
|
|
||||||
state.groupChatListPage = 1
|
|
||||||
} else {
|
|
||||||
state.groupChatListPage = 1
|
|
||||||
}
|
|
||||||
getUserGroupChatList()
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<x-n-modal v-model:show="isShowBox" :title="forwardMode === 2 ? '合并转发' : '逐条转发'" style="width: 997px; height: 740px;background-color: #F9F9FD"
|
<x-n-modal v-model:show="isShowBox" :title="forwardMode === 2 ? '合并转发' : '逐条转发'" style="width: 997px; height: 740px;background-color: #F9F9FD"
|
||||||
:on-after-leave="onMaskClick" content-style="display: flex; justify-content: center; align-items: center;">
|
:on-after-leave="onMaskClick" content-style="display: flex; justify-content: center; align-items: center;">
|
||||||
<div class="w-927px h-627px bg-#fff rounded-3px px-35px pb-20px pt-10px">
|
<div class="w-927px h-627px bg-#fff rounded-3px px-35px py-20px">
|
||||||
<div class="w-100% flex justify-end mb-5px">
|
|
||||||
<n-button text type="primary" @click="onCreateContact">
|
|
||||||
<template #icon>
|
|
||||||
<Plus />
|
|
||||||
</template>
|
|
||||||
创建新聊天
|
|
||||||
</n-button>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center justify-between mb-28px">
|
<div class="flex items-center justify-between mb-28px">
|
||||||
<div class="text-#333639">搜索</div>
|
<div class="text-#333639">搜索</div>
|
||||||
<div class="w-779px h-34px">
|
<div class="w-779px h-34px">
|
||||||
@ -485,19 +168,19 @@ watch(() => state.groupChatListSearchGroupName, (newValue, oldValue) => {
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex justify-between">
|
<div class="flex justify-between">
|
||||||
<div class="w-260px h-517px rounded-4px border-1px border-solid border-#E5E5E5 px-12px">
|
<div class="w-260px h-517px rounded-4px border-1px border-solid border-#E5E5E5 px-12px">
|
||||||
<!-- <div class="border-b-2px border-b-solid border-b-#FBFBFB h-35px flex items-center justify-end">
|
<div class="border-b-2px border-b-solid border-b-#FBFBFB h-35px flex items-center justify-end">
|
||||||
<n-button text color="#46299D" class="text-14px" @click="changeSelectType">
|
<n-button text color="#46299D" class="text-14px" @click="changeSelectType">
|
||||||
{{ selectType === 1 ? '多选' : '取消多选' }}
|
{{ selectType === 1 ? '多选' : '取消多选' }}
|
||||||
</n-button>
|
</n-button>
|
||||||
</div> -->
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<n-virtual-list v-if="!loading" style="max-height: 470px" :item-size="65" :items="searchFilter">
|
<n-virtual-list v-if="!loading" style="max-height: 470px" :item-size="65" :items="searchFilter">
|
||||||
<template #default="{ item }">
|
<template #default="{ item }">
|
||||||
<div class="flex items-center border-b-2px border-b-solid h-65px border-b-#FBFBFB"
|
<div class="flex items-center border-b-2px border-b-solid h-65px border-b-#FBFBFB"
|
||||||
>
|
@click="onTriggerContact(item)">
|
||||||
<div class="mr-22px">
|
<div class="mr-22px">
|
||||||
|
<n-radio v-if="selectType === 1" :checked="item.checked" />
|
||||||
<n-checkbox v-model:checked="item.checked" />
|
<n-checkbox v-else :checked="item.checked" />
|
||||||
</div>
|
</div>
|
||||||
<div class="mr-10px">
|
<div class="mr-10px">
|
||||||
|
|
||||||
@ -576,175 +259,5 @@ watch(() => state.groupChatListSearchGroupName, (newValue, oldValue) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</x-n-modal>
|
</x-n-modal>
|
||||||
|
|
||||||
<!-- 通讯录弹窗 -->
|
|
||||||
<customModal
|
|
||||||
v-model:show="state.isShowAddressBookModal"
|
|
||||||
title="通讯录"
|
|
||||||
:style="state.customModalStyle"
|
|
||||||
:customCloseBtn="true"
|
|
||||||
:closable="false"
|
|
||||||
:customCloseEvent="true"
|
|
||||||
@customCloseModal="closeAddressBookModal"
|
|
||||||
>
|
|
||||||
<template #content>
|
|
||||||
<div class="custom-modal-content">
|
|
||||||
<n-card style="padding: 0 12px">
|
|
||||||
<n-tabs
|
|
||||||
type="line"
|
|
||||||
@update:value="handleAddressBookTabChange"
|
|
||||||
tab-style="font-size: 16px; font-weight: 600;color: #8B8B8B;"
|
|
||||||
>
|
|
||||||
<n-tab name="employeeAddressBook">员工通讯录</n-tab>
|
|
||||||
<n-tab name="groupChatList">群聊列表</n-tab>
|
|
||||||
</n-tabs>
|
|
||||||
<xSearchForm
|
|
||||||
v-if="state.addressBookCurrentTab == 'employeeAddressBook'"
|
|
||||||
:search-config="state.addressBookSearchConfig"
|
|
||||||
customInputPlaceholder="请输入姓名"
|
|
||||||
@change="changeAddressBookSearch"
|
|
||||||
:cols="3"
|
|
||||||
></xSearchForm>
|
|
||||||
<xSearchForm
|
|
||||||
v-if="state.addressBookCurrentTab == 'groupChatList'"
|
|
||||||
:search-config="state.groupChatListSearchConfig"
|
|
||||||
customInputPlaceholder="请输入群聊名称"
|
|
||||||
@change="changeGroupChatListSearch"
|
|
||||||
:cols="3"
|
|
||||||
></xSearchForm>
|
|
||||||
|
|
||||||
<div class="addressBook-content" v-if="state.addressBookCurrentTab == 'employeeAddressBook'">
|
|
||||||
<div class="addressBook-tree" v-if="!state.addressBookSearchNickName">
|
|
||||||
<fl-tree
|
|
||||||
:data="state.treeData"
|
|
||||||
:expandedKeys="state.expandedKeys"
|
|
||||||
:refreshCount="state.treeRefreshCount"
|
|
||||||
:clickKey="state.clickKey"
|
|
||||||
@triggerTreeClick="handleTreeClick"
|
|
||||||
></fl-tree>
|
|
||||||
</div>
|
|
||||||
<div class="addressBook-table">
|
|
||||||
<xNDataTable
|
|
||||||
:columns="state.addressBookColumns"
|
|
||||||
:data="state.addressBookData"
|
|
||||||
:style="{
|
|
||||||
height: `${state.addressBookTableHeight}px`,
|
|
||||||
width: `${state.addressBookTableWidth}px`
|
|
||||||
}"
|
|
||||||
:row-key="row => row.ID"
|
|
||||||
v-model:checked-row-keys="state.selectedRowKeys"
|
|
||||||
flex-height
|
|
||||||
></xNDataTable>
|
|
||||||
<div class="addressBook-pagination">
|
|
||||||
<n-pagination
|
|
||||||
v-model:page="state.addressBookPage"
|
|
||||||
v-model:page-size="state.addressBookPageSize"
|
|
||||||
:item-count="state.addressBookTotal"
|
|
||||||
show-quick-jumper
|
|
||||||
show-size-picker
|
|
||||||
:page-sizes="[10, 20, 50]"
|
|
||||||
:on-update:page="handleAddressBookPagination"
|
|
||||||
:on-update:page-size="handleAddressBookPaginationSize"
|
|
||||||
>
|
|
||||||
<template #prefix="{ itemCount }"> 共 {{ itemCount }} 条记录 </template>
|
|
||||||
</n-pagination>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="groupChatList-content" v-if="state.addressBookCurrentTab == 'groupChatList'">
|
|
||||||
<div class="groupChatList-table">
|
|
||||||
<xNDataTable
|
|
||||||
:columns="state.groupChatListColumns"
|
|
||||||
:data="state.groupChatListData"
|
|
||||||
:style="{
|
|
||||||
height: '500px',
|
|
||||||
width: '1148px'
|
|
||||||
}"
|
|
||||||
:row-key="row => row.id"
|
|
||||||
v-model:checked-row-keys="state.selectedGroupRowKeys"
|
|
||||||
flex-height
|
|
||||||
></xNDataTable>
|
|
||||||
<div class="groupChatList-pagination">
|
|
||||||
<n-pagination
|
|
||||||
v-model:page="state.groupChatListPage"
|
|
||||||
v-model:page-size="state.groupChatListPageSize"
|
|
||||||
:item-count="state.groupChatListTotal"
|
|
||||||
show-quick-jumper
|
|
||||||
show-size-picker
|
|
||||||
:page-sizes="[10, 20, 50]"
|
|
||||||
:on-update:page="handleGroupChatListPagination"
|
|
||||||
:on-update:page-size="handleGroupChatListPaginationSize"
|
|
||||||
>
|
|
||||||
<template #prefix="{ itemCount }"> 共 {{ itemCount }} 条记录 </template>
|
|
||||||
</n-pagination>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 底部操作按钮,仅保留展示 -->
|
|
||||||
<div style="display: flex; justify-content: center; align-items: center; padding: 10px 0;">
|
|
||||||
<n-button color="#C7C7C9" class="w-200px h-34px text-14px text-#fff mr-10px" @click="onAddressBookCancel">取消</n-button>
|
|
||||||
<n-button color="#46299D" class="w-200px h-34px text-14px text-#fff" @click="onAddressBookSubmit">发送</n-button>
|
|
||||||
</div>
|
|
||||||
</n-card>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
</customModal>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.custom-modal-content {
|
|
||||||
.addressBook-content {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
gap: 20px;
|
|
||||||
|
|
||||||
.addressBook-tree {
|
|
||||||
width: 328px;
|
|
||||||
height: 500px;
|
|
||||||
overflow: auto;
|
|
||||||
border: 1px solid #efeff5;
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 12px 20px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.addressBook-table {
|
|
||||||
:deep(.n-data-table-th) {
|
|
||||||
background-color: #46299d;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
.addressBook-pagination {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
align-items: center;
|
|
||||||
padding: 22px 0 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.groupChatList-content {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
gap: 20px;
|
|
||||||
|
|
||||||
.groupChatList-table {
|
|
||||||
:deep(.n-data-table-th) {
|
|
||||||
background-color: #46299d;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
.groupChatList-pagination {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
align-items: center;
|
|
||||||
padding: 22px 0 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
@ -9,8 +9,6 @@ import { ServeClearTalkUnreadNum, ServeCreateTalkList } from '@/api/chat'
|
|||||||
import { useTalkStore, useDialogueStore, useSettingsStore } from '@/store'
|
import { useTalkStore, useDialogueStore, useSettingsStore } from '@/store'
|
||||||
import { isScrollAtBottom, scrollToBottom } from '@/utils/dom'
|
import { isScrollAtBottom, scrollToBottom } from '@/utils/dom'
|
||||||
|
|
||||||
const talkCreateThrottle = new Map()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 好友状态事件
|
* 好友状态事件
|
||||||
*/
|
*/
|
||||||
@ -116,20 +114,7 @@ class Talk extends Base {
|
|||||||
} else {
|
} else {
|
||||||
// 如果发送者ID为2,则为聊天助手,不在pc端处理,不创建会话
|
// 如果发送者ID为2,则为聊天助手,不在pc端处理,不创建会话
|
||||||
if ((this.talk_type === 1 && this.receiver_id !== 2) || this.talk_type !== 1) {
|
if ((this.talk_type === 1 && this.receiver_id !== 2) || this.talk_type !== 1) {
|
||||||
// 节流:相同会话在 5 秒内只创建一次
|
|
||||||
const idx = this.getIndexName()
|
|
||||||
const now = Date.now()
|
|
||||||
const last = talkCreateThrottle.get(idx) || 0
|
|
||||||
if (now - last < 5000) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
talkCreateThrottle.set(idx, now)
|
|
||||||
try {
|
|
||||||
return this.addTalkItem()
|
return this.addTalkItem()
|
||||||
} finally {
|
|
||||||
// 不立即清除时间戳,保留自然过期窗口
|
|
||||||
// 可根据需要在 addTalkItem 成功后也不清除,以维持 5s 窗口
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -187,8 +172,7 @@ class Talk extends Base {
|
|||||||
}).then(({ code, data }) => {
|
}).then(({ code, data }) => {
|
||||||
if (code == 200) {
|
if (code == 200) {
|
||||||
let item = formatTalkItem(data)
|
let item = formatTalkItem(data)
|
||||||
// 如果是自己发送的消息,不应该标记为未读
|
item.unread_num = 1
|
||||||
item.unread_num = this.isCurrSender() ? 0 : 1
|
|
||||||
useTalkStore().addItem(item)
|
useTalkStore().addItem(item)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -18,7 +18,7 @@ export function isLoggedIn() {
|
|||||||
*/
|
*/
|
||||||
export function getAccessToken() {
|
export function getAccessToken() {
|
||||||
// return storage.get(AccessToken) || ''
|
// return storage.get(AccessToken) || ''
|
||||||
return JSON.parse(localStorage.getItem('token'))||'cb5a111b82e99f5ec00da4c8b0f6b853a3c4f96de0d0bd701622de596a751ba651f7c3ac2c32ccbe40d646600580827b7a330fa4e9c320d9cb44e9c50e4b84b9d7d4597fba9f1c6850ff35dce8a8ac8fde05e61a887f59cc332940c82e1c9e18fc5e97d22c71139d6dfc7ac6660772d2cfe458c3adf3fbdbae3313a3cf5a781f2662ed237d4df4a9c438345012eb5b532dfd34e6fbc3f2e1c45c0be80f79332dfb858682028860bc8e62be876e5d370e0526a64b00d1be32081ddf1ede0ba11b82f0387f2070bdc0bf7c201ac14821d45485becee940d93bd7b9cb3231f7ab0cf0921632d02752d8c270ae5e8b2c28458a48da8c4c7addd9da4655546e409f757322957b21540b97e6cceb4e24a18c9886a4acfbb423ea85c720a22ad95582df06180ee458f1b66c254e11bb3c7eac17'
|
return JSON.parse(localStorage.getItem('token'))||''
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,7 +21,6 @@ import { confirmBox } from '@/components/confirm-box/service.js'
|
|||||||
import ws from '@/connect'
|
import ws from '@/connect'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import avatarModule from '@/components/avatar-module/index.vue'
|
import avatarModule from '@/components/avatar-module/index.vue'
|
||||||
import { scrollToBottom } from '@/utils/dom'
|
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
@ -781,11 +780,6 @@ const loadMoreReadListDetail = () => {
|
|||||||
|
|
||||||
const onCustomSkipBottomEvent = () => {
|
const onCustomSkipBottomEvent = () => {
|
||||||
console.log('onCustomSkipBottomEvent')
|
console.log('onCustomSkipBottomEvent')
|
||||||
if (dialogueStore.isOpenMultiSelect) {
|
|
||||||
// 多选模式下,仅滚动到底部,避免触发加载导致选中状态丢失
|
|
||||||
scrollToBottom()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
onLoad({ ...props, limit: 30 })
|
onLoad({ ...props, limit: 30 })
|
||||||
// scrollToBottom()
|
// scrollToBottom()
|
||||||
}
|
}
|
||||||
|
@ -46,9 +46,9 @@ export default defineConfig(({ mode }) => {
|
|||||||
vueJsx({}),
|
vueJsx({}),
|
||||||
compressPlugin(),
|
compressPlugin(),
|
||||||
UnoCSS(),
|
UnoCSS(),
|
||||||
vueDevTools({
|
// vueDevTools({
|
||||||
launchEditor: 'trae',
|
// launchEditor: 'trae',
|
||||||
})
|
// })
|
||||||
],
|
],
|
||||||
define: {
|
define: {
|
||||||
__APP_ENV__: env.APP_ENV
|
__APP_ENV__: env.APP_ENV
|
||||||
|
Loading…
Reference in New Issue
Block a user