1692 lines
52 KiB
Vue
1692 lines
52 KiB
Vue
<template>
|
||
<view class="feeding-container">
|
||
<scroll-view class="feeding-scroll" scroll-y>
|
||
<view class="feeding-content">
|
||
<!-- Tab切换 -->
|
||
<!-- <view class="order-tab-list">
|
||
<view :class="activeTab === 'reservation' ? 'activeItem' : 'tabItem'"
|
||
@click.stop="switchTab('reservation')">
|
||
预约单
|
||
</view>
|
||
<view :class="activeTab === 'instant' ? 'activeItem' : 'tabItem'"
|
||
@click.stop="switchTab('instant')">
|
||
即时单
|
||
</view>
|
||
</view> -->
|
||
|
||
<!-- 表单内容 -->
|
||
<view class="form-wrapper">
|
||
<!-- 选择宠物 -->
|
||
<view class="form-section">
|
||
<view class="form-label-row">
|
||
<text class="required">*</text>
|
||
<text class="form-label">选择宠物</text>
|
||
</view>
|
||
<view class="add-pet-wrapper">
|
||
<view v-for="(pet, index) in selectedPets" :key="pet.id || index"
|
||
class="selected-pet-avatar">
|
||
<image class="pet-avatar-img" :src="pet.avatar || `${imgPrefix}record_avator.png`"
|
||
mode="aspectFill" />
|
||
<view class="remove-pet-btn" @click.stop="removePet(index)">×</view>
|
||
</view>
|
||
<view class="add-pet-btn" @click="addPet">
|
||
<text class="plus-icon">+</text>
|
||
</view>
|
||
</view>
|
||
<text class="add-pet-text">添加宠物</text>
|
||
|
||
</view>
|
||
|
||
<!-- 选择套餐 -->
|
||
<view class="form-section package-section">
|
||
<view class="package-header">
|
||
<text class="required">*</text>
|
||
<text class="form-label">选择宠物套餐</text>
|
||
</view>
|
||
<scroll-view class="package-scroll" scroll-x>
|
||
<view class="package-list">
|
||
<view class="package-card"
|
||
:class="{ 'package-card-selected': formData.selectedPackageIndex === index }"
|
||
v-for="(item, index) in packageList" :key="index" @click="selectPackage(index)">
|
||
<view class="package-info">
|
||
<view class="package-name-row">
|
||
<text class="package-name">{{ item.service_name }}</text>
|
||
<image class="info-icon" :src="imgPrefix + 'trainingTips.png'"
|
||
mode="widthFix" @click.stop="showPackageInfo(item)" />
|
||
</view>
|
||
<text class="package-duration">{{ item.service_desc }}</text>
|
||
<view class="package-price-row">
|
||
<view class="price-content">
|
||
<text class="package-price">¥{{ item.service_price }}</text>
|
||
<text class="package-unit">元/只</text>
|
||
</view>
|
||
<image v-if="formData.selectedPackageIndex === index" class="package-radio"
|
||
src="@/static/images/cart_checked.png" mode="widthFix" />
|
||
<image v-else class="package-radio"
|
||
:src="imgPrefix + 'packageUnchecked.png'" mode="widthFix" />
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</scroll-view>
|
||
</view>
|
||
|
||
<!-- 选择服务时间 -->
|
||
<view class="form-section" v-if="activeTab === 'reservation'" @click="selectTime">
|
||
<view class="service-time-header">
|
||
<text class="required">*</text>
|
||
<text class="service-time-title">选择服务时间</text>
|
||
<view class="service-time-count" v-if="selectedDatesCount > 0">
|
||
<text class="count-text">共{{ selectedDatesCount }}天</text>
|
||
<image class="right-icon" :src="imgPrefix + 'right-arrow.png'" mode="widthFix" />
|
||
</view>
|
||
<view class="service-time-count" v-else>
|
||
<text class="placeholder-text">请选择</text>
|
||
<image class="right-icon" :src="imgPrefix + 'right-arrow.png'" mode="widthFix" />
|
||
</view>
|
||
</view>
|
||
<view class="service-time-content" v-if="formData.serviceTime && selectedDatesCount > 0">
|
||
<view class="service-time-item">
|
||
<text class="service-time-label">已选择日期:</text>
|
||
<text class="service-time-value">{{ selectedDatesList.join(',') }}</text>
|
||
</view>
|
||
<view class="service-time-item">
|
||
<text class="service-time-label">已选择时间段:</text>
|
||
<text class="service-time-value">{{ selectedTimeSlot }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 选择服务地址 -->
|
||
<view class="form-section" @click="selectAddress">
|
||
<view class="info-top-view">
|
||
<text class="required">*</text>
|
||
<view class="title-view">
|
||
<text class="form-label">选择服务地址</text>
|
||
</view>
|
||
<view class="info-view" v-if="addressInfo">
|
||
<view class="address-display">
|
||
<view class="address-name-phone">
|
||
<text class="address-name-text">{{ addressInfo.recipient_name || '' }}</text>
|
||
<text class="address-phone-text">{{ addressInfo.phone || '' }}</text>
|
||
</view>
|
||
<text class="address-detail-text">{{ formData.serviceAddress }}</text>
|
||
</view>
|
||
</view>
|
||
<view class="info-view" v-else>
|
||
<text class="placeholder-text">请选择</text>
|
||
</view>
|
||
<image class="right-icon" :src="imgPrefix + 'right-arrow.png'" mode="widthFix" />
|
||
</view>
|
||
<!-- <text class="nightFee">以下区域需收取调度费:奉贤区、嘉定区、青浦区、松江区、崇明县、金山区</text> -->
|
||
</view>
|
||
|
||
|
||
|
||
<!-- Wi-Fi密码 -->
|
||
<view class="form-section">
|
||
<view class="info-top-view">
|
||
<view class="title-view">
|
||
<text class="form-label">Wi-Fi密码</text>
|
||
</view>
|
||
<view class="info-view">
|
||
<input class="form-input" type="text" v-model="formData.wifiPassword"
|
||
placeholder="以便工作人员拍摄宠物视频" placeholder-class="placeholder-class" />
|
||
</view>
|
||
<view class="right-icon" />
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 服务备注 -->
|
||
<view class="form-section" @click="inputServiceNotes">
|
||
<view class="info-top-view">
|
||
<view class="title-view">
|
||
<text class="form-label">服务备注</text>
|
||
</view>
|
||
<view class="info-view" v-if="formData.serviceNotes">
|
||
<text class="form-label">{{ formData.serviceNotes }}</text>
|
||
</view>
|
||
<view class="info-view" v-else>
|
||
<text class="placeholder-text">请补充宠物注意事项</text>
|
||
</view>
|
||
<image class="right-icon" :src="imgPrefix + 'right-arrow.png'" mode="widthFix" />
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 钥匙交接备注 -->
|
||
<view class="form-section" @click="inputKeyNotes">
|
||
<view class="info-top-view">
|
||
<text class="required">*</text>
|
||
<view class="title-view">
|
||
<text class="form-label">钥匙交接备注</text>
|
||
</view>
|
||
<view class="info-view" v-if="formData.keyNotes">
|
||
<text class="form-label">{{ formData.keyNotes }}</text>
|
||
</view>
|
||
<view class="info-view" v-else>
|
||
<text class="placeholder-text">请补充钥匙交接备注</text>
|
||
</view>
|
||
<image class="right-icon" :src="imgPrefix + 'right-arrow.png'" mode="widthFix" />
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 停车状况 -->
|
||
<view class="form-section form-section-park">
|
||
<view class="info-top-view">
|
||
<text class="required">*</text>
|
||
<view class="title-view">
|
||
<text class="form-label">停车状况</text>
|
||
</view>
|
||
</view>
|
||
<view class="park-list">
|
||
<view class="park-card" v-for="item in parkConditions" :key="item"
|
||
:class="{ 'park-card-selected': formData.parkState === item }"
|
||
@click="selectParkState(item)">
|
||
<text class="park-card-text"
|
||
:class="{ 'park-card-text-selected': formData.parkState === item }">{{ item
|
||
}}</text>
|
||
</view>
|
||
</view>
|
||
<view class="park-input-wrap" v-if="formData.parkState === '其他'">
|
||
<textarea class="park-input" v-model="formData.otherParkState" placeholder="点击输入停车信息"
|
||
placeholder-class="placeholder-class" />
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 说明图片 -->
|
||
<view class="explain-image-section">
|
||
<image class="explain-image"
|
||
:src="imgPrefix + (serviceType === 'feeding' ? 'feedPetLong.png' : 'trainingExplain.png')"
|
||
mode="widthFix" />
|
||
</view>
|
||
</view>
|
||
</scroll-view>
|
||
|
||
<!-- 底部固定栏(含 tip 时上方展示说明条) -->
|
||
<view class="bottom-fixed-wrap">
|
||
<view v-if="tip" class="tip-notice-bar">
|
||
<image class="tip-notice-icon" :src="imgPrefix + 'reservationTime-notice.png'" mode="aspectFit" />
|
||
<text class="tip-notice-text">{{ tip }}</text>
|
||
</view>
|
||
<view class="bottom-action-bar">
|
||
<view class="price-info">
|
||
<view class="estimate-price">
|
||
<text class="estimate-label">预估:</text>
|
||
<text class="estimate-amount">¥{{ estimatedPrice }}</text>
|
||
</view>
|
||
</view>
|
||
<view class="next-step-btn" @click="goToNextStep">
|
||
<text class="next-step-text">下一步</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 服务备注弹窗 -->
|
||
<view class="key-notes-modal" v-if="showServiceNotesModal" @click.stop="closeServiceNotesModal">
|
||
<view class="modal-content" @click.stop="">
|
||
<!-- 标题栏 -->
|
||
<view class="modal-header">
|
||
<view class="close-btn-placeholder"></view>
|
||
<text class="modal-title">服务备注</text>
|
||
<view class="close-btn" @click="closeServiceNotesModal">
|
||
<text class="close-icon">×</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 内容区域 -->
|
||
<view class="content-view">
|
||
<!-- 输入框 -->
|
||
<view class="input-wrapper">
|
||
<textarea class="notes-input" v-model="serviceNotesInput" placeholder="请补充宠物注意事项"
|
||
placeholder-class="input-placeholder" maxlength="100" @input="onServiceNotesInput" />
|
||
<view class="char-count">{{ serviceNotesInput.length }}/100</view>
|
||
</view>
|
||
|
||
<!-- 快捷输入 -->
|
||
<view class="quick-input-section">
|
||
<text class="quick-input-label">快捷输入</text>
|
||
<view class="quick-tags">
|
||
<view class="quick-tag" v-for="(tag, index) in serviceNotesQuickTags" :key="index"
|
||
@click="selectServiceNotesTag(tag)">
|
||
<text class="tag-text">{{ tag }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 提交按钮 -->
|
||
<view class="submit-btn" @click="submitServiceNotes">
|
||
<text class="submit-btn-text">提交</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 服务介绍弹窗 -->
|
||
<view class="service-info-modal" v-if="showServiceInfoModal" @click.stop="closeServiceInfoModal">
|
||
<view class="service-info-modal-content" @click.stop="">
|
||
<view class="service-info-header">
|
||
<text class="service-info-title">服务介绍</text>
|
||
</view>
|
||
<view class="service-info-body">
|
||
<text class="service-info-text">{{ currentServiceInfo }}</text>
|
||
</view>
|
||
<view class="service-info-footer">
|
||
<view class="service-info-btn" @click="closeServiceInfoModal">
|
||
<text class="service-info-btn-text">我知道了</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 钥匙交接备注弹窗 -->
|
||
<view class="key-notes-modal" v-if="showKeyNotesModal" @click.stop="closeKeyNotesModal">
|
||
<view class="modal-content" @click.stop="">
|
||
<!-- 标题栏 -->
|
||
<view class="modal-header">
|
||
<view class="close-btn-placeholder"></view>
|
||
<text class="modal-title">钥匙交接备注</text>
|
||
<view class="close-btn" @click="closeKeyNotesModal">
|
||
<text class="close-icon">×</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 内容区域 -->
|
||
<view class="content-view">
|
||
<!-- 输入框 -->
|
||
<view class="input-wrapper">
|
||
<textarea class="notes-input" v-model="keyNotesInput" placeholder="请补充宠物注意事项"
|
||
placeholder-class="input-placeholder" maxlength="100" @input="onKeyNotesInput" />
|
||
<view class="char-count">{{ keyNotesInput.length }}/100</view>
|
||
</view>
|
||
|
||
<!-- 快捷输入 -->
|
||
<view class="quick-input-section">
|
||
<text class="quick-input-label">快捷输入</text>
|
||
<view class="quick-tags">
|
||
<view class="quick-tag" v-for="(tag, index) in keyNotesQuickTags" :key="index"
|
||
@click="selectQuickTag(tag)">
|
||
<text class="tag-text">{{ tag }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 提交按钮 -->
|
||
<view class="submit-btn" @click="submitKeyNotes">
|
||
<text class="submit-btn-text">提交</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import { imgPrefix } from '@/utils/common';
|
||
import { getHomeServices } from '@/api/common';
|
||
import { createFeedOrder, createWalkOrder, checkHolidayFee } from '@/api/order';
|
||
import { PET_TYPE_CAT, PET_TYPE_DOG } from '@/constants/app.business';
|
||
import moment from 'moment';
|
||
|
||
export default {
|
||
name: 'Feeding',
|
||
data() {
|
||
return {
|
||
imgPrefix,
|
||
serviceType: 'feeding', // 服务类型:feeding(上门喂宠) 或 walking(上门遛宠)
|
||
activeTab: 'reservation',
|
||
formData: {
|
||
pet: null,
|
||
selectedPackageIndex: null,
|
||
serviceTime: null, // 改为存储完整的timeData对象 {dates: [], timeSlot: ''}
|
||
serviceAddress: '',
|
||
parkState: '',
|
||
otherParkState: '',
|
||
wifiPassword: '',
|
||
serviceNotes: '',
|
||
keyNotes: ''
|
||
},
|
||
parkConditions: ['小区', '地库', '路边', '其他'],
|
||
selectedPets: [], // 选中的宠物列表
|
||
addressInfo: null, // 地址信息对象
|
||
packageList: [
|
||
{
|
||
name: '单只小型犬(≤10kg)',
|
||
duration: '服务时长约30分钟',
|
||
price: 128
|
||
},
|
||
{
|
||
name: '单只中型犬(10-25kg)',
|
||
duration: '服务时长约60分钟',
|
||
price: 158
|
||
},
|
||
{
|
||
name: '单只大型犬(>25kg)',
|
||
duration: '服务时长约90分钟',
|
||
price: 188
|
||
}
|
||
],
|
||
showKeyNotesModal: false,
|
||
keyNotesInput: '',
|
||
showServiceNotesModal: false,
|
||
serviceNotesInput: '',
|
||
serviceNotesQuickTags: [
|
||
'怕生怕冷',
|
||
'胆小怕生',
|
||
'攻击性',
|
||
'不可抱',
|
||
'皮肤病',
|
||
'术后恢复',
|
||
'呼吸道敏感',
|
||
'需要安抚',
|
||
'护食',
|
||
'咬人',
|
||
'抓人'
|
||
],
|
||
keyNotesQuickTags: [
|
||
'存于快递柜',
|
||
'放于指定位置',
|
||
'家里有人在'
|
||
],
|
||
showServiceInfoModal: false,
|
||
currentServiceInfo: '',
|
||
holidayFee: 0,
|
||
tip: ''
|
||
};
|
||
},
|
||
computed: {
|
||
// 已选择日期数量
|
||
selectedDatesCount() {
|
||
return this.formData.serviceTime?.dates?.length || 0;
|
||
},
|
||
// 已选择日期列表(格式:YYYY-MM-DD)
|
||
selectedDatesList() {
|
||
return this.formData.serviceTime?.dates || [];
|
||
},
|
||
// 已选择时间段
|
||
selectedTimeSlot() {
|
||
return this.formData.serviceTime?.timeSlot || '';
|
||
},
|
||
// 预估价格(根据选中的套餐计算)
|
||
estimatedPrice() {
|
||
if (this.formData.selectedPackageIndex !== null && this.formData.selectedPackageIndex !== undefined) {
|
||
const selectedPackage = this.packageList[this.formData.selectedPackageIndex];
|
||
if (selectedPackage && selectedPackage.service_price) {
|
||
// 基础价格(包含1只体重最小的宠物1天的费用)
|
||
let basePrice = parseFloat(selectedPackage.service_price) || 0;
|
||
|
||
// 宠物费用:找出体重最小的宠物(套餐已包含),计算其他宠物的额外费用
|
||
let petsFee = 0;
|
||
if (this.selectedPets.length > 0) {
|
||
// 找出体重最小的宠物(weight_id最小的)
|
||
let minWeightId = Infinity;
|
||
let minWeightPetIndex = 0;
|
||
this.selectedPets.forEach((pet, index) => {
|
||
const weightId = pet.weight_id || pet.weight?.weight_id || 0;
|
||
if (weightId < minWeightId) {
|
||
minWeightId = weightId;
|
||
minWeightPetIndex = index;
|
||
}
|
||
});
|
||
|
||
// 遍历所有宠物,计算额外费用
|
||
this.selectedPets.forEach((pet, index) => {
|
||
// 跳过体重最小的那只(套餐已包含)
|
||
if (index === minWeightPetIndex) {
|
||
return;
|
||
}
|
||
|
||
if (this.serviceType === 'feeding') {
|
||
// 上门喂宠:每只额外宠物固定加30元
|
||
petsFee += 30;
|
||
} else if (this.serviceType === 'walking') {
|
||
// 上门遛宠:根据每只狗的体重判断
|
||
const weightId = pet.weight_id || pet.weight?.weight_id || 0;
|
||
|
||
// 根据体重ID判断费用
|
||
if (weightId < 7) {
|
||
petsFee += 40; // weight_id < 7,加40元
|
||
} else if (weightId >= 7) {
|
||
petsFee += 50; // weight_id >= 7,加50元
|
||
} else {
|
||
// 如果没有体重信息,默认加40元
|
||
petsFee += 40;
|
||
}
|
||
}
|
||
});
|
||
}
|
||
let day = this.selectedDatesCount === 0 ? 1 : this.selectedDatesCount;
|
||
// 总价格 = 基础价格 + 附加价格 * 天数
|
||
let totalPrice = (basePrice + petsFee) * day;
|
||
return (totalPrice + this.holidayFee).toFixed(2);
|
||
}
|
||
}
|
||
return '0.00';
|
||
},
|
||
// 会员价格(预估价格的折扣价,假设9折)
|
||
// memberPrice() {
|
||
// const price = parseFloat(this.estimatedPrice);
|
||
// if (price > 0) {
|
||
// return (price * 0.8).toFixed(2);
|
||
// }
|
||
// return '0.00';
|
||
// }
|
||
},
|
||
onLoad(options) {
|
||
// 获取服务类型参数:feeding(上门喂宠) 或 walking(上门遛宠)
|
||
if (options.serviceType) {
|
||
this.serviceType = options.serviceType;
|
||
}
|
||
// 根据服务类型动态设置导航栏标题
|
||
const title = this.serviceType === 'walking' ? '上门遛宠' : '上门喂宠';
|
||
uni.setNavigationBarTitle({
|
||
title: title
|
||
});
|
||
// 调用套餐列表接口
|
||
this.getPackageList();
|
||
// 监听地址选择事件
|
||
uni.$on("selectAddress", this.addressChange);
|
||
},
|
||
onUnload() {
|
||
// 移除事件监听
|
||
uni.$off("selectAddress", this.addressChange);
|
||
},
|
||
methods: {
|
||
getPackageList() {
|
||
// 根据服务类型设置 service_type:上门喂宠=1,上门遛宠=2
|
||
const serviceType = this.serviceType === 'feeding' ? 1 : 2;
|
||
getHomeServices({ service_type: serviceType }).then((res) => {
|
||
// 兼容不同的返回结构
|
||
const list = res?.data || res?.info || res || [];
|
||
if (Array.isArray(list) && list.length > 0) {
|
||
this.packageList = list;
|
||
}
|
||
}).catch((err) => {
|
||
console.error('获取套餐列表失败:', err);
|
||
// 如果接口调用失败,保持使用默认的套餐列表
|
||
});
|
||
},
|
||
switchTab(tab) {
|
||
this.activeTab = tab;
|
||
// 清除所有选择的数据
|
||
this.selectedPets = [];
|
||
this.formData.pet = null;
|
||
this.formData.selectedPackageIndex = null;
|
||
this.formData.serviceTime = null;
|
||
this.addressInfo = null;
|
||
this.formData.serviceAddress = '';
|
||
},
|
||
addPet() {
|
||
uni.navigateTo({
|
||
url: `/pageHome/selectPet/index?serviceType=${this.serviceType}`,
|
||
events: {
|
||
changePet: (pet) => {
|
||
// 检查是否已经添加过这个宠物
|
||
const isExist = this.selectedPets.some(p => p.id === pet.id);
|
||
if (!isExist) {
|
||
this.selectedPets.push(pet);
|
||
// 如果只有一个宠物,也更新 formData.pet
|
||
if (this.selectedPets.length === 1) {
|
||
this.formData.pet = pet;
|
||
}
|
||
} else {
|
||
uni.showToast({
|
||
title: '该宠物已添加',
|
||
icon: 'none',
|
||
duration: 1500
|
||
});
|
||
}
|
||
}
|
||
}
|
||
});
|
||
},
|
||
removePet(index) {
|
||
this.selectedPets.splice(index, 1);
|
||
// 如果删除后没有宠物了,清空 formData.pet
|
||
if (this.selectedPets.length === 0) {
|
||
this.formData.pet = null;
|
||
} else if (this.selectedPets.length === 1) {
|
||
// 如果只有一个了,更新 formData.pet
|
||
this.formData.pet = this.selectedPets[0];
|
||
}
|
||
},
|
||
selectTime() {
|
||
// 构建URL参数,传递已选择的数据
|
||
let url = '/pageHome/service/select-service-time';
|
||
if (this.formData.serviceTime && this.formData.serviceTime.dates && this.formData.serviceTime.dates.length > 0) {
|
||
const dates = encodeURIComponent(JSON.stringify(this.formData.serviceTime.dates));
|
||
const timeSlot = encodeURIComponent(this.formData.serviceTime.timeSlot || '');
|
||
url += `?dates=${dates}&timeSlot=${timeSlot}`;
|
||
}
|
||
|
||
uni.navigateTo({
|
||
url: url,
|
||
events: {
|
||
changeServiceTime: (timeData) => {
|
||
// timeData 包含 dates 和 timeSlot
|
||
// 直接存储完整的timeData对象
|
||
if (timeData && timeData.dates && timeData.dates.length > 0 && timeData.timeSlot) {
|
||
this.formData.serviceTime = timeData;
|
||
// 选择完日期后调用节假日费用校验接口,传递日期数组
|
||
checkHolidayFee({ date: timeData.dates }).then((res) => {
|
||
// 可根据返回结果处理节假日费用展示或价格更新
|
||
if (res && res.data) {
|
||
console.log('check_holiday_fee', res.data);
|
||
this.holidayFee = res.data.fee
|
||
this.tip = res.data.tip
|
||
}
|
||
}).catch((err) => {
|
||
console.error('check_holiday_fee error', err);
|
||
});
|
||
}
|
||
}
|
||
}
|
||
});
|
||
},
|
||
selectPackage(index) {
|
||
this.formData.selectedPackageIndex = index;
|
||
},
|
||
showPackageInfo(item) {
|
||
this.currentServiceInfo = item.service_info || '';
|
||
this.showServiceInfoModal = true;
|
||
},
|
||
closeServiceInfoModal() {
|
||
this.showServiceInfoModal = false;
|
||
},
|
||
selectAddress() {
|
||
uni.navigateTo({
|
||
url: `/pageHome/selectAddress/index?typeSelect=1&addressId=${this.addressInfo?.id || this.addressInfo?.address_id || ""}`
|
||
});
|
||
},
|
||
addressChange(addressInfo) {
|
||
this.addressInfo = addressInfo;
|
||
// 格式化地址信息:省市区 + 详细地址(用于显示)
|
||
const region = [addressInfo.province, addressInfo.city, addressInfo.district].filter(Boolean).join('');
|
||
this.formData.serviceAddress = region ? `${region}${addressInfo.full_address}` : addressInfo.full_address;
|
||
},
|
||
selectParkState(item) {
|
||
this.formData.parkState = item;
|
||
if (item !== '其他') {
|
||
this.formData.otherParkState = '';
|
||
}
|
||
},
|
||
inputServiceNotes() {
|
||
this.serviceNotesInput = this.formData.serviceNotes || '';
|
||
this.showServiceNotesModal = true;
|
||
},
|
||
closeServiceNotesModal() {
|
||
this.showServiceNotesModal = false;
|
||
},
|
||
onServiceNotesInput(e) {
|
||
this.serviceNotesInput = e.detail.value;
|
||
},
|
||
selectServiceNotesTag(tag) {
|
||
if (this.serviceNotesInput.length + tag.length <= 100) {
|
||
this.serviceNotesInput = this.serviceNotesInput ? this.serviceNotesInput + ' ' + tag : tag;
|
||
} else {
|
||
uni.showToast({
|
||
title: '字数超出限制',
|
||
icon: 'none'
|
||
});
|
||
}
|
||
},
|
||
submitServiceNotes() {
|
||
this.formData.serviceNotes = this.serviceNotesInput;
|
||
this.closeServiceNotesModal();
|
||
},
|
||
inputKeyNotes() {
|
||
this.keyNotesInput = this.formData.keyNotes || '';
|
||
this.showKeyNotesModal = true;
|
||
},
|
||
closeKeyNotesModal() {
|
||
this.showKeyNotesModal = false;
|
||
},
|
||
onKeyNotesInput(e) {
|
||
this.keyNotesInput = e.detail.value;
|
||
},
|
||
selectQuickTag(tag) {
|
||
if (this.keyNotesInput.length + tag.length <= 100) {
|
||
this.keyNotesInput = this.keyNotesInput ? this.keyNotesInput + ' ' + tag : tag;
|
||
} else {
|
||
uni.showToast({
|
||
title: '字数超出限制',
|
||
icon: 'none'
|
||
});
|
||
}
|
||
},
|
||
submitKeyNotes() {
|
||
this.formData.keyNotes = this.keyNotesInput;
|
||
this.closeKeyNotesModal();
|
||
},
|
||
validateForm() {
|
||
// 校验选择宠物
|
||
if (!this.selectedPets || this.selectedPets.length === 0) {
|
||
uni.showToast({
|
||
title: '请选择宠物',
|
||
icon: 'none'
|
||
});
|
||
return false;
|
||
}
|
||
|
||
// 校验选择宠物套餐
|
||
if (this.formData.selectedPackageIndex === null || this.formData.selectedPackageIndex === undefined) {
|
||
uni.showToast({
|
||
title: '请选择宠物套餐',
|
||
icon: 'none'
|
||
});
|
||
return false;
|
||
}
|
||
|
||
// 校验选择服务时间(仅在预约单时)
|
||
if (this.activeTab === 'reservation') {
|
||
if (!this.formData.serviceTime || !this.formData.serviceTime.dates || this.formData.serviceTime.dates.length === 0 || !this.formData.serviceTime.timeSlot) {
|
||
uni.showToast({
|
||
title: '请选择服务时间',
|
||
icon: 'none'
|
||
});
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// 校验选择服务地址
|
||
if (!this.addressInfo || !this.addressInfo.id) {
|
||
uni.showToast({
|
||
title: '请选择服务地址',
|
||
icon: 'none'
|
||
});
|
||
return false;
|
||
}
|
||
|
||
// 校验停车状况
|
||
if (!this.formData.parkState) {
|
||
uni.showToast({
|
||
title: '请选择停车状况',
|
||
icon: 'none'
|
||
});
|
||
return false;
|
||
}
|
||
if (this.formData.parkState === '其他' && !(this.formData.otherParkState || '').trim()) {
|
||
uni.showToast({
|
||
title: '请输入停车信息',
|
||
icon: 'none'
|
||
});
|
||
return false;
|
||
}
|
||
|
||
// 校验钥匙交接备注
|
||
if (!this.formData.keyNotes || !this.formData.keyNotes.trim()) {
|
||
uni.showToast({
|
||
title: '请输入钥匙交接备注',
|
||
icon: 'none'
|
||
});
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
},
|
||
goToNextStep() {
|
||
// 校验表单
|
||
if (!this.validateForm()) {
|
||
return;
|
||
}
|
||
|
||
// 构建接口参数
|
||
const selectedPackage = this.packageList[this.formData.selectedPackageIndex];
|
||
if (!selectedPackage) {
|
||
uni.showToast({
|
||
title: '请选择套餐',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
|
||
// 构建宠物数组
|
||
const pets = this.selectedPets.map(pet => ({
|
||
pet_id: pet.id,
|
||
pet_name: pet.name || pet.pet_nickname || ''
|
||
}));
|
||
|
||
// 构建时间段数组
|
||
let slots = [];
|
||
if (this.activeTab === 'instant') {
|
||
// 即时单(现场单):直接设置为今天,格式 YYYY-MM-DD
|
||
const todayStr = moment().format('YYYY-MM-DD');
|
||
|
||
slots = [{
|
||
date: todayStr,
|
||
period_name: '' // 现场单不需要 period_name
|
||
}];
|
||
} else {
|
||
// 预约单:将时间段字符串转换为 period_name 格式
|
||
// 例如 "12:00-15:00" 转换为 "12:00:00 ~ 15:00:00"
|
||
const timeSlot = this.formData.serviceTime.timeSlot;
|
||
const periodName = timeSlot.replace(/-/g, ':00 ~ ') + ':00';
|
||
|
||
slots = this.formData.serviceTime.dates.map(date => ({
|
||
date: date,
|
||
period_name: periodName
|
||
}));
|
||
}
|
||
|
||
// 校验 park_desc 字段
|
||
const parkDesc = this.formData.parkState === '其他' ? (this.formData.otherParkState || '').trim() : '';
|
||
if (this.formData.parkState === '其他' && !parkDesc) {
|
||
uni.showToast({
|
||
title: '请输入停车信息',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
|
||
const orderData = {
|
||
pets: pets,
|
||
service_type: this.serviceType === 'feeding' ? 1 : 2, // 上门喂宠=1, 上门遛宠=2
|
||
service_id: selectedPackage.service_id,
|
||
service_name: selectedPackage.service_name || '',
|
||
address_id: this.addressInfo.id || this.addressInfo.address_id,
|
||
address: this.formData.serviceAddress || this.addressInfo.full_address || '',
|
||
park_desc: (this.formData.otherParkState || '').trim() || this.formData.parkState,
|
||
wifi_password: this.formData.wifiPassword || '',
|
||
remark: this.formData.serviceNotes || '',
|
||
key_handover_remark: this.formData.keyNotes || '',
|
||
slots: slots,
|
||
service_price: +selectedPackage.service_price,
|
||
service_actual_price: +this.estimatedPrice
|
||
};
|
||
|
||
uni.showLoading({
|
||
title: '提交中...',
|
||
mask: true
|
||
});
|
||
|
||
// 根据服务类型调用不同的接口
|
||
const createOrderAPI = this.serviceType === 'walking' ? createWalkOrder : createFeedOrder;
|
||
|
||
createOrderAPI(orderData)
|
||
.then((res) => {
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: '订单创建成功',
|
||
icon: 'success'
|
||
});
|
||
// 获取订单ID(兼容不同的响应结构)
|
||
const orderId = res?.data?.order_id;
|
||
// 跳转到支付确认页面
|
||
setTimeout(() => {
|
||
uni.navigateTo({
|
||
url: `/pageHome/service/payment-confirm?order_id=${orderId}`
|
||
});
|
||
}, 800);
|
||
})
|
||
.catch((err) => {
|
||
uni.hideLoading();
|
||
console.error('创建订单失败:', err);
|
||
uni.showToast({
|
||
title: err?.msg || err?.message || '创建订单失败',
|
||
icon: 'none'
|
||
});
|
||
});
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.feeding-container {
|
||
width: 100%;
|
||
height: 100vh;
|
||
background-color: #faf7f8;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.feeding-scroll {
|
||
flex: 1;
|
||
height: 100%;
|
||
padding-bottom: calc(140rpx + env(safe-area-inset-bottom));
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.feeding-content {
|
||
padding: 0 20rpx;
|
||
padding-top: 20rpx;
|
||
}
|
||
|
||
.order-tab-list {
|
||
display: flex;
|
||
align-items: flex-end;
|
||
margin-top: 20rpx;
|
||
|
||
.tabItem {
|
||
flex: 1;
|
||
text-align: center;
|
||
background-color: #ffd8e6;
|
||
border-radius: 16rpx 16rpx 0px 0px;
|
||
height: 92rpx;
|
||
line-height: 92rpx;
|
||
font-size: 24rpx;
|
||
color: #333;
|
||
}
|
||
|
||
.activeItem {
|
||
background-color: #fff;
|
||
flex: 1;
|
||
text-align: center;
|
||
height: 92rpx;
|
||
line-height: 92rpx;
|
||
border-radius: 16rpx 16rpx 0px 0px;
|
||
font-size: 28rpx;
|
||
font-weight: 500;
|
||
color: #333;
|
||
}
|
||
}
|
||
|
||
.form-wrapper {
|
||
background-color: #fff;
|
||
padding: 0rpx 20rpx;
|
||
border-radius: 0px 0px 16rpx 16rpx;
|
||
}
|
||
|
||
.form-section {
|
||
width: 100%;
|
||
background-color: #fff;
|
||
display: flex;
|
||
flex-direction: column;
|
||
padding: 36rpx 0;
|
||
box-sizing: border-box;
|
||
border-bottom: 1px solid #ececec;
|
||
|
||
&:last-child {
|
||
border-bottom: none;
|
||
}
|
||
}
|
||
|
||
.form-section-park {
|
||
.park-list {
|
||
margin-top: 16rpx;
|
||
width: 100%;
|
||
display: flex;
|
||
flex-direction: row;
|
||
flex-wrap: wrap;
|
||
align-items: center;
|
||
gap: 24rpx;
|
||
}
|
||
|
||
.park-card {
|
||
padding: 12rpx 20rpx;
|
||
border-radius: 182rpx;
|
||
background-color: #f5f5f5;
|
||
color: #000;
|
||
}
|
||
|
||
.park-card-selected {
|
||
background-color: #fee9f3;
|
||
}
|
||
|
||
.park-card-text {
|
||
font-size: 24rpx;
|
||
color: #333;
|
||
}
|
||
|
||
.park-card-text-selected {
|
||
color: #FF19A0;
|
||
}
|
||
|
||
.park-input-wrap {
|
||
width: 100%;
|
||
height: 200rpx;
|
||
margin-top: 32rpx;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.park-input {
|
||
width: 100%;
|
||
height: 100%;
|
||
padding: 32rpx;
|
||
border-radius: 30rpx;
|
||
color: #333;
|
||
box-sizing: border-box;
|
||
background-color: #f9f7f9;
|
||
font-size: 24rpx;
|
||
}
|
||
}
|
||
|
||
.form-label-row {
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
box-sizing: border-box;
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.form-label {
|
||
font-size: 24rpx;
|
||
color: #333;
|
||
display: flex;
|
||
flex: 1;
|
||
align-items: center;
|
||
}
|
||
|
||
.required-star {
|
||
font-size: 24rpx;
|
||
color: #FF19A0;
|
||
margin-right: 4rpx;
|
||
}
|
||
|
||
.add-pet-wrapper {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 16rpx;
|
||
margin-top: 20rpx;
|
||
flex-wrap: wrap;
|
||
padding-left: 12rpx;
|
||
}
|
||
|
||
.selected-pet-avatar {
|
||
position: relative;
|
||
width: 64rpx;
|
||
height: 64rpx;
|
||
}
|
||
|
||
.pet-avatar-img {
|
||
width: 64rpx;
|
||
height: 64rpx;
|
||
border-radius: 50%;
|
||
background-color: #f0f0f0;
|
||
}
|
||
|
||
.remove-pet-btn {
|
||
position: absolute;
|
||
top: -8rpx;
|
||
right: -8rpx;
|
||
width: 32rpx;
|
||
height: 32rpx;
|
||
border-radius: 50%;
|
||
background-color: #FF19A0;
|
||
color: #fff;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 24rpx;
|
||
line-height: 1;
|
||
border: 2rpx solid #fff;
|
||
}
|
||
|
||
.add-pet-btn {
|
||
width: 64rpx;
|
||
height: 64rpx;
|
||
border: 1rpx dashed #3D3D3D;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background: #EBEBEB;
|
||
}
|
||
|
||
.plus-icon {
|
||
font-size: 60rpx;
|
||
color: #999;
|
||
line-height: 1;
|
||
}
|
||
|
||
.add-pet-text {
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
margin-top: 8rpx;
|
||
}
|
||
|
||
.info-top-view {
|
||
width: 100%;
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.required {
|
||
color: #FF19A0;
|
||
font-size: 24rpx;
|
||
margin-right: 4rpx;
|
||
}
|
||
|
||
.title-view {
|
||
display: flex;
|
||
flex: 1;
|
||
align-items: center;
|
||
}
|
||
|
||
.info-view {
|
||
max-width: 60%;
|
||
}
|
||
|
||
.address-display {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
width: 100%;
|
||
|
||
}
|
||
|
||
.address-name-phone {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 16rpx;
|
||
margin-bottom: 8rpx;
|
||
}
|
||
|
||
.address-name-text {
|
||
font-size: 24rpx;
|
||
color: #333;
|
||
}
|
||
|
||
.address-phone-text {
|
||
font-size: 24rpx;
|
||
color: #333;
|
||
}
|
||
|
||
.address-detail-text {
|
||
font-size: 24rpx;
|
||
color: #333;
|
||
text-align: left;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
width: 100%;
|
||
}
|
||
|
||
.placeholder-text {
|
||
color: #9B939A;
|
||
font-size: 24rpx;
|
||
}
|
||
|
||
.form-input {
|
||
text-align: right;
|
||
font-size: 24rpx;
|
||
color: #333;
|
||
width: 100%;
|
||
}
|
||
|
||
.placeholder-class {
|
||
color: #9B939A;
|
||
}
|
||
|
||
.right-icon {
|
||
margin-left: 16rpx;
|
||
width: 10rpx;
|
||
height: 18rpx;
|
||
}
|
||
|
||
|
||
.service-time-header {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.service-time-title {
|
||
font-size: 24rpx;
|
||
color: #333;
|
||
margin-left: 4rpx;
|
||
}
|
||
|
||
.service-time-count {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-left: auto;
|
||
}
|
||
|
||
.count-text {
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
margin-right: 8rpx;
|
||
}
|
||
|
||
.service-time-content {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 16rpx;
|
||
margin-top: 16rpx;
|
||
}
|
||
|
||
.service-time-item {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
}
|
||
|
||
.service-time-label {
|
||
color: #3D3D3D;
|
||
flex-shrink: 0;
|
||
margin-right: 8rpx;
|
||
font-size: 24rpx;
|
||
line-height: 36rpx;
|
||
}
|
||
|
||
.service-time-value {
|
||
color: #3D3D3D;
|
||
flex: 1;
|
||
word-break: break-all;
|
||
font-size: 24rpx;
|
||
line-height: 36rpx;
|
||
}
|
||
|
||
|
||
.form-selector {
|
||
width: 100%;
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
justify-content: flex-end;
|
||
box-sizing: border-box;
|
||
margin-top: 0;
|
||
}
|
||
|
||
.selector-text {
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
flex: 1;
|
||
}
|
||
|
||
.selector-text.placeholder {
|
||
color: #999;
|
||
}
|
||
|
||
.selector-desc {
|
||
font-size: 24rpx;
|
||
}
|
||
|
||
.arrow-icon {
|
||
width: 10rpx;
|
||
height: 18rpx;
|
||
flex-shrink: 0;
|
||
margin-left: 8rpx;
|
||
}
|
||
|
||
.dispatch-fee-notice {
|
||
margin-top: 12rpx;
|
||
}
|
||
|
||
.nightFee {
|
||
color: #ff19a0;
|
||
font-family: PingFangSC;
|
||
font-size: 20rpx;
|
||
font-weight: normal;
|
||
margin-top: 20rpx;
|
||
}
|
||
|
||
.notice-text {
|
||
font-size: 24rpx;
|
||
color: #FF19A0;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.explain-image-section {
|
||
width: 100%;
|
||
margin-top: 20rpx;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.explain-image {
|
||
width: 100%;
|
||
height: auto;
|
||
display: block;
|
||
}
|
||
|
||
.key-notes-modal {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background-color: rgba(0, 0, 0, 0);
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: flex-end;
|
||
z-index: 1000;
|
||
animation: fadeIn 0.3s ease forwards;
|
||
}
|
||
|
||
.key-notes-modal .modal-content {
|
||
width: 100%;
|
||
background-color: #fff;
|
||
border-radius: 24rpx 24rpx 0 0;
|
||
padding: 40rpx;
|
||
padding-bottom: calc(40rpx + env(safe-area-inset-bottom));
|
||
box-sizing: border-box;
|
||
max-height: 80vh;
|
||
overflow-y: auto;
|
||
transform: translateY(100%);
|
||
animation: slideUp 0.3s ease forwards;
|
||
}
|
||
|
||
.key-notes-modal .modal-header {
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-bottom: 40rpx;
|
||
position: relative;
|
||
}
|
||
|
||
.key-notes-modal .modal-title {
|
||
font-size: 36rpx;
|
||
font-weight: 600;
|
||
color: #333;
|
||
flex: 1;
|
||
text-align: center;
|
||
}
|
||
|
||
.key-notes-modal .close-btn-placeholder {
|
||
width: 48rpx;
|
||
height: 48rpx;
|
||
}
|
||
|
||
.key-notes-modal .close-btn {
|
||
width: 48rpx;
|
||
height: 48rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.key-notes-modal .close-icon {
|
||
font-size: 48rpx;
|
||
color: #666;
|
||
line-height: 1;
|
||
}
|
||
|
||
.key-notes-modal .content-view {
|
||
width: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.key-notes-modal .input-wrapper {
|
||
position: relative;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.key-notes-modal .notes-input {
|
||
width: 100%;
|
||
min-height: 216rpx;
|
||
background-color: #F5F5F5;
|
||
border-radius: 12rpx;
|
||
padding: 24rpx;
|
||
box-sizing: border-box;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
.key-notes-modal .input-placeholder {
|
||
color: #999;
|
||
}
|
||
|
||
.key-notes-modal .char-count {
|
||
position: absolute;
|
||
bottom: 16rpx;
|
||
right: 24rpx;
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
}
|
||
|
||
.key-notes-modal .quick-input-section {
|
||
margin-bottom: 32rpx;
|
||
}
|
||
|
||
.key-notes-modal .quick-input-label {
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
margin-bottom: 16rpx;
|
||
display: block;
|
||
}
|
||
|
||
.key-notes-modal .quick-tags {
|
||
display: flex;
|
||
flex-direction: row;
|
||
flex-wrap: wrap;
|
||
gap: 16rpx;
|
||
}
|
||
|
||
.key-notes-modal .quick-tag {
|
||
padding: 12rpx 24rpx;
|
||
background-color: #fff;
|
||
border: 1px solid #E0E0E0;
|
||
border-radius: 8rpx;
|
||
}
|
||
|
||
.key-notes-modal .tag-text {
|
||
font-size: 24rpx;
|
||
color: #333;
|
||
}
|
||
|
||
.key-notes-modal .submit-btn {
|
||
width: 100%;
|
||
height: 96rpx;
|
||
background-color: #FF19A0;
|
||
border-radius: 12rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border-radius: 100px;
|
||
}
|
||
|
||
.key-notes-modal .submit-btn-text {
|
||
font-size: 32rpx;
|
||
color: #fff;
|
||
font-weight: 500;
|
||
}
|
||
|
||
@keyframes fadeIn {
|
||
from {
|
||
background-color: rgba(0, 0, 0, 0);
|
||
}
|
||
|
||
to {
|
||
background-color: rgba(0, 0, 0, 0.5);
|
||
}
|
||
}
|
||
|
||
@keyframes slideUp {
|
||
from {
|
||
transform: translateY(100%);
|
||
}
|
||
|
||
to {
|
||
transform: translateY(0);
|
||
}
|
||
}
|
||
|
||
/* 服务介绍弹窗样式 */
|
||
.service-info-modal {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background-color: rgba(0, 0, 0, 0.5);
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 1000;
|
||
animation: fadeIn 0.3s ease forwards;
|
||
}
|
||
|
||
.service-info-modal-content {
|
||
width: 600rpx;
|
||
background-color: #fff;
|
||
border-radius: 24rpx;
|
||
box-sizing: border-box;
|
||
overflow: hidden;
|
||
animation: scaleIn 0.3s ease forwards;
|
||
}
|
||
|
||
.service-info-header {
|
||
padding: 40rpx 40rpx 24rpx;
|
||
text-align: center;
|
||
}
|
||
|
||
.service-info-title {
|
||
font-size: 32rpx;
|
||
font-weight: 600;
|
||
color: #333333;
|
||
}
|
||
|
||
.service-info-body {
|
||
padding: 0rpx 40rpx;
|
||
min-height: 120rpx;
|
||
max-height: 400rpx;
|
||
overflow-y: auto;
|
||
padding-bottom: 40rpx;
|
||
}
|
||
|
||
.service-info-text {
|
||
font-size: 28rpx;
|
||
color: #333333;
|
||
line-height: 1.8;
|
||
word-break: break-all;
|
||
}
|
||
|
||
.service-info-footer {
|
||
padding: 0 40rpx 40rpx;
|
||
}
|
||
|
||
.service-info-btn {
|
||
width: 100%;
|
||
height: 88rpx;
|
||
background-color: #FF19A0;
|
||
border-radius: 44rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.service-info-btn-text {
|
||
font-size: 32rpx;
|
||
color: #fff;
|
||
}
|
||
|
||
@keyframes scaleIn {
|
||
from {
|
||
transform: scale(0.9);
|
||
opacity: 0;
|
||
}
|
||
|
||
to {
|
||
transform: scale(1);
|
||
opacity: 1;
|
||
}
|
||
}
|
||
|
||
.package-section {
|
||
padding: 32rpx 0;
|
||
border-bottom: 1px solid #ececec;
|
||
}
|
||
|
||
.package-header {
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
margin-bottom: 24rpx;
|
||
}
|
||
|
||
.package-header .required {
|
||
color: #FF19A0;
|
||
font-size: 28rpx;
|
||
margin-right: 4rpx;
|
||
}
|
||
|
||
.package-header .form-label {
|
||
font-size: 24rpx;
|
||
}
|
||
|
||
.package-scroll {
|
||
width: 100%;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.package-list {
|
||
display: flex;
|
||
flex-direction: row;
|
||
gap: 16rpx;
|
||
}
|
||
|
||
.package-card {
|
||
flex-shrink: 0;
|
||
width: 300rpx;
|
||
background-color: #F6F6F6;
|
||
border-radius: 16rpx;
|
||
padding: 16rpx;
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
box-sizing: border-box;
|
||
border: 1px solid transparent;
|
||
}
|
||
|
||
.package-card-selected {
|
||
border: 1px solid #FF19A0;
|
||
background: rgba(231, 64, 152, 0.1);
|
||
}
|
||
|
||
.package-info {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8rpx;
|
||
}
|
||
|
||
.package-name-row {
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
gap: 8rpx;
|
||
}
|
||
|
||
.package-name {
|
||
font-size: 24rpx;
|
||
color: #222222;
|
||
}
|
||
|
||
.info-icon {
|
||
width: 32rpx;
|
||
height: 32rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.package-duration {
|
||
font-size: 22rpx;
|
||
color: #3D3D3D;
|
||
}
|
||
|
||
.package-price-row {
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-top: 4rpx;
|
||
}
|
||
|
||
.price-content {
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: baseline;
|
||
gap: 4rpx;
|
||
}
|
||
|
||
.package-price {
|
||
font-size: 24rpx;
|
||
color: #FF19A0;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.package-unit {
|
||
font-size: 24rpx;
|
||
color: #FF19A0;
|
||
}
|
||
|
||
.package-radio {
|
||
width: 36rpx;
|
||
height: 36rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.bottom-fixed-wrap {
|
||
position: fixed;
|
||
bottom: 0;
|
||
left: 0;
|
||
right: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
z-index: 100;
|
||
}
|
||
|
||
.tip-notice-bar {
|
||
background-color: #FFE5F0;
|
||
padding: 12rpx 20rpx;
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
gap: 12rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.tip-notice-icon {
|
||
width: 30rpx;
|
||
height: 30rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.tip-notice-text {
|
||
color: #FF19A0;
|
||
font-size: 24rpx;
|
||
flex: 1;
|
||
}
|
||
|
||
.bottom-action-bar {
|
||
background-color: #fff;
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 24rpx 32rpx;
|
||
padding-bottom: calc(24rpx + env(safe-area-inset-bottom));
|
||
box-sizing: border-box;
|
||
border-top: 1px solid #f0f0f0;
|
||
}
|
||
|
||
.price-info {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 16rpx;
|
||
flex: 1;
|
||
}
|
||
|
||
.estimate-price {
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: baseline;
|
||
gap: 8rpx;
|
||
}
|
||
|
||
.estimate-label {
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
}
|
||
|
||
.estimate-amount {
|
||
font-size: 48rpx;
|
||
color: #FF19A0;
|
||
}
|
||
|
||
.member-price-row {
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
gap: 4rpx;
|
||
}
|
||
|
||
.vip-price-icon {
|
||
width: 86rpx;
|
||
height: 28rpx;
|
||
}
|
||
|
||
.member-price-amount {
|
||
font-size: 28rpx;
|
||
color: #3D3D3D;
|
||
}
|
||
|
||
.next-step-btn {
|
||
background-color: #FF19A0;
|
||
border-radius: 50rpx;
|
||
padding: 20rpx 60rpx;
|
||
margin-left: 32rpx;
|
||
}
|
||
|
||
.next-step-text {
|
||
font-size: 32rpx;
|
||
color: #fff;
|
||
font-weight: 500;
|
||
}
|
||
</style>
|