Merge pull request #20 from Development-team-1/owner-vue
점주용 페이지 vue.js로 변경
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/owner-vue/node_modules/
|
||||
8
config-service/.idea/.gitignore
generated
vendored
Normal file
8
config-service/.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# 디폴트 무시된 파일
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# 에디터 기반 HTTP 클라이언트 요청
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
@@ -14,6 +14,16 @@ spring:
|
||||
|
||||
cloud:
|
||||
gateway:
|
||||
globalcors:
|
||||
cors-configurations:
|
||||
'[/**]':
|
||||
allowedOrigins: "http://localhost:8080"
|
||||
allowedMethods:
|
||||
- POST
|
||||
- GET
|
||||
- PUT
|
||||
- OPTIONS
|
||||
- DELETE
|
||||
routes:
|
||||
- id: owner-frontend-service
|
||||
uri: lb://OWNER-FRONTEND-SERVICE
|
||||
@@ -67,4 +77,4 @@ token:
|
||||
refresh-expired-time: 604800000
|
||||
secret: my-secret
|
||||
refresh-token-name: refresh-token
|
||||
access-token-name: access-token
|
||||
access-token-name: access-token
|
||||
|
||||
8
owner-vue/.idea/.gitignore
generated
vendored
Normal file
8
owner-vue/.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# 디폴트 무시된 파일
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# 에디터 기반 HTTP 클라이언트 요청
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
5
owner-vue/babel.config.js
Normal file
5
owner-vue/babel.config.js
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@vue/cli-plugin-babel/preset'
|
||||
]
|
||||
}
|
||||
54
owner-vue/package.json
Normal file
54
owner-vue/package.json
Normal file
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"name": "owner-admin",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@mdi/js": "^6.5.95",
|
||||
"axios": "^0.26.0",
|
||||
"core-js": "^3.6.5",
|
||||
"moment": "^2.29.1",
|
||||
"vue": "^2.6.11",
|
||||
"vue-router": "^3.2.0",
|
||||
"vuedraggable": "^2.24.3",
|
||||
"vuetify": "^2.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@mdi/font": "^6.1.95",
|
||||
"@vue/cli-plugin-babel": "~4.5.0",
|
||||
"@vue/cli-plugin-eslint": "~4.5.0",
|
||||
"@vue/cli-plugin-router": "~4.5.0",
|
||||
"@vue/cli-service": "~4.5.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"eslint": "^6.7.2",
|
||||
"eslint-plugin-vue": "^6.2.2",
|
||||
"sass": "~1.32.0",
|
||||
"sass-loader": "^10.0.0",
|
||||
"vue-cli-plugin-vuetify": "~2.4.2",
|
||||
"vue-template-compiler": "^2.6.11",
|
||||
"vuetify-loader": "^1.7.0"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
"env": {
|
||||
"node": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:vue/essential",
|
||||
"eslint:recommended"
|
||||
],
|
||||
"parserOptions": {
|
||||
"parser": "babel-eslint"
|
||||
},
|
||||
"rules": {}
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"not dead"
|
||||
]
|
||||
}
|
||||
BIN
owner-vue/public/favicon.ico
Normal file
BIN
owner-vue/public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
18
owner-vue/public/index.html
Normal file
18
owner-vue/public/index.html
Normal file
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900">
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
||||
28
owner-vue/src/App.vue
Normal file
28
owner-vue/src/App.vue
Normal file
@@ -0,0 +1,28 @@
|
||||
<template>
|
||||
<v-app id="inspire">
|
||||
<Sidebar :drawer="drawer" />
|
||||
<Topbar @drawerEvent="drawer = !drawer" />
|
||||
<v-main style="background: #f5f5f540">
|
||||
<v-container class="py-8 px-6" fluid>
|
||||
<router-view></router-view>
|
||||
</v-container>
|
||||
</v-main>
|
||||
</v-app>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Sidebar from "./components/Sidebar";
|
||||
import Topbar from "./components/Topbar";
|
||||
|
||||
export default {
|
||||
name: "App",
|
||||
components: { Topbar, Sidebar},
|
||||
data: () => ({
|
||||
cards: ["Today", "Yesterday"],
|
||||
drawer: null,
|
||||
}),
|
||||
mounted() {
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
23
owner-vue/src/api/order.js
Normal file
23
owner-vue/src/api/order.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import axios from "axios";
|
||||
|
||||
export default {
|
||||
requestPrevOrder(startDate, endDate, page) {
|
||||
const options = {
|
||||
params: {
|
||||
startDate: startDate,
|
||||
endDate: endDate,
|
||||
page: page
|
||||
}
|
||||
}
|
||||
return axios.get("http://localhost:8001/order-service/prevOrder", options);
|
||||
},
|
||||
requestOrder(orderDate, lastOrderId) {
|
||||
const options = {
|
||||
params: {
|
||||
orderDate: orderDate,
|
||||
lastOrderId: lastOrderId
|
||||
}
|
||||
}
|
||||
return axios.get("http://localhost:8001/order-service/orderMain", options);
|
||||
}
|
||||
}
|
||||
BIN
owner-vue/src/assets/logo.png
Normal file
BIN
owner-vue/src/assets/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.7 KiB |
1
owner-vue/src/assets/logo.svg
Normal file
1
owner-vue/src/assets/logo.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 87.5 100"><defs><style>.cls-1{fill:#1697f6;}.cls-2{fill:#7bc6ff;}.cls-3{fill:#1867c0;}.cls-4{fill:#aeddff;}</style></defs><title>Artboard 46</title><polyline class="cls-1" points="43.75 0 23.31 0 43.75 48.32"/><polygon class="cls-2" points="43.75 62.5 43.75 100 0 14.58 22.92 14.58 43.75 62.5"/><polyline class="cls-3" points="43.75 0 64.19 0 43.75 48.32"/><polygon class="cls-4" points="64.58 14.58 87.5 14.58 43.75 100 43.75 62.5 64.58 14.58"/></svg>
|
||||
|
After Width: | Height: | Size: 539 B |
55
owner-vue/src/components/DatePicker.vue
Normal file
55
owner-vue/src/components/DatePicker.vue
Normal file
@@ -0,0 +1,55 @@
|
||||
<template>
|
||||
<v-menu
|
||||
v-model="isPop"
|
||||
:close-on-content-click="false"
|
||||
:nudge-right="40"
|
||||
transition="scale-transition"
|
||||
offset-y
|
||||
min-width="auto"
|
||||
>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-text-field
|
||||
v-model="value"
|
||||
:label="label"
|
||||
prepend-icon="mdi-calendar"
|
||||
readonly
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
></v-text-field>
|
||||
</template>
|
||||
<v-date-picker
|
||||
v-model="value"
|
||||
@input="input">
|
||||
</v-date-picker>
|
||||
</v-menu>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const moment = require('moment');
|
||||
|
||||
export default {
|
||||
name: "DatePicker",
|
||||
props: {
|
||||
'label': String
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
isPop: false,
|
||||
value: moment().format('YYYY-MM-DD')
|
||||
}
|
||||
},
|
||||
created: function() {
|
||||
this.$emit('inputDate', this.value);
|
||||
},
|
||||
methods: {
|
||||
input: function() {
|
||||
this.isPop = false;
|
||||
this.$emit('inputDate', this.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
44
owner-vue/src/components/OrderCard.vue
Normal file
44
owner-vue/src/components/OrderCard.vue
Normal file
@@ -0,0 +1,44 @@
|
||||
<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>상세보기</v-btn>
|
||||
</v-toolbar>
|
||||
<v-card-title>{{ itemNames.join(", ") }}</v-card-title>
|
||||
<v-card-subtitle></v-card-subtitle>
|
||||
<v-card-text>{{ orderTime }}</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-btn v-if="orderStatus === 'PENDING'"
|
||||
block depressed color="primary">
|
||||
주문 대기
|
||||
</v-btn>
|
||||
<v-btn v-else-if="orderStatus === 'PLACED'"
|
||||
block depressed color="primary">
|
||||
주문 수령
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "OrderCard",
|
||||
data: function() {
|
||||
return {
|
||||
|
||||
};
|
||||
},
|
||||
props: {
|
||||
orderId: Number,
|
||||
userName: Number,
|
||||
itemNames: [],
|
||||
orderTime: String,
|
||||
orderStatus: String
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
52
owner-vue/src/components/Sidebar.vue
Normal file
52
owner-vue/src/components/Sidebar.vue
Normal file
@@ -0,0 +1,52 @@
|
||||
<template>
|
||||
<!-- <v-navigation-drawer v-model="drawer" app> -->
|
||||
<v-navigation-drawer app>
|
||||
<v-img
|
||||
height="140"
|
||||
class="pa-4"
|
||||
src="https://preview.pixlr.com/images/800wm/1439/2/1439104804.jpg"
|
||||
>
|
||||
<div class="text-center">
|
||||
<v-avatar class="mb-4" color="grey darken-1" size="64">
|
||||
<v-img
|
||||
aspect-ratio="30"
|
||||
src="https://yt3.ggpht.com/esazPAO03T0f0vKdByJvkDy6MSwjyG5f-c_2S2CJapszQ3KPQyZarpoqvgv0Us0atUbILytj=s88-c-k-c0x00ffffff-no-rj"
|
||||
/>
|
||||
</v-avatar>
|
||||
<h2 class="white--text">Web Burden</h2>
|
||||
</div>
|
||||
</v-img>
|
||||
<v-divider></v-divider>
|
||||
<v-list>
|
||||
<v-list-item v-for="[icon, text] in links" :key="icon" link>
|
||||
<v-list-item-icon>
|
||||
<v-icon>{{ icon }}</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>{{ text }}</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-navigation-drawer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "Sidebar",
|
||||
props: ["drawer"],
|
||||
data() {
|
||||
return {
|
||||
links: [
|
||||
["mdi-microsoft-windows", "Dashboard"],
|
||||
["mdi-account", "Profile"],
|
||||
["mdi-clipboard-list-outline", "Products"],
|
||||
["mdi-card-account-details-outline", "Orders"],
|
||||
["mdi-cog", "System Setting"],
|
||||
],
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
149
owner-vue/src/components/Topbar.vue
Normal file
149
owner-vue/src/components/Topbar.vue
Normal file
@@ -0,0 +1,149 @@
|
||||
<template>
|
||||
<v-app-bar app elevate-on-scroll elevation="3" color="white">
|
||||
<v-app-bar-nav-icon @click="$emit('drawerEvent')"></v-app-bar-nav-icon>
|
||||
<v-spacer />
|
||||
<v-col lg="6" cols="12">
|
||||
<v-form>
|
||||
<v-text-field
|
||||
class="p-0 m-0 mt-6"
|
||||
full-width
|
||||
dense
|
||||
append-icon="mdi-magnify"
|
||||
outlined
|
||||
rounded
|
||||
placeholder="Search"
|
||||
/>
|
||||
</v-form>
|
||||
</v-col>
|
||||
<v-spacer />
|
||||
<v-menu offset-y>
|
||||
<template v-slot:activator="{ attrs, on }">
|
||||
<span
|
||||
class="mx-5 mr-10"
|
||||
style="cursor: pointer"
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
>
|
||||
<v-badge content="3" color="red" offset-y="10" offset-x="10">
|
||||
<v-icon>mdi-bell</v-icon>
|
||||
</v-badge>
|
||||
</span>
|
||||
</template>
|
||||
<v-list three-line width="250">
|
||||
<template v-for="(item, index) in items">
|
||||
<v-subheader
|
||||
v-if="item.header"
|
||||
:key="item.header"
|
||||
v-text="item.header"
|
||||
></v-subheader>
|
||||
|
||||
<v-divider
|
||||
v-else-if="item.divider"
|
||||
:key="index"
|
||||
:inset="item.inset"
|
||||
></v-divider>
|
||||
|
||||
<v-list-item v-else :key="item.title">
|
||||
<v-list-item-avatar>
|
||||
<v-img :src="item.avatar"></v-img>
|
||||
</v-list-item-avatar>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-title v-html="item.title"></v-list-item-title>
|
||||
<v-list-item-subtitle
|
||||
v-html="item.subtitle"
|
||||
></v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</template>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
<v-menu offset-y>
|
||||
<template v-slot:activator="{ attrs, on }">
|
||||
<span style="cursor: pointer" v-bind="attrs" v-on="on">
|
||||
<v-chip link>
|
||||
<v-badge dot bottom color="green" offset-y="10" offset-x="10">
|
||||
<v-avatar size="40">
|
||||
<v-img src="https://randomuser.me/api/portraits/women/81.jpg" />
|
||||
</v-avatar>
|
||||
</v-badge>
|
||||
<span class="ml-3">Jane Smith</span>
|
||||
</v-chip>
|
||||
</span>
|
||||
</template>
|
||||
<v-list width="250" class="py-0">
|
||||
<v-list-item two-line>
|
||||
<v-list-item-avatar>
|
||||
<img src="https://randomuser.me/api/portraits/women/81.jpg" />
|
||||
</v-list-item-avatar>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>Jane Smith</v-list-item-title>
|
||||
<v-list-item-subtitle>Logged In</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<v-divider />
|
||||
<v-list-item link v-for="(menu, i) in menus" :key="i">
|
||||
<v-list-item-icon>
|
||||
<v-icon>{{ menu.icon }}</v-icon>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-title>
|
||||
{{ menu.title }}
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</v-app-bar>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "Topbar",
|
||||
data() {
|
||||
return {
|
||||
menus: [
|
||||
{ title: "Profile", icon: "mdi-account" },
|
||||
{ title: "Change Password", icon: "mdi-key" },
|
||||
{ title: "Setting", icon: "mdi-cog" },
|
||||
{ title: "Logout", icon: "mdi-logout" },
|
||||
],
|
||||
items: [
|
||||
{
|
||||
avatar: "https://cdn.vuetifyjs.com/images/lists/1.jpg",
|
||||
title: "Brunch this weekend?",
|
||||
subtitle: `<span class="text--primary">Ali Connors</span> — I'll be in your neighborhood doing errands this weekend. Do you want to hang out?`,
|
||||
},
|
||||
{ divider: true, inset: true },
|
||||
{
|
||||
avatar: "https://cdn.vuetifyjs.com/images/lists/2.jpg",
|
||||
title: 'Summer BBQ <span class="grey--text text--lighten-1">4</span>',
|
||||
subtitle: `<span class="text--primary">to Alex, Scott, Jennifer</span> — Wish I could come, but I'm out of town this weekend.`,
|
||||
},
|
||||
{ divider: true, inset: true },
|
||||
{
|
||||
avatar: "https://cdn.vuetifyjs.com/images/lists/3.jpg",
|
||||
title: "Oui oui",
|
||||
subtitle:
|
||||
'<span class="text--primary">Sandra Adams</span> — Do you have Paris recommendations? Have you ever been?',
|
||||
},
|
||||
{ divider: true, inset: true },
|
||||
{
|
||||
avatar: "https://cdn.vuetifyjs.com/images/lists/4.jpg",
|
||||
title: "Birthday gift",
|
||||
subtitle:
|
||||
'<span class="text--primary">Trevor Hansen</span> — Have any ideas about what we should get Heidi for her birthday?',
|
||||
},
|
||||
{ divider: true, inset: true },
|
||||
{
|
||||
avatar: "https://cdn.vuetifyjs.com/images/lists/5.jpg",
|
||||
title: "Recipe to try",
|
||||
subtitle:
|
||||
'<span class="text--primary">Britta Holt</span> — We should eat this: Grate, Squash, Corn, and tomatillo Tacos.',
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
16
owner-vue/src/main.js
Normal file
16
owner-vue/src/main.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import 'font-awesome/css/font-awesome.min.css' // Ensure you are using css-loader
|
||||
import Vue from 'vue'
|
||||
import App from './App.vue'
|
||||
import vuetify from './plugins/vuetify'
|
||||
import router from './router'
|
||||
import axios from "axios";
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
new Vue({
|
||||
vuetify,
|
||||
router,
|
||||
render: h => h(App)
|
||||
}).$mount('#app')
|
||||
Vue.component('axios',axios)
|
||||
|
||||
11
owner-vue/src/plugins/vuetify.js
Normal file
11
owner-vue/src/plugins/vuetify.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import '@mdi/font/css/materialdesignicons.css'
|
||||
import Vue from 'vue';
|
||||
import Vuetify from 'vuetify/lib/framework';
|
||||
|
||||
Vue.use(Vuetify);
|
||||
|
||||
export default new Vuetify({
|
||||
icons: {
|
||||
iconfont: 'mdi', // default - only for display purposes
|
||||
},
|
||||
});
|
||||
40
owner-vue/src/router/index.js
Normal file
40
owner-vue/src/router/index.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import Vue from 'vue'
|
||||
import VueRouter from 'vue-router'
|
||||
|
||||
Vue.use(VueRouter)
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: '/',
|
||||
name: 'dashboard',
|
||||
component: () => import('./../views/Dashboard')
|
||||
},
|
||||
{
|
||||
path: '/category',
|
||||
name: 'category',
|
||||
component: () => import('./../views/Category')
|
||||
},
|
||||
{
|
||||
path: '/menu',
|
||||
name: 'menu',
|
||||
component: () => import('./../views/Menu')
|
||||
},
|
||||
{
|
||||
path: '/prev-order',
|
||||
name: 'prev-order',
|
||||
component: () => import('./../views/PrevOrder')
|
||||
},
|
||||
{
|
||||
path: '/order',
|
||||
name: 'order',
|
||||
component: () => import('./../views/Order.vue')
|
||||
}
|
||||
]
|
||||
|
||||
const router = new VueRouter({
|
||||
mode: 'history',
|
||||
base: process.env.BASE_URL,
|
||||
routes
|
||||
})
|
||||
|
||||
export default router
|
||||
5
owner-vue/src/views/About.vue
Normal file
5
owner-vue/src/views/About.vue
Normal file
@@ -0,0 +1,5 @@
|
||||
<template>
|
||||
<div class="about">
|
||||
<h1>This is an about page</h1>
|
||||
</div>
|
||||
</template>
|
||||
150
owner-vue/src/views/Category.vue
Normal file
150
owner-vue/src/views/Category.vue
Normal file
@@ -0,0 +1,150 @@
|
||||
<template>
|
||||
<div>
|
||||
<v-subheader class="py-0 d-flex justify-space-between rounded-lg">
|
||||
<h3>Category List</h3>
|
||||
<div style="text-align: right">
|
||||
<span class="group pa-2">
|
||||
<v-btn
|
||||
elevation="2"
|
||||
icon
|
||||
color="success"
|
||||
@click="clickAdd"
|
||||
><v-icon>{{ icons.mdiPlus }}</v-icon></v-btn>
|
||||
</span>
|
||||
<v-btn
|
||||
elevation="2"
|
||||
icon
|
||||
color="primary"
|
||||
@click="clickSave"
|
||||
><v-icon>{{ icons.mdiContentSave }}</v-icon></v-btn>
|
||||
</div>
|
||||
|
||||
</v-subheader>
|
||||
|
||||
<v-expansion-panels style="display: block">
|
||||
<draggable v-model="categoryList" id="categoryEl" >
|
||||
<v-expansion-panel
|
||||
v-for="item in categoryList" :key="item.categoryId" class="category-item" :data-id="item.categoryId"
|
||||
>
|
||||
<v-expansion-panel-header >
|
||||
<span contenteditable="true" >{{ item.name }}</span>
|
||||
|
||||
<template v-slot:actions>
|
||||
<v-btn
|
||||
elevation="2"
|
||||
icon
|
||||
@click.stop="clickDelete($event)"
|
||||
><v-icon>{{ icons.mdiDelete }}</v-icon></v-btn>
|
||||
</template>
|
||||
|
||||
</v-expansion-panel-header>
|
||||
<v-expansion-panel-content>
|
||||
item-list
|
||||
</v-expansion-panel-content>
|
||||
</v-expansion-panel>
|
||||
</draggable>
|
||||
</v-expansion-panels>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import draggable from 'vuedraggable'
|
||||
import {
|
||||
mdiContentSave, mdiDelete,
|
||||
mdiPlus,
|
||||
} from '@mdi/js'
|
||||
import axios from "axios";
|
||||
|
||||
export default {
|
||||
name: "Category",
|
||||
components:{
|
||||
draggable
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
icons: {
|
||||
mdiContentSave,
|
||||
mdiPlus,
|
||||
mdiDelete,
|
||||
},
|
||||
categoryList: [
|
||||
|
||||
],
|
||||
deletedList: []
|
||||
}
|
||||
},
|
||||
methods:{
|
||||
clickAdd:function (){
|
||||
var count = this.categoryList.length+1
|
||||
var item = {
|
||||
name: 'new Category',
|
||||
order:count
|
||||
}
|
||||
this.categoryList.push(item)
|
||||
},
|
||||
clickDelete:function (event){
|
||||
var category = event.currentTarget.parentNode.parentNode.parentNode;
|
||||
let delCategory = {
|
||||
categoryId : category.dataset.id,
|
||||
name : category.children[0].children[0].innerHTML,
|
||||
}
|
||||
this.deletedList.push(delCategory)
|
||||
category.remove();
|
||||
},
|
||||
clickSave:function (){
|
||||
var vm =this;
|
||||
let data = {
|
||||
storeId : "1",
|
||||
categoryList: [],
|
||||
deletedList: vm.deletedList
|
||||
}
|
||||
|
||||
var categoryEl = document.querySelector("#categoryEl");
|
||||
categoryEl.childNodes.forEach(function(item ,index){
|
||||
let category = {
|
||||
categoryId : item.dataset.id,
|
||||
name : item.children[0].children[0].innerHTML,
|
||||
order : index+1
|
||||
}
|
||||
data.categoryList.push(category)
|
||||
})
|
||||
axios({
|
||||
method:'put',
|
||||
url:'/store-service/category',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json;charset=UTF-8'
|
||||
},
|
||||
data: data,
|
||||
responseType:'json'
|
||||
})
|
||||
.then(function (response) {
|
||||
console.log(response)
|
||||
vm.deletedList=[]
|
||||
vm.getCategoryList()
|
||||
});
|
||||
|
||||
},
|
||||
getCategoryList:function(){
|
||||
var vm =this;
|
||||
axios({
|
||||
method:'get',
|
||||
url:'/store-service/category',
|
||||
responseType:'json'
|
||||
})
|
||||
.then(function (response) {
|
||||
console.log(response.data.data)
|
||||
vm.categoryList = response.data.data;
|
||||
});
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getCategoryList();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
212
owner-vue/src/views/Dashboard.vue
Normal file
212
owner-vue/src/views/Dashboard.vue
Normal file
@@ -0,0 +1,212 @@
|
||||
<template>
|
||||
<div class="dashboard">
|
||||
<v-subheader class="py-0 d-flex justify-space-between rounded-lg">
|
||||
<h3>Dashboard</h3>
|
||||
<v-btn color="success">
|
||||
View Orders
|
||||
</v-btn>
|
||||
</v-subheader>
|
||||
<br>
|
||||
<v-row>
|
||||
<v-col lg="7" cols="12">
|
||||
<v-alert dense text type="success">
|
||||
Login Successfully! Welcome to <strong>Web Burden</strong>
|
||||
</v-alert>
|
||||
<v-row>
|
||||
<v-col lg="6" cols="12" v-for="(item,index) in activityLog" :key="index">
|
||||
<v-card elevation="2" class="rounded-lg">
|
||||
<v-card-text class="d-flex justify-space-between align-center">
|
||||
<div>
|
||||
<strong>{{ item.title }}</strong> <br>
|
||||
<span>Last 3 weeks</span>
|
||||
</div>
|
||||
<v-avatar size="60" :color="item.color" style="border: 3px solid #444">
|
||||
<span style="color: white">{{item.amount}} +</span>
|
||||
</v-avatar>
|
||||
</v-card-text>
|
||||
<v-card-actions class="d-flex justify-space-between">
|
||||
|
||||
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-col>
|
||||
<v-col cols="12" lg="5">
|
||||
<v-card>
|
||||
<v-card-title>Activities</v-card-title>
|
||||
<v-card-text class="py-0">
|
||||
<v-timeline align-top dense>
|
||||
<v-timeline-item color="indigo" small>
|
||||
<strong>5 Minuts ago</strong>
|
||||
<div class="text-caption">
|
||||
You have new order please check this out
|
||||
</div>
|
||||
</v-timeline-item>
|
||||
<v-timeline-item color="green" small>
|
||||
<strong>35 Minuts ago</strong>
|
||||
<div class="text-caption mb-2">
|
||||
A Product has delivered!
|
||||
</div>
|
||||
</v-timeline-item>
|
||||
|
||||
<v-timeline-item color="indigo" small>
|
||||
<strong>44 Minuts ago</strong>
|
||||
<div class="text-caption">
|
||||
You have new order please check this out
|
||||
</div>
|
||||
</v-timeline-item>
|
||||
</v-timeline>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-col>
|
||||
<v-col>
|
||||
<v-card>
|
||||
<v-data-table
|
||||
caption="Recent Order list"
|
||||
:headers="headers"
|
||||
:items="desserts"
|
||||
:items-per-page="5"
|
||||
class="elevation-1"
|
||||
>
|
||||
<template v-slot:item.action="">
|
||||
<v-btn color="success" outlined small shaped >View</v-btn>
|
||||
</template>
|
||||
</v-data-table>
|
||||
</v-card>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "Dashboard",
|
||||
data() {
|
||||
return {
|
||||
activityLog: [
|
||||
{title: 'Total Products', amount: 50, icon: 'mdi-account', color: 'cyan lighten-3'},
|
||||
{title: 'Total Customer', amount: 3433, icon: 'mdi-account-group-outline', color: 'green darken-2'},
|
||||
{title: 'Total Sale', amount: 3433, icon: 'mdi-account-group-outline', color: 'blue-grey darken-1'},
|
||||
{
|
||||
title: 'Pending Orders',
|
||||
amount: 3433,
|
||||
icon: 'mdi-account-group-outline',
|
||||
color: 'deep-orange darken-1'
|
||||
},
|
||||
],
|
||||
headers: [
|
||||
{
|
||||
text: 'Dessert (100g serving)',
|
||||
align: 'start',
|
||||
sortable: false,
|
||||
value: 'name',
|
||||
},
|
||||
{text: 'Calories', value: 'calories'},
|
||||
{text: 'Fat (g)', value: 'fat'},
|
||||
{text: 'Carbs (g)', value: 'carbs'},
|
||||
{text: 'Protein (g)', value: 'protein'},
|
||||
{text: 'Iron (%)', value: 'iron'},
|
||||
{text: 'Actions', value: 'action'},
|
||||
],
|
||||
desserts: [
|
||||
{
|
||||
name: 'Frozen Yogurt',
|
||||
calories: 159,
|
||||
fat: 6.0,
|
||||
carbs: 24,
|
||||
protein: 4.0,
|
||||
iron: '1%',
|
||||
},
|
||||
{
|
||||
name: 'Ice cream sandwich',
|
||||
calories: 237,
|
||||
fat: 9.0,
|
||||
carbs: 37,
|
||||
protein: 4.3,
|
||||
iron: '1%',
|
||||
},
|
||||
{
|
||||
name: 'Eclair',
|
||||
calories: 262,
|
||||
fat: 16.0,
|
||||
carbs: 23,
|
||||
protein: 6.0,
|
||||
iron: '7%',
|
||||
},
|
||||
{
|
||||
name: 'Cupcake',
|
||||
calories: 305,
|
||||
fat: 3.7,
|
||||
carbs: 67,
|
||||
protein: 4.3,
|
||||
iron: '8%',
|
||||
},
|
||||
{
|
||||
name: 'Gingerbread',
|
||||
calories: 356,
|
||||
fat: 16.0,
|
||||
carbs: 49,
|
||||
protein: 3.9,
|
||||
iron: '16%',
|
||||
},
|
||||
{
|
||||
name: 'Jelly bean',
|
||||
calories: 375,
|
||||
fat: 0.0,
|
||||
carbs: 94,
|
||||
protein: 0.0,
|
||||
iron: '0%',
|
||||
},
|
||||
{
|
||||
name: 'Lollipop',
|
||||
calories: 392,
|
||||
fat: 0.2,
|
||||
carbs: 98,
|
||||
protein: 0,
|
||||
iron: '2%',
|
||||
},
|
||||
{
|
||||
name: 'Honeycomb',
|
||||
calories: 408,
|
||||
fat: 3.2,
|
||||
carbs: 87,
|
||||
protein: 6.5,
|
||||
iron: '45%',
|
||||
},
|
||||
{
|
||||
name: 'Donut',
|
||||
calories: 452,
|
||||
fat: 25.0,
|
||||
carbs: 51,
|
||||
protein: 4.9,
|
||||
iron: '22%',
|
||||
},
|
||||
{
|
||||
name: 'KitKat',
|
||||
calories: 518,
|
||||
fat: 26.0,
|
||||
carbs: 65,
|
||||
protein: 7,
|
||||
iron: '6%',
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onButtonClick(item) {
|
||||
console.log('click on ' + item.no)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.overlap-icon {
|
||||
position: absolute;
|
||||
top: -33px;
|
||||
text-align: center;
|
||||
padding-top: 12px;
|
||||
}
|
||||
</style>
|
||||
15
owner-vue/src/views/Home.vue
Normal file
15
owner-vue/src/views/Home.vue
Normal file
@@ -0,0 +1,15 @@
|
||||
<template>
|
||||
<div class="home">
|
||||
<img alt="Vue logo" src="../assets/logo.png">
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// @ is an alias to /src
|
||||
|
||||
export default {
|
||||
name: 'Home',
|
||||
components: {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
122
owner-vue/src/views/Menu.vue
Normal file
122
owner-vue/src/views/Menu.vue
Normal file
@@ -0,0 +1,122 @@
|
||||
<template>
|
||||
<div>
|
||||
<v-subheader class="py-0 d-flex justify-space-between rounded-lg">
|
||||
<h3>메뉴 관리</h3>
|
||||
</v-subheader>
|
||||
<v-form @submit.prevent>
|
||||
<v-container>
|
||||
<v-row>
|
||||
<v-col
|
||||
cols="12"
|
||||
md="4"
|
||||
>
|
||||
<v-text-field
|
||||
v-model="word"
|
||||
label="검색"
|
||||
required
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-form>
|
||||
<v-col>
|
||||
<v-data-table
|
||||
:headers="headers"
|
||||
:items="menus"
|
||||
:items-per-page="itemsPerPage"
|
||||
hide-default-footer
|
||||
class="elevation-1"
|
||||
>
|
||||
</v-data-table>
|
||||
<div class="text-center pt-2">
|
||||
<v-pagination
|
||||
v-model="page"
|
||||
:length="pageCount"
|
||||
:total-visible="totalVisible"
|
||||
@click="getMenu"
|
||||
></v-pagination>
|
||||
</div>
|
||||
</v-col>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
mdiContentSave, mdiDelete,
|
||||
mdiPlus,
|
||||
|
||||
} from '@mdi/js'
|
||||
import axios from "axios";
|
||||
|
||||
export default {
|
||||
name: "Category",
|
||||
components:{
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
icons: {
|
||||
mdiContentSave,
|
||||
mdiPlus,
|
||||
mdiDelete,
|
||||
},
|
||||
page: 1,
|
||||
pageCount: 1,
|
||||
itemsPerPage: 10,
|
||||
totalVisible: 10,
|
||||
headers: [
|
||||
{
|
||||
text: '메뉴번호',
|
||||
align: 'start',
|
||||
sortable: false,
|
||||
value: 'id',
|
||||
},
|
||||
{ text: '이름', value: 'name' },
|
||||
{ text: '카테고리', value: 'categoryName' },
|
||||
{ text: '가격', value: 'price' },
|
||||
],
|
||||
word:"",
|
||||
menus: [],
|
||||
}
|
||||
},
|
||||
methods:{
|
||||
getMenu(){
|
||||
var vm = this;
|
||||
const searchParam= {
|
||||
word: vm.word,
|
||||
page: vm.page-1
|
||||
}
|
||||
axios({
|
||||
method:'get',
|
||||
url:'/store-service/item',
|
||||
params : searchParam,
|
||||
responseType:'json'
|
||||
})
|
||||
.then(function (response) {
|
||||
const page = response.data.data.page;
|
||||
vm.menus = response.data.data.itemList;
|
||||
vm.page = page.startPage+1;
|
||||
vm.pageCount = page.totalPage;
|
||||
});
|
||||
}
|
||||
},
|
||||
watch:{
|
||||
page:function () {
|
||||
this.getMenu();
|
||||
},
|
||||
word:function () {
|
||||
if(this.page == 1)
|
||||
this.getMenu()
|
||||
else
|
||||
this.page =1;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getMenu()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
119
owner-vue/src/views/Order.vue
Normal file
119
owner-vue/src/views/Order.vue
Normal file
@@ -0,0 +1,119 @@
|
||||
<template>
|
||||
<div class="dashboard">
|
||||
<v-subheader class="py-0 d-flex justify-space-between rounded-lg">
|
||||
<h3>주문</h3>
|
||||
<v-btn color="success" @click="search">
|
||||
검색
|
||||
</v-btn>
|
||||
</v-subheader>
|
||||
<br>
|
||||
|
||||
<v-row>
|
||||
<date-picker :label=" '주문일' " @inputDate="inputDate"></date-picker>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col v-for="card in cards" cols="4" :key="card.orderId">
|
||||
<order-card
|
||||
:order-id="card.orderId"
|
||||
:userName="card.userName"
|
||||
:itemNames="card.itemNames"
|
||||
:orderTime="card.orderTime"
|
||||
:orderStatus="card.orderStatus"
|
||||
>
|
||||
</order-card>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<br><br><br>
|
||||
<v-row justify="center" v-if="showButton">
|
||||
<v-btn rounded outlined color="primary"
|
||||
@click="more">더보기</v-btn>
|
||||
</v-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import OrderApi from '../api/order.js';
|
||||
|
||||
import OrderCard from '../components/OrderCard.vue'
|
||||
import DatePicker from "@/components/DatePicker";
|
||||
|
||||
export default {
|
||||
name: "Order",
|
||||
components: {
|
||||
OrderCard,
|
||||
DatePicker
|
||||
},
|
||||
mounted() {
|
||||
this.search();
|
||||
},
|
||||
data: () => {
|
||||
return {
|
||||
date: '',
|
||||
cards: [],
|
||||
lastOrderId: null,
|
||||
showButton: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
search: function() {
|
||||
this.cards = [];
|
||||
this.lastOrderId = null;
|
||||
OrderApi.requestOrder(this.date, this.lastOrderId)
|
||||
.then( (response) => {
|
||||
this.renderCard(response.data);
|
||||
})
|
||||
.catch( (error) => {
|
||||
console.log(error);
|
||||
})
|
||||
},
|
||||
renderCard: function (json) {
|
||||
const orders = json.data;
|
||||
const size = orders.length;
|
||||
|
||||
if (size === 0) {
|
||||
alert("검색 데이터가 없습니다.");
|
||||
this.showButton = false;
|
||||
} else {
|
||||
this.showButton = true;
|
||||
}
|
||||
|
||||
orders.forEach( (order, index) => {
|
||||
if (index === (size - 1)) {
|
||||
this.lastOrderId = order.orderId;
|
||||
}
|
||||
|
||||
let orderItemNames = []
|
||||
order.orderItemResponses.forEach( (orderItem) => {
|
||||
orderItemNames.push(orderItem.itemId);
|
||||
})
|
||||
|
||||
this.cards.push({
|
||||
orderId: order.orderId,
|
||||
userName: order.orderId,
|
||||
itemNames: orderItemNames,
|
||||
orderTime: order.orderTime,
|
||||
orderStatus: order.orderStatus
|
||||
})
|
||||
});
|
||||
},
|
||||
inputDate: function(value) {
|
||||
this.date = value;
|
||||
},
|
||||
more: function() {
|
||||
OrderApi.requestOrder(this.date, this.lastOrderId)
|
||||
.then( (response) => {
|
||||
this.renderCard(response.data);
|
||||
})
|
||||
.catch( (error) => {
|
||||
console.log(error);
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
163
owner-vue/src/views/PrevOrder.vue
Normal file
163
owner-vue/src/views/PrevOrder.vue
Normal file
@@ -0,0 +1,163 @@
|
||||
<template>
|
||||
<div class="dashboard">
|
||||
<v-subheader class="py-0 d-flex justify-space-between rounded-lg">
|
||||
<h3>지난 주문</h3>
|
||||
<v-btn color="success" v-on:click="search">
|
||||
검색
|
||||
</v-btn>
|
||||
</v-subheader>
|
||||
<br>
|
||||
|
||||
<v-row>
|
||||
<date-picker :label=" '시작일' " @inputDate="inputStartDate"></date-picker>
|
||||
<date-picker :label=" '종료일' " @inputDate="inputEndDate"></date-picker>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<div class="subtitle-1">{{startDate}} ~ {{endDate}} 내역</div>
|
||||
</v-row>
|
||||
<br>
|
||||
|
||||
<v-data-table
|
||||
:headers="headers"
|
||||
:items="orders"
|
||||
:items-per-page="itemsPerPage"
|
||||
hide-default-footer
|
||||
class="elevation-1"
|
||||
>
|
||||
</v-data-table>
|
||||
<div class="text-center pt-2">
|
||||
<v-pagination
|
||||
v-model="page"
|
||||
:length="pageCount"
|
||||
:total-visible="totalVisible"
|
||||
></v-pagination>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import orderApi from '../api/order.js';
|
||||
|
||||
import DatePicker from "@/components/DatePicker";
|
||||
|
||||
const moment = require('moment');
|
||||
|
||||
export default {
|
||||
name: "PrevOrder",
|
||||
components: {
|
||||
'date-picker': DatePicker
|
||||
},
|
||||
mounted: function() {
|
||||
orderApi.requestPrevOrder(this.startDate, this.endDate, this.page - 1)
|
||||
.then( (response) => {
|
||||
this.renderList(response.data);
|
||||
})
|
||||
.catch( (error) => {
|
||||
console.log(error);
|
||||
});
|
||||
},
|
||||
watch: {
|
||||
"page": function (newPage) {
|
||||
orderApi.requestPrevOrder(this.startDate, this.endDate, newPage - 1)
|
||||
.then( (response) => {
|
||||
this.renderList(response.data);
|
||||
})
|
||||
.catch( (error) => {
|
||||
console.log(error);
|
||||
console.log(error.response.data);
|
||||
});
|
||||
}
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
// date
|
||||
startDate: '',
|
||||
endDate: '',
|
||||
|
||||
// pagination
|
||||
page: 1,
|
||||
pageCount: 1,
|
||||
itemsPerPage: 10,
|
||||
totalVisible: 10,
|
||||
|
||||
// data table
|
||||
headers: [
|
||||
{
|
||||
text: '주문번호',
|
||||
align: 'start',
|
||||
sortable: false,
|
||||
value: 'orderId',
|
||||
},
|
||||
{ text: '주문상태', value: 'orderStatus' },
|
||||
{ text: '주문시간', value: 'orderTime' },
|
||||
{ text: '주문상품', value: 'orderItemNames' },
|
||||
{ text: '결제금액', value: 'orderPrice' },
|
||||
{ text: '닉네임', value: 'userName' },
|
||||
],
|
||||
orders: [],
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
search: function() {
|
||||
if(!this.checkDate()) return;
|
||||
|
||||
orderApi.requestPrevOrder(this.startDate, this.endDate, this.page - 1)
|
||||
.then( (response) => {
|
||||
this.renderList(response.data);
|
||||
})
|
||||
.catch( (error) => {
|
||||
console.log(error);
|
||||
});
|
||||
},
|
||||
renderList: function(json) {
|
||||
const orders = json.data.orders;
|
||||
|
||||
this.orders = [];
|
||||
orders.forEach(order => {
|
||||
let orderItemNames = [];
|
||||
order.orderItems.forEach(orderItem => {
|
||||
orderItemNames.push(orderItem.orderItemId);
|
||||
})
|
||||
|
||||
this.orders.push({
|
||||
orderId: order.orderId,
|
||||
orderStatus: order.orderStatus,
|
||||
orderTime: order.orderTime,
|
||||
orderItemNames: orderItemNames.join(", "),
|
||||
orderPrice: order.orderPrice,
|
||||
userName: order.userName
|
||||
});
|
||||
})
|
||||
|
||||
// pagination setting
|
||||
const page = json.data.page;
|
||||
this.page = page.startPage + 1;
|
||||
this.pageCount = page.totalPage;
|
||||
},
|
||||
checkDate: function() {
|
||||
if (!this.startDate || !this.endDate) {
|
||||
alert("시작일과 종료일을 입력해주세요.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (moment(this.startDate).isAfter(this.endDate)) {
|
||||
alert("시작일은 종료일보다 클 수 없습니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
inputStartDate: function(value) {
|
||||
this.startDate = value;
|
||||
},
|
||||
inputEndDate: function(value) {
|
||||
this.endDate = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
17
owner-vue/vue.config.js
Normal file
17
owner-vue/vue.config.js
Normal file
@@ -0,0 +1,17 @@
|
||||
module.exports = {
|
||||
transpileDependencies: [
|
||||
'vuetify'
|
||||
],
|
||||
devServer:{
|
||||
proxy:{
|
||||
'store-service/' :{
|
||||
target: 'http://localhost:8001',
|
||||
ws:true,
|
||||
},
|
||||
'order-service/' :{
|
||||
target: 'http://localhost:8001',
|
||||
ws:true,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,17 @@
|
||||
package com.justpickup.storeservice.domain.item.dto;
|
||||
|
||||
import com.justpickup.storeservice.domain.category.dto.CategoryDto;
|
||||
import com.justpickup.storeservice.domain.item.entity.Item;
|
||||
import com.justpickup.storeservice.global.entity.Yn;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class ItemDto {
|
||||
|
||||
private Long id;
|
||||
@@ -16,15 +22,15 @@ public class ItemDto {
|
||||
|
||||
private Long price;
|
||||
|
||||
private CategoryDto categoryDto;
|
||||
|
||||
/*
|
||||
private PhotoDto photoDto;
|
||||
private CategoryDto categoryDto;
|
||||
private StoreDto storeDto;
|
||||
private List<ItemOptionDto> itemOptionDtoList;
|
||||
*/
|
||||
|
||||
// == 생성 메소드 == //
|
||||
@Builder
|
||||
public ItemDto(Long id, String name, Yn salesYn, Long price) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
@@ -41,6 +47,16 @@ public class ItemDto {
|
||||
.build();
|
||||
}
|
||||
|
||||
public static ItemDto createWithCategoryItemDto(Item item) {
|
||||
return ItemDto.builder()
|
||||
.id(item.getId())
|
||||
.name(item.getName())
|
||||
.categoryDto(new CategoryDto(item.getCategory()))
|
||||
.price(item.getPrice())
|
||||
.salesYn(item.getSalesYn())
|
||||
.build();
|
||||
}
|
||||
|
||||
// TODO: 2022/02/03 queryDsl 쿼리 생성 시 구현 필요
|
||||
// public static ItemDto createFullItemDto(Item item) {
|
||||
// return null
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.justpickup.storeservice.domain.item.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ItemSearch {
|
||||
|
||||
@NotNull
|
||||
private String type;
|
||||
|
||||
private String word;
|
||||
|
||||
|
||||
}
|
||||
@@ -1,7 +1,12 @@
|
||||
package com.justpickup.storeservice.domain.item.repository;
|
||||
|
||||
import com.justpickup.storeservice.domain.item.entity.Item;
|
||||
import com.justpickup.storeservice.domain.store.entity.Store;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ItemRepository extends JpaRepository<Item, Long> {
|
||||
|
||||
List<Item> findByStore(Store store);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.justpickup.storeservice.domain.item.repository;
|
||||
|
||||
import com.justpickup.storeservice.domain.category.entity.QCategory;
|
||||
import com.justpickup.storeservice.domain.item.entity.Item;
|
||||
import com.justpickup.storeservice.domain.item.entity.QItem;
|
||||
import com.justpickup.storeservice.domain.store.entity.QStore;
|
||||
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.util.List;
|
||||
|
||||
@Repository
|
||||
@RequiredArgsConstructor
|
||||
public class ItemRepositoryCustom {
|
||||
|
||||
private final JPAQueryFactory queryFactory;
|
||||
|
||||
public Page<Item> findItem(Long storeId,String word, Pageable pageable){
|
||||
|
||||
//count 가져오기
|
||||
Long count = queryFactory.select(QItem.item.count())
|
||||
.from(QItem.item)
|
||||
.join(QItem.item.category)
|
||||
.leftJoin(QItem.item.store)
|
||||
.on(QItem.item.store.id.eq(storeId))
|
||||
.where(
|
||||
QItem.item.name.contains(word)
|
||||
.or(QItem.item.category.name.contains(word))
|
||||
)
|
||||
.limit(pageable.getPageSize())
|
||||
.offset(pageable.getOffset())
|
||||
.fetchOne();
|
||||
|
||||
//List 가져오기
|
||||
List<Item> itemList = queryFactory.selectFrom(QItem.item)
|
||||
.join(QItem.item.category).fetchJoin()
|
||||
.leftJoin(QItem.item.store)
|
||||
.on(QItem.item.store.id.eq(storeId))
|
||||
.where(
|
||||
QItem.item.name.contains(word)
|
||||
.or(QItem.item.category.name.contains(word))
|
||||
)
|
||||
.limit(pageable.getPageSize())
|
||||
.offset(pageable.getOffset())
|
||||
.fetch();
|
||||
|
||||
return PageableExecutionUtils.getPage(itemList,pageable,() -> count);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,14 @@
|
||||
package com.justpickup.storeservice.domain.item.service;
|
||||
|
||||
import com.justpickup.storeservice.domain.item.dto.ItemDto;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ItemService {
|
||||
|
||||
ItemDto findItemByItemId(Long itemId);
|
||||
|
||||
Page<ItemDto> findItemList(Long storeId,String word, Pageable pageable);
|
||||
}
|
||||
|
||||
@@ -1,14 +1,26 @@
|
||||
package com.justpickup.storeservice.domain.item.service;
|
||||
|
||||
import com.justpickup.storeservice.domain.category.exception.NotFoundStoreException;
|
||||
import com.justpickup.storeservice.domain.item.dto.ItemDto;
|
||||
import com.justpickup.storeservice.domain.item.dto.ItemSearch;
|
||||
import com.justpickup.storeservice.domain.item.entity.Item;
|
||||
import com.justpickup.storeservice.domain.item.exception.NotExistItemException;
|
||||
import com.justpickup.storeservice.domain.item.repository.ItemRepository;
|
||||
import com.justpickup.storeservice.domain.item.repository.ItemRepositoryCustom;
|
||||
import com.justpickup.storeservice.domain.store.entity.Store;
|
||||
import com.justpickup.storeservice.domain.store.repository.StoreRepository;
|
||||
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.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Transactional(readOnly = true)
|
||||
@@ -16,6 +28,8 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
public class ItemServiceImpl implements ItemService {
|
||||
|
||||
private final ItemRepository itemRepository;
|
||||
private final ItemRepositoryCustom itemRepositoryCustom;
|
||||
private final StoreRepository storeRepository;
|
||||
|
||||
|
||||
@Override
|
||||
@@ -25,4 +39,15 @@ public class ItemServiceImpl implements ItemService {
|
||||
|
||||
return ItemDto.createItemDto(findItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<ItemDto> findItemList( Long storeId,String word, Pageable pageable) {
|
||||
|
||||
Page<Item> itemList = itemRepositoryCustom.findItem(storeId,word,pageable);
|
||||
return PageableExecutionUtils.getPage(itemList.stream()
|
||||
.map(ItemDto::createWithCategoryItemDto)
|
||||
.collect(Collectors.toList()),pageable,itemList::getTotalElements);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.justpickup.storeservice.domain.item.web;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.justpickup.storeservice.domain.item.dto.ItemDto;
|
||||
import com.justpickup.storeservice.domain.item.service.ItemService;
|
||||
import com.justpickup.storeservice.global.dto.Result;
|
||||
@@ -8,21 +10,85 @@ import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.hibernate.annotations.Parameter;
|
||||
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.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/item")
|
||||
public class ItemController {
|
||||
|
||||
private final ItemService itemService;
|
||||
|
||||
@GetMapping("/{itemId}")
|
||||
@GetMapping("/item")
|
||||
public ResponseEntity<Result<GetItemResponse>> getItemList( @RequestParam String word,
|
||||
@PageableDefault(page = 0, size = 10) Pageable pageable){
|
||||
|
||||
Long storeId = 1L;
|
||||
|
||||
Page<ItemDto> itemDtoList = itemService.findItemList(storeId,word,pageable);
|
||||
List<GetItemListResponse.Item> itemList = itemDtoList.stream()
|
||||
.map(GetItemListResponse.Item::new)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
GetItemListResponse getItemResponse = new GetItemListResponse(
|
||||
itemList,
|
||||
itemDtoList.getNumber(),
|
||||
itemDtoList.getTotalPages()
|
||||
);
|
||||
|
||||
|
||||
return ResponseEntity.status(HttpStatus.OK)
|
||||
.body((Result<GetItemResponse>)Result.createSuccessResult(getItemResponse));
|
||||
}
|
||||
|
||||
|
||||
@Data @NoArgsConstructor @AllArgsConstructor
|
||||
static class GetItemListResponse {
|
||||
private List<Item> itemList;
|
||||
private Page page;
|
||||
|
||||
public GetItemListResponse(List<Item> itemList, int startPage,int totalPage) {
|
||||
this.itemList = itemList;
|
||||
this.page = new Page(startPage,totalPage);
|
||||
}
|
||||
|
||||
@Data
|
||||
static class Item{
|
||||
private Long id;
|
||||
private String name;
|
||||
private Yn salesYn;
|
||||
private Long price;
|
||||
private String categoryName;
|
||||
|
||||
public Item(ItemDto itemDto) {
|
||||
this.id = itemDto.getId();
|
||||
this.name = itemDto.getName();
|
||||
this.salesYn = itemDto.getSalesYn();
|
||||
this.price = itemDto.getPrice();
|
||||
this.categoryName = itemDto.getCategoryDto().getName();
|
||||
}
|
||||
}
|
||||
|
||||
@Data @AllArgsConstructor
|
||||
static class Page {
|
||||
int startPage;
|
||||
int totalPage;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/item/{itemId}")
|
||||
public ResponseEntity getItem(@PathVariable("itemId") Long itemId) {
|
||||
ItemDto itemByItemId = itemService.findItemByItemId(itemId);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
server:
|
||||
port: 0
|
||||
port: 12343
|
||||
|
||||
spring:
|
||||
application:
|
||||
|
||||
Reference in New Issue
Block a user