SFH5/pages/book/index.vue
2026-03-16 11:10:28 +08:00

457 lines
12 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="container" :class="[`${themeInfo.theme}-theme`, `${themeInfo.language}`]">
<view class="header-wrap">
<wxNavbar :title="$t('tabbar.book')"></wxNavbar>
<!-- 头部的筛选 -->
<view class="header">
<view class="header-text" @click="open">
<uv-icon name="dropdown" custom-prefix="custom-icon" size="16" :color="themeInfo.iconColor"></uv-icon>
&nbsp;&nbsp;{{ $t("book.location") }}:&nbsp;{{ popupData.selectCity }}
</view>
<view class="header-text" @click="tomapMode">
{{ $t("book.map") }}&nbsp;&nbsp;
<uv-icon name="setting1" custom-prefix="custom-icon" size="16" :color="themeInfo.iconColor"></uv-icon>
</view>
</view>
</view>
<!-- location窗口 -->
<uv-overlay :show="popupData.show" @click="open" z-index="99" >
<view class="location-popup">
<view class="select-area-wrap" :style="{ 'margin-top': `${state.navHeight}px` }" @click.stop.prevent>
<view class="city inner-wrap">
<view class="top-wrap">
<uv-icon name="halfArrow" custom-prefix="custom-icon" size="16" color="#0F2232"></uv-icon>
<text class="text">{{ $t("book.city") }}</text>
</view>
<view class="select-wrap">
<view
class="select-item"
v-for="(item, index) in popupData.cityData"
:key="index"
:class="{ select: item === popupData.selectCity }"
@click="handleCity(item)">
<view class="circle"></view>
<view class="name">{{ item }}</view>
</view>
</view>
</view>
<view class="border"></view>
<view class="area inner-wrap">
<view class="top-wrap">
<uv-icon name="halfArrow" custom-prefix="custom-icon" size="16" color="#0F2232"></uv-icon>
<text class="text">{{ $t("book.area") }}</text>
</view>
<view class="select-wrap">
<view
class="select-item"
v-for="(item, index) in popupData.areaData"
:key="index"
:class="{ select: item === popupData.selectDistrict }"
@click="handleDistrict(item)">
<view class="circle"></view>
<view class="name">{{ item }}</view>
</view>
</view>
</view>
</view>
</view>
</uv-overlay>
<!-- 热推门店详情 -->
<view class="get-location-wrap" @click="handleAuthorize" v-if="locationState.showGetLocation">
{{ $t("book.get") }}
</view>
<view :style="{ 'margin-top': `${state.navHeight}px` }" class="shopDetail" v-if="siteData.list?.length">
<siteDetail v-for="item in siteData.list" :key="item.id" :siteItem="item" @showCode="handleShowCode"></siteDetail>
</view>
<view class="footer">
<myCustomtTabBar direction="horizontal" :show-icon="true" :selected="2" @onTabItemTap="onTabItemTap" />
</view>
<!-- 门禁二维码 -->
<myPopup v-model="state.showQrcode" bgColor="transparent">
<view class="qrcode-wrap">
<view class="get-code-btn" v-show="!state.qrcodeUrl">
<uv-button @click="GetQRCode">
{{ $t("book.getCode") }}
</uv-button>
</view>
<image class="qrcodeImg" :src="state.qrcodeUrl"></image>
</view>
<view class="btn-wrap">
<uv-button @click="RemoteOpenDoor" :loading="state.openDoorLoading" :loadingText="t('unlock.remoteOpenLoading')">{{ state.openDoorText }}</uv-button>
</view>
</myPopup>
</view>
</template>
<script setup>
import { ref, reactive } from "vue";
import { onLoad, onShow, onHide, onShareAppMessage} from "@dcloudio/uni-app";
import { onTabItemTap, getDistance, navbarHeightAndStatusBarHeight,shareParam,mergeFiveGoatStores } from "@/utils/common.js";
import { ClientSite } from "@/Apis/book.js";
import wxNavbar from "@/components/wxNavbar.vue";
import myCustomtTabBar from "@/components/myCustomtTabBar.vue";
import siteDetail from '@/components/siteDetail.vue';
import myPopup from '@/components/myPopup.vue';
import { useLockApi } from '@/Apis/lock.js';
import { AppId } from '@/config/index.js'
// 主题色配置
import { useMainStore } from "@/store/index.js";
const { themeInfo, storeState } = useMainStore();
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
import { useLocation } from "@/hooks/useLocation";
const { locationState, openLocationAuthorize, getLocation } = useLocation();
const getLockApi = useLockApi();
const getApi = ClientSite();
const state = reactive({
navHeight: 0,
showQrcode: false,
qrcodeUrl: '',
firstLoad: false,
openDoorLoading: false,
clickItem: {},
openDoorText: t('unlock.remoteOpen'),
});
onShareAppMessage((res) => {
if (res.from === "button") {
// 来自页面内分享按钮
console.log(res.target);
}
return shareParam;
});
onLoad(() => {
uni.hideTabBar();
state.navHeight = Number(navbarHeightAndStatusBarHeight().navbarHeight) + 50;
// 获取城市数据
getCityData();
state.firstLoad = true;
// 小红书onshow第一次 不会触发
// #ifdef MP-XHS
getLocation().finally(() => {
getSiteDetail();
// #ifndef MP-WEIXIN
locationState.showGetLocation = false;
// #endif
});
// #endif
});
onShow(() => {
getLocation().finally(() => {
getSiteDetail();
// #ifndef MP-WEIXIN
locationState.showGetLocation = false;
// #endif
});
});
onHide(() => {
state.firstLoad = false;
});
/**
* 开门功能相关
*/
const handleShowCode = (item) => {
state.clickItem = item;
state.showQrcode = true;
state.qrcodeUrl = '';
}
// 远程开门
const RemoteOpenDoor = () => {
if (!state.clickItem?.id || state.openDoorLoading) return;
state.openDoorLoading = true;
getLockApi.RemoteOpenDoor({ siteId: state.clickItem.id }).then(res => {
state.openDoorLoading = false;
if (res.code === 200) {
uni.showToast({
title: t('unlock.remoteOpenSuccess'),
icon: 'none'
});
state.openDoorText = t('unlock.remoteOpenSuccess');
setTimeout(() => {
state.openDoorText = t('unlock.remoteOpen');
}, 3000);
} else {
uni.showToast({
title: t('unlock.remoteOpenFail'),
icon: 'none'
});
}
});
}
// 获取二维码
const GetQRCode = () => {
if (!state.clickItem?.id) return;
uni.showLoading();
getLockApi.GetAccesscontrolQRCodeBySite({ siteId: state.clickItem.id }).then(res => {
if (res.code === 200) {
state.qrcodeUrl = res.data;
}
uni.hideLoading();
});
}
// 跳转到地图页
const tomapMode = ()=>{
uni.navigateTo({
url: "/pages/book/mapmode"
});
}
/**
* 顶部popup 相关功能
*/
const popupData = reactive({
show: false,
selectCity: "",
selectDistrict: "",
cityData: [],
areaData: [],
});
const open = () => {
popupData.show = !popupData.show;
}
const getCityData = () => {
getApi.GetCityAll().then(res => {
if(res.code === 200) {
popupData.cityData = res.data;
popupData.cityData.unshift("全部");
// 首次直接选择全部
popupData.selectCity = popupData.cityData[0];
}
})
}
const handleCity = (city) => {
popupData.selectCity = city;
if (city === "全部") {
popupData.areaData = ["全部"];
popupData.selectDistrict = "全部";
getSiteDetail();
} else {
getApi.GetDistrictByCity(city).then(res => {
if (res.code === 200) {
popupData.areaData = res.data;
popupData.areaData.unshift("全部");
popupData.selectDistrict = popupData.areaData[0];
}
let currentCity = city === "全部" ? "" : city;
getSiteDetail(currentCity, "");
});
}
}
const handleDistrict = (item) => {
popupData.selectDistrict = item;
let currentCity = popupData.selectCity === "全部" ? "" : popupData.selectCity;
let district = item === "全部" ? "" : item;
getSiteDetail(currentCity, district);
}
let siteData = reactive({
list: [],
isLoading: false,
});
// 获取门店信息
const getSiteDetail = (city, district,isAll) => {
if (siteData.isLoading) return;
// #ifdef MP-WEIXIN
// if (locationState.showGetLocation) {
// uni.showToast({
// title: t("book.getSite"),
// icon: "none",
// duration: 2000
// });
// return;
// }
// #endif
uni.showLoading();
siteData.isLoading = true;
let getCity = city || "";
let getDistrict = district || "";
if (!city) {
getCity = popupData.selectCity == "全部" ? "" : popupData.selectCity;
getDistrict = popupData.selectDistrict == "全部" ? "" : popupData.selectDistrict;
}
if(isAll){
getCity = "";
getDistrict = "";
}
getApi.getSiteDetailsAll({
city: getCity,
district: getDistrict
}).then(res => {
if (res.code === 200) {
siteData.list = mergeFiveGoatStores(res.data);
if (locationState?.latitude && locationState?.longitude) {
const { latitude, longitude } = locationState;
siteData.list.forEach(item => {
const { distance, number } = getDistance(latitude, longitude, item.latitude, item.longitude);
item.distance = distance;
item.distanceNumber = number;
});
siteData.list.sort((a, b) => a.distanceNumber - b.distanceNumber);
if (state.firstLoad) filterSiteData();
}else {
// 如果是金刚就不是显示全部
if(AppId === 'wxb20921dfdd0b94f4' || AppId === 'wx3c4ab696101d77d1') {
if (state.firstLoad) filterSiteData(true);
}
}
}
uni.hideLoading();
siteData.isLoading = false;
}).catch(err => {
uni.hideLoading();
siteData.isLoading = false;
});
}
const handleAuthorize = () => {
openLocationAuthorize().then(res => {
state.firstLoad = true;
if (res) getSiteDetail('全部','全部',true);
});
}
// 首次只显示距离最近的城市 noLocation 沒有定位的情况下顯示深圳
const filterSiteData = (noLocation) => {
state.firstLoad = false;
if (!siteData.list.length) return;
let city = siteData.list[0]['city'];
// 如果是金刚的appid默认显示深圳的门店
if(noLocation){
if(AppId === 'wxb20921dfdd0b94f4' || AppId === 'wx3c4ab696101d77d1') {
city = siteData.list.find(item => item.city.indexOf("深圳") !== -1)?.city;
}
}
siteData.list = siteData.list.filter((item) => item.city.indexOf(city) !== -1);
popupData.selectCity = city;
getApi.GetDistrictByCity(city).then(res => {
if (res.code === 200) {
popupData.areaData = res.data;
popupData.areaData.unshift("全部");
popupData.selectDistrict = popupData.areaData[0];
}
});
}
</script>
<style lang="scss" scoped>
@import '@/static/style/theme.scss';
.container {
width: 100%;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
align-items: center;
.qrcode-wrap {
position: relative;
width: 100%;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
border-radius: 18rpx;
.get-code-btn {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.qrcodeImg {
background-color: #FFFFFF;
height: 600rpx;
width: 600rpx;
}
}
.btn-wrap {
width: 600rpx;
margin: 0 auto;
margin-top: 40rpx;
}
.qrcode-wrap,
.btn-wrap {
::v-deep .uv-button {
color: var(--text-color);
background-color: var(--btn-color1);
border: none;
font-size: 32rpx;
font-weight: bold;
text-justify: 20rpx;
.uv-button__loading-text {
font-size: 32rpx!important;
font-weight: bold;
text-justify: 20rpx;
}
}
}
}
.header-wrap {
position: fixed;
width: 100%;
background: linear-gradient(to bottom, var(--left-linear), var(--right-linear));
z-index: 999;
::v-deep .wxNavbar {
background: transparent !important;
}
}
// 头部的筛选
.header {
height: 50px;
width: 100%;
padding: 0 40rpx;
display: flex;
align-items: center;
justify-content: space-between;
.header-text {
font-size: 28rpx;
font-weight: bold;
display: flex;
align-items: center;
color: var(--whiteOrBlack);
& > .header-icon {
width: 28rpx;
height: 28rpx;
}
}
}
// 门店列表
.shopDetail {
width: 100%;
margin-bottom: 300rpx;
display: flex;
flex-direction: column;
align-items: center;
}
.get-location-wrap {
position: fixed;
height: 74rpx;
background-color: var(--main-color);
border-radius: 45rpx 0rpx 0rpx 45rpx;
border: 4rpx solid var(--stress-text);
box-shadow: 0rpx 4rpx 10rpx 0rpx rgba(0, 0, 0, 0.1);
right: -4px;
top: 75%;
padding: 0 20rpx 0 30rpx;
z-index: 9;
display: flex;
justify-content: center;
align-items: center;
color: var(--stress-text);
font-size: 28rpx;
font-weight: 700;
}
</style>