浏览代码

设备上线时间 不填默认 null

xu 3 月之前
父节点
当前提交
1aaa47bb15
共有 3 个文件被更改,包括 55 次插入32 次删除
  1. 5 5
      server/dao/uhf_reader.go
  2. 34 16
      server/service/uhf/reader.go
  3. 16 11
      server/service/vehicle/vehicle.go

+ 5 - 5
server/dao/uhf_reader.go

@@ -23,11 +23,11 @@ type UHFReader struct {
 	COMPort  string `gorm:"size:50" json:"com_port"`       // COM3 /dev/ttyUSB0
 	BaudRate int    `gorm:"default:9600" json:"baud_rate"` // 波特率
 
-	Status         string    `gorm:"size:20;default:'offline'" json:"status"`
-	IsActive       bool      `gorm:"default:true" json:"is_active"`
-	Description    string    `gorm:"size:200" json:"description"`
-	ParkingLotID   uint      `json:"parking_lot_id"`
-	LastOnlineTime time.Time `json:"last_online_time" gorm:"comment:最后上线时间"`
+	Status         string     `gorm:"size:20;default:'offline'" json:"status"`
+	IsActive       bool       `gorm:"default:true" json:"is_active"`
+	Description    string     `gorm:"size:200" json:"description"`
+	ParkingLotID   uint       `json:"parking_lot_id"`
+	LastOnlineTime *time.Time `json:"last_online_time" gorm:"comment:最后上线时间;default:null"`
 
 	ChannelID uint     `gorm:"comment:绑定通道ID" json:"channel_id"`
 	Channel   *Channel `gorm:"foreignKey:ChannelID;references:ID" json:"channel"`

+ 34 - 16
server/service/uhf/reader.go

@@ -237,13 +237,16 @@ func handleReportData(report *ReportData) {
 	if len(report.Epcs) == 0 {
 		return
 	}
+
 	epc := report.Epcs[0]
+
+	fmt.Println("<UNK>", epc)
 	now := time.Now().Unix()
 
 	epcMutex.Lock()
 	defer epcMutex.Unlock()
 
-	// 3秒防抖
+	// ===================== 修复:3秒防抖 =====================
 	if lastTime, ok := epcLastTime[epc]; ok && now-lastTime < debounceSecond {
 		return
 	}
@@ -265,7 +268,7 @@ func handleReportData(report *ReportData) {
 	allowTemporary := channel.AllowTemporary
 
 	vehicleService := service.ServiceGroupApp.VehicleServiceGroup.VehicleService
-	shortlistService := service.ServiceGroupApp.VehicleServiceGroup.ShortlistService // 黑白名单服务
+	shortlistService := service.ServiceGroupApp.VehicleServiceGroup.ShortlistService
 
 	// ===================== 1. 根据EPC查询车辆 =====================
 	vehicle, err := vehicleService.GetVehicleByPlateNumber("", epc)
@@ -273,13 +276,18 @@ func handleReportData(report *ReportData) {
 	if err != nil || vehicle.ID == 0 {
 		isTempVehicle = true
 	} else {
-		isTempVehicle = (vehicle.VehicleType.Name == "临时车")
+		// ===================== 修复:防止空指针panic =====================
+		if vehicle.VehicleType != nil {
+			isTempVehicle = (vehicle.VehicleTypeID == 1)
+		} else {
+			isTempVehicle = true
+		}
 	}
 
 	// ===================== 2. 查询黑白名单 =====================
 	isBlack, isWhite := shortlistService.CheckVehicleShortlist(epc)
 
-	// ===================== 3. 黑名单优先判断:无论什么车,黑名单一律禁止 =====================
+	// ===================== 3. 黑名单优先判断 =====================
 	if isBlack {
 		fmt.Printf("🚫 禁止通行 | 车辆在黑名单中 | 设备:%s EPC:%s\n", report.DeviceCode, epc)
 		epcLastTime[epc] = now
@@ -288,14 +296,11 @@ func handleReportData(report *ReportData) {
 
 	// ===================== 4. 临时车规则 =====================
 	if isTempVehicle {
-		// 通道不允许临时车 + 不在白名单 → 禁止
 		if !allowTemporary && !isWhite {
 			fmt.Printf("🚫 禁止通行 | 临时车不允许此通道且不在白名单 | 设备:%s EPC:%s\n", report.DeviceCode, epc)
 			epcLastTime[epc] = now
 			return
 		}
-
-		// 临时车 + 不在白名单 → 禁止
 		if !isWhite {
 			fmt.Printf("🚫 禁止通行 | 临时车不在白名单 | 设备:%s EPC:%s\n", report.DeviceCode, epc)
 			epcLastTime[epc] = now
@@ -305,36 +310,49 @@ func handleReportData(report *ReportData) {
 
 	// ===================== 5. 入口 =====================
 	if direction == "in" {
+		// 关键:只要状态是 false 就允许进入
 		if !epcStatus[epc] {
 			fmt.Printf("🟢 入口开闸 | 设备:%s EPC:%s 临时车:%v 白名单:%v\n", report.DeviceCode, epc, isTempVehicle, isWhite)
-
-			// 开闸
 			handler.reader.CloseRelay1(2)
 
 			// 记录入场
 			var vehicleEntry request.VehicleEntry
 			vehicleEntry.RFIDTag = epc
-			vehicleService.VehicleEntry(vehicleEntry)
+			vehicleEntry.ParkingLotID = channel.ParkingLotID
+			_, err := vehicleService.VehicleEntry(vehicleEntry)
 
-			epcStatus[epc] = true
+			if err != nil {
+				fmt.Printf("❌ 入场记录失败:%v | EPC:%s\n", err, epc)
+				// 关键:不设置 epcStatus[epc] = true
+				// 让下一次刷卡可以继续进入
+			} else {
+				// ✅ 只有成功才修改状态
+				epcStatus[epc] = true
+			}
+		} else {
+			fmt.Printf("⚠️  已在场内,禁止重复入场 | EPC:%s\n", epc)
 		}
 	}
 
 	// ===================== 6. 出口 =====================
 	if direction == "out" {
 		fmt.Printf("🔴 出口开闸 | 设备:%s EPC:%s 临时车:%v 白名单:%v\n", report.DeviceCode, epc, isTempVehicle, isWhite)
-
-		// 开闸
 		handler.reader.CloseRelay1(2)
 
 		// 记录出场
 		var vehicleExit request.VehicleExit
 		vehicleExit.RFIDTag = epc
-		vehicleService.VehicleExit(vehicleExit)
-
-		epcStatus[epc] = false
+		_, err := vehicleService.VehicleExit(vehicleExit)
+		if err != nil {
+			fmt.Printf("❌ 出场记录失败:%v | EPC:%s\n", err, epc)
+			// 关键:不设置 epcStatus[epc] = false
+		} else {
+			// ✅ 只有成功才重置状态
+			epcStatus[epc] = false
+		}
 	}
 
+	// 更新最后读卡时间
 	epcLastTime[epc] = now
 }
 

+ 16 - 11
server/service/vehicle/vehicle.go

@@ -287,23 +287,28 @@ func (s *VehicleService) calculateFee(vehicle *dao.Vehicle, stayTime int64) floa
 		return 0
 	}
 
-	// 4. 基础费用计算
-	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
+	// ===================== 修复这里 =====================
+	// 4. 在免费时长内 → 直接 0 元
+	if stayTime <= int64(feeConfig.StartTime) {
+		return 0
 	}
 
-	// 5. 每日封顶
+	// 5. 超过免费时长 → 开始计费
+	extraTime := stayTime - int64(feeConfig.StartTime)
+	extraUnits := extraTime / int64(feeConfig.UnitTime)
+	if extraTime%int64(feeConfig.UnitTime) > 0 {
+		extraUnits++
+	}
+
+	// 起步费 + 超时费用
+	fee := feeConfig.StartFee + float64(extraUnits)*feeConfig.UnitFee
+
+	// 6. 每日封顶
 	if feeConfig.DailyMaxFee > 0 && fee > feeConfig.DailyMaxFee {
 		fee = feeConfig.DailyMaxFee
 	}
 
-	// 6. VIP 折扣
+	// 7. VIP 折扣
 	if isVIP {
 		fee *= feeConfig.VIPDiscount
 	}