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.

1512 lines
36 KiB

2 months ago
<template>
<view class="confirm-container">
<scroll-view class="content-scroll" scroll-y>
<!-- 收货地址 -->
<view class="address-section">
<!-- 有地址时显示 -->
<view class="section-header" @click="selectAddress" v-if="address.name">
<view class="address-info">
<view class="user-info">
<text class="username">{{ address.name }}</text>
<text class="phone">{{ formatPhone(address.phone) }}</text>
<text class="default-tag" v-if="address.isDefault">默认地址</text>
</view>
<view class="address-detail">
<text>{{ address.fullAddress }}</text>
</view>
</view>
<uni-icons type="right" size="16" color="#c0c4cc" />
</view>
<!-- 没有地址时显示 -->
<view class="empty-address" @click="selectAddress" v-else>
<view class="empty-address-content">
<uni-icons type="location" size="24" color="#c0c4cc" />
<view class="empty-address-text">
<text class="empty-title">请选择收货地址</text>
<text class="empty-tip">点击添加收货地址信息</text>
</view>
</view>
<uni-icons type="right" size="16" color="#c0c4cc" />
</view>
</view>
<!-- 预约日期 -->
<view class="date-section">
<view class="section-title">
<text>预约日期</text>
<text class="required">*</text>
</view>
<view class="date-picker-container">
<uni-datetime-picker
v-model="selectedDate"
type="date"
:clear-icon="false"
placeholder="请选择预约日期"
@change="onDateChange"
>
<view class="date-input">
<text class="date-text" :class="{ placeholder: !selectedDate }">
{{ selectedDate || "请选择预约日期" }}
</text>
<uni-icons type="calendar" size="18" color="#c0c4cc" />
</view>
</uni-datetime-picker>
</view>
</view>
<!-- 商品信息 -->
<view class="goods-section">
<view class="section-title">
<text>IP资产供应商{{ supplier || "苏州XXX博物馆" }}</text>
</view>
2 months ago
<view
class="goods-card"
v-for="(item, index) in goodsList"
:key="index"
>
2 months ago
<image
class="goods-image"
2 months ago
:src="item.image || '/static/image/goods-default.jpg'"
2 months ago
mode="aspectFill"
/>
<view class="goods-info">
<text class="goods-name">{{
2 months ago
item.name || "食在苏州 | 世界美食之都巡礼+实物探真"
2 months ago
}}</text>
2 months ago
<!-- 规格列表 -->
<view class="specifications-list">
<view
class="spec-item"
v-for="(spec, specIndex) in item.specifications"
:key="specIndex"
@click="selectSpecification(index, specIndex)"
>
<view class="spec-content">
<text class="spec-label">规格{{ specIndex + 1 }}</text>
<text
class="spec-text"
:class="{ placeholder: !spec.selectedSpec }"
>
{{ spec.selectedSpec || "请选择规格" }}
</text>
</view>
<uni-icons type="right" size="14" color="#c0c4cc" />
</view>
<!-- 添加规格按钮 -->
<view
class="add-spec-btn"
v-if="item.specifications.length < item.quantity"
@click="addSpecification(index)"
>
<text class="add-spec-text">+ 添加规格</text>
</view>
</view>
<text class="goods-price">¥{{ item.price || "699.00" }}</text>
2 months ago
</view>
</view>
</view>
<!-- 履约方式 -->
<!-- <view class="delivery-section">
<view class="section-row" @click="selectDeliveryMethod">
<text class="section-label">履约方式</text>
<view class="section-value">
<text :class="{ placeholder: !deliveryMethod }">
{{ deliveryMethod || "预约发货+到店核销 >" }}
</text>
</view>
</view>
</view> -->
<!-- 备注 -->
<view class="note-section">
<view class="section-row">
<text class="section-label">备注</text>
<view class="note-input">
<input
v-model="note"
placeholder="选填"
placeholder-class="placeholder"
maxlength="200"
/>
</view>
</view>
</view>
<!-- 费用明细 -->
<view class="cost-section">
<view class="cost-item">
<text class="cost-label">商品金额</text>
<text class="cost-value">¥{{ goodsInfo.price || "699.00" }}</text>
</view>
<view class="cost-item">
<text class="cost-label">运费</text>
<text class="cost-value">{{ shipping || "预约发货时计算" }}</text>
</view>
<view class="cost-item">
<text class="cost-label">优惠券</text>
<text class="cost-value coupon">{{ coupon || "无可用 >" }}</text>
</view>
</view>
<view class="submit-section-content" style="height: 230rpx"> </view>
</scroll-view>
2 months ago
<!-- 规格选择弹窗 -->
<uni-popup ref="specificationPopup" type="bottom">
<view class="specification-popup">
<view class="popup-header">
<text class="popup-title">选择规格</text>
<text class="popup-close" @click="closeSpecificationPopup">×</text>
</view>
<view class="popup-content">
<!-- 商品信息 -->
<view class="goods-preview">
<image
class="preview-image"
:src="currentGoods.image || '/static/image/goods-default.jpg'"
mode="aspectFill"
/>
<view class="preview-info">
<text class="preview-name">{{ currentGoods.name }}</text>
<!-- <text class="preview-price">¥{{ currentGoods.price }}</text> -->
</view>
</view>
<!-- 一级规格选择 -->
<view class="spec-section">
<text class="spec-title">
{{ specificationData.level1Title || "规格" }}
<text class="required">*</text>
</text>
<view class="spec-options">
<view
v-for="(option, index) in specificationData.level1Options"
:key="index"
:class="['spec-option', { active: selectedLevel1 === index }]"
@click="selectLevel1(index)"
>
<text class="option-text">{{ option.name }}</text>
</view>
</view>
</view>
<!-- 二级规格选择 -->
<view
class="spec-section"
v-if="
specificationData.level2Options &&
specificationData.level2Options.length > 0
"
>
<text class="spec-title">
{{ specificationData.level2Title || "子规格" }}
<text class="required">*</text>
</text>
<view class="spec-options">
<view
v-for="(option, index) in specificationData.level2Options"
:key="index"
:class="['spec-option', { active: selectedLevel2 === index }]"
@click="selectLevel2(index)"
>
<text class="option-text">{{ option.name }}</text>
</view>
</view>
</view>
<!-- 数量选择 -->
<!-- <view class="quantity-section">
<text class="quantity-title">数量</text>
<view class="quantity-control">
<text class="quantity-btn" @click="decreaseQuantity">-</text>
<text class="quantity-value">{{ quantity }}</text>
<text class="quantity-btn" @click="increaseQuantity">+</text>
</view>
</view> -->
</view>
<!-- 确认按钮 -->
<view class="popup-actions">
<button
class="confirm-spec-btn"
@click="confirmSpecification"
:disabled="!canConfirmSpec"
>
确认规格
</button>
</view>
</view>
</uni-popup>
2 months ago
<!-- 底部提交区域 -->
<view
class=" "
style="position: fixed; width: 100%; bottom: 0; z-index: 98"
>
<view class="submit-section">
<view class="total-price">
<text class="total-amount">¥{{ totalAmount || "699.00" }}</text>
</view>
<button class="submit-btn" @click="submitOrder">提交订单</button>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
// 收货地址信息
address: {
name: "",
phone: "",
fullAddress: "",
isDefault: false,
},
// 选中的日期
selectedDate: "",
// 商品信息
goodsInfo: {
id: "",
name: "",
desc: "",
price: "",
image: "",
},
2 months ago
// 商品列表
goodsList: [],
2 months ago
// 供应商
supplier: "",
// 履约方式
deliveryMethod: "",
// 备注
note: "",
// 运费
shipping: "",
// 优惠券
coupon: "",
// 总金额
totalAmount: "",
2 months ago
// 规格选择相关
currentGoodsIndex: -1,
currentSpecIndex: -1,
currentGoods: {},
specificationData: {
level1Title: "",
level1Options: [],
level2Title: "",
level2Options: [],
},
selectedLevel1: -1,
selectedLevel2: -1,
quantity: 1,
2 months ago
};
},
onLoad(options) {
// 接收页面参数
if (options.goodsId) {
this.loadGoodsInfo(options.goodsId);
}
if (options.goodsName) {
this.goodsInfo.name = decodeURIComponent(options.goodsName);
}
this.loadDefaultAddress();
// 监听地址选择事件
uni.$on("addressSelected", this.handleAddressSelected);
},
onShow() {
// 从地址选择页面返回时,优先检查用户选择的地址
const hasSelectedAddress = this.checkSelectedAddress();
// 如果没有选择地址且当前也没有地址,才加载默认地址
if (!hasSelectedAddress && !this.address.id) {
this.loadDefaultAddress();
}
},
onUnload() {
// 移除事件监听
uni.$off("addressSelected", this.handleAddressSelected);
},
2 months ago
computed: {
// 是否可以确认规格
canConfirmSpec() {
// 必须选择一级规格
if (this.selectedLevel1 < 0) {
return false;
}
// 如果有二级规格选项,则必须选择二级规格
if (
this.specificationData.level2Options &&
this.specificationData.level2Options.length > 0
) {
return this.selectedLevel2 >= 0;
}
// 如果没有二级规格选项,只需要选择一级规格即可
return true;
},
},
2 months ago
methods: {
// 返回上一页
goBack() {
uni.navigateBack();
},
// 处理地址选择事件
handleAddressSelected(data) {
if (data.fromPage === "orderConfirm") {
this.updateAddressInfo(data.address);
console.log("地址已更新:", this.address);
}
},
// 更新地址信息的统一方法
updateAddressInfo(addressData) {
this.address = {
id: addressData.id,
name: addressData.name,
phone: addressData.tel,
fullAddress: addressData.address || this.getFullAddress(addressData),
isDefault: addressData.is_default == 1,
};
},
// 检查storage中的选中地址
checkSelectedAddress() {
try {
const selectedAddress = uni.getStorageSync("selectedAddress");
if (selectedAddress) {
this.updateAddressInfo(selectedAddress);
// 清除storage
uni.removeStorageSync("selectedAddress");
return true; // 表示找到了选中的地址
}
return false;
} catch (error) {
console.error("读取选中地址失败:", error);
return false;
}
},
// 获取完整地址
getFullAddress(addressData) {
const province = addressData.province_text || "";
const city = addressData.city_text || "";
const district = addressData.district_text || "";
const detail = addressData.detail_addr || "";
return `${province}${city}${district}${detail}`;
},
// 格式化手机号
formatPhone(phone) {
if (!phone) return "";
return phone.replace(/(\d{3})\d{4}(\d{4})/, "$1****$2");
},
// 选择收货地址
selectAddress() {
uni.navigateTo({
url: "/subPackages/user/travelerList?from=orderConfirm",
});
},
// 日期变化回调
onDateChange(date) {
this.selectedDate = date;
console.log("选择的日期:", date);
},
// 选择履约方式
selectDeliveryMethod() {
const itemList = ["预约发货+到店核销", "预约发货+快递配送", "到店自提"];
uni.showActionSheet({
itemList: itemList,
success: (res) => {
this.deliveryMethod = itemList[res.tapIndex];
console.log("选择的履约方式:", this.deliveryMethod);
},
fail: (err) => {
console.log("取消选择履约方式");
},
});
},
// 加载商品信息
async loadGoodsInfo(goodsId) {
try {
// 这里调用实际的API接口获取商品详情
const goodsData = await this.getGoodsDetail(goodsId);
this.goodsInfo = goodsData;
this.supplier = goodsData.supplier;
2 months ago
// 初始化商品列表
this.goodsList = [
{
id: goodsData.id,
name: goodsData.name,
price: goodsData.price,
image: goodsData.image,
quantity: 3, // 默认数量为3,可以根据实际需求调整
specifications: [
{
selectedSpec: "",
selectedLevel1: -1,
selectedLevel2: -1,
},
],
},
];
this.calculateTotalAmount();
2 months ago
} catch (error) {
console.error("加载商品信息失败:", error);
2 months ago
// 使用模拟数据
this.loadMockGoodsData();
2 months ago
}
},
2 months ago
// 加载模拟商品数据
loadMockGoodsData() {
this.goodsList = [
{
id: 1,
name: "食在苏州 | 世界美食之都巡礼+实物探真",
price: "699.00",
image: "/static/image/goods-sample.jpg",
quantity: 3,
specifications: [
{
selectedSpec: "",
selectedLevel1: -1,
selectedLevel2: -1,
},
],
},
{
id: 2,
name: "苏州园林文化体验套餐",
price: "899.00",
image: "/static/image/goods-sample.jpg",
quantity: 2,
specifications: [
{
selectedSpec: "",
selectedLevel1: -1,
selectedLevel2: -1,
},
],
},
];
this.calculateTotalAmount();
},
2 months ago
// 加载默认地址
async loadDefaultAddress() {
try {
2 months ago
this.Post({
isDefault:1
},
"/framework/concat/selectList",
'DES'
).then((res) => {
if(res.data){
this.updateAddressInfo(res.data[0]);
}
});
2 months ago
// 这里调用实际的API接口获取默认地址
} catch (error) {
console.error("加载默认地址失败:", error);
}
},
2 months ago
// 选择规格
selectSpecification(goodsIndex, specIndex) {
this.currentGoodsIndex = goodsIndex;
this.currentSpecIndex = specIndex;
this.currentGoods = this.goodsList[goodsIndex];
this.loadSpecificationData(this.currentGoods.id);
// 回显之前的选择
const currentSpec = this.currentGoods.specifications[specIndex];
this.selectedLevel1 = currentSpec.selectedLevel1 || -1;
this.selectedLevel2 = currentSpec.selectedLevel2 || -1;
this.quantity = this.currentGoods.quantity || 1;
this.$refs.specificationPopup.open();
},
// 添加规格
addSpecification(goodsIndex) {
const goods = this.goodsList[goodsIndex];
if (goods.specifications.length < goods.quantity) {
goods.specifications.push({
selectedSpec: "",
selectedLevel1: -1,
selectedLevel2: -1,
});
}
},
// 关闭规格选择弹窗
closeSpecificationPopup() {
this.$refs.specificationPopup.close();
this.resetSpecificationData();
},
// 重置规格选择数据
resetSpecificationData() {
this.selectedLevel1 = -1;
this.selectedLevel2 = -1;
this.quantity = 1; // 保持默认数量为1
},
// 加载规格数据
async loadSpecificationData(goodsId) {
try {
const specData = await this.getSpecificationData(goodsId);
this.specificationData = specData;
// 如果有之前的选择,需要更新二级规格选项
if (
this.selectedLevel1 >= 0 &&
this.specificationData.level1Options[this.selectedLevel1]
) {
const level1Option =
this.specificationData.level1Options[this.selectedLevel1];
if (level1Option.children) {
this.specificationData.level2Options = level1Option.children;
} else {
this.specificationData.level2Options = [];
}
}
} catch (error) {
console.error("加载规格数据失败:", error);
// 使用模拟数据
this.loadMockSpecificationData();
}
},
// 选择一级规格
selectLevel1(index) {
this.selectedLevel1 = index;
this.selectedLevel2 = -1; // 重置二级选择
// 根据一级选择更新二级选项
if (
this.specificationData.level1Options[index] &&
this.specificationData.level1Options[index].children
) {
this.specificationData.level2Options =
this.specificationData.level1Options[index].children;
} else {
this.specificationData.level2Options = [];
}
},
// 选择二级规格
selectLevel2(index) {
this.selectedLevel2 = index;
},
// 减少数量
decreaseQuantity() {
if (this.quantity > 1) {
this.quantity--;
}
},
// 增加数量
increaseQuantity() {
this.quantity++;
},
// 确认规格选择
confirmSpecification() {
// 校验一级规格
if (this.selectedLevel1 < 0) {
uni.showToast({
title: "请选择一级规格",
icon: "none",
});
return;
}
// 校验二级规格(如果有二级规格选项)
if (
this.specificationData.level2Options &&
this.specificationData.level2Options.length > 0
) {
if (this.selectedLevel2 < 0) {
uni.showToast({
title: "请选择二级规格",
icon: "none",
});
return;
}
}
const level1Option =
this.specificationData.level1Options[this.selectedLevel1];
const level2Option =
this.selectedLevel2 >= 0
? this.specificationData.level2Options[this.selectedLevel2]
: null;
// 构建规格文本
let specText = level1Option.name;
if (level2Option) {
specText += ` / ${level2Option.name}`;
}
// if (this.quantity > 1) {
// specText += ` × ${this.quantity}`;
// }
// 更新商品规格信息
this.goodsList[this.currentGoodsIndex].specifications[
this.currentSpecIndex
].selectedSpec = specText;
this.goodsList[this.currentGoodsIndex].specifications[
this.currentSpecIndex
].selectedLevel1 = this.selectedLevel1;
this.goodsList[this.currentGoodsIndex].specifications[
this.currentSpecIndex
].selectedLevel2 = this.selectedLevel2;
// 更新价格
let price = level1Option.price || this.currentGoods.price;
if (level2Option && level2Option.price) {
price = level2Option.price;
}
this.goodsList[this.currentGoodsIndex].price = price;
// 重新计算总金额
this.calculateTotalAmount();
this.closeSpecificationPopup();
uni.showToast({
title: "规格选择成功",
icon: "success",
});
},
// 计算总金额
calculateTotalAmount() {
let total = 0;
this.goodsList.forEach((item) => {
if (item.price) {
// 计算已选择规格的数量
const selectedSpecsCount = item.specifications.filter(
(spec) => spec.selectedSpec
).length;
total += parseFloat(item.price) * selectedSpecsCount;
}
});
this.totalAmount = total.toFixed(2);
},
// 加载模拟规格数据
loadMockSpecificationData() {
this.specificationData = {
level1Title: "套餐类型",
level1Options: [
{
name: "标准套餐",
price: "699.00",
children: [
{ name: "单人套餐", price: "699.00" },
{ name: "双人套餐", price: "1299.00" },
{ name: "家庭套餐", price: "1899.00" },
],
},
{
name: "豪华套餐",
price: "999.00",
children: [
{ name: "VIP单人", price: "999.00" },
{ name: "VIP双人", price: "1799.00" },
{ name: "VIP家庭", price: "2599.00" },
],
},
{
name: "定制套餐",
price: "1299.00",
children: [
{ name: "定制单人", price: "1299.00" },
{ name: "定制双人", price: "2299.00" },
],
},
],
level2Title: "具体套餐",
level2Options: [],
};
},
2 months ago
// 提交订单
async submitOrder() {
// 验证必填项
if (!this.selectedDate) {
uni.showToast({
title: "请选择预约日期",
icon: "none",
});
return;
}
2 months ago
// 验证所有商品是否已选择规格
const unselectedGoods = this.goodsList.filter((item) => {
// 检查是否有规格未选择
return item.specifications.some((spec) => !spec.selectedSpec);
});
if (unselectedGoods.length > 0) {
2 months ago
uni.showToast({
2 months ago
title: "请选择所有商品的规格",
2 months ago
icon: "none",
});
return;
}
if (!this.address.name) {
uni.showToast({
title: "请选择收货地址",
icon: "none",
});
return;
}
try {
uni.showLoading({
title: "提交中...",
});
const orderData = {
goodsId: this.goodsInfo.id,
addressId: this.address.id,
deliveryDate: this.selectedDate,
deliveryMethod: this.deliveryMethod,
note: this.note,
totalAmount: this.totalAmount,
};
const result = await this.createOrder(orderData);
uni.hideLoading();
if (result.success) {
uni.showToast({
title: "订单提交成功",
icon: "success",
});
// 跳转到订单详情或订单列表
setTimeout(() => {
uni.redirectTo({
url: "/subPackages/orderQy/detail?orderId=" + result.orderId,
});
}, 1500);
}
} catch (error) {
uni.hideLoading();
console.error("提交订单失败:", error);
uni.showToast({
title: "提交失败,请重试",
icon: "none",
});
}
},
// API接口 - 获取商品详情
async getGoodsDetail(goodsId) {
// 模拟API数据
return new Promise((resolve) => {
setTimeout(() => {
resolve({
id: goodsId,
name: "食在苏州 | 世界美食之都巡礼+实物探真",
desc: "商品规格信息描述",
price: "699.00",
image: "/static/image/goods-sample.jpg",
supplier: "苏州XXX博物馆",
});
}, 500);
});
},
2 months ago
// API接口 - 获取规格数据
async getSpecificationData(goodsId) {
2 months ago
// 模拟API数据
return new Promise((resolve) => {
setTimeout(() => {
resolve({
2 months ago
level1Title: "套餐类型",
level1Options: [
{
name: "标准套餐",
price: "699.00",
children: [
{ name: "单人套餐", price: "699.00" },
{ name: "双人套餐", price: "1299.00" },
{ name: "家庭套餐", price: "1899.00" },
],
},
{
name: "豪华套餐",
price: "999.00",
children: [
{ name: "VIP单人", price: "999.00" },
{ name: "VIP双人", price: "1799.00" },
{ name: "VIP家庭", price: "2599.00" },
],
},
{
name: "定制套餐",
price: "1299.00",
children: [
{ name: "定制单人", price: "1299.00" },
{ name: "定制双人", price: "2299.00" },
],
},
],
level2Title: "具体套餐",
level2Options: [],
2 months ago
});
2 months ago
}, 300);
2 months ago
});
},
2 months ago
2 months ago
// API接口 - 创建订单
async createOrder(orderData) {
// 模拟API调用
return new Promise((resolve) => {
setTimeout(() => {
resolve({
success: true,
orderId: "EQ" + Date.now(),
});
}, 1000);
});
},
},
};
</script>
<style lang="scss" scoped>
// 主题色彩变量
$primary-color: #667eea;
$secondary-color: #f8f9fa;
$text-primary: #2d3748;
$text-secondary: #718096;
$text-muted: #a0aec0;
$border-color: #e2e8f0;
$success-color: #48bb78;
$warning-color: #ed8936;
$danger-color: #f56565;
$bg-light: #f7fafc;
.confirm-container {
height: 100vh;
background-color: $bg-light;
display: flex;
flex-direction: column;
}
.content-scroll {
flex: 1;
padding: 20rpx;
width: 710rpx;
}
// 通用section样式
.section-header,
.section-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 24rpx 30rpx;
background-color: #ffffff;
border-radius: 16rpx;
margin-bottom: 20rpx;
}
.section-title {
font-size: 28rpx;
color: $text-primary;
font-weight: 600;
margin-bottom: 16rpx;
.required {
color: $danger-color;
margin-left: 4rpx;
}
}
// 收货地址
.address-section {
margin-bottom: 24rpx;
}
.address-info {
flex: 1;
}
.user-info {
display: flex;
align-items: center;
margin-bottom: 12rpx;
gap: 16rpx;
}
.username {
font-size: 28rpx;
color: $text-primary;
font-weight: 600;
}
.phone {
font-size: 24rpx;
color: $text-secondary;
}
.default-tag {
font-size: 20rpx;
color: $primary-color;
background-color: rgba(102, 126, 234, 0.1);
padding: 4rpx 12rpx;
border-radius: 12rpx;
}
.address-detail {
font-size: 26rpx;
color: $text-secondary;
line-height: 1.4;
}
// 空地址状态
.empty-address {
display: flex;
justify-content: space-between;
align-items: center;
padding: 24rpx 30rpx;
background-color: #ffffff;
border-radius: 16rpx;
margin-bottom: 20rpx;
border: 2rpx dashed $border-color;
transition: all 0.3s ease;
&:active {
background-color: rgba(102, 126, 234, 0.02);
border-color: $primary-color;
}
}
.empty-address-content {
display: flex;
align-items: center;
gap: 16rpx;
}
.empty-address-text {
display: flex;
flex-direction: column;
gap: 6rpx;
}
.empty-title {
font-size: 28rpx;
color: $text-primary;
font-weight: 500;
}
.empty-tip {
font-size: 24rpx;
color: $text-muted;
}
// 预约日期
.date-section {
margin-bottom: 24rpx;
}
.date-picker-container {
background-color: #ffffff;
border-radius: 16rpx;
padding: 24rpx 30rpx;
}
.date-input {
display: flex;
justify-content: space-between;
align-items: center;
}
.date-text {
font-size: 28rpx;
color: $text-primary;
&.placeholder {
color: $text-muted;
}
}
// 商品信息
.goods-section {
margin-bottom: 24rpx;
}
.goods-card {
display: flex;
background-color: #ffffff;
border-radius: 16rpx;
padding: 24rpx;
gap: 20rpx;
}
.goods-image {
width: 120rpx;
height: 120rpx;
border-radius: 12rpx;
flex-shrink: 0;
}
.goods-info {
flex: 1;
display: flex;
flex-direction: column;
gap: 12rpx;
}
.goods-name {
font-size: 26rpx;
color: $text-primary;
font-weight: 600;
line-height: 1.4;
}
.goods-desc {
font-size: 24rpx;
color: $text-secondary;
line-height: 1.3;
}
.goods-price {
font-size: 32rpx;
color: $danger-color;
font-weight: 600;
margin-top: auto;
}
// 履约方式
.delivery-section {
margin-bottom: 24rpx;
}
.section-label {
font-size: 28rpx;
color: $text-primary;
font-weight: 500;
}
.section-value {
display: flex;
align-items: center;
text {
font-size: 26rpx;
color: $text-primary;
&.placeholder {
color: $text-muted;
}
}
}
// 备注
.note-section {
margin-bottom: 24rpx;
.section-row {
align-items: flex-start;
}
}
.note-input {
flex: 1;
margin-left: 40rpx;
input {
font-size: 26rpx;
color: $text-primary;
text-align: right;
width: 100%;
}
.placeholder {
color: $text-muted;
}
}
// 费用明细
.cost-section {
background-color: #ffffff;
border-radius: 16rpx;
padding: 24rpx 30rpx;
margin-bottom: 24rpx;
}
.cost-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16rpx 0;
&:not(:last-child) {
border-bottom: 1px solid $border-color;
}
}
.cost-label {
font-size: 26rpx;
color: $text-primary;
}
.cost-value {
font-size: 26rpx;
color: $text-primary;
&.coupon {
color: $text-muted;
}
}
// 底部提交区域
.submit-section {
flex-shrink: 0; // 防止被压缩
display: flex;
align-items: center;
justify-content: space-between;
padding: 24rpx 30rpx;
background-color: #ffffff;
border-top: 1px solid $border-color;
box-shadow: 0 -2rpx 12rpx rgba(0, 0, 0, 0.04);
// 添加安全区域适配
padding-bottom: calc(24rpx + env(safe-area-inset-bottom));
}
.submit-section-content {
padding-bottom: calc(24rpx + env(safe-area-inset-bottom));
}
.total-price {
flex: 1;
}
.total-amount {
font-size: 36rpx;
color: $danger-color;
font-weight: 600;
font-family: "SF Mono", "Monaco", "Cascadia Code", monospace;
}
.submit-btn {
background-color: $text-primary;
color: #ffffff;
border: none;
border-radius: 32rpx;
padding: 4rpx 48rpx;
font-size: 28rpx;
font-weight: 600;
transition: all 0.3s ease;
&:active {
transform: scale(0.95);
background-color: rgba(45, 55, 72, 0.8);
}
}
2 months ago
// 规格选择弹窗样式
.specification-popup {
background: white;
border-radius: 24rpx 24rpx 0 0;
max-height: 80vh;
overflow: hidden;
}
.popup-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 32rpx 30rpx 24rpx;
border-bottom: 1rpx solid $border-color;
.popup-title {
font-size: 32rpx;
font-weight: 600;
color: $text-primary;
}
.popup-close {
font-size: 40rpx;
color: $text-muted;
line-height: 1;
padding: 8rpx;
cursor: pointer;
transition: color 0.3s;
&:active {
color: $text-secondary;
}
}
}
.popup-content {
padding: 30rpx;
max-height: 60vh;
overflow-y: auto;
}
// 商品预览
.goods-preview {
display: flex;
align-items: center;
gap: 20rpx;
padding: 24rpx;
background: $bg-light;
border-radius: 16rpx;
margin-bottom: 30rpx;
.preview-image {
width: 80rpx;
height: 80rpx;
border-radius: 12rpx;
flex-shrink: 0;
}
.preview-info {
flex: 1;
display: flex;
flex-direction: column;
gap: 8rpx;
}
.preview-name {
font-size: 26rpx;
color: $text-primary;
font-weight: 500;
line-height: 1.3;
}
.preview-price {
font-size: 28rpx;
color: $danger-color;
font-weight: 600;
}
}
// 规格选择区域
.spec-section {
margin-bottom: 30rpx;
.spec-title {
font-size: 28rpx;
color: $text-primary;
font-weight: 600;
margin-bottom: 20rpx;
display: block;
.required {
color: $danger-color;
margin-left: 4rpx;
}
}
.spec-options {
display: flex;
flex-wrap: wrap;
gap: 16rpx;
}
.spec-option {
padding: 16rpx 24rpx;
border: 2rpx solid $border-color;
border-radius: 12rpx;
background: white;
transition: all 0.3s ease;
cursor: pointer;
&:active {
transform: scale(0.95);
}
&.active {
border-color: $primary-color;
background: rgba(102, 126, 234, 0.1);
}
.option-text {
font-size: 26rpx;
color: $text-primary;
font-weight: 500;
}
}
}
// 数量选择
.quantity-section {
display: flex;
justify-content: space-between;
align-items: center;
padding: 24rpx 0;
border-top: 1rpx solid $border-color;
.quantity-title {
font-size: 28rpx;
color: $text-primary;
font-weight: 600;
}
.quantity-control {
display: flex;
align-items: center;
gap: 20rpx;
}
.quantity-btn {
width: 60rpx;
height: 60rpx;
border: 2rpx solid $border-color;
border-radius: 12rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
color: $text-primary;
font-weight: 600;
background: white;
transition: all 0.3s ease;
cursor: pointer;
&:active {
background: $bg-light;
border-color: $primary-color;
}
}
.quantity-value {
font-size: 28rpx;
color: $text-primary;
font-weight: 600;
min-width: 60rpx;
text-align: center;
}
}
// 确认按钮
.popup-actions {
padding: 24rpx 30rpx 40rpx;
border-top: 1rpx solid $border-color;
background: white;
.confirm-spec-btn {
width: 100%;
height: 88rpx;
background: $primary-color;
color: white;
border: none;
border-radius: 44rpx;
font-size: 32rpx;
font-weight: 600;
transition: all 0.3s ease;
&:active {
transform: scale(0.98);
background: rgba(102, 126, 234, 0.8);
}
&:disabled {
background: $text-muted;
cursor: not-allowed;
}
}
}
// 商品卡片中的规格信息样式
.specifications-list {
margin: 12rpx 0;
}
.spec-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16rpx 0;
border-bottom: 1rpx solid #f0f0f0;
&:last-child {
border-bottom: none;
}
}
.spec-content {
flex: 1;
display: flex;
flex-direction: column;
gap: 8rpx;
}
.spec-label {
font-size: 22rpx;
color: $text-secondary;
font-weight: 500;
}
.spec-text {
font-size: 24rpx;
color: $text-primary;
font-weight: 500;
&.placeholder {
color: $text-muted;
}
}
.add-spec-btn {
display: flex;
align-items: center;
justify-content: center;
padding: 20rpx 0;
margin-top: 8rpx;
border: 2rpx dashed $border-color;
border-radius: 12rpx;
background: rgba(102, 126, 234, 0.02);
transition: all 0.3s ease;
&:active {
background: rgba(102, 126, 234, 0.1);
border-color: $primary-color;
}
}
.add-spec-text {
font-size: 24rpx;
color: $primary-color;
font-weight: 500;
}
2 months ago
</style>