| | |
| | | <template> |
| | | <div class="container mx-auto px-4 py-8 max-w-6xl"> |
| | | <h1 class="text-2xl font-bold mb-6">填写并核对订单信息</h1> |
| | | |
| | | <!-- 收货人信息 --> |
| | | <div class="bg-white p-6 rounded-lg shadow-sm mb-4"> |
| | | <div class="flex justify-between items-center mb-4"> |
| | | <h2 class="text-lg font-medium">收货人信息</h2> |
| | | <el-button type="primary" link @click="showAddressDialog = true">新增收货地址</el-button> |
| | | <div class="container mx-auto py-8"> |
| | | <div class="bg-white rounded-sm"> |
| | | <div class="border-b border-[#f2f2f2]"> |
| | | <h2 class="text-[16px] font-bold px-6 py-4">收货人信息</h2> |
| | | </div> |
| | | |
| | | <el-skeleton :loading="loading.addresses" :rows="3" animated> |
| | | <template #default> |
| | | <el-radio-group v-model="selectedAddress" class="w-full"> |
| | | <el-radio |
| | | v-for="address in addresses" |
| | | :key="address.id" |
| | | :label="address.id" |
| | | class="!flex p-4 border rounded-lg mb-2 hover:bg-gray-50" |
| | | > |
| | | <div class="flex-1"> |
| | | <div class="flex items-center gap-4"> |
| | | <span class="font-medium">{{ address.name }} {{ address.city }}</span> |
| | | <span class="text-gray-600">{{ address.phone }}</span> |
| | | <el-tag size="small" type="success" v-if="address.isDefault">默认地址</el-tag> |
| | | </div> |
| | | <div class="text-gray-600 mt-1">{{ address.fullAddress }}</div> |
| | | </div> |
| | | </el-radio> |
| | | </el-radio-group> |
| | | </template> |
| | | </el-skeleton> |
| | | <div class="p-6"> |
| | | <div class="flex items-center justify-between mb-4"> |
| | | <el-button type="primary" link @click="showAddressDialog = true"> |
| | | 新增收货地址 |
| | | </el-button> |
| | | </div> |
| | | <div class="bg-[#f5f5f5] rounded p-4" v-if="selectedAddress"> |
| | | <div class="flex items-center justify-between"> |
| | | <div> |
| | | <span class="font-medium">{{ selectedAddress.name }}</span> |
| | | <span class="ml-4 text-gray-500">{{ selectedAddress.phone }}</span> |
| | | </div> |
| | | <el-tag size="small" type="success" effect="plain" v-if="selectedAddress.isDefault">默认地址</el-tag> |
| | | </div> |
| | | <div class="text-gray-600 mt-2">{{ selectedAddress.fullAddress }}</div> |
| | | </div> |
| | | <div v-else class="bg-[#f5f5f5] text-center py-4 text-gray-500"> |
| | | 请添加收货地址 |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 支付方式 --> |
| | | <div class="bg-white p-6 rounded-lg shadow-sm mb-4"> |
| | | <h2 class="text-lg font-medium mb-4">支付方式</h2> |
| | | <el-radio-group v-model="paymentMethod"> |
| | | <el-radio label="online" class="mr-6">在线支付</el-radio> |
| | | <!-- <el-radio label="cod">货到付款</el-radio> --> |
| | | </el-radio-group> |
| | | <div class="bg-white rounded-sm"> |
| | | <div class="border-b border-[#f2f2f2]"> |
| | | <h2 class="text-[16px] font-bold px-6 py-4">支付方式</h2> |
| | | </div> |
| | | <div class="p-6"> |
| | | <div class="bg-[#f5f5f5] rounded p-4"> |
| | | <el-radio-group v-model="paymentMethod"> |
| | | <el-radio label="online">在线支付</el-radio> |
| | | </el-radio-group> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 送货清单 --> |
| | | <div class="bg-white p-6 rounded-lg shadow-sm mb-4"> |
| | | <div class="flex justify-between items-center mb-4"> |
| | | <h2 class="text-lg font-medium">送货清单</h2> |
| | | <div class="flex items-center gap-4"> |
| | | <el-tooltip content="价格说明"> |
| | | <el-icon><InfoFilled /></el-icon> |
| | | </el-tooltip> |
| | | <!-- <el-link type="primary" @click="goToCart">返回修改购物车</el-link> --> |
| | | </div> |
| | | <!-- 配送方式 --> |
| | | <div class="bg-white rounded-sm"> |
| | | <div class="border-b border-[#f2f2f2]"> |
| | | <h2 class="text-[16px] font-bold px-6 py-4">配送方式</h2> |
| | | </div> |
| | | |
| | | <div class="bg-blue-50 p-4 rounded-lg mb-4"> |
| | | <div class="flex justify-between mb-4"> |
| | | <div class="flex gap-4"> |
| | | <span>配送方式:</span> |
| | | <el-radio-group v-model="deliveryMethod"> |
| | | <el-radio label="jd">顺丰快递</el-radio> |
| | | <el-radio label="self">申通快递</el-radio> |
| | | <el-radio label="self">圆通快递</el-radio> |
| | | <el-radio label="self">邮政快递</el-radio> |
| | | </el-radio-group> |
| | | </div> |
| | | <!-- <el-link type="primary" @click="showDeliveryDialog = true">修改</el-link> --> |
| | | </div> |
| | | <div class="text-gray-600">配送时间:{{ deliveryTime }}</div> |
| | | </div> |
| | | |
| | | <!-- 商品列表 --> |
| | | <el-skeleton :loading="loading.products" :rows="2" animated> |
| | | <template #default> |
| | | <div v-for="product in products" :key="product.id" class="border-t py-4"> |
| | | <div class="text-gray-600 mb-4">商家:{{ product.shopName }}</div> |
| | | <div class="flex gap-4"> |
| | | <el-image :src="product.image" style="width: 80px; height: 80px" fit="cover" :preview-src-list="[product.image]"> |
| | | <template #error> |
| | | <div class="image-slot"> |
| | | <el-icon><Picture /></el-icon> |
| | | </div> |
| | | </template> |
| | | </el-image> |
| | | <div class="flex-1"> |
| | | <div class="flex justify-between"> |
| | | <div> |
| | | <div class="font-medium">{{ product.name }}</div> |
| | | <div class="text-gray-500 mt-1">厂商:{{ product.specs }}</div> |
| | | </div> |
| | | <div class="text-right"> |
| | | <div class="text-red-500">¥{{ product.price.toFixed(2) }}</div> |
| | | <div class="text-gray-600">x{{ product.quantity }}</div> |
| | | <div>{{ product.stock > 0 ? '有货' : '无货' }}</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="p-6"> |
| | | <div class="bg-[#f5f5f5] rounded p-4"> |
| | | <div class="flex items-center justify-between"> |
| | | <div class="flex items-center gap-6"> |
| | | <el-radio-group v-model="deliveryMethod"> |
| | | <el-radio label="sf">顺丰速运</el-radio> |
| | | <el-radio label="zt">中通快递</el-radio> |
| | | <el-radio label="yd">韵达快递</el-radio> |
| | | <el-radio label="ems">EMS</el-radio> |
| | | </el-radio-group> |
| | | </div> |
| | | <!-- <div class="text-gray-500 text-sm"> |
| | | <i class="el-icon-time mr-1"></i> |
| | | 配送时间:预计3月10日(周一) 09:00-15:00 送达 |
| | | </div> --> |
| | | </div> |
| | | </template> |
| | | </el-skeleton> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 发票信息 --> |
| | | <div class="bg-white p-6 rounded-lg shadow-sm mb-4"> |
| | | <div class="flex justify-between items-center"> |
| | | <h2 class="text-lg font-medium">发票信息</h2> |
| | | <el-tooltip content="开企业抬头发票需要填写纳税人识别号,以免影响报销"> |
| | | <el-icon><InfoFilled /></el-icon> |
| | | </el-tooltip> |
| | | <div class="bg-white rounded-sm"> |
| | | <div class="border-b border-[#f2f2f2]"> |
| | | <h2 class="text-[16px] font-bold px-6 py-4">发票信息</h2> |
| | | </div> |
| | | <div class="mt-4"> |
| | | <el-button :disabled="loading.submit" @click="invoice.type = 'none'">不开发票</el-button> |
| | | <el-button type="primary" link @click="showInvoiceDialog = true">修改</el-button> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 优惠/礼品卡 --> |
| | | <div class="bg-white p-6 rounded-lg shadow-sm mb-4"> |
| | | <el-collapse v-model="activeCollapse"> |
| | | <el-collapse-item title="使用优惠/礼品卡/抵用" name="coupons"> |
| | | <el-skeleton :loading="loading.coupons" :rows="2" animated> |
| | | <template #default> |
| | | <div class="p-4" v-if="coupons.length"> |
| | | <div v-for="coupon in coupons" :key="coupon.id" class="mb-2"> |
| | | <el-checkbox v-model="coupon.selected"> {{ coupon.name }} - 优惠{{ coupon.amount }}元 </el-checkbox> |
| | | </div> |
| | | <div class="p-6"> |
| | | <div class="flex items-center justify-between mb-4"> |
| | | <div class="flex items-center gap-4"> |
| | | <el-radio-group v-model="invoiceForm.needInvoice" class="flex items-center"> |
| | | <el-radio :label="false">不开发票</el-radio> |
| | | <el-radio :label="true">开发票</el-radio> |
| | | </el-radio-group> |
| | | </div> |
| | | </div> |
| | | <div v-if="invoiceForm.needInvoice" class="bg-[#f5f5f5] rounded p-4"> |
| | | <el-form :model="invoiceForm" label-width="100px"> |
| | | <el-form-item label="发票抬头"> |
| | | <div class="flex items-center gap-4" style="flex-direction: column;"> |
| | | <el-radio-group v-model="invoiceForm.type" class="mb-4"> |
| | | <el-radio label="personal">个人</el-radio> |
| | | <el-radio label="company">单位</el-radio> |
| | | </el-radio-group> |
| | | |
| | | <template v-if="invoiceForm.type === 'personal'"> |
| | | <div class="w-full"> |
| | | <el-input v-model="invoiceForm.personalName" placeholder="请填写个人姓名" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <template v-if="invoiceForm.type === 'company'"> |
| | | <div class="space-y-4"> |
| | | <el-input v-model="invoiceForm.title" placeholder="请填写单位名称" /> |
| | | <el-input v-model="invoiceForm.taxNumber" placeholder="请填写纳税人识别号" /> |
| | | <div class="flex gap-4"> |
| | | <el-input v-model="invoiceForm.address" placeholder="请填写单位地址" /> |
| | | <el-input v-model="invoiceForm.phone" placeholder="请填写单位电话" /> |
| | | </div> |
| | | <div class="flex gap-4"> |
| | | <el-input v-model="invoiceForm.bank" placeholder="请填写开户银行" /> |
| | | <el-input v-model="invoiceForm.bankAccount" placeholder="请填写银行账号" /> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | </div> |
| | | <div class="p-4" v-else>暂无可用优惠</div> |
| | | </template> |
| | | </el-skeleton> |
| | | </el-collapse-item> |
| | | </el-collapse> |
| | | </div> |
| | | |
| | | <!-- 订单金额 --> |
| | | <div class="bg-white p-6 rounded-lg shadow-sm"> |
| | | <div class="flex justify-end text-right"> |
| | | <div> |
| | | <div class="flex justify-between gap-8 mb-2"> |
| | | <span>商品总额:</span> |
| | | <span>¥{{ orderAmount.subtotal.toFixed(2) }}</span> |
| | | </div> |
| | | <div class="flex justify-between gap-8 mb-2"> |
| | | <span>运费:</span> |
| | | <span>¥{{ orderAmount.shipping.toFixed(2) }}</span> |
| | | </div> |
| | | <div class="flex justify-between gap-8 mb-2" v-if="orderAmount.discount > 0"> |
| | | <span>优惠金额:</span> |
| | | <span class="text-red-500">-¥{{ orderAmount.discount.toFixed(2) }}</span> |
| | | </div> |
| | | <div class="flex justify-between gap-8 text-lg font-medium text-red-500"> |
| | | <span>应付总额:</span> |
| | | <span>¥{{ orderAmount.total.toFixed(2) }}</span> |
| | | </div> |
| | | <div class="text-gray-500 text-sm mt-2">寄送至:{{ selectedAddressText }}</div> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 提交订单按钮 --> |
| | | <div class="flex justify-end mt-6"> |
| | | <el-button type="success" size="large" :loading="loading.submit" @click="submitOrder"> 提交订单 </el-button> |
| | | <!-- 商品清单 --> |
| | | <div class="bg-white rounded-sm"> |
| | | <div class="border-b border-[#f2f2f2]"> |
| | | <h2 class="text-[16px] font-bold px-6 py-4">商品清单</h2> |
| | | </div> |
| | | <div class="p-6"> |
| | | <div class="rounded overflow-hidden"> |
| | | <div class="bg-[#f5f5f5] p-4 flex items-center text-gray-500 text-sm"> |
| | | <div class="flex-1">商品信息</div> |
| | | <div class="w-[160px] text-center">单价</div> |
| | | <div class="w-[160px] text-center">数量</div> |
| | | <div class="w-[160px] text-center">小计</div> |
| | | </div> |
| | | <div v-for="item in selectedItems" :key="item.addID" class="p-4 flex items-center border-t border-[#f0f0f0] hover:bg-[#f5f5f5]"> |
| | | <div class="flex-1 flex items-center gap-4"> |
| | | <el-image :src="item.image" class="w-20 h-20 object-cover border" /> |
| | | <div class="flex-1"> |
| | | <div class="text-base font-medium mb-2 line-clamp-2">{{ item.name }}</div> |
| | | <div class="text-gray-500 text-[12px] mb-1">厂商:{{ item.companyName }}</div> |
| | | <div class="text-gray-500 text-[12px]">型号:{{ item.model }}</div> |
| | | </div> |
| | | </div> |
| | | <div class="w-[160px] text-center">¥{{ item.price.toFixed(2) }}</div> |
| | | <div class="w-[160px] text-center">{{ item.quantity }}</div> |
| | | <div class="w-[160px] text-center text-[#e4393c] font-medium">¥{{ (item.price * item.quantity).toFixed(2) }}</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 订单金额 --> |
| | | <div class="bg-white rounded-sm"> |
| | | <div class="border-b border-[#f2f2f2]"> |
| | | <h2 class="text-[16px] font-bold px-6 py-4">订单金额</h2> |
| | | </div> |
| | | <div class="p-6"> |
| | | <div class="flex justify-end"> |
| | | <div class="w-[400px] space-y-3"> |
| | | <div class="flex justify-between text-gray-600"> |
| | | <span>商品总额:</span> |
| | | <span>¥{{ totalAmount.toFixed(2) }}</span> |
| | | </div> |
| | | <div class="flex justify-between text-gray-600"> |
| | | <span>运费:</span> |
| | | <span>¥{{ shippingFee.toFixed(2) }}</span> |
| | | </div> |
| | | <div class="flex justify-between items-center pt-4 border-t text-xl"> |
| | | <span>应付金额:</span> |
| | | <span class="text-[#e4393c] font-bold">¥{{ finalAmount.toFixed(2) }}</span> |
| | | </div> |
| | | <div class="flex justify-end mt-4"> |
| | | <el-button |
| | | type="danger" |
| | | size="large" |
| | | class="w-[180px]" |
| | | @click="submitOrder" |
| | | > |
| | | 提交订单 |
| | | </el-button> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 新增地址对话框 --> |
| | | <el-dialog v-model="showAddressDialog" title="新增收货地址" width="500px"> |
| | | <el-form :model="newAddress" :rules="addressRules" ref="addressForm"> |
| | | <el-form-item label="收货人" prop="name"> |
| | | <el-input v-model="newAddress.name" /> |
| | | <el-dialog v-model="showAddressDialog" title="新增收货地址" width="500px" destroy-on-close> |
| | | <el-form :model="addressForm" label-width="80px"> |
| | | <el-form-item label="收货人"> |
| | | <el-input v-model="addressForm.name" placeholder="请输入收货人姓名" /> |
| | | </el-form-item> |
| | | <el-form-item label="手机号码" prop="phone"> |
| | | <el-input v-model="newAddress.phone" /> |
| | | <el-form-item label="手机号码"> |
| | | <el-input v-model="addressForm.phone" placeholder="请输入手机号码" /> |
| | | </el-form-item> |
| | | <el-form-item label="所在地区" prop="region"> |
| | | <el-cascader v-model="newAddress.region" :options="regionOptions" placeholder="请选择所在地区" /> |
| | | <el-form-item label="所在地区"> |
| | | <el-cascader |
| | | v-model="addressForm.region" |
| | | :options="regionOptions" |
| | | placeholder="请选择所在地区" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="详细地址" prop="address"> |
| | | <el-input v-model="newAddress.address" type="textarea" :rows="2" /> |
| | | <el-form-item label="详细地址"> |
| | | <el-input |
| | | v-model="addressForm.detail" |
| | | type="textarea" |
| | | placeholder="请输入详细地址" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-checkbox v-model="newAddress.isDefault">设为默认地址</el-checkbox> |
| | | <el-checkbox v-model="addressForm.isDefault">设为默认地址</el-checkbox> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <div class="flex justify-end gap-2"> |
| | | <el-button @click="showAddressDialog = false">取消</el-button> |
| | | <el-button type="primary" @click="saveAddress" :loading="loading.saveAddress"> 保存 </el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <!-- 发票信息对话框 --> |
| | | <el-dialog v-model="showInvoiceDialog" title="发票信息" width="500px"> |
| | | <el-form :model="invoice" :rules="invoiceRules" ref="invoiceForm"> |
| | | <el-form-item label="发票类型" prop="type"> |
| | | <el-radio-group v-model="invoice.type"> |
| | | <el-radio label="personal">个人</el-radio> |
| | | <el-radio label="company">单位</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | <template v-if="invoice.type === 'company'"> |
| | | <el-form-item label="单位名称" prop="companyName"> |
| | | <el-input v-model="invoice.companyName" /> |
| | | </el-form-item> |
| | | <el-form-item label="税号" prop="taxNumber"> |
| | | <el-input v-model="invoice.taxNumber" /> |
| | | </el-form-item> |
| | | </template> |
| | | </el-form> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="showInvoiceDialog = false">取消</el-button> |
| | | <el-button type="primary" @click="saveInvoice" :loading="loading.saveInvoice"> 确定 </el-button> |
| | | </span> |
| | | <el-button type="primary" @click="saveAddress">保存</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { ref, computed, onMounted } from 'vue'; |
| | | import { ref, computed } from 'vue'; |
| | | import { useRouter } from 'vue-router'; |
| | | import { ElMessage, ElMessageBox } from 'element-plus'; |
| | | import { InfoFilled, Picture } from '@element-plus/icons-vue'; |
| | | import { SERVE_URL } from '@/constants'; |
| | | import type { FormInstance } from 'element-plus'; |
| | | |
| | | import { ElMessage } from 'element-plus'; |
| | | import { CreditCard, Money } from '@element-plus/icons-vue'; |
| | | import { useCartStore } from '@/stores/useCartStore'; |
| | | import wechat from '@/assets/icons/wechat-pay.svg'; |
| | | import alipay from '@/assets/icons/alipay.svg'; |
| | | const router = useRouter(); |
| | | const cartStore = useCartStore(); |
| | | |
| | | // 加载状态 |
| | | const loading = ref({ |
| | | addresses: false, |
| | | products: false, |
| | | coupons: false, |
| | | submit: false, |
| | | saveAddress: false, |
| | | saveInvoice: false, |
| | | // 选中的商品 |
| | | const selectedItems = computed(() => { |
| | | return cartStore.items.filter(item => item.selected); |
| | | }); |
| | | |
| | | // 地址相关 |
| | | const addresses = ref([ |
| | | { |
| | | id: 1, |
| | | name: '义维流体科技有限公司', |
| | | city: '上海', |
| | | phone: '189****7818', |
| | | fullAddress: '上海 闵行区 江月路 999号', |
| | | isDefault: true, |
| | | }, |
| | | ]); |
| | | |
| | | const selectedAddress = ref(1); |
| | | // 收货地址相关 |
| | | const showAddressDialog = ref(false); |
| | | const showDeliveryDialog = ref(false); |
| | | const addressForm = ref<FormInstance>(); |
| | | const newAddress = ref({ |
| | | const selectedAddress = ref(null); |
| | | const addressForm = ref({ |
| | | name: '', |
| | | phone: '', |
| | | region: [], |
| | | address: '', |
| | | isDefault: false, |
| | | detail: '', |
| | | isDefault: false |
| | | }); |
| | | |
| | | // 地区选项数据 |
| | | // 支付方式 |
| | | const paymentMethod = ref('online'); |
| | | |
| | | // 配送方式 |
| | | const deliveryMethod = ref('sf'); |
| | | |
| | | // 发票信息 |
| | | const invoiceForm = ref({ |
| | | needInvoice: false, |
| | | type: 'personal', |
| | | personalName: '', |
| | | title: '', |
| | | taxNumber: '', |
| | | address: '', |
| | | phone: '', |
| | | bank: '', |
| | | bankAccount: '' |
| | | }); |
| | | |
| | | // 金额计算 |
| | | const totalAmount = computed(() => { |
| | | return selectedItems.value.reduce((total, item) => total + item.price * item.quantity, 0); |
| | | }); |
| | | |
| | | const shippingFee = computed(() => { |
| | | return deliveryMethod.value === 'express' ? 0 : 0; |
| | | }); |
| | | |
| | | const finalAmount = computed(() => { |
| | | return totalAmount.value + shippingFee.value; |
| | | }); |
| | | |
| | | // 保存地址 |
| | | const saveAddress = () => { |
| | | if (!addressForm.value.name || !addressForm.value.phone || !addressForm.value.detail) { |
| | | ElMessage.warning('请填写完整的地址信息'); |
| | | return; |
| | | } |
| | | // 这里应该调用API保存地址 |
| | | selectedAddress.value = { |
| | | name: addressForm.value.name, |
| | | phone: addressForm.value.phone, |
| | | fullAddress: addressForm.value.detail, |
| | | isDefault: addressForm.value.isDefault |
| | | }; |
| | | |
| | | // 重置表单内容 |
| | | addressForm.value = { |
| | | name: '', |
| | | phone: '', |
| | | region: [], |
| | | detail: '', |
| | | isDefault: false |
| | | }; |
| | | |
| | | showAddressDialog.value = false; |
| | | ElMessage.success('地址保存成功'); |
| | | }; |
| | | |
| | | // 提交订单 |
| | | const submitOrder = () => { |
| | | if (!selectedAddress.value) { |
| | | ElMessage.warning('请选择收货地址'); |
| | | return; |
| | | } |
| | | |
| | | // 创建订单对象 |
| | | const order = { |
| | | orderNo: 'DD' + Date.now(), |
| | | items: selectedItems.value, |
| | | address: selectedAddress.value, |
| | | paymentMethod: '在线支付', |
| | | deliveryMethod: getDeliveryMethodName(deliveryMethod.value), |
| | | invoice: invoiceForm.value.needInvoice ? invoiceForm.value : null, |
| | | totalAmount: totalAmount.value, |
| | | shippingFee: shippingFee.value, |
| | | finalAmount: finalAmount.value, |
| | | createTime: new Date().toLocaleString() |
| | | }; |
| | | |
| | | // 保存订单信息 |
| | | localStorage.setItem('currentOrder', JSON.stringify(order)); |
| | | |
| | | // 清除购物车中已下单的商品 |
| | | selectedItems.value.forEach(item => { |
| | | cartStore.removeFromCart(item.addID); |
| | | }); |
| | | |
| | | // 跳转到支付页面 |
| | | router.push('/payment'); |
| | | }; |
| | | |
| | | // 获取配送方式名称 |
| | | const getDeliveryMethodName = (method: string) => { |
| | | const methodMap = { |
| | | sf: '顺丰速运', |
| | | zt: '中通快递', |
| | | yd: '韵达快递', |
| | | ems: 'EMS' |
| | | }; |
| | | return methodMap[method] || method; |
| | | }; |
| | | |
| | | // 地区选项数据(示例) |
| | | const regionOptions = ref([ |
| | | { |
| | | value: 'shanghai', |
| | | label: '上海', |
| | | children: [ |
| | | { |
| | | value: 'minhang', |
| | | label: '闵行区', |
| | | children: [ |
| | | { |
| | | value: 'pujiang', |
| | | label: '江月路', |
| | | }, |
| | | ], |
| | | value: 'pudong', |
| | | label: '浦东新区' |
| | | }, |
| | | ], |
| | | }, |
| | | ]); |
| | | |
| | | const addressRules = { |
| | | name: [{ required: true, message: '请输入收货人姓名', trigger: 'blur' }], |
| | | phone: [ |
| | | { required: true, message: '请输入手机号码', trigger: 'blur' }, |
| | | { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }, |
| | | ], |
| | | region: [{ required: true, message: '请选择所在地区', trigger: 'change' }], |
| | | address: [{ required: true, message: '请输入详细地址', trigger: 'blur' }], |
| | | }; |
| | | |
| | | // 支付和配送方式 |
| | | const paymentMethod = ref('online'); |
| | | const deliveryMethod = ref('jd'); |
| | | const deliveryTime = ref('预计三天后送达'); |
| | | |
| | | // 商品相关 |
| | | const products = ref([]); |
| | | |
| | | // 发票相关 |
| | | const showInvoiceDialog = ref(false); |
| | | const invoiceForm = ref<FormInstance>(); |
| | | const invoice = ref({ |
| | | type: 'none', |
| | | companyName: '', |
| | | taxNumber: '', |
| | | }); |
| | | const invoiceRules = { |
| | | companyName: [{ required: true, message: '请输入单位名称', trigger: 'blur' }], |
| | | taxNumber: [{ required: true, message: '请输入税号', trigger: 'blur' }], |
| | | }; |
| | | |
| | | // 优惠券相关 |
| | | const activeCollapse = ref(['']); |
| | | const coupons = ref([ |
| | | { |
| | | id: 1, |
| | | name: '新人专享券', |
| | | amount: 5, |
| | | selected: false, |
| | | }, |
| | | { |
| | | id: 2, |
| | | name: '满30减3元券', |
| | | amount: 3, |
| | | selected: false, |
| | | }, |
| | | ]); |
| | | |
| | | // 订单金额计算 |
| | | const orderAmount = computed(() => { |
| | | const subtotal = products.value.reduce((sum, product) => { |
| | | return sum + product.price * product.quantity; |
| | | }, 0); |
| | | |
| | | const discount = coupons.value.filter((coupon) => coupon.selected).reduce((sum, coupon) => sum + coupon.amount, 0); |
| | | |
| | | return { |
| | | subtotal, |
| | | shipping: 0, |
| | | discount, |
| | | total: subtotal - discount, |
| | | }; |
| | | }); |
| | | |
| | | onMounted(() => { |
| | | // 从localStorage获取产品信息 |
| | | const savedProduct = localStorage.getItem('currentProduct'); |
| | | if (savedProduct) { |
| | | const productData = JSON.parse(savedProduct); |
| | | |
| | | // 合并默认值和保存的产品数据 |
| | | let productItem = { |
| | | id: productData.Id, |
| | | name: productData.ModelType, |
| | | applicationCode: productData.RecordNumber, |
| | | price: productData.Price, |
| | | image: `${SERVE_URL}${productData.PhysicalPicturePath}`, |
| | | quantity: 1, |
| | | stock: 999, |
| | | shopName: productData.Model, |
| | | specs: productData.CompanyName, |
| | | certificatePath: `${SERVE_URL}${productData.CertificatePath}`, |
| | | brand: productData.CompanyName, |
| | | model: productData.Model, |
| | | power: '详询厂家', |
| | | voltage: '详询厂家', |
| | | speed: '详询厂家', |
| | | protection: '详询厂家', |
| | | detailImages: [`${SERVE_URL}${productData.PhysicalPicturePath}`], |
| | | specifications: { |
| | | 产品型号: productData.Model, |
| | | 生产企业: productData.CompanyName, |
| | | 备案编号: productData.RecordNumber, |
| | | 备案时间: productData.RecordTime, |
| | | 能效等级: `${productData.EnergyEfficiencyClass}级`, |
| | | }, |
| | | }; |
| | | console.log(productItem); |
| | | products.value.push(productItem); |
| | | } |
| | | }); |
| | | |
| | | // 选中地址文本 |
| | | const selectedAddressText = computed(() => { |
| | | const address = addresses.value.find((addr) => addr.id === selectedAddress.value); |
| | | if (!address) return ''; |
| | | return `${address.fullAddress} 收货人:${address.name} ${address.phone}`; |
| | | }); |
| | | |
| | | // 保存地址 |
| | | const saveAddress = async () => { |
| | | if (!addressForm.value) return; |
| | | |
| | | await addressForm.value.validate(async (valid) => { |
| | | if (valid) { |
| | | loading.value.saveAddress = true; |
| | | try { |
| | | // 模拟保存地址 |
| | | const newAddr = { |
| | | id: addresses.value.length + 1, |
| | | name: newAddress.value.name, |
| | | city: newAddress.value.region[0], |
| | | phone: newAddress.value.phone, |
| | | fullAddress: `${newAddress.value.region.join(' ')} ${newAddress.value.address}`, |
| | | isDefault: newAddress.value.isDefault, |
| | | }; |
| | | |
| | | addresses.value.push(newAddr); |
| | | showAddressDialog.value = false; |
| | | ElMessage.success('地址保存成功'); |
| | | |
| | | // 如果设为默认地址,更新其他地址的默认状态 |
| | | if (newAddr.isDefault) { |
| | | addresses.value.forEach((addr) => { |
| | | if (addr.id !== newAddr.id) { |
| | | addr.isDefault = false; |
| | | } |
| | | }); |
| | | } |
| | | } catch (error) { |
| | | ElMessage.error('保存地址失败'); |
| | | } finally { |
| | | loading.value.saveAddress = false; |
| | | { |
| | | value: 'xuhui', |
| | | label: '徐汇区' |
| | | } |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | // 保存发票信息 |
| | | const saveInvoice = async () => { |
| | | if (invoice.value.type === 'none' || !invoiceForm.value) { |
| | | showInvoiceDialog.value = false; |
| | | return; |
| | | ] |
| | | } |
| | | |
| | | await invoiceForm.value.validate(async (valid) => { |
| | | if (valid) { |
| | | loading.value.saveInvoice = true; |
| | | try { |
| | | // 模拟保存发票信息 |
| | | showInvoiceDialog.value = false; |
| | | ElMessage.success('发票信息保存成功'); |
| | | } finally { |
| | | loading.value.saveInvoice = false; |
| | | } |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | // 提交订单 |
| | | const submitOrder = async () => { |
| | | // 表单验证 |
| | | if (!selectedAddress.value) { |
| | | ElMessage.warning('请选择收货地址'); |
| | | return; |
| | | } |
| | | |
| | | try { |
| | | loading.value.submit = true; |
| | | |
| | | // 确认提交 |
| | | await ElMessageBox.confirm(`确认提交订单?应付金额:¥${orderAmount.value.total.toFixed(2)}`, '提交订单', { |
| | | confirmButtonText: '确认', |
| | | cancelButtonText: '取消', |
| | | type: 'warning', |
| | | }); |
| | | |
| | | // 模拟订单提交 |
| | | await new Promise((resolve) => setTimeout(resolve, 1000)); |
| | | const orderId = Math.floor(Math.random() * 1000000); |
| | | ElMessage.success('订单提交成功'); |
| | | |
| | | // 根据支付方式跳转 |
| | | if (paymentMethod.value === 'online') { |
| | | router.push(`/payment?orderId=${orderId}`); |
| | | } else { |
| | | router.push(`/order/success?orderId=${orderId}`); |
| | | } |
| | | } catch (error) { |
| | | if (error === 'cancel') return; |
| | | ElMessage.error('提交订单失败'); |
| | | } finally { |
| | | loading.value.submit = false; |
| | | } |
| | | }; |
| | | |
| | | // 返回购物车 |
| | | const goToCart = () => { |
| | | router.push('/cart'); |
| | | }; |
| | | // 其他省市区数据... |
| | | ]); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | :deep(.el-radio__input.is-checked + .el-radio__label) { |
| | | color: inherit; |
| | | :deep(.el-radio__input.is-checked .el-radio__inner) { |
| | | border-color: #e4393c; |
| | | background: #e4393c; |
| | | } |
| | | |
| | | .image-slot { |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | width: 100%; |
| | | height: 100%; |
| | | background: #f5f7fa; |
| | | color: #909399; |
| | | :deep(.el-radio__input.is-checked + .el-radio__label) { |
| | | color: #e4393c; |
| | | } |
| | | |
| | | :deep(.el-button--primary) { |
| | | --el-button-bg-color: #e4393c; |
| | | --el-button-border-color: #e4393c; |
| | | --el-button-hover-bg-color: #f15b5f; |
| | | --el-button-hover-border-color: #f15b5f; |
| | | } |
| | | |
| | | :deep(.el-button--primary.is-plain) { |
| | | --el-button-bg-color: #fff; |
| | | --el-button-border-color: #e4393c; |
| | | --el-button-hover-bg-color: #fff4f4; |
| | | --el-button-hover-border-color: #e4393c; |
| | | --el-button-text-color: #e4393c; |
| | | } |
| | | |
| | | .line-clamp-2 { |
| | | display: -webkit-box; |
| | | -webkit-line-clamp: 2; |
| | | -webkit-box-orient: vertical; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | :deep(.el-form-item__label) { |
| | | color: #666; |
| | | } |
| | | |
| | | :deep(.el-input) { |
| | | --el-input-border-color: #dcdfe6; |
| | | --el-input-hover-border-color: #c0c4cc; |
| | | --el-input-focus-border-color: #e4393c; |
| | | } |
| | | </style> |