後端
views
將 isDelivered
更新為 True 的同時,也要取得現在時間,更新 deliveredAt
欄位
1 2 3 4 5 6 7 8 9 10 11 12 13
|
@api_view(['PUT']) @permission_classes([IsAdminUser]) def updateOrderToDelivered(request, pk): order = Order.objects.get(id=pk) order.isDelivered = True timezone_taipei = pytz.timezone('Asia/Taipei') now = timezone.now().astimezone(timezone_taipei) order.deliveredAt = now order.save() return Response('訂單狀態已更新為:已運送')
|
urls
1 2
| path('<str:pk>/delivered/', views.updateOrderToDelivered, name='order-delivered'),
|
Postman 測試
老套路,後端寫好 API 後,先用 Postman 測試看是否有成功回傳資料,一樣帶入擁有 admin 權限的 token
來檢視所有訂單資料

前端
constants 定義常數
1 2 3 4 5
| export const ORDER_DELIVER_REQUEST = "ORDER_DELIVER_REQUEST"; export const ORDER_DELIVER_SUCCESS = "ORDER_DELIVER_SUCCESS"; export const ORDER_DELIVER_FAIL = "ORDER_DELIVER_FAIL"; export const ORDER_DELIVER_RESET = "ORDER_DELIVER_RESET";
|
reducers
此 orderDeliverReducer
跟 orderPayReducer
類似,都是更新訂單狀態的 reducer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
export const orderDeliverReducer = (state = {}, action) => { switch (action.type) { case ORDER_DELIVER_REQUEST: return { loading: true };
case ORDER_DELIVER_SUCCESS: return { loading: false, success: true };
case ORDER_DELIVER_FAIL: return { loading: false, error: action.payload };
default: return state; } };
|
好習慣,在 store
註冊完此 reducer
後,都要去前台查看 Redux DevTools
檢查是否有成功註冊
actions
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
|
export const deliverOrder = (order) => async (dispatch, getState) => { try { dispatch({ type: ORDER_DELIVER_REQUEST, });
const { userLogin: { userInfo }, } = getState();
const config = { headers: { "Content-type": "application/json", Authorization: `Bearer ${userInfo.token}`, }, };
const { data } = await axios.put(`/api/orders/${order.id}/delivered/`, {}, config);
dispatch({ type: ORDER_DELIVER_SUCCESS, payload: data, }); } catch (error) { dispatch({ type: ORDER_DELIVER_FAIL, payload: error.response && error.response.data.detail ? error.response.data.detail : error.message, }); } };
|
回到訂單明細前端頁面
更新運送狀態按鈕規劃放在訂單明細頁面,所以回到 OrderPage.js
,加入觸發 deliverHandler
事件的按鈕
- 當按下按鈕時,就在
usEffect
中重置 orderDeliver
的狀態
- 要判斷只有
Admin
、且訂單狀態為 已付款
、未運送
才顯示此按鈕
- 為此按鈕添加
loading
狀態
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| const orderDeliver = useSelector((state) => state.orderDeliver); const { loading: loadingDeliver, success: successDeliver } = orderDeliver;
const { userInfo } = useSelector((state) => state.userLogin); ... useEffect(() => { if (!order || successPay || order.id !== Number(orderId) || successDeliver) { dispatch({ type: ORDER_PAY_RESET }); dispatch({ type: ORDER_DELIVER_RESET });
dispatch(getOrderDetails(orderId)); } else if (!order.isPaid) { setSdkReady(true); } }, [dispatch, navigate, order, orderId, successPay, successDeliver]);
... const deliverOrderHandler = () => { dispatch(deliverOrder(order)); };
return ( <> ... {/* 更新訂單運送狀態 按鈕 */} {loadingDeliver && <Loader />} {userInfo && userInfo.isAdmin && order.isPaid && !order.isDelivered && ( <ListGroup.Item> <Button type='button' className='btn btn-block' onClick={deliverOrderHandler}> 更新狀態為已送達 </Button> </ListGroup.Item> )} ); </>
|
最後一樣至 App.js
加入路由並用 <AdminRoute>
包裹以限制非管理員無法進入此頁面
最後成品畫面如下:

解決無法訪問其他用戶問題
解決非用戶本人,連管理員也沒有權限訪問特定訂單的問題,比如說有另一個用戶的訂單,當初設計時,只有用戶本人可以查看自己的訂單,此邏輯是無誤的

但現在導致管理員也無法查看特定用戶的訂單,就有點不合理,所以這邊回到 order_views.py
,在 if order.user == user:
的判斷中加入 or user.is_staff:
的判斷,管理員就能成功查看所有用戶的訂單了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
@api_view(['GET']) @permission_classes([IsAuthenticated]) def getOrderById(request, pk): user = request.user try: order = Order.objects.get(id=pk) if order.user == user or user.is_staff: serializer = OrderSerializer(order, many=False) return Response(serializer.data) else: return Response({'detail':'你沒有權限查看此訂單'},status=status.HTTP_400_BAD_REQUEST) except: return Response({'detail':'訂單不存在'},status=status.HTTP_400_BAD_REQUEST)
|
若您覺得這篇文章對您有幫助,歡迎分享出去讓更多人看到⊂◉‿◉つ~
留言版