Java生鮮電商平臺-售後模塊的設計與架構數據庫
說明:任何一個的電商平臺都有售後服務系統,那麼對於咱們這個生鮮的電商平臺,售後系統須要思考如下幾個維度。微信
1. 買家的需求維度架構
說明:買家在平臺上沒找到本身想要的東西,咱們須要提供給他一個入口,告訴咱們他有這個需求,咱們進行改進。系統須要有記錄這種狀況,同時也有回覆客戶的狀況。app
2. 投訴入口設計
說明:有客戶性子比較急,他有問題,就會立刻打電話給客服,客服須要解答與回答,維護客戶關係。對於系統而言,須要記錄這種狀況,而後分析問題與解決問題。日誌
3. IM聊天入口code
說明:客戶有時候也不想寫信息,也不想打電話,可否有一個時刻的IM聊天記錄呢?對於系統而言須要記錄這種信息,咱們目前系統沒處理,採用的是微信,以及銷售人員的反饋機制。blog
4. 退貨問題圖片
說明:售後系統中,退貨問題是最繁瑣的,買家存在如下兩種狀況。rem
4.1 買家要錢不要貨。顧名思義,有些買家就是不要貨了,他須要咱們退錢給他,這個配送端有一個一件退貨功能,錢退到買家的餘額裏面,下次能夠繼續購買。
4.2 買家要貨不要錢,顧名思義,有些買家的確須要這個貨物,對於咱們退錢給他,他是不接受的,由於他真的須要這種東西,你讓他再去買,客戶體驗很是差,可能 就沒有下次購物了。對於這種狀況,咱們用時間軸來繼續整個過程。(說明,因爲這個系統設計到生鮮電商方面,其餘的電商方面可能會不同。)
相關數據庫的設計與架構以下:
1. 買家平臺建議信息表
CREATE TABLE `suggestion` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自動增長ID', `suggestion_content` varchar(1024) DEFAULT NULL COMMENT '建議內容', `suggestion_imgs` varchar(255) DEFAULT NULL COMMENT '多張圖片', `user_id` bigint(20) DEFAULT NULL COMMENT '所屬用戶ID', `create_time` datetime DEFAULT NULL COMMENT '建立時間', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=78 DEFAULT CHARSET=utf8 COMMENT='用戶對平臺的建議';
說明: 平臺建議表,是買家對平臺的建議以及本身的需求的一個入口,能夠是圖片與內容兩點。
好比說:他說咱們送的菜有問題,不少爛的,那麼他是須要拍圖片證實的。
2. 平臺回覆信息表
CREATE TABLE `suggestion_reply` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自動增長ID', `suggestion_id` bigint(20) DEFAULT NULL COMMENT '客戶的建議ID', `content` varchar(512) DEFAULT NULL COMMENT '回覆的內容', `create_time` datetime DEFAULT NULL COMMENT '建立時間', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8 COMMENT='客戶建議回覆信息表';
說明:做爲一個平臺,平臺須要回覆客戶的信息,買家也須要看到,固然這邊系統是不區分是買家仍是賣家的,咱們都是能夠數據的處理的。
3. 售後系統時間軸的設計
說明:其實咱們系統須要知道整個售後的過程的,好比買家何時發起的不要錢,要貨,而後師傅是何時知道這個消息的,如何進行售後的,他們會遇到什麼問題,
固然這裏面有不少的問題,系統能夠作的事情實際上是不多的,而咱們須要作的是更多的事情。
CREATE TABLE `order_timeline` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自動增長ID', `item_id` bigint(20) DEFAULT NULL COMMENT '訂單項ID', `remarks` varchar(256) DEFAULT NULL COMMENT '備註', `create_time` datetime DEFAULT NULL COMMENT '建立時間', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1980 DEFAULT CHARSET=utf8 COMMENT='售後模塊,退換貨時間軸,針對的是某一個訂單項';
相關時間軸運營截圖以下:
整個業務不算複雜,須要的一種思路與解決思路的方案:
關於補貨流程:
補貨需求 業務需求: 當賣家主動點擊缺貨,則配送師傅看到這個異常訂單項,而後他有兩種選擇, 第一種補貨(有貨,他也想補或者客戶說要貨不要錢) 第二種不補貨(無貨可補,他不想補或者客戶說退錢等等) 第一種補貨業務: 1. 當配送師傅點擊已補貨,則把這個訂單項對應的金額從買家中直接扣除,前提是線上付款,若是這個訂單是線下付款,則不用處理扣款邏輯,直接修改狀態便可。同時記錄時間軸日誌。 第二種不補貨業務: 2. 當師傅點擊不補貨,則這個訂單項不作任何扣款邏輯,無論線下仍是線上,直接修改狀態便可,同時記錄時間軸日誌。 補充說明:補貨與不補貨屬於互斥操做,即已補貨後不容許再出現不補貨,不補貨後再也不容許出現補貨。按照規則來處理。
相關業務核心代碼以下:
/** * 訂單項退貨*/ @RestController @RequestMapping("/delivery") public class OrderReturnController extends BaseController { private static final Logger logger = LoggerFactory.getLogger(OrderReturnController.class); @Autowired private OrderItemService orderItemService; @Autowired private OrderReturnService orderReturnService; /** * 訂單項退貨 * */ @RequestMapping(value = "/order/return/item", method = { RequestMethod.GET, RequestMethod.POST }) public JsonResult orderReturnItem(HttpServletRequest request, HttpServletResponse response, @Param("itemId") Long itemId, @Param("deliveryId") Long deliveryId, @Param("status") int status) { try { if (itemId == null) { return new JsonResult(JsonResultCode.FAILURE, "item參數有誤", ""); } OrderItem orderItem = orderItemService.getOrderItemByItemId(itemId); if (orderItem == null) { return new JsonResult(JsonResultCode.FAILURE, "無此訂單項", ""); } String returnMsg = ""; if(status == BuyerStatus.THREE){ returnMsg = TimelineTemplate.return_MSG; }if(status == BuyerStatus.FOUR){ returnMsg = TimelineTemplate.BACK_MSG; }if(status == BuyerStatus.ZERO){ returnMsg = TimelineTemplate.OFF_MSG; } orderItemService.updateOrderItemStatus(itemId, status, deliveryId, returnMsg); return new JsonResult(JsonResultCode.SUCCESS, "操做成功", ""); } catch (Exception ex) { logger.error("[OrderReturnController][orderReturnItem] exception :", ex); return new JsonResult(JsonResultCode.FAILURE, "系統錯誤,請稍後重試", ""); } } /** * 退還列表 */ @RequestMapping(value = "/order/return/list", method = { RequestMethod.GET, RequestMethod.POST }) public JsonResult orderReturnList(HttpServletRequest request, HttpServletResponse response,@Param("deliveryId") Long deliveryId, @Param("status") int status) { try { // 組裝成爲最終的列表結果 List<OrderReturnVo> listResult = new ArrayList<OrderReturnVo>(); List<OrderGoodsVo> goodsList = orderReturnService.getReturnOrderGoodsList(deliveryId,status); if (CollectionUtils.isEmpty(goodsList)) { return new JsonResult(JsonResultCode.SUCCESS, "查詢完成", listResult); } // 臨時參數,判斷時間 Map<String, List<OrderReturnEntity>> paramTimeMap = new HashMap<String, List<OrderReturnEntity>>(); // 過濾賣家 Map<String, List<OrderGoodsVo>> paramSellerMap = new HashMap<String, List<OrderGoodsVo>>(); for (OrderGoodsVo vo : goodsList) { String bestTime = DateUtil.dateToString(vo.getBestTime(), "yyyy-MM-dd"); // 時間相同 if (paramTimeMap.get(bestTime) != null) { List<OrderReturnEntity> mapOrderReturnEntity = paramTimeMap.get(bestTime); // 組裝時間 OrderReturnVo resultVo = new OrderReturnVo(); resultVo.setBestTime(bestTime); // 判斷是不是同一個賣家的 if (paramSellerMap.get(vo.getSellerName()) != null) { OrderReturnEntity entity = new OrderReturnEntity(); List<OrderGoodsVo> listVo = paramSellerMap.get(vo.getSellerName()); listVo.add(vo); entity.setListOrderGoodsVo(listVo); resultVo.setListOrderReturnEntity(mapOrderReturnEntity); }else { //不一樣買家 OrderReturnEntity entity = new OrderReturnEntity(); entity.setSellerName(vo.getSellerName()); List<OrderGoodsVo> listVo =new ArrayList<OrderGoodsVo>(); listVo.add(vo); entity.setListOrderGoodsVo(listVo); mapOrderReturnEntity.add(entity); paramSellerMap.put(vo.getSellerName(), listVo); } } else { // 組裝時間 OrderReturnVo resultVo = new OrderReturnVo(); resultVo.setBestTime(bestTime); OrderReturnEntity entity = new OrderReturnEntity(); entity.setSellerName(vo.getSellerName()); List<OrderGoodsVo> paramOrderGoodsVo = new ArrayList<OrderGoodsVo>(); paramOrderGoodsVo.add(vo); entity.setListOrderGoodsVo(paramOrderGoodsVo); List<OrderReturnEntity> listOrderReturnEntity = new ArrayList<OrderReturnEntity>(); listOrderReturnEntity.add(entity); resultVo.setListOrderReturnEntity(listOrderReturnEntity); listResult.add(resultVo); paramSellerMap.put(vo.getSellerName(), paramOrderGoodsVo); paramTimeMap.put(bestTime, listOrderReturnEntity); } } return new JsonResult(JsonResultCode.SUCCESS, "查詢信息成功", listResult); } catch (Exception ex) { logger.error("[OrderReturnController][orderReturnItem] exception :", ex); return new JsonResult(JsonResultCode.FAILURE, "系統錯誤,請稍後重試", ""); } }
APP運營截圖相對而言比較簡單,我這邊就不貼出來了。