vehicle.go 9.0 KB

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