This commit is contained in:
2025-08-18 01:58:23 +08:00
parent 33567109ed
commit 5e8c9614ef
71 changed files with 6864 additions and 6 deletions

View File

@@ -0,0 +1,86 @@
package com.ruoyi.web.controller.common;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.utils.StringUtils;
import org.springframework.web.bind.annotation.*;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* 开放平台回调接收端
* 注意:/product/receive 与 /order/receive 为示例路径,请在开放平台配置时使用你自己的正式回调地址
*/
@RestController
@RequestMapping("/open/callback")
public class OpenCallbackController extends BaseController {
@PostMapping("/product/receive")
public JSONObject receiveProductCallback(
@RequestParam("appid") String appid,
@RequestParam(value = "timestamp", required = false) Long timestamp,
@RequestParam("sign") String sign,
@RequestBody JSONObject body
) {
if (!verifySign(appid, timestamp, sign, body)) {
JSONObject fail = new JSONObject();
fail.put("result", "fail");
fail.put("msg", "签名失败");
return fail;
}
JSONObject ok = new JSONObject();
ok.put("result", "success");
ok.put("msg", "接收成功");
return ok;
}
@PostMapping("/order/receive")
public JSONObject receiveOrderCallback(
@RequestParam("appid") String appid,
@RequestParam(value = "timestamp", required = false) Long timestamp,
@RequestParam("sign") String sign,
@RequestBody JSONObject body
) {
if (!verifySign(appid, timestamp, sign, body)) {
JSONObject fail = new JSONObject();
fail.put("result", "fail");
fail.put("msg", "签名失败");
return fail;
}
JSONObject ok = new JSONObject();
ok.put("result", "success");
ok.put("msg", "接收成功");
return ok;
}
private boolean verifySign(String appid, Long timestamp, String sign, JSONObject body) {
// TODO: 这里需要根据appid查出对应的 appKey/appSecret
// 为了示例,直接使用 ERPAccount.ACCOUNT_HUGE 的常量。生产请替换为从数据库/配置读取
String appKey = "1016208368633221";
String appSecret = "waLiRMgFcixLbcLjUSSwo370Hp1nBcBu";
String json = body == null ? "{}" : body.toJSONString();
String data = appKey + "," + md5(json) + "," + (timestamp == null ? 0 : timestamp) + "," + appSecret;
String local = md5(data);
return StringUtils.equalsIgnoreCase(local, sign);
}
private String md5(String str) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(str.getBytes(StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
sb.append(String.format("%02x", b & 0xff));
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,466 @@
package com.ruoyi.web.controller.erp;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.erp.domain.*;
import com.ruoyi.erp.request.ERPAccount;
import com.ruoyi.erp.request.ProductCreateRequest;
import com.ruoyi.erp.request.ProductCategoryListQueryRequest;
import com.ruoyi.erp.request.ProductPropertyListQueryRequest;
import com.ruoyi.erp.request.AuthorizeListQueryRequest;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* ERP 商品接口
* 基于“生成的文案与图片”快速创建商品
*/
@RestController
@RequestMapping("/erp/product")
@Validated
public class ProductController extends BaseController {
@PostMapping("/createByPromotion")
public R<?> createByPromotion(@RequestBody @Validated CreateProductFromPromotionRequest req) {
try {
ERPAccount account = resolveAccount(req.getAppid());
// 1) 组装 ERPShop
ERPShop erpShop = new ERPShop();
erpShop.setChannelCatid(req.getChannelCatId());
erpShop.setItemBizType(req.getItemBizType());
erpShop.setSpBizType(req.getSpBizType());
erpShop.setPrice(req.getPrice());
erpShop.setExpressFee(req.getExpressFee());
erpShop.setStock(req.getStock());
erpShop.setOuterid(req.getOuterId());
erpShop.setStuffStatus(req.getStuffStatus());
// 发布店铺(必填)
PublishShop shop = new PublishShop();
shop.setUserName(req.getUserName());
shop.setProvince(req.getProvince());
shop.setCity(req.getCity());
shop.setDistrict(req.getDistrict());
shop.setTitle(req.getTitle());
shop.setContent(req.getContent());
shop.setImages(req.getImages());
shop.setWhiteImages(req.getWhiteImages());
shop.setServiceSupport(req.getServiceSupport());
List<PublishShop> publishShops = new ArrayList<>();
publishShops.add(shop);
erpShop.setPublishShop(publishShops);
// 属性(选填)
if (req.getChannelPv() != null && !req.getChannelPv().isEmpty()) {
List<Channelpv> pvList = new ArrayList<>();
for (CreateProductFromPromotionRequest.ChannelPvDto pvDto : req.getChannelPv()) {
Channelpv pv = new Channelpv();
pv.setPropertyid(pvDto.getPropertyId());
pv.setPropertyName(pvDto.getPropertyName());
pv.setValueid(pvDto.getValueId());
pv.setValueName(pvDto.getValueName());
pvList.add(pv);
}
erpShop.setChannelpv(pvList);
}
// 多规格(选填)
if (req.getSkuItems() != null && !req.getSkuItems().isEmpty()) {
List<SkuItems> skuItems = new ArrayList<>();
for (CreateProductFromPromotionRequest.SkuItemDto s : req.getSkuItems()) {
SkuItems si = new SkuItems();
si.setPrice(s.getPrice());
si.setStock(s.getStock());
si.setSkuText(s.getSkuText());
si.setOuterid(s.getOuterId());
skuItems.add(si);
}
erpShop.setSkuItems(skuItems);
}
// 2) 调用开放接口
ProductCreateRequest createRequest = new ProductCreateRequest(account);
JSONObject body = JSONObject.parseObject(JSON.toJSONString(erpShop));
createRequest.setRequestBody(body);
String resp = createRequest.getResponseBody();
return R.ok(JSONObject.parse(resp));
} catch (Exception e) {
return R.fail("创建失败: " + e.getMessage());
}
}
/**
* 获取类目下拉
*/
@GetMapping("/categories")
public R<?> categories(@RequestParam int itemBizType,
@RequestParam(required = false) Integer spBizType,
@RequestParam(required = false) Integer flashSaleType,
@RequestParam(required = false) String appid) {
try {
ProductCategoryListQueryRequest req = new ProductCategoryListQueryRequest(resolveAccount(appid));
req.setItemBizType(itemBizType);
if (spBizType != null) req.setSpBizType(spBizType);
if (flashSaleType != null) req.setFlashSaleType(flashSaleType);
String resp = req.getResponseBody();
JSONObject jo = JSONObject.parseObject(resp);
// 兼容不同返回格式:{"code":0,"data":{"list":[...]}}
List<JSONObject> rows = new java.util.ArrayList<>();
Object dataObj = jo.get("data");
if (dataObj instanceof com.alibaba.fastjson2.JSONArray) {
rows.addAll(((com.alibaba.fastjson2.JSONArray) dataObj).toJavaList(JSONObject.class));
} else if (dataObj instanceof JSONObject) {
JSONObject dataJson = (JSONObject) dataObj;
if (dataJson.get("list") instanceof com.alibaba.fastjson2.JSONArray) {
rows.addAll(dataJson.getJSONArray("list").toJavaList(JSONObject.class));
} else if (dataJson.get("categories") instanceof com.alibaba.fastjson2.JSONArray) {
rows.addAll(dataJson.getJSONArray("categories").toJavaList(JSONObject.class));
}
} else if (jo.get("list") instanceof com.alibaba.fastjson2.JSONArray) {
rows.addAll(jo.getJSONArray("list").toJavaList(JSONObject.class));
} else if (jo.get("categories") instanceof com.alibaba.fastjson2.JSONArray) {
rows.addAll(jo.getJSONArray("categories").toJavaList(JSONObject.class));
}
List<Option> options = new java.util.ArrayList<>();
for (JSONObject row : rows) {
String id = firstNonBlank(
row.getString("channel_cat_id"),
row.getString("cat_id"),
row.getString("id"),
row.getString("channelCatId")
);
String name = firstNonBlank(
row.getString("channel_cat_name"),
row.getString("name"),
row.getString("cat_name"),
row.getString("category_name"),
row.getString("title")
);
if (id != null && name != null) options.add(new Option(id, name));
}
return R.ok(options);
} catch (Exception e) {
return R.fail("获取类目失败: " + e.getMessage());
}
}
/**
* 获取商品属性(基于 itemBizType / spBizType / channelCatId
*/
@GetMapping("/pv")
public R<?> properties(@RequestParam int itemBizType,
@RequestParam int spBizType,
@RequestParam String channelCatId,
@RequestParam(required = false) String subPropertyId,
@RequestParam(required = false) String appid) {
try {
System.out.println("获取商品属性");
ProductPropertyListQueryRequest req = new ProductPropertyListQueryRequest(resolveAccount(appid));
req.setItemBizType(itemBizType);
req.setSpBizType(spBizType);
req.setChannelCatId(channelCatId);
if (subPropertyId != null && !subPropertyId.isEmpty()) req.setSubPropertyId(subPropertyId);
String resp = req.getResponseBody();
JSONObject jo = JSONObject.parseObject(resp);
java.util.List<JSONObject> rows = new java.util.ArrayList<>();
Object dataObj = jo.get("data");
if (dataObj instanceof com.alibaba.fastjson2.JSONArray) {
rows.addAll(((com.alibaba.fastjson2.JSONArray) dataObj).toJavaList(JSONObject.class));
} else if (dataObj instanceof JSONObject) {
JSONObject dataJson = (JSONObject) dataObj;
if (dataJson.get("list") instanceof com.alibaba.fastjson2.JSONArray) {
rows.addAll(dataJson.getJSONArray("list").toJavaList(JSONObject.class));
} else if (dataJson.get("pv_list") instanceof com.alibaba.fastjson2.JSONArray) {
rows.addAll(dataJson.getJSONArray("pv_list").toJavaList(JSONObject.class));
}
} else if (jo.get("list") instanceof com.alibaba.fastjson2.JSONArray) {
rows.addAll(jo.getJSONArray("list").toJavaList(JSONObject.class));
}
// 规范化输出
java.util.List<java.util.Map<String, Object>> props = new java.util.ArrayList<>();
for (JSONObject row : rows) {
if (row == null) continue;
String pid = firstNonBlank(row.getString("property_id"), row.getString("propertyId"), row.getString("id"));
String pname = firstNonBlank(row.getString("property_name"), row.getString("propertyName"), row.getString("name"));
if (pid == null || pname == null) continue;
java.util.List<java.util.Map<String, String>> values = new java.util.ArrayList<>();
Object vs = row.get("values");
if (vs instanceof com.alibaba.fastjson2.JSONArray) {
for (Object o : (com.alibaba.fastjson2.JSONArray) vs) {
if (o instanceof JSONObject) {
JSONObject v = (JSONObject) o;
String vid = firstNonBlank(v.getString("value_id"), v.getString("valueId"), v.getString("id"));
String vname = firstNonBlank(v.getString("value_name"), v.getString("valueName"), v.getString("name"));
if (vid != null && vname != null) {
java.util.Map<String, String> m = new java.util.HashMap<>();
m.put("valueId", vid);
m.put("valueName", vname);
values.add(m);
}
}
}
} else if (row.get("value_list") instanceof com.alibaba.fastjson2.JSONArray) {
for (Object o : row.getJSONArray("value_list")) {
if (o instanceof JSONObject) {
JSONObject v = (JSONObject) o;
String vid = firstNonBlank(v.getString("value_id"), v.getString("valueId"), v.getString("id"));
String vname = firstNonBlank(v.getString("value_name"), v.getString("valueName"), v.getString("name"));
if (vid != null && vname != null) {
java.util.Map<String, String> m = new java.util.HashMap<>();
m.put("valueId", vid);
m.put("valueName", vname);
values.add(m);
}
}
}
} else if (row.get("items") instanceof com.alibaba.fastjson2.JSONArray) { // 实际返回为 items
for (Object o : row.getJSONArray("items")) {
if (o instanceof JSONObject) {
JSONObject v = (JSONObject) o;
String vid = firstNonBlank(v.getString("value_id"), v.getString("valueId"), v.getString("id"));
String vname = firstNonBlank(v.getString("value_name"), v.getString("valueName"), v.getString("name"));
if (vid != null && vname != null) {
java.util.Map<String, String> m = new java.util.HashMap<>();
m.put("valueId", vid);
m.put("valueName", vname);
values.add(m);
}
}
}
}
java.util.Map<String, Object> p = new java.util.HashMap<>();
p.put("propertyId", pid);
p.put("propertyName", pname);
// 透传是否必填0/1不同接口可能是 required 或 must
Integer required = row.getInteger("required");
if (required == null) required = row.getInteger("must");
if (required != null) p.put("required", required);
p.put("values", values);
props.add(p);
}
return R.ok(props);
} catch (Exception e) {
return R.fail("获取属性失败: " + e.getMessage());
}
}
private static String firstNonBlank(String... vals) {
if (vals == null) return null;
for (String v : vals) { if (v != null && v.trim().length() > 0) return v; }
return null;
}
public static class Option {
public final String value; public final String label;
public Option(String value, String label) { this.value = value; this.label = label; }
}
/**
* 获取授权的闲鱼会员名下拉
*/
@GetMapping("/usernames")
public R<?> usernames(@RequestParam(defaultValue = "1") int pageNum,
@RequestParam(defaultValue = "100") int pageSize,
@RequestParam(required = false) String appid) {
try {
AuthorizeListQueryRequest req = new AuthorizeListQueryRequest(resolveAccount(appid));
req.setPagination(pageNum, pageSize);
String resp = req.getResponseBody();
JSONObject jo = JSONObject.parseObject(resp);
java.util.List<Option> options = new java.util.ArrayList<>();
java.util.function.Consumer<JSONObject> addRow = row -> {
if (row == null) return;
String name = firstNonBlank(row.getString("user_name"), row.getString("xy_name"), row.getString("username"), row.getString("nick"));
if (name != null) {
String label = name;
for (ERPAccount a : ERPAccount.values()) {
if (name.equals(a.getXyName())) {
label = name + "(" + a.getRemark() + ")";
break;
}
}
options.add(new Option(name, label));
}
};
Object data = jo.get("data");
if (data instanceof com.alibaba.fastjson2.JSONArray) {
for (Object o : (com.alibaba.fastjson2.JSONArray) data) addRow.accept((JSONObject) o);
} else if (data instanceof JSONObject) {
JSONObject d = (JSONObject) data;
if (d.get("list") instanceof com.alibaba.fastjson2.JSONArray) {
for (Object o : d.getJSONArray("list")) addRow.accept((JSONObject) o);
} else if (d.get("users") instanceof com.alibaba.fastjson2.JSONArray) {
for (Object o : d.getJSONArray("users")) addRow.accept((JSONObject) o);
}
}
return R.ok(options);
} catch (Exception e) {
return R.fail("获取会员名失败: " + e.getMessage());
}
}
/**
* 获取可用ERP账号仅返回appid与会员名隐藏密钥
*/
@GetMapping("/ERPAccount")
public R<?> erpAccounts() {
java.util.List<Option> list = new java.util.ArrayList<>();
for (ERPAccount a : ERPAccount.values()) {
// 仅显示备注作为 labelvalue 仍为 appid
list.add(new Option(a.getApiKey(), a.getRemark()));
}
return R.ok(list);
}
private ERPAccount resolveAccount(String appid) {
if (appid != null && !appid.isEmpty()) {
for (ERPAccount a : ERPAccount.values()) {
if (a.getApiKey().equals(appid)) return a;
}
}
return ERPAccount.ACCOUNT_HUGE;
}
/**
* 用于承接前端“生成的文案与图片”并补足必填参数
*/
public static class CreateProductFromPromotionRequest {
// 必填-类目/类型/行业
@NotBlank
private String channelCatId;
@NotNull
private Integer itemBizType;
@NotNull
private Integer spBizType;
// 必填-价格/邮费/库存
@NotNull @Min(1)
private Long price;
@NotNull @Min(0)
private Long expressFee;
@NotNull @Min(1)
private Integer stock;
// 发布店铺信息(必填)
@NotBlank
private String userName;
@NotNull
private Integer province;
@NotNull
private Integer city;
@NotNull
private Integer district;
// 文案与图片(必填)
@NotBlank
private String title;
@NotBlank
private String content;
@NotNull
@Size(min = 1)
private List<String> images;
// 选填
private String whiteImages;
private String serviceSupport; // 多个用逗号分隔
private String outerId;
private Integer stuffStatus;
private List<SkuItemDto> skuItems;
private List<ChannelPvDto> channelPv;
// getters/setters
public String getChannelCatId() { return channelCatId; }
public void setChannelCatId(String channelCatId) { this.channelCatId = channelCatId; }
public Integer getItemBizType() { return itemBizType; }
public void setItemBizType(Integer itemBizType) { this.itemBizType = itemBizType; }
public Integer getSpBizType() { return spBizType; }
public void setSpBizType(Integer spBizType) { this.spBizType = spBizType; }
public Long getPrice() { return price; }
public void setPrice(Long price) { this.price = price; }
public Long getExpressFee() { return expressFee; }
public void setExpressFee(Long expressFee) { this.expressFee = expressFee; }
public Integer getStock() { return stock; }
public void setStock(Integer stock) { this.stock = stock; }
public String getUserName() { return userName; }
public void setUserName(String userName) { this.userName = userName; }
public Integer getProvince() { return province; }
public void setProvince(Integer province) { this.province = province; }
public Integer getCity() { return city; }
public void setCity(Integer city) { this.city = city; }
public Integer getDistrict() { return district; }
public void setDistrict(Integer district) { this.district = district; }
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
public String getContent() { return content; }
public void setContent(String content) { this.content = content; }
public List<String> getImages() { return images; }
public void setImages(List<String> images) { this.images = images; }
public String getWhiteImages() { return whiteImages; }
public void setWhiteImages(String whiteImages) { this.whiteImages = whiteImages; }
public String getServiceSupport() { return serviceSupport; }
public void setServiceSupport(String serviceSupport) { this.serviceSupport = serviceSupport; }
public String getOuterId() { return outerId; }
public void setOuterId(String outerId) { this.outerId = outerId; }
public Integer getStuffStatus() { return stuffStatus; }
public void setStuffStatus(Integer stuffStatus) { this.stuffStatus = stuffStatus; }
public List<SkuItemDto> getSkuItems() { return skuItems; }
public void setSkuItems(List<SkuItemDto> skuItems) { this.skuItems = skuItems; }
public List<ChannelPvDto> getChannelPv() { return channelPv; }
public void setChannelPv(List<ChannelPvDto> channelPv) { this.channelPv = channelPv; }
public static class SkuItemDto {
@NotNull @Min(0)
private Long price;
@NotNull @Min(0)
private Integer stock;
@NotBlank
private String skuText;
private String outerId;
public Long getPrice() { return price; }
public void setPrice(Long price) { this.price = price; }
public Integer getStock() { return stock; }
public void setStock(Integer stock) { this.stock = stock; }
public String getSkuText() { return skuText; }
public void setSkuText(String skuText) { this.skuText = skuText; }
public String getOuterId() { return outerId; }
public void setOuterId(String outerId) { this.outerId = outerId; }
}
public static class ChannelPvDto {
@NotBlank
private String propertyId;
@NotBlank
private String propertyName;
@NotBlank
private String valueId;
@NotBlank
private String valueName;
public String getPropertyId() { return propertyId; }
public void setPropertyId(String propertyId) { this.propertyId = propertyId; }
public String getPropertyName() { return propertyName; }
public void setPropertyName(String propertyName) { this.propertyName = propertyName; }
public String getValueId() { return valueId; }
public void setValueId(String valueId) { this.valueId = valueId; }
public String getValueName() { return valueName; }
public void setValueName(String valueName) { this.valueName = valueName; }
}
// 扩展:支持多账号,多店铺
private String appid; // 选用的ERP应用appid
public String getAppid() { return appid; }
public void setAppid(String appid) { this.appid = appid; }
}
}

View File

@@ -0,0 +1,36 @@
package com.ruoyi.web.controller.erp;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.erp.service.IRegionService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@RequestMapping("/erp/region")
public class RegionController extends BaseController {
@Resource
private IRegionService regionService;
@GetMapping("/provinces")
public R<?> provinces() {
return R.ok(regionService.listProvinces());
}
@GetMapping("/cities")
public R<?> cities(@RequestParam Integer provId) {
return R.ok(regionService.listCities(provId));
}
@GetMapping("/areas")
public R<?> areas(@RequestParam Integer provId, @RequestParam Integer cityId) {
return R.ok(regionService.listAreas(provId, cityId));
}
}

View File

@@ -1,5 +1,7 @@
package com.ruoyi.web.controller.jarvis;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.http.HttpUtils;
@@ -35,6 +37,55 @@ public class JDOrderController {
param.put("skey", skey);
param.put("promotionContent", promotionContent);
result = HttpUtils.sendJsonPost(url, param.toJSONString());
// 尝试将 priceInfo.price 提取为顶层 price 字段
try {
Object parsed = JSON.parse(result);
if (parsed instanceof JSONArray) {
JSONArray arr = (JSONArray) parsed;
for (int i = 0; i < arr.size(); i++) {
Object el = arr.get(i);
if (el instanceof JSONObject) {
JSONObject obj = (JSONObject) el;
JSONObject priceInfo = obj.getJSONObject("priceInfo");
if (priceInfo != null && priceInfo.get("price") != null) {
obj.put("price", priceInfo.get("price"));
}
}
}
result = arr.toJSONString();
} else if (parsed instanceof JSONObject) {
JSONObject obj = (JSONObject) parsed;
if (obj.get("list") instanceof JSONArray) {
JSONArray list = obj.getJSONArray("list");
for (int i = 0; i < list.size(); i++) {
JSONObject o = list.getJSONObject(i);
if (o != null) {
JSONObject priceInfo = o.getJSONObject("priceInfo");
if (priceInfo != null && priceInfo.get("price") != null) {
o.put("price", priceInfo.get("price"));
}
}
}
obj.put("list", list);
} else if (obj.get("data") instanceof JSONArray) {
JSONArray data = obj.getJSONArray("data");
for (int i = 0; i < data.size(); i++) {
JSONObject o = data.getJSONObject(i);
if (o != null) {
JSONObject priceInfo = o.getJSONObject("priceInfo");
if (priceInfo != null && priceInfo.get("price") != null) {
o.put("price", priceInfo.get("price"));
}
}
}
obj.put("data", data);
}
result = obj.toJSONString();
}
} catch (Exception ignore) {
// 返回不是有效JSON时忽略
}
} catch (Exception e) {
System.out.println(e.getMessage());
}