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.

1969 lines
53 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<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>
<!-- 支付二维码 -->
<view class="qrcode-section" v-if="showPayQrCode">
<view class="qrcode-title">微信支付</view>
<view class="qrcode-wrapper">
<uqrcode v-if="payQrCode" ref="payQrCode" canvas-id="pay-qrcode" :value="payQrCode" :size="400"
:sizeUnit="'rpx'" :start="true" :auto="true" :loading="false" @error="onQrCodeError"
@success="onQrCodeSuccess" :options="{
margin: 10,
colorDark: '#000000',
colorLight: '#ffffff'
}"></uqrcode>
</view>
<view class="qrcode-tip">请使用微信扫码支付</view>
</view>
</view>
<!-- 底部立即支付按钮 -->
<view v-if="showPayQrCode" class="bottom-pay-btn">
<u-button type="primary" shape="circle" @click="scrollToPayQr" class="pay-btn">
立即支付
</u-button>
</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: '', // 支付二维码
payTimer: null, // 定时器
showPriceEdit: false,
editPrice: '',
showPayQrCode: false
};
},
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);
// 重置二维码显示状态
this.showPayQrCode = false;
this.payQrCode = '';
},
onUnload() {
// 清除支付状态检查定时器
if (this.payTimer) {
clearInterval(this.payTimer)
this.payTimer = null
}
},
methods: {
// 获取产品列表
async getList(type,site_id) {
const res = await this.$u.api.accompanyProduct({
type: type,
page: 1,
page_size: 999,
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);
await this.$u.api
.accompanyOrderDetail({
id: id || this.orderId,
})
.then((res) => {
for (const key in this.form) {
if (res.hasOwnProperty(key)) {
this.form[key] = res[key];
}
}
// 确保数量字段有默认值
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();
}
},
// 打开地图选点
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)
}
});
},
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 {
const {
result
} = await this.$u.api.accompanyPay({
no: re.no,
});
//待支付状态
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
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()
// 开始轮询支付状态
this.startPayCheck()
} 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",
});
}
}
},
// 开始检查支付状态
startPayCheck() {
this.payTimer = setInterval(async () => {
try {
const res = await this.$u.api.accompanyOrderDetail({
id: this.orderId
})
if (res.pay_status === 1) {
clearInterval(this.payTimer)
// 隐藏支付二维码
this.showPayQrCode = false
this.form.pay_status = 2
uni.showToast({
title: '支付成功',
icon: 'success'
})
}
} catch (err) {
console.error('检查支付状态失败', err)
}
}, 3000) // 每3秒检查一次
},
// 组件销毁时清除定时器
beforeDestroy() {
if (this.payTimer) {
clearInterval(this.payTimer)
}
},
// 更多菜单点击
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;
},
// 二维码生成成功
onQrCodeSuccess() {
console.log('二维码生成成功');
uni.showToast({
title: '二维码生成成功',
icon: 'success'
});
},
// 二维码生成错误
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;
},
// 立即支付方法
scrollToPayQr: async function() {
try {
// 1. 获取微信支付参数
const res = await this.$u.api.accompanyOrderPayParams({
no: this.form.no
});
console.log("获取支付参数:", res);
// 从嵌套的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: '支付成功',
icon: 'success'
});
// 支付成功后刷新订单详情
this.getDetail();
},
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;
.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%;
}
}
.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>