| | |
| | | |
| | | <scroll-view scroll-y class="page-scroll"> |
| | | <view class="page-content"> |
| | | <view v-if="activeMode === 'local'" class="service-point-card cell-card" @click="openStorePopup"> |
| | | <view v-if="activeMode === 'local'" class="service-point-card cell-card" @click="openStorePopup0"> |
| | | <view class="cell-left with-icon"> |
| | | <image class="cell-icon" src="/static/icon/ic_store@2x.png" mode="widthFix"></image> |
| | | <view class="store-cell-copy"> |
| | | <text class="cell-title">{{ selectedStore ? selectedStore.name : servicePointPlaceholder }}</text> |
| | | <view class="store-cell-copy-addr"> |
| | | <image src="/static/icon/home_ic_location3@2x.png" mode="widthFix"></image> |
| | | <text v-if="selectedStore" class="store-cell-subtitle">{{ selectedStore.address }}</text> |
| | | <image class="cell-icon" src="/static/icon/ic_store@2x.png" mode="widthFix"></image> |
| | | <view class="store-cell-copy"> |
| | | <text class="cell-title">{{ selectedStore ? selectedStore.name : servicePointPlaceholder }}</text> |
| | | <view class="store-cell-copy-addr1" v-if="selectedStore"> |
| | | <image src="/static/icon/home_ic_location3@2x.png" mode="widthFix"></image> |
| | | <text class="store-cell-subtitle">{{ selectedStore.address }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <view class="cell-right"> |
| | | <u-icon name="arrow-right" size="22" color="#222222"></u-icon> |
| | | </view> |
| | | <view class="cell-right"> |
| | | <u-icon name="arrow-right" size="18" color="#222222"></u-icon> |
| | | </view> |
| | | </view> |
| | | |
| | | <view v-else class="address-card section-card"> |
| | | <view class="address-row" @tap="openStorePopup"> |
| | | <view class="address-row" @click="openStorePopup"> |
| | | <view class="address-left"> |
| | | <view class="address-badge send">寄</view> |
| | | <view class="address-copy"> |
| | | <text class="address-title">寄件地址</text> |
| | | <text class="address-desc">请选择寄件服务点</text> |
| | | <text class="address-title" v-if="!sendStore">寄件地址</text> |
| | | <text class="address-desc" v-if="!sendStore">请选择寄件服务点</text> |
| | | <view v-if="sendStore" class="store-cell-copy-addr"> |
| | | <text class="store-cell-title">{{ sendStore.name }}</text> |
| | | <view class="store-cell-subtitle-container"> |
| | | <image src="/static/icon/home_ic_location3@2x.png" mode="widthFix"></image> |
| | | <text class="store-cell-subtitle">{{ sendStore.address }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <u-icon name="arrow-right" size="20" color="#222222"></u-icon> |
| | | </view> |
| | | <view class="address-row no-border" @tap="openReceiveAddress"> |
| | | <view class="address-row no-border" @click="openReceiveAddress"> |
| | | <view class="address-left"> |
| | | <view class="address-badge receive">收</view> |
| | | <view class="address-copy"> |
| | | <text class="address-title">取件地址</text> |
| | | <text class="address-desc">请选择取件服务点或者其他地址</text> |
| | | <text class="address-title" v-if="!receiveStore && !receiveAddr">取件地址</text> |
| | | <text class="address-desc" v-if="!receiveStore && !receiveAddr">请选择取件服务点或者其他地址</text> |
| | | <view v-if="receiveStore" class="store-cell-copy-addr"> |
| | | <text class="store-cell-title">{{ receiveStore.name }}</text> |
| | | <view class="store-cell-subtitle-container"> |
| | | <image src="/static/icon/home_ic_location3@2x.png" mode="widthFix"></image> |
| | | <text class="store-cell-subtitle">{{ receiveStore.address }}</text> |
| | | </view> |
| | | </view> |
| | | <view v-if="receiveAddr" class="store-cell-copy-addr"> |
| | | <text class="store-cell-title">{{ receiveAddr.name }}</text> |
| | | <view class="store-cell-subtitle-container"> |
| | | <image src="/static/icon/home_ic_location3@2x.png" mode="widthFix"></image> |
| | | <text class="store-cell-subtitle">{{ receiveAddr.addr }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <u-icon name="arrow-right" size="20" color="#222222"></u-icon> |
| | |
| | | </view> |
| | | <view class="form-row"> |
| | | <text class="form-label">收件人</text> |
| | | <input v-model="form.receiver" class="form-input" :class="{ 'filled-input': form.receiver }" type="text" placeholder="请输入收件人姓名" placeholder-style="color: #B2B2B2;" placeholder-class="input-placeholder" /> |
| | | <input v-model="form.receiver" class="form-input" :class="{ 'filled-input': form.receiver }" type="text" placeholder="请输入收件人姓名" placeholder-style="color: #B2B2B2;" /> |
| | | </view> |
| | | <view class="form-row no-border"> |
| | | <text class="form-label">收件电话</text> |
| | | <input v-model="form.mobile" class="form-input" :class="{ 'filled-input': form.mobile }" type="number" placeholder="请输入收件人电话" placeholder-style="color: #B2B2B2;" placeholder-class="input-placeholder" /> |
| | | <input v-model="form.mobile" class="form-input" :class="{ 'filled-input': form.mobile }" type="number" placeholder="请输入收件人电话" placeholder-style="color: #B2B2B2;" /> |
| | | </view> |
| | | <view class="form-row dashed-row"> |
| | | <text class="form-label">预计到店时间</text> |
| | | <view class="row-picker"> |
| | | <view class="row-picker" @click="showArriveTimePicker = true"> |
| | | <text :class="form.arriveTime ? 'picker-value-text' : 'placeholder-text'">{{ form.arriveTime || '请选择' }}</text> |
| | | <u-icon name="arrow-right" size="18" color="#222222"></u-icon> |
| | | </view> |
| | | </view> |
| | | <view class="form-row no-border"> |
| | | <text class="form-label">预计取件时间</text> |
| | | <view class="row-picker"> |
| | | <view class="row-picker" @click="showPickupTimePicker = true"> |
| | | <text :class="form.pickupTime ? 'picker-value-text' : 'placeholder-text'">{{ form.pickupTime || '请选择' }}</text> |
| | | <u-icon name="arrow-right" size="18" color="#222222"></u-icon> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <u-datetime-picker |
| | | :show="showArriveTimePicker" |
| | | v-model="arriveTimeValue" |
| | | mode="datetime" |
| | | confirmText="确定" |
| | | cancelText="取消" |
| | | title="选择预计到店时间" |
| | | @confirm="confirmArriveTime" |
| | | @cancel="showArriveTimePicker = false" |
| | | @close="showArriveTimePicker = false" |
| | | ></u-datetime-picker> |
| | | <u-datetime-picker |
| | | :show="showPickupTimePicker" |
| | | v-model="pickupTimeValue" |
| | | mode="datetime" |
| | | confirmText="确定" |
| | | cancelText="取消" |
| | | title="选择预计取件时间" |
| | | @confirm="confirmPickupTime" |
| | | @cancel="showPickupTimePicker = false" |
| | | @close="showPickupTimePicker = false" |
| | | ></u-datetime-picker> |
| | | |
| | | <view class="section-card luggage-card"> |
| | | <view class="section-head between"> |
| | |
| | | <text class="section-title">寄存行李类型</text> |
| | | <text class="section-desc">(多选,必填)</text> |
| | | </view> |
| | | <view class="price-note"> |
| | | <view class="price-note" @click="goRichText(9)"> |
| | | <image class="price-note-icon" src="/static/icon/ic_tips@2x.png" mode="widthFix"></image> |
| | | <text>价格说明</text> |
| | | </view> |
| | | </view> |
| | | <view |
| | | v-for="item in luggageTypes" |
| | | :key="item.id" |
| | | v-for="(item, index) in luggageTypes" |
| | | :key="index" |
| | | class="luggage-item" |
| | | :class="{ active: luggageCountMap[item.id] > 0 }" |
| | | @tap="selectLuggage(item.id)" |
| | | :class="{ active: item.count > 0 }" |
| | | > |
| | | <view class="luggage-info"> |
| | | <image class="luggage-image" src="" mode="aspectFit"></image> |
| | | <view class="luggage-image"> |
| | | <image style="height: 100%;" :src="item.iconFull" mode="heightFix"></image> |
| | | </view> |
| | | <view class="luggage-copy"> |
| | | <text class="luggage-name">{{ item.name }}</text> |
| | | <text class="luggage-size">{{ item.size }}</text> |
| | | <text class="luggage-size">{{ item.remark || '' }}</text> |
| | | </view> |
| | | </view> |
| | | <view v-if="luggageCountMap[item.id] > 0" class="luggage-stepper" @tap.stop> |
| | | <view class="step-btn" @tap="decreaseCount(item.id)"> |
| | | <u-icon name="minus" size="18" color="#B9C0C9"></u-icon> |
| | | </view> |
| | | <text class="step-count">{{ luggageCountMap[item.id] }}</text> |
| | | <view class="step-btn active" @tap="increaseCount(item.id)"> |
| | | <u-icon name="plus" size="18" color="#FFFFFF"></u-icon> |
| | | </view> |
| | | </view> |
| | | <view v-else class="luggage-stepper add-only" @tap.stop> |
| | | <view class="step-btn active" @tap="increaseCount(item.id)"> |
| | | <u-icon name="plus" size="18" color="#FFFFFF"></u-icon> |
| | | </view> |
| | | <view class="luggage-stepper"> |
| | | <image class="step-btn" src="/static/icon/ic_jian@2x.png" mode="widthFix" @click="decreaseCount(index)"></image> |
| | | <text class="step-count">{{ item.count || 0}}</text> |
| | | <image class="step-btn" src="/static/icon/ic_jia@2x.png" mode="widthFix" @click="increaseCount(index)"></image> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="section-card goods-card" @tap="openGoodsPopup"> |
| | | <view class="section-head between arrow-head"> |
| | | <view class="section-card goods-card"> |
| | | <view class="section-head between arrow-head" @click="showGoodsPopup = true"> |
| | | <view> |
| | | <text class="section-title">物品信息</text> |
| | | </view> |
| | | <view class="required-wrap"> |
| | | <text class="section-required goods-required-text">{{ selectedGoodsText }}</text> |
| | | <u-icon name="arrow-right" size="18" color="#A8AFBA"></u-icon> |
| | | <text class="section-required goods-required-text" :style="{ color: form.goodTypeName ? '#111111' : '#B2B2B2' }">{{ form.goodTypeName || '必选,请选择' }}</text> |
| | | <u-icon name="arrow-right" size="12" color="#A8AFBA"></u-icon> |
| | | </view> |
| | | </view> |
| | | <view class="goods-upload-row"> |
| | | <view class="upload-box"> |
| | | <view class="upload-box" @click="chooseAndUploadImage(9)"> |
| | | <image class="upload-icon" src="/static/image/btn_upload@2x.png" mode="widthFix"></image> |
| | | </view> |
| | | <view v-for="(item, index) in uploadedImages" :key="index" class="uploaded-box"> |
| | | <view v-for="(item, index) in uploadedImages" :key="index" class="uploaded-box" @click="deleteImage(index)"> |
| | | <image class="uploaded-image" :src="item.url" mode="aspectFill"></image> |
| | | <text class="uploaded-delete">删除</text> |
| | | <text class="uploaded-delete" @click="deleteImage(index)">删除</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view v-if="activeMode === 'city'" class="section-card service-time-card"> |
| | | <view v-if="activeMode === 'city' && amountData" class="section-card service-time-card"> |
| | | <view class="section-head"> |
| | | <text class="section-title">服务时效</text> |
| | | <text class="section-desc">(必选)</text> |
| | |
| | | v-for="item in serviceTimes" |
| | | :key="item.id" |
| | | class="service-time-item" |
| | | :class="{ active: selectedServiceTime === item.id }" |
| | | @tap="selectedServiceTime = item.id" |
| | | :class="{ active: isUrgent === item.id }" |
| | | @tap="isUrgent = item.id" |
| | | > |
| | | <text class="service-time-name"> |
| | | <text>标速达</text> |
| | | <text>(预计6小时内送达)</text> |
| | | <text>{{ item.name }}</text> |
| | | <text>(预计{{ item.serviceTime }}小时内送达)</text> |
| | | </text> |
| | | <text class="service-time-price">{{ item.price }}</text> |
| | | <text class="service-time-price">¥{{ item.price }}</text> |
| | | </view> |
| | | </view> |
| | | |
| | |
| | | <text class="unit-text">元</text> |
| | | </view> |
| | | </view> |
| | | <view v-if="insuranceFeeText" class="insurance-tip-row"> |
| | | <text class="insurance-tip-label">物品保费:</text> |
| | | <text class="insurance-tip-value">{{ insuranceFeeText }}</text> |
| | | <view v-if="amountData || showInsuranceTip" class="insurance-tip-row"> |
| | | <text v-if="showInsuranceTip" class="insurance-tip-warning">{{ showInsuranceTipText }}</text> |
| | | <text v-else></text> |
| | | <view style="display: flex; align-items: center;"> |
| | | <text v-if="amountData" class="insurance-tip-label">物品保费:</text> |
| | | <text v-if="amountData" class="insurance-tip-value">¥{{ amountData.insuranceFee }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | |
| | | <u-popup :show="showStorePopup" mode="bottom" round="24" :closeOnClickOverlay="true" @close="showStorePopup = false"> |
| | | <view class="store-popup-wrap"> |
| | | <view class="store-popup-head"> |
| | | <text class="store-popup-title">选择服务点</text> |
| | | <text class="store-popup-title">{{ storePopupType === 'receive' ? '选择取件服务点' : (activeMode === 'city' ? '选择寄件服务点' : '选择服务点') }}</text> |
| | | <view class="store-popup-close" @tap="showStorePopup = false"> |
| | | <u-icon name="close" size="28" color="#999999"></u-icon> |
| | | </view> |
| | | </view> |
| | | <view class="store-search-bar"> |
| | | <image class="store-search-icon" src="/static/icon/ic_search2@2x.png" mode="widthFix"></image> |
| | | <input v-model="storeKeyword" class="store-search-input" type="text" placeholder="搜索服务点名称" placeholder-class="store-search-placeholder" /> |
| | | <input v-model="storeForm.keyword" class="store-search-input" type="text" @confirm="searchStore" placeholder="搜索服务点名称" placeholder-class="store-search-placeholder" /> |
| | | </view> |
| | | <scroll-view scroll-y class="store-list-scroll"> |
| | | <view |
| | | v-for="item in filteredStores" |
| | | :key="item.id" |
| | | class="store-option" |
| | | :class="{ active: tempSelectedStoreId === item.id }" |
| | | @tap="tempSelectedStoreId = item.id" |
| | | > |
| | | <scroll-view scroll-y class="store-list-scroll" @scrolltolower="getNearbyShopList"> |
| | | <view |
| | | v-for="(item, index) in storeList" |
| | | :key="index" |
| | | class="store-option" |
| | | :class="{ active: item.active }" |
| | | @click="storeList.forEach((row,i) => row.active = index === i)" |
| | | > |
| | | <view class="store-option-main"> |
| | | <image class="store-thumb" src="" mode="aspectFill"></image> |
| | | <image class="store-thumb" :src="item.coverImg || '/static/icon/default2.png'" mode="aspectFill"></image> |
| | | <view class="store-option-copy"> |
| | | <view class="store-option-head"> |
| | | <text class="store-option-name">{{ item.name }}</text> |
| | |
| | | <image class="store-option-address-icon" src="/static/icon/home_ic_location3@2x.png" mode="widthFix"></image> |
| | | <text class="store-option-address">{{ item.address }}</text> |
| | | </view> |
| | | <text class="store-option-time">{{ item.time }}</text> |
| | | <text class="store-option-time">{{ item.shopHours || '' }}</text> |
| | | </view> |
| | | </view> |
| | | <view v-if="tempSelectedStoreId === item.id" class="store-check"> |
| | |
| | | <text class="goods-main-title">物品名称</text> |
| | | <text class="goods-main-required">(必选)</text> |
| | | </view> |
| | | <view class="goods-danger-tip"> |
| | | <view class="goods-danger-tip" @click="goRichText(10)"> |
| | | <image class="goods-danger-icon" src="/static/icon/ic_tips@2x.png" mode="widthFix"></image> |
| | | <text>禁寄物品</text> |
| | | </view> |
| | | </view> |
| | | <text class="goods-popup-desc">为确保物品寄递安全,请检查是否不夹带易燃易爆物品</text> |
| | | <view class="goods-tag-grid"> |
| | | <view |
| | | v-for="item in goodsOptions" |
| | | :key="item.id" |
| | | class="goods-tag" |
| | | :class="{ active: tempSelectedGoodsIds.includes(item.id) }" |
| | | @tap="toggleGoods(item.id)" |
| | | > |
| | | <text>{{ item.name }}</text> |
| | | <view style="display: block;height: 500rpx;overflow-y: auto;margin-top:10px ;"> |
| | | <view class="goods-tag-grid"> |
| | | <view |
| | | v-for="(item, index) in goodsOptions" |
| | | :key="index" |
| | | class="goods-tag" |
| | | :class="{ active: item.active }" |
| | | @click="goodsOptions.forEach((row,i) => row.active = i === index)" |
| | | > |
| | | <text>{{ item.name }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="goods-save-btn" @tap="confirmGoods">保存</view> |
| | | </view> |
| | | </u-popup> |
| | |
| | | </view> |
| | | </view> |
| | | <view class="amount-popup-content"> |
| | | <view v-for="item in amountDetails" :key="item.label" class="amount-row"> |
| | | <view v-for="(item, index) in amountData.itemList" :key="index" class="amount-row"> |
| | | <view class="amount-row-left"> |
| | | <text class="amount-row-label">{{ item.label }}</text> |
| | | <text v-if="item.count" class="amount-row-count">x{{ item.count }}</text> |
| | | <text class="amount-row-label">{{ item.categoryName }}</text> |
| | | <text v-if="item.quantity" class="amount-row-count">x{{ item.quantity }}</text> |
| | | </view> |
| | | <text class="amount-row-value">{{ item.value }}</text> |
| | | <text class="amount-row-value">{{ '¥' + item.unitPrice }}</text> |
| | | </view> |
| | | <view v-if="activeMode === 'city' && amountData.distance" class="amount-row amount-row-extra"> |
| | | <view class="amount-row-left"> |
| | | <text class="amount-row-label">配送里程</text> |
| | | </view> |
| | | <text class="amount-row-value">{{ amountData.distance + 'km' }}</text> |
| | | </view> |
| | | <view v-if="activeMode !== 'city' && amountData.days" class="amount-row amount-row-extra"> |
| | | <view class="amount-row-left"> |
| | | <text class="amount-row-label">寄存天数</text> |
| | | </view> |
| | | <text class="amount-row-value">{{ amountData.days + '天' }}</text> |
| | | </view> |
| | | <view v-if="amountData.insuranceFee" class="amount-row amount-row-extra"> |
| | | <view class="amount-row-left"> |
| | | <text class="amount-row-label">物品保费</text> |
| | | </view> |
| | | <text class="amount-row-value">{{ '¥' + amountData.insuranceFee }}</text> |
| | | </view> |
| | | </view> |
| | | <view class="agreement-bar popup-agreement-bar"> |
| | | <image class="agreement-icon" src="/static/icon/ic_accept_sel@2x.png" mode="widthFix"></image> |
| | | <view class="agreement-bar popup-agreement-bar" @click="toggleAgreement"> |
| | | <image class="agreement-icon" :src="agreementChecked ? '/static/icon/ic_accept_sel@2x.png' : '/static/icon/ic_accept@2x.png'" mode="widthFix" /> |
| | | <text class="agreement-text">我已阅读并同意</text> |
| | | <text class="agreement-link">《用户服务协议》</text> |
| | | <text class="agreement-link" @tap="goRichText(0)">《用户服务协议》</text> |
| | | <text class="agreement-text">及</text> |
| | | <text class="agreement-link">《隐私政策》</text> |
| | | <text class="agreement-link" @tap="goRichText(1)">《隐私政策》</text> |
| | | </view> |
| | | <view class="bottom-action-row popup-action-row"> |
| | | <view class="total-wrap"> |
| | | <text class="total-label">总费用</text> |
| | | <text class="total-price">¥150.00</text> |
| | | <text class="detail-text">明细</text> |
| | | <u-icon name="arrow-up" size="18" color="#7B7F86"></u-icon> |
| | | <text class="total-price">{{ amountData ? '¥' + amountData.totalPrice : '¥--' }}</text> |
| | | <view style="display: flex; align-items: center;" @click="showAmountPopup = false"> |
| | | <text class="detail-text">明细</text> |
| | | <u-icon name="arrow-up" size="13" color="#7B7F86"></u-icon> |
| | | </view> |
| | | </view> |
| | | <view class="submit-btn active-submit-btn">立即下单</view> |
| | | <view class="submit-btn active-submit-btn" @click="createOrder">立即下单</view> |
| | | </view> |
| | | </view> |
| | | </u-popup> |
| | | |
| | | <view class="bottom-bar"> |
| | | <view class="agreement-bar"> |
| | | <image class="agreement-icon" :src="agreementChecked ? '/static/icon/ic_accept_sel@2x.png' : '/static/icon/ic_accept@2x.png'" mode="widthFix"></image> |
| | | <view class="agreement-bar" @click="toggleAgreement"> |
| | | <image class="agreement-icon" :src="agreementChecked ? '/static/icon/ic_accept_sel@2x.png' : '/static/icon/ic_accept@2x.png'" mode="widthFix" /> |
| | | <text class="agreement-text">我已阅读并同意</text> |
| | | <text class="agreement-link">《用户服务协议》</text> |
| | | <text class="agreement-link" @click="goRichText(0)">《用户服务协议》</text> |
| | | <text class="agreement-text">及</text> |
| | | <text class="agreement-link">《隐私政策》</text> |
| | | <text class="agreement-link" @click="goRichText(1)">《隐私政策》</text> |
| | | </view> |
| | | <view class="bottom-action-row"> |
| | | <view class="total-wrap"> |
| | | <text class="total-label">总费用</text> |
| | | <text class="total-price">{{ totalPriceText }}</text> |
| | | <text class="detail-text detail-click" @tap.stop="openAmountPopup">明细</text> |
| | | <u-icon name="arrow-down" size="18" color="#999999"></u-icon> |
| | | <text class="total-price">{{ amountData ? '¥' + amountData.totalPrice : '¥--' }}</text> |
| | | <template v-if="amountData"> |
| | | <text class="detail-text detail-click" @tap.stop="openAmountPopup">明细</text> |
| | | <u-icon name="arrow-down" size="18" color="#999999"></u-icon> |
| | | </template> |
| | | </view> |
| | | <view class="submit-btn active-submit-btn">立即下单</view> |
| | | <view class="submit-btn active-submit-btn" @click="createOrder">立即下单</view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 选择服务点/地址 --> |
| | | <u-action-sheet |
| | | :show="showReceiveAddress" |
| | | @close="showReceiveAddress = false" |
| | | @select="caozuo" |
| | | :actions="actions" |
| | | :round="15" |
| | | cancelText="取消" /> |
| | | </view> |
| | | </template> |
| | | |
| | | <script> |
| | | import { mapState } from 'vuex' |
| | | export default { |
| | | data() { |
| | | return { |
| | | showStorePopup: false, |
| | | showGoodsPopup: false, |
| | | showAmountPopup: false, |
| | | showArriveTimePicker: false, |
| | | showPickupTimePicker: false, |
| | | arriveTimeValue: Number(new Date()), |
| | | pickupTimeValue: Number(new Date()), |
| | | activeMode: 'local', |
| | | modeTabs: [ |
| | | { label: '就地寄存', value: 'local' }, |
| | | { label: '同城寄送', value: 'city' } |
| | | ], |
| | | agreementChecked: true, |
| | | storeKeyword: '', |
| | | agreementChecked: false, |
| | | tempSelectedStoreId: 2, |
| | | selectedStoreId: 2, |
| | | tempSelectedGoodsIds: [1], |
| | | selectedGoodsIds: [1], |
| | | selectedLuggageId: 1, |
| | | selectedServiceTime: 1, |
| | | luggageCountMap: { |
| | | 1: 1, |
| | | 2: 1, |
| | | 3: 0 |
| | | }, |
| | | isUrgent: 0, |
| | | form: { |
| | | receiver: '蔡子瑄', |
| | | mobile: '18166525368', |
| | | arriveTime: '2026-04-15 16:30', |
| | | pickupTime: '2026-04-17 16:30', |
| | | insurance: '200', |
| | | remark: '' |
| | | receiver: '', |
| | | mobile: '', |
| | | arriveTime: '', |
| | | pickupTime: '', |
| | | goodType: '', |
| | | goodTypeName: '', |
| | | insurance: '', |
| | | remark: '', |
| | | goodsImages: [], |
| | | }, |
| | | luggageTypes: [ |
| | | { id: 1, name: '大件行李箱', size: '24-28寸' }, |
| | | { id: 2, name: '中件行李箱', size: '24-28寸' }, |
| | | { id: 3, name: '小件行李箱', size: '24-28寸' } |
| | | ], |
| | | serviceTimes: [ |
| | | { id: 1, name: '标准达(预计6小时内送达)', price: '¥50' }, |
| | | { id: 2, name: '急速达(预计4小时内送达)', price: '¥70' } |
| | | ], |
| | | storeList: [ |
| | | { id: 1, name: '中铁快运南站旗舰店', address: '合肥南站负一层100号', time: '周一至周日 7:00~23:00', distance: '239m' }, |
| | | { id: 2, name: '中铁快运合肥火车站', address: '合肥火车站一层12号', time: '周一至周日 7:00~23:00', distance: '12.8km' }, |
| | | { id: 3, name: '合肥火车站北广场', address: '合肥火车站一层12号', time: '周一至周日 7:00~23:00', distance: '13.1km' }, |
| | | { id: 4, name: '小铁无忧存', address: '合肥火车站一层12号', time: '周一至周日 7:00~23:00', distance: '16.3km' }, |
| | | { id: 5, name: '中铁快运合肥火车站', address: '合肥火车站一层12号', time: '周一至周日 7:00~23:00', distance: '20.8km' } |
| | | ], |
| | | goodsOptions: [ |
| | | { id: 1, name: '文件' }, |
| | | { id: 2, name: '衣服' }, |
| | | { id: 3, name: '滑雪板' }, |
| | | { id: 4, name: '发票' }, |
| | | { id: 5, name: '手机' }, |
| | | { id: 6, name: '电脑' }, |
| | | { id: 7, name: '鞋子' }, |
| | | { id: 8, name: '护肤品' }, |
| | | { id: 9, name: '白酒' }, |
| | | { id: 10, name: '鞋子' }, |
| | | { id: 11, name: '护肤品' }, |
| | | { id: 12, name: '白酒' }, |
| | | { id: 13, name: '鞋子' }, |
| | | { id: 14, name: '护肤品' }, |
| | | { id: 15, name: '白酒' } |
| | | ], |
| | | amountDetails: [ |
| | | { label: '大件行李箱', count: 1, value: '¥35' }, |
| | | { label: '中件行李箱', count: 1, value: '¥35' }, |
| | | { label: '寄存天数', count: '', value: '2天' }, |
| | | { label: '行李保价', count: '', value: '¥10' } |
| | | ], |
| | | uploadedImages: [ |
| | | { url: '/static/icon/nav_home_sel@2x.png' }, |
| | | { url: '/static/icon/nav_xingcheng_sel@2x.png' } |
| | | amountData: null, |
| | | showInsuranceTip: false, |
| | | showInsuranceTipText: '', |
| | | luggageTypes: [], |
| | | serviceTimes: [], |
| | | |
| | | storeList: [], |
| | | selectedStore: null, |
| | | sendStore: null, |
| | | receiveStore: null, |
| | | receiveAddr: null, |
| | | storePopupType: 'send', |
| | | storeForm: { |
| | | keyword: '', |
| | | page: 1, |
| | | isSearch: true |
| | | }, |
| | | |
| | | goodsOptions: [], |
| | | uploadedImages: [], |
| | | |
| | | showReceiveAddress: false, |
| | | actions: [ |
| | | { name: '选择服务点' }, |
| | | { name: '选择地址簿' } |
| | | ] |
| | | } |
| | | }, |
| | | computed: { |
| | | selectedStore() { |
| | | return this.storeList.find(item => item.id === this.selectedStoreId) || null |
| | | watch: { |
| | | 'form.insurance': { |
| | | handler() { |
| | | this.calculateLocalPrice() |
| | | } |
| | | }, |
| | | isUrgent: { |
| | | handler() { |
| | | if (this.activeMode === 'city') { |
| | | this.calculateRemotePrice() |
| | | } |
| | | } |
| | | } |
| | | }, |
| | | computed: { |
| | | ...mapState(['latitude', 'longitude', 'cityId']), |
| | | servicePointPlaceholder() { |
| | | return this.activeMode === 'city' ? '选择寄送服务点' : '选择寄存服务点' |
| | | }, |
| | | filteredStores() { |
| | | const keyword = (this.storeKeyword || '').trim() |
| | | if (!keyword) { |
| | | return this.storeList |
| | | } |
| | | return this.storeList.filter(item => item.name.includes(keyword) || item.address.includes(keyword)) |
| | | }, |
| | | selectedGoodsText() { |
| | | if (!this.selectedGoodsIds.length) { |
| | |
| | | .map(item => item.name) |
| | | return labels.join('、') |
| | | }, |
| | | insuranceFeeText() { |
| | | if (!this.form.insurance) { |
| | | return '' |
| | | } |
| | | return '+10' |
| | | }, |
| | | totalPriceText() { |
| | | return '¥150.00' |
| | | } |
| | | }, |
| | | onLoad() { |
| | | this.getNearbyShopList() |
| | | this.getCategoryList() |
| | | this.getCitySizeList() |
| | | this.agreementChecked=false |
| | | uni.$on('updateAddress', (data) => { |
| | | console.log(data) |
| | | this.receiveAddr = data |
| | | }) |
| | | }, |
| | | methods: { |
| | | caozuo(e) { |
| | | var that = this; |
| | | if (e.name === '选择服务点') { |
| | | that.storePopupType = 'receive' |
| | | that.receiveStore = null |
| | | that.showStorePopup = true |
| | | } else if (e.name === '选择地址簿') { |
| | | that.receiveAddr = null |
| | | uni.navigateTo({ |
| | | url: '/pages/address/address?type=1' |
| | | }) |
| | | } |
| | | that.showReceiveAddress = false |
| | | }, |
| | | async uploadFiles(filePaths, maxCount = 9) { |
| | | if (!filePaths || filePaths.length === 0) { |
| | | return [] |
| | | } |
| | | const limitedPaths = filePaths.slice(0, maxCount) |
| | | const uploadTasks = limitedPaths.map(filePath => { |
| | | return new Promise((resolve, reject) => { |
| | | uni.uploadFile({ |
| | | url: this.$baseUrl + '/web/public/upload', |
| | | filePath: filePath, |
| | | name: 'file', |
| | | formData: { |
| | | folder: 'orders' |
| | | }, |
| | | success: (res) => { |
| | | if (res.statusCode === 200) { |
| | | const data = JSON.parse(res.data) |
| | | if (data.code === 200) { |
| | | resolve(data.data) |
| | | } else { |
| | | reject(new Error(data.msg || '上传失败')) |
| | | } |
| | | } else { |
| | | reject(new Error('上传失败')) |
| | | } |
| | | }, |
| | | fail: (err) => { |
| | | reject(err) |
| | | } |
| | | }) |
| | | }) |
| | | }) |
| | | try { |
| | | const results = await Promise.all(uploadTasks) |
| | | return results |
| | | } catch (error) { |
| | | uni.showToast({ |
| | | title: '上传失败', |
| | | icon: 'none' |
| | | }) |
| | | throw error |
| | | } |
| | | }, |
| | | deleteImage(index) { |
| | | this.uploadedImages.splice(index, 1) |
| | | this.form.goodsImages.splice(index, 1) |
| | | }, |
| | | async chooseAndUploadImage(maxCount = 9) { |
| | | const currentCount = this.form.goodsImages.length |
| | | const remainingCount = maxCount - currentCount |
| | | if (remainingCount <= 0) { |
| | | uni.showToast({ |
| | | title: `最多上传${maxCount}张图片`, |
| | | icon: 'none' |
| | | }) |
| | | return |
| | | } |
| | | uni.chooseImage({ |
| | | count: remainingCount, |
| | | sizeType: ['compressed'], |
| | | sourceType: ['album', 'camera'], |
| | | success: async (res) => { |
| | | const tempFilePaths = res.tempFilePaths |
| | | uni.showLoading({ |
| | | title: '上传中...', |
| | | mask: true |
| | | }) |
| | | try { |
| | | const uploadResults = await this.uploadFiles(tempFilePaths, maxCount) |
| | | const addrs = uploadResults.map(item => item.imgaddr) |
| | | const fullPaths = uploadResults.map(item => item.url || item.path || item) |
| | | this.uploadedImages = [...this.uploadedImages, ...fullPaths.map(url => ({ url }))] |
| | | this.form.goodsImages = [...this.form.goodsImages, ...addrs] |
| | | uni.hideLoading() |
| | | uni.showToast({ |
| | | title: '上传成功', |
| | | icon: 'success' |
| | | }) |
| | | } catch (error) { |
| | | uni.hideLoading() |
| | | } |
| | | } |
| | | }) |
| | | }, |
| | | searchStore() { |
| | | this.storeList = [] |
| | | this.storeForm.page = 1 |
| | | this.storeForm.isSearch = true |
| | | this.getNearbyShopList() |
| | | }, |
| | | switchMode(mode) { |
| | | this.activeMode = mode |
| | | this.selectedStore = null |
| | | this.sendStore = null |
| | | this.receiveStore = null |
| | | this.receiveAddr = null |
| | | this.form.receiver = '' |
| | | this.form.mobile = '' |
| | | this.form.arriveTime = '' |
| | | this.form.pickupTime = '' |
| | | this.form.goodType = '' |
| | | this.form.goodTypeName = '' |
| | | this.form.insurance = '' |
| | | this.form.remark = '' |
| | | this.form.goodsImages = [] |
| | | this.amountData = null |
| | | this.uploadedImages = [] |
| | | this.luggageTypes.forEach(item => { |
| | | item.count = 0 |
| | | }) |
| | | }, |
| | | toggleAgreement() { |
| | | this.agreementChecked = !this.agreementChecked |
| | | }, |
| | | goRichText(type) { |
| | | uni.navigateTo({ |
| | | url: '/pages/rich-text/rich-text?type=' + type |
| | | }) |
| | | }, |
| | | openReceiveAddress() { |
| | | uni.showToast({ |
| | | title: '取件地址待接入', |
| | | icon: 'none' |
| | | }) |
| | | this.showReceiveAddress = true |
| | | }, |
| | | openAmountPopup() { |
| | | this.showAmountPopup = true |
| | | }, |
| | | openStorePopup() { |
| | | this.tempSelectedStoreId = this.selectedStoreId |
| | | this.storePopupType = 'send' |
| | | this.tempSelectedStoreId = null |
| | | this.showStorePopup = true |
| | | }, |
| | | openStorePopup0() { |
| | | this.storePopupType = 'send0' |
| | | this.tempSelectedStoreId = null |
| | | this.showStorePopup = true |
| | | }, |
| | | confirmStore() { |
| | | this.selectedStoreId = this.tempSelectedStoreId |
| | | |
| | | console.log("=========================") |
| | | const selected = this.storeList.find(item => item.active) |
| | | console.log(selected) |
| | | if (this.storePopupType === 'send') { |
| | | this.sendStore = selected |
| | | } else if (this.storePopupType === 'receive') { |
| | | this.receiveStore = selected |
| | | this.receiveAddr = null |
| | | this.calculateRemotePrice() |
| | | } else { |
| | | this.selectedStore = selected |
| | | this.calculateLocalPrice() |
| | | } |
| | | this.showStorePopup = false |
| | | }, |
| | | openGoodsPopup() { |
| | | this.tempSelectedGoodsIds = [...this.selectedGoodsIds] |
| | | this.showGoodsPopup = true |
| | | }, |
| | | toggleGoods(id) { |
| | | if (this.tempSelectedGoodsIds.includes(id)) { |
| | | this.tempSelectedGoodsIds = this.tempSelectedGoodsIds.filter(item => item !== id) |
| | | confirmGoods() { |
| | | if (!this.goodsOptions.find(item => item.active)) { |
| | | uni.showToast({ title: '请选择物品信息', icon: 'none' }) |
| | | return |
| | | } |
| | | this.tempSelectedGoodsIds = [...this.tempSelectedGoodsIds, id] |
| | | }, |
| | | confirmGoods() { |
| | | this.selectedGoodsIds = [...this.tempSelectedGoodsIds] |
| | | this.form.goodTypeName = this.goodsOptions.find(item => item.active)?.name || '' |
| | | this.form.goodType = this.goodsOptions.find(item => item.active)?.id || '' |
| | | this.showInsuranceTip = this.goodsOptions.find(item => item.active)?.relationOtherField === '1' |
| | | this.showInsuranceTipText = this.goodsOptions.find(item => item.active)?.relationRemark |
| | | this.showGoodsPopup = false |
| | | }, |
| | | selectLuggage(id) { |
| | | this.selectedLuggageId = id |
| | | confirmArriveTime(e) { |
| | | const date = new Date(e.value) |
| | | const year = date.getFullYear() |
| | | const month = String(date.getMonth() + 1).padStart(2, '0') |
| | | const day = String(date.getDate()).padStart(2, '0') |
| | | const hour = String(date.getHours()).padStart(2, '0') |
| | | const minute = String(date.getMinutes()).padStart(2, '0') |
| | | this.form.arriveTime = `${year}-${month}-${day} ${hour}:${minute}` |
| | | this.showArriveTimePicker = false |
| | | this.calculateLocalPrice() |
| | | }, |
| | | increaseCount(id) { |
| | | const current = this.luggageCountMap[id] || 0 |
| | | this.$set(this.luggageCountMap, id, current + 1) |
| | | }, |
| | | decreaseCount(id) { |
| | | const current = this.luggageCountMap[id] || 0 |
| | | if (current <= 0) { |
| | | confirmPickupTime(e) { |
| | | const date = new Date(e.value) |
| | | const year = date.getFullYear() |
| | | const month = String(date.getMonth() + 1).padStart(2, '0') |
| | | const day = String(date.getDate()).padStart(2, '0') |
| | | const hour = String(date.getHours()).padStart(2, '0') |
| | | const minute = String(date.getMinutes()).padStart(2, '0') |
| | | const pickupTime = `${year}-${month}-${day} ${hour}:${minute}` |
| | | if (this.form.arriveTime && new Date(pickupTime) <= new Date(this.form.arriveTime)) { |
| | | uni.showToast({ title: '预计取件时间必须大于预计到店时间', icon: 'none' }) |
| | | return |
| | | } |
| | | this.$set(this.luggageCountMap, id, current - 1) |
| | | this.form.pickupTime = pickupTime |
| | | this.showPickupTimePicker = false |
| | | this.calculateLocalPrice() |
| | | }, |
| | | // 物品分类 |
| | | async getCategoryList() { |
| | | const res = await this.$u.api.getCategoryList({ type: 2 }) |
| | | if (res.code === 200) { |
| | | res.data.forEach(item => { |
| | | item.active = false |
| | | }) |
| | | this.goodsOptions = res.data || [] |
| | | } |
| | | }, |
| | | async getCitySizeList() { |
| | | const res = await this.$u.api.getCitySizeList({ cityId: this.cityId }) |
| | | if (res.code === 200) { |
| | | res.data.forEach(item => { |
| | | item.count = 0 |
| | | }) |
| | | this.luggageTypes = res.data || [] |
| | | } |
| | | }, |
| | | async getNearbyShopList() { |
| | | if (!this.storeForm.isSearch) return; |
| | | const res = await this.$u.api.getNearbyShopList({ |
| | | capacity: 10, |
| | | page: this.storeForm.page, |
| | | model: { |
| | | latitude: this.latitude, |
| | | longitude: this.longitude, |
| | | cityId: this.cityId, |
| | | name:this.storeForm.keyword, |
| | | sortType: 1 |
| | | } |
| | | }) |
| | | if (res.code === 200) { |
| | | res.data.records.forEach(item => { |
| | | item.active = false |
| | | }) |
| | | this.storeList = [...this.storeList, ...res.data.records || []] |
| | | this.storeForm.page++ |
| | | this.storeForm.isSearch = this.storeList.length <= res.data.total |
| | | } |
| | | }, |
| | | increaseCount(index) { |
| | | this.luggageTypes[index].count++ |
| | | this.calculateLocalPrice() |
| | | }, |
| | | decreaseCount(index) { |
| | | if (this.luggageTypes[index].count > 0) { |
| | | this.luggageTypes[index].count-- |
| | | } |
| | | this.calculateLocalPrice() |
| | | }, |
| | | async calculateLocalPrice() { |
| | | if (this.activeMode === 'city') { |
| | | this.calculateRemotePrice() |
| | | } else { |
| | | this.calculateLocalPriceOnly() |
| | | } |
| | | }, |
| | | async calculateLocalPriceOnly() { |
| | | if (!this.selectedStore || !this.form.arriveTime || !this.form.pickupTime) { |
| | | this.amountData = null |
| | | return |
| | | } |
| | | const luggageList = this.luggageTypes |
| | | .filter(item => item.count > 0) |
| | | .map(item => ({ |
| | | categoryId: item.id, |
| | | quantity: item.count |
| | | })) |
| | | if (luggageList.length === 0) { |
| | | this.amountData = null |
| | | return |
| | | } |
| | | const res = await this.$u.api.calculateLocalPrice({ |
| | | cityId: this.cityId, |
| | | shopId: this.selectedStore.id, |
| | | depositStartTime: this.form.arriveTime + ':00', |
| | | depositEndTime: this.form.pickupTime + ':00', |
| | | items: luggageList, |
| | | declaredAmount: this.form.insurance || 0 |
| | | }) |
| | | if (res.code === 200) { |
| | | res.data.itemList.forEach(item => { |
| | | item.unitPrice = item.unitPrice / 100 |
| | | }) |
| | | res.data.totalPrice = res.data.totalPrice / 100 |
| | | res.data.insuranceFee = res.data.insuranceFee / 100 |
| | | this.amountData = res.data |
| | | } |
| | | }, |
| | | async calculateRemotePrice() { |
| | | if (!this.sendStore || !this.form.arriveTime || !this.form.pickupTime) { |
| | | this.amountData = null |
| | | return |
| | | } |
| | | if (!this.receiveStore && !this.receiveAddr) { |
| | | this.amountData = null |
| | | return |
| | | } |
| | | const luggageList = this.luggageTypes |
| | | .filter(item => item.count > 0) |
| | | .map(item => ({ |
| | | categoryId: item.id, |
| | | quantity: item.count |
| | | })) |
| | | if (luggageList.length === 0) { |
| | | this.amountData = null |
| | | return |
| | | } |
| | | let fromLat = '' |
| | | let fromLgt = '' |
| | | let toLat = '' |
| | | let toLgt = '' |
| | | if (this.sendStore) { |
| | | fromLat = this.sendStore.latitude |
| | | fromLgt = this.sendStore.longitude |
| | | } |
| | | if (this.receiveStore) { |
| | | toLat = this.receiveStore.latitude |
| | | toLgt = this.receiveStore.longitude |
| | | } else if (this.receiveAddr) { |
| | | toLat = this.receiveAddr.latitude |
| | | toLgt = this.receiveAddr.longitude |
| | | } |
| | | const res = await this.$u.api.calculateRemotePrice({ |
| | | cityId: this.cityId, |
| | | fromLat: fromLat, |
| | | fromLgt: fromLgt, |
| | | toLat: toLat, |
| | | toLgt: toLgt, |
| | | urgent: this.isUrgent, |
| | | depositStartTime: this.form.arriveTime + ':00', |
| | | depositEndTime: this.form.pickupTime + ':00', |
| | | items: luggageList, |
| | | declaredAmount: this.form.insurance || 0 |
| | | }) |
| | | if (res.code === 200) { |
| | | res.data.itemList.forEach(item => { |
| | | item.unitPrice = item.unitPrice / 100 |
| | | }) |
| | | res.data.totalPrice = res.data.totalPrice / 100 |
| | | res.data.insuranceFee = res.data.insuranceFee / 100 |
| | | this.serviceTimes = [ |
| | | { id: 0, name: '标准达', serviceTime: res.data.standardHours, price: res.data.itemPrice / 100 }, |
| | | { id: 1, name: '急速达', serviceTime: res.data.urgentHours, price: (res.data.urgentFee + res.data.itemPrice) / 100 } |
| | | ] |
| | | this.amountData = res.data |
| | | } |
| | | }, |
| | | async createOrder() { |
| | | if (this.activeMode === 'local') { |
| | | if (!this.selectedStore) { |
| | | uni.showToast({ title: '请选择门店', icon: 'none' }) |
| | | return |
| | | } |
| | | } else { |
| | | if (!this.sendStore) { |
| | | uni.showToast({ title: '请选择寄件服务点', icon: 'none' }) |
| | | return |
| | | } |
| | | if (!this.receiveStore && !this.receiveAddr) { |
| | | uni.showToast({ title: '请选择取件地址', icon: 'none' }) |
| | | return |
| | | } |
| | | } |
| | | if (!this.form.receiver) { |
| | | uni.showToast({ title: '请输入收件人姓名', icon: 'none' }) |
| | | return |
| | | } |
| | | if (!this.form.mobile) { |
| | | uni.showToast({ title: '请输入收件人电话', icon: 'none' }) |
| | | return |
| | | } |
| | | const mobileRegex = /^1\d{10}$/ |
| | | const landlineRegex = /^\d{3,4}-?\d{7,8}$/ |
| | | if (!mobileRegex.test(this.form.mobile) && !landlineRegex.test(this.form.mobile)) { |
| | | uni.showToast({ title: '请输入正确的手机号或固定电话', icon: 'none' }) |
| | | return |
| | | } |
| | | if (!this.form.arriveTime) { |
| | | uni.showToast({ title: '请选择预计到店时间', icon: 'none' }) |
| | | return |
| | | } |
| | | if (!this.form.pickupTime) { |
| | | uni.showToast({ title: '请选择预计取件时间', icon: 'none' }) |
| | | return |
| | | } |
| | | if (new Date(this.form.pickupTime) <= new Date(this.form.arriveTime)) { |
| | | uni.showToast({ title: '预计取件时间必须大于预计到店时间', icon: 'none' }) |
| | | return |
| | | } |
| | | const luggageList = this.luggageTypes |
| | | .filter(item => item.count > 0) |
| | | .map(item => ({ |
| | | categoryId: item.id, |
| | | quantity: item.count |
| | | })) |
| | | if (luggageList.length === 0) { |
| | | uni.showToast({ title: '请选择行李类型', icon: 'none' }) |
| | | return |
| | | } |
| | | if (!this.form.goodType) { |
| | | uni.showToast({ title: '请选择物品信息', icon: 'none' }) |
| | | return |
| | | } |
| | | if (!this.form.goodsImages ||!this.form.goodsImages.length) { |
| | | uni.showToast({ title: '请上传物品照片', icon: 'none' }) |
| | | return |
| | | } |
| | | if (!this.form.goodsImages ||!this.form.goodsImages.length) { |
| | | uni.showToast({ title: '请上传物品照片', icon: 'none' }) |
| | | return |
| | | } |
| | | if (this.form.insurance === '' || this.form.insurance <= 0) { |
| | | uni.showToast({ title: '请输入保价费', icon: 'none' }) |
| | | return |
| | | } |
| | | if (!this.agreementChecked) { |
| | | uni.showToast({ title: '请先阅读并同意用户服务协议及隐私政策', icon: 'none' }) |
| | | return |
| | | } |
| | | const items = luggageList.map(item => ({ |
| | | categoryId: item.categoryId, |
| | | quantity: item.quantity |
| | | })) |
| | | let orderParams = { |
| | | cityId: this.cityId, |
| | | declaredAmount: this.form.insurance || 0, |
| | | expectedDepositTime: this.form.arriveTime + ':00', |
| | | expectedTakeTime: this.form.pickupTime + ':00', |
| | | goodType: this.form.goodType, |
| | | goodsImages: this.form.goodsImages, |
| | | items: items, |
| | | remark: this.form.remark, |
| | | takePhone: this.form.mobile, |
| | | takeUser: this.form.receiver, |
| | | type: this.activeMode === 'local' ? 0 : 1, |
| | | isUrgent: this.isUrgent |
| | | } |
| | | if (this.activeMode === 'local') { |
| | | orderParams.depositShopId = this.selectedStore.id |
| | | } else { |
| | | orderParams.depositShopId = this.sendStore.id |
| | | orderParams.fromShopId = this.sendStore.id |
| | | if (this.receiveStore) { |
| | | orderParams.toType = 0 |
| | | orderParams.takeShopId = this.receiveStore.id |
| | | orderParams.takeLat = this.receiveStore.latitude |
| | | orderParams.takeLgt = this.receiveStore.longitude |
| | | orderParams.takeLocation = this.receiveStore.address |
| | | } else if (this.receiveAddr) { |
| | | orderParams.toType = 1 |
| | | orderParams.toAddrId = this.receiveAddr.id |
| | | orderParams.takeLat = this.receiveAddr.latitude |
| | | orderParams.takeLgt = this.receiveAddr.longitude |
| | | orderParams.takeLocation = this.receiveAddr.addr |
| | | } |
| | | } |
| | | const res = await this.$u.api.createOrder(orderParams) |
| | | if (res.code === 200) { |
| | | if (res.data) { |
| | | this.processPayment(res.data.response, res.data.orderId) |
| | | } |
| | | } |
| | | }, |
| | | processPayment(paymentData, orderId) { |
| | | uni.requestPayment({ |
| | | provider: 'wxpay', |
| | | timeStamp: paymentData.timeStamp || '', |
| | | nonceStr: paymentData.nonceStr || '', |
| | | package: paymentData.package || '', |
| | | signType: paymentData.signType || 'MD5', |
| | | paySign: paymentData.paySign || '', |
| | | success: (res) => { |
| | | uni.redirectTo({ |
| | | url: '/pages/payment-success/payment-success?orderId=' + orderId |
| | | }); |
| | | }, |
| | | fail: (err) => { |
| | | if (err.errMsg.includes('cancel')) { |
| | | uni.showToast({ title: '已取消支付', icon: 'none' }) |
| | | } else { |
| | | uni.showToast({ title: '支付失败', icon: 'none' }) |
| | | } |
| | | uni.setStorageSync("orderStatus",-2) |
| | | uni.switchTab({ |
| | | url: '/pages/itinerary/itinerary' |
| | | }); |
| | | |
| | | } |
| | | }) |
| | | } |
| | | } |
| | | } |
| | |
| | | position: relative; |
| | | width: 50%; |
| | | text-align: center; |
| | | font-size: 28rpx; |
| | | font-weight: 500; |
| | | font-weight: 600; |
| | | font-size: 32rpx; |
| | | color: #9097a3; |
| | | } |
| | | |
| | |
| | | .store-popup-wrap { |
| | | background: #ffffff; |
| | | border-radius: 24rpx 24rpx 0 0; |
| | | padding: 0 30rpx; |
| | | box-sizing: border-box; |
| | | padding: 0 30rpx 16rpx 30rpx; |
| | | box-sizing: border-box; |
| | | } |
| | | |
| | |
| | | |
| | | .store-list-scroll { |
| | | max-height: 70vh; |
| | | min-height: 50vh; |
| | | margin-top: 30rpx; |
| | | } |
| | | |
| | |
| | | .store-option-address-row { |
| | | margin-top: 8rpx; |
| | | display: flex; |
| | | align-items: center; |
| | | align-items: flex-start; |
| | | flex-wrap: wrap; |
| | | } |
| | | |
| | | .store-option-address-icon { |
| | | flex-shrink: 0; |
| | | width: 24rpx; |
| | | height: 24rpx; |
| | | margin-right: 4rpx; |
| | | margin-top: 6rpx; |
| | | } |
| | | |
| | | .store-option-address { |
| | | flex: 1; |
| | | font-size: 26rpx; |
| | | color: #9ea4af; |
| | | } |
| | |
| | | flex-direction: column; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .store-cell-copy-addr { |
| | | |
| | | .store-cell-copy-addr1 { |
| | | display: flex; |
| | | align-items: baseline; |
| | | image { |
| | | width: 24rpx; |
| | | height: 24rpx; |
| | | margin-right: 4rpx; |
| | | } |
| | | } |
| | | |
| | | .store-cell-copy-addr { |
| | | display: flex; |
| | | flex-direction: column; |
| | | .store-cell-subtitle-container { |
| | | display: flex; |
| | | align-items: center; |
| | | image { |
| | | flex-shrink: 0; |
| | | width: 24rpx; |
| | | height: 24rpx; |
| | | margin-right: 4rpx; |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | font-size: 30rpx; |
| | | color: #222222; |
| | | line-height: 1.3; |
| | | } |
| | | |
| | | .cell-title.placeholder { |
| | | color: #9097a3; |
| | | font-weight: 400; |
| | | } |
| | | |
| | | .store-cell-subtitle { |
| | |
| | | |
| | | .luggage-item { |
| | | display: flex; |
| | | align-items: baseline; |
| | | align-items: flex-end; |
| | | justify-content: space-between; |
| | | padding: 24rpx; |
| | | box-sizing: border-box; |
| | |
| | | height: 100rpx; |
| | | border-radius: 8rpx; |
| | | margin-right: 18rpx; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | background: #f0f1f4; |
| | | overflow: hidden; |
| | | margin-right: 24rpx; |
| | |
| | | } |
| | | |
| | | .step-btn { |
| | | width: 36rpx; |
| | | height: 36rpx; |
| | | border-radius: 18rpx; |
| | | background: #eef1f5; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .step-btn.active { |
| | | background: #27aef8; |
| | | width: 44rpx; |
| | | height: 44rpx; |
| | | } |
| | | |
| | | .step-count { |
| | |
| | | .goods-upload-row { |
| | | display: flex; |
| | | align-items: center; |
| | | flex-wrap: wrap; |
| | | gap: 12rpx; |
| | | margin-top: 8rpx; |
| | | } |
| | |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | height: 28rpx; |
| | | line-height: 28rpx; |
| | | height: 40rpx; |
| | | line-height: 40rpx; |
| | | text-align: center; |
| | | font-size: 18rpx; |
| | | color: #ffffff; |
| | | background: rgba(0, 0, 0, 0.48); |
| | | font-weight: 400; |
| | | font-size: 24rpx; |
| | | color: #FFFFFF; |
| | | background: rgba(0,0,0,0.5); |
| | | border-radius: 0rpx 0rpx 8rpx 8rpx; |
| | | } |
| | | |
| | | .service-time-card { |
| | |
| | | font-weight: 500; |
| | | color: #333333; |
| | | border: 2rpx solid transparent; |
| | | white-space: nowrap; /* 防止文本换行 */ |
| | | overflow: hidden; /* 隐藏溢出的内容 */ |
| | | text-overflow: ellipsis; /* 显示省略号来代表被修剪的文本 */ |
| | | box-sizing: border-box; |
| | | } |
| | | |
| | |
| | | padding-bottom: 14rpx; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: flex-end; |
| | | justify-content: space-between; |
| | | font-size: 22rpx; |
| | | } |
| | | |
| | |
| | | color: #999999; |
| | | } |
| | | |
| | | .insurance-tip-warning { |
| | | color: #ff4d4f; |
| | | font-size: 22rpx; |
| | | font-weight: 400; |
| | | } |
| | | |
| | | .insurance-tip-value { |
| | | margin-left: 8rpx; |
| | | color: #ff4d4f; |