379 lines
8.3 KiB
Vue
379 lines
8.3 KiB
Vue
![]() |
<template>
|
|||
|
<fix-base-style :styleSpacing="styleSpacing" :styleColor="styleColor" :index="index">
|
|||
|
<view class="fix-positioning">
|
|||
|
<view :class="[`is-${mode}`]" class="header">
|
|||
|
<view class="item">
|
|||
|
<view v-if="mode == 'mode-1'">
|
|||
|
<view>{{ locationData.name }},{{ locationData.time }}</view>
|
|||
|
<view class="mt-10 text-size-m row-center" @click="moreStore">
|
|||
|
<cl-icon name="location"></cl-icon>
|
|||
|
<text class="mx-6">{{ locationData.store }}</text>
|
|||
|
<text class="text-grey">{{ locationData.distance }}</text>
|
|||
|
<text class="mx-6">更多门店</text>
|
|||
|
<cl-icon name="arrow-bottom"></cl-icon>
|
|||
|
</view>
|
|||
|
<view></view>
|
|||
|
</view>
|
|||
|
<view v-if="mode == 'mode-2'" @click="moreStore">
|
|||
|
<view class="row-center">
|
|||
|
<cl-icon name="location"></cl-icon>
|
|||
|
<text class="mx-6">{{ locationData.store }}</text>
|
|||
|
<cl-icon name="arrow-right"></cl-icon>
|
|||
|
</view>
|
|||
|
<view class="mt-10 text-size-m">
|
|||
|
<text class="text-grey mx-6">{{ locationData.distance }}</text>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
<view v-if="mode == 'mode-3'" @click="moreStore">
|
|||
|
<view class="row-center">
|
|||
|
<cl-icon name="location"></cl-icon>
|
|||
|
<text class="mx-6">{{ locationData.address }}</text>
|
|||
|
</view>
|
|||
|
<view class="mt-10 text-size-m">
|
|||
|
<text class="text-grey">由</text>
|
|||
|
<text class="text-grey mx-6">{{ locationData.store }}</text>
|
|||
|
<text class="text-grey">提供</text>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
<view class="is-bg" :style="headerBackground"></view>
|
|||
|
</view>
|
|||
|
<view class="banner" v-if="banner.open">
|
|||
|
<swiper
|
|||
|
:class="[{ 'is-float': float.open }]"
|
|||
|
:style="{ height: `${props.banner.height}rpx` }"
|
|||
|
>
|
|||
|
<swiper-item v-for="(item, index) in banner.list" :key="index">
|
|||
|
<image
|
|||
|
:src="item.pic"
|
|||
|
:class="[{ 'is-float': float.open }]"
|
|||
|
class="banner-item"
|
|||
|
:style="{ height: `${props.banner.height}rpx` }"
|
|||
|
/>
|
|||
|
</swiper-item>
|
|||
|
</swiper>
|
|||
|
<view class="float" v-if="float.open">
|
|||
|
<view class="left" :style="leftStyle" @click="toPath(float.left.link)">
|
|||
|
<template v-if="float.left.mode === 'mode-1'">
|
|||
|
<image class="icon" mode="widthFix" :src="float.left.icon"></image>
|
|||
|
<view class="mt-20 text">{{ float.left.text }}</view>
|
|||
|
</template>
|
|||
|
</view>
|
|||
|
<view class="right" :style="rightStyle" @click="toPath(float.right.link)">
|
|||
|
<template v-if="float.right.mode === 'mode-1'">
|
|||
|
<image class="icon" mode="widthFix" :src="float.right.icon"></image>
|
|||
|
<view class="mt-20 text">{{ float.right.text }}</view>
|
|||
|
</template>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</fix-base-style>
|
|||
|
</template>
|
|||
|
|
|||
|
<script lang="ts" name="fix-positioning" setup>
|
|||
|
import { computed, watch, ref, type PropType } from "vue";
|
|||
|
import type { Form } from "../../types/form";
|
|||
|
import { baseProps } from "../../hooks";
|
|||
|
import { useCool, useStore } from "/@/cool";
|
|||
|
|
|||
|
const props = defineProps({
|
|||
|
mode: {
|
|||
|
type: String,
|
|||
|
default: "",
|
|||
|
},
|
|||
|
banner: {
|
|||
|
type: Object as PropType<{ open: boolean; height: number; list: Form.Banner[] }>,
|
|||
|
default: () => {
|
|||
|
return {
|
|||
|
open: false,
|
|||
|
height: 750,
|
|||
|
list: [],
|
|||
|
};
|
|||
|
},
|
|||
|
},
|
|||
|
float: {
|
|||
|
type: Object,
|
|||
|
default: () => {
|
|||
|
return {
|
|||
|
open: false,
|
|||
|
left: {
|
|||
|
text: "",
|
|||
|
mode: "mode-1",
|
|||
|
icon: "",
|
|||
|
color: "#000",
|
|||
|
backgroundColor: "#FFFFFF",
|
|||
|
link: {
|
|||
|
name: "",
|
|||
|
type: "",
|
|||
|
appid: "",
|
|||
|
page: "",
|
|||
|
},
|
|||
|
},
|
|||
|
right: {
|
|||
|
text: "",
|
|||
|
mode: "mode-1",
|
|||
|
icon: "",
|
|||
|
color: "#000",
|
|||
|
backgroundColor: "#FFFFFF",
|
|||
|
link: {
|
|||
|
name: "",
|
|||
|
appid: "",
|
|||
|
type: "",
|
|||
|
page: "",
|
|||
|
},
|
|||
|
},
|
|||
|
};
|
|||
|
},
|
|||
|
},
|
|||
|
index: {
|
|||
|
type: Number,
|
|||
|
default: 0,
|
|||
|
},
|
|||
|
...baseProps,
|
|||
|
});
|
|||
|
const { service, router } = useCool();
|
|||
|
const { user } = useStore();
|
|||
|
const emits = defineEmits(["jump"]);
|
|||
|
|
|||
|
const headerBackground = computed(() => {
|
|||
|
return {
|
|||
|
opacity: props.styleColor.opacity,
|
|||
|
backgroundColor: props.styleColor.backgroundColor,
|
|||
|
};
|
|||
|
});
|
|||
|
|
|||
|
const leftStyle = computed(() => {
|
|||
|
let url = "";
|
|||
|
if (props.float.left.mode === "mode-2") {
|
|||
|
url = props.float.left.icon;
|
|||
|
}
|
|||
|
return {
|
|||
|
backgroundColor: props.float.left.backgroundColor,
|
|||
|
color: props.float.left.color,
|
|||
|
backgroundImage: `url('${url}')`,
|
|||
|
};
|
|||
|
});
|
|||
|
|
|||
|
const rightStyle = computed(() => {
|
|||
|
let url = "";
|
|||
|
if (props.float.right.mode === "mode-2") {
|
|||
|
url = props.float.right.icon;
|
|||
|
}
|
|||
|
return {
|
|||
|
backgroundColor: props.float.right.backgroundColor,
|
|||
|
color: props.float.right.color,
|
|||
|
backgroundImage: `url('${url}')`,
|
|||
|
};
|
|||
|
});
|
|||
|
const locationData = ref({
|
|||
|
name: "张大仙",
|
|||
|
time: "早上好",
|
|||
|
store: "南村番禺店",
|
|||
|
distance: "距离你 0.7km",
|
|||
|
address: "广州番禺南村镇(建奇大厦5号)...",
|
|||
|
});
|
|||
|
watch(
|
|||
|
() => props.mode,
|
|||
|
async (newValue) => {
|
|||
|
locationData.value.time = getTimePeriod();
|
|||
|
getStore();
|
|||
|
},
|
|||
|
{
|
|||
|
deep: true,
|
|||
|
immediate: true,
|
|||
|
},
|
|||
|
);
|
|||
|
|
|||
|
function distanceInMeters(distanceInKilometers: number) {
|
|||
|
let dis = "0m";
|
|||
|
if (distanceInKilometers < 1) {
|
|||
|
// 如果距离小于1公里,将其转换为米(1公里 = 1000米)
|
|||
|
dis = Math.floor(distanceInKilometers * 1000) + "m";
|
|||
|
} else {
|
|||
|
dis = distanceInKilometers + "km";
|
|||
|
}
|
|||
|
|
|||
|
return "距离你 " + dis;
|
|||
|
}
|
|||
|
|
|||
|
function getTimePeriod() {
|
|||
|
const now = new Date();
|
|||
|
const hours = now.getHours();
|
|||
|
|
|||
|
if (hours >= 5 && hours < 12) {
|
|||
|
return "早上好!"; // 5:00 - 11:59
|
|||
|
} else if (hours >= 12 && hours < 14) {
|
|||
|
return "中午好!"; // 12:00 - 13:59
|
|||
|
} else if (hours >= 14 && hours < 18) {
|
|||
|
return "下午好!"; // 14:00 - 17:59
|
|||
|
} else if (hours >= 18 && hours < 24) {
|
|||
|
return "晚上好!"; // 18:00 - 23:59
|
|||
|
} else {
|
|||
|
return "深夜好!"; // 00:00 - 4:59
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function getStore() {
|
|||
|
uni.getLocation({
|
|||
|
type: "wgs84",
|
|||
|
success(res) {
|
|||
|
service.store.sample
|
|||
|
.vicinity({
|
|||
|
...res,
|
|||
|
size: 1,
|
|||
|
page: 1,
|
|||
|
})
|
|||
|
.then((res: any) => {
|
|||
|
if (res.list.length) {
|
|||
|
const { intact, sampleName, distance } = res.list[0];
|
|||
|
locationData.value.distance = distanceInMeters(distance);
|
|||
|
locationData.value.store = sampleName;
|
|||
|
locationData.value.address = intact;
|
|||
|
locationData.value.name = user.info?.nickName || "游客";
|
|||
|
}
|
|||
|
});
|
|||
|
},
|
|||
|
fail(result) {
|
|||
|
// 第一次拒绝后,下次点击提示打开设置授权弹窗
|
|||
|
uni.showModal({
|
|||
|
title: "定位获取失败",
|
|||
|
content: "附近门店查找失败,是否去设置授权打开?",
|
|||
|
success(modal: any) {
|
|||
|
if (modal.confirm) {
|
|||
|
uni.openSetting({
|
|||
|
success: (res) => {},
|
|||
|
});
|
|||
|
}
|
|||
|
},
|
|||
|
});
|
|||
|
},
|
|||
|
});
|
|||
|
}
|
|||
|
function moreStore() {
|
|||
|
router.push("/pages/partnership/sample/vicinity");
|
|||
|
}
|
|||
|
|
|||
|
function toPath(link: Form.Link) {
|
|||
|
emits("jump", link);
|
|||
|
}
|
|||
|
</script>
|
|||
|
|
|||
|
<style lang="scss" scoped>
|
|||
|
.fix-positioning {
|
|||
|
display: flex;
|
|||
|
flex-direction: column;
|
|||
|
align-items: center;
|
|||
|
justify-content: space-between;
|
|||
|
min-height: 140rpx;
|
|||
|
overflow: hidden;
|
|||
|
position: relative;
|
|||
|
box-sizing: border-box;
|
|||
|
.header {
|
|||
|
position: absolute;
|
|||
|
top: 0;
|
|||
|
width: 100%;
|
|||
|
padding: 20rpx;
|
|||
|
box-sizing: border-box;
|
|||
|
min-height: 140rpx;
|
|||
|
|
|||
|
.is-bg {
|
|||
|
position: absolute;
|
|||
|
top: 0;
|
|||
|
left: 0;
|
|||
|
bottom: 0;
|
|||
|
right: 0;
|
|||
|
z-index: 1;
|
|||
|
}
|
|||
|
.item {
|
|||
|
position: absolute;
|
|||
|
top: 0;
|
|||
|
left: 0;
|
|||
|
bottom: 0;
|
|||
|
right: 0;
|
|||
|
z-index: 2;
|
|||
|
padding: 20rpx;
|
|||
|
}
|
|||
|
}
|
|||
|
.banner {
|
|||
|
width: 100%;
|
|||
|
height: 100%;
|
|||
|
position: relative;
|
|||
|
.banner-item {
|
|||
|
width: 750rpx;
|
|||
|
max-width: 100%;
|
|||
|
min-height: 750rpx;
|
|||
|
height: 100%;
|
|||
|
}
|
|||
|
.float {
|
|||
|
display: flex;
|
|||
|
justify-content: center;
|
|||
|
position: absolute;
|
|||
|
bottom: 20rpx;
|
|||
|
left: 20rpx;
|
|||
|
right: 20rpx;
|
|||
|
|
|||
|
.left {
|
|||
|
margin-right: 30rpx;
|
|||
|
}
|
|||
|
.right {
|
|||
|
margin-left: 30rpx;
|
|||
|
}
|
|||
|
.left,
|
|||
|
.right {
|
|||
|
width: 240rpx;
|
|||
|
height: 280rpx;
|
|||
|
border-radius: 12rpx;
|
|||
|
background-size: 100% 100%;
|
|||
|
display: flex;
|
|||
|
flex-direction: column;
|
|||
|
justify-content: center;
|
|||
|
align-items: center;
|
|||
|
.text {
|
|||
|
font-size: 32rpx;
|
|||
|
font-family: PingFang SC;
|
|||
|
font-weight: bold;
|
|||
|
}
|
|||
|
.icon {
|
|||
|
width: 140rpx;
|
|||
|
height: 140rpx;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
.is-mode-4 {
|
|||
|
display: none;
|
|||
|
}
|
|||
|
.row-center {
|
|||
|
display: flex;
|
|||
|
align-items: center;
|
|||
|
}
|
|||
|
.flex-1 {
|
|||
|
flex: 1;
|
|||
|
}
|
|||
|
|
|||
|
.is-float {
|
|||
|
min-height: 750rpx;
|
|||
|
:deep(.uni-swiper-wrapper) {
|
|||
|
overflow: inherit !important;
|
|||
|
}
|
|||
|
}
|
|||
|
.mt-20 {
|
|||
|
margin-top: 20rpx;
|
|||
|
}
|
|||
|
.mt-10 {
|
|||
|
margin-top: 10rpx;
|
|||
|
}
|
|||
|
.text-size-m {
|
|||
|
font-size: 24rpx;
|
|||
|
}
|
|||
|
.mx-6 {
|
|||
|
margin: 0 6rpx;
|
|||
|
}
|
|||
|
.text-grey {
|
|||
|
color: #9e9e9e;
|
|||
|
}
|
|||
|
}
|
|||
|
</style>
|