Merge pull request #18 from Development-team-1/feature/owner-prev-order

Feature/점주 서비스 - 지난 주문 페이지 구현
This commit is contained in:
백창훈
2022-02-14 10:22:59 +09:00
committed by GitHub
13 changed files with 549 additions and 7 deletions

View File

@@ -64,11 +64,17 @@
== snippets 작성 컨벤션
domain-httpRequestCode-etc
== 주문
=== 점주 서비스 - 주문 페이지
== 점주 서비스
=== 주문 페이지
- 페이지 offset : 6
operation::orderMain-get[snippets='curl-request,http-request,http-response,request-parameters,response-fields']
=== 점주 서비스 - 주문 페이지 (잘못된 파라미터 형식)
operation::orderMain-get-badParameterException[snippets='curl-request,http-request,http-response,request-parameters,response-fields']
=== 점주 서비스 - 지난 주문 페이지
operation::prevOrder-get[snippets='curl-request,http-request,http-response,request-parameters,response-fields']
=== 점주 서비스 - 지난 주문 페이지 (잘못된 파라미터 형식)
operation::prevOrder-get-BindException[snippets='curl-request,http-request,http-response,request-parameters,response-fields']

View File

@@ -0,0 +1,31 @@
package com.justpickup.orderservice.domain.order.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.NotNull;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
@Data @NoArgsConstructor @AllArgsConstructor
public class PrevOrderSearch {
@DateTimeFormat(pattern = "yyyy-MM-dd")
@NotNull(message = "시작일은 필수 값입니다.")
private LocalDate startDate;
@DateTimeFormat(pattern = "yyyy-MM-dd")
@NotNull(message = "종료일은 필수 값입니다.")
private LocalDate endDate;
public LocalDateTime getStartDateTime() {
return startDate.atStartOfDay();
}
public LocalDateTime getEndDateTime() {
return LocalDateTime.of(endDate, LocalTime.of(23, 59, 59));
}
}

View File

@@ -1,10 +1,14 @@
package com.justpickup.orderservice.domain.order.repository;
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.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.support.PageableExecutionUtils;
import org.springframework.stereotype.Repository;
import java.time.LocalDateTime;
@@ -48,4 +52,32 @@ public class OrderRepositoryCustom {
return lastOrderId != null ? order.id.lt(lastOrderId) : null;
}
public Page<Order> findPrevOrderMain(PrevOrderSearch search, Pageable pageable, Long storeId) {
// 카운트 가져오기
Long count = queryFactory
.select(order.countDistinct())
.from(order)
.innerJoin(order.transaction)
.where(
order.orderTime.between(search.getStartDateTime(), search.getEndDateTime()),
order.storeId.eq(storeId)
)
.fetchOne();
// 데이터 가져오기
List<Order> orders = queryFactory
.selectFrom(order)
.join(order.transaction).fetchJoin()
.where(
order.orderTime.between(search.getStartDateTime(), search.getEndDateTime()),
order.storeId.eq(storeId)
)
.orderBy(order.orderTime.desc())
.limit(pageable.getPageSize())
.offset(pageable.getOffset())
.distinct()
.fetch();
return PageableExecutionUtils.getPage(orders, pageable, () -> count);
}
}

View File

@@ -2,9 +2,14 @@ package com.justpickup.orderservice.domain.order.service;
import com.justpickup.orderservice.domain.order.dto.OrderDto;
import com.justpickup.orderservice.domain.order.dto.OrderSearchCondition;
import com.justpickup.orderservice.domain.order.dto.PrevOrderSearch;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import java.util.List;
public interface OrderService {
List<OrderDto> findOrderMain(OrderSearchCondition condition, Long storeId);
Page<OrderDto> findPrevOrderMain(PrevOrderSearch search, Pageable pageable, Long storeId);
}

View File

