chat-app/src/pages/search/searchByCondition/index.vue

710 lines
23 KiB
Vue
Raw Normal View History

<template>
<div class="outer-layer search-by-condition-page">
<div class="root">
<ZPaging
ref="zPaging"
:show-scrollbar="false"
@query="queryAllSearch"
:refresher-enabled="false"
:auto="false"
:loading-more-default-as-loading="true"
:inside-more="true"
>
<template #top v-if="state.showPageTitle">
<customNavbar :title="state.pageTitle"></customNavbar>
</template>
<div v-if="state.condition === 'date'" class="search-by-date">
<tm-time-picker
:show="state.showMonthPicker"
:showDetail="{
year: true,
month: true,
day: false,
hour: false,
minute: false,
second: false,
am_pm: false,
}"
:showSuffix="{
year: '',
month: '',
}"
:defaultValue="state.nowDate"
format="YYYY年MM月"
start=""
:end="state.maxDate"
@confirm="confirmSelectedMonth"
:round="0"
:title="$t('search.condition.date_pickerTitle')"
>
<div class="search-date-picker">
<span class="text-[28rpx] font-regular">
{{ state.selectedMonth }}
</span>
<img src="/src/static/image/search/down-pointer.png" />
</div>
</tm-time-picker>
<tm-calendar-view
:show="true"
:hideTool="true"
:hideButton="true"
:dateStyle="state.dateStyle"
:defaultValue="state.selectedDateArray"
v-model="state.selectedDateArray"
:disabledDate="state.disabledDateArray"
@click="selectDate"
model="day"
:end="state.maxDate"
@getDArray="getDArray"
:showDefault="false"
></tm-calendar-view>
</div>
<div
class="search-by-condition-input-list"
v-if="
state.condition === 'imgAndVideo' ||
state.condition === 'file' ||
state.condition === 'link'
"
:style="{
padding: state.condition === 'imgAndVideo' ? '0 27rpx' : '',
}"
>
<div
class="search-by-condition-input"
v-if="state.condition === 'file' || state.condition === 'link'"
>
<customInput
:searchText="state.searchText"
:first_talk_record_infos="state.first_talk_record_infos"
@inputSearchText="inputSearchText"
></customInput>
<span
@click="cancelSearch"
class="search-by-condition-input-text text-[32rpx] font-medium"
>
{{ $t('cancel') }}
</span>
</div>
<div class="search-by-condition-list">
<div class="condition-dimensionality">
<div
class="condition-dimensionality-each"
v-for="(conditionItem,
conditionIndex) in state.searchResultList"
:key="conditionIndex"
>
<div class="condition-dimensionality-each-month">
<span class="text-[28rpx] font-regular">
{{ conditionItem.dateMonth }}
</span>
</div>
<div
class="condition-each-resultList"
:class="[
state.condition === 'imgAndVideo'
? 'condition-type-imgAndVideo-result'
: '',
]"
>
<div
class="condition-each-resultList-each"
v-for="(item, index) in conditionItem.monthResultList"
:key="index"
:style="{
border: state.condition === 'imgAndVideo' ? '0' : '',
padding:
state.condition === 'imgAndVideo' ? '0 0 10rpx' : '',
}"
>
<div
class="condition-result-imgAndVideo"
v-if="state.condition === 'imgAndVideo'"
>
<div
class="condition-result-imgAndVideo-area"
v-if="item?.extra?.items?.length > 0"
>
<div
class="condition-result-imgAndVideo-each"
v-for="(imgItem, imgIndex) in item?.extra?.items"
:key="imgIndex"
>
<tm-image
preview
:src="imgItem?.content"
v-if="imgItem?.type == 3"
model="aspectFill"
/>
</div>
</div>
<div
class="condition-result-imgAndVideo-area"
v-if="item?.extra?.url"
>
<tm-image
preview
:src="
item?.msg_type === 3
? item?.extra?.url
: item?.msg_type === 5
? item?.extra?.cover
: ''
"
model="aspectFill"
/>
</div>
</div>
<div
class="condition-each-result-main"
v-if="
state.condition === 'file' || state.condition === 'link'
"
>
<searchItem
:searchItem="item"
:conditionType="state.msg_type"
></searchItem>
<span
class="text-[24rpx] font-medium condition-each-result-main-date"
>
{{ item.dateTime }}
</span>
</div>
<div
class="condition-each-result-attachments"
v-if="
state.condition === 'file' || state.condition === 'link'
"
>
<div class="attachment-avatar">
<img
:src="item?.extra?.file_avatar"
v-if="state.condition === 'file'"
/>
<img
src="/src/static/image/search/result-link-icon.png"
v-if="state.condition === 'link'"
/>
</div>
<div class="attachment-info">
<div class="attachment-info-title">
<span
class="text-[28rpx] font-regular"
v-if="state.condition === 'file'"
>
{{ item?.extra?.name }}
</span>
<span
class="text-[28rpx] font-regular"
v-if="state.condition === 'link'"
>
{{ $t('record.share.link') }}
</span>
</div>
<div
class="attachment-sub-info"
:style="{
margin:
state.condition === 'file' ? '20rpx 0 0' : '',
}"
>
<span
class="text-[24rpx] font-regular"
v-if="state.condition === 'file'"
>
{{ item?.extra?.typeText }}
</span>
<span
class="text-[24rpx] font-regular"
v-if="state.condition === 'file'"
style="margin: 0 0 0 20rpx;"
>
{{ item?.extra?.fileSize }}
</span>
<span
class="text-[24rpx] font-regular"
v-if="state.condition === 'link'"
>
{{ item?.extra?.content }}
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</ZPaging>
</div>
</div>
</template>
<script setup>
import fileType_PPT from '@/static/image/search/fileType_PPT.png'
import fileType_EXCEL from '@/static/image/search/fileType_EXCEL.png'
import fileType_WORD from '@/static/image/search/fileType_WORD.png'
import fileType_PDF from '@/static/image/search/fileType_PDF.png'
import fileType_Files from '@/static/image/search/fileType_Files.png'
import { fileFormatSize, fileSuffix } from '@/utils/strings'
import searchItem from '../components/searchItem.vue'
import customInput from '@/components/custom-input/custom-input.vue'
import ZPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
import useZPaging from '@/uni_modules/z-paging/components/z-paging/js/hooks/useZPaging.js'
import { parseTime } from '@/utils/datetime'
import { onMounted, reactive, computed, ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { ServeTalkDate } from '@/api/search/index'
import { ServeFindTalkRecords } from '@/api/chat/index'
import { useDialogueStore } from '@/store'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const zPaging = ref()
useZPaging(zPaging)
const dialogueStore = useDialogueStore()
const dialogueParams = reactive({
talk_type: computed(() => dialogueStore.talk.talk_type),
receiver_id: computed(() => dialogueStore.talk.receiver_id),
})
let nowDay = new Date().setHours(0, 0, 0, 0)
const state = reactive({
receiver_id: '', //目标人id
pageTitle: '', //页面标题
dateStyle: [], //日期样式
nowDate: new Date(nowDay), //当前时间
maxDate: new Date(nowDay), //可选择最大时间
selectedDateArray: Array(new Date(nowDay)), //选择的月份数组
showMonthPicker: false, //是否显示月份选择
selectedMonth: new Date(nowDay), //当前选择的月份
disabledDateArray: [], //被禁用的日期数组
dArray: [], //日历日期数组
showPageTitle: false, //是否显示页面标题
searchText: '', //搜索内容
first_talk_record_infos: Object,
searchResultList: [], //搜索结果列表
cursor: 0, //上次查询的游标
msg_type: 0, //查询的消息类型
})
onLoad((options) => {
console.log(options)
if (options.receiver_id) {
state.receiver_id = Number(options.receiver_id)
}
if (options.condition) {
state.condition = options.condition
if (options.condition === 'date') {
state.showPageTitle = true
state.pageTitle = t('search.condition.date')
ServeQueryTalkDate(parseTime(state.nowDate, '{y}{m}'))
} else if (options.condition === 'imgAndVideo') {
state.showPageTitle = true
state.pageTitle = t('record.searchType.imgWithVideo')
state.msg_type = '3,5'
queryAllSearch()
} else if (options.condition === 'file') {
console.log(dialogueParams)
let first_talk_record_infos = {
receiver_name: t('record.searchType.files'),
}
state.first_talk_record_infos = Object.assign(
{},
state.first_talk_record_infos,
first_talk_record_infos,
)
state.msg_type = 6
queryAllSearch()
} else if (options.condition === 'link') {
console.log(dialogueParams)
let first_talk_record_infos = {
receiver_name: t('record.searchType.link'),
}
state.first_talk_record_infos = Object.assign(
{},
state.first_talk_record_infos,
first_talk_record_infos,
)
state.msg_type = 14
queryAllSearch()
}
}
})
onMounted(() => {
state.selectedMonth = parseTime(state.selectedMonth, '{y}年{m}月')
state.dateStyle = [
{
date: state.nowDate, //日期
text: false, //浅色背景。
color: '#46299D', //主题色.
extra: '今天', //额外的内容,在日期下方显示的文本。
},
]
})
//查看存在聊天记录的天数
const ServeQueryTalkDate = (month) => {
let params = {
month: month,
talk_type: 2, //1私聊2群聊
receiver_id: state.receiver_id, //目标人id
}
const resp = ServeTalkDate(params)
console.log(resp)
resp.then(({ code, data }) => {
console.log(data)
if (code == 200) {
if (data && data.length > 0) {
const formattedData = data.map(
(item) =>
item.substring(0, 4) +
'/' +
item.substring(4, 6) +
'/' +
item.substring(6, 8),
)
let disabledDateArray = state.dArray.filter(
(dIt) => !formattedData.includes(dIt),
)
disabledDateArray = disabledDateArray.map((item) =>
item.replace(/\//g, '-'),
)
console.log(disabledDateArray)
state.disabledDateArray = disabledDateArray
} else {
state.disabledDateArray = state.dArray
}
} else {
}
})
resp.catch(() => {})
}
//点击选择日期
const selectDate = (e) => {
if (e == parseTime(state.nowDate, '{y}/{m}/{d}')) {
console.log('==今日')
state.dateStyle = [
{
date: state.nowDate, //日期
text: false, //浅色背景。
color: '#46299D', //主题色.
extra: '今天', //额外的内容,在日期下方显示的文本。
},
]
} else {
state.dateStyle = [
{
date: state.nowDate, //日期
text: false, //浅色背景。
color: '', //主题色.
extra: '今天', //额外的内容,在日期下方显示的文本。
},
{
date: new Date(e), //日期
text: false, //浅色背景。
color: '#46299D', //主题色.
},
]
}
}
//点击确认选择月份
const confirmSelectedMonth = (e) => {
console.log(e)
state.selectedMonth = parseTime(e, '{y}年{m}月')
// console.log()
let newDate = new Date(e)
newDate.setHours(0, 0, 0, 0)
newDate.setDate(1)
state.selectedDateArray = Array(new Date(newDate))
state.dateStyle = [
{
date: state.nowDate, //日期
text: false, //浅色背景。
color: '', //主题色.
extra: '今天', //额外的内容,在日期下方显示的文本。
},
]
ServeQueryTalkDate(parseTime(e, '{y}{m}'))
}
//获取日历日期数组
const getDArray = (dArray) => {
state.dArray = dArray
}
//输入搜索内容
const inputSearchText = (e) => {
state.searchText = e
}
//点击取消搜索
2025-03-10 01:57:21 +00:00
const cancelSearch = () => {
uni.navigateBack({
delta: 1,
})
}
//查询数据
const queryAllSearch = () => {
let params = {
talk_type: dialogueParams.talk_type, //1私聊2群聊
receiver_id: dialogueParams.receiver_id, //目标用户id或群聊id
msg_type: state.msg_type, //消息类型0:全部;2:代码;3:图片;4:音频;5:视频;6:文件;7:位置;9:会话;11群投票;12图文混合
cursor: state.cursor, //上次查询的游标
limit: 10, //数据行数
no_limit: '', //1不限制
direction: 'up', //down向下查最新up向上查老数据
start_time: '',
end_time: '',
group_member_user_id: 0, //群成员id当查询群历史消息的时候需要指定群成员的时候送
}
console.log(params)
const resp = ServeFindTalkRecords(params)
console.log(resp)
resp.then(({ code, data }) => {
console.log(data)
if (code == 200) {
let dateList = state.searchResultList
let noMore = false
if (data?.items?.length > 0) {
data.items.forEach((item) => {
item.dateTime = parseTime(item?.created_at, '{m}/{d}')
item.extra.fileSize = fileFormatSize(item?.extra?.size)
item.extra.typeText = item?.extra?.name
? fileSuffix(item?.extra?.name)
: ''
item.extra.file_avatar = fileTypeAvatar(item?.extra?.typeText)
console.log(item.extra.type)
let year = new Date(item.created_at).getFullYear()
let month = new Date(item.created_at).getMonth() + 1
let dateMonth =
year == state.nowDate.getFullYear() &&
month == state.nowDate.getMonth() + 1
? t('result.date.nowMonth')
: year + '年' + month + '月'
if (dateList.length > 0) {
let hasAdd = false
dateList.forEach((dateItem) => {
if (dateItem.dateMonth === dateMonth) {
dateItem.monthResultList.push(item)
hasAdd = true
}
})
if (!hasAdd) {
console.log(dateList)
dateList.push({
dateMonth: dateMonth,
monthResultList: [item],
})
}
} else {
dateList.push({
dateMonth: dateMonth,
monthResultList: [item],
})
}
})
} else {
noMore = true
}
console.log(dateList)
state.cursor = data?.cursor
zPaging.value?.completeByNoMore(dateList, noMore)
} else {
zPaging.value?.complete([])
}
})
resp.catch(() => {
zPaging.value?.complete([])
})
}
//文件类型图标
const fileTypeAvatar = (fileType) => {
let file_type_avatar = fileType_Files
if (fileType) {
if (fileType === 'ppt' || fileType === 'pptx') {
file_type_avatar = fileType_PPT
} else if (fileType === 'pdf') {
file_type_avatar = fileType_PDF
} else if (fileType === 'doc' || fileType === 'docx') {
file_type_avatar = fileType_WORD
} else if (fileType === 'xls' || fileType === 'xlsx') {
file_type_avatar = fileType_EXCEL
} else {
file_type_avatar = fileType_Files
}
}
return file_type_avatar
}
</script>
<style scoped lang="scss">
.search-by-date {
.search-date-picker {
padding: 20rpx 32rpx;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
span {
line-height: 40rpx;
color: $theme-hint-text;
}
img {
width: 18rpx;
height: 11rpx;
margin: 0 0 0 26rpx;
}
}
}
body::v-deep .text-overflow-1 {
color: #666666 !important;
line-height: 44rpx !important;
font-size: 32rpx !important;
font-weight: bold !important;
}
body::v-deep .tmicon-times-circle-fill {
width: 37rpx;
height: 37rpx;
}
body::v-deep .round-3 {
background: linear-gradient(to right, #674bbc, #46299d);
}
.search-by-condition-input-list {
padding: 20rpx 48rpx 0 42rpx;
.search-by-condition-input {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
.search-by-condition-input-text {
flex-shrink: 0;
margin: 0 0 0 20rpx;
color: $theme-primary;
}
}
.search-by-condition-list {
.condition-dimensionality {
.condition-dimensionality-each {
.condition-dimensionality-each-month {
padding: 24rpx 0 10rpx;
span {
line-height: 40rpx;
color: $theme-hint-text;
}
}
.condition-each-resultList {
.condition-each-resultList-each {
border-bottom: 1px solid $theme-border-color;
padding: 0 0 20rpx;
.condition-each-result-main {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
.condition-each-result-main-date {
line-height: 34rpx;
color: $theme-hint-text;
}
}
.condition-each-result-attachments {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
padding: 24rpx 30rpx;
background-color: #f3f3f3;
border-radius: 8rpx;
.attachment-avatar {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
flex-shrink: 0;
img {
width: 96rpx;
height: 96rpx;
}
}
.attachment-info {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
margin: 0 0 0 22rpx;
.attachment-info-title {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
span {
line-height: 40rpx;
color: $theme-text;
}
}
.attachment-sub-info {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
span {
line-height: 34rpx;
color: $theme-hint-text;
word-break: break-all;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
text-overflow: ellipsis;
}
}
}
}
}
}
.condition-type-imgAndVideo-result {
border-bottom: 0;
padding: 0;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
flex-wrap: wrap;
.condition-each-resultList-each {
.condition-result-imgAndVideo {
margin: 0 5rpx;
::v-deep .overflow {
width: 164rpx !important;
height: 164rpx !important;
}
.condition-result-imgAndVideo-area {
::v-deep .overflow {
width: 164rpx !important;
height: 164rpx !important;
}
::v-deep .round-0 {
width: 164rpx !important;
height: 164rpx !important;
}
}
}
}
}
}
}
}
}
</style>