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.

493 lines
12 KiB

<template>
<div style="background: #FAEDCD;">
<div class="top">
<u-image mode="scaleToFill" width="100%" height="100%" :src="require('@/static/map-title-bkg.png')"></u-image>
</div>
<div class="container">
<img ref="image"
src="static/map.png"
alt="" @load="load">
<div class="area" :style="{ 'height': area.h +'px', 'width': area.w +'px' }">
<div class="pointer"
v-for="(item, index) in pointers"
:key="index"
:style="{ 'transform': `translate(calc(${area.w * item.x / 100}px - 50%),calc(${area.h * item.y / 100}px - 50%))` }"
@click="$u.throttle(() => toDetail(item))">
<div class="pointer__horn" :class="{ 'pointer__horn--active': item.has_answer > 0 }" :style="{ 'transform': `translate(-3rpx, calc(-50% - 4rpx)) rotate(${item.d}deg)` }"></div>
<div class="box" :style="{ 'transform': transformBox(item.d) }">
<div class="box__image" :class="{ 'box--active': item.has_answer > 0 }">
<img :src="item.image ? item.image.url : ''" alt="">
</div>
<div class="box__text" :class="{ 'box__text--active': item.has_answer > 0 }" :style="{ 'transform': (item.d > 100 || item.d < -100) ? 'translate(-50rpx, 136rpx)' : '' }">{{ item.name }}</div>
</div>
<!-- <div class="box" :class="{ 'box&#45;&#45;active': item.has_answer > 0 }" :style="{ 'transform': `rotate(${item.d}deg)` }">-->
<!-- <img :style="{ 'transform': `rotate(${-item.d}deg)` }" :src="item.image ? item.image.url : ''" alt="">-->
<!-- </div>-->
<!-- <div class="text"-->
<!-- :class="{ 'text&#45;&#45;active': item.has_answer > 0 }"-->
<!-- :style="{-->
<!-- 'transform': translateText(item.d)-->
<!-- }">-->
<!-- {{ item.name }}-->
<!-- </div>-->
</div>
</div>
</div>
<transition name="progress-box"
enter-active-class="fade-in"
leave-to-class="fade-out">
<div class="progress" v-show="isShowProgress">
<div class="close">
<u-icon name="close-circle" :size="25" color="#666666" @click="isShowProgress = false"></u-icon>
</div>
<div class="box">
<div class="box__line-progress">
<u-line-progress :height="11" active-color="#b93736" :striped="true" :percent="(done/pointers.length)*100" :striped-active="true">
<template #default>
<div class="box__line-progress--img">
<u-image mode="heightFix" :height="97" :src="require('@/static/line-progress-img.png')"></u-image>
</div>
</template>
</u-line-progress>
</div>
<div class="box__text">
<span>完成</span>
<span style="font-style: italic;padding-right: 4rpx;" class="box__text--red">{{pointers.length - done}}</span>
<span>家红色场馆打卡</span><br><span>即可获得</span>
<span class="box__text--red">荣誉证书</span>
</div>
</div>
</div>
</transition>
<transition name="expand-progress-box"
enter-active-class="fade-in"
leave-to-class="fade-out" >
<div class="progress expand-progress" v-show="!isShowProgress" @click="isShowProgress = true">
<u-icon name="arrow-left-double" color="#C52A34"></u-icon>
打卡进度
</div>
</transition>
</div>
</template>
<script>
export default {
data() {
return {
done: 0,
isShowProgress: true,
area: {
w: 100,
h: 200
},
pointers: [
{
x: 37,
y: 34,
d: -30
},
{
x: 74,
y: 39,
d: 38
},
{
x: 43,
y: 72,
d: -170
},
{
x: 21,
y: 60,
d: -155
},
]
};
},
methods: {
toDetail (item) {
this.$u.vuex('vuex_point_id', item.id)
uni.navigateTo({
url: `/pages/detail/detail`
})
},
load () {
this.area.w = this.$refs['image'].getBoundingClientRect().width
this.area.h = this.$refs['image'].getBoundingClientRect().height
},
async getPoints () {
function convertToEquivalentAngle(angle) {
if (angle > 180) {
return angle - 360;
} else if (angle < -180) {
return angle + 360;
} else {
return angle;
}
}
this.pointers = []
const res = await this.$u.api.getPoints()
this.done = res.point_answer_total || 0
this.pointers = res.points?.map((i, index) => {
return {
d: convertToEquivalentAngle(70 * index + 1),
...i
}
})
}
},
computed: {
transformBox () {
return function (deg) {
if (deg) {
if ((deg % 360) > -90 && (deg % 360) < 90) {
return `translate(calc(${Math.floor(Math.sin(Math.PI / 180 * deg) * 80)}rpx - 48rpx), calc(${-1 * Math.floor(Math.cos(Math.PI / 180 * deg) * 80)}rpx - 48rpx))`
} else {
return `translate(calc(${Math.floor(Math.sin(Math.PI / 180 * deg) * 80)}rpx - 48rpx), calc(${-1 * Math.floor(Math.cos(Math.PI / 180 * deg) * 80)}rpx - 48rpx))`
}
} else {
return 'translate(0, 0)'
}
}
},
translateText () {
return function (deg) {
if (deg) {
if ((deg % 360) > -90 && (deg % 360) < 90) {
return `translate(calc(${Math.floor(Math.sin(Math.PI / 180 * deg) * 152)}rpx - 50%), calc(${-Math.floor(Math.cos(Math.PI / 180 * deg) * 152)}rpx - 100%))`
} else {
return `translate(calc(${Math.floor(Math.sin(Math.PI / 180 * deg) * 152)}rpx - 50%), calc(${-Math.floor(Math.cos(Math.PI / 180 * deg) * 152)}rpx ))`
}
} else {
return 'translate(0, 0)'
}
}
}
},
mounted() {
},
onLoad() {
this.getPoints()
}
}
</script>
<style lang="scss">
.top {
width: 100%;
height: 247rpx;
background: transparent;
}
.container {
background: #FAEDCD;
height: calc(100vh - 247rpx);
width: 100vw;
overflow: scroll;
position: relative;
& > img {
width: auto;
height: 100%;
transition: all .2s;
padding: 20rpx 0;
transform: translateX(-50%);
position: absolute;
top: 0;
left: 50%;
}
& .area {
padding: 20rpx 0;
margin: 0 auto;
.pointer {
width: 16rpx;
height: 16rpx;
border-radius: 100%;
background: #fff;
transform-origin: center;
border: 3rpx solid #C52A34;
display: inline-block;
position: relative;
&__horn {
width: 20rpx;
height: 26rpx;
clip-path: polygon(20% 0, 80% 0%, 50% 100%, 20% 0);
background: #F5D8AD;
filter: drop-shadow(2rpx 4rpx 2rpx #90D2CF);
transform-origin: 50% 100%;
position: absolute;
&--active {
background: #C52A34;
}
}
& .box {
transform-origin: 0 0;
position: absolute;
&__text {
width: 200rpx;
word-break: break-word;
background: #F5D8AD;
border-radius: 6rpx;
filter: drop-shadow(2rpx 4rpx 2rpx #90D2CF);
color: #C52A34;
font-size: 20rpx;
zoom: .85;
text-align: center;
transform: translate(-50rpx,-100%);
padding: 10rpx 8rpx;
position: absolute;
top: 0;
&--active {
background: #b93736;
color: #fff;
}
}
&__image {
width: 116rpx;
height: 116rpx;
border-radius: 100%;
box-sizing: border-box;
border: 5rpx #F5D8AD solid;
display: flex;
justify-content: center;
align-items: center;
filter: drop-shadow(2rpx 4rpx 4rpx #90D2CF);
& > img {
width: 106rpx;
height: 106rpx;
border-radius: 100%;
}
}
&--active {
border-color: #b93736;
}
&--active::before {
content: '已打卡';
font-size: 20rpx;
color: #fff;
background: #b93736;
border-radius: 30rpx;
zoom: .8;
clip-path: circle(84rpx at 84% 178%);
padding: 6rpx 14rpx 5rpx 122rpx;
z-index: 2;
position: absolute;
top: -1rpx;
left: -96rpx;
}
&--active::after {
background: #b93736;
}
}
}
//.pointer {
// width: 16rpx;
// height: 16rpx;
// border-radius: 100%;
// background: #fff;
// border: 3rpx solid #C52A34;
// display: inline-block;
//
// position: relative;
//
// & .text {
// background: #F5D8AD;
// border-radius: 6rpx;
// word-break: keep-all;
// filter: drop-shadow(2rpx 4rpx 2rpx #90D2CF);
// color: #C52A34;
// font-size: 20rpx;
// text-align: center;
// transform-origin: 50% 0;
//
// padding: 12rpx 10rpx;
// position: absolute;
//
// &--active {
// background: #b93736;
// color: #fff;
// }
// }
// & .box {
// width: 116rpx;
// height: 116rpx;
// border-radius: 100%;
// box-sizing: border-box;
// border: 5rpx #F5D8AD solid;
// display: flex;
// justify-content: center;
// align-items: center;
// filter: drop-shadow(2rpx 4rpx 2rpx #90D2CF);
// transform-origin: 50% calc(100% + 26rpx + 5rpx);
//
// position: absolute;
// top: calc(-116rpx - 26rpx);
// left: -50rpx;
//
// &--active {
// border-color: #b93736;
// }
// & > img {
// width: 106rpx;
// height: 106rpx;
// border-radius: 100%;
//
// }
// &::after {
// content: '';
// height: 26rpx;
// width: 22rpx;
// background: #F5D8AD;
// clip-path: polygon(0 0, 100% 0, 50% 100%,0 0);
//
// transform: translate(-50% , 100%);
// position: absolute;
// bottom: 0;
// left: 50%;
// }
// &--active::before {
// content: '已打卡';
// font-size: 20rpx;
// color: #fff;
// background: #b93736;
// border-radius: 30rpx;
// zoom: .8;
// clip-path: circle(84rpx at 84% 178%);
//
// padding: 6rpx 14rpx 5rpx 122rpx;
// z-index: 2;
// position: absolute;
// top: -1rpx;
// left: -96rpx;
// }
// &--active::after {
// background: #b93736;
// }
// }
//}
}
}
.expand-progress {
color: #D33838;
background: #F5D8AD;
word-break: break-word;
font-size: 20rpx;
width: 20rpx;
border-radius: 10rpx 0 0 10rpx;
filter: drop-shadow(4rpx 4rpx 4rpx #F08456) drop-shadow(4rpx 10rpx 8rpx #F6A996);
padding: 10rpx 18rpx;
}
.progress {
z-index: 999;
position: fixed;
right: 0;
bottom: 40rpx;
& .close {
transform: translateX(-100%);
position: absolute;
top: -2rpx;
left: 0;
}
& .box {
background: #F5D8AD;
border-radius: 30rpx 0 0 30rpx;
filter: drop-shadow(4rpx 4rpx 4rpx #F08456) drop-shadow(8rpx 10rpx 8rpx #F6A996);
padding: 20rpx 22rpx;
::v-deep .u-progress {
overflow: visible !important;
}
::v-deep .u-active {
border-radius: 20rpx;
position: relative;
}
&__line-progress {
width: 282rpx;
height: 100rpx;
display: flex;
align-items: center;
&--img {
overflow: auto;
transform: translateX(50%);
position: absolute;
right: 0;
}
}
&__text {
text-align: center;
zoom: .85;
font-size: 16rpx;
font-weight: 400;
color: #666666;
&--red {
font-size: 30rpx;
color: #D33838;
font-weight: 600;
}
}
}
}
.fade-in {
animation: fade-in .8s cubic-bezier(0.39, 0.575, 0.565, 1) both;
}
@keyframes fade-in {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.fade-out {
animation: fade-out 0.6s ease-out both;
}
@keyframes fade-out {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
</style>