fee_config.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. package vehicle
  2. import (
  3. "errors"
  4. "math"
  5. "wails-app/internal/dao"
  6. "wails-app/internal/global"
  7. "wails-app/internal/model/vehicle/request"
  8. )
  9. type FeeConfigService struct{}
  10. // validateFeeRules 校验收费规则的数值合法性,防止脏配置静默改变计费。
  11. // 全零配置允许(显式免费),但单位时间必须大于 0,金额必须非负且有限。
  12. func validateFeeRules(req request.FeeConfigCreate) error {
  13. if req.StartTime < 0 {
  14. return errors.New("免费时长不能为负数")
  15. }
  16. if req.UnitTime <= 0 {
  17. return errors.New("单位时间必须大于0分钟")
  18. }
  19. if req.StartFee < 0 || math.IsNaN(req.StartFee) || math.IsInf(req.StartFee, 0) {
  20. return errors.New("起步价必须为非负有限数值")
  21. }
  22. if req.UnitFee < 0 || math.IsNaN(req.UnitFee) || math.IsInf(req.UnitFee, 0) {
  23. return errors.New("单位费用必须为非负有限数值")
  24. }
  25. if req.DailyMaxFee < 0 || math.IsNaN(req.DailyMaxFee) || math.IsInf(req.DailyMaxFee, 0) {
  26. return errors.New("日封顶金额必须为非负有限数值")
  27. }
  28. if req.DailyMaxFee > 0 && req.DailyMaxFee < req.StartFee {
  29. return errors.New("日封顶金额不能低于起步价")
  30. }
  31. if req.VIPDiscount <= 0 || req.VIPDiscount > 1 || math.IsNaN(req.VIPDiscount) || math.IsInf(req.VIPDiscount, 0) {
  32. return errors.New("VIP折扣必须在(0,1]区间,如0.8表示八折")
  33. }
  34. if req.FreeExitMinutes < 0 {
  35. return errors.New("缴费后免费离场分钟数不能为负数")
  36. }
  37. return nil
  38. }
  39. // CreateFeeConfig 创建收费配置
  40. func (s *FeeConfigService) CreateFeeConfig(req request.FeeConfigCreate) error {
  41. if err := validateFeeRules(req); err != nil {
  42. return err
  43. }
  44. // 检查车辆类型是否存在
  45. var vehicleType dao.VehicleType
  46. result := global.GVA_DB.First(&vehicleType, req.VehicleTypeID)
  47. if result.RowsAffected == 0 {
  48. return errors.New("车辆类型不存在")
  49. }
  50. // 检查车辆类型是否已存在收费配置
  51. var existingConfig dao.FeeConfig
  52. result = global.GVA_DB.Where("vehicle_type_id = ?", req.VehicleTypeID).First(&existingConfig)
  53. if result.RowsAffected > 0 {
  54. return errors.New("该车辆类型的收费配置已存在")
  55. }
  56. config := dao.FeeConfig{
  57. VehicleTypeID: req.VehicleTypeID,
  58. StartTime: req.StartTime,
  59. StartFee: req.StartFee,
  60. UnitTime: req.UnitTime,
  61. UnitFee: req.UnitFee,
  62. DailyMaxFee: req.DailyMaxFee,
  63. FreeExitMinutes: req.FreeExitMinutes,
  64. IsVIPFree: req.IsVIPFree,
  65. VIPDiscount: req.VIPDiscount,
  66. Description: req.Description,
  67. }
  68. return global.GVA_DB.Create(&config).Error
  69. }
  70. // UpdateFeeConfig 更新收费配置
  71. func (s *FeeConfigService) UpdateFeeConfig(req request.FeeConfigUpdate) error {
  72. if err := validateFeeRules(request.FeeConfigCreate{
  73. VehicleTypeID: req.VehicleTypeID,
  74. StartTime: req.StartTime,
  75. StartFee: req.StartFee,
  76. UnitTime: req.UnitTime,
  77. UnitFee: req.UnitFee,
  78. DailyMaxFee: req.DailyMaxFee,
  79. FreeExitMinutes: req.FreeExitMinutes,
  80. IsVIPFree: req.IsVIPFree,
  81. VIPDiscount: req.VIPDiscount,
  82. Description: req.Description,
  83. }); err != nil {
  84. return err
  85. }
  86. var config dao.FeeConfig
  87. result := global.GVA_DB.First(&config, req.ID)
  88. if result.RowsAffected == 0 {
  89. return errors.New("收费配置不存在")
  90. }
  91. // 检查车辆类型是否存在
  92. var vehicleType dao.VehicleType
  93. result = global.GVA_DB.First(&vehicleType, req.VehicleTypeID)
  94. if result.RowsAffected == 0 {
  95. return errors.New("车辆类型不存在")
  96. }
  97. // 检查车辆类型是否被其他配置使用
  98. var existingConfig dao.FeeConfig
  99. result = global.GVA_DB.Where("vehicle_type_id = ? AND id != ?", req.VehicleTypeID, req.ID).First(&existingConfig)
  100. if result.RowsAffected > 0 {
  101. return errors.New("该车辆类型的收费配置已存在")
  102. }
  103. config.VehicleTypeID = req.VehicleTypeID
  104. config.StartTime = req.StartTime
  105. config.StartFee = req.StartFee
  106. config.UnitTime = req.UnitTime
  107. config.UnitFee = req.UnitFee
  108. config.DailyMaxFee = req.DailyMaxFee
  109. config.FreeExitMinutes = req.FreeExitMinutes
  110. config.IsVIPFree = req.IsVIPFree
  111. config.VIPDiscount = req.VIPDiscount
  112. config.Description = req.Description
  113. return global.GVA_DB.Save(&config).Error
  114. }
  115. // GetFeeConfigByID 根据ID获取收费配置
  116. func (s *FeeConfigService) GetFeeConfigByID(id uint) (dao.FeeConfig, error) {
  117. var config dao.FeeConfig
  118. result := global.GVA_DB.First(&config, id)
  119. if result.RowsAffected == 0 {
  120. return dao.FeeConfig{}, errors.New("收费配置不存在")
  121. }
  122. return config, nil
  123. }
  124. // GetFeeConfigByVehicleType 根据车辆类型ID获取收费配置
  125. func (s *FeeConfigService) GetFeeConfigByVehicleType(vehicleTypeID uint) (dao.FeeConfig, error) {
  126. var config dao.FeeConfig
  127. result := global.GVA_DB.Where("vehicle_type_id = ?", vehicleTypeID).First(&config)
  128. if result.RowsAffected == 0 {
  129. return dao.FeeConfig{}, errors.New("收费配置不存在")
  130. }
  131. return config, nil
  132. }
  133. // ListFeeConfigs 获取收费配置列表
  134. func (s *FeeConfigService) ListFeeConfigs(req request.FeeConfigQuery) (int64, []dao.FeeConfig, error) {
  135. var configs []dao.FeeConfig
  136. var total int64
  137. query := global.GVA_DB.Model(&dao.FeeConfig{})
  138. if req.VehicleTypeID > 0 {
  139. query = query.Where("vehicle_type_id = ?", req.VehicleTypeID)
  140. }
  141. // 计算总数
  142. query.Count(&total)
  143. // 分页兜底(gin 不解析 default 标签,Page/PageSize 可能为 0 或负数)
  144. if req.Page <= 0 {
  145. req.Page = 1
  146. }
  147. if req.PageSize <= 0 {
  148. req.PageSize = 10
  149. }
  150. offset := (req.Page - 1) * req.PageSize
  151. result := query.Offset(offset).Limit(req.PageSize).Preload("VehicleType").Find(&configs)
  152. if result.Error != nil {
  153. return 0, nil, result.Error
  154. }
  155. return total, configs, nil
  156. }
  157. // DeleteFeeConfig 删除收费配置
  158. func (s *FeeConfigService) DeleteFeeConfig(id uint) error {
  159. result := global.GVA_DB.Delete(&dao.FeeConfig{}, id)
  160. if result.RowsAffected == 0 {
  161. return errors.New("收费配置不存在")
  162. }
  163. return result.Error
  164. }