@@ -2,6 +2,8 @@ package com.justpickup.orderservice.domain.order.service;
import com.justpickup.orderservice.domain.order.dto.OrderDto;
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.repository.OrderRepository;
import com.justpickup.orderservice.domain.order.repository.OrderRepositoryCustom;
import com.justpickup.orderservice.global.client.store.GetItemResponse;
@@ -10,6 +12,9 @@ import com.justpickup.orderservice.global.client.user.GetCustomerResponse;
import com.justpickup.orderservice.global.client.user.UserClient;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.support.PageableExecutionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -37,6 +42,27 @@ public class OrderServiceImpl implements OrderService {
.collect(Collectors.toList());
// 사용자명 및 아이템 이름 가져오기
getUserNameAndItemName(orderDtoList);
return orderDtoList;
}
@Override
public Page<OrderDto> findPrevOrderMain(PrevOrderSearch search, Pageable pageable, Long storeId) {
Page<Order> orderPage = orderRepositoryCustom.findPrevOrderMain(search, pageable, storeId);
List<OrderDto> orderDtoList = orderPage.getContent()
.stream()
.map(OrderDto::createFullField)
.collect(Collectors.toList());
// 사용자명 및 아이템 이름 가져오기
getUserNameAndItemName(orderDtoList);
return PageableExecutionUtils.getPage(orderDtoList, pageable, orderPage::getTotalElements);
}
private void getUserNameAndItemName(List<OrderDto> orderDtoList) {
orderDtoList.forEach(orderDto -> {
GetCustomerResponse getCustomerResponse =
userClient.getUser(orderDto.getUserId()).getData();
@@ -49,7 +75,5 @@ public class OrderServiceImpl implements OrderService {
orderItemDto.setItemName(getItemResponse.getName());
});
});
return orderDtoList;
}
}

View File

@@ -0,0 +1,28 @@
package com.justpickup.orderservice.domain.order.validator;
import com.justpickup.orderservice.domain.order.dto.PrevOrderSearch;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import java.time.LocalDate;
@Component
public class PrevOrderSearchValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return PrevOrderSearch.class.equals(clazz);
}
@Override
public void validate(Object target, Errors errors) {
PrevOrderSearch search = (PrevOrderSearch) target;
LocalDate startDate = search.getStartDate();
LocalDate endDate = search.getEndDate();
if (startDate.isAfter(endDate)) {
errors.rejectValue("startDate", "isAfter", "시작일은 종료일보다 클 수 없습니다.");
}
}
}

View File

