Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Sign in
Toggle navigation
K
kiaisoft_tuananh_nuxt
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
1
Issues
1
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
TTS Tran Viet Anh
kiaisoft_tuananh_nuxt
Commits
6f198a23
Commit
6f198a23
authored
Feb 16, 2023
by
Le Dinh Trung
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'feature/UI-vuetify' into 'dev'
Feature/ui vuetify See merge request
!19
parents
68c8f625
4b0a2154
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
687 additions
and
570 deletions
+687
-570
Navbar.vue
components/Navbar.vue
+5
-5
web.js
middleware/web.js
+2
-2
index.vue
pages/categories/index.vue
+261
-178
home.vue
pages/home.vue
+1
-1
login.vue
pages/login.vue
+14
-9
index.vue
pages/posts/index.vue
+144
-139
index.vue
pages/products/index.vue
+166
-179
index.vue
pages/users/index.vue
+87
-57
axios.js
plugins/axios.js
+7
-0
No files found.
components/Navbar.vue
View file @
6f198a23
...
...
@@ -9,28 +9,28 @@
<v-app-bar-nav-icon
/>
<v-toolbar-title>
<v-btn
href
=
"/users"
>
<v-btn
to
=
"/users"
>
<span>
USER
</span>
<v-icon
dense
>
mdi-account
</v-icon>
</v-btn>
<v-btn
href
=
"/categories"
>
<v-btn
to
=
"/categories"
>
<span>
CATEGORY
</span>
<v-icon
dense
>
mdi-heart
</v-icon>
</v-btn>
<v-btn
href
=
"/products"
>
<v-btn
to
=
"/products"
>
<span>
PRODUCT
</span>
<v-icon
dense
>
mdi-briefcase
</v-icon>
</v-btn>
<v-btn
href
=
"/posts"
>
<v-btn
to
=
"/posts"
>
<span>
POST
</span>
<v-icon
dense
>
mdi-newspaper
...
...
@@ -86,7 +86,7 @@ export default {
const
resp
=
await
this
.
$axios
.
post
(
'
/logout
'
,
{
token
:
this
.
$auth
.
$storage
.
getUniversal
(
'
token
'
)
})
if
(
resp
.
status
==
'
200
'
)
{
if
(
resp
.
status
==
=
200
)
{
this
.
$toast
.
success
(
'
Logout!
'
,
{
duration
:
2000
})
...
...
middleware/web.js
View file @
6f198a23
export
default
({
redirect
,
store
})
=>
{
if
(
typeof
localStorage
!==
'
undefined
'
&&
!
localStorage
.
getItem
(
'
token
'
))
{
export
default
({
redirect
,
store
,
$auth
})
=>
{
if
(
!
$auth
.
$storage
.
getLocalStorage
(
'
token
'
))
{
return
redirect
(
'
/login
'
)
}
}
pages/categories/index.vue
View file @
6f198a23
...
...
@@ -10,119 +10,87 @@
</v-breadcrumbs>
</div>
<!-- modal-create -->
<v-dialog
v-model=
"dialog3"
persistent
max-width=
"600px"
>
<v-card>
<v-card-title>
<span
class=
"text-h5"
>
Category
</span>
</v-card-title>
<v-card-text>
<v-container>
<v-row>
<v-col
cols=
"12"
>
<v-text-field
v-model=
"eName"
label=
"Name"
readonly
/>
</v-col>
<v-col
cols=
"12"
>
<v-text-field
v-model=
"eOrdering"
label=
"Ordering"
type=
"number"
readonly
/>
</v-col>
<v-col
cols=
"12"
>
<v-select
v-model=
"eParentId"
:items=
"categories.filter(category => category.id !== eID)"
item-text=
"name"
item-value=
"id"
label=
"Parent"
readonly
/>
</v-col>
<v-col
cols=
"12"
>
<v-img
:src=
"eImage"
/>
</v-col>
</v-row>
</v-container>
<small>
*indicates required field
</small>
</v-card-text>
<v-card-actions>
<v-spacer
/>
<v-btn
color=
"blue darken-1"
text
@
click=
"dialog3 = false"
>
Close
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<v-dialog
v-model=
"dialog2"
persistent
max-width=
"600px"
>
<v-dialog
v-model=
"dialog2"
persistent
max-width=
"600px"
>
<v-card>
<v-card-title>
<span
class=
"text-h5"
>
Category Edit
</span>
</v-card-title>
<v-card-text>
<v-container>
<v-row>
<v-col
cols=
"12"
>
<v-text-field
v-model=
"eName"
label=
"Name"
:rules=
"nameRules"
required
/>
</v-col>
<v-col
cols=
"12"
>
<v-text-field
v-model=
"eOrdering"
label=
"Ordering"
type=
"number"
:rules=
"requiredRules"
required
/>
</v-col>
<v-col
cols=
"12"
>
<v-select
v-model=
"eParentId"
:items=
"categories.filter(category =>category.id !== eID)"
item-text=
"name"
item-value=
"id"
label=
"Parent"
/>
</v-col>
<v-col
cols=
"12"
>
<v-file-input
v-model=
"eImage"
accept=
"image/*"
label=
"Image"
prepend-icon=
"mdi-camera"
/>
</v-col>
<v-img
v-if=
"typeof eImage === 'string'"
:src=
"eImage"
/>
</v-row>
<v-form
ref=
"formEdit"
>
<v-row>
<v-col
cols=
"12"
>
<v-text-field
v-model=
"eName"
label=
"Name"
:rules=
"nameRules"
required
/>
</v-col>
<v-col
cols=
"12"
>
<v-text-field
v-model=
"eOrdering"
label=
"Ordering"
type=
"number"
:rules=
"requiredRules"
required
/>
</v-col>
<v-col
cols=
"12"
>
<v-autocomplete
v-model=
"eParentId"
:items=
"
categories.filter((category) => category.id !== eID)
"
item-text=
"name"
item-value=
"id"
label=
"Parent"
>
<
template
#item
="{
item
}"
>
<div
:class=
"`category-$
{item.depth}`">
{{
item
.
name
}}
</div>
</
template
>
</v-autocomplete>
</v-col>
<v-col
cols=
"12"
>
<v-file-input
v-model=
"eImage"
accept=
"image/*"
label=
"Image"
prepend-icon=
"mdi-camera"
@
change=
"fileSelected"
/>
</v-col>
<v-col
cols=
"12"
>
<img
v-if=
"file"
:src=
"file"
>
</v-col>
<v-col
cols=
"12"
text-align=
" left"
>
<v-img
v-if=
"typeof eImage === 'string'"
contain
height=
"100px"
width=
"150px"
:src=
"eImage"
/>
</v-col>
</v-row>
</v-form>
</v-container>
<small>
*indicates required field
</small>
</v-card-text>
<v-card-actions>
<v-spacer
/>
<v-btn
color=
"blue darken-1"
text
@
click=
"dialog2 = false"
@
click=
"
dialog2 = false;
clearFile();
clearEditData();
"
>
Close
</v-btn>
...
...
@@ -130,18 +98,33 @@
color=
"blue darken-1"
text
type=
"submit"
@
click=
"dialog2 = false; updateCategory();"
@
click=
"
dialog2 = false;
updateCategory();
"
>
Save
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<v-data-table
:headers=
"headers"
:items=
"categories"
:item-class=
"indentation"
sort-by=
"calories"
class=
"elevation-1"
>
<v-data-table
:headers=
"headers"
:items=
"categories"
:item-class=
"indentation"
:search=
"searchTable"
sort-by=
"calories"
class=
"elevation-1"
>
<
template
#top
>
<v-toolbar
flat
>
<v-toolbar-title>
Category Manage
</v-toolbar-title>
<v-divider
class=
"mx-4"
inset
vertical
/>
<v-text-field
v-model=
"searchTable"
append-icon=
"mdi-magnify"
label=
"Search"
single-line
hide-details
/>
<v-spacer
/>
<v-toolbar-title
style=
"float: right"
>
<v-dialog
...
...
@@ -151,13 +134,8 @@
lazy-validation
>
<template
#activator
="
{ on, attrs }">
<v-btn
color=
"primary"
dark
v-bind=
"attrs"
v-on=
"on"
>
New Category
<v-btn
color=
"primary"
dark
v-bind=
"attrs"
v-on=
"on"
>
CREATE NEW
</v-btn>
</
template
>
<v-card>
...
...
@@ -167,11 +145,7 @@
<v-card-text>
<v-container>
<v-row>
<v-col
cols=
"12"
sm=
"6"
md=
"4"
>
<v-col
cols=
"12"
>
<v-text-field
v-model=
"name"
label=
"Name"
...
...
@@ -190,32 +164,46 @@
/>
</v-col>
<v-col
cols=
"12"
>
<v-
select
<v-
autocomplete
v-model=
"parent_id"
:items=
"categories"
:search=
"search"
:filter=
"filter"
item-text=
"name"
item-value=
"id"
label=
"Parent*"
:rules=
"requiredRules"
/>
>
<
template
#item
="{
item
}"
>
<div
:class=
"`category-$
{item.depth}`">
{{
item
.
name
}}
</div>
</
template
>
</v-autocomplete>
</v-col>
<v-col
cols=
"12"
>
<v-file-input
v-model=
"image"
label=
"Image"
prepend-icon=
"mdi-camera"
@
change=
"fileSelected"
/>
</v-col>
<v-col
cols=
"12"
>
<img
v-if=
"file"
:src=
"file"
contain
>
</v-col>
</v-row>
</v-container>
<small>
*indicates required field
</small>
</v-card-text>
<v-card-actions>
<v-spacer
/>
<v-btn
color=
"blue darken-1"
text
@
click=
"dialog1 = false"
@
click=
"
dialog1 = false;
clearFile();
"
>
Close
</v-btn>
...
...
@@ -223,7 +211,10 @@
color=
"blue darken-1"
text
type=
"submit"
@
click=
"dialog1 = false; createCategory();"
@
click=
"
dialog1 = false;
createCategory();
"
>
Save
</v-btn>
...
...
@@ -246,13 +237,22 @@
<v-text-field
v-model=
"editedItem.id"
label=
"id"
/>
</v-col>
<v-col
cols=
"12"
sm=
"6"
md=
"4"
>
<v-text-field
v-model=
"editedItem.ordering"
label=
"ordering"
/>
<v-text-field
v-model=
"editedItem.ordering"
label=
"ordering"
/>
</v-col>
<v-col
cols=
"12"
sm=
"6"
md=
"4"
>
<v-text-field
v-model=
"editedItem.created_at"
label=
"created_at"
/>
<v-text-field
v-model=
"editedItem.created_at"
label=
"created_at"
/>
</v-col>
<v-col
cols=
"12"
sm=
"6"
md=
"4"
>
<v-text-field
v-model=
"editedItem.updated_at"
label=
"updated_at"
/>
<v-text-field
v-model=
"editedItem.updated_at"
label=
"updated_at"
/>
</v-col>
</v-row>
</v-container>
...
...
@@ -278,7 +278,14 @@
<v-btn
color=
"blue darken-1"
text
@
click=
"closeDelete"
>
Cancel
</v-btn>
<v-btn
color=
"blue darken-1"
text
@
click=
"deleteCategory(); dialogDelete = false"
>
<v-btn
color=
"blue darken-1"
text
@
click=
"
deleteCategory();
dialogDelete = false;
"
>
OK
</v-btn>
<v-spacer
/>
...
...
@@ -290,22 +297,33 @@
<
template
#
[`
item
.
index
`
]=
"{ index }"
>
{{
index
+
1
}}
</
template
>
<
template
#
item.created_at
=
"{ item }"
>
<
template
#
[`
item
.
created_at
`
]
=
"{ item }"
>
<span>
{{
formatDate
(
item
.
created_at
)
}}
</span>
</
template
>
<
template
#
item.updated_at
=
"{ item }"
>
<
template
#
[`
item
.
updated_at
`
]
=
"{ item }"
>
<span>
{{
formatDate
(
item
.
updated_at
)
}}
</span>
</
template
>
<
template
#item.actions=
"{ item }"
>
<v-icon
:id=
"item.id"
small
@
click=
"dialog2 = true; editCategory(item)"
>
<
template
#
[`
item
.
actions
`
]=
"{ item }"
>
<v-icon
:id=
"item.id"
small
@
click=
"
dialog2 = true;
editCategory(item);
"
>
mdi-pencil
</v-icon>
<v-icon
:id=
"item.id"
small
@
click=
"dialogDelete = true; getID(item)"
>
<v-icon
:id=
"item.id"
small
@
click=
"
dialogDelete = true;
getID(item);
"
>
mdi-delete
</v-icon>
<v-icon
:id=
"item.id"
small
@
click=
"dialog3 = true; showCategory(item)"
>
mdi-account-details
</v-icon>
</
template
>
<
template
#no-data
>
<v-btn
color=
"primary"
@
click=
"initialize"
>
...
...
@@ -317,12 +335,14 @@
</v-app>
</template>
<
script
>
export
default
{
layout
:
'
admin
'
,
middleware
:
[
'
web
'
],
data
:
()
=>
{
return
{
search
:
''
,
searchTable
:
''
,
file
:
null
,
parent_id
:
''
,
name
:
''
,
ordering
:
''
,
...
...
@@ -331,23 +351,26 @@ export default {
dialog
:
false
,
dialog1
:
false
,
dialog2
:
false
,
dialog3
:
false
,
dialogDelete
:
false
,
options
:
[],
headers
:
[
{
text
:
'
#
'
,
align
:
'
start
'
,
value
:
'
index
'
,
groupable
:
false
value
:
'
index
'
},
{
text
:
'
Name
'
,
value
:
'
name
'
,
groupable
:
false
},
{
text
:
'
Odering
'
,
value
:
'
ordering
'
,
groupable
:
false
},
{
text
:
'
Created
'
,
value
:
'
created_at
'
,
groupable
:
false
},
{
text
:
'
Updated
'
,
value
:
'
updated_at
'
,
groupable
:
false
},
{
text
:
'
Actions
'
,
value
:
'
actions
'
,
sortable
:
false
,
groupable
:
false
}
{
text
:
'
Ordering
'
,
value
:
'
ordering
'
,
filterable
:
true
},
{
text
:
'
Created
'
,
value
:
'
created_at
'
},
{
text
:
'
Updated
'
,
value
:
'
updated_at
'
},
{
text
:
'
Actions
'
,
value
:
'
actions
'
,
sortable
:
false
}
],
categories
:
[],
categoryTrees
:
[],
eID
:
''
,
eName
:
''
,
eOrdering
:
''
,
...
...
@@ -359,7 +382,7 @@ export default {
name
:
''
,
id
:
''
,
ordering
:
''
,
parent_id
:
''
,
parent_id
:
[]
,
created_at
:
''
,
updated_at
:
''
},
...
...
@@ -388,9 +411,7 @@ export default {
v
=>
!!
v
||
'
Name is required
'
,
v
=>
(
v
&&
v
.
length
<=
255
)
||
'
Name must be less than 255 characters
'
],
requiredRules
:
[
v
=>
!!
v
||
'
This field is required
'
,
],
requiredRules
:
[
v
=>
!!
v
||
'
This field is required
'
],
numberRules
:
[
v
=>
!!
v
||
'
This field is required
'
,
v
=>
v
>
0
||
'
value must be a positive integer
'
...
...
@@ -400,6 +421,11 @@ export default {
computed
:
{
formTitle
()
{
return
this
.
editedIndex
===
-
1
?
'
New Item
'
:
'
Edit Item
'
},
filter
()
{
return
this
.
caseSensitive
?
(
item
,
search
,
textKey
)
=>
item
[
textKey
].
includes
(
search
)
:
undefined
}
},
watch
:
{
...
...
@@ -413,6 +439,7 @@ export default {
created
()
{
this
.
initialize
()
this
.
getCategories
()
this
.
getCategoryTrees
()
},
methods
:
{
indentation
(
item
)
{
...
...
@@ -458,11 +485,29 @@ export default {
}
this
.
close
()
},
getCategoryTrees
()
{
this
.
$axios
.
get
(
'
/categories-tree/
'
,
{
headers
:
{
Authorization
:
`Bearer
${
this
.
$auth
.
$storage
.
getUniversal
(
'
token
'
)}
`
}
})
.
then
((
response
)
=>
{
this
.
categoryTrees
=
response
.
data
.
data
})
.
catch
(
function
(
error
)
{
console
.
log
(
error
)
})
},
getCategories
()
{
this
.
$axios
.
get
(
'
/categories/
'
,
{
headers
:
{
Authorization
:
`Bearer
${
this
.
$auth
.
$storage
.
getUniversal
(
'
token
'
)}
`
Authorization
:
`Bearer
${
this
.
$auth
.
$storage
.
getUniversal
(
'
token
'
)}
`
}
})
.
then
((
response
)
=>
{
...
...
@@ -482,14 +527,11 @@ export default {
fd
.
append
(
'
image
'
,
this
.
image
)
}
this
.
$axios
.
post
(
'
/categories/
'
,
fd
,
{
headers
:
{
Authorization
:
`Bearer
${
this
.
$auth
.
$storage
.
getUniversal
(
'
token
'
)}
`
}
.
post
(
'
/categories/
'
,
fd
,
{
headers
:
{
Authorization
:
`Bearer
${
this
.
$auth
.
$storage
.
getUniversal
(
'
token
'
)}
`
}
)
}
)
.
then
((
response
)
=>
{
self
.
$toast
.
success
(
'
Category created successfully!
'
,
{
duration
:
3000
...
...
@@ -505,6 +547,8 @@ export default {
})
})
this
.
getCategories
()
this
.
getCategoryTrees
()
this
.
clearFile
()
this
.
clearData
()
},
deleteCategory
()
{
...
...
@@ -512,12 +556,13 @@ export default {
const
currentPostIndex
=
this
.
editedIndex
try
{
this
.
$axios
.
delete
(
`/categories/
${
this
.
eID
}
`
,
{
headers
:
{
Authorization
:
`Bearer
${
this
.
$auth
.
$storage
.
getUniversal
(
'
token
'
)}
`
}
})
.
delete
(
`/categories/
${
this
.
eID
}
`
,
{
headers
:
{
Authorization
:
`Bearer
${
this
.
$auth
.
$storage
.
getUniversal
(
'
token
'
)}
`
}
})
.
then
((
response
)
=>
{
this
.
categories
.
splice
(
currentPostIndex
,
1
)
self
.
$toast
.
success
(
'
Category deleted successfully!
'
,
{
...
...
@@ -544,12 +589,6 @@ export default {
console
.
log
(
this
.
eID
)
console
.
log
(
this
.
eImage
)
},
showCategory
(
item
)
{
this
.
eName
=
item
.
name
this
.
eOrdering
=
item
.
ordering
this
.
eParentId
=
item
.
parent_id
this
.
eImage
=
item
.
image
},
updateCategory
(
userID
)
{
const
self
=
this
const
fd
=
new
FormData
()
...
...
@@ -565,32 +604,63 @@ export default {
}
try
{
this
.
$axios
.
post
(
`categories/update/
${
this
?.
eID
}
`,
fd,
{
headers: {
Authorization: `
Bearer
$
{
this
.
$auth
.
$storage
.
getUniversal
(
'
token
'
)}
`
}
.
post
(
`categories/update/
${
this
?.
eID
}
`, fd, {
headers: {
Authorization: `
Bearer
$
{
this
.
$auth
.
$storage
.
getUniversal
(
'
token
'
)}
`
}
)
}
)
.then((response) => {
self.$toast.success('User updated successfully!', {
duration: 3000
})
this.editedItem = response.data.data
Object.assign(this.categories[this.editedIndex], this.editedItem)
this.clearFile()
})
} catch (error) {
console.log(error)
}
},
clearData () {
// eslint-disable-next-line no-unused-expressions
this.parent_id = '',
this.name = '',
this.ordering = '',
this.parent_id = ''
this.name = ''
this.ordering = ''
this.image = null
},
clearEditData () {
this.eParentId = ''
this.eName = ''
this.eOrdering = ''
this.eImage = null
},
fileSelected (event) {
if (event) {
this.file = URL.createObjectURL(event)
console.log(this.file)
} else {
this.file = null
}
},
clearFile () {
this.file = null
}
// onOpen (e) {
// if (!this.__initial) {
// this.__initial = true
// return
// }
// // this.eParentId.length = 0
// console.log('toggle arrow clicked', e)
// },
// selectCategory (e) {
// console.log(e[0])
// console.log(this.eParentId)
// // this.eParentId.length = 0
// // this.eParentId.push(e[0])
// }
}
}
</
script
>
...
...
@@ -599,9 +669,9 @@ export default {
.depth-0
{
background-color
:
rgba
(
211
,
211
,
211
,
0.555
);
}
.depth-1
{
.depth-1
{
padding-left
:
30px
!important
;
background-color
:
rgba
(
211
,
211
,
211
,
0.133
);
background-color
:
rgba
(
211
,
211
,
211
,
0.133
);
}
.depth-1
>
td
:nth-child
(
2
)
{
padding-left
:
30px
!important
;
...
...
@@ -618,4 +688,17 @@ export default {
.depth-5
>
td
:nth-child
(
2
)
{
padding-left
:
150px
!important
;
}
.category-1
{
padding-left
:
30px
!important
;
}
.category-2
{
padding-left
:
60px
!important
;
}
.category-3
{
padding-left
:
90px
!important
;
}
img
{
width
:
100px
;
height
:
150px
;
}
</
style
>
pages/home.vue
View file @
6f198a23
...
...
@@ -79,6 +79,6 @@
<
script
>
export
default
{
layout
:
'
admin
'
,
middleware
:
[
'
web
'
]
,
middleware
:
[
'
web
'
]
}
</
script
>
pages/login.vue
View file @
6f198a23
...
...
@@ -109,10 +109,15 @@ export default {
this
.
password
=
''
this
.
checkbox
=
false
},
async
login
()
{
async
login
()
{
try
{
const
resp
=
await
this
.
$axios
.
post
(
'
/login
'
,
{
const
resp
=
await
fetch
(
'
http://127.0.0.1:8000/api/login
'
,
{
method
:
'
POST
'
,
headers
:
{
'
Content-Type
'
:
'
application/json
'
,
Accept
:
'
application/json
'
},
body
:
JSON
.
stringify
({
email
:
this
.
email
,
password
:
this
.
password
,
status
:
this
.
status
...
...
@@ -121,7 +126,7 @@ export default {
return
response
.
json
()
})
console
.
log
(
resp
.
status
)
localStorage
.
setItem
(
'
token
'
,
resp
.
data
.
bearer_token
)
localStorage
.
setItem
(
'
token
'
,
resp
.
data
.
bearer_token
)
this
.
$auth
.
$storage
.
setUniversal
(
'
token
'
,
resp
.
data
.
bearer_token
)
this
.
$auth
.
$storage
.
setUniversal
(
'
userName
'
,
resp
.
data
.
name
)
this
.
$auth
.
$storage
.
setUniversal
(
'
loggedIn
'
,
'
true
'
)
...
...
@@ -132,13 +137,13 @@ export default {
this
.
$router
.
push
(
'
home
'
)
}
}
catch
(
e
)
{
this
.
$toast
.
error
(
"
Username or Password not valid
"
,
{
duration
:
2000
,
})
;
this
.
$router
.
push
(
"
/login
"
);
this
.
$toast
.
error
(
'
Username or Password not valid
'
,
{
duration
:
2000
})
this
.
$router
.
push
(
'
/login
'
)
}
}
}
}
}
</
script
>
<
style
scoped
>
...
...
pages/posts/index.vue
View file @
6f198a23
<!-- eslint-disable vue/require-v-for-key -->
<!-- eslint-disable-next-line no-console -->
<
template
>
<div>
<div>
...
...
@@ -10,91 +11,12 @@
</v-breadcrumbs>
</div>
<div
style=
"float: right"
/>
<!-- modal-show -->
<v-dialog
v-model=
"dialog2"
persistent
max-width=
"600px"
>
<v-card>
<v-card-title>
<span
class=
"text-h5"
>
POST
</span>
</v-card-title>
<v-card-text>
<v-container>
<v-row>
<v-col
cols=
"12"
sm=
"6"
md=
"4"
>
<v-text-field
v-model=
"sTitle"
label=
"Title"
readonly
/>
</v-col>
<v-col
cols=
"12"
>
<v-select
v-model=
"sCategoryId"
:items=
"categories"
item-text=
"name"
item-value=
"id"
label=
"Category"
readonly
/>
</v-col>
<v-col
cols=
"12"
>
<v-textarea
v-model=
"sContent"
label=
"Content"
word-break=
"break-word"
readonly
/>
</v-col>
<v-col
cols=
"12"
>
<v-select
v-model=
"sStatus"
:items=
"statusDefaul"
item-text=
"name"
item-value=
"id"
label=
"Status"
readonly
/>
</v-col>
<v-col
cols=
"12"
>
<!-- <v-col v-for="(image, index) in sImages" :key="index" cols="12">
<v-img :src="image"/> -->
<v-img
v-if=
"typeof sImages === 'string'"
:src=
"sImages"
/>
</v-col>
</v-row>
</v-container>
<small>
*indicates required field
</small>
</v-card-text>
<v-card-actions>
<v-spacer
/>
<v-btn
color=
"blue darken-1"
text
@
click=
"dialog2 = false"
>
Close
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<!-- modal-edit -->
<v-dialog
v-model=
"dialog"
persistent
max-width=
"600px"
lazy-validation
>
<v-card>
<v-card-title>
...
...
@@ -111,25 +33,43 @@
<v-text-field
v-model=
"eTitle"
label=
"Title*"
:rules=
"requiredRules"
required
/>
</v-col>
<v-col
cols=
"12"
>
<v-select
<
!-- <
v-select
v-model="eCategoryId"
:items="categories"
item-text="name"
item-value="id"
label="Category"
/>
:rules="requiredRules"
/> -->
<v-autocomplete
v-model=
"eCategoryId"
:items=
"
categories.filter((category) => category.id !== eId)
"
item-text=
"name"
item-value=
"id"
label=
"Category"
>
<
template
#item
="{
item
}"
>
<div
:class=
"`category-$
{item.depth}`">
{{
item
.
name
}}
</div>
</
template
>
</v-autocomplete>
</v-col>
<v-col
cols=
"12"
>
<v-textarea
v-model=
"eContent"
label=
"Content"
required
:rules=
"requiredRules"
/>
</v-col>
<v-col
...
...
@@ -137,10 +77,11 @@
>
<v-select
v-model=
"eStatus"
:items=
"statusDefaul"
:items=
"statusDefaul
t
"
item-text=
"name"
item-value=
"id"
label=
"Status"
:rules=
"requiredRules"
/>
</v-col>
<v-col
cols=
"12"
>
...
...
@@ -151,18 +92,37 @@
small-chips
dense
prepend-icon=
"mdi-camera"
@
change=
"fileSelected"
/>
</v-col>
<v-col
cols=
"12"
class=
"v-image v-responsive theme--dark"
>
<img
v-if=
"file"
contain
max-height=
"300"
max-width=
"500"
:src=
"file"
>
</v-col>
<v-col
cols=
"12"
text-align=
" left"
>
<v-img
v-for=
"(imageEdit, index) in eImages"
:key=
"index"
contain
height=
"100px"
width=
"150px"
:src=
"imageEdit"
/>
</v-col>
</v-row>
</v-container>
<small>
*indicates required field
</small>
</v-card-text>
<v-card-actions>
<v-spacer
/>
<v-btn
color=
"blue darken-1"
text
@
click=
"dialog = false"
@
click=
"dialog = false
; clearFile()
"
>
Close
</v-btn>
...
...
@@ -197,18 +157,25 @@
</v-dialog>
<!-- table -->
<div>
<v-data-table
:headers=
"headers"
:items=
"posts"
sort-by=
"calories"
class=
"elevation-1"
>
<v-data-table
:headers=
"headers"
:items=
"posts"
:search=
"searchTable"
sort-by=
"calories"
class=
"elevation-1"
>
<
template
#top
>
<v-toolbar
flat
>
<v-toolbar-title>
Post Manage
</v-toolbar-title>
<v-divider
class=
"mx-4"
inset
vertical
/>
<v-text-field
v-model=
"searchTable"
append-icon=
"mdi-magnify"
label=
"Search"
single-line
hide-details
/>
<v-spacer
/>
<v-toolbar-title>
<!-- modal-create -->
<v-dialog
v-model=
"dialog1"
persistent
max-width=
"600px"
enctype=
"multipart/form-data"
lazy-validation
>
<template
#activator
="
{ on, attrs }">
<v-btn
...
...
@@ -217,7 +184,7 @@
v-bind=
"attrs"
v-on=
"on"
>
New Post
create new
</v-btn>
</
template
>
<v-card>
...
...
@@ -235,24 +202,35 @@
<v-text-field
v-model=
"title"
label=
"Title*"
:rules=
"requiredRules"
required
/>
</v-col>
<v-col
cols=
"12"
>
<v-
select
<v-
autocomplete
v-model=
"category_id"
:items=
"categories"
:search=
"search"
:filter=
"filter"
item-text=
"name"
item-value=
"id"
label=
"Category"
/>
:rules=
"requiredRules"
>
<
template
#item
="{
item
}"
>
<div
:class=
"`category-$
{item.depth}`">
{{
item
.
name
}}
</div>
</
template
>
</v-autocomplete>
</v-col>
<v-col
cols=
"12"
>
<v-textarea
v-model=
"content"
label=
"Content"
:rules=
"requiredRules"
required
/>
</v-col>
...
...
@@ -261,10 +239,11 @@
>
<v-select
v-model=
"status"
:items=
"statusDefaul"
:items=
"statusDefaul
t
"
item-text=
"name"
item-value=
"id"
label=
"Status"
:rules=
"requiredRules"
/>
</v-col>
<v-col
cols=
"12"
>
...
...
@@ -275,19 +254,28 @@
dense
accept=
"image/*"
prepend-icon=
"mdi-camera"
:rules=
"requiredRules"
@
change=
"fileSelected"
/>
</v-col>
<v-col
cols=
"12"
class=
"v-image v-responsive theme--dark"
>
<img
v-if=
"file"
contain
max-height=
"300"
max-width=
"500"
:src=
"file"
>
</v-col>
</v-row>
</v-container>
<small>
*indicates required field
</small>
</v-card-text>
<v-card-actions>
<v-spacer
/>
<v-btn
color=
"blue darken-1"
text
@
click=
"dialog1 = false"
@
click=
"dialog1 = false
; clearFile()
"
>
Close
</v-btn>
...
...
@@ -312,7 +300,7 @@
{{
categories
.
find
(
x
=>
x
.
id
===
item
.
category_id
)?.
name
}}
</
template
>
<
template
#
[`
item
.
status
`
]=
"{ item }"
>
{{
statusDefaul
.
find
(
x
=>
x
.
id
==
item
.
status
)?.
name
}}
{{
statusDefaul
t
.
find
(
x
=>
x
.
id
==
item
.
status
)?.
name
}}
</
template
>
<
template
#
[`
item
.
user_id
`
]=
"{ item }"
>
{{
users
.
find
(
x
=>
x
.
id
===
item
.
user_id
)?.
name
}}
...
...
@@ -324,9 +312,6 @@
<v-icon
:id=
"item.id"
small
@
click=
"dialogDelete = true; getID(item)"
>
mdi-delete
</v-icon>
<v-icon
:id=
"item.id"
small
@
click=
"showPost(item)"
>
mdi-account-details
</v-icon>
</
template
>
<
template
#no-data
>
<v-btn
color=
"primary"
@
click=
"initialize"
>
...
...
@@ -346,15 +331,17 @@ export default {
middleware
:
[
'
web
'
],
data
:
()
=>
{
return
{
filter
:
''
,
search
:
''
,
searchTable
:
''
,
file
:
null
,
dialog1
:
false
,
dialog2
:
false
,
title
:
''
,
category_id
:
null
,
content
:
''
,
user_id
:
''
,
status
:
null
,
images
:
[]
,
images
:
null
,
dialog
:
false
,
dialogDelete
:
false
,
headers
:
[
...
...
@@ -377,41 +364,35 @@ export default {
href
:
'
/home
'
},
{
text
:
'
P
roduc
t
'
,
text
:
'
P
os
t
'
,
disabled
:
false
,
href
:
'
/p
roduc
ts
'
href
:
'
/p
os
ts
'
}
],
statusDefaul
:
[
statusDefaul
t
:
[
{
name
:
'
Draft
'
,
id
:
'
1
'
id
:
1
},
{
name
:
'
Publish
'
,
id
:
'
2
'
id
:
2
},
{
name
:
'
Unpublish
'
,
id
:
'
3
'
id
:
3
}
],
posts
:
[],
categories
:
[],
users
:
[],
sTitle
:
''
,
sCategoryId
:
''
,
sContent
:
''
,
sUserId
:
''
,
sStatus
:
[],
sImages
:
[],
eId
:
''
,
eTitle
:
''
,
eCategoryId
:
[],
eContent
:
''
,
eUserId
:
''
,
eStatus
:
''
,
eImages
:
[]
,
eImages
:
null
,
message
:
[],
editedIndex
:
-
1
,
editedItem
:
{
...
...
@@ -428,7 +409,18 @@ export default {
status
:
''
,
created_at
:
''
,
updated_at
:
''
}
},
requiredRules
:
[
v
=>
!!
v
||
'
This field is required
'
],
numberRules
:
[
v
=>
!!
v
||
'
This field is required
'
,
v
=>
v
>
0
||
'
value must be a positive integer
'
],
imageRules
:
[
v
=>
!!
v
||
'
Images is required
'
,
v
=>
(
v
&&
v
.
length
>
0
)
||
'
Images is required
'
]
}
},
computed
:
{
...
...
@@ -561,6 +553,8 @@ export default {
this
.
editedItem
=
response
.
data
.
data
console
.
log
(
this
.
editedItem
)
this
.
posts
.
push
(
this
.
editedItem
)
this
.
clearData
()
this
.
clearFile
()
})
.
catch
((
errors
)
=>
{
self
.
$toast
.
error
(
'
something went wrong while trying create!
'
,
{
...
...
@@ -569,14 +563,14 @@ export default {
})
},
getID
(
item
)
{
this
.
eI
D
=
item
.
id
this
.
eI
d
=
item
.
id
this
.
editedIndex
=
this
.
categories
.
indexOf
(
item
)
},
deletePost
()
{
const
self
=
this
const
currentPostIndex
=
this
.
editedIndex
this
.
$axios
.
delete
(
`/posts/
${
this
.
eI
D
}
`
,
{
.
delete
(
`/posts/
${
this
.
eI
d
}
`
,
{
headers
:
{
Authorization
:
`Bearer
${
this
.
$auth
.
$storage
.
getUniversal
(
'
token
'
)}
`
}
...
...
@@ -594,30 +588,13 @@ export default {
})
})
},
async
showPost
(
item
)
{
const
ID
=
item
.
id
try
{
const
resp
=
await
this
.
$axios
.
get
(
`/posts/
${
ID
}
`
,
{
headers
:
{
Authorization
:
`Bearer
${
this
.
$auth
.
$storage
.
getUniversal
(
'
token
'
)}
`
}
})
this
.
sTitle
=
resp
.
data
.
data
.
title
this
.
sContent
=
resp
.
data
.
data
.
content
this
.
sCategoryId
=
resp
.
data
.
data
.
category_id
this
.
sStatus
=
resp
.
data
.
data
.
status
this
.
sImages
=
resp
.
data
.
data
.
images
}
catch
(
error
)
{
console
.
log
(
error
)
}
this
.
dialog2
=
true
},
editPost
(
item
)
{
this
.
eId
=
item
.
id
this
.
eTitle
=
item
.
title
this
.
eCategoryId
=
item
.
category_id
this
.
eContent
=
item
.
content
this
.
eStatus
=
item
.
status
this
.
eImages
=
item
.
images
this
.
editedIndex
=
this
.
posts
.
indexOf
(
item
)
console
.
log
(
this
.
editedIndex
)
this
.
dialog
=
true
...
...
@@ -628,9 +605,10 @@ export default {
fd
.
append
(
'
title
'
,
this
.
eTitle
)
fd
.
append
(
'
category_id
'
,
this
.
eCategoryId
)
fd
.
append
(
'
content
'
,
this
.
eContent
)
fd
.
append
(
'
images
'
,
this
.
eImages
)
fd
.
append
(
'
status
'
,
this
.
eStatus
)
if
(
typeof
this
.
eImages
!==
'
string
'
&&
this
.
eImages
!=
null
)
{
fd
.
append
(
'
images
'
,
this
.
eImages
)
}
const
currentPostIndex
=
this
.
editedIndex
this
.
$axios
.
post
(
...
...
@@ -648,6 +626,7 @@ export default {
})
this.editedItem = response.data.data
Object.assign(this.posts[currentPostIndex], this.editedItem)
this.clearFile()
})
.catch((error) => {
console.log(error)
...
...
@@ -657,13 +636,39 @@ export default {
})
},
fileSelected (event) {
console.log(event)
console.log(this.images)
if (event) {
this.file = URL.createObjectURL(event)
console.log(this.file)
} else {
this.file = null
}
},
clearData () {
this.title = ''
this.category_id = null
this.content = ''
this.status = null
this.images = []
},
clearFile () {
this.file = null
}
}
}
</
script
>
<
style
>
.category-1
{
padding-left
:
30px
!important
;
}
.category-2
{
padding-left
:
60px
!important
;
}
.category-3
{
padding-left
:
90px
!important
;
}
img
{
width
:
100%
;
height
:
100%
;
}
</
style
>
pages/products/index.vue
View file @
6f198a23
...
...
@@ -7,112 +7,6 @@
</
template
>
</v-breadcrumbs>
</div>
<!-- show-modal -->
<v-dialog
v-model=
"dialog2"
persistent
max-width=
"600px"
>
<v-card>
<v-card-title>
<span
class=
"text-h5"
>
PRODUCT
</span>
</v-card-title>
<v-card-text>
<v-container>
<v-row>
<v-col
cols=
"12"
sm=
"6"
md=
"4"
>
<v-text-field
v-model=
"sName"
label=
"Name"
readonly
/>
</v-col>
<v-col
cols=
"12"
>
<v-select
v-model=
"sCategoryId"
:items=
"categories"
item-text=
"name"
item-value=
"id"
label=
"Category"
readonly
/>
</v-col>
<v-col
cols=
"12"
>
<v-text-field
v-model=
"sPrice"
label=
"Price"
readonly
/>
</v-col>
<v-col
cols=
"12"
>
<v-text-field
v-model=
"sDescription"
label=
"Description"
readonly
/>
</v-col>
<v-col
v-for=
"(image, index) in sImages"
:key=
"index"
cols=
"12"
>
<v-img
:src=
"image"
contain
/>
</v-col>
<v-col
cols=
"12"
/>
<v-row
v-for=
"(variant, index) in sVariants"
:key=
"'A' +index"
>
<v-col
cols=
"12"
sm=
"6"
md=
"4"
>
<v-text-field
v-model=
"variant.color"
label=
"Color"
readonly
/>
</v-col>
<v-col
cols=
"12"
sm=
"6"
md=
"4"
>
<v-text-field
v-model=
"variant.size"
label=
"Size"
readonly
/>
</v-col>
<v-col
cols=
"12"
sm=
"6"
md=
"4"
>
<v-text-field
v-model=
"variant.quantity"
label=
"Quantity"
readonly
/>
</v-col>
<v-col
/>
</v-row>
</v-row>
</v-container>
</v-card-text>
<v-card-actions>
<v-spacer
/>
<v-btn
color=
"blue darken-1"
text
type=
"submit"
@
click=
"dialog2 = false"
>
Close
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<!-- edit-modal -->
<v-dialog
v-model=
"dialog3"
...
...
@@ -128,8 +22,6 @@
<v-row>
<v-col
cols=
"12"
sm=
"6"
md=
"4"
>
<v-text-field
v-model=
"eName"
...
...
@@ -141,14 +33,21 @@
<v-col
cols=
"12"
>
<v-
select
<v-
autocomplete
v-model=
"eCategoryId"
class=
"select--menu my-select"
:items=
"categories"
item-text=
"name"
item-value=
"id"
label=
"Category"
:rules=
"requiredRules"
/>
>
<
template
#item
="{
item
}"
>
<div
:class=
"`category-$
{item.depth}`">
{{
item
.
name
}}
</div>
</
template
>
</v-autocomplete>
</v-col>
<v-col
cols=
"12"
>
<v-text-field
...
...
@@ -172,9 +71,30 @@
small-chips
dense
multiple
@
change=
"fileSelected"
@
click:clear=
"clearImage"
/>
</v-col>
<v-col
v-if=
"files"
cols=
"12"
style=
"display:flex; text-align:left"
>
<v-img
v-for=
"(image, index) in files"
:key=
"index"
:src=
"image"
contain
height=
"100px"
width=
"150px"
/>
</v-col>
<v-col
cols=
"12"
style=
"display:flex; text-align:left"
>
<v-img
v-for=
"(imageEdit, index) in eImages"
:key=
"index"
contain
height=
"100px"
width=
"150px"
:src=
"imageEdit"
/>
</v-col>
<v-img
v-if=
"typeof eImages === 'string'"
:src=
"eImages"
/>
<v-col
cols=
"12"
>
<v-btn
class=
"mx-2"
...
...
@@ -244,14 +164,13 @@
</v-row>
</v-row>
</v-container>
<small>
*indicates required field
</small>
</v-card-text>
<v-card-actions>
<v-spacer
/>
<v-btn
color=
"blue darken-1"
text
@
click=
"dialog3 = false"
@
click=
"dialog3 = false
; clearImage();
"
>
Close
</v-btn>
...
...
@@ -306,13 +225,19 @@
<v-data-table
:headers=
"headers"
:items=
"products"
:search=
"searchTable"
sort-by=
"calories"
class=
"elevation-1"
>
<
template
#top
>
<v-toolbar
flat
>
<v-toolbar-title>
Product Manage
</v-toolbar-title>
<v-divider
class=
"mx-4"
inset
vertical
/>
<v-text-field
v-model=
"searchTable"
append-icon=
"mdi-magnify"
label=
"Search"
single-line
hide-details
/>
<v-spacer
/>
<v-toolbar-title>
<v-dialog
...
...
@@ -328,7 +253,7 @@
v-bind=
"attrs"
v-on=
"on"
>
New Product
create new
</v-btn>
</
template
>
<v-card>
...
...
@@ -340,8 +265,6 @@
<v-row>
<v-col
cols=
"12"
sm=
"6"
md=
"4"
>
<v-text-field
v-model=
"name"
...
...
@@ -354,14 +277,20 @@
<v-col
cols=
"12"
>
<v-
select
<v-
autocomplete
v-model=
"category_id"
:items=
"categories"
item-text=
"name"
item-value=
"id"
label=
"Category"
:rules=
"requiredRules"
/>
>
<
template
#item
="{
item
}"
>
<div
:class=
"`category-$
{item.depth}`">
{{
item
.
name
}}
</div>
</
template
>
</v-autocomplete>
</v-col>
<v-col
cols=
"12"
>
<v-text-field
...
...
@@ -388,8 +317,20 @@
:rules=
"imageRules"
lazy-validation
prepend-icon=
"mdi-camera"
@
change=
"fileSelected"
@
click:clear=
"clearImage"
/>
</v-col>
<v-col
v-if=
"files"
cols=
"12"
style=
"display:flex; justify-content: space-around;"
>
<img
v-for=
"(image, index) in files"
:key=
"index"
:src=
"image"
contain
height=
"100px"
width=
"150px"
>
</v-col>
<v-col
cols=
"12"
>
<v-btn
class=
"mx-2"
...
...
@@ -459,14 +400,13 @@
</v-row>
</v-row>
</v-container>
<small>
*indicates required field
</small>
</v-card-text>
<v-card-actions>
<v-spacer
/>
<v-btn
color=
"blue darken-1"
text
@
click=
"dialog1 = false"
@
click=
"dialog1 = false
; clearData ();
"
>
Close
</v-btn>
...
...
@@ -487,6 +427,15 @@
<
template
#
[`
item
.
index
`
]=
"{ index }"
>
{{
index
+
1
}}
</
template
>
<
template
#
[`
item
.
variants
`
]=
"{ item }"
>
{{
item
.
variants_count
}}
</
template
>
<
template
#
[`
item
.
status
`
]=
"{ item }"
>
<v-switch
v-model=
"item.status"
@
click=
"switchStatus(item)"
/>
</
template
>
<
template
#
[`
item
.
actions
`
]=
"{ item }"
>
<v-icon
:id=
"item.id"
small
@
click=
"editProduct(item)"
>
mdi-pencil
...
...
@@ -494,9 +443,6 @@
<v-icon
:id=
"item.id"
small
@
click=
"dialogDelete = true; getID(item)"
>
mdi-delete
</v-icon>
<v-icon
:id=
"item.id"
small
@
click=
"showProduct(item)"
>
mdi-account-details
</v-icon>
</
template
>
<
template
#no-data
>
<v-btn
color=
"primary"
@
click=
"initialize"
>
...
...
@@ -514,6 +460,8 @@ export default {
middleware
:
[
'
web
'
],
data
:
()
=>
{
return
{
searchTable
:
''
,
files
:
[],
name
:
''
,
id
:
''
,
category_id
:
''
,
...
...
@@ -521,6 +469,7 @@ export default {
stock
:
''
,
description
:
''
,
images
:
[],
status
:
''
,
variants
:
[
{
color
:
''
,
...
...
@@ -533,7 +482,6 @@ export default {
quantity
:
''
,
dialog
:
false
,
dialog1
:
false
,
dialog2
:
false
,
dialog3
:
false
,
dialogDelete
:
false
,
dialogDeleteVariant
:
false
,
...
...
@@ -549,6 +497,8 @@ export default {
{
text
:
'
Category
'
,
value
:
'
category.name
'
},
{
text
:
'
Price
'
,
value
:
'
price
'
},
{
text
:
'
Stock
'
,
value
:
'
stock
'
},
{
text
:
'
Variants
'
,
value
:
'
variants
'
},
{
text
:
'
Status
'
,
value
:
'
status
'
},
{
text
:
'
Actions
'
,
value
:
'
actions
'
,
sortable
:
false
}
],
items
:
[
...
...
@@ -568,19 +518,7 @@ export default {
products
:
[],
product
:
[],
categories
:
[],
sName
:
''
,
sCategoryId
:
''
,
sPrice
:
''
,
sDescription
:
''
,
sStock
:
''
,
sImages
:
[],
sVariants
:
[
{
color
:
''
,
size
:
''
,
quantity
:
''
}
],
categoryTrees
:
[],
idVariant
:
''
,
editedVariantIndex
:
''
,
eId
:
''
,
...
...
@@ -604,7 +542,8 @@ export default {
category_id
:
''
,
price
:
''
,
description
:
''
,
stock
:
''
stock
:
''
,
variants_count
:
''
},
defaultItem
:
{
name
:
''
,
...
...
@@ -647,6 +586,7 @@ export default {
this
.
initialize
()
this
.
getProducts
()
this
.
getCategories
()
this
.
getCategoryTrees
()
},
methods
:
{
initialize
()
{
...
...
@@ -704,6 +644,22 @@ export default {
}
this
.
close
()
},
getCategoryTrees
()
{
this
.
$axios
.
get
(
'
/categories-tree/
'
,
{
headers
:
{
Authorization
:
`Bearer
${
this
.
$auth
.
$storage
.
getUniversal
(
'
token
'
)}
`
}
})
.
then
((
response
)
=>
{
this
.
categoryTrees
=
response
.
data
.
data
})
.
catch
(
function
(
error
)
{
console
.
log
(
error
)
})
},
getCategories
()
{
this
.
$axios
.
get
(
'
/categories/
'
,
{
...
...
@@ -757,8 +713,10 @@ export default {
duration
:
3000
})
this
.
editedItem
=
response
.
data
.
data
this
.
editedItem
.
variants_count
=
response
.
data
.
data
.
variants
.
length
console
.
log
(
this
.
editedItem
)
this
.
products
.
push
(
this
.
editedItem
)
this
.
clearData
()
})
.
catch
((
errors
)
=>
{
console
.
log
(
errors
.
response
.
data
.
message
)
...
...
@@ -792,27 +750,6 @@ export default {
console
.
log
(
error
)
}
},
async
showProduct
(
item
)
{
const
ID
=
item
.
id
try
{
const
resp
=
await
this
.
$axios
.
get
(
`/products/
${
ID
}
`
,
{
method
:
'
GET
'
,
headers
:
{
Authorization
:
`Bearer
${
this
.
$auth
.
$storage
.
getUniversal
(
'
token
'
)}
`
}
})
this
.
sName
=
resp
.
data
.
data
.
name
this
.
sPrice
=
resp
.
data
.
data
.
price
this
.
sCategoryId
=
resp
.
data
.
data
.
category_id
this
.
sDescription
=
resp
.
data
.
data
.
description
this
.
sStock
=
resp
.
data
.
data
.
stock
this
.
sVariants
=
resp
.
data
.
data
.
variants
this
.
sImages
=
resp
.
data
.
data
.
images
}
catch
(
error
)
{
console
.
log
(
error
)
}
this
.
dialog2
=
true
},
editProduct
(
item
)
{
this
.
eId
=
item
.
id
this
.
eName
=
item
.
name
...
...
@@ -821,6 +758,7 @@ export default {
this
.
eStock
=
item
.
stock
this
.
eDescription
=
item
.
description
this
.
eVariants
=
item
.
variants
this
.
eImages
=
item
.
images
this
.
editedIndex
=
this
.
products
.
indexOf
(
item
)
console
.
log
(
item
.
variants
)
this
.
dialog3
=
true
...
...
@@ -856,7 +794,7 @@ export default {
}
)
.then((response) => {
self.$toast.success('
User
updated successfully!', {
self.$toast.success('
Product
updated successfully!', {
duration: 3000
})
console.log(response)
...
...
@@ -889,28 +827,77 @@ export default {
this.idVariant = item.id
},
removeVariant () {
const self = this
const currentVariantIndex = this.editedVariantIndex
if (this.idVariant !== null) {
try {
this.$axios.delete(`
/
products
/
delete
-
variant
/
$
{
this
.
idVariant
}
`,
{
headers: {
Authorization: `
Bearer
$
{
this
.
$auth
.
$storage
.
getUniversal
(
'
token
'
)}
`
}
this.eVariants.splice(currentVariantIndex, 1)
},
fileSelected (event) {
if (event) {
for (let i = 0; i < event.length; i++) {
console.log(event[i])
this.files.push(URL.createObjectURL(event[i]))
}
}
console.log(this.files)
},
clearData () {
this.name = ''
this.category_id = ''
this.price = ''
this.description = ''
this.images = []
this.variants = [
{
color: '',
size: '',
quantity: ''
}
]
this.files.length = 0
},
clearImage () {
this.files.length = 0
},
switchStatus (item) {
const status = item.status ? 1 : 0
const self = this
const fd = new FormData()
fd.append('status', status)
this.$axios
.post(`
/
products
/
update
-
status
/
$
{
item
.
id
}
`,
fd, {
headers: {
Authorization: `
Bearer
$
{
this
.
$auth
.
$storage
.
getUniversal
(
'
token
'
)}
`
}
).then((response) => {
self.$toast.success('Remove variant successfully!', {
duration: 3000
})
}
)
.then((response) => {
console.log(response)
self.$toast.success('Updated status successfully!', {
duration: 3000
})
this.getProducts(
)
} catch (error)
{
}
)
.catch((error) =>
{
console.log(error)
}
this.eVariants.splice(currentVariantIndex, 1)
}
self.$toast.error('ERR!', {
duration: 3000
})
})
}
}
}
</
script
>
<
style
>
.category-1
{
padding-left
:
30px
!important
;
}
.category-2
{
padding-left
:
60px
!important
;
}
.category-3
{
padding-left
:
90px
!important
;
}
img
{
width
:
100px
;
height
:
150px
;
}
</
style
>
pages/users/index.vue
View file @
6f198a23
...
...
@@ -18,29 +18,30 @@
</v-card-title>
<v-card-text>
<v-container>
<v-row>
<v-col
cols=
"12"
sm=
"6"
md=
"4"
>
<v-text-field
v-model=
"eName"
label=
"Legal name*"
:rules=
"nameRules"
required
/>
</v-col>
<v-col
cols=
"12"
>
<v-text-field
v-model=
"eEmail"
label=
"Email*"
:rules=
"emailRules"
required
/>
</v-col>
<v-col
cols=
"12"
>
<v-text-field
v-model=
"ePassword"
label=
"Password*"
type=
"password"
:rules=
"passwordRules"
required
/>
</v-col>
</v-row>
<v-form
ref=
"formEdit"
>
<v-row>
<v-col
cols=
"12"
sm=
"6"
md=
"4"
>
<v-text-field
v-model=
"eName"
label=
"Legal name*"
:rules=
"nameRules"
required
/>
</v-col>
<v-col
cols=
"12"
>
<v-text-field
v-model=
"eEmail"
label=
"Email*"
:rules=
"emailRules"
required
/>
</v-col>
<v-col
cols=
"12"
>
<v-text-field
v-model=
"ePassword"
label=
"Password*"
type=
"password"
:rules=
"passwordRules"
required
/>
</v-col>
</v-row>
</v-form>
</v-container>
<small>
*indicates required field
</small>
</v-card-text>
<v-card-actions>
<v-spacer
/>
<v-btn
color=
"blue darken-1"
text
@
click=
"dialog2 = false"
>
<v-btn
color=
"blue darken-1"
text
@
click=
"dialog2 = false
; clearData();
"
>
Close
</v-btn>
<v-btn
...
...
@@ -48,8 +49,9 @@
text
type=
"submit"
@
click=
"
dialog2 = false;
//
dialog2 = false;
updateUser();
validateForm();
"
>
Save
...
...
@@ -85,25 +87,30 @@
<v-data-table
:headers=
"headers"
:items=
"users"
:search=
"searchTable"
sort-by=
"calories"
class=
"elevation-1"
>
<
template
#top
>
<v-toolbar
flat
>
<v-toolbar-title>
User Manage
</v-toolbar-title>
<v-divider
class=
"mx-4"
inset
vertical
/>
<v-text-field
v-model=
"searchTable"
append-icon=
"mdi-magnify"
label=
"Search"
single-line
hide-details
/>
<v-spacer
/>
<v-toolbar-title
style=
"float: right"
>
<v-dialog
v-model=
"dialog1"
persistent
max-width=
"600px"
@
submit.prevent=
"createUser"
lazy-validation
>
<template
#activator
="
{ on, attrs }">
<v-btn
color=
"primary"
dark
v-bind=
"attrs"
v-on=
"on"
>
New USER
CREATE NEW
</v-btn>
</
template
>
<v-card>
...
...
@@ -112,35 +119,36 @@
</v-card-title>
<v-card-text>
<v-container>
<v-row>
<v-col
cols=
"12"
sm=
"6"
md=
"4"
>
<v-text-field
v-model=
"name"
label=
"Legal name*"
:rules=
"nameRules"
required
/>
</v-col>
<v-col
cols=
"12"
>
<v-text-field
v-model=
"email"
label=
"Email*"
:rules=
"emailRules"
required
/>
</v-col>
<v-col
cols=
"12"
>
<v-text-field
v-model=
"password"
label=
"Password*"
type=
"password"
:rules=
"passwordRules"
required
/>
</v-col>
</v-row>
<v-form
ref=
"form"
>
<v-row>
<v-col
cols=
"12"
sm=
"6"
md=
"4"
>
<v-text-field
v-model=
"name"
label=
"Legal name*"
:rules=
"nameRules"
required
/>
</v-col>
<v-col
cols=
"12"
>
<v-text-field
v-model=
"email"
label=
"Email*"
:rules=
"emailRules"
required
/>
</v-col>
<v-col
cols=
"12"
>
<v-text-field
v-model=
"password"
label=
"Password*"
type=
"password"
:rules=
"passwordRules"
required
/>
</v-col>
</v-row>
</v-form>
</v-container>
<small>
*indicates required field
</small>
</v-card-text>
<v-card-actions>
<v-spacer
/>
...
...
@@ -152,8 +160,9 @@
text
type=
"submit"
@
click=
"
dialog1 = false;
//
dialog1 = false;
createUser();
validateForm()
"
>
Save
...
...
@@ -167,10 +176,10 @@
<
template
#
[`
item
.
index
`
]=
"{ index }"
>
{{
index
+
1
}}
</
template
>
<
template
#
item.created_at
=
"{ item }"
>
<
template
#
[`
item
.
created_at
`
]
=
"{ item }"
>
<span>
{{
formatDate
(
item
.
created_at
)
}}
</span>
</
template
>
<
template
#
item.updated_at
=
"{ item }"
>
<
template
#
[`
item
.
updated_at
`
]
=
"{ item }"
>
<span>
{{
formatDate
(
item
.
updated_at
)
}}
</span>
</
template
>
<
template
#
[`
item
.
actions
`
]=
"{ item }"
>
...
...
@@ -211,6 +220,8 @@ export default {
middleware
:
[
'
web
'
],
data
:
()
=>
{
return
{
searchTable
:
''
,
valid
:
true
,
email
:
''
,
name
:
''
,
password
:
''
,
...
...
@@ -224,9 +235,8 @@ export default {
align
:
'
start
'
,
value
:
'
index
'
},
{
text
:
'
Name
'
,
value
:
'
name
'
},
{
text
:
'
Name
'
,
value
:
'
name
'
,
sortable
:
false
},
{
text
:
'
email
'
,
value
:
'
email
'
},
{
text
:
'
status
'
,
value
:
'
id
'
,
sortable
:
false
},
{
text
:
'
created
'
,
value
:
'
created_at
'
},
{
text
:
'
updated
'
,
value
:
'
updated_at
'
},
{
text
:
'
Actions
'
,
value
:
'
actions
'
,
sortable
:
false
}
...
...
@@ -378,6 +388,7 @@ export default {
}
)
.
then
((
response
)
=>
{
this
.
dialog1
=
false
self
.
$toast
.
success
(
'
User created successfully!
'
,
{
duration
:
3000
})
...
...
@@ -385,8 +396,11 @@ export default {
this
.
editedItem
=
response
.
data
.
data
console
.
log
(
this
.
editedItem
)
this
.
users
.
push
(
this
.
editedItem
)
this
.
clearData
()
})
.
catch
((
errors
)
=>
{
this
.
dialog1
=
true
this
.
validate
()
console
.
log
(
errors
.
response
.
data
.
message
)
this
.
message
=
errors
.
response
.
data
.
message
self
.
$toast
.
error
(
'
something went wrong while trying create!
'
,
{
...
...
@@ -443,6 +457,7 @@ export default {
}
)
.then((response) => {
this.dialog2 = false
self.$toast.success('User updated successfully!', {
duration: 3000
})
...
...
@@ -460,6 +475,21 @@ export default {
getID (item) {
this.eID = item.id
this.editedIndex = this.users.indexOf(item)
},
clearData () {
this.name = ''
this.email = ''
this.password = ''
},
async validate (name) {
const { valid } = await this.$refs.form.validate()
if (valid) { alert('Form is valid') }
},
async validateForm (name) {
const { valid } = await this.$refs.formEdit.validate()
if (valid) { alert('Form is valid') }
}
}
}
...
...
plugins/axios.js
View file @
6f198a23
...
...
@@ -12,6 +12,13 @@ export default function ({ $axios }, inject, redirect) {
}
})
$axios
.
onError
((
error
)
=>
{
const
code
=
parseInt
(
error
.
response
&&
error
.
response
.
status
)
if
(
code
===
403
)
{
redirect
(
'
/login
'
)
}
})
const
api
=
$axios
.
create
({
headers
:
{
common
:
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment