442 lines
9.6 KiB
JavaScript
442 lines
9.6 KiB
JavaScript
const { DataTypes } = require('sequelize');
|
||
const { sequelize } = require('../config/database');
|
||
|
||
/**
|
||
* Appointment Model
|
||
* Represents user appointment bookings
|
||
*/
|
||
const Appointment = sequelize.define('Appointment', {
|
||
id: {
|
||
type: DataTypes.UUID,
|
||
defaultValue: DataTypes.UUIDV4,
|
||
primaryKey: true,
|
||
},
|
||
userId: {
|
||
type: DataTypes.UUID,
|
||
allowNull: false,
|
||
field: 'user_id',
|
||
references: {
|
||
model: 'user',
|
||
key: 'id',
|
||
},
|
||
},
|
||
serviceId: {
|
||
type: DataTypes.UUID,
|
||
allowNull: true,
|
||
field: 'service_id',
|
||
references: {
|
||
model: 'service',
|
||
key: 'id',
|
||
},
|
||
},
|
||
// 热门服务ID(用于从首页热门服务进入的预约)
|
||
hotServiceId: {
|
||
type: DataTypes.INTEGER,
|
||
allowNull: true,
|
||
field: 'hot_service_id',
|
||
},
|
||
// 服务类型
|
||
serviceType: {
|
||
type: DataTypes.STRING(50),
|
||
allowNull: true,
|
||
field: 'service_type',
|
||
comment: '服务类型: travel, accommodation, guide, translation, consulting, other',
|
||
},
|
||
appointmentNo: {
|
||
type: DataTypes.STRING(50),
|
||
allowNull: false,
|
||
unique: true,
|
||
field: 'appointment_no',
|
||
},
|
||
realName: {
|
||
type: DataTypes.STRING(100),
|
||
allowNull: false,
|
||
field: 'real_name',
|
||
},
|
||
contactMethod: {
|
||
type: DataTypes.ENUM('phone', 'whatsapp', 'wechat'),
|
||
allowNull: true,
|
||
field: 'contact_method',
|
||
},
|
||
contactValue: {
|
||
type: DataTypes.STRING(100),
|
||
allowNull: true,
|
||
field: 'contact_value',
|
||
},
|
||
// 多联系方式支持
|
||
wechatId: {
|
||
type: DataTypes.STRING(100),
|
||
allowNull: true,
|
||
field: 'wechat_id',
|
||
},
|
||
phone: {
|
||
type: DataTypes.STRING(50),
|
||
allowNull: true,
|
||
},
|
||
phoneCountryCode: {
|
||
type: DataTypes.STRING(10),
|
||
allowNull: true,
|
||
field: 'phone_country_code',
|
||
},
|
||
whatsapp: {
|
||
type: DataTypes.STRING(50),
|
||
allowNull: true,
|
||
},
|
||
appointmentDate: {
|
||
type: DataTypes.DATEONLY,
|
||
allowNull: true,
|
||
field: 'appointment_date',
|
||
},
|
||
appointmentTime: {
|
||
type: DataTypes.TIME,
|
||
allowNull: true,
|
||
field: 'appointment_time',
|
||
},
|
||
notes: {
|
||
type: DataTypes.TEXT,
|
||
allowNull: true,
|
||
},
|
||
status: {
|
||
type: DataTypes.ENUM('pending', 'confirmed', 'in-progress', 'completed', 'cancelled'),
|
||
defaultValue: 'pending',
|
||
allowNull: false,
|
||
},
|
||
amount: {
|
||
type: DataTypes.DECIMAL(10, 2),
|
||
allowNull: true,
|
||
},
|
||
paidAt: {
|
||
type: DataTypes.DATE,
|
||
allowNull: true,
|
||
field: 'paid_at',
|
||
},
|
||
// ========== 机票预约专用字段 ==========
|
||
// 行程类型: single-单程, round-往返
|
||
tripType: {
|
||
type: DataTypes.ENUM('single', 'round'),
|
||
allowNull: true,
|
||
field: 'trip_type',
|
||
},
|
||
// 出发日期
|
||
departureDate: {
|
||
type: DataTypes.DATEONLY,
|
||
allowNull: true,
|
||
field: 'departure_date',
|
||
},
|
||
// 返程日期
|
||
returnDate: {
|
||
type: DataTypes.DATEONLY,
|
||
allowNull: true,
|
||
field: 'return_date',
|
||
},
|
||
// 出发城市
|
||
departureCity: {
|
||
type: DataTypes.STRING(100),
|
||
allowNull: true,
|
||
field: 'departure_city',
|
||
},
|
||
// 到达城市
|
||
arrivalCity: {
|
||
type: DataTypes.STRING(100),
|
||
allowNull: true,
|
||
field: 'arrival_city',
|
||
},
|
||
// 成人人数
|
||
adultCount: {
|
||
type: DataTypes.INTEGER,
|
||
allowNull: true,
|
||
defaultValue: 0,
|
||
field: 'adult_count',
|
||
},
|
||
// 儿童人数
|
||
childCount: {
|
||
type: DataTypes.INTEGER,
|
||
allowNull: true,
|
||
defaultValue: 0,
|
||
field: 'child_count',
|
||
},
|
||
// 婴儿人数
|
||
infantCount: {
|
||
type: DataTypes.INTEGER,
|
||
allowNull: true,
|
||
defaultValue: 0,
|
||
field: 'infant_count',
|
||
},
|
||
// 舱位类型: economy-经济舱, premium_economy-超级经济舱, business-商务舱
|
||
cabinType: {
|
||
type: DataTypes.ENUM('economy', 'premium_economy', 'business'),
|
||
allowNull: true,
|
||
field: 'cabin_type',
|
||
},
|
||
// 行李件数
|
||
luggageCount: {
|
||
type: DataTypes.INTEGER,
|
||
allowNull: true,
|
||
field: 'luggage_count',
|
||
},
|
||
// ========== 酒店预定专用字段 (Hotel Reservation) ==========
|
||
// 入住日期
|
||
checkInDate: {
|
||
type: DataTypes.DATEONLY,
|
||
allowNull: true,
|
||
field: 'check_in_date',
|
||
},
|
||
// 退房日期
|
||
checkOutDate: {
|
||
type: DataTypes.DATEONLY,
|
||
allowNull: true,
|
||
field: 'check_out_date',
|
||
},
|
||
// 国家/城市
|
||
countryCity: {
|
||
type: DataTypes.STRING(200),
|
||
allowNull: true,
|
||
field: 'country_city',
|
||
},
|
||
// 酒店名称
|
||
hotelName: {
|
||
type: DataTypes.STRING(200),
|
||
allowNull: true,
|
||
field: 'hotel_name',
|
||
},
|
||
// 房间数量
|
||
roomCount: {
|
||
type: DataTypes.INTEGER,
|
||
allowNull: true,
|
||
field: 'room_count',
|
||
},
|
||
// 房间类型
|
||
roomType: {
|
||
type: DataTypes.STRING(100),
|
||
allowNull: true,
|
||
field: 'room_type',
|
||
},
|
||
// 是否需要餐食
|
||
needMeal: {
|
||
type: DataTypes.BOOLEAN,
|
||
allowNull: true,
|
||
field: 'need_meal',
|
||
},
|
||
// 餐食计划: breakfast-早餐, three_meals-三餐, all_inclusive-全包
|
||
mealPlan: {
|
||
type: DataTypes.ENUM('breakfast', 'three_meals', 'all_inclusive'),
|
||
allowNull: true,
|
||
field: 'meal_plan',
|
||
},
|
||
// ========== VIP贵宾室/接送机专用字段 ==========
|
||
// 到达航班号
|
||
arrivalFlightNo: {
|
||
type: DataTypes.STRING(50),
|
||
allowNull: true,
|
||
field: 'arrival_flight_no',
|
||
},
|
||
// 出发航班号
|
||
departureFlightNo: {
|
||
type: DataTypes.STRING(50),
|
||
allowNull: true,
|
||
field: 'departure_flight_no',
|
||
},
|
||
// 机场/航站楼
|
||
airportTerminal: {
|
||
type: DataTypes.STRING(200),
|
||
allowNull: true,
|
||
field: 'airport_terminal',
|
||
},
|
||
// 送达地址
|
||
deliveryAddress: {
|
||
type: DataTypes.TEXT,
|
||
allowNull: true,
|
||
field: 'delivery_address',
|
||
},
|
||
// ========== 无成人陪伴儿童专用字段 ==========
|
||
// 行程
|
||
itinerary: {
|
||
type: DataTypes.TEXT,
|
||
allowNull: true,
|
||
},
|
||
// 儿童年龄
|
||
childAge: {
|
||
type: DataTypes.INTEGER,
|
||
allowNull: true,
|
||
field: 'child_age',
|
||
},
|
||
// 男孩数量
|
||
boyCount: {
|
||
type: DataTypes.INTEGER,
|
||
allowNull: true,
|
||
field: 'boy_count',
|
||
},
|
||
// 女孩数量
|
||
girlCount: {
|
||
type: DataTypes.INTEGER,
|
||
allowNull: true,
|
||
field: 'girl_count',
|
||
},
|
||
// ========== 高铁票代订专用字段 ==========
|
||
// 出发站
|
||
originStation: {
|
||
type: DataTypes.STRING(100),
|
||
allowNull: true,
|
||
field: 'origin_station',
|
||
},
|
||
// 到达站
|
||
destinationStation: {
|
||
type: DataTypes.STRING(100),
|
||
allowNull: true,
|
||
field: 'destination_station',
|
||
},
|
||
// 座位等级: first-一等座, second-二等座, third-三等座
|
||
seatClass: {
|
||
type: DataTypes.ENUM('first', 'second', 'third'),
|
||
allowNull: true,
|
||
field: 'seat_class',
|
||
},
|
||
// 乘客数量
|
||
passengerCount: {
|
||
type: DataTypes.INTEGER,
|
||
allowNull: true,
|
||
field: 'passenger_count',
|
||
},
|
||
// ========== 医疗/特殊需求专用字段 ==========
|
||
// 医院名称
|
||
hospitalName: {
|
||
type: DataTypes.STRING(200),
|
||
allowNull: true,
|
||
field: 'hospital_name',
|
||
},
|
||
// 病情描述
|
||
conditionDescription: {
|
||
type: DataTypes.TEXT,
|
||
allowNull: true,
|
||
field: 'condition_description',
|
||
},
|
||
// 特殊协助原因
|
||
specialAssistanceReason: {
|
||
type: DataTypes.TEXT,
|
||
allowNull: true,
|
||
field: 'special_assistance_reason',
|
||
},
|
||
// ========== 宠物托运专用字段 ==========
|
||
// 出发地
|
||
origin: {
|
||
type: DataTypes.STRING(200),
|
||
allowNull: true,
|
||
},
|
||
// 目的地
|
||
destination: {
|
||
type: DataTypes.STRING(200),
|
||
allowNull: true,
|
||
},
|
||
// 航班号
|
||
flightNo: {
|
||
type: DataTypes.STRING(50),
|
||
allowNull: true,
|
||
field: 'flight_no',
|
||
},
|
||
// 宠物类型
|
||
petType: {
|
||
type: DataTypes.STRING(100),
|
||
allowNull: true,
|
||
field: 'pet_type',
|
||
},
|
||
// 宠物名称
|
||
petName: {
|
||
type: DataTypes.STRING(100),
|
||
allowNull: true,
|
||
field: 'pet_name',
|
||
},
|
||
// 是否有检疫证明
|
||
hasQuarantineCert: {
|
||
type: DataTypes.BOOLEAN,
|
||
allowNull: true,
|
||
field: 'has_quarantine_cert',
|
||
},
|
||
// ========== 导游/翻译服务专用字段 ==========
|
||
// 服务天数
|
||
serviceDays: {
|
||
type: DataTypes.INTEGER,
|
||
allowNull: true,
|
||
field: 'service_days',
|
||
},
|
||
// ========== 咨询服务专用字段 ==========
|
||
// 具体需求
|
||
specificRequirements: {
|
||
type: DataTypes.TEXT,
|
||
allowNull: true,
|
||
field: 'specific_requirements',
|
||
},
|
||
// ========== 物流专用字段 ==========
|
||
// 物品名称
|
||
itemName: {
|
||
type: DataTypes.STRING(200),
|
||
allowNull: true,
|
||
field: 'item_name',
|
||
},
|
||
// 物品数量
|
||
itemQuantity: {
|
||
type: DataTypes.INTEGER,
|
||
allowNull: true,
|
||
field: 'item_quantity',
|
||
},
|
||
// 起运港
|
||
originPort: {
|
||
type: DataTypes.STRING(200),
|
||
allowNull: true,
|
||
field: 'origin_port',
|
||
},
|
||
// 目的港
|
||
destinationPort: {
|
||
type: DataTypes.STRING(200),
|
||
allowNull: true,
|
||
field: 'destination_port',
|
||
},
|
||
// 货物名称
|
||
cargoName: {
|
||
type: DataTypes.STRING(200),
|
||
allowNull: true,
|
||
field: 'cargo_name',
|
||
},
|
||
// 货物数量
|
||
cargoQuantity: {
|
||
type: DataTypes.INTEGER,
|
||
allowNull: true,
|
||
field: 'cargo_quantity',
|
||
},
|
||
// ========== 旅游规划专用字段 ==========
|
||
// 出行日期
|
||
travelDate: {
|
||
type: DataTypes.DATEONLY,
|
||
allowNull: true,
|
||
field: 'travel_date',
|
||
},
|
||
// 旅游目的地
|
||
travelDestination: {
|
||
type: DataTypes.STRING(200),
|
||
allowNull: true,
|
||
field: 'travel_destination',
|
||
},
|
||
// 旅游天数
|
||
travelDays: {
|
||
type: DataTypes.INTEGER,
|
||
allowNull: true,
|
||
field: 'travel_days',
|
||
},
|
||
}, {
|
||
tableName: 'appointment',
|
||
timestamps: true,
|
||
underscored: true,
|
||
indexes: [
|
||
{ fields: ['user_id'] },
|
||
{ fields: ['service_id'] },
|
||
{ fields: ['hot_service_id'] },
|
||
{ fields: ['appointment_no'] },
|
||
{ fields: ['status'] },
|
||
{ fields: ['appointment_date'] },
|
||
{ fields: ['departure_date'] },
|
||
{ fields: ['check_in_date'] },
|
||
{ fields: ['travel_date'] },
|
||
],
|
||
});
|
||
|
||
module.exports = Appointment;
|