first
This commit is contained in:
@@ -0,0 +1,447 @@
|
||||
<!-- 签到界面 -->
|
||||
<template>
|
||||
<s-layout title="签到有礼">
|
||||
<s-empty v-if="state.loading" icon="/static/data-empty.png" text="签到活动还未开始" />
|
||||
<view v-if="state.loading" />
|
||||
<view class="sign-wrap" v-else-if="!state.loading">
|
||||
<!-- 签到日历 -->
|
||||
<view class="content-box calendar">
|
||||
<view class="sign-everyday ss-flex ss-col-center ss-row-between ss-p-x-30">
|
||||
<text class="sign-everyday-title">签到日历</text>
|
||||
<view class="sign-num-box">
|
||||
已连续签到 <text class="sign-num">{{ state.signInfo.continuousDay }}</text> 天
|
||||
</view>
|
||||
</view>
|
||||
<view class="list acea-row row-between-wrapper" style="
|
||||
padding: 0 30rpx;
|
||||
height: 240rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
">
|
||||
<view class="item" v-for="(item, index) in state.signConfigList" :key="index">
|
||||
<view :class="
|
||||
(index === state.signConfigList.length ? 'reward' : '') +
|
||||
' ' +
|
||||
(state.signInfo.continuousDay >= item.day ? 'rewardTxt' : '')
|
||||
">
|
||||
第{{ item.day }}天
|
||||
</view>
|
||||
<view class="venus" :class="
|
||||
(index + 1 === state.signConfigList.length ? 'reward' : '') +
|
||||
' ' +
|
||||
(state.signInfo.continuousDay >= item.day ? 'venusSelect' : '')
|
||||
">
|
||||
</view>
|
||||
<view class="num" :class="state.signInfo.continuousDay >= item.day ? 'on' : ''">
|
||||
+ {{ item.point }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 签到按钮 -->
|
||||
<view class="myDateTable">
|
||||
<view class="ss-flex ss-col-center ss-row-center sign-box ss-m-y-40">
|
||||
<button class="ss-reset-button sign-btn" v-if="!state.signInfo.todaySignIn" @tap="onSign">
|
||||
签到
|
||||
</button>
|
||||
<button class="ss-reset-button already-btn" v-else disabled> 已签到 </button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 签到说明 TODO @【签到】这里改成【已累计签到】;改版,接入 sheepjs -->
|
||||
<view class="bg-white ss-m-t-16 ss-p-t-30 ss-p-b-60 ss-p-x-40">
|
||||
<view class="activity-title ss-m-b-30">签到说明</view>
|
||||
<view class="activity-des">1、已累计签到{{state.signInfo.totalDay}}天</view>
|
||||
<view class="activity-des">
|
||||
2、据说连续签到第 {{ state.maxDay }} 天可获得超额积分,一定要坚持签到哦~~~
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 签到结果弹窗 -->
|
||||
<su-popup :show="state.showModel" type="center" round="10" :isMaskClick="false">
|
||||
<view class="model-box ss-flex-col">
|
||||
<view class="ss-m-t-56 ss-flex-col ss-col-center">
|
||||
<text class="cicon-check-round"></text>
|
||||
<view class="score-title">
|
||||
<text v-if="state.signResult.point">{{ state.signResult.point }} 积分 </text>
|
||||
<text v-if="state.signResult.experience"> {{ state.signResult.experience }} 经验</text>
|
||||
</view>
|
||||
<view class="model-title ss-flex ss-col-center ss-m-t-22 ss-m-b-30">
|
||||
已连续打卡 {{ state.signResult.day }} 天
|
||||
</view>
|
||||
</view>
|
||||
<view class="model-bg ss-flex-col ss-col-center ss-row-right">
|
||||
<view class="title ss-m-b-64">签到成功</view>
|
||||
<view class="ss-m-b-40">
|
||||
<button class="ss-reset-button confirm-btn" @tap="onConfirm">确认</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</su-popup>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import sheep from '@/sheep';
|
||||
import {
|
||||
onReady
|
||||
} from '@dcloudio/uni-app';
|
||||
import {
|
||||
reactive
|
||||
} from 'vue';
|
||||
import SignInApi from '@/sheep/api/member/signin';
|
||||
|
||||
const headerBg = sheep.$url.css('/static/img/shop/app/sign.png');
|
||||
|
||||
const state = reactive({
|
||||
loading: true,
|
||||
|
||||
signInfo: {}, // 签到信息
|
||||
|
||||
signConfigList: [], // 签到配置列表
|
||||
maxDay: 0, // 最大的签到天数
|
||||
|
||||
showModel: false, // 签到弹框
|
||||
signResult: {}, // 签到结果
|
||||
});
|
||||
|
||||
// 发起签到
|
||||
async function onSign() {
|
||||
const {
|
||||
code,
|
||||
data
|
||||
} = await SignInApi.createSignInRecord();
|
||||
if (code !== 0) {
|
||||
return;
|
||||
}
|
||||
state.showModel = true;
|
||||
state.signResult = data;
|
||||
// 重新获得签到信息
|
||||
await getSignInfo();
|
||||
}
|
||||
|
||||
// 签到确认刷新页面
|
||||
function onConfirm() {
|
||||
state.showModel = false;
|
||||
}
|
||||
|
||||
// 获得个人签到统计
|
||||
async function getSignInfo() {
|
||||
const {
|
||||
code,
|
||||
data
|
||||
} = await SignInApi.getSignInRecordSummary();
|
||||
if (code !== 0) {
|
||||
return;
|
||||
}
|
||||
state.signInfo = data;
|
||||
state.loading = false;
|
||||
}
|
||||
|
||||
// 获取签到配置
|
||||
async function getSignConfigList() {
|
||||
const {
|
||||
code,
|
||||
data
|
||||
} = await SignInApi.getSignInConfigList();
|
||||
if (code !== 0) {
|
||||
return;
|
||||
}
|
||||
state.signConfigList = data;
|
||||
if (data.length > 0) {
|
||||
state.maxDay = data[data.length - 1].day;
|
||||
}
|
||||
}
|
||||
|
||||
onReady(() => {
|
||||
getSignInfo();
|
||||
getSignConfigList();
|
||||
});
|
||||
// TODO 1)css 需要优化,例如说引入的图片;2)删除多余的样式
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.header-box {
|
||||
border-top: 2rpx solid rgba(#dfdfdf, 0.5);
|
||||
}
|
||||
|
||||
// 日历
|
||||
.calendar {
|
||||
background: #fff;
|
||||
|
||||
.sign-everyday {
|
||||
height: 100rpx;
|
||||
background: rgba(255, 255, 255, 1);
|
||||
border: 2rpx solid rgba(223, 223, 223, 0.4);
|
||||
|
||||
.sign-everyday-title {
|
||||
font-size: 32rpx;
|
||||
color: rgba(51, 51, 51, 1);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.sign-num-box {
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
color: rgba(153, 153, 153, 1);
|
||||
|
||||
.sign-num {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #4A8EFC;
|
||||
padding: 0 10rpx;
|
||||
font-family: OPPOSANS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 年月日
|
||||
.bar {
|
||||
height: 100rpx;
|
||||
|
||||
.date {
|
||||
font-size: 30rpx;
|
||||
font-family: OPPOSANS;
|
||||
font-weight: 500;
|
||||
color: #333333;
|
||||
line-height: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.cicon-back {
|
||||
margin-top: 6rpx;
|
||||
font-size: 30rpx;
|
||||
color: #c4c4c4;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.cicon-forward {
|
||||
margin-top: 6rpx;
|
||||
font-size: 30rpx;
|
||||
color: #c4c4c4;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
// 星期
|
||||
.week {
|
||||
.week-item {
|
||||
font-size: 24rpx;
|
||||
font-weight: 500;
|
||||
color: rgba(153, 153, 153, 1);
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
// 日历表
|
||||
.myDateTable {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.dateCell {
|
||||
width: calc(750rpx / 7);
|
||||
height: 80rpx;
|
||||
font-size: 26rpx;
|
||||
font-weight: 400;
|
||||
color: rgba(51, 51, 51, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.is-sign {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
position: relative;
|
||||
|
||||
.is-sign-num {
|
||||
font-size: 24rpx;
|
||||
font-family: OPPOSANS;
|
||||
font-weight: 500;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.is-sign-image {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.cell-num {
|
||||
font-size: 24rpx;
|
||||
font-family: OPPOSANS;
|
||||
font-weight: 500;
|
||||
color: #333333;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.cicon-title {
|
||||
position: absolute;
|
||||
right: -10rpx;
|
||||
top: -6rpx;
|
||||
font-size: 20rpx;
|
||||
color: red;
|
||||
}
|
||||
|
||||
// 签到按钮
|
||||
.sign-box {
|
||||
height: 140rpx;
|
||||
width: 100%;
|
||||
|
||||
.sign-btn {
|
||||
width: 710rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 35rpx;
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
box-shadow: 0 0.2em 0.5em rgba(#4A8EFC, 0.4);
|
||||
background: linear-gradient(132deg, #4A8EFC 0%, #50C3FD 100%);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.already-btn {
|
||||
width: 710rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 35rpx;
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.model-box {
|
||||
width: 520rpx;
|
||||
// height: 590rpx;
|
||||
background: linear-gradient(132deg, #4A8EFC 0%, #50C3FD 100%);
|
||||
// background: linear-gradient(177deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
|
||||
border-radius: 10rpx;
|
||||
|
||||
.cicon-check-round {
|
||||
font-size: 70rpx;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.score-title {
|
||||
font-size: 34rpx;
|
||||
font-family: OPPOSANS;
|
||||
font-weight: 500;
|
||||
color: #fcff00;
|
||||
}
|
||||
|
||||
.model-title {
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.model-bg {
|
||||
width: 520rpx;
|
||||
height: 344rpx;
|
||||
background-size: 100% 100%;
|
||||
background-image: v-bind(headerBg);
|
||||
background-repeat: no-repeat;
|
||||
border-radius: 0 0 10rpx 10rpx;
|
||||
|
||||
.title {
|
||||
font-size: 34rpx;
|
||||
font-weight: bold;
|
||||
// color: var(--ui-BG-Main);
|
||||
color: #4A8EFC;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
width: 220rpx;
|
||||
height: 70rpx;
|
||||
border: 2rpx solid #4A8EFC;
|
||||
border-radius: 35rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: #4A8EFC;
|
||||
line-height: normal;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
|
||||
.confirm-btn {
|
||||
width: 220rpx;
|
||||
height: 70rpx;
|
||||
background: linear-gradient(132deg, #4A8EFC 0%, #50C3FD 100%);
|
||||
box-shadow: 0 0.2em 0.5em rgba(#4A8EFC, 0.4);
|
||||
border-radius: 35rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: #ffffff;
|
||||
line-height: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//签到说明
|
||||
.activity-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
color: #333333;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.activity-des {
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
color: #666666;
|
||||
line-height: 40rpx;
|
||||
}
|
||||
|
||||
.reward {
|
||||
background-image: url('https://kxcharge.oss-cn-beijing.aliyuncs.com/mini/reward.png');
|
||||
width: 75rpx;
|
||||
height: 56rpx;
|
||||
}
|
||||
|
||||
.rewardTxt {
|
||||
width: 74rpx;
|
||||
height: 32rpx;
|
||||
background-color: #f4b409;
|
||||
border-radius: 16rpx;
|
||||
font-size: 20rpx;
|
||||
color: #a57d3f;
|
||||
line-height: 32rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.venus {
|
||||
background-image: url('https://kxcharge.oss-cn-beijing.aliyuncs.com/mini/venus.png');
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
width: 56rpx;
|
||||
height: 56rpx;
|
||||
margin: 10rpx 0;
|
||||
}
|
||||
|
||||
.venusSelect {
|
||||
background-image: url('https://kxcharge.oss-cn-beijing.aliyuncs.com/mini/venusSelect.png');
|
||||
}
|
||||
|
||||
.num {
|
||||
font-size: 36rpx;
|
||||
font-family: 'Guildford Pro';
|
||||
}
|
||||
|
||||
.item {
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid #eee;
|
||||
height: 130rpx;
|
||||
}
|
||||
|
||||
.on {
|
||||
background-color: #999 !important;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,578 @@
|
||||
<template>
|
||||
<s-layout title="月度账单" navbar="normal" onShareAppMessage>
|
||||
<view class="block">
|
||||
<scroll-view scroll-y="true" style="height: 84vh;">
|
||||
<view class="bottom"></view>
|
||||
<view class="top">
|
||||
<view class="timeSelect">
|
||||
<view class="monthBtn" @click="changeMonth('sub')">上个月</view>
|
||||
<picker mode="date" :value="date" @change="bindDateChange($event)" fields='month' class="datePicker">
|
||||
<view class="uni-input">{{ formatDate(date)}}<u-icon name="arrow-down"></u-icon></view>
|
||||
</picker>
|
||||
<view class="monthBtn" @click="changeMonth('add')">下个月</view>
|
||||
</view>
|
||||
<view class="totalData">
|
||||
<text class="label">本月为您节省(元)</text>
|
||||
<text class="money">{{toFix(totalMonitorData.economizeMoney ,2)}}</text>
|
||||
<text class="power">约等于电量:{{ toFix((totalMonitorData.economizeMoney / 0.90961475),2) }}度</text>
|
||||
<view class="dataInfo">
|
||||
<view class="info">
|
||||
<text class="number">{{ toFix(totalMonitorData.totalSpent,2)}}</text>
|
||||
<text class="label">本月支出(元)</text>
|
||||
</view>
|
||||
<view class="info">
|
||||
<text class="number">{{ toFix(totalMonitorData.totalPower,2)}}</text>
|
||||
<text class="label">本月电量(度)</text>
|
||||
</view>
|
||||
<view class="info">
|
||||
<text class="number">{{totalMonitorData.totalOrders}}</text>
|
||||
<text class="label">总笔数(笔)</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="class">
|
||||
<text class="title">支出分类</text>
|
||||
<view class="charts-box">
|
||||
<qiun-data-charts type="ring" :opts="expendDataOpts" :chartData="expendData" />
|
||||
</view>
|
||||
<view class="expendLegen">
|
||||
<view class="item" v-for="(item,index) in expendLegend" :key="index">
|
||||
<view class="left">
|
||||
<text class="icon" :style="{background: item.color}"></text>
|
||||
{{item.label}}
|
||||
</view>
|
||||
<text class="value">¥{{item.value}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="class">
|
||||
<text class="title">充电优惠分类</text>
|
||||
<view class="charts-box">
|
||||
<qiun-data-charts type="ring" :opts="powerDiscountOpts" :chartData="powerDiscountData" />
|
||||
</view>
|
||||
<view class="powerDiscountLegen">
|
||||
<view class="item" v-for="(item,index) in powerDiscountLegend" :key="index">
|
||||
<view class="left">
|
||||
<text class="icon" :style="{background: item.color}"></text>
|
||||
{{item.label}}({{item.percent}})
|
||||
</view>
|
||||
<text class="line"></text>
|
||||
<text class="value">¥{{item.value}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<view class="btn">
|
||||
<u-button type="primary" text="去充电" @click="goToStation"></u-button>
|
||||
</view>
|
||||
</view>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from 'dayjs';
|
||||
import {
|
||||
getOrderReport
|
||||
} from "@/sheep/api/charge/order.js";
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
date: new Date,
|
||||
expendLegend: [{
|
||||
color: "#01b3c3",
|
||||
label: '充电支出',
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
color: "#2bcbdb",
|
||||
label: '超时占位费',
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
color: "#73e4ee",
|
||||
label: '省钱会员',
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
color: "#a3f1f8",
|
||||
label: '券包套餐',
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
color: "#bcfaf8",
|
||||
label: '零售支出',
|
||||
value: 0
|
||||
}
|
||||
],
|
||||
expendData: {
|
||||
series: [{
|
||||
data: [{
|
||||
name: '充电支出',
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
name: '超时占位费',
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
name: '省钱会员',
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
name: '券包套餐',
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
name: '零售支出',
|
||||
value: 0
|
||||
},
|
||||
]
|
||||
}]
|
||||
},
|
||||
expendDataOpts: {
|
||||
rotate: false,
|
||||
rotateLock: false,
|
||||
color: ["#01b3c3", "#2bcbdb", "#73e4ee", "#a3f1f8", "#bcfaf8"],
|
||||
padding: [5, 5, 5, 5],
|
||||
dataLabel: false,
|
||||
enableScroll: false,
|
||||
legend: {
|
||||
show: false,
|
||||
position: "bottom",
|
||||
lineHeight: 25
|
||||
},
|
||||
title: {
|
||||
name: "0.00",
|
||||
fontSize: 25,
|
||||
color: "#000"
|
||||
},
|
||||
subtitle: {
|
||||
name: "本月支出(元)",
|
||||
fontSize: 15,
|
||||
color: "#737169"
|
||||
},
|
||||
extra: {
|
||||
ring: {
|
||||
ringWidth: 30,
|
||||
activeOpacity: 0.5,
|
||||
activeRadius: 10,
|
||||
offsetAngle: 0,
|
||||
labelWidth: 15,
|
||||
border: false,
|
||||
borderWidth: 3,
|
||||
borderColor: "#FFFFFF"
|
||||
}
|
||||
}
|
||||
},
|
||||
powerDiscountLegend: [{
|
||||
color: "#fd4c03",
|
||||
label: '会员优惠',
|
||||
value: 0,
|
||||
percent: '0%'
|
||||
},
|
||||
{
|
||||
color: "#f97729",
|
||||
label: '卡券优惠',
|
||||
value: 0,
|
||||
percent: '0%'
|
||||
},
|
||||
{
|
||||
color: "#fc9a56",
|
||||
label: '商家优惠',
|
||||
value: 0,
|
||||
percent: '0%'
|
||||
},
|
||||
{
|
||||
color: "#fcba8f",
|
||||
label: '红包优惠',
|
||||
value: 0,
|
||||
percent: '0%'
|
||||
},
|
||||
{
|
||||
color: "#ffdebf",
|
||||
label: '碳积分优惠',
|
||||
value: 0,
|
||||
percent: '0%'
|
||||
}
|
||||
],
|
||||
powerDiscountOpts: {
|
||||
rotate: false,
|
||||
rotateLock: false,
|
||||
color: ["#fd4c03", "#f97729", "#fc9a56", "#fcba8f", "#ffdebf"],
|
||||
// padding: [5,5,5,5],
|
||||
dataLabel: false,
|
||||
enableScroll: false,
|
||||
legend: {
|
||||
show: false,
|
||||
position: "bottom",
|
||||
lineHeight: 25
|
||||
},
|
||||
title: {
|
||||
name: "0.00",
|
||||
fontSize: 25,
|
||||
color: "#000"
|
||||
},
|
||||
subtitle: {
|
||||
name: "充电节省(元)",
|
||||
fontSize: 15,
|
||||
color: "#737169"
|
||||
},
|
||||
extra: {
|
||||
ring: {
|
||||
ringWidth: 30,
|
||||
activeOpacity: 0.5,
|
||||
activeRadius: 10,
|
||||
offsetAngle: 0,
|
||||
labelWidth: 15,
|
||||
border: false,
|
||||
borderWidth: 3,
|
||||
borderColor: "#FFFFFF"
|
||||
}
|
||||
}
|
||||
},
|
||||
powerDiscountData: {
|
||||
series: [{
|
||||
data: [{
|
||||
name: '会员优惠',
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
name: '卡券优惠',
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
name: '商家优惠',
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
name: '红包优惠',
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
name: '碳积分优惠',
|
||||
value: 0
|
||||
},
|
||||
]
|
||||
}]
|
||||
},
|
||||
expendParmasMap: new Map([
|
||||
['chargingExpense', '充电支出'],
|
||||
['timeoutExpense', '超时占位费'],
|
||||
['membershipExpense', '省钱会员'],
|
||||
['voucherPackageExpense', '券包套餐'],
|
||||
['retailExpense', '零售支出']
|
||||
]),
|
||||
powerDiscountParmasMap: new Map([
|
||||
['membershipCouponDiscount', '会员优惠'],
|
||||
['cardCouponDiscount', '卡券优惠'],
|
||||
['merchantCouponDiscount', '商家优惠'],
|
||||
['redPacketCouponDiscount', '红包优惠'],
|
||||
['carbonCreditCouponDiscount', '碳积分优惠']
|
||||
]),
|
||||
totalMonitorData: {
|
||||
economizeMoney: 0,
|
||||
totalSpent: 0,
|
||||
totalPower: 0,
|
||||
totalOrders: 0,
|
||||
}
|
||||
};
|
||||
},
|
||||
filters: {
|
||||
|
||||
},
|
||||
methods: {
|
||||
formatDate(date) {
|
||||
return moment(date).format('YYYY年MM月')
|
||||
},
|
||||
toFix(data, num) {
|
||||
if (!data) {
|
||||
return '0.00'
|
||||
}
|
||||
return Number(data).toFixed(num);
|
||||
},
|
||||
goToStation() {
|
||||
uni.reLaunch({
|
||||
url: '/pages/home-page/home-page'
|
||||
})
|
||||
},
|
||||
changeMonth(type) {
|
||||
if (type == 'sub') {
|
||||
this.date = moment(this.date).subtract(1, 'month');
|
||||
} else {
|
||||
this.date = moment(this.date).add(1, 'month');
|
||||
}
|
||||
this.getReportData();
|
||||
},
|
||||
bindDateChange(e) {
|
||||
this.date = e.detail.value
|
||||
this.getReportData();
|
||||
},
|
||||
|
||||
async getReportData() {
|
||||
try {
|
||||
const startTs = moment(this.date).startOf('month').valueOf();
|
||||
const endTs = moment(this.date).endOf('month').valueOf();
|
||||
const {
|
||||
data
|
||||
} = await getOrderReport(startTs, endTs);
|
||||
if (data) {
|
||||
this.totalMonitorData = data;
|
||||
for (const key in data) {
|
||||
if (this.expendParmasMap.get(key)) {
|
||||
const findLegend = this.expendLegend.find(k => k.label == this.expendParmasMap.get(key));
|
||||
this.$set(findLegend, 'value', Number(data[key]).toFixed(2));
|
||||
const findData = this.expendData.series[0].data.find(k => k.name == this.expendParmasMap.get(key));
|
||||
this.$set(findData, 'value', Number(Number(data[key]).toFixed(2)));
|
||||
}
|
||||
if (this.powerDiscountParmasMap.get(key)) {
|
||||
const findLegend = this.powerDiscountLegend.find(k => k.label == this.powerDiscountParmasMap.get(
|
||||
key));
|
||||
this.$set(findLegend, 'value', Number(data[key]).toFixed(2));
|
||||
const findData = this.powerDiscountData.series[0].data.find(k => k.name == this.powerDiscountParmasMap
|
||||
.get(key));
|
||||
this.$set(findData, 'value', Number(Number(data[key]).toFixed(2)));
|
||||
}
|
||||
}
|
||||
this.expendDataOpts.title.name = this.expendLegend.reduce((pre, item) => {
|
||||
pre = Number(pre) + Number(item.value);
|
||||
return (pre).toFixed(2);
|
||||
}, 0)
|
||||
this.powerDiscountOpts.title.name = this.powerDiscountLegend.reduce((pre, item) => {
|
||||
pre = Number(pre) + Number(item.value);
|
||||
return (pre).toFixed(2);
|
||||
}, 0)
|
||||
this.powerDiscountLegend = this.powerDiscountLegend.map((ele, index, arr) => {
|
||||
const total = arr.reduce((sum, i) => {
|
||||
sum += Number(i.value || 0);
|
||||
return sum;
|
||||
}, 0)
|
||||
ele.percent = (ele.value / total * 100).toFixed(2) + '%';
|
||||
return ele;
|
||||
})
|
||||
} else {
|
||||
this.expendLegend.forEach(item => item.value = 0);
|
||||
this.expendDataOpts.title.name = '0.00';
|
||||
this.powerDiscountOpts.title.name = '0.00';
|
||||
this.powerDiscountLegend = this.powerDiscountLegend.map(item => {
|
||||
item.percent = 0 + '%';
|
||||
item.value = 0;
|
||||
return item;
|
||||
});
|
||||
this.powerDiscountData.series[0].data.forEach(item => item.value = 0);
|
||||
this.expendData.series[0].data.forEach(item => item.value = 0);
|
||||
this.totalMonitorData = {
|
||||
economizeMoney: 0,
|
||||
totalSpent: 0,
|
||||
totalPower: 0,
|
||||
totalOrders: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// consoel.log(this.expendDataOpts, this.e)
|
||||
} catch (e) {
|
||||
//TODO handle the exception
|
||||
}
|
||||
}
|
||||
},
|
||||
onShow() {
|
||||
this.getReportData();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
page {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.block {
|
||||
position: relative;
|
||||
|
||||
.bottom {
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
top: -10px;
|
||||
height: 23vh;
|
||||
width: 750rpx;
|
||||
background: linear-gradient(45deg, #00c3ffa6, #0b91ff);
|
||||
}
|
||||
|
||||
.top,
|
||||
.class {
|
||||
width: 660rpx;
|
||||
margin: 20rpx auto;
|
||||
padding: 25rpx;
|
||||
border-radius: 20rpx;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.top {
|
||||
.timeSelect {
|
||||
display: flex;
|
||||
background: #f5f5f5;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 85%;
|
||||
margin: auto;
|
||||
border-radius: 40rpx;
|
||||
padding: 8rpx;
|
||||
|
||||
.monthBtn {
|
||||
background-color: #fff;
|
||||
// border-radius: 25%;
|
||||
padding: 10rpx 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 25%;
|
||||
border-radius: 25rpx;
|
||||
}
|
||||
|
||||
.datePicker {
|
||||
width: 50%;
|
||||
|
||||
.uni-input {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.totalData {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-top: 25rpx;
|
||||
|
||||
.label {
|
||||
color: #bcb6b3;
|
||||
}
|
||||
|
||||
.money {
|
||||
font-size: 55rpx;
|
||||
font-weight: 600;
|
||||
color: #42a5f5;
|
||||
display: inline-block;
|
||||
margin: 20rpx 0rpx;
|
||||
}
|
||||
|
||||
.power {
|
||||
display: inline-block;
|
||||
padding: 10rpx 15rpx;
|
||||
font-size: 30rpx;
|
||||
margin: 0rpx 0rpx 20rpx;
|
||||
color: #42a5f5;
|
||||
text-align: center;
|
||||
width: 50%;
|
||||
border-radius: 25rpx;
|
||||
background-color: rgba(66, 165, 245, 0.3);
|
||||
}
|
||||
|
||||
.dataInfo {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: space-around;
|
||||
border-radius: 15rpx;
|
||||
padding: 20rpx 0;
|
||||
background-color: rgba(66, 165, 245, 0.1);
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.number {
|
||||
font-size: 35rpx;
|
||||
font-weight: 600;
|
||||
display: inline-block;
|
||||
margin-bottom: 15rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.class {
|
||||
.title {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.charts-box {
|
||||
width: 100%;
|
||||
height: 30vh;
|
||||
}
|
||||
|
||||
.expendLegen {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
|
||||
.item {
|
||||
width: 48%;
|
||||
display: flex;
|
||||
margin-bottom: 15rpx;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.powerDiscountLegen {
|
||||
.item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 15rpx;
|
||||
|
||||
.line {
|
||||
display: inline-block;
|
||||
border-bottom: 2rpx dashed #bab9b5;
|
||||
height: 2rpx;
|
||||
width: 43%;
|
||||
margin: 0 20rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.left {
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
.icon {
|
||||
display: inline-block;
|
||||
width: 25rpx;
|
||||
height: 25rpx;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
padding: 30rpx 0;
|
||||
width: 750rpx;
|
||||
background-color: #fff;
|
||||
|
||||
.u-button {
|
||||
margin: auto !important;
|
||||
width: 700rpx !important;
|
||||
border-radius: 50rpx !important;
|
||||
height: 103rpx !important;
|
||||
|
||||
.u-button__text {
|
||||
font-size: 37.5rpx !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,525 @@
|
||||
<template>
|
||||
<s-layout title="正在充电" navbar="normal" onShareAppMessage @clickLeft="clearTimer">
|
||||
<view class="container">
|
||||
<view class="charging-percentage">
|
||||
<view class="percentage-container">
|
||||
<image src="https://kxcharge.oss-cn-beijing.aliyuncs.com/147.png" class="circle"></image>
|
||||
<view class="percentage">
|
||||
<text class="value">{{ data.soc?data.soc:0 }}</text>
|
||||
<text>%</text>
|
||||
</view>
|
||||
<view class="status">
|
||||
充电中...
|
||||
</view>
|
||||
</view>
|
||||
<view class="name">
|
||||
<text>{{data.stationName}}</text>
|
||||
<image src="https://kxcharge.oss-cn-beijing.aliyuncs.com/27574.png"></image>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="detail-info">
|
||||
<view class="rest-time">
|
||||
<image src="https://kxcharge.oss-cn-beijing.aliyuncs.com/27698 (2).png"></image>
|
||||
<text>预计充满时间:{{ estimatedFullTime }}</text>
|
||||
</view>
|
||||
|
||||
<view class="cost-info">
|
||||
<view class="item">
|
||||
<view class="name">
|
||||
已充电量
|
||||
</view>
|
||||
<view class="value">
|
||||
{{data.chargedPower}}度
|
||||
</view>
|
||||
</view>
|
||||
<view class="line"></view>
|
||||
<view class="item">
|
||||
<view class="name">
|
||||
充电时长
|
||||
</view>
|
||||
<view class="value">
|
||||
{{chargingDuration}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="line"></view>
|
||||
<view class="item">
|
||||
<view class="name">
|
||||
费用总计
|
||||
</view>
|
||||
<view class="value">
|
||||
{{data.chargedAmount}}元
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="cable-info">
|
||||
<view class="item">
|
||||
<text>实时电流</text>
|
||||
<text class="value">{{data.outputCurrent}}</text>
|
||||
</view>
|
||||
<view class="item">
|
||||
<text>实时电压</text>
|
||||
<text class="value">{{data.outputVoltage}}</text>
|
||||
</view>
|
||||
<view class="item">
|
||||
<text>实时功率</text>
|
||||
<text class="value">{{ (data.outputCurrent * data.outputVoltage).toFixed(2) }}KW</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="split-line"></view>
|
||||
|
||||
<view style="width:100%;">
|
||||
<view class="header">
|
||||
<view class="line"></view>
|
||||
<view>
|
||||
订单信息
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view style="width: 100%;">
|
||||
<view class="list-item">
|
||||
<text>订单编号</text>
|
||||
<text class="value">{{data.seqNumber}}</text>
|
||||
</view>
|
||||
<view class="list-item">
|
||||
<text>绑定车牌</text>
|
||||
<text class="value">{{data.carNumber}}</text>
|
||||
</view>
|
||||
<view class="list-item">
|
||||
<text>充电时间</text>
|
||||
<text class="value">{{ formatTime }}</text>
|
||||
</view>
|
||||
<view class="list-item">
|
||||
<text>充电桩编号</text>
|
||||
<text class="value">{{data.equipmentConnectorCode}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
<ljs-loading v-if="progress>0">{{progress}}%</ljs-loading>
|
||||
|
||||
</view>
|
||||
|
||||
<template v-slot:kxTabBar>
|
||||
<kx-tabbar-wrapper>
|
||||
<view class="tab-bar">
|
||||
<button class="left item" @click="toPage('/pages/pay/recharge')">
|
||||
续缴
|
||||
</button>
|
||||
<button class="right item" :disabled="interval>0" @click="endCharge()">
|
||||
{{interval>0?`(${interval}秒)`:''}}结束
|
||||
</button>
|
||||
</view>
|
||||
</kx-tabbar-wrapper>
|
||||
</template>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
ref,
|
||||
onMounted,
|
||||
onUnmounted,
|
||||
computed
|
||||
} from 'vue'
|
||||
import {
|
||||
getOrder as getOrderApi
|
||||
} from '@/sheep/api/charge/operations';
|
||||
import * as OrderApi from "@/sheep/api/charge/order";
|
||||
|
||||
const interval = ref(0) // 剩余秒数
|
||||
const data = ref({})
|
||||
let timer = null
|
||||
let countdownTimer = null // 新增倒计时定时器
|
||||
let durationTimer = null // 新增充电时长定时器
|
||||
let hasInitializedTimers = false // 新增标志变量
|
||||
const chargeStatus = ref([5, 6, 7, 8, 9])
|
||||
const progress = ref(0)
|
||||
let progressTimer = null
|
||||
|
||||
const toPage = (url) => {
|
||||
uni.navigateTo({
|
||||
url
|
||||
});
|
||||
};
|
||||
|
||||
// 清除所有定时器
|
||||
const clearTimers = () => {
|
||||
if (timer) {
|
||||
clearTimeout(timer)
|
||||
timer = null
|
||||
}
|
||||
if (countdownTimer) {
|
||||
clearInterval(countdownTimer)
|
||||
countdownTimer = null
|
||||
}
|
||||
if (durationTimer) {
|
||||
clearInterval(durationTimer)
|
||||
durationTimer = null
|
||||
}
|
||||
if (progressTimer) {
|
||||
clearTimeout(progressTimer)
|
||||
progressTimer = null
|
||||
}
|
||||
hasInitializedTimers = false // 重置标志
|
||||
}
|
||||
// 格式化时间戳
|
||||
const formatTime = computed(() => {
|
||||
if (!data.value.startTime) return '--'
|
||||
|
||||
const date = new Date(parseInt(data.value.startTime))
|
||||
|
||||
// 格式化为 YYYY-MM-DD HH:mm:ss
|
||||
return `${date.getFullYear()}-${padZero(date.getMonth()+1)}-${padZero(date.getDate())} ${padZero(date.getHours())}:${padZero(date.getMinutes())}:${padZero(date.getSeconds())}`
|
||||
})
|
||||
|
||||
// 计算预计充满时间(响应式)
|
||||
const estimatedFullTime = computed(() => {
|
||||
if (!data.value.soc) return '计算中...'
|
||||
|
||||
const remainingPercent = 100 - data.value.soc
|
||||
const totalMinutes = Math.ceil(remainingPercent * 1.5) // 假设每1%需要1.5分钟
|
||||
|
||||
const hours = Math.floor(totalMinutes / 60)
|
||||
const minutes = totalMinutes % 60
|
||||
|
||||
if (hours > 0) {
|
||||
return `${hours}小时${minutes}分钟`
|
||||
} else {
|
||||
return `${minutes}分钟`
|
||||
}
|
||||
})
|
||||
|
||||
const endCharge = async () => {
|
||||
const response = await OrderApi.endCharge(data.value.seqNumber);
|
||||
if (response.code === 0) {
|
||||
clearTimers()
|
||||
progress.value = 90
|
||||
afterEndCharge()
|
||||
}
|
||||
};
|
||||
|
||||
const afterEndCharge = async () => {
|
||||
progress.value--
|
||||
const orderResponse = await OrderApi.getOrderInfo(data.value.seqNumber);
|
||||
if (chargeStatus.value.includes(orderResponse.data.chargeStatus) || progress.value <= 0) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/order-info/order-info?id=` + data.value.seqNumber
|
||||
})
|
||||
} else {
|
||||
progressTimer = setTimeout(() => {
|
||||
afterEndCharge()
|
||||
}, 5000)
|
||||
}
|
||||
}
|
||||
|
||||
// 补零函数
|
||||
const padZero = (num) => {
|
||||
return num < 10 ? `0${num}` : num
|
||||
}
|
||||
// 格式化时间为 HH:mm:ss
|
||||
const formatDuration = (seconds) => {
|
||||
const hours = Math.floor(seconds / 3600)
|
||||
const minutes = Math.floor((seconds % 3600) / 60)
|
||||
const secs = seconds % 60
|
||||
|
||||
return [
|
||||
hours.toString().padStart(2, '0'),
|
||||
minutes.toString().padStart(2, '0'),
|
||||
secs.toString().padStart(2, '0')
|
||||
].join(':')
|
||||
}
|
||||
|
||||
// 计算充电时长(响应式)
|
||||
const chargingDuration = computed(() => {
|
||||
if (!data.value.startTime) return '00:00:00'
|
||||
|
||||
const now = Date.now()
|
||||
const startTimestamp = parseInt(data.value.startTime)
|
||||
const diffInSeconds = Math.floor((now - startTimestamp) / 1000)
|
||||
|
||||
return formatDuration(diffInSeconds)
|
||||
})
|
||||
|
||||
// 计算剩余秒数并开始倒计时
|
||||
const startCountdown = (startTime) => {
|
||||
const now = Date.now()
|
||||
const startTimestamp = parseInt(startTime)
|
||||
const diffInSeconds = Math.floor((now - startTimestamp) / 1000)
|
||||
|
||||
// 如果超过60秒,不显示倒计时
|
||||
if (diffInSeconds >= 60) {
|
||||
interval.value = 0
|
||||
return
|
||||
}
|
||||
|
||||
// 计算剩余秒数
|
||||
interval.value = 60 - diffInSeconds
|
||||
|
||||
// 开始倒计时
|
||||
countdownTimer = setInterval(() => {
|
||||
interval.value -= 1
|
||||
|
||||
// 倒计时结束
|
||||
if (interval.value <= 0) {
|
||||
clearInterval(countdownTimer)
|
||||
countdownTimer = null
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
// 开始充电时长计时
|
||||
const startDurationTimer = () => {
|
||||
// 先清除已有的定时器
|
||||
if (durationTimer) clearInterval(durationTimer)
|
||||
|
||||
// 每秒更新一次
|
||||
durationTimer = setInterval(() => {
|
||||
// computed属性会自动更新
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
onLoad(({
|
||||
seqNumber
|
||||
}) => {
|
||||
getOrder(seqNumber)
|
||||
})
|
||||
|
||||
onHide(() => {
|
||||
clearTimers()
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
clearTimers()
|
||||
})
|
||||
|
||||
onBackPress(() => {
|
||||
clearTimers()
|
||||
})
|
||||
|
||||
const getOrder = async seqNumber => {
|
||||
const res = await getOrderApi(seqNumber)
|
||||
data.value = res.data
|
||||
|
||||
// 修改后的计时器初始化逻辑
|
||||
if (res.data.startTime && !hasInitializedTimers) {
|
||||
startCountdown(res.data.startTime)
|
||||
startDurationTimer()
|
||||
hasInitializedTimers = true // 设置标志为true
|
||||
}
|
||||
|
||||
if (res.data.orderStatus === 4) {
|
||||
clearTimers()
|
||||
uni.navigateTo({
|
||||
url: `/pages/order-info/order-info?id=` + res.data.seqNumber
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
timer = setTimeout(() => {
|
||||
getOrder(seqNumber)
|
||||
}, 10000)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.container {
|
||||
padding-top: 54rpx;
|
||||
background: url('https://kxcharge.oss-cn-beijing.aliyuncs.com/mini/box.png') 0 0/100% 812rpx no-repeat;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.charging-percentage {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.percentage-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
background: url('https://kxcharge.oss-cn-beijing.aliyuncs.com/mini/percentage.png') 0 0/100% 100% no-repeat;
|
||||
width: 416rpx;
|
||||
height: 416rpx;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.circle {
|
||||
width: 347rpx;
|
||||
height: 347rpx;
|
||||
position: absolute;
|
||||
transform-origin: center center;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.percentage {
|
||||
font-weight: bold;
|
||||
font-size: 42rpx;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 99rpx;
|
||||
}
|
||||
|
||||
.status {
|
||||
font-size: 33rpx;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.name {
|
||||
background: rgba(255, 255, 255, 0.19);
|
||||
border-radius: 45rpx;
|
||||
border: 1rpx solid #FFFFFF;
|
||||
padding: 8rpx 38rpx;
|
||||
margin: 38rpx 0 64rpx;
|
||||
font-weight: bold;
|
||||
font-size: 30rpx;
|
||||
color: #FFFFFF;
|
||||
|
||||
image {
|
||||
width: 26rpx;
|
||||
height: 26rpx;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.detail-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0rpx 0rpx 20rpx 1rpx rgba(53, 127, 251, 0.1);
|
||||
border-radius: 36rpx 36rpx 0rpx 0rpx;
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.rest-time {
|
||||
font-weight: 800;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
margin-bottom: 24rpx;
|
||||
|
||||
image {
|
||||
width: 20rpx;
|
||||
height: 32rpx;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.cost-info {
|
||||
background: rgba(48, 114, 246, .1);
|
||||
border-radius: 25rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
width: 690rpx;
|
||||
padding: 30rpx 0;
|
||||
font-size: 28rpx;
|
||||
color: #000000;
|
||||
|
||||
.line {
|
||||
width: 1rpx;
|
||||
height: 61rpx;
|
||||
background: #DCDCDC;
|
||||
}
|
||||
|
||||
.item {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-weight: bold;
|
||||
font-size: 32rpx;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.cable-info {
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
margin: 30rpx 0;
|
||||
font-size: 24rpx;
|
||||
color: #000000;
|
||||
width: 100%;
|
||||
|
||||
.value {
|
||||
font-weight: bold;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.split-line {
|
||||
width: 693rpx;
|
||||
height: 0rpx;
|
||||
border: 1rpx solid #E3E3E3;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.header {
|
||||
font-weight: 800;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.line {
|
||||
width: 7rpx;
|
||||
height: 32rpx;
|
||||
margin-right: 16rpx;
|
||||
background: #3072F6;
|
||||
}
|
||||
}
|
||||
|
||||
.list-item {
|
||||
font-size: 28rpx;
|
||||
color: #999999;
|
||||
|
||||
.value {
|
||||
color: #333333;
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.list-item+.list-item {
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.tab-bar {
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
width: 100%;
|
||||
|
||||
.item {
|
||||
width: 334rpx;
|
||||
// padding: 24rpx 0;
|
||||
font-weight: bold;
|
||||
font-size: 30rpx;
|
||||
color: #FFFFFF;
|
||||
background: linear-gradient(132deg, #4A8EFC 0%, #50C3FD 100%);
|
||||
border-radius: 45rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.right {
|
||||
background: linear-gradient(131deg, #FC754A 0%, #FD5050 100%);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,426 @@
|
||||
<template>
|
||||
<s-layout title="开始充电" navbar="normal" onShareAppMessage @clickLeft="clearTimer">
|
||||
|
||||
<kx-equipment-info :detail="detail"></kx-equipment-info>
|
||||
|
||||
<uni-card is-shadow spacing="0" padding="30rpx">
|
||||
<view class="header">
|
||||
<view class="line"></view>
|
||||
<view>
|
||||
价格信息
|
||||
</view>
|
||||
</view>
|
||||
<view class="time">
|
||||
价格时段:{{currentCostTemplatePrice.startTimeStr}}-{{currentCostTemplatePrice.endTimeStr}}
|
||||
</view>
|
||||
<view class="charge">
|
||||
<view class="price">
|
||||
<text>{{(currentCostTemplatePriceType.pricePower+currentCostTemplatePriceType.priceService).toFixed(2)}}</text>
|
||||
元/度
|
||||
</view>
|
||||
<view class="vip">
|
||||
<image src="https://kxcharge.oss-cn-beijing.aliyuncs.com/16568@2x.png" mode="aspectFit"></image>
|
||||
<text>
|
||||
¥{{(currentCostTemplatePriceType.pricePower+currentCostTemplatePriceType.priceService).toFixed(2)}}元/度
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="time" style="margin-bottom: 0;">
|
||||
电价{{currentCostTemplatePriceType.pricePower}}元/度,服务费{{currentCostTemplatePriceType.priceService}}元/度
|
||||
</view>
|
||||
</uni-card>
|
||||
|
||||
<uni-card is-shadow spacing="0" padding="30rpx">
|
||||
<view class="header">
|
||||
<view class="line"></view>
|
||||
<view>
|
||||
停车场收费
|
||||
</view>
|
||||
</view>
|
||||
<view class="remark">
|
||||
{{detail.stationVo.openExplain}}
|
||||
</view>
|
||||
|
||||
</uni-card>
|
||||
|
||||
<uni-card is-shadow spacing="0" padding="30rpx">
|
||||
<view class="header">
|
||||
<view class="line"></view>
|
||||
<view>
|
||||
占用收费
|
||||
</view>
|
||||
</view>
|
||||
<view class="remark">
|
||||
充电完成后超过30分钟不拔枪,系统将按照0.17元/分钟计算收取设备占用费,费用上线为30元
|
||||
</view>
|
||||
|
||||
</uni-card>
|
||||
|
||||
<uni-card is-shadow spacing="0" padding="30rpx">
|
||||
<view class="header">
|
||||
<view class="line"></view>
|
||||
<view>
|
||||
充电爱车
|
||||
</view>
|
||||
<view style="flex:1;">
|
||||
<view class="right" @click="toPage('/pages/my-car/add-my-car/add-my-car')">
|
||||
<image src="https://kxcharge.oss-cn-beijing.aliyuncs.com/27672.png" style="width:28rpx;height:28rpx;margin-right: 10rpx;"></image>
|
||||
<text>添加爱车</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="car-info" @click="toPage(`/pages/my-car/my-car?connectorCode=${connectorCode}`)">
|
||||
<image src="https://kxcharge.oss-cn-beijing.aliyuncs.com/27673.png"></image>
|
||||
<text>{{ plateNumber }}</text>
|
||||
</view>
|
||||
</uni-card>
|
||||
|
||||
<uni-card is-shadow spacing="0" padding="30rpx">
|
||||
<view class="header">
|
||||
<view class="line"></view>
|
||||
<view>
|
||||
付款方式
|
||||
</view>
|
||||
</view>
|
||||
<view class="pay-info">
|
||||
<view class="account">
|
||||
<text>账户余额</text>
|
||||
<text class="value">{{ balance }}</text>
|
||||
</view>
|
||||
<view class="recharge" @click="toPage(`/pages/pay/recharge?connectorCode=${connectorCode}`)">去充值 ></view>
|
||||
</view>
|
||||
</uni-card>
|
||||
|
||||
<ljs-loading v-if="progress>0">{{progress}}%</ljs-loading>
|
||||
|
||||
<template v-slot:kxTabBar>
|
||||
<kx-tabbar-wrapper>
|
||||
<view class="tab-bar" @click="startCharge">
|
||||
开始充电
|
||||
</view>
|
||||
</kx-tabbar-wrapper>
|
||||
</template>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import PayWalletApi from '@/sheep/api/pay/wallet';
|
||||
import * as MemberApi from "@/sheep/api/charge/member";
|
||||
import * as OrderApi from "@/sheep/api/charge/order";
|
||||
import dayjs from 'dayjs'
|
||||
import customParseFormat from 'dayjs/plugin/customParseFormat'
|
||||
import {
|
||||
getConnectorInfo as getConnectorInfoApi
|
||||
} from '@/sheep/api/charge/operations'
|
||||
|
||||
dayjs.extend(customParseFormat);
|
||||
|
||||
const balance = ref(0);
|
||||
const plateNumber = ref('');
|
||||
const orderSeqNumber = ref('');
|
||||
const progress = ref(0);
|
||||
const connectorCode = ref('');
|
||||
const detail = ref({
|
||||
equipmentModelRespVO: {},
|
||||
stationVo: {},
|
||||
workState: 3,
|
||||
connectorCode: ''
|
||||
})
|
||||
let timer = null
|
||||
let getDataTimer = null
|
||||
const currentCostTemplatePrice = ref({})
|
||||
const currentCostTemplatePriceType = ref({})
|
||||
|
||||
const toPage = (url) => {
|
||||
uni.navigateTo({
|
||||
url
|
||||
});
|
||||
};
|
||||
|
||||
const getConnectorInfo = async id => {
|
||||
const res = await getConnectorInfoApi(id)
|
||||
detail.value = res.data
|
||||
getDataTimer = setTimeout(() => {
|
||||
getConnectorInfo(id)
|
||||
}, 5000)
|
||||
}
|
||||
|
||||
const getPrice = () => {
|
||||
const now = dayjs()
|
||||
const {
|
||||
costTemplatePriceRespVOS: costTemplatePrice,
|
||||
costTemplatePriceTypeRespVOS: costTemplatePriceType
|
||||
} = detail.value.stationVo.costTemplateRespVO
|
||||
currentCostTemplatePrice.value = costTemplatePrice.filter(({
|
||||
endTimeStr,
|
||||
startTimeStr
|
||||
}) => {
|
||||
const start = dayjs(startTimeStr, 'HH:mm'),
|
||||
end = dayjs(endTimeStr, 'HH:mm')
|
||||
return start.isBefore(now) && end.isAfter(now)
|
||||
})?.[0]
|
||||
currentCostTemplatePriceType.value = costTemplatePriceType.filter(({
|
||||
typeName
|
||||
}) => currentCostTemplatePrice.value.priceTypeId === typeName)?.[0]
|
||||
}
|
||||
|
||||
onLoad(async (options) => {
|
||||
connectorCode.value = options.connectorCode;
|
||||
if (options.carInfo) {
|
||||
plateNumber.value = JSON.parse(options.carInfo).plateNumber
|
||||
}
|
||||
await getConnectorInfo(options.connectorCode)
|
||||
getPrice()
|
||||
});
|
||||
|
||||
// 将初始化逻辑提取到单独的函数
|
||||
const initData = async () => {
|
||||
const response = await PayWalletApi.getPayWallet();
|
||||
if (response.code === 0) {
|
||||
balance.value = (response.data.balance / 100).toFixed(2);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
const responseCar = await MemberApi.getMyCar();
|
||||
if (responseCar.code === 0) {
|
||||
const cars = responseCar.data;
|
||||
// 查找 isDefault = 1 的车辆
|
||||
const defaultCar = cars.find(car => car.isDefault === 1);
|
||||
if (plateNumber.value === '') {
|
||||
if (defaultCar) {
|
||||
plateNumber.value = defaultCar.plateNumber; // 有默认车辆,赋值
|
||||
} else if (cars.length > 0) {
|
||||
plateNumber.value = cars[0].plateNumber; // 没有默认车辆,取第一辆
|
||||
} else {
|
||||
plateNumber.value = ""; // 没有车辆,设为空
|
||||
}
|
||||
}
|
||||
}
|
||||
initData(); // 页面初次加载时调用
|
||||
});
|
||||
|
||||
onShow(() => {
|
||||
initData(); // 页面再次显示时调用
|
||||
});
|
||||
|
||||
const startCharge = async () => {
|
||||
const response = await OrderApi.startCharge(connectorCode.value, plateNumber.value, 1);
|
||||
|
||||
if (response.code === 0) {
|
||||
orderSeqNumber.value = response.data;
|
||||
startProgress();
|
||||
}
|
||||
};
|
||||
|
||||
onHide(() => {
|
||||
progress.value = 0;
|
||||
clearTimer()
|
||||
})
|
||||
onBackPress(() => {
|
||||
progress.value = 0;
|
||||
clearTimer()
|
||||
})
|
||||
onUnmounted(() => {
|
||||
progress.value = 0;
|
||||
clearTimer()
|
||||
})
|
||||
|
||||
const clearTimer = () => {
|
||||
if (timer) {
|
||||
clearTimeout(timer)
|
||||
timer = null
|
||||
}
|
||||
if (getDataTimer) {
|
||||
clearTimeout(getDataTimer)
|
||||
getDataTimer = null
|
||||
}
|
||||
}
|
||||
|
||||
const startProgress = () => {
|
||||
progress.value = 0;
|
||||
let count = 0;
|
||||
const query = async () => {
|
||||
progress.value += 3
|
||||
count++
|
||||
const orderResponse = await OrderApi.getOrderInfo(orderSeqNumber.value);
|
||||
// TODO
|
||||
if (count >= 1 || orderResponse.data.orderStatus === 2) {
|
||||
progress.value = 100
|
||||
clearTimer()
|
||||
uni.navigateTo({
|
||||
url: '/pages/charging/index?seqNumber=' + orderResponse.data.seqNumber
|
||||
});
|
||||
return
|
||||
}
|
||||
if (count >= 1 || orderResponse.data.orderStatus === 6) {
|
||||
progress.value = 100
|
||||
clearTimer()
|
||||
uni.navigateTo({
|
||||
url: `/pages/order-info/order-info?id=` + orderResponse.data.seqNumber
|
||||
})
|
||||
return
|
||||
}
|
||||
timer = setTimeout(() => {
|
||||
query();
|
||||
}, 1000)
|
||||
}
|
||||
query()
|
||||
}
|
||||
// const startProgress = () => {
|
||||
// progress.value = 0;
|
||||
// intervalId.value = setInterval(async () => {
|
||||
// progress.value += 10;
|
||||
// if (progress.value >= 3000) {
|
||||
// clearInterval(intervalId.value);
|
||||
// setTimeout(() => {
|
||||
// uni.navigateTo({
|
||||
// url: '/pages/charging/index'
|
||||
// });
|
||||
// }, 1000);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// const orderResponse = await OrderApi.getOrderInfo(orderSeqNumber.value);
|
||||
|
||||
// if (orderResponse.data.orderStatus === 4) {
|
||||
// clearInterval(intervalId.value);
|
||||
// progress.value = 100;
|
||||
// setTimeout(() => {
|
||||
// uni.navigateTo({
|
||||
// url: '/pages/charging/index'
|
||||
// });
|
||||
// }, 1000);
|
||||
// }
|
||||
// }, 1000);
|
||||
// };
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.header {
|
||||
font-weight: 800;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.line {
|
||||
width: 7rpx;
|
||||
height: 32rpx;
|
||||
margin-right: 16rpx;
|
||||
background: #3072F6;
|
||||
}
|
||||
|
||||
.right {
|
||||
float: right;
|
||||
font-size: 30rpx;
|
||||
color: #337BFB;
|
||||
}
|
||||
}
|
||||
|
||||
.time {
|
||||
font-size: 24rpx;
|
||||
color: #333333;
|
||||
margin: 20rpx 0;
|
||||
}
|
||||
|
||||
.price {
|
||||
font-size: 24rpx;
|
||||
color: #333;
|
||||
display: inline-block;
|
||||
margin-right: 18rpx;
|
||||
vertical-align: middle;
|
||||
|
||||
text {
|
||||
font-size: 40rpx;
|
||||
color: #EB5336;
|
||||
}
|
||||
}
|
||||
|
||||
.vip {
|
||||
width: 230rpx;
|
||||
height: 45rpx;
|
||||
background: linear-gradient(180deg, #FADBB7 0%, #F6BA85 100%);
|
||||
border-radius: 10rpx 10rpx 10rpx 10rpx;
|
||||
display: inline-block;
|
||||
|
||||
image {
|
||||
width: 82rpx;
|
||||
height: 45rpx;
|
||||
}
|
||||
|
||||
text {
|
||||
font-size: 24rpx;
|
||||
color: #3A3E5E;
|
||||
}
|
||||
}
|
||||
|
||||
.remark {
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.car-info {
|
||||
background: #F5F6FA;
|
||||
border-radius: 20rpx;
|
||||
font-size: 30rpx;
|
||||
color: #323551;
|
||||
text-align: center;
|
||||
padding: 30rpx 0;
|
||||
|
||||
image {
|
||||
width: 50rpx;
|
||||
height: 40rpx;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.pay-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.account {
|
||||
font-size: 24rpx;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-weight: bold;
|
||||
font-size: 32rpx;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
|
||||
.recharge {
|
||||
font-size: 26rpx;
|
||||
color: #666666;
|
||||
}
|
||||
}
|
||||
|
||||
.tab-bar {
|
||||
background: linear-gradient(132deg, #4A8EFC 0%, #50C3FD 100%);
|
||||
border-radius: 45rpx;
|
||||
font-weight: bold;
|
||||
font-size: 30rpx;
|
||||
color: #FFF;
|
||||
text-align: center;
|
||||
padding: 24rpx 0;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
width: 100%;
|
||||
height: 20rpx;
|
||||
background-color: #e0e0e0;
|
||||
border-radius: 10rpx;
|
||||
overflow: hidden;
|
||||
margin-top: 20rpx;
|
||||
|
||||
.progress {
|
||||
height: 100%;
|
||||
background-color: #4A8EFC;
|
||||
width: v-bind(progress + '%');
|
||||
transition: width 1s linear;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,14 @@
|
||||
<template>
|
||||
<s-layout title="电站详情" navbar="normal" onShareAppMessage>
|
||||
<kx-equipment-info></kx-equipment-info>
|
||||
<kx-equipment-info></kx-equipment-info>
|
||||
|
||||
<template v-slot:kxTabBar>
|
||||
<kx-tabbar></kx-tabbar>
|
||||
</template>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
||||
</script>
|
||||
@@ -0,0 +1,330 @@
|
||||
<!-- 首页,支持店铺装修 -->
|
||||
<template>
|
||||
<s-layout title="首页" navbar="normal" tabbar="pages/index/index" onShareAppMessage>
|
||||
<view class="container">
|
||||
<kx-search-bar class="search-bar" scroll id="kxSearchBar"></kx-search-bar>
|
||||
<view class="banner">
|
||||
<uni-swiper-dot :info="carouselList"
|
||||
:dots-styles="{backgroundColor: 'rgba(255,255,255, .4)',selectedBackgroundColor: 'rgba(255,255,255)'}"
|
||||
:current="currentCarousel">
|
||||
<swiper autoplay circular @change="onCarouselChange">
|
||||
<swiper-item v-for="item in carouselList" :key="item.id">
|
||||
<image :src="item.url" mode="aspectFit" style="width:100%;height:100%;"></image>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</uni-swiper-dot>
|
||||
</view>
|
||||
<view>
|
||||
<view class="charging" v-for="item in chargingList" :key="item.id">
|
||||
<view class="left">
|
||||
<view class="icon">
|
||||
<image :src="userStore?.userInfo?.avatar || 'https://kxcharge.oss-cn-beijing.aliyuncs.com/default-avatar.png'" mode="aspectFill">
|
||||
</image>
|
||||
</view>
|
||||
<view class="info">
|
||||
<view class="car-no">
|
||||
{{item.plateNumber}}
|
||||
</view>
|
||||
<view class="progress">
|
||||
<view class="icon">
|
||||
|
||||
</view>
|
||||
<view>
|
||||
正在充电中<span class="ellipsis">......</span>{{ item.endSoc }}%
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="right" @click="toPage('/pages/charging/index?seqNumber=' + item.seqNumber)">
|
||||
查看详情
|
||||
<uni-icons type="arrow-right" size="16" color="#3072F6" style="vertical-align: middle;"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="station-header">
|
||||
附近充电站
|
||||
</view>
|
||||
<view class="station-tabs"
|
||||
:style="{top:stationTabsTop+'px',backgroundColor:(scrollTop>stationTabsTop)?'#f5f9ff':'transparent'}">
|
||||
<view class="item" v-for="(item,index) in tabs" :key="item.index" :class="{active:tabIndex===index}"
|
||||
@tap="onTabTap(index)">
|
||||
{{item.text}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="station-list">
|
||||
<kx-station-info :station="item" v-for="item in stationList" :key="item.id"></kx-station-info>
|
||||
<kx-tabbar-placeholder></kx-tabbar-placeholder>
|
||||
</view>
|
||||
</view>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
getStationList,
|
||||
getChargingPage
|
||||
} from '@/sheep/api/charge/operations'
|
||||
import {
|
||||
getCarouselList
|
||||
} from '@/sheep/api/charge/member'
|
||||
|
||||
// onPageScroll
|
||||
const {
|
||||
scrollTop
|
||||
} = usePageScroll()
|
||||
|
||||
let longitude = null,
|
||||
latitude = null
|
||||
|
||||
const userStore = computed(() => {
|
||||
return sheep.$store('user').$state
|
||||
});
|
||||
|
||||
const stationTabsTop = ref(0)
|
||||
|
||||
onMounted(() => {
|
||||
uni.createSelectorQuery().in(getCurrentInstance().proxy).select("#kxSearchBar").boundingClientRect((data) => {
|
||||
stationTabsTop.value = data.height + sheep.$platform.navbar
|
||||
}).exec();
|
||||
})
|
||||
|
||||
|
||||
const stationList = ref([])
|
||||
const chargingList = ref([])
|
||||
|
||||
const carouselList = ref([])
|
||||
const currentCarousel = ref(0)
|
||||
|
||||
onShow(() => {
|
||||
const actualLocation = sheep.$store('user').actualLocation
|
||||
longitude = actualLocation.longitude
|
||||
latitude = actualLocation.latitude
|
||||
getStationList({
|
||||
longitude,
|
||||
latitude
|
||||
}).then(res => {
|
||||
stationList.value = res.data
|
||||
})
|
||||
getChargingPage().then(({
|
||||
data
|
||||
}) => {
|
||||
chargingList.value = data.list
|
||||
})
|
||||
getCarouselList().then(res => {
|
||||
carouselList.value = res.data
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
|
||||
const onCarouselChange = (e) => {
|
||||
currentCarousel.value = e.detail.current
|
||||
}
|
||||
|
||||
// 隐藏原生tabBar
|
||||
uni.hideTabBar();
|
||||
|
||||
const tabIndex = ref(0)
|
||||
|
||||
const tabs = [{
|
||||
text: '距离最近'
|
||||
}, {
|
||||
text: '价格最低'
|
||||
}, {
|
||||
text: '快充'
|
||||
}, {
|
||||
text: '慢充'
|
||||
}]
|
||||
|
||||
const onTabTap = (index) => {
|
||||
tabIndex.value = index;
|
||||
|
||||
// 确定 rank 的值
|
||||
let rank = '';
|
||||
switch (index) {
|
||||
case 0:
|
||||
rank = 'distance'; // 距离最近
|
||||
break;
|
||||
case 1:
|
||||
rank = 'price'; // 价格最低
|
||||
break;
|
||||
case 2:
|
||||
rank = 'fast'; // 快充(如果需要)
|
||||
break;
|
||||
case 3:
|
||||
rank = 'slow'; // 慢充(如果需要)
|
||||
break;
|
||||
default:
|
||||
rank = '';
|
||||
}
|
||||
|
||||
// 重新获取站点列表
|
||||
getStationList({
|
||||
longitude,
|
||||
latitude,
|
||||
rank
|
||||
}).then(res => {
|
||||
stationList.value = res.data;
|
||||
});
|
||||
}
|
||||
|
||||
const toPage = (url) => {
|
||||
if (!url) return; // 如果没有设置路径,则不跳转
|
||||
|
||||
// 判断是否是 tabBar 页面
|
||||
const tabBarPages = [
|
||||
'/pages/index/index',
|
||||
'/pages/map/index',
|
||||
'/pages/order/index',
|
||||
'/pages/my/index'
|
||||
];
|
||||
|
||||
if (tabBarPages.includes(url)) {
|
||||
// 使用 switchTab 跳转 tabBar 页面
|
||||
uni.switchTab({
|
||||
url
|
||||
});
|
||||
} else {
|
||||
// 其他页面使用 navigateTo
|
||||
uni.navigateTo({
|
||||
url
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.ellipsis {
|
||||
display: inline-block;
|
||||
vertical-align: bottom;
|
||||
overflow: hidden;
|
||||
animation: ellipsis 3s infinite steps(4, jump-none);
|
||||
}
|
||||
|
||||
@keyframes ellipsis {
|
||||
from {
|
||||
width: 18.1rpx;
|
||||
}
|
||||
|
||||
to {
|
||||
width: 36.5rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
background: url('https://kxcharge.oss-cn-beijing.aliyuncs.com/1.png') 0 0/100% 424rpx no-repeat, #f5f9ff;
|
||||
}
|
||||
|
||||
.banner {
|
||||
width: 690rpx;
|
||||
height: 300rpx;
|
||||
margin: 20rpx auto 30rpx;
|
||||
}
|
||||
|
||||
.grid-item-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
padding: 15px 0;
|
||||
|
||||
.text {
|
||||
font-size: 26rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.img {
|
||||
width: 90rpx;
|
||||
height: 90rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.charging {
|
||||
width: 690rpx;
|
||||
height: 140rpx;
|
||||
background: linear-gradient(90deg, #FFFFFF 0%, #C8E7FF 100%);
|
||||
box-shadow: inset 0rpx 3rpx 6rpx 1rpx #FFFFFF;
|
||||
border-radius: 87rpx;
|
||||
margin: 30rpx auto 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 20rpx 30rpx;
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 94rpx;
|
||||
height: 94rpx;
|
||||
// background: #B7CFFB;
|
||||
border-radius: 34rpx;
|
||||
}
|
||||
|
||||
.info {
|
||||
margin-left: 20rpx;
|
||||
margin-top: 5rpx;
|
||||
|
||||
.icon {
|
||||
width: 20rpx;
|
||||
height: 20rpx;
|
||||
background: #03E698;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.car-no {
|
||||
font-weight: bold;
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
margin-bottom: 15rpx;
|
||||
}
|
||||
|
||||
.progress {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.right {
|
||||
font-size: 24rpx;
|
||||
color: #3072F6;
|
||||
}
|
||||
}
|
||||
|
||||
.station-header {
|
||||
display: inline-block;
|
||||
margin: 30rpx 0 25rpx 30rpx;
|
||||
font-weight: 800;
|
||||
font-size: 36rpx;
|
||||
color: #333;
|
||||
background: url('https://kxcharge.oss-cn-beijing.aliyuncs.com/5946@2x.png') 0 bottom/100% 12rpx no-repeat
|
||||
}
|
||||
|
||||
.station-tabs {
|
||||
display: flex;
|
||||
padding: 0 0 20rpx 30rpx;
|
||||
position: -webkit-sticky;
|
||||
position: sticky;
|
||||
z-index: 100;
|
||||
|
||||
.item {
|
||||
font-weight: bold;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
padding: 5rpx 12rpx;
|
||||
}
|
||||
|
||||
.item+.item {
|
||||
margin-left: 60rpx;
|
||||
}
|
||||
|
||||
.item.active {
|
||||
background: rgba(48, 114, 246, 0.1);
|
||||
border-radius: 25rpx 25rpx 25rpx 25rpx;
|
||||
color: #3072F6;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,377 @@
|
||||
<template>
|
||||
<s-layout navbar="normal" onShareAppMessage>
|
||||
<view class="block">
|
||||
<view class="carInfo">
|
||||
<image src="https://kxcharge.oss-cn-beijing.aliyuncs.com/add-car-image.png" mode="aspectFit"></image>
|
||||
<view class="carType">
|
||||
<text class="title">车型</text>
|
||||
<text>新能源汽车</text>
|
||||
</view>
|
||||
<view class="plateNum" @click="inputPlate">
|
||||
<text class="title">车牌号</text>
|
||||
<view class="num">
|
||||
<text class="numItem" v-for="(item,index) in blockArr" :key="index">{{item || ''}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="isDefault" v-if="!isEdit">
|
||||
<text class="title">是否为默认充电车辆</text>
|
||||
<uv-switch v-model="defaultCar"></uv-switch>
|
||||
</view>
|
||||
<view class="carType" v-else>
|
||||
<text class="title">车辆识别代码</text>
|
||||
<text>未认证</text>
|
||||
</view>
|
||||
</view>
|
||||
<uv-button type="primary" text="添加车辆" shape="circle" @click="addCar('add')" v-if="!isEdit"></uv-button>
|
||||
<view v-else>
|
||||
<uv-button type="primary" text="编辑车辆" shape="circle" @click="addCar('edit')"></uv-button>
|
||||
<view class="delCar" @click="onDelCar">删除车辆</view>
|
||||
</view>
|
||||
<!-- <text @click="goBack" class="goBack">我再想想</text> -->
|
||||
<uv-popup ref="popup" mode="bottom" @change="onPopupChange">
|
||||
<view class="popup-content">
|
||||
<view class="btn">
|
||||
<text @click="()=>$refs.popup.close()">取消</text>
|
||||
<text @click="submitPlate">确定</text>
|
||||
</view>
|
||||
<view>
|
||||
<text class="label">车牌号</text>
|
||||
<view class="num">
|
||||
<text class="text-block" v-for="(item,index) in popBlockArr" :key="index">{{item || ''}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<uv-keyboard :autoChange="true" ref="uKeyboard" mode="car" :overlay="false" @change="clickKeyboard($event)"
|
||||
:tooltip="false" @backspace="backspace"></uv-keyboard>
|
||||
</view>
|
||||
</uv-popup>
|
||||
|
||||
<uv-modal ref="modal" content='是否确认删除该车辆?' title='提示' :showCancelButton="true" class="modal"
|
||||
@cancel="showModal = false" @confirm="submitDel"></uv-modal>
|
||||
</view>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
delCar,
|
||||
createCar,
|
||||
editCar
|
||||
} from "@/sheep/api/charge/member"
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
defaultCar: true,
|
||||
showModal: false,
|
||||
plateValue: '',
|
||||
isFocus: false,
|
||||
time1: 0,
|
||||
time2: 0,
|
||||
time3: 0,
|
||||
blockArr: new Array(8),
|
||||
popBlockArr: new Array(8),
|
||||
isEdit: false,
|
||||
carId: '',
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
clickKeyboard(event) {
|
||||
if (this.plateValue.length >= 8) {
|
||||
return;
|
||||
}
|
||||
this.plateValue += event;
|
||||
this.plateValue.split("").forEach((k, index) => {
|
||||
this.popBlockArr[index] = k;
|
||||
});
|
||||
},
|
||||
backspace() {
|
||||
this.popBlockArr = this.popBlockArr.map((item, index, arr) => {
|
||||
if (!arr[index + 1]) item = '';
|
||||
return item;
|
||||
});
|
||||
this.plateValue = this.popBlockArr.join("")
|
||||
// console.log('this.popBlockArr: ',this.popBlockArr, this.plateValue);
|
||||
},
|
||||
addCar(type) {
|
||||
if (!this.plateValue) {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: '请输入车牌号'
|
||||
})
|
||||
return;
|
||||
}
|
||||
const data = {
|
||||
plateNumber: this.plateValue,
|
||||
isDefault: Number(this.defaultCar),
|
||||
plateType: 1
|
||||
}
|
||||
if (this.carId) {
|
||||
data['id'] = this.carId;
|
||||
}
|
||||
try {
|
||||
const method = type == "add" ? createCar : editCar;
|
||||
const tip = type == "add" ? '添加' : '编辑'
|
||||
method(data).then(res => {
|
||||
console.log('res: ', res);
|
||||
uni.showToast({
|
||||
title: `${tip}成功!`,
|
||||
icon: 'success'
|
||||
})
|
||||
// 使用 setTimeout 延迟跳转
|
||||
setTimeout(() => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/my-car/my-car`
|
||||
});
|
||||
}, 1500); // 2000 毫秒 = 2 秒
|
||||
}).catch(err => {
|
||||
uni.showToast({
|
||||
title: `${tip}失败!`,
|
||||
icon: 'error'
|
||||
})
|
||||
})
|
||||
} catch (e) {
|
||||
uni.showToast({
|
||||
title: '添加失败!',
|
||||
icon: 'error'
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
goBack() {
|
||||
uni.navigateBack();
|
||||
},
|
||||
inputPlate() {
|
||||
// if (this.isEdit) return;
|
||||
this.$refs.popup.open()
|
||||
this.$refs.uKeyboard.open()
|
||||
},
|
||||
onPopupChange(e) {
|
||||
if (e) {
|
||||
this.open()
|
||||
} else {
|
||||
this.close()
|
||||
}
|
||||
},
|
||||
open() {
|
||||
this.$refs.popup.open();
|
||||
this.time2 = setTimeout(() => {
|
||||
this.isFocus = true;
|
||||
}, 1000)
|
||||
},
|
||||
close() {
|
||||
this.isFocus = false;
|
||||
this.plateValue = '';
|
||||
},
|
||||
submitPlate() {
|
||||
if (!this.plateValue) {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: '输入的车牌号是否为空'
|
||||
})
|
||||
return;
|
||||
}
|
||||
// const plateArr = this.plateValue.split("")
|
||||
if (this.plateValue.length !== 8 && this.plateValue.length !== 7) {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: '输入的车牌号有误,请重新输入'
|
||||
})
|
||||
return;
|
||||
}
|
||||
this.$refs.popup.close()
|
||||
this.$refs.uKeyboard.close()
|
||||
|
||||
this.plateValue.split("").forEach((k, index) => {
|
||||
this.blockArr[index] = k;
|
||||
});
|
||||
this.blockArr = this.blockArr.filter(k => k);
|
||||
},
|
||||
onDelCar() {
|
||||
this.$refs.modal.open();
|
||||
},
|
||||
submitDel() {
|
||||
try {
|
||||
delCar(this.carId).then(res => {
|
||||
this.$refs.modal.close();;
|
||||
uni.showToast({
|
||||
title: '删除成功!',
|
||||
icon: 'success'
|
||||
})
|
||||
// 使用 setTimeout 延迟跳转
|
||||
setTimeout(() => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/my-car/my-car`
|
||||
});
|
||||
}, 1500); // 2000 毫秒 = 2 秒
|
||||
}).catch(err => {
|
||||
console.log('err: ', err);
|
||||
uni.showToast({
|
||||
title: '删除失败!',
|
||||
icon: 'error'
|
||||
})
|
||||
})
|
||||
} catch (e) {
|
||||
//TODO handle the exception
|
||||
uni.showToast({
|
||||
title: '删除失败!',
|
||||
icon: 'error'
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
clearTimeout(this.time1);
|
||||
clearTimeout(this.time2);
|
||||
clearTimeout(this.time3);
|
||||
},
|
||||
onLoad(options) {
|
||||
if (options.carInfo) {
|
||||
console.log('options.carInfo: ', options.carInfo);
|
||||
const info = JSON.parse(options.carInfo);
|
||||
this.defaultCar = info.isDefault
|
||||
this.plateValue = info.plateNumber;
|
||||
this.plateValue.split("").forEach((k, index) => {
|
||||
this.blockArr[index] = k;
|
||||
});
|
||||
this.blockArr = this.blockArr.filter(k => k);
|
||||
this.popBlockArr = this.blockArr;
|
||||
this.isEdit = true;
|
||||
this.carId = info.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
page {
|
||||
|
||||
background-color: #f0f3f8;
|
||||
}
|
||||
|
||||
.block {
|
||||
height: 100vh;
|
||||
padding: 15rpx;
|
||||
|
||||
.carInfo {
|
||||
background-color: #fff;
|
||||
border-radius: 20rpx;
|
||||
|
||||
image {
|
||||
width: 730rpx;
|
||||
height: 365rpx;
|
||||
}
|
||||
|
||||
.carType {
|
||||
padding: 0 30rpx 30rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 35rpx;
|
||||
}
|
||||
|
||||
.title {
|
||||
color: #999999;
|
||||
margin-right: 25rpx;
|
||||
}
|
||||
|
||||
.plateNum {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 15rpx 30rpx;
|
||||
|
||||
.num {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.numItem {
|
||||
display: inline-block;
|
||||
margin-right: 10rpx;
|
||||
width: 60rpx;
|
||||
background-color: #f2f2f2;
|
||||
height: 70rpx;
|
||||
line-height: 50rpx;
|
||||
text-align: center;
|
||||
padding: 13rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.isDefault {
|
||||
padding: 0 25rpx 30rpx 15rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.delCar {
|
||||
margin-top: 25rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: #797979;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
.uv-button {
|
||||
margin-top: 40rpx;
|
||||
width: 720rpx !important;
|
||||
height: 110rpx !important;
|
||||
|
||||
.uv-button__text {
|
||||
font-size: 35rpx !important;
|
||||
}
|
||||
}
|
||||
|
||||
.goBack {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: #797979;
|
||||
font-size: 40rpx;
|
||||
margin: 30rpx auto;
|
||||
}
|
||||
|
||||
.popup-content {
|
||||
padding: 35rpx 35rpx 450rpx;
|
||||
position: relative;
|
||||
|
||||
.label {
|
||||
font-size: 22rpx;
|
||||
color: #797979;
|
||||
}
|
||||
|
||||
.btn {
|
||||
color: #1890ff;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 50rpx;
|
||||
}
|
||||
|
||||
.num {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.text-block {
|
||||
display: inline-block;
|
||||
margin-right: 10rpx;
|
||||
width: 60rpx;
|
||||
background-color: #f2f2f2;
|
||||
height: 70rpx;
|
||||
line-height: 80rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.uv-popup {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
|
||||
.uv-popup__content {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,242 @@
|
||||
<template>
|
||||
<s-layout title="我的车辆" navbar="normal" onShareAppMessage>
|
||||
<view class="block">
|
||||
<uv-loading-icon text="加载中" v-if="isShowPageLoading"></uv-loading-icon>
|
||||
<scroll-view scroll-y="true" v-else class="scroll">
|
||||
<view class="noCar" v-if="isShowNoCar">
|
||||
<text class="title">您还没有添加车辆</text>
|
||||
<text class="tip">添加车辆可以获得更贴心的服务</text>
|
||||
<image src="https://kxcharge.oss-cn-beijing.aliyuncs.com/mini/car-default.png" mode="aspectFit"></image>
|
||||
<uv-button type="primary" text="添加车辆" shape="circle" @click="goToAddCar"></uv-button>
|
||||
</view>
|
||||
<view v-else>
|
||||
<view class="scrollItem" v-for="(item,index) in carList" :key="item.id" @click="goToInfo(item)">
|
||||
<text class="plateNum">{{item.plateNumber}}</text>
|
||||
<view class="info">
|
||||
<image src="https://kxcharge.oss-cn-beijing.aliyuncs.com/car-icon.png" mode="aspectFit"></image>
|
||||
<view class="detail">
|
||||
<view class="item"><text class="title">汽车类型:</text>{{item.CarType}}</view>
|
||||
<view class="item"><text class="title">上次充电地点:</text>{{item.latelyPlace || ''}}</view>
|
||||
<view class="item"><text class="title">上次充电时间:</text>{{item.LatelyTime || ''}}</view>
|
||||
<view class="item"><text class="title">充电次数:</text>{{item.chargeQuantity}}</view>
|
||||
<view class="item"><text class="title">创建时间:</text>{{formatTime(item.createTime)}}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="default" v-if="item.isDefault">
|
||||
默认车辆
|
||||
</view>
|
||||
<view class="default" v-else style="background-color: #1890ff;" @click.stop="setDefault(item.id)">
|
||||
设为默认
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<uv-button type="primary" text="添加车辆" shape="circle" @click="goToAddCar"></uv-button>
|
||||
<uv-modal ref="modal" content='是否设置该车辆为默认车辆' title='提示' :showCancelButton="true" class="modal"
|
||||
@cancel="showModal = false" @confirm="submitDefault"></uv-modal>
|
||||
</view>
|
||||
|
||||
</scroll-view>
|
||||
</view>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from "dayjs";
|
||||
import {
|
||||
getMyCar,
|
||||
setDefaultCar
|
||||
} from "@/sheep/api/charge/member";
|
||||
let connectorCode = null
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
carList: [],
|
||||
isShowNoCar: true,
|
||||
showModal: false,
|
||||
carTypeMap: new Map([
|
||||
[1, '新能源汽车']
|
||||
]),
|
||||
activeId: '',
|
||||
isShowPageLoading: true
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
formatTime(ts) {
|
||||
return moment(ts).format("YYYY-MM-DD HH:mm");
|
||||
},
|
||||
getCarList() {
|
||||
this.isShowPageLoading = true;
|
||||
getMyCar().then(res => {
|
||||
const {
|
||||
data
|
||||
} = res;
|
||||
this.isShowNoCar = data.length === 0;
|
||||
if (!this.isShowNoCar) {
|
||||
data.forEach(item => {
|
||||
item['CarType'] = this.carTypeMap.get(item.plateType);
|
||||
item['LatelyTime'] = item.latelyTime ? moment(item.latelyTime).format("YYYY-MM-DD HH:mm:ss") :
|
||||
'';
|
||||
this.carList.push(item);
|
||||
})
|
||||
|
||||
}
|
||||
}).finally(() => {
|
||||
this.isShowPageLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
goToInfo(data) {
|
||||
if (connectorCode) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/equipment-detail/index?carInfo=${JSON.stringify(data)}&connectorCode=${connectorCode}`
|
||||
})
|
||||
} else {
|
||||
uni.navigateTo({
|
||||
url: `/pages/my-car/add-my-car/add-my-car?carInfo=${JSON.stringify(data)}`
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
goToAddCar() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/my-car/add-my-car/add-my-car'
|
||||
})
|
||||
},
|
||||
|
||||
setDefault(id) {
|
||||
this.activeId = id;
|
||||
this.$refs.modal.open();
|
||||
},
|
||||
submitDefault() {
|
||||
try {
|
||||
setDefaultCar(this.activeId, 0).then(res => {
|
||||
this.carList = [];
|
||||
this.getCarList();
|
||||
this.$refs.modal.close();;
|
||||
uni.showToast({
|
||||
icon: 'success',
|
||||
title: '设置成功!'
|
||||
})
|
||||
}).catch(err => {
|
||||
uni.showToast({
|
||||
icon: 'fail',
|
||||
title: '设置失败!'
|
||||
})
|
||||
console.log('err: ', err);
|
||||
})
|
||||
} catch (e) {
|
||||
//TODO handle the exception
|
||||
uni.showToast({
|
||||
icon: 'fail',
|
||||
title: '设置失败!'
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
if (options.connectorCode) {
|
||||
connectorCode = options.connectorCode
|
||||
}
|
||||
},
|
||||
onShow() {
|
||||
this.carList = [];
|
||||
this.getCarList();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
page {
|
||||
background-color: #f0f3f8;
|
||||
}
|
||||
|
||||
.block {
|
||||
|
||||
// height: 100vh;
|
||||
// background-color: #f2f2f2;
|
||||
.noCar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
image {
|
||||
width: 650rpx;
|
||||
height: 650rpx;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 58rpx;
|
||||
margin: 180rpx 40rpx 15rpx;
|
||||
}
|
||||
|
||||
.tip {
|
||||
color: #a7a7a7;
|
||||
margin-left: 40rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.scroll {
|
||||
background-color: #fff;
|
||||
padding: 15rpx;
|
||||
}
|
||||
|
||||
.uv-button {
|
||||
margin-top: 50rpx;
|
||||
width: 375rpx !important;
|
||||
height: 95rpx !important;
|
||||
margin: 20rpx auto;
|
||||
|
||||
.uv-button__text {
|
||||
font-size: 35rpx !important;
|
||||
}
|
||||
}
|
||||
|
||||
.scrollItem {
|
||||
background-color: #fff;
|
||||
margin: 35rpx 15rpx 0;
|
||||
position: relative;
|
||||
padding: 30rpx 20rpx 0;
|
||||
border-radius: 20rpx;
|
||||
|
||||
.plateNum {
|
||||
font-size: 35rpx;
|
||||
display: inline-block;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
font-size: 25rpx;
|
||||
|
||||
image {
|
||||
width: 220rpx;
|
||||
height: 220rpx;
|
||||
margin-right: 30rpx;
|
||||
}
|
||||
|
||||
.item {
|
||||
margin-bottom: 25rpx;
|
||||
}
|
||||
|
||||
.title {
|
||||
width: 160rpx;
|
||||
display: inline-block;
|
||||
text-align: right;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.default {
|
||||
position: absolute;
|
||||
top: 20rpx;
|
||||
right: 0rpx;
|
||||
color: #fff;
|
||||
background-color: #61ec0b;
|
||||
border-top-left-radius: 25rpx;
|
||||
border-bottom-left-radius: 25rpx;
|
||||
padding: 8rpx 15rpx;
|
||||
font-size: 25rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,346 @@
|
||||
<template>
|
||||
<s-layout title="我的" navbar="normal" tabbar="pages/my/index" onShareAppMessage>
|
||||
<view class="container">
|
||||
<view class="info flex justify-around align-center">
|
||||
<view class="avatar flex">
|
||||
<view class="image">
|
||||
<image :src="userStore?.userInfo?.avatar || 'https://kxcharge.oss-cn-beijing.aliyuncs.com/default-avatar.png'"
|
||||
style="width:100%;height:100%;" mode="aspectFill">
|
||||
</image>
|
||||
</view>
|
||||
<view class="name flex flex-column justify-center">
|
||||
<view>
|
||||
<text>
|
||||
{{ userStore? userStore.userInfo.nickname : '未登录' }}
|
||||
</text>
|
||||
<image v-if="userStore?.userInfo?.level" src="https://kxcharge.oss-cn-beijing.aliyuncs.com/16491.png"
|
||||
style="width:100%;height:100%;"></image>
|
||||
</view>
|
||||
<view class="level">
|
||||
{{ userStore ? 'KC充电用户' : '请先登录' }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="check">
|
||||
</view>
|
||||
</view>
|
||||
<view class="account flex justify-around">
|
||||
<view class="item flex align-center" @click="toPage('/pages/pay/recharge')">
|
||||
<view class="title">
|
||||
账户余额
|
||||
</view>
|
||||
<view class="value">
|
||||
{{ userStore ? (userStore.userWallet.balance / 100).toFixed(2) : 0 }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="item flex align-center" @click="toPage('/pages/user/wallet/score')">
|
||||
<view class="title">
|
||||
积分
|
||||
</view>
|
||||
<view class="value">
|
||||
{{ userStore ? userStore.userInfo.point : 0 }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="banner">
|
||||
<image src="https://kxcharge.oss-cn-beijing.aliyuncs.com/16490.png" mode="aspectFill" style="width:100%;height:100%;"></image>
|
||||
</view>
|
||||
|
||||
<uni-card padding="40rpx 20rpx" margin="8rpx" spacing="20rpx">
|
||||
<template v-slot:title>
|
||||
<uni-row>
|
||||
<uni-col :span="5">
|
||||
<view class="text-bold">我的爱车</view>
|
||||
</uni-col>
|
||||
<uni-col :span="5" :push="14">
|
||||
<view @click="toPage('/pages/my-car/my-car')">全部车辆></view>
|
||||
</uni-col>
|
||||
</uni-row>
|
||||
</template>
|
||||
<view class="flex align-center" @click="toPage('/pages/my-car/add-my-car/add-my-car')">
|
||||
<image v-if="userStore?.userInfo?.plateNumber" src="https://kxcharge.oss-cn-beijing.aliyuncs.com/16580.png"
|
||||
style="width:60rpx;height:60rpx;margin-right: 10rpx;"></image>
|
||||
<image v-else src="https://kxcharge.oss-cn-beijing.aliyuncs.com/27672.png" style="width:28rpx;height:28rpx;margin-right: 10rpx;">
|
||||
</image>
|
||||
<text v-if="userStore?.userInfo?.plateNumber">{{ userStore ? userStore.userInfo.plateNumber : 0 }}</text>
|
||||
<text v-else>添加我的爱车</text>
|
||||
</view>
|
||||
<view slot="actions" class="flex justify-around card-actions">
|
||||
<view class="flex align-center">
|
||||
<uni-icons type="heart" size="18" color="#999"></uni-icons>
|
||||
<text>停车减免</text>
|
||||
</view>
|
||||
<view class="flex align-center">
|
||||
<uni-icons type="heart" size="18" color="#999"></uni-icons>
|
||||
<text>充电安全</text>
|
||||
</view>
|
||||
<view class="flex align-center">
|
||||
<uni-icons type="heart" size="18" color="#999"></uni-icons>
|
||||
<text>精准推荐</text>
|
||||
</view>
|
||||
</view>
|
||||
</uni-card>
|
||||
|
||||
<view class="service">
|
||||
<view class="more-header">
|
||||
更多服务
|
||||
</view>
|
||||
|
||||
<uni-grid :column="4" :highlight="true" :show-border="false" :square="false">
|
||||
<uni-grid-item v-for="(item, index) in menus" :index="index" :key="index">
|
||||
<view class="grid-item-box" @click="toPage(item.path)">
|
||||
<image :src="item.icon" mode="aspectFit" class="img"></image>
|
||||
<text class="text">{{item.text}}</text>
|
||||
</view>
|
||||
</uni-grid-item>
|
||||
</uni-grid>
|
||||
</view>
|
||||
</view>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
showAuthModal
|
||||
} from '@/sheep/hooks/useModal';
|
||||
import * as UserApi from '@/sheep/api/charge/member';
|
||||
|
||||
const userStore = computed(() => {
|
||||
return sheep.$store('user').$state;
|
||||
});
|
||||
// // 获取最新的用户数据
|
||||
// const getUserData = async () => {
|
||||
// try {
|
||||
// const {
|
||||
// data
|
||||
// } = await UserApi.getUserInfo();
|
||||
// if (data) {
|
||||
// userStore.userInfo = data;
|
||||
// console.log('获取到新的用户数据:', data);
|
||||
// }
|
||||
// } catch (error) {
|
||||
// console.error('获取用户信息失败:', error);
|
||||
// }
|
||||
// };
|
||||
|
||||
// 检查登录状态
|
||||
const checkLoginStatus = () => {
|
||||
const token = uni.getStorageSync('token');
|
||||
if (!token) {
|
||||
showAuthModal();
|
||||
return;
|
||||
}
|
||||
|
||||
const cachedUserStore = uni.getStorageSync('user-store');
|
||||
if (cachedUserStore) {
|
||||
try {
|
||||
const parsedUserStore = JSON.parse(cachedUserStore);
|
||||
if (parsedUserStore.isLogin) {
|
||||
userStore.value = parsedUserStore;
|
||||
// getUserData();
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('解析用户信息失败:', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// // 组件挂载时检查登录状态
|
||||
// onMounted(() => {
|
||||
// checkLoginStatus();
|
||||
// });
|
||||
|
||||
// 添加页面显示时的处理
|
||||
onShow(() => {
|
||||
checkLoginStatus();
|
||||
sheep.$store('user').getInfo()
|
||||
sheep.$store('user').getWallet()
|
||||
});
|
||||
|
||||
const menus = [{
|
||||
icon: 'https://kxcharge.oss-cn-beijing.aliyuncs.com/16582.png',
|
||||
text: '账单',
|
||||
path: '/pages/user/wallet/money'
|
||||
}, {
|
||||
icon: 'https://kxcharge.oss-cn-beijing.aliyuncs.com/16588.png',
|
||||
text: '订单',
|
||||
path: '/pages/order/index'
|
||||
}, {
|
||||
icon: 'https://kxcharge.oss-cn-beijing.aliyuncs.com/16585.png',
|
||||
text: '联系客服'
|
||||
}, {
|
||||
icon: 'https://kxcharge.oss-cn-beijing.aliyuncs.com/16587.png',
|
||||
text: '设置',
|
||||
path: '/pages/public/setting'
|
||||
}]
|
||||
|
||||
onLaunch(() => {
|
||||
// 隐藏原生导航栏 使用自定义底部导航
|
||||
uni.hideTabBar();
|
||||
});
|
||||
|
||||
const toLogin = () => {
|
||||
const token = uni.getStorageSync('token');
|
||||
if (!token) {
|
||||
showAuthModal();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const toPage = (url) => {
|
||||
uni.navigateTo({
|
||||
url
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.card-actions {
|
||||
border-top: 2rpx solid #eee;
|
||||
padding-top: 10rpx;
|
||||
}
|
||||
|
||||
text {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.container {
|
||||
background: url('https://kxcharge.oss-cn-beijing.aliyuncs.com/1.png') 0 0/100% 424rpx no-repeat, #f5f9ff;
|
||||
padding-top: 28rpx;
|
||||
height: 100%;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
.image {
|
||||
width: 114rpx;
|
||||
height: 114rpx;
|
||||
border-radius: 50%;
|
||||
border: 8rpx solid #FFFFFF;
|
||||
margin-right: 28rpx;
|
||||
overflow: hidden;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.name {
|
||||
font-weight: 800;
|
||||
font-size: 30rpx;
|
||||
color: #323551;
|
||||
|
||||
image {
|
||||
width: 60rpx;
|
||||
height: 38rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.level {
|
||||
margin-top: 26rpx;
|
||||
font-size: 24rpx;
|
||||
color: #666666;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.check {
|
||||
width: 130rpx;
|
||||
height: 52rpx;
|
||||
}
|
||||
|
||||
.account {
|
||||
padding: 36rpx 50rpx;
|
||||
|
||||
.title {
|
||||
font-size: 24rpx;
|
||||
color: #000000;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-weight: bold;
|
||||
font-size: 32rpx;
|
||||
color: #000000;
|
||||
}
|
||||
}
|
||||
|
||||
.banner {
|
||||
margin: 0 auto;
|
||||
width: 690rpx;
|
||||
height: 138rpx;
|
||||
}
|
||||
|
||||
.service {
|
||||
// background: url('https://kxcharge.oss-cn-beijing.aliyuncs.com/6043.png') 0 0/100% 100% no-repeat;
|
||||
background: #fff;
|
||||
border-radius: 40rpx;
|
||||
padding: 50rpx 40rpx;
|
||||
}
|
||||
|
||||
.item-container {
|
||||
.item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 82rpx;
|
||||
height: 82rpx;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 26rpx;
|
||||
color: #333333;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.car-info {
|
||||
background: #F5F6FA;
|
||||
border-radius: 20rpx;
|
||||
font-size: 30rpx;
|
||||
padding: 30rpx;
|
||||
margin: 30rpx 0;
|
||||
|
||||
.left {
|
||||
color: #323551;
|
||||
}
|
||||
|
||||
.right {
|
||||
color: #337BFB;
|
||||
}
|
||||
}
|
||||
|
||||
.more-header {
|
||||
display: inline-block;
|
||||
font-weight: 800;
|
||||
font-size: 36rpx;
|
||||
color: #333;
|
||||
background: url('https://kxcharge.oss-cn-beijing.aliyuncs.com/5946@2x.png') 0 bottom/100% 12rpx no-repeat
|
||||
}
|
||||
|
||||
.grid-item-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.text {
|
||||
font-size: 26rpx;
|
||||
color: #333333;
|
||||
margin-top: 12rpx;
|
||||
}
|
||||
|
||||
.img {
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
margin-top: 30rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,541 @@
|
||||
<template>
|
||||
<s-layout title="订单详情" navbar="normal" onShareAppMessage>
|
||||
<view class="block">
|
||||
<uv-loading-page :loading="isShowLoading"></uv-loading-page>
|
||||
<scroll-view scroll-y="true" class="chargeInfo" style="height: 90vh;">
|
||||
<view class="bg">
|
||||
<!-- <image src="/static/image/personal/bg-user.png" mode="widthFix"></image> -->
|
||||
<text class="tip">感谢您的光临!</text>
|
||||
</view>
|
||||
<view class="stationInfo">
|
||||
<view class="stationName">
|
||||
<text class="name">{{ orderInfo.stationName }}</text>
|
||||
<view class="map" @click="toMap()">
|
||||
<image src="https://kxcharge.oss-cn-beijing.aliyuncs.com/nav.png" mode="aspectFit"></image>
|
||||
导航
|
||||
</view>
|
||||
</view>
|
||||
<view class="address">
|
||||
{{orderInfo.address || ''}}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="orderInfo">
|
||||
<view class="orderCode" style="margin-bottom: 20rpx;display: flex;align-items: center;">
|
||||
<text class="label">订单编号:</text>
|
||||
<text class="seq" style="color: #000;">{{orderInfo.StartChargeSeq}}</text>
|
||||
<text v-if="orderInfo.discountType == 2"
|
||||
style="width: 60rpx;border:1px solid #ddd; padding: 10rpx; margin-left: 10px;border-radius: 5px; color: #f4ea2a;font-style: italic;text-align: center;">SVIP</text>
|
||||
<text v-if="orderInfo.discountType == 1"
|
||||
style="width: 60rpx;border:1px solid #ddd; padding: 10rpx; margin-left: 10px;border-radius: 5px; color: #f4ea2a;font-style: italic;text-align: center;">VIP</text>
|
||||
</view>
|
||||
<view class="chargeTime" style="margin-bottom: 20rpx;">
|
||||
<text>订单状态:</text>
|
||||
<text>{{ orderInfo.status || '未知' }}</text>
|
||||
</view>
|
||||
<view class="chargeTime" style="margin-bottom: 20rpx;">
|
||||
<text>车牌号:</text>
|
||||
<text>{{ orderInfo.carNumber || '未绑定车牌号' }}</text>
|
||||
</view>
|
||||
<view class="chargeTime" style="margin-bottom: 20rpx;">
|
||||
<text>充电桩度数:</text>
|
||||
<text>{{ fixedNum(orderInfo.chargedPower,2)}}度</text>
|
||||
</view>
|
||||
<view class="chargeTime" style="margin-bottom: 20rpx;">
|
||||
<text>充电时间:</text>
|
||||
<text>{{ timePip(orderInfo.startTime,'YYYY-MM-DD HH:mm')}}至{{ timePip(orderInfo.endTime,'HH:mm')}}</text>
|
||||
</view>
|
||||
<view class="orderMoney" style="margin-bottom: 20rpx;">
|
||||
<view class="total">
|
||||
<view class="money">
|
||||
<text>订单费用</text>
|
||||
<text style="color: #000;">¥{{ fixedNum(orderInfo.allAmount,2)}}</text>
|
||||
</view>
|
||||
<view class="isExpand" @click="isExpand = !isExpand" style="display: flex; align-items: center;">
|
||||
{{ isExpand ? '收起' : '展开'}}
|
||||
<uv-icon :name="isExpand ? 'arrow-up' : 'arrow-down'"></uv-icon>
|
||||
</view>
|
||||
</view>
|
||||
<view class="table" style="margin-top: 20rpx; border-bottom: 1rpx solid #e2e2e2;">
|
||||
<view v-if="isExpand">
|
||||
<view style="display: flex;color: #000; width: 100%; height: 80rpx;">
|
||||
<view style="width: 20%; text-align: center;">开始时段</view>
|
||||
<view style="width: 20%; text-align: center;">结束时段</view>
|
||||
<view style="width: 20%; text-align: center;">电费</view>
|
||||
<view style="width: 20%; text-align: center;">服务费</view>
|
||||
<view style="width: 20%; text-align: center;">总费用</view>
|
||||
</view>
|
||||
<view v-for="(item, index) in orderInfo.orderDetailsRespVOList" :key="index"
|
||||
style="display: flex;color: #000; width: 100%; height: 80rpx;">
|
||||
<view style="width: 20%; text-align: center;">{{ timePip(Number(item.startTime),'HH:mm') }}</view>
|
||||
<view style="width: 20%; text-align: center;">
|
||||
{{ timePip(Number(item.endTime),'HH:mm') }}
|
||||
</view>
|
||||
<view style="width: 20%; text-align: center;">{{ fixedNum(item.chargedPrice,2) }}</view>
|
||||
<view style="width: 20%; text-align: center;">{{ fixedNum(item.servicePrice,2) }}</view>
|
||||
<view style="width: 20%; text-align: center;">
|
||||
{{ fixedNum((item.chargedPrice + item.servicePrice),2) }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="preferential">
|
||||
|
||||
<view class="item">
|
||||
<text class="label">折扣优惠</text>
|
||||
<text class="val">-¥{{ fixedNum(orderInfo.serviceDiscountAmount,2) }}</text>
|
||||
</view>
|
||||
<view class="item">
|
||||
<text class="label">优惠券</text>
|
||||
<text class="val">-¥{{ fixedNum(orderInfo.couponPrice,2) }}</text>
|
||||
</view>
|
||||
<view class="item">
|
||||
<text class="label" style="font-weight: 600;">优惠减免合计</text>
|
||||
<text class="val"
|
||||
style="color: #f00;">-¥{{ fixedNum((orderInfo.serviceDiscountAmount + orderInfo.couponPrice),2) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="actualMoney">
|
||||
实付<text style="color: #000; font-weight: 600;">-¥{{ fixedNum(orderInfo.inPay,2) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
<view class="payment">
|
||||
<view class="item" style="margin-bottom: 20rpx;">
|
||||
<text class="label">支付时间:{{ timePip(orderInfo.payTime,'YYYY-MM-DD HH:mm') }}</text>
|
||||
</view>
|
||||
<view class="item" style="margin-bottom: 20rpx;">
|
||||
<text class="label">支付方式:<text style="color: #000;">{{paymentType(orderInfo.amountMethod)}}</text></text>
|
||||
</view>
|
||||
<view class="item" v-if="orderInfo.failReasonMsg">
|
||||
<text class="label">充电结束原因:{{orderInfo.failReasonMsg || ''}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="code" v-if="stationInfo.codeImage">
|
||||
<uv-image :showLoading="true" :src="stationInfo.codeImage" width="100px" height="100px"
|
||||
:showMenuByLongpress="true"></uv-image>
|
||||
<text class="tips"> 长按识别图片,请添加会员群。</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
|
||||
<kx-tabbar-wrapper v-slot:kxTabBar>
|
||||
<view class="tab-bar" @click="toPay" v-if="orderInfo.pay === 0 && orderInfo.startChargeSeqStat === 4">
|
||||
主动结算
|
||||
</view>
|
||||
<view class="tab-bar" @click="goToStation" v-else>
|
||||
继续充电
|
||||
</view>
|
||||
</kx-tabbar-wrapper>
|
||||
|
||||
<uv-modal :show="showModal" content='是否结算该订单?' title='提示' :showCancelButton="true" class="modal"
|
||||
@cancel="showModal = false" @confirm="submitPay"></uv-modal>
|
||||
|
||||
</view>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from "dayjs";
|
||||
import {
|
||||
convertSecondsToTime,
|
||||
Tips
|
||||
} from "@/sheep/util/utils";
|
||||
import {
|
||||
getOrderInfo,
|
||||
proactiveBilling
|
||||
} from "@/sheep/api/charge/order"
|
||||
import {
|
||||
getDictData,
|
||||
getDictDataAlone
|
||||
} from "@/sheep/api/charge/system";
|
||||
import {
|
||||
getStationDetail
|
||||
} from "@/sheep/api/charge/operations";
|
||||
|
||||
const PayTypeMap = new Map([
|
||||
[1, '先充后付支付'],
|
||||
[2, '预充值支付'],
|
||||
[3, '余额支付']
|
||||
])
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
id: '',
|
||||
orderInfo: {},
|
||||
statusMap: new Map([
|
||||
[1, '启动中'],
|
||||
[2, '进行中'],
|
||||
[3, '停止中'],
|
||||
[4, '已完成'],
|
||||
[5, '未知'],
|
||||
]),
|
||||
orderStopReason: new Map(),
|
||||
isShowLoading: true,
|
||||
showOverlay: false,
|
||||
isExpand: false,
|
||||
showModal: false,
|
||||
isPop: false,
|
||||
seconds: 15,
|
||||
time: 0,
|
||||
stationInfo: {
|
||||
codeImage: ''
|
||||
}
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
toPay() {
|
||||
this.showModal = true;
|
||||
},
|
||||
paymentType(type) {
|
||||
return PayTypeMap.get(type) || '余额支付';
|
||||
},
|
||||
|
||||
submitPay() {
|
||||
proactiveBilling(this.orderInfo.id).then(res => {
|
||||
this.showModal = false;
|
||||
if (res.statusCode === 200) {
|
||||
Tips({
|
||||
title: '结算成功!',
|
||||
icon: 'success'
|
||||
})
|
||||
uni.navigateBack();
|
||||
} else {
|
||||
Tips({
|
||||
title: res.data.detail,
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}).catch(err => {
|
||||
Tips({
|
||||
title: err.error.detail,
|
||||
icon: 'none'
|
||||
})
|
||||
this.showModal = false;
|
||||
})
|
||||
},
|
||||
|
||||
// 首页
|
||||
goToStation() {
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/index'
|
||||
})
|
||||
|
||||
},
|
||||
|
||||
closePop() {
|
||||
clearInterval(this.time);
|
||||
this.isPop = false;
|
||||
},
|
||||
|
||||
// goToShare() {
|
||||
// uni.reLaunch({
|
||||
// url: '/pages/invite-code/q-code/q-code'
|
||||
// })
|
||||
// },
|
||||
|
||||
// 获取订单详情
|
||||
async getOrderInfo() {
|
||||
this.isShowLoading = true;
|
||||
try {
|
||||
const {
|
||||
data
|
||||
} = await getOrderInfo(this.id);
|
||||
this.orderInfo = data;
|
||||
this.$set(this.orderInfo, 'status', this.statusMap.get(this.orderInfo.orderStatus));
|
||||
this.$set(this.orderInfo, 'StartChargeSeq', this.orderInfo.seqNumber?.substring(9));
|
||||
this.$set(this.orderInfo, 'failReasonMsg', this.orderStopReason.get(String(this.orderInfo.stopReason)));
|
||||
this.isShowLoading = false;
|
||||
const {
|
||||
data: res
|
||||
} = await getStationDetail({
|
||||
id: data.stationId,
|
||||
longitude: 0,
|
||||
latitude: 0
|
||||
});
|
||||
this.stationInfo = res;
|
||||
this.$set(this.stationInfo, 'codeImage', JSON.parse(res.codeUrl || '[]')?.[0]);
|
||||
console.log('res: ', res);
|
||||
} catch (e) {
|
||||
console.log('e: ', e);
|
||||
//TODO handle the exception
|
||||
}
|
||||
|
||||
},
|
||||
// 导航
|
||||
toMap() {
|
||||
uni.openLocation({
|
||||
latitude: this.orderInfo.stationLat,
|
||||
longitude: this.orderInfo.stationLng,
|
||||
name: this.orderInfo.stationName,
|
||||
address: this.orderInfo.address
|
||||
});
|
||||
},
|
||||
|
||||
async getChargeStopMsg() {
|
||||
try {
|
||||
const {
|
||||
data
|
||||
} = await getDictDataAlone('stop_charge_type');
|
||||
data.forEach(item => {
|
||||
this.orderStopReason.set(item.value, item.label)
|
||||
})
|
||||
} catch (e) {
|
||||
console.log('e: ', e);
|
||||
//TODO handle the exception
|
||||
}
|
||||
},
|
||||
timePip(val, format) {
|
||||
if (!val) {
|
||||
return '';
|
||||
}
|
||||
return moment(val).format(format);
|
||||
},
|
||||
fixedNum(num, fix) {
|
||||
if (!num) {
|
||||
return '0.00'
|
||||
}
|
||||
return Number(num).toFixed(fix)
|
||||
},
|
||||
formatData(item) {
|
||||
item['status'] = this.statusMap.get(item.orderStatus);
|
||||
item['StartTime'] = moment(item.startTime).format("YYYY-MM-DD HH:mm:ss");
|
||||
return item;
|
||||
}
|
||||
},
|
||||
async onLoad(option) {
|
||||
this.id = option.id;
|
||||
await this.getChargeStopMsg();
|
||||
this.getOrderInfo();
|
||||
this.isPop = option.isPop || false;
|
||||
if (this.isPop) {
|
||||
this.time = setInterval(() => {
|
||||
if (this.seconds < 1) {
|
||||
this.isPop = false;
|
||||
clearInterval(this.time);
|
||||
} else {
|
||||
this.seconds -= 1
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.tab-bar {
|
||||
background: linear-gradient(132deg, #4A8EFC 0%, #50C3FD 100%);
|
||||
border-radius: 45rpx;
|
||||
font-weight: bold;
|
||||
font-size: 30rpx;
|
||||
color: #FFF;
|
||||
text-align: center;
|
||||
padding: 24rpx 0;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
page {
|
||||
// background-color: rgb(191, 248, 250);
|
||||
// background-image: url(/static/images/bg-user.jpg);
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.block {
|
||||
height: 100vh;
|
||||
background: url('https://kxcharge.oss-cn-beijing.aliyuncs.com/mini/box.png') 0 0/100% 812rpx no-repeat;
|
||||
|
||||
// background-color: #f2f2f2;
|
||||
// padding-bottom: 130rpx;
|
||||
.chargeInfo {
|
||||
.bg {
|
||||
// image {
|
||||
// width: 100%;
|
||||
// height: 100%;
|
||||
// position: absolute;
|
||||
// top: 0;
|
||||
// left: 0;
|
||||
// }
|
||||
width: 100%;
|
||||
position: relative;
|
||||
height: 17vh;
|
||||
width: 750rpx;
|
||||
// background: linear-gradient(
|
||||
// 180deg,#3c9cff 5%,#ebebeb 40%);
|
||||
|
||||
.tip {
|
||||
position: absolute;
|
||||
bottom: 8vh;
|
||||
left: 50rpx;
|
||||
font-size: 38rpx;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.stationInfo {
|
||||
width: 650rpx;
|
||||
padding: 25rpx;
|
||||
margin: auto;
|
||||
background-color: #fff;
|
||||
border-radius: 12rpx;
|
||||
position: relative;
|
||||
box-shadow: 0rpx 0rpx 20rpx 5rpx #ccc;
|
||||
top: -50rpx;
|
||||
|
||||
.stationName {
|
||||
display: flex;
|
||||
font-size: 30rpx;
|
||||
justify-content: space-between;
|
||||
|
||||
.name {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.map {
|
||||
color: #229bff;
|
||||
|
||||
image {
|
||||
width: 25rpx;
|
||||
margin-right: 15rpx;
|
||||
height: 25rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.address {
|
||||
font-size: 25rpx;
|
||||
color: #aaa;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.orderInfo {
|
||||
width: 650rpx;
|
||||
padding: 25rpx;
|
||||
margin: -20rpx auto 0;
|
||||
|
||||
background-color: #fff;
|
||||
border-radius: 12rpx;
|
||||
box-shadow: 0rpx 0rpx 20rpx 5rpx #ccc;
|
||||
color: #aaa;
|
||||
font-size: 30rpx;
|
||||
|
||||
.total {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.preferential {
|
||||
margin-top: 20rpx;
|
||||
border-bottom: 1rpx solid #e2e2e2;
|
||||
color: #000;
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.actualMoney {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 25rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.payment {
|
||||
|
||||
.item {
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
padding: 30rpx 0;
|
||||
width: 750rpx;
|
||||
|
||||
.uv-button {
|
||||
margin: auto !important;
|
||||
width: 700rpx !important;
|
||||
border-radius: 50rpx !important;
|
||||
height: 103rpx !important;
|
||||
|
||||
.uv-button__text {
|
||||
font-size: 37.5rpx !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.uv-fade-enter-active {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.content {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
color: #229bff;
|
||||
|
||||
.header {
|
||||
position: absolute;
|
||||
z-index: 9999;
|
||||
right: 0;
|
||||
color: #fff !important;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 99%;
|
||||
padding: 10rpx 0;
|
||||
|
||||
.uv-icon__icon {
|
||||
color: #fff !important;
|
||||
}
|
||||
}
|
||||
|
||||
.uv-button {
|
||||
margin-top: 30rpx;
|
||||
border-radius: 50rpx;
|
||||
width: 270rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.code,
|
||||
.payment {
|
||||
width: 650rpx;
|
||||
padding: 25rpx;
|
||||
margin: auto;
|
||||
background-color: #fff;
|
||||
border-radius: 12rpx;
|
||||
box-shadow: 0rpx 0rpx 20rpx 5rpx #ccc;
|
||||
font-size: 30rpx;
|
||||
margin-top: 30rpx;
|
||||
}
|
||||
|
||||
.code {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
|
||||
.tips {
|
||||
display: inline-block;
|
||||
margin-left: 20rpx;
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,633 @@
|
||||
<template>
|
||||
<s-layout title="订单" navbar="normal" tabbar="pages/order/index" onShareAppMessage>
|
||||
<view class="block">
|
||||
<view class="tabs">
|
||||
<view class="item" v-for="(item,index) in tabList" :key="index" :class="{'activeItem': activeTab === item[0]}"
|
||||
@click="getTrottle(item)">
|
||||
<text class="label">{{item[1]}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<uv-loading-icon text="加载中" v-if="isShowPageLoading"></uv-loading-icon>
|
||||
<scroll-view scroll-y="true" v-else @scrolltolower="nextPage" style="height:60vh;" :refresher-enabled="true"
|
||||
:refresher-triggered="nowRefsh" @refresherrefresh="refresh">
|
||||
<template v-if="orderList.length > 0">
|
||||
<view class="orderItem" v-for="(item,index) in orderList" :key="item.id">
|
||||
<view class="top">
|
||||
<view class="code">
|
||||
<!-- <text class="subCode" >订单编号:{{item.StartChargeSeq}}</text> -->
|
||||
<uni-tooltip :content="'订单编号:' +item.StartChargeSeq" placement="top" style="width: 80%;">
|
||||
<uv-text class="subCode" :lines="1" :text="'订单编号:' +item.StartChargeSeq"
|
||||
style="font-size: 30rpx; font-weight: 600;"></uv-text>
|
||||
</uni-tooltip>
|
||||
<text style="display: inline-block; width: 15%;">{{item.status}}</text>
|
||||
</view>
|
||||
<view class="time">{{item.StartTime}}</view>
|
||||
</view>
|
||||
<view class="bottom">
|
||||
<view class="item">
|
||||
<text class="label">实付金额</text>
|
||||
<text class="val">{{fixedNum(item.inPay,2)}}</text>
|
||||
</view>
|
||||
<view class="item">
|
||||
<text class="label">站点名称</text>
|
||||
<text class="val">{{item.stationName || ''}}</text>
|
||||
</view>
|
||||
<view class="item">
|
||||
<text class="label">车牌号</text>
|
||||
<text class="val">{{item.plateNumber || '未绑定车牌号'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="opBtn">
|
||||
<view class="btn errorBtn" @click="toPay(item)" v-if="item.pay === 0 && item.startChargeSeqStat === 4"
|
||||
style="margin-right: 10rpx;">主动结算
|
||||
</view>
|
||||
<!-- <view class="btn" style="margin-right: 20rpx;" @click="goToTicket(item)">去开票</view> -->
|
||||
<view class="btn" style="margin-right: 20rpx;" @click="goToInfo(item)">查看详情</view>
|
||||
<view v-if="item.plateNumber == null" class="btn" style="background-color: #00b26a;" @click="open(item)">
|
||||
绑定车牌</view>
|
||||
</view>
|
||||
</view>
|
||||
<uv-loading-icon text="加载中" v-if="isShowLoading"></uv-loading-icon>
|
||||
<view class="loadTip" v-else>
|
||||
到底了...
|
||||
</view>
|
||||
<kx-tabbar-placeholder></kx-tabbar-placeholder>
|
||||
</template>
|
||||
|
||||
<view class="noData" v-else>
|
||||
<image src="https://kxcharge.oss-cn-beijing.aliyuncs.com/noData.png" mode="aspectFit"></image>
|
||||
<text class="label">暂无数据</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<uv-toast ref="uToast"></uv-toast>
|
||||
<uv-modal :show="showModal" content='是否结算该订单?' title='提示' :showCancelButton="true" class="modal"
|
||||
@cancel="showModal = false" @confirm="submitPay"></uv-modal>
|
||||
|
||||
<uv-popup :show="showPop" mode="bottom">
|
||||
<view class="btn">
|
||||
<text @click="showPop = false">取消</text>
|
||||
<picker @change="selectPlateNum($event)" :range="columns" range-key="label">
|
||||
<text @click="showPop = false;isSelectCar = true" style="color: #1890ff;">选择车辆</text>
|
||||
</picker>
|
||||
<text @click="submitPlate">确定</text>
|
||||
</view>
|
||||
<view>
|
||||
<text class="label">车牌号</text>
|
||||
<view class="num">
|
||||
<text class="block" v-for="(item,index) in popBlockArr" :key="index">{{item || ''}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<uv-keyboard :autoChange="true" ref="uKeyboard" mode="car" :show="true" :overlay="false"
|
||||
@change="clickKeyboard($event)" :tooltip="false" @backspace="backspace"></uv-keyboard>
|
||||
</uv-popup>
|
||||
|
||||
<uv-modal :show="showbindCarModal" :content='modalContent' title='提示' :showCancelButton="true" class="modal"
|
||||
@cancel="showbindCarModal = false" @confirm="saveCarPlate"></uv-modal>
|
||||
</view>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
proactiveBilling
|
||||
} from "@/sheep/api/charge/order";
|
||||
import {
|
||||
convertSecondsToTime,
|
||||
throttle,
|
||||
Tips
|
||||
} from "@/sheep/util/utils";
|
||||
import moment from "dayjs";
|
||||
import * as OrderApi from "@/sheep/api/charge/order";
|
||||
import * as UserApi from "@/sheep/api/charge/member";
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
tabMap: new Map([
|
||||
['all', '全部'],
|
||||
[2, '进行中'],
|
||||
[4, '已完成'],
|
||||
[5, '待处理'],
|
||||
]),
|
||||
statusMap: new Map([
|
||||
[1, '启动中'],
|
||||
[2, '进行中'],
|
||||
[3, '停止中'],
|
||||
[4, '已完成'],
|
||||
[5, '未知'],
|
||||
]),
|
||||
tabList: [],
|
||||
activeTab: 'all',
|
||||
time: 0,
|
||||
pagetion: {
|
||||
page: 1,
|
||||
pageSize: 10
|
||||
},
|
||||
orderList: [],
|
||||
time2: 0,
|
||||
isShowLoading: false,
|
||||
isShowPageLoading: true,
|
||||
time3: 0,
|
||||
nowRefsh: false,
|
||||
getTrottle: undefined,
|
||||
time4: 0,
|
||||
showModal: true,
|
||||
payOrderId: '',
|
||||
|
||||
orderId: null,
|
||||
showPop: false,
|
||||
popBlockArr: new Array(8),
|
||||
plateValue: '',
|
||||
isSelectCar: false,
|
||||
columns: [],
|
||||
plateNum: '未设置',
|
||||
showbindCarModal: false,
|
||||
modalContent: '',
|
||||
|
||||
totalData: {
|
||||
economizeMoney: 0,
|
||||
totalMoney: 0,
|
||||
totalPower: 0
|
||||
},
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getTrottle = throttle((data) => {
|
||||
this.active(data)
|
||||
}, 800)
|
||||
},
|
||||
methods: {
|
||||
fixedNum(num, fix) {
|
||||
if (!num) {
|
||||
return '0.00'
|
||||
}
|
||||
return Number(num).toFixed(fix)
|
||||
},
|
||||
clickKeyboard(event) {
|
||||
if (this.plateValue.length >= 8) {
|
||||
return;
|
||||
}
|
||||
this.plateValue += event;
|
||||
this.plateValue.split("").forEach((k, index) => {
|
||||
this.popBlockArr[index] = k;
|
||||
});
|
||||
},
|
||||
backspace() {
|
||||
this.popBlockArr = this.popBlockArr.map((item, index, arr) => {
|
||||
if (!arr[index + 1]) item = '';
|
||||
return item;
|
||||
});
|
||||
},
|
||||
selectPlateNum(e) {
|
||||
const {
|
||||
detail
|
||||
} = e;
|
||||
this.plateNum = this.columns[detail.value].label;
|
||||
|
||||
this.bindCarconfirm();
|
||||
},
|
||||
open(orderInfo) {
|
||||
this.showPop = true;
|
||||
this.orderId = orderInfo.id;
|
||||
console.log(this.orderId)
|
||||
},
|
||||
getCarList() {
|
||||
this.columns = []
|
||||
if (!sheep.$store('user').userInfo.token) return
|
||||
UserApi.getMyCar().then(res => {
|
||||
const {
|
||||
data
|
||||
} = res
|
||||
// if (statusCode === 200) {
|
||||
const find = data.find(item => item.isDefault);
|
||||
console.log('find', find)
|
||||
this.plateNum = this.initPlate ? this.initPlate : (find?.plateNumber || '未设置')
|
||||
data.forEach(item => {
|
||||
this.columns.push({
|
||||
label: item.plateNumber,
|
||||
id: item.id
|
||||
})
|
||||
})
|
||||
// }
|
||||
}).catch(err => {
|
||||
console.log('err: ', err);
|
||||
})
|
||||
},
|
||||
submitPlate() {
|
||||
if (!this.plateValue) {
|
||||
Tips({
|
||||
icon: 'none',
|
||||
title: '输入的车牌号是否为空'
|
||||
})
|
||||
return;
|
||||
}
|
||||
// const plateArr = this.plateValue.split("")
|
||||
if (this.plateValue.length !== 8 && this.plateValue.length !== 7) {
|
||||
Tips({
|
||||
icon: 'none',
|
||||
title: '输入的车牌号有误,请重新输入'
|
||||
})
|
||||
return;
|
||||
}
|
||||
this.showPop = false;
|
||||
this.bindCarconfirm();
|
||||
},
|
||||
bindCarconfirm() {
|
||||
let plate = this.isSelectCar ? this.plateNum : this.plateValue;
|
||||
this.modalContent = `是否为此订单绑定车牌【${plate}】?`;
|
||||
this.showbindCarModal = true;
|
||||
},
|
||||
saveCarPlate() {
|
||||
let plate = this.isSelectCar ? this.plateNum : this.plateValue;
|
||||
OrderApi.licensePlateBinding(this.orderId, plate).then(res => {
|
||||
this.orderId = null;
|
||||
this.popBlockArr = new Array(8);
|
||||
this.plateValue = '',
|
||||
this.isSelectCar = false;
|
||||
|
||||
this.showbindCarModal = false;
|
||||
Tips({
|
||||
icon: 'none',
|
||||
title: '绑定成功!'
|
||||
})
|
||||
this.refresh();
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
this.showbindCarModal = false;
|
||||
})
|
||||
},
|
||||
|
||||
active(data) {
|
||||
this.isShowPageLoading = true;
|
||||
this.activeTab = data[0];
|
||||
this.orderList = [];
|
||||
this.pagetion.page = 1;
|
||||
clearInterval(this.time4);
|
||||
|
||||
this.getData();
|
||||
if (this.activeTab === '2') {
|
||||
this.time4 = setInterval(() => {
|
||||
this.getData();
|
||||
}, 5000)
|
||||
}
|
||||
},
|
||||
toPay(data) {
|
||||
this.payOrderId = data.id;
|
||||
this.showModal = true;
|
||||
},
|
||||
|
||||
submitPay() {
|
||||
proactiveBilling(this.payOrderId).then(res => {
|
||||
if (res.statusCode === 200) {
|
||||
Tips({
|
||||
title: res.data.msg,
|
||||
icon: 'success'
|
||||
})
|
||||
this.orderList = [];
|
||||
this.getData();
|
||||
} else {
|
||||
Tips({
|
||||
title: res.data.detail,
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
this.showModal = false;
|
||||
}).catch(err => {
|
||||
Tips({
|
||||
title: err.error.detail,
|
||||
icon: 'none'
|
||||
})
|
||||
this.showModal = false;
|
||||
})
|
||||
},
|
||||
nextPage() {
|
||||
if (this.isShowLoading) {
|
||||
clearTimeout(this.time3);
|
||||
this.time3 = setTimeout(() => {
|
||||
this.pagetion.page += 1;
|
||||
this.getData();
|
||||
}, 2000)
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
refresh() {
|
||||
this.nowRefsh = true;
|
||||
this.pagetion.page = 1;
|
||||
this.getData();
|
||||
},
|
||||
|
||||
goToInfo(item) {
|
||||
if (item.status !== '进行中') {
|
||||
uni.navigateTo({
|
||||
url: `/pages/order-info/order-info?id=${item.seqNumber}`
|
||||
})
|
||||
} else {
|
||||
uni.navigateTo({
|
||||
url: `/pages/charging/index?seqNumber=${item.seqNumber}`
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
async getData() {
|
||||
try {
|
||||
const {
|
||||
data
|
||||
} = await OrderApi.getOrderList(this.pagetion, this.activeTab);
|
||||
if (data) {
|
||||
const {
|
||||
list,
|
||||
total
|
||||
} = data;
|
||||
if (this.nowRefsh || this.isShowPageLoading) {
|
||||
this.orderList = [];
|
||||
}
|
||||
this.isShowLoading = this.hasNext(total);
|
||||
if (this.activeTab === '2') {
|
||||
this.orderList = list?.map(item => this.formatData(item))
|
||||
} else {
|
||||
list?.forEach(item => {
|
||||
this.orderList.push(this.formatData(item));
|
||||
})
|
||||
}
|
||||
this.nowRefsh = false;
|
||||
this.isShowPageLoading = false;
|
||||
}
|
||||
const {
|
||||
data: result
|
||||
} = await OrderApi.getTotalOrder();
|
||||
result && (this.totalData = result);
|
||||
|
||||
} catch (e) {
|
||||
this.isShowPageLoading = false;
|
||||
this.$nextTick(() => {
|
||||
this.$refs.uToast.show({
|
||||
message: '数据异常,稍后重试',
|
||||
type: 'error',
|
||||
duration: '3000'
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
hasNext(total) {
|
||||
return this.pagetion.page * this.pagetion.pageSize < total
|
||||
},
|
||||
|
||||
formatData(item) {
|
||||
item['status'] = this.statusMap.get(item.orderStatus);
|
||||
item['StartTime'] = moment(item.startTime).format("YYYY-MM-DD HH:mm:ss");
|
||||
item['EndTime'] = item['endTime'] ? moment(item.endTime).format("YYYY-MM-DD HH:mm:ss") : '';
|
||||
item['StartChargeSeq'] = item['seqNumber'].substring(9);
|
||||
item['interval'] = item['endTime'] ? convertSecondsToTime(item.startTime, item.endTime) :
|
||||
convertSecondsToTime(item.startTime, +new Date());
|
||||
return item;
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
this.tabList = Array.from(this.tabMap);
|
||||
console.log(this.tabList)
|
||||
if (options.type) {
|
||||
this.activeTab = options.type
|
||||
}
|
||||
this.isShowPageLoading = true;
|
||||
|
||||
},
|
||||
onShow() {
|
||||
this.orderList = [];
|
||||
this.getData();
|
||||
this.getCarList();
|
||||
if (this.activeTab === '2') {
|
||||
this.time4 = setInterval(() => {
|
||||
this.getData();
|
||||
}, 5000)
|
||||
}
|
||||
},
|
||||
onHide() {
|
||||
clearTimeout(this.time);
|
||||
clearTimeout(this.time2);
|
||||
clearTimeout(this.time3);
|
||||
clearTimeout(this.time4);
|
||||
},
|
||||
beforeDestroy() {
|
||||
clearTimeout(this.time);
|
||||
clearTimeout(this.time2);
|
||||
clearTimeout(this.time3);
|
||||
clearTimeout(this.time4);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.block {
|
||||
background-color: #f5f9ff;
|
||||
|
||||
.header {
|
||||
width: 640rpx;
|
||||
margin: auto;
|
||||
padding: 30rpx;
|
||||
border-top-right-radius: 25rpx;
|
||||
border-top-left-radius: 25rpx;
|
||||
background: linear-gradient(45deg, #00c3ffa6, #0b91ff);
|
||||
font-size: 30rpx;
|
||||
color: #fffc;
|
||||
position: relative;
|
||||
|
||||
.saveMoney {
|
||||
color: #fff;
|
||||
margin: 20rpx 0;
|
||||
|
||||
.money {
|
||||
font-size: 45rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.saveInfo {
|
||||
display: flex;
|
||||
|
||||
.vlaueData {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.billInfo {
|
||||
position: absolute;
|
||||
right: 20rpx;
|
||||
top: 30rpx;
|
||||
font-size: 25rpx;
|
||||
border-radius: 25rpx;
|
||||
color: #fff;
|
||||
background-color: #a5d2f78c;
|
||||
}
|
||||
}
|
||||
|
||||
.tabs {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
// background-color: #fff;
|
||||
padding: 0 15rpx;
|
||||
|
||||
.item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
padding-top: 15rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
&::after {
|
||||
width: 25rpx;
|
||||
height: 5rpx;
|
||||
content: "";
|
||||
display: inline-block;
|
||||
margin-top: 15rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.activeItem {
|
||||
|
||||
.label {
|
||||
color: #229bff;
|
||||
}
|
||||
|
||||
&::after {
|
||||
background-color: #229bff;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.orderItem {
|
||||
padding: 25rpx;
|
||||
width: 650rpx;
|
||||
background-color: #fff;
|
||||
box-shadow: 0rpx 0rpx 8rpx 5rpx rgba(172, 172, 172, 0.3);
|
||||
margin: 30rpx auto;
|
||||
color: #aaaaaa;
|
||||
font-size: 30rpx;
|
||||
border-radius: 15rpx;
|
||||
|
||||
.top {
|
||||
border-bottom: 1rpx solid #e2e2e2;
|
||||
padding-bottom: 20rpx;
|
||||
color: #aaaaaa;
|
||||
|
||||
.code {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.uv-text__value {
|
||||
font-weight: 600 !important;
|
||||
font-size: 30rpx !important;
|
||||
color: #000 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bottom {
|
||||
.item {
|
||||
color: #aaaaaa;
|
||||
margin: 15rpx 0;
|
||||
|
||||
.label {
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.opBtn {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
.btn {
|
||||
color: #fff;
|
||||
padding: 15rpx 25rpx;
|
||||
border-radius: 50rpx;
|
||||
background-color: #229bff;
|
||||
}
|
||||
|
||||
.errorBtn {
|
||||
background-color: #f56c6c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.uv-loading-icon {
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
.loadTip {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 10rpx;
|
||||
color: #aaaaaa;
|
||||
}
|
||||
|
||||
.noData {
|
||||
position: relative;
|
||||
|
||||
image {
|
||||
width: 750rpx;
|
||||
height: 50vh;
|
||||
}
|
||||
|
||||
.label {
|
||||
color: #aaaaaa;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
width: 750rpx;
|
||||
top: 35vh;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.uv-slide-up-enter-active {
|
||||
|
||||
|
||||
.uv-popup__content {
|
||||
padding: 35rpx 35rpx 450rpx;
|
||||
position: relative;
|
||||
|
||||
.label {
|
||||
font-size: 22rpx;
|
||||
color: #797979;
|
||||
}
|
||||
|
||||
.btn {
|
||||
color: #1890ff;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 50rpx;
|
||||
}
|
||||
|
||||
.num {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.block {
|
||||
display: inline-block;
|
||||
margin-right: 10rpx;
|
||||
width: 46rpx;
|
||||
background-color: #f2f2f2;
|
||||
height: 50rpx;
|
||||
line-height: 50rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.uv-popup {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
|
||||
.uv-popup__content {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,310 @@
|
||||
<!-- 收银台 -->
|
||||
<template>
|
||||
<s-layout title="收银台">
|
||||
<view class="bg-white ss-modal-box ss-flex-col">
|
||||
<!-- 订单信息 -->
|
||||
<view class="modal-header ss-flex-col ss-col-center ss-row-center">
|
||||
<view class="money-box ss-m-b-20">
|
||||
<text class="money-text">{{ fen2yuan(state.orderInfo.price) }}</text>
|
||||
</view>
|
||||
<view class="time-text">
|
||||
<text>{{ payDescText }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 支付方式 -->
|
||||
<view class="modal-content ss-flex-1">
|
||||
<view class="pay-title ss-p-l-30 ss-m-y-30">选择支付方式</view>
|
||||
<radio-group @change="onTapPay">
|
||||
<label class="pay-type-item" v-for="item in state.payMethods" :key="item.title">
|
||||
<view
|
||||
class="pay-item ss-flex ss-col-center ss-row-between ss-p-x-30 border-bottom"
|
||||
:class="{ 'disabled-pay-item': item.disabled }"
|
||||
>
|
||||
<view class="ss-flex ss-col-center">
|
||||
<image
|
||||
class="pay-icon"
|
||||
v-if="item.disabled"
|
||||
:src="sheep.$url.static('/static/img/shop/pay/cod_disabled.png')"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
<image
|
||||
class="pay-icon"
|
||||
v-else
|
||||
:src="sheep.$url.static(item.icon)"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
<text class="pay-title">{{ item.title }}</text>
|
||||
</view>
|
||||
<view class="check-box ss-flex ss-col-center ss-p-l-10">
|
||||
<view class="userInfo-money ss-m-r-10" v-if="item.value === 'wallet'">
|
||||
余额: {{ fen2yuan(userWallet.balance) }}元
|
||||
</view>
|
||||
<radio
|
||||
:value="item.value"
|
||||
color="var(--ui-BG-Main)"
|
||||
style="transform: scale(0.8)"
|
||||
:disabled="item.disabled"
|
||||
:checked="state.payment === item.value"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</label>
|
||||
</radio-group>
|
||||
</view>
|
||||
|
||||
<!-- 工具 -->
|
||||
<view class="modal-footer ss-flex ss-row-center ss-col-center ss-m-t-80 ss-m-b-40">
|
||||
<button v-if="state.payStatus === 0" class="ss-reset-button past-due-btn">
|
||||
检测支付环境中
|
||||
</button>
|
||||
<button v-else-if="state.payStatus === -1" class="ss-reset-button past-due-btn" disabled>
|
||||
支付已过期
|
||||
</button>
|
||||
<button
|
||||
v-else
|
||||
class="ss-reset-button save-btn"
|
||||
@tap="onPay"
|
||||
:disabled="state.payStatus !== 1"
|
||||
:class="{ 'disabled-btn': state.payStatus !== 1 }"
|
||||
>
|
||||
立即支付
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</s-layout>
|
||||
</template>
|
||||
<script setup>
|
||||
import { computed, reactive } from 'vue';
|
||||
import { onLoad } from '@dcloudio/uni-app';
|
||||
import sheep from '@/sheep';
|
||||
import { fen2yuan, useDurationTime } from '@/sheep/hooks/useGoods';
|
||||
import PayOrderApi from '@/sheep/api/pay/order';
|
||||
import PayChannelApi from '@/sheep/api/pay/channel';
|
||||
import { getPayMethods, goPayResult } from '@/sheep/platform/pay';
|
||||
|
||||
const userWallet = computed(() => sheep.$store('user').userWallet);
|
||||
|
||||
// 检测支付环境
|
||||
const state = reactive({
|
||||
orderType: 'goods', // 订单类型; goods - 商品订单, recharge - 充值订单
|
||||
orderInfo: {}, // 支付单信息
|
||||
payStatus: 0, // 0=检测支付环境, -2=未查询到支付单信息, -1=支付已过期, 1=待支付,2=订单已支付
|
||||
payMethods: [], // 可选的支付方式
|
||||
payment: '', // 选中的支付方式
|
||||
connectorCode: '', // 枪号
|
||||
});
|
||||
|
||||
const onPay = () => {
|
||||
if (state.payment === '') {
|
||||
sheep.$helper.toast('请选择支付方式');
|
||||
return;
|
||||
}
|
||||
if (state.payment === 'wallet') {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '确定要支付吗?',
|
||||
success: function (res) {
|
||||
if (res.confirm) {
|
||||
sheep.$platform.pay(state.payment, state.orderType, state.orderInfo.id,state.connectorCode);
|
||||
}
|
||||
},
|
||||
});
|
||||
} else {
|
||||
sheep.$platform.pay(state.payment, state.orderType, state.orderInfo.id,state.connectorCode);
|
||||
}
|
||||
};
|
||||
|
||||
// 支付文案提示
|
||||
const payDescText = computed(() => {
|
||||
if (state.payStatus === 2) {
|
||||
return '该订单已支付';
|
||||
}
|
||||
if (state.payStatus === 1) {
|
||||
const time = useDurationTime(state.orderInfo.expireTime);
|
||||
if (time.ms <= 0) {
|
||||
state.payStatus = -1;
|
||||
return '';
|
||||
}
|
||||
return `剩余支付时间 ${time.h}:${time.m}:${time.s} `;
|
||||
}
|
||||
if (state.payStatus === -2) {
|
||||
return '未查询到支付单信息';
|
||||
}
|
||||
return '';
|
||||
});
|
||||
|
||||
// 状态转换:payOrder.status => payStatus
|
||||
function checkPayStatus() {
|
||||
if (state.orderInfo.status === 10 || state.orderInfo.status === 20) {
|
||||
// 支付成功
|
||||
state.payStatus = 2;
|
||||
// 跳转回支付成功页
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '订单已支付',
|
||||
showCancel: false,
|
||||
success: function () {
|
||||
goPayResult(state.orderInfo.id, state.orderType);
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (state.orderInfo.status === 30) {
|
||||
// 支付关闭
|
||||
state.payStatus = -1;
|
||||
return;
|
||||
}
|
||||
state.payStatus = 1; // 待支付
|
||||
}
|
||||
|
||||
// 切换支付方式
|
||||
function onTapPay(e) {
|
||||
state.payment = e.detail.value;
|
||||
}
|
||||
|
||||
// 设置支付订单信息
|
||||
async function setOrder(id) {
|
||||
// 获得支付订单信息
|
||||
const { data, code } = await PayOrderApi.getOrder(id, true);
|
||||
if (code !== 0 || !data) {
|
||||
state.payStatus = -2;
|
||||
return;
|
||||
}
|
||||
state.orderInfo = data;
|
||||
// 设置支付状态
|
||||
checkPayStatus();
|
||||
// 获得支付方式
|
||||
await setPayMethods();
|
||||
}
|
||||
|
||||
// 获得支付方式
|
||||
async function setPayMethods() {
|
||||
const { data, code } = await PayChannelApi.getEnableChannelCodeList(state.orderInfo.appId);
|
||||
if (code !== 0) {
|
||||
return;
|
||||
}
|
||||
state.payMethods = getPayMethods(data);
|
||||
state.payMethods.find((item) => {
|
||||
if (item.value && !item.disabled) {
|
||||
state.payment = item.value;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onLoad((options) => {
|
||||
if (
|
||||
sheep.$platform.name === 'WechatOfficialAccount' &&
|
||||
sheep.$platform.os === 'ios' &&
|
||||
!sheep.$platform.landingPage.includes('pages/pay/index')
|
||||
) {
|
||||
location.reload();
|
||||
return;
|
||||
}
|
||||
// 获得支付订单信息
|
||||
let id = options.id;
|
||||
if (options.orderType) {
|
||||
state.orderType = options.orderType;
|
||||
}
|
||||
// 枪号
|
||||
if (options.connectorCode) {
|
||||
state.connectorCode = options.connectorCode;
|
||||
}
|
||||
setOrder(id);
|
||||
// 刷新钱包的缓存
|
||||
sheep.$store('user').getWallet();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.pay-icon {
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
margin-right: 26rpx;
|
||||
}
|
||||
|
||||
.ss-modal-box {
|
||||
// max-height: 1000rpx;
|
||||
|
||||
.modal-header {
|
||||
position: relative;
|
||||
padding: 60rpx 20rpx 40rpx;
|
||||
|
||||
.money-text {
|
||||
color: $red;
|
||||
font-size: 46rpx;
|
||||
font-weight: bold;
|
||||
font-family: OPPOSANS;
|
||||
|
||||
&::before {
|
||||
content: '¥';
|
||||
font-size: 30rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.time-text {
|
||||
font-size: 26rpx;
|
||||
color: $gray-b;
|
||||
}
|
||||
|
||||
.close-icon {
|
||||
position: absolute;
|
||||
top: 10rpx;
|
||||
right: 20rpx;
|
||||
font-size: 46rpx;
|
||||
opacity: 0.2;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
overflow-y: auto;
|
||||
|
||||
.pay-title {
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.pay-tip {
|
||||
font-size: 26rpx;
|
||||
color: #bbbbbb;
|
||||
}
|
||||
|
||||
.pay-item {
|
||||
height: 86rpx;
|
||||
}
|
||||
.disabled-pay-item {
|
||||
.pay-title {
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
|
||||
.userInfo-money {
|
||||
font-size: 26rpx;
|
||||
color: #bbbbbb;
|
||||
line-height: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.save-btn {
|
||||
width: 710rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 40rpx;
|
||||
background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
|
||||
color: $white;
|
||||
}
|
||||
.disabled-btn {
|
||||
background: #e5e5e5;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.past-due-btn {
|
||||
width: 710rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 40rpx;
|
||||
background-color: #999;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,167 @@
|
||||
<!-- 充值记录 -->
|
||||
<template>
|
||||
<s-layout class="widthdraw-log-wrap" title="充值记录">
|
||||
<!-- 记录卡片 -->
|
||||
<view class="wallet-log-box ss-p-b-30">
|
||||
<view class="log-list" v-for="item in state.pagination.list" :key="item">
|
||||
<view class="head ss-flex ss-col-center ss-row-between">
|
||||
<view class="title">充值金额</view>
|
||||
<view class="num" :class="item.refundStatus === 10 ? 'danger-color' : 'success-color'">
|
||||
{{ fen2yuan(item.payPrice) }} 元
|
||||
<text v-if="item.bonusPrice > 0">(赠送 {{ fen2yuan(item.bonusPrice) }} 元)</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="status-box item ss-flex ss-col-center ss-row-between">
|
||||
<view class="item-title">支付状态</view>
|
||||
<view
|
||||
class="status-text"
|
||||
:class="item.refundStatus === 10 ? 'danger-color' : 'success-color'"
|
||||
>
|
||||
{{ item.refundStatus === 10 ? '已退款' : '已支付' }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="time-box item ss-flex ss-col-center ss-row-between">
|
||||
<text class="item-title">充值渠道</text>
|
||||
<view class="time ss-ellipsis-1">{{ item.payChannelName }}</view>
|
||||
</view>
|
||||
<view class="time-box item ss-flex ss-col-center ss-row-between">
|
||||
<text class="item-title">充值单号</text>
|
||||
<view class="time"> {{ item.payOrderChannelOrderNo }} </view>
|
||||
</view>
|
||||
<view class="time-box item ss-flex ss-col-center ss-row-between">
|
||||
<text class="item-title">充值时间</text>
|
||||
<view class="time">
|
||||
{{ sheep.$helper.timeFormat(item.payTime, 'yyyy-mm-dd hh:MM:ss') }}</view
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<s-empty
|
||||
v-if="state.pagination.total === 0"
|
||||
icon="/static/comment-empty.png"
|
||||
text="暂无充值记录"
|
||||
/>
|
||||
<uni-load-more
|
||||
v-if="state.pagination.total > 0"
|
||||
:status="state.loadStatus"
|
||||
:content-text="{
|
||||
contentdown: '上拉加载更多',
|
||||
}"
|
||||
@tap="loadMore"
|
||||
/>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive } from 'vue';
|
||||
import { onLoad, onReachBottom } from '@dcloudio/uni-app';
|
||||
import _ from 'lodash-es';
|
||||
import PayWalletApi from '@/sheep/api/pay/wallet';
|
||||
import sheep from '@/sheep';
|
||||
import { fen2yuan } from '../../sheep/hooks/useGoods';
|
||||
|
||||
const state = reactive({
|
||||
pagination: {
|
||||
list: [],
|
||||
total: 0,
|
||||
pageNo: 1,
|
||||
pageSize: 5,
|
||||
},
|
||||
loadStatus: '',
|
||||
});
|
||||
|
||||
async function getLogList(page = 1, list_rows = 5) {
|
||||
const { code, data } = await PayWalletApi.getWalletRechargePage({
|
||||
pageNo: page,
|
||||
pageSize: list_rows,
|
||||
});
|
||||
if (code !== 0) {
|
||||
return;
|
||||
}
|
||||
state.pagination.list = _.concat(state.pagination.list, data.list);
|
||||
state.pagination.total = data.total;
|
||||
state.loadStatus = state.pagination.list.length < state.pagination.total ? 'more' : 'noMore';
|
||||
}
|
||||
|
||||
// 加载更多
|
||||
function loadMore() {
|
||||
if (state.loadStatus === 'noMore') {
|
||||
return;
|
||||
}
|
||||
state.pagination.pageNo++;
|
||||
getLogList();
|
||||
}
|
||||
|
||||
onLoad(() => {
|
||||
getLogList();
|
||||
});
|
||||
|
||||
onReachBottom(() => {
|
||||
loadMore();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 记录卡片
|
||||
.log-list {
|
||||
min-height: 213rpx;
|
||||
background: $white;
|
||||
margin-bottom: 10rpx;
|
||||
padding-bottom: 10rpx;
|
||||
|
||||
.head {
|
||||
padding: 0 35rpx;
|
||||
height: 80rpx;
|
||||
border-bottom: 1rpx solid $gray-e;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.title {
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: $dark-3;
|
||||
}
|
||||
|
||||
.num {
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.item {
|
||||
padding: 0 30rpx 10rpx;
|
||||
|
||||
.item-icon {
|
||||
color: $gray-d;
|
||||
font-size: 36rpx;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
width: 180rpx;
|
||||
font-size: 24rpx;
|
||||
font-weight: 400;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.status-text {
|
||||
font-size: 24rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.time {
|
||||
font-size: 24rpx;
|
||||
font-weight: 400;
|
||||
color: #c0c0c0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.warning-color {
|
||||
color: #faad14;
|
||||
}
|
||||
.danger-color {
|
||||
color: #ff4d4f;
|
||||
}
|
||||
.success-color {
|
||||
color: #67c23a;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,287 @@
|
||||
<!-- 充值界面 -->
|
||||
<template>
|
||||
<s-layout title="充值" class="withdraw-wrap" navbar="inner">
|
||||
<view class="wallet-num-box ss-flex ss-col-center ss-row-between" :style="[
|
||||
{
|
||||
marginTop: '-' + Number(statusBarHeight + 88) + 'rpx',
|
||||
paddingTop: Number(statusBarHeight + 108) + 'rpx',
|
||||
},
|
||||
]">
|
||||
<view class="">
|
||||
<view class="num-title">当前余额(元)</view>
|
||||
<view class="wallet-num">{{ fen2yuan(userStore?userStore.userWallet.balance:0) }}</view>
|
||||
</view>
|
||||
<button class="ss-reset-button log-btn" @tap="sheep.$router.go('/pages/pay/recharge-log')">
|
||||
充值记录
|
||||
</button>
|
||||
</view>
|
||||
<view class="recharge-box">
|
||||
<view class="recharge-card-box">
|
||||
<view class="input-label ss-m-b-50">充值金额</view>
|
||||
<view class="input-box ss-flex border-bottom ss-p-b-20">
|
||||
<view class="unit">¥</view>
|
||||
<uni-easyinput v-model="state.recharge_money" type="digit" placeholder="请输入充值金额" :inputBorder="false" />
|
||||
</view>
|
||||
<view class="face-value-box ss-flex ss-flex-wrap ss-m-y-40">
|
||||
<button class="ss-reset-button face-value-btn" v-for="item in state.packageList" :key="item.money"
|
||||
:class="[{ 'btn-active': state.recharge_money === fen2yuan(item.payPrice) }]" @tap="onCard(item.payPrice)">
|
||||
<text class="face-value-title">{{ fen2yuan(item.payPrice) }}</text>
|
||||
<view v-if="item.bonusPrice" class="face-value-tag">
|
||||
送 {{ fen2yuan(item.bonusPrice) }} 元
|
||||
</view>
|
||||
</button>
|
||||
</view>
|
||||
<button class="ss-reset-button save-btn ss-m-t-60" @tap="onConfirm">
|
||||
确认充值
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
computed,
|
||||
reactive
|
||||
} from 'vue';
|
||||
import sheep from '@/sheep';
|
||||
import {
|
||||
onLoad
|
||||
} from '@dcloudio/uni-app';
|
||||
import {
|
||||
fen2yuan
|
||||
} from '@/sheep/hooks/useGoods';
|
||||
import PayWalletApi from '@/sheep/api/pay/wallet';
|
||||
import {
|
||||
WxaSubscribeTemplate
|
||||
} from '@/sheep/util/const';
|
||||
|
||||
const connectorCode = ref(0)
|
||||
const userStore = computed(() => {
|
||||
return sheep.$store('user').$state
|
||||
});
|
||||
|
||||
const statusBarHeight = sheep.$platform.device.statusBarHeight * 2;
|
||||
const headerBg = sheep.$url.css('/static/img/shop/user/withdraw_bg.png');
|
||||
|
||||
const state = reactive({
|
||||
recharge_money: '', // 输入的充值金额
|
||||
packageList: [],
|
||||
});
|
||||
|
||||
// 点击卡片,选择充值金额
|
||||
function onCard(e) {
|
||||
state.recharge_money = fen2yuan(e);
|
||||
}
|
||||
|
||||
// 获得钱包充值套餐列表
|
||||
async function getRechargeTabs() {
|
||||
const {
|
||||
code,
|
||||
data
|
||||
} = await PayWalletApi.getWalletRechargePackageList();
|
||||
if (code !== 0) {
|
||||
return;
|
||||
}
|
||||
state.packageList = data;
|
||||
}
|
||||
|
||||
// 发起支付
|
||||
async function onConfirm() {
|
||||
const {
|
||||
code,
|
||||
data
|
||||
} = await PayWalletApi.createWalletRecharge({
|
||||
packageId: state.packageList.find((item) => fen2yuan(item.payPrice) === state.recharge_money)?.id,
|
||||
payPrice: state.recharge_money * 100,
|
||||
});
|
||||
if (code !== 0) {
|
||||
return;
|
||||
}
|
||||
// #ifdef MP
|
||||
sheep.$platform.useProvider('wechat').subscribeMessage(WxaSubscribeTemplate.PAY_WALLET_RECHARGER_SUCCESS);
|
||||
// #endif
|
||||
const connectorCodeStr = connectorCode.value || '';
|
||||
sheep.$router.go('/pages/pay/index', {
|
||||
id: data.payOrderId,
|
||||
orderType: 'recharge',
|
||||
connectorCode: connectorCodeStr // 传递枪号
|
||||
});
|
||||
}
|
||||
onShow(() => {
|
||||
sheep.$store('user').getWallet()
|
||||
});
|
||||
onLoad((options) => {
|
||||
getRechargeTabs();
|
||||
// 枪号
|
||||
if (options.connectorCode) {
|
||||
connectorCode.value = options.connectorCode;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep() {
|
||||
.uni-input-input {
|
||||
font-family: OPPOSANS !important;
|
||||
}
|
||||
}
|
||||
|
||||
.wallet-num-box {
|
||||
padding: 0 40rpx 80rpx;
|
||||
background: url('https://kxcharge.oss-cn-beijing.aliyuncs.com/mini/box.png') 0 0/100% 812rpx no-repeat;
|
||||
border-radius: 0 0 5% 5%;
|
||||
|
||||
.num-title {
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
color: $white;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.wallet-num {
|
||||
font-size: 60rpx;
|
||||
font-weight: 500;
|
||||
color: $white;
|
||||
font-family: OPPOSANS;
|
||||
}
|
||||
|
||||
.log-btn {
|
||||
width: 170rpx;
|
||||
height: 60rpx;
|
||||
line-height: 60rpx;
|
||||
border: 1rpx solid $white;
|
||||
border-radius: 30rpx;
|
||||
padding: 0;
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
|
||||
.recharge-box {
|
||||
position: relative;
|
||||
padding: 0 30rpx;
|
||||
margin-top: -60rpx;
|
||||
}
|
||||
|
||||
.save-btn {
|
||||
width: 620rpx;
|
||||
height: 86rpx;
|
||||
border-radius: 44rpx;
|
||||
font-size: 30rpx;
|
||||
background: linear-gradient(132deg, #4A8EFC 0%, #50C3FD 100%);
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.recharge-card-box {
|
||||
width: 690rpx;
|
||||
background: var(--ui-BG);
|
||||
border-radius: 20rpx;
|
||||
padding: 30rpx;
|
||||
box-sizing: border-box;
|
||||
|
||||
.input-label {
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.unit {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 48rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.uni-easyinput__placeholder-class {
|
||||
font-size: 30rpx;
|
||||
height: 60rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
:deep(.uni-easyinput__content-input) {
|
||||
font-size: 48rpx;
|
||||
}
|
||||
|
||||
.face-value-btn {
|
||||
width: 200rpx;
|
||||
height: 144rpx;
|
||||
border: 1px solid var(--ui-BG-Main);
|
||||
border-radius: 10rpx;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
margin-bottom: 15rpx;
|
||||
margin-right: 15rpx;
|
||||
|
||||
&:nth-of-type(3n) {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.face-value-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 500;
|
||||
color: var(--ui-BG-Main);
|
||||
font-family: OPPOSANS;
|
||||
|
||||
&::after {
|
||||
content: '元';
|
||||
font-size: 24rpx;
|
||||
margin-left: 6rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.face-value-tag {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
height: 40rpx;
|
||||
line-height: 40rpx;
|
||||
background: var(--ui-BG-Main);
|
||||
opacity: 0.8;
|
||||
border-radius: 10rpx 0 20rpx 0;
|
||||
top: 0;
|
||||
left: -2rpx;
|
||||
padding: 0 16rpx;
|
||||
font-size: 22rpx;
|
||||
color: $white;
|
||||
font-family: OPPOSANS;
|
||||
}
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
content: ' ';
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: var(--ui-BG-Main);
|
||||
opacity: 0.1;
|
||||
z-index: 0;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-active {
|
||||
z-index: 1;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
background: var(--ui-BG-Main);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.face-value-title {
|
||||
color: $white;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
font-family: OPPOSANS;
|
||||
}
|
||||
|
||||
.face-value-tag {
|
||||
background: $white;
|
||||
color: var(--ui-BG-Main);
|
||||
font-family: OPPOSANS;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,329 @@
|
||||
<!-- 支付结果页面 -->
|
||||
<template>
|
||||
<s-layout title="支付结果" :bgStyle="{ color: '#FFF' }">
|
||||
<view class="pay-result-box ss-flex-col ss-row-center ss-col-center">
|
||||
<!-- 信息展示 -->
|
||||
<view class="pay-waiting ss-m-b-30" v-if="payResult === 'waiting'" />
|
||||
<image
|
||||
class="pay-img ss-m-b-30"
|
||||
v-if="payResult === 'success'"
|
||||
:src="sheep.$url.static('/static/img/shop/order/order_pay_success.gif')"
|
||||
/>
|
||||
<image
|
||||
class="pay-img ss-m-b-30"
|
||||
v-if="['failed', 'closed'].includes(payResult)"
|
||||
:src="sheep.$url.static('/static/img/shop/order/order_paty_fail.gif')"
|
||||
/>
|
||||
<view class="tip-text ss-m-b-30" v-if="payResult === 'success'">支付成功</view>
|
||||
<view class="tip-text ss-m-b-30" v-if="payResult === 'failed'">支付失败</view>
|
||||
<view class="tip-text ss-m-b-30" v-if="payResult === 'closed'">该订单已关闭</view>
|
||||
<view class="tip-text ss-m-b-30" v-if="payResult === 'waiting'">检测支付结果...</view>
|
||||
<view class="pay-total-num ss-flex" v-if="payResult === 'success'">
|
||||
<view>¥{{ fen2yuan(state.orderInfo.price) }}</view>
|
||||
</view>
|
||||
|
||||
<!-- 操作区 -->
|
||||
<view class="btn-box ss-flex ss-row-center ss-m-t-50">
|
||||
<button
|
||||
class="back-btn ss-reset-button"
|
||||
@tap="state.connectorCode ?
|
||||
sheep.$router.redirect('/pages/equipment-detail/index', { connectorCode: state.connectorCode }) :
|
||||
sheep.$router.go('/pages/index/index')"
|
||||
>
|
||||
{{ state.connectorCode ? '继续充电' : '返回首页' }}
|
||||
</button>
|
||||
<button
|
||||
class="check-btn ss-reset-button"
|
||||
v-if="payResult === 'failed'"
|
||||
@tap="
|
||||
sheep.$router.redirect('/pages/pay/index', { id: state.id, orderType: state.orderType })
|
||||
"
|
||||
>
|
||||
重新支付
|
||||
</button>
|
||||
<button class="check-btn ss-reset-button" v-if="payResult === 'success'" @tap="onOrder">
|
||||
查看订单
|
||||
</button>
|
||||
<button
|
||||
class="check-btn ss-reset-button"
|
||||
v-if="payResult === 'success' && state.tradeOrder.type === 3"
|
||||
@tap="sheep.$router.redirect('/pages/activity/groupon/order')"
|
||||
>
|
||||
我的拼团
|
||||
</button>
|
||||
</view>
|
||||
|
||||
<!-- #ifdef MP -->
|
||||
<view
|
||||
class="subscribe-box ss-flex ss-m-t-44"
|
||||
v-if="showSubscribeBtn && state.orderType === 'goods'"
|
||||
>
|
||||
<image class="subscribe-img" :src="sheep.$url.static('/static/img/shop/order/cargo.png')" />
|
||||
<view class="subscribe-title ss-m-r-48 ss-m-l-16">获取实时发货信息与订单状态</view>
|
||||
<view class="subscribe-start" @tap="subscribeMessage">立即订阅</view>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onLoad, onHide, onShow } from '@dcloudio/uni-app';
|
||||
import { reactive, computed, ref } from 'vue';
|
||||
import { isEmpty } from 'lodash-es';
|
||||
import sheep from '@/sheep';
|
||||
import PayOrderApi from '@/sheep/api/pay/order';
|
||||
import { fen2yuan } from '@/sheep/hooks/useGoods';
|
||||
import OrderApi from '@/sheep/api/trade/order';
|
||||
import { WxaSubscribeTemplate } from '@/sheep/util/const';
|
||||
|
||||
const state = reactive({
|
||||
id: 0, // 支付单号
|
||||
orderType: 'goods', // 订单类型
|
||||
result: 'unpaid', // 支付状态
|
||||
orderInfo: {}, // 支付订单信息
|
||||
tradeOrder: {}, // 商品订单信息,只有在 orderType 为 goods 才会请求。目的:【我的拼团】按钮的展示
|
||||
counter: 0, // 获取结果次数
|
||||
connectorCode: '', // 枪号
|
||||
});
|
||||
|
||||
// 支付结果 result => payResult
|
||||
const payResult = computed(() => {
|
||||
if (state.result === 'unpaid') {
|
||||
return 'waiting';
|
||||
}
|
||||
if (state.result === 'paid') {
|
||||
return 'success';
|
||||
}
|
||||
if (state.result === 'failed') {
|
||||
return 'failed';
|
||||
}
|
||||
if (state.result === 'closed') {
|
||||
return 'closed';
|
||||
}
|
||||
});
|
||||
|
||||
// 获得订单信息
|
||||
async function getOrderInfo(id) {
|
||||
state.counter++;
|
||||
// 1. 加载订单信息
|
||||
const { data, code } = await PayOrderApi.getOrder(id);
|
||||
if (code === 0) {
|
||||
state.orderInfo = data;
|
||||
if (!state.orderInfo || state.orderInfo.status === 30) {
|
||||
// 支付关闭
|
||||
state.result = 'closed';
|
||||
return;
|
||||
}
|
||||
if (state.orderInfo.status !== 0) {
|
||||
// 非待支付,可能是已支付,可能是已退款
|
||||
state.result = 'paid';
|
||||
// #ifdef MP
|
||||
uni.showModal({
|
||||
title: '支付结果',
|
||||
showCancel: false, // 不要取消按钮
|
||||
content: '支付成功',
|
||||
success: () => {
|
||||
// 订阅只能由用户主动触发,只能包一层 showModal 诱导用户点击
|
||||
autoSubscribeMessage();
|
||||
},
|
||||
});
|
||||
|
||||
// #endif
|
||||
// 特殊:获得商品订单信息
|
||||
if (state.orderType === 'goods') {
|
||||
const { data, code } = await OrderApi.getOrderDetail(
|
||||
state.orderInfo.merchantOrderId,
|
||||
true,
|
||||
);
|
||||
if (code === 0) {
|
||||
state.tradeOrder = data;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 2.1 情况三一:未支付,且轮询次数小于三次,则继续轮询
|
||||
if (state.counter < 3 && state.result === 'unpaid') {
|
||||
setTimeout(() => {
|
||||
getOrderInfo(id);
|
||||
}, 1500);
|
||||
}
|
||||
// 2.2 情况二:超过三次检测才判断为支付失败
|
||||
if (state.counter >= 3) {
|
||||
state.result = 'failed';
|
||||
}
|
||||
}
|
||||
|
||||
function onOrder() {
|
||||
if (state.orderType === 'recharge') {
|
||||
sheep.$router.redirect('/pages/pay/recharge-log');
|
||||
} else {
|
||||
sheep.$router.redirect('/pages/order/list');
|
||||
}
|
||||
}
|
||||
|
||||
// #ifdef MP
|
||||
const showSubscribeBtn = ref(false); // 默认隐藏
|
||||
const SUBSCRIBE_BTN_STATUS_STORAGE_KEY = 'subscribe_btn_status';
|
||||
function subscribeMessage() {
|
||||
if (state.orderType !== 'goods') {
|
||||
return;
|
||||
}
|
||||
const event = [WxaSubscribeTemplate.TRADE_ORDER_DELIVERY];
|
||||
if (state.tradeOrder.type === 3) {
|
||||
event.push(WxaSubscribeTemplate.PROMOTION_COMBINATION_SUCCESS);
|
||||
}
|
||||
sheep.$platform.useProvider('wechat').subscribeMessage(event, () => {
|
||||
// 订阅后记录一下订阅状态
|
||||
uni.removeStorageSync(SUBSCRIBE_BTN_STATUS_STORAGE_KEY);
|
||||
uni.setStorageSync(SUBSCRIBE_BTN_STATUS_STORAGE_KEY, '已订阅');
|
||||
// 隐藏订阅按钮
|
||||
showSubscribeBtn.value = false;
|
||||
});
|
||||
}
|
||||
async function autoSubscribeMessage() {
|
||||
// 1. 校验是否手动订阅过
|
||||
const subscribeBtnStatus = uni.getStorageSync(SUBSCRIBE_BTN_STATUS_STORAGE_KEY);
|
||||
if (!subscribeBtnStatus) {
|
||||
showSubscribeBtn.value = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 订阅消息
|
||||
subscribeMessage();
|
||||
}
|
||||
// #endif
|
||||
|
||||
onLoad(async (options) => {
|
||||
// 支付订单号
|
||||
if (options.id) {
|
||||
state.id = options.id;
|
||||
}
|
||||
// 订单类型
|
||||
if (options.orderType) {
|
||||
state.orderType = options.orderType;
|
||||
}
|
||||
// 枪号
|
||||
if (options.connectorCode) {
|
||||
state.connectorCode = options.connectorCode;
|
||||
}
|
||||
// 支付结果传值过来是失败,则直接显示失败界面
|
||||
if (options.payState === 'fail') {
|
||||
state.result = 'failed';
|
||||
} else {
|
||||
// 轮询三次检测订单支付结果
|
||||
await getOrderInfo(state.id);
|
||||
}
|
||||
});
|
||||
|
||||
onShow(() => {
|
||||
if (isEmpty(state.orderInfo)) {
|
||||
return;
|
||||
}
|
||||
getOrderInfo(state.id);
|
||||
});
|
||||
|
||||
onHide(() => {
|
||||
state.result = 'unpaid';
|
||||
state.counter = 0;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@keyframes rotation {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.score-img {
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
margin: 0 4rpx;
|
||||
}
|
||||
|
||||
.pay-result-box {
|
||||
padding: 60rpx 0;
|
||||
|
||||
.pay-waiting {
|
||||
margin-top: 20rpx;
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
border: 10rpx solid rgb(233, 231, 231);
|
||||
border-bottom-color: rgb(204, 204, 204);
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
// -webkit-animation: rotation 1s linear infinite;
|
||||
animation: rotation 1s linear infinite;
|
||||
}
|
||||
|
||||
.pay-img {
|
||||
width: 130rpx;
|
||||
height: 130rpx;
|
||||
}
|
||||
|
||||
.tip-text {
|
||||
font-size: 30rpx;
|
||||
font-weight: bold;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.pay-total-num {
|
||||
font-size: 36rpx;
|
||||
font-weight: 500;
|
||||
color: #333333;
|
||||
font-family: OPPOSANS;
|
||||
}
|
||||
|
||||
.btn-box {
|
||||
width: 100%;
|
||||
|
||||
.back-btn {
|
||||
width: 190rpx;
|
||||
height: 70rpx;
|
||||
font-size: 28rpx;
|
||||
border: 2rpx solid #dfdfdf;
|
||||
border-radius: 35rpx;
|
||||
font-weight: 400;
|
||||
color: #595959;
|
||||
}
|
||||
|
||||
.check-btn {
|
||||
width: 190rpx;
|
||||
height: 70rpx;
|
||||
font-size: 28rpx;
|
||||
border: 2rpx solid #dfdfdf;
|
||||
border-radius: 35rpx;
|
||||
font-weight: 400;
|
||||
color: #595959;
|
||||
margin-left: 32rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.subscribe-box {
|
||||
.subscribe-img {
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
}
|
||||
|
||||
.subscribe-title {
|
||||
font-weight: 500;
|
||||
font-size: 32rpx;
|
||||
line-height: 36rpx;
|
||||
color: #434343;
|
||||
}
|
||||
|
||||
.subscribe-start {
|
||||
color: var(--ui-BG-Main);
|
||||
font-weight: 700;
|
||||
font-size: 32rpx;
|
||||
line-height: 36rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,283 @@
|
||||
<template>
|
||||
<s-layout title="电价详情" navbar="normal" onShareAppMessage>
|
||||
<view class="block">
|
||||
<view class="header">
|
||||
<text class="name title">时段</text>
|
||||
<view class="formula">
|
||||
<view class="item" style="margin-right: 5rpx;">
|
||||
<text class="name">价格</text>
|
||||
<text class="unit">(元/度)</text>
|
||||
</view>
|
||||
<view>=</view>
|
||||
<view class="item">
|
||||
<text class="name">电价</text>
|
||||
<text class="unit">(元/度)</text>
|
||||
</view>
|
||||
<view style="margin-right: 8rpx;">+</view>
|
||||
<view class="item">
|
||||
<text class="name">服务费</text>
|
||||
<text class="unit">(元/度)</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<scroll-view scroll-y="true" class="scroll">
|
||||
<view class="item" :class="{nowItem: item.isNow}" v-for="(item,index) in intervalList" :key="index">
|
||||
<view class="left">
|
||||
<text class="now" v-if="item.isNow">当前时段</text>
|
||||
<text class="time">{{item.interval}}</text>
|
||||
</view>
|
||||
<view class="info">
|
||||
<view class="price">
|
||||
<text style="width: 80rpx;">价格</text>
|
||||
<text class="total">{{fixedNum(item.eleMoney + item.serviceMoney,2)}}</text>
|
||||
<text>{{fixedNum(item.eleMoney,2)}}</text>
|
||||
<text>{{fixedNum(item.serviceMoney,2)}}</text>
|
||||
</view>
|
||||
<view class="price vip">
|
||||
<text style="width: 80rpx;">VIP</text>
|
||||
<text class="total">{{fixedNum(discountPrice(item.eleMoney, item.interval),2)}}</text>
|
||||
<text>{{fixedNum(item.eleMoney,2)}}</text>
|
||||
<text>{{ fixedNum(countDiscountPrice(item.interval),2)}}</text>
|
||||
</view>
|
||||
<view class="price vip">
|
||||
<text style="width: 80rpx;">SVIP</text>
|
||||
<text class="total">{{fixedNum(vipPrice(item.eleMoney, item.interval),2)}}</text>
|
||||
<text>{{fixedNum(item.eleMoney ,2)}}</text>
|
||||
<text>{{fixedNum(countVipPrice(item.interval),2)}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="tip">
|
||||
充电费用仅供参考,实际以充电桩上费用为准
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
</view>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from 'dayjs';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
electricityFee: {},
|
||||
serviceFee: {},
|
||||
intervalList: [],
|
||||
priceServiceDiscount: [],
|
||||
isShowVip: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
fixedNum(num, fix) {
|
||||
// console.log('num: ',num);
|
||||
if (!num) {
|
||||
return "0.00"
|
||||
}
|
||||
return Number(num).toFixed(fix)
|
||||
},
|
||||
discountPrice(eleMoney, time) {
|
||||
const servicePrice = this.priceServiceDiscount.find(item => item.time == time)?.priceDiscount;
|
||||
return +eleMoney + +servicePrice;
|
||||
},
|
||||
vipPrice(eleMoney, time) {
|
||||
const servicePrice = this.priceServiceDiscount.find(item => item.time == time)?.vipDiscountServiceFee;
|
||||
return +eleMoney + +servicePrice;
|
||||
},
|
||||
countDiscountPrice(time) {
|
||||
return this.priceServiceDiscount.find(item => item.time == time)?.priceDiscount;
|
||||
},
|
||||
countVipPrice(time) {
|
||||
return this.priceServiceDiscount.find(item => item.time == time)?.vipDiscountServiceFee;
|
||||
},
|
||||
handelData() {
|
||||
console.log('this.electricityFee, this.serviceFee: ', this.electricityFee, this.serviceFee);
|
||||
const list = []
|
||||
for (const key in this.electricityFee) {
|
||||
const now = +new Date();
|
||||
const timeArr = key.split("-").map(t => moment(`${moment().format("YYYY-MM-DD")} ${t}`).valueOf());
|
||||
const obj = {
|
||||
interval: key,
|
||||
eleMoney: this.electricityFee[key] || 0,
|
||||
isNow: now > timeArr[0] && now <= timeArr[1]
|
||||
};
|
||||
if (this.serviceFee[key] || this.serviceFee[key] === 0) {
|
||||
obj['serviceMoney'] = this.serviceFee[key] || 0
|
||||
} else {
|
||||
for (const k in this.serviceFee) {
|
||||
const t = moment(`${moment().format("YYYY-MM-DD")} ${k.split("-")[1]}`).valueOf();
|
||||
if (timeArr[1] < t) {
|
||||
obj['serviceMoney'] = this.serviceFee[k] || 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
list.push(obj);
|
||||
}
|
||||
const index = list.findIndex(k => k.isNow);
|
||||
if (index > -1) this.intervalList.push(list[index]);
|
||||
const itemsToKeep = list.slice(0, index).concat(list.slice(index + 1));
|
||||
itemsToKeep.sort((a, b) => {
|
||||
const atime = moment(`${moment().format("YYYY-MM-DD")} ${a.interval.split("-")[1]}`).valueOf();
|
||||
const btime = moment(`${moment().format("YYYY-MM-DD")} ${b.interval.split("-")[1]}`).valueOf();
|
||||
return atime - btime
|
||||
}).forEach(item => {
|
||||
this.intervalList.push(item)
|
||||
})
|
||||
const deletedItems = list.splice(index, 1);
|
||||
console.log('this.intervalList, list: ', this.intervalList, list);
|
||||
}
|
||||
},
|
||||
onLoad(option) {
|
||||
console.log(89, option)
|
||||
|
||||
// 解析 electricityFee 和 serviceFee
|
||||
const parseFeeString = (feeString) => {
|
||||
const result = {};
|
||||
const items = feeString.split(";").filter(item => item); // 按分号分割并过滤空项
|
||||
items.forEach((item) => {
|
||||
// 找到最后一个冒号的位置
|
||||
const lastColonIndex = item.lastIndexOf(":");
|
||||
if (lastColonIndex === -1) return; // 如果没有冒号,跳过
|
||||
|
||||
const key = item.slice(0, lastColonIndex); // 时间区间(如 "00:00-01:00")
|
||||
const value = item.slice(lastColonIndex + 1); // 数值(如 "1.0")
|
||||
|
||||
if (key && value) {
|
||||
result[key] = parseFloat(value);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
this.electricityFee = parseFeeString(option.electricityFee.slice(1, -1));
|
||||
this.serviceFee = parseFeeString(option.serviceFee.slice(1, -1));
|
||||
this.priceServiceDiscount = JSON.parse(option.priceServiceDiscount);
|
||||
this.isShowVip = true;
|
||||
this.handelData();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.block {
|
||||
background-color: #fff;
|
||||
height: 100vh;
|
||||
|
||||
.header {
|
||||
width: 680rpx;
|
||||
margin: auto;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 20rpx 0;
|
||||
|
||||
.formula {
|
||||
display: flex;
|
||||
width: 60%;
|
||||
justify-content: flex-end;
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 105rpx;
|
||||
|
||||
.unit {
|
||||
font-size: 25rpx;
|
||||
color: #aaaaaa;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.name {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.title {
|
||||
display: inline-block;
|
||||
width: 30%;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.scroll {
|
||||
padding-bottom: 25rpx;
|
||||
|
||||
.item {
|
||||
width: 700rpx;
|
||||
margin: auto;
|
||||
border-radius: 12rpx;
|
||||
box-shadow: 0px 0px 5px 5px #f1f1f1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 30rpx;
|
||||
color: #666;
|
||||
font-size: 30rpx;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
.left {
|
||||
width: 30%;
|
||||
text-align: center;
|
||||
padding: 50rpx 0;
|
||||
|
||||
.now {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-color: #1890FF;
|
||||
padding: 5rpx 20rpx;
|
||||
color: #fff;
|
||||
font-size: 25rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.time,
|
||||
.total {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.info {
|
||||
width: 70%;
|
||||
padding: 20rpx 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
color: #1890FF;
|
||||
|
||||
.price {
|
||||
width: 95%;
|
||||
padding: 10rpx 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
color: #1890FF;
|
||||
}
|
||||
|
||||
.vip {
|
||||
color: #fe5d0f;
|
||||
}
|
||||
|
||||
// padding-right: 10rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.nowItem {
|
||||
border: 1rpx solid #1890FF;
|
||||
background: #1890FF4D;
|
||||
}
|
||||
}
|
||||
|
||||
.tip {
|
||||
font-size: 25rpx;
|
||||
color: #aaaaaa;
|
||||
width: 700rpx;
|
||||
margin: auto;
|
||||
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,15 @@
|
||||
<!-- FAQ 常见问题 -->
|
||||
<template>
|
||||
<s-layout class="set-wrap" title="合作联系" :bgStyle="{ color: '#FFF' }">
|
||||
<image src="https://kxcharge.oss-cn-beijing.aliyuncs.com/qywx.jpg" mode="widthFix" show-menu-by-longpress></image>
|
||||
<template v-slot:kxTabBar>
|
||||
<kx-tabbar-wrapper>
|
||||
<view class="tab-bar">
|
||||
扫码识别,商业合作
|
||||
</view>
|
||||
</kx-tabbar-wrapper>
|
||||
</template>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup></script>
|
||||
@@ -0,0 +1,60 @@
|
||||
<!-- 错误界面 -->
|
||||
<template>
|
||||
<view class="error-page">
|
||||
<s-empty
|
||||
v-if="errCode === 'NetworkError'"
|
||||
icon="/static/internet-empty.png"
|
||||
text="网络连接失败"
|
||||
showAction
|
||||
actionText="重新连接"
|
||||
@clickAction="onReconnect"
|
||||
buttonColor="#ff3000"
|
||||
/>
|
||||
<s-empty
|
||||
v-else-if="errCode === 'TemplateError'"
|
||||
icon="/static/internet-empty.png"
|
||||
text="未找到模板"
|
||||
showAction
|
||||
actionText="重新加载"
|
||||
@clickAction="onReconnect"
|
||||
buttonColor="#ff3000"
|
||||
/>
|
||||
<s-empty
|
||||
v-else-if="errCode !== ''"
|
||||
icon="/static/internet-empty.png"
|
||||
:text="errMsg"
|
||||
showAction
|
||||
actionText="重新加载"
|
||||
@clickAction="onReconnect"
|
||||
buttonColor="#ff3000"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onLoad } from '@dcloudio/uni-app';
|
||||
import { ref } from 'vue';
|
||||
import { ShoproInit } from '@/sheep';
|
||||
|
||||
const errCode = ref('');
|
||||
const errMsg = ref('');
|
||||
|
||||
onLoad((options) => {
|
||||
errCode.value = options.errCode;
|
||||
errMsg.value = options.errMsg;
|
||||
});
|
||||
|
||||
// 重新连接
|
||||
async function onReconnect() {
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/index',
|
||||
});
|
||||
await ShoproInit();
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.error-page {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,118 @@
|
||||
<!-- FAQ 常见问题 -->
|
||||
<template>
|
||||
<s-layout class="set-wrap" title="常见问题" :bgStyle="{ color: '#FFF' }">
|
||||
<uni-collapse>
|
||||
<uni-collapse-item v-for="(item, index) in state.list" :key="item">
|
||||
<template v-slot:title>
|
||||
<view class="ss-flex ss-col-center header">
|
||||
<view class="ss-m-l-20 ss-m-r-20 icon">
|
||||
<view class="rectangle">
|
||||
<view class="num ss-flex ss-row-center ss-col-center">
|
||||
{{ index + 1 < 10 ? '0' + (index + 1) : index + 1 }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="triangle"> </view>
|
||||
</view>
|
||||
<view class="title ss-m-t-36 ss-m-b-36">
|
||||
{{ item.title }}
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<view class="content ss-p-l-78 ss-p-r-40 ss-p-b-50 ss-p-t-20">
|
||||
<text class="text">{{ item.content }}</text>
|
||||
</view>
|
||||
</uni-collapse-item>
|
||||
</uni-collapse>
|
||||
<s-empty
|
||||
v-if="state.list.length === 0 && !state.loading"
|
||||
text="暂无常见问题"
|
||||
icon="/static/collect-empty.png"
|
||||
/>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onLoad } from '@dcloudio/uni-app';
|
||||
import { reactive } from 'vue';
|
||||
import sheep from '@/sheep';
|
||||
|
||||
const state = reactive({
|
||||
list: [],
|
||||
loading: true,
|
||||
});
|
||||
|
||||
async function getFaqList() {
|
||||
const { error, data } = await sheep.$api.data.faq();
|
||||
if (error === 0) {
|
||||
state.list = data;
|
||||
state.loading = false;
|
||||
}
|
||||
}
|
||||
onLoad(() => {
|
||||
// TODO 【文章】目前简单做,使用营销文章,作为 faq
|
||||
if (true) {
|
||||
sheep.$router.go('/pages/public/richtext', {
|
||||
title: '常见问题',
|
||||
})
|
||||
return;
|
||||
}
|
||||
getFaqList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.header {
|
||||
.title {
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: #333333;
|
||||
line-height: 30rpx;
|
||||
max-width: 688rpx;
|
||||
}
|
||||
|
||||
.icon {
|
||||
position: relative;
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
|
||||
.rectangle {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 40rpx;
|
||||
height: 36rpx;
|
||||
background: var(--ui-BG-Main);
|
||||
border-radius: 4px;
|
||||
|
||||
.num {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: 24rpx;
|
||||
font-weight: 500;
|
||||
color: var(--ui-BG);
|
||||
line-height: 32rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.triangle {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 4rpx solid transparent;
|
||||
border-right: 4rpx solid transparent;
|
||||
border-top: 8rpx solid var(--ui-BG-Main);
|
||||
position: absolute;
|
||||
left: 16rpx;
|
||||
bottom: -4rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
border-bottom: 1rpx solid #dfdfdf;
|
||||
|
||||
.text {
|
||||
font-size: 26rpx;
|
||||
color: #666666;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,54 @@
|
||||
<!-- 文章展示 -->
|
||||
<template>
|
||||
<s-layout class="set-wrap" :title="state.title" :bgStyle="{ color: '#FFF' }">
|
||||
<view class="ss-p-30">
|
||||
<mp-html class="richtext" :content="state.content" />
|
||||
</view>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onLoad } from '@dcloudio/uni-app';
|
||||
import { reactive } from 'vue';
|
||||
import ArticleApi from '@/sheep/api/promotion/article';
|
||||
|
||||
const state = reactive({
|
||||
title: '',
|
||||
content: '',
|
||||
});
|
||||
|
||||
async function getRichTextContent(id, title) {
|
||||
const { code, data } = await ArticleApi.getArticle(id, title);
|
||||
if (code !== 0) {
|
||||
return;
|
||||
}
|
||||
state.content = data.content;
|
||||
// 标题不一致时,修改标题
|
||||
if (state.title !== data.title) {
|
||||
state.title = data.title;
|
||||
uni.setNavigationBarTitle({
|
||||
title: state.title,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onLoad((options) => {
|
||||
if (options.title) {
|
||||
state.title = options.title;
|
||||
uni.setNavigationBarTitle({
|
||||
title: state.title,
|
||||
});
|
||||
}
|
||||
getRichTextContent(options.id, options.title);
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.set-title {
|
||||
margin: 0 30rpx;
|
||||
}
|
||||
|
||||
.richtext {
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,201 @@
|
||||
<template>
|
||||
<s-layout class="set-wrap" title="系统设置" :bgStyle="{ color: '#fff' }">
|
||||
<view class="header-box ss-flex-col ss-row-center ss-col-center">
|
||||
<image class="logo-img ss-m-b-46" :src="sheep.$url.cdn(appInfo.logo)" mode="aspectFit"></image>
|
||||
<view class="name ss-m-b-24">{{ appInfo.name }}</view>
|
||||
</view>
|
||||
|
||||
<view class="container-list">
|
||||
<uni-list :border="false">
|
||||
<uni-list-item title="当前版本" :rightText="appInfo.version" showArrow clickable :border="false" class="list-border"
|
||||
@tap="onCheckUpdate" />
|
||||
<uni-list-item title="本地缓存" :rightText="storageSize" showArrow :border="false" class="list-border" />
|
||||
<uni-list-item title="关于我们" showArrow clickable :border="false" class="list-border" @tap="
|
||||
sheep.$router.go('/pages/public/richtext', {
|
||||
title: '关于我们'
|
||||
})
|
||||
" />
|
||||
<!-- 为了过审 只有 iOS-App 有注销账号功能 -->
|
||||
<uni-list-item v-if="isLogin && sheep.$platform.os === 'ios' && sheep.$platform.name === 'App'" title="注销账号"
|
||||
rightText="" showArrow clickable :border="false" class="list-border" @click="onLogoff" />
|
||||
</uni-list>
|
||||
</view>
|
||||
<view class="set-footer ss-flex-col ss-row-center ss-col-center">
|
||||
<view class="agreement-box ss-flex ss-col-center ss-m-b-40">
|
||||
<view class="ss-flex ss-col-center ss-m-b-10">
|
||||
<view class="tcp-text" @tap="
|
||||
sheep.$router.go('/pages/public/richtext', {
|
||||
title: '用户协议'
|
||||
})
|
||||
">
|
||||
《用户协议》
|
||||
</view>
|
||||
<view class="agreement-text">与</view>
|
||||
<view class="tcp-text" @tap="
|
||||
sheep.$router.go('/pages/public/richtext', {
|
||||
title: '隐私协议'
|
||||
})
|
||||
">
|
||||
《隐私协议》
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="copyright-text ss-m-b-10">{{ appInfo.copyright }}</view>
|
||||
<view class="copyright-text">{{ appInfo.copytime }}</view>
|
||||
</view>
|
||||
<su-fixed bottom placeholder>
|
||||
<view class="ss-p-x-20 ss-p-b-40">
|
||||
<button class="loginout-btn ss-reset-button ui-BG-Main ui-Shadow-Main" @tap="onLogout" v-if="isLogin">
|
||||
退出登录
|
||||
</button>
|
||||
</view>
|
||||
</su-fixed>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import sheep from '@/sheep';
|
||||
import {
|
||||
computed,
|
||||
reactive
|
||||
} from 'vue';
|
||||
import AuthUtil from '@/sheep/api/member/auth';
|
||||
|
||||
const appInfo = computed(() => sheep.$store('app').info);
|
||||
const isLogin = computed(() => sheep.$store('user').isLogin);
|
||||
const storageSize = uni.getStorageInfoSync().currentSize + 'Kb';
|
||||
const state = reactive({
|
||||
showModal: false,
|
||||
});
|
||||
|
||||
function onCheckUpdate() {
|
||||
sheep.$platform.checkUpdate();
|
||||
// 小程序初始化时已检查更新
|
||||
// H5实时更新无需检查
|
||||
// App 1.跳转应用市场更新 2.手动热更新 3.整包更新
|
||||
}
|
||||
|
||||
// 注销账号
|
||||
function onLogoff() {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '确认注销账号?',
|
||||
success: async function(res) {
|
||||
if (!res.confirm) {
|
||||
return;
|
||||
}
|
||||
const {
|
||||
code
|
||||
} = await AuthUtil.logout();
|
||||
if (code !== 0) {
|
||||
return;
|
||||
}
|
||||
sheep.$store('user').logout();
|
||||
sheep.$router.go('/pages/index/user');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// 退出账号
|
||||
function onLogout() {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '确认退出账号?',
|
||||
success: async function(res) {
|
||||
if (!res.confirm) {
|
||||
return;
|
||||
}
|
||||
const {
|
||||
code
|
||||
} = await AuthUtil.logout();
|
||||
if (code !== 0) {
|
||||
return;
|
||||
}
|
||||
sheep.$store('user').logout();
|
||||
sheep.$router.go('/pages/my/index');
|
||||
},
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.container-list {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.set-title {
|
||||
margin: 0 30rpx;
|
||||
}
|
||||
|
||||
.header-box {
|
||||
padding: 100rpx 0;
|
||||
|
||||
.logo-img {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.name {
|
||||
font-size: 42rpx;
|
||||
font-weight: 400;
|
||||
color: $dark-3;
|
||||
}
|
||||
|
||||
.version {
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
line-height: 32rpx;
|
||||
color: $gray-b;
|
||||
}
|
||||
}
|
||||
|
||||
.set-footer {
|
||||
margin: 100rpx 0 0 0;
|
||||
|
||||
.copyright-text {
|
||||
font-size: 22rpx;
|
||||
font-weight: 500;
|
||||
color: $gray-c;
|
||||
line-height: 30rpx;
|
||||
}
|
||||
|
||||
.agreement-box {
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
|
||||
.tcp-text {
|
||||
color: var(--ui-BG-Main);
|
||||
}
|
||||
|
||||
.agreement-text {
|
||||
color: $dark-9;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.loginout-btn {
|
||||
width: 100%;
|
||||
height: 80rpx;
|
||||
border-radius: 40rpx;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
.list-border {
|
||||
font-size: 28rpx;
|
||||
font-weight: 400;
|
||||
color: #333333;
|
||||
border-bottom: 2rpx solid #eeeeee;
|
||||
}
|
||||
|
||||
:deep(.uni-list-item__content-title) {
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
:deep(.uni-list-item__extra-text) {
|
||||
color: #bbbbbb;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,18 @@
|
||||
<!-- 网页加载 -->
|
||||
<template>
|
||||
<view>
|
||||
<web-view :src="url" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onLoad } from '@dcloudio/uni-app';
|
||||
import { ref } from 'vue';
|
||||
|
||||
const url = ref('');
|
||||
onLoad((options) => {
|
||||
url.value = decodeURIComponent(options.url);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@@ -0,0 +1,27 @@
|
||||
<template>
|
||||
<s-layout navbar="normal" onShareAppMessage>
|
||||
</s-layout>
|
||||
</template>
|
||||
<script setup>
|
||||
import tenantId from '@/sheep/config/tenantId';
|
||||
|
||||
onLoad(async () => {
|
||||
uni.showLoading({
|
||||
title: '加载中...',
|
||||
mask: true
|
||||
})
|
||||
Promise.all([tenantId.getTenantByWebsite(), sheep.$store('user').getLocation()])
|
||||
.then(() => {
|
||||
// 加载Shopro底层依赖
|
||||
ShoproInit();
|
||||
sheep.$store('dict').getDictData()
|
||||
uni.hideLoading()
|
||||
uni.switchTab({
|
||||
url: '/pages/index/index'
|
||||
})
|
||||
}, err => {
|
||||
uni.hideLoading()
|
||||
console.log(err)
|
||||
})
|
||||
})
|
||||
</script>
|
||||
@@ -0,0 +1,614 @@
|
||||
<template>
|
||||
<s-layout :title="station?.stationName" navbar="normal" onShareAppMessage>
|
||||
<uni-card is-shadow spacing="0" padding="30rpx">
|
||||
<view class="info-container">
|
||||
<view class="content">
|
||||
<view class="header">
|
||||
<view class="name">
|
||||
<image src="https://kxcharge.oss-cn-beijing.aliyuncs.com/16511.png"></image>
|
||||
<text>{{station.stationName}}</text>
|
||||
</view>
|
||||
<view class="favorite" @click="toggleFavorite">
|
||||
<image src="https://kxcharge.oss-cn-beijing.aliyuncs.com/27697(1).png" v-if="station.favorite"></image>
|
||||
<image src="https://kxcharge.oss-cn-beijing.aliyuncs.com/27697.png" v-else></image>
|
||||
<text :class="{active:station.favorite}">收藏</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="abstract">
|
||||
<text>{{station.stationType}}</text>
|
||||
<view class="line"></view>
|
||||
<text>{{station.openExplain}}</text>
|
||||
<view class="line"></view>
|
||||
<text>{{station.remarks}}</text>
|
||||
</view>
|
||||
<view class="abstract">
|
||||
<image src="https://kxcharge.oss-cn-beijing.aliyuncs.com/16512.png"></image>
|
||||
<text>营业时间:{{station.openExplain}}</text>
|
||||
</view>
|
||||
<scroll-view scroll-x="true" class="detail">
|
||||
<image :src="station.imgFlagPath"></image>
|
||||
<image :src="station.imgFullView"></image>
|
||||
<image :src="station.imgMainEntrance"></image>
|
||||
<image :src="station.imgOther"></image>
|
||||
<image :src="station.imgPilesFeature"></image>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<view class="tip">
|
||||
<text>{{station.address}}</text>
|
||||
<view class="distance">
|
||||
<uni-icons type="paperplane-filled" color="#3072F6" :size="13"></uni-icons>
|
||||
{{station?.distance?.toFixed(2)}}米
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</uni-card>
|
||||
|
||||
<view class="tabs">
|
||||
<view class="tab-item" :class="{active:currentType===CONNECT_TYPE.FAST}" @click="onToggleType(CONNECT_TYPE.FAST)">
|
||||
<view class="icon">快</view>
|
||||
<view class="text">{{station.leisureConnectorNumber}}空/共{{station.connectorNumber}}</view>
|
||||
<view class="arrow">
|
||||
<!-- <image src="https://kxcharge.oss-cn-beijing.aliyuncs.com/jiantou1.png"></image> -->
|
||||
</view>
|
||||
</view>
|
||||
<view class="tab-item slow" :class="{active:currentType===CONNECT_TYPE.SLOW}"
|
||||
@click="onToggleType(CONNECT_TYPE.SLOW)">
|
||||
<view class="icon">慢</view>
|
||||
<view class="text">{{station.slowLeisureConnectorNumber}}空/共{{station.slowConnectorNumber}}</view>
|
||||
<view class="arrow">
|
||||
<!-- <image src="https://kxcharge.oss-cn-beijing.aliyuncs.com/jiantou2.png"></image> -->
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<uni-card is-shadow spacing="0" padding="30rpx">
|
||||
<view class="price-container">
|
||||
<view class="header">
|
||||
<view class="title">
|
||||
<view class="line"></view>
|
||||
价格信息
|
||||
</view>
|
||||
<view class="detail" @click="goToPriceDetails()">价格详情<uni-icons type="right" size="14"></uni-icons></view>
|
||||
</view>
|
||||
<view class="time">价格时段:08:30-24:00</view>
|
||||
<view class="charge">
|
||||
<view class="price">
|
||||
<text>{{station.currentPrice}}</text>
|
||||
元/度
|
||||
</view>
|
||||
<view class="vip">
|
||||
<image src="https://kxcharge.oss-cn-beijing.aliyuncs.com/16568@2x.png" mode="aspectFit"></image>
|
||||
<text>
|
||||
¥{{station.currentPrice}}/度
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="tip">
|
||||
<image src="https://kxcharge.oss-cn-beijing.aliyuncs.com/16415@2x.png" mode="aspectFit"></image>
|
||||
<text>停车说明:{{station.parkExplain}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</uni-card>
|
||||
|
||||
<uni-card is-shadow spacing="0" padding="30rpx">
|
||||
<view class="list-container">
|
||||
<view class="header">
|
||||
<view class="title">
|
||||
<view class="line"></view>
|
||||
终端列表
|
||||
</view>
|
||||
<view class="detail" @click="viewList">查看全部<uni-icons type="right" size="14"></uni-icons></view>
|
||||
</view>
|
||||
<view class="list">
|
||||
<view class="list-item" v-for="item in list" :key="item.id"
|
||||
@click="WORK_STATE.get(item.workState).clickable ? onChargeStart(item) : null">
|
||||
<view class="status" :class="[WORK_STATE.get(item.workState).state,{plug:item.insertArmsState==='1'}]">
|
||||
{{item.insertArmsState==='1'?'已插枪':WORK_STATE.get(item.workState).text}}
|
||||
</view>
|
||||
<view class="info">
|
||||
<view class="name">{{item.connectorName}}</view>
|
||||
<view class="remark">{{item.connectorCode}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</uni-card>
|
||||
|
||||
<template v-slot:kxTabBar>
|
||||
<kx-tabbar @contact-service="contactService"></kx-tabbar>
|
||||
</template>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
createFavorite,
|
||||
deleteFavorite,
|
||||
getStationDetail
|
||||
} from '@/sheep/api/charge/operations'
|
||||
|
||||
const CONNECT_TYPE = {
|
||||
FAST: 1,
|
||||
SLOW: 2
|
||||
}
|
||||
|
||||
const WORK_STATE = new Map([
|
||||
[0, { state: 'hitch', text: '故障', clickable: false }],
|
||||
[1, { state: 'hitch', text: '故障', clickable: false }],
|
||||
[2, { state: 'idle', text: '空闲', clickable: true }],
|
||||
[3, { state: 'charging', text: '充电中', clickable: false }],
|
||||
[4, { state: 'idle', text: '空闲', clickable: true }]
|
||||
])
|
||||
|
||||
const station = ref({})
|
||||
let refreshInterval = null // 存储定时器ID
|
||||
let isRefreshing = false // 标记是否正在刷新中
|
||||
|
||||
const contactService = () => {
|
||||
uni.makePhoneCall({
|
||||
phoneNumber: station.value.serviceTel
|
||||
});
|
||||
}
|
||||
|
||||
// 获取站点详情
|
||||
const fetchStationDetail = async () => {
|
||||
try {
|
||||
const { data } = await getStationDetail({
|
||||
id,
|
||||
longitude,
|
||||
latitude
|
||||
})
|
||||
station.value = data
|
||||
} catch (error) {
|
||||
console.error('获取站点详情失败:', error)
|
||||
} finally {
|
||||
isRefreshing = false
|
||||
}
|
||||
}
|
||||
|
||||
// 启动定时刷新
|
||||
const startRefresh = () => {
|
||||
// 先清除已有的定时器
|
||||
stopRefresh()
|
||||
|
||||
// 立即执行第一次刷新
|
||||
fetchStationDetail()
|
||||
|
||||
// 设置定时器,每5秒刷新一次
|
||||
// refreshInterval = setInterval(() => {
|
||||
// if (!isRefreshing) {
|
||||
// isRefreshing = true
|
||||
// fetchStationDetail()
|
||||
// }
|
||||
// }, 5000)
|
||||
}
|
||||
|
||||
// 停止定时刷新
|
||||
const stopRefresh = () => {
|
||||
if (refreshInterval) {
|
||||
clearInterval(refreshInterval)
|
||||
refreshInterval = null
|
||||
}
|
||||
isRefreshing = false
|
||||
}
|
||||
|
||||
let id, longitude, latitude
|
||||
onLoad((params) => {
|
||||
id = params.id
|
||||
longitude = params.longitude
|
||||
latitude = params.latitude
|
||||
|
||||
// 开始定时刷新
|
||||
startRefresh()
|
||||
})
|
||||
|
||||
// 页面卸载时停止定时刷新
|
||||
onUnload(() => {
|
||||
stopRefresh()
|
||||
})
|
||||
|
||||
const toggleFavorite = () => {
|
||||
const {
|
||||
stationLat: latitude,
|
||||
stationLng: longitude,
|
||||
id,
|
||||
favorite
|
||||
} = station.value
|
||||
let api = createFavorite
|
||||
if (favorite) {
|
||||
api = deleteFavorite
|
||||
}
|
||||
api({
|
||||
stationId: id
|
||||
}).then(() => {
|
||||
fetchStationDetail()
|
||||
})
|
||||
}
|
||||
|
||||
const currentType = ref(CONNECT_TYPE.FAST)
|
||||
const onToggleType = (val) => {
|
||||
currentType.value = val
|
||||
}
|
||||
|
||||
const goToPriceDetails = () => {
|
||||
const priceServiceDiscount = station.value.costTemplateRespVO.costTemplatePriceRespVOS.map(item => {
|
||||
return {
|
||||
time: `${item.startTimeStr}-${item.endTimeStr}`
|
||||
}
|
||||
})
|
||||
uni.navigateTo({
|
||||
url: `/pages/price-details/price-details?priceServiceDiscount=${JSON.stringify(priceServiceDiscount)}&electricityFee=${JSON.stringify(station.value.electricityFee)}&serviceFee=${JSON.stringify(station.value.serviceFee)}`
|
||||
})
|
||||
}
|
||||
|
||||
const list = computed(() => {
|
||||
return station.value?.equipmentConnectorInfoVOS?.filter(el => el.equipmentModelRespVO.type === currentType
|
||||
.value)
|
||||
})
|
||||
|
||||
const viewList = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/equipment-list/index'
|
||||
})
|
||||
}
|
||||
|
||||
const onChargeStart = (item) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/equipment-detail/index?connectorCode=${item.connectorCode}`
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.info-container {
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.name {
|
||||
font-weight: 800;
|
||||
font-size: 34rpx;
|
||||
color: #333;
|
||||
|
||||
image {
|
||||
width: 36rpx;
|
||||
height: 38rpx;
|
||||
display: inline-block;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.favorite {
|
||||
float: right;
|
||||
|
||||
image {
|
||||
width: 30rpx;
|
||||
height: 24rpx;
|
||||
display: inline-block;
|
||||
margin-right: 4rpx;
|
||||
}
|
||||
|
||||
text {
|
||||
font-weight: 500;
|
||||
font-size: 24rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
text.active {
|
||||
color: #FC8229;
|
||||
}
|
||||
}
|
||||
|
||||
.abstract {
|
||||
margin-top: 10rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
image {
|
||||
width: 24rpx;
|
||||
height: 24rpx;
|
||||
display: inline-block;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
|
||||
text {
|
||||
font-weight: 500;
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.line {
|
||||
width: 1rpx;
|
||||
height: 21rpx;
|
||||
border: 1rpx solid #ccc;
|
||||
margin: 0 10rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.detail {
|
||||
margin: 10rpx 0;
|
||||
white-space: nowrap;
|
||||
|
||||
image {
|
||||
width: 200rpx;
|
||||
height: 112rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.tip {
|
||||
padding-top: 20rpx;
|
||||
border-top: 1rpx solid #E3E3E3;
|
||||
|
||||
text {
|
||||
font-weight: 500;
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
|
||||
.distance {
|
||||
float: right;
|
||||
background: rgba(48, 114, 246, .1);
|
||||
border-radius: 25rpx;
|
||||
font-weight: bold;
|
||||
font-size: 24rpx;
|
||||
color: #3072F6;
|
||||
padding: 0 10rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tabs {
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
position: relative;
|
||||
|
||||
.tab-item {
|
||||
color: #40C5A8;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0rpx 0rpx 20rpx 1rpx rgba(53, 127, 251, 0.1);
|
||||
border-radius: 20rpx 20rpx 20rpx 20rpx;
|
||||
width: 334rpx;
|
||||
height: 90rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.icon {
|
||||
font-weight: bold;
|
||||
font-size: 26rpx;
|
||||
color: #FFFFFF;
|
||||
padding: 8rpx 10rpx;
|
||||
margin-right: 10rpx;
|
||||
background: #40C5A8;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.text {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
position: absolute;
|
||||
width: 30rpx;
|
||||
height: 30rpx;
|
||||
bottom: -2rpx;
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.tab-item.slow {
|
||||
color: #FC8229;
|
||||
|
||||
.icon {
|
||||
background: #FC8229;
|
||||
}
|
||||
}
|
||||
|
||||
.tab-item.active {
|
||||
background: #40C5A8;
|
||||
|
||||
.icon {
|
||||
color: #40C5A8;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.text {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.tab-item.active.slow {
|
||||
background: #FC8229;
|
||||
|
||||
.icon {
|
||||
color: #FC8229;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.price-container {
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-weight: 800;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.line {
|
||||
width: 8rpx;
|
||||
height: 32rpx;
|
||||
background: #3072F6;
|
||||
border-radius: 0rpx 0rpx 0rpx 0rpx;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.detail {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 26rpx;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.time {
|
||||
font-size: 24rpx;
|
||||
color: #333333;
|
||||
margin: 26rpx 0;
|
||||
}
|
||||
|
||||
.price {
|
||||
font-size: 24rpx;
|
||||
color: #333;
|
||||
display: inline-block;
|
||||
margin-right: 18rpx;
|
||||
vertical-align: middle;
|
||||
|
||||
text {
|
||||
font-size: 40rpx;
|
||||
color: #EB5336;
|
||||
}
|
||||
}
|
||||
|
||||
.vip {
|
||||
width: 194rpx;
|
||||
height: 45rpx;
|
||||
background: linear-gradient(180deg, #FADBB7 0%, #F6BA85 100%);
|
||||
border-radius: 10rpx 10rpx 10rpx 10rpx;
|
||||
display: inline-block;
|
||||
|
||||
image {
|
||||
width: 82rpx;
|
||||
height: 45rpx;
|
||||
}
|
||||
|
||||
text {
|
||||
font-size: 24rpx;
|
||||
color: #3A3E5E;
|
||||
}
|
||||
}
|
||||
|
||||
.tip {
|
||||
padding-top: 20rpx;
|
||||
border-top: 1rpx solid #E3E3E3;
|
||||
margin-top: 14rpx;
|
||||
|
||||
image {
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
}
|
||||
|
||||
text {
|
||||
font-weight: 500;
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.list-container {
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-weight: 800;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.line {
|
||||
width: 8rpx;
|
||||
height: 32rpx;
|
||||
background: #3072F6;
|
||||
border-radius: 0rpx 0rpx 0rpx 0rpx;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.detail {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 26rpx;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.time {
|
||||
font-size: 24rpx;
|
||||
color: #333333;
|
||||
margin: 26rpx 0;
|
||||
}
|
||||
}
|
||||
|
||||
.list-item {
|
||||
display: flex;
|
||||
padding: 30rpx 0;
|
||||
color: #333333;
|
||||
align-items: center;
|
||||
|
||||
&:not(:last-child) {
|
||||
border-bottom: 1rpx solid #E3E3E3;
|
||||
}
|
||||
|
||||
.status {
|
||||
width: 98rpx;
|
||||
height: 98rpx;
|
||||
border-radius: 50%;
|
||||
border-width: 6rpx;
|
||||
border-style: solid;
|
||||
border-color: rgba(48, 114, 246, 0.4);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 20rpx;
|
||||
font-size: 28rpx;
|
||||
color: #3072F6;
|
||||
|
||||
&.idle {
|
||||
border-color: rgba(64, 197, 168, 0.4);
|
||||
color: #40C5A8;
|
||||
}
|
||||
|
||||
&.hitch {
|
||||
border-color: rgba(184, 184, 184, 0.4);
|
||||
color: red;
|
||||
}
|
||||
|
||||
&.plug {
|
||||
border-color: rgba(13, 192, 226, 0.4);
|
||||
color: #0DC0E2;
|
||||
}
|
||||
|
||||
&.charging {
|
||||
border-color: rgba(13, 192, 226, 0.4);
|
||||
color: #0d22e2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.name {
|
||||
font-weight: bold;
|
||||
font-size: 28rpx;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.remark {
|
||||
font-size: 24rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,220 @@
|
||||
<!-- 我的商品收藏 -->
|
||||
<template>
|
||||
<s-layout title="收藏站点">
|
||||
<view class="cart-box ss-flex ss-flex-col ss-row-between">
|
||||
<!-- 头部 -->
|
||||
<view class="cart-header ss-flex ss-col-center ss-row-between ss-p-x-30">
|
||||
<view class="header-left ss-flex ss-col-center ss-font-26">
|
||||
共
|
||||
<text class="goods-number ui-TC-Main ss-flex">{{ state.pagination.total }}</text> 个站点
|
||||
</view>
|
||||
<view class="header-right">
|
||||
<button v-if="state.editMode && state.pagination.total" class="ss-reset-button" @tap="state.editMode = false">
|
||||
取消
|
||||
</button>
|
||||
<button v-if="!state.editMode && state.pagination.total" class="ss-reset-button ui-TC-Main"
|
||||
@tap="state.editMode = true">
|
||||
编辑
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 内容 -->
|
||||
<view class="cart-content">
|
||||
<kx-station-info v-for="item in state.pagination.list" :station="item.stationInfoVO"
|
||||
:key="item.id"></kx-station-info>
|
||||
<!-- <view class="goods-box ss-r-10 ss-m-b-14" v-for="item in state.pagination.list" :key="item.id">
|
||||
<view class="ss-flex ss-col-center">
|
||||
<label class="check-box ss-flex ss-col-center ss-p-l-10" v-if="state.editMode" @tap="onSelect(item.id)">
|
||||
<radio :checked="state.selectedCollectList.includes(item.id)" color="var(--ui-BG-Main)"
|
||||
style="transform: scale(0.8)" @tap.stop="onSelect(item.id)" />
|
||||
</label>
|
||||
<s-goods-item :title="item.spuName" :img="item.picUrl" :price="item.price" priceColor="#FF3000"
|
||||
:titleWidth="400" @tap="
|
||||
sheep.$router.go('/pages/goods/index', {
|
||||
id: item.spuId,
|
||||
})
|
||||
" />
|
||||
</view>
|
||||
</view> -->
|
||||
</view>
|
||||
|
||||
<!-- 底部 -->
|
||||
<su-fixed bottom :val="0" placeholder v-show="state.editMode">
|
||||
<view class="cart-footer ss-flex ss-col-center ss-row-between ss-p-x-30 border-bottom">
|
||||
<view class="footer-left ss-flex ss-col-center">
|
||||
<label class="check-box ss-flex ss-col-center ss-p-r-30" @tap="onSelectAll">
|
||||
<radio :checked="state.selectAll" color="var(--ui-BG-Main)" style="transform: scale(0.7)"
|
||||
@tap.stop="onSelectAll" />
|
||||
<view> 全选 </view>
|
||||
</label>
|
||||
</view>
|
||||
<view class="footer-right">
|
||||
<button class="ss-reset-button ui-BG-Main-Gradient pay-btn ss-font-28 ui-Shadow-Main" @tap="onCancel">
|
||||
取消收藏
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</su-fixed>
|
||||
</view>
|
||||
<uni-load-more v-if="state.pagination.total > 0" :status="state.loadStatus" :content-text="{
|
||||
contentdown: '上拉加载更多',
|
||||
}" @tap="loadMore" />
|
||||
<s-empty v-if="state.pagination.total === 0" text="暂无收藏" icon="/static/collect-empty.png" />
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import sheep from '@/sheep';
|
||||
import {
|
||||
reactive
|
||||
} from 'vue';
|
||||
import {
|
||||
onLoad,
|
||||
onReachBottom
|
||||
} from '@dcloudio/uni-app';
|
||||
import _ from 'lodash-es';
|
||||
import {
|
||||
getFavoritePage,
|
||||
deleteFavorite
|
||||
} from '@/sheep/api/charge/operations';
|
||||
import {
|
||||
resetPagination
|
||||
} from '@/sheep/util';
|
||||
|
||||
const sys_navBar = sheep.$platform.navbar;
|
||||
|
||||
const state = reactive({
|
||||
pagination: {
|
||||
list: [],
|
||||
total: 0,
|
||||
pageNo: 1,
|
||||
pageSize: 6,
|
||||
},
|
||||
loadStatus: '',
|
||||
|
||||
editMode: false,
|
||||
selectedCollectList: [], // 选中的 SPU 数组
|
||||
selectAll: false,
|
||||
});
|
||||
|
||||
async function getData() {
|
||||
state.loadStatus = 'loading';
|
||||
const res = await sheep.$store('user').getLocation()
|
||||
const {
|
||||
latitude,
|
||||
longitude
|
||||
} = res
|
||||
const {
|
||||
code,
|
||||
data
|
||||
} = await getFavoritePage({
|
||||
pageNo: state.pagination.pageNo,
|
||||
pageSize: state.pagination.pageSize,
|
||||
latitude,
|
||||
longitude
|
||||
});
|
||||
if (code !== 0) {
|
||||
return;
|
||||
}
|
||||
state.pagination.list = _.concat(state.pagination.list, data.list);
|
||||
state.pagination.total = data.total;
|
||||
state.loadStatus = state.pagination.list.length < state.pagination.total ? 'more' : 'noMore';
|
||||
}
|
||||
|
||||
// 单选选中
|
||||
const onSelect = (spuId) => {
|
||||
if (!state.selectedCollectList.includes(spuId)) {
|
||||
state.selectedCollectList.push(spuId);
|
||||
} else {
|
||||
state.selectedCollectList.splice(state.selectedCollectList.indexOf(spuId), 1);
|
||||
}
|
||||
state.selectAll = state.selectedCollectList.length === state.pagination.list.length;
|
||||
};
|
||||
|
||||
// 全选
|
||||
const onSelectAll = () => {
|
||||
state.selectAll = !state.selectAll;
|
||||
if (!state.selectAll) {
|
||||
state.selectedCollectList = [];
|
||||
} else {
|
||||
state.selectedCollectList = state.pagination.list.map((item) => item.spuId);
|
||||
}
|
||||
};
|
||||
|
||||
async function onCancel() {
|
||||
if (!state.selectedCollectList) {
|
||||
return;
|
||||
}
|
||||
// 取消收藏
|
||||
for (const id of state.selectedCollectList) {
|
||||
await deleteFavorite(id);
|
||||
}
|
||||
|
||||
// 清空选择 + 重新加载
|
||||
state.editMode = false;
|
||||
state.selectedCollectList = [];
|
||||
state.selectAll = false;
|
||||
resetPagination(state.pagination);
|
||||
await getData();
|
||||
}
|
||||
|
||||
// 加载更多
|
||||
function loadMore() {
|
||||
if (state.loadStatus === 'noMore') {
|
||||
return;
|
||||
}
|
||||
state.pagination.pageNo++;
|
||||
getData();
|
||||
}
|
||||
|
||||
onReachBottom(() => {
|
||||
loadMore();
|
||||
});
|
||||
|
||||
onLoad(() => {
|
||||
getData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.cart-box {
|
||||
.cart-header {
|
||||
height: 70rpx;
|
||||
// background-color: #f6f6f6;
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: v-bind('sys_navBar') rpx;
|
||||
z-index: 1000;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.cart-footer {
|
||||
height: 100rpx;
|
||||
background-color: #fff;
|
||||
|
||||
.pay-btn {
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
border-radius: 40rpx;
|
||||
padding: 0 40rpx;
|
||||
min-width: 200rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.cart-content {
|
||||
width: 100%;
|
||||
margin-top: 70rpx;
|
||||
// padding: 0 20rpx;
|
||||
box-sizing: border-box;
|
||||
|
||||
.goods-box {
|
||||
background-color: #fff;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,308 @@
|
||||
<!-- 商品浏览记录 -->
|
||||
<template>
|
||||
<s-layout title="我的足迹" :bgStyle="{ color: '#f2f2f2' }">
|
||||
<view class="cart-box ss-flex ss-flex-col ss-row-between">
|
||||
<!-- 头部 -->
|
||||
<view class="cart-header ss-flex ss-col-center ss-row-between ss-p-x-30">
|
||||
<view class="header-left ss-flex ss-col-center ss-font-26">
|
||||
共
|
||||
<text class="goods-number ui-TC-Main ss-flex">
|
||||
{{ state.pagination.total }}
|
||||
</text>
|
||||
件商品
|
||||
</view>
|
||||
<view class="header-right">
|
||||
<button
|
||||
v-if="state.editMode && state.pagination.total"
|
||||
class="ss-reset-button"
|
||||
@tap="state.editMode = false"
|
||||
>
|
||||
取消
|
||||
</button>
|
||||
<button
|
||||
v-if="!state.editMode && state.pagination.total"
|
||||
class="ss-reset-button ui-TC-Main"
|
||||
@tap="state.editMode = true"
|
||||
>
|
||||
编辑
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 内容 -->
|
||||
<view class="cart-content">
|
||||
<view
|
||||
class="goods-box ss-r-10 ss-m-b-14"
|
||||
v-for="item in state.pagination.list"
|
||||
:key="item.id"
|
||||
>
|
||||
<view class="ss-flex ss-col-center">
|
||||
<label
|
||||
class="check-box ss-flex ss-col-center ss-p-l-10"
|
||||
v-if="state.editMode"
|
||||
@tap="onSelect(item.spuId)"
|
||||
>
|
||||
<radio
|
||||
:checked="state.selectedSpuIdList.includes(item.spuId)"
|
||||
color="var(--ui-BG-Main)"
|
||||
style="transform: scale(0.8)"
|
||||
@tap.stop="onSelect(item.spuId)"
|
||||
/>
|
||||
</label>
|
||||
<s-goods-item
|
||||
:title="item.spuName"
|
||||
:img="item.picUrl"
|
||||
:price="item.price"
|
||||
:skuText="item.introduction"
|
||||
priceColor="#FF3000"
|
||||
:titleWidth="400"
|
||||
@tap="
|
||||
sheep.$router.go('/pages/goods/index', {
|
||||
id: item.spuId,
|
||||
})
|
||||
"
|
||||
>
|
||||
</s-goods-item>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 底部 -->
|
||||
<su-fixed bottom :val="0" placeholder v-show="state.editMode">
|
||||
<view class="cart-footer ss-flex ss-col-center ss-row-between ss-p-x-30 border-bottom">
|
||||
<view class="footer-left ss-flex ss-col-center">
|
||||
<label class="check-box ss-flex ss-col-center ss-p-r-30" @tap="onSelectAll">
|
||||
<radio
|
||||
:checked="state.selectAll"
|
||||
color="var(--ui-BG-Main)"
|
||||
style="transform: scale(0.7)"
|
||||
@tap.stop="onSelectAll"
|
||||
/>
|
||||
<view>全选</view>
|
||||
</label>
|
||||
</view>
|
||||
<view class="footer-right ss-flex">
|
||||
<button
|
||||
:class="[
|
||||
'ss-reset-button pay-btn ss-font-28 ',
|
||||
{
|
||||
'ui-BG-Main-Gradient': state.selectedSpuIdList.length > 0,
|
||||
'ui-Shadow-Main': state.selectedSpuIdList.length > 0,
|
||||
},
|
||||
]"
|
||||
@tap="onDelete"
|
||||
>
|
||||
删除足迹
|
||||
</button>
|
||||
<button
|
||||
class="ss-reset-button ui-BG-Main-Gradient pay-btn ss-font-28 ui-Shadow-Main ml-2"
|
||||
@tap="onClean"
|
||||
>
|
||||
清空
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</su-fixed>
|
||||
</view>
|
||||
<uni-load-more
|
||||
v-if="state.pagination.total > 0"
|
||||
:status="state.loadStatus"
|
||||
:content-text="{
|
||||
contentdown: '上拉加载更多',
|
||||
}"
|
||||
@tap="loadMore"
|
||||
/>
|
||||
<s-empty
|
||||
v-if="state.pagination.total === 0"
|
||||
text="暂无浏览记录"
|
||||
icon="/static/collect-empty.png"
|
||||
/>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import sheep from '@/sheep';
|
||||
import { reactive } from 'vue';
|
||||
import { onLoad, onReachBottom } from '@dcloudio/uni-app';
|
||||
import _ from 'lodash-es';
|
||||
import SpuHistoryApi from '@/sheep/api/product/history';
|
||||
import { cloneDeep } from '@/sheep/helper/utils';
|
||||
|
||||
const sys_navBar = sheep.$platform.navbar;
|
||||
const pagination = {
|
||||
list: [],
|
||||
pageNo: 1,
|
||||
total: 1,
|
||||
pageSize: 10,
|
||||
};
|
||||
const state = reactive({
|
||||
pagination: cloneDeep(pagination),
|
||||
loadStatus: '',
|
||||
editMode: false,
|
||||
selectedSpuIdList: [],
|
||||
selectAll: false,
|
||||
});
|
||||
|
||||
async function getList() {
|
||||
state.loadStatus = 'loading';
|
||||
const { code, data } = await SpuHistoryApi.getBrowseHistoryPage({
|
||||
pageNo: state.pagination.pageNo,
|
||||
pageSize: state.pagination.pageSize,
|
||||
});
|
||||
if (code !== 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
state.pagination.list = _.concat(state.pagination.list, data.list);
|
||||
state.pagination.total = data.total;
|
||||
state.loadStatus = state.pagination.list.length < state.pagination.total ? 'more' : 'noMore';
|
||||
}
|
||||
|
||||
// 单选选中
|
||||
const onSelect = (id) => {
|
||||
if (!state.selectedSpuIdList.includes(id)) {
|
||||
state.selectedSpuIdList.push(id);
|
||||
} else {
|
||||
state.selectedSpuIdList.splice(state.selectedSpuIdList.indexOf(id), 1);
|
||||
}
|
||||
state.selectAll = state.selectedSpuIdList.length === state.pagination.list.length;
|
||||
};
|
||||
|
||||
// 全选
|
||||
const onSelectAll = () => {
|
||||
state.selectAll = !state.selectAll;
|
||||
if (!state.selectAll) {
|
||||
state.selectedSpuIdList = [];
|
||||
} else {
|
||||
state.pagination.list.forEach((item) => {
|
||||
if (state.selectedSpuIdList.includes(item.spuId)) {
|
||||
state.selectedSpuIdList.splice(state.selectedSpuIdList.indexOf(item.spuId), 1);
|
||||
}
|
||||
state.selectedSpuIdList.push(item.spuId);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 删除足迹
|
||||
async function onDelete() {
|
||||
if (state.selectedSpuIdList.length <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { code } = await SpuHistoryApi.deleteBrowseHistory(state.selectedSpuIdList);
|
||||
if (code === 0) {
|
||||
reload();
|
||||
}
|
||||
}
|
||||
|
||||
// 清空
|
||||
async function onClean() {
|
||||
const { code } = await SpuHistoryApi.cleanBrowseHistory();
|
||||
if (code === 0) {
|
||||
reload();
|
||||
}
|
||||
}
|
||||
|
||||
function reload() {
|
||||
state.editMode = false;
|
||||
state.selectedSpuIdList = [];
|
||||
state.selectAll = false;
|
||||
state.pagination = pagination;
|
||||
getList();
|
||||
}
|
||||
|
||||
// 加载更多
|
||||
function loadMore() {
|
||||
if (state.loadStatus !== 'noMore') {
|
||||
state.pagination.pageNo += 1;
|
||||
getList();
|
||||
}
|
||||
}
|
||||
|
||||
onReachBottom(() => {
|
||||
loadMore();
|
||||
});
|
||||
|
||||
onLoad(() => {
|
||||
getList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.cart-box {
|
||||
.cart-header {
|
||||
height: 70rpx;
|
||||
background-color: #f6f6f6;
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: v-bind('sys_navBar') rpx;
|
||||
z-index: 1000;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.cart-footer {
|
||||
height: 100rpx;
|
||||
background-color: #fff;
|
||||
|
||||
.pay-btn {
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
border-radius: 40rpx;
|
||||
padding: 0 40rpx;
|
||||
min-width: 200rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.cart-content {
|
||||
width: 100%;
|
||||
padding: 0 20rpx;
|
||||
box-sizing: border-box;
|
||||
margin-top: 70rpx;
|
||||
.goods-box {
|
||||
background-color: #fff;
|
||||
&:last-child {
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.title-card {
|
||||
padding: 36rpx 0 46rpx 20rpx;
|
||||
|
||||
.img-box {
|
||||
width: 164rpx;
|
||||
height: 164rpx;
|
||||
|
||||
.order-img {
|
||||
width: 164rpx;
|
||||
height: 164rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.check-box {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.title-text {
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.params-box {
|
||||
.params-title {
|
||||
height: 38rpx;
|
||||
background: #f4f4f4;
|
||||
border-radius: 2rpx;
|
||||
font-size: 24rpx;
|
||||
font-weight: 400;
|
||||
color: #666666;
|
||||
}
|
||||
}
|
||||
|
||||
.price-text {
|
||||
color: $red;
|
||||
font-family: OPPOSANS;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,282 @@
|
||||
<template>
|
||||
<s-layout title="选择自提门店" :bgStyle="{ color: '#FFF' }">
|
||||
<view class="storeBox" ref="container">
|
||||
<view
|
||||
class="storeBox-box"
|
||||
v-for="(item, index) in state.storeList"
|
||||
:key="index"
|
||||
@tap="checked(item)"
|
||||
>
|
||||
<view class="store-img">
|
||||
<image :src="item.logo" class="img" />
|
||||
</view>
|
||||
<view class="store-cent-left">
|
||||
<view class="store-name">{{ item.name }}</view>
|
||||
<view class="store-address line1">
|
||||
{{ item.areaName }}{{ ', ' + item.detailAddress }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="row-right ss-flex-col ss-col-center">
|
||||
<view>
|
||||
<!-- #ifdef H5 -->
|
||||
<a class="store-phone" :href="'tel:' + item.phone">
|
||||
<view class="iconfont">
|
||||
<view class="ss-rest-button">
|
||||
<text class="_icon-forward" />
|
||||
</view>
|
||||
</view>
|
||||
</a>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef MP -->
|
||||
<view class="store-phone" @click="call(item.phone)">
|
||||
<view class="iconfont">
|
||||
<view class="ss-rest-button">
|
||||
<text class="_icon-forward" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
<view class="store-distance ss-flex ss-row-center" @tap.stop="showMaoLocation(item)">
|
||||
<text class="addressTxt" v-if="item.distance">
|
||||
距离{{ item.distance.toFixed(2) }}千米
|
||||
</text>
|
||||
<text class="addressTxt" v-else>查看地图</text>
|
||||
<view class="iconfont">
|
||||
<view class="ss-rest-button">
|
||||
<text class="_icon-forward" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import DeliveryApi from '@/sheep/api/trade/delivery';
|
||||
import { onMounted, reactive } from 'vue';
|
||||
import { onLoad } from '@dcloudio/uni-app';
|
||||
import sheep from '@/sheep';
|
||||
|
||||
const LONGITUDE = 'user_longitude';
|
||||
const LATITUDE = 'user_latitude';
|
||||
const state = reactive({
|
||||
loaded: false,
|
||||
loading: false,
|
||||
storeList: [],
|
||||
system_store: {},
|
||||
locationShow: false,
|
||||
user_latitude: 0,
|
||||
user_longitude: 0,
|
||||
});
|
||||
|
||||
const call = (phone) => {
|
||||
uni.makePhoneCall({
|
||||
phoneNumber: phone,
|
||||
});
|
||||
};
|
||||
const selfLocation = () => {
|
||||
// #ifdef H5
|
||||
const jsWxSdk = sheep.$platform.useProvider('wechat').jsWxSdk;
|
||||
if (jsWxSdk.isWechat()) {
|
||||
jsWxSdk.getLocation((res) => {
|
||||
state.user_latitude = res.latitude;
|
||||
state.user_longitude = res.longitude;
|
||||
uni.setStorageSync(LATITUDE, res.latitude);
|
||||
uni.setStorageSync(LONGITUDE, res.longitude);
|
||||
getList();
|
||||
});
|
||||
} else {
|
||||
// #endif
|
||||
uni.getLocation({
|
||||
type: 'gcj02',
|
||||
success: (res) => {
|
||||
try {
|
||||
state.user_latitude = res.latitude;
|
||||
state.user_longitude = res.longitude;
|
||||
uni.setStorageSync(LATITUDE, res.latitude);
|
||||
uni.setStorageSync(LONGITUDE, res.longitude);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
getList();
|
||||
},
|
||||
complete: () => {
|
||||
getList();
|
||||
},
|
||||
});
|
||||
// #ifdef H5
|
||||
}
|
||||
// #endif
|
||||
};
|
||||
const showMaoLocation = (e) => {
|
||||
// #ifdef H5
|
||||
const jsWxSdk = sheep.$platform.useProvider('wechat').jsWxSdk;
|
||||
if (jsWxSdk.isWechat()) {
|
||||
jsWxSdk.openLocation({
|
||||
latitude: Number(e.latitude),
|
||||
longitude: Number(e.longitude),
|
||||
name: e.name,
|
||||
address: `${e.areaName}-${e.detailAddress}`,
|
||||
});
|
||||
} else {
|
||||
// #endif
|
||||
uni.openLocation({
|
||||
latitude: Number(e.latitude),
|
||||
longitude: Number(e.longitude),
|
||||
name: e.name,
|
||||
address: `${e.areaName}-${e.detailAddress}`,
|
||||
success: function () {
|
||||
console.log('success');
|
||||
},
|
||||
});
|
||||
// #ifdef H5
|
||||
}
|
||||
// #endif
|
||||
};
|
||||
|
||||
/**
|
||||
* 选中门店
|
||||
*/
|
||||
const checked = (addressInfo) => {
|
||||
uni.$emit('SELECT_PICK_UP_INFO', {
|
||||
addressInfo,
|
||||
});
|
||||
sheep.$router.back();
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取门店列表数据
|
||||
*/
|
||||
const getList = async () => {
|
||||
if (state.loading || state.loaded) {
|
||||
return;
|
||||
}
|
||||
state.loading = true;
|
||||
const { data, code } = await DeliveryApi.getDeliveryPickUpStoreList({
|
||||
latitude: state.user_latitude,
|
||||
longitude: state.user_longitude,
|
||||
});
|
||||
if (code !== 0) {
|
||||
return;
|
||||
}
|
||||
state.loading = false;
|
||||
state.storeList = data;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
if (state.user_latitude && state.user_longitude) {
|
||||
getList();
|
||||
} else {
|
||||
selfLocation();
|
||||
getList();
|
||||
}
|
||||
});
|
||||
onLoad(() => {
|
||||
try {
|
||||
state.user_latitude = uni.getStorageSync(LATITUDE);
|
||||
state.user_longitude = uni.getStorageSync(LONGITUDE);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.line1 {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.geoPage {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
z-index: 10000;
|
||||
}
|
||||
|
||||
.storeBox {
|
||||
width: 100%;
|
||||
background-color: #fff;
|
||||
padding: 0 30rpx;
|
||||
}
|
||||
|
||||
.storeBox-box {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 23rpx 0;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.store-cent {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.store-cent-left {
|
||||
//width: 45%;
|
||||
flex: 2;
|
||||
}
|
||||
|
||||
.store-img {
|
||||
flex: 1;
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 6rpx;
|
||||
margin-right: 22rpx;
|
||||
}
|
||||
|
||||
.store-img .img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.store-name {
|
||||
color: #282828;
|
||||
font-size: 30rpx;
|
||||
margin-bottom: 22rpx;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.store-address {
|
||||
color: #666666;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.store-phone {
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
color: #fff;
|
||||
border-radius: 50%;
|
||||
display: block;
|
||||
text-align: center;
|
||||
line-height: 48rpx;
|
||||
background-color: #e83323;
|
||||
margin-bottom: 22rpx;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.store-distance {
|
||||
font-size: 22rpx;
|
||||
color: #e83323;
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-size: 20rpx;
|
||||
}
|
||||
|
||||
.row-right {
|
||||
flex: 2;
|
||||
//display: flex;
|
||||
//flex-direction: column;
|
||||
//align-items: flex-end;
|
||||
//width: 33.5%;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,470 @@
|
||||
<!-- 用户信息 -->
|
||||
<template>
|
||||
<s-layout title="用户信息" class="set-userinfo-wrap">
|
||||
<uni-forms
|
||||
:model="state.model"
|
||||
:rules="state.rules"
|
||||
labelPosition="left"
|
||||
border
|
||||
class="form-box"
|
||||
>
|
||||
<!-- 头像 -->
|
||||
<view class="ss-flex ss-row-center ss-col-center ss-p-t-60 ss-p-b-0 bg-white">
|
||||
<view class="header-box-content">
|
||||
<su-image
|
||||
class="content-img"
|
||||
isPreview
|
||||
:current="0"
|
||||
:src="state.model?.avatar"
|
||||
:height="160"
|
||||
:width="160"
|
||||
:radius="80"
|
||||
mode="scaleToFill"
|
||||
/>
|
||||
<view class="avatar-action">
|
||||
<!-- #ifdef MP -->
|
||||
<button
|
||||
class="ss-reset-button avatar-action-btn"
|
||||
open-type="chooseAvatar"
|
||||
@chooseavatar="onChooseAvatar"
|
||||
>
|
||||
修改
|
||||
</button>
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef MP -->
|
||||
<button class="ss-reset-button avatar-action-btn" @tap="onChangeAvatar">修改</button>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="bg-white ss-p-x-30">
|
||||
<!-- 昵称 + 性别 -->
|
||||
<uni-forms-item name="nickname" label="昵称">
|
||||
<uni-easyinput
|
||||
v-model="state.model.nickname"
|
||||
type="nickname"
|
||||
placeholder="设置昵称"
|
||||
:inputBorder="false"
|
||||
:placeholderStyle="placeholderStyle"
|
||||
/>
|
||||
</uni-forms-item>
|
||||
<uni-forms-item name="sex" label="性别">
|
||||
<view class="ss-flex ss-col-center ss-h-100">
|
||||
<radio-group @change="onChangeGender" class="ss-flex ss-col-center">
|
||||
<label class="radio" v-for="item in sexRadioMap" :key="item.value">
|
||||
<view class="ss-flex ss-col-center ss-m-r-32">
|
||||
<radio
|
||||
:value="item.value"
|
||||
color="var(--ui-BG-Main)"
|
||||
style="transform: scale(0.8)"
|
||||
:checked="parseInt(item.value) === state.model?.sex"
|
||||
/>
|
||||
<view class="gender-name">{{ item.name }}</view>
|
||||
</view>
|
||||
</label>
|
||||
</radio-group>
|
||||
</view>
|
||||
</uni-forms-item>
|
||||
|
||||
<uni-forms-item name="mobile" label="手机号" @tap="onChangeMobile">
|
||||
<uni-easyinput
|
||||
v-model="userInfo.mobile"
|
||||
placeholder="请绑定手机号"
|
||||
:inputBorder="false"
|
||||
disabled
|
||||
:styles="{ disableColor: '#fff' }"
|
||||
:placeholderStyle="placeholderStyle"
|
||||
:clearable="false"
|
||||
>
|
||||
<template v-slot:right>
|
||||
<view class="ss-flex ss-col-center">
|
||||
<su-radio v-if="userInfo.verification?.mobile" :modelValue="true" />
|
||||
<button v-else class="ss-reset-button ss-flex ss-col-center ss-row-center">
|
||||
<text class="_icon-forward" style="color: #bbbbbb; font-size: 26rpx"></text>
|
||||
</button>
|
||||
</view>
|
||||
</template>
|
||||
</uni-easyinput>
|
||||
</uni-forms-item>
|
||||
|
||||
<uni-forms-item name="password" label="登录密码" @tap="onSetPassword">
|
||||
<uni-easyinput
|
||||
v-model="userInfo.password"
|
||||
placeholder="点击修改登录密码"
|
||||
:inputBorder="false"
|
||||
:styles="{ disableColor: '#fff' }"
|
||||
disabled
|
||||
placeholderStyle="color:#BBBBBB;font-size:28rpx;line-height:normal"
|
||||
:clearable="false"
|
||||
>
|
||||
<template v-slot:right>
|
||||
<view class="ss-flex ss-col-center">
|
||||
<su-radio
|
||||
class="ss-flex"
|
||||
v-if="userInfo.verification?.password"
|
||||
:modelValue="true"
|
||||
/>
|
||||
<button v-else class="ss-reset-button ss-flex ss-col-center ss-row-center">
|
||||
<text class="_icon-forward" style="color: #bbbbbb; font-size: 26rpx" />
|
||||
</button>
|
||||
</view>
|
||||
</template>
|
||||
</uni-easyinput>
|
||||
</uni-forms-item>
|
||||
</view>
|
||||
|
||||
<view class="bg-white ss-m-t-14">
|
||||
<uni-list>
|
||||
<uni-list-item
|
||||
clickable
|
||||
@tap="sheep.$router.go('/pages/user/address/list')"
|
||||
title="地址管理"
|
||||
showArrow
|
||||
:border="false"
|
||||
class="list-border"
|
||||
/>
|
||||
</uni-list>
|
||||
</view>
|
||||
</uni-forms>
|
||||
|
||||
<!-- 当前社交平台的绑定关系,只处理 wechat 微信场景 -->
|
||||
<view v-if="sheep.$platform.name !== 'H5'">
|
||||
<view class="title-box ss-p-l-30">第三方账号绑定</view>
|
||||
<view class="account-list ss-flex ss-row-between">
|
||||
<view v-if="'WechatOfficialAccount' === sheep.$platform.name" class="ss-flex ss-col-center">
|
||||
<image
|
||||
class="list-img"
|
||||
:src="sheep.$url.static('/static/img/shop/platform/WechatOfficialAccount.png')"
|
||||
/>
|
||||
<text class="list-name">微信公众号</text>
|
||||
</view>
|
||||
<view v-if="'WechatMiniProgram' === sheep.$platform.name" class="ss-flex ss-col-center">
|
||||
<image
|
||||
class="list-img"
|
||||
:src="sheep.$url.static('/static/img/shop/platform/WechatMiniProgram.png')"
|
||||
/>
|
||||
<text class="list-name">微信小程序</text>
|
||||
</view>
|
||||
<view v-if="'App' === sheep.$platform.name" class="ss-flex ss-col-center">
|
||||
<image
|
||||
class="list-img"
|
||||
:src="sheep.$url.static('/static/img/shop/platform/wechat.png')"
|
||||
/>
|
||||
<text class="list-name">微信开放平台</text>
|
||||
</view>
|
||||
<view class="ss-flex ss-col-center">
|
||||
<view class="info ss-flex ss-col-center" v-if="state.thirdInfo">
|
||||
<image class="avatar ss-m-r-20" :src="sheep.$url.cdn(state.thirdInfo.avatar)" />
|
||||
<text class="name">{{ state.thirdInfo.nickname }}</text>
|
||||
</view>
|
||||
<view class="bind-box ss-m-l-20">
|
||||
<button
|
||||
v-if="state.thirdInfo.openid"
|
||||
class="ss-reset-button relieve-btn"
|
||||
@tap="unBindThirdOauth"
|
||||
>
|
||||
解绑
|
||||
</button>
|
||||
<button v-else class="ss-reset-button bind-btn" @tap="bindThirdOauth">绑定</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<su-fixed bottom placeholder bg="none">
|
||||
<view class="footer-box ss-p-20">
|
||||
<button class="ss-rest-button logout-btn ui-Shadow-Main" @tap="onSubmit">保存</button>
|
||||
</view>
|
||||
</su-fixed>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, reactive, onBeforeMount } from 'vue';
|
||||
import sheep from '@/sheep';
|
||||
import { clone } from 'lodash-es';
|
||||
import { showAuthModal } from '@/sheep/hooks/useModal';
|
||||
import FileApi from '@/sheep/api/infra/file';
|
||||
import UserApi from '@/sheep/api/member/user';
|
||||
|
||||
const state = reactive({
|
||||
model: {}, // 个人信息
|
||||
rules: {},
|
||||
thirdInfo: {}, // 社交用户的信息
|
||||
});
|
||||
|
||||
const placeholderStyle = 'color:#BBBBBB;font-size:28rpx;line-height:normal';
|
||||
|
||||
const sexRadioMap = [
|
||||
{
|
||||
name: '男',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
name: '女',
|
||||
value: '2',
|
||||
},
|
||||
];
|
||||
|
||||
const userInfo = computed(() => sheep.$store('user').userInfo);
|
||||
|
||||
// 选择性别
|
||||
function onChangeGender(e) {
|
||||
state.model.sex = e.detail.value;
|
||||
}
|
||||
|
||||
// 修改手机号
|
||||
const onChangeMobile = () => {
|
||||
showAuthModal('changeMobile');
|
||||
};
|
||||
|
||||
// 选择微信的头像,进行上传
|
||||
function onChooseAvatar(e) {
|
||||
const tempUrl = e.detail.avatarUrl || '';
|
||||
uploadAvatar(tempUrl);
|
||||
}
|
||||
|
||||
// 手动选择头像,进行上传
|
||||
function onChangeAvatar() {
|
||||
uni.chooseImage({
|
||||
success: async (chooseImageRes) => {
|
||||
const tempUrl = chooseImageRes.tempFilePaths[0];
|
||||
await uploadAvatar(tempUrl);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// 上传头像文件
|
||||
async function uploadAvatar(tempUrl) {
|
||||
if (!tempUrl) {
|
||||
return;
|
||||
}
|
||||
let { data } = await FileApi.uploadFile(tempUrl);
|
||||
state.model.avatar = data;
|
||||
}
|
||||
|
||||
// 修改密码
|
||||
function onSetPassword() {
|
||||
showAuthModal('changePassword');
|
||||
}
|
||||
|
||||
// 绑定第三方账号
|
||||
async function bindThirdOauth() {
|
||||
let result = await sheep.$platform.useProvider('wechat').bind();
|
||||
if (result) {
|
||||
await getUserInfo();
|
||||
}
|
||||
}
|
||||
|
||||
// 解绑第三方账号
|
||||
function unBindThirdOauth() {
|
||||
uni.showModal({
|
||||
title: '解绑提醒',
|
||||
content: '解绑后您将无法通过微信登录此账号',
|
||||
cancelText: '再想想',
|
||||
confirmText: '确定',
|
||||
success: async function (res) {
|
||||
if (!res.confirm) {
|
||||
return;
|
||||
}
|
||||
const result = await sheep.$platform.useProvider('wechat').unbind(state.thirdInfo.openid);
|
||||
if (result) {
|
||||
await getUserInfo();
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// 保存信息
|
||||
async function onSubmit() {
|
||||
const { code } = await UserApi.updateUser({
|
||||
avatar: state.model.avatar,
|
||||
nickname: state.model.nickname,
|
||||
sex: state.model.sex,
|
||||
});
|
||||
if (code === 0) {
|
||||
await getUserInfo();
|
||||
}
|
||||
}
|
||||
|
||||
// 获得用户信息
|
||||
const getUserInfo = async () => {
|
||||
// 个人信息
|
||||
const userInfo = await sheep.$store('user').getInfo();
|
||||
state.model = clone(userInfo);
|
||||
|
||||
// 获得社交用户的信息
|
||||
if (sheep.$platform.name !== 'H5') {
|
||||
const result = await sheep.$platform.useProvider('wechat').getInfo();
|
||||
state.thirdInfo = result || {};
|
||||
}
|
||||
};
|
||||
|
||||
onBeforeMount(() => {
|
||||
getUserInfo();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep() {
|
||||
.uni-file-picker {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.uni-file-picker__container {
|
||||
margin: -14rpx -12rpx;
|
||||
}
|
||||
|
||||
.file-picker__progress {
|
||||
height: 0 !important;
|
||||
}
|
||||
|
||||
.uni-list-item__content-title {
|
||||
font-size: 28rpx !important;
|
||||
color: #333333 !important;
|
||||
line-height: normal !important;
|
||||
}
|
||||
|
||||
.uni-icons {
|
||||
font-size: 40rpx !important;
|
||||
}
|
||||
|
||||
.is-disabled {
|
||||
color: #333333;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.disabled) {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.gender-name {
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
line-height: normal;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.title-box {
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: #666666;
|
||||
line-height: 100rpx;
|
||||
}
|
||||
|
||||
.logout-btn {
|
||||
width: 710rpx;
|
||||
height: 80rpx;
|
||||
background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
|
||||
border-radius: 40rpx;
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
.radio-dark {
|
||||
filter: grayscale(100%);
|
||||
filter: gray;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.content-img {
|
||||
border-radius: 50%;
|
||||
}
|
||||
.header-box-content {
|
||||
position: relative;
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
overflow: hidden;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.avatar-action {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
bottom: 0;
|
||||
z-index: 1;
|
||||
width: 160rpx;
|
||||
height: 46rpx;
|
||||
background: rgba(#000000, 0.3);
|
||||
|
||||
.avatar-action-btn {
|
||||
width: 160rpx;
|
||||
height: 46rpx;
|
||||
font-weight: 500;
|
||||
font-size: 24rpx;
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
// 绑定项
|
||||
.account-list {
|
||||
background-color: $white;
|
||||
height: 100rpx;
|
||||
padding: 0 20rpx;
|
||||
|
||||
.list-img {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
|
||||
.list-name {
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.info {
|
||||
.avatar {
|
||||
width: 38rpx;
|
||||
height: 38rpx;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.name {
|
||||
font-size: 28rpx;
|
||||
font-weight: 400;
|
||||
color: $dark-9;
|
||||
}
|
||||
}
|
||||
|
||||
.bind-box {
|
||||
width: 100rpx;
|
||||
height: 50rpx;
|
||||
line-height: normal;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 24rpx;
|
||||
|
||||
.bind-btn {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 25rpx;
|
||||
background: #f4f4f4;
|
||||
color: #999999;
|
||||
}
|
||||
.relieve-btn {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 25rpx;
|
||||
background: var(--ui-BG-Main-opacity-1);
|
||||
color: var(--ui-BG-Main);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.list-border {
|
||||
font-size: 28rpx;
|
||||
font-weight: 400;
|
||||
color: #333333;
|
||||
border-bottom: 2rpx solid #eeeeee;
|
||||
}
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,379 @@
|
||||
<!-- 我的钱包 -->
|
||||
<template>
|
||||
<s-layout class="wallet-wrap" title="钱包">
|
||||
<!-- 钱包卡片 -->
|
||||
<view class="header-box ss-flex ss-row-center ss-col-center">
|
||||
<view class="card-box ui-BG-Main ui-Shadow-Main">
|
||||
<view class="card-head ss-flex ss-col-center">
|
||||
<view class="card-title ss-m-r-10">钱包余额(元)</view>
|
||||
<view
|
||||
@tap="state.showMoney = !state.showMoney"
|
||||
class="ss-eye-icon"
|
||||
:class="state.showMoney ? 'cicon-eye' : 'cicon-eye-off'"
|
||||
/>
|
||||
</view>
|
||||
<view class="ss-flex ss-row-between ss-col-center ss-m-t-64">
|
||||
<view class="money-num">{{
|
||||
state.showMoney ? fen2yuan(userWallet.balance) : '*****'
|
||||
}}</view>
|
||||
<button class="ss-reset-button topup-btn" @tap="sheep.$router.go('/pages/pay/recharge')">
|
||||
充值
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<su-sticky>
|
||||
<!-- 统计 -->
|
||||
<view class="filter-box ss-p-x-30 ss-flex ss-col-center ss-row-between">
|
||||
<uni-datetime-picker
|
||||
v-model="state.data"
|
||||
type="daterange"
|
||||
@change="onChangeTime"
|
||||
:end="state.today"
|
||||
>
|
||||
<button class="ss-reset-button date-btn">
|
||||
<text>{{ dateFilterText }}</text>
|
||||
<text class="cicon-drop-down ss-seldate-icon"></text>
|
||||
</button>
|
||||
</uni-datetime-picker>
|
||||
<view class="total-box">
|
||||
<view class="ss-m-b-10">总收入¥{{ fen2yuan(state.summary.totalIncome) }}</view>
|
||||
<view>总支出¥{{ fen2yuan(state.summary.totalExpense) }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<su-tabs
|
||||
:list="tabMaps"
|
||||
@change="onChange"
|
||||
:scrollable="false"
|
||||
:current="state.currentTab"
|
||||
></su-tabs>
|
||||
</su-sticky>
|
||||
<s-empty v-if="state.pagination.total === 0" text="暂无数据" icon="/static/data-empty.png" />
|
||||
|
||||
<!-- 钱包记录 -->
|
||||
<view v-if="state.pagination.total > 0">
|
||||
<view
|
||||
class="wallet-list ss-flex border-bottom"
|
||||
v-for="item in state.pagination.list"
|
||||
:key="item.id"
|
||||
>
|
||||
<view class="list-content">
|
||||
<view class="title-box ss-flex ss-row-between ss-m-b-20">
|
||||
<text class="title ss-line-1">
|
||||
{{ item.title }}
|
||||
</text>
|
||||
<view class="money">
|
||||
<text v-if="item.price >= 0" class="add">+{{ fen2yuan(item.price) }}</text>
|
||||
<text v-else class="minus">{{ fen2yuan(item.price) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<text class="time">
|
||||
{{ sheep.$helper.timeFormat(state.createTime, 'yyyy-mm-dd hh:MM:ss') }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<uni-load-more
|
||||
v-if="state.pagination.total > 0"
|
||||
:status="state.loadStatus"
|
||||
:content-text="{
|
||||
contentdown: '上拉加载更多',
|
||||
}"
|
||||
/>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, reactive } from 'vue';
|
||||
import { onLoad, onReachBottom } from '@dcloudio/uni-app';
|
||||
import sheep from '@/sheep';
|
||||
import dayjs from 'dayjs';
|
||||
import _ from 'lodash-es';
|
||||
import PayWalletApi from '@/sheep/api/pay/wallet';
|
||||
import { fen2yuan } from '@/sheep/hooks/useGoods';
|
||||
import { resetPagination } from '@/sheep/util';
|
||||
|
||||
const headerBg = sheep.$url.css('/static/img/shop/user/wallet_card_bg.png');
|
||||
|
||||
// 数据
|
||||
const state = reactive({
|
||||
showMoney: false,
|
||||
date: [], // 筛选的时间段
|
||||
currentTab: 0,
|
||||
pagination: {
|
||||
list: [],
|
||||
total: 0,
|
||||
pageNo: 1,
|
||||
pageSize: 8,
|
||||
},
|
||||
summary: {
|
||||
totalIncome: 0,
|
||||
totalExpense: 0,
|
||||
},
|
||||
loadStatus: '',
|
||||
today: '',
|
||||
});
|
||||
|
||||
const tabMaps = [
|
||||
{
|
||||
name: '全部',
|
||||
value: '',
|
||||
},
|
||||
{
|
||||
name: '收入',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
name: '支出',
|
||||
value: '2',
|
||||
},
|
||||
];
|
||||
|
||||
const userWallet = computed(() => sheep.$store('user').userWallet);
|
||||
|
||||
// 格式化时间段
|
||||
const dateFilterText = computed(() => {
|
||||
if (state.date[0] === state.date[1]) {
|
||||
return state.date[0];
|
||||
} else {
|
||||
return state.date.join('~');
|
||||
}
|
||||
});
|
||||
|
||||
// 获得钱包记录分页
|
||||
async function getLogList() {
|
||||
state.loadStatus = 'loading';
|
||||
const { data, code } = await PayWalletApi.getWalletTransactionPage({
|
||||
pageNo: state.pagination.pageNo,
|
||||
pageSize: state.pagination.pageSize,
|
||||
type: tabMaps[state.currentTab].value,
|
||||
'createTime[0]': state.date[0] + ' 00:00:00',
|
||||
'createTime[1]': state.date[1] + ' 23:59:59',
|
||||
});
|
||||
if (code !== 0) {
|
||||
return;
|
||||
}
|
||||
state.pagination.list = _.concat(state.pagination.list, data.list);
|
||||
state.pagination.total = data.total;
|
||||
state.loadStatus = state.pagination.list.length < state.pagination.total ? 'more' : 'noMore';
|
||||
}
|
||||
|
||||
// 获得钱包统计
|
||||
async function getSummary() {
|
||||
const { data, code } = await PayWalletApi.getWalletTransactionSummary({
|
||||
createTime: [state.date[0] + ' 00:00:00', state.date[1] + ' 23:59:59'],
|
||||
});
|
||||
if (code !== 0) {
|
||||
return;
|
||||
}
|
||||
state.summary = data;
|
||||
}
|
||||
|
||||
onLoad(() => {
|
||||
state.today = dayjs().format('YYYY-MM-DD');
|
||||
state.date = [state.today, state.today];
|
||||
getLogList();
|
||||
getSummary();
|
||||
// 刷新钱包的缓存
|
||||
sheep.$store('user').getWallet();
|
||||
});
|
||||
|
||||
// 处理 tab 切换
|
||||
function onChange(e) {
|
||||
state.currentTab = e.index;
|
||||
// 重新加载列表
|
||||
resetPagination(state.pagination);
|
||||
getLogList();
|
||||
getSummary();
|
||||
}
|
||||
|
||||
// 处理时间筛选
|
||||
function onChangeTime(e) {
|
||||
state.date[0] = e[0];
|
||||
state.date[1] = e[e.length - 1];
|
||||
// 重新加载列表
|
||||
resetPagination(state.pagination);
|
||||
getLogList();
|
||||
getSummary();
|
||||
}
|
||||
|
||||
onReachBottom(() => {
|
||||
if (state.loadStatus === 'noMore') {
|
||||
return;
|
||||
}
|
||||
state.pagination.pageNo++;
|
||||
getLogList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 钱包
|
||||
.header-box {
|
||||
background-color: $white;
|
||||
padding: 30rpx;
|
||||
|
||||
.card-box {
|
||||
width: 100%;
|
||||
min-height: 300rpx;
|
||||
padding: 40rpx;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 30rpx;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
box-sizing: border-box;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 2;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: v-bind(headerBg) no-repeat;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.card-head {
|
||||
color: $white;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
.ss-eye-icon {
|
||||
font-size: 40rpx;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
.money-num {
|
||||
font-size: 70rpx;
|
||||
line-height: 70rpx;
|
||||
font-weight: 500;
|
||||
color: $white;
|
||||
font-family: OPPOSANS;
|
||||
}
|
||||
|
||||
.reduce-num {
|
||||
font-size: 26rpx;
|
||||
font-weight: 400;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
.topup-btn {
|
||||
width: 120rpx;
|
||||
height: 60rpx;
|
||||
line-height: 60rpx;
|
||||
border-radius: 30px;
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
background-color: $white;
|
||||
color: var(--ui-BG-Main);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 筛选
|
||||
|
||||
.filter-box {
|
||||
height: 114rpx;
|
||||
background-color: $bg-page;
|
||||
|
||||
.total-box {
|
||||
font-size: 24rpx;
|
||||
font-weight: 500;
|
||||
color: $dark-9;
|
||||
}
|
||||
|
||||
.date-btn {
|
||||
background-color: $white;
|
||||
line-height: 54rpx;
|
||||
border-radius: 27rpx;
|
||||
padding: 0 20rpx;
|
||||
font-size: 24rpx;
|
||||
font-weight: 500;
|
||||
color: $dark-6;
|
||||
|
||||
.ss-seldate-icon {
|
||||
font-size: 50rpx;
|
||||
color: $dark-9;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tabs-box {
|
||||
background: $white;
|
||||
border-bottom: 2rpx solid #eeeeee;
|
||||
}
|
||||
|
||||
// tab
|
||||
.wallet-tab-card {
|
||||
.tab-item {
|
||||
height: 80rpx;
|
||||
position: relative;
|
||||
|
||||
.tab-title {
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
.cur-tab-title {
|
||||
font-weight: $font-weight-bold;
|
||||
}
|
||||
|
||||
.tab-line {
|
||||
width: 60rpx;
|
||||
height: 6rpx;
|
||||
border-radius: 6rpx;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
bottom: 2rpx;
|
||||
background-color: var(--ui-BG-Main);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 钱包记录
|
||||
.wallet-list {
|
||||
padding: 30rpx;
|
||||
background-color: #ffff;
|
||||
|
||||
.head-img {
|
||||
width: 70rpx;
|
||||
height: 70rpx;
|
||||
border-radius: 50%;
|
||||
background: $gray-c;
|
||||
}
|
||||
|
||||
.list-content {
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
flex: 1;
|
||||
|
||||
.title {
|
||||
font-size: 28rpx;
|
||||
color: $dark-3;
|
||||
width: 400rpx;
|
||||
}
|
||||
|
||||
.time {
|
||||
color: $gray-c;
|
||||
font-size: 22rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.money {
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
font-family: OPPOSANS;
|
||||
.add {
|
||||
color: var(--ui-BG-Main);
|
||||
}
|
||||
|
||||
.minus {
|
||||
color: $dark-3;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,277 @@
|
||||
<!-- 我的积分 -->
|
||||
<template>
|
||||
<s-layout class="wallet-wrap" title="我的积分" navbar="inner">
|
||||
<view
|
||||
class="header-box ss-flex ss-flex-col ss-row-center ss-col-center"
|
||||
:style="[
|
||||
{
|
||||
marginTop: '-' + Number(statusBarHeight + 88) + 'rpx',
|
||||
paddingTop: Number(statusBarHeight + 88) + 'rpx',
|
||||
},
|
||||
]"
|
||||
>
|
||||
<view class="header-bg">
|
||||
<view class="bg" />
|
||||
</view>
|
||||
<view class="score-box ss-flex-col ss-row-center ss-col-center">
|
||||
<view class="ss-m-b-30">
|
||||
<text class="all-title ss-m-r-8">当前积分</text>
|
||||
</view>
|
||||
<text class="all-num">{{ userInfo.point || 0 }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- tab -->
|
||||
<su-sticky :customNavHeight="sys_navBar">
|
||||
<!-- 统计 -->
|
||||
<view class="filter-box ss-p-x-30 ss-flex ss-col-center ss-row-between">
|
||||
<uni-datetime-picker
|
||||
v-model="state.date"
|
||||
type="daterange"
|
||||
@change="onChangeTime"
|
||||
:end="state.today"
|
||||
>
|
||||
<button class="ss-reset-button date-btn">
|
||||
<text>{{ dateFilterText }}</text>
|
||||
<text class="cicon-drop-down ss-seldate-icon"></text>
|
||||
</button>
|
||||
</uni-datetime-picker>
|
||||
|
||||
</view>
|
||||
<su-tabs
|
||||
:list="tabMaps"
|
||||
@change="onChange"
|
||||
:scrollable="false"
|
||||
:current="state.currentTab"
|
||||
></su-tabs>
|
||||
</su-sticky>
|
||||
|
||||
<!-- list -->
|
||||
<view class="list-box">
|
||||
<view v-if="state.pagination.total > 0">
|
||||
<view
|
||||
class="list-item ss-flex ss-col-center ss-row-between"
|
||||
v-for="item in state.pagination.list"
|
||||
:key="item.id"
|
||||
>
|
||||
<view class="ss-flex-col">
|
||||
<view class="name"
|
||||
>{{ item.title }}{{ item.description ? ' - ' + item.description : '' }}</view
|
||||
>
|
||||
<view class="time">{{
|
||||
sheep.$helper.timeFormat(item.createTime, 'yyyy-mm-dd hh:MM:ss')
|
||||
}}</view>
|
||||
</view>
|
||||
<view class="add" v-if="item.point > 0">+{{ item.point }}</view>
|
||||
<view class="minus" v-else>{{ item.point }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<s-empty v-else text="暂无数据" icon="/static/data-empty.png" />
|
||||
</view>
|
||||
|
||||
<uni-load-more
|
||||
v-if="state.pagination.total > 0"
|
||||
:status="state.loadStatus"
|
||||
:content-text="{
|
||||
contentdown: '上拉加载更多',
|
||||
}"
|
||||
@tap="onLoadMore"
|
||||
/>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import sheep from '@/sheep';
|
||||
import { onLoad, onReachBottom } from '@dcloudio/uni-app';
|
||||
import { computed, reactive } from 'vue';
|
||||
import _ from 'lodash-es';
|
||||
import dayjs from 'dayjs';
|
||||
import PointApi from '@/sheep/api/member/point';
|
||||
import { resetPagination } from '@/sheep/util';
|
||||
|
||||
const statusBarHeight = sheep.$platform.device.statusBarHeight * 2;
|
||||
const userInfo = computed(() => sheep.$store('user').userInfo);
|
||||
const sys_navBar = sheep.$platform.navbar;
|
||||
|
||||
const state = reactive({
|
||||
currentTab: 0,
|
||||
pagination: {
|
||||
list: 0,
|
||||
total: 0,
|
||||
pageSize: 6,
|
||||
pageNo: 1,
|
||||
},
|
||||
loadStatus: '',
|
||||
date: [],
|
||||
today: '',
|
||||
});
|
||||
|
||||
const tabMaps = [
|
||||
{
|
||||
name: '全部',
|
||||
value: 'all',
|
||||
},
|
||||
{
|
||||
name: '收入',
|
||||
value: 'true',
|
||||
},
|
||||
{
|
||||
name: '支出',
|
||||
value: 'false',
|
||||
},
|
||||
];
|
||||
|
||||
const dateFilterText = computed(() => {
|
||||
if (state.date[0] === state.date[1]) {
|
||||
return state.date[0];
|
||||
} else {
|
||||
return state.date.join('~');
|
||||
}
|
||||
});
|
||||
|
||||
async function getLogList() {
|
||||
state.loadStatus = 'loading';
|
||||
let { code, data } = await PointApi.getPointRecordPage({
|
||||
pageNo: state.pagination.pageNo,
|
||||
pageSize: state.pagination.pageSize,
|
||||
addStatus: state.currentTab > 0 ? tabMaps[state.currentTab].value : undefined,
|
||||
'createTime[0]': state.date[0] + ' 00:00:00',
|
||||
'createTime[1]': state.date[1] + ' 23:59:59',
|
||||
});
|
||||
if (code !== 0) {
|
||||
return;
|
||||
}
|
||||
state.pagination.list = _.concat(state.pagination.list, data.list);
|
||||
state.pagination.total = data.total;
|
||||
state.loadStatus = state.pagination.list.length < state.pagination.total ? 'more' : 'noMore';
|
||||
}
|
||||
|
||||
onLoad(() => {
|
||||
state.today = dayjs().format('YYYY-MM-DD');
|
||||
state.date = [state.today, state.today];
|
||||
getLogList();
|
||||
});
|
||||
|
||||
function onChange(e) {
|
||||
state.currentTab = e.index;
|
||||
resetPagination(state.pagination);
|
||||
getLogList();
|
||||
}
|
||||
|
||||
function onChangeTime(e) {
|
||||
state.date[0] = e[0];
|
||||
state.date[1] = e[e.length - 1];
|
||||
resetPagination(state.pagination);
|
||||
getLogList();
|
||||
}
|
||||
|
||||
function onLoadMore() {
|
||||
if (state.loadStatus === 'noMore') {
|
||||
return;
|
||||
}
|
||||
state.pagination.pageNo++;
|
||||
getLogList();
|
||||
}
|
||||
|
||||
onReachBottom(() => {
|
||||
onLoadMore();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.header-box {
|
||||
width: 100%;
|
||||
background: linear-gradient(180deg, var(--ui-BG-Main) 0%, var(--ui-BG-Main-gradient) 100%)
|
||||
no-repeat;
|
||||
background-size: 750rpx 100%;
|
||||
padding: 0 0 120rpx 0;
|
||||
box-sizing: border-box;
|
||||
|
||||
.score-box {
|
||||
height: 100%;
|
||||
|
||||
.all-num {
|
||||
font-size: 50rpx;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
font-family: OPPOSANS;
|
||||
}
|
||||
|
||||
.all-title {
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.cicon-help-o {
|
||||
color: #fff;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 筛选
|
||||
.filter-box {
|
||||
height: 114rpx;
|
||||
background-color: $bg-page;
|
||||
|
||||
.total-box {
|
||||
font-size: 24rpx;
|
||||
font-weight: 500;
|
||||
color: $dark-9;
|
||||
}
|
||||
|
||||
.date-btn {
|
||||
background-color: $white;
|
||||
line-height: 54rpx;
|
||||
border-radius: 27rpx;
|
||||
padding: 0 20rpx;
|
||||
font-size: 24rpx;
|
||||
font-weight: 500;
|
||||
color: $dark-6;
|
||||
|
||||
.ss-seldate-icon {
|
||||
font-size: 50rpx;
|
||||
color: $dark-9;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.list-box {
|
||||
.list-item {
|
||||
background: #fff;
|
||||
border-bottom: 1rpx solid #dfdfdf;
|
||||
padding: 30rpx;
|
||||
|
||||
.name {
|
||||
font-size: 28rpx;
|
||||
|
||||
font-weight: 500;
|
||||
color: rgba(102, 102, 102, 1);
|
||||
line-height: 28rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.time {
|
||||
font-size: 24rpx;
|
||||
|
||||
font-weight: 500;
|
||||
color: rgba(196, 196, 196, 1);
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.add {
|
||||
font-size: 30rpx;
|
||||
|
||||
font-weight: 500;
|
||||
color: #e6b873;
|
||||
}
|
||||
|
||||
.minus {
|
||||
font-size: 30rpx;
|
||||
|
||||
font-weight: 500;
|
||||
color: $dark-3;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user