mrr.sj.front/pages/search/search-history.vue

455 lines
11 KiB
Vue

<template>
<view class="searchhis-page">
<!-- 搜索框 -->
<search-box
v-model="searchText"
placeholder="输入手艺人/服务/店铺等"
@search="onSearch"
@confirm="onSearch"
/>
<view class="history_content">
<!-- 历史搜索 -->
<view class="history-section">
<view class="section-header">
<view class="header-left">
<text class="section-title">历史搜索</text>
</view>
<view v-if="isDel" class="del_select">
<view @click="showConfirmModal = true" class="allDel"
>全部删除</view
>
<image
class="split"
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/35ec857d-02c6-41e1-b6e9-fea885625743"
/>
<view class="allDel" @click="isDel = false">完成</view>
</view>
<view v-else class="header-right" @click="isDel = true">
<image
class="delete-icon"
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/e454c821-7fb3-4c89-8cc4-e7771361985b"
></image>
</view>
</view>
</view>
<!-- 标签分类 -->
<view class="category-section">
<view
class="history-list history_list history_cau"
v-if="historyList.length"
>
<view v-for="item in historyList" class="history-item history_item">
<text class="history-text text-overflow-1">{{ item }}</text>
</view>
</view>
<!-- 历史记录列表 -->
<view
class="history-list history_list history_list_show"
v-if="historyList.length"
>
<view
v-for="(item, index) in showHistoryList"
class="history-item"
@click="selectHistory(item)"
>
<text class="history-text text-overflow-1">{{ item }}</text>
<image
@click="removeHistory(index)"
v-if="isDel"
class="delIcon"
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/9cc3f293-80ca-41ab-b964-90e144fcdcfb"
/>
</view>
<view
v-if="!isDel && !isMore && this.historyList.length > this.maxNum"
class="history-item del_tag"
style="padding: 0"
@click="isMore = true"
>
<image
class="moreIcon"
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/201c503d-ed9e-4090-9f14-1f6ffdabcc93"
/>
</view>
</view>
<view class="history-null" v-else>暂无搜索历史</view>
</view>
<!-- 热门搜索 -->
<view class="history-section" style="margin-top: 40rpx">
<view class="section-header">
<view class="header-left">
<text class="section-title">热门搜索</text>
</view>
<view class="header-right" @click="getHotList">
<image
class="delete-icon"
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/22482af8-2036-411a-b7f7-f7dbf76441a0"
></image>
</view>
</view>
</view>
<!-- 标签分类 -->
<view class="category-section">
<!-- 历史记录列表 -->
<view class="history-list" v-if="hotList.length">
<view
v-for="(item, index) in hotList"
:key="index"
class="history-item"
@click="selectHistory(item)"
>
<text class="history-text text-overflow-1">{{ item }}</text>
</view>
</view>
<view class="history-null" v-else>暂无热门搜索</view>
</view>
</view>
<confirm-modal
:visible="showConfirmModal"
title="确认删除最近搜索记录吗?"
cancel-text="取消"
confirm-text="删除"
@cancel="showConfirmModal = false"
@confirm="clearHistory"
/>
</view>
</template>
<script>
import confirmModal from "./components/confirm-modal.vue";
import searchBox from "./components/search-box.vue";
import request from "../../utils/request";
export default {
components: {
searchBox,
confirmModal,
},
data() {
return {
searchText: "",
historyList: [],
hotList: [],
isMore: false,
isDel: false,
maxNum: 20,
showConfirmModal: false, // 控制自定义弹窗的显示
};
},
mounted() {},
async onShow() {
this.uploadHistory();
this.getHotList();
this.updateMaxNum();
},
watch: {
isDel(nVal) {
if (!nVal) {
this.updateMaxNum();
}
},
},
computed: {
showHistoryList() {
if (this.isMore || this.isDel) {
return this.historyList.slice(0, 20);
} else {
return this.historyList.slice(
0,
this.historyList.length > this.maxNum ? this.maxNum : 20
);
}
},
},
methods: {
updateMaxNum() {
this.$nextTick(async () => {
if (!this.historyList.length) return;
const count = await this.calculateTwoRowsItems();
this.maxNum = count;
});
},
async calculateTwoRowsItems() {
return new Promise(async (resolve) => {
const containerRect = await new Promise((res) => {
uni
.createSelectorQuery()
.in(this)
.select(".history_list_show")
.boundingClientRect(res)
.exec();
});
if (!containerRect) {
resolve(0);
return;
}
const containerWidth = containerRect.width + 10;
const itemRects = await new Promise((res) => {
uni
.createSelectorQuery()
.in(this)
.selectAll(".history_item")
.boundingClientRect(res)
.exec();
});
console.log(itemRects,'zzz')
if (!itemRects || itemRects.length === 0) {
resolve(0);
return;
}
// 提取所有 item 的宽度(过滤无效值)
const itemWidths = itemRects
.map((rect) => rect?.width || 0)
.filter((w) => w > 0);
const horizontalGap = 10; // 假设 item 之间的水平间距为 10rpx
let currentRowWidth = 0; // 当前行已占用宽度
let rowCount = 1; // 当前行数(从 1 开始)
let totalItems = 0; // 总数量
for (const width of itemWidths) {
// 计算当前 item 加入后的总宽度(含间距)
const requiredWidth =
currentRowWidth + width + (currentRowWidth > 0 ? horizontalGap : 0);
if (requiredWidth <= containerWidth) {
// 能放入当前行
currentRowWidth = requiredWidth;
totalItems++;
} else {
// 超出当前行,换行
rowCount++;
if (rowCount > 2) {
// 超过两行,停止计算
break;
}
// 放入新行
currentRowWidth = width;
totalItems++;
}
}
console.log(
currentRowWidth,
containerWidth,
totalItems,
itemWidths.length,
currentRowWidth + itemRects[0].height < containerWidth
);
if (
totalItems === itemWidths.length ||
currentRowWidth + itemRects[0].height + 10 < containerWidth
) {
resolve(totalItems);
} else {
resolve(totalItems - 1);
}
});
},
getHotList() {
request
.post("/user/AppSearchLog/list", { page: 1, limit: 20 })
.then((res) => {
console.log(res.data.list, "res.data.list");
this.hotList = res.data.list.map((it) => it.search_val);
});
},
openMore() {},
uploadHistory() {
let that = this;
that.historyList = uni.getStorageSync("historyList") || [];
},
removeHistory(index, value) {
const list = this.historyList.filter((_, i) => {
if (index === i) {
return false;
} else {
return true;
}
});
if (value) {
list.unshift(value);
}
this.historyList = list;
uni.setStorageSync("historyList", list);
},
onSearch() {
let that = this;
if (!that.searchText.trim()) return;
// 添加到历史记录
let i = that.historyList.indexOf(that.searchText);
setTimeout(() => {
if (i != -1) {
this.removeHistory(i, that.searchText);
} else {
this.historyList = [that.searchText, ...this.historyList];
uni.setStorageSync("historyList", this.historyList);
}
}, 200);
// TODO: 执行搜索
uni.navigateTo({
url: `/pages/search/search-result?searchText=${this.searchText}`,
});
},
selectHistory(item) {
if (this.isDel) return;
let that = this;
that.searchText = item;
that.onSearch();
},
clearHistory() {
this.isDel = false;
this.showConfirmModal = false;
let that = this;
that.historyList = [];
that.haveHistory = false;
uni.removeStorageSync("historyList");
},
},
onLoad() {
// 从本地存储加载历史记录
try {
const history = uni.getStorageSync("searchHistory");
if (history) {
this.historyList = JSON.parse(history);
}
} catch (e) {
console.error("Failed to load search history:", e);
}
},
onUnload() {
// 保存历史记录到本地存储
try {
uni.setStorageSync("searchHistory", JSON.stringify(this.historyList));
} catch (e) {
console.error("Failed to save search history:", e);
}
},
};
</script>
<style lang="less" scoped>
.del_select {
display: flex;
align-items: center;
gap: 18rpx;
font-size: 26rpx;
color: #999999;
.split {
width: 2rpx;
height: 24rpx;
}
}
.history_content {
background-color: #fff;
height: 100%;
padding: 24rpx 30rpx;
}
.searchhis-page {
background-color: #f2f4f7;
/* #ifdef APP-PLUS */
padding-top: var(--status-bar-height);
/* #endif */
height: 100vh;
overflow: hidden;
box-sizing: border-box;
}
.history-section {
box-sizing: border-box;
}
.section-header {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
}
.header-left {
flex-direction: row;
align-items: center;
}
.clock-icon {
width: 40rpx;
height: 40rpx;
margin-right: 20rpx;
}
.section-title {
font-weight: 500;
font-size: 30rpx;
color: #333333;
}
.delete-icon {
width: 26rpx;
height: 26rpx;
}
.category-section {
}
.category-title {
font-size: 28rpx;
color: #333;
}
.history-list {
margin-top: 20rpx;
display: flex;
flex-flow: row wrap;
gap: 10rpx;
margin-right: 50rpx;
}
.history-item {
max-width: 400rpx;
font-size: 24rpx;
color: #5b5b5b;
padding: 12rpx 24rpx;
background: #f6f5f7;
border-radius: 29rpx;
display: flex;
align-items: center;
justify-content: center;
min-height: 57rpx;
min-width: 57rpx;
box-sizing: border-box;
gap: 12rpx;
.delIcon {
width: 13rpx;
height: 13rpx;
flex-shrink: 0;
}
}
.history-text {
width: 100%;
}
.moreIcon {
width: 15rpx;
height: 9rpx;
}
.history-null {
padding-top: 20rpx;
font-size: 24rpx;
color: #666;
box-sizing: border-box;
}
.history_cau {
position: absolute;
right: -100000rpx;
z-index: -100;
visibility: hidden;
}
</style>