@@ -2,8 +2,10 @@ package com.justpickup.orderservice.domain.order.web;
import com.justpickup.orderservice.domain.order.dto.OrderDto;
import com.justpickup.orderservice.domain.order.dto.OrderSearchCondition;
import com.justpickup.orderservice.domain.order.dto.PrevOrderSearch;
import com.justpickup.orderservice.domain.order.entity.OrderStatus;
import com.justpickup.orderservice.domain.order.service.OrderService;
import com.justpickup.orderservice.domain.order.validator.PrevOrderSearchValidator;
import com.justpickup.orderservice.domain.orderItem.dto.OrderItemDto;
import com.justpickup.orderservice.global.dto.Result;
import lombok.AllArgsConstructor;
@@ -11,12 +13,18 @@ import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;
@@ -27,9 +35,10 @@ import java.util.stream.Collectors;
public class OrderController {
private final OrderService orderService;
private final PrevOrderSearchValidator prevOrderSearchValidator;
@GetMapping("/orderMain")
public ResponseEntity orderMain(@Valid OrderSearchCondition condition) {
public ResponseEntity<Result> orderMain(@Valid OrderSearchCondition condition) {
// TODO: 2022/02/04 JWT 구현 시 변경 요망
Long userId = 1L;
Long storeId = 1L;
@@ -81,4 +90,70 @@ public class OrderController {
this.itemName = orderItemDto.getItemName();
}
}
@GetMapping("/prevOrder")
public ResponseEntity<Result> findPrevOrder(@Valid PrevOrderSearch prevOrderSearch,
@PageableDefault(page = 0, size = 10) Pageable pageable,
BindingResult bindingResult) throws BindException {
// validation
if (bindingResult.hasErrors()) throw new BindException(bindingResult);
prevOrderSearchValidator.validate(prevOrderSearch, bindingResult);
if (bindingResult.hasErrors()) throw new BindException(bindingResult);
// get data
Page<OrderDto> prevOrderMain = orderService.findPrevOrderMain(prevOrderSearch, pageable, 1L);
// format data
ResponsePrevOrder responsePrevOrder =
new ResponsePrevOrder(prevOrderMain.getContent(), prevOrderMain.getNumber(), prevOrderMain.getTotalPages());
return ResponseEntity.ok(Result.createSuccessResult(responsePrevOrder));
}
@Data @AllArgsConstructor @NoArgsConstructor
static class ResponsePrevOrder {
private List<OrderVo> orders;
private Page page;
public ResponsePrevOrder(List<OrderDto> orderDtoList, int startPage, int totalPage) {
orders = orderDtoList.stream().map(OrderVo::new).collect(Collectors.toList());
page = new Page(startPage, totalPage);
}
@Data
static class OrderVo {
private Long orderId;
private OrderStatus orderStatus;
private String orderTime;
private Long orderPrice;
private String userName;
private List<OrderItemVo> orderItems;
public OrderVo(OrderDto orderDto) {
this.orderId = orderDto.getId();
this.orderStatus = orderDto.getOrderStatus();
this.orderTime = orderDto.getOrderTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
this.orderPrice = orderDto.getOrderPrice();
this.userName = orderDto.getUserName();
this.orderItems = orderDto.getOrderItemDtoList()
.stream().map(OrderItemVo::new).collect(Collectors.toList());
}
}
@Data
static class OrderItemVo {
private Long orderItemId;
private String orderItemName;
public OrderItemVo(OrderItemDto orderItemDto) {
this.orderItemId = orderItemDto.getId();
this.orderItemName = orderItemDto.getItemName();
}
}
@Data @AllArgsConstructor
static class Page {
int startPage;
int totalPage;
}
}
}

View File

@@ -4,8 +4,10 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.justpickup.orderservice.config.TestConfig;
import com.justpickup.orderservice.domain.order.dto.OrderDto;
import com.justpickup.orderservice.domain.order.dto.OrderSearchCondition;
import com.justpickup.orderservice.domain.order.dto.PrevOrderSearch;
import com.justpickup.orderservice.domain.order.entity.OrderStatus;
import com.justpickup.orderservice.domain.order.service.OrderService;
import com.justpickup.orderservice.domain.order.validator.PrevOrderSearchValidator;
import com.justpickup.orderservice.domain.orderItem.dto.OrderItemDto;
import com.justpickup.orderservice.global.dto.Code;
import org.junit.jupiter.api.DisplayName;
@@ -14,11 +16,16 @@ 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.boot.test.mock.mockito.SpyBean;
import org.springframework.context.annotation.Import;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import static org.mockito.BDDMockito.given;
@@ -26,10 +33,11 @@ import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.docu
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.requestParameters;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.restdocs.request.RequestDocumentation.*;
@WebMvcTest(OrderController.class)
@Import(TestConfig.class)
@@ -45,6 +53,9 @@ class OrderControllerTest {
@MockBean
OrderService orderService;
@SpyBean
PrevOrderSearchValidator prevOrderSearchValidator;
@Test
@DisplayName("점주 서비스 - 주문 페이지")
void getOrderMain() throws Exception {
@@ -169,4 +180,101 @@ class OrderControllerTest {
return List.of(orderDto_1, orderDto_2);
}
@Test
@DisplayName("점주 서비스 - 지난 주문 페이지")
void getPrevOrder() throws Exception {
// GIVEN
LocalDate startDate = LocalDate.of(2022, 2, 3);
LocalDate endDate = LocalDate.of(2022, 2, 4);
String page = "0";
PrevOrderSearch search = new PrevOrderSearch(LocalDate.of(2022, 2, 3), LocalDate.of(2022, 2, 4));
PageRequest pageRequest = PageRequest.of(Integer.parseInt(page), 10);
given(orderService.findPrevOrderMain(search, pageRequest, 1L))
.willReturn(
new PageImpl<>(getOrderMainDtoList(), pageRequest, 1)
);
// WHEN
ResultActions actions = mockMvc.perform(get("/prevOrder")
.param("startDate", startDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))
.param("endDate", endDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))
.param("page", page)
);
// THEN
actions.andExpect(status().isOk())
.andExpect(jsonPath("code").value(Code.SUCCESS.name()))
.andExpect(jsonPath("message").isEmpty())
.andExpect(jsonPath("data.orders[*].orderId").exists())
.andExpect(jsonPath("data.orders[*].orderStatus").exists())
.andExpect(jsonPath("data.orders[*].orderTime").exists())
.andExpect(jsonPath("data.orders[*].orderPrice").exists())
.andExpect(jsonPath("data.orders[*].userName").exists())
.andExpect(jsonPath("data.orders[*].orderItems[*].orderItemId").exists())
.andExpect(jsonPath("data.orders[*].orderItems[*].orderItemName").exists())
.andExpect(jsonPath("data.page.startPage").value(0))
.andExpect(jsonPath("data.page.totalPage").value(1))
.andDo(print())
.andDo(document("prevOrder-get",
requestParameters(
parameterWithName("startDate").description("시작날짜 YYYY-MM-DD"),
parameterWithName("endDate").description("종료날짜 YYYY-MM-DD"),
parameterWithName("page").optional().description("검색 페이지 (0부터 시작)")
),
responseFields(
fieldWithPath("code").description("결과 코드 SUCCESS/ERROR"),
fieldWithPath("message").description("메시지"),
fieldWithPath("data.orders[*].orderId").description("주문 고유번호"),
fieldWithPath("data.orders[*].orderStatus").description("주문상태"),
fieldWithPath("data.orders[*].orderTime").description("주문시간"),
fieldWithPath("data.orders[*].orderPrice").description("결제금액"),
fieldWithPath("data.orders[*].userName").description("닉네임"),
fieldWithPath("data.orders[*].orderItems[*].orderItemId").description("주문상품 고유번호"),
fieldWithPath("data.orders[*].orderItems[*].orderItemName").description("주문상품 이름"),
fieldWithPath("data.page.startPage").description("현재 페이지 (0부터 시작)"),
fieldWithPath("data.page.totalPage").description("총 페이지 개수")
)
))
;
}
@Test
@DisplayName("점주 서비스 - 지난 주문 페이지 (파라미터 오류)")
void getPrevOrderBindException() throws Exception {
// GIVEN
LocalDate startDate = LocalDate.of(2023, 2, 3);
LocalDate endDate = LocalDate.of(2022, 2, 4);
String page = "0";
PrevOrderSearch search = new PrevOrderSearch(startDate, endDate);
// THEN
ResultActions actions = mockMvc.perform(get("/prevOrder")
.param("startDate", startDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))
.param("endDate", endDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))
.param("page", page)
);
// WHEN
actions.andExpect(status().isBadRequest())
.andExpect(jsonPath("code").value(Code.ERROR.name()))
.andExpect(jsonPath("message").isNotEmpty())
.andExpect(jsonPath("data").isEmpty())
.andDo(print())
.andDo(document("prevOrder-get-BindException",
requestParameters(
parameterWithName("startDate").description("시작날짜 YYYY-MM-DD"),
parameterWithName("endDate").description("종료날짜 YYYY-MM-DD"),
parameterWithName("page").optional().description("검색 페이지 (0부터 시작)")
),
responseFields(
fieldWithPath("code").description("결과 코드 SUCCESS/ERROR"),
fieldWithPath("message").description("메시지"),
fieldWithPath("data").description("데이터")
)
))
;
}
}

