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.
2218 lines
56 KiB
2218 lines
56 KiB
<template>
|
|
<!-- 解决滚动穿透 -->
|
|
<page-meta
|
|
:page-style="'overflow:' + (popShow ? 'hidden' : 'visible')"
|
|
></page-meta>
|
|
<view class="bg" v-if="info">
|
|
<!-- <view class="sendwayArea" :style="{'width': isPost==3?'340rpx':'170rpx'}" v-if="isPost>=1&&isPost<=3">
|
|
<view v-if="isPost==1||isPost==3" :class="['sendway-item',info.is_post==1?'active':'']"
|
|
@click="info.is_post=1" style="left: -2rpx;">邮寄配送</view>
|
|
<view v-if="isPost==2||isPost==3" :class="['sendway-item',info.is_post==2?'active':'']"
|
|
@click="info.is_post=2" style="right: -2rpx;">到店自提</view>
|
|
|
|
</view> -->
|
|
|
|
<!-- 邮寄 -->
|
|
<view class="address" style="margin-bottom: 36rpx">
|
|
<view class="a-title">
|
|
<view>收货地址</view>
|
|
<view>
|
|
<view
|
|
class="more-person flex-center"
|
|
v-if="addressList.length > 0"
|
|
@click="changeAddressPopup('open', '', null)"
|
|
>
|
|
更多<uni-icons
|
|
style="width: 14rpx"
|
|
type="right"
|
|
size="14"
|
|
></uni-icons>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="btn-box">
|
|
<view class="contacts box" v-if="contacts">
|
|
<view class="contacts-left">
|
|
<view class="name-phone">
|
|
<view class="name">{{ contacts.name }}</view>
|
|
<view class="phone">{{ contacts.tel }}</view>
|
|
</view>
|
|
<view class="adds text-overflowRows">{{
|
|
contacts.province_text +
|
|
contacts.city_text +
|
|
contacts.district_text +
|
|
contacts.detail_addr
|
|
}}</view>
|
|
</view>
|
|
<image
|
|
@click="changeAddressAddPopup('open', '', contacts)"
|
|
:src="
|
|
showImg('/uploads/20250514/dd77d7706bc9bffd2bb928d1772e8413.png')
|
|
"
|
|
mode="aspectFill"
|
|
></image>
|
|
</view>
|
|
<view
|
|
v-else
|
|
class="a-img flex-center"
|
|
@click.stop="changeAddressAddPopup('open', '', {})"
|
|
>
|
|
<uni-icons style="width: 32rpx" type="plusempty" size="14"></uni-icons
|
|
>添加
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<!-- 按供应商分组显示商品 -->
|
|
<view
|
|
v-for="(supplierGroup, supplierIndex) in groupedGoods"
|
|
:key="supplierGroup.supplierId"
|
|
>
|
|
<!-- 供应商卡片 -->
|
|
<view class="supplier-card">
|
|
<!-- 供应商名称 -->
|
|
<view class="supplier-header">
|
|
<text class="supplier-name">{{ supplierGroup.supplierName }}</text>
|
|
</view>
|
|
|
|
<!-- 该供应商的商品列表 -->
|
|
<view class="supplier-goods">
|
|
<view
|
|
class="commodity-item"
|
|
v-for="(sku, index) in supplierGroup.goods"
|
|
:key="index"
|
|
>
|
|
<view class="commodity box">
|
|
<image
|
|
class="img"
|
|
:src="showImg(sku.specUrl)"
|
|
mode="aspectFill"
|
|
></image>
|
|
<view class="title flex-c">
|
|
<view class="commodity-info">
|
|
<view class="text-overflowRows">{{ sku.goodsName }}</view>
|
|
<view class="commodity-price">
|
|
{{ sku.salePrice }}
|
|
</view>
|
|
</view>
|
|
<view class="commodity-info">
|
|
<view class="text-overflowRows" style="width: 90%"
|
|
>{{ sku.specValueOne }}-{{ sku.specValueTwo }}</view
|
|
>
|
|
<view class="commodity-num"> x{{ sku.quantity }} </view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<view
|
|
class="commodity box sb"
|
|
style="padding-left: 10rpx"
|
|
v-if="false"
|
|
>
|
|
<view class="title" style="font-weight: bold"> 购买数量 </view>
|
|
<view class="num-box">
|
|
<view
|
|
:class="['ctrl', sku.quantity > 1 ? '' : 'disabled']"
|
|
@click="reduce(sku, supplierIndex, index)"
|
|
>-</view
|
|
>
|
|
<input
|
|
class="num"
|
|
type="text"
|
|
v-model="sku.quantity"
|
|
:disabled="true"
|
|
/>
|
|
<view :class="['ctrl']" @click="plus(sku)">+</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 该供应商的备注 -->
|
|
<view class="supplier-remark">
|
|
<view class="section-row">
|
|
<text class="section-label">备注</text>
|
|
<view class="note-input">
|
|
<input
|
|
v-model="supplierRemarks[supplierGroup.supplierId]"
|
|
placeholder="选填"
|
|
placeholder-class="placeholder"
|
|
maxlength="200"
|
|
/>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 订单信息卡片 -->
|
|
<view class="order-info-card" style="margin-bottom: 36rpx">
|
|
<!-- 积分兑换 -->
|
|
<view class="card-section">
|
|
<view class="section-row" @click="openPointsPopup">
|
|
<text class="section-label">积分兑换</text>
|
|
<div style="display: flex; align-items: center">
|
|
<view class="section-value coupon">{{
|
|
usePoints > 0
|
|
? `已抵扣¥${(usePoints / POINTS_TO_YUAN_RATIO).toFixed(2)}`
|
|
: "可用积分" + userPoints
|
|
}}</view>
|
|
<uni-icons type="right" color="#999999" size="16"></uni-icons>
|
|
</div>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 费用明细 -->
|
|
<view class="card-section price-section">
|
|
<view class="price-detail">
|
|
<view class="text">商品总价:</view>
|
|
<view class="price">{{ getGoodsTotal() }}</view>
|
|
</view>
|
|
<view class="price-detail">
|
|
<view class="text">运费:</view>
|
|
<view class="price">{{
|
|
post > 0 ? "¥" + post.toFixed(2) : "包邮"
|
|
}}</view>
|
|
</view>
|
|
<view class="price-detail" v-if="usePoints > 0">
|
|
<view class="text">积分抵扣:</view>
|
|
<view class="price deduction"
|
|
>-¥{{ (usePoints / POINTS_TO_YUAN_RATIO).toFixed(2) }}</view
|
|
>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 底部支付区域 -->
|
|
<view class="payment-bottom">
|
|
<view class="total-amount">
|
|
<text class="total-label">实付金额:</text>
|
|
<text class="total-price">{{ total() }}</text>
|
|
</view>
|
|
<view class="btn" :class="{ loading: isOrderLoading }" @click="order()">
|
|
<text v-if="!isOrderLoading">立即支付</text>
|
|
<text v-else>支付中...</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 选择收货地址弹窗 -->
|
|
<uni-popup
|
|
ref="addressPopup"
|
|
type="bottom"
|
|
backgroundColor="#F4F4F4"
|
|
@change="changPopShow"
|
|
>
|
|
<view class="people-popup">
|
|
<view class="top-box">
|
|
<view class="top flex-between">
|
|
<text class="text-overflow" @click="changeAddressPopup('close')"
|
|
>取消</text
|
|
>
|
|
<text
|
|
class="confirm"
|
|
@click="changeAddressPopup('close', 'confirm')"
|
|
>确定</text
|
|
>
|
|
</view>
|
|
</view>
|
|
<!-- <navigator url="/subPackages/user/myAddressAdd" class="button">添加收货地址</navigator> -->
|
|
<view class="button" @click="changeAddressAddPopup('open', '', {})"
|
|
>添加收货地址</view
|
|
>
|
|
<view class="popup-list" v-if="addressList.length > 0">
|
|
<view
|
|
:class="['popup-item', contacts.id == item.id ? 'active' : '']"
|
|
v-for="(item, index) in addressList"
|
|
:key="index"
|
|
@click="seldThisAddress(item)"
|
|
>
|
|
<view class="item-top flex-between">
|
|
<view style="padding-right: 71rpx">
|
|
<view class="name flex-start">
|
|
{{ item.name }}
|
|
<text>{{ item.tel }}</text>
|
|
<text class="tag" v-if="item.is_default == 1">默认</text>
|
|
</view>
|
|
<view class="subtitle text-overflowRows">{{
|
|
item.province_text +
|
|
item.city_text +
|
|
item.district_text +
|
|
item.detail_addr
|
|
}}</view>
|
|
</view>
|
|
<view>
|
|
<img
|
|
@click.stop="changeAddressAddPopup('open', '', item)"
|
|
:src="
|
|
showImg(
|
|
'/uploads/20250514/dd77d7706bc9bffd2bb928d1772e8413.png'
|
|
)
|
|
"
|
|
alt=""
|
|
/>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</uni-popup>
|
|
<!-- 新增编辑收货地址弹窗 -->
|
|
<uni-popup
|
|
ref="addressAddPopup"
|
|
type="bottom"
|
|
backgroundColor="#F4F4F4"
|
|
@change="changPopShow"
|
|
style="border-radius: 13rpx 13rpx 0 0"
|
|
>
|
|
<view class="people-popup">
|
|
<view class="top-box">
|
|
<view class="top flex-between" style="height: fit-content">
|
|
<text class="text-overflow" @click="changeAddressAddPopup('close')"
|
|
>取消</text
|
|
>
|
|
<text style="font-size: 35rpx; font-weight: 600">{{
|
|
addressTitle
|
|
}}</text>
|
|
<text style="color: #515150" class="confirm" @click="saveAddress"
|
|
>保存</text
|
|
>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="add-edit-content">
|
|
<addressAddVue ref="addressAddVueRef"></addressAddVue>
|
|
</view>
|
|
</view>
|
|
</uni-popup>
|
|
|
|
<!-- 积分兑换弹窗 -->
|
|
<uni-popup
|
|
ref="pointsPopup"
|
|
type="bottom"
|
|
backgroundColor="#F4F4F4"
|
|
@change="changPopShow"
|
|
>
|
|
<view class="points-popup">
|
|
<view class="popup-header">
|
|
<text class="popup-close" @click="closePointsPopup">取消</text>
|
|
<text class="popup-title">积分兑换</text>
|
|
<text class="popup-confirm" @click="confirmPointsUse">确定</text>
|
|
</view>
|
|
|
|
<view class="popup-content">
|
|
<!-- 兑换规则 -->
|
|
<view class="exchange-rule">
|
|
<text class="rule-title">兑换规则</text>
|
|
<text class="rule-desc">{{ POINTS_TO_YUAN_RATIO }}积分抵扣1元</text>
|
|
</view>
|
|
|
|
<!-- 当前积分 -->
|
|
<view class="current-points">
|
|
<text class="points-label">当前{{ userPoints }}积分</text>
|
|
<text class="points-value"
|
|
>本订单最多可用{{ getMaxUsablePoints() }}积分({{
|
|
(getMaxUsablePoints() / POINTS_TO_YUAN_RATIO).toFixed(2)
|
|
}}元)</text
|
|
>
|
|
</view>
|
|
|
|
<!-- 积分选择 -->
|
|
<view class="points-options-section">
|
|
<view
|
|
class="option-item"
|
|
:class="{ active: tempUsePoints == 0 }"
|
|
@click="selectPointsOption(0)"
|
|
>
|
|
<view class="option-radio">
|
|
<view class="radio-dot" v-if="tempUsePoints == 0"></view>
|
|
</view>
|
|
<view class="option-content">
|
|
<text class="option-title">不使用积分</text>
|
|
</view>
|
|
</view>
|
|
|
|
<view
|
|
class="option-item"
|
|
:class="{ active: tempUsePoints == getMaxUsablePoints() }"
|
|
@click="selectPointsOption(getMaxUsablePoints())"
|
|
v-if="getMaxUsablePoints() > 0"
|
|
>
|
|
<view class="option-radio">
|
|
<view
|
|
class="radio-dot"
|
|
v-if="tempUsePoints == getMaxUsablePoints()"
|
|
></view>
|
|
</view>
|
|
<view class="option-content">
|
|
<text class="option-title"
|
|
>使用全部可用积分{{ getMaxUsablePoints() }}积分抵扣{{
|
|
(getMaxUsablePoints() / POINTS_TO_YUAN_RATIO).toFixed(2)
|
|
}}元</text
|
|
>
|
|
<text class="option-desc">最大可用积分数量</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</uni-popup>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
import addressAddVue from "../../components/addressAdd.vue";
|
|
import Decimal from "decimal.js";
|
|
export default {
|
|
components: { addressAddVue },
|
|
data() {
|
|
return {
|
|
contacts: null,
|
|
info: null, //规格的信息
|
|
detail: null, //商品的信息
|
|
|
|
orderGoods: [],
|
|
|
|
post: 0,
|
|
flag: true,
|
|
addressList: [],
|
|
reserve_name: "",
|
|
reserve_idcard: "",
|
|
reserve_phone: "",
|
|
remark: "", // 改为按供应商分组的备注对象
|
|
supplierRemarks: {}, // 按供应商ID存储备注的对象
|
|
groupedGoods: [], // 按供应商分组的商品数据
|
|
coupon: "",
|
|
allprice: 0,
|
|
|
|
// 积分相关
|
|
userPoints: 0, // 用户可用积分
|
|
usePoints: 0, // 使用的积分数量
|
|
tempUsePoints: 0, // 弹窗中临时的积分数量
|
|
|
|
// 积分常量
|
|
POINTS_EXCHANGE_AMOUNT: 650, // 积分兑换数量
|
|
POINTS_EXCHANGE_VALUE: 6.5, // 积分兑换价值(元)
|
|
POINTS_TO_YUAN_RATIO: 100, // 积分与元的兑换比例(100积分=1元)
|
|
|
|
// 加载状态
|
|
isOrderLoading: false, // 下单加载状态
|
|
isPolling: false, // 轮询状态标志
|
|
|
|
isPost: "1", //0=核销,1=邮寄,2=自取,3=邮寄/自提
|
|
sendType: 1, // 0=核销,1=邮寄,2=自取,3=邮寄/自提
|
|
pickupAddress: { id: null, address: "" },
|
|
pickupPerson: { name: "", phone: "" },
|
|
popShow: false, // 解决滚动穿透
|
|
|
|
addressTitle: "添加收货地址",
|
|
isShipping: false,
|
|
shipperMsg: "",
|
|
};
|
|
},
|
|
onLoad() {
|
|
this.info = this.$store.state.user.sshoppingCart;
|
|
if (!this.info) {
|
|
uni.navigateBack();
|
|
return;
|
|
}
|
|
// console.log(this.info);
|
|
|
|
// 根据规格信息 记录发货方式 is_post ,使用方式:0=核销,1=邮寄,2=自取,3=邮寄/自提
|
|
if (this.info) {
|
|
this.isPost = this.info.is_post || "1";
|
|
// this.info.is_post = this.isPost==3?1:this.isPost
|
|
}
|
|
this.handleOrderGoods();
|
|
// console.log(this.isPost);
|
|
},
|
|
onShow() {
|
|
this.getTotalPoints();
|
|
|
|
// this.coupon = this.$store.state.user.coupon
|
|
this.getAllAddressList();
|
|
this.tempUsePoints = this.usePoints; // 初始化临时积分
|
|
|
|
// 更新自提点
|
|
uni.$on("updateDataByConnect", this.getDataByConnect);
|
|
},
|
|
onUnload() {
|
|
uni.$off("updateDataByConnect", this.getDataByConnect);
|
|
// 停止轮询
|
|
this.isPolling = false;
|
|
this.isOrderLoading = false;
|
|
},
|
|
onReady() {
|
|
// 页面准备完成后的初始化操作
|
|
},
|
|
methods: {
|
|
// 按供应商分组商品
|
|
handleOrderGoods() {
|
|
if (!this.info || !Array.isArray(this.info)) {
|
|
this.groupedGoods = [];
|
|
return;
|
|
}
|
|
|
|
// 按supplierId分组
|
|
const supplierMap = new Map();
|
|
|
|
this.info.forEach((item) => {
|
|
const supplierId = item.supplierId || "default";
|
|
const supplierName = item.supplierName || "默认供应商";
|
|
|
|
if (!supplierMap.has(supplierId)) {
|
|
supplierMap.set(supplierId, {
|
|
supplierId,
|
|
supplierName,
|
|
goods: [],
|
|
});
|
|
// 初始化该供应商的备注
|
|
this.$set(this.supplierRemarks, supplierId, "");
|
|
}
|
|
|
|
supplierMap.get(supplierId).goods.push(item);
|
|
});
|
|
|
|
this.groupedGoods = Array.from(supplierMap.values());
|
|
console.log("分组后的商品:", this.groupedGoods);
|
|
},
|
|
|
|
// 获取总积分
|
|
async getTotalPoints() {
|
|
try {
|
|
if (!uni.getStorageSync("userInfo")) return;
|
|
this.Post({}, "/framework/points/getLastBalance", "DES").then((res) => {
|
|
if (res.code === 200) {
|
|
this.userPoints = res.data.balance || 0;
|
|
this.POINTS_TO_YUAN_RATIO = res.data.changeValue;
|
|
}
|
|
});
|
|
} catch (error) {
|
|
console.error("获取总积分失败:", error);
|
|
}
|
|
},
|
|
|
|
// 轮询查询订单状态
|
|
async pollOrderStatus(params = {}) {
|
|
const {
|
|
maxAttempts = 30, // 最大轮询次数,默认30次
|
|
interval = 2000, // 轮询间隔,默认2秒
|
|
onSuccess = null, // 成功回调
|
|
onFailure = null, // 失败回调
|
|
onTimeout = null, // 超时回调
|
|
...requestParams // 其他请求参数
|
|
} = params;
|
|
|
|
let attempts = 0;
|
|
this.isPolling = true; // 开始轮询
|
|
|
|
const poll = async () => {
|
|
// 检查页面是否已销毁或轮询是否已停止
|
|
if (!this.isPolling) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
attempts++;
|
|
|
|
const res = await this.Post(
|
|
requestParams,
|
|
"/framework/ygOrder/queryToken",
|
|
"DES"
|
|
);
|
|
|
|
// 再次检查轮询状态
|
|
if (!this.isPolling) {
|
|
return;
|
|
}
|
|
|
|
if (res && res.code === 200) {
|
|
const status = res.data?.status;
|
|
|
|
if (status === 1) {
|
|
// 成功状态,停止轮询
|
|
this.isPolling = false;
|
|
if (onSuccess && typeof onSuccess === "function") {
|
|
onSuccess(res.data);
|
|
}
|
|
return;
|
|
} else if (status === 2) {
|
|
// 失败状态,停止轮询
|
|
this.isPolling = false;
|
|
if (onFailure && typeof onFailure === "function") {
|
|
onFailure(res.data);
|
|
}
|
|
return;
|
|
} else if (status === 0) {
|
|
// 下单中,继续轮询
|
|
if (attempts >= maxAttempts) {
|
|
// 达到最大轮询次数,停止轮询
|
|
this.isPolling = false;
|
|
if (onTimeout && typeof onTimeout === "function") {
|
|
onTimeout({ message: "轮询超时", attempts });
|
|
}
|
|
return;
|
|
}
|
|
|
|
// 继续轮询
|
|
setTimeout(() => {
|
|
if (this.isPolling) {
|
|
poll();
|
|
}
|
|
}, interval);
|
|
} else {
|
|
// 未知状态,停止轮询
|
|
this.isPolling = false;
|
|
if (onFailure && typeof onFailure === "function") {
|
|
onFailure({ message: "未知状态", status, data: res.data });
|
|
}
|
|
}
|
|
} else if (res && res.code === 500) {
|
|
// 服务器错误,直接调用失败回调
|
|
this.isPolling = false;
|
|
onFailure({ message: "服务器错误", code: res.code, error: res });
|
|
return;
|
|
}
|
|
} catch (error) {
|
|
// 异常处理,直接调用失败回调
|
|
this.isPolling = false;
|
|
if (onFailure && typeof onFailure === "function") {
|
|
onFailure({ message: "请求异常", attempts, error });
|
|
}
|
|
return;
|
|
}
|
|
};
|
|
|
|
// 开始轮询
|
|
poll();
|
|
},
|
|
|
|
getContacts() {
|
|
if (this.info.is_post == 0) {
|
|
return;
|
|
}
|
|
|
|
this.Post({}, "/api/user/getDefaultConsignee").then((res) => {
|
|
if (res) {
|
|
this.contacts = res.data;
|
|
this.getPost();
|
|
}
|
|
});
|
|
},
|
|
getPost() {
|
|
if (this.info.is_post == 0 || !this.contacts) {
|
|
return;
|
|
}
|
|
|
|
// 调用新的运费计算方法
|
|
this.calculateFreight();
|
|
},
|
|
|
|
plus(sku) {
|
|
this.$nextTick(() => {
|
|
sku.quantity += 1;
|
|
if (this.flag) {
|
|
this.getPost();
|
|
}
|
|
});
|
|
},
|
|
reduce(sku, supplierIndex, index) {
|
|
if (sku.quantity > 1) {
|
|
this.$nextTick(() => {
|
|
sku.quantity -= 1;
|
|
if (this.flag) {
|
|
this.getPost();
|
|
}
|
|
});
|
|
} else if (sku.quantity == 1) {
|
|
this.$nextTick(() => {
|
|
// 从原始info数组中移除该商品
|
|
const skuIndex = this.info.findIndex(
|
|
(item) =>
|
|
item.goodsName === sku.goodsName &&
|
|
item.specValueOne === sku.specValueOne &&
|
|
item.specValueTwo === sku.specValueTwo
|
|
);
|
|
if (skuIndex !== -1) {
|
|
this.info.splice(skuIndex, 1);
|
|
}
|
|
|
|
if (this.flag) {
|
|
this.getPost();
|
|
}
|
|
// 重新分组
|
|
this.handleOrderGoods();
|
|
});
|
|
}
|
|
},
|
|
// 选择收货地址弹窗
|
|
changeAddressPopup(type, confirm, index) {
|
|
if (type == "open") this.$refs.addressPopup.open("bottom");
|
|
else this.$refs.addressPopup.close();
|
|
this.$forceUpdate();
|
|
},
|
|
// 获取收货地址列表
|
|
getAllAddressList() {
|
|
this.Post({}, "/api/user/consigneeList").then((res) => {
|
|
let oldId = (this.contacts || {}).id;
|
|
if (res.code == 200) this.addressList = res.data || [];
|
|
if (this.addressList.some((v) => v.id == oldId)) {
|
|
this.contacts = this.addressList.find((v) => v.id == oldId);
|
|
this.getPost();
|
|
} else if (this.addressList.some((v) => v.is_default == 1)) {
|
|
this.contacts = this.addressList.find((v) => v.is_default == 1);
|
|
this.getPost();
|
|
} else if (this.addressList.length > 0) {
|
|
this.contacts = this.addressList[0];
|
|
this.getPost();
|
|
}
|
|
});
|
|
},
|
|
// 选择收货地址
|
|
seldThisAddress(item) {
|
|
if (!this.contacts) this.contacts = {};
|
|
this.contacts = item;
|
|
if (this.flag) {
|
|
this.getPost();
|
|
}
|
|
this.$refs.addressPopup.close();
|
|
this.$forceUpdate();
|
|
},
|
|
// 收货地址新增弹窗
|
|
changeAddressAddPopup(type, confirm, item) {
|
|
if (type == "open") {
|
|
this.addressTitle = "新增收货地址";
|
|
if (item.id) {
|
|
this.addressTitle = "编辑收货地址";
|
|
}
|
|
// this.id = item.id
|
|
|
|
this.$refs.addressAddPopup.open("bottom");
|
|
|
|
this.$nextTick(() => {
|
|
this.$refs.addressAddVueRef.init(item);
|
|
});
|
|
} else {
|
|
this.$refs.addressAddPopup.close();
|
|
}
|
|
this.$forceUpdate();
|
|
},
|
|
|
|
// 保存地址
|
|
async saveAddress() {
|
|
let res = await this.$refs.addressAddVueRef.postSave();
|
|
if (res && (res.code == 1 || res.code == 200)) {
|
|
this.contacts = res.data;
|
|
this.getAllAddressList();
|
|
this.changeAddressAddPopup("close");
|
|
}
|
|
},
|
|
|
|
// 计算积分抵扣
|
|
calculatePointsDeduction() {
|
|
let points = parseInt(this.usePoints) || 0;
|
|
// 限制使用积分不能超过可用积分
|
|
if (points > this.userPoints) {
|
|
points = this.userPoints;
|
|
this.usePoints = points;
|
|
}
|
|
|
|
// 计算实际支付金额(不含积分抵扣)
|
|
let actualPaymentAmount = this.getActualPaymentAmount();
|
|
let actualPaymentDecimal = new Decimal(actualPaymentAmount);
|
|
let ratioDecimal = new Decimal(this.POINTS_TO_YUAN_RATIO);
|
|
|
|
// 限制积分抵扣金额不能超过实际支付金额
|
|
let maxPoints = actualPaymentDecimal.mul(ratioDecimal).floor().toNumber();
|
|
if (points > maxPoints) {
|
|
points = maxPoints;
|
|
this.usePoints = points;
|
|
}
|
|
},
|
|
|
|
// 全部使用积分
|
|
useAllPoints() {
|
|
// 计算实际支付金额(不含积分抵扣)
|
|
let actualPaymentAmount = this.getActualPaymentAmount();
|
|
let actualPaymentDecimal = new Decimal(actualPaymentAmount);
|
|
let ratioDecimal = new Decimal(this.POINTS_TO_YUAN_RATIO);
|
|
|
|
// 根据实际支付金额计算最大可用积分
|
|
let maxPointsFromPayment = actualPaymentDecimal
|
|
.mul(ratioDecimal)
|
|
.floor()
|
|
.toNumber();
|
|
let maxPoints = Math.min(this.userPoints, maxPointsFromPayment);
|
|
this.usePoints = maxPoints;
|
|
},
|
|
|
|
// 获取商品总价(不含运费,单位:元)
|
|
getGoodsTotalAmount() {
|
|
let allPriceDecimal = new Decimal(0);
|
|
if (this.info && Array.isArray(this.info)) {
|
|
this.info.forEach((sku) => {
|
|
// 解析商品价格(单位:元)
|
|
|
|
if (sku.salePrice) {
|
|
let priceStr = sku.salePrice
|
|
.toString()
|
|
.replace("¥", "")
|
|
.replace("¥", "");
|
|
try {
|
|
let priceDecimal = new Decimal(priceStr);
|
|
let quantityDecimal = new Decimal(sku.quantity || 0);
|
|
|
|
if (priceDecimal.isPositive() && quantityDecimal.isPositive()) {
|
|
// 使用Decimal进行精确计算
|
|
allPriceDecimal = allPriceDecimal.plus(
|
|
priceDecimal.mul(quantityDecimal)
|
|
);
|
|
}
|
|
} catch (error) {}
|
|
}
|
|
});
|
|
}
|
|
|
|
return allPriceDecimal.toNumber();
|
|
},
|
|
|
|
// 获取商品总价(显示用,单位:元)
|
|
getGoodsTotal() {
|
|
let allPriceYuan = this.getGoodsTotalAmount();
|
|
return "¥" + allPriceYuan.toFixed(2);
|
|
},
|
|
|
|
// 获取总运费(单位:元)
|
|
getTotalPost() {
|
|
// 如果有计算的运费,则返回运费,否则返回0
|
|
return this.post ? this.post : 0;
|
|
},
|
|
|
|
// 计算运费
|
|
calculateFreight() {
|
|
if (!this.contacts) {
|
|
return;
|
|
}
|
|
|
|
this.flag = false;
|
|
|
|
// 构建商品数组信息,不根据供应商区分
|
|
let shoppingCartBoList = [];
|
|
this.info.forEach((sku) => {
|
|
shoppingCartBoList.push({
|
|
goodsId: sku.goodsId,
|
|
specId: sku.specId,
|
|
quantity: sku.quantity,
|
|
});
|
|
});
|
|
|
|
// 调用运费计算接口
|
|
this.Post(
|
|
{
|
|
shoppingCartBoList: this.info,
|
|
userContactId: this.contacts.id,
|
|
method: "POST",
|
|
},
|
|
"/framework/ygOrder/calculateMultiSpecFreight",
|
|
"DES"
|
|
)
|
|
.then((res) => {
|
|
if (res && res.code === 200) {
|
|
this.isShipping = true;
|
|
this.post = Number(res.data.total) || 0;
|
|
this.flag = true;
|
|
} else {
|
|
uni.showToast({
|
|
title: res.msg || "运费计算失败",
|
|
icon: "none",
|
|
});
|
|
this.flag = true;
|
|
}
|
|
})
|
|
.catch((err) => {
|
|
this.shipperMsg = err.data.msg;
|
|
this.isShipping = false;
|
|
|
|
console.error("运费计算错误:", err);
|
|
this.flag = true;
|
|
});
|
|
},
|
|
|
|
// 获取当前订单最大可用积分
|
|
getMaxUsablePoints() {
|
|
let actualPaymentAmount = this.getActualPaymentAmount();
|
|
let actualPaymentDecimal = new Decimal(actualPaymentAmount);
|
|
let minPaymentDecimal = new Decimal(0.01); // 最少支付0.01元
|
|
|
|
// 最大可兑换金额 = 实际支付金额 - 0.01元
|
|
let maxExchangeAmount = actualPaymentDecimal.minus(minPaymentDecimal);
|
|
|
|
// 如果实际支付金额小于等于0.01元,则不能使用积分
|
|
if (maxExchangeAmount.lessThanOrEqualTo(0)) {
|
|
return 0;
|
|
}
|
|
|
|
let ratioDecimal = new Decimal(this.POINTS_TO_YUAN_RATIO);
|
|
let maxPointsFromPayment = maxExchangeAmount
|
|
.mul(ratioDecimal)
|
|
.floor()
|
|
.toNumber();
|
|
return Math.min(this.userPoints, maxPointsFromPayment);
|
|
},
|
|
|
|
// 获取实际支付金额(不含积分抵扣,单位:元)
|
|
getActualPaymentAmount() {
|
|
let goodsPriceDecimal = new Decimal(this.getGoodsTotalAmount()); // 商品总价(元)
|
|
let postPriceDecimal = new Decimal(this.getTotalPost()); // 运费(元)
|
|
let totalPriceDecimal = goodsPriceDecimal.plus(postPriceDecimal);
|
|
|
|
// 优惠券计算(以元为单位)
|
|
if (this.coupon) {
|
|
if (this.coupon.percent == 0) {
|
|
// 满减券
|
|
let discountsDecimal = new Decimal(this.coupon.discounts);
|
|
if (discountsDecimal.greaterThan(goodsPriceDecimal)) {
|
|
totalPriceDecimal = postPriceDecimal;
|
|
} else {
|
|
totalPriceDecimal = goodsPriceDecimal
|
|
.plus(postPriceDecimal)
|
|
.minus(discountsDecimal);
|
|
}
|
|
} else {
|
|
// 折扣券
|
|
let percentDecimal = new Decimal(this.coupon.percent);
|
|
let hundredDecimal = new Decimal(100);
|
|
let discountDecimal = goodsPriceDecimal
|
|
.mul(percentDecimal)
|
|
.div(hundredDecimal);
|
|
totalPriceDecimal = goodsPriceDecimal
|
|
.plus(postPriceDecimal)
|
|
.minus(discountDecimal);
|
|
}
|
|
}
|
|
|
|
// 确保金额不为负数
|
|
let zeroDecimal = new Decimal(0);
|
|
return totalPriceDecimal.lessThan(zeroDecimal)
|
|
? 0
|
|
: totalPriceDecimal.toNumber();
|
|
},
|
|
|
|
// 总价计算(最终支付金额)
|
|
total() {
|
|
let goodsPriceDecimal = new Decimal(this.getGoodsTotalAmount()); // 商品总价(元)
|
|
let postPriceDecimal = new Decimal(this.getTotalPost()); // 运费(元)
|
|
let usePointsDecimal = new Decimal(parseInt(this.usePoints) || 0);
|
|
let ratioDecimal = new Decimal(this.POINTS_TO_YUAN_RATIO);
|
|
let pointsDeductionDecimal = usePointsDecimal.div(ratioDecimal); // 积分抵扣(元,100积分=1元)
|
|
|
|
let totalPriceDecimal = goodsPriceDecimal.plus(postPriceDecimal);
|
|
|
|
// 优惠券计算(以元为单位)
|
|
if (this.coupon) {
|
|
if (this.coupon.percent == 0) {
|
|
// 满减券
|
|
let discountsDecimal = new Decimal(this.coupon.discounts);
|
|
if (discountsDecimal.greaterThan(goodsPriceDecimal)) {
|
|
totalPriceDecimal = postPriceDecimal;
|
|
} else {
|
|
totalPriceDecimal = goodsPriceDecimal
|
|
.plus(postPriceDecimal)
|
|
.minus(discountsDecimal);
|
|
}
|
|
} else {
|
|
// 折扣券
|
|
let percentDecimal = new Decimal(this.coupon.percent);
|
|
let hundredDecimal = new Decimal(100);
|
|
let discountDecimal = goodsPriceDecimal
|
|
.mul(percentDecimal)
|
|
.div(hundredDecimal);
|
|
totalPriceDecimal = goodsPriceDecimal
|
|
.plus(postPriceDecimal)
|
|
.minus(discountDecimal);
|
|
}
|
|
}
|
|
|
|
// 积分抵扣(积分只能抵扣商品价格,不能抵扣运费)
|
|
totalPriceDecimal = totalPriceDecimal.minus(pointsDeductionDecimal);
|
|
|
|
// 保存总价用于订单提交
|
|
this.allprice = totalPriceDecimal.toNumber();
|
|
|
|
let zeroDecimal = new Decimal(0);
|
|
return totalPriceDecimal.lessThan(zeroDecimal)
|
|
? "¥0.00"
|
|
: "¥" + totalPriceDecimal.toFixed(2);
|
|
},
|
|
// 预定
|
|
order() {
|
|
if (this.isOrderLoading) {
|
|
return; // 防止重复点击
|
|
}
|
|
|
|
if (!this.contacts) {
|
|
uni.showToast({
|
|
title: "请选择收货地址",
|
|
icon: "none",
|
|
});
|
|
return;
|
|
}
|
|
if (!this.isShipping) {
|
|
uni.showToast({
|
|
title: this.shipperMsg,
|
|
icon: "none",
|
|
});
|
|
return;
|
|
}
|
|
|
|
this.isOrderLoading = true; // 开始加载
|
|
|
|
// 按供应商分组构建 createDtos
|
|
let createDtos = [];
|
|
this.groupedGoods.forEach((supplierGroup) => {
|
|
const supplierRemark =
|
|
this.supplierRemarks[supplierGroup.supplierId] || "";
|
|
createDtos.push({
|
|
supplierId: supplierGroup.supplierId,
|
|
remark: supplierRemark,
|
|
shoppingCartBoList: supplierGroup.goods,
|
|
});
|
|
});
|
|
|
|
let data = {
|
|
createDtos: createDtos,
|
|
userContactId: this.contacts.id,
|
|
expectedAmount: this.allprice,
|
|
usePoints: this.usePoints ? 0 : 1, // 是否使用积分
|
|
pointsQuantity: parseInt(this.usePoints) || 0, // 使用的积分数量
|
|
shippingFee: this.post || 0, // 使用计算出的运费
|
|
};
|
|
|
|
this.Post(
|
|
{
|
|
method: "POST",
|
|
...data,
|
|
},
|
|
"/framework/ygOrder/preAddOrder",
|
|
"DES"
|
|
)
|
|
.then((res) => {
|
|
if (res.code == 200) {
|
|
this.pollOrderStatus({
|
|
authToken: res.msg,
|
|
maxAttempts: 20,
|
|
interval: 2000,
|
|
onSuccess: (data) => {
|
|
this.isOrderLoading = false; // 结束加载
|
|
this.getTotalPoints();
|
|
// 处理成功逻辑
|
|
// uni.showToast({
|
|
// title: "订单创建成功",
|
|
// icon: "success",
|
|
// });
|
|
this.orderPay(res.msg);
|
|
},
|
|
onFailure: (data) => {
|
|
this.isOrderLoading = false; // 结束加载
|
|
// 处理失败逻辑
|
|
uni.showToast({
|
|
title: data.msg,
|
|
icon: "none",
|
|
});
|
|
},
|
|
onTimeout: (info) => {
|
|
this.isOrderLoading = false; // 结束加载
|
|
// 处理超时逻辑
|
|
uni.showToast({
|
|
title: "订单处理超时",
|
|
icon: "error",
|
|
});
|
|
},
|
|
});
|
|
} else {
|
|
this.isOrderLoading = false; // 结束加载
|
|
uni.showToast({
|
|
title: res.msg || "下单失败",
|
|
icon: "error",
|
|
});
|
|
}
|
|
})
|
|
.catch((error) => {
|
|
this.isOrderLoading = false; // 结束加载
|
|
uni.showToast({
|
|
title: "网络错误,请重试",
|
|
icon: "error",
|
|
});
|
|
});
|
|
},
|
|
orderPay(token) {
|
|
this.Post(
|
|
{
|
|
method: "POST",
|
|
orderNo: token,
|
|
fromType: 1,
|
|
payAmount: this.allprice,
|
|
},
|
|
"/framework/wxPay/submitShopPurOrder",
|
|
"DES"
|
|
).then((res) => {
|
|
uni.requestPayment({
|
|
nonceStr: res.data.wxInfo.nonceStr,
|
|
package: res.data.wxInfo.package,
|
|
paySign: res.data.wxInfo.paySign,
|
|
signType: res.data.wxInfo.signType,
|
|
timeStamp: res.data.wxInfo.timeStamp,
|
|
success: () => {
|
|
uni.redirectTo({
|
|
url: "/subPackages/haveFeeling/list",
|
|
});
|
|
},
|
|
fail() {
|
|
uni.redirectTo({
|
|
url: "/subPackages/haveFeeling/list",
|
|
});
|
|
},
|
|
});
|
|
});
|
|
},
|
|
|
|
// ---------------自提-----------------------
|
|
changPopShow(e) {
|
|
this.popShow = e.show;
|
|
},
|
|
|
|
getDataByConnect(data) {
|
|
if (data.msgType == "updatePickUpPoint") {
|
|
this.pickupAddress = data.data;
|
|
}
|
|
},
|
|
|
|
// 打开积分兑换弹窗
|
|
openPointsPopup() {
|
|
this.tempUsePoints = this.usePoints;
|
|
this.$refs.pointsPopup.open("bottom");
|
|
},
|
|
|
|
// 关闭积分兑换弹窗
|
|
closePointsPopup() {
|
|
this.$refs.pointsPopup.close();
|
|
},
|
|
|
|
// 选择积分选项
|
|
selectPointsOption(points) {
|
|
// 如果选择使用积分,需要检查用户是否有足够积分
|
|
if (points > 0 && this.userPoints < points) {
|
|
uni.showToast({
|
|
title: "积分不足",
|
|
icon: "none",
|
|
});
|
|
return;
|
|
}
|
|
|
|
// 检查积分兑换是否超过实际支付金额
|
|
if (points > 0) {
|
|
let actualPaymentAmount = this.getActualPaymentAmount();
|
|
let actualPaymentDecimal = new Decimal(actualPaymentAmount);
|
|
let ratioDecimal = new Decimal(this.POINTS_TO_YUAN_RATIO);
|
|
let maxPoints = actualPaymentDecimal
|
|
.mul(ratioDecimal)
|
|
.floor()
|
|
.toNumber();
|
|
|
|
if (points > maxPoints) {
|
|
uni.showToast({
|
|
title: `最多只能使用${maxPoints}积分`,
|
|
icon: "none",
|
|
});
|
|
return;
|
|
}
|
|
}
|
|
|
|
this.tempUsePoints = points;
|
|
},
|
|
|
|
// 确认使用积分
|
|
confirmPointsUse() {
|
|
// 最终确认前再次验证积分使用是否合法
|
|
if (this.tempUsePoints > 0) {
|
|
// 检查用户积分是否足够
|
|
if (this.userPoints < this.tempUsePoints) {
|
|
uni.showToast({
|
|
title: "积分不足",
|
|
icon: "none",
|
|
});
|
|
return;
|
|
}
|
|
|
|
// 检查是否超过实际支付金额
|
|
let actualPaymentAmount = this.getActualPaymentAmount();
|
|
let actualPaymentDecimal = new Decimal(actualPaymentAmount);
|
|
let ratioDecimal = new Decimal(this.POINTS_TO_YUAN_RATIO);
|
|
let maxPoints = actualPaymentDecimal
|
|
.mul(ratioDecimal)
|
|
.floor()
|
|
.toNumber();
|
|
|
|
if (this.tempUsePoints > maxPoints) {
|
|
uni.showToast({
|
|
title: `最多只能使用${maxPoints}积分`,
|
|
icon: "none",
|
|
});
|
|
return;
|
|
}
|
|
}
|
|
|
|
this.usePoints = this.tempUsePoints;
|
|
this.closePointsPopup();
|
|
uni.showToast({
|
|
title:
|
|
this.usePoints > 0 ? `已使用${this.usePoints}积分` : "已取消积分使用",
|
|
icon: "none",
|
|
});
|
|
},
|
|
|
|
// 获取最大优惠券
|
|
async getMaxCouponData() {
|
|
let allPrice = 0;
|
|
let skuIds = [];
|
|
if (this.info && Array.isArray(this.info.goods)) {
|
|
this.info.goods.forEach((v) => {
|
|
allPrice += v.skuInfo.money * v.skuInfo.quantity;
|
|
if (v.skuInfo.quantity > 0) {
|
|
skuIds.push(v.skuInfo.id);
|
|
}
|
|
});
|
|
}
|
|
let param = { money: allPrice, sku_ids: skuIds.join(",") };
|
|
let res = await this.getMaxCoupon(param);
|
|
if (res.id) {
|
|
this.coupon = res;
|
|
}
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.bg {
|
|
min-height: 100vh;
|
|
overflow-x: hidden;
|
|
background: #f2f4f7;
|
|
padding-bottom: 200rpx;
|
|
}
|
|
view {
|
|
box-sizing: border-box;
|
|
}
|
|
.flex-shrink-0 {
|
|
flex-shrink: 0;
|
|
}
|
|
.box {
|
|
width: 100%;
|
|
min-height: 100rpx;
|
|
padding: 20rpx;
|
|
background: #ffffff;
|
|
border-radius: 16rpx;
|
|
}
|
|
.address {
|
|
width: 697rpx;
|
|
height: 291rpx;
|
|
background: #ffffff;
|
|
border-radius: 13rpx;
|
|
margin: 0 auto;
|
|
margin-top: 26rpx;
|
|
.a-title {
|
|
font-size: 31rpx;
|
|
font-family: PingFang SC;
|
|
font-weight: bold;
|
|
color: #000000;
|
|
padding: 30rpx 18rpx;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
display: flex;
|
|
width: 100%;
|
|
.more-person {
|
|
width: 133rpx;
|
|
height: 60rpx;
|
|
border-radius: 30rpx;
|
|
border: 1px solid #999999;
|
|
font-family: PingFang SC;
|
|
font-weight: 400;
|
|
font-size: 28rpx;
|
|
color: #000000;
|
|
line-height: 16rpx;
|
|
}
|
|
}
|
|
.btn-box {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
border-top: 1rpx solid rgba(216, 216, 216, 1);
|
|
height: 176rpx;
|
|
.a-img {
|
|
width: 219rpx;
|
|
height: 73rpx;
|
|
border-radius: 37rpx;
|
|
border: 1px solid #333333;
|
|
font-family: PingFang SC;
|
|
font-weight: 400;
|
|
font-size: 29rpx;
|
|
color: #000000;
|
|
}
|
|
}
|
|
}
|
|
|
|
.pickself {
|
|
width: 697rpx;
|
|
height: 120rpx;
|
|
background: #ffffff;
|
|
border-radius: 13rpx;
|
|
margin: 0 auto;
|
|
margin-top: 26rpx;
|
|
.pickpoint {
|
|
display: flex;
|
|
width: 100%;
|
|
font-size: 31rpx;
|
|
font-weight: bold;
|
|
padding: 40rpx 18rpx;
|
|
}
|
|
.pickpointAddress {
|
|
display: flex;
|
|
font-weight: 500;
|
|
flex: 1;
|
|
width: 10rpx;
|
|
align-items: center;
|
|
justify-content: flex-end;
|
|
}
|
|
.pickpointImg {
|
|
width: 20rpx;
|
|
height: 20rpx;
|
|
}
|
|
.pointAddressText {
|
|
padding: 0 20rpx 0 40rpx;
|
|
flex: 1;
|
|
text-align: right;
|
|
width: 10rpx;
|
|
}
|
|
}
|
|
|
|
.pickup-person-area {
|
|
width: 697rpx;
|
|
background: #ffffff;
|
|
border-radius: 13rpx;
|
|
margin: 0 auto;
|
|
margin-top: 26rpx;
|
|
margin-bottom: 30rpx;
|
|
.pickpoint {
|
|
display: flex;
|
|
width: 100%;
|
|
font-size: 31rpx;
|
|
font-weight: bold;
|
|
padding: 40rpx 18rpx;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
.more-person {
|
|
width: 140rpx;
|
|
height: 58rpx;
|
|
}
|
|
.btn-box {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 0 20rpx;
|
|
border-top: 1rpx solid rgba(216, 216, 216, 1);
|
|
}
|
|
.pickup-person-list {
|
|
border-top: 1rpx solid #d8d8d8;
|
|
.person-list-area {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
padding: 40rpx 21rpx;
|
|
.person-item {
|
|
width: 160rpx;
|
|
height: 74rpx;
|
|
line-height: 68rpx;
|
|
background: rgba(153, 153, 153, 0.1);
|
|
border-radius: 11rpx;
|
|
border: 1px solid #999999;
|
|
position: relative;
|
|
font-size: 29rpx;
|
|
font-weight: 400;
|
|
font-size: 29rpx;
|
|
color: #000000;
|
|
text-align: center;
|
|
padding: 0 22rpx;
|
|
text-overflow: ellipsis;
|
|
overflow: hidden;
|
|
white-space: nowrap;
|
|
font-weight: bold;
|
|
margin-right: 24rpx;
|
|
margin-bottom: 24rpx;
|
|
}
|
|
.person-item.active {
|
|
background: rgba(116, 165, 170, 0.1);
|
|
border: 2px solid #74a5aa;
|
|
}
|
|
.person-item-active-img {
|
|
width: 24rpx;
|
|
height: 24rpx;
|
|
position: absolute;
|
|
right: 0;
|
|
bottom: 0;
|
|
background-color: #74a5aa;
|
|
color: white;
|
|
font-size: 20rpx;
|
|
line-height: 1.2;
|
|
border-radius: 10rpx 0rpx 10rpx 0rpx;
|
|
}
|
|
}
|
|
.current-person {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 0 44rpx 22rpx;
|
|
image {
|
|
width: 44rpx;
|
|
height: 44rpx;
|
|
}
|
|
.name {
|
|
text {
|
|
padding-left: 20rpx;
|
|
font-size: 25rpx;
|
|
color: #666666;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.commodity {
|
|
display: flex;
|
|
// align-items: center;
|
|
.img {
|
|
width: 174rpx;
|
|
height: 174rpx;
|
|
background: #f2f4f7;
|
|
border-radius: 10rpx;
|
|
flex-shrink: 0;
|
|
}
|
|
.title {
|
|
flex: 1;
|
|
margin-left: 20rpx;
|
|
font-size: 31rpx;
|
|
font-family: PingFangSC-Medium, PingFang SC;
|
|
font-weight: 500;
|
|
color: #000000;
|
|
}
|
|
.num-box {
|
|
display: flex;
|
|
align-items: center;
|
|
margin-left: 20rpx;
|
|
width: 160rpx;
|
|
justify-content: space-between;
|
|
.num {
|
|
text-align: center;
|
|
width: 50rpx;
|
|
}
|
|
.ctrl {
|
|
width: 47rpx;
|
|
height: 47rpx;
|
|
background: #74a5aa;
|
|
border-radius: 50%;
|
|
font-family: PingFang SC;
|
|
font-weight: 400;
|
|
font-size: 34rpx;
|
|
color: #ffffff;
|
|
line-height: 47rpx;
|
|
text-align: center;
|
|
}
|
|
.ctrl.disabled {
|
|
background: #e8e8e8;
|
|
color: #999999;
|
|
}
|
|
}
|
|
}
|
|
// 主题色彩变量
|
|
$primary-color: #74a5aa;
|
|
$secondary-color: #f8f9fa;
|
|
$text-primary: #333333;
|
|
$text-secondary: #666666;
|
|
$text-muted: #999999;
|
|
$border-color: #e8e8e8;
|
|
$success-color: #74a5aa;
|
|
$warning-color: #74a5aa;
|
|
$danger-color: #74a5aa;
|
|
$bg-light: #f9f9f9;
|
|
|
|
.section-label {
|
|
font-size: 28rpx;
|
|
color: $text-primary;
|
|
font-weight: 500;
|
|
}
|
|
|
|
// 订单信息卡片样式
|
|
.order-info-card {
|
|
background-color: #ffffff;
|
|
border-radius: 16rpx;
|
|
padding: 24rpx 30rpx;
|
|
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
|
|
width: 697rpx;
|
|
margin: 0 auto;
|
|
|
|
.card-section {
|
|
&:not(:last-child) {
|
|
border-bottom: 1rpx solid #f0f0f0;
|
|
padding-bottom: 20rpx;
|
|
margin-bottom: 20rpx;
|
|
}
|
|
|
|
.section-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
cursor: pointer;
|
|
transition: background-color 0.3s;
|
|
border-radius: 8rpx;
|
|
min-height: 60rpx;
|
|
&:active {
|
|
background-color: rgba(116, 165, 170, 0.05);
|
|
}
|
|
|
|
.section-label {
|
|
font-size: 28rpx;
|
|
color: $text-primary;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.section-value {
|
|
font-size: 26rpx;
|
|
color: $text-primary;
|
|
|
|
&.coupon {
|
|
color: $text-muted;
|
|
}
|
|
}
|
|
}
|
|
|
|
.note-input {
|
|
flex: 1;
|
|
margin-left: 40rpx;
|
|
|
|
input {
|
|
font-size: 26rpx;
|
|
color: $text-primary;
|
|
text-align: right;
|
|
width: 100%;
|
|
}
|
|
|
|
.placeholder {
|
|
color: $text-muted;
|
|
}
|
|
}
|
|
|
|
// 价格明细区域
|
|
&.price-section {
|
|
.price-detail {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: 8rpx 0;
|
|
|
|
.text {
|
|
font-size: 26rpx;
|
|
font-family: PingFangSC-Regular, PingFang SC;
|
|
font-weight: 400;
|
|
color: #666;
|
|
}
|
|
|
|
.price {
|
|
font-size: 26rpx;
|
|
font-family: PingFangSC-Regular, PingFang SC;
|
|
font-weight: 500;
|
|
color: #ff4757;
|
|
|
|
&.deduction {
|
|
color: #ff4757;
|
|
}
|
|
|
|
&.final {
|
|
font-size: 32rpx;
|
|
font-weight: bold;
|
|
color: #ff4757;
|
|
}
|
|
}
|
|
}
|
|
|
|
.total-price {
|
|
padding-top: 12rpx;
|
|
margin-top: 12rpx;
|
|
border-top: 1rpx solid #e8e8e8;
|
|
|
|
.text {
|
|
font-size: 28rpx;
|
|
font-weight: 600;
|
|
color: #333;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 积分兑换弹窗样式
|
|
.points-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,
|
|
.popup-confirm {
|
|
font-size: 28rpx;
|
|
color: $text-secondary;
|
|
padding: 8rpx;
|
|
cursor: pointer;
|
|
transition: color 0.3s;
|
|
|
|
&:active {
|
|
color: $text-primary;
|
|
}
|
|
}
|
|
|
|
.popup-confirm {
|
|
color: $primary-color;
|
|
font-weight: 600;
|
|
}
|
|
}
|
|
|
|
.popup-content {
|
|
padding: 30rpx;
|
|
max-height: 60vh;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
// 兑换规则
|
|
.exchange-rule {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: 24rpx;
|
|
background: $bg-light;
|
|
border-radius: 16rpx;
|
|
margin-bottom: 30rpx;
|
|
|
|
.rule-title {
|
|
font-size: 28rpx;
|
|
color: $text-primary;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.rule-desc {
|
|
font-size: 26rpx;
|
|
color: $primary-color;
|
|
font-weight: 500;
|
|
}
|
|
}
|
|
|
|
// 当前积分
|
|
.current-points {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: 20rpx 0;
|
|
border-bottom: 1rpx solid $border-color;
|
|
margin-bottom: 30rpx;
|
|
|
|
.points-label {
|
|
font-size: 28rpx;
|
|
color: $text-primary;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.points-value {
|
|
font-size: 26rpx;
|
|
color: $success-color;
|
|
font-weight: 600;
|
|
}
|
|
}
|
|
|
|
// 积分选项区域
|
|
.points-options-section {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 20rpx;
|
|
|
|
.option-item {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 24rpx 20rpx;
|
|
border: 2rpx solid #e8e8e8;
|
|
border-radius: 16rpx;
|
|
background: #ffffff;
|
|
cursor: pointer;
|
|
transition: all 0.3s;
|
|
|
|
&.active {
|
|
border-color: $primary-color;
|
|
background: rgba(116, 165, 170, 0.05);
|
|
}
|
|
|
|
&:active {
|
|
transform: scale(0.98);
|
|
}
|
|
|
|
.option-radio {
|
|
width: 40rpx;
|
|
height: 40rpx;
|
|
border: 2rpx solid #ddd;
|
|
border-radius: 50%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
margin-right: 24rpx;
|
|
transition: all 0.3s;
|
|
|
|
.radio-dot {
|
|
width: 20rpx;
|
|
height: 20rpx;
|
|
background: $primary-color;
|
|
border-radius: 50%;
|
|
}
|
|
}
|
|
|
|
&.active .option-radio {
|
|
border-color: $primary-color;
|
|
}
|
|
|
|
.option-content {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8rpx;
|
|
|
|
.option-title {
|
|
font-size: 30rpx;
|
|
color: $text-primary;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.option-desc {
|
|
font-size: 24rpx;
|
|
color: #999;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 底部支付区域
|
|
.payment-bottom {
|
|
width: 100%;
|
|
min-height: 166rpx;
|
|
background: #ffffff;
|
|
box-shadow: 0rpx -3rpx 9rpx 1rpx rgba(227, 229, 232, 0.5);
|
|
display: flex;
|
|
position: fixed;
|
|
bottom: 0;
|
|
padding: 20rpx 20rpx 40rpx;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
|
|
.total-amount {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: flex-start;
|
|
|
|
.total-label {
|
|
font-size: 24rpx;
|
|
color: #666666;
|
|
margin-bottom: 4rpx;
|
|
}
|
|
|
|
.total-price {
|
|
font-size: 32rpx;
|
|
font-weight: bold;
|
|
color: #ff4757;
|
|
}
|
|
}
|
|
|
|
.btn {
|
|
width: 250rpx;
|
|
height: 80rpx;
|
|
background: #74a5aa;
|
|
border-radius: 40rpx;
|
|
text-align: center;
|
|
line-height: 80rpx;
|
|
font-weight: bold;
|
|
font-size: 32rpx;
|
|
color: #ffffff;
|
|
transition: all 0.3s ease;
|
|
|
|
&.loading {
|
|
background: #cccccc;
|
|
opacity: 0.8;
|
|
pointer-events: none;
|
|
}
|
|
}
|
|
}
|
|
|
|
.btn-list {
|
|
width: 100%;
|
|
min-height: 166rpx;
|
|
background: #ffffff;
|
|
box-shadow: 0rpx -3rpx 9rpx 1rpx rgba(227, 229, 232, 0.5);
|
|
display: flex;
|
|
position: fixed;
|
|
bottom: 0;
|
|
padding: 20rpx 20rpx 40rpx;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
.btn {
|
|
width: 250rpx;
|
|
height: 80rpx;
|
|
background: #74a5aa;
|
|
border-radius: 40rpx;
|
|
text-align: center;
|
|
line-height: 80rpx;
|
|
|
|
font-weight: bold;
|
|
font-size: 32rpx;
|
|
color: #ffffff;
|
|
transition: all 0.3s ease;
|
|
|
|
&.loading {
|
|
background: #cccccc;
|
|
opacity: 0.8;
|
|
pointer-events: none;
|
|
}
|
|
}
|
|
}
|
|
.contacts {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
height: 100%;
|
|
image {
|
|
width: 36rpx;
|
|
height: 36rpx;
|
|
}
|
|
.contacts-left {
|
|
.name-phone {
|
|
display: flex;
|
|
align-items: baseline;
|
|
.name {
|
|
font-size: 32rpx;
|
|
font-family: PingFang SC;
|
|
font-weight: 400;
|
|
color: #222222;
|
|
}
|
|
.phone {
|
|
margin-left: 27rpx;
|
|
font-size: 25rpx;
|
|
font-family: PingFang SC;
|
|
font-weight: 400;
|
|
color: #666666;
|
|
}
|
|
}
|
|
.adds {
|
|
font-size: 27rpx;
|
|
font-family: PingFang SC;
|
|
font-weight: 400;
|
|
color: #6c7a94;
|
|
margin-top: 20rpx;
|
|
max-width: 500rpx;
|
|
}
|
|
}
|
|
}
|
|
.people-popup {
|
|
padding: 26rpx;
|
|
min-height: 800rpx;
|
|
|
|
.top-box {
|
|
height: 80rpx;
|
|
|
|
.top {
|
|
position: fixed;
|
|
left: 0;
|
|
right: 0;
|
|
color: #000;
|
|
height: 80rpx;
|
|
font-size: 0;
|
|
overflow: hidden;
|
|
padding: 0 26rpx;
|
|
|
|
text {
|
|
text-align: left;
|
|
font-size: 31rpx;
|
|
font-weight: 400;
|
|
color: #000000;
|
|
}
|
|
|
|
.confirm {
|
|
font-weight: 400;
|
|
color: #000000;
|
|
}
|
|
}
|
|
}
|
|
|
|
.popup-list {
|
|
height: 666rpx;
|
|
overflow: scroll;
|
|
|
|
.popup-item {
|
|
border-radius: 12rpx;
|
|
padding: 2rpx;
|
|
margin-top: 24rpx;
|
|
font-size: 24rpx;
|
|
color: #333333;
|
|
font-weight: 400;
|
|
background-color: #ffffff;
|
|
|
|
.item-top {
|
|
border-radius: 12rpx;
|
|
padding: 30rpx 40rpx;
|
|
background-color: #ffffff;
|
|
|
|
img {
|
|
color: #666666;
|
|
width: 40rpx;
|
|
height: 40rpx;
|
|
}
|
|
|
|
.name {
|
|
overflow: hidden;
|
|
font-family: PingFang SC;
|
|
font-weight: 400;
|
|
font-size: 32rpx;
|
|
display: flex;
|
|
align-items: baseline;
|
|
|
|
text {
|
|
color: #666;
|
|
font-size: 25rpx;
|
|
padding: 0 24rpx;
|
|
}
|
|
|
|
.tag {
|
|
padding: 0 8rpx;
|
|
height: 32rpx;
|
|
border-radius: 7rpx;
|
|
line-height: 30rpx;
|
|
text-align: center;
|
|
font-size: 23rpx;
|
|
font-family: PingFang SC;
|
|
font-weight: 500;
|
|
color: #ffffff;
|
|
background: #74a5aa;
|
|
}
|
|
}
|
|
|
|
.com-flex-start {
|
|
margin: 0 0 30rpx;
|
|
}
|
|
|
|
.subtitle {
|
|
font-weight: 400;
|
|
flex: 1;
|
|
text-align: left;
|
|
margin-top: 33rpx;
|
|
color: #333333;
|
|
font-size: 25rpx;
|
|
}
|
|
}
|
|
}
|
|
|
|
.popup-item.active {
|
|
background: #74a5aa;
|
|
}
|
|
}
|
|
|
|
.button {
|
|
text-align: center;
|
|
width: 100%;
|
|
height: 80rpx;
|
|
line-height: 80rpx;
|
|
background-color: #ffffff;
|
|
border-radius: 40rpx;
|
|
font-family: PingFang SC;
|
|
font-weight: 400;
|
|
font-size: 33rpx;
|
|
color: #000000;
|
|
}
|
|
}
|
|
|
|
.person-info {
|
|
padding: 30rpx 30rpx 15rpx 30rpx;
|
|
background: #fff;
|
|
margin-top: 30rpx;
|
|
border-radius: 16rpx;
|
|
}
|
|
.person-title {
|
|
font-size: 32rpx;
|
|
font-weight: bold;
|
|
color: #000;
|
|
}
|
|
.line {
|
|
border-bottom: 1px solid #e3e5e8;
|
|
}
|
|
.flex {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
.left {
|
|
width: 140rpx;
|
|
height: 104rpx;
|
|
line-height: 104rpx;
|
|
font-family: PingFang;
|
|
font-weight: bold;
|
|
font-size: 31rpx;
|
|
color: #000000;
|
|
}
|
|
.input {
|
|
font-size: 31rpx;
|
|
font-weight: 400;
|
|
text-align: right;
|
|
}
|
|
.remark {
|
|
padding: 30rpx;
|
|
display: flex;
|
|
align-items: center;
|
|
width: 698rpx;
|
|
min-height: 120rpx;
|
|
background: #ffffff;
|
|
margin: 0 auto;
|
|
border-radius: 14rpx;
|
|
.remark-title {
|
|
font-size: 31rpx;
|
|
font-family: PingFang SC;
|
|
font-weight: bold;
|
|
color: #000000;
|
|
flex-shrink: 0;
|
|
}
|
|
input {
|
|
margin-left: 64rpx;
|
|
width: 500rpx;
|
|
font-size: 31rpx;
|
|
}
|
|
}
|
|
.sb {
|
|
justify-content: space-between;
|
|
}
|
|
.tag {
|
|
margin-top: 10rpx;
|
|
// display: flex;
|
|
// align-items: center;
|
|
.tag-item {
|
|
background: rgba(116, 165, 170, 0.08);
|
|
border-radius: 4rpx;
|
|
padding: 2rpx 6rpx;
|
|
font-size: 20rpx;
|
|
font-family: PingFangSC-Regular, PingFang SC;
|
|
font-weight: 400;
|
|
color: rgba(116, 165, 170, 1);
|
|
margin-right: 18rpx;
|
|
}
|
|
}
|
|
.flex-c {
|
|
display: flex;
|
|
flex-direction: column;
|
|
// justify-content: space-between;
|
|
}
|
|
.new-box {
|
|
background: #fff;
|
|
width: 698rpx;
|
|
margin: 0 auto 20rpx;
|
|
border-radius: 14rpx;
|
|
}
|
|
|
|
// 供应商卡片样式
|
|
.supplier-card {
|
|
background-color: #ffffff;
|
|
border-radius: 16rpx;
|
|
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
|
|
width: 697rpx;
|
|
margin: 30rpx auto;
|
|
overflow: hidden;
|
|
border: 1rpx solid #f0f0f0;
|
|
}
|
|
|
|
// 供应商标题样式
|
|
.supplier-header {
|
|
padding: 20rpx 24rpx;
|
|
background: #ffffff;
|
|
|
|
.supplier-name {
|
|
font-size: 30rpx;
|
|
font-weight: 600;
|
|
color: #333333;
|
|
}
|
|
}
|
|
|
|
// 供应商商品列表样式
|
|
.supplier-goods {
|
|
padding: 0;
|
|
|
|
.commodity-item {
|
|
border-bottom: 1rpx solid #f0f0f0;
|
|
|
|
&:last-child {
|
|
border-bottom: none;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 供应商备注样式
|
|
.supplier-remark {
|
|
background-color: #ffffff;
|
|
padding: 20rpx 24rpx;
|
|
border-top: 1rpx solid #f0f0f0;
|
|
|
|
.section-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
min-height: 60rpx;
|
|
|
|
.section-label {
|
|
font-size: 28rpx;
|
|
color: #333333;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.note-input {
|
|
flex: 1;
|
|
margin-left: 40rpx;
|
|
|
|
input {
|
|
font-size: 26rpx;
|
|
color: #333333;
|
|
text-align: right;
|
|
width: 100%;
|
|
}
|
|
|
|
.placeholder {
|
|
color: #999999;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.tickets-box {
|
|
width: 698rpx;
|
|
margin: 26rpx auto 0;
|
|
border-radius: 13rpx;
|
|
background: #fff;
|
|
height: 120rpx;
|
|
.order-title {
|
|
margin: 31rpx 0 31rpx 30rpx;
|
|
font-size: 31rpx;
|
|
font-family: PingFang SC;
|
|
font-weight: bold;
|
|
color: #000000;
|
|
}
|
|
|
|
.coupon-price {
|
|
color: #ff4757;
|
|
font-size: 30rpx;
|
|
font-weight: bold;
|
|
}
|
|
}
|
|
.commodity-info {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
font-size: 32rpx;
|
|
&:last-child {
|
|
font-size: 24rpx;
|
|
font-family: PingFang SC;
|
|
font-weight: 400;
|
|
color: #666666;
|
|
padding-top: 20rpx;
|
|
}
|
|
.commodity-price {
|
|
color: #ff4757;
|
|
&:before {
|
|
content: "¥";
|
|
font-size: 24rpx;
|
|
}
|
|
}
|
|
}
|
|
.top-line {
|
|
border-top: rgba(216, 216, 216, 1) solid 2rpx;
|
|
}
|
|
.post {
|
|
height: 120rpx;
|
|
padding: 0 30rpx;
|
|
|
|
font-size: 32rpx;
|
|
font-family: PingFang SC;
|
|
font-weight: bold;
|
|
color: #000000;
|
|
}
|
|
|
|
.sendwayArea {
|
|
margin: 26rpx;
|
|
display: flex;
|
|
border: 1px solid #515150;
|
|
border-radius: 13rpx;
|
|
width: fit-content;
|
|
background-color: white;
|
|
height: 94rpx;
|
|
position: relative;
|
|
.sendway-item {
|
|
padding: 26rpx;
|
|
width: 170rpx;
|
|
font-size: 28rpx;
|
|
border-radius: 13rpx;
|
|
font-weight: 500;
|
|
position: absolute;
|
|
top: -2rpx;
|
|
bottom: -2rpx;
|
|
}
|
|
.sendway-item.active {
|
|
background-image: linear-gradient(135deg, #9ee4fe, #7fd491);
|
|
}
|
|
}
|
|
|
|
.add-edit-content {
|
|
background-color: white;
|
|
padding: 0 20rpx;
|
|
border-radius: 20rpx;
|
|
}
|
|
|
|
.coupon-btn {
|
|
color: #999999;
|
|
display: flex;
|
|
align-items: center;
|
|
.select {
|
|
display: block;
|
|
width: 153rpx;
|
|
height: 40rpx;
|
|
background: #c3282e;
|
|
border-radius: 9rpx;
|
|
font-weight: 500;
|
|
font-size: 24rpx;
|
|
color: #ffffff;
|
|
text-align: center;
|
|
line-height: 40rpx;
|
|
font-family: PingFang SC;
|
|
margin-right: 20rpx;
|
|
}
|
|
}
|
|
.shop-name {
|
|
font-weight: bold;
|
|
font-size: 31rpx;
|
|
color: #333333;
|
|
padding-bottom: 12rpx;
|
|
min-height: fit-content;
|
|
}
|
|
</style>
|
|
|