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.
791 lines
19 KiB
791 lines
19 KiB
<template> |
|
<view class="container"> |
|
<navbar> </navbar> |
|
<view class="content"> |
|
<view class="info"> |
|
<view> |
|
<view>{{ siteInfo.siteName }}</view> |
|
<view @click="$refs.popupInfo.open('bottom')"> |
|
<text>详情</text> |
|
<uni-icons type="right" size="12"></uni-icons> |
|
</view> |
|
</view> |
|
<view>{{ siteInfo.address }}</view> |
|
<view>距您{{ siteInfo.juli | distanceFilter }}km</view> |
|
<view> |
|
<view>油站开票</view> |
|
</view> |
|
<view class="nav" @click="openMap"> |
|
<image src="../static/details/nav.png" mode="" /> |
|
<view>导航</view> |
|
</view> |
|
</view> |
|
<view class="price"> |
|
<view @click="select"> |
|
<text>{{ params.oilProductCode }} </text> |
|
<image src="../static/details/allow-up.png" mode="" /> |
|
</view> |
|
<view> |
|
¥<text>{{ params.sitePrice }}</text |
|
>/L |
|
</view> |
|
<view> |
|
<view>油站价 ¥{{ params.oilSitePrice || "--" }}/L</view> |
|
<view>指导价 ¥{{ params.marketPrice || "--" }}/L</view> |
|
</view> |
|
<view |
|
>享油站价<text>直降¥{{ priceDiff }}/L</text></view |
|
> |
|
</view> |
|
<view class="spear"> |
|
<view class="title">选择油枪</view> |
|
<view class="number"> |
|
<view |
|
class="item" |
|
:class="params.oilsBar == item.value ? 'active' : ''" |
|
v-for="(item, index) in handleInfo.currentSpear" |
|
:key="index" |
|
@click="selectSpear(item)" |
|
> |
|
<text>{{ item.label }}</text> |
|
号 |
|
</view> |
|
</view> |
|
</view> |
|
<view class="input"> |
|
<view> |
|
<text>¥</text> |
|
<input |
|
v-model="params.sitePriceAmount" |
|
type="digit" |
|
maxlength="4" |
|
placeholder="输入金额,实时计算优惠" |
|
placeholder-class="placeholder-class" |
|
@blur="blurInput" |
|
/> |
|
<view>约{{ discountInfo.volume || "0.00" }}L</view> |
|
</view> |
|
</view> |
|
<view class="total" v-show="discountInfo.volume"> |
|
<view class="title">合计优惠</view> |
|
<view class="items"> |
|
<view class="item"> |
|
<text>直降优惠</text> |
|
<text class="red" |
|
>-¥{{ discountInfo.discountAmount || "0.00" }}</text |
|
> |
|
</view> |
|
<view class="item"> |
|
<text class="special" @click="$refs.popupIllustrate.open('bottom')"> |
|
服务费 |
|
</text> |
|
<text>+¥{{ discountInfo.serviceCharge || "0.00" }}</text> |
|
</view> |
|
</view> |
|
</view> |
|
</view> |
|
|
|
<view class="settlement"> |
|
<view class="left"> |
|
<view |
|
>实付:<text |
|
>¥{{ discountInfo.actualAmountPaid || "0.00" }}</text |
|
></view |
|
> |
|
<view |
|
>优惠¥{{ |
|
discountInfo.discountAmount |
|
| preferential(discountInfo.serviceCharge) |
|
}}</view |
|
> |
|
</view> |
|
<view class="right" @click="createCOrder">去支付</view> |
|
</view> |
|
|
|
<uni-popup |
|
ref="popupInfo" |
|
background-color="#f6f6f6" |
|
borderRadius="20rpx 20rpx 0 0" |
|
@touchmove.stop.prevent |
|
> |
|
<info @close="$refs.popupInfo.close()" /> |
|
</uni-popup> |
|
|
|
<uni-popup |
|
ref="popupIllustrate" |
|
background-color="#fff" |
|
borderRadius="20rpx 20rpx 0 0" |
|
@touchmove.stop.prevent |
|
> |
|
<illustrate |
|
:discountInfo="discountInfo" |
|
@close="$refs.popupIllustrate.close()" |
|
/> |
|
</uni-popup> |
|
|
|
<uni-popup |
|
ref="popup" |
|
background-color="#fff" |
|
borderRadius="20rpx 20rpx 0 0" |
|
@touchmove.stop.prevent |
|
> |
|
<options |
|
v-if="handleInfo.number.length" |
|
:handleInfo="handleInfo" |
|
:params.sync="params" |
|
@close="close" |
|
/> |
|
</uni-popup> |
|
</view> |
|
</template> |
|
|
|
<script> |
|
import serve from "api/site/details.js"; |
|
|
|
import info from "./components/info.vue"; |
|
import options from "./components/options.vue"; |
|
import illustrate from "./components/illustrate.vue"; |
|
export default { |
|
components: { |
|
info, |
|
options, |
|
illustrate, |
|
}, |
|
data() { |
|
return { |
|
params: { |
|
sitePriceAmount: "", |
|
oilProductCode: "", |
|
oilsBar: "", |
|
sitePrice: "", |
|
oilSitePrice: "", |
|
}, |
|
discountInfo: {}, |
|
siteInfo: {}, |
|
handleInfo: { |
|
number: [], |
|
spear: {}, |
|
currentSpear: [], |
|
}, |
|
}; |
|
}, |
|
onLoad(options) { |
|
let { siteInfo } = options; |
|
if (!siteInfo) { |
|
uni.showToast({ |
|
title: "油站信息错误", |
|
icon: "none", |
|
}); |
|
return; |
|
} |
|
this.getById(JSON.parse(siteInfo)); |
|
this.hasLocationAuthHandle(() => { |
|
this.$utils.obtainLocationHandle(appInstance).then(() => { |
|
this.getById(JSON.parse(siteInfo)); |
|
}); |
|
}); |
|
}, |
|
filters: { |
|
preferential(discountAmount, serviceCharge) { |
|
if (!discountAmount) return "0.00"; |
|
return ( |
|
(discountAmount * 100000 - serviceCharge * 100000) / |
|
100000 |
|
).toFixed(2); |
|
}, |
|
distanceFilter(value) { |
|
if (value) { |
|
return (value / 1000).toFixed(2); |
|
} |
|
return "0.00"; |
|
}, |
|
}, |
|
computed: { |
|
priceDiff() { |
|
let { oilSitePrice, sitePrice } = this.params; |
|
if (oilSitePrice && sitePrice) { |
|
return (oilSitePrice - sitePrice).toFixed(2); |
|
} |
|
return "--"; |
|
}, |
|
}, |
|
methods: { |
|
async createCOrder() { |
|
let isHas = this.hasLocationAuthHandle(() => { |
|
this.getById(this.siteInfo); |
|
}); |
|
if (!isHas) return; |
|
let isBeyond = await this.beyondDistance(); |
|
if (!isBeyond) return; |
|
if (!this.checkParams()) return; |
|
serve |
|
.createCOrder({ |
|
targetApp: "SAAS", |
|
orderType: "REAL_ORDER", |
|
orderSource: "WECHAT_MINIAPPS", |
|
orderMethod: "SITE_SCAN", |
|
suppleMark: 0, |
|
version: 1, |
|
createSource: "XOIL_DRIVER_WECHAT_APPLET", |
|
...this.params, |
|
}) |
|
.then((res) => { |
|
if (res.code !== 20000) return; |
|
this.wxPay(res.data); |
|
}); |
|
}, |
|
// 检测定位权限是否开启 |
|
hasLocationAuthHandle(callback = () => {}) { |
|
const appInstance = getApp(); |
|
let { hasLocationAuth } = appInstance.globalData; |
|
if (!hasLocationAuth) { |
|
uni.showModal({ |
|
title: "未打开小程序定位", |
|
content: "需获取您的地理位置才可以继续加油", |
|
confirmText: "开启定位", |
|
success: (res) => { |
|
if (res.confirm) { |
|
uni.openSetting({ |
|
success: (res) => { |
|
if (res.authSetting["scope.userLocation"]) { |
|
callback(); |
|
} |
|
}, |
|
}); |
|
} |
|
}, |
|
}); |
|
return false; |
|
} |
|
return true; |
|
}, |
|
// 检测距离 |
|
async beyondDistance() { |
|
let { juli, siteName, siteId, id } = this.siteInfo; |
|
if (juli > 10000) { |
|
let firstRes = await this.$utils.obtainLocationHandle(); |
|
let { latitude, longitude } = firstRes; |
|
let secondRes = await serve.getById({ |
|
id: siteId || id, |
|
latitude, |
|
longitude, |
|
}); |
|
if (secondRes.code !== 20000) return false; |
|
if (secondRes.data.juli > 10000) { |
|
uni.showModal({ |
|
title: siteName, |
|
content: "您与加油站距离较远,请到达加油站与加油员确认金额后付款", |
|
confirmText: "导航到站", |
|
cancelText: "我知道了", |
|
success: (res) => { |
|
if (res.confirm) { |
|
this.openMap(); |
|
} |
|
}, |
|
}); |
|
return false; |
|
} |
|
return true; |
|
} |
|
return true; |
|
}, |
|
checkParams() { |
|
if (!this.params.oilsBar) { |
|
uni.showToast({ |
|
title: "请选择油枪", |
|
icon: "none", |
|
}); |
|
return false; |
|
} |
|
if (!this.params.sitePriceAmount) { |
|
uni.showToast({ |
|
title: "请输入加油金额", |
|
icon: "none", |
|
}); |
|
return false; |
|
} |
|
if (this.params.sitePriceAmount < 10) { |
|
uni.showToast({ |
|
title: "加油金额不得小于10元", |
|
icon: "none", |
|
}); |
|
return false; |
|
} |
|
return true; |
|
}, |
|
wxPay(info) { |
|
let userIp = ""; |
|
wx.request({ |
|
url: "http://ip-api.com/json", |
|
success: function (e) { |
|
userIp = e.data.query; |
|
}, |
|
}); |
|
serve |
|
.wxPay({ |
|
openId: uni.getStorageSync("openid"), |
|
orderId: info.id, |
|
payCode: "WECHAT_ORDER_PAY_WECHAT", |
|
payChannel: "WECHAT_MINIAPPS_PAYMENT", |
|
payClient: "XOIL_DRIVER_WECHAT_APPLET", |
|
userIp: userIp ? userIp : "218.57.171.85", |
|
appId: getApp().globalData.appId, |
|
}) |
|
.then((res) => { |
|
if (res.code === 20000) { |
|
uni.requestPayment({ |
|
provider: "wxpay", |
|
...res.data.baseWxOrderVo, |
|
success: (res) => { |
|
if (res.errMsg === "requestPayment:ok") { |
|
uni.navigateTo({ |
|
url: `/subPackages/order/paymentResult/index?orderSerialNumber=${info.orderSerialNumber}`, |
|
}); |
|
} |
|
}, |
|
}); |
|
} |
|
}); |
|
}, |
|
blurInput() { |
|
if (this.params.sitePriceAmount === "") { |
|
this.discountInfo = {}; |
|
return; |
|
} |
|
if (this.params.sitePriceAmount < 10) { |
|
uni.showToast({ |
|
title: "加油金额不得小于10元", |
|
icon: "none", |
|
}); |
|
return; |
|
} |
|
serve |
|
.getPayDisInfo({ |
|
siteId: this.siteInfo.id, |
|
...this.params, |
|
}) |
|
.then((res) => { |
|
if (res.code !== 20000) return; |
|
this.discountInfo = res.data; |
|
}); |
|
}, |
|
openMap() { |
|
let { latitude, longitude } = this.siteInfo; |
|
uni.openLocation({ |
|
latitude: latitude, |
|
longitude: longitude, |
|
scale: 12, |
|
}); |
|
}, |
|
getById(siteInfo) { |
|
const appInstance = getApp(); |
|
let { latitude, longitude } = appInstance.globalData.location; |
|
let params = { |
|
id: siteInfo.siteId || siteInfo.id, |
|
latitude: latitude, |
|
longitude: longitude, |
|
}; |
|
serve.getById(params).then((res) => { |
|
if (res.code !== 20000) return; |
|
this.siteInfo = res.data; |
|
this.spearNumberHandle( |
|
res.data.oilSiteChannelDetailsVos[0].oilSitePriceDetailsVos |
|
); |
|
}); |
|
}, |
|
spearNumberHandle(siteChannelInfo) { |
|
let number = []; //油号 |
|
let spear = {}; //油枪 |
|
siteChannelInfo.forEach((item) => { |
|
number.push({ |
|
label: item.oilProductCode, |
|
value: item.oilProductCode, |
|
sitePrice: item.sitePrice, |
|
oilSitePrice: item.oilSitePrice, |
|
marketPrice: item.marketPrice, |
|
sitePriceId: item.priceId, |
|
}); |
|
// item.oilsBars数据结构为['','',''] 此处不适用 转化为[{},{},{}] |
|
spear[item.oilProductCode] = item.oilsBars.reduce((prev, item) => { |
|
prev.push({ |
|
label: item, |
|
value: item, |
|
}); |
|
return prev; |
|
}, []); |
|
}); |
|
|
|
let defaultTarget = number[0]; |
|
Object.assign(this.params, { |
|
...defaultTarget, |
|
oilProductCode: defaultTarget.value, |
|
}); |
|
|
|
this.handleInfo = { |
|
number, |
|
spear, |
|
currentSpear: spear[defaultTarget.value], |
|
}; |
|
}, |
|
select() { |
|
this.$refs.popup.open("bottom"); |
|
this.$bus.$emit("syncNumberSpear", this.params); |
|
}, |
|
selectSpear(item) { |
|
this.params.oilsBar = item.value; |
|
}, |
|
close(params) { |
|
this.$refs.popup.close(); |
|
if (params) { |
|
let { oilProductCode } = params; |
|
this.handleInfo.currentSpear = this.handleInfo.spear[oilProductCode]; |
|
} |
|
if (this.params.sitePriceAmount !== "") { |
|
this.blurInput(); |
|
} |
|
}, |
|
}, |
|
}; |
|
</script> |
|
|
|
<style lang="scss" scoped> |
|
::v-deep { |
|
.placeholder-class { |
|
color: #ff0000; |
|
font-size: 36rpx; |
|
font-weight: 500; |
|
} |
|
} |
|
|
|
.container { |
|
min-height: 100vh; |
|
background: #f6f6f6; |
|
} |
|
.content { |
|
margin-top: 20rpx; |
|
padding: 0 30rpx 225rpx; |
|
.info { |
|
position: relative; |
|
padding: 30rpx; |
|
background: #fff; |
|
border-radius: 15rpx; |
|
> view { |
|
&:nth-of-type(1) { |
|
display: flex; |
|
justify-content: space-between; |
|
> view { |
|
&:nth-of-type(1) { |
|
font-size: 35rpx; |
|
font-weight: 550; |
|
color: #333; |
|
} |
|
&:nth-of-type(2) { |
|
color: #999; |
|
font-size: 24rpx; |
|
} |
|
} |
|
} |
|
&:nth-of-type(2) { |
|
margin-top: 30rpx; |
|
font-size: 25rpx; |
|
color: #333; |
|
} |
|
&:nth-of-type(3) { |
|
margin-top: 10rpx; |
|
font-size: 25rpx; |
|
color: #999; |
|
} |
|
&:nth-of-type(4) { |
|
margin-top: 10rpx; |
|
> view { |
|
display: inline-block; |
|
padding: 3rpx 10rpx; |
|
font-size: 18rpx; |
|
color: #33333390; |
|
border: 1rpx solid #999; |
|
border-radius: 6rpx; |
|
} |
|
} |
|
&.nav { |
|
position: absolute; |
|
bottom: 20rpx; |
|
right: 47rpx; |
|
> image { |
|
vertical-align: bottom; |
|
width: 50rpx; |
|
height: 50rpx; |
|
} |
|
> view { |
|
text-align: center; |
|
font-size: 22rpx; |
|
} |
|
} |
|
} |
|
} |
|
.price { |
|
position: relative; |
|
display: flex; |
|
margin-top: 20rpx; |
|
padding: 25rpx 25rpx 80rpx; |
|
background: #fff; |
|
border-radius: 15rpx; |
|
> view { |
|
&:nth-of-type(1) { |
|
padding-left: 30rpx; |
|
width: 200rpx; |
|
height: 100rpx; |
|
|
|
line-height: 100rpx; |
|
background: #f5f5f5; |
|
border-radius: 15rpx; |
|
> text { |
|
font-size: 40rpx; |
|
font-weight: 550; |
|
} |
|
> image { |
|
margin-left: 40rpx; |
|
width: 32rpx; |
|
height: 32rpx; |
|
transform: rotate(180deg); |
|
} |
|
} |
|
&:nth-of-type(2) { |
|
margin-left: 20rpx; |
|
height: 100rpx; |
|
line-height: 100rpx; |
|
|
|
font-size: 30rpx; |
|
color: #ff0000; |
|
> text { |
|
position: relative; |
|
top: -5rpx; |
|
font-size: 45rpx; |
|
font-weight: 550; |
|
} |
|
} |
|
&:nth-of-type(3) { |
|
flex: 1; |
|
padding: 10rpx 0; |
|
height: 100rpx; |
|
> view { |
|
padding-right: 20rpx; |
|
text-align: right; |
|
font-size: 24rpx; |
|
line-height: 40rpx; |
|
color: #9a9fa5; |
|
} |
|
} |
|
&:nth-of-type(4) { |
|
position: absolute; |
|
left: 20rpx; |
|
bottom: 20rpx; |
|
padding-left: 10rpx; |
|
width: calc(100% - 40rpx); |
|
height: 40rpx; |
|
line-height: 40rpx; |
|
color: #999; |
|
font-size: 24rpx; |
|
background: #f5f5f5; |
|
border-radius: 9rpx; |
|
> text { |
|
color: #ff0000; |
|
} |
|
} |
|
} |
|
} |
|
.spear { |
|
margin-top: 20rpx; |
|
padding: 25rpx 25rpx 40rpx; |
|
background: #fff; |
|
border-radius: 15rpx; |
|
> .title { |
|
font-size: 32rpx; |
|
font-weight: 550; |
|
} |
|
> .number { |
|
display: flex; |
|
flex-wrap: wrap; |
|
margin-top: 20rpx; |
|
.item { |
|
&:nth-of-type(4n + 1) { |
|
margin-left: 0; |
|
} |
|
&:nth-of-type(n + 5) { |
|
margin-top: 20rpx; |
|
} |
|
margin-left: 4%; |
|
width: 22%; |
|
height: 70rpx; |
|
line-height: 70rpx; |
|
font-size: 26rpx; |
|
text-align: center; |
|
background: #f5f5f5; |
|
border-radius: 15rpx; |
|
border: 1px solid #f5f5f5; |
|
> text { |
|
font-size: 38rpx; |
|
} |
|
&.active { |
|
color: #ff0000; |
|
background: #fff8f5; |
|
border-color: #ff0000; |
|
} |
|
} |
|
} |
|
} |
|
.input { |
|
margin-top: 20rpx; |
|
padding: 25rpx 25rpx 40rpx; |
|
background: #fff; |
|
border-radius: 15rpx; |
|
> view { |
|
background: #fff8f5; |
|
&:nth-of-type(1) { |
|
display: flex; |
|
padding-left: 20rpx; |
|
height: 100rpx; |
|
line-height: 100rpx; |
|
color: #ff0000; |
|
border: 1rpx solid #ff0000; |
|
border-radius: 15rpx; |
|
text { |
|
// vertical-align: top; |
|
font-size: 40rpx; |
|
} |
|
input { |
|
font-size: 50rpx; |
|
// display: inline-block; |
|
margin-left: 10rpx; |
|
height: 100rpx; |
|
font-weight: 550; |
|
// line-height: 100rpx; |
|
} |
|
> view { |
|
width: 200rpx; |
|
font-size: 28rpx; |
|
color: #999; |
|
} |
|
} |
|
} |
|
} |
|
.total { |
|
margin-top: 20rpx; |
|
padding: 25rpx 25rpx 40rpx; |
|
background: #fff; |
|
border-radius: 15rpx; |
|
> .title { |
|
font-size: 32rpx; |
|
font-weight: 550; |
|
} |
|
> .items { |
|
margin-top: 20rpx; |
|
padding-left: 40rpx; |
|
.item { |
|
display: flex; |
|
justify-content: space-between; |
|
margin-top: 20rpx; |
|
&:nth-of-type(1) { |
|
margin-top: 0; |
|
> text:nth-of-type(1) { |
|
&::before { |
|
content: "惠"; |
|
} |
|
} |
|
} |
|
&:nth-of-type(2) { |
|
> text:nth-of-type(1) { |
|
&::before { |
|
content: "服"; |
|
} |
|
} |
|
} |
|
> text { |
|
position: relative; |
|
font-size: 28rpx; |
|
&.special { |
|
&::after { |
|
content: "?"; |
|
position: absolute; |
|
right: -35rpx; |
|
top: 50%; |
|
transform: translateY(-50%); |
|
width: 25rpx; |
|
height: 25rpx; |
|
line-height: 25rpx; |
|
text-align: center; |
|
font-size: 24rpx; |
|
color: #999; |
|
background: #fff; |
|
border: 1rpx solid #999; |
|
border-radius: 20rpx; |
|
} |
|
} |
|
&:nth-of-type(1) { |
|
&::before { |
|
position: absolute; |
|
top: 50%; |
|
left: -40rpx; |
|
transform: translateY(-50%); |
|
width: 35rpx; |
|
height: 35rpx; |
|
line-height: 35rpx; |
|
text-align: center; |
|
color: #fff; |
|
font-size: 24rpx; |
|
background: #fd471f; |
|
border-radius: 7rpx; |
|
} |
|
} |
|
&.red { |
|
color: #ff0000; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
.settlement { |
|
box-sizing: content-box; |
|
display: flex; |
|
position: fixed; |
|
bottom: 0; |
|
left: 0; |
|
padding: 25rpx 25rpx 80rpx; |
|
width: calc(100% - 49rpx); |
|
height: 80rpx; |
|
background: #fff; |
|
> view { |
|
&.left { |
|
flex: 1; |
|
padding-right: 30rpx; |
|
height: 80rpx; |
|
view { |
|
text-align: right; |
|
// line-height: 85rpx; |
|
&:nth-of-type(1) { |
|
font-weight: 550; |
|
font-size: 28rpx; |
|
text { |
|
font-size: 40rpx; |
|
} |
|
} |
|
&:nth-of-type(2) { |
|
font-size: 24rpx; |
|
color: #ff6634; |
|
} |
|
} |
|
} |
|
&.right { |
|
width: 260rpx; |
|
height: 80rpx; |
|
line-height: 80rpx; |
|
text-align: center; |
|
color: #fff; |
|
font-weight: 550; |
|
background: #ff6634; |
|
border-radius: 45rpx; |
|
} |
|
} |
|
} |
|
</style>
|
|
|