View File

@@ -0,0 +1,13 @@
package com.justpickup.ownerfrontendservice.domain.prevorder.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class PrevOrderController {
@GetMapping("/prev-order")
public String prevOrder() {
return "domain/prev-order/prev-order";
}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,207 @@
<!DOCTYPE html>
<html lang="ko"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layouts/layout}"
>
<head></head>
<div layout:fragment="content">
<!-- Page Heading -->
<h1 class="h3 mb-4 text-gray-800">지난 주문</h1>
<!-- Search Form -->
<form id="search-form" class="mb-4">
<div class="form-row align-items-center">
<div class="col-auto my-1">
<input type="date" class="form-control" id="start-date" name="startDate" />
</div>
<span> ~ </span>
<div class="col-auto my-1">
<input type="date" class="form-control" id="end-date" name="endDate" />
</div>
<div class="col-auto my-1">
<button type="button" class="btn btn-outline-primary" id="confirm">조회</button>
</div>
</div>
<input type="hidden" name="page" id="page" value="0" />
<input type="hidden" id="select-start-date" />
<input type="hidden" id="select-end-date" />
</form>
<h5 class="mb-4" id="header-date"></h5>
<!-- Table -->
<div class="table-responsive-xl">
<table class="table">
<thead>
<tr>
<th scope="col">주문번호</th>
<th scope="col">주문상태</th>
<th scope="col">주문시간</th>
<th scope="col">주문상품</th>
<th scope="col">결제금액</th>
<th scope="col">닉네임</th>
</tr>
</thead>
<tbody id="table-body">
</tbody>
</table>
</div>
<!-- Pagination -->
<nav aria-label="Page navigation example">
<ul class="pagination justify-content-center" id="pagination">
</ul>
</nav>
<script>
const defaultOpts = {
'visiblePages': 10,
'initiateStartPageClick': false,
'first': '<<',
'prev': '<',
'next': '>',
'last': '>>',
'inPageClick': function (event, page) {
clickPage(page - 1);
}
};
function init() {
}
function setEvent() {
$("#confirm").click(() => {
searchPrevOrder();
});
}
function searchPrevOrder() {
if (!dateValidation()) return null;
$("#page").val(0);
getPrevOrderData()
.then((response) => response.json())
.then((myJson) => {
if (myJson.code == "SUCCESS") {
drawHeader();
drawTable(myJson.data.orders, myJson.data.page.startPage + 1, myJson.data.page.totalPage);
drawPagination(myJson.data.orders, myJson.data.page.startPage + 1, myJson.data.page.totalPage);
return;
}
if (myJson.code == "ERROR") {
alert(myJson.message);
return;
}
});
}
function clickPage(page) {
if (!dateValidation()) return null;
$("#page").val(page);
getPrevOrderData()
.then((response) => response.json())
.then((myJson) => {
if (myJson.code == "SUCCESS") {
drawHeader();
drawTable(myJson.data.orders, myJson.data.page.startPage + 1, myJson.data.page.totalPage);
return;
}
if (myJson.code == "ERROR") {
alert(myJson.message());
return;
}
});
}
function drawHeader() {
let text = $("#start-date").val() + " ~ " + $("#end-date").val() + " 주문내역";
$("#header-date").html(text);
}
function drawTable(data, startPage, totalPage) {
$("#table-body").empty();
if (data.length <= 0) {
$("#table-body").html("<td>검색 결과가 없습니다.</td>");
return;
}
const limit = 10;
let html = "";
let rownum = (startPage - 1) * limit
for (let index = 0; index < data.length; index++) {
let order = data[index];
let tr = "<tr>";
tr += "<th scope=\"row\">" + ++rownum + "</th>\n";
tr += "<td>" + order.orderStatus + "</td>\n";
tr += "<td>" + order.orderTime + "</td>\n";
let orderItemNames = [];
order.orderItems.forEach(orderItem => {
orderItemNames.push(orderItem.orderItemName);
});
tr += "<td><span class=\"d-inline-block text-truncate\" style=\"max-width: 80%\">"
+ orderItemNames.join(", ")
+ "</span></td>\n";
tr += "<td>" + order.orderPrice + "</td>\n";
tr += "<td>" + order.userName + "</td>\n";
tr += "</tr>";
html += tr;
}
$("#table-body").html(html);
}
function drawPagination(data, startPage, totalPages) {
$("#pagination").twbsPagination('destroy');
if (data.length <= 0) return;
$("#pagination").twbsPagination($.extend({}, defaultOpts, {
startPage: startPage,
totalPages: totalPages,
}));
}
function dateValidation() {
const startDateTag = document.querySelector("#start-date");
const endDateTag = document.querySelector("#end-date");
if (!startDateTag.value) {
alert("시작일을 선택해주세요.");
startDateTag.focus();
return false;
}
if (!endDateTag.value) {
alert("종료일을 선택해주세요");
endDateTag.focus();
return false;
}
let startDate = startDateTag.valueAsDate;
let endDate = endDateTag.valueAsDate;
if (startDate.getTime() > endDate.getTime()) {
alert("시작일은 종료일보다 클 수 없습니다.");
startDateTag.focus();
return false;
}
return true;
}
function getPrevOrderData() {
let params = $("#search-form").serialize();
return fetch(url.orderService + "/prevOrder?" + params);
}
</script>
</div>
</html>

View File

@@ -49,7 +49,7 @@
</li>
<li class="nav-item">
<a class="nav-link" href="order">
<a class="nav-link" href="category">
<i class="fas fa-fw fa-table"></i>
<span>카테고리 관리</span></a>
</li>

View File

@@ -56,6 +56,9 @@
<!-- Page level plugins -->
<script src="vendor/chart.js/Chart.min.js"></script>
<!-- Pagination plugins -->
<script src="vendor/twbs-pagination/jquery.pwbsPagination.min.js"></script>
<script src="common.js"></script>
<script>
$(function() {