2021春節技術比賽之轉件存儲設計
一、題目背景
由於公司業務發展,不斷有新的業務線加入。
新的業務線加入就會有新的配套信息系統來支撐。
目前我們信息部支撐宅急送物流快遞業務操作系統,供應鏈/倉儲業務操作系統,領送相關業務操作系統。
三條業務線都有各自的特點,但每條業務線又有相似之處。
作爲實現業務信息化的我們要支撐業務需要,同時也在提高自己。
目前三條業務線的相似之處就是都要把貨物轉給第三方承運商,
我們的下游承運商可能是京東快遞,順豐,申通,圓通,韻達等等,當然也包括宅急送自己在內!
這樣就帶來的一個問題,我們不可能一直將三條業務線的系統與第三方承運商的物流運輸平臺進行對接信息。
所以我們要打造一個平臺,一個能支撐三條業務線的“轉件”平臺
二、題目淺析
作爲一個所謂的“轉件”平臺上游可以接收各條業務線產生的訂單
下游對接各個承運商。
同時承運商本身也可以是上游訂單的生產者。
“轉件”平臺起到承上啓下與資源整合的作用。
所有的訂單和狀態都要經過“轉件”平臺,而且一個訂單或者運單可能多次經過轉件平臺。
如下所示
例如倉儲產生了一個訂單,訂單號爲C_01,經過轉件平臺轉給領送,領送分配給C_01的訂單的運單號爲L_01,在我們的轉件系統產生如下一條數據
由於領送(我們假設領送有配送能力)配送能力有限會再次進行轉件操作
將L_01這個運單再次通過轉件平臺轉給宅急送,宅急送分配給L_01這個訂單(下游系統認爲領送下的是訂單而非運單)的運單號是Z_01
再一次在我們的系統裏產生一條如下數據
同樣宅急送又一次轉給了郵政,同樣也產生了如下一條數據
這樣就將一個具體的實物訂單經過多次轉件之後至少再“轉件”平臺產生了3條數據
接下來說關於訂單/運單狀態的情況
訂單通過“轉件”平臺傳遞給下游第三方承運商,同時承運商也要回傳訂單或運單的狀態和跟蹤軌跡
上游的業務線需要通過轉件平臺接收狀態和軌跡信息
如果我們的訂單或者運單出現了兩次以上轉件,倉儲轉給領送,領送又轉給了宅急送,宅急送又轉給了郵政
倉儲系統需要所有的物流跟蹤軌跡數據,轉件平臺會回傳所有的數據
宅急送轉件給郵政,這個時候郵政需要將狀態信息通過“轉件”平臺回傳給宅急送
同樣宅急送也需要將領送訂單的狀態軌跡信息回傳給領送
一個訂單最後到收貨人手裏經過了三次轉件
每個承運商都負責了其中一段運輸路線
上游系統需要下游系統所有的物流跟蹤軌跡
以上圖表僅提供業務理解使用
到這裏“轉件”平臺出現了兩張表 運單表和狀態軌跡表
那麼問題來了!比賽題目是什麼那?如下
三、具體題目
根據上面的業務描述和理解給出具體的下單數據庫存儲和狀態軌跡數據存儲的設計並實現對應的微服務
其中微服務API實現包括訂單接收、軌跡接收、軌跡查詢3個API。
訂單接收和狀態軌跡數據格式爲定義的標準格式(稍後公佈)
軌跡查詢條件爲任意上下游單號(例如:C_01、L_01、Z_01、Y_01)返回全流程按時間升序的軌跡信息
四、技術選型範圍
持久性存儲選型:mongodb、elasticsearch、mysql
編程語言:JAVA(版本1.8及以上)
五、注意事項及時間安排
仔細理解業務需求,在規定的時間和技術棧完成符合標準的設計和實現
具體API的數據結構稍後給出。可以單人蔘賽也可以多人組隊。
稍後找時間進行統一講解一下
(具體比賽時間等過了春節之後再定,應該在2021年2月份之前完成)
六、測試評比規則及流程
評比規則:
下單API的平均TPS*30%+狀態回傳API的平均TPS*30%+狀態查詢API的平均TPS*40%=最終結果(不使用)
下單API100萬條總時長*30%+狀態回傳API1000萬條總時長*30%+狀態查詢API100萬次查詢總時長*40%=最終結果(使用)
以最終結果進行排名,TopN名獲得相應獎勵(TPS是最終結果越大越好,時長是最終結果越小越好)
如果出現比賽結果相同現象將進行復賽
複賽以平均TPS總和優異者獲勝
基本比賽流程如下:
1、下單接口的調用執行
2、對應下單數據的狀態信息調用執行
3、對應狀態信息查詢調用執行
數據提前預設好結構一致,請求次數與條數一致
以下情況視爲自動退賽:
1、沒有充分理解業務需求,開發程序無任何參考價值的
2、沒有按時參加比賽的
3、以一切手段作弊的(比如:抄襲其他參賽設計或代碼,開源代碼不算,主動交流的不算)
4、不按規則流程執行搗亂的
以下2021-02-23日補充
具體API規範(以下樣例僅API接口交互規則作爲標準,實際請求爲以http post請求,json格式,詳細數據在body中。更明確的是這裏只規定了http協議數據包格式,其他比如序列化等組件,model實體都可以自己設計)
import java.util.Date;
import java.util.List;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class BiSaiController {
/**
* 創建訂單
* 接口實體類爲內部類,這裏只是做個樣例看,實際使用的時候可能調用不到
* @param or
* @return
*/
@PostMapping("/createorder")
public ReturnRoot createOrder(@RequestBody OrderRoot or) {
//解析數據
//保存數據庫
//返回必要的信息
return new ReturnRoot();
}
/**
* 創建狀態
* 接口實體類爲內部類,這裏只是做個樣例看,實際使用的時候可能調用不到
* @param or
* @return
*/
@PostMapping("/createstatus")
public ReturnStatus createStatus(@RequestBody StatusRoot sr) {
//解析數據
//保存數據庫
//返回必要的信息
return new ReturnStatus();
}
/**
* 狀態查詢
* 接口實體類爲內部類,這裏只是做個樣例看,實際使用的時候可能調用不到
* @param waybillorordernumber 運單號或訂單號
* @return
*/
@PostMapping("/querystatus")
public List<Traces> queryStatus(@RequestBody String waybillorordernumber) {
//解析數據
//查詢數據庫
//返回查詢的信息
return new ArrayList<Traces>();
}
//-------訂單相關實體類-----------------------------------------------------------------------------------------
class OrderRoot {
private String resourceTypeName;
private AccountInfo accountInfo;
private String sourceCode;
private String orderType;
private String resourceCode;
private String orderNo;
private String mailNo;
private String goodsName;
private String goodsNum;
private String goodsWeight;
private String goodsVolume;
private String remarks;
private String goodsValue;
private String codFlag;
private String codAmount;
private String extendedInfo;
private Sender sender;
private Receiver receiver;
public void setResourceTypeName(String resourceTypeName) {
this.resourceTypeName = resourceTypeName;
}
public String getResourceTypeName() {
return resourceTypeName;
}
public void setAccountInfo(AccountInfo accountInfo) {
this.accountInfo = accountInfo;
}
public AccountInfo getAccountInfo() {
return accountInfo;
}
public void setSourceCode(String sourceCode) {
this.sourceCode = sourceCode;
}
public String getSourceCode() {
return sourceCode;
}
public void setOrderType(String orderType) {
this.orderType = orderType;
}
public String getOrderType() {
return orderType;
}
public void setResourceCode(String resourceCode) {
this.resourceCode = resourceCode;
}
public String getResourceCode() {
return resourceCode;
}
public void setOrderNo(String orderNo) {
this.orderNo = orderNo;
}
public String getOrderNo() {
return orderNo;
}
public void setMailNo(String mailNo) {
this.mailNo = mailNo;
}
public String getMailNo() {
return mailNo;
}
public void setGoodsName(String goodsName) {
this.goodsName = goodsName;
}
public String getGoodsName() {
return goodsName;
}
public void setGoodsNum(String goodsNum) {
this.goodsNum = goodsNum;
}
public String getGoodsNum() {
return goodsNum;
}
public void setGoodsWeight(String goodsWeight) {
this.goodsWeight = goodsWeight;
}
public String getGoodsWeight() {
return goodsWeight;
}
public void setGoodsVolume(String goodsVolume) {
this.goodsVolume = goodsVolume;
}
public String getGoodsVolume() {
return goodsVolume;
}
public void setRemarks(String remarks) {
this.remarks = remarks;
}
public String getRemarks() {
return remarks;
}
public void setGoodsValue(String goodsValue) {
this.goodsValue = goodsValue;
}
public String getGoodsValue() {
return goodsValue;
}
public void setCodFlag(String codFlag) {
this.codFlag = codFlag;
}
public String getCodFlag() {
return codFlag;
}
public void setCodAmount(String codAmount) {
this.codAmount = codAmount;
}
public String getCodAmount() {
return codAmount;
}
public void setExtendedInfo(String extendedInfo) {
this.extendedInfo = extendedInfo;
}
public String getExtendedInfo() {
return extendedInfo;
}
public void setSender(Sender sender) {
this.sender = sender;
}
public Sender getSender() {
return sender;
}
public void setReceiver(Receiver receiver) {
this.receiver = receiver;
}
public Receiver getReceiver() {
return receiver;
}
}
class AccountInfo {
private String siteCode;
private String customerName;
public void setSiteCode(String siteCode) {
this.siteCode = siteCode;
}
public String getSiteCode() {
return siteCode;
}
public void setCustomerName(String customerName) {
this.customerName = customerName;
}
public String getCustomerName() {
return customerName;
}
}
class Sender {
private String sendName;
private String sendPro;
private String sendCity;
private String sendDistrict;
private String sendAddress;
private String sendPhone;
private String sendMobile;
public void setSendName(String sendName) {
this.sendName = sendName;
}
public String getSendName() {
return sendName;
}
public void setSendPro(String sendPro) {
this.sendPro = sendPro;
}
public String getSendPro() {
return sendPro;
}
public void setSendCity(String sendCity) {
this.sendCity = sendCity;
}
public String getSendCity() {
return sendCity;
}
public void setSendDistrict(String sendDistrict) {
this.sendDistrict = sendDistrict;
}
public String getSendDistrict() {
return sendDistrict;
}
public void setSendAddress(String sendAddress) {
this.sendAddress = sendAddress;
}
public String getSendAddress() {
return sendAddress;
}
public void setSendPhone(String sendPhone) {
this.sendPhone = sendPhone;
}
public String getSendPhone() {
return sendPhone;
}
public void setSendMobile(String sendMobile) {
this.sendMobile = sendMobile;
}
public String getSendMobile() {
return sendMobile;
}
}
class Receiver {
private String receiveName;
private String receivePro;
private String receiveCity;
private String receiveDistrict;
private String receiveAddress;
private String receivePhone;
private String receiveMobile;
public void setReceiveName(String receiveName) {
this.receiveName = receiveName;
}
public String getReceiveName() {
return receiveName;
}
public void setReceivePro(String receivePro) {
this.receivePro = receivePro;
}
public String getReceivePro() {
return receivePro;
}
public void setReceiveCity(String receiveCity) {
this.receiveCity = receiveCity;
}
public String getReceiveCity() {
return receiveCity;
}
public void setReceiveDistrict(String receiveDistrict) {
this.receiveDistrict = receiveDistrict;
}
public String getReceiveDistrict() {
return receiveDistrict;
}
public void setReceiveAddress(String receiveAddress) {
this.receiveAddress = receiveAddress;
}
public String getReceiveAddress() {
return receiveAddress;
}
public void setReceivePhone(String receivePhone) {
this.receivePhone = receivePhone;
}
public String getReceivePhone() {
return receivePhone;
}
public void setReceiveMobile(String receiveMobile) {
this.receiveMobile = receiveMobile;
}
public String getReceiveMobile() {
return receiveMobile;
}
}
class ReturnRoot {
private String resourceCode;
private String success;
private String reason;
private String orderNo;
private String mailNo;
private String consigneeBranchCode;
private String packageCenterCode;
private String packageCenterName;
private String firstCode;
private String secondCode;
private String thirdCode;
public void setResourceCode(String resourceCode) {
this.resourceCode = resourceCode;
}
public String getResourceCode() {
return resourceCode;
}
public void setSuccess(String success) {
this.success = success;
}
public String getSuccess() {
return success;
}
public void setReason(String reason) {
this.reason = reason;
}
public String getReason() {
return reason;
}
public void setOrderNo(String orderNo) {
this.orderNo = orderNo;
}
public String getOrderNo() {
return orderNo;
}
public void setMailNo(String mailNo) {
this.mailNo = mailNo;
}
public String getMailNo() {
return mailNo;
}
public void setConsigneeBranchCode(String consigneeBranchCode) {
this.consigneeBranchCode = consigneeBranchCode;
}
public String getConsigneeBranchCode() {
return consigneeBranchCode;
}
public void setPackageCenterCode(String packageCenterCode) {
this.packageCenterCode = packageCenterCode;
}
public String getPackageCenterCode() {
return packageCenterCode;
}
public void setPackageCenterName(String packageCenterName) {
this.packageCenterName = packageCenterName;
}
public String getPackageCenterName() {
return packageCenterName;
}
public void setFirstCode(String firstCode) {
this.firstCode = firstCode;
}
public String getFirstCode() {
return firstCode;
}
public void setSecondCode(String secondCode) {
this.secondCode = secondCode;
}
public String getSecondCode() {
return secondCode;
}
public void setThirdCode(String thirdCode) {
this.thirdCode = thirdCode;
}
public String getThirdCode() {
return thirdCode;
}
}
//-------訂單相關實體類-----------------------------------------------------------------------------------------
//-------狀態軌跡相關實體類-----------------------------------------------------------------------------------------
class StatusRoot {
private String sourceNumber;
private String companyCode;
private String companyName;
private String orderNumber;
private String businessType;
private List<Traces> traces;
public void setSourceNumber(String sourceNumber) {
this.sourceNumber = sourceNumber;
}
public String getSourceNumber() {
return sourceNumber;
}
public void setCompanyCode(String companyCode) {
this.companyCode = companyCode;
}
public String getCompanyCode() {
return companyCode;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
public String getCompanyName() {
return companyName;
}
public void setOrderNumber(String orderNumber) {
this.orderNumber = orderNumber;
}
public String getOrderNumber() {
return orderNumber;
}
public void setBusinessType(String businessType) {
this.businessType = businessType;
}
public String getBusinessType() {
return businessType;
}
public void setTraces(List<Traces> traces) {
this.traces = traces;
}
public List<Traces> getTraces() {
return traces;
}
}
class Traces {
private String countryCode;
private String timeZone;
private Date operatingTime;
private String statusDesc;
private String action;
private String state;
private String city;
private String district;
private String street;
private String pointType;
private String pointNumber;
private String pointName;
private String pointContact;
private String nextStation;
private String nextType;
private String nextCode;
private String nextName;
private String operator;
private String operatorContact;
private String receiver;
private String exceptDesc;
private String remark;
public void setCountryCode(String countryCode) {
this.countryCode = countryCode;
}
public String getCountryCode() {
return countryCode;
}
public void setTimeZone(String timeZone) {
this.timeZone = timeZone;
}
public String getTimeZone() {
return timeZone;
}
public void setOperatingTime(Date operatingTime) {
this.operatingTime = operatingTime;
}
public Date getOperatingTime() {
return operatingTime;
}
public void setStatusDesc(String statusDesc) {
this.statusDesc = statusDesc;
}
public String getStatusDesc() {
return statusDesc;
}
public void setAction(String action) {
this.action = action;
}
public String getAction() {
return action;
}
public void setState(String state) {
this.state = state;
}
public String getState() {
return state;
}
public void setCity(String city) {
this.city = city;
}
public String getCity() {
return city;
}
public void setDistrict(String district) {
this.district = district;
}
public String getDistrict() {
return district;
}
public void setStreet(String street) {
this.street = street;
}
public String getStreet() {
return street;
}
public void setPointType(String pointType) {
this.pointType = pointType;
}
public String getPointType() {
return pointType;
}
public void setPointNumber(String pointNumber) {
this.pointNumber = pointNumber;
}
public String getPointNumber() {
return pointNumber;
}
public void setPointName(String pointName) {
this.pointName = pointName;
}
public String getPointName() {
return pointName;
}
public void setPointContact(String pointContact) {
this.pointContact = pointContact;
}
public String getPointContact() {
return pointContact;
}
public void setNextStation(String nextStation) {
this.nextStation = nextStation;
}
public String getNextStation() {
return nextStation;
}
public void setNextType(String nextType) {
this.nextType = nextType;
}
public String getNextType() {
return nextType;
}
public void setNextCode(String nextCode) {
this.nextCode = nextCode;
}
public String getNextCode() {
return nextCode;
}
public void setNextName(String nextName) {
this.nextName = nextName;
}
public String getNextName() {
return nextName;
}
public void setOperator(String operator) {
this.operator = operator;
}
public String getOperator() {
return operator;
}
public void setOperatorContact(String operatorContact) {
this.operatorContact = operatorContact;
}
public String getOperatorContact() {
return operatorContact;
}
public void setReceiver(String receiver) {
this.receiver = receiver;
}
public String getReceiver() {
return receiver;
}
public void setExceptDesc(String exceptDesc) {
this.exceptDesc = exceptDesc;
}
public String getExceptDesc() {
return exceptDesc;
}
public void setRemark(String remark) {
this.remark = remark;
}
public String getRemark() {
return remark;
}
}
class ReturnStatus {
private int state;
private String reason;
public void setState(int state) {
this.state = state;
}
public int getState() {
return state;
}
public void setReason(String reason) {
this.reason = reason;
}
public String getReason() {
return reason;
}
}
//-------狀態軌跡相關實體類-----------------------------------------------------------------------------------------
}
http請求json標準樣例
訂單
"resourceTypeName": "快速遞",
"accountInfo": {
"siteCode": "A001",
"customerName": "555111"
},
"sourceCode": "801",
"orderType ": "00",
"resourceCode": "JD",
"orderNo": "ZJS861520269945",
"mailNo": "JDVB07604780549",
"goodsName": "服裝",
"goodsNum": "999",
"goodsWeight": "50000",
"goodsVolume": null,
"remarks": null,
"goodsValue": "0",
"codFlag": "否",
"codAmount": "0",
"extendedInfo": null,
"sender": {
"sendName": "PQ 金月",
"sendPro": "北京市",
"sendCity": "北京市",
"sendDistrict": "朝陽區",
"sendAddress": "北京市朝陽區三里屯",
"sendPhone": null,
"sendMobile": "325038"
},
"receiver": {
"receiveName": null,
"receivePro": "北京市",
"receiveCity": "北京市",
"receiveDistrict": "東城區",
"receiveAddress": null,
"receivePhone": null,
"receiveMobile": "0000000"
}
}
返回樣例
{
"resourceCode": "123",
"success": "true",
"reason": "請求成功",
"orderNo": "ZJS861706963526",
"mailNo": "JDVB07604780549",
"consigneeBranchCode": "B07",
"packageCenterCode": "HB01",
"packageCenterName": "華北運轉中心",
"firstCode": "010",
"secondCode": "BB07",
"thirdCode": "1001"
}
狀態
"sourceNumber": "123456789",
"companyCode": "ems",
"companyName": "郵政",
"orderNumber": "ZJS111887059675",
"businessType": "2",
"traces": [
{
"countryCode": "CN",
"timeZone": "8",
"operatingTime": "2019-01-01 00:00:00",
"statusDesc": "",
"action": "T_ARRIVAL",
"state": "浙江省",
"city": "杭州市",
"district": "西湖區",
"street": "五常街道",
"pointType": "2",
"pointNumber": "123",
"pointName": "XX 分撥站",
"pointContact": "",
"nextStation": "上海市",
"nextType": "2",
"nextCode": "456",
"nextName": "XX 分撥站",
"operator": "王 XX",
"operatorContact": "",
"receiver": "王 XX",
"exceptDesc": "",
"remark": ""
}
]
}
返回
{"state":0,"reason":""}
查詢
"orderorwillnum": "LS1000000200022"
}
返回
[
{
"countryCode": "CN",
"timeZone": "8",
"operatingTime": "2021-02-27T19:27:03",
"statusDesc": "",
"action": "T_ARRIVAL",
"state": "浙江省",
"city": "杭州市",
"district": "西湖區",
"street": "五常街道",
"pointType": "2",
"pointNumber": "123",
"pointName": "XX 分撥站",
"pointContact": "",
"nextStation": "上海市",
"nextType": "2",
"nextCode": "456",
"nextName": "XX 分撥站",
"operator": "王 XX",
"operatorContact": "",
"receiver": "王 XX",
"exceptDesc": "",
"remark": ""
},
{
"countryCode": "CN",
"timeZone": "8",
"operatingTime": "2021-03-14T15:19:02",
"statusDesc": "",
"action": "T_ARRIVAL",
"state": "浙江省",
"city": "杭州市",
"district": "西湖區",
"street": "五常街道",
"pointType": "2",
"pointNumber": "123",
"pointName": "XX 分撥站",
"pointContact": "",
"nextStation": "上海市",
"nextType": "2",
"nextCode": "456",
"nextName": "XX 分撥站",
"operator": "王 XX",
"operatorContact": "",
"receiver": "王 XX",
"exceptDesc": "",
"remark": ""
},
{
"countryCode": "CN",
"timeZone": "8",
"operatingTime": "2021-03-15T17:26:54",
"statusDesc": "",
"action": "T_ARRIVAL",
"state": "浙江省",
"city": "杭州市",
"district": "西湖區",
"street": "五常街道",
"pointType": "2",
"pointNumber": "123",
"pointName": "XX 分撥站",
"pointContact": "",
"nextStation": "上海市",
"nextType": "2",
"nextCode": "456",
"nextName": "XX 分撥站",
"operator": "王 XX",
"operatorContact": "",
"receiver": "王 XX",
"exceptDesc": "",
"remark": ""
},
{
"countryCode": "CN",
"timeZone": "8",
"operatingTime": "2021-03-16T03:21:46",
"statusDesc": "",
"action": "T_ARRIVAL",
"state": "浙江省",
"city": "杭州市",
"district": "西湖區",
"street": "五常街道",
"pointType": "2",
"pointNumber": "123",
"pointName": "XX 分撥站",
"pointContact": "",
"nextStation": "上海市",
"nextType": "2",
"nextCode": "456",
"nextName": "XX 分撥站",
"operator": "王 XX",
"operatorContact": "",
"receiver": "王 XX",
"exceptDesc": "",
"remark": ""
},
{
"countryCode": "CN",
"timeZone": "8",
"operatingTime": "2021-03-21T15:08:52",
"statusDesc": "",
"action": "T_ARRIVAL",
"state": "浙江省",
"city": "杭州市",
"district": "西湖區",
"street": "五常街道",
"pointType": "2",
"pointNumber": "123",
"pointName": "XX 分撥站",
"pointContact": "",
"nextStation": "上海市",
"nextType": "2",
"nextCode": "456",
"nextName": "XX 分撥站",
"operator": "王 XX",
"operatorContact": "",
"receiver": "王 XX",
"exceptDesc": "",
"remark": ""
},
{
"countryCode": "CN",
"timeZone": "8",
"operatingTime": "2021-03-26T18:02:58",
"statusDesc": "",
"action": "T_ARRIVAL",
"state": "浙江省",
"city": "杭州市",
"district": "西湖區",
"street": "五常街道",
"pointType": "2",
"pointNumber": "123",
"pointName": "XX 分撥站",
"pointContact": "",
"nextStation": "上海市",
"nextType": "2",
"nextCode": "456",
"nextName": "XX 分撥站",
"operator": "王 XX",
"operatorContact": "",
"receiver": "王 XX",
"exceptDesc": "",
"remark": ""
},
{
"countryCode": "CN",
"timeZone": "8",
"operatingTime": "2021-04-03T20:25:52",
"statusDesc": "",
"action": "T_ARRIVAL",
"state": "浙江省",
"city": "杭州市",
"district": "西湖區",
"street": "五常街道",
"pointType": "2",
"pointNumber": "123",
"pointName": "XX 分撥站",
"pointContact": "",
"nextStation": "上海市",
"nextType": "2",
"nextCode": "456",
"nextName": "XX 分撥站",
"operator": "王 XX",
"operatorContact": "",
"receiver": "王 XX",
"exceptDesc": "",
"remark": ""
},
{
"countryCode": "CN",
"timeZone": "8",
"operatingTime": "2021-04-08T11:49:44",
"statusDesc": "",
"action": "T_ARRIVAL",
"state": "浙江省",
"city": "杭州市",
"district": "西湖區",
"street": "五常街道",
"pointType": "2",
"pointNumber": "123",
"pointName": "XX 分撥站",
"pointContact": "",
"nextStation": "上海市",
"nextType": "2",
"nextCode": "456",
"nextName": "XX 分撥站",
"operator": "王 XX",
"operatorContact": "",
"receiver": "王 XX",
"exceptDesc": "",
"remark": ""
}
]
七、獎品
價值1000+RMB的 三星 (SAMSUNG) 27英寸 1800R曲面 FHD高清 愛眼 窄邊框 FreeSync 可壁掛遊戲電腦顯示器
希望牛逼的你快來拿下他
同款鏈接 https://item.jd.com/100003374425.html
就是下面我用的這款,有興趣可以來看看