Commit 6f198a23 authored by Le Dinh Trung's avatar Le Dinh Trung

Merge branch 'feature/UI-vuetify' into 'dev'

Feature/ui vuetify

See merge request !19
parents 68c8f625 4b0a2154
...@@ -9,28 +9,28 @@ ...@@ -9,28 +9,28 @@
<v-app-bar-nav-icon /> <v-app-bar-nav-icon />
<v-toolbar-title> <v-toolbar-title>
<v-btn href="/users"> <v-btn to="/users">
<span>USER</span> <span>USER</span>
<v-icon dense> <v-icon dense>
mdi-account mdi-account
</v-icon> </v-icon>
</v-btn> </v-btn>
<v-btn href="/categories"> <v-btn to="/categories">
<span>CATEGORY</span> <span>CATEGORY</span>
<v-icon dense> <v-icon dense>
mdi-heart mdi-heart
</v-icon> </v-icon>
</v-btn> </v-btn>
<v-btn href="/products"> <v-btn to="/products">
<span>PRODUCT</span> <span>PRODUCT</span>
<v-icon dense> <v-icon dense>
mdi-briefcase mdi-briefcase
</v-icon> </v-icon>
</v-btn> </v-btn>
<v-btn href="/posts"> <v-btn to="/posts">
<span>POST</span> <span>POST</span>
<v-icon dense> <v-icon dense>
mdi-newspaper mdi-newspaper
...@@ -86,7 +86,7 @@ export default { ...@@ -86,7 +86,7 @@ export default {
const resp = await this.$axios.post('/logout', { const resp = await this.$axios.post('/logout', {
token: this.$auth.$storage.getUniversal('token') token: this.$auth.$storage.getUniversal('token')
}) })
if (resp.status == '200') { if (resp.status === 200) {
this.$toast.success('Logout!', { this.$toast.success('Logout!', {
duration: 2000 duration: 2000
}) })
......
export default ({ redirect, store }) => { export default ({ redirect, store, $auth }) => {
if (typeof localStorage !== 'undefined' && !localStorage.getItem('token')) { if (!$auth.$storage.getLocalStorage('token')) {
return redirect('/login') return redirect('/login')
} }
} }
...@@ -10,73 +10,14 @@ ...@@ -10,73 +10,14 @@
</v-breadcrumbs> </v-breadcrumbs>
</div> </div>
<!-- modal-create --> <!-- modal-create -->
<v-dialog <v-dialog v-model="dialog2" persistent max-width="600px">
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-card> <v-card>
<v-card-title> <v-card-title>
<span class="text-h5">Category Edit</span> <span class="text-h5">Category Edit</span>
</v-card-title> </v-card-title>
<v-card-text> <v-card-text>
<v-container> <v-container>
<v-form ref="formEdit">
<v-row> <v-row>
<v-col cols="12"> <v-col cols="12">
<v-text-field <v-text-field
...@@ -96,13 +37,21 @@ ...@@ -96,13 +37,21 @@
/> />
</v-col> </v-col>
<v-col cols="12"> <v-col cols="12">
<v-select <v-autocomplete
v-model="eParentId" v-model="eParentId"
:items="categories.filter(category =>category.id !== eID)" :items="
categories.filter((category) => category.id !== eID)
"
item-text="name" item-text="name"
item-value="id" item-value="id"
label="Parent" label="Parent"
/> >
<template #item="{item}">
<div :class="`category-${item.depth}`">
{{ item.name }}
</div>
</template>
</v-autocomplete>
</v-col> </v-col>
<v-col cols="12"> <v-col cols="12">
<v-file-input <v-file-input
...@@ -110,19 +59,38 @@ ...@@ -110,19 +59,38 @@
accept="image/*" accept="image/*"
label="Image" label="Image"
prepend-icon="mdi-camera" 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-col>
<v-img v-if="typeof eImage === 'string'" :src="eImage" />
</v-row> </v-row>
</v-form>
</v-container> </v-container>
<small>*indicates required field</small>
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
<v-spacer /> <v-spacer />
<v-btn <v-btn
color="blue darken-1" color="blue darken-1"
text text
@click="dialog2 = false" @click="
dialog2 = false;
clearFile();
clearEditData();
"
> >
Close Close
</v-btn> </v-btn>
...@@ -130,18 +98,33 @@ ...@@ -130,18 +98,33 @@
color="blue darken-1" color="blue darken-1"
text text
type="submit" type="submit"
@click="dialog2 = false; updateCategory();" @click="
dialog2 = false;
updateCategory();
"
> >
Save Save
</v-btn> </v-btn>
</v-card-actions> </v-card-actions>
</v-card> </v-card>
</v-dialog> </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> <template #top>
<v-toolbar flat> <v-toolbar flat>
<v-toolbar-title>Category Manage</v-toolbar-title> <v-text-field
<v-divider class="mx-4" inset vertical /> v-model="searchTable"
append-icon="mdi-magnify"
label="Search"
single-line
hide-details
/>
<v-spacer /> <v-spacer />
<v-toolbar-title style="float: right"> <v-toolbar-title style="float: right">
<v-dialog <v-dialog
...@@ -151,13 +134,8 @@ ...@@ -151,13 +134,8 @@
lazy-validation lazy-validation
> >
<template #activator="{ on, attrs }"> <template #activator="{ on, attrs }">
<v-btn <v-btn color="primary" dark v-bind="attrs" v-on="on">
color="primary" CREATE NEW
dark
v-bind="attrs"
v-on="on"
>
New Category
</v-btn> </v-btn>
</template> </template>
<v-card> <v-card>
...@@ -167,11 +145,7 @@ ...@@ -167,11 +145,7 @@
<v-card-text> <v-card-text>
<v-container> <v-container>
<v-row> <v-row>
<v-col <v-col cols="12">
cols="12"
sm="6"
md="4"
>
<v-text-field <v-text-field
v-model="name" v-model="name"
label="Name" label="Name"
...@@ -190,32 +164,46 @@ ...@@ -190,32 +164,46 @@
/> />
</v-col> </v-col>
<v-col cols="12"> <v-col cols="12">
<v-select <v-autocomplete
v-model="parent_id" v-model="parent_id"
:items="categories" :items="categories"
:search="search"
:filter="filter"
item-text="name" item-text="name"
item-value="id" item-value="id"
label="Parent*" label="Parent*"
:rules="requiredRules" :rules="requiredRules"
/> >
<template #item="{item}">
<div :class="`category-${item.depth}`">
{{ item.name }}
</div>
</template>
</v-autocomplete>
</v-col> </v-col>
<v-col cols="12"> <v-col cols="12">
<v-file-input <v-file-input
v-model="image" v-model="image"
label="Image" label="Image"
prepend-icon="mdi-camera" prepend-icon="mdi-camera"
@change="fileSelected"
/> />
</v-col> </v-col>
<v-col cols="12">
<img v-if="file" :src="file" contain>
</v-col>
</v-row> </v-row>
</v-container> </v-container>
<small>*indicates required field</small>
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
<v-spacer /> <v-spacer />
<v-btn <v-btn
color="blue darken-1" color="blue darken-1"
text text
@click="dialog1 = false" @click="
dialog1 = false;
clearFile();
"
> >
Close Close
</v-btn> </v-btn>
...@@ -223,7 +211,10 @@ ...@@ -223,7 +211,10 @@
color="blue darken-1" color="blue darken-1"
text text
type="submit" type="submit"
@click="dialog1 = false; createCategory();" @click="
dialog1 = false;
createCategory();
"
> >
Save Save
</v-btn> </v-btn>
...@@ -246,13 +237,22 @@ ...@@ -246,13 +237,22 @@
<v-text-field v-model="editedItem.id" label="id" /> <v-text-field v-model="editedItem.id" label="id" />
</v-col> </v-col>
<v-col cols="12" sm="6" md="4"> <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>
<v-col cols="12" sm="6" md="4"> <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>
<v-col cols="12" sm="6" md="4"> <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-col>
</v-row> </v-row>
</v-container> </v-container>
...@@ -278,7 +278,14 @@ ...@@ -278,7 +278,14 @@
<v-btn color="blue darken-1" text @click="closeDelete"> <v-btn color="blue darken-1" text @click="closeDelete">
Cancel Cancel
</v-btn> </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 OK
</v-btn> </v-btn>
<v-spacer /> <v-spacer />
...@@ -290,22 +297,33 @@ ...@@ -290,22 +297,33 @@
<template #[`item.index`]="{ index }"> <template #[`item.index`]="{ index }">
{{ index + 1 }} {{ index + 1 }}
</template> </template>
<template #item.created_at="{ item }"> <template #[`item.created_at`]="{ item }">
<span>{{ formatDate(item.created_at) }}</span> <span>{{ formatDate(item.created_at) }}</span>
</template> </template>
<template #item.updated_at="{ item }"> <template #[`item.updated_at`]="{ item }">
<span>{{ formatDate(item.updated_at) }}</span> <span>{{ formatDate(item.updated_at) }}</span>
</template> </template>
<template #item.actions="{ item }"> <template #[`item.actions`]="{ item }">
<v-icon :id="item.id" small @click="dialog2 = true; editCategory(item)"> <v-icon
:id="item.id"
small
@click="
dialog2 = true;
editCategory(item);
"
>
mdi-pencil mdi-pencil
</v-icon> </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 mdi-delete
</v-icon> </v-icon>
<v-icon :id="item.id" small @click="dialog3 = true; showCategory(item)">
mdi-account-details
</v-icon>
</template> </template>
<template #no-data> <template #no-data>
<v-btn color="primary" @click="initialize"> <v-btn color="primary" @click="initialize">
...@@ -317,12 +335,14 @@ ...@@ -317,12 +335,14 @@
</v-app> </v-app>
</template> </template>
<script> <script>
export default { export default {
layout: 'admin', layout: 'admin',
middleware: ['web'], middleware: ['web'],
data: () => { data: () => {
return { return {
search: '',
searchTable: '',
file: null,
parent_id: '', parent_id: '',
name: '', name: '',
ordering: '', ordering: '',
...@@ -331,23 +351,26 @@ export default { ...@@ -331,23 +351,26 @@ export default {
dialog: false, dialog: false,
dialog1: false, dialog1: false,
dialog2: false, dialog2: false,
dialog3: false,
dialogDelete: false, dialogDelete: false,
options: [], options: [],
headers: [ headers: [
{ {
text: '#', text: '#',
align: 'start', align: 'start',
value: 'index', value: 'index'
groupable: false
}, },
{ text: 'Name', value: 'name', groupable: false }, { text: 'Name', value: 'name', groupable: false },
{ text: 'Odering', value: 'ordering', groupable: false }, { text: 'Ordering', value: 'ordering', filterable: true },
{ text: 'Created', value: 'created_at', groupable: false }, { text: 'Created', value: 'created_at' },
{ text: 'Updated', value: 'updated_at', groupable: false }, { text: 'Updated', value: 'updated_at' },
{ text: 'Actions', value: 'actions', sortable: false, groupable: false } {
text: 'Actions',
value: 'actions',
sortable: false
}
], ],
categories: [], categories: [],
categoryTrees: [],
eID: '', eID: '',
eName: '', eName: '',
eOrdering: '', eOrdering: '',
...@@ -359,7 +382,7 @@ export default { ...@@ -359,7 +382,7 @@ export default {
name: '', name: '',
id: '', id: '',
ordering: '', ordering: '',
parent_id: '', parent_id: [],
created_at: '', created_at: '',
updated_at: '' updated_at: ''
}, },
...@@ -388,9 +411,7 @@ export default { ...@@ -388,9 +411,7 @@ export default {
v => !!v || 'Name is required', v => !!v || 'Name is required',
v => (v && v.length <= 255) || 'Name must be less than 255 characters' v => (v && v.length <= 255) || 'Name must be less than 255 characters'
], ],
requiredRules: [ requiredRules: [v => !!v || 'This field is required'],
v => !!v || 'This field is required',
],
numberRules: [ numberRules: [
v => !!v || 'This field is required', v => !!v || 'This field is required',
v => v > 0 || 'value must be a positive integer' v => v > 0 || 'value must be a positive integer'
...@@ -400,6 +421,11 @@ export default { ...@@ -400,6 +421,11 @@ export default {
computed: { computed: {
formTitle () { formTitle () {
return this.editedIndex === -1 ? 'New Item' : 'Edit Item' return this.editedIndex === -1 ? 'New Item' : 'Edit Item'
},
filter () {
return this.caseSensitive
? (item, search, textKey) => item[textKey].includes(search)
: undefined
} }
}, },
watch: { watch: {
...@@ -413,6 +439,7 @@ export default { ...@@ -413,6 +439,7 @@ export default {
created () { created () {
this.initialize() this.initialize()
this.getCategories() this.getCategories()
this.getCategoryTrees()
}, },
methods: { methods: {
indentation (item) { indentation (item) {
...@@ -458,11 +485,29 @@ export default { ...@@ -458,11 +485,29 @@ export default {
} }
this.close() 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 () { getCategories () {
this.$axios this.$axios
.get('/categories/', { .get('/categories/', {
headers: { headers: {
Authorization: `Bearer ${this.$auth.$storage.getUniversal('token')}` Authorization: `Bearer ${this.$auth.$storage.getUniversal(
'token'
)}`
} }
}) })
.then((response) => { .then((response) => {
...@@ -482,14 +527,11 @@ export default { ...@@ -482,14 +527,11 @@ export default {
fd.append('image', this.image) fd.append('image', this.image)
} }
this.$axios this.$axios
.post('/categories/', .post('/categories/', fd, {
fd,
{
headers: { headers: {
Authorization: `Bearer ${this.$auth.$storage.getUniversal('token')}` Authorization: `Bearer ${this.$auth.$storage.getUniversal('token')}`
} }
} })
)
.then((response) => { .then((response) => {
self.$toast.success('Category created successfully!', { self.$toast.success('Category created successfully!', {
duration: 3000 duration: 3000
...@@ -505,6 +547,8 @@ export default { ...@@ -505,6 +547,8 @@ export default {
}) })
}) })
this.getCategories() this.getCategories()
this.getCategoryTrees()
this.clearFile()
this.clearData() this.clearData()
}, },
deleteCategory () { deleteCategory () {
...@@ -512,10 +556,11 @@ export default { ...@@ -512,10 +556,11 @@ export default {
const currentPostIndex = this.editedIndex const currentPostIndex = this.editedIndex
try { try {
this.$axios this.$axios
.delete(`/categories/${this.eID}`, .delete(`/categories/${this.eID}`, {
{
headers: { headers: {
Authorization: `Bearer ${this.$auth.$storage.getUniversal('token')}` Authorization: `Bearer ${this.$auth.$storage.getUniversal(
'token'
)}`
} }
}) })
.then((response) => { .then((response) => {
...@@ -544,12 +589,6 @@ export default { ...@@ -544,12 +589,6 @@ export default {
console.log(this.eID) console.log(this.eID)
console.log(this.eImage) 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) { updateCategory (userID) {
const self = this const self = this
const fd = new FormData() const fd = new FormData()
...@@ -565,32 +604,63 @@ export default { ...@@ -565,32 +604,63 @@ export default {
} }
try { try {
this.$axios this.$axios
.post(`categories/update/${this?.eID}`, .post(`categories/update/${this?.eID}`, fd, {
fd,
{
headers: { headers: {
Authorization: `Bearer ${this.$auth.$storage.getUniversal('token')}` Authorization: `Bearer ${this.$auth.$storage.getUniversal(
} 'token'
)}`
} }
) })
.then((response) => { .then((response) => {
self.$toast.success('User updated successfully!', { self.$toast.success('User updated successfully!', {
duration: 3000 duration: 3000
}) })
this.editedItem = response.data.data this.editedItem = response.data.data
Object.assign(this.categories[this.editedIndex], this.editedItem) Object.assign(this.categories[this.editedIndex], this.editedItem)
this.clearFile()
}) })
} catch (error) { } catch (error) {
console.log(error) console.log(error)
} }
}, },
clearData () { clearData () {
// eslint-disable-next-line no-unused-expressions this.parent_id = ''
this.parent_id = '', this.name = ''
this.name = '', this.ordering = ''
this.ordering = '',
this.image = null 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> </script>
...@@ -618,4 +688,17 @@ export default { ...@@ -618,4 +688,17 @@ export default {
.depth-5 > td:nth-child(2) { .depth-5 > td:nth-child(2) {
padding-left: 150px !important; 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> </style>
...@@ -79,6 +79,6 @@ ...@@ -79,6 +79,6 @@
<script> <script>
export default { export default {
layout: 'admin', layout: 'admin',
middleware: ['web'], middleware: ['web']
} }
</script> </script>
...@@ -109,10 +109,15 @@ export default { ...@@ -109,10 +109,15 @@ export default {
this.password = '' this.password = ''
this.checkbox = false this.checkbox = false
}, },
async login() { async login () {
try { 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, email: this.email,
password: this.password, password: this.password,
status: this.status status: this.status
...@@ -132,13 +137,13 @@ export default { ...@@ -132,13 +137,13 @@ export default {
this.$router.push('home') this.$router.push('home')
} }
} catch (e) { } catch (e) {
this.$toast.error("Username or Password not valid", { this.$toast.error('Username or Password not valid', {
duration: 2000, duration: 2000
}); })
this.$router.push("/login"); this.$router.push('/login')
}
} }
} }
}
} }
</script> </script>
<style scoped> <style scoped>
......
<!-- eslint-disable vue/require-v-for-key --> <!-- eslint-disable vue/require-v-for-key -->
<!-- eslint-disable-next-line no-console -->
<template> <template>
<div> <div>
<div> <div>
...@@ -10,91 +11,12 @@ ...@@ -10,91 +11,12 @@
</v-breadcrumbs> </v-breadcrumbs>
</div> </div>
<div style="float: right" /> <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 --> <!-- modal-edit -->
<v-dialog <v-dialog
v-model="dialog" v-model="dialog"
persistent persistent
max-width="600px" max-width="600px"
lazy-validation
> >
<v-card> <v-card>
<v-card-title> <v-card-title>
...@@ -111,25 +33,43 @@ ...@@ -111,25 +33,43 @@
<v-text-field <v-text-field
v-model="eTitle" v-model="eTitle"
label="Title*" label="Title*"
:rules="requiredRules"
required required
/> />
</v-col> </v-col>
<v-col <v-col
cols="12" cols="12"
> >
<v-select <!-- <v-select
v-model="eCategoryId" v-model="eCategoryId"
:items="categories" :items="categories"
item-text="name" item-text="name"
item-value="id" item-value="id"
label="Category" 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>
<v-col cols="12"> <v-col cols="12">
<v-textarea <v-textarea
v-model="eContent" v-model="eContent"
label="Content" label="Content"
required required
:rules="requiredRules"
/> />
</v-col> </v-col>
<v-col <v-col
...@@ -137,10 +77,11 @@ ...@@ -137,10 +77,11 @@
> >
<v-select <v-select
v-model="eStatus" v-model="eStatus"
:items="statusDefaul" :items="statusDefault"
item-text="name" item-text="name"
item-value="id" item-value="id"
label="Status" label="Status"
:rules="requiredRules"
/> />
</v-col> </v-col>
<v-col cols="12"> <v-col cols="12">
...@@ -151,18 +92,37 @@ ...@@ -151,18 +92,37 @@
small-chips small-chips
dense dense
prepend-icon="mdi-camera" 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-col>
</v-row> </v-row>
</v-container> </v-container>
<small>*indicates required field</small>
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
<v-spacer /> <v-spacer />
<v-btn <v-btn
color="blue darken-1" color="blue darken-1"
text text
@click="dialog = false" @click="dialog = false; clearFile()"
> >
Close Close
</v-btn> </v-btn>
...@@ -197,18 +157,25 @@ ...@@ -197,18 +157,25 @@
</v-dialog> </v-dialog>
<!-- table --> <!-- table -->
<div> <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> <template #top>
<v-toolbar flat> <v-toolbar flat>
<v-toolbar-title>Post Manage</v-toolbar-title> <v-text-field
<v-divider class="mx-4" inset vertical /> v-model="searchTable"
append-icon="mdi-magnify"
label="Search"
single-line
hide-details
/>
<v-spacer /> <v-spacer />
<v-toolbar-title> <v-toolbar-title>
<!-- modal-create -->
<v-dialog <v-dialog
v-model="dialog1" v-model="dialog1"
persistent persistent
max-width="600px" max-width="600px"
enctype="multipart/form-data" enctype="multipart/form-data"
lazy-validation
> >
<template #activator="{ on, attrs }"> <template #activator="{ on, attrs }">
<v-btn <v-btn
...@@ -217,7 +184,7 @@ ...@@ -217,7 +184,7 @@
v-bind="attrs" v-bind="attrs"
v-on="on" v-on="on"
> >
New Post create new
</v-btn> </v-btn>
</template> </template>
<v-card> <v-card>
...@@ -235,24 +202,35 @@ ...@@ -235,24 +202,35 @@
<v-text-field <v-text-field
v-model="title" v-model="title"
label="Title*" label="Title*"
:rules="requiredRules"
required required
/> />
</v-col> </v-col>
<v-col <v-col
cols="12" cols="12"
> >
<v-select <v-autocomplete
v-model="category_id" v-model="category_id"
:items="categories" :items="categories"
:search="search"
:filter="filter"
item-text="name" item-text="name"
item-value="id" item-value="id"
label="Category" label="Category"
/> :rules="requiredRules"
>
<template #item="{item}">
<div :class="`category-${item.depth}`">
{{ item.name }}
</div>
</template>
</v-autocomplete>
</v-col> </v-col>
<v-col cols="12"> <v-col cols="12">
<v-textarea <v-textarea
v-model="content" v-model="content"
label="Content" label="Content"
:rules="requiredRules"
required required
/> />
</v-col> </v-col>
...@@ -261,10 +239,11 @@ ...@@ -261,10 +239,11 @@
> >
<v-select <v-select
v-model="status" v-model="status"
:items="statusDefaul" :items="statusDefault"
item-text="name" item-text="name"
item-value="id" item-value="id"
label="Status" label="Status"
:rules="requiredRules"
/> />
</v-col> </v-col>
<v-col cols="12"> <v-col cols="12">
...@@ -275,19 +254,28 @@ ...@@ -275,19 +254,28 @@
dense dense
accept="image/*" accept="image/*"
prepend-icon="mdi-camera" prepend-icon="mdi-camera"
:rules="requiredRules"
@change="fileSelected" @change="fileSelected"
/> />
</v-col> </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-row>
</v-container> </v-container>
<small>*indicates required field</small>
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
<v-spacer /> <v-spacer />
<v-btn <v-btn
color="blue darken-1" color="blue darken-1"
text text
@click="dialog1 = false" @click="dialog1 = false; clearFile()"
> >
Close Close
</v-btn> </v-btn>
...@@ -312,7 +300,7 @@ ...@@ -312,7 +300,7 @@
{{ categories.find(x => x.id === item.category_id)?.name }} {{ categories.find(x => x.id === item.category_id)?.name }}
</template> </template>
<template #[`item.status`]="{ item }"> <template #[`item.status`]="{ item }">
{{ statusDefaul.find(x => x.id == item.status)?.name }} {{ statusDefault.find(x => x.id == item.status)?.name }}
</template> </template>
<template #[`item.user_id`]="{ item }"> <template #[`item.user_id`]="{ item }">
{{ users.find(x => x.id === item.user_id)?.name }} {{ users.find(x => x.id === item.user_id)?.name }}
...@@ -324,9 +312,6 @@ ...@@ -324,9 +312,6 @@
<v-icon :id="item.id" small @click="dialogDelete = true; getID(item)"> <v-icon :id="item.id" small @click="dialogDelete = true; getID(item)">
mdi-delete mdi-delete
</v-icon> </v-icon>
<v-icon :id="item.id" small @click="showPost(item)">
mdi-account-details
</v-icon>
</template> </template>
<template #no-data> <template #no-data>
<v-btn color="primary" @click="initialize"> <v-btn color="primary" @click="initialize">
...@@ -346,15 +331,17 @@ export default { ...@@ -346,15 +331,17 @@ export default {
middleware: ['web'], middleware: ['web'],
data: () => { data: () => {
return { return {
filter: '',
search: '',
searchTable: '',
file: null, file: null,
dialog1: false, dialog1: false,
dialog2: false,
title: '', title: '',
category_id: null, category_id: null,
content: '', content: '',
user_id: '', user_id: '',
status: null, status: null,
images: [], images: null,
dialog: false, dialog: false,
dialogDelete: false, dialogDelete: false,
headers: [ headers: [
...@@ -377,41 +364,35 @@ export default { ...@@ -377,41 +364,35 @@ export default {
href: '/home' href: '/home'
}, },
{ {
text: 'Product', text: 'Post',
disabled: false, disabled: false,
href: '/products' href: '/posts'
} }
], ],
statusDefaul: [ statusDefault: [
{ {
name: 'Draft', name: 'Draft',
id: '1' id: 1
}, },
{ {
name: 'Publish', name: 'Publish',
id: '2' id: 2
}, },
{ {
name: 'Unpublish', name: 'Unpublish',
id: '3' id: 3
} }
], ],
posts: [], posts: [],
categories: [], categories: [],
users: [], users: [],
sTitle: '',
sCategoryId: '',
sContent: '',
sUserId: '',
sStatus: [],
sImages: [],
eId: '', eId: '',
eTitle: '', eTitle: '',
eCategoryId: [], eCategoryId: [],
eContent: '', eContent: '',
eUserId: '', eUserId: '',
eStatus: '', eStatus: '',
eImages: [], eImages: null,
message: [], message: [],
editedIndex: -1, editedIndex: -1,
editedItem: { editedItem: {
...@@ -428,7 +409,18 @@ export default { ...@@ -428,7 +409,18 @@ export default {
status: '', status: '',
created_at: '', created_at: '',
updated_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: { computed: {
...@@ -561,6 +553,8 @@ export default { ...@@ -561,6 +553,8 @@ export default {
this.editedItem = response.data.data this.editedItem = response.data.data
console.log(this.editedItem) console.log(this.editedItem)
this.posts.push(this.editedItem) this.posts.push(this.editedItem)
this.clearData()
this.clearFile()
}) })
.catch((errors) => { .catch((errors) => {
self.$toast.error('something went wrong while trying create!', { self.$toast.error('something went wrong while trying create!', {
...@@ -569,14 +563,14 @@ export default { ...@@ -569,14 +563,14 @@ export default {
}) })
}, },
getID (item) { getID (item) {
this.eID = item.id this.eId = item.id
this.editedIndex = this.categories.indexOf(item) this.editedIndex = this.categories.indexOf(item)
}, },
deletePost () { deletePost () {
const self = this const self = this
const currentPostIndex = this.editedIndex const currentPostIndex = this.editedIndex
this.$axios this.$axios
.delete(`/posts/${this.eID}`, { .delete(`/posts/${this.eId}`, {
headers: { headers: {
Authorization: `Bearer ${this.$auth.$storage.getUniversal('token')}` Authorization: `Bearer ${this.$auth.$storage.getUniversal('token')}`
} }
...@@ -594,30 +588,13 @@ export default { ...@@ -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) { editPost (item) {
this.eId = item.id this.eId = item.id
this.eTitle = item.title this.eTitle = item.title
this.eCategoryId = item.category_id this.eCategoryId = item.category_id
this.eContent = item.content this.eContent = item.content
this.eStatus = item.status this.eStatus = item.status
this.eImages = item.images
this.editedIndex = this.posts.indexOf(item) this.editedIndex = this.posts.indexOf(item)
console.log(this.editedIndex) console.log(this.editedIndex)
this.dialog = true this.dialog = true
...@@ -628,9 +605,10 @@ export default { ...@@ -628,9 +605,10 @@ export default {
fd.append('title', this.eTitle) fd.append('title', this.eTitle)
fd.append('category_id', this.eCategoryId) fd.append('category_id', this.eCategoryId)
fd.append('content', this.eContent) fd.append('content', this.eContent)
fd.append('images', this.eImages)
fd.append('status', this.eStatus) fd.append('status', this.eStatus)
if (typeof this.eImages !== 'string' && this.eImages != null) {
fd.append('images', this.eImages)
}
const currentPostIndex = this.editedIndex const currentPostIndex = this.editedIndex
this.$axios this.$axios
.post( .post(
...@@ -648,6 +626,7 @@ export default { ...@@ -648,6 +626,7 @@ export default {
}) })
this.editedItem = response.data.data this.editedItem = response.data.data
Object.assign(this.posts[currentPostIndex], this.editedItem) Object.assign(this.posts[currentPostIndex], this.editedItem)
this.clearFile()
}) })
.catch((error) => { .catch((error) => {
console.log(error) console.log(error)
...@@ -657,13 +636,39 @@ export default { ...@@ -657,13 +636,39 @@ export default {
}) })
}, },
fileSelected (event) { fileSelected (event) {
console.log(event) if (event) {
console.log(this.images) 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> </script>
<style> <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> </style>
...@@ -7,112 +7,6 @@ ...@@ -7,112 +7,6 @@
</template> </template>
</v-breadcrumbs> </v-breadcrumbs>
</div> </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 --> <!-- edit-modal -->
<v-dialog <v-dialog
v-model="dialog3" v-model="dialog3"
...@@ -128,8 +22,6 @@ ...@@ -128,8 +22,6 @@
<v-row> <v-row>
<v-col <v-col
cols="12" cols="12"
sm="6"
md="4"
> >
<v-text-field <v-text-field
v-model="eName" v-model="eName"
...@@ -141,14 +33,21 @@ ...@@ -141,14 +33,21 @@
<v-col <v-col
cols="12" cols="12"
> >
<v-select <v-autocomplete
v-model="eCategoryId" v-model="eCategoryId"
class="select--menu my-select"
:items="categories" :items="categories"
item-text="name" item-text="name"
item-value="id" item-value="id"
label="Category" label="Category"
:rules="requiredRules" :rules="requiredRules"
/> >
<template #item="{item}">
<div :class="`category-${item.depth}`">
{{ item.name }}
</div>
</template>
</v-autocomplete>
</v-col> </v-col>
<v-col cols="12"> <v-col cols="12">
<v-text-field <v-text-field
...@@ -172,9 +71,30 @@ ...@@ -172,9 +71,30 @@
small-chips small-chips
dense dense
multiple 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-col>
<v-img v-if="typeof eImages === 'string'" :src="eImages" />
<v-col cols="12"> <v-col cols="12">
<v-btn <v-btn
class="mx-2" class="mx-2"
...@@ -244,14 +164,13 @@ ...@@ -244,14 +164,13 @@
</v-row> </v-row>
</v-row> </v-row>
</v-container> </v-container>
<small>*indicates required field</small>
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
<v-spacer /> <v-spacer />
<v-btn <v-btn
color="blue darken-1" color="blue darken-1"
text text
@click="dialog3 = false" @click="dialog3 = false; clearImage();"
> >
Close Close
</v-btn> </v-btn>
...@@ -306,13 +225,19 @@ ...@@ -306,13 +225,19 @@
<v-data-table <v-data-table
:headers="headers" :headers="headers"
:items="products" :items="products"
:search="searchTable"
sort-by="calories" sort-by="calories"
class="elevation-1" class="elevation-1"
> >
<template #top> <template #top>
<v-toolbar flat> <v-toolbar flat>
<v-toolbar-title>Product Manage</v-toolbar-title> <v-text-field
<v-divider class="mx-4" inset vertical /> v-model="searchTable"
append-icon="mdi-magnify"
label="Search"
single-line
hide-details
/>
<v-spacer /> <v-spacer />
<v-toolbar-title> <v-toolbar-title>
<v-dialog <v-dialog
...@@ -328,7 +253,7 @@ ...@@ -328,7 +253,7 @@
v-bind="attrs" v-bind="attrs"
v-on="on" v-on="on"
> >
New Product create new
</v-btn> </v-btn>
</template> </template>
<v-card> <v-card>
...@@ -340,8 +265,6 @@ ...@@ -340,8 +265,6 @@
<v-row> <v-row>
<v-col <v-col
cols="12" cols="12"
sm="6"
md="4"
> >
<v-text-field <v-text-field
v-model="name" v-model="name"
...@@ -354,14 +277,20 @@ ...@@ -354,14 +277,20 @@
<v-col <v-col
cols="12" cols="12"
> >
<v-select <v-autocomplete
v-model="category_id" v-model="category_id"
:items="categories" :items="categories"
item-text="name" item-text="name"
item-value="id" item-value="id"
label="Category" label="Category"
:rules="requiredRules" :rules="requiredRules"
/> >
<template #item="{item}">
<div :class="`category-${item.depth}`">
{{ item.name }}
</div>
</template>
</v-autocomplete>
</v-col> </v-col>
<v-col cols="12"> <v-col cols="12">
<v-text-field <v-text-field
...@@ -388,8 +317,20 @@ ...@@ -388,8 +317,20 @@
:rules="imageRules" :rules="imageRules"
lazy-validation lazy-validation
prepend-icon="mdi-camera" prepend-icon="mdi-camera"
@change="fileSelected"
@click:clear="clearImage"
/> />
</v-col> </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-col cols="12">
<v-btn <v-btn
class="mx-2" class="mx-2"
...@@ -459,14 +400,13 @@ ...@@ -459,14 +400,13 @@
</v-row> </v-row>
</v-row> </v-row>
</v-container> </v-container>
<small>*indicates required field</small>
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
<v-spacer /> <v-spacer />
<v-btn <v-btn
color="blue darken-1" color="blue darken-1"
text text
@click="dialog1 = false" @click="dialog1 = false; clearData ();"
> >
Close Close
</v-btn> </v-btn>
...@@ -487,6 +427,15 @@ ...@@ -487,6 +427,15 @@
<template #[`item.index`]="{ index }"> <template #[`item.index`]="{ index }">
{{ index + 1 }} {{ index + 1 }}
</template> </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 }"> <template #[`item.actions`]="{ item }">
<v-icon :id="item.id" small @click="editProduct(item)"> <v-icon :id="item.id" small @click="editProduct(item)">
mdi-pencil mdi-pencil
...@@ -494,9 +443,6 @@ ...@@ -494,9 +443,6 @@
<v-icon :id="item.id" small @click="dialogDelete = true; getID(item)"> <v-icon :id="item.id" small @click="dialogDelete = true; getID(item)">
mdi-delete mdi-delete
</v-icon> </v-icon>
<v-icon :id="item.id" small @click="showProduct(item)">
mdi-account-details
</v-icon>
</template> </template>
<template #no-data> <template #no-data>
<v-btn color="primary" @click="initialize"> <v-btn color="primary" @click="initialize">
...@@ -514,6 +460,8 @@ export default { ...@@ -514,6 +460,8 @@ export default {
middleware: ['web'], middleware: ['web'],
data: () => { data: () => {
return { return {
searchTable: '',
files: [],
name: '', name: '',
id: '', id: '',
category_id: '', category_id: '',
...@@ -521,6 +469,7 @@ export default { ...@@ -521,6 +469,7 @@ export default {
stock: '', stock: '',
description: '', description: '',
images: [], images: [],
status: '',
variants: [ variants: [
{ {
color: '', color: '',
...@@ -533,7 +482,6 @@ export default { ...@@ -533,7 +482,6 @@ export default {
quantity: '', quantity: '',
dialog: false, dialog: false,
dialog1: false, dialog1: false,
dialog2: false,
dialog3: false, dialog3: false,
dialogDelete: false, dialogDelete: false,
dialogDeleteVariant: false, dialogDeleteVariant: false,
...@@ -549,6 +497,8 @@ export default { ...@@ -549,6 +497,8 @@ export default {
{ text: 'Category', value: 'category.name' }, { text: 'Category', value: 'category.name' },
{ text: 'Price', value: 'price' }, { text: 'Price', value: 'price' },
{ text: 'Stock', value: 'stock' }, { text: 'Stock', value: 'stock' },
{ text: 'Variants', value: 'variants' },
{ text: 'Status', value: 'status' },
{ text: 'Actions', value: 'actions', sortable: false } { text: 'Actions', value: 'actions', sortable: false }
], ],
items: [ items: [
...@@ -568,19 +518,7 @@ export default { ...@@ -568,19 +518,7 @@ export default {
products: [], products: [],
product: [], product: [],
categories: [], categories: [],
sName: '', categoryTrees: [],
sCategoryId: '',
sPrice: '',
sDescription: '',
sStock: '',
sImages: [],
sVariants: [
{
color: '',
size: '',
quantity: ''
}
],
idVariant: '', idVariant: '',
editedVariantIndex: '', editedVariantIndex: '',
eId: '', eId: '',
...@@ -604,7 +542,8 @@ export default { ...@@ -604,7 +542,8 @@ export default {
category_id: '', category_id: '',
price: '', price: '',
description: '', description: '',
stock: '' stock: '',
variants_count: ''
}, },
defaultItem: { defaultItem: {
name: '', name: '',
...@@ -647,6 +586,7 @@ export default { ...@@ -647,6 +586,7 @@ export default {
this.initialize() this.initialize()
this.getProducts() this.getProducts()
this.getCategories() this.getCategories()
this.getCategoryTrees()
}, },
methods: { methods: {
initialize () { initialize () {
...@@ -704,6 +644,22 @@ export default { ...@@ -704,6 +644,22 @@ export default {
} }
this.close() 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 () { getCategories () {
this.$axios this.$axios
.get('/categories/', { .get('/categories/', {
...@@ -757,8 +713,10 @@ export default { ...@@ -757,8 +713,10 @@ export default {
duration: 3000 duration: 3000
}) })
this.editedItem = response.data.data this.editedItem = response.data.data
this.editedItem.variants_count = response.data.data.variants.length
console.log(this.editedItem) console.log(this.editedItem)
this.products.push(this.editedItem) this.products.push(this.editedItem)
this.clearData()
}) })
.catch((errors) => { .catch((errors) => {
console.log(errors.response.data.message) console.log(errors.response.data.message)
...@@ -792,27 +750,6 @@ export default { ...@@ -792,27 +750,6 @@ export default {
console.log(error) 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) { editProduct (item) {
this.eId = item.id this.eId = item.id
this.eName = item.name this.eName = item.name
...@@ -821,6 +758,7 @@ export default { ...@@ -821,6 +758,7 @@ export default {
this.eStock = item.stock this.eStock = item.stock
this.eDescription = item.description this.eDescription = item.description
this.eVariants = item.variants this.eVariants = item.variants
this.eImages = item.images
this.editedIndex = this.products.indexOf(item) this.editedIndex = this.products.indexOf(item)
console.log(item.variants) console.log(item.variants)
this.dialog3 = true this.dialog3 = true
...@@ -856,7 +794,7 @@ export default { ...@@ -856,7 +794,7 @@ export default {
} }
) )
.then((response) => { .then((response) => {
self.$toast.success('User updated successfully!', { self.$toast.success('Product updated successfully!', {
duration: 3000 duration: 3000
}) })
console.log(response) console.log(response)
...@@ -889,28 +827,77 @@ export default { ...@@ -889,28 +827,77 @@ export default {
this.idVariant = item.id this.idVariant = item.id
}, },
removeVariant () { removeVariant () {
const self = this
const currentVariantIndex = this.editedVariantIndex const currentVariantIndex = this.editedVariantIndex
if (this.idVariant !== null) { this.eVariants.splice(currentVariantIndex, 1)
try { },
this.$axios.delete(`/products/delete-variant/${this.idVariant}`, 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: { headers: {
Authorization: `Bearer ${this.$auth.$storage.getUniversal('token')}` Authorization: `Bearer ${this.$auth.$storage.getUniversal('token')}`
} }
} }
).then((response) => { )
self.$toast.success('Remove variant successfully!', { .then((response) => {
console.log(response)
self.$toast.success('Updated status successfully!', {
duration: 3000 duration: 3000
}) })
}) })
this.getProducts() .catch((error) => {
} catch (error) {
console.log(error) console.log(error)
} self.$toast.error('ERR!', {
this.eVariants.splice(currentVariantIndex, 1) duration: 3000
} })
})
} }
} }
} }
</script> </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>
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
</v-card-title> </v-card-title>
<v-card-text> <v-card-text>
<v-container> <v-container>
<v-form ref="formEdit">
<v-row> <v-row>
<v-col cols="12" sm="6" md="4"> <v-col cols="12" sm="6" md="4">
<v-text-field v-model="eName" label="Legal name*" :rules="nameRules" required /> <v-text-field v-model="eName" label="Legal name*" :rules="nameRules" required />
...@@ -35,12 +36,12 @@ ...@@ -35,12 +36,12 @@
/> />
</v-col> </v-col>
</v-row> </v-row>
</v-form>
</v-container> </v-container>
<small>*indicates required field</small>
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
<v-spacer /> <v-spacer />
<v-btn color="blue darken-1" text @click="dialog2 = false"> <v-btn color="blue darken-1" text @click="dialog2 = false; clearData();">
Close Close
</v-btn> </v-btn>
<v-btn <v-btn
...@@ -48,8 +49,9 @@ ...@@ -48,8 +49,9 @@
text text
type="submit" type="submit"
@click=" @click="
dialog2 = false; // dialog2 = false;
updateUser(); updateUser();
validateForm();
" "
> >
Save Save
...@@ -85,25 +87,30 @@ ...@@ -85,25 +87,30 @@
<v-data-table <v-data-table
:headers="headers" :headers="headers"
:items="users" :items="users"
:search="searchTable"
sort-by="calories" sort-by="calories"
class="elevation-1" class="elevation-1"
> >
<template #top> <template #top>
<v-toolbar flat> <v-toolbar flat>
<v-toolbar-title>User Manage</v-toolbar-title> <v-text-field
<v-divider class="mx-4" inset vertical /> v-model="searchTable"
append-icon="mdi-magnify"
label="Search"
single-line
hide-details
/>
<v-spacer /> <v-spacer />
<v-toolbar-title style="float: right"> <v-toolbar-title style="float: right">
<v-dialog <v-dialog
v-model="dialog1" v-model="dialog1"
persistent persistent
max-width="600px" max-width="600px"
@submit.prevent="createUser"
lazy-validation lazy-validation
> >
<template #activator="{ on, attrs }"> <template #activator="{ on, attrs }">
<v-btn color="primary" dark v-bind="attrs" v-on="on"> <v-btn color="primary" dark v-bind="attrs" v-on="on">
New USER CREATE NEW
</v-btn> </v-btn>
</template> </template>
<v-card> <v-card>
...@@ -112,6 +119,7 @@ ...@@ -112,6 +119,7 @@
</v-card-title> </v-card-title>
<v-card-text> <v-card-text>
<v-container> <v-container>
<v-form ref="form">
<v-row> <v-row>
<v-col cols="12" sm="6" md="4"> <v-col cols="12" sm="6" md="4">
<v-text-field <v-text-field
...@@ -139,8 +147,8 @@ ...@@ -139,8 +147,8 @@
/> />
</v-col> </v-col>
</v-row> </v-row>
</v-form>
</v-container> </v-container>
<small>*indicates required field</small>
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
<v-spacer /> <v-spacer />
...@@ -152,8 +160,9 @@ ...@@ -152,8 +160,9 @@
text text
type="submit" type="submit"
@click=" @click="
dialog1 = false; // dialog1 = false;
createUser(); createUser();
validateForm()
" "
> >
Save Save
...@@ -167,10 +176,10 @@ ...@@ -167,10 +176,10 @@
<template #[`item.index`]="{ index }"> <template #[`item.index`]="{ index }">
{{ index + 1 }} {{ index + 1 }}
</template> </template>
<template #item.created_at="{ item }"> <template #[`item.created_at`]="{ item }">
<span>{{ formatDate(item.created_at) }}</span> <span>{{ formatDate(item.created_at) }}</span>
</template> </template>
<template #item.updated_at="{ item }"> <template #[`item.updated_at`]="{ item }">
<span>{{ formatDate(item.updated_at) }}</span> <span>{{ formatDate(item.updated_at) }}</span>
</template> </template>
<template #[`item.actions`]="{ item }"> <template #[`item.actions`]="{ item }">
...@@ -211,6 +220,8 @@ export default { ...@@ -211,6 +220,8 @@ export default {
middleware: ['web'], middleware: ['web'],
data: () => { data: () => {
return { return {
searchTable: '',
valid: true,
email: '', email: '',
name: '', name: '',
password: '', password: '',
...@@ -224,9 +235,8 @@ export default { ...@@ -224,9 +235,8 @@ export default {
align: 'start', align: 'start',
value: 'index' value: 'index'
}, },
{ text: 'Name', value: 'name' }, { text: 'Name', value: 'name', sortable: false },
{ text: 'email', value: 'email' }, { text: 'email', value: 'email' },
{ text: 'status', value: 'id', sortable: false },
{ text: 'created', value: 'created_at' }, { text: 'created', value: 'created_at' },
{ text: 'updated', value: 'updated_at' }, { text: 'updated', value: 'updated_at' },
{ text: 'Actions', value: 'actions', sortable: false } { text: 'Actions', value: 'actions', sortable: false }
...@@ -378,6 +388,7 @@ export default { ...@@ -378,6 +388,7 @@ export default {
} }
) )
.then((response) => { .then((response) => {
this.dialog1 = false
self.$toast.success('User created successfully!', { self.$toast.success('User created successfully!', {
duration: 3000 duration: 3000
}) })
...@@ -385,8 +396,11 @@ export default { ...@@ -385,8 +396,11 @@ export default {
this.editedItem = response.data.data this.editedItem = response.data.data
console.log(this.editedItem) console.log(this.editedItem)
this.users.push(this.editedItem) this.users.push(this.editedItem)
this.clearData()
}) })
.catch((errors) => { .catch((errors) => {
this.dialog1 = true
this.validate()
console.log(errors.response.data.message) console.log(errors.response.data.message)
this.message = errors.response.data.message this.message = errors.response.data.message
self.$toast.error('something went wrong while trying create!', { self.$toast.error('something went wrong while trying create!', {
...@@ -443,6 +457,7 @@ export default { ...@@ -443,6 +457,7 @@ export default {
} }
) )
.then((response) => { .then((response) => {
this.dialog2 = false
self.$toast.success('User updated successfully!', { self.$toast.success('User updated successfully!', {
duration: 3000 duration: 3000
}) })
...@@ -460,6 +475,21 @@ export default { ...@@ -460,6 +475,21 @@ export default {
getID (item) { getID (item) {
this.eID = item.id this.eID = item.id
this.editedIndex = this.users.indexOf(item) 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') }
} }
} }
} }
......
...@@ -12,6 +12,13 @@ export default function ({ $axios }, inject, redirect) { ...@@ -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({ const api = $axios.create({
headers: { headers: {
common: { common: {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment