diff --git a/CLAUDE.md b/CLAUDE.md index d204ec4..5463d41 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -16,7 +16,7 @@ ### 小程序 (miniprogram/) - **框架**: uni-app + Vue 3 + Vite - **UI库**: uView Plus 3.6 -- **国际化**: vue-i18n (中文/英文/葡萄牙语) +- **国际化**: vue-i18n (中文/英文/西班牙语) ### 管理后台 (admin/) - **框架**: Vue 3 + Vite @@ -96,7 +96,7 @@ docker-compose up -d - **基础路径**: `/api/v1/` - **认证方式**: Bearer Token (JWT) -- **多语言**: `Accept-Language` 头或 `?language=zh|en|pt` +- **多语言**: `Accept-Language` 头或 `?language=zh|en|es` ### 主要API端点 @@ -160,7 +160,7 @@ GET /api/v1/withdrawals # 提现记录 ## 注意事项 -1. **多语言字段**: Service、Category、Notification等模型包含 `_zh`、`_en`、`_pt` 后缀的字段 +1. **多语言字段**: Service、Category、Notification等模型包含 `_zh`、`_en`、`_es` 后缀的字段 2. **UUID主键**: 所有主表使用UUID而非自增ID 3. **预约编号格式**: `APT` + `YYYYMMDD` + 6位数字 4. **订单编号格式**: `ORD` + `YYYYMMDD` + 6位数字 diff --git a/admin/src/views/appointments/index.vue b/admin/src/views/appointments/index.vue index 979a9f7..a6f5ebd 100644 --- a/admin/src/views/appointments/index.vue +++ b/admin/src/views/appointments/index.vue @@ -169,7 +169,7 @@
@@ -185,10 +185,13 @@ - {{ appointmentDetails.service?.titleZh || '-' }} + {{ appointmentDetails.service?.titleZh || appointmentDetails.hotService?.name_zh || '-' }} - {{ appointmentDetails.service?.category?.nameZh || '-' }} + {{ appointmentDetails.service?.category?.nameZh || (appointmentDetails.hotService ? '热门服务' : '-') }} + + + {{ getServiceTypeLabel(appointmentDetails.serviceType) }} @@ -199,11 +202,11 @@ {{ appointmentDetails.paidAt ? formatDate(appointmentDetails.paidAt) : '-' }} - - {{ appointmentDetails.appointmentDate || '-' }} + + {{ appointmentDetails.appointmentDate }} - - {{ appointmentDetails.appointmentTime || '-' }} + + {{ appointmentDetails.appointmentTime }} {{ formatDate(appointmentDetails.createdAt) }} @@ -216,14 +219,292 @@ - {{ appointmentDetails.realName }} + {{ appointmentDetails.realName || '-' }} - + {{ getContactMethodLabel(appointmentDetails.contactMethod) }} {{ appointmentDetails.contactValue }} + + {{ appointmentDetails.phoneCountryCode ? `+${appointmentDetails.phoneCountryCode} ` : '' }}{{ appointmentDetails.phone }} + + + {{ appointmentDetails.whatsapp }} + + + {{ appointmentDetails.wechatId }} + + + + + + + {{ appointmentDetails.tripType === 'single' ? '单程' : '往返' }} + + + {{ getCabinTypeLabel(appointmentDetails.cabinType) }} + + + {{ appointmentDetails.departureCity }} + + + {{ appointmentDetails.arrivalCity }} + + + {{ appointmentDetails.departureDate }} + + + {{ appointmentDetails.returnDate }} + + + {{ appointmentDetails.adultCount }}人 + + + {{ appointmentDetails.childCount }}人 + + + {{ appointmentDetails.infantCount }}人 + + + {{ appointmentDetails.luggageCount }}件 + + + + + + + {{ appointmentDetails.checkInDate }} + + + {{ appointmentDetails.checkOutDate }} + + + {{ appointmentDetails.countryCity }} + + + {{ appointmentDetails.hotelName }} + + + {{ appointmentDetails.roomCount }}间 + + + {{ appointmentDetails.roomType }} + + + {{ appointmentDetails.adultCount }}人 + + + {{ appointmentDetails.childCount }}人 + + + {{ appointmentDetails.needMeal ? '是' : '否' }} + + + {{ getMealPlanLabel(appointmentDetails.mealPlan) }} + + + + + + + {{ appointmentDetails.arrivalFlightNo }} + + + {{ appointmentDetails.departureFlightNo }} + + + {{ appointmentDetails.airportTerminal }} + + + {{ appointmentDetails.deliveryAddress }} + + + + + + + {{ appointmentDetails.childAge }}岁 + + + {{ appointmentDetails.boyCount }}人 + + + {{ appointmentDetails.girlCount }}人 + + + {{ appointmentDetails.itinerary }} + + + + + + + {{ appointmentDetails.originStation }} + + + {{ appointmentDetails.destinationStation }} + + + {{ appointmentDetails.departureDate }} + + + {{ getSeatClassLabel(appointmentDetails.seatClass) }} + + + {{ appointmentDetails.passengerCount }}人 + + + + + + + {{ appointmentDetails.hospitalName }} + + + {{ appointmentDetails.conditionDescription }} + + + {{ appointmentDetails.specialAssistanceReason }} + + + + + + + {{ appointmentDetails.origin }} + + + {{ appointmentDetails.destination }} + + + {{ appointmentDetails.flightNo }} + + + {{ appointmentDetails.petType }} + + + {{ appointmentDetails.petName }} + + + {{ appointmentDetails.hasQuarantineCert ? '有' : '无' }} + + + + + + + {{ appointmentDetails.serviceDays }}天 + + + + + + + {{ appointmentDetails.itemName }} + + + {{ appointmentDetails.itemQuantity }} + + + {{ appointmentDetails.originPort }} + + + {{ appointmentDetails.destinationPort }} + + + {{ appointmentDetails.cargoName }} + + + {{ appointmentDetails.cargoQuantity }} + + + + + + + {{ appointmentDetails.travelDate }} + + + {{ appointmentDetails.travelDestination }} + + + {{ appointmentDetails.travelDays }}天 + + + + + + + {{ appointmentDetails.specificRequirements }} + @@ -585,11 +866,120 @@ function getLanguageLabel(lang) { const labels = { zh: '中文', en: 'English', - pt: 'Português' + es: 'Español' } return labels[lang] || lang } +function getServiceTypeLabel(type) { + const labels = { + travel: '旅行服务', + accommodation: '住宿服务', + guide: '导游服务', + translation: '翻译服务', + consulting: '咨询服务', + flight: '机票预订', + hotel: '酒店预订', + train: '高铁票预订', + vip_lounge: 'VIP贵宾室', + airport_transfer: '接送机', + pet_transport: '宠物托运', + medical: '医疗服务', + logistics: '物流服务', + other: '其他服务' + } + return labels[type] || type +} + +function getCabinTypeLabel(type) { + const labels = { + economy: '经济舱', + premium_economy: '超级经济舱', + business: '商务舱' + } + return labels[type] || type +} + +function getMealPlanLabel(plan) { + const labels = { + breakfast: '早餐', + three_meals: '三餐', + all_inclusive: '全包' + } + return labels[plan] || plan +} + +function getSeatClassLabel(seatClass) { + const labels = { + first: '一等座', + second: '二等座', + third: '三等座' + } + return labels[seatClass] || seatClass +} + +// Field detection helpers +function hasFlightFields(data) { + return data && ( + data.tripType || data.cabinType || data.departureCity || data.arrivalCity || + data.departureDate || data.returnDate || data.luggageCount || + (data.adultCount && !data.checkInDate && !data.originStation) + ) +} + +function hasHotelFields(data) { + return data && ( + data.checkInDate || data.checkOutDate || data.countryCity || + data.hotelName || data.roomCount || data.roomType || + data.needMeal !== null || data.mealPlan + ) +} + +function hasVipFields(data) { + return data && ( + data.arrivalFlightNo || data.departureFlightNo || + data.airportTerminal || data.deliveryAddress + ) +} + +function hasUnaccompaniedMinorFields(data) { + return data && ( + data.childAge || data.boyCount || data.girlCount || data.itinerary + ) +} + +function hasTrainFields(data) { + return data && ( + data.originStation || data.destinationStation || data.seatClass || data.passengerCount + ) +} + +function hasMedicalFields(data) { + return data && ( + data.hospitalName || data.conditionDescription || data.specialAssistanceReason + ) +} + +function hasPetFields(data) { + return data && ( + data.petType || data.petName || data.hasQuarantineCert !== null || + (data.origin && data.destination && data.flightNo) + ) +} + +function hasLogisticsFields(data) { + return data && ( + data.itemName || data.itemQuantity || data.originPort || + data.destinationPort || data.cargoName || data.cargoQuantity + ) +} + +function hasTravelFields(data) { + return data && ( + data.travelDate || data.travelDestination || data.travelDays + ) +} + // Initialize onMounted(() => { fetchCategories() diff --git a/admin/src/views/categories/index.vue b/admin/src/views/categories/index.vue index 3d28fc6..171a42e 100644 --- a/admin/src/views/categories/index.vue +++ b/admin/src/views/categories/index.vue @@ -15,7 +15,7 @@ - +