记得上下班打卡 | git大法好,push需谨慎

Commit be55213a authored by 姜秀龙's avatar 姜秀龙

feat(goblin): 商品订单支持粉丝俱乐部来源标记

- 入参 referrerApp、referrerUserId 同时传才写入 order_source,否则落库空串
- 列表/详情 VO 返回 referrerApp、referrerUserId,Redis 老订单兼容空串
- DDL: docu/order_referrer_goblin.sql
Co-authored-by: 's avatarCursor <cursoragent@cursor.com>
parent 6bde6f9a
# 粉丝俱乐部 ↔ 正在现场 技术设计(已定稿)
服务前缀:`/adam``/order``/kylin``/goblin`
**已定**:多端 JTI · 静默登录 `silent_mobile` · 订单来源标记 · A 侧列表用 B token 调**原接口**、不过滤来源(不新建列表接口)
---
## 一、多端登录(JTI)
| 模块 | 改动 |
|------|------|
| **adam** `AdamLoginController#ssoProcess`、各 `login/*` | JWT 加 `jti`,Redis `session:{jti}`;去掉 `adam:identity:sso:{uid}` 互踢 |
| **adam** `AdamAuthorityInterceptor`、各业务拦截器 | 验 JWT 后查 `jti` 是否有效 |
---
## 二、静默登录
**链路**`A 前端 → A 后端 → POST /adam/login/silent_mobile`(A 前端不调 B)
| 接口 | 说明 |
|------|------|
| `POST /adam/login/silent_mobile` | `otp = DES(手机号11位+Unix秒)`,密钥仅 A/Adam 服务端配置化 |
| A 自建如 `POST /api/launch-zhengzai` | 代调 silent_mobile,把 **B token** 给 WebView / 前端 |
A 侧订单:持 **B token** 调现有 `GET /kylin/order/list``POST /goblin/order/list` 等,**不加来源筛选**
---
## 三、订单来源标记
### 入参(`PayOrderParam` / `GoblinOrderParam`)
| 字段 | 落库 |
|------|------|
| `referrerApp` | ✅ → 演出/商品均为 `order_source`**与 referrerUserId 同时传**才写入,否则 `''` |
| `referrerUserId` | ✅ → `referrer_user_id`;未传写 `''` |
### 落库与实现位置
| 表 | 粉丝俱乐部来源 | 客户端来源(不变) | 新增 |
|----|----------------|-------------------|------|
| `kylin_order_tickets` | `order_source` | `order_type`(header) | `referrer_user_id` |
| `goblin_store_order` | `order_source` | `source`(header) | `referrer_user_id` |
`POST /order/pre``POST /goblin/pre``KylinOrderTicketsServiceImpl#order``GoblinOrderServiceImpl` 建单处赋值。
### 列表 / 详情返回
| 类型 | VO |
|------|-----|
| 演出 | `KylinOrderListVo``KylinOrderTicketVo`(详情内)字段 `referrerApp``referrerUserId` |
| 商品 | `GoblinAppOrderListVo``GoblinStoreOrderVo`(详情内)字段 `referrerApp``referrerUserId` |
DDL:`docu/order_referrer_kylin.sql``docu/order_referrer_goblin.sql`
---
## 四、分批实现(建议每批一个 commit)
| 顺序 | 范围 | 建议 commit message |
|------|------|---------------------|
| 1 | JTI 多端登录(adam 签发 + Redis 会话 + 拦截器去掉互踢) | `feat(adam): 多端登录 JTI 会话,取消单设备互踢` |
| 2 | `silent_mobile` 密钥配置化(若需)+ 文档/注释 | `chore(adam): silent_mobile 密钥配置化`(可选,与 1 合并亦可) |
| 3 | 演出订单 DDL + 落库 + 列表详情 VO | `feat(kylin): 演出订单粉丝俱乐部来源标记` |
| 4 | 商品订单 DDL + 落库 + 列表详情 VO | `feat(goblin): 商品订单粉丝俱乐部来源标记` |
> A 项目(粉丝俱乐部)侧:`launch-zhengzai`、WebView 传参、持 B token 调原列表接口 — **在 A 仓库单独 commit**,不在本仓库。
---
## 变更记录
| 日期 | 说明 |
|------|------|
| 2026-05-16 | 定稿;移除新建列表接口;A 用 B token 调原接口 |
-- 商品订单:粉丝俱乐部来源标记
ALTER TABLE goblin_store_order
ADD COLUMN order_source varchar(255) NOT NULL DEFAULT '' COMMENT '粉丝俱乐部来源标识' AFTER source,
ADD COLUMN referrer_user_id varchar(64) NOT NULL DEFAULT '' COMMENT '粉丝俱乐部侧用户id' AFTER order_source;
......@@ -37,5 +37,9 @@ public class GoblinOrderParam {
private AddressVo addressesVo;
@ApiModelProperty(value = "商品相关参数集合")
private List<GoblinOrderStoreParam> goblinOrderStoreParamList;
@ApiModelProperty(value = "粉丝俱乐部来源标识,如DOUDOU之家;与 referrerUserId 同时传才打标")
private String referrerApp;
@ApiModelProperty(value = "粉丝俱乐部侧用户id")
private String referrerUserId;
}
......@@ -55,6 +55,10 @@ public class GoblinAppOrderListVo implements Serializable, Cloneable {
private String mixId;
@ApiModelProperty(value = " 混合售名称")
private String mixName;
@ApiModelProperty(value = "粉丝俱乐部来源标识")
private String referrerApp;
@ApiModelProperty(value = "粉丝俱乐部侧用户id")
private String referrerUserId;
private static final GoblinAppOrderListVo obj = new GoblinAppOrderListVo();
public static GoblinAppOrderListVo getNew() {
......
......@@ -77,6 +77,10 @@ public class GoblinStoreOrderVo implements Serializable, Cloneable {
private String cancelReason;
@ApiModelProperty(value = " 订单来源[app|h5|applet]")
private String source;
@ApiModelProperty(value = "粉丝俱乐部来源标识")
private String referrerApp;
@ApiModelProperty(value = "粉丝俱乐部侧用户id")
private String referrerUserId;
@ApiModelProperty(value = " 版本号")
private String version;
@ApiModelProperty(value = " 是否会员")
......@@ -186,6 +190,8 @@ public class GoblinStoreOrderVo implements Serializable, Cloneable {
this.setDeviceFrom(source.getDeviceFrom());
this.setCancelReason(source.getCancelReason());
this.setSource(source.getSource());
this.setReferrerApp(source.getOrderSource() == null ? "" : source.getOrderSource());
this.setReferrerUserId(source.getReferrerUserId() == null ? "" : source.getReferrerUserId());
this.setVersion(source.getVersion());
this.setIsMember(source.getIsMember());
this.setOrderType(source.getOrderType());
......@@ -237,6 +243,8 @@ public class GoblinStoreOrderVo implements Serializable, Cloneable {
this.setDeviceFrom(source.getDeviceFrom());
this.setCancelReason(source.getCancelReason());
this.setSource(source.getSource());
this.setReferrerApp(source.getOrderSource() == null ? "" : source.getOrderSource());
this.setReferrerUserId(source.getReferrerUserId() == null ? "" : source.getReferrerUserId());
this.setVersion(source.getVersion());
this.setIsMember(source.getIsMember());
this.setOrderType(source.getOrderType());
......
......@@ -190,6 +190,16 @@ public class GoblinStoreOrder implements Serializable,Cloneable {
*/
private String source;
/**
* 粉丝俱乐部来源标识
*/
private String orderSource;
/**
* 粉丝俱乐部侧用户id
*/
private String referrerUserId;
/**
* 版本号
*/
......
......@@ -78,6 +78,7 @@ public class GoblinOrderAppServiceImpl implements IGoblinOrderAppService {
}
GoblinAppOrderListVo vo = GoblinAppOrderListVo.getNew();
BeanUtils.copyProperties(orderVo, vo);
fillReferrerDefaults(vo, orderVo);
vo.setRestTime(getRestTime(orderVo));
List<GoblinOrderSkuVo> skuVos = ObjectUtil.getGoblinOrderSkuVoArrayList();
for (String orderSkuId : orderVo.getOrderSkuVoIds()) {
......@@ -100,6 +101,7 @@ public class GoblinOrderAppServiceImpl implements IGoblinOrderAppService {
GoblinStoreOrderVo orderVo = redisUtils.getGoblinOrder(orderId);
GoblinAppOrderListVo vo = GoblinAppOrderListVo.getNew();
BeanUtils.copyProperties(orderVo, vo);
fillReferrerDefaults(vo, orderVo);
vo.setRestTime(getRestTime(orderVo));
List<GoblinOrderSkuVo> skuVos = ObjectUtil.getGoblinOrderSkuVoArrayList();
for (String orderSkuId : orderVo.getOrderSkuVoIds()) {
......@@ -119,6 +121,7 @@ public class GoblinOrderAppServiceImpl implements IGoblinOrderAppService {
if (orderVo == null || (!orderVo.getUserId().equals(uid) && uid != null)) {
return ResponseDto.failure(ErrorMapping.get("20003"));
}
normalizeReferrerFields(orderVo);
GoblinAppOrderDetailsVo vo = GoblinAppOrderDetailsVo.getNew();
vo.setStoreOrderVo(orderVo);
List<GoblinOrderSkuVo> skuVos = ObjectUtil.getGoblinOrderSkuVoArrayList();
......@@ -769,4 +772,19 @@ public class GoblinOrderAppServiceImpl implements IGoblinOrderAppService {
private boolean noZhengzaiOrder(String uid) {
return !uid.equals("zhengzai");
}
private void fillReferrerDefaults(GoblinAppOrderListVo vo, GoblinStoreOrderVo orderVo) {
normalizeReferrerFields(orderVo);
vo.setReferrerApp(orderVo.getReferrerApp());
vo.setReferrerUserId(orderVo.getReferrerUserId());
}
private void normalizeReferrerFields(GoblinStoreOrderVo orderVo) {
if (orderVo.getReferrerApp() == null) {
orderVo.setReferrerApp("");
}
if (orderVo.getReferrerUserId() == null) {
orderVo.setReferrerUserId("");
}
}
}
......@@ -515,6 +515,7 @@ public class GoblinOrderServiceImpl implements IGoblinOrderService {
storeOrder.setPayType(param.getPayType());
storeOrder.setDeviceFrom(param.getDeviceFrom());
storeOrder.setSource(source);
applyReferrerMark(storeOrder, param);
storeOrder.setVersion(version);
storeOrder.setIsMember(isMember ? 1 : 0);
storeOrder.setOrderType(0);
......@@ -763,7 +764,10 @@ public class GoblinOrderServiceImpl implements IGoblinOrderService {
sqlDataOrder.add(new Object[]{
storeOrder.getMasterOrderCode(), storeOrder.getOrderId(), storeOrder.getStoreId(), storeOrder.getStoreName(), storeOrder.getOrderCode(), storeOrder.getUserId(), storeOrder.getUserName(), storeOrder.getUserMobile(), storeOrder.getPriceTotal(), storeOrder.getPayCode(),
storeOrder.getPriceActual(), storeOrder.getPriceRefund(), storeOrder.getPriceExpress(), storeOrder.getPriceCoupon(), storeOrder.getStorePriceCoupon(), storeOrder.getPriceVoucher(), storeOrder.getStatus(), storeOrder.getUcouponId(), storeOrder.getStoreCouponId(), storeOrder.getPayType(), storeOrder.getDeviceFrom(),
storeOrder.getSource(), storeOrder.getVersion(), storeOrder.getIsMember(), storeOrder.getOrderType(), storeOrder.getWriteOffCode(), storeOrder.getPayCountdownMinute(), storeOrder.getIpAddress(), storeOrder.getMarketId(), storeOrder.getMarketType(), storeOrder.getCreatedAt(), "", ""
storeOrder.getSource(),
storeOrder.getOrderSource() == null ? "" : storeOrder.getOrderSource(),
storeOrder.getReferrerUserId() == null ? "" : storeOrder.getReferrerUserId(),
storeOrder.getVersion(), storeOrder.getIsMember(), storeOrder.getOrderType(), storeOrder.getWriteOffCode(), storeOrder.getPayCountdownMinute(), storeOrder.getIpAddress(), storeOrder.getMarketId(), storeOrder.getMarketType(), storeOrder.getCreatedAt(), "", ""
});
GoblinOrderAttr orderAttr = item.getOrderAttr();
sqlDataAttr.add(new Object[]{
......@@ -1468,4 +1472,12 @@ public class GoblinOrderServiceImpl implements IGoblinOrderService {
}
return "";
}
private void applyReferrerMark(GoblinStoreOrder storeOrder, GoblinOrderParam param) {
ReferrerOrderMarkUtil.apply(param.getReferrerApp(), param.getReferrerUserId(),
(referrerApp, referrerUserId) -> {
storeOrder.setOrderSource(referrerApp);
storeOrder.setReferrerUserId(referrerUserId);
});
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment