diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/erp/ProductController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/erp/ProductController.java index c6ab66e..7ed9116 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/erp/ProductController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/erp/ProductController.java @@ -16,6 +16,7 @@ import com.ruoyi.erp.request.ProductCategoryListQueryRequest; import com.ruoyi.erp.request.ProductPropertyListQueryRequest; import com.ruoyi.erp.request.AuthorizeListQueryRequest; import com.ruoyi.erp.request.ProductPublishRequest; +import com.ruoyi.erp.request.ProductDownShelfRequest; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -550,6 +551,217 @@ public class ProductController extends BaseController { public String getAppid() { return appid; } public void setAppid(String appid) { this.appid = appid; } } + + /** + * 下架商品(单个) + */ + @PostMapping("/downShelf") + public R downShelf(@RequestBody @Validated DownShelfRequest req) { + try { + ERPAccount account = resolveAccount(req.getAppid()); + ProductDownShelfRequest downShelfRequest = new ProductDownShelfRequest(account); + downShelfRequest.setProductId(req.getProductId()); + String resp = downShelfRequest.getResponseBody(); + JSONObject jo = JSONObject.parseObject(resp); + return R.ok(jo); + } catch (Exception e) { + log.error("下架商品失败: productId={}", req.getProductId(), e); + return R.fail("下架失败: " + e.getMessage()); + } + } + + /** + * 批量上架商品 + */ + @PostMapping("/batchPublish") + public R batchPublish(@RequestBody @Validated BatchPublishRequest req) { + try { + ERPAccount account = resolveAccount(req.getAppid()); + List productIds = req.getProductIds(); + + if (productIds == null || productIds.isEmpty()) { + return R.fail("商品ID列表不能为空"); + } + + if (req.getUserName() == null || req.getUserName().isEmpty()) { + return R.fail("闲鱼会员名不能为空"); + } + + List> results = new ArrayList<>(); + int successCount = 0; + int failCount = 0; + + for (Long productId : productIds) { + HashMap result = new HashMap<>(); + result.put("productId", productId); + + try { + ProductPublishRequest publishRequest = new ProductPublishRequest(account); + publishRequest.setProductId(productId); + publishRequest.setUserName(req.getUserName()); + if (req.getSpecifyPublishTime() != null) { + publishRequest.setSpecifyPublishTime(req.getSpecifyPublishTime()); + } + String resp = publishRequest.getResponseBody(); + JSONObject jo = JSONObject.parseObject(resp); + + if (jo != null && jo.getInteger("code") != null && jo.getInteger("code") == 0) { + result.put("success", true); + result.put("msg", "上架成功"); + result.put("response", jo); + successCount++; + } else { + result.put("success", false); + result.put("msg", jo != null ? jo.getString("msg") : "上架失败"); + result.put("response", jo); + failCount++; + } + } catch (Exception e) { + log.error("批量上架商品失败: productId={}", productId, e); + result.put("success", false); + result.put("msg", "上架异常: " + e.getMessage()); + result.put("response", null); + failCount++; + } + + results.add(result); + } + + HashMap summary = new HashMap<>(); + summary.put("total", productIds.size()); + summary.put("success", successCount); + summary.put("fail", failCount); + summary.put("results", results); + + JSONObject response = new JSONObject(); + response.put("code", failCount == 0 ? 0 : 500); + response.put("msg", failCount == 0 ? "全部上架成功" : String.format("成功: %d, 失败: %d", successCount, failCount)); + response.put("data", summary); + + return R.ok(response); + } catch (Exception e) { + log.error("批量上架商品异常", e); + return R.fail("批量上架失败: " + e.getMessage()); + } + } + + /** + * 批量下架商品 + */ + @PostMapping("/batchDownShelf") + public R batchDownShelf(@RequestBody @Validated BatchDownShelfRequest req) { + try { + ERPAccount account = resolveAccount(req.getAppid()); + List productIds = req.getProductIds(); + + if (productIds == null || productIds.isEmpty()) { + return R.fail("商品ID列表不能为空"); + } + + List> results = new ArrayList<>(); + int successCount = 0; + int failCount = 0; + + for (Long productId : productIds) { + HashMap result = new HashMap<>(); + result.put("productId", productId); + + try { + ProductDownShelfRequest downShelfRequest = new ProductDownShelfRequest(account); + downShelfRequest.setProductId(productId); + String resp = downShelfRequest.getResponseBody(); + JSONObject jo = JSONObject.parseObject(resp); + + if (jo != null && jo.getInteger("code") != null && jo.getInteger("code") == 0) { + result.put("success", true); + result.put("msg", "下架成功"); + result.put("response", jo); + successCount++; + } else { + result.put("success", false); + result.put("msg", jo != null ? jo.getString("msg") : "下架失败"); + result.put("response", jo); + failCount++; + } + } catch (Exception e) { + log.error("批量下架商品失败: productId={}", productId, e); + result.put("success", false); + result.put("msg", "下架异常: " + e.getMessage()); + result.put("response", null); + failCount++; + } + + results.add(result); + } + + HashMap summary = new HashMap<>(); + summary.put("total", productIds.size()); + summary.put("success", successCount); + summary.put("fail", failCount); + summary.put("results", results); + + JSONObject response = new JSONObject(); + response.put("code", failCount == 0 ? 0 : 500); + response.put("msg", failCount == 0 ? "全部下架成功" : String.format("成功: %d, 失败: %d", successCount, failCount)); + response.put("data", summary); + + return R.ok(response); + } catch (Exception e) { + log.error("批量下架商品异常", e); + return R.fail("批量下架失败: " + e.getMessage()); + } + } + + /** + * 下架请求体 + */ + public static class DownShelfRequest { + @NotNull + private Long productId; + private String appid; + + public Long getProductId() { return productId; } + public void setProductId(Long productId) { this.productId = productId; } + public String getAppid() { return appid; } + public void setAppid(String appid) { this.appid = appid; } + } + + /** + * 批量上架请求体 + */ + public static class BatchPublishRequest { + @NotNull + @Size(min = 1, message = "商品ID列表不能为空") + private List productIds; + @NotBlank(message = "闲鱼会员名不能为空") + private String userName; + private String specifyPublishTime; + private String appid; + + public List getProductIds() { return productIds; } + public void setProductIds(List productIds) { this.productIds = productIds; } + public String getUserName() { return userName; } + public void setUserName(String userName) { this.userName = userName; } + public String getSpecifyPublishTime() { return specifyPublishTime; } + public void setSpecifyPublishTime(String specifyPublishTime) { this.specifyPublishTime = specifyPublishTime; } + public String getAppid() { return appid; } + public void setAppid(String appid) { this.appid = appid; } + } + + /** + * 批量下架请求体 + */ + public static class BatchDownShelfRequest { + @NotNull + @Size(min = 1, message = "商品ID列表不能为空") + private List productIds; + private String appid; + + public List getProductIds() { return productIds; } + public void setProductIds(List productIds) { this.productIds = productIds; } + public String getAppid() { return appid; } + public void setAppid(String appid) { this.appid = appid; } + } } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/ErpProductController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/ErpProductController.java new file mode 100644 index 0000000..c86ec2d --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/ErpProductController.java @@ -0,0 +1,179 @@ +package com.ruoyi.web.controller.jarvis; + +import java.util.List; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.jarvis.domain.ErpProduct; +import com.ruoyi.jarvis.service.IErpProductService; +import com.ruoyi.common.utils.poi.ExcelUtil; +import com.ruoyi.common.core.page.TableDataInfo; + +/** + * 闲鱼商品Controller + * + * @author ruoyi + * @date 2024-01-01 + */ +@RestController +@RequestMapping("/jarvis/erpProduct") +public class ErpProductController extends BaseController +{ + @Autowired + private IErpProductService erpProductService; + + /** + * 查询闲鱼商品列表 + */ + @PreAuthorize("@ss.hasPermi('jarvis:erpProduct:list')") + @GetMapping("/list") + public TableDataInfo list(ErpProduct erpProduct) + { + startPage(); + List list = erpProductService.selectErpProductList(erpProduct); + return getDataTable(list); + } + + /** + * 导出闲鱼商品列表 + */ + @PreAuthorize("@ss.hasPermi('jarvis:erpProduct:export')") + @Log(title = "闲鱼商品", businessType = BusinessType.EXPORT) + @GetMapping("/export") + public AjaxResult export(ErpProduct erpProduct) + { + List list = erpProductService.selectErpProductList(erpProduct); + ExcelUtil util = new ExcelUtil(ErpProduct.class); + return util.exportExcel(list, "闲鱼商品数据"); + } + + /** + * 获取闲鱼商品详细信息 + */ + @PreAuthorize("@ss.hasPermi('jarvis:erpProduct:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) + { + return success(erpProductService.selectErpProductById(id)); + } + + /** + * 新增闲鱼商品 + */ + @PreAuthorize("@ss.hasPermi('jarvis:erpProduct:add')") + @Log(title = "闲鱼商品", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody ErpProduct erpProduct) + { + return toAjax(erpProductService.insertErpProduct(erpProduct)); + } + + /** + * 修改闲鱼商品 + */ + @PreAuthorize("@ss.hasPermi('jarvis:erpProduct:edit')") + @Log(title = "闲鱼商品", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody ErpProduct erpProduct) + { + return toAjax(erpProductService.updateErpProduct(erpProduct)); + } + + /** + * 删除闲鱼商品 + */ + @PreAuthorize("@ss.hasPermi('jarvis:erpProduct:remove')") + @Log(title = "闲鱼商品", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) + { + return toAjax(erpProductService.deleteErpProductByIds(ids)); + } + + /** + * 从闲鱼ERP拉取商品列表并保存 + */ + @PreAuthorize("@ss.hasPermi('jarvis:erpProduct:pull')") + @Log(title = "拉取闲鱼商品", businessType = BusinessType.INSERT) + @PostMapping("/pull") + public AjaxResult pullProductList( + @RequestParam(required = false) String appid, + @RequestParam(defaultValue = "1") Integer pageNo, + @RequestParam(defaultValue = "50") Integer pageSize, + @RequestParam(required = false) Integer productStatus) + { + try { + int count = erpProductService.pullAndSaveProductList(appid, pageNo, pageSize, productStatus); + return success("成功拉取并保存 " + count + " 个商品"); + } catch (Exception e) { + return error("拉取商品列表失败: " + e.getMessage()); + } + } + + /** + * 批量上架商品 + */ + @PreAuthorize("@ss.hasPermi('jarvis:erpProduct:publish')") + @Log(title = "批量上架商品", businessType = BusinessType.UPDATE) + @PostMapping("/batchPublish") + public AjaxResult batchPublish(@RequestBody BatchOperationRequest request) + { + try { + return success("批量上架功能请调用 /erp/product/batchPublish 接口"); + } catch (Exception e) { + return error("批量上架失败: " + e.getMessage()); + } + } + + /** + * 批量下架商品 + */ + @PreAuthorize("@ss.hasPermi('jarvis:erpProduct:downShelf')") + @Log(title = "批量下架商品", businessType = BusinessType.UPDATE) + @PostMapping("/batchDownShelf") + public AjaxResult batchDownShelf(@RequestBody BatchOperationRequest request) + { + try { + return success("批量下架功能请调用 /erp/product/batchDownShelf 接口"); + } catch (Exception e) { + return error("批量下架失败: " + e.getMessage()); + } + } + + /** + * 批量操作请求体 + */ + public static class BatchOperationRequest { + private java.util.List productIds; + private String appid; + + public java.util.List getProductIds() { + return productIds; + } + + public void setProductIds(java.util.List productIds) { + this.productIds = productIds; + } + + public String getAppid() { + return appid; + } + + public void setAppid(String appid) { + this.appid = appid; + } + } +} + diff --git a/ruoyi-system/src/main/java/com/ruoyi/jarvis/domain/ErpProduct.java b/ruoyi-system/src/main/java/com/ruoyi/jarvis/domain/ErpProduct.java new file mode 100644 index 0000000..4f4068c --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/jarvis/domain/ErpProduct.java @@ -0,0 +1,282 @@ +package com.ruoyi.jarvis.domain; + +import com.ruoyi.common.annotation.Excel; +import com.ruoyi.common.core.domain.BaseEntity; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +/** + * 闲鱼商品对象 erp_product + * + * @author ruoyi + * @date 2024-01-01 + */ +public class ErpProduct extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 主键ID */ + private Long id; + + /** 管家商品ID */ + @Excel(name = "管家商品ID") + private Long productId; + + /** 商品标题 */ + @Excel(name = "商品标题") + private String title; + + /** 商品图片(主图) */ + @Excel(name = "商品图片") + private String mainImage; + + /** 商品价格(分) */ + @Excel(name = "商品价格") + private Long price; + + /** 商品库存 */ + @Excel(name = "商品库存") + private Integer stock; + + /** 商品状态 1:上架 2:下架 3:已售 */ + @Excel(name = "商品状态", readConverterExp = "1=上架,2=下架,3=已售") + private Integer productStatus; + + /** 销售状态 */ + @Excel(name = "销售状态") + private Integer saleStatus; + + /** 闲鱼会员名 */ + @Excel(name = "闲鱼会员名") + private String userName; + + /** 上架时间 */ + @Excel(name = "上架时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Long onlineTime; + + /** 下架时间 */ + @Excel(name = "下架时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Long offlineTime; + + /** 售出时间 */ + @Excel(name = "售出时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Long soldTime; + + /** 创建时间(闲鱼) */ + @Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Long createTimeXy; + + /** 更新时间(闲鱼) */ + @Excel(name = "更新时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Long updateTimeXy; + + /** ERP应用ID */ + @Excel(name = "ERP应用ID") + private String appid; + + /** 商品链接 */ + @Excel(name = "商品链接") + private String productUrl; + + /** 备注 */ + @Excel(name = "备注") + private String remark; + + public void setId(Long id) + { + this.id = id; + } + + public Long getId() + { + return id; + } + + public void setProductId(Long productId) + { + this.productId = productId; + } + + public Long getProductId() + { + return productId; + } + + public void setTitle(String title) + { + this.title = title; + } + + public String getTitle() + { + return title; + } + + public void setMainImage(String mainImage) + { + this.mainImage = mainImage; + } + + public String getMainImage() + { + return mainImage; + } + + public void setPrice(Long price) + { + this.price = price; + } + + public Long getPrice() + { + return price; + } + + public void setStock(Integer stock) + { + this.stock = stock; + } + + public Integer getStock() + { + return stock; + } + + public void setProductStatus(Integer productStatus) + { + this.productStatus = productStatus; + } + + public Integer getProductStatus() + { + return productStatus; + } + + public void setSaleStatus(Integer saleStatus) + { + this.saleStatus = saleStatus; + } + + public Integer getSaleStatus() + { + return saleStatus; + } + + public void setUserName(String userName) + { + this.userName = userName; + } + + public String getUserName() + { + return userName; + } + + public void setOnlineTime(Long onlineTime) + { + this.onlineTime = onlineTime; + } + + public Long getOnlineTime() + { + return onlineTime; + } + + public void setOfflineTime(Long offlineTime) + { + this.offlineTime = offlineTime; + } + + public Long getOfflineTime() + { + return offlineTime; + } + + public void setSoldTime(Long soldTime) + { + this.soldTime = soldTime; + } + + public Long getSoldTime() + { + return soldTime; + } + + public void setCreateTimeXy(Long createTimeXy) + { + this.createTimeXy = createTimeXy; + } + + public Long getCreateTimeXy() + { + return createTimeXy; + } + + public void setUpdateTimeXy(Long updateTimeXy) + { + this.updateTimeXy = updateTimeXy; + } + + public Long getUpdateTimeXy() + { + return updateTimeXy; + } + + public void setAppid(String appid) + { + this.appid = appid; + } + + public String getAppid() + { + return appid; + } + + public void setProductUrl(String productUrl) + { + this.productUrl = productUrl; + } + + public String getProductUrl() + { + return productUrl; + } + + @Override + public void setRemark(String remark) + { + this.remark = remark; + } + + @Override + public String getRemark() + { + return remark; + } + + @Override + public String toString() { + return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) + .append("id", getId()) + .append("productId", getProductId()) + .append("title", getTitle()) + .append("mainImage", getMainImage()) + .append("price", getPrice()) + .append("stock", getStock()) + .append("productStatus", getProductStatus()) + .append("saleStatus", getSaleStatus()) + .append("userName", getUserName()) + .append("onlineTime", getOnlineTime()) + .append("offlineTime", getOfflineTime()) + .append("soldTime", getSoldTime()) + .append("createTimeXy", getCreateTimeXy()) + .append("updateTimeXy", getUpdateTimeXy()) + .append("appid", getAppid()) + .append("productUrl", getProductUrl()) + .append("remark", getRemark()) + .append("createTime", getCreateTime()) + .append("updateTime", getUpdateTime()) + .toString(); + } +} + diff --git a/ruoyi-system/src/main/java/com/ruoyi/jarvis/mapper/ErpProductMapper.java b/ruoyi-system/src/main/java/com/ruoyi/jarvis/mapper/ErpProductMapper.java new file mode 100644 index 0000000..40ce1bd --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/jarvis/mapper/ErpProductMapper.java @@ -0,0 +1,79 @@ +package com.ruoyi.jarvis.mapper; + +import java.util.List; +import com.ruoyi.jarvis.domain.ErpProduct; + +/** + * 闲鱼商品Mapper接口 + * + * @author ruoyi + * @date 2024-01-01 + */ +public interface ErpProductMapper +{ + /** + * 查询闲鱼商品 + * + * @param id 闲鱼商品主键 + * @return 闲鱼商品 + */ + public ErpProduct selectErpProductById(Long id); + + /** + * 查询闲鱼商品列表 + * + * @param erpProduct 闲鱼商品 + * @return 闲鱼商品集合 + */ + public List selectErpProductList(ErpProduct erpProduct); + + /** + * 新增闲鱼商品 + * + * @param erpProduct 闲鱼商品 + * @return 结果 + */ + public int insertErpProduct(ErpProduct erpProduct); + + /** + * 修改闲鱼商品 + * + * @param erpProduct 闲鱼商品 + * @return 结果 + */ + public int updateErpProduct(ErpProduct erpProduct); + + /** + * 删除闲鱼商品 + * + * @param id 闲鱼商品主键 + * @return 结果 + */ + public int deleteErpProductById(Long id); + + /** + * 批量删除闲鱼商品 + * + * @param ids 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteErpProductByIds(Long[] ids); + + /** + * 根据商品ID和appid查询 + * + * @param productId 商品ID + * @param appid ERP应用ID + * @return 闲鱼商品 + */ + public ErpProduct selectErpProductByProductIdAndAppid(Long productId, String appid); + + /** + * 批量插入或更新闲鱼商品 + * + * @param erpProducts 闲鱼商品列表 + * @return 结果 + */ + public int batchInsertOrUpdateErpProduct(List erpProducts); +} + diff --git a/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/IErpProductService.java b/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/IErpProductService.java new file mode 100644 index 0000000..383e645 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/IErpProductService.java @@ -0,0 +1,73 @@ +package com.ruoyi.jarvis.service; + +import java.util.List; +import com.ruoyi.jarvis.domain.ErpProduct; + +/** + * 闲鱼商品Service接口 + * + * @author ruoyi + * @date 2024-01-01 + */ +public interface IErpProductService +{ + /** + * 查询闲鱼商品 + * + * @param id 闲鱼商品主键 + * @return 闲鱼商品 + */ + public ErpProduct selectErpProductById(Long id); + + /** + * 查询闲鱼商品列表 + * + * @param erpProduct 闲鱼商品 + * @return 闲鱼商品集合 + */ + public List selectErpProductList(ErpProduct erpProduct); + + /** + * 新增闲鱼商品 + * + * @param erpProduct 闲鱼商品 + * @return 结果 + */ + public int insertErpProduct(ErpProduct erpProduct); + + /** + * 修改闲鱼商品 + * + * @param erpProduct 闲鱼商品 + * @return 结果 + */ + public int updateErpProduct(ErpProduct erpProduct); + + /** + * 批量删除闲鱼商品 + * + * @param ids 需要删除的闲鱼商品主键集合 + * @return 结果 + */ + public int deleteErpProductByIds(Long[] ids); + + /** + * 删除闲鱼商品信息 + * + * @param id 闲鱼商品主键 + * @return 结果 + */ + public int deleteErpProductById(Long id); + + /** + * 从闲鱼ERP拉取商品列表并保存 + * + * @param appid ERP应用ID + * @param pageNo 页码 + * @param pageSize 每页大小 + * @param productStatus 商品状态 + * @return 拉取结果 + */ + public int pullAndSaveProductList(String appid, Integer pageNo, Integer pageSize, Integer productStatus); +} + diff --git a/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/ErpProductServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/ErpProductServiceImpl.java new file mode 100644 index 0000000..487dcfc --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/ErpProductServiceImpl.java @@ -0,0 +1,281 @@ +package com.ruoyi.jarvis.service.impl; + +import java.util.ArrayList; +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.ruoyi.jarvis.mapper.ErpProductMapper; +import com.ruoyi.jarvis.domain.ErpProduct; +import com.ruoyi.jarvis.service.IErpProductService; +import com.ruoyi.erp.request.ERPAccount; +import com.ruoyi.erp.request.ProductListQueryRequest; +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * 闲鱼商品Service业务层处理 + * + * @author ruoyi + * @date 2024-01-01 + */ +@Service +public class ErpProductServiceImpl implements IErpProductService +{ + private static final Logger log = LoggerFactory.getLogger(ErpProductServiceImpl.class); + + @Autowired + private ErpProductMapper erpProductMapper; + + /** + * 查询闲鱼商品 + * + * @param id 闲鱼商品主键 + * @return 闲鱼商品 + */ + @Override + public ErpProduct selectErpProductById(Long id) + { + return erpProductMapper.selectErpProductById(id); + } + + /** + * 查询闲鱼商品列表 + * + * @param erpProduct 闲鱼商品 + * @return 闲鱼商品 + */ + @Override + public List selectErpProductList(ErpProduct erpProduct) + { + return erpProductMapper.selectErpProductList(erpProduct); + } + + /** + * 新增闲鱼商品 + * + * @param erpProduct 闲鱼商品 + * @return 结果 + */ + @Override + public int insertErpProduct(ErpProduct erpProduct) + { + // 检查是否已存在 + ErpProduct existing = erpProductMapper.selectErpProductByProductIdAndAppid( + erpProduct.getProductId(), erpProduct.getAppid()); + if (existing != null) { + // 更新已存在的商品 + erpProduct.setId(existing.getId()); + return erpProductMapper.updateErpProduct(erpProduct); + } + return erpProductMapper.insertErpProduct(erpProduct); + } + + /** + * 修改闲鱼商品 + * + * @param erpProduct 闲鱼商品 + * @return 结果 + */ + @Override + public int updateErpProduct(ErpProduct erpProduct) + { + return erpProductMapper.updateErpProduct(erpProduct); + } + + /** + * 批量删除闲鱼商品 + * + * @param ids 需要删除的闲鱼商品主键 + * @return 结果 + */ + @Override + public int deleteErpProductByIds(Long[] ids) + { + return erpProductMapper.deleteErpProductByIds(ids); + } + + /** + * 删除闲鱼商品信息 + * + * @param id 闲鱼商品主键 + * @return 结果 + */ + @Override + public int deleteErpProductById(Long id) + { + return erpProductMapper.deleteErpProductById(id); + } + + /** + * 从闲鱼ERP拉取商品列表并保存 + * + * @param appid ERP应用ID + * @param pageNo 页码 + * @param pageSize 每页大小 + * @param productStatus 商品状态 + * @return 拉取并保存的商品数量 + */ + @Override + public int pullAndSaveProductList(String appid, Integer pageNo, Integer pageSize, Integer productStatus) + { + try { + // 解析ERP账号 + ERPAccount account = resolveAccount(appid); + + // 创建查询请求 + ProductListQueryRequest request = new ProductListQueryRequest(account); + if (pageNo != null) { + request.setPageNo(pageNo); + } + if (pageSize != null) { + request.setPageSize(pageSize); + } + if (productStatus != null) { + request.setProductStatus(productStatus); + } + + // 调用接口获取商品列表 + String responseBody = request.getResponseBody(); + JSONObject response = JSONObject.parseObject(responseBody); + + if (response == null || response.getInteger("code") == null || response.getInteger("code") != 0) { + log.error("拉取商品列表失败: {}", responseBody); + return 0; + } + + // 解析商品列表 + JSONObject data = response.getJSONObject("data"); + if (data == null) { + log.warn("拉取商品列表返回数据为空"); + return 0; + } + + JSONArray productList = data.getJSONArray("list"); + if (productList == null || productList.isEmpty()) { + log.info("拉取商品列表为空"); + return 0; + } + + // 转换为实体对象并保存 + List erpProducts = new ArrayList<>(); + for (int i = 0; i < productList.size(); i++) { + JSONObject productJson = productList.getJSONObject(i); + ErpProduct erpProduct = parseProductJson(productJson, appid); + if (erpProduct != null) { + erpProducts.add(erpProduct); + } + } + + // 批量保存或更新 + if (!erpProducts.isEmpty()) { + // 逐个保存(兼容更新) + int savedCount = 0; + for (ErpProduct product : erpProducts) { + ErpProduct existing = erpProductMapper.selectErpProductByProductIdAndAppid( + product.getProductId(), product.getAppid()); + if (existing != null) { + product.setId(existing.getId()); + erpProductMapper.updateErpProduct(product); + } else { + erpProductMapper.insertErpProduct(product); + } + savedCount++; + } + log.info("成功拉取并保存 {} 个商品", savedCount); + return savedCount; + } + + return 0; + } catch (Exception e) { + log.error("拉取商品列表异常", e); + throw new RuntimeException("拉取商品列表失败: " + e.getMessage(), e); + } + } + + /** + * 解析商品JSON数据 + */ + private ErpProduct parseProductJson(JSONObject productJson, String appid) { + try { + ErpProduct product = new ErpProduct(); + + // 管家商品ID + Long productId = productJson.getLong("product_id"); + if (productId == null) { + log.warn("商品ID为空,跳过: {}", productJson); + return null; + } + product.setProductId(productId); + + // 商品标题 + product.setTitle(productJson.getString("title")); + + // 商品图片(取第一张) + JSONArray images = productJson.getJSONArray("images"); + if (images != null && !images.isEmpty()) { + product.setMainImage(images.getString(0)); + } + + // 价格(分) + Long price = productJson.getLong("price"); + if (price == null) { + // 尝试从price字段解析 + Object priceObj = productJson.get("price"); + if (priceObj instanceof Number) { + price = ((Number) priceObj).longValue(); + } + } + product.setPrice(price); + + // 库存 + Integer stock = productJson.getInteger("stock"); + product.setStock(stock); + + // 商品状态 + Integer productStatus = productJson.getInteger("product_status"); + product.setProductStatus(productStatus); + + // 销售状态 + Integer saleStatus = productJson.getInteger("sale_status"); + product.setSaleStatus(saleStatus); + + // 闲鱼会员名 + product.setUserName(productJson.getString("user_name")); + + // 时间字段(时间戳,秒) + product.setOnlineTime(productJson.getLong("online_time")); + product.setOfflineTime(productJson.getLong("offline_time")); + product.setSoldTime(productJson.getLong("sold_time")); + product.setCreateTimeXy(productJson.getLong("create_time")); + product.setUpdateTimeXy(productJson.getLong("update_time")); + + // ERP应用ID + product.setAppid(appid); + + // 商品链接 + product.setProductUrl(productJson.getString("product_url")); + + return product; + } catch (Exception e) { + log.error("解析商品JSON失败: {}", productJson, e); + return null; + } + } + + /** + * 解析ERP账号 + */ + private ERPAccount resolveAccount(String appid) { + if (appid != null && !appid.isEmpty()) { + for (ERPAccount account : ERPAccount.values()) { + if (account.getApiKey().equals(appid)) { + return account; + } + } + } + return ERPAccount.ACCOUNT_HUGE; // 默认账号 + } +} + diff --git a/ruoyi-system/src/main/resources/mapper/jarvis/ErpProductMapper.xml b/ruoyi-system/src/main/resources/mapper/jarvis/ErpProductMapper.xml new file mode 100644 index 0000000..5438f45 --- /dev/null +++ b/ruoyi-system/src/main/resources/mapper/jarvis/ErpProductMapper.xml @@ -0,0 +1,169 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + select id, product_id, title, main_image, price, stock, product_status, sale_status, + user_name, online_time, offline_time, sold_time, create_time_xy, update_time_xy, + appid, product_url, remark, create_time, update_time + from erp_product + + + + + + + + + + insert into erp_product + + product_id, + title, + main_image, + price, + stock, + product_status, + sale_status, + user_name, + online_time, + offline_time, + sold_time, + create_time_xy, + update_time_xy, + appid, + product_url, + remark, + create_time, + update_time, + + + #{productId}, + #{title}, + #{mainImage}, + #{price}, + #{stock}, + #{productStatus}, + #{saleStatus}, + #{userName}, + #{onlineTime}, + #{offlineTime}, + #{soldTime}, + #{createTimeXy}, + #{updateTimeXy}, + #{appid}, + #{productUrl}, + #{remark}, + #{createTime}, + #{updateTime}, + + + + + update erp_product + + product_id = #{productId}, + title = #{title}, + main_image = #{mainImage}, + price = #{price}, + stock = #{stock}, + product_status = #{productStatus}, + sale_status = #{saleStatus}, + user_name = #{userName}, + online_time = #{onlineTime}, + offline_time = #{offlineTime}, + sold_time = #{soldTime}, + create_time_xy = #{createTimeXy}, + update_time_xy = #{updateTimeXy}, + appid = #{appid}, + product_url = #{productUrl}, + remark = #{remark}, + update_time = #{updateTime}, + + where id = #{id} + + + + delete from erp_product where id = #{id} + + + + delete from erp_product where id in + + #{id} + + + + + insert into erp_product + (product_id, title, main_image, price, stock, product_status, sale_status, + user_name, online_time, offline_time, sold_time, create_time_xy, update_time_xy, + appid, product_url, remark) + values + + (#{item.productId}, #{item.title}, #{item.mainImage}, #{item.price}, #{item.stock}, + #{item.productStatus}, #{item.saleStatus}, #{item.userName}, #{item.onlineTime}, + #{item.offlineTime}, #{item.soldTime}, #{item.createTimeXy}, #{item.updateTimeXy}, + #{item.appid}, #{item.productUrl}, #{item.remark}) + + ON DUPLICATE KEY UPDATE + title = VALUES(title), + main_image = VALUES(main_image), + price = VALUES(price), + stock = VALUES(stock), + product_status = VALUES(product_status), + sale_status = VALUES(sale_status), + user_name = VALUES(user_name), + online_time = VALUES(online_time), + offline_time = VALUES(offline_time), + sold_time = VALUES(sold_time), + create_time_xy = VALUES(create_time_xy), + update_time_xy = VALUES(update_time_xy), + product_url = VALUES(product_url), + remark = VALUES(remark), + update_time = NOW() + + + + diff --git a/sql/闲鱼商品菜单.sql b/sql/闲鱼商品菜单.sql new file mode 100644 index 0000000..98e21d4 --- /dev/null +++ b/sql/闲鱼商品菜单.sql @@ -0,0 +1,37 @@ +-- 闲鱼商品菜单配置 +-- 菜单类型:M=目录 C=菜单 F=按钮 + +-- 1. 主菜单(如果是放在系统管理下,parent_id为1;如果是独立菜单,需要先创建一个jarvis目录) +-- 假设放在系统管理(parent_id=1)下,可以根据实际情况调整 + +-- 闲鱼商品管理菜单(主菜单) +insert into sys_menu values(2000, '闲鱼商品管理', 1, 10, 'erpProduct', 'system/erpProduct/index', '', '', 1, 0, 'C', '0', '0', 'jarvis:erpProduct:list', 'shopping', 'admin', sysdate(), '', null, '闲鱼商品管理菜单'); + +-- 闲鱼商品管理按钮权限 +insert into sys_menu values(2001, '商品查询', 2000, 1, '', '', '', '', 1, 0, 'F', '0', '0', 'jarvis:erpProduct:query', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values(2002, '商品新增', 2000, 2, '', '', '', '', 1, 0, 'F', '0', '0', 'jarvis:erpProduct:add', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values(2003, '商品修改', 2000, 3, '', '', '', '', 1, 0, 'F', '0', '0', 'jarvis:erpProduct:edit', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values(2004, '商品删除', 2000, 4, '', '', '', '', 1, 0, 'F', '0', '0', 'jarvis:erpProduct:remove', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values(2005, '商品导出', 2000, 5, '', '', '', '', 1, 0, 'F', '0', '0', 'jarvis:erpProduct:export', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values(2006, '拉取商品', 2000, 6, '', '', '', '', 1, 0, 'F', '0', '0', 'jarvis:erpProduct:pull', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values(2007, '批量上架', 2000, 7, '', '', '', '', 1, 0, 'F', '0', '0', 'jarvis:erpProduct:publish', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values(2008, '批量下架', 2000, 8, '', '', '', '', 1, 0, 'F', '0', '0', 'jarvis:erpProduct:downShelf', '#', 'admin', sysdate(), '', null, ''); + +-- 给管理员角色(role_id=1)添加闲鱼商品菜单权限 +insert into sys_role_menu(role_id, menu_id) values(1, 2000); +insert into sys_role_menu(role_id, menu_id) values(1, 2001); +insert into sys_role_menu(role_id, menu_id) values(1, 2002); +insert into sys_role_menu(role_id, menu_id) values(1, 2003); +insert into sys_role_menu(role_id, menu_id) values(1, 2004); +insert into sys_role_menu(role_id, menu_id) values(1, 2005); +insert into sys_role_menu(role_id, menu_id) values(1, 2006); +insert into sys_role_menu(role_id, menu_id) values(1, 2007); +insert into sys_role_menu(role_id, menu_id) values(1, 2008); + +-- 注意: +-- 1. 如果菜单需要放在其他目录下(比如jarvis目录),请修改parent_id +-- 2. order_num 是显示顺序,可以根据需要调整(值越大越靠后) +-- 3. 如果管理员角色ID不是1,请修改上面的role_id值 +-- 4. 如果需要给其他角色添加权限,可以复制上面的insert语句并修改role_id +-- 5. 执行完此SQL后,需要清除Redis缓存或重启系统才能看到菜单 + diff --git a/sql/闲鱼商品表.sql b/sql/闲鱼商品表.sql new file mode 100644 index 0000000..57be154 --- /dev/null +++ b/sql/闲鱼商品表.sql @@ -0,0 +1,31 @@ +-- 闲鱼商品表 +CREATE TABLE `erp_product` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `product_id` bigint(20) NOT NULL COMMENT '管家商品ID', + `title` varchar(500) DEFAULT NULL COMMENT '商品标题', + `main_image` varchar(1000) DEFAULT NULL COMMENT '商品图片(主图)', + `price` bigint(20) DEFAULT NULL COMMENT '商品价格(分)', + `stock` int(11) DEFAULT NULL COMMENT '商品库存', + `product_status` int(11) DEFAULT NULL COMMENT '商品状态 1:上架 2:下架 3:已售', + `sale_status` int(11) DEFAULT NULL COMMENT '销售状态', + `user_name` varchar(100) DEFAULT NULL COMMENT '闲鱼会员名', + `online_time` bigint(20) DEFAULT NULL COMMENT '上架时间(时间戳)', + `offline_time` bigint(20) DEFAULT NULL COMMENT '下架时间(时间戳)', + `sold_time` bigint(20) DEFAULT NULL COMMENT '售出时间(时间戳)', + `create_time_xy` bigint(20) DEFAULT NULL COMMENT '创建时间(闲鱼,时间戳)', + `update_time_xy` bigint(20) DEFAULT NULL COMMENT '更新时间(闲鱼,时间戳)', + `appid` varchar(100) DEFAULT NULL COMMENT 'ERP应用ID', + `product_url` varchar(1000) DEFAULT NULL COMMENT '商品链接', + `remark` varchar(500) DEFAULT NULL COMMENT '备注', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_product_id_appid` (`product_id`, `appid`), + KEY `idx_product_id` (`product_id`), + KEY `idx_appid` (`appid`), + KEY `idx_product_status` (`product_status`), + KEY `idx_user_name` (`user_name`), + KEY `idx_online_time` (`online_time`), + KEY `idx_update_time_xy` (`update_time_xy`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='闲鱼商品表'; +