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>
|