package service import ( "context" "errors" "fmt" "time" "gitea.com/red-future/common/consul" "gitea.com/red-future/common/http" "github.com/gogf/gf/v2/util/gconv" marketConsts "shop-user-trade/consts/market" marketDao "shop-user-trade/dao/market" marketDto "shop-user-trade/model/dto/market" marketEntity "shop-user-trade/model/entity/market" ) type market struct{} // Market 市场服务 var Market = new(market) // Create 创建市场物品 func (s *market) Create(ctx context.Context, req *marketDto.CreateMarketReq) (int64, error) { // 检查该背包项是否已经在市场中 existing, _ := marketDao.Market.GetByKnapsackID(ctx, req.KnapsackID) if existing != nil && existing.Id > 0 { return 0, errors.New("该物品已在市场中") } // 设置上架过期时间(默认7天) if req.ListExpireAt == nil { defaultExpire := time.Now().Add(7 * 24 * time.Hour).Unix() req.ListExpireAt = &defaultExpire } id, err := marketDao.Market.Insert(ctx, req) if err != nil { return 0, fmt.Errorf("创建市场物品失败: %w", err) } return id, nil } // GetOne 获取单个市场物品 func (s *market) GetOne(ctx context.Context, req *marketDto.GetMarketReq) (*marketDto.GetMarketRes, error) { item, err := marketDao.Market.GetOne(ctx, req) if err != nil { return nil, err } if item == nil { return nil, errors.New("市场物品不存在") } return &marketDto.GetMarketRes{ MarketItem: s.entityToItem(item), }, nil } // List 获取市场列表(支持分页和搜索) func (s *market) List(ctx context.Context, req *marketDto.ListMarketReq) (*marketDto.ListMarketRes, error) { list, total, err := marketDao.Market.List(ctx, req) if err != nil { return nil, err } res := &marketDto.ListMarketRes{Total: total} for _, item := range list { itemCopy := item res.List = append(res.List, s.entityToItem(&itemCopy)) } return res, nil } // Unlist 下架市场物品 func (s *market) Unlist(ctx context.Context, req *marketDto.UnlistMarketReq) error { item, err := marketDao.Market.GetByID(ctx, req.ID) if err != nil { return err } if item == nil { return errors.New("市场物品不存在") } if item.Status != marketConsts.MarketStatusActive { return errors.New("只有活跃状态的物品才能下架") } inactiveStatus := marketConsts.MarketStatusInactive updateReq := &marketDto.UpdateMarketReq{ Id: item.Id, Status: &inactiveStatus, Updater: req.OperatorName, } if _, err = marketDao.Market.Update(ctx, updateReq); err != nil { return fmt.Errorf("更新市场物品失败: %w", err) } return nil } // UpdatePrice 更新价格 func (s *market) UpdatePrice(ctx context.Context, req *marketDto.UpdatePriceReq) error { item, err := marketDao.Market.GetByID(ctx, req.ID) if err != nil { return err } if item == nil { return errors.New("市场物品不存在") } if item.Status != marketConsts.MarketStatusActive { return errors.New("只有活跃状态的物品才能更新价格") } updateReq := &marketDto.UpdateMarketReq{ Id: item.Id, Price: &req.Price, Updater: req.OperatorName, } if _, err = marketDao.Market.Update(ctx, updateReq); err != nil { return fmt.Errorf("更新价格失败: %w", err) } return nil } // Buy 购买市场物品 - 调用order模块创建订单 func (s *market) Buy(ctx context.Context, req *marketDto.BuyMarketReq) (string, error) { item, err := marketDao.Market.GetByID(ctx, req.MarketID) if err != nil { return "", err } if item == nil { return "", errors.New("市场物品不存在") } if err = s.canBeBought(item); err != nil { return "", err } // 检查买家不能是卖家 if item.UserID == req.BuyerID { return "", errors.New("不能购买自己上架的物品") } // 调用order模块创建订单 orderAddr, err := consul.GetInstanceAddr(ctx, "order") if err != nil { return "", fmt.Errorf("获取order服务地址失败: %w", err) } orderReq := map[string]interface{}{ "user_id": req.BuyerID, "order_type": "market", "subject": item.AssetName, "description": item.Description, "order_items": []map[string]interface{}{ { "asset_id": item.AssetID, "asset_name": item.AssetName, "asset_type": item.Type, "image_url": item.ImageURL, "stocks": []map[string]interface{}{ { "stock_id": item.StockDetailID, "batch_id": item.BatchID, "batch_no": item.BatchNo, "quantity": 1, "price": item.Price, "stock_mode": item.StockMode, "stock_attrs": map[string]interface{}{ "market_id": item.Id, "seller_id": item.UserID, }, }, }, }, }, "shipping_info": map[string]interface{}{}, } orderRes := &struct { Code int `json:"code"` Message string `json:"message"` Data struct { OrderNo string `json:"order_no"` TotalAmount int64 `json:"total_amount"` PayAmount int64 `json:"pay_amount"` ExpiredAt string `json:"expired_at"` } `json:"data"` }{} err = http.Post(ctx, fmt.Sprintf("http://%s/order/create", orderAddr), nil, orderRes, orderReq) // #nosec G107 if err != nil { return "", fmt.Errorf("创建订单失败: %w", err) } // 更新市场物品状态为已售出 soldStatus := marketConsts.MarketStatusSold updateReq := &marketDto.UpdateMarketReq{ Id: item.Id, Status: &soldStatus, } if _, err = marketDao.Market.Update(ctx, updateReq); err != nil { return "", fmt.Errorf("更新市场物品失败: %w", err) } return orderRes.Data.OrderNo, nil } // ExpireExpiredItems 将过期的市场物品标记为过期状态(定时任务调用) func (s *market) ExpireExpiredItems(ctx context.Context) (int64, error) { expiredList, err := marketDao.Market.ListExpired(ctx) if err != nil { return 0, fmt.Errorf("查询过期物品失败: %w", err) } if len(expiredList) == 0 { return 0, nil } count := int64(len(expiredList)) expiredStatus := marketConsts.MarketStatusExpired for _, item := range expiredList { updateReq := &marketDto.UpdateMarketReq{ Id: item.Id, Status: &expiredStatus, } if _, err = marketDao.Market.Update(ctx, updateReq); err != nil { return count, fmt.Errorf("更新过期物品状态失败: %w", err) } } return count, nil } // canBeBought 检查市场物品是否可以购买 func (s *market) canBeBought(item *marketEntity.Market) error { if item.Status != marketConsts.MarketStatusActive { return errors.New("物品状态不可购买") } if item.ListExpireAt != nil && *item.ListExpireAt < time.Now().Unix() { return errors.New("物品已过期") } return nil } // entityToItem 实体转换为Item func (s *market) entityToItem(e *marketEntity.Market) *marketDto.MarketItem { item := &marketDto.MarketItem{} if err := gconv.Struct(e, item); err != nil { return item } item.ID = e.Id item.Status = e.Status if e.CreatedAt != nil { item.CreatedAt = e.CreatedAt.String() } if e.UpdatedAt != nil { item.UpdatedAt = e.UpdatedAt.String() } return item }