Merge pull request #58 from Development-team-1/owner_dashboard
Owner dashboard
This commit is contained in:
@@ -24,6 +24,9 @@ export default {
|
||||
getOrder() {
|
||||
return axios.get(process.env.VUE_APP_ORDER_API_URL + "/order/orders");
|
||||
},
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -9,8 +9,9 @@
|
||||
<v-app-bar-nav-icon @click="$router.back()">
|
||||
<v-icon>mdi-arrow-left</v-icon>
|
||||
</v-app-bar-nav-icon>
|
||||
|
||||
<v-spacer></v-spacer>
|
||||
<v-toolbar-title>
|
||||
<v-toolbar-title style="position: absolute; left: 50%; transform:translateX(-50%);">
|
||||
<v-img :src="require('@/assets/just-logo.png')"></v-img>
|
||||
</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<v-icon>mdi-arrow-left</v-icon>
|
||||
</v-app-bar-nav-icon>
|
||||
<v-spacer></v-spacer>
|
||||
<v-toolbar-title>
|
||||
<v-toolbar-title style="position: absolute; left: 50%; transform:translateX(-50%);">
|
||||
<b>{{store.name}}</b>
|
||||
</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
@@ -23,11 +23,19 @@
|
||||
:color="favoriteStore.color"
|
||||
>{{ favoriteStore.icon }}</v-icon>
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="white"
|
||||
elevation="0"
|
||||
@click="logout"
|
||||
>
|
||||
<v-icon>mdi-logout</v-icon>
|
||||
</v-btn>
|
||||
</v-app-bar>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import storeApi from "@/api/store";
|
||||
import authApi from "@/api/auth";
|
||||
|
||||
export default {
|
||||
name: "StoreNavigation",
|
||||
@@ -71,7 +79,14 @@ export default {
|
||||
}
|
||||
this.favoriteStore.status= !this.favoriteStore.status
|
||||
|
||||
},
|
||||
logout: function () {
|
||||
if(confirm("로그아웃하시겠습니까?")){
|
||||
authApi.logout();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
mounted() {
|
||||
console.log(this.$route.params)
|
||||
|
||||
@@ -64,12 +64,12 @@ const routes = [
|
||||
name: 'notification',
|
||||
component: () => import('../views/NotificationView')
|
||||
},
|
||||
{
|
||||
path: "/item/:itemId",
|
||||
beforeEnter: authCheck,
|
||||
name: 'itemDetail',
|
||||
component: () => import('../views/ItemDetail')
|
||||
},
|
||||
// {
|
||||
// path: "/item/:itemId",
|
||||
// beforeEnter: authCheck,
|
||||
// name: 'itemDetail',
|
||||
// component: () => import('../views/ItemDetail')
|
||||
// },
|
||||
{
|
||||
path: "/order",
|
||||
beforeEnter: authCheck,
|
||||
@@ -110,6 +110,19 @@ const routes = [
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/item',
|
||||
redirect: 'item',
|
||||
component: StoreLayout,
|
||||
children: [
|
||||
{
|
||||
path: "/item/:itemId",
|
||||
beforeEnter: authCheck,
|
||||
name: 'itemDetail',
|
||||
component: () => import('../views/ItemDetail')
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/auth',
|
||||
name: 'auth',
|
||||
|
||||
@@ -116,7 +116,6 @@ export default {
|
||||
storeId:-1,
|
||||
itemId:-1,
|
||||
price:0,
|
||||
requireOption:{},
|
||||
otherOptions:[],
|
||||
},
|
||||
}
|
||||
|
||||
@@ -8,17 +8,6 @@
|
||||
<router-view
|
||||
v-on:getStoreId="renderNavigation">
|
||||
</router-view>
|
||||
<div align="right" >
|
||||
<v-btn
|
||||
color="primary"
|
||||
dark
|
||||
right
|
||||
fab
|
||||
@click="toOrder"
|
||||
>
|
||||
<v-icon>mdi-basket</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
</v-container>
|
||||
</v-main>
|
||||
<bottom-navigation></bottom-navigation>
|
||||
@@ -56,11 +45,6 @@ export default {
|
||||
|
||||
const response = await storeApi.requestStore(this.store.id);
|
||||
this.store = response.data.data;
|
||||
},
|
||||
toOrder(){
|
||||
if(confirm("주문화면으로 이동할까요?")){
|
||||
this.$router.push("/order")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,9 @@
|
||||
/>
|
||||
<v-btn
|
||||
color="orange"
|
||||
block>수정하기</v-btn>
|
||||
block
|
||||
@click="message('준비중입니다.')"
|
||||
>수정하기</v-btn>
|
||||
</v-form>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
@@ -76,6 +78,9 @@ export default {
|
||||
console.log(error.response)
|
||||
})
|
||||
},
|
||||
message: function(message){
|
||||
alert(message)
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getUserData()
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<v-row>
|
||||
<v-col
|
||||
v-for=" orderItem in orderData.orderItemDtoList"
|
||||
:key = "orderItem.itemId"
|
||||
:key = "orderItem.id"
|
||||
>
|
||||
<v-card
|
||||
class="mx-auto mb-5"
|
||||
@@ -25,7 +25,7 @@
|
||||
<div class="text-body-1 mb-5" style="white-space:nowrap; overflow:hidden; text-overflow:ellipsis;">
|
||||
{{ orderItem.orderItemOptionDtoList ?
|
||||
orderItem.orderItemOptionDtoList.map(x=>x.name).join(', ')
|
||||
: null}}
|
||||
: null}}
|
||||
</div>
|
||||
<div class="text--primary">
|
||||
합계 : <b> {{ orderItem.count * orderItem.price | currency}} 원</b>
|
||||
@@ -40,7 +40,7 @@
|
||||
</v-list-item>
|
||||
|
||||
<v-card-actions class="pb-2">
|
||||
<v-btn block color="warning" @click="message('준비중입니다.')">삭제하기</v-btn>
|
||||
<v-btn block color="warning" @click="deleteOrderItem(orderItem)">삭제하기</v-btn>
|
||||
</v-card-actions>
|
||||
|
||||
</v-card>
|
||||
@@ -98,7 +98,6 @@ export default {
|
||||
getOrder: function(){
|
||||
orderApi.getOrder()
|
||||
.then(response=>{
|
||||
console.log(response)
|
||||
this.orderData=response.data.data
|
||||
})
|
||||
.catch(error=>{
|
||||
@@ -107,9 +106,27 @@ export default {
|
||||
console.log(error.response)
|
||||
})
|
||||
},
|
||||
message: function(message){
|
||||
alert(message)
|
||||
}
|
||||
deleteOrderItem: function(orderItem){
|
||||
var vm = this
|
||||
const deleteOrderItemId = orderItem.id
|
||||
console.log(deleteOrderItemId)
|
||||
orderApi.deleteOrderItem(deleteOrderItemId)
|
||||
.then(response=>{
|
||||
console.log(response)
|
||||
alert(response.data.data+"삭제되었습니다.")
|
||||
vm.orderData.orderPrice -=orderItem.price
|
||||
vm.orderData.orderItemDtoList.splice(
|
||||
vm.orderData.orderItemDtoList.indexOf(orderItem),1
|
||||
)
|
||||
if(vm.orderData.orderItemDtoList.length ==0)
|
||||
this.$router.back()
|
||||
})
|
||||
.catch(error=>{
|
||||
alert("문제가 발생하였습니다.")
|
||||
console.log(error.response)
|
||||
})
|
||||
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -54,6 +54,17 @@
|
||||
<br>
|
||||
</div>
|
||||
</div>
|
||||
<div align="right" >
|
||||
<v-btn
|
||||
color="primary"
|
||||
dark
|
||||
right
|
||||
fab
|
||||
@click="toOrder"
|
||||
>
|
||||
<v-icon>mdi-basket</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -94,6 +105,11 @@ export default {
|
||||
},
|
||||
itemDetail: function (itemId) {
|
||||
this.$router.push("/item/"+itemId)
|
||||
},
|
||||
toOrder(){
|
||||
if(confirm("주문화면으로 이동할까요?")){
|
||||
this.$router.push("/order")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,6 +85,9 @@ operation::prevOrder-get[snippets='curl-request,http-request,http-response,reque
|
||||
=== 점주 서비스 - 지난 주문 페이지 (잘못된 파라미터 형식)
|
||||
operation::prevOrder-get-BindException[snippets='curl-request,http-request,http-response,request-headers,request-parameters,response-fields']
|
||||
|
||||
=== 점주 서비스 - 대쉬보드
|
||||
operation::owner-findDashboard[snippets='curl-request,http-request,http-response,request-headers,response-fields']
|
||||
|
||||
== Just Pick-up
|
||||
=== 주문 내역 페이지
|
||||
operation::api-customer-order-history[snippets='curl-request,http-request,http-response,request-headers,request-parameters,response-fields']
|
||||
@@ -95,5 +98,9 @@ operation::add-item-to-basket[snippets='curl-request,http-request,http-response,
|
||||
=== 장바구니 내역 가져오기
|
||||
operation::fetch-order[snippets='curl-request,http-request,http-response,request-headers,response-fields']
|
||||
|
||||
=== 장바구니 상품 삭제
|
||||
operation::delete-orderItem[snippets='curl-request,http-request,http-response,request-headers,path-parameters,response-fields']
|
||||
|
||||
|
||||
=== 주문하기
|
||||
operation::save-order[snippets='curl-request,http-request,http-response,request-headers']
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.justpickup.orderservice.domain.order.dto;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class DashBoardDto {
|
||||
|
||||
//일일 판매금액
|
||||
private Long salesAmount=0L;
|
||||
private BestSellItem bestSellItem;
|
||||
List<SellAmountAWeek> sellAmountAWeeks;
|
||||
|
||||
public static DashBoardDto of(List<OrderPrice> orderPrices , DashBoardDto.BestSellItem bestSellItem , List<SellAmountAWeek> sellAmountAWeeks){
|
||||
DashBoardDto dashBoardDto = new DashBoardDto();
|
||||
orderPrices.forEach(orderPrice -> dashBoardDto.salesAmount+=orderPrice.getOrderPrice());
|
||||
dashBoardDto.bestSellItem = bestSellItem;
|
||||
dashBoardDto.sellAmountAWeeks = sellAmountAWeeks;
|
||||
|
||||
return dashBoardDto;
|
||||
}
|
||||
|
||||
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class OrderPrice{
|
||||
Long orderPrice;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class BestSellItem{
|
||||
Long itemId;
|
||||
String itemName;
|
||||
Long sumCounts;
|
||||
|
||||
public void setItemName(String itemName) {
|
||||
this.itemName = itemName;
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class SellAmountAWeek{
|
||||
Object sellDate;
|
||||
Long sellAmount;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,14 @@
|
||||
package com.justpickup.orderservice.domain.order.dto;
|
||||
|
||||
import com.justpickup.orderservice.domain.orderItem.entity.OrderItem;
|
||||
import com.justpickup.orderservice.domain.orderItemOption.dto.OrderItemOptionDto;
|
||||
import com.justpickup.orderservice.domain.orderItemOption.entity.OrderItemOption;
|
||||
import com.justpickup.orderservice.global.client.store.GetItemResponse;
|
||||
import com.justpickup.orderservice.global.client.store.OptionType;
|
||||
import lombok.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@@ -33,7 +37,9 @@ public class FetchOrderDto {
|
||||
|
||||
private String itemName;
|
||||
|
||||
private List<GetItemResponse.ItemOptionDto> orderItemOptionDtoList;
|
||||
private List<OrderItemOptionDto> orderItemOptionDtoList;
|
||||
|
||||
// private List<GetItemResponse.ItemOptionDto> orderItemOptionDtoList;
|
||||
|
||||
private Long price;
|
||||
|
||||
@@ -43,10 +49,35 @@ public class FetchOrderDto {
|
||||
this.id = orderItem.getId();
|
||||
this.itemId = getItemResponse.getId();
|
||||
this.itemName = getItemResponse.getName();
|
||||
this.orderItemOptionDtoList = getItemResponse.getItemOptions();
|
||||
|
||||
//getItemResponse에는 해당 item에 존재하는 itemOption들이 전부 들어있으므로, orderItem에서 orderItemOption에 있는값들을 가져와서 매칭해줌
|
||||
this.orderItemOptionDtoList = orderItem.getOrderItemOptions().stream().map(orderItemOption -> {
|
||||
OrderItemOptionDto orderItemOptionDto = new OrderItemOptionDto(orderItemOption.getId(), null, null);
|
||||
for (GetItemResponse.ItemOptionDto responseItemOption : getItemResponse.getItemOptions()) {
|
||||
|
||||
if (responseItemOption.getId().equals(orderItemOption.getItemOptionId())) {
|
||||
orderItemOptionDto = new OrderItemOptionDto(orderItemOption.getId(), responseItemOption.getOptionType(), responseItemOption.getName());
|
||||
}
|
||||
}
|
||||
return orderItemOptionDto;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
// this.orderItemOptionDtoList = getItemResponse.getItemOptions();
|
||||
this.price = orderItem.getPrice();
|
||||
this.count = orderItem.getCount();
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class OrderItemOptionDto{
|
||||
private Long id;
|
||||
|
||||
private OptionType optionType;
|
||||
|
||||
private String name;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ public class Order extends BaseEntity {
|
||||
private Transaction transaction;
|
||||
|
||||
@BatchSize(size = 100)
|
||||
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
|
||||
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
private List<OrderItem> orderItems = new ArrayList<>();
|
||||
|
||||
public static Order of(Long userId, Long userCouponId, Long storeId, OrderItem orderItem) {
|
||||
@@ -83,6 +83,13 @@ public class Order extends BaseEntity {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Order deleteOrderItem(OrderItem orderItem) {
|
||||
this.orderPrice -= orderItem.getTotalPrice();
|
||||
this.orderItems.remove(orderItem);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setOrderStatus(OrderStatus orderStatus){
|
||||
this.orderStatus = orderStatus;
|
||||
}
|
||||
@@ -105,8 +112,4 @@ public class Order extends BaseEntity {
|
||||
public void fail() {
|
||||
this.orderStatus = OrderStatus.FAILED;
|
||||
}
|
||||
|
||||
public void changOrderTime(LocalDateTime orderTime) {
|
||||
this.orderTime = orderTime;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,5 +7,7 @@ import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface OrderRepository extends JpaRepository<Order, Long> {
|
||||
Long countByUserIdAndOrderStatus(Long userId, OrderStatus orderStatus);
|
||||
Optional<Order> findByUserIdAndOrderStatus(Long userId, OrderStatus orderStatus);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package com.justpickup.orderservice.domain.order.repository;
|
||||
|
||||
import com.justpickup.orderservice.domain.order.dto.DashBoardDto;
|
||||
import com.justpickup.orderservice.domain.order.dto.OrderMainResult;
|
||||
import com.justpickup.orderservice.domain.order.dto.OrderSearchCondition;
|
||||
import com.justpickup.orderservice.domain.order.dto.PrevOrderSearch;
|
||||
import com.justpickup.orderservice.domain.order.entity.Order;
|
||||
import com.justpickup.orderservice.domain.order.entity.OrderStatus;
|
||||
import com.querydsl.core.types.dsl.BooleanExpression;
|
||||
import com.querydsl.core.types.ConstantImpl;
|
||||
import com.querydsl.core.types.Projections;
|
||||
import com.querydsl.core.types.dsl.*;
|
||||
import com.querydsl.jpa.impl.JPAQueryFactory;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.data.domain.Page;
|
||||
@@ -139,4 +142,75 @@ public class OrderRepositoryCustom {
|
||||
|
||||
}
|
||||
|
||||
public List<DashBoardDto.OrderPrice> salesAmountBetweenADay(Long storeId){
|
||||
LocalDateTime today = LocalDateTime.now();
|
||||
LocalDateTime startTime = LocalDateTime.of(today.getYear(),today.getMonth(),today.getDayOfMonth(),0,0);
|
||||
|
||||
return queryFactory
|
||||
.select(Projections.fields(DashBoardDto.OrderPrice.class,
|
||||
order.orderPrice
|
||||
))
|
||||
.from(order)
|
||||
.where(
|
||||
order.storeId.eq(storeId)
|
||||
.and( order.orderTime.between(startTime,today))
|
||||
).fetch();
|
||||
}
|
||||
|
||||
public DashBoardDto.BestSellItem bestItemBetweenAWeek(Long storeId){
|
||||
LocalDateTime today = LocalDateTime.now();
|
||||
LocalDateTime startTime = LocalDateTime.of(today.getYear(),
|
||||
today.getMonth(),
|
||||
today.getDayOfMonth(),
|
||||
0,0)
|
||||
.minusDays(7);
|
||||
|
||||
return queryFactory.
|
||||
select(
|
||||
Projections.fields(DashBoardDto.BestSellItem.class,
|
||||
orderItem.itemId.as("itemId"),
|
||||
orderItem.count.sum().as("sumCounts")
|
||||
)
|
||||
)
|
||||
.from(orderItem)
|
||||
.join(orderItem.order, order)
|
||||
.where(orderItem.order.storeId.eq(storeId)
|
||||
.and(orderItem.order.orderTime.between(startTime,today)))
|
||||
.groupBy(orderItem.itemId)
|
||||
.orderBy(orderItem.count.sum().desc())
|
||||
.limit(1L)
|
||||
.fetchOne()
|
||||
;
|
||||
}
|
||||
|
||||
public List<DashBoardDto.SellAmountAWeek> salesAmountBetweenAWeek(Long storeId){
|
||||
LocalDateTime today = LocalDateTime.now();
|
||||
LocalDateTime startTime = LocalDateTime.of(today.getYear(),
|
||||
today.getMonth(),
|
||||
today.getDayOfMonth(),
|
||||
0,0)
|
||||
.minusDays(7);
|
||||
|
||||
|
||||
DateTimeTemplate formattedDate =
|
||||
Expressions.dateTimeTemplate(LocalDateTime.class,
|
||||
"CAST({0} AS date) ", orderItem.order.orderTime );
|
||||
|
||||
return queryFactory.
|
||||
select(
|
||||
Projections.fields(DashBoardDto.SellAmountAWeek.class,
|
||||
formattedDate.as("sellDate"),
|
||||
orderItem.price.sum().multiply(orderItem.count.sum()).as("sellAmount")
|
||||
)
|
||||
)
|
||||
.from(orderItem)
|
||||
.join(orderItem.order, order)
|
||||
.where(orderItem.order.storeId.eq(storeId)
|
||||
.and(orderItem.order.orderTime.between(startTime,today)))
|
||||
.groupBy(formattedDate)
|
||||
.fetch();
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.springframework.data.domain.SliceImpl;
|
||||
|
||||
public interface OrderService {
|
||||
OrderMainDto findOrderMain(OrderSearchCondition condition, Long userId);
|
||||
DashBoardDto findDashboard(Long userId);
|
||||
Page<PrevOrderDto> findPrevOrderMain(PrevOrderSearch search, Pageable pageable, Long userId);
|
||||
SliceImpl<OrderHistoryDto> findOrderHistory(Pageable pageable, Long userId);
|
||||
void addItemToBasket(OrderItemDto orderItemDto,Long storeId, Long userId);
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.justpickup.orderservice.domain.orderItemOption.entity.OrderItemOption
|
||||
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;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.domain.Page;
|
||||
@@ -162,7 +163,9 @@ public class OrderServiceImpl implements OrderService {
|
||||
|
||||
//orderItemOption Entity를 생성한다.
|
||||
List<OrderItemOption> orderItemOptions = orderItemDto.getOrderItemOptionDtoList()
|
||||
.stream().map(orderItemOptionDto -> OrderItemOption.of(orderItemDto.getId()))
|
||||
.stream()
|
||||
.filter(orderItemOptionDto -> orderItemOptionDto.getId()!=null)
|
||||
.map(orderItemOptionDto -> OrderItemOption.of(orderItemOptionDto.getId()))
|
||||
.collect(toList());
|
||||
|
||||
//orderItem을 Entity를 생성한다.
|
||||
@@ -174,29 +177,40 @@ public class OrderServiceImpl implements OrderService {
|
||||
//HARD_CODE
|
||||
Long userCouponId=0L;
|
||||
|
||||
Long countByUserIdAndOrderStatus = orderRepository.countByUserIdAndOrderStatus(userId, OrderStatus.PENDING);
|
||||
if(countByUserIdAndOrderStatus>=2) throw new OrderException("장바구니 데이터는 2건 이상 일 수 없습니다.");
|
||||
|
||||
Optional<Order> optionalOrder = orderRepository.findByUserIdAndOrderStatus(userId, OrderStatus.PENDING);
|
||||
if(optionalOrder.isPresent()){
|
||||
if(!optionalOrder.get().addOrderItem(orderItem)
|
||||
.getStoreId().equals(storeId))
|
||||
throw new OrderException("장바구니에 여러 카페의 메뉴를 담을수 없습니다.");
|
||||
}else{
|
||||
|
||||
orderRepository.save(Order.of(userId,userCouponId,storeId,orderItem));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FetchOrderDto fetchOrder(Long userId) {
|
||||
|
||||
//장바구니
|
||||
Order order = orderRepositoryCustom.fetchOrderBasket(userId)
|
||||
.orElseThrow(() -> new OrderException("장바구니 정보를 찾을 수 없습니다."));
|
||||
|
||||
|
||||
// feign 통신 -> store 정보 가져옴
|
||||
GetStoreResponse store = storeClient.getStore(String.valueOf(order.getStoreId())).getData();
|
||||
|
||||
// feign 통신 -> item, option 정보 가져옴
|
||||
List<GetItemResponse> data = storeClient.getItemAndItemOptions(order.getOrderItems().stream()
|
||||
.map(OrderItem::getItemId)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toUnmodifiableList())
|
||||
).getData();
|
||||
|
||||
Map<Long, GetItemResponse> itemMap = data.stream().collect(
|
||||
//itemAndOptionMap
|
||||
Map<Long, GetItemResponse> itemOptionMap = data.stream().collect(
|
||||
Collectors.toMap(
|
||||
GetItemResponse::getId
|
||||
, getItemResponse -> getItemResponse
|
||||
@@ -207,7 +221,7 @@ public class OrderServiceImpl implements OrderService {
|
||||
List<FetchOrderDto.OrderItemDto> orderItemDtoList = order.getOrderItems()
|
||||
.stream().map(orderItem ->
|
||||
new FetchOrderDto.OrderItemDto(
|
||||
itemMap.get(orderItem.getItemId())
|
||||
itemOptionMap.get(orderItem.getItemId())
|
||||
,orderItem))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
@@ -236,6 +250,25 @@ public class OrderServiceImpl implements OrderService {
|
||||
order.setOrderStatus(orderStatus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DashBoardDto findDashboard(Long userId) {
|
||||
|
||||
Result<StoreByUserIdResponse> storeByUserId = storeClient.getStoreByUserId(userId);
|
||||
Long storeId = storeByUserId.getData().getId();
|
||||
|
||||
// 하루 판매금액
|
||||
List<DashBoardDto.OrderPrice> orderPrices = orderRepositoryCustom.salesAmountBetweenADay(storeId);
|
||||
|
||||
// 일주일 판매 상위메뉴
|
||||
DashBoardDto.BestSellItem bestSellItem = orderRepositoryCustom.bestItemBetweenAWeek(storeId);
|
||||
bestSellItem.setItemName(storeClient.getItem(bestSellItem.getItemId()).getData().getName());
|
||||
|
||||
// 일주일 판매금액( 일별 )
|
||||
List<DashBoardDto.SellAmountAWeek> sellAmountAWeeks = orderRepositoryCustom.salesAmountBetweenAWeek(storeId);
|
||||
|
||||
return DashBoardDto.of(orderPrices , bestSellItem, sellAmountAWeeks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrderDetailDto findOrderDetail(Long orderId) {
|
||||
Order order = orderRepository.findById(orderId)
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package com.justpickup.orderservice.domain.order.web;
|
||||
|
||||
import com.justpickup.orderservice.domain.order.dto.OrderMainDto;
|
||||
import com.justpickup.orderservice.domain.order.dto.OrderSearchCondition;
|
||||
import com.justpickup.orderservice.domain.order.dto.PrevOrderDto;
|
||||
import com.justpickup.orderservice.domain.order.dto.PrevOrderSearch;
|
||||
import com.justpickup.orderservice.domain.order.dto.*;
|
||||
import com.justpickup.orderservice.domain.order.entity.OrderStatus;
|
||||
import com.justpickup.orderservice.domain.order.service.OrderService;
|
||||
import com.justpickup.orderservice.domain.order.validator.PrevOrderSearchValidator;
|
||||
@@ -40,6 +37,15 @@ public class OrderOwnerApiController {
|
||||
private final OrderService orderService;
|
||||
private final PrevOrderSearchValidator prevOrderSearchValidator;
|
||||
|
||||
@GetMapping("/dashboard")
|
||||
public ResponseEntity<Result> dashboard( @RequestHeader(value="user-id") String userId) {
|
||||
|
||||
DashBoardDto dashboardDto = orderService.findDashboard(Long.valueOf(userId));
|
||||
|
||||
return ResponseEntity.status(HttpStatus.OK)
|
||||
.body(Result.createSuccessResult(dashboardDto));
|
||||
}
|
||||
|
||||
@GetMapping("/order-main")
|
||||
public ResponseEntity<Result> orderMain(@Valid OrderSearchCondition condition,
|
||||
@RequestHeader(value="user-id") String userHeader) {
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.justpickup.orderservice.domain.orderItem.service;
|
||||
|
||||
import com.justpickup.orderservice.domain.order.entity.Order;
|
||||
import com.justpickup.orderservice.domain.order.entity.OrderStatus;
|
||||
import com.justpickup.orderservice.domain.order.exception.OrderException;
|
||||
import com.justpickup.orderservice.domain.order.repository.OrderRepository;
|
||||
import com.justpickup.orderservice.domain.order.repository.OrderRepositoryCustom;
|
||||
import com.justpickup.orderservice.domain.orderItem.entity.OrderItem;
|
||||
import com.justpickup.orderservice.domain.orderItem.repository.OrderItemRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Transactional(readOnly = true)
|
||||
public class OrderItemService {
|
||||
|
||||
private final OrderItemRepository orderItemRepository;
|
||||
private final OrderRepository orderRepository;
|
||||
private final OrderRepositoryCustom orderRepositoryCustom;
|
||||
|
||||
@Transactional
|
||||
public void deleteOrderItem(Long deleteOrderItemId, Long userId){
|
||||
|
||||
|
||||
Order order = orderRepositoryCustom.fetchOrderBasket(userId)
|
||||
.orElseThrow(() -> new OrderException("존재하지 않는 장바구니 아이템입니다."));
|
||||
|
||||
OrderItem orderItem = orderItemRepository.findById(deleteOrderItemId)
|
||||
.orElseThrow(() -> new OrderException("존재하지 않는 장바구니 아이템입니다."));
|
||||
|
||||
order.deleteOrderItem(orderItem);
|
||||
|
||||
if(order.getOrderItems().size() ==0)
|
||||
orderRepository.delete(order);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.justpickup.orderservice.domain.orderItem.web;
|
||||
|
||||
import com.justpickup.orderservice.domain.orderItem.service.OrderItemService;
|
||||
import com.justpickup.orderservice.global.dto.Result;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/api/customer/orderItem")
|
||||
public class OrderItemCustomerApiController {
|
||||
|
||||
private final OrderItemService orderItemService;
|
||||
|
||||
@DeleteMapping("/{orderItemId}")
|
||||
public ResponseEntity deleteOrderItem(@PathVariable Long orderItemId,
|
||||
@RequestHeader(value = "user-id") String userId){
|
||||
orderItemService.deleteOrderItem(orderItemId,Long.parseLong(userId));
|
||||
|
||||
return ResponseEntity.status(HttpStatus.OK).body(Result.createSuccessResult(orderItemId));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -185,12 +185,15 @@ class OrderCustomerApiControllerTest {
|
||||
new FetchOrderDto(2L,2L,12000L,"저스트카페"
|
||||
,List.of(
|
||||
new FetchOrderDto.OrderItemDto(1L,1L,"카페라테",
|
||||
List.of(new GetItemResponse.ItemOptionDto(2L, OptionType.REQUIRED,"Hot")
|
||||
,new GetItemResponse.ItemOptionDto(2L, OptionType.OTHER,"샷추카")),3000L,32L)
|
||||
List.of(new FetchOrderDto.OrderItemDto.OrderItemOptionDto(2L, OptionType.REQUIRED,"Hot")
|
||||
,new FetchOrderDto.OrderItemDto.OrderItemOptionDto(2L, OptionType.OTHER,"샷추카"))
|
||||
,3000L
|
||||
,32L)
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
|
||||
given(orderService.fetchOrder(2L)).willReturn(fetchOrderDto);
|
||||
//When
|
||||
|
||||
|
||||
@@ -320,4 +320,54 @@ class OrderOwnerApiControllerTest {
|
||||
))
|
||||
;
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("점주 서비스 - 대쉬보드")
|
||||
void findDashboard() throws Exception {
|
||||
// GIVEN
|
||||
|
||||
given(orderService.findDashboard(1L))
|
||||
.willReturn(
|
||||
DashBoardDto.builder()
|
||||
.salesAmount(1237801239L)
|
||||
.bestSellItem(new DashBoardDto.BestSellItem(40L,"까메리카노",3217L))
|
||||
.sellAmountAWeeks(
|
||||
List.of(new DashBoardDto.SellAmountAWeek("2022-03-22",1235L),
|
||||
new DashBoardDto.SellAmountAWeek("2022-03-23",235L),
|
||||
new DashBoardDto.SellAmountAWeek("2022-03-24",2235L),
|
||||
new DashBoardDto.SellAmountAWeek("2022-03-25",1635L),
|
||||
new DashBoardDto.SellAmountAWeek("2022-03-26",35L),
|
||||
new DashBoardDto.SellAmountAWeek("2022-03-27",635L))
|
||||
)
|
||||
.build()
|
||||
);
|
||||
// THEN
|
||||
ResultActions actions = mockMvc.perform(get(url + "/dashboard")
|
||||
.header("user-id", "1")
|
||||
);
|
||||
|
||||
// WHEN
|
||||
actions.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("code").value(Code.SUCCESS.name()))
|
||||
.andDo(print())
|
||||
.andDo(document("owner-findDashboard",
|
||||
requestHeaders(
|
||||
headerWithName("user-id").description("유저 고유번호")
|
||||
),
|
||||
responseFields(
|
||||
fieldWithPath("code").description("결과 코드 SUCCESS/ERROR"),
|
||||
fieldWithPath("message").description("메시지"),
|
||||
fieldWithPath("data").description("데이터"),
|
||||
fieldWithPath("data.salesAmount").description("총 판매금약"),
|
||||
fieldWithPath("data.bestSellItem").description("7일간 베스트 판매 상품"),
|
||||
fieldWithPath("data.bestSellItem.itemId").description("7일간 베스트 판매 상품 고유번호"),
|
||||
fieldWithPath("data.bestSellItem.itemName").description("7일간 베스트 판매 상품명"),
|
||||
fieldWithPath("data.bestSellItem.sumCounts").description("7일간 베스트 판매 상품판매량"),
|
||||
fieldWithPath("data.sellAmountAWeeks").description("7일간 판매 통계"),
|
||||
fieldWithPath("data.sellAmountAWeeks[*].sellDate").description("7일간 판매 통계날짜"),
|
||||
fieldWithPath("data.sellAmountAWeeks[*].sellAmount").description("7일간 판매 통계날짜별 판매량")
|
||||
)
|
||||
))
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.justpickup.orderservice.domain.orderItem.web;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.justpickup.orderservice.config.TestConfig;
|
||||
import com.justpickup.orderservice.domain.order.service.OrderService;
|
||||
import com.justpickup.orderservice.domain.order.web.OrderCustomerApiController;
|
||||
import com.justpickup.orderservice.domain.orderItem.service.OrderItemService;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName;
|
||||
import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders;
|
||||
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||
import static org.springframework.restdocs.request.RequestDocumentation.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@WebMvcTest(OrderItemCustomerApiController.class)
|
||||
@Import(TestConfig.class)
|
||||
@AutoConfigureRestDocs(uriHost = "http://just-pickup.com", uriPort = 8001)
|
||||
class OrderItemCustomerApiControllerTest {
|
||||
|
||||
@Autowired
|
||||
ObjectMapper objectMapper;
|
||||
|
||||
@Autowired
|
||||
MockMvc mockMvc;
|
||||
|
||||
@MockBean
|
||||
OrderItemService orderItemService;
|
||||
|
||||
private final String url = "/api/customer/order";
|
||||
|
||||
@Test
|
||||
@DisplayName("주문 아이템 삭제")
|
||||
void deleteOrderItem() throws Exception{
|
||||
|
||||
//given
|
||||
Long orderItemId = 2L;
|
||||
|
||||
//when
|
||||
ResultActions resultActions = mockMvc.perform(
|
||||
delete("/api/customer/orderItem/{orderItemId}",orderItemId)
|
||||
.header("user-id", "2")
|
||||
);
|
||||
|
||||
//then
|
||||
|
||||
resultActions
|
||||
.andExpect(status().isOk())
|
||||
.andDo(print())
|
||||
.andDo(MockMvcRestDocumentation.document("delete-orderItem",
|
||||
pathParameters(
|
||||
parameterWithName("orderItemId").description("orderItem 고유번호")
|
||||
),
|
||||
requestHeaders(
|
||||
headerWithName("user-id").description("유저 고유번호")
|
||||
),
|
||||
responseFields(
|
||||
fieldWithPath("code").description("결과 코드 SUCCESS/ERROR"),
|
||||
fieldWithPath("message").description("메시지"),
|
||||
fieldWithPath("data").description("orderItem 고유번호")
|
||||
)
|
||||
));
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -10,9 +10,11 @@
|
||||
"dependencies": {
|
||||
"@mdi/js": "^6.5.95",
|
||||
"axios": "^0.26.0",
|
||||
"chart.js": "^2.9.4",
|
||||
"core-js": "^3.6.5",
|
||||
"moment": "^2.29.1",
|
||||
"vue": "^2.6.11",
|
||||
"vue-chartjs": "^3.5.1",
|
||||
"vue-daum-postcode": "^0.10.0",
|
||||
"vue-router": "^3.2.0",
|
||||
"vuedraggable": "^2.24.3",
|
||||
|
||||
@@ -26,6 +26,9 @@ export default {
|
||||
}
|
||||
return axios.patch(process.env.VUE_APP_OWNER_SERVICE_BASEURL + "/order-service/order/" + orderId, body);
|
||||
},
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ export default {
|
||||
addItemOption : function () {
|
||||
if(!this.data) return;
|
||||
|
||||
this.dialog = false
|
||||
this.dialog = !this.dialog
|
||||
this.$emit('addItemOption',this.data,this.optionType)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
md="12"
|
||||
>
|
||||
<v-text-field
|
||||
type="number"
|
||||
v-model="modalData.itemPrice"
|
||||
:rules="[() => !!modalData.itemPrice || 'This field is required']"
|
||||
label="가격*"
|
||||
@@ -65,7 +66,7 @@
|
||||
>
|
||||
<v-select
|
||||
v-model="modalData.requiredOption"
|
||||
:items="modalData.requiredOption"
|
||||
:items="modalData.requiredOptionItems"
|
||||
item-text="name"
|
||||
item-value="id"
|
||||
label="필수 옵션*"
|
||||
@@ -87,7 +88,7 @@
|
||||
>
|
||||
<v-select
|
||||
v-model="modalData.otherOption"
|
||||
:items="modalData.otherOption"
|
||||
:items="modalData.otherOptionItems"
|
||||
item-text="name"
|
||||
item-value="id"
|
||||
label="기타 옵션"
|
||||
|
||||
11
owner-vue/src/js/CustomChart.js
Normal file
11
owner-vue/src/js/CustomChart.js
Normal file
@@ -0,0 +1,11 @@
|
||||
// CustomChart.js
|
||||
import { Line, mixins } from 'vue-chartjs'
|
||||
|
||||
export default {
|
||||
extends: Line,
|
||||
mixins: [mixins.reactiveProp],
|
||||
props:['chartData', 'options'],
|
||||
mounted () {
|
||||
this.renderChart(this.chartData, this.options)
|
||||
}
|
||||
}
|
||||
@@ -24,10 +24,16 @@ const authCheck = async function (to, from, next) {
|
||||
};
|
||||
const routes = [
|
||||
{
|
||||
path: '/order',
|
||||
redirect: 'order',
|
||||
path: '/',
|
||||
redirect: 'dashboard',
|
||||
component: DashboardLayout,
|
||||
children: [
|
||||
{
|
||||
path: '/dashboard',
|
||||
name: 'dashboard',
|
||||
beforeEnter: authCheck,
|
||||
component: () => import('./../views/HomeDashBoard')
|
||||
},
|
||||
{
|
||||
path: '/category',
|
||||
name: 'category',
|
||||
@@ -61,7 +67,7 @@ const routes = [
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/',
|
||||
path: '/login',
|
||||
redirect: 'login',
|
||||
component: AuthLayout,
|
||||
children: [
|
||||
|
||||
171
owner-vue/src/views/HomeDashBoard.vue
Normal file
171
owner-vue/src/views/HomeDashBoard.vue
Normal file
@@ -0,0 +1,171 @@
|
||||
<template>
|
||||
|
||||
<v-container fluid>
|
||||
<v-row>
|
||||
|
||||
<v-col
|
||||
cols="12"
|
||||
sm="6"
|
||||
>
|
||||
<v-card elevation="2" class="rounded-lg" style="border-left: 5px solid #f69653">
|
||||
<v-card-title primary-title>
|
||||
<div>
|
||||
<div class="grey--text">{{ salesAmount.title }}</div>
|
||||
</div>
|
||||
<v-card-text class="d-flex justify-space-between align-center">
|
||||
<h3 class="headline">{{salesAmount.data | currency}}원</h3>
|
||||
<v-avatar size="60" >
|
||||
<v-icon
|
||||
:color="salesAmount.color"
|
||||
size="64"
|
||||
>
|
||||
mdi-currency-usd
|
||||
</v-icon>
|
||||
</v-avatar>
|
||||
</v-card-text>
|
||||
</v-card-title>
|
||||
</v-card>
|
||||
</v-col>
|
||||
|
||||
<v-col
|
||||
cols="12"
|
||||
sm="6"
|
||||
>
|
||||
<v-card elevation="2" class="rounded-lg" style="border-left: 5px solid #ed6856">
|
||||
<v-card-title primary-title>
|
||||
<div>
|
||||
<div class="grey--text">{{ bestSellItem.title }}</div>
|
||||
</div>
|
||||
<v-card-text class="d-flex justify-space-between align-center">
|
||||
<h3 class="headline">{{bestSellItem.data.itemName}} {{ bestSellItem.data.sumCounts }}개</h3>
|
||||
<v-avatar size="60" >
|
||||
<v-icon
|
||||
:color="bestSellItem.color"
|
||||
size="64"
|
||||
>
|
||||
mdi-coffee
|
||||
</v-icon>
|
||||
</v-avatar>
|
||||
</v-card-text>
|
||||
</v-card-title>
|
||||
</v-card>
|
||||
</v-col>
|
||||
<v-col cols="12">
|
||||
<v-card style="border-left: 5px solid #00a8e0">
|
||||
<v-card-title>
|
||||
<v-icon
|
||||
:color="sellAmountAWeeks.color"
|
||||
class="mr-12"
|
||||
size="64"
|
||||
>
|
||||
mdi-currency-usd
|
||||
</v-icon>
|
||||
{{ sellAmountAWeeks.title }}
|
||||
</v-card-title>
|
||||
|
||||
<v-sheet color="transparent">
|
||||
<CustomChart
|
||||
v-if="sellAmountAWeeks.loaded"
|
||||
:chart-data="sellAmountAWeeks.data"
|
||||
:options="sellAmountAWeeks.options"/>
|
||||
</v-sheet>
|
||||
</v-card>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import orderApi from "@/api/order";
|
||||
import CustomChart from "@/js/CustomChart";
|
||||
|
||||
export default {
|
||||
name: "HomeDashBoard",
|
||||
components:{
|
||||
CustomChart
|
||||
},
|
||||
props: ['userInfo'],
|
||||
data() {
|
||||
return {
|
||||
salesAmount: {
|
||||
title: "금일 판매금액",
|
||||
color: "#f69653",
|
||||
data: {}
|
||||
},
|
||||
bestSellItem: {
|
||||
title: "주간베스트 판매상품",
|
||||
color: "#ed6856",
|
||||
data: {}
|
||||
},
|
||||
sellAmountAWeeks: {
|
||||
title: "주간 판매금액 그래프",
|
||||
color: "#00a8e0",
|
||||
loaded:false,
|
||||
options:{
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
|
||||
|
||||
scales: {
|
||||
xAxes: [{
|
||||
ticks:{
|
||||
fontColor : 'rgba(12, 13, 13, 1)',
|
||||
fontSize : 14
|
||||
},
|
||||
}],
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
fontColor : 'rgba(12, 13, 13, 1)',
|
||||
fontSize : 14,
|
||||
userCallback:function (ele) {
|
||||
return Number(ele).toFixed(0).replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g, "$1,") + "원"
|
||||
}
|
||||
},
|
||||
}]
|
||||
}
|
||||
|
||||
},
|
||||
data: {
|
||||
labels: [],
|
||||
datasets: [
|
||||
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async getDashboardData() {
|
||||
const response = await orderApi.findDashboard()
|
||||
this.salesAmount.data = response.data.data.salesAmount
|
||||
this.bestSellItem.data = response.data.data.bestSellItem
|
||||
|
||||
var saleDataset={
|
||||
label: '일별 판매 금액',
|
||||
backgroundColor: '#00a8e0',
|
||||
borderColor: 'rgb(75, 192, 192)',
|
||||
fill: false,
|
||||
data: [],
|
||||
}
|
||||
for (const ele of response.data.data.sellAmountAWeeks) {
|
||||
this.sellAmountAWeeks.data.labels.push(ele.sellDate)
|
||||
saleDataset.data.push( ele.sellAmount)
|
||||
}
|
||||
this.sellAmountAWeeks.data.datasets.push(saleDataset)
|
||||
|
||||
this.sellAmountAWeeks.loaded = true
|
||||
},
|
||||
},
|
||||
async mounted() {
|
||||
this.getDashboardData()
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -1,13 +1,16 @@
|
||||
<template>
|
||||
<v-app id="inspire">
|
||||
<side-bar :drawer="drawer" @drawerEvent="drawer = !drawer"></side-bar>
|
||||
<side-bar :drawer="drawer" @drawerEvent="drawer = !drawer" :userInfo="userInfo"/>
|
||||
<top-bar @drawerEvent="drawer = !drawer"
|
||||
:notificationCounts="notificationCounts"/>
|
||||
:notificationCounts="notificationCounts"
|
||||
:userInfo="userInfo"
|
||||
/>
|
||||
<v-main style="background: #f5f5f540">
|
||||
<v-container class="py-8, px-6" fluid>
|
||||
<router-view
|
||||
v-on:plusCount="notificationCounts++"
|
||||
v-on:minusCount="notificationCounts--"
|
||||
:userInfo="userInfo"
|
||||
></router-view>
|
||||
</v-container>
|
||||
</v-main>
|
||||
@@ -18,6 +21,7 @@
|
||||
import Sidebar from './Sidebar.vue'
|
||||
import Topbar from "./Topbar.vue";
|
||||
import notificationApi from "@/api/notification";
|
||||
import userApi from "@/api/user";
|
||||
|
||||
export default {
|
||||
name: "DashboardLayout",
|
||||
@@ -25,20 +29,27 @@ export default {
|
||||
'side-bar': Sidebar,
|
||||
'top-bar': Topbar
|
||||
},
|
||||
mounted() {
|
||||
this.searchNotificationCounts();
|
||||
async mounted() {
|
||||
await this.searchNotificationCounts();
|
||||
// 사용자 정보 가져오기
|
||||
this.userInfo = await this.getUserInfo();
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
drawer: true,
|
||||
notificationCounts: 0
|
||||
notificationCounts: 0,
|
||||
userInfo: {},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
searchNotificationCounts: async function() {
|
||||
const response = await notificationApi.countsNotification();
|
||||
this.notificationCounts = response.data.data;
|
||||
}
|
||||
},
|
||||
getUserInfo: async function() {
|
||||
const response = await userApi.requestUserInfo();
|
||||
return response.data.data;
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -29,7 +29,7 @@ export default {
|
||||
props: ["drawer"],
|
||||
data() {
|
||||
return {
|
||||
drawer_sidebar:false,
|
||||
drawer_sidebar:null,
|
||||
links: [
|
||||
{name: "지난 주문", url: "/prev-order", icon: "mdi-clipboard-check-outline"},
|
||||
{name: "카테고리", url: "/category", icon: "mdi-shape-outline"},
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
<v-icon>mdi-account-circle</v-icon>
|
||||
</v-avatar>
|
||||
</v-badge>
|
||||
<span class="ml-3">{{ userName }}</span>
|
||||
<span class="ml-3">{{ userInfo.name }}</span>
|
||||
</v-chip>
|
||||
</span>
|
||||
</template>
|
||||
@@ -44,7 +44,7 @@
|
||||
</v-list-item-avatar>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>{{ userName }}</v-list-item-title>
|
||||
<v-list-item-title>{{ userInfo.name }}</v-list-item-title>
|
||||
<v-list-item-subtitle>Logged In</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
@@ -63,27 +63,13 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import userApi from "../../api/user";
|
||||
import authApi from "../../api/auth";
|
||||
|
||||
export default {
|
||||
name: "Topbar",
|
||||
props: ["notificationCounts"],
|
||||
data() {
|
||||
return {
|
||||
userName: '',
|
||||
};
|
||||
},
|
||||
async mounted() {
|
||||
// 사용자 정보 가져오기
|
||||
const data = await this.getUserInfo();
|
||||
this.userName = data.name;
|
||||
},
|
||||
props: ["notificationCounts","userInfo"],
|
||||
methods: {
|
||||
getUserInfo: async function() {
|
||||
const response = await userApi.requestUserInfo();
|
||||
return response.data.data;
|
||||
},
|
||||
|
||||
logout: async function() {
|
||||
await authApi.logout();
|
||||
},
|
||||
|
||||
@@ -44,7 +44,7 @@ export default {
|
||||
name: "LoginUser",
|
||||
mounted() {
|
||||
if (false == jwt.isExpired()) {
|
||||
this.$router.push('/order');
|
||||
this.$router.push('/');
|
||||
}
|
||||
},
|
||||
data: function() {
|
||||
@@ -62,7 +62,7 @@ export default {
|
||||
|
||||
const flag = await userApi.requestLoginUser(this.email, this.password);
|
||||
|
||||
if (flag) await this.$router.push('/order');
|
||||
if (flag) await this.$router.push('/');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,7 +162,9 @@ export default {
|
||||
categoryId: 0,
|
||||
categoryList : [],
|
||||
requiredOption : [],
|
||||
otherOption : []
|
||||
requiredOptionItems : [],
|
||||
otherOption : [],
|
||||
otherOptionItems : []
|
||||
}
|
||||
|
||||
store.getCategoryList()
|
||||
@@ -184,10 +186,14 @@ export default {
|
||||
vm.modalData.itemPrice = item.price;
|
||||
vm.modalData.categoryId = item.categoryId;
|
||||
item.itemOptions.forEach(function(ele){
|
||||
if(ele.optionType === "REQUIRED")
|
||||
if(ele.optionType === "REQUIRED"){
|
||||
vm.modalData.requiredOption.push(ele)
|
||||
else
|
||||
vm.modalData.requiredOptionItems.push(ele)
|
||||
}
|
||||
else{
|
||||
vm.modalData.otherOption.push(ele)
|
||||
vm.modalData.otherOptionItems.push(ele)
|
||||
}
|
||||
})
|
||||
});
|
||||
},
|
||||
@@ -198,17 +204,46 @@ export default {
|
||||
method='put'
|
||||
else
|
||||
method='post'
|
||||
store.saveItem(method,itemData);
|
||||
|
||||
|
||||
var requiredOption = []
|
||||
for (const ele of this.modalData.requiredOption) {
|
||||
if(isNaN(ele)) {
|
||||
requiredOption.push(ele)
|
||||
}else{
|
||||
const option = this.modalData.requiredOptionItems.find(value => value.id == ele)
|
||||
requiredOption.push(option)
|
||||
}
|
||||
}
|
||||
|
||||
var otherOption = []
|
||||
for (const ele of this.modalData.otherOption) {
|
||||
if(isNaN(ele)) {
|
||||
otherOption.push(ele)
|
||||
}else{
|
||||
const option = this.modalData.otherOptionItems.find(value => value.id == ele)
|
||||
otherOption.push(option)
|
||||
}
|
||||
}
|
||||
|
||||
this.modalData.requiredOption = requiredOption
|
||||
this.modalData.otherOption = otherOption
|
||||
store.saveItem(method,itemData)
|
||||
},
|
||||
addItemOption:function (itemOptionValue,type){
|
||||
var item = {
|
||||
name:itemOptionValue,
|
||||
optionType:type
|
||||
}
|
||||
if(type ==='REQUIRED')
|
||||
if(type ==='REQUIRED'){
|
||||
this.modalData.requiredOption.push(item)
|
||||
else
|
||||
this.modalData.requiredOptionItems.push(item)
|
||||
}
|
||||
else{
|
||||
this.modalData.otherOption.push(item)
|
||||
this.modalData.otherOptionItems.push(item)
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ public class ItemRepositoryCustom {
|
||||
|
||||
public Optional<Item> fetchItem(Long itemId){
|
||||
Item fetchItem = queryFactory.selectFrom(item)
|
||||
.join(item.itemOptions, itemOption).fetchJoin()
|
||||
.leftJoin(item.itemOptions, itemOption).fetchJoin()
|
||||
.join(item.category,category).fetchJoin()
|
||||
.where(item.id.eq(itemId))
|
||||
.fetchOne();
|
||||
|
||||
@@ -89,10 +89,23 @@ public class ItemServiceImpl implements ItemService {
|
||||
|
||||
item.setItemNameAndPriceAndCategory(itemName,itemPrice,category);
|
||||
|
||||
|
||||
//item에 해당하는 itemoption 전부조회
|
||||
List<ItemOption> byItem = itemOptionRepository.findByItem(item);
|
||||
|
||||
//itemOptionDtos 없는 itemOption 전부 삭제
|
||||
byItem.forEach(itemOption -> {
|
||||
boolean isDeleted = true;
|
||||
for ( ItemOptionDto itemOptionDto: itemOptionDtos) {
|
||||
if(itemOption.getId().equals(itemOptionDto.getId())) isDeleted = false;
|
||||
}
|
||||
if(isDeleted) itemOptionRepository.delete(itemOption);
|
||||
});
|
||||
|
||||
//id가 없으면 저장
|
||||
itemOptionDtos
|
||||
.forEach(itemOptionDto -> {
|
||||
if(itemOptionDto.getId()!=null) return;
|
||||
if (itemOptionRepository.existsById(itemOptionDto.getId()))
|
||||
if(itemOptionDto.getId()==null)
|
||||
itemOptionRepository.save(ItemOptionDto.createItemOption(itemOptionDto, item));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -9,4 +9,5 @@ import java.util.List;
|
||||
|
||||
public interface ItemOptionRepository extends JpaRepository<ItemOption,Long> {
|
||||
|
||||
List<ItemOption> findByItem(Item item);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user