Merge branch 'master' into owner_dashboard
This commit is contained in:
@@ -26,6 +26,8 @@ export default {
|
||||
},
|
||||
deleteOrderItem(orderItemId){
|
||||
return axios.delete(process.env.VUE_APP_ORDER_API_URL + "/orderItem/"+orderItemId);
|
||||
},
|
||||
getOrderDetail(orderId) {
|
||||
return axios.get(process.env.VUE_APP_CUSTOMER_SERVICE_BASEURL + "/order-service/api/order-detail/" + orderId);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
</div>
|
||||
</v-list-item-title>
|
||||
<v-list-item-subtitle class="mb-5">
|
||||
{{ card.orderStatus }}
|
||||
{{ card.orderStatus | getOrderStatusName }}
|
||||
</v-list-item-subtitle>
|
||||
<div class="text-body-1 mb-5">
|
||||
{{ card.orderItemNames }}
|
||||
@@ -50,6 +50,7 @@ export default {
|
||||
name: "OrderHistoryCard",
|
||||
props: {
|
||||
card: {
|
||||
orderId: String,
|
||||
storeId: Number,
|
||||
storeName: String,
|
||||
orderTime: String,
|
||||
@@ -66,7 +67,10 @@ export default {
|
||||
})
|
||||
},
|
||||
clickDetail: function() {
|
||||
alert("준비 중입니다.");
|
||||
this.$router.push({
|
||||
name: "order-detail",
|
||||
params: {orderId: this.card.orderId}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,10 +19,29 @@ axios.interceptors.request.use(function (config) {
|
||||
config.headers.Authorization = "Bearer " + jwt.getToken();
|
||||
return config;
|
||||
});
|
||||
|
||||
Vue.filter('currency', function (value) {
|
||||
var num = new Number(value);
|
||||
return num.toFixed(0).replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g, "$1,")
|
||||
});
|
||||
Vue.filter('getOrderStatusName', function (orderStatus) {
|
||||
switch (orderStatus) {
|
||||
case "PLACED":
|
||||
return "주문신청";
|
||||
case "ACCEPTED":
|
||||
return "주문수락";
|
||||
case "REJECTED":
|
||||
return "주문거절";
|
||||
case "WAITING":
|
||||
return "픽업대기";
|
||||
case "FINISHED":
|
||||
return "픽업완료";
|
||||
case "FAILED":
|
||||
return "주문실패";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
axios.interceptors.response.use(
|
||||
(response) => {
|
||||
@@ -43,6 +62,8 @@ axios.interceptors.response.use(
|
||||
alert("권한이 없습니다. 다시 로그인 해주세요");
|
||||
return Promise.reject(error2);
|
||||
}
|
||||
} else {
|
||||
if (error.response.data.message) alert(error.response.data.message);
|
||||
}
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
@@ -82,6 +82,13 @@ const routes = [
|
||||
name: 'mypage',
|
||||
component: () => import('../views/MyPage')
|
||||
},
|
||||
{
|
||||
path: "/order-detail/:orderId",
|
||||
beforeEnter: authCheck,
|
||||
name: 'order-detail',
|
||||
props: true,
|
||||
component: () => import('../views/OrderDetail')
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
137
customer-vue/src/views/OrderDetail.vue
Normal file
137
customer-vue/src/views/OrderDetail.vue
Normal file
@@ -0,0 +1,137 @@
|
||||
<template>
|
||||
<div>
|
||||
<v-list-item three-line>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title class="text-h5 mb-3">
|
||||
{{ orderInfo.storeName }}
|
||||
<div class="grey--text caption">
|
||||
</div>
|
||||
</v-list-item-title>
|
||||
<v-list-item-subtitle class="mb-5">
|
||||
{{ orderInfo.orderStatus | getOrderStatusName }}
|
||||
</v-list-item-subtitle>
|
||||
<div class="text-body-1 mb-5">
|
||||
주문번호: {{ orderInfo.id }}
|
||||
</div>
|
||||
<div class="text--primary">
|
||||
주문일시: {{ orderInfo.orderTime }}
|
||||
</div>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-divider class="my-4"></v-divider>
|
||||
|
||||
<v-list-item two-line
|
||||
v-for="order in orderItems" :key="order.id"
|
||||
>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title class="mb-2">
|
||||
{{order.name}} {{order.count}}개
|
||||
</v-list-item-title>
|
||||
<v-list-item-subtitle v-if="order.options.length > 0">
|
||||
ㄴ {{order.options}}
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
<v-list-item-action>
|
||||
<v-list-item-action-text class="text-body-1">
|
||||
{{order.totalPrice | currency}}원
|
||||
</v-list-item-action-text>
|
||||
</v-list-item-action>
|
||||
</v-list-item>
|
||||
|
||||
<v-divider class="my-4"></v-divider>
|
||||
|
||||
<v-simple-table class="no-border-table">
|
||||
<template v-slot:default>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><span class="orange--text"><b>합계</b></span></td>
|
||||
<td class="text-right">{{orderInfo.orderPrice | currency}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>포인트사용</td>
|
||||
<td class="text-right">0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>쿠폰 할인</td>
|
||||
<td class="text-right">0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class="orange--text"><b>결제금액</b></span></td>
|
||||
<td class="text-right"><b>{{orderInfo.orderPrice | currency}}</b></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</template>
|
||||
</v-simple-table>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import orderApi from "../api/order";
|
||||
|
||||
export default {
|
||||
name: "OrderDetail",
|
||||
props: ["orderId"],
|
||||
data: function() {
|
||||
return {
|
||||
user: {},
|
||||
orderInfo: {},
|
||||
orderItems: []
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.search();
|
||||
},
|
||||
methods: {
|
||||
search: async function() {
|
||||
const response = await orderApi.getOrderDetail(this.orderId);
|
||||
this.render(response.data);
|
||||
},
|
||||
render: function(json) {
|
||||
const orderDetail = json.data;
|
||||
|
||||
const orderUser = orderDetail.user;
|
||||
this.user = {
|
||||
id: orderUser.id,
|
||||
name: orderUser.name,
|
||||
phoneNumber: orderUser.phoneNumber
|
||||
};
|
||||
|
||||
this.orderInfo = {
|
||||
id: orderDetail.id,
|
||||
orderTime: orderDetail.orderTime,
|
||||
orderPrice: orderDetail.orderPrice,
|
||||
orderStatus: orderDetail.orderStatus,
|
||||
storeName: orderDetail.storeName
|
||||
};
|
||||
|
||||
const orderItems = orderDetail.orderItems;
|
||||
orderItems.forEach(orderItem => {
|
||||
|
||||
let orderItemOptions = []
|
||||
orderItem.options.forEach(option => {
|
||||
const optionTypeName = option.optionType == "REQUIRED" ? "필수" : "기타";
|
||||
orderItemOptions.push(option.name + "(" + optionTypeName + ")");
|
||||
});
|
||||
|
||||
this.orderItems.push({
|
||||
id: orderItem.id,
|
||||
itemId: orderItem.itemId,
|
||||
totalPrice: orderItem.totalPrice,
|
||||
count: orderItem.count,
|
||||
name: orderItem.name,
|
||||
options: orderItemOptions.join(",")
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.no-border-table tbody tr td {
|
||||
border-bottom: none !important;
|
||||
}
|
||||
</style>
|
||||
@@ -51,14 +51,10 @@ export default {
|
||||
methods: {
|
||||
search: async function() {
|
||||
this.isLoading = true;
|
||||
try {
|
||||
this.page = 0;
|
||||
const response = await orderApi.requestOrderHistory(this.page);
|
||||
this.cards = [];
|
||||
this.renderCard(response.data);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
this.page = 0;
|
||||
const response = await orderApi.requestOrderHistory(this.page);
|
||||
this.cards = [];
|
||||
this.renderCard(response.data);
|
||||
this.isLoading = false;
|
||||
},
|
||||
more: async function() {
|
||||
@@ -85,19 +81,11 @@ export default {
|
||||
storeId: order.storeId,
|
||||
storeName: order.storeName,
|
||||
orderPrice: order.orderPrice,
|
||||
orderStatus: this.getOrderStatusName(order.orderStatus),
|
||||
orderStatus: order.orderStatus,
|
||||
orderItemNames: this.getOrderItemName(order.orderItems)
|
||||
})
|
||||
});
|
||||
},
|
||||
getOrderStatusName(orderStatus) {
|
||||
if (orderStatus === "PLACED") return "주문신청";
|
||||
if (orderStatus === "REJECTED") return "주문거절";
|
||||
if (orderStatus === "ACCEPTED") return "주문수락";
|
||||
if (orderStatus === "WAITING") return "픽업대기";
|
||||
if (orderStatus === "FINISHED") return "픽업완료";
|
||||
return orderStatus;
|
||||
},
|
||||
getOrderItemName(orderItems) {
|
||||
const itemSize = orderItems.length;
|
||||
if (itemSize == 1) return orderItems[0].orderItemName;
|
||||
|
||||
@@ -67,6 +67,8 @@ domain-httpRequestCode-etc
|
||||
== 주문
|
||||
=== 주문 수정
|
||||
operation::order-patch[snippets='curl-request,http-request,http-response,path-parameters,request-fields,response-fields']
|
||||
=== 주문 상세보기
|
||||
operation::api-orderDetail[snippets='curl-request,http-request,http-response,path-parameters,response-fields']
|
||||
|
||||
== 점주 서비스
|
||||
=== 주문 페이지
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
package com.justpickup.orderservice.domain.order.dto;
|
||||
|
||||
import com.justpickup.orderservice.domain.order.entity.Order;
|
||||
import com.justpickup.orderservice.domain.order.entity.OrderStatus;
|
||||
import com.justpickup.orderservice.domain.orderItem.entity.OrderItem;
|
||||
import com.justpickup.orderservice.domain.orderItemOption.entity.OrderItemOption;
|
||||
import com.justpickup.orderservice.global.client.store.OptionType;
|
||||
import lombok.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Getter @NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||
public class OrderDetailDto {
|
||||
|
||||
private Long id;
|
||||
private LocalDateTime orderTime;
|
||||
private Long orderPrice;
|
||||
private OrderStatus orderStatus;
|
||||
private String storeName;
|
||||
private OrderDetailUser user;
|
||||
private List<OrderDetailItem> orderItems = new ArrayList<>();
|
||||
|
||||
@Builder
|
||||
public OrderDetailDto(Long id, LocalDateTime orderTime, Long orderPrice, OrderStatus orderStatus,
|
||||
String storeName, OrderDetailUser user, List<OrderDetailItem> orderItems) {
|
||||
this.id = id;
|
||||
this.orderTime = orderTime;
|
||||
this.orderPrice = orderPrice;
|
||||
this.orderStatus = orderStatus;
|
||||
this.storeName = storeName;
|
||||
this.user = user;
|
||||
this.orderItems = orderItems;
|
||||
}
|
||||
|
||||
public static OrderDetailDto of(Order order, String storeName,
|
||||
List<OrderDetailItem> orderItems, OrderDetailUser orderDetailUser) {
|
||||
OrderDetailDto orderDetailDto = new OrderDetailDto();
|
||||
orderDetailDto.id = order.getId();
|
||||
orderDetailDto.orderTime = order.getOrderTime();
|
||||
orderDetailDto.orderPrice = order.getOrderPrice();
|
||||
orderDetailDto.orderStatus = order.getOrderStatus();
|
||||
|
||||
orderDetailDto.storeName = storeName;
|
||||
|
||||
orderDetailDto.user = orderDetailUser;
|
||||
orderDetailDto.orderItems = orderItems;
|
||||
return orderDetailDto;
|
||||
}
|
||||
|
||||
@Getter @NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||
public static class OrderDetailUser {
|
||||
private Long id;
|
||||
private String name;
|
||||
private String phoneNumber;
|
||||
|
||||
@Builder
|
||||
public OrderDetailUser(Long id, String name, String phoneNumber) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.phoneNumber = phoneNumber;
|
||||
}
|
||||
}
|
||||
|
||||
@Getter @NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||
public static class OrderDetailItem {
|
||||
private Long id;
|
||||
private Long itemId;
|
||||
private long totalPrice;
|
||||
private long count;
|
||||
private String name;
|
||||
private List<OrderDetailItemOption> options = new ArrayList<>();
|
||||
|
||||
@Builder
|
||||
public OrderDetailItem(Long id, Long itemId, long totalPrice, long count, String name, List<OrderDetailItemOption> options) {
|
||||
this.id = id;
|
||||
this.itemId = itemId;
|
||||
this.totalPrice = totalPrice;
|
||||
this.count = count;
|
||||
this.name = name;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public static OrderDetailItem of(OrderItem orderItem, String name, List<OrderDetailItemOption> orderDetailItemOption) {
|
||||
OrderDetailItem orderDetailItem = new OrderDetailItem();
|
||||
orderDetailItem.id = orderItem.getId();
|
||||
orderDetailItem.itemId = orderItem.getItemId();
|
||||
orderDetailItem.totalPrice = orderItem.getTotalPrice();
|
||||
orderDetailItem.count = orderItem.getCount();
|
||||
orderDetailItem.name = name;
|
||||
orderDetailItem.options = orderDetailItemOption;
|
||||
return orderDetailItem;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Getter @NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||
public static class OrderDetailItemOption {
|
||||
private Long id;
|
||||
private Long itemOptionId;
|
||||
private String name;
|
||||
private OptionType optionType;
|
||||
|
||||
@Builder
|
||||
public OrderDetailItemOption(Long id, Long itemOptionId, String name, OptionType optionType) {
|
||||
this.id = id;
|
||||
this.itemOptionId = itemOptionId;
|
||||
this.name = name;
|
||||
this.optionType = optionType;
|
||||
}
|
||||
|
||||
public static OrderDetailItemOption of(OrderItemOption orderItemOption, String name, OptionType optionType) {
|
||||
OrderDetailItemOption orderDetailItemOption = new OrderDetailItemOption();
|
||||
orderDetailItemOption.id = orderItemOption.getId();
|
||||
orderDetailItemOption.itemOptionId = orderItemOption.getItemOptionId();
|
||||
orderDetailItemOption.name = name;
|
||||
orderDetailItemOption.optionType = optionType;
|
||||
return orderDetailItemOption;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,9 +112,4 @@ public class Order extends BaseEntity {
|
||||
public void fail() {
|
||||
this.orderStatus = OrderStatus.FAILED;
|
||||
}
|
||||
|
||||
|
||||
public void changeOrderDate(LocalDateTime orderTime){
|
||||
this.orderTime = orderTime;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,6 +80,7 @@ public class OrderRepositoryCustom {
|
||||
.leftJoin(order.transaction)
|
||||
.where(
|
||||
order.orderTime.between(search.getStartDateTime(), search.getEndDateTime()),
|
||||
order.orderStatus.ne(OrderStatus.PENDING),
|
||||
order.storeId.eq(storeId)
|
||||
)
|
||||
.fetchOne();
|
||||
|
||||
@@ -16,4 +16,5 @@ public interface OrderService {
|
||||
FetchOrderDto fetchOrder(Long userId);
|
||||
void saveOrder(Long userId);
|
||||
void modifyOrder(Long userId, OrderStatus orderStatus);
|
||||
OrderDetailDto findOrderDetail(Long orderId);
|
||||
}
|
||||
|
||||
@@ -8,11 +8,10 @@ import com.justpickup.orderservice.domain.order.repository.OrderRepository;
|
||||
import com.justpickup.orderservice.domain.order.repository.OrderRepositoryCustom;
|
||||
import com.justpickup.orderservice.domain.orderItem.dto.OrderItemDto;
|
||||
import com.justpickup.orderservice.domain.orderItem.entity.OrderItem;
|
||||
import com.justpickup.orderservice.domain.orderItem.repository.OrderItemRepositoryCustom;
|
||||
import com.justpickup.orderservice.domain.orderItemOption.entity.OrderItemOption;
|
||||
import com.justpickup.orderservice.global.client.store.GetItemResponse;
|
||||
import com.justpickup.orderservice.global.client.store.GetStoreResponse;
|
||||
import com.justpickup.orderservice.global.client.store.StoreByUserIdResponse;
|
||||
import com.justpickup.orderservice.global.client.store.StoreClient;
|
||||
import com.justpickup.orderservice.global.client.store.*;
|
||||
import com.justpickup.orderservice.global.client.user.GetCustomerResponse;
|
||||
import com.justpickup.orderservice.global.client.user.UserClient;
|
||||
import com.justpickup.orderservice.global.dto.Result;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -27,7 +26,9 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.justpickup.orderservice.domain.order.dto.OrderDetailDto.*;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import static java.util.stream.Collectors.toMap;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@@ -37,6 +38,7 @@ public class OrderServiceImpl implements OrderService {
|
||||
|
||||
private final OrderRepository orderRepository;
|
||||
private final OrderRepositoryCustom orderRepositoryCustom;
|
||||
private final OrderItemRepositoryCustom orderItemRepositoryCustom;
|
||||
private final StoreClient storeClient;
|
||||
private final UserClient userClient;
|
||||
|
||||
@@ -266,4 +268,70 @@ public class OrderServiceImpl implements OrderService {
|
||||
|
||||
return DashBoardDto.of(orderPrices , bestSellItem, sellAmountAWeeks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrderDetailDto findOrderDetail(Long orderId) {
|
||||
Order order = orderRepository.findById(orderId)
|
||||
.orElseThrow(() -> new OrderException(orderId + "는 없는 주문 번호입니다."));
|
||||
|
||||
List<OrderItem> orderItemsWithOptions = orderItemRepositoryCustom.getOrderItemsWithOptions(order.getId());
|
||||
|
||||
|
||||
|
||||
Set<Long> itemIds = new HashSet<>();
|
||||
|
||||
// 아이템 이름 및 옵션 이름 가져오기
|
||||
for (OrderItem orderItem : orderItemsWithOptions) {
|
||||
itemIds.add(orderItem.getItemId());
|
||||
}
|
||||
|
||||
Map<Long, GetItemResponse> itemAndItemOptionMap = storeClient.getItemAndItemOptionMap(itemIds);
|
||||
|
||||
List<OrderDetailItem> orderDetailItems = orderItemsWithOptions.stream()
|
||||
.map(orderItem -> {
|
||||
// 주문 상세 옵션 생성
|
||||
GetItemResponse itemResponse = itemAndItemOptionMap.get(orderItem.getItemId());
|
||||
|
||||
// 아이템 옵션 맵 생성
|
||||
Map<Long, GetItemResponse.ItemOptionDto> itemOptionMap = itemResponse.getItemOptions().stream()
|
||||
.collect(
|
||||
toMap(GetItemResponse.ItemOptionDto::getId, itemOptionDto -> itemOptionDto)
|
||||
);
|
||||
|
||||
List<OrderDetailItemOption> orderDetailItemOptions = orderItem.getOrderItemOptions()
|
||||
.stream()
|
||||
.map(orderItemOption -> {
|
||||
// 옵션 아이디에 해당하는 아이템 옵션 객체 가져오기
|
||||
GetItemResponse.ItemOptionDto itemOptionDto =
|
||||
itemOptionMap.get(orderItemOption.getItemOptionId());
|
||||
|
||||
return OrderDetailItemOption.of(
|
||||
orderItemOption,
|
||||
itemOptionDto.getName(),
|
||||
itemOptionDto.getOptionType()
|
||||
);
|
||||
})
|
||||
.collect(toList());
|
||||
// 아이템 아이디에 해당하는 아이템 이름 가져오기
|
||||
String itemName = itemResponse.getName();
|
||||
return OrderDetailItem.of(orderItem, itemName, orderDetailItemOptions);
|
||||
})
|
||||
.collect(toList());
|
||||
|
||||
// 고객 정보 가져오기
|
||||
GetCustomerResponse customerInfo = userClient.getCustomerById(order.getUserId()).getData();
|
||||
|
||||
// 주문한 사용자 정보 생성
|
||||
OrderDetailUser orderDetailUser = OrderDetailUser.builder()
|
||||
.id(customerInfo.getUserId())
|
||||
.phoneNumber(customerInfo.getPhoneNumber())
|
||||
.name(customerInfo.getUserName())
|
||||
.build();
|
||||
|
||||
// 매장 정보 가져오기
|
||||
GetStoreResponse storeInfo = storeClient.getStore(String.valueOf(order.getStoreId())).getData();
|
||||
|
||||
return OrderDetailDto.of(order, storeInfo.getName(), orderDetailItems, orderDetailUser);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package com.justpickup.orderservice.domain.order.web;
|
||||
|
||||
import com.justpickup.orderservice.domain.order.dto.OrderDetailDto;
|
||||
import com.justpickup.orderservice.domain.order.entity.OrderStatus;
|
||||
import com.justpickup.orderservice.domain.order.exception.OrderException;
|
||||
import com.justpickup.orderservice.domain.order.service.OrderService;
|
||||
import com.justpickup.orderservice.global.client.store.OptionType;
|
||||
import com.justpickup.orderservice.global.dto.Result;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
@@ -10,10 +12,12 @@ import lombok.NoArgsConstructor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PatchMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@@ -26,7 +30,7 @@ public class OrderController {
|
||||
public ResponseEntity<Result> patchOrder(@PathVariable("orderId") Long orderId,
|
||||
@RequestBody PatchOrderRequest patchOrderRequest) {
|
||||
OrderStatus orderStatus = patchOrderRequest.getOrderStatus();
|
||||
if (orderStatus == OrderStatus.PENDING && orderStatus != OrderStatus.FAILED) {
|
||||
if (orderStatus == OrderStatus.PENDING || orderStatus == OrderStatus.FAILED) {
|
||||
throw new OrderException(orderStatus.getMessage() + "는 변경 불가능합니다.");
|
||||
}
|
||||
|
||||
@@ -39,4 +43,83 @@ public class OrderController {
|
||||
static class PatchOrderRequest {
|
||||
private OrderStatus orderStatus;
|
||||
}
|
||||
|
||||
@GetMapping("/api/order-detail/{orderId}")
|
||||
public ResponseEntity<Result> getOrderDetail(@PathVariable Long orderId) {
|
||||
|
||||
OrderDetailDto orderDetail = orderService.findOrderDetail(orderId);
|
||||
return ResponseEntity.ok(Result.createSuccessResult(new OrderDetailResponse(orderDetail)));
|
||||
}
|
||||
|
||||
@Data @NoArgsConstructor @AllArgsConstructor
|
||||
static class OrderDetailResponse {
|
||||
private Long id;
|
||||
private OrderStatus orderStatus;
|
||||
private String orderTime;
|
||||
private Long orderPrice;
|
||||
private String storeName;
|
||||
private OrderDetailUserResponse user;
|
||||
private List<OrderDetailItemResponse> orderItems = new ArrayList<>();
|
||||
|
||||
public OrderDetailResponse(OrderDetailDto dto) {
|
||||
this.id = dto.getId();
|
||||
this.orderStatus = dto.getOrderStatus();
|
||||
this.orderTime = dto.getOrderTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
|
||||
this.orderPrice = dto.getOrderPrice();
|
||||
this.storeName = dto.getStoreName();
|
||||
this.user = new OrderDetailUserResponse(dto.getUser());
|
||||
this.orderItems = dto.getOrderItems().stream()
|
||||
.map(OrderDetailItemResponse::new)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Data
|
||||
static class OrderDetailUserResponse {
|
||||
private Long id;
|
||||
private String name;
|
||||
private String phoneNumber;
|
||||
|
||||
public OrderDetailUserResponse(OrderDetailDto.OrderDetailUser user) {
|
||||
this.id = user.getId();
|
||||
this.name = user.getName();
|
||||
this.phoneNumber = user.getPhoneNumber();
|
||||
}
|
||||
}
|
||||
|
||||
@Data @NoArgsConstructor
|
||||
static class OrderDetailItemResponse {
|
||||
private Long id;
|
||||
private Long itemId;
|
||||
private long totalPrice;
|
||||
private long count;
|
||||
private String name;
|
||||
private List<OrderDetailItemOptionResponse> options = new ArrayList<>();
|
||||
|
||||
public OrderDetailItemResponse(OrderDetailDto.OrderDetailItem orderDetailItem) {
|
||||
this.id = orderDetailItem.getId();
|
||||
this.itemId = orderDetailItem.getItemId();
|
||||
this.totalPrice = orderDetailItem.getTotalPrice();
|
||||
this.count = orderDetailItem.getCount();
|
||||
this.name = orderDetailItem.getName();
|
||||
this.options = orderDetailItem.getOptions().stream()
|
||||
.map(OrderDetailItemOptionResponse::new)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
@Data @NoArgsConstructor
|
||||
static class OrderDetailItemOptionResponse {
|
||||
private Long id;
|
||||
private Long itemOptionId;
|
||||
private String name;
|
||||
private OptionType optionType;
|
||||
|
||||
public OrderDetailItemOptionResponse(OrderDetailDto.OrderDetailItemOption itemOption) {
|
||||
this.id = itemOption.getId();
|
||||
this.itemOptionId = itemOption.getItemOptionId();
|
||||
this.name = itemOption.getName();
|
||||
this.optionType = itemOption.getOptionType();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.justpickup.orderservice.domain.orderItem.repository;
|
||||
|
||||
import com.justpickup.orderservice.domain.orderItem.entity.OrderItem;
|
||||
import com.querydsl.jpa.impl.JPAQueryFactory;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.justpickup.orderservice.domain.orderItem.entity.QOrderItem.orderItem;
|
||||
|
||||
@Repository
|
||||
@RequiredArgsConstructor
|
||||
public class OrderItemRepositoryCustom {
|
||||
|
||||
private final JPAQueryFactory queryFactory;
|
||||
|
||||
public List<OrderItem> getOrderItemsWithOptions(Long orderId) {
|
||||
return queryFactory.selectFrom(orderItem)
|
||||
.leftJoin(orderItem.orderItemOptions).fetchJoin()
|
||||
.where(
|
||||
orderItem.order.id.eq(orderId)
|
||||
)
|
||||
.distinct()
|
||||
.fetch();
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import com.justpickup.orderservice.global.entity.Yn;
|
||||
import lombok.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.justpickup.orderservice.global.client.store;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ItemOptionsResponse {
|
||||
private Long id;
|
||||
private OptionType optionType;
|
||||
private String name;
|
||||
}
|
||||
@@ -32,7 +32,7 @@ public interface StoreClient {
|
||||
Result<GetStoreResponse> getStore(@PathVariable(value = "storeId") String storeId);
|
||||
|
||||
@GetMapping("/api/customer/items/{itemId}")
|
||||
Result<List<GetItemResponse>> getItemAndItemOptions(@PathVariable(value = "itemId") List<Long> itemIds);
|
||||
Result<List<GetItemResponse>> getItemAndItemOptions(@PathVariable(value = "itemId") Iterable<Long> itemIds);
|
||||
|
||||
default Map<Long, String> getStoreNameMap(Set<Long> storeIds) {
|
||||
List<GetStoreResponse> storeResponses = this.getStoreAllById(storeIds).getData();
|
||||
@@ -50,5 +50,11 @@ public interface StoreClient {
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
default Map<Long, GetItemResponse> getItemAndItemOptionMap(Iterable<Long> itemIds) {
|
||||
List<GetItemResponse> responses = this.getItemAndItemOptions(itemIds).getData();
|
||||
return responses.stream()
|
||||
.collect(
|
||||
toMap(GetItemResponse::getId, getItemsResponse -> getItemsResponse)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ public class GlobalExceptionHandler {
|
||||
HttpStatus status = ce.getStatus();
|
||||
Result errorResult = ce.getErrorResult();
|
||||
|
||||
log.warn("[CustomException] {}, {}", status, errorResult);
|
||||
|
||||
return ResponseEntity.status(status)
|
||||
.body(errorResult);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package com.justpickup.orderservice.domain.order.web;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.justpickup.orderservice.config.TestConfig;
|
||||
import com.justpickup.orderservice.domain.order.dto.OrderDetailDto;
|
||||
import com.justpickup.orderservice.domain.order.entity.OrderStatus;
|
||||
import com.justpickup.orderservice.domain.order.repository.OrderRepository;
|
||||
import com.justpickup.orderservice.domain.order.service.OrderService;
|
||||
import com.justpickup.orderservice.domain.order.web.OrderController.PatchOrderRequest;
|
||||
import com.justpickup.orderservice.global.client.store.OptionType;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -18,11 +18,14 @@ import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
|
||||
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
|
||||
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.patch;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.*;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
|
||||
import static org.springframework.restdocs.request.RequestDocumentation.pathParameters;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
|
||||
@@ -77,4 +80,98 @@ class OrderControllerTest {
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("[GET] 주문 상세 내역 가져오기")
|
||||
void getOrderDetail() throws Exception {
|
||||
// GIVEN
|
||||
Long orderId = 1589L;
|
||||
|
||||
given(orderService.findOrderDetail(orderId)).willReturn(getOrderDetailWillReturn(orderId));
|
||||
// THEN
|
||||
ResultActions actions = mockMvc.perform(get("/api/order-detail/{orderId}", String.valueOf(orderId)));
|
||||
// WHEN
|
||||
actions.andExpect(status().isOk())
|
||||
.andDo(print())
|
||||
.andDo(document("api-orderDetail",
|
||||
pathParameters(
|
||||
parameterWithName("orderId").description("주문 고유번호")
|
||||
),
|
||||
responseFields(
|
||||
fieldWithPath("code").description("결과코드 SUCCESS/ERROR"),
|
||||
fieldWithPath("message").description("메세지"),
|
||||
fieldWithPath("data.id").description("주문 고유번호"),
|
||||
fieldWithPath("data.orderTime").description("주문 시간 [yyy-MM-dd]"),
|
||||
fieldWithPath("data.orderPrice").description("주문 금액"),
|
||||
fieldWithPath("data.user.id").description("주문한 회원 고유번호"),
|
||||
fieldWithPath("data.user.name").description("주문한 회원 이름"),
|
||||
fieldWithPath("data.user.phoneNumber").description("주문한 회원 전화번호"),
|
||||
fieldWithPath("data.orderItems[*].id").description("주문아이템 고유번호"),
|
||||
fieldWithPath("data.orderItems[*].itemId").description("아이템 고유번호"),
|
||||
fieldWithPath("data.orderItems[*].totalPrice").description("주문아이템 총합계"),
|
||||
fieldWithPath("data.orderItems[*].count").description("주문아이템 수량"),
|
||||
fieldWithPath("data.orderItems[*].name").description("아이템 이름"),
|
||||
fieldWithPath("data.orderItems[*].options[*].id").description("주문아이템옵션 고유번호"),
|
||||
fieldWithPath("data.orderItems[*].options[*].itemOptionId").description("아이템옵션 고유번호"),
|
||||
fieldWithPath("data.orderItems[*].options[*].name").description("아이템옵션 이름"),
|
||||
fieldWithPath("data.orderItems[*].options[*].optionType").description("아이템옵션 타입")
|
||||
)
|
||||
))
|
||||
;
|
||||
}
|
||||
|
||||
private OrderDetailDto getOrderDetailWillReturn(Long orderId) {
|
||||
OrderDetailDto.OrderDetailUser orderDetailUser = OrderDetailDto.OrderDetailUser.builder()
|
||||
.id(6L)
|
||||
.name("박상범")
|
||||
.phoneNumber("010-1234-5678")
|
||||
.build();
|
||||
|
||||
long id = 11371L;
|
||||
long itemOptionId = 40L;
|
||||
OrderDetailDto.OrderDetailItemOption ice = OrderDetailDto.OrderDetailItemOption.builder()
|
||||
.id(id++)
|
||||
.itemOptionId(itemOptionId++)
|
||||
.name("ICE")
|
||||
.optionType(OptionType.REQUIRED)
|
||||
.build();
|
||||
|
||||
OrderDetailDto.OrderDetailItemOption hot = OrderDetailDto.OrderDetailItemOption.builder()
|
||||
.id(id++)
|
||||
.itemOptionId(itemOptionId++)
|
||||
.name("HOT")
|
||||
.optionType(OptionType.REQUIRED)
|
||||
.build();
|
||||
|
||||
OrderDetailDto.OrderDetailItemOption plus = OrderDetailDto.OrderDetailItemOption.builder()
|
||||
.id(id++)
|
||||
.itemOptionId(itemOptionId++)
|
||||
.name("시럽 추가")
|
||||
.optionType(OptionType.OTHER)
|
||||
.build();
|
||||
|
||||
OrderDetailDto.OrderDetailItem 카페라떼 = OrderDetailDto.OrderDetailItem.builder()
|
||||
.id(id++)
|
||||
.itemId(itemOptionId++)
|
||||
.count(2)
|
||||
.name("카페라떼")
|
||||
.options(List.of(hot, plus))
|
||||
.build();
|
||||
|
||||
OrderDetailDto.OrderDetailItem 아메리카노 = OrderDetailDto.OrderDetailItem.builder()
|
||||
.id(id++)
|
||||
.itemId(itemOptionId++)
|
||||
.count(2)
|
||||
.options(List.of(ice))
|
||||
.name("아메리카노")
|
||||
.build();
|
||||
|
||||
return OrderDetailDto.builder()
|
||||
.id(orderId)
|
||||
.orderTime(LocalDateTime.now())
|
||||
.orderPrice(76600L)
|
||||
.user(orderDetailUser)
|
||||
.orderItems(List.of(카페라떼, 아메리카노))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -28,5 +28,8 @@ export default {
|
||||
},
|
||||
findDashboard(){
|
||||
return axios.get(process.env.VUE_APP_API_URL + "/order/dashboard");
|
||||
},
|
||||
getOrderDetail(orderId) {
|
||||
return axios.get(process.env.VUE_APP_OWNER_SERVICE_BASEURL + "/order-service/api/order-detail/" + orderId);
|
||||
}
|
||||
}
|
||||
@@ -1,84 +1,96 @@
|
||||
<template>
|
||||
<v-card>
|
||||
<v-toolbar elevation="1" dense>
|
||||
<v-toolbar-title>{{ userName }}</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn outlined color="grey grey lighten-1" small
|
||||
@click="clickDetail"
|
||||
>
|
||||
상세보기
|
||||
</v-btn>
|
||||
</v-toolbar>
|
||||
<v-card-title v-if="itemNames.length == 1">
|
||||
{{ itemNames[0] }}
|
||||
</v-card-title>
|
||||
<v-card-title v-if="itemNames.length > 1">
|
||||
{{ itemNames[0] }} 외 {{ itemNames.length - 1 }}건
|
||||
</v-card-title>
|
||||
<v-card-subtitle>{{ orderStatus | getOrderStatusName }}</v-card-subtitle>
|
||||
<v-card-text>{{ orderTime }}</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-row v-if="orderStatus === 'PLACED'">
|
||||
<v-col sm="6">
|
||||
<v-btn
|
||||
block depressed color="#006A95" class="white--text"
|
||||
@click="accepted"
|
||||
>
|
||||
주문수락하기
|
||||
</v-btn>
|
||||
</v-col>
|
||||
<v-col sm="6">
|
||||
<v-btn block depressed color="#FF1400" class="white--text"
|
||||
@click="rejected"
|
||||
>
|
||||
주문거절하기
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row v-else-if="orderStatus === 'ACCEPTED'">
|
||||
<v-col>
|
||||
<v-btn block depressed color="#58ADA0" class="white--text"
|
||||
@click="waiting"
|
||||
>
|
||||
픽업 요청하기
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row v-else-if="orderStatus === 'REJECTED'">
|
||||
<v-col>
|
||||
<v-btn block disabled>
|
||||
거절됨
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row v-else-if="orderStatus === 'WAITING'">
|
||||
<v-col>
|
||||
<v-btn block depressed color="#FF5C00" class="white--text"
|
||||
@click="finished"
|
||||
>
|
||||
고객 수령완료하기
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row v-else-if="orderStatus === 'FINISHED'">
|
||||
<v-col>
|
||||
<v-btn block depressed color="#F9E0AF" class="grey--text">
|
||||
픽업 완료됨
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
<div>
|
||||
<v-card>
|
||||
<v-toolbar elevation="1" dense>
|
||||
<v-toolbar-title>{{ userName }}</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<order-detail-dialog
|
||||
:dialog="false"
|
||||
:orderId="this.id"
|
||||
></order-detail-dialog>
|
||||
</v-toolbar>
|
||||
<v-card-title v-if="itemNames.length == 1">
|
||||
{{ itemNames[0] }}
|
||||
</v-card-title>
|
||||
<v-card-title v-if="itemNames.length > 1">
|
||||
{{ itemNames[0] }} 외 {{ itemNames.length - 1 }}건
|
||||
</v-card-title>
|
||||
<v-card-subtitle>{{ orderStatus | getOrderStatusName }}</v-card-subtitle>
|
||||
<v-card-text>{{ orderTime }}</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-row v-if="orderStatus === 'PLACED'">
|
||||
<v-col sm="6">
|
||||
<v-btn
|
||||
block depressed color="#006A95" class="white--text"
|
||||
@click="accepted"
|
||||
>
|
||||
주문수락하기
|
||||
</v-btn>
|
||||
</v-col>
|
||||
<v-col sm="6">
|
||||
<v-btn block depressed color="#FF1400" class="white--text"
|
||||
@click="rejected"
|
||||
>
|
||||
주문거절하기
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row v-else-if="orderStatus === 'ACCEPTED'">
|
||||
<v-col>
|
||||
<v-btn block depressed color="#58ADA0" class="white--text"
|
||||
@click="waiting"
|
||||
>
|
||||
픽업 요청하기
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row v-else-if="orderStatus === 'REJECTED'">
|
||||
<v-col>
|
||||
<v-btn block disabled>
|
||||
거절됨
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row v-else-if="orderStatus === 'WAITING'">
|
||||
<v-col>
|
||||
<v-btn block depressed color="#FF5C00" class="white--text"
|
||||
@click="finished"
|
||||
>
|
||||
고객 수령완료하기
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row v-else-if="orderStatus === 'FINISHED'">
|
||||
<v-col>
|
||||
<v-btn block depressed color="#F9E0AF" class="grey--text">
|
||||
픽업 완료됨
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row v-else-if="orderStatus === 'FAILED'">
|
||||
<v-col>
|
||||
<v-btn block disabled>
|
||||
주문 실패
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import orderApi from "../api/order";
|
||||
import OrderDetailDialog from "@/components/OrderDetailDialog";
|
||||
|
||||
export default {
|
||||
name: "OrderCard",
|
||||
components: {
|
||||
"order-detail-dialog": OrderDetailDialog
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
|
||||
dialog: false
|
||||
};
|
||||
},
|
||||
props: {
|
||||
@@ -128,9 +140,6 @@ export default {
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
clickDetail: function() {
|
||||
alert("준비중 입니다...");
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
166
owner-vue/src/components/OrderDetailDialog.vue
Normal file
166
owner-vue/src/components/OrderDetailDialog.vue
Normal file
@@ -0,0 +1,166 @@
|
||||
<template>
|
||||
<v-dialog
|
||||
v-model="propDialog"
|
||||
scrollable
|
||||
width="1000px"
|
||||
>
|
||||
<template v-slot:activator="{on, attrs}">
|
||||
<v-btn outlined color="grey grey lighten-1" small
|
||||
@click="clickDetail"
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
>
|
||||
상세보기
|
||||
</v-btn>
|
||||
</template>
|
||||
|
||||
<v-card>
|
||||
<v-toolbar>
|
||||
<span class="text-h5">주문 상세내역</span>
|
||||
</v-toolbar>
|
||||
<v-card-text class="pa-12">
|
||||
<v-row>
|
||||
<v-col cols="12" sm="6">
|
||||
<h1>{{orderInfo.storeName}}</h1><br>
|
||||
<h3>{{orderId}}. {{orderInfo.orderStatus | getOrderStatusName }}</h3><br>
|
||||
주문일시: {{ orderInfo.orderTime }}<br>
|
||||
주 문 자: {{ user.name }}<br>
|
||||
휴대번호: {{ user.phoneNumber }}<br><br><br><br>
|
||||
<v-simple-table class="no-border-table">
|
||||
<template v-slot:default>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><span class="orange--text"><b>합계</b></span></td>
|
||||
<td>{{ orderInfo.orderPrice | currency }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>포인트사용</td>
|
||||
<td>0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>쿠폰 할인</td>
|
||||
<td>0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class="orange--text"><b>결제금액</b></span></td>
|
||||
<td><b>{{ orderInfo.orderPrice | currency }}</b></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</template>
|
||||
</v-simple-table>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="6">
|
||||
<v-simple-table class="no-border-table">
|
||||
<template v-slot:default>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-left">메뉴</th>
|
||||
<th class="text-left">수량</th>
|
||||
<th class="text-left">금액</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="orderItem in orderItems" :key="orderItem.id" class="">
|
||||
<td>
|
||||
{{orderItem.name}}<br>
|
||||
<span class="grey--text" v-if="orderItem.options.length > 0">ㄴ {{orderItem.options}}</span>
|
||||
</td>
|
||||
<td>{{orderItem.count}}</td>
|
||||
<td>{{orderItem.totalPrice | currency}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</template>
|
||||
</v-simple-table>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn
|
||||
color="grey"
|
||||
outlined
|
||||
bold
|
||||
@click="propDialog = false"
|
||||
>
|
||||
닫기
|
||||
</v-btn>
|
||||
<v-spacer></v-spacer>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import orderApi from "../api/order";
|
||||
|
||||
export default {
|
||||
name: "OrderDetailDialog",
|
||||
props: ["dialog", "orderId"],
|
||||
watch: {
|
||||
dialog: function() {
|
||||
this.propDialog = !this.propDialog
|
||||
}
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
propDialog: false,
|
||||
user: {},
|
||||
orderInfo: {},
|
||||
orderItems: []
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
clickDetail: async function() {
|
||||
this.user = {};
|
||||
this.orderInfo = {};
|
||||
this.orderItems = [];
|
||||
const response = await orderApi.getOrderDetail(this.orderId);
|
||||
this.render(response.data);
|
||||
},
|
||||
render(json) {
|
||||
const orderDetail = json.data;
|
||||
|
||||
const orderUser = orderDetail.user;
|
||||
this.user = {
|
||||
id: orderUser.id,
|
||||
name: orderUser.name,
|
||||
phoneNumber: orderUser.phoneNumber
|
||||
};
|
||||
|
||||
this.orderInfo = {
|
||||
id: orderDetail.id,
|
||||
orderTime: orderDetail.orderTime,
|
||||
orderPrice: orderDetail.orderPrice,
|
||||
orderStatus: orderDetail.orderStatus,
|
||||
storeName: orderDetail.storeName
|
||||
};
|
||||
|
||||
const orderItems = orderDetail.orderItems;
|
||||
orderItems.forEach(orderItem => {
|
||||
|
||||
let orderItemOptions = []
|
||||
orderItem.options.forEach(option => {
|
||||
const optionTypeName = option.optionType == "REQUIRED" ? "필수" : "기타";
|
||||
orderItemOptions.push(option.name + "(" + optionTypeName + ")");
|
||||
});
|
||||
|
||||
this.orderItems.push({
|
||||
id: orderItem.id,
|
||||
itemId: orderItem.itemId,
|
||||
totalPrice: orderItem.totalPrice,
|
||||
count: orderItem.count,
|
||||
name: orderItem.name,
|
||||
options: orderItemOptions.join(",")
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.no-border-table tbody tr td {
|
||||
border-bottom: none !important;
|
||||
}
|
||||
</style>
|
||||
@@ -27,8 +27,10 @@ Vue.filter('getOrderStatusName', function (orderStatus) {
|
||||
return "픽업대기중";
|
||||
case "FINISHED":
|
||||
return "픽업완료됨";
|
||||
case "FAILED":
|
||||
return "주문실패";
|
||||
default:
|
||||
break;
|
||||
return orderStatus;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -25,6 +25,12 @@
|
||||
hide-default-footer
|
||||
class="elevation-1"
|
||||
>
|
||||
<template v-slot:item.detail="{ item }">
|
||||
<order-detail-dialog
|
||||
:dialog="false"
|
||||
:orderId="item.orderId"
|
||||
></order-detail-dialog>
|
||||
</template>
|
||||
</v-data-table>
|
||||
<div class="text-center pt-2">
|
||||
<v-pagination
|
||||
@@ -40,13 +46,15 @@
|
||||
import orderApi from '../api/order.js';
|
||||
|
||||
import DatePicker from "@/components/DatePicker";
|
||||
import OrderDetailDialog from "@/components/OrderDetailDialog";
|
||||
|
||||
const moment = require('moment');
|
||||
|
||||
export default {
|
||||
name: "PrevOrder",
|
||||
components: {
|
||||
'date-picker': DatePicker
|
||||
'date-picker': DatePicker,
|
||||
"order-detail-dialog": OrderDetailDialog
|
||||
},
|
||||
mounted: function() {
|
||||
this.search();
|
||||
@@ -81,6 +89,7 @@ export default {
|
||||
{ text: '주문상품', value: 'orderItemNames' },
|
||||
{ text: '결제금액', value: 'orderPrice' },
|
||||
{ text: '닉네임', value: 'userName' },
|
||||
{ text: '상세보기', value: 'detail', sortable: false}
|
||||
],
|
||||
orders: [],
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ public class ItemRepositoryCustom {
|
||||
return queryFactory.selectFrom(item)
|
||||
.join(item.itemOptions,itemOption).fetchJoin()
|
||||
.where(item.id.in(itemIds))
|
||||
.distinct()
|
||||
.fetch();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,28 +1,11 @@
|
||||
package com.justpickup.storeservice.domain.itemoption.repository;
|
||||
|
||||
import com.justpickup.storeservice.domain.itemoption.entity.ItemOption;
|
||||
import com.justpickup.storeservice.domain.itemoption.entity.QItemOption;
|
||||
import com.querydsl.jpa.impl.JPAQueryFactory;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.justpickup.storeservice.domain.item.entity.QItem.item;
|
||||
|
||||
@Repository
|
||||
@RequiredArgsConstructor
|
||||
public class ItemOptionRepositoryCustom {
|
||||
|
||||
private final JPAQueryFactory queryFactory;
|
||||
|
||||
public List<ItemOption> findByItem(Long itemId) {
|
||||
|
||||
return queryFactory.selectFrom(QItemOption.itemOption)
|
||||
.join(QItemOption.itemOption.item)
|
||||
.on(item.id.eq(itemId))
|
||||
.fetch();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,25 +1,4 @@
|
||||
package com.justpickup.storeservice.domain.itemoption.service;
|
||||
|
||||
import com.justpickup.storeservice.domain.item.dto.ItemDto;
|
||||
import com.justpickup.storeservice.domain.itemoption.dto.ItemOptionDto;
|
||||
import com.justpickup.storeservice.domain.itemoption.repository.ItemOptionRepository;
|
||||
import com.justpickup.storeservice.domain.itemoption.repository.ItemOptionRepositoryCustom;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class ItemOptionService {
|
||||
private final ItemOptionRepositoryCustom itemOptionRepositoryCustom;
|
||||
|
||||
public List<ItemOptionDto> getItemOption( ItemDto itemDto){
|
||||
return itemOptionRepositoryCustom.findByItem(itemDto.getId())
|
||||
.stream().map(ItemOptionDto::new)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
public interface ItemOptionService {
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.justpickup.storeservice.domain.itemoption.service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class ItemOptionServiceImpl implements ItemOptionService {
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.justpickup.storeservice.domain.itemoption.web;
|
||||
|
||||
import com.justpickup.storeservice.domain.itemoption.service.ItemOptionService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@@ -7,6 +8,5 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@RequiredArgsConstructor
|
||||
public class ItemOptionController {
|
||||
|
||||
|
||||
|
||||
private final ItemOptionService itemOptionService;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user