Compare commits
6 Commits
478336c2fe
...
b04d25a243
Author | SHA1 | Date | |
---|---|---|---|
|
b04d25a243 | ||
|
9e31271cc3 | ||
|
6d08dbe42f | ||
701d878f7d | |||
7544b3d324 | |||
8c9f634d0b |
@ -32,6 +32,8 @@
|
|||||||
"quill": "^1.3.7",
|
"quill": "^1.3.7",
|
||||||
"quill-image-uploader": "^1.3.0",
|
"quill-image-uploader": "^1.3.0",
|
||||||
"quill-mention": "^4.1.0",
|
"quill-mention": "^4.1.0",
|
||||||
|
"sortablejs": "^1.15.6",
|
||||||
|
"viewerjs": "^1.11.7",
|
||||||
"vue": "^3.3.11",
|
"vue": "^3.3.11",
|
||||||
"vue-cropper": "^1.1.1",
|
"vue-cropper": "^1.1.1",
|
||||||
"vue-router": "^4.2.5",
|
"vue-router": "^4.2.5",
|
||||||
|
@ -62,6 +62,12 @@ importers:
|
|||||||
quill-mention:
|
quill-mention:
|
||||||
specifier: ^4.1.0
|
specifier: ^4.1.0
|
||||||
version: 4.1.0
|
version: 4.1.0
|
||||||
|
sortablejs:
|
||||||
|
specifier: ^1.15.6
|
||||||
|
version: 1.15.6
|
||||||
|
viewerjs:
|
||||||
|
specifier: ^1.11.7
|
||||||
|
version: 1.11.7
|
||||||
vue:
|
vue:
|
||||||
specifier: ^3.3.11
|
specifier: ^3.3.11
|
||||||
version: 3.5.13(typescript@5.2.2)
|
version: 3.5.13(typescript@5.2.2)
|
||||||
@ -2927,6 +2933,9 @@ packages:
|
|||||||
sortablejs@1.14.0:
|
sortablejs@1.14.0:
|
||||||
resolution: {integrity: sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w==}
|
resolution: {integrity: sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w==}
|
||||||
|
|
||||||
|
sortablejs@1.15.6:
|
||||||
|
resolution: {integrity: sha512-aNfiuwMEpfBM/CN6LY0ibyhxPfPbyFeBTYJKCvzkJ2GkUpazIt3H+QIPAMHwqQ7tMKaHz1Qj+rJJCqljnf4p3A==}
|
||||||
|
|
||||||
source-map-js@1.2.1:
|
source-map-js@1.2.1:
|
||||||
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@ -3211,6 +3220,9 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
vue: ^3.0.11
|
vue: ^3.0.11
|
||||||
|
|
||||||
|
viewerjs@1.11.7:
|
||||||
|
resolution: {integrity: sha512-0JuVqOmL5v1jmEAlG5EBDR3XquxY8DWFQbFMprOXgaBB0F7Q/X9xWdEaQc59D8xzwkdUgXEMSSknTpriq95igg==}
|
||||||
|
|
||||||
vite-hot-client@2.0.4:
|
vite-hot-client@2.0.4:
|
||||||
resolution: {integrity: sha512-W9LOGAyGMrbGArYJN4LBCdOC5+Zwh7dHvOHC0KmGKkJhsOzaKbpo/jEjpPKVHIW0/jBWj8RZG0NUxfgA8BxgAg==}
|
resolution: {integrity: sha512-W9LOGAyGMrbGArYJN4LBCdOC5+Zwh7dHvOHC0KmGKkJhsOzaKbpo/jEjpPKVHIW0/jBWj8RZG0NUxfgA8BxgAg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -6520,6 +6532,8 @@ snapshots:
|
|||||||
|
|
||||||
sortablejs@1.14.0: {}
|
sortablejs@1.14.0: {}
|
||||||
|
|
||||||
|
sortablejs@1.15.6: {}
|
||||||
|
|
||||||
source-map-js@1.2.1: {}
|
source-map-js@1.2.1: {}
|
||||||
|
|
||||||
source-map-resolve@0.5.3:
|
source-map-resolve@0.5.3:
|
||||||
@ -6808,6 +6822,8 @@ snapshots:
|
|||||||
evtd: 0.2.4
|
evtd: 0.2.4
|
||||||
vue: 3.5.13(typescript@5.2.2)
|
vue: 3.5.13(typescript@5.2.2)
|
||||||
|
|
||||||
|
viewerjs@1.11.7: {}
|
||||||
|
|
||||||
vite-hot-client@2.0.4(vite@4.5.14(@types/node@18.19.99)(less@4.3.0)(sass@1.88.0)(terser@5.39.0)):
|
vite-hot-client@2.0.4(vite@4.5.14(@types/node@18.19.99)(less@4.3.0)(sass@1.88.0)(terser@5.39.0)):
|
||||||
dependencies:
|
dependencies:
|
||||||
vite: 4.5.14(@types/node@18.19.99)(less@4.3.0)(sass@1.88.0)(terser@5.39.0)
|
vite: 4.5.14(@types/node@18.19.99)(less@4.3.0)(sass@1.88.0)(terser@5.39.0)
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<slot name="content"></slot>
|
<slot name="content"></slot>
|
||||||
<template #footer>
|
<template #footer v-if="actionBtns.cancelBtn || actionBtns.confirmBtn">
|
||||||
<div class="custom-modal-btns">
|
<div class="custom-modal-btns">
|
||||||
<customBtn
|
<customBtn
|
||||||
color="#C7C7C9"
|
color="#C7C7C9"
|
||||||
|
@ -2,14 +2,14 @@
|
|||||||
<div class="row items-center">
|
<div class="row items-center">
|
||||||
<div v-if="state.treeData.edit">
|
<div v-if="state.treeData.edit">
|
||||||
<n-input v-model:value="state.editTitle"
|
<n-input v-model:value="state.editTitle"
|
||||||
style="width:120px" />
|
style="max-width:200px" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<n-popover trigger="hover"
|
<n-popover trigger="hover"
|
||||||
v-else>
|
v-else>
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<div style="width:120px"
|
<div style="max-width:200px"
|
||||||
class="fl-px-sm sf-text-ellipsis">{{ state.treeData.title }}</div>
|
class="fl-px-sm sf-text-ellipsis">{{ state.treeData.title + '(' + state.treeData.staffNum + ')' }}</div>
|
||||||
</template>
|
</template>
|
||||||
<div>{{ state.treeData.title }}</div>
|
<div>{{ state.treeData.title }}</div>
|
||||||
</n-popover>
|
</n-popover>
|
||||||
|
70
src/components/search/highLightText.vue
Normal file
70
src/components/search/highLightText.vue
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
<template>
|
||||||
|
<span>
|
||||||
|
<template v-for="(part, index) in parts" :key="index">
|
||||||
|
<span v-if="part.highlighted" :class="highlightClass">
|
||||||
|
{{ part.text }}
|
||||||
|
</span>
|
||||||
|
<span v-else>{{ part.text }}</span>
|
||||||
|
</template>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
text: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
searchText: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
highlightClass: {
|
||||||
|
type: String,
|
||||||
|
default: 'highlight',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const escapedSearchText = computed(() =>
|
||||||
|
String(props.searchText).replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'),
|
||||||
|
)
|
||||||
|
|
||||||
|
const pattern = computed(() => new RegExp(escapedSearchText.value, 'gi'))
|
||||||
|
|
||||||
|
const parts = computed(() => {
|
||||||
|
if (!props.searchText || !props.text)
|
||||||
|
return [{ text: props.text, highlighted: false }];
|
||||||
|
|
||||||
|
const result = [];
|
||||||
|
let currentIndex = 0;
|
||||||
|
const escapedSearchTextValue = escapedSearchText.value;
|
||||||
|
const searchPattern = new RegExp(`(${escapedSearchTextValue})`, 'gi');
|
||||||
|
|
||||||
|
props.text.replace(searchPattern, (match, p1, offset) => {
|
||||||
|
// 添加非高亮文本
|
||||||
|
if (currentIndex < offset) {
|
||||||
|
result.push({ text: props.text.slice(currentIndex, offset), highlighted: false });
|
||||||
|
}
|
||||||
|
// 添加高亮文本
|
||||||
|
result.push({ text: p1, highlighted: true });
|
||||||
|
// 更新当前索引
|
||||||
|
currentIndex = offset + p1.length;
|
||||||
|
return p1; // 这个返回值不影响最终结果,只是replace方法的要求
|
||||||
|
});
|
||||||
|
|
||||||
|
// 添加剩余的非高亮文本(如果有的话)
|
||||||
|
if (currentIndex < props.text.length) {
|
||||||
|
result.push({ text: props.text.slice(currentIndex), highlighted: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.highlight {
|
||||||
|
color: #7a58de;
|
||||||
|
}
|
||||||
|
</style>
|
337
src/components/search/searchItem.vue
Normal file
337
src/components/search/searchItem.vue
Normal file
@ -0,0 +1,337 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="search-item"
|
||||||
|
:class="props?.conditionType ? 'search-item-condition' : ''"
|
||||||
|
v-if="resultName"
|
||||||
|
:style="props.searchResultKey === 'talk_record_infos_receiver' ? 'margin: 12px 0 0' : ''"
|
||||||
|
>
|
||||||
|
<div class="search-item-avatar">
|
||||||
|
<avatarModule
|
||||||
|
:mode="props.searchItem?.group_type === 0 ? 1 : 2"
|
||||||
|
:avatar="avatarImg"
|
||||||
|
:userName="resultName"
|
||||||
|
:groupType="props.searchItem?.group_type"
|
||||||
|
:customStyle="{
|
||||||
|
width: props?.conditionType ? '32px' : '42px',
|
||||||
|
height: props?.conditionType ? '32px' : '42px',
|
||||||
|
margin: props?.conditionType ? '0 9px 0 0' : '0 10px 0 0'
|
||||||
|
}"
|
||||||
|
:customTextStyle="{
|
||||||
|
fontSize: props?.conditionType ? '10px' : '14px',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
color: '#fff',
|
||||||
|
lineHeight: '24px'
|
||||||
|
}"
|
||||||
|
></avatarModule>
|
||||||
|
<div
|
||||||
|
class="info-tag"
|
||||||
|
v-if="resultType && !searchRecordDetail"
|
||||||
|
:style="'border-color:' + resultTypeColor"
|
||||||
|
>
|
||||||
|
<span class="text-[10px] font-medium" :style="'color:' + resultTypeColor">
|
||||||
|
{{ resultType }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="result-info">
|
||||||
|
<div class="info-name" :class="searchRecordDetail ? 'info-name-searchRecordDetail' : ''">
|
||||||
|
<HighlightText
|
||||||
|
:class="
|
||||||
|
props?.conditionType
|
||||||
|
? 'text-[14px] font-medium'
|
||||||
|
: searchRecordDetail
|
||||||
|
? 'text-[12px] font-medium'
|
||||||
|
: 'text-[14px] font-bold'
|
||||||
|
"
|
||||||
|
:text="resultName"
|
||||||
|
:searchText="props.searchText"
|
||||||
|
/>
|
||||||
|
<div class="info_num" v-if="groupNum">
|
||||||
|
<span class="text-[14px] font-medium">
|
||||||
|
{{ '(' + groupNum + ')' }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div v-if="searchRecordDetail && chatRecordCreatedAt">
|
||||||
|
<span class="text-[12px] font-medium">
|
||||||
|
{{ chatRecordCreatedAt }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="info-detail"
|
||||||
|
v-if="resultDetail"
|
||||||
|
:class="searchRecordDetail ? 'info-detail-searchRecordDetail' : ''"
|
||||||
|
>
|
||||||
|
<HighlightText
|
||||||
|
class="text-[12px] font-regular"
|
||||||
|
:text="resultDetail"
|
||||||
|
:searchText="props.searchText"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="search-item-pointer" v-if="pointerIconSrc">
|
||||||
|
<img :src="pointerIconSrc" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import avatarModule from '@/components/avatar-module/index.vue'
|
||||||
|
import { ref, watch, computed, onMounted, onUnmounted, reactive, defineProps } from 'vue'
|
||||||
|
import HighlightText from './highLightText.vue'
|
||||||
|
import { beautifyTime } from '@/utils/datetime'
|
||||||
|
import { ChatMsgTypeMapping } from '@/constant/message'
|
||||||
|
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
|
||||||
|
} //搜索类型
|
||||||
|
})
|
||||||
|
// 映射表-查找对应结构下的属性名
|
||||||
|
const keyMapping = {
|
||||||
|
user_infos: { avatar: 'avatar', name: 'nickname' },
|
||||||
|
group_infos: { avatar: 'avatar', name: 'name', group_num: 'group_num' },
|
||||||
|
group_member_infos: {
|
||||||
|
avatar: 'group_avatar',
|
||||||
|
name: 'group_name',
|
||||||
|
detailKey: 'user_name',
|
||||||
|
group_num: 'group_num'
|
||||||
|
},
|
||||||
|
combinedGroup: {
|
||||||
|
avatar: props.searchItem?.groupTempType
|
||||||
|
? props.searchItem?.groupTempType === 'group_infos'
|
||||||
|
? 'avatar'
|
||||||
|
: props.searchItem?.groupTempType === 'group_member_infos'
|
||||||
|
? 'group_avatar'
|
||||||
|
: ''
|
||||||
|
: '',
|
||||||
|
name: props.searchItem?.groupTempType
|
||||||
|
? props.searchItem?.groupTempType === 'group_infos'
|
||||||
|
? 'name'
|
||||||
|
: props.searchItem?.groupTempType === 'group_member_infos'
|
||||||
|
? 'group_name'
|
||||||
|
: ''
|
||||||
|
: '',
|
||||||
|
detailKey: props.searchItem?.groupTempType
|
||||||
|
? props.searchItem?.groupTempType === 'group_member_infos'
|
||||||
|
? 'user_name'
|
||||||
|
: ''
|
||||||
|
: '',
|
||||||
|
group_num: props.searchItem?.groupTempType
|
||||||
|
? props.searchItem?.groupTempType === 'group_infos'
|
||||||
|
? 'group_num'
|
||||||
|
: props.searchItem?.groupTempType === 'group_member_infos'
|
||||||
|
? 'group_num'
|
||||||
|
: ''
|
||||||
|
: ''
|
||||||
|
},
|
||||||
|
general_infos: {
|
||||||
|
avatar: 'receiver_avatar',
|
||||||
|
name: 'receiver_name',
|
||||||
|
detailKey: 'count',
|
||||||
|
group_num: 'group_num'
|
||||||
|
},
|
||||||
|
talk_record_infos: {
|
||||||
|
avatar: 'user_avatar',
|
||||||
|
name: 'user_name',
|
||||||
|
detailKey: 'extra',
|
||||||
|
created_at: 'created_at'
|
||||||
|
},
|
||||||
|
talk_record_infos_receiver: {
|
||||||
|
avatar: 'receiver_avatar',
|
||||||
|
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) => {
|
||||||
|
let keyValue = ''
|
||||||
|
if (keys) {
|
||||||
|
keyValue = props?.searchItem ? props?.searchItem[keys] : ''
|
||||||
|
}
|
||||||
|
return keyValue
|
||||||
|
}
|
||||||
|
//头像
|
||||||
|
const avatarImg = computed(() => {
|
||||||
|
let avatar = getKeyValue(keyMapping[props.searchResultKey]?.avatar)
|
||||||
|
if (props?.conditionType) {
|
||||||
|
avatar = props.searchItem.avatar
|
||||||
|
}
|
||||||
|
return avatar
|
||||||
|
})
|
||||||
|
//名称
|
||||||
|
const resultName = computed(() => {
|
||||||
|
let result_name = getKeyValue(keyMapping[props.searchResultKey]?.name)
|
||||||
|
if (props?.conditionType) {
|
||||||
|
result_name = props.searchItem.nickname
|
||||||
|
}
|
||||||
|
return result_name
|
||||||
|
})
|
||||||
|
//文字头像
|
||||||
|
const imgText = computed(() => {
|
||||||
|
return resultName.value.length >= 2 ? resultName.value.slice(-2) : resultName.value
|
||||||
|
})
|
||||||
|
// 映射表-根据groupType设置对应值
|
||||||
|
const groupTypeMapping = {
|
||||||
|
0: {},
|
||||||
|
1: {},
|
||||||
|
2: {
|
||||||
|
result_type: '部门',
|
||||||
|
result_type_color: '#377EC6'
|
||||||
|
},
|
||||||
|
3: {
|
||||||
|
result_type: '项目',
|
||||||
|
result_type_color: '#C1681C'
|
||||||
|
},
|
||||||
|
4: {
|
||||||
|
result_type: '公司',
|
||||||
|
result_type_color: '#7A58DE'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//群人数
|
||||||
|
const groupNum = computed(() => {
|
||||||
|
return getKeyValue(keyMapping[props.searchResultKey]?.group_num)
|
||||||
|
})
|
||||||
|
//群类型tag
|
||||||
|
const resultType = computed(() => {
|
||||||
|
return groupTypeMapping[props.searchItem?.group_type]?.result_type
|
||||||
|
})
|
||||||
|
//群类型tag颜色
|
||||||
|
const resultTypeColor = computed(() => {
|
||||||
|
return groupTypeMapping[props.searchItem?.group_type]?.result_type_color
|
||||||
|
})
|
||||||
|
//搜索聊天记录详情-时间
|
||||||
|
const chatRecordCreatedAt = computed(() => {
|
||||||
|
let created_at = getKeyValue(keyMapping[props.searchResultKey]?.created_at)
|
||||||
|
return beautifyTime(created_at)
|
||||||
|
})
|
||||||
|
//详细内容
|
||||||
|
const resultDetail = computed(() => {
|
||||||
|
let result_detail = props.searchItem[keyMapping[props.searchResultKey]?.detailKey]
|
||||||
|
switch (keyMapping[props.searchResultKey]?.detailKey) {
|
||||||
|
case 'count':
|
||||||
|
result_detail = result_detail + '条聊天记录'
|
||||||
|
break
|
||||||
|
case 'user_name':
|
||||||
|
result_detail = '包含:' + result_detail
|
||||||
|
break
|
||||||
|
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 = ''
|
||||||
|
}
|
||||||
|
return result_detail
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.search-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
padding: 11px 0 12px;
|
||||||
|
border-bottom: 1px solid #f8f8f8;
|
||||||
|
|
||||||
|
.search-item-avatar{
|
||||||
|
position: relative;
|
||||||
|
.info-tag {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0px 6px;
|
||||||
|
border: 1px solid #000;
|
||||||
|
border-radius: 3px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
background-color: #fff;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 4px;
|
||||||
|
span {
|
||||||
|
line-height: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-info {
|
||||||
|
width: 100%;
|
||||||
|
.info-name {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
span {
|
||||||
|
color: #191919;
|
||||||
|
line-height: 22px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.info-name-searchRecordDetail {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
span {
|
||||||
|
color: #999999;
|
||||||
|
line-height: 17px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.info-detail {
|
||||||
|
span {
|
||||||
|
color: #999999;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.info-detail-searchRecordDetail {
|
||||||
|
span {
|
||||||
|
color: #191919;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.search-item-pointer {
|
||||||
|
width: 5.5px;
|
||||||
|
height: 9px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.search-item-condition {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
</style>
|
743
src/components/search/searchList.vue
Normal file
743
src/components/search/searchList.vue
Normal file
@ -0,0 +1,743 @@
|
|||||||
|
<template>
|
||||||
|
<div class="search-list">
|
||||||
|
<div class="search-result">
|
||||||
|
<div class="search-result-list">
|
||||||
|
<div
|
||||||
|
class="search-result-each-part"
|
||||||
|
v-for="(searchResultValue, searchResultKey, searchResultIndex) in state.searchResult"
|
||||||
|
:key="searchResultKey"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="search-result-part"
|
||||||
|
v-if="
|
||||||
|
Array.isArray(state?.searchResult[searchResultKey]) &&
|
||||||
|
state?.searchResult[searchResultKey].length > 0 &&
|
||||||
|
searchResultKey !== 'group_infos' &&
|
||||||
|
searchResultKey !== 'group_member_infos'
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<div class="result-title">
|
||||||
|
<span class="text-[14px] font-regular">
|
||||||
|
{{ getResultKeysValue(searchResultKey) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="result-list">
|
||||||
|
<div
|
||||||
|
class="result-list-each"
|
||||||
|
v-for="(item, index) in state?.searchResult[searchResultKey]"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
|
<searchItem
|
||||||
|
@click="clickSearchItem(searchResultKey, item)"
|
||||||
|
v-if="(props.listLimit && index < 3) || !props.listLimit"
|
||||||
|
:searchResultKey="searchResultKey"
|
||||||
|
:searchItem="item"
|
||||||
|
:searchText="state.searchText"
|
||||||
|
:searchRecordDetail="props.searchRecordDetail"
|
||||||
|
></searchItem>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="result-has-more"
|
||||||
|
v-if="getHasMoreResult(searchResultKey)"
|
||||||
|
@click="toMoreResultPage(searchResultKey)"
|
||||||
|
>
|
||||||
|
<span class="text-[14px] font-regular">
|
||||||
|
{{ getHasMoreResult(searchResultKey) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- <ZPaging
|
||||||
|
ref="zPaging"
|
||||||
|
:show-scrollbar="false"
|
||||||
|
v-model="state.searchResultList"
|
||||||
|
@query="queryAllSearch"
|
||||||
|
:default-page-no="state.pageNum"
|
||||||
|
:default-page-size="props.searchResultPageSize"
|
||||||
|
:loading-more-default-as-loading="true"
|
||||||
|
:inside-more="true"
|
||||||
|
:empty-view-img="searchNoData"
|
||||||
|
:empty-view-text="'检索您要查找的内容吧~'"
|
||||||
|
:empty-view-img-style="{ width: '238px', height: '131px' }"
|
||||||
|
:empty-view-title-style="{
|
||||||
|
color: '#999999',
|
||||||
|
margin: '-10px 0 0',
|
||||||
|
'line-height': '20px',
|
||||||
|
'font-size': '14px',
|
||||||
|
'font-weight': 400,
|
||||||
|
}"
|
||||||
|
:refresher-enabled="false"
|
||||||
|
>
|
||||||
|
<template #top>
|
||||||
|
<div class="searchRoot">
|
||||||
|
<customInput
|
||||||
|
:searchText="state.searchText"
|
||||||
|
:first_talk_record_infos="state.first_talk_record_infos"
|
||||||
|
@inputSearchText="inputSearchText"
|
||||||
|
></customInput>
|
||||||
|
<span
|
||||||
|
class="searchRoot_cancelBtn text-[16px] font-medium"
|
||||||
|
@click="cancelSearch"
|
||||||
|
>
|
||||||
|
取消
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div
|
||||||
|
class="search-record-detail"
|
||||||
|
v-if="props.searchRecordDetail && !props?.hideFirstRecord"
|
||||||
|
>
|
||||||
|
<searchItem
|
||||||
|
@click="
|
||||||
|
clickSearchItem(
|
||||||
|
'talk_record_infos_receiver',
|
||||||
|
state?.first_talk_record_infos,
|
||||||
|
)
|
||||||
|
"
|
||||||
|
searchResultKey="talk_record_infos_receiver"
|
||||||
|
:searchItem="state?.first_talk_record_infos"
|
||||||
|
:pointerIconSrc="pointerIconSrc"
|
||||||
|
></searchItem>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="search-result"
|
||||||
|
:style="
|
||||||
|
!state.searchText ? 'align-items:center;justify-content:center;' : ''
|
||||||
|
"
|
||||||
|
>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</ZPaging> -->
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
// import searchNoData from '@/static/image/search/search-no-data.png'
|
||||||
|
// import customInput from '@/components/custom-input/custom-input.vue'
|
||||||
|
// import pointerIconSrc from '@/static/image/search/search-item-pointer.png'
|
||||||
|
// import lodash from 'lodash'
|
||||||
|
// import { useUserStore } from '@/store'
|
||||||
|
// const userStore = useUserStore()
|
||||||
|
|
||||||
|
// 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'
|
||||||
|
// const zPaging = ref()
|
||||||
|
// useZPaging(zPaging)
|
||||||
|
|
||||||
|
import searchItem from './searchItem.vue'
|
||||||
|
import { ref, reactive, defineEmits, defineProps, onMounted } from 'vue'
|
||||||
|
|
||||||
|
const emits = defineEmits(['toMoreResultPage', 'lastIdChange', 'clickSearchItem'])
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
searchText: '', //搜索内容
|
||||||
|
searchResultList: [], //搜素结果列表
|
||||||
|
searchResult: null, //搜索结果
|
||||||
|
pageNum: 1, //当前请求数据页数
|
||||||
|
uid: 1496 //当前用户id
|
||||||
|
})
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
searchResultPageSize: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
}, //搜索结果每页数据量
|
||||||
|
listLimit: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}, //是否限制列表内数据数量
|
||||||
|
apiParams: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}, //请求参数
|
||||||
|
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
|
||||||
|
} //是否隐藏前缀及搜索群/用户主体信息
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (props.searchText) {
|
||||||
|
state.searchText = props.searchText
|
||||||
|
queryAllSearch(1, 10)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
//输入搜索文本
|
||||||
|
const inputSearchText = (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()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ES搜索聊天记录-主页搜索什么都有、指定用户、指定群、群与用户概览
|
||||||
|
const queryAllSearch = (pageNum, searchResultPageSize) => {
|
||||||
|
let params = {
|
||||||
|
key: state.searchText, //关键字
|
||||||
|
size: searchResultPageSize
|
||||||
|
}
|
||||||
|
if (props.apiParams) {
|
||||||
|
let apiParams = JSON.parse(decodeURIComponent(props.apiParams))
|
||||||
|
params = Object.assign({}, params, apiParams)
|
||||||
|
}
|
||||||
|
const data = {
|
||||||
|
user_infos: [
|
||||||
|
{
|
||||||
|
id: 127,
|
||||||
|
mobile: '17706200252',
|
||||||
|
nickname: '测试-王溢韬',
|
||||||
|
avatar:
|
||||||
|
'https://dci-file-new.bj.bcebos.com/fonchain-main/test/runtime/image/avatar/40/b8ed6fea-6662-416d-8bb3-1fd8a8197061.jpg',
|
||||||
|
created_at: '2025-03-28 11:33:13',
|
||||||
|
erp_user_id: 18282
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 103,
|
||||||
|
mobile: '13814969538',
|
||||||
|
nickname: '王静测试',
|
||||||
|
avatar: '',
|
||||||
|
created_at: '2025-03-27 14:44:23',
|
||||||
|
erp_user_id: 2639
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 57,
|
||||||
|
mobile: '13862027511',
|
||||||
|
nickname: '王西',
|
||||||
|
avatar:
|
||||||
|
'https://dci-file-new.bj.bcebos.com/fonchain-main/test/runtime/image/avatar/40/b8ed6fea-6662-416d-8bb3-1fd8a8197061.jpg',
|
||||||
|
created_at: '2025-03-27 14:44:23',
|
||||||
|
erp_user_id: 18229
|
||||||
|
}
|
||||||
|
],
|
||||||
|
user_count: 9,
|
||||||
|
group_infos: null,
|
||||||
|
group_member_infos: [
|
||||||
|
{
|
||||||
|
id: 79,
|
||||||
|
group_id: 1,
|
||||||
|
group_name: '泰丰国际',
|
||||||
|
group_type: 4,
|
||||||
|
group_avatar: '',
|
||||||
|
group_num: 103,
|
||||||
|
user_id: 103,
|
||||||
|
user_name: '王静',
|
||||||
|
user_card: '',
|
||||||
|
created_at: '2025-03-27 14:44:24'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 55,
|
||||||
|
group_id: 1,
|
||||||
|
group_name: '泰丰国际',
|
||||||
|
group_type: 4,
|
||||||
|
group_avatar: '',
|
||||||
|
group_num: 103,
|
||||||
|
user_id: 57,
|
||||||
|
user_name: '王西',
|
||||||
|
user_card: '',
|
||||||
|
created_at: '2025-03-27 14:44:24'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 35,
|
||||||
|
group_id: 1,
|
||||||
|
group_name: '泰丰国际',
|
||||||
|
group_type: 4,
|
||||||
|
group_avatar: '',
|
||||||
|
group_num: 103,
|
||||||
|
user_id: 37,
|
||||||
|
user_name: '王雯婷',
|
||||||
|
user_card: '',
|
||||||
|
created_at: '2025-03-27 14:44:24'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
group_count: 9,
|
||||||
|
general_infos: [
|
||||||
|
{
|
||||||
|
receiver_id: 40,
|
||||||
|
receiver_name: '孙志远',
|
||||||
|
receiver_avatar:
|
||||||
|
'https://dci-file-new.bj.bcebos.com/fonchain-main/test/runtime/image/avatar/40/b8ed6fea-6662-416d-8bb3-1fd8a8197061.jpg',
|
||||||
|
group_num: 0,
|
||||||
|
talk_type: 1,
|
||||||
|
count: 3,
|
||||||
|
group_type: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
receiver_id: 2,
|
||||||
|
receiver_name: '吹牛个人群',
|
||||||
|
receiver_avatar: '',
|
||||||
|
group_num: 4,
|
||||||
|
talk_type: 2,
|
||||||
|
count: 2,
|
||||||
|
group_type: 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
receiver_id: 3,
|
||||||
|
receiver_name: '丰链30自己人',
|
||||||
|
receiver_avatar:
|
||||||
|
'https://e-cdn.fontree.cn/fonchain-main/prod/image/default/fonchain-chat/3d273326-d2a5-4ad4-a974-32d020c6b3f9.jpg?width=1080&height=2412',
|
||||||
|
group_num: 8,
|
||||||
|
talk_type: 2,
|
||||||
|
count: 2,
|
||||||
|
group_type: 3
|
||||||
|
}
|
||||||
|
],
|
||||||
|
record_count: 3
|
||||||
|
}
|
||||||
|
if ((data.user_infos || []).length > 0) {
|
||||||
|
;(data.user_infos || []).forEach((item) => {
|
||||||
|
item.group_type = 0
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if ((data.group_infos || []).length > 0) {
|
||||||
|
;(data.group_infos || []).forEach((item) => {
|
||||||
|
item.group_type = item.type
|
||||||
|
item.groupTempType = 'group_infos'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if ((data.group_member_infos || []).length > 0) {
|
||||||
|
;(data.group_member_infos || []).forEach((item) => {
|
||||||
|
item.groupTempType = 'group_member_infos'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if ((data.talk_record_infos || []).length > 0) {
|
||||||
|
let receiverInfo = JSON.parse(JSON.stringify(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 || []).forEach((item) => {
|
||||||
|
item.group_type = 0
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let tempGeneral_infos = Array.isArray(data.general_infos)
|
||||||
|
? [...data.general_infos]
|
||||||
|
: data.general_infos
|
||||||
|
delete data.general_infos
|
||||||
|
data.combinedGroup = (data.group_infos || []).concat(data.group_member_infos || [])
|
||||||
|
data.general_infos = tempGeneral_infos
|
||||||
|
|
||||||
|
// 检查数据是否为空
|
||||||
|
let isEmpty = true
|
||||||
|
let dataKeys = Object.keys(data)
|
||||||
|
let paginationKey = ''
|
||||||
|
dataKeys.forEach((item) => {
|
||||||
|
if (Array.isArray(data[item]) && data[item].length > 0) {
|
||||||
|
paginationKey = item
|
||||||
|
isEmpty = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (isEmpty) {
|
||||||
|
if (pageNum === 1) {
|
||||||
|
// 第一页请求且为空,清空结果
|
||||||
|
state.searchResult = null
|
||||||
|
// zPaging.value?.complete([])
|
||||||
|
} else {
|
||||||
|
// 加载更多且为空,保持原列表不变
|
||||||
|
// zPaging.value?.complete(state.searchResult ? [state.searchResult] : [])
|
||||||
|
}
|
||||||
|
} 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
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// zPaging.value?.completeByTotal([data], total)
|
||||||
|
} else {
|
||||||
|
state.searchResult = data
|
||||||
|
// zPaging.value?.complete([data])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// const resp = props.apiRequest(params)
|
||||||
|
// resp.then(({ code, data }) => {
|
||||||
|
// console.log(data)
|
||||||
|
// if (code == 200) {
|
||||||
|
// if ((data.user_infos || []).length > 0) {
|
||||||
|
// ;(data.user_infos || []).forEach((item) => {
|
||||||
|
// item.group_type = 0
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// if ((data.group_infos || []).length > 0) {
|
||||||
|
// ;(data.group_infos || []).forEach((item) => {
|
||||||
|
// item.group_type = item.type
|
||||||
|
// item.groupTempType = 'group_infos'
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// if ((data.group_member_infos || []).length > 0) {
|
||||||
|
// ;(data.group_member_infos || []).forEach((item) => {
|
||||||
|
// item.groupTempType = 'group_member_infos'
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// if ((data.talk_record_infos || []).length > 0) {
|
||||||
|
// let receiverInfo = JSON.parse(JSON.stringify(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 || []).forEach((item) => {
|
||||||
|
// item.group_type = 0
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
|
||||||
|
// let tempGeneral_infos = Array.isArray(data.general_infos)
|
||||||
|
// ? [...data.general_infos]
|
||||||
|
// : data.general_infos
|
||||||
|
// delete data.general_infos
|
||||||
|
// data.combinedGroup = (data.group_infos || []).concat(
|
||||||
|
// data.group_member_infos || [],
|
||||||
|
// )
|
||||||
|
// data.general_infos = tempGeneral_infos
|
||||||
|
|
||||||
|
// // 检查数据是否为空
|
||||||
|
// let isEmpty = true
|
||||||
|
// let dataKeys = Object.keys(data)
|
||||||
|
// let paginationKey = ''
|
||||||
|
// dataKeys.forEach((item) => {
|
||||||
|
// if (Array.isArray(data[item]) && data[item].length > 0) {
|
||||||
|
// paginationKey = item
|
||||||
|
// isEmpty = false
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
|
||||||
|
// if (isEmpty) {
|
||||||
|
// if (pageNum === 1) {
|
||||||
|
// // 第一页请求且为空,清空结果
|
||||||
|
// state.searchResult = null
|
||||||
|
// zPaging.value?.complete([])
|
||||||
|
// } else {
|
||||||
|
// // 加载更多且为空,保持原列表不变
|
||||||
|
// zPaging.value?.complete(state.searchResult ? [state.searchResult] : [])
|
||||||
|
// }
|
||||||
|
// } 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
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// zPaging.value?.completeByTotal([data], total)
|
||||||
|
// } else {
|
||||||
|
// state.searchResult = data
|
||||||
|
// zPaging.value?.complete([data])
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// if (pageNum === 1) {
|
||||||
|
// // 第一页请求失败,清空结果
|
||||||
|
// state.searchResult = null
|
||||||
|
// zPaging.value?.complete([])
|
||||||
|
// } else {
|
||||||
|
// // 加载更多失败,保持原列表不变
|
||||||
|
// zPaging.value?.complete(state.searchResult ? [state.searchResult] : [])
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
|
||||||
|
// resp.catch(() => {
|
||||||
|
// if (pageNum === 1) {
|
||||||
|
// // 第一页请求异常,清空结果
|
||||||
|
// state.searchResult = null
|
||||||
|
// zPaging.value?.complete([])
|
||||||
|
// } else {
|
||||||
|
// // 加载更多异常,保持原列表不变
|
||||||
|
// zPaging.value?.complete(state.searchResult ? [state.searchResult] : [])
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
}
|
||||||
|
|
||||||
|
//点击取消搜索
|
||||||
|
const cancelSearch = () => {
|
||||||
|
const pages = getCurrentPages()
|
||||||
|
if (pages.length > 1) {
|
||||||
|
uni.navigateBack({
|
||||||
|
delta: 1
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
uni.reLaunch({
|
||||||
|
url: '/pages/index/index'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取key对应值
|
||||||
|
const getResultKeysValue = (keys) => {
|
||||||
|
let resultKey = ''
|
||||||
|
switch (keys) {
|
||||||
|
case 'user_infos':
|
||||||
|
resultKey = '通讯录'
|
||||||
|
break
|
||||||
|
case 'group_infos':
|
||||||
|
resultKey = '群聊'
|
||||||
|
break
|
||||||
|
case 'group_member_infos':
|
||||||
|
resultKey = '群聊'
|
||||||
|
break
|
||||||
|
case 'combinedGroup':
|
||||||
|
resultKey = '群聊'
|
||||||
|
break
|
||||||
|
case 'general_infos':
|
||||||
|
resultKey = '聊天记录'
|
||||||
|
break
|
||||||
|
case 'talk_record_infos':
|
||||||
|
resultKey = '相关聊天记录'
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
resultKey = ''
|
||||||
|
}
|
||||||
|
return resultKey
|
||||||
|
}
|
||||||
|
|
||||||
|
//是否还有更多数据
|
||||||
|
const getHasMoreResult = (searchResultKey) => {
|
||||||
|
let has_more_result = ''
|
||||||
|
switch (searchResultKey) {
|
||||||
|
case 'user_infos':
|
||||||
|
if (state.searchResult['user_count'] && state.searchResult['user_count'] > 3) {
|
||||||
|
has_more_result = '更多通讯录'
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'group_infos':
|
||||||
|
if (state.searchResult['group_count'] && state.searchResult['group_count'] > 3) {
|
||||||
|
has_more_result = '更多群聊'
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'group_member_infos':
|
||||||
|
if (state.searchResult['group_count'] && state.searchResult['group_count'] > 3) {
|
||||||
|
has_more_result = '更多群聊'
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'combinedGroup':
|
||||||
|
if (state.searchResult['group_count'] && state.searchResult['group_count'] > 3) {
|
||||||
|
has_more_result = '更多群聊'
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'general_infos':
|
||||||
|
if (state.searchResult['record_count'] && state.searchResult['record_count'] >= 3) {
|
||||||
|
has_more_result = '更多聊天记录'
|
||||||
|
}
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
return has_more_result
|
||||||
|
}
|
||||||
|
|
||||||
|
//点击跳转到更多结果页面
|
||||||
|
const toMoreResultPage = (searchResultKey) => {
|
||||||
|
emits('toMoreResultPage', searchResultKey, state.searchText)
|
||||||
|
}
|
||||||
|
|
||||||
|
//点击了搜索结果项
|
||||||
|
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))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.search-list {
|
||||||
|
.searchRoot {
|
||||||
|
padding: 10px 24px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
|
||||||
|
.searchRoot_cancelBtn {
|
||||||
|
line-height: 22px;
|
||||||
|
color: #46299d;
|
||||||
|
margin: 0 0 0 10px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.search-record-detail {
|
||||||
|
padding: 0 25px;
|
||||||
|
}
|
||||||
|
.search-result {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0 10px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: flex-start;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
.search-result-list {
|
||||||
|
width: 100%;
|
||||||
|
// padding: 0 9px;
|
||||||
|
|
||||||
|
.search-result-part {
|
||||||
|
margin: 18px 0 0;
|
||||||
|
|
||||||
|
.result-title {
|
||||||
|
padding: 0 0 5px;
|
||||||
|
border-bottom: 1px solid #f8f8f8;
|
||||||
|
span {
|
||||||
|
line-height: 20px;
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.result-has-more {
|
||||||
|
padding: 10px 0;
|
||||||
|
border-bottom: 1px solid #f8f8f8;
|
||||||
|
span {
|
||||||
|
color: #191919;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -12,6 +12,7 @@ import {
|
|||||||
} from "vue";
|
} from "vue";
|
||||||
import Sortable from "sortablejs";
|
import Sortable from "sortablejs";
|
||||||
import { debounce } from "lodash-es";
|
import { debounce } from "lodash-es";
|
||||||
|
import { NDataTable } from "naive-ui";
|
||||||
|
|
||||||
// Props 定义
|
// Props 定义
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
@ -1,144 +0,0 @@
|
|||||||
import { createApp, h, ref } from 'vue'
|
|
||||||
import { NImage, NImageGroup } from 'naive-ui'
|
|
||||||
|
|
||||||
interface PreviewOptions {
|
|
||||||
onStart?: () => void
|
|
||||||
onError?: (e: Event) => void
|
|
||||||
showToolbar?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
class ImagePreview {
|
|
||||||
private static instance: {
|
|
||||||
app: any
|
|
||||||
container: HTMLElement
|
|
||||||
} | null = null
|
|
||||||
|
|
||||||
static async preview(
|
|
||||||
sources: string | File | (string | File)[],
|
|
||||||
index = 0,
|
|
||||||
options: PreviewOptions = {},
|
|
||||||
) {
|
|
||||||
try {
|
|
||||||
const urls = await this.normalizeImageSources(
|
|
||||||
Array.isArray(sources) ? sources : [sources]
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!urls.length) {
|
|
||||||
console.warn('[ImagePreview] No valid image sources')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.destroy()
|
|
||||||
options.onStart?.()
|
|
||||||
|
|
||||||
const container = document.createElement('div')
|
|
||||||
container.style.display = 'none'
|
|
||||||
document.body.appendChild(container)
|
|
||||||
|
|
||||||
const app = createApp({
|
|
||||||
setup() {
|
|
||||||
const imageRef = ref<InstanceType<typeof NImage> | null>(null)
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
if (urls.length === 1) {
|
|
||||||
return h(NImage, {
|
|
||||||
ref: imageRef,
|
|
||||||
src: urls[0],
|
|
||||||
previewDisabled: false,
|
|
||||||
preview: true,
|
|
||||||
showToolbar: options.showToolbar ?? true,
|
|
||||||
style: {
|
|
||||||
display: 'none'
|
|
||||||
},
|
|
||||||
onLoad: () => {
|
|
||||||
imageRef.value?.click()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
return h(NImageGroup, {
|
|
||||||
showToolbar: options.showToolbar ?? true,
|
|
||||||
currentIndex: index
|
|
||||||
}, {
|
|
||||||
default: () => urls.map((url, i) => {
|
|
||||||
const imgRef = ref<InstanceType<typeof NImage> | null>(null)
|
|
||||||
return h(NImage, {
|
|
||||||
ref: i === index ? imgRef : undefined,
|
|
||||||
src: url,
|
|
||||||
previewDisabled: false,
|
|
||||||
preview: true,
|
|
||||||
style: {
|
|
||||||
display: 'none'
|
|
||||||
},
|
|
||||||
onLoad: i === index ? () => {
|
|
||||||
imgRef.value?.click()
|
|
||||||
} : undefined
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
app.mount(container)
|
|
||||||
this.instance = { app, container }
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.error('[ImagePreview] Error:', error)
|
|
||||||
options.onError?.(error as Event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async normalizeImageSources(sources: (string | File)[]): Promise<string[]> {
|
|
||||||
const urls: string[] = []
|
|
||||||
|
|
||||||
for (const source of sources) {
|
|
||||||
try {
|
|
||||||
if (typeof source === 'string') {
|
|
||||||
if (source.startsWith('data:') || source.startsWith('http')) {
|
|
||||||
urls.push(source)
|
|
||||||
} else {
|
|
||||||
console.warn('[ImagePreview] Invalid image source:', source)
|
|
||||||
}
|
|
||||||
} else if (source instanceof File) {
|
|
||||||
const url = await this.fileToUrl(source)
|
|
||||||
urls.push(url)
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.warn('[ImagePreview] Failed to process source:', source, error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return urls
|
|
||||||
}
|
|
||||||
|
|
||||||
private static fileToUrl(file: File): Promise<string> {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (!file.type.startsWith('image/')) {
|
|
||||||
reject(new Error('Not an image file'))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const reader = new FileReader()
|
|
||||||
reader.onload = () => resolve(reader.result as string)
|
|
||||||
reader.onerror = reject
|
|
||||||
reader.readAsDataURL(file)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private static destroy() {
|
|
||||||
if (this.instance) {
|
|
||||||
const { app, container } = this.instance
|
|
||||||
app.unmount()
|
|
||||||
container.remove()
|
|
||||||
this.instance = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static close() {
|
|
||||||
this.destroy()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const previewImage = ImagePreview.preview.bind(ImagePreview)
|
|
||||||
export const closePreview = ImagePreview.close.bind(ImagePreview)
|
|
@ -34,6 +34,10 @@ const props = defineProps({
|
|||||||
loading: {
|
loading: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
|
},
|
||||||
|
customInputPlaceholder: {
|
||||||
|
type: String,
|
||||||
|
default: '请输入',
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -205,7 +209,7 @@ initData()
|
|||||||
<template v-if="item.type === 'input'">
|
<template v-if="item.type === 'input'">
|
||||||
<n-input
|
<n-input
|
||||||
:value="formData[item.key]"
|
:value="formData[item.key]"
|
||||||
placeholder="请输入"
|
:placeholder="customInputPlaceholder"
|
||||||
@input="value => handleInputChange(value, item)"
|
@input="value => handleInputChange(value, item)"
|
||||||
clearable
|
clearable
|
||||||
v-bind="item.props"
|
v-bind="item.props"
|
||||||
|
@ -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'))||'46d71a72d8d845ad7ed23eba9bdde260e635407190c2ce1bf7fd22088e41682ea07773ec65cae8946d2003f264d55961f96e0fc5da10eb96d3a348c1664e9644ce2108c311309f398ae8ea1b8200bfd490e5cb6e8c52c9e5d493cbabb163368f8351420451a631dbfa749829ee4cda49b77b5ed2d3dced5d0f2b7dd9ee76ba5465c84a17c23af040cd92b6b2a4ea48befbb5c729dcdad0a9c9668befe84074cc24f78899c1d947f8e7f94c7eda5325b8ed698df729e76febb98549ef3482ae942fb4f4a1c92d21836fa784728f0c5483aab2760a991b6b36e6b10c84f840a6433a6ecc31dee36e8f1c6158818bc89d22851b5e2f6cbf01ab4b3da6e3d06b57c8f750e106226a5a4b9d7fc1d381a54cb92375c09ba1fa8e5fde0392d919c2f2cbcc7e4e2eca8d9860749af00374b249f7d04e2bc43a1fa4e7d7384dde0212f0a5'
|
return JSON.parse(localStorage.getItem('token'))||'79b5c732d96d2b27a48a99dfd4a5566c43aaa5796242e854ebe3ffc198d6876b9628e7b764d9af65ab5dbb2d517ced88170491b74b048c0ba827c0d3741462cb89dc59ed46653a449af837a8262941caaef1334d640773710f8cd96473bacfb190cba595a5d6a9c87d70f0999a3ebb41147213b31b4bdccffca66a56acf3baab5af0154f0dce360079f37709f78e13711036899344bddb0fb4cf0f2890287cb62c3fcbe33368caa5e213624577be8b8420ab75b1f50775ee16142a4321c5d56995f37354a66a969da98d95ba6e65d142ed097e04b411c1ebad2f62866d0ec7e1838420530a9941dbbcd00490199f8b8987a3f4c77465504ba46f90370546f2f3656c248bd63549a43410178becfd0d1888ecbb8e82d291e68cf9da8ec1096e2d8abd4bb9d7edc62d38469e56226683693764f82df03eaa47fe6fd21a9cb83e0e'
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,8 +1,27 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, ref, onMounted, watch, reactive, onBeforeMount, getCurrentInstance } from 'vue'
|
import {
|
||||||
|
computed,
|
||||||
|
ref,
|
||||||
|
onMounted,
|
||||||
|
watch,
|
||||||
|
reactive,
|
||||||
|
onBeforeMount,
|
||||||
|
getCurrentInstance,
|
||||||
|
h
|
||||||
|
} from 'vue'
|
||||||
import { onBeforeRouteUpdate } from 'vue-router'
|
import { onBeforeRouteUpdate } from 'vue-router'
|
||||||
import { useDialogueStore, useTalkStore } from '@/store'
|
import { useDialogueStore, useTalkStore } from '@/store'
|
||||||
import { NDropdown, NIcon, NInput, NPopover, NTabs, NTab, NCard } from 'naive-ui'
|
import {
|
||||||
|
NDropdown,
|
||||||
|
NIcon,
|
||||||
|
NInput,
|
||||||
|
NPopover,
|
||||||
|
NTabs,
|
||||||
|
NTab,
|
||||||
|
NCard,
|
||||||
|
NButton,
|
||||||
|
NPagination
|
||||||
|
} from 'naive-ui'
|
||||||
import { Search, Plus } from '@icon-park/vue-next'
|
import { Search, Plus } from '@icon-park/vue-next'
|
||||||
import TalkItem from './TalkItem.vue'
|
import TalkItem from './TalkItem.vue'
|
||||||
import Skeleton from './Skeleton.vue'
|
import Skeleton from './Skeleton.vue'
|
||||||
@ -13,11 +32,13 @@ import { ISession } from '@/types/chat'
|
|||||||
import { useSessionMenu } from '@/hooks'
|
import { useSessionMenu } from '@/hooks'
|
||||||
import customModal from '@/components/common/customModal.vue'
|
import customModal from '@/components/common/customModal.vue'
|
||||||
import xSearchForm from '@/components/x-naive-ui/x-search-form/index.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 flTree from '@/components/flnlayout/tree/flnindex.vue'
|
||||||
import { processError, processSuccess } from '@/utils/helper/message.js'
|
import { processError, processSuccess } from '@/utils/helper/message.js'
|
||||||
|
import chatAppSearchList from '@/components/search/searchList.vue'
|
||||||
|
|
||||||
const currentInstance = getCurrentInstance()
|
const currentInstance = getCurrentInstance()
|
||||||
const { $request } = currentInstance?.appContext.config.globalProperties
|
const $request = currentInstance?.appContext.config.globalProperties?.$request
|
||||||
|
|
||||||
const {
|
const {
|
||||||
dropdown,
|
dropdown,
|
||||||
@ -34,6 +55,48 @@ const searchKeyword = ref('')
|
|||||||
const topItems = computed((): ISession[] => talkStore.topItems)
|
const topItems = computed((): ISession[] => talkStore.topItems)
|
||||||
const unreadNum = computed(() => talkStore.talkUnreadNum)
|
const unreadNum = computed(() => talkStore.talkUnreadNum)
|
||||||
|
|
||||||
|
//自定义搜索
|
||||||
|
const renderChatAppSearch = () => {
|
||||||
|
return h(
|
||||||
|
chatAppSearchList,
|
||||||
|
{
|
||||||
|
// searchResultKey: 'user_infos',
|
||||||
|
// searchItem: {
|
||||||
|
// avatar:
|
||||||
|
// 'https://e-cdn.fontree.cn/fonchain-main/prod/image/18248/avatar/a0b2bee7-947f-465a-986e-10a1b2b87032.png',
|
||||||
|
// created_at: '2025-03-27 14:44:23',
|
||||||
|
// erp_user_id: 18248,
|
||||||
|
// id: 44,
|
||||||
|
// mobile: '18994430450',
|
||||||
|
// nickname: '周俊耀'
|
||||||
|
// },
|
||||||
|
// searchText: '周'
|
||||||
|
searchResultPageSize: 3,
|
||||||
|
listLimit: true,
|
||||||
|
apiRequest: ServeSeachQueryAll,
|
||||||
|
searchText: '王',
|
||||||
|
onClickSearchItem: (searchText, searchResultKey, talk_type, receiver_id, res) => {
|
||||||
|
console.log(searchText, searchResultKey, talk_type, receiver_id)
|
||||||
|
const result = JSON.parse(decodeURIComponent(res))
|
||||||
|
console.log(result)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
//ES搜索聊天记录-主页搜索什么都有、指定用户、指定群、群与用户概览
|
||||||
|
const ServeSeachQueryAll = () => {
|
||||||
|
let url = '/api/v1/elasticsearch/query-all'
|
||||||
|
let params = {}
|
||||||
|
let config = {
|
||||||
|
baseURL: import.meta.env.VITE_BASE_API
|
||||||
|
}
|
||||||
|
return $request.HTTP.components.postDataByParams(url, params, config).then((res) => {
|
||||||
|
console.log(res)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
isShowAddressBookModal: false, // 是否显示通讯录模态框
|
isShowAddressBookModal: false, // 是否显示通讯录模态框
|
||||||
customModalStyle: {
|
customModalStyle: {
|
||||||
@ -41,20 +104,128 @@ const state = reactive({
|
|||||||
height: '846px',
|
height: '846px',
|
||||||
backgroundColor: '#F9F9FD'
|
backgroundColor: '#F9F9FD'
|
||||||
}, //自定义模态框样式
|
}, //自定义模态框样式
|
||||||
searchConfig: [
|
addressBookSearchConfig: [
|
||||||
{
|
{
|
||||||
label: '姓名',
|
label: '姓名',
|
||||||
key: 'name',
|
key: 'nickName',
|
||||||
type: 'input',
|
type: 'input',
|
||||||
valueType: 'string'
|
valueType: 'string'
|
||||||
}
|
}
|
||||||
], // 搜索配置
|
], // 通讯录搜索配置
|
||||||
|
groupChatListSearchConfig: [
|
||||||
|
{
|
||||||
|
label: '群聊名称',
|
||||||
|
key: 'groupName',
|
||||||
|
type: 'input',
|
||||||
|
valueType: 'string'
|
||||||
|
}
|
||||||
|
], // 群聊列表搜索配置
|
||||||
treeData: [],
|
treeData: [],
|
||||||
expandedKeys: [],
|
expandedKeys: [],
|
||||||
clickKey: '',
|
clickKey: 3,
|
||||||
treeRefreshCount: 0,
|
treeRefreshCount: 0,
|
||||||
treeSelectData: {}
|
treeSelectData: {},
|
||||||
|
addressBookColumns: [
|
||||||
|
{
|
||||||
|
title: '姓名 【工号】',
|
||||||
|
field: 'nickName',
|
||||||
|
width: 200,
|
||||||
|
render(row, index) {
|
||||||
|
return row.nickName + '【' + row.jobNum + '】'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '岗位名称',
|
||||||
|
field: 'positionName',
|
||||||
|
width: 400,
|
||||||
|
ellipsis: 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(' , ')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
field: 'action',
|
||||||
|
width: 200,
|
||||||
|
align: 'center',
|
||||||
|
fixed: 'right',
|
||||||
|
render(row, index) {
|
||||||
|
return h(
|
||||||
|
NButton,
|
||||||
|
{
|
||||||
|
size: 'small',
|
||||||
|
text: true,
|
||||||
|
color: '#46299d',
|
||||||
|
onClick: () => handleEnterChat(row)
|
||||||
|
},
|
||||||
|
{ default: () => '进入聊天' }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
], // 通讯录表格列
|
||||||
|
groupChatListColumns: [
|
||||||
|
{
|
||||||
|
title: '群聊名称',
|
||||||
|
field: 'groupName',
|
||||||
|
width: 200,
|
||||||
|
render(row, index) {
|
||||||
|
return row.groupName
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '群类型',
|
||||||
|
field: 'groupType',
|
||||||
|
width: 400,
|
||||||
|
ellipsis: true,
|
||||||
|
render(row, index) {
|
||||||
|
return row.groupType
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
field: 'action',
|
||||||
|
width: 200,
|
||||||
|
align: 'center',
|
||||||
|
fixed: 'right',
|
||||||
|
render(row, index) {
|
||||||
|
return h(
|
||||||
|
NButton,
|
||||||
|
{
|
||||||
|
size: 'small',
|
||||||
|
text: true,
|
||||||
|
color: '#46299d',
|
||||||
|
onClick: () => handleEnterChat(row)
|
||||||
|
},
|
||||||
|
{ default: () => '进入聊天' }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
], // 群聊列表表格列
|
||||||
|
addressBookData: [], // 通讯录表格数据
|
||||||
|
groupChatListData: [], // 群聊列表表格数据
|
||||||
|
addressBookTableHeight: 524, // 通讯录表格高度
|
||||||
|
addressBookTableWidth: 800, // 通讯录表格宽度
|
||||||
|
addressBookPage: 1, // 通讯录表格页码
|
||||||
|
addressBookPageSize: 10, // 通讯录表格每页条数
|
||||||
|
addressBookTotal: 0, // 通讯录表格总条数
|
||||||
|
addressBookSearchNickName: '', // 通讯录搜索条件-姓名
|
||||||
|
addressBookCurrentTab: 'employeeAddressBook', // 通讯录当前tab
|
||||||
|
groupChatListPage: 1, // 群聊列表表格页码
|
||||||
|
groupChatListPageSize: 10, // 群聊列表表格每页条数
|
||||||
|
groupChatListTotal: 0, // 群聊列表表格总条数
|
||||||
|
groupChatListSearchGroupName: '', // 群聊列表搜索条件-群聊名称
|
||||||
|
chatSearchOptions: [
|
||||||
|
{
|
||||||
|
key: 'chatSearch',
|
||||||
|
type: 'render',
|
||||||
|
render: renderChatAppSearch
|
||||||
|
}
|
||||||
|
] // 聊天搜索选项
|
||||||
})
|
})
|
||||||
|
|
||||||
const items = computed((): ISession[] => {
|
const items = computed((): ISession[] => {
|
||||||
@ -68,13 +239,31 @@ const items = computed((): ISession[] => {
|
|||||||
return keyword.toLowerCase().indexOf(searchKeyword.value.toLowerCase()) != -1
|
return keyword.toLowerCase().indexOf(searchKeyword.value.toLowerCase()) != -1
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
setTimeout(()=>{
|
setTimeout(() => {
|
||||||
console.log('items.value',items.value)
|
console.log('items.value', items.value)
|
||||||
},1000)
|
}, 1000)
|
||||||
watch(() => talkStore, (newValue, oldValue) => {
|
watch(
|
||||||
console.log(newValue);
|
() => talkStore,
|
||||||
|
(newValue, oldValue) => {
|
||||||
},{deep:true,immediate:true})
|
console.log(newValue)
|
||||||
|
},
|
||||||
|
{ deep: true, immediate: true }
|
||||||
|
)
|
||||||
|
watch(
|
||||||
|
() => state.addressBookSearchNickName,
|
||||||
|
(newValue, oldValue) => {
|
||||||
|
// console.log(newValue, 'newValue')
|
||||||
|
if (newValue) {
|
||||||
|
state.addressBookTableWidth = 1142
|
||||||
|
state.addressBookPage = 1
|
||||||
|
} else {
|
||||||
|
state.addressBookTableWidth = 800
|
||||||
|
state.clickKey = 3
|
||||||
|
state.treeRefreshCount++
|
||||||
|
}
|
||||||
|
getDepPoisUser()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
// 列表加载状态
|
// 列表加载状态
|
||||||
const loadStatus = computed(() => talkStore.loadStatus)
|
const loadStatus = computed(() => talkStore.loadStatus)
|
||||||
@ -145,8 +334,11 @@ const showAddressBookModal = () => {
|
|||||||
state.isShowAddressBookModal = true
|
state.isShowAddressBookModal = true
|
||||||
}
|
}
|
||||||
const handleTreeClick = ({ selectedKey, tree }) => {
|
const handleTreeClick = ({ selectedKey, tree }) => {
|
||||||
|
// console.log(tree)
|
||||||
state.clickKey = tree.key
|
state.clickKey = tree.key
|
||||||
state.treeSelectData = tree
|
state.treeSelectData = tree
|
||||||
|
state.addressBookPage = 1
|
||||||
|
getDepPoisUser()
|
||||||
}
|
}
|
||||||
const calcTreeData = (data) => {
|
const calcTreeData = (data) => {
|
||||||
for (let item of data) {
|
for (let item of data) {
|
||||||
@ -172,29 +364,8 @@ const getTreeData = () => {
|
|||||||
let data = res.data.nodes
|
let data = res.data.nodes
|
||||||
calcTreeData(data)
|
calcTreeData(data)
|
||||||
state.treeData = data
|
state.treeData = data
|
||||||
// // 获取最近点击的部门
|
|
||||||
// let localSelect = Local.get("posimanage_treeSelectData");
|
|
||||||
// if (localSelect && JSON.stringify(localSelect) !== "{}") {
|
|
||||||
// state.treeSelectData = localSelect;
|
|
||||||
// state.expandedKeys = localSelect.pathIds;
|
|
||||||
// state.clickKey = localSelect.key;
|
|
||||||
// } else {
|
|
||||||
// if (JSON.stringify(state.treeSelectData) === "{}") {
|
|
||||||
// state.treeSelectData = data[0];
|
|
||||||
// state.clickKey = data[0].key;
|
|
||||||
// }
|
|
||||||
// if (
|
|
||||||
// state.clickKey === data[0].key &&
|
|
||||||
// !state.expandedKeys.includes(data[0].key)
|
|
||||||
// ) {
|
|
||||||
// state.expandedKeys.push(data[0].key);
|
|
||||||
// }
|
|
||||||
// if (!state.expandedKeys.includes(state.clickKey)) {
|
|
||||||
// state.expandedKeys.push(state.clickKey);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
state.treeRefreshCount++
|
state.treeRefreshCount++
|
||||||
// state.tableConfig.refreshCount++;
|
getDepPoisUser()
|
||||||
} else {
|
} else {
|
||||||
processError(res.msg || '获取失败!')
|
processError(res.msg || '获取失败!')
|
||||||
}
|
}
|
||||||
@ -207,6 +378,66 @@ const getTreeData = () => {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
// 获取部门下的人员
|
||||||
|
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) => {
|
||||||
|
// console.log(res)
|
||||||
|
if (res.status === 0 && Array.isArray(res.data.data)) {
|
||||||
|
state.addressBookData = res.data.data || []
|
||||||
|
state.addressBookTotal = res.data.count
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//点击进入对应的聊天
|
||||||
|
const handleEnterChat = (row) => {
|
||||||
|
console.log(row)
|
||||||
|
}
|
||||||
|
//处理页数变化
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//处理通讯录tab切换
|
||||||
|
const handleAddressBookTabChange = (value) => {
|
||||||
|
console.log(value, 'value')
|
||||||
|
state.addressBookCurrentTab = value
|
||||||
|
}
|
||||||
|
//处理群聊列表搜索
|
||||||
|
const changeGroupChatListSearch = (value) => {
|
||||||
|
console.log(value, 'value')
|
||||||
|
}
|
||||||
|
//处理群聊列表页数变化
|
||||||
|
const handleGroupChatListPagination = (value) => {
|
||||||
|
console.log(value, 'value')
|
||||||
|
state.groupChatListPage = value
|
||||||
|
}
|
||||||
|
//处理群聊列表每页条数变化
|
||||||
|
const handleGroupChatListPaginationSize = (value) => {
|
||||||
|
console.log(value, 'value')
|
||||||
|
state.groupChatListPageSize = value
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -224,10 +455,15 @@ const getTreeData = () => {
|
|||||||
<section class="el-container is-vertical height100">
|
<section class="el-container is-vertical height100">
|
||||||
<!-- 工具栏目 -->
|
<!-- 工具栏目 -->
|
||||||
<header class="el-header header-tools">
|
<header class="el-header header-tools">
|
||||||
|
<n-dropdown
|
||||||
|
trigger="click"
|
||||||
|
:options="state.chatSearchOptions"
|
||||||
|
style="width: 248px; height: 677px; overflow-y: scroll;"
|
||||||
|
>
|
||||||
<n-input
|
<n-input
|
||||||
placeholder="搜索好友 / 群聊"
|
placeholder="搜索好友 / 群聊"
|
||||||
v-model:value.trim="searchKeyword"
|
v-model:value.trim="searchKeyword"
|
||||||
|
round
|
||||||
clearable
|
clearable
|
||||||
style="width: 78%;"
|
style="width: 78%;"
|
||||||
>
|
>
|
||||||
@ -235,14 +471,14 @@ const getTreeData = () => {
|
|||||||
<n-icon :component="Search" />
|
<n-icon :component="Search" />
|
||||||
</template>
|
</template>
|
||||||
</n-input>
|
</n-input>
|
||||||
|
</n-dropdown>
|
||||||
<n-button circle @click="isShowGroup = true">
|
<n-button circle @click="isShowGroup = true">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<n-icon :component="Plus" />
|
<n-icon :component="Plus" />
|
||||||
</template>
|
</template>
|
||||||
</n-button>
|
</n-button>
|
||||||
<img
|
<img
|
||||||
style="width: 19px; height: 20px;"
|
style="width: 19px; height: 20px; cursor: pointer;"
|
||||||
src="@/assets/image/chatList/addressBook.png"
|
src="@/assets/image/chatList/addressBook.png"
|
||||||
alt=""
|
alt=""
|
||||||
@click="showAddressBookModal"
|
@click="showAddressBookModal"
|
||||||
@ -250,7 +486,7 @@ const getTreeData = () => {
|
|||||||
</header>
|
</header>
|
||||||
|
|
||||||
<!-- 置顶栏目 -->
|
<!-- 置顶栏目 -->
|
||||||
<!-- <header class="el-header header-top" v-show="loadStatus == 3 && topItems.length > 0">
|
<header class="el-header header-top" v-show="loadStatus == 3 && topItems.length > 0">
|
||||||
<n-popover v-for="item in topItems" :key="item.index_name" placement="bottom" trigger="hover">
|
<n-popover v-for="item in topItems" :key="item.index_name" placement="bottom" trigger="hover">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<div
|
<div
|
||||||
@ -273,10 +509,10 @@ const getTreeData = () => {
|
|||||||
</template>
|
</template>
|
||||||
<span> {{ item.remark || item.name }} </span>
|
<span> {{ item.remark || item.name }} </span>
|
||||||
</n-popover>
|
</n-popover>
|
||||||
</header> -->
|
</header>
|
||||||
|
|
||||||
<!-- 标题栏目 -->
|
<!-- 标题栏目 -->
|
||||||
<!-- <header
|
<header
|
||||||
v-show="loadStatus == 3 && talkStore.talkItems.length > 0"
|
v-show="loadStatus == 3 && talkStore.talkItems.length > 0"
|
||||||
class="el-header header-badge"
|
class="el-header header-badge"
|
||||||
:class="{ shadow: false }"
|
:class="{ shadow: false }"
|
||||||
@ -285,12 +521,11 @@ const getTreeData = () => {
|
|||||||
<p>
|
<p>
|
||||||
<span class="badge unread" v-show="unreadNum">{{ unreadNum }}未读</span>
|
<span class="badge unread" v-show="unreadNum">{{ unreadNum }}未读</span>
|
||||||
</p>
|
</p>
|
||||||
</header> -->
|
</header>
|
||||||
|
|
||||||
<main id="talk-session-list" class="el-main me-scrollbar me-scrollbar-thumb">
|
<main id="talk-session-list" class="el-main me-scrollbar me-scrollbar-thumb">
|
||||||
<template v-if="loadStatus == 2"><Skeleton /></template>
|
<template v-if="loadStatus == 2"><Skeleton /></template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
|
|
||||||
<TalkItem
|
<TalkItem
|
||||||
v-for="item in items"
|
v-for="item in items"
|
||||||
:key="item.index_name"
|
:key="item.index_name"
|
||||||
@ -317,14 +552,34 @@ const getTreeData = () => {
|
|||||||
>
|
>
|
||||||
<template #content>
|
<template #content>
|
||||||
<div class="custom-modal-content">
|
<div class="custom-modal-content">
|
||||||
<n-card>
|
<n-card style="padding: 0 12px;">
|
||||||
<n-tabs type="line">
|
<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="employeeAddressBook">员工通讯录</n-tab>
|
||||||
<n-tab name="groupChatList">群聊列表</n-tab>
|
<n-tab name="groupChatList">群聊列表</n-tab>
|
||||||
</n-tabs>
|
</n-tabs>
|
||||||
<xSearchForm :search-config="state.searchConfig"></xSearchForm>
|
<xSearchForm
|
||||||
<div class="addressBook-content">
|
v-if="state.addressBookCurrentTab == 'employeeAddressBook'"
|
||||||
<div class="addressBook-tree">
|
: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
|
<fl-tree
|
||||||
:data="state.treeData"
|
:data="state.treeData"
|
||||||
:expandedKeys="state.expandedKeys"
|
:expandedKeys="state.expandedKeys"
|
||||||
@ -333,6 +588,58 @@ const getTreeData = () => {
|
|||||||
@triggerTreeClick="handleTreeClick"
|
@triggerTreeClick="handleTreeClick"
|
||||||
></fl-tree>
|
></fl-tree>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="addressBook-table">
|
||||||
|
<xNDataTable
|
||||||
|
:columns="state.addressBookColumns"
|
||||||
|
:data="state.addressBookData"
|
||||||
|
:style="{
|
||||||
|
height: `${state.addressBookTableHeight}px`,
|
||||||
|
width: `${state.addressBookTableWidth}px`
|
||||||
|
}"
|
||||||
|
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: '523px',
|
||||||
|
width: '1148px'
|
||||||
|
}"
|
||||||
|
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>
|
||||||
</n-card>
|
</n-card>
|
||||||
</div>
|
</div>
|
||||||
@ -446,7 +753,13 @@ html[theme-mode='dark'] {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0 12px;
|
padding: 0 12px;
|
||||||
|
:deep(.n-tabs-tab--active) {
|
||||||
|
color: #46299d !important;
|
||||||
|
}
|
||||||
.addressBook-content {
|
.addressBook-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 20px;
|
||||||
.addressBook-tree {
|
.addressBook-tree {
|
||||||
width: 328px;
|
width: 328px;
|
||||||
height: 524px;
|
height: 524px;
|
||||||
@ -456,6 +769,37 @@ html[theme-mode='dark'] {
|
|||||||
padding: 12px 20px;
|
padding: 12px 20px;
|
||||||
box-sizing: border-box;
|
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>
|
</style>
|
||||||
|
Loading…
Reference in New Issue
Block a user