You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
453 lines
9.8 KiB
453 lines
9.8 KiB
<template>
|
|
<view class="container">
|
|
<!-- 搜索栏 -->
|
|
<view class="search-header">
|
|
<view class="search-box">
|
|
<uv-icon name="search" color="#999" size="16"></uv-icon>
|
|
<input
|
|
class="search-input"
|
|
v-model="searchKeyword"
|
|
placeholder="请输入地址"
|
|
confirm-type="search"
|
|
focus
|
|
@input="onSearchInput"
|
|
@confirm="onSearchConfirm"
|
|
/>
|
|
<uv-icon
|
|
v-if="searchKeyword"
|
|
name="close"
|
|
color="#999"
|
|
size="16"
|
|
@click="clearSearch"
|
|
></uv-icon>
|
|
</view>
|
|
<view class="cancel-btn" @click="goBack">取消</view>
|
|
</view>
|
|
|
|
<!-- 搜索历史 -->
|
|
<view class="section" v-if="!searchKeyword && searchHistory.length > 0">
|
|
<view class="section-header">
|
|
<text class="section-title">搜索历史</text>
|
|
<uv-icon
|
|
name="trash"
|
|
color="#999"
|
|
size="16"
|
|
@click="clearHistory"
|
|
></uv-icon>
|
|
</view>
|
|
<view class="history-list">
|
|
<view
|
|
class="history-item"
|
|
v-for="(item, index) in searchHistory"
|
|
:key="index"
|
|
@click="useHistoryItem(item)"
|
|
>
|
|
<uv-icon name="time" color="#999" size="16"></uv-icon>
|
|
<text class="history-text">{{ item }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 搜索结果 -->
|
|
<view class="search-results" v-if="searchKeyword">
|
|
<view class="loading-box" v-if="isSearching">
|
|
<uv-loading-icon></uv-loading-icon>
|
|
<text>搜索中...</text>
|
|
</view>
|
|
|
|
<view
|
|
v-else-if="searchResults.length === 0 && searchKeyword"
|
|
class="no-result"
|
|
>
|
|
<text>没有找到相关地址</text>
|
|
</view>
|
|
|
|
<view v-else class="result-list">
|
|
<view
|
|
class="result-item"
|
|
v-for="(item, index) in searchResults"
|
|
:key="index"
|
|
@click="selectAddress(item)"
|
|
>
|
|
<view class="result-icon">
|
|
<uv-icon name="map-fill" color="#4080FF" size="20"></uv-icon>
|
|
</view>
|
|
<view class="result-info">
|
|
<view class="result-name">{{ item.name }}</view>
|
|
<view class="result-address">{{ item.address }}</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, watch,onMounted } from "vue";
|
|
import { useUserStore } from "@/store";
|
|
|
|
// 搜索关键词
|
|
const searchKeyword = ref("");
|
|
// 搜索历史
|
|
const searchHistory = ref([]);
|
|
// 搜索结果
|
|
const searchResults = ref([]);
|
|
// 是否正在搜索
|
|
const isSearching = ref(false);
|
|
|
|
// 从本地存储加载搜索历史
|
|
const loadSearchHistory = () => {
|
|
try {
|
|
const history = uni.getStorageSync("searchAddressHistory");
|
|
if (history) {
|
|
searchHistory.value = JSON.parse(history);
|
|
}
|
|
} catch (e) {
|
|
console.error("加载搜索历史失败", e);
|
|
}
|
|
};
|
|
|
|
// 保存搜索历史到本地存储
|
|
const saveSearchHistory = () => {
|
|
try {
|
|
uni.setStorageSync(
|
|
"searchAddressHistory",
|
|
JSON.stringify(searchHistory.value)
|
|
);
|
|
} catch (e) {
|
|
console.error("保存搜索历史失败", e);
|
|
}
|
|
};
|
|
|
|
// 添加搜索历史
|
|
const addToHistory = (keyword) => {
|
|
// 如果已存在,先移除
|
|
const index = searchHistory.value.indexOf(keyword);
|
|
if (index !== -1) {
|
|
searchHistory.value.splice(index, 1);
|
|
}
|
|
|
|
// 添加到最前面
|
|
searchHistory.value.unshift(keyword);
|
|
|
|
// 限制历史记录数量
|
|
if (searchHistory.value.length > 10) {
|
|
searchHistory.value.pop();
|
|
}
|
|
|
|
// 保存到本地存储
|
|
saveSearchHistory();
|
|
};
|
|
|
|
// 清空搜索历史
|
|
const clearHistory = () => {
|
|
uni.showModal({
|
|
title: "提示",
|
|
content: "确定要清空搜索历史吗?",
|
|
success: (res) => {
|
|
if (res.confirm) {
|
|
searchHistory.value = [];
|
|
saveSearchHistory();
|
|
}
|
|
},
|
|
});
|
|
};
|
|
|
|
// 使用历史记录项
|
|
const useHistoryItem = (keyword) => {
|
|
searchKeyword.value = keyword;
|
|
searchAddress(keyword);
|
|
};
|
|
|
|
// 清空搜索框
|
|
const clearSearch = () => {
|
|
searchKeyword.value = "";
|
|
searchResults.value = [];
|
|
};
|
|
|
|
// 搜索地址
|
|
const searchAddress = (keyword) => {
|
|
if (!keyword.trim()) {
|
|
searchResults.value = [];
|
|
return;
|
|
}
|
|
|
|
isSearching.value = true;
|
|
|
|
// 这里应该调用地图API进行地址搜索
|
|
// 示例使用模拟数据
|
|
setTimeout(() => {
|
|
// 模拟搜索结果
|
|
if (keyword.includes("上海") || keyword.includes("天河")) {
|
|
searchResults.value = [
|
|
{
|
|
name: "通力电梯(上海旗舰店)",
|
|
address: "上海天河区珠江城洋村路11号",
|
|
latitude: 31.2304,
|
|
longitude: 121.4737,
|
|
},
|
|
{
|
|
name: "上海中心大厦",
|
|
address: "上海市浦东新区陆家嘴环路479号",
|
|
latitude: 31.2338,
|
|
longitude: 121.5079,
|
|
},
|
|
{
|
|
name: "上海天河城",
|
|
address: "上海市徐汇区天钥桥路123号",
|
|
latitude: 31.1898,
|
|
longitude: 121.4326,
|
|
},
|
|
];
|
|
} else if (keyword.includes("北京")) {
|
|
searchResults.value = [
|
|
{
|
|
name: "北京通力电梯有限公司",
|
|
address: "北京市朝阳区建国路88号",
|
|
latitude: 39.9042,
|
|
longitude: 116.4074,
|
|
},
|
|
{
|
|
name: "北京国贸中心",
|
|
address: "北京市朝阳区建国门外大街1号",
|
|
latitude: 39.9088,
|
|
longitude: 116.4614,
|
|
},
|
|
];
|
|
} else {
|
|
searchResults.value = [];
|
|
}
|
|
|
|
isSearching.value = false;
|
|
|
|
// 添加到搜索历史
|
|
if (searchResults.value.length > 0) {
|
|
addToHistory(keyword);
|
|
}
|
|
}, 800);
|
|
|
|
// 实际应用中应该使用类似下面的代码调用地图API
|
|
/*
|
|
uni.request({
|
|
url: 'https://apis.map.qq.com/ws/place/v1/search',
|
|
method: 'GET',
|
|
data: {
|
|
keyword: keyword,
|
|
boundary: 'region(上海,0)', // 可以根据当前城市动态设置
|
|
key: 'YOUR_MAP_KEY'
|
|
},
|
|
success: (res) => {
|
|
isSearching.value = false;
|
|
if (res.data.status === 0 && res.data.data.length > 0) {
|
|
searchResults.value = res.data.data.map(item => ({
|
|
name: item.title,
|
|
address: item.address,
|
|
latitude: item.location.lat,
|
|
longitude: item.location.lng
|
|
}));
|
|
|
|
// 添加到搜索历史
|
|
addToHistory(keyword);
|
|
} else {
|
|
searchResults.value = [];
|
|
}
|
|
},
|
|
fail: (err) => {
|
|
isSearching.value = false;
|
|
console.error('搜索地址失败', err);
|
|
uni.showToast({
|
|
title: '搜索失败,请重试',
|
|
icon: 'none'
|
|
});
|
|
}
|
|
});
|
|
*/
|
|
};
|
|
|
|
// 监听搜索输入
|
|
const onSearchInput = () => {
|
|
if (searchKeyword.value) {
|
|
// 可以实现输入时实时搜索
|
|
// 这里为了性能考虑,不实时搜索,而是在用户停止输入一段时间后搜索
|
|
clearTimeout(window.searchTimeout);
|
|
window.searchTimeout = setTimeout(() => {
|
|
searchAddress(searchKeyword.value);
|
|
}, 500);
|
|
} else {
|
|
searchResults.value = [];
|
|
}
|
|
};
|
|
|
|
// 搜索确认
|
|
const onSearchConfirm = () => {
|
|
if (searchKeyword.value.trim()) {
|
|
searchAddress(searchKeyword.value);
|
|
}
|
|
};
|
|
|
|
// 选择地址
|
|
const selectAddress = (address) => {
|
|
// 将选择的地址保存到store
|
|
useUserStore().setAdressInfo({
|
|
latitude: address.latitude,
|
|
longitude: address.longitude,
|
|
adress: address.name,
|
|
addressDetail: address.address,
|
|
});
|
|
|
|
// 返回上一页
|
|
uni.navigateBack({
|
|
delta: 1,
|
|
});
|
|
};
|
|
|
|
// 返回上一页
|
|
const goBack = () => {
|
|
uni.navigateBack({
|
|
delta: 1,
|
|
});
|
|
};
|
|
|
|
// 页面加载时
|
|
onMounted(() => {
|
|
loadSearchHistory();
|
|
});
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.container {
|
|
font-size: 14px;
|
|
min-height: 100vh;
|
|
background-color: #f8f8f8;
|
|
}
|
|
|
|
.search-header {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 20rpx;
|
|
background-color: #ffffff;
|
|
|
|
.search-box {
|
|
flex: 1;
|
|
display: flex;
|
|
align-items: center;
|
|
background-color: #f5f5f5;
|
|
border-radius: 30rpx;
|
|
padding: 10rpx 20rpx;
|
|
|
|
.search-input {
|
|
flex: 1;
|
|
height: 60rpx;
|
|
margin: 0 20rpx;
|
|
font-size: 28rpx;
|
|
}
|
|
}
|
|
|
|
.cancel-btn {
|
|
padding: 0 20rpx;
|
|
font-size: 28rpx;
|
|
color: #333333;
|
|
}
|
|
}
|
|
|
|
.section {
|
|
background-color: #ffffff;
|
|
margin-top: 20rpx;
|
|
|
|
.section-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: 20rpx 30rpx;
|
|
border-bottom: 1px solid #f5f5f5;
|
|
|
|
.section-title {
|
|
font-size: 28rpx;
|
|
color: #333333;
|
|
}
|
|
}
|
|
|
|
.history-list {
|
|
padding: 0 30rpx;
|
|
|
|
.history-item {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 20rpx 0;
|
|
border-bottom: 1px solid #f5f5f5;
|
|
|
|
.history-text {
|
|
margin-left: 20rpx;
|
|
font-size: 28rpx;
|
|
color: #333333;
|
|
}
|
|
|
|
&:last-child {
|
|
border-bottom: none;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.search-results {
|
|
background-color: #ffffff;
|
|
margin-top: 20rpx;
|
|
min-height: 200rpx;
|
|
|
|
.loading-box {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 40rpx 0;
|
|
|
|
text {
|
|
margin-top: 20rpx;
|
|
font-size: 28rpx;
|
|
color: #999999;
|
|
}
|
|
}
|
|
|
|
.no-result {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
padding: 60rpx 0;
|
|
color: #999999;
|
|
font-size: 28rpx;
|
|
}
|
|
|
|
.result-list {
|
|
.result-item {
|
|
display: flex;
|
|
padding: 20rpx 30rpx;
|
|
border-bottom: 1px solid #f5f5f5;
|
|
|
|
.result-icon {
|
|
margin-right: 20rpx;
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.result-info {
|
|
flex: 1;
|
|
|
|
.result-name {
|
|
font-size: 30rpx;
|
|
color: #333333;
|
|
margin-bottom: 10rpx;
|
|
}
|
|
|
|
.result-address {
|
|
font-size: 26rpx;
|
|
color: #999999;
|
|
}
|
|
}
|
|
|
|
&:last-child {
|
|
border-bottom: none;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style> |