vehicle.go 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. package vehicle
  2. import (
  3. "errors"
  4. "fmt"
  5. "server/dao"
  6. "server/global"
  7. "server/model/vehicle/request"
  8. "time"
  9. )
  10. type VehicleService struct{}
  11. // CreateVehicle 创建车辆信息
  12. func (s *VehicleService) CreateVehicle(req request.VehicleCreate) error {
  13. // 检查车牌号是否已存在
  14. var existingVehicle dao.Vehicle
  15. result := global.GVA_DB.Where("plate_number = ? OR rfid_tag = ?", req.PlateNumber, req.RFIDTag).First(&existingVehicle)
  16. if result.RowsAffected > 0 {
  17. return errors.New("车牌号已存在")
  18. }
  19. // 检查车辆类型是否存在
  20. var vehicleType dao.VehicleType
  21. result = global.GVA_DB.First(&vehicleType, req.VehicleTypeID)
  22. if result.RowsAffected == 0 {
  23. return errors.New("车辆类型不存在")
  24. }
  25. // 处理临时车辆的情况
  26. var ownerId *uint
  27. if req.OwnerId > 0 {
  28. ownerId = &req.OwnerId
  29. }
  30. vehicle := dao.Vehicle{
  31. PlateNumber: req.PlateNumber,
  32. VehicleTypeID: req.VehicleTypeID,
  33. VehicleBrand: req.VehicleBrand,
  34. VehicleColor: req.VehicleColor,
  35. OwnerId: ownerId,
  36. }
  37. return global.GVA_DB.Create(&vehicle).Error
  38. }
  39. // UpdateVehicle 更新车辆信息
  40. func (s *VehicleService) UpdateVehicle(req request.VehicleUpdate) error {
  41. var vehicle dao.Vehicle
  42. result := global.GVA_DB.First(&vehicle, req.ID)
  43. if result.RowsAffected == 0 {
  44. return errors.New("车辆不存在")
  45. }
  46. // 检查车牌号是否被其他车辆使用
  47. var existingVehicle dao.Vehicle
  48. result = global.GVA_DB.Where("(plate_number = ? OR rfid_tag = ?) AND id != ?", req.PlateNumber, req.RFIDTag, req.ID).First(&existingVehicle)
  49. fmt.Println("result", result.RowsAffected)
  50. if result.RowsAffected > 0 {
  51. return errors.New("车牌号已被其他车辆使用")
  52. }
  53. // 检查车辆类型是否存在
  54. var vehicleType dao.VehicleType
  55. result = global.GVA_DB.First(&vehicleType, req.VehicleTypeID)
  56. if result.RowsAffected == 0 {
  57. return errors.New("车辆类型不存在")
  58. }
  59. // 处理临时车辆的情况
  60. var ownerId *uint
  61. if req.OwnerId > 0 {
  62. ownerId = &req.OwnerId
  63. } else {
  64. ownerId = nil
  65. }
  66. err := global.GVA_DB.Model(&vehicle).Updates(map[string]interface{}{
  67. "plate_number": req.PlateNumber,
  68. "rfid_tag": req.RFIDTag,
  69. "vehicle_type_id": req.VehicleTypeID,
  70. "vehicle_brand": req.VehicleBrand,
  71. "vehicle_color": req.VehicleColor,
  72. "owner_id": ownerId,
  73. }).Error
  74. return err
  75. }
  76. // GetVehicleByID 根据ID获取车辆信息
  77. func (s *VehicleService) GetVehicleByID(id uint) (dao.Vehicle, error) {
  78. var vehicle dao.Vehicle
  79. result := global.GVA_DB.First(&vehicle, id)
  80. if result.RowsAffected == 0 {
  81. return dao.Vehicle{}, errors.New("车辆不存在")
  82. }
  83. return vehicle, nil
  84. }
  85. // GetVehicleByPlateNumber 根据车牌号获取车辆信息
  86. func (s *VehicleService) GetVehicleByPlateNumber(plateNumber, RFIDTag string) (dao.Vehicle, error) {
  87. var vehicle dao.Vehicle
  88. result := global.GVA_DB.Where("plate_number = ? or rfid_tag = ?", plateNumber, RFIDTag).Preload("VehicleType").First(&vehicle)
  89. if result.RowsAffected == 0 {
  90. return dao.Vehicle{}, errors.New("车辆不存在")
  91. }
  92. return vehicle, nil
  93. }
  94. func (s *VehicleService) QueryAllVehicles() ([]dao.Vehicle, error) {
  95. var vehicles []dao.Vehicle
  96. err := global.GVA_DB.Find(&vehicles).Error
  97. if err != nil {
  98. return vehicles, err
  99. }
  100. return vehicles, nil
  101. }
  102. // ListVehicles 获取车辆列表
  103. func (s *VehicleService) ListVehicles(req request.VehicleQuery) (int64, []dao.Vehicle, error) {
  104. var vehicles []dao.Vehicle
  105. var total int64
  106. query := global.GVA_DB.Model(&dao.Vehicle{})
  107. if req.PlateNumber != "" {
  108. query = query.Where("plate_number LIKE ?", "%"+req.PlateNumber+"%")
  109. }
  110. if req.VehicleTypeID > 0 {
  111. query = query.Where("vehicle_type_id = ?", req.VehicleTypeID)
  112. }
  113. if req.OwnerId > 0 {
  114. query = query.Where("owner_id = ?", req.OwnerId)
  115. }
  116. // 计算总数
  117. query.Count(&total)
  118. // 分页查询
  119. offset := (req.Page - 1) * req.PageSize
  120. result := query.Offset(offset).Limit(req.PageSize).Preload("Owner").Preload("VehicleType").Find(&vehicles)
  121. if result.Error != nil {
  122. return 0, nil, result.Error
  123. }
  124. return total, vehicles, nil
  125. }
  126. // DeleteVehicle 删除车辆
  127. func (s *VehicleService) DeleteVehicle(id uint) error {
  128. result := global.GVA_DB.Delete(&dao.Vehicle{}, id)
  129. if result.RowsAffected == 0 {
  130. return errors.New("车辆不存在")
  131. }
  132. return result.Error
  133. }
  134. // VehicleEntry 车辆入场
  135. func (s *VehicleService) VehicleEntry(req request.VehicleEntry) (request.VehicleEntryResponse, error) {
  136. // 检查车辆是否存在
  137. vehicle, err := s.GetVehicleByPlateNumber(req.PlateNumber, req.RFIDTag)
  138. if err != nil {
  139. // 如果车辆不存在,创建新车辆,默认使用ID为1的车辆类型(临时车)
  140. createReq := request.VehicleCreate{
  141. PlateNumber: req.PlateNumber,
  142. VehicleTypeID: 1, // 默认类型ID为1(临时车)
  143. OwnerId: 0, // 默认无车主
  144. }
  145. err = s.CreateVehicle(createReq)
  146. if err != nil {
  147. return request.VehicleEntryResponse{}, err
  148. }
  149. vehicle, _ = s.GetVehicleByPlateNumber(req.PlateNumber, req.RFIDTag)
  150. }
  151. // 检查是否有未出场的记录
  152. var existingRecord dao.VehicleRecord
  153. result := global.GVA_DB.Where("(plate_number = ? OR rfid_tag = ?) AND exit_time IS NULL", req.PlateNumber, req.RFIDTag).First(&existingRecord)
  154. if result.RowsAffected > 0 {
  155. return request.VehicleEntryResponse{}, errors.New("车辆已入场,未出场")
  156. }
  157. // 创建入场记录
  158. entryTime := time.Now()
  159. record := dao.VehicleRecord{
  160. PlateNumber: req.PlateNumber,
  161. RFIDTag: req.RFIDTag,
  162. EntryTime: entryTime,
  163. ParkingLotID: req.ParkingLotID,
  164. ParkingSpaceID: req.ParkingSpaceID,
  165. EntryImage: req.EntryImage,
  166. PaymentStatus: "unpaid",
  167. }
  168. err = global.GVA_DB.Create(&record).Error
  169. if err != nil {
  170. return request.VehicleEntryResponse{}, err
  171. }
  172. // 更新车辆最近入场时间
  173. vehicle.LastEntryTime = &entryTime
  174. global.GVA_DB.Save(&vehicle)
  175. response := request.VehicleEntryResponse{
  176. Success: true,
  177. Message: "车辆入场成功",
  178. }
  179. response.Data.PlateNumber = req.PlateNumber
  180. response.Data.EntryTime = entryTime.Unix()
  181. response.Data.ParkingLotID = req.ParkingLotID
  182. response.Data.ParkingSpaceID = req.ParkingSpaceID
  183. return response, nil
  184. }
  185. // VehicleExit 车辆出场
  186. func (s *VehicleService) VehicleExit(req request.VehicleExit) (request.VehicleExitResponse, error) {
  187. // 1. 查询未出场记录
  188. var record dao.VehicleRecord
  189. if err := global.GVA_DB.Where("(plate_number = ? OR rfid_tag = ?) AND exit_time IS NULL", req.PlateNumber, req.RFIDTag).First(&record).Error; err != nil {
  190. return request.VehicleExitResponse{}, errors.New("车辆未入场或已出场")
  191. }
  192. // 2. 获取车辆信息
  193. vehicle, err := s.GetVehicleByPlateNumber(req.PlateNumber, req.RFIDTag)
  194. if err != nil {
  195. return request.VehicleExitResponse{}, err
  196. }
  197. // 3. 计算停留时长 & 费用
  198. exitTime := time.Now()
  199. stayTime := int64(exitTime.Sub(record.EntryTime).Minutes())
  200. if stayTime < 0 {
  201. stayTime = 0
  202. }
  203. fee := s.calculateFee(&vehicle, stayTime)
  204. // 4. 更新出场记录
  205. record.ExitTime = &exitTime
  206. record.StayTime = stayTime
  207. record.Fee = fee
  208. record.ExitImage = req.ExitImage
  209. record.PaymentStatus = "paid"
  210. if err := global.GVA_DB.Save(&record).Error; err != nil {
  211. return request.VehicleExitResponse{}, err
  212. }
  213. // 5. 更新车辆统计信息
  214. vehicle.LastExitTime = &exitTime
  215. vehicle.TotalStayTime += stayTime
  216. vehicle.TotalFee += fee
  217. global.GVA_DB.Save(&vehicle)
  218. // 6. 完全匹配你的匿名结构体返回(正确写法)
  219. var response request.VehicleExitResponse
  220. response.Success = true
  221. response.Message = "车辆出场成功"
  222. response.Data.PlateNumber = record.PlateNumber
  223. response.Data.EntryTime = record.EntryTime.Unix()
  224. response.Data.ExitTime = exitTime.Unix()
  225. response.Data.StayTime = stayTime
  226. response.Data.Fee = fee
  227. response.Data.PaymentStatus = record.PaymentStatus
  228. return response, nil
  229. }
  230. // calculateFee 计算停车费用
  231. func (s *VehicleService) calculateFee(vehicle *dao.Vehicle, stayTime int64) float64 {
  232. // 1. 根据车辆类型ID获取收费配置(唯一)
  233. var feeConfig dao.FeeConfig
  234. if err := global.GVA_DB.Where("vehicle_type_id = ?", vehicle.VehicleTypeID).First(&feeConfig).Error; err != nil {
  235. // 无配置 → 默认计费
  236. return float64(stayTime) * 0.1
  237. }
  238. // 2. 判断VIP有效性
  239. isVIP := false
  240. if vehicle.OwnerId != nil {
  241. var owner dao.Owner
  242. if err := global.GVA_DB.First(&owner, *vehicle.OwnerId).Error; err == nil {
  243. isVIP = owner.IsVip && time.Now().Before(owner.VipExpireTime)
  244. }
  245. }
  246. // 3. VIP 免费
  247. if isVIP && feeConfig.IsVIPFree {
  248. return 0
  249. }
  250. // ===================== 修复这里 =====================
  251. // 4. 在免费时长内 → 直接 0 元
  252. if stayTime <= int64(feeConfig.StartTime) {
  253. return 0
  254. }
  255. // 5. 超过免费时长 → 开始计费
  256. extraTime := stayTime - int64(feeConfig.StartTime)
  257. extraUnits := extraTime / int64(feeConfig.UnitTime)
  258. if extraTime%int64(feeConfig.UnitTime) > 0 {
  259. extraUnits++
  260. }
  261. // 起步费 + 超时费用
  262. fee := feeConfig.StartFee + float64(extraUnits)*feeConfig.UnitFee
  263. // 6. 每日封顶
  264. if feeConfig.DailyMaxFee > 0 && fee > feeConfig.DailyMaxFee {
  265. fee = feeConfig.DailyMaxFee
  266. }
  267. // 7. VIP 折扣
  268. if isVIP {
  269. fee *= feeConfig.VIPDiscount
  270. }
  271. return fee
  272. }