修改选择部门和新增群成员页面交互与样式;新增通讯录页面复用部分适配

This commit is contained in:
wangyifeng 2025-02-06 17:01:28 +08:00
parent 78ca543946
commit dafe65bb72
14 changed files with 982 additions and 91 deletions

View File

@ -14,6 +14,7 @@
@click="clickBtn"
:disabled="props?.disabled"
:class="[props?.disabled ? 'custom-btn-class-disabled' : '']"
:plain="props?.plain"
>
{{ props.btnText }}
</wd-button>
@ -29,6 +30,7 @@ const props = defineProps({
btnText: '', //
subBtnText: '', //
disabled: false, //
plain: false, //
})
//

View File

@ -188,7 +188,7 @@
}
},
{
"path": "pages/addressBook/index",
"path": "pages/chooseByDeps/index",
"type": "page",
"style": {
"navigationStyle": "custom",

View File

@ -1,30 +0,0 @@
<template>
<div class="address-book-page">
<zPaging ref="zPaging" :show-scrollbar="false">
<template #top>
<customNavbar
:title="$t('index.mine.addressBook')"
:shadowNum="0"
></customNavbar>
</template>
<div class="address-book">
</div>
</zPaging>
</div>
</template>
<script setup>
import zPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
</script>
<style scoped lang="scss">
::v-deep .zp-paging-container-content {
height: 100%;
display: flex;
}
.address-book-page {
background-image: url('@/static/image/clockIn/z3280@3x.png');
background-size: cover;
background-position: center bottom;
width: 100%;
}
</style>

View File

@ -90,9 +90,7 @@ const toUserDetailPage = (userItem) => {
uni.navigateTo({
url:
'/pages/dialog/dialogDetail/userDetail?erpUserId=' +
(userItem.erp_user_id || userItem.ID) +
'&user_id=' +
(userItem.user_id || userItem.id),
(userItem.erp_user_id || userItem.ID),
})
}

View File

@ -552,7 +552,7 @@ const showConfirmPrompt = (flag) => {
cancelText: t('cancel'),
onConfirm: async () => {
if (flag === 1) {
useDialogueStore().apiClearRecord()
dialogueStore.apiClearRecord()
} else if (flag === 2) {
let params = {
group_id: dialogueParams.receiver_id, //id
@ -560,7 +560,7 @@ const showConfirmPrompt = (flag) => {
console.log(params)
const res = await ServeDismissGroup(params)
if (res.code === 200) {
useDialogueStore().updateGroupMembers()
dialogueStore.updateGroupMembers()
groupStore.ServeGroupDetail()
uni.navigateBack({
delta: 2,
@ -590,7 +590,7 @@ const inviteMembersInGroup = async (memberList) => {
console.log(params)
const res = await ServeInviteGroup(params)
if (res.code === 200) {
useDialogueStore().updateGroupMembers()
dialogueStore.updateGroupMembers()
groupStore.ServeGroupDetail()
useGroupTypeStore()?.resetGroupInfo()
}

View File

@ -0,0 +1,906 @@
<template>
<div class="choose-deps-page">
<zPaging ref="zPaging" :show-scrollbar="false">
<template #top>
<customNavbar :title="pageTitle"></customNavbar>
</template>
<div class="choose-deps">
<div class="w-full pl-[32rpx] pr-[32rpx]">
<div class="pl-[16rpx] pr-[16rpx] pt-[22rpx] pb-[24rpx] bg-[#FFFFFF]">
<customInput
:searchText="searchVal"
@inputSearchText="inputSearchText"
></customInput>
<div
v-if="crumbs.length"
class="w-full overflow-x-auto mt-[22rpx] leading-[48rpx] text-[#2F2F2F] flex items-center no-scrollbar"
ref="crumbsContainer"
>
<div
v-for="(item, index) in crumbs"
class="flex items-center text-[28rpx] leading-[48rpx] whitespace-nowrap"
:class="[
index === crumbsIndex ? 'text-[#747474]' : 'text-[#46299D]',
index === 0 ? '' : 'ml-[12rpx]',
]"
@click="handleCrumbsClick(index)"
>
<div>{{ item.name }}</div>
<div
v-if="index !== crumbs.length - 1"
class="ml-[20rpx] flex items-center mb-[2rpx]"
>
<tm-icon
name="tmicon-angle-right"
:font-size="20"
:color="index !== crumbs.length - 1 ? '#7A58DE' : '#C1B4EA'"
></tm-icon>
</div>
</div>
</div>
</div>
<div
v-if="state.chooseMode === 1 || state.chooseMode === 2"
class="pl-[32rpx] bg-[#FFFFFF] mt-[20rpx] h-[110rpx] flex items-center"
@click="() => allCheck(allCheckStatus)"
>
<div class="mr-[20rpx]">
<checkBox
:disabled="currentCrumbs?.sons?.length === 0"
:modelValue="allCheckStatus"
></checkBox>
</div>
<div class="font-medium text-[28rpx] leading-[40rpx]">
{{ $t('radio.btn.selectAll') }}
</div>
</div>
<div
v-if="currentCrumbs?.sons?.length"
v-for="item in currentCrumbs?.sons"
@click="
state.chooseMode === 1 || state.chooseMode === 2
? checkItemChange(
item,
item.checkStatus
? item.checkStatus === 'checked'
? 'noChecked'
: 'checked'
: 'checked',
)
: ''
"
class="pl-[32rpx] bg-[#FFFFFF] mt-[20rpx] h-[110rpx] flex items-center"
>
<div class="w-full flex items-center justify-between">
<div class="flex items-center">
<div
class="mr-[20rpx]"
v-if="state.chooseMode === 1 || state.chooseMode === 2"
>
<checkBox
:disabled="!item?.sons?.length"
v-model="item.checkStatus"
@change="(val) => checkItemChange(item, val)"
></checkBox>
</div>
<div class="font-medium text-[28rpx] leading-[40rpx]">
<span>{{ item.name }}</span>
<span v-if="state.chooseMode === 2 || state.chooseMode === 3">
{{ getDepTotalMembers(item) }}
</span>
</div>
</div>
<div
v-if="item.sons?.length"
class="flex items-center mr-[32rpx]"
>
<div class="vDivider mr-[32rpx]"></div>
<div
@click.stop="() => toNextLevel(item)"
class="flex items-center"
>
<div class="mr-[12rpx]">
<tm-image
:width="26"
:height="26"
:src="
item.checkStatus !== 'checked' ? downDep : downDepDis
"
></tm-image>
</div>
<div
class="text-[28rpx] leading-[40rpx] font-medium"
:class="
item.checkStatus !== 'checked'
? 'text-[#46299D]'
: 'text-[#C1B4EA]'
"
>
{{ $t('choose.deps.nextLevel') }}
</div>
</div>
</div>
</div>
</div>
<div
v-if="
currentMembers.length &&
(state.chooseMode === 2 || state.chooseMode === 3)
"
v-for="item in currentMembers"
@click="
state.chooseMode === 1 || state.chooseMode === 2
? checkMember(
item,
membersCheckedKeys.filter((v) => v.ID === item.ID).length >
0
? 'noChecked'
: 'checked',
)
: toUserDetail(item)
"
class="pl-[32rpx] pr-[32rpx] bg-[#FFFFFF] mt-[20rpx] h-[110rpx] flex items-center"
>
<div class="w-full flex items-center justify-between">
<div class="w-full flex items-center">
<div
class="mr-[20rpx]"
v-if="state.chooseMode === 1 || state.chooseMode === 2"
>
<checkBox
:modelValue="
membersCheckedKeys.filter((v) => v.ID === item.ID)
.length > 0
? 'checked'
: 'noChecked'
"
@change="(val) => checkMember(item, val)"
></checkBox>
</div>
<div class="w-full flex items-center">
<div
class="userAvatar flex items-center justify-center"
style="flex-shrink: 0;"
>
{{ item.nickName.slice(-2) }}
</div>
<div
class="ml-[20rpx] flex flex-col justify-center w-[112rpx]"
style="word-break: break-all; flex-shrink: 0;"
>
<div class="text-[28rpx] font-medium leading-[40rpx]">
{{ item.nickName }}
</div>
<div
class="text-[20rpx] text-[#747474] leading-[28rpx] font-regular"
>
{{ item.jobNum }}
</div>
</div>
<tm-popover position="tc" class="max-w-full">
<div
class="max-w-full ml-[6rpx] flex max-h-[68rpx] flex-wrap line-clamp-2"
>
<div
v-for="post in item.positions"
class="postTag truncate mb-[4rpx] ml-[14rpx] max-w-[164rpx]"
>
{{ post.name }}
</div>
</div>
<template v-slot:label>
<div
class="max-h-[250rpx] overflow-y-auto pt-[10rpx] pl-[18rpx] pr-[18rpx] pb-[12rpx]"
>
<div
v-for="post in item.positions"
class="postTag truncate mb-[10rpx]"
>
{{ post.name }}
</div>
</div>
</template>
</tm-popover>
</div>
</div>
</div>
</div>
</div>
</div>
<template #bottom v-if="state.chooseMode === 1 || state.chooseMode === 2">
<div
class="h-[162rpx] pl-[32rpx] pr-[32rpx] bg-[#FFFFFF] confirm-btn-area"
>
<div class="mt-[2rpx] flex justify-between">
<div class="flex flex-col mt-[32rpx]">
<div
@click="openDrawer"
class="flex items-center text-[28rpx] leading-[40rpx] text-[#000000] font-medium"
>
<div>
<span v-if="state.chooseMode === 1">
{{ $t('statistics.selected.deps') }}
</span>
<span v-if="state.chooseMode === 2">
{{ $t('select.member.num') }}
</span>
</div>
<div>
<span v-if="state.chooseMode === 1">
{{ allCheckedList.length }}
</span>
<span v-if="state.chooseMode === 2">
{{ totalMembers + $t('statistic.unit.person') }}
</span>
</div>
<div class="ml-[28rpx]">
<tm-icon
:fontSize="24"
color="#46299D"
name="tmicon-angle-up"
></tm-icon>
</div>
</div>
<div
class="text-[24rpx] leading-[34rpx] text-[#7A58DE] w-[280rpx] truncate"
>
<span v-if="state.chooseMode === 1">
{{ allCheckedList.map((v) => v.name).toString() }}
</span>
<span
v-if="state.chooseMode === 2"
v-for="item in allCheckedList"
>
{{ item.name }}({{ item.staffNum }})
</span>
<span
v-if="state.chooseMode === 2"
v-for="(item, index) in membersCheckedKeys"
>
{{ item.nickName }}
{{ index !== membersCheckedKeys.length - 1 ? ',' : '' }}
</span>
</div>
</div>
<div class="btnBox">
<customBtn
:btnText="$t('ok')"
@clickBtn="handleConfirm"
:disabled="
state.chooseMode === 1
? !allCheckedList.length
: state.chooseMode === 2
? !allCheckedList.length && !membersCheckedKeys.length
: true
"
></customBtn>
</div>
</div>
</div>
<tm-drawer
placement="bottom"
v-model:show="showWin"
:height="800"
:hideHeader="true"
:round="5"
>
<div
class="flex flex-col w-full h-full pt-[36rpx] pl-[32rpx] pr-[32rpx] leading-[60rpx]"
>
<div
class="text-[32rpx] font-medium leading-[44rpx] flex items-center justify-between"
>
<div class="flex items-center ml-[10rpx]">
<div>
<span v-if="state.chooseMode === 1">
{{ $t('statistics.selected.deps') }}
</span>
<span v-if="state.chooseMode === 2">
{{ $t('select.member.num') }}
</span>
</div>
<div>
<span v-if="state.chooseMode === 1">
{{ allCheckedList.length }}
</span>
<span v-if="state.chooseMode === 2">
{{ totalMembers + $t('statistic.unit.person') }}
</span>
</div>
</div>
<div
class="text-[#7A58DE] mr-[10rpx]"
@click="() => (showWin = false)"
>
{{ $t('ok') }}
</div>
</div>
<scroll-view
scroll-y
class="h-[690rpx] mt-[30rpx] scroll-view-style"
>
<div class="flex-1 pb-[20rpx]">
<div
v-for="(item, index) in allCheckedList"
class="flex flex-col"
>
<div v-if="index === 0" class="divider"></div>
<div
class="flex items-center justify-between mt-[36rpx] font-medium text-[#000000] leading-[40rpx] mb-[34rpx]"
>
<div class="text-[28rpx] ml-[10rpx]">
<span>{{ item.name }}</span>
<span v-if="state.chooseMode === 2">
{{ getDepTotalMembers(item) }}
</span>
</div>
<div class="diyBtn">
<customBtn
:plain="true"
:btnText="$t('chatSettings.btn.removeAdmin')"
@clickBtn="deleteNode(item)"
:disabled="userDepIds.includes(item.ID)"
></customBtn>
</div>
</div>
<div class="divider"></div>
</div>
<div
v-for="(item, index) in membersCheckedKeys"
class="flex flex-col"
>
<div
v-if="index === 0 && allCheckedList.length == 0"
class="divider"
></div>
<div
class="flex items-center justify-between mt-[36rpx] font-medium text-[#000000] leading-[40rpx] mb-[34rpx]"
>
<div class="text-[28rpx] ml-[10rpx] flex">
<div>{{ item.nickName }}({{ item.jobNum }})</div>
<div
class="ml-[20rpx] flex h-[68rpx] flex-wrap line-clamp-2 max-w-[342rpx]"
>
<div
v-for="post in item.positions"
class="postTag truncate mb-[4rpx] mr-[14rpx] max-w-[164rpx]"
>
{{ post.name }}
</div>
</div>
</div>
<div class="diyBtn">
<customBtn
:plain="true"
:btnText="$t('chatSettings.btn.removeAdmin')"
@clickBtn="deleteMember(item)"
></customBtn>
</div>
</div>
<div class="divider"></div>
</div>
</div>
</scroll-view>
</div>
</tm-drawer>
</template>
</zPaging>
</div>
</template>
<script setup>
import customInput from '@/components/custom-input/custom-input.vue'
import customBtn from '@/components/custom-btn/custom-btn.vue'
import zPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
import { ref, watch, computed, onMounted, nextTick, reactive } from 'vue'
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 downDep from '@/static/image/chatList/downDep.png'
import downDepDis from '@/static/image/chatList/downDepDis.png'
import checkBox from '@/components/checkBox/index.vue'
import lodash from 'lodash'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const {
groupActiveIndex,
getDepsTreeMy,
depTreeMyList,
crumbs,
crumbsIndex,
depCheckedKeys,
getDepMembers,
membersCheckedKeys,
allChooseMembers,
} = useGroupTypeStore()
const userStore = useUserStore()
const searchVal = ref('')
const crumbsContainer = ref(null)
const showWin = ref(false)
const currentMembers = ref([])
const state = reactive({
chooseMode: 1, //1=2=; 3=
})
onLoad((options) => {
if (options.chooseMode) {
state.chooseMode = Number(options.chooseMode)
}
})
const pageTitle = computed(() => {
let page_title = ''
if (state.chooseMode === 1) {
page_title = t('pageTitle.select.department')
} else if (state.chooseMode === 2) {
page_title = t('chat.manage.addMembers')
} else if (state.chooseMode === 3) {
page_title = t('index.mine.addressBook')
}
return page_title
})
const getAllCheckedNodes = (node, checkedNodes = []) => {
if (node.checkStatus === 'checked') {
checkedNodes.push(node)
}
if (node.sons && Array.isArray(node.sons)) {
node.sons.forEach((son) => getAllCheckedNodes(son, checkedNodes))
}
return checkedNodes
}
const userDepIds = computed(() => {
return userStore.deps.map((v) => v.dept_id)
})
const allCheckedList = computed(() => {
const checkedNodes = []
depTreeMyList.value.forEach((node) => getAllCheckedNodes(node, checkedNodes))
console.log('checkedNodes', checkedNodes)
return checkedNodes
})
const currentCrumbs = computed(() => {
if (crumbs.value[crumbsIndex.value]) {
if (searchVal.value && searchVal.value !== '') {
let filterSons = crumbs.value[crumbsIndex.value].sons.filter((item) =>
item.name.includes(searchVal.value),
)
return {
...crumbs.value[crumbsIndex.value],
sons: filterSons,
}
}
console.log('allCheckedList', crumbs.value[crumbsIndex.value])
return crumbs.value[crumbsIndex.value]
}
return {}
})
const allCheckStatus = computed(() => {
if (!currentCrumbs.value.sons) {
return 'noChecked'
}
const allChecked = currentCrumbs.value.sons.every(
(son) => son.checkStatus === 'checked',
)
const someChecked = currentCrumbs.value.sons.some(
(son) => son.checkStatus === 'checked' || son.checkStatus === 'halfChecked',
)
if (allChecked) {
return 'checked'
} else if (someChecked) {
return 'halfChecked'
} else {
return 'noChecked'
}
})
const findNodeById = (node, targetId) => {
if (node.ID === targetId) {
return node
}
if (node.sons && Array.isArray(node.sons)) {
for (const son of node.sons) {
const found = findNodeById(son, targetId)
if (found) {
return found
}
}
}
return null
}
const findParentNode = (node, targetId) => {
if (!node.sons || !Array.isArray(node.sons)) return null
for (const son of node.sons) {
if (son.ID === targetId) {
return node
}
const parent = findParentNode(son, targetId)
if (parent) {
return parent
}
}
return null
}
//
const updateParentStatus = (node) => {
const parent = findParentNode(depTreeMyList.value[0], node.ID)
if (!parent) return
if (parent.checkStatus !== 'checked') {
const allChecked =
parent.sons &&
Array.isArray(parent.sons) &&
parent.sons.every((son) => son.checkStatus === 'checked')
const someChecked =
parent.sons &&
Array.isArray(parent.sons) &&
parent.sons.some(
(son) =>
son.checkStatus === 'checked' || son.checkStatus === 'halfChecked',
)
if (allChecked) {
parent.checkStatus = 'halfChecked'
} else if (someChecked) {
parent.checkStatus = 'halfChecked'
} else {
parent.checkStatus = 'noChecked'
}
}
updateParentStatus(parent)
}
//
const updateNodeStatus = (node) => {
if (!node.sons || !Array.isArray(node.sons)) return
const allChecked = node.sons.every((son) => son.checkStatus === 'checked')
const someChecked = node.sons.some(
(son) => son.checkStatus === 'checked' || son.checkStatus === 'halfChecked',
)
if (allChecked) {
node.checkStatus = 'halfChecked'
} else if (someChecked) {
node.checkStatus = 'halfChecked'
} else {
node.checkStatus = 'noChecked'
}
}
//
const updateCheckStatus = (node, status) => {
node.checkStatus = status
if (node.sons && Array.isArray(node.sons) && node.sons.length > 0) {
node.sons.forEach((son) => updateCheckStatus(son, status))
}
}
const checkItemChange = (item, val) => {
//
updateCheckStatus(item, val)
//
updateParentStatus(item)
}
const deleteNode = (item) => {
const treeNode = findNodeById(depTreeMyList.value[0], item.ID)
if (!treeNode) return
treeNode.checkStatus = 'noChecked'
updateNodeStatus(treeNode)
updateParentStatus(treeNode)
}
const toNextLevel = async (item) => {
if (item.checkStatus !== 'checked') {
crumbs.value.push(item)
crumbsIndex.value++
await nextTick()
if (crumbsContainer.value) {
crumbsContainer.value.scrollLeft = crumbsContainer.value.scrollWidth
}
}
}
const handleCrumbsClick = (index) => {
crumbsIndex.value = index
crumbs.value = crumbs.value.slice(0, index + 1)
}
const allCheck = (status) => {
let statusT = 'noChecked'
if (status === 'checked') {
statusT = 'noChecked'
} else {
statusT = 'checked'
}
currentCrumbs.value.sons.forEach((item) => {
const itemT = findNodeById(depTreeMyList.value[0], item.ID)
if (!itemT) return
checkItemChange(itemT, statusT)
})
}
const openDrawer = () => {
showWin.value = true
if (allCheckedList.length > 0) {
}
}
// watch(() => depTreeMyList.value, (newValue, oldValue) => {
// console.log("depTreeMyList", newValue);
// }, { deep: true });
// watch(() => searchVal.value, (newValue, oldValue) => {
// console.log("searchVal", newValue);
// });
const handleConfirm = async () => {
if (state.chooseMode === 2) {
const listT = membersCheckedKeys.value.map((v) => v)
const res = await getDepMembers({
departmentIds: allCheckedList.value.map((v) => v.ID),
status: 'notactive',
})
if (res.status == 0 && res.data?.data?.length) {
res.data?.data.forEach((v) => {
listT.push(v)
})
}
allChooseMembers.value = listT
}
depCheckedKeys.value = lodash.cloneDeep(allCheckedList.value)
console.log('depCheckedKeys', depCheckedKeys.value)
uni.navigateBack()
}
const initCheckedKeys = () => {
depCheckedKeys.value.forEach((item) => {
const node = findNodeById(depTreeMyList.value[0], item.ID)
if (node) {
node.checkStatus = 'checked'
updateParentStatus(node)
}
})
}
const init = async () => {
crumbsIndex.value = 0
await getDepsTreeMy()
crumbs.value = depTreeMyList.value.length ? [depTreeMyList.value[0]] : []
initCheckedKeys()
}
onMounted(() => {
init()
})
//
const inputSearchText = (e) => {
searchVal.value = e
}
const calculateTotalStaffNum = (node) => {
let total = node.staffNum || 0
if (node.sons && Array.isArray(node.sons)) {
node.sons.forEach((son) => {
total += calculateTotalStaffNum(son)
})
}
return total
}
const getCurrentMembers = async (depItem) => {
const res = await getDepMembers({
departmentId: depItem.ID,
status: 'notactive',
})
if (res.status === 0) {
currentMembers.value = res.data.data.length
? res.data.data.map((v) => {
return {
...v,
isMember: true,
}
})
: []
} else {
currentMembers.value = []
}
}
const checkMember = (item, val) => {
if (val === 'checked') {
membersCheckedKeys.value.push(item)
} else {
membersCheckedKeys.value = membersCheckedKeys.value.filter(
(v) => v.ID !== item.ID,
)
}
}
watch(
() => currentCrumbs.value,
(newValue, oldValue) => {
getCurrentMembers(newValue)
},
)
const deleteMember = (item) => {
membersCheckedKeys.value = membersCheckedKeys.value.filter(
(v) => v.ID !== item.ID,
)
}
const getDepTotalMembers = (item) => {
const rootNode = depTreeMyList.value[0]
const targetNode = findNodeById(rootNode, item.ID)
if (targetNode) {
return calculateTotalStaffNum(targetNode)
}
return 0
}
const totalMembers = computed(() => {
const depMembers = allCheckedList.value.reduce(
(sum, item) => sum + item.staffNum,
0,
)
const memberCount = membersCheckedKeys.value.length
return depMembers + memberCount
})
//
const toUserDetail = (userItem) => {
console.log(userItem)
uni.navigateTo({
url:
'/pages/dialog/dialogDetail/userDetail??erpUserId=' +
(userItem.erp_user_id || userItem.ID),
})
}
</script>
<style scoped lang="scss">
::v-deep .zp-paging-container-content {
height: 100%;
display: flex;
}
.choose-deps-page {
.choose-deps {
flex: 1;
display: flex;
flex-direction: column;
background-image: url('@/static/image/clockIn/z3280@3x.png');
background-size: cover;
background-position: bottom center;
padding: 20rpx 0;
background-attachment: fixed;
}
}
.divider {
height: 1rpx;
background-color: #707070;
opacity: 0.1;
}
.vDivider {
width: 1rpx;
height: 48rpx;
background-color: #b4b4b4;
}
.avatar-placeholder {
width: 192rpx;
height: 192rpx;
background-color: #e0e0e0;
border-radius: 50%;
margin-bottom: 40rpx;
}
.groupCard {
height: 272rpx;
width: 100%;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
border-radius: 12rpx;
&.firstPanel {
background-image: url('@/static/image/chatList/zu6033@2x.png');
}
&.secondPanel {
background-image: url('@/static/image/chatList/zu6031@2x.png');
margin-top: 28rpx;
margin-bottom: 28rpx;
}
&.thirdPanel {
background-image: url('@/static/image/chatList/zu6032@2x.png');
}
&.activePanel {
box-shadow: 0 0 0 3rpx #46299d;
}
}
.btnBox {
margin: 14rpx 0 0;
::v-deep .custom-btn-class {
padding: 18rpx 104rpx !important;
width: unset !important;
}
::v-deep .is-disabled {
background-color: #e6e6e6 !important;
color: #bebebe !important;
}
::v-deep .wd-button__text {
font-size: 28rpx !important;
font-weight: 500 !important;
line-height: 40rpx !important;
}
}
.no-scrollbar {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
.no-scrollbar::-webkit-scrollbar {
display: none; /* Chrome, Safari, and Opera */
}
.diyBtn {
::v-deep .custom-btn-class {
padding: 8rpx 30rpx !important;
width: unset !important;
min-width: unset !important;
height: unset !important;
}
::v-deep .wd-button__text {
font-size: 24rpx !important;
font-weight: 400 !important;
line-height: 34rpx !important;
color: #191919;
}
::v-deep .custom-btn-class {
background-color: #fff !important;
border: 2rpx solid #d6d6d8 !important;
}
}
.confirm-btn-area {
box-shadow: 0 1px 0 2px rgba(231, 231, 231, 1);
}
.scroll-view-style {
-ms-overflow-style: none;
overflow: -moz-scrollbars-none;
::-webkit-scrollbar {
width: 0 !important;
}
}
.userAvatar {
background: linear-gradient(#674bbc, #46299d);
width: 72rpx;
height: 72rpx;
border-radius: 36rpx;
color: #fff;
font-size: 24rpx;
font-weight: bold;
}
.postTag {
background-color: #eee9f8;
height: 32rpx;
line-height: 32rpx;
font-size: 20rpx;
padding: 0 12rpx 0 12rpx;
color: #46299d;
}
</style>

View File

@ -83,7 +83,6 @@ const { t } = useI18n()
const state = reactive({
erpUserId: '', //erpid
userId: '', //Id
userInfo: null, //
userBasicInfos: [], //
})
@ -94,9 +93,6 @@ onLoad((options) => {
state.erpUserId = Number(options.erpUserId)
getUserInfo()
}
if(options.user_id){
state.userId = Number(options.user_id)
}
})
//
@ -177,7 +173,7 @@ const getUserInfo = () => {
//
const toTalkUser = () => {
talkStore.toTalk(1, state.userId, state.erpUserId)
talkStore.toTalk(1, state.userInfo.sys_id, state.erpUserId)
}
</script>
<style scoped lang="scss">

View File

@ -840,10 +840,7 @@ const toChatSettingsPage = () => {
const toUserDetailPage = (userItem) => {
uni.navigateTo({
url:
'/pages/dialog/dialogDetail/userDetail?erpUserId=' +
userItem.erp_user_id +
'&user_id=' +
userItem.user_id,
'/pages/dialog/dialogDetail/userDetail?erpUserId=' + userItem.erp_user_id,
})
}

View File

@ -135,7 +135,7 @@ const toSearchPage = () => {
//
const toAddressBookPage = () => {
uni.navigateTo({
url: '/pages/addressBook/index',
url: '/pages/chooseByDeps/index?chooseMode=3',
})
}
@ -152,10 +152,10 @@ onShow(() => {
})
onLoad((options) => {
if (options?.openSessionIndex || options?.openSessionIndex === 0) {
if (options?.openSessionIndexName) {
if (items?.value?.length > 0) {
items.value.forEach((openSession,index) => {
if (index === Number(options?.openSessionIndex)) {
items.value.forEach((openSession) => {
if (openSession.index_name === options?.openSessionIndexName) {
dialogueStore.setDialogue(openSession)
if (openSession.unread_num > 0) {
ServeClearTalkUnreadNum({

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -217,11 +217,13 @@ export const useDialogueStore = defineStore('dialogue', {
//清空聊天记录
apiClearRecord() {
const { clearDialogueRecord } = useDialogueListStore()
ServeEmptyMessage({
talk_type: this.talk.talk_type,
receiver_id: this.talk.receiver_id,
}).then((res) => {
if (res.code == 200) {
clearDialogueRecord()
} else {
}
})

View File

@ -2,42 +2,44 @@ import { defineStore } from 'pinia'
import { useDialogueStore } from '@/store'
import lodash from 'lodash'
import {ref} from 'vue'
import {createGlobalState,useStorage} from '@vueuse/core'
import {uniStorage} from "@/utils/uniStorage.js"
import { ref } from 'vue'
import { createGlobalState, useStorage } from '@vueuse/core'
import { uniStorage } from '@/utils/uniStorage.js'
export const useDialogueListStore = createGlobalState(() => {
const dialogueList = useStorage('dialogueList', [], uniStorage)
const zpagingRef = ref()
const virtualList = ref([])
const getDialogueList=(indexName)=>{
return dialogueList.value.find(item=>item.index_name===indexName)
const getDialogueList = (indexName) => {
return dialogueList.value.find((item) => item.index_name === indexName)
}
const addDialogueRecord=(newRecords,type='add')=>{
console.log(newRecords);
const addDialogueRecord = (newRecords, type = 'add') => {
console.log(newRecords)
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)
const existingIndex = dialogueList.value.findIndex(
(item) => item.index_name === dialogue.index_name,
)
if (existingIndex === -1) {
// 如果不存在,直接添加
dialogueList.value.push(dialogue)
} else {
// 如果对话存在,处理 records 数组
const { records = [] } = dialogue
newRecords.forEach(newRecord => {
newRecords.forEach((newRecord) => {
const recordIndex = dialogueList.value[existingIndex].records.findIndex(
record => record.msg_id === newRecord.msg_id
(record) => record.msg_id === newRecord.msg_id,
)
if (recordIndex === -1) {
// 如果记录不存在,添加到 records 数组
if(type==='add'){
if (type === 'add') {
dialogueList.value[existingIndex].records.push(newRecord)
}else{
} else {
dialogueList.value[existingIndex].records.unshift(newRecord)
}
}
@ -47,72 +49,77 @@ export const useDialogueListStore = createGlobalState(() => {
const { index_name, records: _, ...updateProps } = dialogue
dialogueList.value[existingIndex] = {
...dialogueList.value[existingIndex],
...updateProps
...updateProps,
}
}
}
const updateDialogueRecord=(record)=>{
const updateDialogueRecord = (record) => {
const dialogue = lodash.cloneDeep(useDialogueStore())
const item = getDialogueList(dialogue.index_name)
const recordIndex = item.records.findIndex(item=>item.msg_id===record.msg_id)
if(recordIndex!==-1){
const recordIndex = item.records.findIndex(
(item) => item.msg_id === record.msg_id,
)
if (recordIndex !== -1) {
item.records[recordIndex] = {
...item.records[recordIndex],
...record
...record,
}
}
const virtualIndex = virtualList.value.findIndex(item=>item.msg_id===record.msg_id)
if(virtualIndex!==-1){
const virtualIndex = virtualList.value.findIndex(
(item) => item.msg_id === record.msg_id,
)
if (virtualIndex !== -1) {
virtualList.value[virtualIndex] = {
...virtualList.value[virtualIndex],
...record
...record,
}
}
}
const deleteDialogueRecord=(record)=>{
const deleteDialogueRecord = (record) => {
const dialogue = lodash.cloneDeep(useDialogueStore())
const item = getDialogueList(dialogue.index_name)
const recordIndex = item.records.findIndex(item=>item.msg_id===record.msg_id)
if(recordIndex!==-1){
item.records.splice(recordIndex,1)
const recordIndex = item.records.findIndex(
(item) => item.msg_id === record.msg_id,
)
if (recordIndex !== -1) {
item.records.splice(recordIndex, 1)
}
}
const updateUploadProgress=(id,progress)=>{
const record = virtualList.value.find(item=>item.msg_id===id)
if(record){
const updateUploadProgress = (id, progress) => {
const record = virtualList.value.find((item) => item.msg_id === id)
if (record) {
record.uploadCurrent = progress
}
}
const updateZpagingRef=(params)=>{
zpagingRef.value=params
const updateZpagingRef = (params) => {
zpagingRef.value = params
}
const zpagingComplete=(index_name)=>{
const zpagingComplete = (index_name) => {
const item = getDialogueList(index_name)
zpagingRef.value?.complete(lodash.cloneDeep(item.records).reverse())
}
const addChatRecord = (indexName,item)=>{
const addChatRecord = (indexName, item) => {
const dialogue = lodash.cloneDeep(useDialogueStore())
if (dialogue?.index_name === indexName) {
zpagingRef.value?.addChatRecordData(item,false,false)
zpagingRef.value?.addChatRecordData(item, false, false)
}
}
const batchDelDialogueRecord=(msgIds)=>{
const batchDelDialogueRecord = (msgIds) => {
const dialogue = lodash.cloneDeep(useDialogueStore())
const item = getDialogueList(dialogue.index_name)
item.records = item.records.filter(item=>!msgIds.includes(item.msg_id))
item.records = item.records.filter((item) => !msgIds.includes(item.msg_id))
}
//删除会话时同时刪除storage中存儲的會話
const delDialogueStorage = (indexName) =>{
if(dialogueList?.value?.length > 0){
const delDialogueStorage = (indexName) => {
if (dialogueList?.value?.length > 0) {
dialogueList.value.forEach((item, index) => {
if (item?.index_name === indexName) {
dialogueList.value.splice(index, 1)
@ -121,6 +128,14 @@ export const useDialogueListStore = createGlobalState(() => {
}
}
//清空聊天记录时,同时清空本地保存的聊天记录
const clearDialogueRecord = () => {
const dialogue = lodash.cloneDeep(useDialogueStore())
const item = getDialogueList(dialogue.index_name)
item.records = []
virtualList.value = []
}
return {
dialogueList,
zpagingRef,
@ -134,6 +149,7 @@ export const useDialogueListStore = createGlobalState(() => {
addChatRecord,
virtualList,
batchDelDialogueRecord,
delDialogueStorage
delDialogueStorage,
clearDialogueRecord,
}
})

View File

@ -136,7 +136,7 @@ export const useTalkStore = defineStore('talk', {
if (this.findTalkIndex(`${talk_type}_${receiver_id}`) >= 0) {
sessionStorage.setItem(KEY_INDEX_NAME, `${talk_type}_${receiver_id}`)
uni.reLaunch({
url: '/pages/index/index?openSessionIndex=' + this.findTalkIndex(`${talk_type}_${receiver_id}`),
url: '/pages/index/index?openSessionIndexName=' + `${talk_type}_${receiver_id}`,
})
return
}
@ -151,7 +151,7 @@ export const useTalkStore = defineStore('talk', {
}
sessionStorage.setItem(KEY_INDEX_NAME, `${talk_type}_${receiver_id}`)
uni.reLaunch({
url: '/pages/index/index?openSessionIndex=' + this.findTalkIndex(`${talk_type}_${receiver_id}`),
url: '/pages/index/index?openSessionIndexName=' + `${talk_type}_${receiver_id}`,
})
} else {
message.warning(message)

View File

@ -139,5 +139,9 @@
"select.member.num": "已选择",
"statistic.unit.person": "人",
"pageTitle.create.group": "发起群聊",
"pageTitle.select.department": "选择部门"
"pageTitle.select.department": "选择部门",
"radio.btn.selectAll": "全选",
"choose.deps.nextLevel": "下级",
"statistics.selected.deps": "已选择的部门数",
"chat.manage.addMembers": "添加群成员"
}