SFH5/pages/unlock/index.vue
2026-04-10 17:55:32 +08:00

1876 lines
48 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="header">
<uv-tabs @change="handleChange" :current="state.current" :activeStyle="{fontWeight:600,color: '#000000',fontSize: '32rpx'}" :inactiveStyle="{ color: '#000000',fontSize: '32rpx' }" lineWidth="80rpx" lineHeight="6rpx"
lineColor="#FF1E2E" :scrollable="false" :list="list">
</uv-tabs>
</view>
<view class="container" :class="[`${themeInfo.theme}-theme`]">
<view class="unlock-wrap content">
<view class="card orderList" v-for="item in currentOrderList" :key="item.orderId">
<view class="orderInfo">
<!-- <uv-button shape="circle">复制</uv-button> -->
<view class="orderOn">订单号:{{ item.orderNo }} <uv-button @click="copyOrderOn(item)"
shape="circle">复制</uv-button> </view>
<view class="box1">
<!-- 顶部:左中右布局 -->
<view class="top">
<view class="left">
<image src="/static/home/siteicon.svg" class="icon"></image>
<view class="title-wrap">
<text class="title font36 fontb">{{ item.siteName }}</text>
</view>
</view>
</view>
<!-- 底部:地址 -->
<view class="bottom">
<image src="/static/home/siteicon2.svg" class="icon"></image>
<text class="address font26 fontb textGary">{{ item.siteCity }}{{ item.siteDistrict }}{{
item.siteAddress }}</text>
</view>
</view>
<view class="box2">
<view class="item">
<view class="label font26 fontb textGary">仓号:</view>
<view class="value font26 fontb"> {{ item.lockerName }}</view>
</view>
<view class="item">
<view class="label font26 fontb textGary">体积:</view>
<view class="value font26 fontb"> 长{{ item.lockerLength }}m*宽{{ item.lockerWidth }}m*高{{
item.lockerHeight }}m ({{ item.lockerVolume }}m³)</view>
</view>
<view class="item">
<view class="label font26 fontb textGary">仓型: </view>
<view class="value font26 fontb">{{ item.unitTypeName }}</view>
</view>
<view class="item">
<view class="label font26 fontb textGary">租期: </view>
<view class="value font26 fontb"> {{ item.endTime?.substr(0, 10) }}</view>
</view>
<view class="item" v-if="!(item.orderStartStatus == 2 && item.refundLockerStatus === 0)">
<view class="label font26 fontb textGary">{{ $t('common.status') }}: </view>
<view class="value font26 fontb" style="color: #FB322E;">
<template v-if="item.refundLockerStatus === 0">{{ $t("common.notStarted") }}</template>
<template v-else-if="item.refundLockerStatus === 1">{{ $t("unlock.cancelPending")
}}</template>
<template v-else-if="item.refundLockerStatus === 2">{{ $t("unlock.outComplete")
}}</template>
<template v-else-if="item.refundLockerStatus === 3">{{ $t("unlock.disapproval") }} {{
item.orderStatus == 5 ? `(${$t("unlock.overdue")})` : '' }}</template>
<template v-else-if="item.refundLockerStatus === 4">{{ $t("unlock.overdue")
}}</template>
<template v-else-if="item.orderStatus === 8">已取消</template>
</view>
</view>
</view>
</view>
<view class="btn" v-show="[0, 3, 4].includes(item.refundLockerStatus)" v-if="item.orderStatus !== 2">
<uv-button :disabled="!(item.orderStartStatus == 2 && item.orderStatus !== 5 && item.isOpenDoor)"
shape="circle" @click="openDevicePopup(item)">开门</uv-button>
<uv-button :disabled="!(item.orderStartStatus == 2 && item.orderStatus !== 5 && item.isOpenLock)"
shape="circle" @click="openPwdPopup(item)">开锁</uv-button>
<uv-button v-show="item.orderStartStatus == 2 || item.orderStartStatus == 1"
:style="{ opacity: item.renewal ? '1' : '0.5' }" @click="showPayPopup(item)"
shape="circle">续仓</uv-button>
<uv-button shape="circle" @click="openDetailPopup(item)">详情</uv-button>
</view>
<!-- 取消订单 -->
<view class="btn" v-if="item.orderStatus === 8" style="justify-content: end;">
<uv-button shape="circle" @click="openDetailPopup(item)">详情</uv-button>
</view>
<!-- 退仓申请中 -->
<view class="btn" v-show="item.refundLockerStatus === 1">
<uv-button :customStyle="{
}" color="#FB322E" plain shape="circle" @click="cancelMoveOutRqt(item)">取消退仓申请</uv-button>
<uv-button shape="circle" @click="openDetailPopup(item)">{{ $t("unlock.details") }}</uv-button>
</view>
<view class="btn" v-show="item.refundLockerStatus === 2" style="justify-content: end;">
<uv-button shape="circle" @click="openDetailPopup(item)">{{ $t("unlock.details") }}</uv-button>
</view>
<view class="btn" v-if="item.orderStatus == 2">
<uv-button shape="circle" plain :customStyle="{
}" color="#FB322E" @click="openCancelOrder(item)">取消订单</uv-button>
<uv-button shape="circle" :customStyle="{
color: '#fff',
}" color="#FB322E" @click="handlePay(item)">去支付</uv-button>
<uv-button shape="circle" @click="openDetailPopup(item)">详情</uv-button>
</view>
</view>
</view>
<view class="empt font32 fontb"
style="text-align: center;position: absolute; top: 50%;left: 50%;transform: translate(-50%, -50%);"
v-if="currentOrderList.length === 0">
暂无订单
</view>
<view class="footer">
<myCustomtTabBar direction="horizontal" :show-icon="true" :selected="1" @onTabItemTap="onTabItemTap">
</myCustomtTabBar>
</view>
<uv-popup ref="detailPopupRef" zIndex="999" round="24px" :safeAreaInsetBottom="false">
<view class="popupBox popupBoxW710">
<view class="orderList">
<view class="orderInfo">
<image class="close-icon" style="width: 30rpx;height: 30rpx;" src="/static/home/close2.svg" @click="closeDetailPopup"></image>
<view class="orderOn">订单号:{{ state.orderData.orderNo }} <uv-button shape="circle"
@click="copyOrderOn(state.orderData)">复制</uv-button> </view>
<view class="box1">
<!-- 顶部:左中右布局 -->
<view class="top">
<view class="left">
<image src="/static/home/siteicon.svg" class="icon"></image>
<view class="title-wrap">
<text class="title font36 fontb">{{ state.orderData.siteName }} </text>
</view>
</view>
</view>
<!-- 底部:地址 -->
<view class="bottom">
<image src="/static/home/siteicon2.svg" class="icon"></image>
<text class="address font26 fontb textGary">{{ state.orderData.siteCity }}{{
state.orderData.siteDistrict }}{{
state.orderData.siteAddress }}</text>
</view>
</view>
<view class="box2 box2_border">
<view class="item">
<view class="label font26 fontb textGary">仓号: </view>
<view class="value font26 fontb">{{ state.orderData.lockerName }}</view>
</view>
<view class="item">
<view class="label font26 fontb textGary">体积: </view>
<view class="value font26 fontb">长{{ state.orderData['length'] }}m*宽{{
state.orderData.width }}m*高{{
state.orderData.height }}m ({{ state.orderData.volume }}m³)</view>
</view>
<view class="item">
<view class="label font26 fontb textGary">仓型: </view>
<view class="value font26 fontb">{{ state.orderData.unitTypeName }}</view>
</view>
<view class="item"
v-if="!(state.orderData.orderStartStatus == 2 && state.orderData.refundLockerStatus === 0)">
<view class="label font26 fontb textGary">{{ $t('common.status') }}: </view>
<view class="value font26 fontb" style="color: #FB322E;">
<template v-if="state.orderData.refundLockerStatus === 0">{{ $t("common.notStarted")
}}</template>
<template v-else-if="state.orderData.refundLockerStatus === 1">{{
$t("unlock.cancelPending") }}</template>
<template v-else-if="state.orderData.refundLockerStatus === 2">{{
$t("unlock.outComplete") }}</template>
<template v-else-if="state.orderData.refundLockerStatus === 3">{{
$t("unlock.disapproval") }} {{ state.orderData.orderStatus == 5
? `(${$t("unlock.overdue")})` : '' }}</template>
<template v-else-if="state.orderData.refundLockerStatus === 4">{{
$t("unlock.overdue") }}</template>
<template v-else-if="state.orderData.orderStatus === 8">已取消</template>
</view>
</view>
</view>
<view class="box2">
<view class="item">
<view class="label font26 fontb textGary">开始时间: </view>
<view class="value font26 fontb">{{ state.orderData.startTime?.substr(0, 10) }}</view>
</view>
<view class="item">
<view class="label font26 fontb textGary">结束时间: </view>
<view class="value font26 fontb">{{ state.orderData.endTime?.substr(0, 10) }}</view>
</view>
<view class="item">
<view class="label font26 fontb textGary">{{ $t("detail.rentalFee") }}: </view>
<view class="value font26 fontb">{{ currency }} {{ state.orderData.originalPrice }}
</view>
</view>
<view class="item">
<view class="label font26 fontb textGary">租金月费: </view>
<view class="value font26 fontb">{{ currency }} {{
state.orderData.discountData?.[0]?.unitPrice
}}
</view>
</view>
<view class="item">
<view class="label font26 fontb textGary">租期优惠: </view>
<view class="value font26 fontb"> {{ state.orderData.discountData?.[0]?.month }}个月长租(-{{
currency }} {{ state.orderData.discountData?.[0]?.leaseDiscount }}
</view>
</view>
<view class="item">
<view class="label font26 fontb textGary">订单押金: </view>
<view class="value font26 fontb">{{ currency }} {{ state.orderData.deposit }}</view>
</view>
<!-- <view class="item">
<view class="label font26 fontb textGary">{{ $t("detail.discount") }}: </view>
<view class="value font26 fontb">-{{ currency }} {{ state.orderData.favorable }} </view>
</view> -->
<view class="item">
<view class="label font26 fontb textGary">租金总价: </view>
<view class="value font26 fontb">{{ currency }} {{ state.orderData.actualPay }} </view>
</view>
</view>
</view>
<view class="btn" v-if="state.orderData.orderStatus !== 2 && state.orderData.orderStatus !== 8"
v-show="state.orderData.refundLockerStatus != 1 && state.orderData.refundLockerStatus !== 2">
<uv-button class="uv-btn" shape="circle" @click="openMoveOutModal">
{{ $t("unlock.moveout") }}
</uv-button>
</view>
</view>
</view>
</uv-popup>
<uv-popup ref="devicePopupRef" zIndex="999" round="24rpx" :safeAreaInsetBottom="false">
<view class="popupBox popupBoxW650">
<view class="title fontb font32">
<text></text> 开门二维码 <image class="close-icon" style="width: 30rpx;height: 30rpx;" src="/static/home/close2.svg" @click="closeDevicePopup"></image>
</view>
<view class="content">
<img @click="showImage(QRCode)" alt="加载失败" v-show="ifShow" class="paw" width="280rpx" height="280rpx"
:src="QRCode"></img>
<text class="textGray font26" style="z-index: 9; margin: 0 0 30rpx 0;">二维码的有效期仅为15分钟</text>
</view>
<view class="btnBox">
<!-- <uv-button @click="closeDevicePopup" :customStyle="{
height: '86rpx',
color: '#000',
fontSize: '32rpx',
}" shape="circle">
取消
</uv-button> -->
<uv-button @click="GetQRCode" :customStyle="{
width: '86%',
height: '86rpx',
background: '#FB322E',
color: '#fff',
fontSize: '32rpx',
}" color="#FB322E" shape="circle">
刷新
</uv-button>
</view>
</view>
</uv-popup>
<uv-popup ref="pawPopupRef" zIndex="999" round="24px" :safeAreaInsetBottom="false">
<view class="popupBox pwdBox popupBoxW650">
<view class="title fontb font32">
<text></text> 开锁密码 <image class="close-icon" style="width: 30rpx;height: 30rpx;" src="/static/home/close2.svg" @click="closePwdPopup"></image>
</view>
<view class="content">
<text class="font26 textRed fontb" style="font-size: 60rpx;">{{ lockPwd }}#</text>
<text class="textGray font26" style="margin: 20rpx 0 30rpx;">输入密码即可开锁{{ [3, 7].includes(Number(state.selectItem?.lockTypeId)) ?
"或一键开锁" :
"" }}</text>
</view>
<view class="btnBox">
<uv-button @click="closePwdPopup" :customStyle="{
height: '86rpx',
color: '#000',
fontSize: '32rpx',
}" shape="circle">
取消
</uv-button>
<uv-button v-if="[3, 7].includes(Number(state.selectItem?.lockTypeId))" @click="RemoteOpen"
:customStyle="{
height: '86rpx',
background: '#FB322E',
color: '#fff',
fontSize: '32rpx',
}" color="#FB322E" shape="circle">
一键开锁
</uv-button>
<uv-button v-else @click="GetLockPwd" :customStyle="{
height: '86rpx',
background: '#FB322E',
color: '#fff',
fontSize: '32rpx',
}" color="#FB322E" shape="circle">
刷新
</uv-button>
</view>
</view>
</uv-popup>
<uv-popup ref="payPopupRef" mode="bottom" zIndex="999" round="24px">
<view class="popupBox payPopupBox">
<view class="title titleIcon font36 fontb">
<view style="display: flex;align-items: center;">
<image src="/static/home/siteicon.svg" class="icon"></image>
<view class="title-wrap">
<text class="title font36 fontb">{{ state.selectItem.siteName }} {{ state.selectItem.lockerName
}}</text>
</view>
</view>
<image class="close-icon" style="width: 30rpx;height: 30rpx;" src="/static/home/close2.svg" @click="hidePayPopup"></image>
</view>
<view class="title2 font32 fontb">
<view class="bitianBox">续租时长 <view class="bitian">必填</view>
</view>
</view>
<view class="garyBox font28 card20" @click="showMonthPopup">
<view style="display: flex;align-items: center;">租期时长</view>
<view class="select"><text style="margin-right: 10rpx;color: #FB322E;font-weight: bold;">{{
state.month
}}个月</text>
<image src="/static/home/jiantou.svg" style="width: 24rpx;height: 24rpx;" class="icon"></image>
</view>
</view>
<view class="title2 font32 fontb">
<text>租赁体积</text> <text>{{ `${state.lockData?.volume}m³` }}</text>
</view>
<view class="garyBox garyBoxM font28 card20">
<view class="mgb10">
仓号:{{ state.lockData?.name }}
</view>
<view>
尺寸:长{{ state.lockData?.['length'] }}m*宽{{ state.lockData?.width }}m*高{{ state.lockData?.height
}}m
</view>
</view>
<view class="title2 font32 fontb">
<text>租金总价</text> <text>¥ {{ state.priceData?.lockerExpense }}</text>
</view>
<view class="title2 textGary2 fontb font28">
<text>租金月费</text> <text> ¥ {{ state.priceData?.lockerPrice }}</text>
</view>
<view class="title2 textGary2 fontb font28">
<text>租期时长</text> <text> {{ state.month }}个月</text>
</view>
<view class="title2 font32 fontb">
<text>押金费用</text> <text>¥ {{ state.priceData.securityDeposit }}</text>
</view>
<view class="title2 textGary2 fontb font28">
<text>租赁押金在租期结束后给予归还</text>
</view>
<view class="title2 font32 fontb">
<text>优惠信息</text> <text style="color: #FB322E;">-¥ {{ state.priceData.favorable }}</text>
</view>
<view class="title2 textGary2 fontb font28">
<text>租期优惠({{ state.month }}个月长租)</text><text style="color: #FB322E;">-¥ {{
state.priceData.leaseDiscount
}}</text>
</view>
<view class="toOrder card font28">
<view class="left font28">
<text class="price fontb" :class="{ overMaxFont: String(state.priceData?.expense).length > 6 }">
{{
state.priceData.expense ? `¥${state.priceData.expense}`
: '--' }}</text>
<view class="detail" v-if="state.priceData.expense" @click="hidePayPopup"><text
class="detail1"
:class="{ overMaxFont: String(state.priceData?.expense).length > 6 }"
v-if="state.priceData?.expense">¥{{ state.priceData.leaseOriginalPrice }}</text>
<!-- <text
class="font28">明细</text> -->
<!-- <image src="/static/home/jiantouup.svg" style="height: 12rpx;margin-left: 10rpx;"
mode="heightFix" class="icon"></image> -->
</view>
</view>
<view class="right">
<uv-button :customStyle="{
height: '86rpx',
background: '#FB322E',
color: '#fff',
}" :textStyle="{
fontSize: '32rpx',
fontWeight: 'bold',
}" shape="circle" class="goOrder" @click="goOrder">续仓支付</uv-button>
</view>
</view>
</view>
</uv-popup>
<uv-popup ref="monthPopupRef" mode="bottom" zIndex="999" round="24px">
<view class="unitPopupBox">
<view class="title font36 fontb">
租期选择 <image class="close-icon" style="width: 30rpx;height: 30rpx;" src="/static/home/close2.svg" @click="hideMonthPopup"></image>
</view>
<view class="info">
<uv-radio-group v-model="state.radioMonthvalue" activeColor="#fb322e" size="40rpx"
inactiveColor="#D8D8D8">
<view class="list" v-for="item in state.lockData?.discountList">
<view class="left">
<view class="volume mgb10 font28 fontb">
租期: {{ item.month }}个月
</view>
<view class="unit textRed mgb10 font28 fontb">
优惠: 享受{{ (item.discount * 100) / 10 }}折优惠
</view>
<!-- <view class="site textGary mgb10">
尺寸: 120cm*100cm*100cm
</view> -->
</view>
<view class="right">
<view class="radioBox mgb10">
<uv-radio :key="item.month" :name="item.month" size="40rpx">
</uv-radio>
</view>
</view>
</view>
<view class="list">
<view class="left">
<view class="volume mgb10 font28 fontb zuqi" style="display: flex;">
自定义租期: &nbsp;
<!-- <uv-number-box buttonSize="26" integer v-model="state.selfMonth"
color="#ffffff" bgColor="#FB322E" :min="1" :max="24" :step="1"
iconStyle="color: #fff"></uv-number-box> -->
<uv-number-box v-model="state.selfMonth" :min="1" :max="24" :step="1">
<template v-slot:minus>
<view class="minus">
<uv-icon name="minus" size="20rpx">
</uv-icon>
</view>
</template>
<template v-slot:input>
<text style="width: 50px;text-align: center;color: #000;" class="input">
{{ state.selfMonth }}
</text>
</template>
<template v-slot:plus>
<view class="plus">
<uv-icon name="plus" color="#FFFFFF" size="20rpx">
</uv-icon>
</view>
</template>
</uv-number-box>
&nbsp;个月
</view>
<view class="unit textRed mgb10 font28 fontb" v-if="selfDiscount !== 1">
优惠: 享受{{ selfDiscount * 100 / 10 }}折优惠
</view>
<view class="unit textRed mgb10 textRed font28 fontb" v-else>
优惠: --
</view>
<!-- <view class="site textGary mgb10">
尺寸: 120cm*100cm*100cm
</view> -->
</view>
<view class="right">
<view class="radioBox mgb10">
<uv-radio :key="0" :name="-1" size="40rpx">
</uv-radio>
</view>
</view>
</view>
</uv-radio-group>
</view>
<view class="btn" @click="confirmMonth" style="display: flex;justify-content: center;">
<uv-button :customStyle="{
height: '86rpx',
background: '#FB322E',
color: '#fff',
width: '630rpx',
fontSize: '32rpx',
}" color="#FB322E" shape="circle">
确定
</uv-button>
</view>
</view>
</uv-popup>
<!-- 上传图片退仓的弹窗 -->
<uv-popup ref="moveOutPopup" customStyle="width: 710rpx; border-radius: 24px;" :safeAreaInsetBottom="false"
:closeOnClickOverlay="false" zIndex="9999">
<view class="modal-container">
<view class="modal-title">{{ $t("unlock.moveoutReminder") }}</view>
<text class="modal-text">
{{ $t("unlock.moveoutTip") }}
</text>
<text class="textRed mgb10" style="font-size: 26rpx;margin-top: 10rpx;">
{{ $t('unlock.uploadTip') }}
</text>
<view class="upload">
<uv-upload :fileList="moveImageList" name="1" :maxCount="10" width="200rpx" height="200rpx" multiple
:previewFullImage="false" uploadText=" " @afterRead="afterRead" @delete="deletePic">
</uv-upload>
</view>
<view class="modal-button">
<uv-button @click="closeMoveOutModal" :customStyle="{
height: '86rpx',
lineHeight: '86rpx',
color: '#000',
fontSize: '32rpx',
}" shape="circle">
{{ $t("unlock.cancel") }}
</uv-button>
<uv-button :customStyle="{
height: '86rpx',
lineHeight: '86rpx',
color: '#fff',
fontSize: '32rpx',
}" color="#FB322E" shape="circle" @click="handleRefundLocker">
{{ $t("unlock.confirmOut") }}
</uv-button>
</view>
</view>
</uv-popup>
<!-- 成功退仓弹窗 -->
<uv-popup ref="moveOutPopup2" customStyle="width: 710rpx; border-radius: 24rpx;" :safeAreaInsetBottom="false"
:closeOnClickOverlay="false" zIndex="9999">
<view class="modal-container">
<view class="modal-title">{{ $t("unlock.moveoutReminder") }}</view>
<text class="modal-text">
{{ $t("unlock.moveoutSuccess") }}
</text>
<view class="modal-button">
<!-- <view class="modal-button-2" @click="goEvaluate">{{ $t("unlock.evaluate") }}</view> -->
<uv-button @click="closeModal2" :customStyle="{
height: '86rpx',
lineHeight: '86rpx',
color: '#000',
fontSize: '32rpx',
}" shape="circle">
关闭
</uv-button>
</view>
</view>
</uv-popup>
<uv-popup ref="cancelOrderPopupRef" customStyle="width: 710rpx; border-radius: 24rpx;"
:safeAreaInsetBottom="false" :closeOnClickOverlay="false" zIndex="9999">
<view class="modal-container">
<view class="modal-title">{{ $t("common.cancelOrder") }}</view>
<text class="modal-text">
{{ $t("common.cancelOrderTips") }}
</text>
<view class="modal-button">
<!-- <view class="modal-button-2" @click="goEvaluate">{{ $t("unlock.evaluate") }}</view> -->
<uv-button @click="closeCancelOrder" :customStyle="{
height: '86rpx',
lineHeight: '86rpx',
color: '#000',
fontSize: '32rpx',
}" shape="circle">
关闭
</uv-button>
<uv-button :customStyle="{
height: '86rpx',
lineHeight: '86rpx',
color: '#fff',
fontSize: '32rpx',
}" color="#FB322E" shape="circle" @click="cancelOrder">
取消订单
</uv-button>
</view>
</view>
</uv-popup>
</view>
</template>
<script setup>
import { ref, computed } from 'vue';
import { onTabItemTap, onShowRerequestByIsLogin, makePhoneCall } from '/utils/common.js'
import myModal from '@/components/myModal.vue';
import myCustomtTabBar from '@/components/myCustomtTabBar.vue';
import wxNavbar from '@/components/wxNavbar.vue';
import { useCountDown } from "@/hooks/index";
import { onLoad, onShow, onShareAppMessage, onHide } from '@dcloudio/uni-app'
import { useLockApi } from '@/Apis/lock.js';
import myPopup from '@/components/myPopup.vue';
// 主题色配置
import { useMainStore } from "@/store/index.js";
import { navbarHeightAndStatusBarHeight, shareParam } from "@/utils/common.js";
import { currency } from "@/config/index.js";
import { useGoodsApi } from "@/Apis/goodsList.js";
import { useLoginApi } from "@/Apis/login.js";
import { storeToRefs } from 'pinia';
import { useOrderApi } from "@/Apis/order.js";
import { baseImageUrl } from "@/config/index.js";
import { useSiteApi } from "@/Apis/site.js";
import { useI18n } from 'vue-i18n';
import dayjs from 'dayjs';
const payPopupRef = ref(null);
const monthPopupRef = ref(null);
const moveOutPopup = ref(null);
const moveOutPopup2 = ref(null);
const getGoodsApi = useGoodsApi();
const { themeInfo, getUserInfo, getHasVerify } = useMainStore();
const { storeState } = storeToRefs(useMainStore());
const { locale, t } = useI18n();
const getApi = useOrderApi()
const getLockApi = useLockApi();
const getSiteApi = useSiteApi();
const getLoginApi = useLoginApi();
const { count, countDown, cancelCout } = useCountDown();
const devicePopupRef = ref(null);
const pawPopupRef = ref(null);
const detailPopupRef = ref(null);
const cancelOrderPopupRef = ref(null);
uni.hideTabBar();
const state = ref({
orderList: [],
selectItem: {}, // 当前选中的订单
orderData: {},// 详情
month: 24, // 租期
priceData: {}, // 订单价格
lockData: {
discountList: []
}, // 锁详情
radioMonthvalue: 24,
month: 24,
selfMonth: 1,
refundLoading: false,
current: 0,
cancelOrderList: [],
});
const list = [{
name: '在租',
}, {
name: '到期',
}, {
name: '待支付'
},
]
const currentOrderList = computed(() => {
const isType1 = (item) =>
!(item.orderStartStatus == 2 && item.refundLockerStatus === 0)
&& (item.refundLockerStatus === 2)
const isType2 = (item) =>
item.orderStatus == 2
if (state.value.current == 0) {
// 排除 1 和 2
return state.value.orderList.filter(
item => !isType1(item) && !isType2(item)
)
}
if (state.value.current == 1) {
return state.value.orderList.filter(isType1).concat(state.value.cancelOrderList)
}
if (state.value.current == 2) {
return state.value.orderList.filter(isType2)
}
})
const showImage = (url) => {
if (!url) return;
uni.previewImage({
urls: [url],
});
};
const handleChange = (e) => {
state.value.current = e.index
GetOrderList()
if (state.value.current == 1) {
GetCancelOrder()
}
}
const copyOrderOn = (item) => {
uni.setClipboardData({
data: item.orderNo,
success: function () {
uni.showToast({
title: '复制成功',
icon: 'none',
duration: 3000
})
}
});
}
const handlePay = (item) => {
uni.showLoading({
mask: true,
});
let source = window.sf.isSfApp() ? 2 : 1;
getApi
.ContinueOrderPay({
orderId: item.orderId,
source
})
.then((res) => {
uni.hideLoading();
if (res.code === 200) {
let path = window.location.pathname;
if (!path.endsWith('/')) {
path = path + '/';
}
const returnUrl = `${window.location.origin}${path}#/pages/unlock/index`;
if (window.sf.isSfApp()) {
window.sf.goPay({
partnerId: res.data.partnerId, //商户id
prepayId: res.data.package, // 预支付id
nonceStr: res.data.nonceStr, //随机字符串
timeStamp: res.data.timeStamp, //时间戳
sign: res.data.paySign, //签名
package: `prepay_id=${res.data.package}`,
payChannel: 'payByWeChat' // app微信支付
}).then(res => {
const { channelType, status, message, channelResult } = res && res.result || {}
if (status === 0) {
uni.showToast({
title: '支付成功',
icon: 'none',
duration: 3000
})
hidePayPopup();
state.value.current = 0;
GetOrderList();
} else {
uni.showToast({
title: '支付失败',
icon: 'none',
duration: 3000
})
}
}).catch(err => console.log(err))
} else {
uni.showLoading({
title: '支付中',
mask: true
})
window.sf.goPay({
timeStamp: res.data.timeStamp, // 从服务器获取的时间戳
nonceStr: res.data.nonceStr, // 从服务器获取的随机字符串
package: `prepay_id=${res.data.package}`, // 从服务器获取的预支付交易会话标识
signType: res.data.signType, // 签名方式
paySign: res.data.paySign, // 从服务器获取的签名
successUrl: returnUrl,
failUrl: returnUrl
}).then(res => { }).catch(err => console.log(err))
}
} else {
}
});
}
const goOrder = async () => {
if (!state.value.selectItem?.orderId) {
return uni.showToast({
title: '请重新选择订单',
icon: 'none',
duration: 3000
})
}
if (!state.value.month) {
return uni.showToast({
title: '租期',
icon: 'none',
duration: 3000
}
)
}
let source = window.sf.isSfApp() ? 2 : 1;
uni.showLoading({
title: '支付中',
mask: true
})
getApi
.ContinuationOrder({
orderId: state.value.selectItem.orderId,
month: state.value.month,
source
})
.then((res) => {
uni.hideLoading();
if (res.code === 200) {
let path = window.location.pathname;
if (!path.endsWith('/')) {
path = path + '/';
}
const returnUrl = `${window.location.origin}${path}#/pages/unlock/index`;
if (window.sf.isSfApp()) {
window.sf.goPay({
partnerId: res.data.partnerId, //商户id
prepayId: res.data.package, // 预支付id
nonceStr: res.data.nonceStr, //随机字符串
timeStamp: res.data.timeStamp, //时间戳
sign: res.data.paySign, //签名
package: `prepay_id=${res.data.package}`,
payChannel: 'payByWeChat' // app微信支付
}).then(res => {
const { channelType, status, message, channelResult } = res && res.result || {}
if (status === 0) {
uni.showToast({
title: '支付成功',
icon: 'none',
duration: 3000
})
hidePayPopup();
GetOrderList();
} else {
uni.showToast({
title: '支付失败',
icon: 'none',
duration: 3000
})
}
}).catch(err => console.log(err))
} else {
uni.showLoading({
title: '支付中',
mask: true
})
window.sf.goPay({
timeStamp: res.data.timeStamp, // 从服务器获取的时间戳
nonceStr: res.data.nonceStr, // 从服务器获取的随机字符串
package: `prepay_id=${res.data.package}`, // 从服务器获取的预支付交易会话标识
signType: res.data.signType, // 签名方式
paySign: res.data.paySign, // 从服务器获取的签名
successUrl: returnUrl,
failUrl: returnUrl
}).then(res => { }).catch(err => console.log(err))
}
} else {
if (res.code === 1001) {
uni.showModal({
title: t('common.title'),
content: t('common.unpaidOrderTips'),
showCancel: false,
success: function () {
uni.switchTab({
url: '/pages/unlock/index',
})
},
})
return
}
}
});
}
const openCancelOrder = (item) => {
state.value.selectItem = item;
cancelOrderPopupRef.value.open();
}
const closeCancelOrder = () => {
cancelOrderPopupRef.value.close();
}
const cancelOrder = () => {
uni.showLoading({
mark: true,
})
getApi.OrderCountdownTime({ orderId: state.value.selectItem.orderId }).then(res => {
uni.hideLoading()
if (res.code === 200) {
closeCancelOrder();
state.value.current = 1
GetOrderList();
GetCancelOrder()
} else {
uni.showToast({
title: res.msg,
icon: "none",
});
}
})
}
function openMoveOutModal() {
uni.navigateTo({
url: '/pages/moveOut/index?orderId=' + state.value.selectItem.orderId
})
closeDetailPopup();
// moveOutPopup.value.open()
}
function closeMoveOutModal() {
moveOutPopup.value.close()
}
const showMonthPopup = () => {
getLockerById();
monthPopupRef.value.open();
};
const hideMonthPopup = () => {
monthPopupRef.value.close();
};
const confirmMonth = () => {
if (state.value.radioMonthvalue === -1) {
state.value.month = state.value.selfMonth;
} else {
state.value.month = state.value.radioMonthvalue;
}
getLockerExpense();
hideMonthPopup();
}
const selfDiscount = computed(() =>
state.value.lockData.discountList
.sort((a, b) => b.month - a.month)
.find(item => state.value.selfMonth >= item.month)?.discount ?? 1
)
const showPayPopup = (item) => {
state.value.selectItem = item;
payPopupRef.value.open();
getLockerExpense();
getLockerById()
};
const hidePayPopup = () => {
payPopupRef.value.close();
state.value.selectItem = {}
}
const getLockerById = () => {
uni.showLoading();
getSiteApi.GetLockerById({ lockerId: state.value.selectItem.lockerId }).then((res) => {
if (res.code === 200) {
state.value.lockData = res.data;
state.value.lockData.orderId = state.value.selectItem.orderId;
GetOrderById();
getLockerExpense();
}
});
};
const getLockerExpense = () => {
uni.showLoading({
mask: true,
});
getApi
.ContinuationOrderPricePost({
orderId: state.value.selectItem.orderId,
month: state.value.month,
// couponIds: state.value.couponItem.map((item) => item.couponDispositionId),
// point:state.value.point,
// serialNumber: state.value.couponOtherItem.map(x => {
// return {
// dealGroupId: x.dealGroupId,
// number: x.number,
// marketPrice: x.marketPrice,
// purchasePrice: x.price
// }
// })
})
.then((res) => {
uni.hideLoading();
if (res.code === 200) {
state.value.priceData = res.data;
}
if (res.code === 1002) {
uni.showModal({
title: t('common.title'),
content: t('common.ORDER_AMOUNT_ERROR'),
showCancel: false,
success: function () {
clearCoupon();
state.value.point = 0;
},
});
}
});
};
const openDetailPopup = (item) => {
state.value.selectItem = item;
detailPopupRef.value.open();
GetOrderById()
}
const closeDetailPopup = () => {
state.value.selectItem = {};
detailPopupRef.value.close();
}
const openPwdPopup = (item) => {
state.value.selectItem = item;
pawPopupRef.value.open();
GetLockPwd();
}
const closePwdPopup = () => {
state.value.selectItem = {};
pawPopupRef.value.close();
}
const openDevicePopup = (item) => {
state.value.selectItem = item;
devicePopupRef.value.open();
GetQRCode();
}
const closeDevicePopup = () => {
devicePopupRef.value.close();
}
// 发起退仓请求后点击我的订单跳到unlock
function closeModal2() {
moveOutPopup2.value.close()
closeDetailPopup()
GetOrderList();
}
const moveImageList = ref([]);
// 删除图片
const deletePic = (event) => {
moveImageList.value.splice(event.index, 1);
};
// 新增图片方法
const afterRead = async (event) => {
let lists = [].concat(event.file);
let fileListLen = moveImageList.value.length;
lists.map(item => {
moveImageList.value.push({
...item,
status: 'uploading'
});
});
for (let i = 0; i < lists.length; i++) {
const result = await uploadImage(lists[i].url);
let item = moveImageList.value[fileListLen];
moveImageList.value.splice(fileListLen, 1, Object.assign(item, {
status: result ? 'success' : 'failed',
url: result
}));
fileListLen++;
}
}
// 上传图片请求
const uploadImage = async (url) => {
let resUrl = '';
try {
const res = await getApi.UploaderImage({ filePath: url });
resUrl = res.data;
} catch (error) {
console.error('UploaderImage error:', error);
}
return resUrl;
}
// 确认退仓
const handleRefundLocker = async () => {
try {
const hasLoadingImage = moveImageList.value.find(item => item.status === 'uploading');
if (hasLoadingImage) {
uni.showToast({
title: '图片上传中,请稍后',
icon: 'none'
});
return;
}
const imageList = moveImageList.value.filter(item => item.status === 'success');
if (!imageList.length) {
uni.showToast({
title: '请上传图片',
icon: 'none'
});
return;
}
if (state.value.refundLoading) return;
uni.showLoading({ mask: true });
state.value.refundLoading = true;
let imageUrls = imageList.map(item => item.url);
imageUrls = imageUrls.join(',');
const { code } = await getApi.ApplyForRefundLocker({ orderId: state.value.selectItem.orderId, imageUrl: imageUrls });
if (code == 200) {
moveOutPopup.value.close();
moveOutPopup2.value.open();
}
uni.hideLoading();
state.value.refundLoading = false;
} catch (error) {
uni.hideLoading();
state.value.refundLoading = false;
}
}
// 取消退仓
const cancelMoveOutRqt = (item) => {
uni.showLoading()
getApi.CancelApplyForRefundLocker(item.orderId).then(res => {
uni.hideLoading()
if (res.code === 200) {
GetOrderList()
}
})
}
// 获取锁的密码
function RemoteOpen() {
uni.showLoading({ mask: true })
getLockApi.RemoteOpen({ lockMac: state.value.selectItem.lockMac, input: '', siteId: state.value.selectItem.siteId }).then(res => {
state.tryPWDCount++
if (res.data.isSuccess) {
uni.showToast({
title: t('door.UnlockSuccessful'),
duration: 3000,
icon: 'none'
})
uni.hideLoading()
} else {
uni.hideLoading()
uni.showToast({
title: res.data.message,
duration: 3000,
icon: 'none'
})
}
})
}
const lockPwd = ref('')
// 获取锁的密码
function GetLockPwd() {
lockPwd.value = ''
uni.showLoading({ mask: true })
getLockApi.GetDyncPwdByMac({ lockMac: state.value.selectItem.lockMac, siteId: state.value.selectItem.siteId }).then(res => {
if (!res.data.password) {
uni.hideLoading()
uni.showToast({
title: res.data.message,
duration: 3000,
icon: 'none'
})
} else {
uni.hideLoading()
lockPwd.value = res.data.password
}
})
}
const QRCode = ref('')
const ifShow = ref(false)
// 获取二维码
function GetQRCode() {
uni.showLoading({ mask: true })
getLockApi.GetAccesscontrolQRCodeBySite({ siteId: state.value.selectItem.siteId, orderId: state.value.selectItem.orderId }).then(res => {
if (res.code === 200) {
QRCode.value = res.data
ifShow.value = true
} else {
ifShow.value = false
}
uni.hideLoading();
})
}
const GetOrderById = () => {
uni.showLoading()
state.value.orderData = {}
getApi.GetOrderById({ orderId: state.value.selectItem.orderId }).then(res => {
uni.hideLoading()
if (res.code === 200) {
state.value.orderData = res.data
}
})
}
const GetCancelOrder = () => {
uni.showLoading()
getApi.GetCancelOrder().then(res => {
state.value.cancelOrderList = []
if (res.code === 200) {
state.value.cancelOrderList = res.data
}
uni.hideLoading();
})
}
const GetOrderList = () => {
uni.showLoading()
getApi.GetOrderList().then(res => {
state.value.orderList = []
if (res.code === 200) {
state.value.orderList = res.data;
//检查是否验证过
// checkedHasVerify()
}
uni.hideLoading();
})
}
onShareAppMessage((res) => {
if (res.from === "button") {
// 来自页面内分享按钮
console.log(res.target);
}
return shareParam;
});
onLoad((params) => {
// GetOrderList()unpaid
})
onHide(() => {
})
const goVaild = () => {
uni.navigateTo({
url: "/pagesb/validationInfo/index",
});
};
const token = ref(uni.getStorageSync('token'))
onShow(() => {
uni.hideTabBar()
token.value = uni.getStorageSync('token')
const app = getApp()
const type = app.globalData?.tabParams?.type
if (type === "unpaid") {
state.value.current = 2
} else if (type === "paid") {
state.value.current = 0
}
if (type) {
app.globalData.tabParams = {}
}
onShowRerequestByIsLogin(() => {
GetOrderList();
if (state.value.current === 2) {
GetCancelOrder()
}
}, (err) => {
state.value.orderList = []
})
})
</script>
<style scoped lang="scss">
@import '@/static/style/theme.scss';
// 解决H5转微信小程序使用v-show不生效的问题
[hidden] {
display: none !important;
}
.modal-container {
// height: 700rpx;
// background: #000;
display: flex;
justify-content: flex-start;
align-items: center;
flex-direction: column;
padding: 32rpx;
.modal-title {
width: 100%;
text-align: center;
font-weight: bold;
font-size: 36rpx;
color: #000000;
}
:deep(.uv-upload__wrap) {
display: flex;
}
.modal-text {
width: 100%;
margin-top: 20rpx;
font-size: 26rpx;
font-weight: 600;
text-align: center;
line-height: 32rpx;
}
.upload {
margin-top: 30rpx;
height: 250rpx;
width: 100%;
// background: #000;
display: flex;
justify-content: center;
// overflow-x: scroll;
overflow-y: scroll;
// white-space: nowrap;
flex-wrap: nowrap;
// overflow: hidden;
}
.modal-button {
margin-top: 20rpx;
width: 100%;
min-height: 86rpx;
display: flex;
gap: 20rpx;
:deep(.uv-button-wrapper) {
flex: 1;
}
}
}
.modal-container2 {
height: 400rpx;
@extend .modal-container
}
.payPopupBox {
.titleIcon {
display: flex;
align-items: center;
padding: 32rpx 0;
padding-top: 0;
image {
width: 32rpx;
height: 32rpx;
margin-right: 8rpx;
}
}
.garyBox {
border: 3rpx solid #F6F6F7;
background-color: #F8F9FB;
display: flex;
justify-content: space-between;
padding: 26rpx;
border-radius: 12rpx;
color: #808386;
font-weight: 600;
.select {
display: flex;
align-items: center;
}
}
.garyBoxM {
display: flex;
flex-direction: column;
}
.bitianBox {
display: flex;
align-items: center;
vertical-align: middle;
}
.title2 {
margin-bottom: 20rpx;
display: flex;
justify-content: space-between;
.bitian {
border: 1px solid #FB322E;
padding: 2rpx 8rpx;
color: #FB322E;
border-radius: 99rpx;
text-align: center;
font-size: 18rpx;
margin-left: 10rpx;
}
}
.toOrder {
padding: 0;
padding-left: 28rpx;
border-radius: 999rpx;
display: flex;
justify-content: space-between;
// align-items: center;
background-color: #0D1118;
color: #FFFFFF;
.left {
color: #E9CBA1;
display: flex;
align-items: center;
font-size: 38rpx;
.price {
&.overMaxFont {
font-size: 32rpx;
}
}
.detail {
display: flex;
align-items: center;
margin-left: 20rpx;
color: #d0d1d2;
font-size: 28rpx;
.overMaxFont {
font-size: 24rpx;
}
image {
margin-left: 10rpx;
}
}
}
.right {
display: flex;
align-items: center;
margin-right: -1px;
text {
display: flex;
align-items: center;
}
.goOrder {
height: 86rpx;
width: 250rpx;
:deep(.uv-button) {
font-size: 28rpx;
border: none;
font-weight: 600;
}
}
}
}
}
.unitPopupBox {
min-height: 50%;
padding: 32rpx;
:deep(.uv-radio__label-wrap){
display: none;
}
.title {
margin-bottom: 20px;
display: flex;
justify-content: space-between;
align-items: center;
}
:deep(.uv-radio-group) {
width: 100%;
}
.info {
display: flex;
font-size: 28rpx;
.list {
display: flex;
width: 100%;
padding-bottom: 20rpx;
border-bottom: 1px dashed #787B7E10;
margin-bottom: 20rpx;
.left {
flex: 1;
font-size: 28rpx;
.zuqi {
display: flex;
align-items: center;
.minus {
width: 40rpx;
height: 40rpx;
border-width: 1px;
border-color: #E6E6E6;
border-style: solid;
border-top-left-radius: 100px;
border-top-right-radius: 100px;
border-bottom-left-radius: 100px;
border-bottom-right-radius: 100px;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
align-items: center;
line-height: 1;
}
.input {
padding: 10rpx;
background-color: #EBEBEB;
border-radius: 8rpx;
margin: 0 10rpx;
font-weight: 600;
}
.plus {
width: 40rpx;
height: 40rpx;
background-color: #FF0000;
border-radius: 50%;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
align-items: center;
line-height: 1;
}
}
}
.radioBox {
display: flex;
justify-content: end;
}
}
}
}
.popupBoxW710 {
width: 710rpx;
}
.popupBoxW650 {
width: 650rpx;
}
.popupBox {
display: flex;
flex-direction: column;
padding: 32rpx;
.title {
z-index: 9;
display: flex;
justify-content: space-between;
align-items: center;
}
.content {
display: flex;
flex-direction: column;
justify-content: center;
text {
margin: 20rpx 0;
text-align: center;
}
}
.btnBox {
display: flex;
gap: 20rpx;
padding: 0 20rpx;
width: 100%;
:deep(.uv-button-wrapper) {
flex: 1;
}
}
.orderList {
display: flex;
flex-direction: column;
.close-icon {
position: absolute;
right: 0.9rem;
width: 0.75rem;
height: 0.75rem;
}
.box2_border {
margin-bottom: 20rpx;
padding-top: 20rpx;
border-bottom: 1px solid rgba(120, 123, 126, 0.1);
border-top: 1px solid rgba(120, 123, 126, 0.1);
}
.box2 {
display: flex;
flex-direction: column;
padding-bottom: 10rpx;
.item {
display: flex;
margin-bottom: 16rpx;
.label {
padding-right: 10rpx;
}
}
}
.orderOn {
width: 100%;
display: flex;
align-items: center;
color: #626466;
font-size: 20rpx;
margin-bottom: 20rpx;
:deep(.uv-button) {
font-size: 14rpx;
color: #6f6f6f;
font-weight: bold;
height: 30rpx;
}
}
.orderInfo {
width: 100%;
display: flex;
flex-direction: column;
border-bottom: 1px solid rgba(120, 123, 126, 0.1);
margin-bottom: 30rpx;
:deep(.uv-button) {
margin-left: 8rpx;
height: 30rpx;
width: 70rpx;
padding: 0;
}
}
image {
width: 32rpx;
height: 32rpx;
margin-right: 8rpx;
}
/* 顶部行 */
.top {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20rpx;
image {
margin-top: 8rpx;
}
.left {
display: flex;
image {
margin-top: 8rpx;
}
.title-wrap {
display: flex;
flex-direction: row;
align-items: center;
.tag {
background-color: $sfgrayBgColor;
margin-left: 8rpx;
border-radius: 8px;
height: 35rpx;
line-height: 35rpx;
padding: 0 8rpx;
}
}
}
.right {
.distance {}
}
}
/* 底部地址行 */
.bottom {
display: flex;
margin-bottom: 30rpx;
image {
margin-top: 2rpx;
}
.address {
flex: 1;
word-wrap: break-word;
word-break: break-all;
}
}
.btn {
display: flex;
justify-content: space-between;
:deep(.uv-button) {
min-width: 135rpx;
height: 60rpx;
font-size: 26rpx;
line-height: 60rpx;
color: #6f6f6f;
font-weight: bold;
// border-color: #A8AAAC !important;
border-width: 1.5px !important;
}
:deep(.uv-button--info) {
border-color: #A8AAAC !important;
}
}
}
.paw {
margin: -20rpx auto -34rpx;
z-index: 1;
}
}
.header {
width: 100%;
// padding: 20rpx;
background-color: #FFFFFF;
:deep(.uv-tabs__wrapper__nav__item) {
height: 80rpx !important;
}
:deep(.uv-tabs__wrapper__nav__item__text) {
font-size: 32rpx;
}
:deep(.uv-tabs__wrapper__nav__line) {
margin-bottom: -2px;
}
}
.container {
width: 100%;
// height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
padding-bottom: 0;
.unlock-wrap {
height: calc(100vh - 160rpx);
padding-bottom: 160rpx;
overflow: auto;
}
.content {
display: flex;
width: 100%;
flex-direction: column;
.orderList {
display: flex;
flex-direction: column;
.box2 {
display: flex;
flex-direction: column;
padding-bottom: 10rpx;
.item {
display: flex;
margin-bottom: 16rpx;
.label {
padding-right: 10rpx;
}
}
}
.orderOn {
width: 100%;
display: flex;
align-items: center;
color: #626466;
font-size: 20rpx;
margin-bottom: 20rpx;
:deep(.uv-button) {
font-size: 14rpx;
color: #6f6f6f;
font-weight: bold;
}
}
.orderInfo {
width: 100%;
display: flex;
flex-direction: column;
border-bottom: 1px solid rgba(120, 123, 126, 0.1);
margin-bottom: 30rpx;
:deep(.uv-button) {
margin-left: 8rpx;
height: 30rpx;
width: 70rpx;
padding: 0;
}
}
image {
width: 32rpx;
height: 32rpx;
margin-right: 8rpx;
}
/* 顶部行 */
.top {
display: flex;
justify-content: space-between;
margin-bottom: 20rpx;
image {
margin-top: 0rpx;
}
.left {
display: flex;
align-items: center;
.title-wrap {
display: flex;
flex-direction: row;
align-items: center;
.title {}
.tag {
background-color: $sfgrayBgColor;
margin-left: 8rpx;
border-radius: 8px;
height: 35rpx;
line-height: 35rpx;
padding: 0 8rpx;
}
}
}
.right {
.distance {}
}
}
/* 底部地址行 */
.bottom {
display: flex;
margin-bottom: 20rpx;
image {
margin-top: 2rpx;
}
.address {
flex: 1;
word-wrap: break-word;
word-break: break-all;
}
}
.btn {
display: flex;
justify-content: space-between;
:deep(.uv-button) {
min-width: 135rpx;
height: 60rpx;
font-size: 26rpx;
line-height: 60rpx;
color: #6f6f6f;
font-weight: bold;
border-width: 1.5px !important;
}
:deep(.uv-button--info) {
border-color: #A8AAAC !important;
}
}
}
}
}
</style>