daShangDao_psiServer/service/car.go
2026-06-18 13:01:56 +08:00

494 lines
12 KiB
Go

package service
import (
"errors"
"fmt"
"gorm.io/gorm"
"psi/constant"
"psi/database"
"psi/models"
systemReq "psi/models/request"
systemRes "psi/models/response"
"strconv"
"time"
)
type CarService struct{}
// GetCarList 获取小车列表
func (s *CarService) GetCarList(req systemReq.QueryCarRequest, db ...*gorm.DB) ([]systemRes.CarResponse, int64, error) {
databaseConn := database.OptionalDB(db...)
if req.Page < 1 {
req.Page = 1
}
if req.PageSize < 1 || req.PageSize > 100 {
req.PageSize = 20
}
query := databaseConn.Model(&models.Car{}).Where("is_del = ?", 0)
if req.Keyword != "" {
query = query.Where("code like ? OR name like ?", "%"+req.Keyword+"%", "%"+req.Keyword+"%")
}
var total int64
if err := query.Count(&total).Error; err != nil {
return nil, 0, errors.New("查询小车总数失败")
}
var cars []models.Car
offset := (req.Page - 1) * req.PageSize
if err := query.Order("id DESC").Offset(offset).Limit(req.PageSize).Find(&cars).Error; err != nil {
return nil, 0, errors.New("查询小车列表失败")
}
responses := make([]systemRes.CarResponse, 0, len(cars))
for _, car := range cars {
resp := systemRes.ConvertCarToResponse(car)
var carShops []models.CarShop
if err := databaseConn.Where("car_id = ? AND is_del = ?", car.ID, 0).Find(&carShops).Error; err == nil {
shops := make([]systemRes.CarShopInfo, 0, len(carShops))
for _, cs := range carShops {
shops = append(shops, systemRes.CarShopInfo{
ShopID: strconv.FormatInt(cs.ShopID, 10),
ShopName: cs.ShopName,
ShopType: cs.ShopType,
ShopTypeText: getShopTypeText(cs.ShopType),
})
}
resp.Shops = shops
}
responses = append(responses, resp)
}
return responses, total, nil
}
// GetCarByID 获取小车信息
func (s *CarService) GetCarByID(id int64, db ...*gorm.DB) (*systemRes.CarResponse, error) {
databaseConn := database.OptionalDB(db...)
var car models.Car
if err := databaseConn.Where("id = ? AND is_del = ?", id, 0).First(&car).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errors.New("小车不存在")
}
return nil, errors.New("查询小车失败")
}
resp := systemRes.ConvertCarToResponse(car)
var carShops []models.CarShop
if err := databaseConn.Where("car_id = ? AND is_del = ?", car.ID, 0).Find(&carShops).Error; err == nil {
shops := make([]systemRes.CarShopInfo, 0, len(carShops))
for _, cs := range carShops {
shops = append(shops, systemRes.CarShopInfo{
ShopID: strconv.FormatInt(cs.ShopID, 10),
ShopName: cs.ShopName,
ShopType: cs.ShopType,
ShopTypeText: getShopTypeText(cs.ShopType),
})
}
resp.Shops = shops
}
return &resp, nil
}
// CreateCar 创建小车
func (s *CarService) CreateCar(req systemReq.CreateCarRequest, id int64, db ...*gorm.DB) (int64, error) {
databaseConn := database.OptionalDB(db...)
var count int64
databaseConn.Model(&models.Car{}).
Where("code = ? AND is_del = ?", req.Code, 0).
Count(&count)
if count > 0 {
return 0, errors.New("小车编号已存在")
}
var warehouse models.Warehouse
if err := databaseConn.Where("id = ? AND is_del = ?", req.WarehouseID, 0).First(&warehouse).Error; err != nil {
return 0, errors.New("仓库不存在")
}
car := models.Car{
WarehouseID: req.WarehouseID,
PushType: req.PushType,
ReleaseType: req.ReleaseType,
Code: req.Code,
Name: req.Name,
Capacity: req.Capacity,
Appearance: req.Appearance,
CreatedAt: time.Now().Unix(),
UpdatedAt: time.Now().Unix(),
IsDel: 0,
}
if err := databaseConn.Create(&car).Error; err != nil {
return 0, errors.New("创建小车失败")
}
// 处理店铺绑定
if len(req.ShopInfo) > 0 {
if err := s.bindShopsToCar(car.ID, id, req.ShopInfo, databaseConn); err != nil {
return 0, err
}
}
return car.ID, nil
}
// UpdateCar 修改小车
func (s *CarService) UpdateCar(req systemReq.UpdateCarRequest, id int64, db ...*gorm.DB) error {
databaseConn := database.OptionalDB(db...)
var car models.Car
if err := databaseConn.Where("id = ? AND is_del = ?", req.ID, 0).First(&car).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return errors.New("小车不存在")
}
return errors.New("查询小车失败")
}
updates := make(map[string]interface{})
updates["updated_at"] = time.Now().Unix()
if req.Name != "" {
updates["name"] = req.Name
}
if req.Capacity != nil {
updates["capacity"] = *req.Capacity
}
if req.Appearance != nil {
updates["appearance"] = *req.Appearance
}
if req.PushType != nil {
updates["push_type"] = *req.PushType
}
if req.ReleaseType != nil {
updates["release_type"] = *req.ReleaseType
}
if err := databaseConn.Model(&car).Updates(updates).Error; err != nil {
return errors.New("更新小车失败")
}
// 处理店铺绑定
if len(req.ShopInfo) > 0 {
if err := s.bindShopsToCar(car.ID, id, req.ShopInfo, databaseConn); err != nil {
return err
}
}
return nil
}
// DeleteCar 删除小车
func (s *CarService) DeleteCar(id int64, db ...*gorm.DB) error {
databaseConn := database.OptionalDB(db...)
if id == 0 {
return errors.New("小车ID不能为空")
}
var car models.Car
if err := databaseConn.Where("id = ? AND is_del = ?", id, 0).First(&car).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return errors.New("小车不存在")
}
return errors.New("查询小车失败")
}
var taskCount int64
if err := databaseConn.Model(&models.WaveTask{}).Where("car_id = ? AND is_del = ? AND status NOT IN (?, ?)",
id, 0, constant.WaveStatusCompleted, constant.WaveStatusCancelled).Count(&taskCount).Error; err != nil {
return errors.New("查询任务状态失败")
}
if taskCount > 0 {
return errors.New("该小车存在未完成的任务,无法删除")
}
now := time.Now().Unix()
tx := databaseConn.Begin()
if tx.Error != nil {
return errors.New("开启事务失败")
}
if err := tx.Model(&car).Updates(map[string]interface{}{
"is_del": 1,
"updated_at": now,
}).Error; err != nil {
tx.Rollback()
return errors.New("删除小车失败")
}
if err := tx.Model(&models.CarShop{}).Where("car_id = ? AND is_del = ?", id, 0).Updates(map[string]interface{}{
"is_del": 1,
"updated_at": now,
}).Error; err != nil {
tx.Rollback()
return errors.New("删除小车店铺绑定关系失败")
}
if err := tx.Commit().Error; err != nil {
return errors.New("提交事务失败")
}
return nil
}
// bindShopsToCar 处理小车与店铺的绑定关系(新增/更新时调用)
func (s *CarService) bindShopsToCar(carID, id int64, info []map[string]interface{}, db *gorm.DB) error {
// 获取当前已存在的绑定关系
var existingBindings []models.CarShop
if err := db.Where("car_id = ? AND is_del = ?", carID, 0).Find(&existingBindings).Error; err != nil {
return errors.New("查询现有绑定关系失败")
}
// 构建已存在店铺ID的集合
existingShopIDs := make(map[int64]bool)
for _, binding := range existingBindings {
existingShopIDs[binding.ShopID] = true
}
// 构建传入的店铺ID集合
newShopIDs := make(map[int64]bool)
currentTime := time.Now().Unix()
for _, shopInfo := range info {
shopIDStr := getStringFromInfo(shopInfo, "id")
if shopIDStr == "" {
continue
}
var shopID int64
fmt.Sscanf(shopIDStr, "%d", &shopID)
if shopID == 0 {
continue
}
newShopIDs[shopID] = true
}
// 判断是否需要更新:如果两个集合完全相同,则不需要操作
if len(existingShopIDs) == len(newShopIDs) {
sameCount := 0
for shopID := range existingShopIDs {
if newShopIDs[shopID] {
sameCount++
}
}
if sameCount == len(existingShopIDs) {
return nil
}
}
// 找出需要删除的店铺(在旧列表中但不在新列表中)
var toDeleteShopIDs []int64
for shopID := range existingShopIDs {
if !newShopIDs[shopID] {
toDeleteShopIDs = append(toDeleteShopIDs, shopID)
}
}
// 删除不在新列表中的绑定关系
if len(toDeleteShopIDs) > 0 {
if err := db.Model(&models.CarShop{}).
Where("car_id = ? AND shop_id IN ? AND is_del = ?", carID, toDeleteShopIDs, 0).
Update("is_del", 1).Error; err != nil {
return errors.New("删除店铺绑定关系失败")
}
}
// 找出需要新增的店铺绑定(在新列表中但不在旧列表中)
var newBindings []models.CarShop
for _, shopInfo := range info {
shopIDStr := getStringFromInfo(shopInfo, "id")
if shopIDStr == "" {
continue
}
var shopID int64
fmt.Sscanf(shopIDStr, "%d", &shopID)
if shopID == 0 {
continue
}
// 如果已经存在,则跳过
if existingShopIDs[shopID] {
continue
}
// 获取店铺信息
var shop models.Shop
err := db.Where("id = ? AND del_flag = ?", shopID, 0).First(&shop).Error
if err != nil {
// 使用新创建的店铺数据创建绑定关系
shopTypeStr := getStringFromInfo(shopInfo, "shop_type")
var shopType int8 = 1
if shopTypeStr != "" {
fmt.Sscanf(shopTypeStr, "%d", &shopType)
}
shopStatusStr := getStringFromInfo(shopInfo, "status")
var shopStatus int8 = 1
if shopTypeStr != "" {
fmt.Sscanf(shopStatusStr, "%d", &shopStatus)
}
shopMallIdStr := getStringFromInfo(shopInfo, "mall_id")
var shopMallId int64 = 1
if shopMallIdStr != "" {
fmt.Sscanf(shopMallIdStr, "%d", &shopMallId)
}
// 店铺不存在,先同步创建店铺
newShop := models.Shop{
ID: shopID,
MallID: shopMallId,
ShopType: shopType,
ShopAliasName: getStringFromInfo(shopInfo, "shop_alias_name"),
Status: shopStatus,
DelFlag: 0,
CreateTime: currentTime,
UpdateTime: currentTime,
CreateBy: id,
UpdateBy: 0,
}
if err := db.Create(&newShop).Error; err != nil {
return errors.New("同步创建店铺失败")
}
newBinding := models.CarShop{
CarID: carID,
ShopID: shopID,
ShopName: getStringFromInfo(shopInfo, "shop_alias_name"),
ShopType: shopType,
CreatedAt: currentTime,
UpdatedAt: currentTime,
IsDel: 0,
}
newBindings = append(newBindings, newBinding)
} else {
// 使用店铺表中的数据创建绑定关系
newBinding := models.CarShop{
CarID: carID,
ShopID: shopID,
ShopName: shop.ShopAliasName,
ShopType: shop.ShopType,
CreatedAt: currentTime,
UpdatedAt: currentTime,
IsDel: 0,
}
newBindings = append(newBindings, newBinding)
}
}
// 批量创建新的绑定关系
if len(newBindings) > 0 {
if err := db.Create(&newBindings).Error; err != nil {
return errors.New("创建店铺绑定关系失败")
}
}
return nil
}
// GetCarCapacityByID 根据小车ID查询容量
func (s *CarService) GetCarCapacityByID(carID int64, db ...*gorm.DB) (int64, error) {
databaseConn := database.OptionalDB(db...)
if carID <= 0 {
return 0, errors.New("小车ID无效")
}
var car models.Car
if err := databaseConn.Where("id = ? AND is_del = ?", carID, 0).Select("capacity").First(&car).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return 0, errors.New("小车不存在或已删除")
}
return 0, errors.New("查询小车容量失败")
}
if car.Capacity <= 0 {
return 0, errors.New("小车容量配置不正确")
}
return car.Capacity, nil
}
// 辅助函数:从 info map 中安全获取 string 类型值
func getStringFromInfo(info map[string]interface{}, key string) string {
if info == nil {
return ""
}
if val, ok := info[key]; ok {
if str, ok := val.(string); ok {
return str
}
}
return ""
}
// 辅助函数:从 info map 中安全获取 int64 类型值
func getInt64FromInfo(info map[string]interface{}, key string) int64 {
if info == nil {
return 0
}
if val, ok := info[key]; ok {
switch v := val.(type) {
case float64:
return int64(v)
case int64:
return v
case int:
return int64(v)
}
}
return 0
}
// 辅助函数:从 info map 中安全获取 int8 类型值
func getInt8FromInfo(info map[string]interface{}, key string, defaultVal int8) int8 {
if info == nil {
return defaultVal
}
if val, ok := info[key]; ok {
switch v := val.(type) {
case float64:
return int8(v)
case int64:
return int8(v)
case int:
return int8(v)
case int8:
return v
}
}
return defaultVal
}
// getShopTypeText 获取店铺类型文本描述
func getShopTypeText(shopType int8) string {
switch shopType {
case 1:
return "拼多多"
case 2:
return "孔夫子"
case 5:
return "闲鱼"
default:
return "未知"
}
}