You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2351 lines
64 KiB

11 months ago
<template>
<page-meta :page-style="`overflow:${
isShowService || isShowHospital || isShowTime || isShowArchive
? 'hidden'
: 'visible'
};`"></page-meta>
<view class="page">
<image class="bkg" mode="aspectFill" src="~@/package_sub/static/AddOrder/bkg.png"></image>
<view class="container">
<!-- <view v-if="form.pay_status === 2" class="refund-text">
订单已退款
</view> -->
<view class="step">
<view class="step-item" v-for="(i, index) in stepList" :class="{ 'is-active': index < currentStep }"
:key="index">
<view class="step-item__dot">
<u-icon v-if="index < currentStep-1" name="checkmark" color="#fff" size="16"></u-icon>
<u-icon v-else-if="index === currentStep-1" name="dot-fill" color="#fff" size="16"></u-icon>
</view>
<view class="step-item__text">{{ i.name }}</view>
</view>
</view>
<view v-if="form.pay_status === 0">
<view class="switch-service">
<view class="switch-service__icon">
<u-icon :name="
accompanyProduct.cover
? accompanyProduct.cover.url
: vuex_default_icon
" size="30"></u-icon>
</view>
<view class="switch-service__name">
{{ accompanyProduct.name || "未选择" }}
</view>
<view v-if="!orderId" class="switch-service__btn" @click="isShowService = true">
<image src="~@/package_sub/static/switch.png" mode="aspectFit"></image>
<text>更换服务</text>
</view>
</view>
<!-- 产品数量选择 - 独立的Cell -->
<view v-if="!orderId && accompanyProduct.id && form.can_multi_num==1" class="quantity-card">
<view class="quantity-card__header">
<view class="quantity-card__title">产品数量</view>
<view class="quantity-card__content">
<view class="quantity-control">
<u-button size="mini" type="default" @click="decreaseQuantity"
:disabled="form.quantity <= 1"
:custom-style="{ width: '60rpx', height: '60rpx', borderRadius: '50%' }"
:throttle-time="0">
<u-icon name="minus" size="20" color="#666"></u-icon>
</u-button>
<view class="quantity-display">{{ form.quantity }}</view>
<u-button size="mini" type="default" @click="increaseQuantity"
:custom-style="{ width: '60rpx', height: '60rpx', borderRadius: '50%' }"
:throttle-time="0">
<u-icon name="plus" size="20" color="#666"></u-icon>
</u-button>
</view>
</view>
</view>
</view>
<view class="card" v-if="form.nurse_id && nurse.id">
<view class="desc-card__title">
护工信息
</view>
<view class="desc-card__content">
<view class="desc-card__content--title">
<u-tag :text="workStatus.get(form.status)" mode="dark" />
</view>
<br />
<view class="desc-card__content--title"> 姓名 </view>
<view class="desc-card__content--value">
{{ nurse.name }}
</view>
<br />
<view class="desc-card__content--title"> 联系方式 </view>
<view class="desc-card__content--value"> {{ nurse.mobile }} </view>
<br />
<view class="desc-card__content--title"> 性别 </view>
<view class="desc-card__content--value"> {{ nurse.sex == 1 ? '男' : '女' }} </view>
<br />
</view>
</view>
<u-form :model="form" :rules="rules" ref="uForm" :label-width="178" :error-type="['toast']">
<view class="form-card form-card-1">
<!-- 站点 根据前面选择的站点来 :select-open="isShowSite"
@click="orderId ? false : (isShowSite = true)"-->
<u-form-item label="站点区域" prop="site_id" required>
<u-input :type="!!orderId ? 'input' : 'input'" placeholder="请选择站点区域"
:disabled="true" :value="site_name" />
</u-form-item>
<u-form-item label="预约人" prop="appoint_name" required>
<u-input ref="appointNameInput" v-model="form.appoint_name" :disabled="!!orderId"
placeholder="请填写预约人" />
</u-form-item>
<u-form-item label="预约人电话" prop="appoint_mobile" required>
<u-input ref="appointMobileInput" :disabled="!!orderId" v-model="form.appoint_mobile"
placeholder="请填写预约人电话" type="number" />
</u-form-item>
<u-form-item :label="(form.type == 1 ? '被服务' : '被服务') +'人'" prop="user_archive_id" required>
<u-input :type="!!orderId ? 'input' : 'select'" placeholder="请选择人员" :disabled="!!orderId"
:value="archive.name" :select-open="isShowArchive" @click="handleArchiveClick" />
</u-form-item>
<u-form-item label="就诊医院" prop="hospital" required v-if="form.type == 1">
<u-input :type="!!orderId ? 'input' : 'select'" placeholder="请选择就诊医院" :disabled="!!orderId"
:value="hospital.name" :select-open="isShowHospital"
@click="orderId ? false : (isShowHospital = true)" />
</u-form-item>
<u-form-item :label="(form.type == 1 ? '就诊' : '服务') + '时间'" prop="time" required>
<u-input :type="!!orderId ? 'input' : 'select'" placeholder="请选择时间" :disabled="!!orderId"
v-model="form.time" :select-open="isShowTime"
@click="orderId ? false : (isShowTime = true)" />
</u-form-item>
<u-form-item label="是否可以自理">
<view slot="right">
<u-input v-if="!!orderId" disabled :value="form.my_provide ? '是' : '否'" />
<u-radio-group v-else v-model="form.my_provide" active-color="#c20d12">
<u-radio :name="1"></u-radio>
<u-radio :name="0"></u-radio>
</u-radio-group>
</view>
</u-form-item>
<u-form-item label="详细地址" prop="city" v-if="form.type == 2">
<u-input v-model="form.city" :disabled="!!orderId" placeholder="请填写详细地址" type="textarea" />
<view style="text-align: right;color:blue" @click="openMap"></view>
</u-form-item>
<u-form-item :label="'选择'+ (form.type == 1 ? '陪诊师' : '照护师') +'性别'" :border-bottom="false">
<view slot="right">
<u-input v-if="!!orderId" disabled placeholder="请选择性别"
:value="sex(form.accompany_sex)" />
<u-radio-group v-else :disabled="!!orderId" v-model="form.accompany_sex"
active-color="#c20d12">
<u-radio :name="1"></u-radio>
<u-radio :name="2"></u-radio>
<u-radio :name="0">任意</u-radio>
</u-radio-group>
</view>
</u-form-item>
</view>
<view class="form-card form-card-2" v-if="form.type == 1">
<view class="title">
<view class="title__left">
<text>上传资料</text>
<text>挂号单</text>
</view>
<!-- <view class="title__right">
点击查看示例
</view> -->
</view>
<view>
<u-upload v-if="!orderId" :action="action" ref="uUpload" :header="{
['Authorization']: `Bearer ${token}`,
}"></u-upload>
<image v-else v-for="img in fileList" :src="img.url" :key="img.url" mode="aspectFit"
style="max-width: 200rpx;max-height: 180rpx;"></image>
</view>
</view>
<view class="form-card form-card-3">
<u-form-item label="其他服务需求" prop="content" required :border-bottom="false">
<u-input :disabled="!!orderId" border :custom-style="{ 'letter-spacing': '2rpx' }"
border-color="#dad9d9" placeholder="请简单描述您要就诊的科室及就诊内容(内容加密保护)" v-model="form.content"
type="textarea"></u-input>
</u-form-item>
</view>
</u-form>
</view>
<view class="desc-card" v-if="form.pay_status === 1">
<view class="desc-card__title"> 订单信息 </view>
<view class="desc-card__content">
<view class="desc-card__content--title"> 服务内容 </view>
<view class="desc-card__content--value">
{{ accompanyProduct.name }}
</view>
<br />
<view class="desc-card__content--title"> 数量 </view>
<view class="desc-card__content--value">
{{ form.quantity || 1 }}
</view>
<br />
<!-- <view class="desc-card__content&#45;&#45;title"> 服务标价 </view>-->
<!-- <view class="desc-card__content&#45;&#45;value"> ¥ 288 </view>-->
<!-- <br />-->
<view class="desc-card__content--title"> 订单金额 </view>
<view class="desc-card__content--value">
¥ {{ (accompanyProduct.price || 0) * (form.quantity || 1) }}
</view>
<br />
<view class="desc-card__content--title"> 订单编号 </view>
<view class="desc-card__content--value"> {{ form.no }} </view>
<br />
<view class="desc-card__content--title"> 下单日期 </view>
<view class="desc-card__content--value">
{{ form.created_at }}
</view>
</view>
6 months ago
<!-- 支付区域 -->
11 months ago
<view class="qrcode-section" v-if="showPayQrCode">
6 months ago
<!-- Tab 切换 -->
<view class="payment-tabs">
<view
class="tab-item"
:class="{ 'tab-active': activeTab === 'qrcode' }"
@click="switchTab('qrcode')"
>
付款二维码
</view>
<view
class="tab-item"
:class="{ 'tab-active': activeTab === 'pay' }"
@click="switchTab('pay')"
>
立即支付
</view>
</view>
<!-- Tab 内容 -->
<view class="tab-content">
<!-- 付款二维码 Tab -->
<view v-if="activeTab === 'qrcode'" class="tab-panel">
6 months ago
<view class="qrcode-wrapper" style="position: relative;">
6 months ago
<!-- 显示图片可长按识别 -->
<image
v-if="qrcodeImagePath"
:src="qrcodeImagePath"
mode="aspectFit"
show-menu-by-longpress
6 months ago
:class="{ 'qrcode-disabled': qrcodeExpired }"
6 months ago
style="width: 400rpx; height: 400rpx; display: block; margin: 0 auto;"
></image>
<!-- Canvas 绘制使用 hide 属性隐藏但保持可渲染 -->
<uqrcode
v-else-if="payQrCode"
ref="payQrCode"
canvas-id="pay-qrcode"
:value="payQrCode"
:size="400"
:sizeUnit="'rpx'"
:start="true"
:auto="true"
:loading="false"
:hide="true"
@error="onQrCodeError"
@complete="onQrCodeComplete"
:options="{
margin: 10,
colorDark: '#000000',
colorLight: '#ffffff'
}"
></uqrcode>
<view v-else style="text-align: center; color: #999; padding: 40rpx;">
正在生成二维码...
</view>
6 months ago
<!-- 二维码失效遮罩层 -->
<view v-if="qrcodeExpired && (qrcodeImagePath || payQrCode)" class="qrcode-overlay" @click="regetQrcode">
<view class="reget-btn">
<text>重新获取</text>
</view>
</view>
6 months ago
</view>
<view class="qrcode-tip">请使用微信扫码支付</view>
</view>
<!-- 立即支付 Tab -->
<view v-if="activeTab === 'pay'" class="tab-panel">
<view class="pay-button-section">
<u-button
type="primary"
shape="circle"
@click="scrollToPayQr"
6 months ago
:disabled="payCooldownSeconds > 0"
6 months ago
class="pay-btn-large"
:custom-style="{
width: '100%',
height: '88rpx',
fontSize: '32rpx',
6 months ago
fontWeight: '500',
opacity: payCooldownSeconds > 0 ? 0.6 : 1
6 months ago
}"
>
6 months ago
{{ payCooldownSeconds > 0 ? `支付成功,${payCooldownSeconds}秒后可再次支付` : '立即支付' }}
6 months ago
</u-button>
</view>
</view>
11 months ago
</view>
</view>
</view>
<!-- 服务完成 -->
<view v-if="form.pay_status === 2">
<view class="switch-service">
<view class="switch-service__icon">
<u-icon :name="vuex_default_icon" size="30"></u-icon>
</view>
<view class="switch-service__name">
<view>医康养 就医省心</view>
<view style="font-size: 24rpx; color: #999999">期待下次为您服务</view>
</view>
<view class="switch-service__btn" style="font-size: 24rpx; color: #999999">
订单已完成
</view>
</view>
<view class="desc-card">
<view class="desc-card__title"> 预约信息 </view>
<view class="desc-card__content">
<view class="desc-card__content--title" v-if="form.type == 1"> </view>
<view class="desc-card__content--value" v-if="form.type == 1">
{{ hospital.site ? hospital.site.name : "" }}
</view>
<br />
<view class="desc-card__content--title" v-if="form.type == 1"> </view>
<view class="desc-card__content--value" v-if="form.type == 1"> {{ hospital.name }} </view>
<br />
<view class="desc-card__content--title" v-if="form.type == 1"> </view>
<view class="desc-card__content--value" v-if="form.type == 1"> {{ form.time }} </view>
<br />
<view class="desc-card__content--title"> 预约人 </view>
<view class="desc-card__content--value">
{{ form.appoint_name }}
</view>
<br />
<view class="desc-card__content--title"> 预约人电话 </view>
<view class="desc-card__content--value">
{{ form.appoint_mobile }}
</view>
<br />
<view class="desc-card__content--title" v-if="form.type == 1"> </view>
<view class="desc-card__content--title" v-if="form.type == 2"> </view>
<view class="desc-card__content--value" v-if="form.type == 1 || form.type == 2">
{{ sex(form.accompany_sex) }}
</view>
<br />
<view class="desc-card__content--title"> 服务需求 </view>
<view class="desc-card__content--value"> {{ form.content || ' ' }} </view>
</view>
</view>
<view class="desc-card">
<view class="desc-card__title"> 被服务人信息 </view>
<view class="desc-card__content">
<view class="desc-card__content--title"> 姓名 </view>
<view class="desc-card__content--value"> {{ archive.name || ' ' }} </view>
<br />
<view class="desc-card__content--title"> 身份证 </view>
<view class="desc-card__content--value"> {{ archive.idcard || ' ' }} </view>
<br />
<view class="desc-card__content--title"> 地址 </view>
<view class="desc-card__content--value"> {{ archive.address || ' ' }} </view>
<br />
<view class="desc-card__content--title"> 手机号 </view>
<view class="desc-card__content--value"> {{ archive.mobile || ' ' }} </view>
<br />
<view class="desc-card__content--title"> 行动能力 </view>
<view class="desc-card__content--value"> {{ archive.is_move ? '无障碍' : '有障碍' }} </view>
</view>
</view>
<view class="desc-card">
<view class="desc-card__title"> 订单信息 </view>
<view class="desc-card__content">
<view class="desc-card__content--title"> 服务内容 </view>
<view class="desc-card__content--value">
{{ accompanyProduct.name }}
</view>
<br />
<view class="desc-card__content--title"> 数量 </view>
<view class="desc-card__content--value">
{{ form.quantity || 1 }}
</view>
<br />
<!-- <view class="desc-card__content&#45;&#45;title"> 服务标价 </view>-->
<!-- <view class="desc-card__content&#45;&#45;value"> ¥ 288 </view>-->
<!-- <br />-->
<view class="desc-card__content--title"> 订单金额 </view>
<view class="desc-card__content--value">
¥ {{ (accompanyProduct.price || 0) * (form.quantity || 1) }}
</view>
<br />
<view class="desc-card__content--title"> 订单编号 </view>
<view class="desc-card__content--value"> {{ form.no }} </view>
<br />
<view class="desc-card__content--title"> 下单日期 </view>
<view class="desc-card__content--value">
{{ form.created_at }}
</view>
</view>
</view>
</view>
</view>
<view class="bottom-bar" v-if="form.pay_status===0">
<view class="price">
<text>实付</text>
<text>¥ {{ orderId ? paidPrice : ((accompanyProduct.price || 0) * (form.quantity || 1)) }}</text>
<view class="edit-icon-touch" @click="openPriceEdit">
<u-icon name="edit-pen" size="24" color="#c20d12"></u-icon>
</view>
</view>
<u-button v-if="form.pay_status === 0" style="margin-left: auto;" shape="circle" ripple
:custom-style="payBtnStyle" :throttle-time="2000"
@click="pay">立即{{ form.pay_status === 0 && !orderId ? '下单' : '支付' }}</u-button>
<view v-if="orderId && form.pay_status === 1 && form.status !== 4" class="more"
@click="isShowMoreAction = true">更多</view>
</view>
<!-- 服务列表 -->
<u-popup v-model="isShowService" mode="bottom" safe-area-inset-bottom closeable :border-radius="10"
:height="800">
<view class="service-list">
<view class="service-list-item" v-for="(item, i) in list_service" :key="i" @click="changeService(item)">
<view class="service-list-item__icon">
<!-- <u-icon name="integral" size="30"></u-icon> -->
<image style="width: 70rpx; height: 70rpx" :src="item.cover.url"></image>
</view>
<view class="service-list-item__name">
{{ item.name }}
</view>
<view class="service-list-item__price"> ¥{{ item.price }} </view>
</view>
</view>
</u-popup>
<!-- 如果前面没有选站点 就需要选择产品下的站点 -->
<u-select v-model="isShowSite" value-name="id" @confirm="confirmSite" label-name="name"
:list="list_psite"></u-select>
<!-- 选择就诊人可以新增 -->
<u-popup v-model="isShowArchive" mode="bottom" safe-area-inset-bottom closeable :border-radius="10"
:height="800">
<view class="service-list" style="padding-bottom: 120rpx">
<view class="service-list-item" v-for="(item, i) in list_archive" :key="i"
@click="confirmArchive(item)">
<view class="service-list-item__namewrap">
<view class="service-list-item__name">
{{ item.name }}
</view>
<view class="service-list-item__price">
{{ item.mobile }}
</view>
</view>
<view class="service-list-item__address">
<text>{{ item.address }}</text>
<view class="icon">
<u-icon name="edit-pen" :size="40" color="#999999" @tap.stop="editUser(item)"></u-icon>
<!-- <u-icon name="trash" style="margin-left: 40rpx;" :size="40" color="red"
@tap.stop="delUser(item)"></u-icon> -->
</view>
</view>
</view>
</view>
<view class="service-list-btn">
<u-button shape="circle" ripple :custom-style="payBtnStyle" @click="addArchive"></u-button>
</view>
</u-popup>
<!-- 新增就诊人 -->
<service-archive ref="serviceArchive" :mobile="form.appoint_mobile" @addSuccess="addSuccess"></service-archive>
<!-- 选择 站点下的医院 -->
<u-select v-model="isShowHospital" value-name="id" @confirm="confirmHospital" label-name="name"
:list="list_hospital"></u-select>
<!-- 服务时间 -->
<u-picker v-model="isShowTime" :params="{
year: true,
month: true,
day: true,
hour: true,
minute: true,
second: false,
}" mode="time" @confirm="confirmTime"></u-picker>
<!-- 更多操作-->
<u-action-sheet safe-area-inset-bottom :list="moreActionList" v-model="isShowMoreAction"
@click="moreActionClick" />
<!-- 优惠不显示先 -->
<u-popup v-model="isShowPayPopup" class="pay-popup" mode="bottom" closeable :z-index="10073"
:close-icon-size="40" close-icon="close-circle" :border-radius="20" :height="800">
<view class="pay-popup-container">
<view class="service">
<view class="service__icon">
<u-icon name="integral" size="40"></u-icon>
</view>
<view class="service__text">
<view class="service__text--price">¥600.00</view>
<view class="service__text--name">专享半天陪诊</view>
</view>
</view>
<view class="row">
<view class="row__title"> 平台保障 </view>
<view class="row__content d-flex ai-center cards">
<view class="cards__icon d-flex jc-center ai-center">
<u-icon name="integral" size="30"></u-icon>
</view>
<view style="padding-left: 18rpx" class="flex-1">
<view class="d-flex ai-center">
<view style="font-size: 28rpx">半天陪诊·3次卡</view>
<view class="d-flex ai-center" style="margin-left: auto">
<text style="
font-size: 24rpx;
padding-right: 22rpx;
font-weight: bold;
">¥ 600</text>
<u-checkbox :value="false" shape="circle" active-color="#c20d12" />
</view>
</view>
<view class="d-flex ai-center">
<view style="color: #999; font-size: 24rpx">本次预约可直接抵扣1次</view>
<view style="
font-size: 16rpx;
color: #999;
font-weight: 500;
margin-left: auto;
">低至¥246/
</view>
</view>
</view>
</view>
</view>
<view class="row">
<view class="row__title"> 平台保障 </view>
<view class="row__content d-flex jc-center">
<view class="row__content--first"></view>
<view class="row__content--name">陪诊服务险</view>
<view class="d-flex ai-center" style="margin-left: auto">
<text style="
font-size: 24rpx;
padding-right: 22rpx;
font-weight: bold;
">¥ 600</text>
<u-checkbox :value="false" shape="circle" active-color="#c20d12" />
</view>
</view>
</view>
<view class="row">
<view class="row__title"> 本单优惠 </view>
<view class="row__content d-flex jc-center">
<view class="row__content--first" style="background: #c31014"></view>
<view class="row__content--name" style="color: #999">请选择优惠券</view>
<view style="margin-left: auto">
<u-icon name="arrow-down" :size="24"></u-icon>
</view>
</view>
</view>
<view class="row use-card"> 新人优惠券 20 服务满1元可用 </view>
<view class="row">
<view class="row__content d-flex jc-center">
<view class="row__content--first" style="background: #c31014"></view>
<view class="row__content--name">无忧赠险保障</view>
<view style="margin-left: auto; color: #c31014"> -25 </view>
</view>
</view>
<view class="is-auth">
<u-checkbox v-model="isAuth" shape="circle" active-color="#c20d12">
<text style="padding-left: 10rpx">我已认真阅读预约相关</text>
<text style="color: #c20d12" @click.stop.prevent>服务条款同意书</text>
</u-checkbox>
</view>
</view>
</u-popup>
<u-top-tips :z-index="10080" ref="uTips"></u-top-tips>
<u-popup v-model="showPriceEdit" mode="center" :mask="true">
<view
style="padding: 60rpx 40rpx; background: #fff; border-radius: 16rpx; min-width: 480rpx; box-sizing: border-box;">
<view
style="font-size: 36rpx; font-weight: bold; margin-bottom: 40rpx; text-align: center; color: #222;">
修改总价</view>
<u-input v-model="editPrice" type="digit" placeholder="请输入新总价"
style="margin-bottom: 40rpx; font-size: 32rpx; border-radius: 8rpx; background: #f7f7f7; padding: 20rpx 24rpx;"
border />
<view style="display: flex; justify-content: space-between; gap: 30rpx;">
<u-button size="medium" style="flex:1; border-radius: 8rpx;"
@click="showPriceEdit = false">取消</u-button>
<u-button size="medium" type="primary" style="flex:1; border-radius: 8rpx;"
@click="confirmEditPrice">确定</u-button>
</view>
</view>
</u-popup>
</view>
</template>
<script>
import serviceArchive from "@/component/serviceArchive/service-archive.vue";
import {
ROOTPATH as baseUrl
} from "@/common/config.js";
import {
isNull
} from "@/common/util.js"
import uqrcode from "@/uni_modules/Sansnn-uQRCode/components/uqrcode/uqrcode.vue";
export default {
components: {
serviceArchive,
uqrcode
},
data() {
return {
paidPrice: 0,
workStatus: new Map([
[0, '待处理'],
[1, '已到客户家'],
[2, '已接到客户'],
[3, '已到医院'],
[4, '完成服务']
]),
payBtnStyle: {
"background-image": "linear-gradient(-90deg, #e26165 0%, #c10d12 94%, #c10d12 100%)",
"font-weight": "500",
"font-size": "28rpx",
color: "#fff",
width: "288rpx",
"margin-right": "25rpx"
},
//more action
isShowMoreAction: false,
// service
isShowService: false,
// form
fileList: [],
isShowHospital: false,
isShowTime: false,
isShowArchive: false,
list_service: [],
list_hospital: [],
list_archive: [],
orderId: "",
nurse: {},
isShowSite: false,
list_psite: [],
site_name: '',
canSelectSite: false, // 是否需要选择 站点
form: {
type: 1,
is_show: false,
accompany_product_id: "",
site_id: '',
user_archive_id: "",
city: "",
hospital: "",
time: "",
my_provide: 1,
appoint_name: "",
appoint_mobile: "",
accompany_sex: "",
file_ids: "",
content: "",
pay_status: 0,
no: "",
quantity: 1,
},
rules: {
user_archive_id: [{
type: "number",
required: true,
message: "请选择人员",
trigger: ["blur", "change"],
}, ],
time: [{
required: true,
message: "请选择时间",
trigger: ["blur", "change"],
}, ],
hospital: [{
validator: (rule, value, callback) => {
if (this.form.type == 2) {
return true
} else {
return !!value
}
},
message: "请选择就诊医院",
trigger: ["blur", "change"],
}, ],
appoint_name: [{
required: true,
message: "请输入预约人",
trigger: ["blur", "change"],
}, ],
appoint_mobile: [{
required: true,
message: "请输入预约人电话",
trigger: ["blur", "change"],
},
{
// 自定义验证函数,见上说明
validator: (rule, value, callback) => {
return this.$u.test.mobile(value);
},
message: "预约人电话不正确",
// 触发器可以同时用blur和change
trigger: ["change", "blur"],
},
],
content: [{
required: true,
message: "请填写其他服务需求",
trigger: ["blur", "change"],
}, ],
// site_id: [
// {
// required: true,
// message: "请选择站点区域",
// trigger: ["blur", "change"],
// },
// ],
},
action: `${baseUrl}/api/mobile/upload-file`,
isAuth: false,
//
// pay popup
isShowPayPopup: false,
payQrCode: '', // 支付二维码
6 months ago
qrcodeImagePath: '', // 二维码图片路径
6 months ago
qrcodeExpired: false, // 二维码是否失效
11 months ago
payTimer: null, // 定时器
showPriceEdit: false,
editPrice: '',
6 months ago
showPayQrCode: false,
activeTab: 'qrcode', // 当前选中的 tab: 'qrcode' 或 'pay'
6 months ago
paySuccessTime: null, // 支付成功的时间戳
payCooldownSeconds: 0, // 支付冷却倒计时(秒)
payCooldownTimer: null, // 支付冷却定时器
11 months ago
};
},
onReady() {
this.$refs.uForm.setRules(this.rules);
},
onLoad(option) {
this.form.can_multi_num = option.can_multi_num ? Number(option.can_multi_num) : 0
this.form.accompany_product_id = option.id ? Number(option.id) : "";
this.form.type = Number(option.type);
this.form.site_id = option.site_id ? Number(option.site_id) : ''
this.site_name = option.site_id ? option.site_name : ''
this.canSelectSite = option.site_id ? true : false
// this.site_name = this.vuex_site?this.vuex_site.name:'全部'
console.log("this.vuex_site", this.form.site_id, this.site_name)
uni.setNavigationBarTitle({
title: option.type == 1 ? '预约陪诊' : '预约居家照护'
})
if (!this.orderId && option.order_id) {
this.orderId = option.order_id;
this.getDetail();
}
this.getList(option.type, option.site_id);
this.getHospital(option.site_id);
6 months ago
// 重置二维码显示状态
this.showPayQrCode = false;
this.payQrCode = '';
this.qrcodeImagePath = '';
this.qrcodeExpired = false;
this.activeTab = 'qrcode'; // 默认显示二维码 tab
11 months ago
},
onUnload() {
// 清除支付状态检查定时器
if (this.payTimer) {
clearInterval(this.payTimer)
this.payTimer = null
}
6 months ago
// 清除支付冷却定时器
this.stopPayCooldown()
11 months ago
},
methods: {
// 获取产品列表
async getList(type,site_id) {
const res = await this.$u.api.accompanyProduct({
type: type,
page: 1,
6 months ago
page_size: 999,
11 months ago
site_id:site_id
});
this.list_service = res.data;
if (!this.orderId) {
this.list_psite = res.data.filter(item => item.id == this.form.accompany_product_id)[0].site
}
},
async getDetail(id) {
console.log(id, this.orderId);
6 months ago
// 保存当前显示状态,防止被接口数据覆盖
const wasShowingQrCode = this.showPayQrCode
const wasPayStatus = this.form.pay_status
const isQrcodeTab = this.activeTab === 'qrcode'
11 months ago
await this.$u.api
.accompanyOrderDetail({
id: id || this.orderId,
})
.then((res) => {
6 months ago
// 保存接口返回的真实 pay_status
const realPayStatus = res.pay_status
11 months ago
for (const key in this.form) {
if (res.hasOwnProperty(key)) {
this.form[key] = res[key];
}
}
6 months ago
// 如果当前在二维码 tab强制保持显示状态和支付状态
if (isQrcodeTab) {
this.showPayQrCode = true
this.form.pay_status = 1
} else if (wasShowingQrCode || wasPayStatus === 1) {
// 如果之前已经显示了二维码区域,强制保持显示状态(防止接口数据覆盖)
this.showPayQrCode = true
this.form.pay_status = 1
}
11 months ago
// 确保数量字段有默认值
if (!this.form.quantity) {
this.form.quantity = 1;
}
this.form['created_at'] = res['created_at']
this.form['status'] = res['status']
this.form['nurse_id'] = res['nurse_id']
this.nurse = res['nurse']
this.fileList = res.files.map(i => ({
url: i.url
}))
this.paidPrice = res.price
uni.setNavigationBarTitle({
title: res.accompany_product ? res.accompany_product.name : '订单详情'
})
});
},
async getHospital(site_id) {
const res = await this.$u.api.listHospital({
site_id: site_id,
page: 1,
page_size: 999,
});
this.list_hospital = res.data;
},
async getUserArchive() {
const res = await this.$u.api.userArchive({
page: 1,
page_size: 999,
user_mobile: this.form.appoint_mobile
});
this.list_archive = res.data;
},
changeService(item) {
this.info = item;
this.form.accompany_product_id = item.id;
// if (this.canSelectSite) {
// this.list_psite = item.site
// this.form.site_id = ''
// this.site_name = ''
// }
this.getHospital(item.site_id);
this.isShowService = false;
this.form.hospital = "";
// 更换服务时重置数量为1
this.form.quantity = 1;
},
// 增加数量
increaseQuantity() {
if (this.form.quantity < 99) { // 限制最大数量为99
this.form.quantity++;
} else {
uni.showToast({
title: '最大数量为99',
icon: 'none'
});
}
},
// 减少数量
decreaseQuantity() {
if (this.form.quantity > 1) {
this.form.quantity--;
} else {
uni.showToast({
title: '最小数量为1',
icon: 'none'
});
}
},
confirmHospital(e) {
this.form.hospital = e[0].value;
},
confirmTime(e) {
this.form.time = `${e.year}-${e.month}-${e.day} ${e.hour}:${e.minute}:00`;
},
confirmSite(e) {
console.log("e", e)
this.form.site_id = e[0].value;
this.site_name = e[0].label;
console.log("this.form.site_id", this.form.site_id)
},
// 服务对象
confirmArchive(e) {
this.form.user_archive_id = e.id;
this.isShowArchive = false;
},
addArchive() {
this.$refs.serviceArchive.isShow = true;
},
editUser(item) {
this.$refs.serviceArchive.form = item
this.$refs.serviceArchive.isShow = true;
},
delUser(item) {
uni.showModal({
title: '确认删除该人员?',
success: async (res) => {
if (res.confirm) {
try {
if (!item?.id) return
const res = await this.$u.api.userArchiveDestroy({
id: item?.id
})
this.getUserArchive()
} catch (err) {
console.error(err)
}
}
}
})
},
addSuccess(e) {
if (e) {
this.getUserArchive();
}
},
6 months ago
// 打开地图选点
openMap(){
console.log("chooseLocation")
let that = this
uni.chooseLocation({
success(res){
console.log("chooseLocationres",res)
if (res.errMsg === 'chooseLocation:ok') {
that.form.city = res.address
console.log('位置名称:' + res.name);
console.log('详细地址:' + res.address);
console.log('纬度:' + res.latitude);
console.log('经度:' + res.longitude);
}
},
fail(err){
uni.showToast({
title:'打开地图失败',
icon:'none'
})
console.log("err",err)
}
});
11 months ago
},
pay() {
if (!this.orderId) {
if (!this.form.site_id) {
uni.showToast({
title: '请选择站点区域',
icon: 'none'
})
return
}
console.log("this.form", this.form)
this.$refs.uForm.validate(async (valid) => {
if (valid) {
console.log("验证通过");
this.form.file_ids =
this.$refs.uUpload?.lists
?.filter((val) => {
return val.progress === 100;
})
?.map((i) => i.response?.id) || [];
// 陪诊 文件和 需求 必填之一
if (this.form.type === 1) {
if (this.form.file_ids.length < 1 && isNull(this.form.content)) {
uni.showToast({
title: '请填写服务需求或上传资料',
icon: 'none'
})
return
}
}
if (this.form.type === 2) {
if (isNull(this.form.content)) {
uni.showToast({
title: '请填写服务需求',
icon: 'none'
})
return
}
}
// return
this.form.price = this.orderId ? this.paidPrice : (this.accompanyProduct.price *
this.form.quantity)
this.form.total = this.form.quantity.toString()
const res = await this.$u.api.accompanyProductOrder(this.form);
if (res) {
console.log(res);
this.orderId = res.id;
this.paidPrice = res.price
this.payOrder(res);
}
} else {
console.log("验证失败");
}
});
} else {
this.payOrder(this.form);
}
// if (!this.isShowPayPopup) {
// this.isShowPayPopup = true
// return
// }
// if (!this.isAuth && this.currentStep === 0) {
// this.$refs.uTips.show({
// title: '请认真阅读《服务条款同意书》',
// type: 'warning',
// duration: '2000'
// })
// return
// }
// this.isShowPayPopup = false
// this.currentStep = 3
},
async payOrder(re) {
try {
6 months ago
const res = await this.$u.api.accompanyPay({
11 months ago
no: re.no,
6 months ago
})
console.log("获取支付参数:", res,res.errcode && res.errcode===10002);
if(res.errcode && res.errcode===10002){
// 强制保持二维码显示状态和订单状态
this.showPayQrCode = true
this.form.pay_status = 1
// 设置二维码失效状态
this.qrcodeExpired = true
uni.showToast({
title: res.errmsg,
icon: 'none'
});
return;
}
// 如果成功获取二维码,重置失效状态
this.qrcodeExpired = false
const result = res.result
11 months ago
//待支付状态
this.form.pay_status = 1
this.form.no = re.no
this.form.created_at = re.time
console.log('支付结果:', result);
// 显示loading
uni.showLoading({
title: '生成支付二维码...',
mask: true
})
// 本地生成二维码
this.payQrCode = result.code_url
6 months ago
// 重置图片路径,等待二维码生成完成后转换为图片
this.qrcodeImagePath = ''
11 months ago
this.showPayQrCode = true
console.log('二维码URL:', this.payQrCode);
console.log('显示二维码:', this.showPayQrCode);
// 确保二维码数据不为空
if (!this.payQrCode) {
console.error('二维码URL为空');
uni.showToast({
title: '二维码生成失败',
icon: 'none'
});
return;
}
// 隐藏loading
uni.hideLoading()
6 months ago
// 开始检查支付状态(只在二维码 tab 时启动)
if (this.activeTab === 'qrcode') {
this.startPayCheck()
}
11 months ago
} catch (err) {
console.log('支付错误:', err);
// 检查是否是订单待审核错误
if (err.data && (err.data.errcode === 10002 || (err.data.errmsg && err.data.errmsg.includes(
'订单待审核')))) {
// 订单待审核只显示modal不显示toast
uni.showModal({
title: '订单待审核',
content: '订单待审核,审核通过后才能支付',
showCancel: false,
success: () => {
uni.switchTab({
url: '/pages/index/staffIndex',
success: () => {
// 通过全局事件总线通知首页切换到相应标签页
setTimeout(() => {
uni.$emit('switchToPendingReview');
}, 100);
}
});
}
});
} else {
// 其他错误显示toast
uni.showToast({
title: err.data?.errmsg || "支付失败",
icon: "none",
});
}
}
},
6 months ago
// 停止支付状态检测
stopPayCheck() {
if (this.payTimer) {
clearInterval(this.payTimer)
this.payTimer = null
}
},
11 months ago
// 开始检查支付状态
startPayCheck() {
6 months ago
// 先清除旧的定时器,避免重复创建
this.stopPayCheck()
// 如果订单已支付pay_status === 2或不在二维码 tab不启动检测
// pay_status === 0未支付或 pay_status === 1待支付时都需要检测
if (this.form.pay_status === 2 || this.activeTab !== 'qrcode') {
return
}
11 months ago
this.payTimer = setInterval(async () => {
6 months ago
// 如果不在二维码 tab 或订单已支付,停止检测
if (this.activeTab !== 'qrcode' || this.form.pay_status === 2) {
this.stopPayCheck()
return
}
11 months ago
try {
const res = await this.$u.api.accompanyOrderDetail({
id: this.orderId
})
6 months ago
// 检查支付状态pay_status === 1 表示支付成功
11 months ago
if (res.pay_status === 1) {
6 months ago
// 支付成功,停止检测
this.stopPayCheck()
11 months ago
// 隐藏支付二维码
this.showPayQrCode = false
6 months ago
this.payQrCode = ''
this.qrcodeImagePath = ''
6 months ago
this.qrcodeExpired = false
11 months ago
this.form.pay_status = 2
6 months ago
// 刷新订单详情
await this.getDetail(this.orderId)
11 months ago
uni.showToast({
title: '支付成功',
6 months ago
icon: 'success',
duration: 1500
11 months ago
})
6 months ago
// 延迟跳转,确保 toast 显示完成
setTimeout(() => {
uni.redirectTo({
url: `/package_sub/order/orderStaffDetail?id=${this.orderId}`
})
}, 1500)
} else if (res.pay_status === 0) {
// 如果接口返回未支付状态,但在二维码 tab 中,保持显示状态
// 不更新 form.pay_status避免跳回填写预约界面
// 只更新其他订单信息,不更新 pay_status
this.showPayQrCode = true
// form.pay_status 保持为 1不更新为 0
11 months ago
}
6 months ago
// 其他状态(如 pay_status === 2已经在上面处理了
11 months ago
} catch (err) {
console.error('检查支付状态失败', err)
}
}, 3000) // 每3秒检查一次
},
// 组件销毁时清除定时器
beforeDestroy() {
if (this.payTimer) {
clearInterval(this.payTimer)
}
6 months ago
// 清除支付冷却定时器
this.stopPayCooldown()
},
// 重新获取二维码
regetQrcode() {
if (this.form && this.form.no) {
this.payOrder({ no: this.form.no, time: this.form.created_at })
}
},
// 启动支付冷却期30秒
startPayCooldown() {
// 先清除旧的定时器
this.stopPayCooldown()
// 设置冷却时间为30秒
this.payCooldownSeconds = 30
this.paySuccessTime = Date.now()
// 启动倒计时定时器
this.payCooldownTimer = setInterval(() => {
this.payCooldownSeconds--
if (this.payCooldownSeconds <= 0) {
// 冷却期结束
this.stopPayCooldown()
}
}, 1000) // 每秒更新一次
},
// 停止支付冷却期
stopPayCooldown() {
if (this.payCooldownTimer) {
clearInterval(this.payCooldownTimer)
this.payCooldownTimer = null
}
this.payCooldownSeconds = 0
this.paySuccessTime = null
11 months ago
},
// 更多菜单点击
moreActionClick(index) {
let name = this.moreActionList[index].text
let fn = () => {}
switch (this.moreActionList[index].tag) {
case 'cancel':
fn = () => this.$u.api.accompanyProductOrder({
id: this.orderId,
pay_status: -1
}).then(_ => {
this.getDetail()
this.form.pay_status = 2
})
break;
case 'chargeback':
fn = () => this.$u.api.orderRefund({
id: this.orderId
}).then(_ => {
this.getDetail().then(_ => {
if (this.form.status) {
uni.showModal({
title: "已成功提交退款申请",
content: "当前订单已分配护工,需等待客服处理",
showCancel: false
})
}
})
})
break;
}
uni.showModal({
title: "操作",
content: `是否确认${name}`,
success: (status) => {
if (status.confirm) {
fn()
} else {}
},
fail: () => {},
})
},
confirmEditPrice() {
if (!this.editPrice || isNaN(this.editPrice) || Number(this.editPrice) < 0) {
uni.showToast({
title: '请输入有效金额',
icon: 'none'
});
return;
}
if (this.orderId) {
// 编辑订单时,直接修改实付金额
this.paidPrice = Number(this.editPrice);
} else {
// 新建订单时,修改总价,需要计算单价
const newTotalPrice = Number(this.editPrice);
const quantity = this.form.quantity || 1;
// 根据总价和数量计算单价
this.accompanyProduct.price = newTotalPrice / quantity;
}
this.showPriceEdit = false;
},
async handleArchiveClick() {
if (!this.form.appoint_name) {
uni.$u.toast('请先填写预约人');
this.$refs.appointNameInput && this.$refs.appointNameInput.focus && this.$refs.appointNameInput
.focus();
return;
}
if (!this.form.appoint_mobile) {
uni.$u.toast('请先填写预约人电话');
this.$refs.appointMobileInput && this.$refs.appointMobileInput.focus && this.$refs
.appointMobileInput.focus();
return;
}
await this.getUserArchive();
this.isShowArchive = true;
},
6 months ago
// 二维码生成成功(保留兼容性)
11 months ago
onQrCodeSuccess() {
console.log('二维码生成成功');
6 months ago
},
// 二维码生成完成回调(将 canvas 转换为图片)
onQrCodeComplete(e) {
// 当二维码成功生成后,将其转换为图片
if (e && e.success && this.$refs.payQrCode) {
// 延迟一下,确保 canvas 完全渲染完成
setTimeout(() => {
if (this.$refs.payQrCode) {
this.$refs.payQrCode.toTempFilePath({
success: (res) => {
// 获取临时文件路径
this.qrcodeImagePath = res.tempFilePath
console.log('二维码图片生成成功:', this.qrcodeImagePath)
},
fail: (err) => {
console.error('二维码转图片失败:', err)
// 如果转换失败,仍然显示 canvas虽然不能长按识别
uni.showToast({
icon: 'none',
title: '二维码图片生成失败'
})
}
})
}
}, 500) // 延迟 500ms 确保 canvas 渲染完成
}
11 months ago
},
// 二维码生成错误
onQrCodeError(error) {
console.error('二维码生成错误:', error);
uni.showToast({
title: '二维码生成失败: ' + (error.errMsg || '未知错误'),
icon: 'none'
});
},
openPriceEdit() {
// 获取当前总价
const currentTotalPrice = this.orderId ? this.paidPrice : ((this.accompanyProduct.price || 0) * (this.form
.quantity || 1));
this.editPrice = currentTotalPrice.toString();
this.showPriceEdit = true;
},
6 months ago
// Tab 切换
async switchTab(tab) {
6 months ago
const previousTab = this.activeTab
6 months ago
this.activeTab = tab
6 months ago
// 如果切换到非二维码 tab停止支付状态检测
if (tab !== 'qrcode') {
this.stopPayCheck()
}
// 如果切换到二维码 tab先设置显示状态防止底部栏闪烁
6 months ago
if (tab === 'qrcode') {
6 months ago
this.showPayQrCode = true
this.form.pay_status = 1
}
// 每次切换 tab 都重新请求接口,获取最新的订单信息(包含最新的 no
if (this.orderId) {
await this.getDetail(this.orderId)
}
// 如果切换到二维码 tab直接重新获取二维码
if (tab === 'qrcode' && this.form.no) {
await this.payOrder({ no: this.form.no, time: this.form.created_at })
6 months ago
}
},
11 months ago
// 立即支付方法
scrollToPayQr: async function() {
6 months ago
// 检查是否在支付冷却期内
if (this.payCooldownSeconds > 0) {
uni.showToast({
title: `支付成功后${this.payCooldownSeconds}秒内不能重复支付`,
icon: 'none',
duration: 2000
})
return
}
// 保存当前显示状态,防止 getDetail 重置状态
const wasShowingQrCode = this.showPayQrCode
const wasPayStatus = this.form.pay_status
6 months ago
// 每次点击都重新获取最新的订单信息(包含最新的 no
if (this.orderId) {
await this.getDetail(this.orderId)
6 months ago
// 如果之前已经显示了二维码区域,强制保持显示状态(防止 getDetail 重置)
if (wasShowingQrCode || wasPayStatus === 1) {
this.showPayQrCode = true
this.form.pay_status = 1
}
6 months ago
}
if (!this.form.no) {
uni.showToast({
title: '订单号不存在',
icon: 'none'
})
return
}
11 months ago
try {
6 months ago
// 1. 获取微信支付参数(使用最新的 no
11 months ago
const res = await this.$u.api.accompanyOrderPayParams({
no: this.form.no
});
6 months ago
console.log("获取支付参数:", res,res.errcode && res.errcode===10002);
if(res.errcode && res.errcode===10002){
// 强制保持二维码显示状态和订单状态(即使 getDetail 可能已经重置了)
this.showPayQrCode = true
this.form.pay_status = 1
// 如果当前在二维码 tab设置二维码失效状态
if (this.activeTab === 'qrcode') {
this.qrcodeExpired = true
}
uni.showToast({
title: res.errmsg,
icon: 'none'
});
return;
}
11 months ago
// 从嵌套的config对象中获取支付参数
const payConfig = res.config || res;
// 2. 发起微信支付
await uni.requestPayment({
provider: 'wxpay',
timeStamp: payConfig.timestamp || payConfig.timeStamp,
nonceStr: payConfig.nonceStr,
package: payConfig.package,
signType: payConfig.signType,
paySign: payConfig.paySign,
success: () => {
uni.showToast({
title: '支付成功',
6 months ago
icon: 'success',
duration: 1500
11 months ago
});
// 支付成功后刷新订单详情
this.getDetail();
6 months ago
// 启动支付冷却期30秒
this.startPayCooldown();
// 延迟跳转,确保 toast 显示完成
setTimeout(() => {
uni.redirectTo({
url: `/package_sub/order/orderStaffDetail?id=${this.orderId}`
})
}, 1500)
11 months ago
},
fail: (err) => {
if (err.errMsg && err.errMsg.indexOf('cancel') > -1) {
uni.showToast({
title: '已取消支付',
icon: 'none'
});
} else {
uni.showToast({
title: '支付失败',
icon: 'none'
});
console.log("支付失败", err);
}
}
});
} catch (e) {
uni.showToast({
title: e.errmsg || '拉起支付失败',
icon: 'none'
});
}
},
},
computed: {
// step
stepList() {
return [{
name: "填写预约",
},
{
name: "在线支付",
},
// {
// name: "专人" + (this.form.type == 1 ? "陪诊" : "陪护"),
// },
{
name: "服务完成",
},
]
},
//
currentStep() {
if (!this.orderId) {
return 1;
}
if (this.form.pay_status === 0) {
return 1;
}
if (this.form.pay_status === 1) {
return 2;
}
// if (this.form.pay_status === 1 && this.form.status) {
// return 3;
// }
if (this.form.pay_status === 2) {
return 3;
}
return 0;
},
sex() {
return function(val) {
if (val == 1) {
return "男";
} else if (val == 2) {
return "女";
} else {
return "都可以";
}
};
},
token() {
return this.vuex_token ?
this.vuex_token :
uni.getStorageSync("lifeData")?.vuex_token;
},
accompanyProduct() {
return (
this.list_service.find(
(i) => i.id === this.form.accompany_product_id
) || {}
);
},
hospital() {
return this.list_hospital.find((i) => i.id == this.form.hospital) || {};
},
archive() {
return (
this.list_archive.find((i) => i.id === this.form.user_archive_id) || {}
);
},
moreActionList() {
if (this.form.pay_status === 0) {
return [{
text: '取消订单',
fontSize: 28,
tag: 'cancel'
}]
} else if (this.form.pay_status === 1) {
return [{
text: '退单',
fontSize: 28,
tag: 'chargeback'
}]
}
}
},
};
</script>
<style lang="scss">
.d-flex {
display: flex;
}
.jc-center {
justify-content: center;
}
.ai-center {
align-items: center;
}
.flex-1 {
flex: 1;
}
.pay-popup>.u-drawer {
bottom: calc(constant(safe-area-inset-bottom) + 80rpx + 28rpx + 27rpx) !important;
bottom: calc(env(safe-area-inset-bottom) + 80rpx + 28rpx + 27rpx) !important;
}
.pay-popup>.u-drawer .u-drawer-bottom {
overflow: initial !important;
background: #f4efee;
&::before {
font: normal normal normal 14px / 1 uicon-iconfont;
content: "\e65f 陪诊有保障,就医更安心";
font-size: 24rpx;
line-height: 70rpx;
color: #ffffff;
font-weight: 500;
box-sizing: border-box;
background: linear-gradient(90deg,
#c10d12 0%,
#c10d12 4%,
#e16265 99%,
#e16265 100%);
position: absolute;
width: 100%;
height: 100rpx;
padding-left: 70rpx;
border-radius: 20rpx 20rpx 0 0;
top: -70rpx;
left: 0;
}
}
.pay-popup>.u-drawer .u-mask {
bottom: calc(constant(safe-area-inset-bottom) + 80rpx + 28rpx) !important;
bottom: calc(env(safe-area-inset-bottom) + 80rpx + 28rpx) !important;
}
.pay-popup>.u-drawer .u-drawer__scroll-view {
position: relative;
background: #f4efee;
}
.pay-popup {
&-container {
padding-bottom: 20rpx;
.service {
border-radius: 10rpx;
padding: 28rpx 39rpx;
margin: 32rpx 25rpx 0;
display: flex;
align-items: center;
&__icon {
display: flex;
justify-content: center;
align-items: center;
background: #f1e7d9;
padding: 20rpx;
width: 124rpx;
height: 122rpx;
}
&__text {
padding-left: 12rpx;
font-weight: 500;
&--price {
font-size: 40rpx;
color: #c20d12;
font-weight: 500;
}
&--name {
font-size: 24rpx;
color: #333333;
font-weight: 500;
}
}
}
.row {
margin: 30rpx 46rpx 0;
&__title {
padding-left: 22rpx;
font-size: 28rpx;
line-height: 40rpx;
color: #000000;
font-weight: 500;
}
&__content {
margin-top: 26rpx;
padding: 22rpx;
background: #fff;
border-radius: 5rpx;
&--first {
width: 51rpx;
height: 47rpx;
border-radius: 15rpx;
line-height: 47rpx;
text-align: center;
font-size: 30rpx;
color: #fff;
background-color: #e1a664;
}
&--name {
font-size: 28rpx;
line-height: 47rpx;
color: #000000;
font-weight: 500;
padding-left: 16rpx;
}
}
.u-checkbox__label {
margin: 0;
}
}
.cards {
&__icon {
width: 90rpx;
height: 83rpx;
background: #f3e7d8;
border-radius: 10rpx;
}
}
.use-card {
text-align: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 570rpx;
margin: 30rpx auto 0;
height: 66rpx;
line-height: 66rpx;
font-size: 28rpx;
color: #e1a664;
font-weight: 500;
background: #f1e7d9;
}
.is-auth {
padding-left: 56rpx;
margin-top: 22rpx;
}
}
}
</style>
<style lang="scss" scoped>
.page {
position: relative;
.card {
background: #fff;
margin: 60rpx 25rpx 0;
padding: 36rpx 38rpx;
border-radius: 10rpx;
}
.bkg {
width: 100vw;
z-index: 0;
height: 550rpx;
position: absolute;
top: 0;
left: 0;
}
.container {
z-index: 1;
position: relative;
padding-bottom: calc(27rpx * 2 + 80rpx + 20rpx);
padding-bottom: calc(constant(safe-area-inset-bottom) + 27rpx * 2 + 80rpx + 20rpx);
padding-bottom: calc(env(safe-area-inset-bottom) + 27rpx * 2 + 80rpx + 20rpx);
.refund-text {
font-size: 44rpx;
font-weight: 600;
color: #c20d12;
letter-spacing: 4rpx;
padding: 64rpx 37rpx 0;
}
.step {
display: flex;
justify-content: space-evenly;
padding: 64rpx 37rpx 0;
position: relative;
&::before {
content: "";
height: 12rpx;
background: #fff;
border-radius: 6rpx;
position: absolute;
left: 37rpx;
right: 37rpx;
top: calc(26rpx / 2 + 64rpx - 6rpx);
}
&-item {
&__dot {
width: 30rpx;
height: 30rpx;
border-radius: 100%;
filter: drop-shadow(0 0 10rpx rgba(211, 32, 2, 0.3));
background-color: #9b9c9c;
border: 2rpx solid #ffffff;
margin: auto;
display: flex;
align-items: center;
justify-content: center;
}
&__text {
font-size: 24rpx;
color: #333333;
font-weight: 500;
margin-top: 30rpx;
}
}
.is-active {
.step-item__dot {
filter: drop-shadow(4.384px 8.988px 10px rgba(211, 32, 2, 0.57));
background-image: linear-gradient(-90deg,
#e26165 0%,
#c10d12 94%,
#c10d12 100%);
transform: scale(2, 2);
}
.step-item__text {
color: #c20d12;
}
}
}
.switch-service {
border-radius: 10rpx;
background-color: #ffffff;
margin: 60rpx 25rpx 0;
padding: 28rpx 39rpx;
display: flex;
align-items: center;
&__icon {
display: flex;
justify-content: center;
align-items: center;
background: #f9f5e9;
padding: 20rpx;
}
&__name {
padding-left: 14rpx;
font-size: 28rpx;
color: #333333;
font-weight: 500;
}
&__btn {
display: flex;
align-items: center;
margin-left: auto;
&>image {
width: 31rpx;
height: 27rpx;
}
&>text {
font-size: 24rpx;
color: #999999;
padding-left: 20rpx;
}
}
}
.form-card {
border-radius: 10rpx;
background-color: #ffffff;
padding: 36rpx 38rpx;
margin: 0 25rpx;
&-1 {
margin-top: 44rpx;
}
&-2 {
margin-top: 24rpx;
.title {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 24rpx;
margin-bottom: 26rpx;
&__left text:nth-child(1) {
color: #333;
}
&__left text:nth-child(2) {
color: #999;
}
&__right {
color: #c20d12;
}
}
::v-deep .u-add-wrap {
background: #fff;
border: 2rpx dashed #999999;
}
}
&-3 {
margin-top: 20rpx;
.title {
font-size: 24rpx;
color: #333333;
margin-bottom: 22rpx;
}
}
}
.is-auth {
padding-left: 56rpx;
margin-top: 22rpx;
}
::v-deep .form-card-1 .u-input__input {
text-align: right;
}
.desc-card {
border-bottom: 2rpx solid #efefef;
padding: 48rpx 70rpx 46rpx;
&__title {
font-size: 28rpx;
color: #000000;
font-weight: bold;
position: relative;
padding-left: 24rpx;
&::before {
content: "";
background: linear-gradient(0deg,
#c10d12 0%,
#c10d12 6%,
#e26165 100%);
border-radius: 4rpx;
width: 6rpx;
position: absolute;
top: 0;
left: 0;
bottom: 0;
}
}
&__content {
line-height: 65rpx;
margin-top: 34rpx;
&--title {
display: inline-block;
width: 240rpx;
padding-right: 64rpx;
font-size: 24rpx;
color: #999999;
font-weight: 500;
}
&--value {
display: inline-block;
font-size: 24rpx;
color: #333333;
font-weight: 500;
}
}
}
}
}
.bottom-bar {
background: #fff;
position: fixed;
padding-top: 27rpx;
padding-bottom: 27rpx;
padding-bottom: calc(constant(safe-area-inset-bottom) + 27rpx);
padding-bottom: calc(env(safe-area-inset-bottom) + 27rpx);
width: 100vw;
left: 0;
bottom: 0;
z-index: 10074;
display: flex;
align-items: center;
justify-content: space-between;
filter: drop-shadow(0 2rpx 6rpx #00000020);
.price {
margin-left: 50rpx;
color: #c20d12;
&>text:nth-child(1) {
font-size: 24rpx;
}
&>text:nth-child(2) {
color: #c20d12;
font-weight: 500;
font-size: 40rpx;
}
}
.more {
font-size: 26rpx;
color: #666;
padding-right: 20rpx;
}
}
.service-list {
padding-top: 80rpx;
&-item {
border: 2rpx solid #e6e6eb;
border-radius: 10rpx;
background-color: #ffffff;
margin: 0 25rpx;
padding: 28rpx 39rpx;
display: flex;
align-items: center;
flex-wrap: wrap;
&__namewrap {
display: flex;
align-items: center;
width: 100%;
}
&__address {
margin-top: 10rpx;
width: 100%;
padding-left: 14rpx;
display: flex;
justify-content: space-between;
align-items: center;
}
&__icon {
display: flex;
justify-content: center;
align-items: center;
// background: #f9f5e9;
// padding: 20rpx;
}
&__name {
padding-left: 14rpx;
font-size: 28rpx;
color: #333333;
font-weight: 500;
}
&__price {
color: #c20d12;
font-weight: 500;
margin-left: auto;
}
}
&-btn {
position: fixed;
bottom: 40rpx;
left: calc(50% - 144rpx);
}
&-item+&-item {
margin-top: 20rpx;
}
}
.qrcode-section {
margin-top: 30rpx;
text-align: center;
padding: 20rpx;
6 months ago
background: #fff;
border-radius: 20rpx;
box-shadow: 0 4rpx 16rpx #e6eaf1;
.payment-tabs {
display: flex;
border-bottom: 2rpx solid #e5e5e5;
margin-bottom: 30rpx;
.tab-item {
flex: 1;
text-align: center;
padding: 20rpx 0;
font-size: 30rpx;
color: #666;
position: relative;
transition: all 0.3s;
&.tab-active {
color: #1479ff;
font-weight: 500;
&::after {
content: '';
position: absolute;
bottom: -2rpx;
left: 50%;
transform: translateX(-50%);
width: 60rpx;
height: 4rpx;
background: #1479ff;
border-radius: 2rpx;
}
}
}
}
.tab-content {
.tab-panel {
min-height: 400rpx;
}
.pay-button-section {
padding: 60rpx 0;
display: flex;
justify-content: center;
align-items: center;
}
}
11 months ago
.qrcode-title {
font-size: 28rpx;
color: #333;
margin-bottom: 20rpx;
}
.qrcode-wrapper {
width: 400rpx;
height: 400rpx;
margin: 0 auto;
background: #fff;
padding: 20rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
display: flex;
align-items: center;
justify-content: center;
.qrcode-image {
width: 100%;
height: 100%;
}
6 months ago
image {
&.qrcode-disabled {
filter: grayscale(100%);
opacity: 0.5;
}
}
.qrcode-overlay {
position: absolute;
top: 20rpx;
left: 20rpx;
right: 20rpx;
bottom: 20rpx;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
border-radius: 8rpx;
.reget-btn {
background: #1479ff;
color: #fff;
padding: 20rpx 40rpx;
border-radius: 40rpx;
font-size: 28rpx;
font-weight: 500;
cursor: pointer;
&:active {
opacity: 0.8;
}
}
}
11 months ago
}
.qrcode-tip {
font-size: 24rpx;
color: #999;
margin-top: 20rpx;
}
}
.edit-icon-touch {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 48rpx;
min-height: 48rpx;
margin-left: 10rpx;
border-radius: 50%;
&:active {
background: #f5f5f5;
}
}
// 数量选择Card样式
.quantity-card {
background: #fff;
border-radius: 20rpx;
margin: 30rpx;
box-shadow: 0 4rpx 16rpx #e6eaf1;
padding: 30rpx;
&__header {
display: flex;
justify-content: space-between;
align-items: center;
}
&__title {
font-size: 28rpx;
color: #000000;
font-weight: bold;
position: relative;
padding-left: 24rpx;
&::before {
content: "";
background: linear-gradient(0deg,
#c10d12 0%,
#c10d12 6%,
#e26165 100%);
border-radius: 4rpx;
width: 6rpx;
position: absolute;
top: 0;
left: 0;
bottom: 0;
}
}
&__content {
display: flex;
align-items: center;
.quantity-control {
display: flex;
align-items: center;
justify-content: center;
.quantity-display {
width: 120rpx;
height: 60rpx;
line-height: 60rpx;
text-align: center;
background: #f8f8f8;
border-radius: 8rpx;
margin: 0 20rpx;
font-size: 28rpx;
color: #333;
font-weight: 500;
}
}
}
}
// 底部支付按钮样式
.bottom-pay-btn {
position: fixed;
left: 0;
bottom: 0;
width: 100vw;
background: #fff;
z-index: 9999;
box-shadow: 0 -2rpx 8rpx #00000010;
padding: 20rpx 30rpx 40rpx 30rpx;
display: flex;
justify-content: center;
.pay-btn {
width: 100%;
font-size: 32rpx;
border-radius: 40rpx;
font-weight: 500;
}
}
</style>