Files
barg-restuarant/pages/admin/_branch/foods/_food.vue
T
2024-05-13 12:41:43 +03:30

590 lines
22 KiB
Vue

<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="primary" class="mr-auto" :to="{name: 'admin-branch-foods'}">برگشت به صفحه قبل</CButton>
<CButton v-if="$route.params.food === 'new'" size="sm" color="success" class="mr-1" @click="post">افزودن</CButton>
<CButton v-else size="sm" color="success" class="mr-1" @click="update">بروزرسانی</CButton>
</CustomSubHeader>
<CRow>
<CCol lg="6">
<CCard>
<CCardBody>
<CForm>
<CRow>
<CCol sm="12">
<el-checkbox v-model="food.special" label="قرار گرفتن در منوی ویژه سرآشپز"/>
</CCol>
<CCol sm="12">
<el-checkbox v-model="food.havePoint" label="افزودن امتیاز به مشتری برای خرید این محصول"/>
</CCol>
<CCol sm="12">
<el-checkbox v-model="food.sale" label="این محصول به صورت عادی فروخته شود"/>
</CCol>
<CCol sm="12">
<el-checkbox v-model="food.club" label="این محصول با امتیاز به فروش برسد"/>
</CCol>
<el-divider></el-divider>
<CCol sm="12">
<CInput
v-if="food.club"
:class="validation.point ? 'err' : null"
label="مقدار امتیاز برای خرید"
:description="validation.point ? validation.point.msg : null"
v-model="food.point"
/>
</CCol>
<CCol sm="12">
<CInput
:class="validation.name ? 'err' : null"
label="نام"
:description="validation.name ? validation.name.msg : null"
v-model="food.name"
/>
</CCol>
<CCol sm="12">
<CInput
:class="validation.short_description ? 'err' : null"
label="توضیحات کوتاه"
placeholder="پرس ویژه (اختیاری)"
:description="validation.short_description ? validation.short_description.msg : null"
v-model="food.short_description"
/>
</CCol>
<CCol sm="12">
<CInput
:class="validation.description ? 'err' : null"
label="توضیحات"
placeholder="مواد تشکیل دهنده (اختیاری)"
:description="validation.description ? validation.description.msg : null"
v-model="food.description"
/>
</CCol>
<CCol sm="12">
<CInput
:class="validation.estimated_time ? 'err' : null"
label="زمان آماده سازی (دقیقه)"
placeholder="اختیاری"
:description="validation.estimated_time ? validation.estimated_time.msg : null"
v-model="food.estimated_time"
/>
</CCol>
<CCol sm="12">
<CInput
:class="validation.stock ? 'err' : null"
label="موجودی"
:description="validation.stock ? validation.stock.msg : null"
v-model="food.stock"
/>
</CCol>
<CCol sm="12">
<CInput
:class="validation.price ? 'err' : null"
label="قیمت (ريال)"
:description="validation.price ? validation.price.msg : null"
v-model="food.price"
/>
</CCol>
<CCol sm="12">
<CInput
:class="validation.static_discount ? 'err' : null"
label="تخفیف روز (درصد)"
placeholder="اختیاری"
:description="validation.static_discount ? validation.static_discount.msg : null"
v-model="food.static_discount"
/>
</CCol>
</CRow>
<CRow>
<CCol s="12">
<span>دسته بندی</span>
</CCol>
<CCol sm="12" class="err">
<el-select v-model="food.category" filterable style="width: 100%;margin-top: 5px;">
<el-option v-for="item in foodCategories" :key="item._id" :value="item._id" :label="item.name"/>
</el-select>
<p v-if="validation.category" class="text-danger" style="margin-top: 5px;">{{ validation.category.msg }}</p>
</CCol>
</CRow>
<CRow>
<CCol s="12" class="mt-3">
<span>ترتیب نمایش در منو</span>
</CCol>
<CCol sm="12" class="err">
<el-select v-model="food.index" filterable style="width: 100%;margin-top: 5px;">
<el-option
v-for="item in foods.length + 10"
v-if="!foods.find(item2=>Number(item2.index) === item && item2.category === food.category)"
:key="item + 202"
:value="item"
:label="item"/>
</el-select>
<p v-if="validation.index" class="text-danger" style="margin-top: 5px;">{{ validation.index.msg }}</p>
</CCol>
</CRow>
<CRow>
<CCol s="12">
<span>انتخاب منو</span>
</CCol>
<CCol sm="12" class="err">
<el-select v-model="food.menuType_id" filterable style="width: 100%;margin-top: 5px;">
<el-option v-for="item in menuTypes" :key="item._id" :value="item._id" :label="item.name"/>
</el-select>
<p v-if="validation.category" class="text-danger" style="margin-top: 5px;">{{ validation.menuType_id.msg }}</p>
</CCol>
</CRow>
</CForm>
</CCardBody>
</CCard>
</CCol>
<CCol lg="6">
<CCard>
<CCardBody>
<h3>تصویر: (اختیاری)</h3>
<el-divider></el-divider>
<img :src="food.image" alt="" style="width: 100%;max-width: 300px;display: block">
<input type="file" ref="image" @change="imagePreview">
</CCardBody>
</CCard>
</CCol>
<CCol v-if="$route.params.food !== 'new'">
<CCard>
<CCardBody>
<div class="row mb-5">
<div class="col-sm-2">
<div class="callout">
<small class="text-muted">تعداد کل رای ها</small><br>
<strong class="h4">{{ food.ratings.length }}</strong>
</div>
</div><!--/.col-->
<div class="col-sm-2">
<div class="callout rate">
<small class="text-muted">میانگین امتیاز ها</small><br>
<strong class="h4">
{{ food.rate }}
</strong>
<i class="fas fa-star"></i>
</div>
</div><!--/.col-->
</div><!--/.row-->
<h3>نظرات مشتریان</h3>
<el-divider></el-divider>
<el-table
:data="food.ratings.filter(item=>item.comment && item.comment.length)"
style="width: 100%">
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
prop=""
label="نام"
width="">
<template slot-scope="scope" v-if="scope.row.user_id">
{{ scope.row.user_id.first_name + ' ' + scope.row.user_id.last_name }}
</template>
</el-table-column>
<el-table-column
label="تاریخ"
width="">
<template slot-scope="scope">
{{ jDate(scope.row.cretated_at) }}
</template>
</el-table-column>
<el-table-column
label="امتیاز"
width="">
<template slot-scope="scope">
<span>{{ scope.row.rate }}</span>
<i class="fas fa-star"></i>
</template>
</el-table-column>
<el-table-column
label="نظر"
width="">
<template slot-scope="scope">
<span>
<el-popover v-if="scope.row.comment" placement="top-end" trigger="hover" :content="scope.row.comment">
<i v-if="scope.row.comment.length > 25" class="el-icon-info" slot="reference"></i>
</el-popover>
{{ scope.row.comment || 'بدون پاسخ' }}
</span>
</template>
</el-table-column>
<el-table-column
label="پاسخ"
width="">
<template slot-scope="scope">
<span>
<el-popover v-if="scope.row.replay" placement="top-end" trigger="hover" :content="scope.row.replay">
<i v-if="scope.row.replay.length > 25" class="el-icon-info" slot="reference"></i>
</el-popover>
{{ scope.row.replay || 'بدون پاسخ' }}
</span>
</template>
</el-table-column>
<el-table-column
label="ویرایش"
width=""
align="center">
<template slot-scope="scope">
<CButton color="danger" variant="outline" @click="deleteComment(scope.row._id)" :key="scope.row._id + Math.random()">
<i class="far fa-trash-alt"></i>
</CButton>
<CButton color="primary" variant="outline" @click="openDialog(scope.row._id, scope.row.replay)" :key="scope.row._id + Math.random()">
<i class="far fa-comment-alt"></i>
</CButton>
<CButton
variant="outline"
:title="scope.row.confirmed ? 'غیرفعال کردن' : 'فعال کردن'"
:color="scope.row.confirmed ? 'danger' : 'success'"
:key="scope.row._id"
@click="changeCommentStatus(scope.row._id,!scope.row.confirmed)"
>
<i class="fas" :class="scope.row.confirmed ? 'fa-do-not-enter' : 'fa-check'"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
</CCol>
</CRow>
<el-dialog
title="پاسخ"
:visible.sync="dialogVisible"
width="50%">
<CTextarea
:class="validation.replay ? 'err' : null"
placeholder="پیام خود را وارد کنید"
:description="validation.replay ? validation.replay.msg : null"
v-model="replay"/>
<span slot="footer" class="dialog-footer">
<el-button type="success" @click="addReply">ارسال</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import axiosUploadProcess from "@/mixins/axiosUploadProcess"
import moment from "moment-jalaali"
export default {
data() {
return {
foods: null,
foodCategories: null,
menuTypes: null,
food: null,
validation: {},
dialogVisible : false,
replay : '',
commentId : ''
}
},
mixins: [axiosUploadProcess],
computed: {
title() {
return this.$route.params.food === 'new' ? 'افزودن غذا' : 'مشاهده غذا'
}
},
methods: {
openDialog(id , text){
this.commentId = id
this.replay = text
this.dialogVisible = true
},
jDate(date) {
return moment(date).format('jYYYY/jMM/jDD')
},
imagePreview(e) {
this.food.image = URL.createObjectURL(e.target.files[0])
},
changeCommentStatus(id, status) {
this.$axios.post(`/api/admin/commentStatus/${id}`, {confirmed: status})
.then(res => {
this.$message({
type: 'success',
message: 'وضعیت کامنت یا موفقیت تغییر کرد'
})
this.$nuxt.refresh()
})
.catch(err => {
if (err) console.log(err)
this.$message({
type: 'error',
message: 'مشکلی پیش آمده، لطفا دوباره تلاش کنید'
})
})
},
addReply(){
this.validation = {}
this.$axios.post(`/api/admin/replayComment/${this.commentId}`, {replay: this.replay})
.then(res => {
this.dialogVisible = false;
this.$message({
type: 'success',
message: 'پاسخ با موفقیت ثبت شد'
})
this.$nuxt.refresh()
})
.catch(err => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
if (err.response.status === 500) {
return this.$message({
type: "error",
message: "مشکلی در ارسال درخواست پیش آمده",
});
}
if (err.response.status === 422){
this.$message({
type: 'warning',
message: 'پارامترها را بررسی کنید'
})
this.validation = err.response.data.validation;
} else console.log(err.response.data);
})
},
deleteComment(id){
this.$confirm("کامنت حذف شود؟", "اخطار", {
confirmButtonText: "بله",
cancelButtonText: "لغو",
type: "warning",
})
.then(async () => {
this.validation = {}
this.$axios.delete(`/api/admin/deleteComment/${id}`)
.then(res => {
this.$message({
type: 'success',
message: 'کامنت با موفقیت حذف شد'
})
this.$nuxt.refresh()
})
.catch(err => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
if (err.response.status === 500) {
return this.$message({
type: "error",
message: "مشکلی در ارسال درخواست پیش آمده",
});
}
if (err.response.status === 422){
this.$message({
type: 'warning',
message: 'پارامترها را بررسی کنید'
})
this.validation = err.response.data.validation;
} else console.log(err.response.data);
})
})
.catch(() => {
this.$message({
type: "warning",
message: "عملیات لغو شد",
});
});
},
post() {
this.validation = {}
const data = new FormData()
data.append('name', this.food.name)
data.append('price', this.food.price)
data.append('description', this.food.description)
data.append('short_description', this.food.short_description)
this.food.estimated_time && data.append('estimated_time', this.food.estimated_time)
data.append('stock', this.food.stock)
data.append('category', this.food.category)
data.append('static_discount', this.food.static_discount)
data.append('special', this.food.special)
data.append('index', this.food.index)
data.append('menuType_id', this.food.menuType_id)
data.append('havePoint', this.food.havePoint)
data.append('club', this.food.club)
data.append('point', this.food.point)
data.append('sale', this.food.sale)
data.append('branchId', this.$route?.params?.branch)
if (this.$refs.image.files[0]) data.append('image', this.$refs.image.files[0])
this.$axios.post(`/api/admin/food`, data, this.axiosConfig)
.then(response => {
this.$message({
type: 'success',
message: 'غذا با موفقیت ایجاد شد.'
})
this.$router.push({name: 'admin-branch-foods'})
})
.catch(err => {
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
if (err.response.status === 422) this.validation = err.response.data.validation
else console.log(err.response.data)
})
},
update() {
this.validation = {}
const data = new FormData()
data.append('name', this.food.name)
data.append('menuType_id', this.food.menuType_id)
data.append('price', this.food.price)
data.append('description', this.food.description || '')
data.append('short_description', this.food.short_description || '')
this.food.estimated_time && data.append('estimated_time', this.food.estimated_time)
data.append('stock', this.food.stock)
data.append('category', this.food.category)
data.append('static_discount', this.food.static_discount)
data.append('special', this.food.special)
data.append('index', this.food.index)
data.append('havePoint', this.food.havePoint)
data.append('club', this.food.club)
data.append('point', this.food.point)
data.append('sale', this.food.sale)
data.append('branchId', this.$route?.params?.branch)
if (this.$refs.image.files[0]) data.append('image', this.$refs.image.files[0])
this.$axios.put(`/api/admin/food/${this.food._id}`, data, this.axiosConfig)
.then(response => {
this.$message({
type: 'success',
message: 'اطلاعات بروزرسانی شد.'
})
this.$nuxt.refresh()
this.$refs.image.value = null
})
.catch(err => {
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
if (err.response.status === 422) this.validation = err.response.data.validation
else console.log(err.response.data)
})
}
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({$axios, params, error }) {
try {
const foods = await $axios.get(`/api/public/foods/getAll/${params?.branch}`)
const menuTypes = await $axios.get(`/api/public/menuTypes/getAll/${params?.branch}`)
const foodCategories = await $axios.get(`/api/public/foodCategories/getAll/${params?.branch}`)
if (params.food !== 'new') {
const food = await $axios.get(`/api/admin/food/${params.food}`)
return {
foods: foods.data,
menuTypes: menuTypes.data,
foodCategories: foodCategories.data,
food: food.data
}
} else {
return {
foods: foods.data,
menuTypes: menuTypes.data,
foodCategories: foodCategories.data,
food: {
name: '',
image: '',
price: 0,
stock: 0,
description: '',
short_description: '',
estimated_time: '',
category: '',
static_discount: 0,
index: 0,
special : false,
havePoint : false,
club : false,
sale: true,
point : 0,
menuType_id: 0,
}
}
}
} catch (e) {
if (e?.response?.status === 401) {
error({
status: 401,
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (e?.response?.status === 403) {
error({
status: 403,
message: e?.response?.data?.message,
});
}
if (e?.response?.status === 500) {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات پیش آمده",
});
} else
error({
status: 404,
message: "اطلاعات مورد نظر پیدا نشد",
});
}
}
}
</script>
<style lang="scss">
.callout {
border: 0.5px solid rgba(#000, 0.3);
border-right: 6px solid blue;
border-radius: 5px;
padding: 3px 5px;
&.rate {
border-right: 5px solid goldenrod;
i {
color: goldenrod;
font-size: 19px;
}
}
}
</style>