Compare commits
	
		
			2 Commits
		
	
	
		
			8c9f634d0b
			...
			701d878f7d
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 701d878f7d | |||
| 7544b3d324 | 
							
								
								
									
										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> | ||||
| @ -34,6 +34,10 @@ const props = defineProps({ | ||||
|   loading: { | ||||
|     type: Boolean, | ||||
|     default: false, | ||||
|   }, | ||||
|   customInputPlaceholder: { | ||||
|     type: String, | ||||
|     default: '请输入', | ||||
|   } | ||||
| }) | ||||
| 
 | ||||
| @ -205,7 +209,7 @@ initData() | ||||
|           <template v-if="item.type === 'input'"> | ||||
|             <n-input | ||||
|               :value="formData[item.key]" | ||||
|               placeholder="请输入" | ||||
|               :placeholder="customInputPlaceholder" | ||||
|               @input="value => handleInputChange(value, item)" | ||||
|               clearable | ||||
|               v-bind="item.props" | ||||
|  | ||||
| @ -18,7 +18,7 @@ export function isLoggedIn() { | ||||
|  */ | ||||
| export function getAccessToken() { | ||||
|   // return storage.get(AccessToken) || ''
 | ||||
|   return JSON.parse(localStorage.getItem('token'))||'79b5c732d96d2b27a48a99dfd4a5566c43aaa5796242e854ebe3ffc198d6876b9628e7b764d9af65ab5dbb2d517ced88170491b74b048c0ba827c0d3741462cb89dc59ed46653a449af837a8262941caaef1334d640773710f8cd96473bacfb190cba595a5d6a9c87d70f0999a3ebb41147213b31b4bdccffca66a56acf3baab5af0154f0dce360079f37709f78e13711036899344bddb0fb4cf0f2890287cb62c3fcbe33368caa5e213624577be8b8420ab75b1f50775ee16142a4321c5d56995f37354a66a969da98d95ba6e65d142ed097e04b411c1ebad2f62866d0ec7e1838420530a9941dbbcd00490199f8b891bd3a81a1ac4e73e2aed60deeaec60792c525cc0c96e8f4a666eca6ee7a10716507b402cde5759bbcda1fa681fbe4dcdfe05abbc2b1644c68dc74ebaf8d9c9cc4eb61afaf3de52fa357dbfdfe17acf14' | ||||
|   return JSON.parse(localStorage.getItem('token'))||'79b5c732d96d2b27a48a99dfd4a5566c43aaa5796242e854ebe3ffc198d6876b9628e7b764d9af65ab5dbb2d517ced88170491b74b048c0ba827c0d3741462cb89dc59ed46653a449af837a8262941caaef1334d640773710f8cd96473bacfb190cba595a5d6a9c87d70f0999a3ebb41147213b31b4bdccffca66a56acf3baab5af0154f0dce360079f37709f78e13711036899344bddb0fb4cf0f2890287cb62c3fcbe33368caa5e213624577be8b8420ab75b1f50775ee16142a4321c5d56995f37354a66a969da98d95ba6e65d142ed097e04b411c1ebad2f62866d0ec7e1838420530a9941dbbcd00490199f8b8987a3f4c77465504ba46f90370546f2f3656c248bd63549a43410178becfd0d1888ecbb8e82d291e68cf9da8ec1096e2d8abd4bb9d7edc62d38469e56226683693764f82df03eaa47fe6fd21a9cb83e0e' | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  | ||||
| @ -35,6 +35,7 @@ import xSearchForm from '@/components/x-naive-ui/x-search-form/index.vue' | ||||
| import xNDataTable from '@/components/x-naive-ui/x-n-data-table/index.vue' | ||||
| import flTree from '@/components/flnlayout/tree/flnindex.vue' | ||||
| import { processError, processSuccess } from '@/utils/helper/message.js' | ||||
| import chatAppSearchList from '@/components/search/searchList.vue' | ||||
| 
 | ||||
| const currentInstance = getCurrentInstance() | ||||
| const $request = currentInstance?.appContext.config.globalProperties?.$request | ||||
| @ -54,6 +55,48 @@ const searchKeyword = ref('') | ||||
| const topItems = computed((): ISession[] => talkStore.topItems) | ||||
| 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({ | ||||
|   isShowAddressBookModal: false, // 是否显示通讯录模态框 | ||||
|   customModalStyle: { | ||||
| @ -61,15 +104,22 @@ const state = reactive({ | ||||
|     height: '846px', | ||||
|     backgroundColor: '#F9F9FD' | ||||
|   }, //自定义模态框样式 | ||||
|   searchConfig: [ | ||||
|   addressBookSearchConfig: [ | ||||
|     { | ||||
|       label: '姓名', | ||||
|       key: 'name', | ||||
|       key: 'nickName', | ||||
|       type: 'input', | ||||
|       valueType: 'string' | ||||
|     } | ||||
|   ], // 搜索配置 | ||||
| 
 | ||||
|   ], // 通讯录搜索配置 | ||||
|   groupChatListSearchConfig: [ | ||||
|     { | ||||
|       label: '群聊名称', | ||||
|       key: 'groupName', | ||||
|       type: 'input', | ||||
|       valueType: 'string' | ||||
|     } | ||||
|   ], // 群聊列表搜索配置 | ||||
|   treeData: [], | ||||
|   expandedKeys: [], | ||||
|   clickKey: 3, | ||||
| @ -77,11 +127,11 @@ const state = reactive({ | ||||
|   treeSelectData: {}, | ||||
|   addressBookColumns: [ | ||||
|     { | ||||
|       title: '姓名', | ||||
|       field: 'name', | ||||
|       title: '姓名 【工号】', | ||||
|       field: 'nickName', | ||||
|       width: 200, | ||||
|       render(row, index) { | ||||
|         return row.nickName | ||||
|         return row.nickName + '【' + row.jobNum + '】' | ||||
|       } | ||||
|     }, | ||||
|     { | ||||
| @ -90,8 +140,12 @@ const state = reactive({ | ||||
|       width: 400, | ||||
|       ellipsis: true, | ||||
|       render(row, index) { | ||||
|         let positionName = row.nowPositions.map((item) => item.name).join(' , ') | ||||
|         return positionName | ||||
|         let positionNames = Array.isArray(row.depPositions) | ||||
|           ? row.depPositions.flatMap((dep) => | ||||
|               Array.isArray(dep.positions) ? dep.positions.map((pos) => pos.name) : [] | ||||
|             ) | ||||
|           : [] | ||||
|         return positionNames.join(' , ') | ||||
|       } | ||||
|     }, | ||||
|     { | ||||
| @ -114,12 +168,64 @@ const state = reactive({ | ||||
|       } | ||||
|     } | ||||
|   ], // 通讯录表格列 | ||||
|   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 // 通讯录表格总条数 | ||||
|   addressBookTotal: 0, // 通讯录表格总条数 | ||||
|   addressBookSearchNickName: '', // 通讯录搜索条件-姓名 | ||||
|   addressBookCurrentTab: 'employeeAddressBook', // 通讯录当前tab | ||||
|   groupChatListPage: 1, // 群聊列表表格页码 | ||||
|   groupChatListPageSize: 10, // 群聊列表表格每页条数 | ||||
|   groupChatListTotal: 0, // 群聊列表表格总条数 | ||||
|   groupChatListSearchGroupName: '', // 群聊列表搜索条件-群聊名称 | ||||
|   chatSearchOptions: [ | ||||
|     { | ||||
|       key: 'chatSearch', | ||||
|       type: 'render', | ||||
|       render: renderChatAppSearch | ||||
|     } | ||||
|   ] // 聊天搜索选项 | ||||
| }) | ||||
| 
 | ||||
| const items = computed((): ISession[] => { | ||||
| @ -143,6 +249,21 @@ watch( | ||||
|   }, | ||||
|   { 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) | ||||
| @ -213,9 +334,10 @@ const showAddressBookModal = () => { | ||||
|   state.isShowAddressBookModal = true | ||||
| } | ||||
| const handleTreeClick = ({ selectedKey, tree }) => { | ||||
|   console.log(tree) | ||||
|   // console.log(tree) | ||||
|   state.clickKey = tree.key | ||||
|   state.treeSelectData = tree | ||||
|   state.addressBookPage = 1 | ||||
|   getDepPoisUser() | ||||
| } | ||||
| const calcTreeData = (data) => { | ||||
| @ -242,30 +364,8 @@ const getTreeData = () => { | ||||
|         let data = res.data.nodes | ||||
|         calcTreeData(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++ | ||||
|         getDepPoisUser() | ||||
|         // state.tableConfig.refreshCount++; | ||||
|       } else { | ||||
|         processError(res.msg || '获取失败!') | ||||
|       } | ||||
| @ -282,13 +382,14 @@ const getTreeData = () => { | ||||
| const getDepPoisUser = () => { | ||||
|   let url = '/user/v2/list' | ||||
|   let params = { | ||||
|     departmentId: state.clickKey, | ||||
|     departmentId: state.addressBookSearchNickName ? undefined : state.clickKey, | ||||
|     page: state.addressBookPage, | ||||
|     pageSize: state.addressBookPageSize, | ||||
|     status: 'notactive' | ||||
|     status: 'notactive', | ||||
|     nickName: state.addressBookSearchNickName | ||||
|   } | ||||
|   $request.HTTP.components.postDataByParams(url, params).then((res) => { | ||||
|     console.log(res) | ||||
|     // console.log(res) | ||||
|     if (res.status === 0 && Array.isArray(res.data.data)) { | ||||
|       state.addressBookData = res.data.data || [] | ||||
|       state.addressBookTotal = res.data.count | ||||
| @ -310,6 +411,33 @@ const handleAddressBookPaginationSize = (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> | ||||
| 
 | ||||
| <template> | ||||
| @ -327,25 +455,30 @@ const handleAddressBookPaginationSize = (pageSize) => { | ||||
|   <section class="el-container is-vertical height100"> | ||||
|     <!-- 工具栏目 --> | ||||
|     <header class="el-header header-tools"> | ||||
|       <n-input | ||||
|         placeholder="搜索好友 / 群聊" | ||||
|         v-model:value.trim="searchKeyword" | ||||
|         round | ||||
|         clearable | ||||
|         style="width: 78%;" | ||||
|       <n-dropdown | ||||
|         trigger="click" | ||||
|         :options="state.chatSearchOptions" | ||||
|         style="width: 248px; height: 677px; overflow-y: scroll;" | ||||
|       > | ||||
|         <template #prefix> | ||||
|           <n-icon :component="Search" /> | ||||
|         </template> | ||||
|       </n-input> | ||||
| 
 | ||||
|         <n-input | ||||
|           placeholder="搜索好友 / 群聊" | ||||
|           v-model:value.trim="searchKeyword" | ||||
|           round | ||||
|           clearable | ||||
|           style="width: 78%;" | ||||
|         > | ||||
|           <template #prefix> | ||||
|             <n-icon :component="Search" /> | ||||
|           </template> | ||||
|         </n-input> | ||||
|       </n-dropdown> | ||||
|       <n-button circle @click="isShowGroup = true"> | ||||
|         <template #icon> | ||||
|           <n-icon :component="Plus" /> | ||||
|         </template> | ||||
|       </n-button> | ||||
|       <img | ||||
|         style="width: 19px; height: 20px;" | ||||
|         style="width: 19px; height: 20px; cursor: pointer;" | ||||
|         src="@/assets/image/chatList/addressBook.png" | ||||
|         alt="" | ||||
|         @click="showAddressBookModal" | ||||
| @ -420,13 +553,33 @@ const handleAddressBookPaginationSize = (pageSize) => { | ||||
|     <template #content> | ||||
|       <div class="custom-modal-content"> | ||||
|         <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="groupChatList">群聊列表</n-tab> | ||||
|           </n-tabs> | ||||
|           <xSearchForm :search-config="state.searchConfig"></xSearchForm> | ||||
|           <div class="addressBook-content"> | ||||
|             <div class="addressBook-tree"> | ||||
|           <xSearchForm | ||||
|             v-if="state.addressBookCurrentTab == 'employeeAddressBook'" | ||||
|             :search-config="state.addressBookSearchConfig" | ||||
|             customInputPlaceholder="请输入姓名" | ||||
|             @change="changeAddressBookSearch" | ||||
|             :cols="3" | ||||
|           ></xSearchForm> | ||||
|           <xSearchForm | ||||
|             v-if="state.addressBookCurrentTab == 'groupChatList'" | ||||
|             :search-config="state.groupChatListSearchConfig" | ||||
|             customInputPlaceholder="请输入群聊名称" | ||||
|             @change="changeGroupChatListSearch" | ||||
|             :cols="3" | ||||
|           ></xSearchForm> | ||||
|           <div | ||||
|             class="addressBook-content" | ||||
|             v-if="state.addressBookCurrentTab == 'employeeAddressBook'" | ||||
|           > | ||||
|             <div class="addressBook-tree" v-if="!state.addressBookSearchNickName"> | ||||
|               <fl-tree | ||||
|                 :data="state.treeData" | ||||
|                 :expandedKeys="state.expandedKeys" | ||||
| @ -461,6 +614,33 @@ const handleAddressBookPaginationSize = (pageSize) => { | ||||
|               </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> | ||||
|         </n-card> | ||||
|       </div> | ||||
|     </template> | ||||
| @ -573,6 +753,9 @@ html[theme-mode='dark'] { | ||||
|   box-sizing: border-box; | ||||
|   width: 100%; | ||||
|   padding: 0 12px; | ||||
|   :deep(.n-tabs-tab--active) { | ||||
|     color: #46299d !important; | ||||
|   } | ||||
|   .addressBook-content { | ||||
|     display: flex; | ||||
|     flex-direction: row; | ||||
| @ -600,5 +783,23 @@ html[theme-mode='dark'] { | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   .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> | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user