小星加油
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

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