From 5c2469137c82756036ee8f94a0cbf27da6238225 Mon Sep 17 00:00:00 2001 From: 18631081161 <2088094923@qq.com> Date: Sun, 21 Dec 2025 17:22:48 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9B=BD=E9=99=85=E5=8C=96,=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E5=90=8E=E5=8F=B0=E4=BF=AE=E6=94=B9.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CLAUDE.md | 6 +- admin/src/views/appointments/index.vue | 410 +++++++++++++++++- admin/src/views/categories/index.vue | 6 +- admin/src/views/home-content/index.vue | 6 +- admin/src/views/notifications/index.vue | 10 +- admin/src/views/services/index.vue | 8 +- admin/src/views/users/index.vue | 6 +- backend/src/config/swagger.js | 16 +- backend/src/migrations/012-rename-pt-to-es.js | 71 +++ backend/src/models/Category.js | 8 +- backend/src/models/HotService.js | 2 +- backend/src/models/Notification.js | 8 +- backend/src/models/Service.js | 8 +- backend/src/routes/adminServiceRoutes.js | 8 +- backend/src/routes/userRoutes.js | 2 +- .../src/services/adminAppointmentService.js | 21 +- .../src/services/adminNotificationService.js | 8 +- backend/src/services/adminServiceService.js | 16 +- .../src/services/adminStatisticsService.js | 12 +- backend/src/services/appointmentService.js | 26 +- backend/src/services/homeService.js | 4 +- backend/src/services/notificationService.js | 6 +- backend/src/services/serviceService.js | 6 +- backend/src/services/userService.js | 6 +- .../src/components/language-switcher.vue | 2 +- miniprogram/src/locale/en.js | 2 +- miniprogram/src/locale/es.js | 254 +++++++++++ miniprogram/src/locale/index.js | 8 +- miniprogram/src/locale/pt.js | 254 ----------- miniprogram/src/locale/zh.js | 2 +- miniprogram/src/pages/me/me-page.vue | 2 +- .../src/pages/me/my-appointments-page.vue | 4 +- miniprogram/src/utils/i18n.js | 6 +- 33 files changed, 840 insertions(+), 374 deletions(-) create mode 100644 backend/src/migrations/012-rename-pt-to-es.js create mode 100644 miniprogram/src/locale/es.js delete mode 100644 miniprogram/src/locale/pt.js 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 @@ - +