Feat:寻看点和抽奖

This commit is contained in:
lifizer
2024-02-06 12:42:46 +08:00
parent c88b6aa8a8
commit f3115fe7c8
73 changed files with 5324 additions and 6887 deletions
+55
View File
@@ -0,0 +1,55 @@
<template>
<view class="components-checkbox-icon jc-center ai-center" :class="{'isSelected':isSelected}" @click="change">
<image class="icon-hook" :src="webUrl+'/20240109175325131970.png'" mode="scaleToFill" v-if="isSelected"/>
</view>
</template>
<script setup>
import {VUE_APP_RESOURCES_URL} from '../config/index'
export default {
name: 'CheckboxIcon',
props: {
defaultState: {
type: Boolean,
default: false
}
},
data() {
return {
webUrl: VUE_APP_RESOURCES_URL
}
},
computed: {
isSelected: function() {
return this.defaultState
}
},
methods: {
change() {
this.$emit('change', !this.isSelected)
}
}
}
</script>
<style scoped lang="less">
.components-checkbox-icon {
display: inline-flex;
width: 32rpx;
height: 32rpx;
box-sizing: border-box;
border: 2rpx solid #D5D7D8;
border-radius: 50%;
}
.icon-hook {
width: 24rpx;
height: 24rpx;
}
.isSelected {
border: 3px solid #FD5749;
background: #FD5749;
}
</style>
+57
View File
@@ -0,0 +1,57 @@
<template>
<view class="components-checkbox-icon jc-center ai-center" :class="{'isSelected':isSelected}" @click="change"
v-if="ready">
<image class="icon-hook" :src="webUrl+'/20240109175325131970.png'" mode="scaleToFill" v-if="isSelected"/>
</view>
</template>
<script setup>
import {computed, getCurrentInstance, onMounted, ref} from '@vue/composition-api'
import {VUE_APP_RESOURCES_URL} from '../config/index'
const webUrl = VUE_APP_RESOURCES_URL
const emit = defineEmits(['change'])
const {proxy} = getCurrentInstance()
const props = defineProps({
defaultState: {
type: Boolean,
default: false
},
mark: Array
})
const ready = ref(false)
onMounted(() => {
ready.value = true
})
const isSelected = computed(() => {
return props.defaultState
})
const change = () => {
emit('change', !isSelected.value, props.mark)
}
</script>
<style scoped lang="less">
.components-checkbox-icon {
display: inline-flex;
width: 32rpx;
height: 32rpx;
box-sizing: border-box;
border: 2rpx solid #D5D7D8;
border-radius: 50%;
}
.icon-hook {
width: 24rpx;
height: 24rpx;
}
.isSelected {
border: 3px solid #FD5749;
background: #FD5749;
}
</style>
+1 -5
View File
@@ -81,15 +81,11 @@
<script type="text/babel">
import uniPopup from "./uni-popup/uni-popup.vue";
import uniPopupMessage from "./uni-popup/uni-popup-message.vue";
import uniPopupDialog from "./uni-popup/uni-popup-dialog.vue";
export default {
name: "CitySelect",
components: {
uniPopup,
uniPopupMessage,
uniPopupDialog
uniPopup
},
props: ["callback", "items", "defaultValue"],
data() {
-122
View File
@@ -1,122 +0,0 @@
<template>
<view>
<view class="coupon-list-window" :class="value === true ? 'on' : ''">
<view class="title">
优惠券
<text class="iconfont icon-guanbi" @click="close"></text>
</view>
<view v-if="couponList.length > 0">
<view class="coupon-list">
<div
class="item acea-row row-center-wrapper"
v-for="coupon in couponList"
:key="coupon.id"
@click="click(coupon)"
>
<div class="money">
<div>
<span class="num">{{ coupon.couponPrice }}</span>
</div>
<div class="pic-num">{{ coupon.useMinPrice }}元可用</div>
</div>
<div class="text">
<div class="condition line1">{{ coupon.couponTitle }}</div>
<div class="data acea-row row-between-wrapper">
<div v-if="coupon.endTime === 0">不限时</div>
<div v-else>截止:{{ coupon.endTime }}</div>
<div
class="iconfont icon-xuanzhong1 font-color-red"
v-if="checked === coupon.id"
></div>
<div class="iconfont icon-weixuanzhong" v-else></div>
</div>
</div>
</div>
</view>
<view class="couponNo bg-color-red" @click="couponNo">不使用优惠券</view>
</view>
<view v-if="!couponList.length && loaded">
<view class="pictrue">
<image src="http://admin-api.xdd618.com/file/pic/20210203154207179472.png" class="image" />
</view>
</view>
</view>
<view class="mask" @touchmove.prevent :hidden="value === false" @click="close"></view>
</view>
</template>
<style scoped lang="less">
.coupon-list-window .iconfont {
font-size: 40rpx;
}
.couponNo {
font-size: 30rpx;
font-weight: bold;
color: #fff;
width: 690rpx;
height: 86rpx;
border-radius: 43rpx;
text-align: center;
line-height: 86rpx;
margin: 60rpx auto;
}
</style>
<script>
import { getOrderCoupon } from "@/api/order";
import DataFormatT from "@/components/DataFormatT";
export default {
name: "CouponListWindow",
components: {
DataFormatT
},
props: {
value: Boolean,
checked: Number,
price: {
type: [Number, String],
default: undefined
},
cartid: {
type: String,
default: ""
}
},
data: function() {
return {
couponList: [],
loaded: false
};
},
watch: {
price(n) {
if (n === undefined || n == null) return;
this.getCoupon();
},
cartid(n) {
if (n === undefined || n == null) return;
this.getCoupon();
}
},
mounted: function() {},
methods: {
close: function() {
this.$emit("input", false);
this.$emit("close");
},
getCoupon() {
getOrderCoupon(this.cartid).then(res => {
this.couponList = res.data;
this.loaded = true;
});
},
click(coupon) {
this.$emit("checked", coupon);
this.$emit("input", false);
},
couponNo: function() {
this.$emit("checked", null);
this.$emit("input", false);
}
}
};
</script>
-75
View File
@@ -1,75 +0,0 @@
<template>
<view>
<view class="coupon-list-window" :class="coupon.coupon === true ? 'on' : ''">
<view class="title">
优惠券
<text class="iconfont icon-guanbi" @click="close"></text>
</view>
<view class="coupon-list" v-if="coupon.list.length > 0">
<view
class="item acea-row row-center-wrapper"
v-for="(item, couponpopIndex) in coupon.list"
:key="couponpopIndex"
@click="getCouponUser(couponpopIndex, item.id)"
>
<view class="money">
<text class="num">{{ item.coupon_price }}</text>
</view>
<view class="text">
<view class="condition line1">购物满{{ item.use_min_price }}元可用</view>
<view class="data acea-row row-between-wrapper">
<view v-if="item.end_time === 0">不限时</view>
<view v-else>{{ item.start_time }}-{{ item.end_time }}</view>
<view
class="bnt acea-row row-center-wrapper"
:class="!item.is_use ? 'bg-color-red' : 'gray'"
>{{ !item.is_use ? "立即领取" : "已领取" }}</view>
</view>
</view>
</view>
</view>
<!--无优惠券-->
<view class="pictrue" v-else>
<image src="http://admin-api.xdd618.com/file/pic/20210203154207179472.png" class="image" />
</view>
</view>
<view class="mask" @touchmove.prevent :hidden="coupon.coupon === false" @click="close"></view>
</view>
</template>
<script>
import { getCouponReceive } from "@/api/user";
export default {
name: "CouponPop",
props: {
coupon: {
type: Object,
default: () => {}
}
},
data: function() {
return {};
},
mounted: function() {},
methods: {
close: function() {
this.$emit("changeFun", { action: "changecoupon", value: false }); //$emit():注册事件;
},
getCouponUser: function(index, id) {
let that = this,
list = that.coupon.list;
if (list[index].is_use === true) return;
getCouponReceive(id).then(function() {
uni.showToast({
title: "已领取",
icon: "none",
duration: 2000
});
that.$set(list[index], "is_use", true);
that.$emit("changefun", { action: "currentcoupon", value: index });
that.$emit("changeFun", { action: "changecoupon", value: false });
});
}
}
};
</script>
+5 -5
View File
@@ -1,6 +1,6 @@
<template>
<view class="components-coupons">
<image class="coupons__cover" :src="data.image" mode="scaleToFill"/>
<image class="coupons__cover" :src="data.image" mode="widthFix"/>
<view class="coupons__section flex jc-between ai-center">
<view>有效期至
@@ -9,7 +9,7 @@
<view class="coupons__tag coupons__tag-expire" v-if="data.status===2">已到期</view>
<view class="coupons__tag" @click="goGoods()" v-if="data.status===0 && !radioModel">去使用</view>
<view @click="selectCoupon">
<radio :value="data.id" :checked="data.checked" color="#FF564A" v-if="radioModel && data.status===0"/>
<radio :value="data.id" :checked="data.checked" color="#FF564A" v-if="radioModel && data.status===0"/>
</view>
</view>
@@ -17,7 +17,7 @@
<view class="coupons__rules-title" @click="changeRules()">使用规则
<image :class="{'open':isOpen}" :src="webUrl+'/20231125220409665027.png'" mode="scaleToFill"/>
</view>
<view v-html="data.description" v-show="isOpen"></view>
<rich-text :nodes="data.description" v-show="isOpen"/>
</view>
</view>
</template>
@@ -47,7 +47,7 @@ export default {
this.isOpen = !this.isOpen
},
goGoods() {
uni.switchTab({url:'/pages/home/landMark'})
uni.switchTab({url: '/pages/home/landMark'})
// this.$global.navToGoods(this.data.productId)
},
selectCoupon() {
@@ -72,7 +72,7 @@ export default {
.coupons__cover {
width: 100%;
height: 300rpx;
height: auto;
}
.coupons__section {
+5 -4
View File
@@ -58,7 +58,7 @@
:key="index" v-if="type===0" @click="goStore(item.hotelId)">
<image class="cover" :src="item.hotelImage" mode="scaleToFill"/>
<image class="logo" :src="item.hotelLogo" mode="scaleToFill"/>
<view style="width: 100%">
<view style="width: 100%;box-sizing: border-box;padding:0 8rpx">
<view class="name tc one-t">{{ item.hotelName }}</view>
<rich-text class="text tc one-t" :nodes="item.hotelText"/>
</view>
@@ -486,12 +486,13 @@ export default {
}
.name {
padding-bottom: 10rpx;
font-size: 24rpx;
padding-bottom: 8rpx;
font-size: 22rpx;
line-height: 1.3;
}
.text {
padding-bottom: 10rpx;
padding-bottom: 8rpx;
font-size: 16rpx;
}
}
-142
View File
@@ -1,142 +0,0 @@
<template>
<view>
<view
id="_drag_button"
class="drag"
:style="'left: ' + left + 'px; top:' + top + 'px;'"
@touchstart="touchstart"
@touchmove.stop.prevent="touchmove"
@touchend="touchend"
@click.stop.prevent="click"
:class="{transition: isDock && !isMove }"
>
<image style="width: 100%;height: 100%;" mode="scaleToFill" src="http://admin-api.xdd618.com/file/pic/20210809112551575811.png"></image>
</view>
</view>
</template>
<script>
export default {
name: 'drag-button',
props: {
isDock:{
type: Boolean,
default: false
},
existTabBar:{
type: Boolean,
default: false
}
},
data() {
return {
top:0,
left:0,
width: 0,
height: 0,
offsetWidth: 0,
offsetHeight: 0,
windowWidth: 0,
windowHeight: 0,
isMove: true,
edge: 10,
text: '按钮'
}
},
mounted() {
const sys = uni.getSystemInfoSync();
this.windowWidth = sys.windowWidth;
this.windowHeight = sys.windowHeight;
// #ifdef APP-PLUS
this.existTabBar && (this.windowHeight -= 50);
// #endif
if (sys.windowTop) {
this.windowHeight += sys.windowTop;
}
console.log(sys)
const query = uni.createSelectorQuery().in(this);
query.select('#_drag_button').boundingClientRect(data => {
this.width = data.width;
this.height = data.height;
this.offsetWidth = data.width / 2;
this.offsetHeight = data.height / 2;
this.left = this.windowWidth - this.width - this.edge;
this.top = this.windowHeight - this.height - this.edge;
}).exec();
},
methods: {
click() {
this.$emit('btnClick');
},
touchstart(e) {
this.$emit('btnTouchstart');
},
touchmove(e) {
// 单指触摸
if (e.touches.length !== 1) {
return false;
}
this.isMove = true;
this.left = e.touches[0].clientX - this.offsetWidth;
let clientY = e.touches[0].clientY - this.offsetHeight;
// #ifdef H5
clientY += this.height;
// #endif
let edgeBottom = this.windowHeight - this.height - this.edge;
// 上下触及边界
if (clientY < this.edge) {
this.top = this.edge;
} else if (clientY > edgeBottom) {
this.top = edgeBottom;
} else {
this.top = clientY
}
},
touchend(e) {
if (this.isDock) {
let edgeRigth = this.windowWidth - this.width - this.edge;
if (this.left < this.windowWidth / 2 - this.offsetWidth) {
this.left = this.edge;
} else {
this.left = edgeRigth;
}
}
this.isMove = false;
this.$emit('btnTouchend');
},
}}
</script>
<style lang="scss">
.drag {
display: flex;
justify-content: center;
align-items: center;
//background-color: rgba(0, 0, 0, 0.5);
//box-shadow: 0 0 6upx rgba(0, 0, 0, 0.4);
color: $uni-text-color-inverse;
width: 100rpx;
height: 100rpx;
border-radius: 50%;
font-size: $uni-font-size-sm;
position: fixed;
z-index: 999999;
&.transition {
transition: left .3s ease,top .3s ease;
}
}
</style>
-40
View File
@@ -1,40 +0,0 @@
# 轮播组件
# 基础式
<ls-swiper :list="base_lsit" imgKey="imgUrl" :loop="true" :dots='true' :autoplay='true' @clickItem="clickItem()" />
# 链式
<ls-swiper :list="list" imgKey="imgUrl" imgWidth="300" previousMargin="20" nextMargin='20'/>
# 卡片式
<ls-swiper :list="base_lsit" imgKey="imgUrl" :crown="true" :loop="true" :shadow='true' height='130' previousMargin="120" nextMargin='120' imgRadius="5" />
# props
参数名 | 说明 | 类型 | 默认值
-----------------|-------------------------------------------------- -|-------------|------------
list | 轮播数据 | Array | 必输
imgKey | 轮播数据key(图片url属性) | String | 必输 (自定义模式,非必输)
autoplay | 是否自动播放 | Boolean | false
loop | 是否循环 | Boolean | false
autoplay | 是否自动播放 | Boolean | false
dots | 是否显示轮播点 | Boolean | false
crown | 卡片特效 (中间突出,两边缩放特效) | Boolean | false
interval | 播放时间间隔 | Number | 2000
duration | 滑动速度 | Number | 1500
bottom | 轮播点下边距 | Number | 10 (单位:px,设计图建议以375px为准)
height | 高度 | Number | 200 (单位:px,设计图建议以375px为准)
previousMargin | 图片前边距 | Number | 0 (单位:px,设计图建议以375px为准)
nextMargin | 图片后间距 | Number | 0 (单位:px,设计图建议以375px为准)
imgRadius | 图片圆角 | Number | 0 (单位:px,设计图建议以375px为准)
imgWidth | 图片宽度 | String | 100%
@clickItem | 点击事件 | Function |
@change | 切换事件 | Function |
# 自定义
<ls-swiper :list="list">
<template v-slot="{data}">
xxx
</template>
</ls-swiper>
如有其他需求,可在插槽内编写自定义内容, 自动覆盖原图片样式。
-180
View File
@@ -1,180 +0,0 @@
<template>
<view class="ls-wrap">
<swiper class="ls-swiper" :style="{height: height *2 + 'rpx'}" :autoplay="autoplay" :interval="interval" :duration="duration"
:circular='loop' @change='change' :previous-margin='previousMargin + "rpx"' :next-margin='nextMargin + "rpx"'>
<swiper-item v-for="(item,index) in list" :key='index' @click="$emit('clickItem',item)">
<view v-if="list && list.length>0" class="item" :class="[!crown ? '' : current==index ? 'crown-active':'crown']">
<image v-if="!slotsMode" class="item-img" :class="[imgShadow?'imgShadow':'']" :src="item[imgKey]" :style="{ borderRadius: imgRadius + 'px',width:imgWidth}"
mode=""></image>
<slot v-else :data='item'></slot>
</view>
</swiper-item>
</swiper>
<view class="dots flex" :style="{bottom: bottom * 2 + 'rpx'}" v-if="dots">
<view class="dot" :class="[current == i ? 'curr-dot' : '']" v-for="(d,i) in list" :key='i'>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
list: {
type: Array,
default: () => []
},
// 轮播图片key
imgKey: {
type: String,
required: true
},
// 高度
height: {
type: Number,
default: 200
},
// 图片圆角
imgRadius: {
type: Number,
default: 0
},
// 图片阴影
imgShadow: {
type: Boolean,
default: false
},
// 前边距
previousMargin: {
type: Number,
default: 0
},
// 后边距
nextMargin: {
type: Number,
default: 0
},
// 图片宽度
imgWidth: {
type: String,
default: '100%'
},
// 是否循环
loop: {
type: Boolean,
default: false
},
// 自动播放
autoplay: {
type: Boolean,
default: false
},
// 播放时间间隔
interval: {
type: Number,
default: 2000
},
// 滑动速度
duration: {
type: Number,
default: 1200
},
// 显示指示点
dots: {
type: Boolean,
default: false
},
// 轮播点下边距
bottom: {
type: Number,
default: 10
},
// 卡片特效
crown: {
type: Boolean,
default: false
},
slotsMode: {
type: Boolean,
default: false
},
},
data() {
return {
current: 0,
slots: false
};
},
watch: {
// 判断异步数据源,是否使用插槽自定义样式
list: {
handler(val) {
if (val.length > 0 && this.$slots.default) {
this.slots = true
}
},
immediate: true,
}
},
methods: {
change(event) {
let current = event.detail.current
this.current = current
this.$emit('change', this.list[current])
}
}
}
</script>
<style lang="scss" scoped>
.ls-wrap {
position: relative;
.crown {
transform: scale(0.93, 0.85);
}
.item {
height: 100%;
transition: 1.2s;
}
.item-img {
width: 100%;
height: 100%;
}
.imgShadow {
height: calc(100% - 10px);
margin-bottom: 10px;
box-shadow: 0 6px 6px rgba(0, 0, 0, .15);
}
.crown-active {
transform: scale(1);
}
.dots {
display: flex;
position: absolute;
left: 50%;
transform: translateX(-50%);
.dot {
width: 6rpx;
height: 6rpx;
border-radius: 50%;
background-color: #D6D6D6;
margin-right: 8rpx;
}
.curr-dot {
height: 6rpx;
width: 22rpx;
border-radius: 6rpx;
background-color: #fff;
}
}
}
</style>
@@ -7,7 +7,8 @@ import MescrollEmpty from '@/components/mescroll-uni/components/mescroll-empty.v
-->
<template>
<view class="mescroll-empty" :class="{ 'empty-fixed': option.fixed }" :style="{ 'z-index': option.zIndex, top: option.top }">
<image v-if="icon" class="empty-icon" :src="icon" mode="widthFix" />
<image v-if="option.width" :style="{'width':option.width+'rpx','height':option.height+'rpx'}" :src="icon" mode="widthFix"/>
<image v-else-if="icon" class="empty-icon" :src="icon" mode="widthFix" />
<view v-if="tip" class="empty-tip">{{ tip }}</view>
<view v-if="option.btnText" class="empty-btn" @click="emptyClick">{{ option.btnText }}</view>
</view>