From 23e535562d0b1411d1e17345ae2e8d6f18d1bbfa Mon Sep 17 00:00:00 2001
From: qiube <18969599531@163.com>
Date: Fri, 26 Dec 2025 18:13:11 +0800
Subject: [PATCH] =?UTF-8?q?feat(order):=20=E4=BC=98=E5=8C=96=E5=88=9B?=
=?UTF-8?q?=E5=BB=BA=E8=AE=A2=E5=8D=95=E9=A1=B5=E9=9D=A2=E7=9A=84=E5=9C=B0?=
=?UTF-8?q?=E5=9D=80=E5=AD=97=E6=AE=B5=E5=92=8C=E5=BF=85=E5=A1=AB=E9=A1=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 调整新加坡、马来西亚、菲律宾、泰国、越南等国家的必填字段配置
- 将邮编和城市设为PayPal要求的必填项,越南使用省/市/郡/区/坊代替城市
- 重新排列表单字段顺序,优化移动端显示效果
- 添加更多地址信息按钮,将详细地址2放入折叠区域
- 实现地址组件自动更新功能,将省/州、市/郡、区/坊等信息拼接到详细地址1
- 更新国际化文本,添加更多和收起按钮的翻译
- 为创建订单和订单确认页面添加路由元信息,标记为不显示导航栏的客户页面
---
src/i18n/locales.js | 24 +-
src/router/index.js | 6 +-
src/utils/countryConfig.js | 25 +-
src/views/CreateOrder.vue | 618 +++++++++++++++++++++---------------
src/views/OrderConfirm.vue | 156 ++++++++-
src/views/ProductDetail.vue | 293 ++++++++++-------
6 files changed, 732 insertions(+), 390 deletions(-)
diff --git a/src/i18n/locales.js b/src/i18n/locales.js
index 5cda75c..3e6a0ba 100644
--- a/src/i18n/locales.js
+++ b/src/i18n/locales.js
@@ -30,6 +30,8 @@ const zh = {
pleaseEnter: '请输入',
optional: '可选',
required: '必填',
+ more: '更多',
+ collapse: '收起',
addressFormat: '地址格式',
phoneCode: '国际区号',
mustMatchId: '需与证件一致,支持当地语言+英文',
@@ -234,6 +236,8 @@ const en = {
pleaseEnter: 'Please enter',
optional: 'Optional',
required: 'Required',
+ more: 'More',
+ collapse: 'Collapse',
addressFormat: 'Address Format',
phoneCode: 'Phone Code',
mustMatchId: 'Must match ID, supports local language + English',
@@ -436,6 +440,8 @@ const may = {
pleaseEnter: 'Sila masukkan',
optional: 'Pilihan',
required: 'Diperlukan',
+ more: 'Lebih Banyak',
+ collapse: 'Tutup',
addressFormat: 'Format Alamat',
phoneCode: 'Kod Telefon',
mustMatchId: 'Mesti sepadan dengan ID, menyokong bahasa tempatan + Inggeris',
@@ -633,9 +639,14 @@ const fil = {
pleaseEnter: 'Mangyaring ipasok',
optional: 'Opsiyonal',
required: 'Kinakailangan',
+ more: 'Higit Pa',
+ collapse: 'Itago',
addressFormat: 'Format ng Address',
phoneCode: 'Phone Code',
- mustMatchId: 'Dapat tumugma sa ID, sumusuporta sa lokal na wika + Ingles'
+ mustMatchId: 'Dapat tumugma sa ID, sumusuporta sa lokal na wika + Ingles',
+ // 占位符文本
+ placeholderAddressLine1: 'Mangyaring ipasok ang numero ng bahay, kalye, gusali',
+ placeholderAddressLine2: 'Mangyaring ipasok ang sahig, numero ng unit (opsyonal)'
},
product: {
selectCurrency: 'Pumili ng Currency at Wika',
@@ -779,6 +790,8 @@ const th = {
pleaseEnter: 'กรุณากรอก',
optional: 'ไม่บังคับ',
required: 'จำเป็น',
+ more: 'เพิ่มเติม',
+ collapse: 'ย่อ',
addressFormat: 'รูปแบบที่อยู่',
phoneCode: 'รหัสโทรศัพท์',
mustMatchId: 'ต้องตรงกับบัตรประชาชน รองรับภาษาท้องถิ่น + อังกฤษ',
@@ -979,6 +992,8 @@ const vie = {
pleaseEnter: 'Vui lòng nhập',
optional: 'Tùy chọn',
required: 'Bắt buộc',
+ more: 'Thêm',
+ collapse: 'Thu gọn',
addressFormat: 'Định Dạng Địa Chỉ',
phoneCode: 'Mã Điện Thoại',
mustMatchId: 'Phải khớp với ID, hỗ trợ ngôn ngữ địa phương + tiếng Anh',
@@ -1176,9 +1191,14 @@ const id = {
pleaseEnter: 'Silakan masukkan',
optional: 'Opsional',
required: 'Diperlukan',
+ more: 'Lebih Banyak',
+ collapse: 'Tutup',
addressFormat: 'Format Alamat',
phoneCode: 'Kode Telepon',
- mustMatchId: 'Harus sesuai dengan ID, mendukung bahasa lokal + Inggris'
+ mustMatchId: 'Harus sesuai dengan ID, mendukung bahasa lokal + Inggris',
+ // 占位符文本
+ placeholderAddressLine1: 'Silakan masukkan nomor rumah, jalan, gedung',
+ placeholderAddressLine2: 'Silakan masukkan lantai, nomor unit (opsional)'
},
product: {
selectCurrency: 'Pilih Mata Uang dan Bahasa',
diff --git a/src/router/index.js b/src/router/index.js
index 9124d1c..378a294 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -44,12 +44,14 @@ const routes = [
{
path: '/create-order',
name: 'CreateOrder',
- component: CreateOrder
+ component: CreateOrder,
+ meta: { isCustomerPage: true } // 标记为客户页面,不显示导航栏
},
{
path: '/order/confirm',
name: 'OrderConfirm',
- component: () => import('../views/OrderConfirm.vue')
+ component: () => import('../views/OrderConfirm.vue'),
+ meta: { isCustomerPage: true } // 标记为客户页面,不显示导航栏
},
{
path: '/paypal/success',
diff --git a/src/utils/countryConfig.js b/src/utils/countryConfig.js
index 4763762..7012f8f 100644
--- a/src/utils/countryConfig.js
+++ b/src/utils/countryConfig.js
@@ -25,8 +25,9 @@ export const countryConfigs = {
phoneCode: '+65',
postcodeLength: 6,
postcodePattern: /^\d{6}$/,
- requiredFields: ['shippingName', 'shippingPhone', 'shippingCountry', 'shippingCity',
- 'shippingAddressLine1', 'shippingBlockNumber', 'shippingUnitNumber', 'shippingPostcode'],
+ // 新加坡:城市和邮编是PayPal要求必填的
+ requiredFields: ['shippingName', 'shippingPhone', 'shippingCountry',
+ 'shippingCity', 'shippingAddressLine1', 'shippingBlockNumber', 'shippingUnitNumber', 'shippingPostcode'],
specialFields: ['shippingBlockNumber', 'shippingUnitNumber'],
fieldLabels: {
shippingBlockNumber: '组屋号 (Block Number)',
@@ -45,8 +46,9 @@ export const countryConfigs = {
phoneCode: '+60',
postcodeLength: 5,
postcodePattern: /^\d{5}$/,
- requiredFields: ['shippingName', 'shippingPhone', 'shippingCountry', 'shippingCity',
- 'shippingStateMalaysia', 'shippingAddressLine1', 'shippingPostcode'],
+ // 马来西亚:城市和邮编是PayPal要求必填的;州属放入更多按钮中,改为非必填
+ requiredFields: ['shippingName', 'shippingPhone', 'shippingCountry',
+ 'shippingCity', 'shippingAddressLine1', 'shippingPostcode'],
specialFields: ['shippingStateMalaysia'],
fieldLabels: {
shippingStateMalaysia: '州属 (State)',
@@ -64,8 +66,9 @@ export const countryConfigs = {
phoneCode: '+63',
postcodeLength: 4,
postcodePattern: /^\d{4}$/,
- requiredFields: ['shippingName', 'shippingPhone', 'shippingCountry', 'shippingCity',
- 'shippingState', 'shippingBarangay', 'shippingAddressLine1', 'shippingPostcode'],
+ // 菲律宾:城市和邮编是PayPal要求必填的;省放入更多按钮中,改为非必填
+ requiredFields: ['shippingName', 'shippingPhone', 'shippingCountry',
+ 'shippingCity', 'shippingBarangay', 'shippingAddressLine1', 'shippingPostcode'],
specialFields: ['shippingBarangay'],
fieldLabels: {
shippingBarangay: 'Barangay(社区编号)',
@@ -84,8 +87,9 @@ export const countryConfigs = {
phoneCode: '+66',
postcodeLength: 5,
postcodePattern: /^\d{5}$/,
- requiredFields: ['shippingName', 'shippingPhone', 'shippingCountry', 'shippingCity',
- 'shippingState', 'shippingAddressLine1', 'shippingPostcode', 'shippingAddressThai'],
+ // 泰国:城市和邮编是PayPal要求必填的;府放入更多按钮中,改为非必填
+ requiredFields: ['shippingName', 'shippingPhone', 'shippingCountry',
+ 'shippingCity', 'shippingAddressLine1', 'shippingAddressThai', 'shippingPostcode'],
specialFields: ['shippingAddressThai', 'shippingAdministrativeArea'],
fieldLabels: {
shippingAddressThai: '泰文地址 (Thai Address)',
@@ -105,8 +109,9 @@ export const countryConfigs = {
phoneCode: '+84',
postcodeLength: 5,
postcodePattern: /^\d{5}$/,
- requiredFields: ['shippingName', 'shippingPhone', 'shippingCountry', 'shippingProvince',
- 'shippingDistrict', 'shippingWard', 'shippingAddressLine1', 'shippingPostcode'],
+ // 越南:使用省/市/郡/区/坊代替城市;邮编是PayPal要求必填的
+ requiredFields: ['shippingName', 'shippingPhone', 'shippingCountry',
+ 'shippingProvince', 'shippingDistrict', 'shippingWard', 'shippingAddressLine1', 'shippingPostcode'],
specialFields: ['shippingProvince', 'shippingDistrict', 'shippingWard'],
fieldLabels: {
shippingProvince: '省 (Tỉnh)',
diff --git a/src/views/CreateOrder.vue b/src/views/CreateOrder.vue
index 133d334..9705712 100644
--- a/src/views/CreateOrder.vue
+++ b/src/views/CreateOrder.vue
@@ -21,20 +21,20 @@
fit="cover"
class="product-info-image"
/>
-
-
{{ productInfo.name }}
-
- SKU:
- {{ productInfo.sku }}
-
-
- {{ $t('product.unitPrice') }}:
- {{ productInfo.currency }} {{ formatPrice(productInfo.price) }}
- {{ $t('product.quantity') }}:
- x{{ productInfo.quantity }}
- {{ $t('order.subtotal') }}:
- {{ productInfo.currency }} {{ formatPrice(productInfo.price * productInfo.quantity) }}
-
+
{{ productInfo.name }}
+
+
+
+ SKU:
+ {{ productInfo.sku }}
+
+
+ {{ $t('product.unitPrice') }}:
+ {{ productInfo.currency }} {{ formatPrice(productInfo.price) }}
+ {{ $t('product.quantity') }}:
+ x{{ productInfo.quantity }}
+ {{ $t('order.subtotal') }}:
+ {{ productInfo.currency }} {{ formatPrice(productInfo.price * productInfo.quantity) }}
@@ -76,50 +76,74 @@
{{ $t('order.shippingAddress') }}
-
-
+
+
+
+
+
+
+
+
+
+ {{ currentCountryConfig.name }}{{ t('order.postcodeHint').replace('{0}', currentCountryConfig.postcodeLength) }}
+
+
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
@@ -159,39 +183,6 @@
/>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -202,75 +193,56 @@
/>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ currentCountryConfig.name }}{{ t('order.postcodeHint').replace('{0}', currentCountryConfig.postcodeLength) }}
-
-
-
-
-
-
+
+
-
-
+
+
-
-
+
+
+
+
+
+
+
+ {{ showMoreAddressFields ? t('order.collapse') : t('order.more') }}
+
+
+
+
+
+
+
+
+
+
+
{{ $t('order.submit') }}
@@ -287,6 +259,7 @@ import { ref, reactive, computed, watch, onMounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { ElMessage } from 'element-plus'
+import { ArrowDown, ArrowUp } from '@element-plus/icons-vue'
import { createCustomerOrder } from '../api/order'
import { formatAmount } from '../utils/helpers'
import { getCountryConfig, getCountryByCurrency, validatePostcode, getRequiredFields } from '../utils/countryConfig'
@@ -301,13 +274,13 @@ const formRef = ref()
const loading = ref(false)
const productInfo = ref(null)
const postcodeMatching = ref(false) // 邮编匹配中
+const showMoreAddressFields = ref(false) // 控制更多地址字段的显示
+const isAutoUpdating = ref(false) // 防止自动更新时的递归调用
const form = reactive({
customerName: '',
customerPhone: '',
customerEmail: '',
- shippingName: '',
- shippingPhone: '',
shippingCountry: '',
shippingState: '',
shippingCity: '',
@@ -324,9 +297,7 @@ const form = reactive({
shippingProvince: '',
shippingDistrict: '',
shippingWard: '',
- shippingStateMalaysia: '',
- shippingFloorUnit: '',
- remark: ''
+ shippingStateMalaysia: ''
})
// 当前国家配置
@@ -363,12 +334,13 @@ const currentCountryDisplayName = computed(() => {
return countryNameMap[lang] || countryNameMap.en || form.shippingCountry
})
-// 是否显示特定字段
+ // 是否显示特定字段
const showField = (fieldName) => {
if (!currentCountryConfig.value) {
- // 默认显示基础字段
- return ['shippingName', 'shippingPhone', 'shippingCountry', 'shippingCity',
- 'shippingState', 'shippingStreet', 'shippingPostcode'].includes(fieldName)
+ // 默认显示基础字段(包括详细地址)
+ return ['shippingCountry', 'shippingCity',
+ 'shippingState', 'shippingPostcode',
+ 'shippingAddressLine1', 'shippingAddressLine2'].includes(fieldName)
}
const specialFields = currentCountryConfig.value.specialFields || []
@@ -385,8 +357,8 @@ const showField = (fieldName) => {
}
// 基础字段始终显示
- const baseFields = ['shippingName', 'shippingPhone', 'shippingCountry',
- 'shippingCity', 'shippingState', 'shippingStreet',
+ const baseFields = ['shippingCountry',
+ 'shippingCity', 'shippingState',
'shippingPostcode', 'shippingAddressLine1', 'shippingAddressLine2']
if (baseFields.includes(fieldName)) {
return true
@@ -408,17 +380,9 @@ const getFieldLabel = (fieldName) => {
return fieldName
}
-// 获取城市字段标签(根据国家动态显示)
+// 获取城市字段标签(根据国家动态显示,只显示对应语言,不包含中文)
const getCityLabel = () => {
- if (form.shippingCountry === 'TH') {
- return t('order.cityTown') + ' (县/Amphoe)'
- } else if (form.shippingCountry === 'PH') {
- return t('order.cityTown') + ' (市/City)'
- } else if (form.shippingCountry === 'SG') {
- return t('order.cityTown') + ' (城市/City)'
- } else if (form.shippingCountry === 'MY') {
- return t('order.cityTown') + ' (城市/City)'
- }
+ // 直接返回国际化翻译,i18n会根据当前语言环境自动返回对应语言的标签
return t('order.cityTown')
}
@@ -440,6 +404,66 @@ const getStatePlaceholder = () => {
return t('order.placeholderStateOptional')
}
+// 自动更新详细地址1(将省/州、市/郡、区/坊等信息拼接到详细地址1)
+// 使用一个标志来跟踪是否应该自动更新(避免用户手动编辑时被覆盖)
+const updateAddressLine1 = () => {
+ if (isAutoUpdating.value) return // 防止递归更新
+
+ isAutoUpdating.value = true
+
+ try {
+ // 构建地址组件数组(省/州、市/郡、区/坊等)
+ const addressParts = []
+
+ // 根据国家添加不同的地址组件
+ if (form.shippingCountry === 'VN') {
+ // 越南:省、市/郡、区/坊
+ if (form.shippingProvince) addressParts.push(form.shippingProvince)
+ if (form.shippingDistrict) addressParts.push(form.shippingDistrict)
+ if (form.shippingWard) addressParts.push(form.shippingWard)
+ } else {
+ // 其他国家:城市、州/省
+ if (form.shippingCity) addressParts.push(form.shippingCity)
+ if (form.shippingState) addressParts.push(form.shippingState)
+ if (form.shippingCountry === 'MY' && form.shippingStateMalaysia) {
+ addressParts.push(form.shippingStateMalaysia)
+ }
+ }
+
+ // 如果有地址组件,拼接到详细地址1
+ if (addressParts.length > 0) {
+ const addressSuffix = addressParts.join(', ')
+ const currentAddress = form.shippingAddressLine1 || ''
+
+ // 检查当前地址是否已包含这些组件(避免重复拼接)
+ const hasAllParts = addressParts.every(part => currentAddress.includes(part))
+
+ if (!hasAllParts) {
+ // 移除旧的地址组件(如果存在),保留用户手动输入的门牌号、街道、楼栋等信息
+ let cleanAddress = currentAddress
+ addressParts.forEach(part => {
+ // 移除该组件及其前后的逗号和空格
+ const escapedPart = part.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
+ // 移除 ", 组件" 或 "组件, " 或单独的 "组件"
+ cleanAddress = cleanAddress.replace(new RegExp(`,\\s*${escapedPart}(?=\\s|,|$)`, 'g'), '')
+ cleanAddress = cleanAddress.replace(new RegExp(`${escapedPart}\\s*,`, 'g'), '')
+ cleanAddress = cleanAddress.replace(new RegExp(`^${escapedPart}\\s*$`, 'g'), '')
+ })
+ cleanAddress = cleanAddress.trim().replace(/^,\s*|,\s*$/g, '').replace(/,\s*,/g, ',')
+
+ // 追加新的地址组件
+ if (cleanAddress) {
+ form.shippingAddressLine1 = `${cleanAddress}, ${addressSuffix}`
+ } else {
+ form.shippingAddressLine1 = addressSuffix
+ }
+ }
+ }
+ } finally {
+ isAutoUpdating.value = false
+ }
+}
+
// 监听国家变化,清空相关字段
watch(() => form.shippingCountry, (newCountry, oldCountry) => {
if (newCountry !== oldCountry) {
@@ -453,14 +477,19 @@ watch(() => form.shippingCountry, (newCountry, oldCountry) => {
form.shippingDistrict = ''
form.shippingWard = ''
form.shippingAdministrativeArea = ''
-
- // 更新电话区号提示
- if (currentCountryConfig.value) {
- form.shippingPhone = currentCountryConfig.value.phoneCode + ' '
- }
+ // 清空详细地址1(因为地址组件已清空)
+ form.shippingAddressLine1 = ''
}
})
+// 监听地址组件变化,自动更新详细地址1
+watch([() => form.shippingCity, () => form.shippingState, () => form.shippingStateMalaysia,
+ () => form.shippingProvince, () => form.shippingDistrict, () => form.shippingWard],
+ () => {
+ updateAddressLine1()
+ }
+)
+
// 监听邮编变化,自动匹配城市
watch(() => form.shippingPostcode, async (newPostcode) => {
if (!newPostcode || !form.shippingCountry) return
@@ -501,21 +530,30 @@ const getRules = () => {
customerEmail: [
{ type: 'email', message: t('order.validationInvalidEmail'), trigger: 'blur' }
],
- shippingName: [
- { required: true, message: t('order.validationRequired', [t('order.shippingName')]), trigger: 'blur' }
- ],
- shippingPhone: [
- { required: true, message: t('order.validationRequired', [t('order.shippingPhone')]), trigger: 'blur' },
- { pattern: /^[0-9+\-\s()]+$/, message: t('order.validationInvalidPhone'), trigger: 'blur' }
- ],
shippingCountry: [
{ required: true, message: t('order.validationSelectCountry'), trigger: 'change' }
],
- shippingCity: [
- { required: true, message: t('order.validationRequired', [t('order.cityTown')]), trigger: 'blur' }
+ // 详细地址1始终必填
+ shippingAddressLine1: [
+ { required: true, message: t('order.validationRequired', [t('order.addressLine1')]), trigger: 'blur' }
],
- shippingStreet: [
- { required: true, message: t('order.validationRequired', [t('order.street')]), trigger: 'blur' }
+ // 邮编始终必填(PayPal要求)
+ shippingPostcode: [
+ { required: true, message: t('order.validationRequired', [t('order.postcode')]), trigger: 'blur' },
+ {
+ validator: (rule, value, callback) => {
+ if (value && currentCountryConfig.value && !validatePostcode(form.shippingCountry, value)) {
+ callback(new Error(t('order.validationPostcodeFormat', [currentCountryConfig.value.postcodeLength])))
+ } else {
+ callback()
+ }
+ },
+ trigger: 'blur'
+ }
+ ],
+ // 城市始终必填(PayPal要求,越南除外)
+ shippingCity: [
+ { required: true, message: t('order.validationRequired', [t('order.city')]), trigger: 'blur' }
]
}
@@ -523,28 +561,6 @@ const getRules = () => {
if (currentCountryConfig.value) {
const requiredFields = getRequiredFields(form.shippingCountry)
- if (requiredFields.includes('shippingAddressLine1')) {
- baseRules.shippingAddressLine1 = [
- { required: true, message: t('order.validationRequired', [t('order.addressLine1')]), trigger: 'blur' }
- ]
- }
-
- if (requiredFields.includes('shippingPostcode')) {
- baseRules.shippingPostcode = [
- { required: true, message: t('order.validationRequired', [t('order.postcode')]), trigger: 'blur' },
- {
- validator: (rule, value, callback) => {
- if (value && !validatePostcode(form.shippingCountry, value)) {
- callback(new Error(t('order.validationPostcodeFormat', [currentCountryConfig.value.postcodeLength])))
- } else {
- callback()
- }
- },
- trigger: 'blur'
- }
- ]
- }
-
if (requiredFields.includes('shippingBlockNumber')) {
baseRules.shippingBlockNumber = [
{ required: true, message: t('order.validationRequired', [t('order.blockNumber')]), trigger: 'blur' }
@@ -639,12 +655,12 @@ const submitForm = async () => {
customerName: form.customerName,
customerPhone: form.customerPhone,
customerEmail: form.customerEmail || null,
- shippingName: form.shippingName,
- shippingPhone: form.shippingPhone,
+ shippingName: form.customerName, // 使用客户姓名作为收货人姓名
+ shippingPhone: form.customerPhone, // 使用客户电话作为收货人电话
shippingCountry: form.shippingCountry,
shippingState: form.shippingState || null,
shippingCity: shippingCity, // 使用映射后的值,越南使用 shippingDistrict
- shippingStreet: form.shippingStreet || form.shippingAddressLine1, // 兼容旧字段
+ shippingStreet: form.shippingAddressLine1, // 使用详细地址1
shippingPostcode: form.shippingPostcode || null,
// 东南亚地址扩展字段
shippingAddressLine1: form.shippingAddressLine1 || null,
@@ -658,8 +674,6 @@ const submitForm = async () => {
shippingDistrict: form.shippingDistrict || null,
shippingWard: form.shippingWard || null,
shippingStateMalaysia: form.shippingStateMalaysia || null,
- shippingFloorUnit: form.shippingFloorUnit || null,
- remark: form.remark || null
}
const response = await createCustomerOrder(orderData)
@@ -703,10 +717,6 @@ onMounted(async () => {
const countryCode = getCountryByCurrency(data.product.currency)
if (countryCode) {
form.shippingCountry = countryCode
- const config = getCountryConfig(countryCode)
- if (config) {
- form.shippingPhone = config.phoneCode + ' '
- }
}
}
}
@@ -755,22 +765,18 @@ onMounted(async () => {
.product-info-main {
display: flex;
- gap: 20px;
+ align-items: center;
+ gap: 15px;
+ margin-bottom: 15px;
}
.product-info-image {
- width: 120px;
- height: 120px;
- border-radius: 8px;
+ width: 80px;
+ height: 80px;
+ border-radius: 6px;
border: 1px solid #e4e7ed;
flex-shrink: 0;
-}
-
-.product-info-details {
- flex: 1;
- display: flex;
- flex-direction: column;
- gap: 10px;
+ object-fit: cover;
}
.product-info-name {
@@ -778,6 +784,13 @@ onMounted(async () => {
font-weight: 600;
color: #303133;
line-height: 1.5;
+ flex: 1;
+}
+
+.product-info-details {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
}
.product-info-sku {
@@ -830,39 +843,74 @@ onMounted(async () => {
font-weight: 700;
}
-/* 移动端优化 */
+/* 移动端优先设计 - 响应式优化 */
@media (max-width: 768px) {
.create-order {
- padding: 10px;
+ padding: 0;
max-width: 100%;
}
+ .el-card {
+ border-radius: 0;
+ box-shadow: none;
+ border: none;
+ margin: 0;
+ }
+
.card-header {
font-size: 16px;
- padding: 10px 0;
+ padding: 12px 16px;
+ font-weight: 600;
}
+ .el-card__body {
+ padding: 16px;
+ }
+
+ /* 商品信息卡片优化 */
.product-info-card {
- margin-bottom: 15px;
+ margin-bottom: 16px;
+ border: 1px solid #e4e7ed;
+ border-radius: 8px;
}
.product-card-header {
font-size: 14px;
+ font-weight: 600;
+ }
+
+ .product-info-content {
+ padding: 12px 0;
}
.product-info-main {
- flex-direction: column;
+ flex-direction: row;
gap: 12px;
+ align-items: flex-start;
+ margin-bottom: 12px;
}
.product-info-image {
- width: 100%;
- height: 200px;
- align-self: center;
+ width: 60px;
+ height: 60px;
+ flex-shrink: 0;
+ border-radius: 6px;
}
-
+
.product-info-name {
font-size: 14px;
+ line-height: 1.4;
+ word-break: break-word;
+ flex: 1;
+ }
+
+ .product-info-details {
+ gap: 8px;
+ }
+
+ .product-info-sku {
+ padding: 8px 10px;
+ font-size: 12px;
}
.product-info-price {
@@ -870,33 +918,58 @@ onMounted(async () => {
align-items: flex-start;
gap: 8px;
padding: 10px;
+ font-size: 13px;
+ }
+
+ .price-label,
+ .quantity-label {
+ font-size: 12px;
+ }
+
+ .price-value,
+ .quantity-value {
+ font-size: 14px;
}
.total-label {
margin-left: 0;
margin-top: 8px;
- font-size: 16px;
+ font-size: 14px;
+ font-weight: 600;
}
.total-value {
- font-size: 20px;
+ font-size: 18px;
}
/* 表单优化 */
+ .el-form {
+ padding: 0;
+ }
+
.el-form-item {
- margin-bottom: 18px;
+ margin-bottom: 16px;
}
.el-form-item__label {
- padding-bottom: 5px;
+ padding-bottom: 6px;
font-size: 14px;
font-weight: 600;
+ line-height: 1.4;
+ margin-bottom: 4px;
}
.el-input,
.el-select,
.el-textarea {
width: 100%;
+ font-size: 14px;
+ }
+
+ .el-input__inner,
+ .el-textarea__inner {
+ font-size: 14px;
+ padding: 10px 12px;
}
/* 地址字段优化 */
@@ -911,39 +984,22 @@ onMounted(async () => {
width: 100%;
}
- /* 按钮优化 */
- .el-form-item:last-child {
- margin-bottom: 0;
- padding-top: 15px;
- border-top: 1px solid #e4e7ed;
- }
-
- .el-form-item:last-child .el-button {
- width: 100%;
- margin: 0;
- height: 44px;
- font-size: 16px;
- }
-
- .el-form-item:last-child .el-button + .el-button {
- margin-top: 10px;
- margin-left: 0;
- }
-
/* 分隔线优化 */
.el-divider {
- margin: 20px 0;
+ margin: 16px 0;
}
.el-divider__text {
font-size: 14px;
- padding: 0 15px;
+ padding: 0 12px;
+ font-weight: 600;
}
/* 提示信息优化 */
.el-alert {
- margin-bottom: 15px;
+ margin-bottom: 12px;
font-size: 12px;
+ padding: 10px 12px;
}
/* 输入组优化 */
@@ -951,23 +1007,73 @@ onMounted(async () => {
display: flex;
flex-direction: column;
width: 100%;
+ gap: 10px;
}
.desktop-input-group {
display: flex;
width: 100%;
+ gap: 4%;
}
.mobile-postcode-group {
display: flex;
flex-direction: column;
width: 100%;
+ gap: 8px;
}
.desktop-postcode-group {
display: flex;
align-items: center;
width: 100%;
+ gap: 10px;
+ }
+
+ /* 按钮优化 */
+ .el-form-item:last-child {
+ margin-bottom: 0;
+ padding-top: 16px;
+ border-top: 1px solid #e4e7ed;
+ position: sticky;
+ bottom: 0;
+ background: white;
+ z-index: 10;
+ }
+
+ .el-form-item:last-child .el-button {
+ width: 100%;
+ margin: 0;
+ height: 48px;
+ font-size: 16px;
+ font-weight: 600;
+ border-radius: 8px;
+ }
+
+ .el-form-item:last-child .el-button + .el-button {
+ margin-top: 10px;
+ margin-left: 0;
+ }
+
+ /* 更多按钮优化 */
+ .el-button--text {
+ font-size: 14px;
+ padding: 8px 0;
+ }
+
+ /* 国家选择器优化 */
+ .el-select {
+ width: 100%;
+ }
+
+ /* 文本域优化 */
+ .el-textarea {
+ width: 100%;
+ }
+
+ .el-textarea__inner {
+ min-height: 80px;
+ line-height: 1.5;
}
}
diff --git a/src/views/OrderConfirm.vue b/src/views/OrderConfirm.vue
index 7c433cf..94d7fe1 100644
--- a/src/views/OrderConfirm.vue
+++ b/src/views/OrderConfirm.vue
@@ -152,7 +152,7 @@
:style="isMobile ? 'width: 100%' : 'width: 200px'"
>
- {{ $t('confirm.payNow') }}
+ {{ countdown > 0 ? `${$t('confirm.payNow')} (${countdown}s)` : $t('confirm.payNow') }}
{{ $t('confirm.back') }}
@@ -168,7 +168,7 @@