|
|
@@ -0,0 +1,292 @@
|
|
|
+package vehicle
|
|
|
+
|
|
|
+import (
|
|
|
+ "errors"
|
|
|
+ "server/dao"
|
|
|
+ "server/global"
|
|
|
+ "server/model/vehicle/request"
|
|
|
+ "time"
|
|
|
+)
|
|
|
+
|
|
|
+type vehicleService struct{}
|
|
|
+
|
|
|
+func NewVehicleService() *vehicleService {
|
|
|
+ return &vehicleService{}
|
|
|
+}
|
|
|
+
|
|
|
+// CreateVehicle 创建车辆信息
|
|
|
+func (s *vehicleService) CreateVehicle(req request.VehicleCreate) error {
|
|
|
+ // 检查车牌号是否已存在
|
|
|
+ var existingVehicle dao.Vehicle
|
|
|
+ result := global.GVA_DB.Where("plate_number = ?", req.PlateNumber).First(&existingVehicle)
|
|
|
+ if result.RowsAffected > 0 {
|
|
|
+ return errors.New("车牌号已存在")
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理临时车辆的情况
|
|
|
+ var ownerId *uint
|
|
|
+ if req.OwnerId > 0 {
|
|
|
+ ownerId = &req.OwnerId
|
|
|
+ }
|
|
|
+
|
|
|
+ vehicle := dao.Vehicle{
|
|
|
+ PlateNumber: req.PlateNumber,
|
|
|
+ VehicleType: req.VehicleType,
|
|
|
+ VehicleBrand: req.VehicleBrand,
|
|
|
+ VehicleColor: req.VehicleColor,
|
|
|
+ OwnerId: ownerId,
|
|
|
+ }
|
|
|
+
|
|
|
+ return global.GVA_DB.Create(&vehicle).Error
|
|
|
+}
|
|
|
+
|
|
|
+// UpdateVehicle 更新车辆信息
|
|
|
+func (s *vehicleService) UpdateVehicle(req request.VehicleUpdate) error {
|
|
|
+ var vehicle dao.Vehicle
|
|
|
+ result := global.GVA_DB.First(&vehicle, req.ID)
|
|
|
+ if result.RowsAffected == 0 {
|
|
|
+ return errors.New("车辆不存在")
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查车牌号是否被其他车辆使用
|
|
|
+ var existingVehicle dao.Vehicle
|
|
|
+ result = global.GVA_DB.Where("plate_number = ? AND id != ?", req.PlateNumber, req.ID).First(&existingVehicle)
|
|
|
+ if result.RowsAffected > 0 {
|
|
|
+ return errors.New("车牌号已被其他车辆使用")
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理临时车辆的情况
|
|
|
+ var ownerId *uint
|
|
|
+ if req.OwnerId > 0 {
|
|
|
+ ownerId = &req.OwnerId
|
|
|
+ } else {
|
|
|
+ ownerId = nil
|
|
|
+ }
|
|
|
+
|
|
|
+ vehicle.PlateNumber = req.PlateNumber
|
|
|
+ vehicle.VehicleType = req.VehicleType
|
|
|
+ vehicle.VehicleBrand = req.VehicleBrand
|
|
|
+ vehicle.VehicleColor = req.VehicleColor
|
|
|
+ vehicle.OwnerId = ownerId
|
|
|
+
|
|
|
+ return global.GVA_DB.Save(&vehicle).Error
|
|
|
+}
|
|
|
+
|
|
|
+// GetVehicleByID 根据ID获取车辆信息
|
|
|
+func (s *vehicleService) GetVehicleByID(id uint) (dao.Vehicle, error) {
|
|
|
+ var vehicle dao.Vehicle
|
|
|
+ result := global.GVA_DB.First(&vehicle, id)
|
|
|
+ if result.RowsAffected == 0 {
|
|
|
+ return dao.Vehicle{}, errors.New("车辆不存在")
|
|
|
+ }
|
|
|
+ return vehicle, nil
|
|
|
+}
|
|
|
+
|
|
|
+// GetVehicleByPlateNumber 根据车牌号获取车辆信息
|
|
|
+func (s *vehicleService) GetVehicleByPlateNumber(plateNumber string) (dao.Vehicle, error) {
|
|
|
+ var vehicle dao.Vehicle
|
|
|
+ result := global.GVA_DB.Where("plate_number = ?", plateNumber).First(&vehicle)
|
|
|
+ if result.RowsAffected == 0 {
|
|
|
+ return dao.Vehicle{}, errors.New("车辆不存在")
|
|
|
+ }
|
|
|
+ return vehicle, nil
|
|
|
+}
|
|
|
+
|
|
|
+// ListVehicles 获取车辆列表
|
|
|
+func (s *vehicleService) ListVehicles(req request.VehicleQuery) (int64, []dao.Vehicle, error) {
|
|
|
+ var vehicles []dao.Vehicle
|
|
|
+ var total int64
|
|
|
+
|
|
|
+ query := global.GVA_DB.Model(&dao.Vehicle{})
|
|
|
+
|
|
|
+ if req.PlateNumber != "" {
|
|
|
+ query = query.Where("plate_number LIKE ?", "%"+req.PlateNumber+"%")
|
|
|
+ }
|
|
|
+
|
|
|
+ if req.VehicleType != "" {
|
|
|
+ query = query.Where("vehicle_type = ?", req.VehicleType)
|
|
|
+ }
|
|
|
+
|
|
|
+ if req.OwnerId > 0 {
|
|
|
+ query = query.Where("owner_id = ?", req.OwnerId)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算总数
|
|
|
+ query.Count(&total)
|
|
|
+
|
|
|
+ // 分页查询
|
|
|
+ offset := (req.Page - 1) * req.PageSize
|
|
|
+ result := query.Offset(offset).Limit(req.PageSize).Find(&vehicles)
|
|
|
+ if result.Error != nil {
|
|
|
+ return 0, nil, result.Error
|
|
|
+ }
|
|
|
+
|
|
|
+ return total, vehicles, nil
|
|
|
+}
|
|
|
+
|
|
|
+// DeleteVehicle 删除车辆
|
|
|
+func (s *vehicleService) DeleteVehicle(id uint) error {
|
|
|
+ result := global.GVA_DB.Delete(&dao.Vehicle{}, id)
|
|
|
+ if result.RowsAffected == 0 {
|
|
|
+ return errors.New("车辆不存在")
|
|
|
+ }
|
|
|
+ return result.Error
|
|
|
+}
|
|
|
+
|
|
|
+// VehicleEntry 车辆入场
|
|
|
+func (s *vehicleService) VehicleEntry(req request.VehicleEntry) (request.VehicleEntryResponse, error) {
|
|
|
+ // 检查车辆是否存在
|
|
|
+ vehicle, err := s.GetVehicleByPlateNumber(req.PlateNumber)
|
|
|
+ if err != nil {
|
|
|
+ // 如果车辆不存在,创建新车辆
|
|
|
+ createReq := request.VehicleCreate{
|
|
|
+ PlateNumber: req.PlateNumber,
|
|
|
+ VehicleType: "普通车辆", // 默认类型
|
|
|
+ OwnerId: 0, // 默认无车主
|
|
|
+ }
|
|
|
+ err = s.CreateVehicle(createReq)
|
|
|
+ if err != nil {
|
|
|
+ return request.VehicleEntryResponse{}, err
|
|
|
+ }
|
|
|
+ vehicle, _ = s.GetVehicleByPlateNumber(req.PlateNumber)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查是否有未出场的记录
|
|
|
+ var existingRecord dao.VehicleRecord
|
|
|
+ result := global.GVA_DB.Where("plate_number = ? AND exit_time IS NULL", req.PlateNumber).First(&existingRecord)
|
|
|
+ if result.RowsAffected > 0 {
|
|
|
+ return request.VehicleEntryResponse{}, errors.New("车辆已入场,未出场")
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建入场记录
|
|
|
+ entryTime := time.Now()
|
|
|
+ record := dao.VehicleRecord{
|
|
|
+ PlateNumber: req.PlateNumber,
|
|
|
+ EntryTime: entryTime,
|
|
|
+ ParkingLotID: req.ParkingLotID,
|
|
|
+ ParkingSpaceID: req.ParkingSpaceID,
|
|
|
+ EntryImage: req.EntryImage,
|
|
|
+ PaymentStatus: "unpaid",
|
|
|
+ }
|
|
|
+
|
|
|
+ err = global.GVA_DB.Create(&record).Error
|
|
|
+ if err != nil {
|
|
|
+ return request.VehicleEntryResponse{}, err
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新车辆最近入场时间
|
|
|
+ vehicle.LastEntryTime = entryTime
|
|
|
+ global.GVA_DB.Save(&vehicle)
|
|
|
+
|
|
|
+ response := request.VehicleEntryResponse{
|
|
|
+ Success: true,
|
|
|
+ Message: "车辆入场成功",
|
|
|
+ }
|
|
|
+ response.Data.PlateNumber = req.PlateNumber
|
|
|
+ response.Data.EntryTime = entryTime.Unix()
|
|
|
+ response.Data.ParkingLotID = req.ParkingLotID
|
|
|
+ response.Data.ParkingSpaceID = req.ParkingSpaceID
|
|
|
+
|
|
|
+ return response, nil
|
|
|
+}
|
|
|
+
|
|
|
+// VehicleExit 车辆出场
|
|
|
+func (s *vehicleService) VehicleExit(req request.VehicleExit) (request.VehicleExitResponse, error) {
|
|
|
+ // 检查是否有未出场的记录
|
|
|
+ var record dao.VehicleRecord
|
|
|
+ result := global.GVA_DB.Where("plate_number = ? AND exit_time IS NULL", req.PlateNumber).First(&record)
|
|
|
+ if result.RowsAffected == 0 {
|
|
|
+ return request.VehicleExitResponse{}, errors.New("车辆未入场")
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取车辆信息
|
|
|
+ vehicle, err := s.GetVehicleByPlateNumber(req.PlateNumber)
|
|
|
+ if err != nil {
|
|
|
+ return request.VehicleExitResponse{}, err
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算费用
|
|
|
+ exitTime := time.Now()
|
|
|
+ stayTime := int64(exitTime.Sub(record.EntryTime).Minutes()) // 转换为分钟
|
|
|
+ fee := s.calculateFee(vehicle, stayTime)
|
|
|
+
|
|
|
+ // 更新出场记录
|
|
|
+ record.ExitTime = exitTime
|
|
|
+ record.StayTime = stayTime
|
|
|
+ record.Fee = fee
|
|
|
+ record.ExitImage = req.ExitImage
|
|
|
+ record.PaymentStatus = "paid" // 假设出场时已支付
|
|
|
+
|
|
|
+ err = global.GVA_DB.Save(&record).Error
|
|
|
+ if err != nil {
|
|
|
+ return request.VehicleExitResponse{}, err
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新车辆信息
|
|
|
+ vehicle.LastExitTime = exitTime
|
|
|
+ vehicle.TotalStayTime += stayTime
|
|
|
+ vehicle.TotalFee += fee
|
|
|
+ global.GVA_DB.Save(&vehicle)
|
|
|
+
|
|
|
+ response := request.VehicleExitResponse{
|
|
|
+ Success: true,
|
|
|
+ Message: "车辆出场成功",
|
|
|
+ }
|
|
|
+ response.Data.PlateNumber = req.PlateNumber
|
|
|
+ response.Data.EntryTime = record.EntryTime.Unix()
|
|
|
+ response.Data.ExitTime = exitTime.Unix()
|
|
|
+ response.Data.StayTime = stayTime
|
|
|
+ response.Data.Fee = fee
|
|
|
+ response.Data.PaymentStatus = record.PaymentStatus
|
|
|
+
|
|
|
+ return response, nil
|
|
|
+}
|
|
|
+
|
|
|
+// calculateFee 计算停车费用
|
|
|
+func (s *vehicleService) calculateFee(vehicle dao.Vehicle, stayTime int64) float64 {
|
|
|
+ // 获取收费配置
|
|
|
+ var feeConfig dao.FeeConfig
|
|
|
+ result := global.GVA_DB.Where("vehicle_type = ?", vehicle.VehicleType).First(&feeConfig)
|
|
|
+ if result.RowsAffected == 0 {
|
|
|
+ // 使用默认收费标准
|
|
|
+ return float64(stayTime) * 0.1 // 默认0.1元/分钟
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查是否是VIP且免费
|
|
|
+ isVIP := false
|
|
|
+ if vehicle.OwnerId != nil {
|
|
|
+ var owner dao.Owner
|
|
|
+ ownerResult := global.GVA_DB.First(&owner, *vehicle.OwnerId)
|
|
|
+ if ownerResult.RowsAffected > 0 {
|
|
|
+ // 检查是否是VIP且未过期
|
|
|
+ isVIP = owner.IsVip && time.Now().Before(owner.VipExpireTime)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if isVIP && feeConfig.IsVIPFree {
|
|
|
+ return 0
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算费用
|
|
|
+ fee := feeConfig.StartFee
|
|
|
+ if stayTime > int64(feeConfig.StartTime) {
|
|
|
+ extraTime := stayTime - int64(feeConfig.StartTime)
|
|
|
+ extraUnits := extraTime / int64(feeConfig.UnitTime)
|
|
|
+ if extraTime%int64(feeConfig.UnitTime) > 0 {
|
|
|
+ extraUnits++
|
|
|
+ }
|
|
|
+ fee += float64(extraUnits) * feeConfig.UnitFee
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查每日最高费用
|
|
|
+ if fee > feeConfig.DailyMaxFee {
|
|
|
+ fee = feeConfig.DailyMaxFee
|
|
|
+ }
|
|
|
+
|
|
|
+ // 应用VIP折扣
|
|
|
+ if isVIP {
|
|
|
+ fee *= feeConfig.VIPDiscount
|
|
|
+ }
|
|
|
+
|
|
|
+ return fee
|
|
|
+}
|