transfer project in github

This commit is contained in:
hamid.zarghami1@gmail.com
2024-05-12 15:29:27 +03:30
commit e644edbd65
348 changed files with 164991 additions and 0 deletions
+609
View File
@@ -0,0 +1,609 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="primary" class="mr-auto" :to="{name: 'admin-customers'}">برگشت به صفحه قبل</CButton>
</CustomSubHeader>
<CRow>
<CCol lg="6">
<CCard>
<CCardBody>
<CForm>
<template v-if="$route.params.profile !== 'new'">
<h4>مشخصات مشتری</h4>
<el-divider/>
</template>
<CRow>
<CCol sm="12">
<CInput
label="نام"
disabled
:value="customer.first_name"
/>
</CCol>
<CCol sm="12">
<CInput
label="نام خانوادگی"
disabled
:value="customer.last_name"
/>
</CCol>
<CCol sm="12">
<CInput
label="کد مشتری"
disabled
:value="customer.business_code"
/>
<p class="form-err" v-if="validation.username">{{ validation.username.msg }}</p>
</CCol>
<CCol sm="12">
<CInput
label="تلفن همراه"
disabled
:value="customer.mobile_number"
/>
</CCol>
<CCol sm="12">
<CInput
label="ایمیل"
disabled
:value="customer.email"
/>
</CCol>
<CCol sm="12">
<CInput
label="کد ملی"
disabled
:value="customer.national_code"
/>
</CCol>
<CCol sm="12">
<CInput
label="شغل"
disabled
:value="customer.job"
/>
</CCol>
<CCol sm="12">
<CInput
label="تاریخ تولد"
disabled
:value="jDateOfCustomer(customer.birth_date)"
/>
</CCol>
<CCol sm="12">
<CInput
label="تاریخ ازدواج"
disabled
:value="jDateOfCustomer(customer.marriage_date)"
/>
</CCol>
<CCol sm="12">
<CInput
label="امتیاز"
disabled
:value="customer.score"
/>
</CCol>
<CCol sm="12">
<CInput
label="موجودی کیف پول"
disabled
:value="customer.bagAmount + ' ریال'"
/>
</CCol>
</CRow>
</CForm>
</CCardBody>
</CCard>
</CCol>
<CCol lg="6">
<CCard>
<CCardBody>
<h4>کد های تخفیف مشتری</h4>
<el-divider></el-divider>
<el-table
:data="customer.discount_codes"
style="width: 100%">
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
prop="discount_code"
label="کد"
width="">
</el-table-column>
<el-table-column
label="درصد تخفیف"
width="">
<template slot-scope="scope">
{{ scope.row.discount_amount + '%' }}
</template>
</el-table-column>
<el-table-column
label="استفاده شده"
width="">
<template slot-scope="scope">
<span v-if="scope.row.used_by.includes(customer._id)">بله</span>
<span v-else>خیر</span>
</template>
</el-table-column>
<el-table-column
prop="province"
label="تاریخ انقضا"
width="">
<template slot-scope="scope">
{{ jDateDiscount(scope.row.discount_expire_date) }}
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
</CCol>
<CCol sm="12">
<CCard>
<CCardBody>
<h4>آدرس های مشتری</h4>
<el-divider></el-divider>
<el-table
:data="customer.addresses"
style="width: 100%">
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
prop="title"
label="عنوان"
width="100">
</el-table-column>
<el-table-column
prop="province"
label="استان"
width="100">
</el-table-column>
<el-table-column
prop="city"
label="شهر"
width="100">
</el-table-column>
<el-table-column
prop="address"
label="آدرس"
width="600">
</el-table-column>
<el-table-column
label="ویرایش"
width="200"
align="center">
<template slot-scope="scope">
<CButton color="danger" variant="outline" @click="deleteAddress(scope.row._id)" :key="scope.row._id + Math.random()">
<i class="far fa-trash-alt"></i>
</CButton>
<CButton
variant="outline"
title="بروزرسانی"
color="success"
:key="scope.row._id"
@click="openDialog(scope.row)">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
</CCol>
<CCol sm="12">
<CCard>
<CCardBody>
<h4>لیست تراکنش ها</h4>
<el-divider></el-divider>
<el-table
:data="payments.docs"
style="width: 100%">
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
label="نوع تراکنش"
width="">
<template slot-scope="scope">
<el-tag
type="success"
effect="dark">
<span>{{
scope.row.action === 'increaseBag' ? 'افزایش کیف پول' : scope.row.action === 'decreaseBag' ? 'کاهش کیف پول' : 'پرداخت اینترنتی'
}}
</span>
</el-tag>
</template>
</el-table-column>
<el-table-column
label="وضعیت پرداخت"
width="">
<template slot-scope="scope">
<el-tag
:type="scope.row.status === 'paid' ? 'success' : 'danger' "
effect="dark">
<span>{{ scope.row.status === 'paid' ? 'پرداخت موفق' : 'پرداخت ناموفق'}}</span>
</el-tag>
</template>
</el-table-column>
<el-table-column
label="مبلغ"
width="">
<template slot-scope="scope">
{{ scope.row.cost.toLocaleString() + ' ریال' }}
</template>
</el-table-column>
<el-table-column
label="تاریخ و ساعت"
width="">
<template slot-scope="scope">
{{ jDate(scope.row.created_at) }}
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
<CCard class="col" v-if="payments.totalDocs>20">
<CRow alignHorizontal="center" style="padding : 10px">
<el-pagination :hide-on-single-page="true" layout="prev, pager, next" :page-size="payments.limit"
@current-change="handleCurrentChange" :current-page.sync="payments.page" :total="payments.totalDocs">
</el-pagination>
</CRow>
</CCard>
</CCol>
<CCol sm="12">
<CCard>
<CCardBody>
<h4>لاگ امتیازها</h4>
<el-divider></el-divider>
<el-table
:data="customer.scoreLogs"
style="width: 100%">
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
label="وضعیت"
width="">
<template slot-scope="scope">
<el-tag
:type="scope.row.action === 'decrease'? 'danger' : 'success'"
effect="dark">
<span>{{scope.row.action === 'decrease' ? 'کاهش امتیاز' : 'افزایش امتیاز' }}</span>
</el-tag>
</template>
</el-table-column>
<el-table-column
label="برای"
width="">
<template slot-scope="scope">
<span>{{ forWhat(scope.row.forWhat)}}</span>
</template>
</el-table-column>
<el-table-column
label="امتیاز"
prop="score"
width="">
</el-table-column>
<el-table-column
label="تاریخ و ساعت"
width="">
<template slot-scope="scope">
{{ jDate(scope.row.created_at) }}
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
</CCol>
</CRow>
<el-dialog
title="آدرس"
:visible.sync="dialogVisible"
width="50%">
<CInput
label="عنوان"
:class="validation.title ? 'err' : null"
:description="validation.title ? validation.title.msg : null"
v-model="address.title"/>
<CInput
label="استان"
:class="validation.province ? 'err' : null"
:disabled="true"
:description="validation.province ? validation.province.msg : null"
v-model="address.province"/>
<CInput
label="شهر"
:class="validation.city ? 'err' : null"
:disabled="true"
:description="validation.city ? validation.city.msg : null"
v-model="address.city"/>
<CInput
label="آدرس"
:class="validation.address ? 'err' : null"
:description="validation.address ? validation.address.msg : null"
v-model="address.address"/>
<span slot="footer" class="dialog-footer">
<el-button type="success" @click="updateAddress">بروزرسانی</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import moment from "moment-jalaali"
export default {
data() {
return {
title: 'مشاهده پروفایل مشتری',
customer: null,
payments : null,
dialogVisible: false,
validation: {},
address: {}
}
},
computed: {
pageQuery() {
return this.$route.query.page;
}
},
watch:{
pageQuery(newPage, oldPage) {
this.$nuxt.refresh();
}
},
methods: {
forWhat(status) {
switch (status) {
case 'birthDate':
return 'تولد'
case 'marriageDate':
return 'سالگرد ازدواج'
case 'buy':
return 'خرید'
case 'register':
return 'ثبت نام'
case 'invite':
return 'دعوت دوستان'
case 'emailVerify':
return 'تایید ایمیل'
default :
return 'نامشخص'
}
},
handleCurrentChange(page) {
// if (!_.isEmpty(this.search)) {
// this.handleSearch(page);
// } else {
this.$router.push({
name: "admin-customers-profile",
query: {
page: page
}
});
// }
},
openDialog(address) {
this.address = address
this.dialogVisible = true
},
updateAddress() {
this.validation = {}
this.$axios.put(`/api/admin/address/${this.address._id}`, this.address)
.then(res => {
this.dialogVisible = false;
this.$message({
type: 'success',
message: 'آدرس با موفقیت ثبت شد'
})
this.$nuxt.refresh()
})
.catch(err => {
console.log(err.response.data)
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);
})
},
deleteAddress(id) {
this.$confirm("آدرس حذف شود؟", "اخطار", {
confirmButtonText: "بله",
cancelButtonText: "لغو",
type: "warning",
})
.then(async () => {
this.validation = {}
this.$axios.delete(`/api/admin/address/${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 === 404) {
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: "عملیات لغو شد",
});
});
},
imagePreview(e) {
this.customer.profile_pic = URL.createObjectURL(e.target.files[0])
},
jDate(date) {
return moment(date).format('jYYYY/jMM/jDD HH:MM')
},
jDateOfCustomer(date) {
if (date){
return moment(date).format('jYYYY/jMM/jDD')
}
},
jDateDiscount(date) {
return moment(date , 'X').format('jYYYY/jMM/jDD')
},
update() {
this.validation = {}
const data = new FormData()
data.append("first_name", this.customer.first_name)
data.append("last_name", this.customer.last_name)
data.append("mobile_number", this.customer.mobile_number)
data.append("email", this.customer.email)
data.append("username", this.customer.username)
data.append("permissions", JSON.stringify(this.customer.permissions))
data.append("password", this.customer.password)
data.append("password_confirmation", this.customer.password_confirmation)
if (this.$refs.profile_pic.files[0]) data.append("profile_pic", this.$refs.profile_pic.files[0])
this.$axios.put(`/api/admin/admin/${this.customer._id}`, data, this.axiosConfig)
.then(response => {
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 === 422) this.validation = err.response.data.validation
else console.log(err.response.data)
})
}
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({$axios, params, query , error}) {
try {
const customer = await $axios.get(`/api/admin/user/${params.profile}`)
const payments = await $axios.get(`/api/admin/payments/${params.profile}?page=${query.page || 1}`)
return {
customer: customer.data,
payments: payments.data
}
} 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>
+191
View File
@@ -0,0 +1,191 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<a :href="`/api/public/users/exportExel/${$auth.user._id}`" target="_blank" class="mr-auto">
<CButton size="sm" color="success">خروجی اکسل</CButton>
</a>
</CustomSubHeader>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>{{ list_title }}</span>
</slot>
</CCardHeader>
<CCardBody>
<el-table
:data="customers.docs"
style="width: 100%">
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
prop="first_name"
label="نام"
width="">
</el-table-column>
<el-table-column
prop="last_name"
label="نام خانوادگی"
width="">
</el-table-column>
<el-table-column
prop="mobile_number"
label="شماره موبایل"
width="">
</el-table-column>
<el-table-column
prop="business_code"
label="کد مشتری"
width="">
</el-table-column>
<el-table-column
prop="score"
label="score"
width="">
</el-table-column>
<el-table-column
label="مشاهده"
width="70"
align="center">
<template slot-scope="scope">
<CButton color="success" variant="outline" :key="scope.row._id"
:to="{name: 'admin-branch-customers-profile',params: {profile: scope.row._id}}">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
<CCard class="col" v-if="customers.totalDocs>20">
<CRow alignHorizontal="center" style="padding : 10px">
<el-pagination :hide-on-single-page="true" layout="prev, pager, next" :page-size="customers.limit"
@current-change="handleCurrentChange" :current-page.sync="customers.page" :total="customers.totalDocs">
</el-pagination>
</CRow>
</CCard>
</div>
</template>
<script>
export default {
data() {
return {
title: 'لیست مشتریان',
list_title: 'لیست',
customers: null
}
},
computed: {
pageQuery() {
return this.$route.query.page;
}
},
watch:{
pageQuery(newPage, oldPage) {
this.$nuxt.refresh();
}
},
methods: {
handleCurrentChange(page) {
// if (!_.isEmpty(this.search)) {
// this.handleSearch(page);
// } else {
this.$router.push({
name: "admin-branch-customers",
query: {
page: page
}
});
// }
},
deleteUser(id) {
this.$confirm('کاربر حذف شود؟', 'هشدار', {
confirmButtonText: 'بله',
cancelButtonText: 'لغو',
type: 'warning'
}).then(async () => {
this.$axios.delete(`/api/admin/admin/${id}`)
.then(res => {
this.$message({
type: 'success',
message: 'کاربر با موفقیت حذف شد'
})
this.customers.docs = this.customers.docs.filter(item => item._id !== id)
})
.catch(err => {
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
console.log(err.response.data)
})
}).catch(() => {
this.$message({
type: 'warning',
message: 'عملیات لغو شد'
})
})
},
async createExel(){
try {
const createExel = await this.$axios.$get(`/api/admin/users/exportExel`);
console.log(createExel)
}catch (e) {
if (e?.response?.status === 401) {
this.$message({
type: 'warning',
message: 'شما اجازه دسترسی به این صفحه را ندارید لطفا دوباره وارد شوید'
})
} else {
this.$message({
type: 'warning',
message: 'مشکلی در گرفتن اطلاعات بوجود آمده است'
})
}
}
}
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({$axios,query, error, params}) {
try {
const customers = await $axios.get(`/api/admin/users/${params.branch}?page=${query.page || 1}`)
return {
customers: customers.data
}
} catch (e) {
if (e?.response?.status === 401) {
error({
status: 401,
message: 'شما اجازه دسترسی به این صفحه را ندارید لطفا دوباره وارد شوید'
})
} else {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات بوجود آمده است",
});
}
}
}
}
</script>
+315
View File
@@ -0,0 +1,315 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<!-- <CButton size="sm" color="success" :to="{name: 'admin-discounts-discount',params:{profile: 'new'}}" class="mr-auto">افزودن</CButton>-->
</CustomSubHeader>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>{{ list_title }}</span>
</slot>
</CCardHeader>
<CCardBody>
<h2>افزودن کد تخفیف</h2>
<el-divider></el-divider>
<el-button-group>
<el-button :type="newDiscountIsPublic ? 'info' : 'primary'" @click="newDiscountIsPublic = false" icon="el-icon-arrow-left">کد تخفیف اختصاصی</el-button>
<el-button :type="newDiscountIsPublic ? 'primary' : 'info'" @click="newDiscountIsPublic = true" icon="el-icon-arrow-left">کد تخفیف عمومی</el-button>
</el-button-group>
<br>
<el-select
v-if="!newDiscountIsPublic"
v-model="discount_user_id"
filterable
style="width: 300px;margin-top: 20px;margin-bottom: 10px;">
<el-option
v-for="item in users"
:key="item._id"
:value="item._id"
:label="item.business_code + ' ' + '(' + item.first_name + ' ' + item.last_name + ')'"/>
</el-select>
<p class="text-danger" v-if="validation.discount_user_id">{{ validation.discount_user_id.msg }}</p>
<div v-if="newDiscountIsPublic" style="margin-top: 20px;margin-bottom: 10px;">
<el-switch
style="direction: ltr;margin-bottom: 20px;"
v-model="publicDiscountIsAuto"
active-text="ایجاد کد تخفیف توسط سیستم"
inactive-text="وارد کردن کد دستی">
</el-switch>
<el-input v-model="customDiscountCode" v-if="!publicDiscountIsAuto" placeholder="کدتخفیف دستی را وارد کنید" style="width: 300px;display: block;"></el-input>
<p class="text-danger" v-if="validation.customDiscountCode">{{ validation.customDiscountCode.msg }}</p>
</div>
<el-input v-model="discount_amount" placeholder="درصد تخفیف را وارد کنید" style="display: block;width: 300px;margin-bottom: 10px;"></el-input>
<p class="text-danger" v-if="validation.discount_amount">{{ validation.discount_amount.msg }}</p>
<date-picker
v-model="discount_expire_date"
placeholder="تاریخ انقضای کد را مشخص کنید"
format="X"
displayFormat="jYYYY/jMM/jDD"
style="display: block;width: 300px!important;margin-bottom: 10px;"/>
<p class="text-danger" v-if="validation.discount_expire_date">{{ validation.discount_expire_date.msg }}</p>
<el-select
v-model="menuTypeId"
filterable
placeholder="منو را انتخاب کنید"
style="width: 300px;margin-bottom: 20px;">
<el-option
v-for="item in menuTypes"
:key="item._id"
:value="item._id"
:label="item.name"/>
</el-select>
<p class="text-danger" v-if="validation.menuTypeId">{{ validation.menuTypeId.msg }}</p>
<br>
<el-button type="success" @click="addDiscount">ایجاد کد تخفیف</el-button>
</CCardBody>
</CCard>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>{{ list_title }}</span>
</slot>
</CCardHeader>
<CCardBody>
<el-table
:data="discounts.docs"
style="width: 100%">
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
prop="discount_code"
label="کد تخفیف"
width="">
</el-table-column>
<el-table-column
label="درصد تخفیف"
width="">
<template slot-scope="scope">
<span class="text-success">{{ scope.row.discount_amount + '%' }}</span>
</template>
</el-table-column>
<el-table-column
label="تاریخ انقضا"
width="">
<template slot-scope="scope">
{{ jDate(scope.row.discount_expire_date) }}
</template>
</el-table-column>
<el-table-column
label="در دسترس برای"
width="">
<template slot-scope="scope">
<span v-if="scope.row.isPublic" class="text-success">برای همه</span>
<span v-else>{{ scope.row.discount_user_id.first_name + ' ' + scope.row.discount_user_id.last_name }}</span>
</template>
</el-table-column>
<el-table-column
label="حذف"
width="75"
align="center">
<template slot-scope="scope">
<CButton color="danger" variant="outline" :key="scope.row._id + Math.random()" @click="deleteUser(scope.row._id)">
<i class="far fa-trash-alt"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
<CCard class="col" v-if="discounts.totalDocs>20">
<CRow alignHorizontal="center" style="padding : 10px">
<el-pagination :hide-on-single-page="true" layout="prev, pager, next" :page-size="discounts.limit"
@current-change="handleCurrentChange" :current-page.sync="discounts.page" :total="discounts.totalDocs">
</el-pagination>
</CRow>
</CCard>
</div>
</template>
<script>
import moment from 'moment-jalaali'
export default {
data() {
return {
title: 'لیست کدهای تخفیف',
list_title: 'لیست',
// base data
discounts: null,
users: null,
menuTypes: null,
// discount details
discount_user_id: '',
discount_expire_date: '',
menuTypeId: '',
discount_amount: '',
customDiscountCode: '',
newDiscountIsPublic: true,
publicDiscountIsAuto: true,
loading: false,
// validation
validation: {}
}
},
watch: {
pageQuery(newPage, oldPage) {
this.$nuxt.refresh();
},
newDiscountIsPublic(newVal, oldVal) {
this.validation = {}
},
publicDiscountIsAuto(newVal, oldVal) {
this.validation = {}
}
},
computed: {
pageQuery() {
return this.$route.query.page;
}
},
methods: {
handleCurrentChange(page) {
// if (!_.isEmpty(this.search)) {
// this.handleSearch(page);
// } else {
this.$router.push({
name: "admin-branch-discounts",
query: {
page: page
}
});
// }
},
addDiscount() {
const loading = this.$loading({
lock: true,
text: 'Loading',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
});
this.validation = {}
const data = {
discount_user_id: this.discount_user_id,
discount_expire_date: this.discount_expire_date,
discount_amount: this.discount_amount,
menuTypeId: this.menuTypeId,
customDiscountCode: this.customDiscountCode,
newDiscountIsPublic: this.newDiscountIsPublic,
publicDiscountIsAuto: this.publicDiscountIsAuto,
branchId: this.$route.params.branch
}
this.$axios.post('/api/admin/discountCode', data)
.then(res => {
loading.close()
this.$alert('', 'موفق', {
type: 'success',
message: `کد تخفیف: ${res.data.discount_code}`
})
this.discount_user_id = ''
this.discount_expire_date = ''
this.discount_amount = ''
this.menuTypeId = ''
this.customDiscountCode = ''
this.$nuxt.refresh()
})
.catch(err => {
loading.close()
if (err.response.status === 422) return this.validation = err.response.data.validation
else if (err.response.status === 500) error({
status: 500,
message: err.response.data.message,
});
else console.log(err)
})
},
deleteUser(id) {
this.$confirm('کد تخفیف حذف شود؟', 'هشدار', {
confirmButtonText: 'بله',
cancelButtonText: 'لغو',
type: 'warning'
}).then(async () => {
this.$axios.delete(`/api/admin/discountCode/${id}`)
.then(res => {
this.$message({
type: 'success',
message: 'کد تخفیف با موفقیت حذف شد'
})
this.discounts.docs = this.discounts.docs.filter(item => item._id !== id)
})
.catch(err => {
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
console.log(err.response.data)
})
}).catch(() => {
this.$message({
type: 'warning',
message: 'عملیات لغو شد'
})
})
},
jDate(date) {
return moment(date, 'X').format('jYYYY/jMM/jDD')
}
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({$axios, query, error, params}) {
try {
const users = await $axios.get(`/api/admin/users/getAll/${params.branch}`)
const menuTypes = await $axios.get(`/api/public/menuTypes/getAll/${params.branch}`)
const discounts = await $axios.get(`/api/admin/discountCodes/${params.branch}?page=${query.page || 1}`)
return {
users: users.data,
discounts: discounts.data,
menuTypes: menuTypes.data
}
} catch (e) {
if (e?.response?.status === 401) {
error({
status: 401,
message: 'شما اجازه دسترسی به این صفحه را ندارید لطفا دوباره وارد شوید'
})
} else {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات بوجود آمده است",
});
}
}
}
}
</script>
<style lang="scss">
.el-button:focus {
outline-color: #39f !important;
}
</style>
@@ -0,0 +1,203 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="primary" class="mr-auto" :to="{name: 'admin-branch-food-categories'}">برگشت به صفحه
قبل</CButton>
<CButton v-if="$route.params.category === '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">
<CInput
:class="validation.name ? 'err' : null"
label="نام"
:description="validation.name ? validation.name.msg : null"
v-model="foodCategory.name"
/>
</CCol>
</CRow>
<CRow>
<CCol s="12">
<span>نوع منو</span>
</CCol>
<CCol sm="12" class="err">
<el-select v-model="foodCategory.type" 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.type" class="text-danger" style="margin-top: 5px;">{{ validation.type.msg }}</p>
</CCol>
</CRow>
<CRow>
<CCol s="12" class="mt-3">
<span>ترتیب نمایش در منو</span>
</CCol>
<CCol sm="12" class="err">
<el-select v-model="foodCategory.index" filterable style="width: 100%;margin-top: 5px;">
<el-option
v-for="item in 1000"
v-if="!foodCategories.filter(item2=>Number(item2.index) === item && item2.type._id === foodCategory.type).length"
: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>
</CForm>
<el-divider></el-divider>
<h3>کاور</h3>
<img :src="foodCategory.cover" style="width: 100%;max-width: 300px;" alt="">
<input type="file" ref="cover" @change="preview">
<p class="text-danger" v-if="validation.cover">{{ validation.cover.msg }}</p>
</CCardBody>
</CCard>
</CCol>
</CRow>
</div>
</template>
<script>
import axiosUploadProcess from "@/mixins/axiosUploadProcess"
export default {
data() {
return {
foodCategories: null,
foodCategory: null,
menuTypes: null,
validation: {}
}
},
mixins: [axiosUploadProcess],
computed: {
title() {
return this.$route.params.category === 'new' ? 'افزودن دسته بندی' : 'مشاهده دسته بندی'
}
},
methods: {
preview(event) {
this.foodCategory.cover = URL.createObjectURL(event.target.files[0])
},
post() {
this.validation = {}
const data = new FormData()
data.append('name', this.foodCategory.name)
data.append('type', this.foodCategory.type)
data.append('index', this.foodCategory.index)
data.append('cover', this.$refs.cover.files[0])
data.append('branchId', this.$route?.params?.branch)
this.$axios.post(`/api/admin/foodCategory`, data, this.axiosConfig)
.then(response => {
this.$message({
type: 'success',
message: 'دسته بندی با موفقیت ایجاد شد.'
})
this.$refs.cover.value = null
this.$router.push({name: 'admin-branch-food-categories'})
})
.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.foodCategory.name)
data.append('type', this.foodCategory.type)
data.append('index', this.foodCategory.index)
data.append('branchId', this.$route?.params?.branch)
if (this.$refs.cover.files[0]) data.append('cover', this.$refs.cover.files[0])
this.$axios.put(`/api/admin/foodCategory/${this.foodCategory._id}`, data, this.axiosConfig)
.then(response => {
this.$message({
type: 'success',
message: 'اطلاعات بروزرسانی شد.'
})
this.$refs.cover.value = null
this.$nuxt.refresh()
})
.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 foodCategories = await $axios.get(`/api/public/foodCategories/getAll/${params?.branch}`)
const menuTypes = await $axios.get(`/api/admin/allMenuType/getAll/${params?.branch}`)
if (params.category !== 'new') {
const foodCategory = await $axios.get(`/api/public/foodCategory/${params.category}`)
return {
foodCategories: foodCategories.data,
menuTypes: menuTypes.data,
foodCategory: foodCategory.data
}
} else {
return {
foodCategories: foodCategories.data,
menuTypes: menuTypes.data,
foodCategory: {
name: '',
type: '',
cover: '',
index: 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>
@@ -0,0 +1,187 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="success" :to="{name: 'admin-branch-food-categories-category',params:{category: 'new'}}"
class="mr-auto">افزودن</CButton>
</CustomSubHeader>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>{{ list_title }}</span>
</slot>
</CCardHeader>
<CCardBody>
<el-table
:data="foodCategories.docs"
style="width: 100%">
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
label="کاور"
width="200">
<template slot-scope="scope">
<img :src="scope.row.cover" style="width: 100%;" alt="">
</template>
</el-table-column>
<el-table-column
prop="name"
label="نام"
width="">
</el-table-column>
<el-table-column
prop="type.name"
label="نوع منو"
:filters="filter"
:filter-method="filterType"
width="">
</el-table-column>
<el-table-column
label="ویرایش"
width="110"
align="center">
<template slot-scope="scope">
<CButton color="danger" variant="outline" :key="scope.row._id + Math.random()" @click="remove(scope.row._id)">
<i class="far fa-trash-alt"></i>
</CButton>
<CButton color="success" variant="outline" :key="scope.row._id" :to="{name:
'admin-branch-food-categories-category',params: {category: scope.row._id}}">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
<CCard class="col" v-if="foodCategories.totalDocs>20">
<CRow alignHorizontal="center" style="padding : 10px">
<el-pagination :hide-on-single-page="true" layout="prev, pager, next" :page-size="foodCategories.limit"
@current-change="handleCurrentChange" :current-page.sync="foodCategories.page" :total="foodCategories.totalDocs">
</el-pagination>
</CRow>
</CCard>
</div>
</template>
<script>
export default {
data() {
return {
title: 'لیست دسته بندی غذاها',
list_title: 'لیست',
foodCategories: null,
menuTypes: null
}
},
computed: {
pageQuery() {
return this.$route.query.page;
},
filter(){
const fill = []
for (const item of this.menuTypes) {
fill.push({
text : item.name,
value : item._id
})
}
return fill
}
},
watch: {
pageQuery(newPage, oldPage) {
this.$nuxt.refresh();
}
},
methods: {
handleCurrentChange(page) {
// if (!_.isEmpty(this.search)) {
// this.handleSearch(page);
// } else {
this.$router.push({
name: "admin-branch-food-categories",
query: {
page: page
}
});
// }
},
filterType(value, row){
return row.type._id === value;
},
remove(id) {
this.$confirm('این مورد حذف شود؟', 'هشدار', {
confirmButtonText: 'بله',
cancelButtonText: 'لغو',
type: 'warning'
}).then(async () => {
this.$axios.delete(`/api/admin/foodCategory/${id}`)
.then(res => {
this.$message({
type: 'success',
message: 'دسته بندی با موفقیت حذف شد'
})
this.foodCategories.docs = this.foodCategories.docs.filter(item => item._id !== id)
})
.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
})
} else console.log(err.response.data)
})
}).catch(() => {
this.$message({
type: 'warning',
message: 'عملیات لغو شد'
})
})
}
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({$axios,query, error, params}) {
try {
const foodCategories = await $axios.get(`/api/admin/foodCategory/getAll/${params.branch}?page=${query.page ||
1}`)
const menuTypes = await $axios.get(`/api/admin/allMenuType/getAll/${params.branch}`)
return {
foodCategories: foodCategories.data,
menuTypes: menuTypes.data
}
} catch (e) {
if (e?.response?.status === 401) {
error({
status: 401,
message: 'شما اجازه دسترسی به این صفحه را ندارید لطفا دوباره وارد شوید'
})
} else {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات بوجود آمده است",
});
}
}
}
}
</script>
+573
View File
@@ -0,0 +1,573 @@
<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>
</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('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('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
}
}
}
} 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>
+336
View File
@@ -0,0 +1,336 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="success" :to="{name: 'admin-branch-foods-food',params:{food: 'new'}}" class="mr-auto">
افزودن</CButton>
</CustomSubHeader>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-filter"></i>
<span style="color:#000">فیلتر</span>
</slot>
</CCardHeader>
<CCardBody>
<CRow>
<CCol md="6">
<CRow style="flex-direction : column;">
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>نام</span>
</CCol>
<CCol col="md-9">
<el-input style="width : 100%" placeholder="" v-model="search.name"></el-input>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>دسته بندی</span>
</CCol>
<CCol col="md-9">
<el-select filterable clearable style="width : 100%" v-model="search.category"
placeholder="">
<el-option
v-for="item in foodCategories"
:key="item._id"
:value="item._id"
:label="item.name"/>
</el-select>
</CCol>
</CRow>
</CCol>
</CRow>
</CCol>
<CCol md="6">
<CRow style="flex-direction : column;">
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>فروش به صورت عادی</span>
</CCol>
<CCol col="md-9">
<el-select v-model="search.sale" clearable style="width : 100%">
<el-option :key="1" label="بله" :value="true"></el-option>
<el-option :key="2" label="خیر" :value="false"></el-option>
</el-select>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>فروش در باشگاه مشتریان</span>
</CCol>
<CCol col="md-9">
<el-select v-model="search.club" clearable style="width : 100%">
<el-option :key="1" label="بله" :value="true"></el-option>
<el-option :key="2" label="خیر" :value="false"></el-option>
</el-select>
</CCol>
</CRow>
</CCol>
</CRow>
</CCol>
</CRow>
<CRow>
<el-button :loading="loading" @click="handleSearch" size="small"
style="width: auto;margin: 25px auto auto auto;" type="primary"
icon="el-icon-search">
جست و جو
</el-button>
</CRow>
</CCardBody>
</CCard>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>{{ list_title }}</span>
</slot>
</CCardHeader>
<CCardBody>
<el-table
:data="foods.docs"
style="width: 100%">
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
label="عکس"
width="">
<template slot-scope="scope">
<img v-if="scope.row.image" :src="scope.row.image" alt="" style="width: 100px;">
<i v-else class="fal fa-image-polaroid" style="font-size: 115px;"></i>
</template>
</el-table-column>
<el-table-column
prop="name"
label="نام"
width="">
</el-table-column>
<el-table-column
label="قیمت"
width="">
<template slot-scope="scope">
<span v-if="scope.row.price">{{ scope.row.price.toLocaleString() + ' ريال ' }}</span>
<span v-else class="text-danger">بدون قیمت</span>
</template>
</el-table-column>
<el-table-column
label="قیمت با تخفیف"
width="">
<template slot-scope="scope">
<span v-if="scope.row.static_discount">{{ (scope.row.price - (scope.row.price / 100) * scope.row.static_discount).toLocaleString() + ' ريال ' }}</span>
<span v-else class="text-danger">{{ scope.row.price.toLocaleString() + ' ريال ' }}</span>
</template>
</el-table-column>
<el-table-column
label="تعداد موجود"
width="">
<template slot-scope="scope">
<span v-if="scope.row.stock" class="text-success">{{ scope.row.stock }}</span>
<span v-else class="text-danger">اتمام موجودی</span>
</template>
</el-table-column>
<el-table-column
label="درصد تخفیف"
width="">
<template slot-scope="scope">
<span v-if="scope.row.static_discount" class="text-success">{{ scope.row.static_discount + '%' }}</span>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column
label="امتیاز مشتریان"
width="">
<template slot-scope="scope">
<span>{{ scope.row.rate }}</span>
<i class="fas fa-star" style="color: goldenrod;"></i>
</template>
</el-table-column>
<el-table-column
label="دسته بندی"
width="">
<template slot-scope="scope">
{{ getFoodCategoryName(scope.row.category) }}
</template>
</el-table-column>
<el-table-column
label="ویرایش"
width="110"
align="center">
<template slot-scope="scope">
<CButton color="danger" variant="outline" :key="scope.row._id + Math.random()" @click="remove(scope.row._id)">
<i class="far fa-trash-alt"></i>
</CButton>
<CButton color="success" variant="outline" :key="scope.row._id" :to="{name: 'admin-branch-foods-food',params:
{food: scope.row._id}}">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
<CCard class="col" v-if="foods.totalDocs>20">
<CRow alignHorizontal="center" style="padding : 10px">
<el-pagination :hide-on-single-page="true" layout="prev, pager, next" :page-size="foods.limit"
@current-change="handleCurrentChange" :current-page.sync="foods.page" :total="foods.totalDocs">
</el-pagination>
</CRow>
</CCard>
</div>
</template>
<script>
const _ = require('lodash');
export default {
data() {
return {
title: 'لیست غذاها',
list_title: 'لیست',
foodCategories: null,
foods: null,
loading : false,
search: {},
}
},
computed: {
pageQuery() {
return this.$route.query.page;
}
},
watch: {
pageQuery(newPage, oldPage) {
this.$nuxt.refresh();
}
},
methods: {
handleCurrentChange(page) {
if (!_.isEmpty(this.search)) {
this.handleSearch(page);
} else {
this.$router.push({
name: "admin-branch-foods",
query: {
page: page
}
});
}
},
getFoodCategoryName(id) {
return this.foodCategories.filter(item => item._id === id)[0].name
},
remove(id) {
this.$confirm('این مورد حذف شود؟', 'هشدار', {
confirmButtonText: 'بله',
cancelButtonText: 'لغو',
type: 'warning'
}).then(async () => {
this.$axios.delete(`/api/admin/food/${id}`)
.then(res => {
this.$message({
type: 'success',
message: 'غذا با موفقیت حذف شد'
})
this.foods.docs = this.foods.docs.filter(item => item._id !== id)
})
.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
})
} else console.log(err.response.data)
})
}).catch(() => {
this.$message({
type: 'warning',
message: 'عملیات لغو شد'
})
})
},
handleSearch(page) {
this.loading = true;
const data = {
club: this.search.club,
sale: this.search.sale,
name: this.search.name,
category: this.search.category,
branchId: this.$route?.params?.branch
}
this.$axios.post(`/api/admin/food/search?page=${page}`, data, this.axiosConfig)
.then((result) => {
this.foods = result.data;
this.loading = false;
})
.catch(err => {
this.loading = false;
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, query, error, params}) {
try {
const foodCategories = await $axios.get(`/api/public/foodCategories/getAll/${params.branch}`)
const foods = await $axios.get(`/api/admin/food/getAll/${params.branch}?page=${query.page || 1}`)
return {
foodCategories: foodCategories.data,
foods: foods.data
}
} catch (e) {
if (e?.response?.status === 401) {
error({
status: 401,
message: 'شما اجازه دسترسی به این صفحه را ندارید لطفا دوباره وارد شوید'
})
} else {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات بوجود آمده است",
});
}
}
}
}
</script>
+265
View File
@@ -0,0 +1,265 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<!-- <CButton size="sm" color="success" :to="{name: 'admin-foods-food',params:{food: 'new'}}" class="mr-auto">افزودن</CButton>-->
</CustomSubHeader>
<CCard v-if="hasPermission('super-admin')">
<CCardBody>
<CRow>
<CCol col="12" sm="6">
<CCallout color="info">
<small class="text-muted">تعداد مشتری ها</small><br>
<strong class="h4">{{ customers.length }}</strong>
</CCallout>
</CCol>
<CCol col="12" sm="6">
<CCallout color="danger">
<small class="text-muted">تعداد سفارشات</small><br>
<strong class="h4">{{ orders.length }}</strong>
</CCallout>
</CCol>
</CRow>
</CCardBody>
</CCard>
<CCol v-if="hasPermission('super-admin')">
<CRow>
<CCol sm="6">
<CCard>
<CCardHeader>
<strong>
<span>تعداد مشتریان بر اساس شغل</span>
</strong>
</CCardHeader>
<CCardBody>
<canvas id="myChart" width="400" height="400"></canvas>
</CCardBody>
</CCard>
</CCol>
</CRow>
</CCol>
<CCard v-if="hasPermission('super-admin')">
<CCardHeader>
<strong>
<span>لیست تخفیف های ویژه امروز مورخ: </span>
<span>{{ jDate(Date.now()) }}</span>
</strong>
</CCardHeader>
<CCardBody>
<el-table
:data="offFoods"
style="width: 100%">
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
label="عکس"
width="">
<template slot-scope="scope">
<img v-if="scope.row.image" :src="scope.row.image" alt="" style="width: 100px;">
<i v-else class="fal fa-image-polaroid" style="font-size: 115px;"></i>
</template>
</el-table-column>
<el-table-column
prop="name"
label="نام"
width="">
</el-table-column>
<el-table-column
label="قیمت"
width="">
<template slot-scope="scope">
<span class="text-success" v-if="scope.row.price">{{ scope.row.price.toLocaleString() + ' ريال ' }}</span>
<span class="text-danger" v-else>بدون قیمت</span>
</template>
</el-table-column>
<el-table-column
label="قیمت با تخفیف"
width="">
<template slot-scope="scope">
<span v-if="scope.row.static_discount">{{ (scope.row.price - (scope.row.price / 100) * scope.row.static_discount).toLocaleString() + ' ريال ' }}</span>
<span v-else class="text-danger">{{ scope.row.price.toLocaleString() + ' ريال ' }}</span>
</template>
</el-table-column>
<el-table-column
label="تعداد موجود"
width="">
<template slot-scope="scope">
<span class="text-success" v-if="scope.row.stock">{{ scope.row.stock }}</span>
<span class="text-danger" v-else>اتمام موجودی</span>
</template>
</el-table-column>
<el-table-column
label="درصد تخفیف"
width="">
<template slot-scope="scope">
<span class="text-success" v-if="scope.row.static_discount">{{ scope.row.static_discount + '%' }}</span>
</template>
</el-table-column>
<el-table-column
label="دسته بندی"
width="">
<template slot-scope="scope">
{{ getFoodCategoryName(scope.row.category) }}
</template>
</el-table-column>
<el-table-column
label="مشاهده"
width="75"
align="center">
<template slot-scope="scope">
<CButton color="success" variant="outline" :key="scope.row._id" :to="{name: 'admin-foods-food',params: {food: scope.row._id}}">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
</div>
</template>
<script>
import moment from "moment-jalaali"
import login from "@/pages/admin/login";
export default {
data() {
return {
title: 'داشبورد',
list_title: 'لیست',
foodCategories: null,
foods: null,
idToken: '',
permissionGranted: false,
customers : null,
orders : null
}
},
computed: {
offFoods() {
return this.foods.filter(item => item.static_discount)
},
branchId(){
return this.$store?.state?.admin?.branchId
}
},
methods: {
jDate(date) {
return moment(date).format("jYYYY/jMM/jDD")
},
getFoodCategoryName(id) {
return this.foodCategories.filter(item => item._id === id)[0].name
},
hasPermission(permission) {
if (this.$auth.loggedIn) return this.$auth.user.permissions.includes(permission)
else return false
},
},
head() {
return {
title: this.title
}
},
async mounted() {
await Notification.requestPermission()
const typePermission = await Notification.permission
this.permissionGranted = typePermission === 'granted'
const getAdmin = this.$auth.$state.user
if (typePermission === 'granted') {
if (getAdmin) {
this.idToken = await this.$fire.messaging.getToken()
await this.$axios.post('/api/admin/addFcmToken', {
fcmToken: this.idToken
})
}
}
if (this.hasPermission('super-admin')){
const counts = {};
this.customers.forEach(function (x) { counts[x.job] = (counts[x.job] || 0) + 1; });
let keys = Object.keys(counts).map(item => item === 'undefined' ? 'نامشخص' : item);
let values = Object.values(counts).map(item => item === 'undefined' ? 'نامشخص' : item);
const CHART_COLORS = {
red: 'rgb(255, 99, 132)',
orange: 'rgb(255, 159, 64)',
yellow: 'rgb(255, 205, 86)',
green: 'rgb(75, 192, 192)',
blue: 'rgb(54, 162, 235)',
purple: 'rgb(153, 102, 255)',
grey: 'rgb(201, 203, 207)'
};
const ctx = document.getElementById('myChart');
const myChart = new Chart(ctx, {
type: 'pie',
data: {
labels: keys,
datasets: [{
// label: '# of Votes',
data: values,
backgroundColor: Object.values(CHART_COLORS),
borderWidth: 1
}]
},
options: {
responsive: true,
scales: {
y: {
beginAtZero: true
}
}
}
});
}
},
layout: 'admin',
async asyncData({$axios, error , redirect , route}) {
try {
const branchId = route?.params?.branch
const requests = [
$axios.get(`/api/public/foodCategories/getAll/${branchId}`),
$axios.get(`/api/public/foods/getAll/${branchId}`,{progress: false}),
$axios.get(`/api/admin/users/forReport/${branchId}`,{progress: false}),
$axios.get(`/api/admin/order/forReport/${branchId}`,{progress: false})
];
const fetch = await Promise.all(requests);
const [foodCategories, foods, customers, orders] = fetch;
return {
foodCategories: foodCategories.data,
foods: foods.data,
customers: customers.data,
orders: orders.data
}
} catch (e) {
if (e?.response?.status === 401) {
redirect('/admin/login')
} else {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات بوجود آمده است",
});
}
}
}
}
</script>
+163
View File
@@ -0,0 +1,163 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="primary" class="mr-auto" :to="{name: 'admin-branch-jobs'}">برگشت به صفحه قبل</CButton>
<CButton v-if="$route.params.type === '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>
<!-- <template v-if="$route.params.profile !== 'new'">-->
<!-- <h4>مشخصات منو</h4>-->
<!-- <el-divider/>-->
<!-- </template>-->
<CRow>
<CCol sm="12">
<CInput
:class="validation.name ? 'err' : null"
label="نام"
:description="validation.name ? validation.name.msg : null"
v-model="job.name"
/>
</CCol>
</CRow>
<CRow>
<CCol s="12" class="mt-3">
<span>ترتیب نمایش در منو</span>
</CCol>
<CCol sm="12" class="err">
<el-select v-model="job.index" filterable style="width: 100%;margin-top: 5px;">
<el-option
v-for="item in 1000"
v-if="!jobs.filter(item2=>Number(item2.index) === item).length"
: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>
</CForm>
</CCardBody>
</CCard>
</CCol>
</CRow>
</div>
</template>
<script>
export default {
data() {
return {
jobs: null,
job: null,
validation: {}
}
},
computed: {
title() {
return this.$route.params.type === 'new' ? 'افزودن شغل' : 'مشاهده شغل'
}
},
methods: {
post() {
this.validation = {}
const data = this.job
this.$axios.post(`/api/admin/job`, data)
.then(response => {
this.$message({
type: 'success',
message: 'شغل با موفقیت ایجاد شد.'
})
this.$router.push({name: 'admin-branch-jobs'})
})
.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 = this.job
this.$axios.put(`/api/admin/job/${this.job._id}`, data)
.then(response => {
this.$message({
type: 'success',
message: 'اطلاعات بروزرسانی شد.'
})
})
.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 jobs = await $axios.get(`/api/public/job`)
if (params.type !== 'new') {
const job = await $axios.get(`/api/admin/job/${params.type}`)
return {
jobs: jobs.data,
job: job.data
}
} else {
return {
jobs: jobs.data,
job: {
name: '',
index: 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>
+155
View File
@@ -0,0 +1,155 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="success" :to="{name: 'admin-branch-jobs-type',params:{type: 'new'}}"
class="mr-auto">افزودن
</CButton>
</CustomSubHeader>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>{{ list_title }}</span>
</slot>
</CCardHeader>
<CCardBody>
<el-table
:data="jobs.docs"
style="width: 100%">
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
prop="name"
label="نام"
width="">
</el-table-column>
<el-table-column
label="ویرایش"
width="110"
align="center">
<template slot-scope="scope">
<CButton color="danger" variant="outline" :key="scope.row._id + Math.random()" @click="remove(scope.row._id)">
<i class="far fa-trash-alt"></i>
</CButton>
<CButton color="success" variant="outline" :key="scope.row._id" :to="{name: 'admin-branch-jobs-type',params:
{type: scope.row._id}}">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
<CCard class="col" v-if="jobs.totalDocs>20">
<CRow alignHorizontal="center" style="padding : 10px">
<el-pagination :hide-on-single-page="true" layout="prev, pager, next" :page-size="jobs.limit"
@current-change="handleCurrentChange" :current-page.sync="jobs.page" :total="jobs.totalDocs">
</el-pagination>
</CRow>
</CCard>
</div>
</template>
<script>
export default {
data() {
return {
title: 'لیست انواع منوها',
list_title: 'لیست',
jobs: null
}
},
computed: {
pageQuery() {
return this.$route.query.page;
}
},
watch: {
pageQuery(newPage, oldPage) {
this.$nuxt.refresh();
}
},
methods: {
handleCurrentChange(page) {
// if (!_.isEmpty(this.search)) {
// this.handleSearch(page);
// } else {
this.$router.push({
name: "admin-branch-menu-types",
query: {
page: page
}
});
// }
},
remove(id) {
this.$confirm('این مورد حذف شود؟', 'هشدار', {
confirmButtonText: 'بله',
cancelButtonText: 'لغو',
type: 'warning'
}).then(async () => {
this.$axios.delete(`/api/admin/job/${id}`)
.then(res => {
this.$message({
type: 'success',
message: 'منو با موفقیت حذف شد'
})
this.jobs.docs = this.jobs.docs.filter(item => item._id !== id)
})
.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
})
} else console.log(err.response.data)
})
}).catch(() => {
this.$message({
type: 'warning',
message: 'عملیات لغو شد'
})
})
}
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({$axios,query , error}) {
try {
const jobs = await $axios.get(`/api/admin/job?page=${query.page || 1}`)
return {
jobs: jobs.data
}
} catch (e) {
if (e?.response?.status === 401) {
error({
status: 401,
message: 'شما اجازه دسترسی به این صفحه را ندارید لطفا دوباره وارد شوید'
})
} else {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات بوجود آمده است",
});
}
}
}
}
</script>
+174
View File
@@ -0,0 +1,174 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="primary" class="mr-auto" :to="{name: 'admin-branch-menu-types'}">برگشت به صفحه
قبل</CButton>
<CButton v-if="$route.params.type === '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>
<!-- <template v-if="$route.params.profile !== 'new'">-->
<!-- <h4>مشخصات منو</h4>-->
<!-- <el-divider/>-->
<!-- </template>-->
<CRow>
<CCol sm="12">
<CInput
:class="validation.name ? 'err' : null"
label="نام"
:description="validation.name ? validation.name.msg : null"
v-model="menuType.name"
/>
</CCol>
<CCol sm="12">
<el-checkbox v-model="menuType.showOnWebSite">در وبسایت نمایش داده شود</el-checkbox>
</CCol>
<CCol sm="12">
<el-checkbox v-model="menuType.isCafeMenu">منوی کافه است</el-checkbox>
</CCol>
</CRow>
<CRow>
<CCol s="12" class="mt-3">
<span>ترتیب نمایش در منو</span>
</CCol>
<CCol sm="12" class="err">
<el-select v-model="menuType.index" filterable style="width: 100%;margin-top: 5px;">
<el-option
v-for="item in 1000"
v-if="!menuTypes.filter(item2=>Number(item2.index) === item).length"
: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>
</CForm>
</CCardBody>
</CCard>
</CCol>
</CRow>
</div>
</template>
<script>
export default {
data() {
return {
menuTypes: null,
menuType: null,
validation: {}
}
},
computed: {
title() {
return this.$route.params.type === 'new' ? 'افزودن منو' : 'مشاهده منو'
}
},
methods: {
post() {
this.validation = {}
const data = this.menuType
data.branchId = this.$route?.params?.branch
this.$axios.post(`/api/admin/menuType`, data)
.then(response => {
this.$message({
type: 'success',
message: 'منو با موفقیت ایجاد شد.'
})
this.$router.push({name: 'admin-branch-menu-types'})
})
.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 = this.menuType
data.branchId = this.$route?.params?.branch
this.$axios.put(`/api/admin/menuType/${this.menuType._id}`, data)
.then(response => {
this.$message({
type: 'success',
message: 'اطلاعات بروزرسانی شد.'
})
})
.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 menuTypes = await $axios.get(`/api/public/menuTypes/getAll/${params?.branch}`)
if (params.type !== 'new') {
const menuType = await $axios.get(`/api/public/menuType/${params.type}`)
return {
menuTypes: menuTypes.data,
menuType: menuType.data
}
} else {
return {
menuTypes: menuTypes.data,
menuType: {
name: '',
showOnWebSite: true,
isCafeMenu: false,
index: 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>
+154
View File
@@ -0,0 +1,154 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="success" :to="{name: 'admin-branch-menu-types-type',params:{type: 'new'}}"
class="mr-auto">افزودن</CButton>
</CustomSubHeader>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>{{ list_title }}</span>
</slot>
</CCardHeader>
<CCardBody>
<el-table
:data="menuTypes.docs"
style="width: 100%">
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
prop="name"
label="نام"
width="">
</el-table-column>
<el-table-column
label="ویرایش"
width="110"
align="center">
<template slot-scope="scope">
<CButton color="danger" variant="outline" :key="scope.row._id + Math.random()" @click="remove(scope.row._id)">
<i class="far fa-trash-alt"></i>
</CButton>
<CButton color="success" variant="outline" :key="scope.row._id"
:to="{name: 'admin-branch-menu-types-type',params: {type: scope.row._id}}">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
<CCard class="col" v-if="menuTypes.totalDocs>20">
<CRow alignHorizontal="center" style="padding : 10px">
<el-pagination :hide-on-single-page="true" layout="prev, pager, next" :page-size="menuTypes.limit"
@current-change="handleCurrentChange" :current-page.sync="menuTypes.page" :total="menuTypes.totalDocs">
</el-pagination>
</CRow>
</CCard>
</div>
</template>
<script>
export default {
data() {
return {
title: 'لیست انواع منوها',
list_title: 'لیست',
menuTypes: null
}
},
computed: {
pageQuery() {
return this.$route.query.page;
}
},
watch: {
pageQuery(newPage, oldPage) {
this.$nuxt.refresh();
}
},
methods: {
handleCurrentChange(page) {
// if (!_.isEmpty(this.search)) {
// this.handleSearch(page);
// } else {
this.$router.push({
name: "admin-branch-menu-types",
query: {
page: page
}
});
// }
},
remove(id) {
this.$confirm('این مورد حذف شود؟', 'هشدار', {
confirmButtonText: 'بله',
cancelButtonText: 'لغو',
type: 'warning'
}).then(async () => {
this.$axios.delete(`/api/admin/menuType/${id}`)
.then(res => {
this.$message({
type: 'success',
message: 'منو با موفقیت حذف شد'
})
this.menuTypes.docs = this.menuTypes.docs.filter(item => item._id !== id)
})
.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
})
} else console.log(err.response.data)
})
}).catch(() => {
this.$message({
type: 'warning',
message: 'عملیات لغو شد'
})
})
}
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({$axios,query , error, params}) {
try {
const menuTypes = await $axios.get(`/api/admin/menuType/getAll/${params?.branch}?page=${query.page || 1}`)
return {
menuTypes: menuTypes.data
}
} catch (e) {
if (e?.response?.status === 401) {
error({
status: 401,
message: 'شما اجازه دسترسی به این صفحه را ندارید لطفا دوباره وارد شوید'
})
} else {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات بوجود آمده است",
});
}
}
}
}
</script>
+182
View File
@@ -0,0 +1,182 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<!-- <CButton size="sm" color="success" class="mr-auto" @click="addInfo">بروزرسانی</CButton>-->
</CustomSubHeader>
<CCard>
<CCardBody>
<CCol lg="6" sm="12">
<el-switch
style="display: flex; direction: ltr!important; justify-content: right"
v-model="notif.multi"
active-color="#13ce66"
inactive-color="#ff4949"
active-text="ارسال عمومی"
inactive-text="ارسال اختصاصی">
</el-switch>
<!-- <el-checkbox v-model="notif.multi" label="ارسال عمومی"/>-->
</CCol>
<CCol class="mt-4" v-if="!notif.multi" lg="6" sm="12">
<el-select
v-model="notif.user_id"
filterable
style="width: 300px;margin-top: 20px;margin-bottom: 10px;">
<el-option
v-for="item in users"
:key="item._id"
:value="item._id"
:label="item.business_code + ' ' + '(' + item.first_name + ' ' + item.last_name + ')'"/>
</el-select>
</CCol>
<CCol class="mt-4" sm="12" lg="6">
<CInput
:class="validation.title ? 'err' : null"
label="عنوان"
:description="validation.title ? validation.title.msg : null"
v-model="notif.title"
/>
</CCol>
<CCol class="mt-4" sm="12" lg="6">
<CTextarea
:class="validation.body ? 'err' : null"
label="متن پیام"
:description="validation.body ? validation.body.msg : null"
v-model="notif.body"
/>
</CCol>
<CCol class="mt-4" sm="12" lg="6">
<el-button type="success" @click="sendNotification">ارسال</el-button>
</CCol>
</CCardBody>
</CCard>
</div>
</template>
<script>
import moment from 'moment-jalaali'
export default {
data() {
return {
title: 'ارسال نوتیفیکیشن',
list_title: 'لیست',
// base data
notif: {
multi: true,
user_id: '',
title: '',
body: '',
},
users: null,
// validation
validation: {}
}
},
methods: {
sendNotification() {
this.validation = {}
this.$axios.post('/api/admin/notification', this.notif)
.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);
});
},
jDate(date) {
return moment(date, 'X').format('jYYYY/jMM/jDD')
}
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({$axios, error , params}) {
try {
const users = await $axios.get(`/api/admin/users/getAll/${params?.branch}`)
return {
users: users.data,
}
} 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">
.el-button:focus {
outline-color: #39f !important;
}
#map {
width: 100vh;
height: 50vh;
}
.holder-logo {
left: 0;
}
.mapboxgl-ctrl-attrib-button {
display: none;
}
</style>
+775
View File
@@ -0,0 +1,775 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="primary" class="mr-auto" :to="{name: 'admin-branch-orders'}">برگشت به صفحه قبل</CButton>
<CButton size="sm" color="danger" class="mr-1" @click="remove">حذف</CButton>
</CustomSubHeader>
<CRow>
<CCol>
<CCard>
<CCardHeader>
<span><b><i class="fal fa-info-circle"></i></b></span>
<span><b>اطلاعات</b></span>
</CCardHeader>
<CCardBody>
<CForm>
<CRow>
<el-card class="box-card">
<CCol class="m-2" sm="12">
<span>شماره سفارش:</span>
<span>{{ order.number }}</span>
</CCol>
<CCol class="m-2" sm="12">
<span>تاریخ ایجاد:</span>
<span>{{ jDate(order.createdOn) }}</span>
</CCol>
<CCol class="m-2" sm="12">
<span>توضیحات سفارش:</span>
<span>{{ order.description }}</span>
</CCol>
<CCol class="m-2" sm="12">
<span>مشتری:</span>
<nuxt-link :to="{name : 'admin-branch-customers-profile' , params : {profile : order.user_id._id}}">
{{ order.user_id.first_name + ' ' + order.user_id.last_name }}
</nuxt-link>
</CCol>
<CCol class="m-2" sm="12">
<span>وضعیت سفارش:</span>
<span>
<b>
<el-tag
size="medium"
:type="showOrderStatus(order.status).type "
effect="dark">
<span>{{ showOrderStatus(order.status).message }}</span>
</el-tag>
</b>
</span>
<el-button type="info" size="medium" class="mr-1" @click="openChangeStatus(order.status)">تغییر وضعیت</el-button>
</CCol>
</el-card>
</CRow>
<CRow>
<el-card class="box-card mt-4">
<CCol v-if="order.orderType === 'online'" class="m-2" sm="12">
<span>مجموع:</span>
<span>{{ order.sum.toLocaleString() + ' ریال' }}</span>
</CCol>
<CCol v-if="order.orderType === 'online'" class="m-2" sm="12">
<span>هزینه ارسال:</span>
<span>{{ order.routePrice.toLocaleString() + ' ریال' }}</span>
</CCol>
<CCol v-if="order.orderType === 'online'" class="m-2" sm="12">
<span>مالیات:</span>
<span>{{ order.tax.toLocaleString() + ' ریال' }}</span>
</CCol>
<CCol v-if="order.orderType === 'online'" class="m-2" sm="12">
<span>تخفیف:</span>
<span>{{ order.percent.toLocaleString() + ' ریال' }}</span>
</CCol>
<CCol class="m-2" sm="12" v-if="order.discount_code">
<span>کد تخفیف:</span>
<span>{{ order.discount_code }}</span>
</CCol>
<CCol class="m-2" sm="12" v-if="order.discount_code">
<span>درصد تخفیف:</span>
<span>{{ order.discount_amount }}</span>
</CCol>
<CCol class="m-2" sm="12">
<span>جمع کل:</span>
<span v-if="order.orderType === 'online'">{{ order.total.toLocaleString() + ' ریال' }}</span>
<span v-else>{{ order.total + ' امتیاز' }}</span>
</CCol>
</el-card>
</CRow>
<CRow>
<el-card class="box-card mt-4">
<CCol class="m-2" v-if="order.payment.length">
<CCardHeader>
<!-- <span><b><i class="fal fal fa-utensils"></i></b></span>-->
<span><b>لیست تراکنشات</b></span>
</CCardHeader>
<CCardBody>
<el-table
:data="order.payment"
style="width: 100%">
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
label="شناسه تراکنش"
width="350"
prop="transactionId"/>
<el-table-column
label="شماره پیگیری"
width=""
prop="refId"/>
<el-table-column
label="نوع تراکنش"
width="">
<template slot-scope="scope">
<el-tag
type="success"
effect="dark">
<span>{{
scope.row.action === 'increaseBag' ? 'افزایش کیف پول' : scope.row.action === 'decreaseBag' ? 'کاهش کیف پول' : 'پرداخت اینترنتی'
}}
</span>
</el-tag>
</template>
</el-table-column>
<el-table-column
label="وضعیت پرداخت"
width="">
<template slot-scope="scope">
<el-tag
:type="scope.row.status === 'paid' ? 'success' : 'danger' "
effect="dark">
<span>{{ scope.row.status === 'paid' ? 'پرداخت موفق' : 'پرداخت ناموفق' }}</span>
</el-tag>
</template>
</el-table-column>
<el-table-column
label="مبلغ"
width="">
<template slot-scope="scope">
{{ scope.row.cost.toLocaleString() + ' ریال' }}
</template>
</el-table-column>
<el-table-column
label="تاریخ و ساعت"
width="">
<template slot-scope="scope">
{{ jDate(scope.row.created_at) }}
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCol>
<CCol class="m-2" v-if="scoreLogs.length">
<CCardHeader>
<!-- <span><b><i class="fal fal fa-utensils"></i></b></span>-->
<span><b>لیست امتیازات استفاده شده</b></span>
</CCardHeader>
<CCardBody>
<el-table
:data="scoreLogs"
style="width: 100%">
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
label="نوع"
width="">
کاهش
</el-table-column>
<el-table-column
label="وضعیت پرداخت"
width="">
<template slot-scope="scope">
<el-tag
type="success"
effect="dark">
<span>پرداخت موفق</span>
</el-tag>
</template>
</el-table-column>
<el-table-column
label="امتیاز"
width=""
prop="score"/>
<!-- <el-table-column-->
<!-- label="مبلغ به ازای امتیاز"-->
<!-- width="">-->
<!-- <template slot-scope="scope">-->
<!-- {{ (scope.row.score*pointPrice).toLocaleString() + ' ریال' }}-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column
label="تاریخ و ساعت"
width="">
<template slot-scope="scope">
{{ jDate(scope.row.created_at) }}
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCol>
<!-- <CCol class="m-2" sm="12" v-if="order.bag">-->
<!-- <span>مقدار پرداخت شده از کیف پول:</span>-->
<!-- <span>{{ order.discount_amount }}</span>-->
<!-- </CCol>-->
<!-- <CCol class="m-2" sm="12" v-if="order.payment">-->
<!-- <span>شماره پیگیری:</span>-->
<!-- <span v-if="order.payment.length">{{ order.payment[0].refId }}</span>-->
<!-- </CCol>-->
<CCol class="m-2" sm="12">
<span>وضعیت پرداخت:</span>
<span>
<b>
<el-tag
size="medium"
:type="showPaymentStatus(order.paymentStatus).type"
effect="dark">
<span>{{ showPaymentStatus(order.paymentStatus).message }}</span>
</el-tag>
</b>
</span>
<!-- <el-button type="info" size="medium" class="mr-1" @click="openChangePayStatus(order.paymentStatus)">تغییر وضعیت</el-button>-->
</CCol>
</el-card>
</CRow>
</CForm>
</CCardBody>
</CCard>
<CCard>
<CCardHeader>
<span><b><i class="fal fa-map-marker-alt"></i></b></span>
<span><b>آدرس</b></span>
</CCardHeader>
<CCardBody>
<CForm>
<CRow v-if="order.address">
<el-card class="box-card">
<CCol class="m-2" sm="12">
<span>عنوان:</span>
<span>{{ order.address.title }}</span>
</CCol>
<CCol class="m-2" sm="12">
<span>استان:</span>
<span>{{ order.address.province }}</span>
</CCol>
<CCol class="m-2" sm="12">
<span>شهر:</span>
<span>{{ order.address.city }}</span>
</CCol>
<CCol class="m-2" sm="12">
<span>آدرس:</span>
<span>{{ order.address.address }}</span>
</CCol>
</el-card>
<el-card class="box-card mt-4 text-center">
<template>
<no-ssr>
<mapir class="d-inline-flex" id="map" :min-zoom="12" :max-zoom="18" :zoom="15" logo-position="top-left" :center="order.address.location.coordinates || center" :apiKey="apiKey">
<mapNavigationControl position="top-right"/>
<mapMarker
:coordinates.sync="order.address.location.coordinates || center"
color="red"
:draggable="false"
/>
</mapir>
</no-ssr>
</template>
</el-card>
</CRow>
</CForm>
</CCardBody>
</CCard>
<CCard>
<CCardHeader>
<span><b><i class="fal fal fa-utensils"></i></b></span>
<span><b>سفارشات</b></span>
</CCardHeader>
<CCardBody>
<el-table
:data="order.order_items"
style="width: 100%">
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
label="عکس"
width="">
<template slot-scope="scope">
<img v-if="scope.row.product_id" :src="scope.row.product_id.image" alt="" style="width: 100px;">
<i v-else class="fal fa-image-polaroid" style="font-size: 115px;"></i>
</template>
</el-table-column>
<el-table-column
label="نام"
width="">
<template slot-scope="scope">
<span v-if="scope.row.product_id">{{ scope.row.product_id.name }}</span>
</template>
</el-table-column>
<el-table-column
:label="order.orderType === 'club' ? 'امتیاز' : 'قیمت'"
width="">
<template slot-scope="scope">
<span v-if="order.orderType === 'club'">
<span v-if="scope.row.point">{{ scope.row.point + ' امتیاز ' }}</span>
<span v-else class="text-danger">-</span>
</span>
<span v-else>
<span v-if="scope.row.price">{{ scope.row.price.toLocaleString() + ' ريال ' }}</span>
<span v-else class="text-danger">-</span>
</span>
</template>
</el-table-column>
<el-table-column
v-if="order.orderType === 'online'"
label="قیمت با تخفیف"
width="">
<template slot-scope="scope">
<span v-if="scope.row.static_discount">{{ (scope.row.price - (scope.row.price / 100) * scope.row.static_discount).toLocaleString() + ' ريال ' }}</span>
<span v-else class="text-danger">{{ scope.row.price.toLocaleString() + ' ريال ' }}</span>
</template>
</el-table-column>
<el-table-column
v-if="order.orderType === 'online'"
label="درصد تخفیف"
width="">
<template slot-scope="scope">
<span v-if="scope.row.static_discount" class="text-success">{{ scope.row.static_discount + '%' }}</span>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column
label="تعداد"
width="">
<template slot-scope="scope">
<span v-if="scope.row.quantity" class="text-success">{{ scope.row.quantity }}</span>
</template>
</el-table-column>
<el-table-column
v-if="order.orderType === 'online'"
label="جمع بدون تخفیف"
width="">
<template slot-scope="scope">
<span v-if="scope.row.quantity" class="text-success">{{ (scope.row.price * scope.row.quantity).toLocaleString() + ' ریال' }}</span>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column
v-if="order.orderType === 'online'"
label="جمع با تخفیف"
width="">
<template slot-scope="scope">
<span v-if="scope.row.quantity" class="text-success">
{{ ((scope.row.price - (scope.row.price / 100) * scope.row.static_discount) * scope.row.quantity).toLocaleString() + ' ریال' }}</span>
<span v-else>-</span>
</template>
</el-table-column>
<!-- <el-table-column-->
<!-- label="مشتری"-->
<!-- width="">-->
<!-- <template slot-scope="scope">-->
<!-- <nuxt-link v-if="scope.row.user_id" :to="{name: 'admin-customers-profile',params: {profile: scope.row.user_id._id}}">{{ scope.row.user_id.first_name + ' ' + scope.row.user_id.last_name }}</nuxt-link>-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- <el-table-column-->
<!-- label="جمع کل"-->
<!-- width="">-->
<!-- <template slot-scope="scope">-->
<!-- <span>{{ scope.row.total.toLocaleString() + ' ریال' }}</span>-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- <el-table-column-->
<!-- label="وضعیت سفارش"-->
<!-- width="">-->
<!-- <template slot-scope="scope" :v-html="showOrderStatus(scope.row.status)">-->
<!-- <el-tag-->
<!-- :type="showOrderStatus(scope.row.status).type"-->
<!-- effect="dark">-->
<!-- <span>{{ showOrderStatus(scope.row.status).message }}</span>-->
<!-- </el-tag>-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- <el-table-column-->
<!-- label="وضعیت پرداخت"-->
<!-- width="">-->
<!-- <template slot-scope="scope">-->
<!-- <el-tag-->
<!-- :type="showPaymentStatus(scope.row.paymentStatus).type"-->
<!-- effect="dark">-->
<!-- <span>{{ showPaymentStatus(scope.row.paymentStatus).message }}</span>-->
<!-- </el-tag>-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- <el-table-column-->
<!-- label="مشاهده"-->
<!-- width="110"-->
<!-- align="center">-->
<!-- <template slot-scope="scope">-->
<!-- <CButton color="success" variant="outline" :key="scope.row._id" :to="{name: 'admin-orders-order',params: {order: scope.row._id}}">-->
<!-- <i class="far fa-eye"></i>-->
<!-- </CButton>-->
<!-- </template>-->
<!-- </el-table-column>-->
</el-table>
</CCardBody>
</CCard>
</CCol>
</CRow>
<el-dialog
title="تغییر وضعیت سفارش"
:visible.sync="dialogVisible"
width="50%">
<el-select v-model="status" placeholder="">
<el-option
v-for="item in allStatus"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
<el-button type="success" class="mr-1" @click="updateStatus">ارسال</el-button>
</el-dialog>
<el-dialog
title="تغییر وضعیت پرداخت"
:visible.sync="dialogVisiblePay"
width="50%">
<el-select v-model="statusPay" placeholder="">
<el-option
v-for="item in allStatusPay"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
<el-button type="success" class="mr-1" @click="updatePaymentStatus">ارسال</el-button>
</el-dialog>
</div>
</template>
<script>
import axiosUploadProcess from "@/mixins/axiosUploadProcess"
import moment from "moment-jalaali"
let mapirVue = {}
if (process.client)
mapirVue = require('mapir-vue')
export default {
components: {
'mapir': mapirVue.mapir,
'mapMarker': mapirVue.mapMarker,
'mapNavigationControl': mapirVue.mapNavigationControl,
'mapGeolocateControl': mapirVue.mapGeolocateControl,
},
data() {
return {
apiKey: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImRiYjIwMmRhYzAxYzFjNzgwYjgxNWQyZDgyMWNmNmY1Njk0MThhMGE3N2Q1M2Y0OTZkYzQzYTgxMmNmN2U3ZWJjNzI5MjY5YjkxMjA4MTYyIn0.eyJhdWQiOiIxNDk3OSIsImp0aSI6ImRiYjIwMmRhYzAxYzFjNzgwYjgxNWQyZDgyMWNmNmY1Njk0MThhMGE3N2Q1M2Y0OTZkYzQzYTgxMmNmN2U3ZWJjNzI5MjY5YjkxMjA4MTYyIiwiaWF0IjoxNjI3MzI2Mzc0LCJuYmYiOjE2MjczMjYzNzQsImV4cCI6MTYyOTkxODM3NCwic3ViIjoiIiwic2NvcGVzIjpbImJhc2ljIl19.hyKNSy4fmPps6yIdm33Wof-mES9ujh5lmI3VFWyecbkNCm9ATPwsZ9s53A3a1wPJmHfLBXpCcob5NGL-GjZlVfqfRBiReRMr_iniCjUOnqENfFwVEJutxI-xrzVe7PZzOgx1Vr6WwSUHvQ36eJSS1lBlHlqCgwRbkG0hs4YdZsKhzhfYdlAluNw9djjUAMbRWZVL0EluP9CYko4w8tB0KHUZMZYGQcevCfb_3OU9ygHo7B--Z5aTPfm7IK4eP0gHsZ_t857B3tu3ZJB1mkgxc2R9gZUflKqj1ZqkYiR0uMGP-571enXh6pYQLXL2k-gOxLIedCaE6XytxVXhENnotA',
order: null,
status: '',
statusPay: '',
pointPrice : 800,
center: [49.6848857, 34.0821617],
validation: {},
dialogVisible: false,
dialogVisiblePay: false,
allStatus: [
{
label: 'لغو شده',
value: 'canceled'
},
{
label: 'در حال آماده سازی',
value: 'processing'
},
// {
// label: 'ارسال شده',
// value: 'sent'
// },
{
label: 'تحویل داده شده',
value: 'delivered'
}
],
allStatusPay: [
{
label: 'بازگشت مبلغ',
value: 'refund'
},
{
label: 'پرداخت شده',
value: 'paid'
},
{
label: 'پرداخت نشده',
value: 'unpaid'
}
]
}
},
mixins: [axiosUploadProcess],
computed: {
title() {
return 'مشاهده سفارش'
},
scoreLogs() {
return this.order.user_id.scoreLogs.filter(item => item?.order_id === this.order._id && item.forWhat === 'buy' && item.action === 'decrease')
}
},
methods: {
openChangeStatus(status) {
this.status = status
this.dialogVisible = true
},
openChangePayStatus(status) {
this.statusPay = status
this.dialogVisiblePay = true
},
showPaymentStatus(status) {
switch (status) {
case 'unpaid':
return {
type: 'danger',
message: 'پرداخت نشده'
}
case 'paid':
return {
type: 'success',
message: 'پرداخت شده'
}
case 'refund':
return {
type: 'warning',
message: 'برگشت خورده'
}
default :
return {
type: 'info',
message: 'وضعیت نا مشخص'
}
}
},
showOrderStatus(status) {
switch (status) {
case 'canceled':
return {
type: 'danger',
message: 'لغو شده'
}
case 'processing':
return {
type: 'primary',
message: 'در حال آماده سازی'
}
case 'sent':
return {
type: 'warning',
message: 'ارسال شده'
}
case 'delivered':
return {
type: 'success',
message: 'تحویل داده شده'
}
default :
return {
type: 'info',
message: 'وضعیت نا مشخص'
}
}
},
jDate(date) {
return moment(date).format('jYYYY/jMM/jDD HH:mm')
},
updateStatus() {
this.validation = {}
const data = new FormData()
data.append('status', this.status)
this.$axios.put(`/api/admin/order/${this.order._id}`, data, this.axiosConfig)
.then(response => {
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 === 422) {
this.validation = err.response.data.validation
this.$message({
type: 'error',
message: 'اطلاعات رو بررسی و دوباره تلاش کنید'
})
} else {
this.$alert(err.response.data.error.message, 'خطا', {
confirmButtonText: 'باشه'
})
}
})
},
updatePaymentStatus() {
this.validation = {}
const data = new FormData()
data.append('status', this.statusPay)
this.$axios.put(`/api/admin/payments/${this.order._id}`, data, this.axiosConfig)
.then(response => {
this.dialogVisiblePay = 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 === 422) {
this.validation = err.response.data.validation
this.$message({
type: 'error',
message: 'اطلاعات رو بررسی و دوباره تلاش کنید'
})
} else {
this.$message({
type: 'error',
message: err.response.data.message
})
}
})
},
remove() {
this.$confirm('این مورد حذف شود؟', 'هشدار', {
confirmButtonText: 'بله',
cancelButtonText: 'لغو',
type: 'warning'
}).then(async () => {
this.$axios.delete(`/api/admin/order/${this.order._id}`)
.then(res => {
this.$message({
type: 'success',
message: 'سفارش با موفقیت حذف شد'
})
this.$router.push({
name: "admin-branch-orders"
});
})
.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
})
} else console.log(err.response.data)
})
}).catch(() => {
this.$message({
type: 'warning',
message: 'عملیات لغو شد'
})
})
}
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({$axios, params, error}) {
try {
const order = await $axios.get(`/api/admin/order/${params.order}`)
return {
order: order.data
}
} 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">
#map {
width: 100vh;
height: 50vh;
}
.holder-logo {
left: 0;
}
.mapboxgl-ctrl-attrib-button {
display: none;
}
.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>
+423
View File
@@ -0,0 +1,423 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
</CustomSubHeader>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-filter"></i>
<span style="color:#000">فیلتر</span>
</slot>
</CCardHeader>
<CCardBody>
<CRow>
<CCol md="6">
<CRow style="flex-direction : column;">
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>شماره سفارش</span>
</CCol>
<CCol col="md-9">
<el-input style="width : 100%" placeholder="" v-model="search.number"></el-input>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>مشتری</span>
</CCol>
<CCol col="md-9">
<el-select filterable clearable style="width : 100%" v-model="search.userId"
placeholder="انتخاب مشتری">
<el-option
v-for="item in users"
:key="item._id"
:value="item._id"
:label="item.business_code + ' ' + '(' + item.first_name + ' ' + item.last_name + ')'"/>
</el-select>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>تاریخ</span>
</CCol>
<CCol col="md-9">
<date-picker range clearable format="YYYY-MM-DD" display-format="jMMMM jD"
v-model="search.date"></date-picker>
</CCol>
</CRow>
</CCol>
</CRow>
</CCol>
<CCol md="6">
<CRow style="flex-direction : column;">
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>وضعیت سفارش</span>
</CCol>
<CCol col="md-9">
<el-select v-model="search.orderStatus" clearable style="width : 100%">
<el-option v-for="item in allStatus" :key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>وضعیت پرداخت</span>
</CCol>
<CCol col="md-9">
<el-select v-model="search.paymentStatus" clearable style="width : 100%">
<el-option :key="1" label="پرداخت شده" value="paid">
</el-option>
<el-option :key="2" label="پرداخت نشده" value="unpaid">
</el-option>
<el-option :key="3" label="برگشت خورده" value="refund">
</el-option>
</el-select>
</CCol>
</CRow>
</CCol>
</CRow>
</CCol>
</CRow>
<CRow>
<el-button :loading="loading" @click="handleSearch" size="small"
style="width: auto;margin: 25px auto auto auto;" type="primary"
icon="el-icon-search">
جست و جو
</el-button>
</CRow>
</CCardBody>
</CCard>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>{{ list_title }}</span>
</slot>
</CCardHeader>
<CCardBody>
<el-table
v-loading="loading"
:data="orders.docs"
style="width: 100%">
<el-table-column
type="index"
label="#">
</el-table-column>
<!-- <el-table-column-->
<!-- label="شماره سفارش"-->
<!-- prop="number"-->
<!-- width="">-->
<!-- </el-table-column>-->
<el-table-column
label="مشتری"
min-width="150">
<template slot-scope="scope">
<nuxt-link v-if="scope.row.user_id"
:to="{name: 'admin-branch-customers-profile',params: {profile: scope.row.user_id._id}}">{{
scope.row.user_id.first_name + ' ' + scope.row.user_id.last_name }}
</nuxt-link>
</template>
</el-table-column>
<el-table-column
label="امتیاز"
min-width="70">
<template slot-scope="scope">
<span>{{ scope.row.scorePoint.toLocaleString() }}</span>
<!-- <span>{{ scope.row.orderType === 'club' ? ' امتیاز' : ' ریال'}}</span>-->
</template>
</el-table-column>
<el-table-column
label="ارزش امتیاز"
min-width="110">
<template slot-scope="scope">
<span>{{ scope.row.scoreCost.toLocaleString() + ' ریال'}}</span>
<!-- <span>{{ scope.row.orderType === 'club' ? ' امتیاز' : ' ریال'}}</span>-->
</template>
</el-table-column>
<el-table-column
label="کیف پول"
width="">
<template slot-scope="scope">
<span>{{ scope.row.bagCost.toLocaleString() + ' ریال' }}</span>
<!-- <span>{{ scope.row.orderType === 'club' ? ' امتیاز' : ' ریال'}}</span>-->
</template>
</el-table-column>
<el-table-column
label="پرداخت آنلاین"
min-width="115">
<template slot-scope="scope">
<span v-if="scope.row.payTotal">{{ scope.row.payTotal.toLocaleString() + ' ریال' }}</span>
<span v-else>0 ریال</span>
</template>
</el-table-column>
<el-table-column
label="جمع کل"
min-width="115">
<template slot-scope="scope">
<el-popover trigger="hover" placement="top">
<span>{{ scope.row.total.toLocaleString() }}</span>
<span>{{ scope.row.orderType === 'club' ? ' امتیاز' : ' ریال' }}</span>
<div slot="reference" class="name-wrapper">
<span>{{ scope.row.total.toLocaleString() }}</span>
<span>{{ scope.row.orderType === 'club' ? ' امتیاز' : ' ریال' }}</span>
</div>
</el-popover>
</template>
</el-table-column>
<el-table-column
label="وضعیت سفارش"
min-width="120">
<template slot-scope="scope" :v-html="showOrderStatus(scope.row.status)">
<el-tag
:type="showOrderStatus(scope.row.status).type"
effect="dark">
<span>{{ showOrderStatus(scope.row.status).message }}</span>
</el-tag>
</template>
</el-table-column>
<!-- <el-table-column-->
<!-- label="وضعیت پرداخت"-->
<!-- width="">-->
<!-- <template slot-scope="scope">-->
<!-- <el-tag-->
<!-- :type="showPaymentStatus(scope.row.paymentStatus).type"-->
<!-- effect="dark">-->
<!-- <span>{{ showPaymentStatus(scope.row.paymentStatus).message }}</span>-->
<!-- </el-tag>-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column
label="تاریخ"
min-width="150">
<template slot-scope="scope">
<el-popover trigger="hover" placement="top">
<p>{{ jDate(scope.row.createdOn) }}</p>
<div slot="reference" class="name-wrapper">
{{ jDate(scope.row.createdOn) }}
</div>
</el-popover>
</template>
</el-table-column>
<el-table-column
label="مشاهده"
width="110"
align="center">
<template slot-scope="scope">
<CButton color="success" variant="outline" :key="scope.row._id"
:to="{name: 'admin-branch-orders-order',params: {order: scope.row._id}}">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
<CCard class="col" v-if="orders.totalDocs>20">
<CRow alignHorizontal="center" style="padding : 10px">
<el-pagination :hide-on-single-page="true" layout="prev, pager, next" :page-size="orders.limit"
@current-change="handleCurrentChange" :current-page.sync="orders.page" :total="orders.totalDocs">
</el-pagination>
</CRow>
</CCard>
</div>
</template>
<script>
import moment from "moment-jalaali";
const _ = require('lodash');
export default {
data() {
return {
title: 'لیست سفارشات',
list_title: 'لیست',
orders: null,
search: {},
users: null,
loading: false,
allStatus: [
{
label: 'لغو شده',
value: 'canceled'
},
{
label: 'در حال آماده سازی',
value: 'processing'
},
{
label: 'ارسال شده',
value: 'sent'
},
{
label: 'تحویل داده شده',
value: 'delivered'
}
]
}
},
computed: {
pageQuery() {
return this.$route.query.page;
}
},
watch: {
pageQuery(newPage, oldPage) {
this.$nuxt.refresh();
}
},
methods: {
jDate(date) {
return moment(date).format('jYYYY/jMM/jDD HH:mm')
},
showPaymentStatus(status) {
switch (status) {
case 'unpaid':
return {
type: 'danger',
message: 'پرداخت نشده'
}
case 'paid':
return {
type: 'success',
message: 'پرداخت شده'
}
case 'refund':
return {
type: 'warning',
message: 'برگشت خورده'
}
default :
return {
type: 'info',
message: 'وضعیت نا مشخص'
}
}
},
showOrderStatus(status) {
switch (status) {
case 'canceled':
return {
type: 'danger',
message: 'لغو شده'
}
case 'processing':
return {
type: 'primary',
message: 'در حال آماده سازی'
}
case 'sent':
return {
type: 'warning',
message: 'ارسال شده'
}
case 'delivered':
return {
type: 'success',
message: 'تحویل داده شده'
}
default :
return {
type: 'info',
message: 'وضعیت نا مشخص'
}
}
},
handleCurrentChange(page) {
if (!_.isEmpty(this.search)) {
this.handleSearch(page);
} else {
this.$router.push({
name: "admin-branch-orders",
query: {
page: page
}
});
}
},
handleSearch(page) {
this.loading = true;
const data = {
branchId: this.$route?.params?.branch,
number: this.search.number,
userId: this.search.userId,
orderStatus: this.search.orderStatus,
paymentStatus: this.search.paymentStatus,
date: this.search.date,
}
this.$axios.post(`/api/admin/order/search?page=${page}`, data, this.axiosConfig)
.then((result) => {
this.orders = result.data;
this.loading = false;
})
.catch(err => {
this.loading = false;
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, query, error , params}) {
try {
const order = await $axios.get(`/api/admin/order/getAll/${params?.branch}?page=${query.page || 1}`)
const users = await $axios.get(`/api/admin/users/getAll/${params?.branch}`)
return {
orders: order.data,
users: users.data
}
} catch (e) {
if (e?.response?.status === 401) {
error({
status: 401,
message: 'شما اجازه دسترسی به این صفحه را ندارید لطفا دوباره وارد شوید'
})
} else {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات بوجود آمده است",
});
}
}
}
}
</script>
+213
View File
@@ -0,0 +1,213 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="primary" class="mr-auto" :to="{name: 'admin-branch-party-sets'}">برگشت به صفحه قبل</CButton>
<CButton v-if="$route.params.set === '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">
<CInput
:class="validation.title ? 'err' : null"
label="عنوان"
:description="validation.title ? validation.title.msg : null"
v-model="partySet.title"
/>
</CCol>
<CCol sm="12">
<CInput
:class="validation.description ? 'err' : null"
label="توضیحات"
:description="validation.description ? validation.description.msg : null"
v-model="partySet.description"
/>
</CCol>
<CCol sm="12">
<CInput
:class="validation.price ? 'err' : null"
label="قیمت (ريال)"
:description="validation.price ? validation.price.msg : null"
v-model="partySet.price"
/>
</CCol>
<CCol s="12">
<span>ترتیب نمایش در منو</span>
</CCol>
<CCol sm="12" class="err">
<el-select v-model="partySet.index" filterable style="width: 100%;margin-top: 5px;">
<el-option
v-for="item in 1000"
v-if="!partySets.filter(item2=>Number(item2.index) === item).length"
: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>
<CCol sm="12" class="mt-3">
<el-checkbox v-model="partySet.active">منو برای مشتریان نمایش داده شود</el-checkbox>
</CCol>
</CRow>
</CForm>
</CCardBody>
</CCard>
</CCol>
<CCol lg="6">
<CCard>
<CCardBody>
<h3>تصویر: (اختیاری)</h3>
<el-divider></el-divider>
<img :src="partySet.image" alt="" style="width: 100%;max-width: 300px;display: block">
<input type="file" ref="image" @change="imagePreview">
</CCardBody>
</CCard>
</CCol>
</CRow>
</div>
</template>
<script>
import axiosUploadProcess from "@/mixins/axiosUploadProcess"
export default {
data() {
return {
partySets: null,
partySet: null,
validation: {}
}
},
mixins: [axiosUploadProcess],
computed: {
title() {
return this.$route.params.food === 'new' ? 'افزودن منوی ویژه مهمانی' : 'مشاهده منوی ویژه'
}
},
methods: {
imagePreview(e) {
this.partySet.image = URL.createObjectURL(e.target.files[0])
},
post() {
this.validation = {}
const data = new FormData()
data.append('title', this.partySet.title)
data.append('description', this.partySet.description)
data.append('active', this.partySet.active)
data.append('price', this.partySet.price)
data.append('index', this.partySet.index)
if (this.$refs.image.files[0]) data.append('image', this.$refs.image.files[0])
this.$axios.post(`/api/admin/partySet`, data, this.axiosConfig)
.then(response => {
this.$message({
type: 'success',
message: 'منوی ویژه با موفقیت ایجاد شد.'
})
this.$router.push({name: 'admin-branch-party-sets'})
})
.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('title', this.partySet.title)
data.append('description', this.partySet.description)
data.append('active', this.partySet.active)
data.append('price', this.partySet.price)
data.append('index', this.partySet.index)
if (this.$refs.image.files[0]) data.append('image', this.$refs.image.files[0])
this.$axios.put(`/api/admin/partySet/${this.partySet._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 partySets = await $axios.get(`/api/public/partySets`)
if (params.set !== 'new') {
const partySet = await $axios.get(`/api/public/partySet/${params.set}`)
return {
partySets: partySets.data,
partySet: partySet.data
}
} else {
return {
partySets: partySets.data,
partySet: {
title: '',
description: '',
price: 0,
active: true,
image: '',
index: 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>
+181
View File
@@ -0,0 +1,181 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="success" :to="{name: 'admin-branch-party-sets-set',params:{set: 'new'}}" class="mr-auto">
افزودن</CButton>
</CustomSubHeader>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>{{ list_title }}</span>
</slot>
</CCardHeader>
<CCardBody>
<el-table
:data="partySets.docs"
style="width: 100%">
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
label="عکس"
width="">
<template slot-scope="scope">
<img v-if="scope.row.image" :src="scope.row.image" alt="" style="width: 100px;">
<i v-else class="fal fa-image-polaroid" style="font-size: 115px;"></i>
</template>
</el-table-column>
<el-table-column
prop="title"
label="عنوان"
width="">
</el-table-column>
<el-table-column
label="قیمت"
width="">
<template slot-scope="scope">
<span v-if="scope.row.price">{{ scope.row.price.toLocaleString() + ' ريال ' }}</span>
<span v-else class="text-danger">بدون قیمت</span>
</template>
</el-table-column>
<el-table-column
label="وضعیت"
width="">
<template slot-scope="scope">
<span class="text-success" v-if="scope.row.active">فعال</span>
<span class="text-danger" v-else>غیر فعال</span>
</template>
</el-table-column>
<el-table-column
label="ویرایش"
width="110"
align="center">
<template slot-scope="scope">
<CButton color="danger" variant="outline" :key="scope.row._id + Math.random()" @click="remove(scope.row._id)">
<i class="far fa-trash-alt"></i>
</CButton>
<CButton color="success" variant="outline" :key="scope.row._id"
:to="{name: 'admin-branch-party-sets-set',params: {set: scope.row._id}}">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
<CCard class="col" v-if="partySets.totalDocs>20">
<CRow alignHorizontal="center" style="padding : 10px">
<el-pagination :hide-on-single-page="true" layout="prev, pager, next" :page-size="partySets.limit"
@current-change="handleCurrentChange" :current-page.sync="partySets.page" :total="partySets.totalDocs">
</el-pagination>
</CRow>
</CCard>
</div>
</template>
<script>
export default {
data() {
return {
title: 'لیست منوهای ویژه مهمانی',
list_title: 'لیست',
partySets: null
}
},
computed: {
pageQuery() {
return this.$route.query.page;
}
},
watch: {
pageQuery(newPage, oldPage) {
this.$nuxt.refresh();
}
},
methods: {
handleCurrentChange(page) {
// if (!_.isEmpty(this.search)) {
// this.handleSearch(page);
// } else {
this.$router.push({
name: "admin-branch-party-sets",
query: {
page: page
}
});
// }
},
remove(id) {
this.$confirm('این مورد حذف شود؟', 'هشدار', {
confirmButtonText: 'بله',
cancelButtonText: 'لغو',
type: 'warning'
}).then(async () => {
this.$axios.delete(`/api/admin/partySet/${id}`)
.then(res => {
this.$message({
type: 'success',
message: 'منو با موفقیت حذف شد'
})
this.partySets.docs = this.partySets.docs.filter(item => item._id !== id)
})
.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
})
} else console.log(err.response.data)
})
}).catch(() => {
this.$message({
type: 'warning',
message: 'عملیات لغو شد'
})
})
}
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({$axios, query, error}) {
try {
const partySets = await $axios.get(`/api/admin/partySets?page=${query.page || 1}`)
return {
partySets: partySets.data
}
} catch (e) {
if (e?.response?.status === 401) {
error({
status: 401,
message: 'شما اجازه دسترسی به این صفحه را ندارید لطفا دوباره وارد شوید'
})
} else {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات بوجود آمده است",
});
}
}
}
}
</script>
+254
View File
@@ -0,0 +1,254 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
</CustomSubHeader>
<CCard>
<CCardBody>
<CRow>
<CCol sm="6">
<div>از تاریخ:</div>
<div class="mt-3"><date-picker type="datetime" v-model="startDate" clearable format="YYYY-MM-DD HH:mm" display-format="jYYYY-jMM-jDD HH:mm"/></div>
</CCol>
<CCol sm="6">
<div>تا تاریخ:</div>
<div class="mt-3"><date-picker type="datetime" v-model="endDate" clearable format="YYYY-MM-DD HH:mm" display-format="jYYYY-jMM-jDD HH:mm"/></div>
</CCol>
<CCol sm="12" class="text-center mt-4">
<CButton size="sm" color="success" class="mr-1" @click="getReports">گرفتن گزارش</CButton>
</CCol>
</CRow>
<!-- <div class="d-flex justify-content-center align-items-center">-->
<!-- <span>از تاریخ: </span>-->
<!-- <span><date-picker v-model="date" clearable format="YYYY-MM-DD" display-format="jYYYY-jMM-jDD"/></span>-->
<!-- </div>-->
</CCardBody>
</CCard>
<CCard>
<CCardBody>
<CRow>
<CCol col="12" sm="6">
<CCallout color="info">
<small class="text-muted">جمع کل</small><br>
<strong class="h4">{{ reports.total.toLocaleString() + ' ریال' }}</strong>
</CCallout>
</CCol>
<CCol col="12" sm="6">
<CCallout color="danger">
<small class="text-muted">تعداد سفارشات</small><br>
<strong class="h4">{{ reports.count }}</strong>
</CCallout>
</CCol>
</CRow>
</CCardBody>
</CCard>
<!-- <CCard>-->
<!-- <CCardHeader>-->
<!-- <strong>-->
<!-- <span>نمودار تعداد سفارشات</span>-->
<!-- </strong>-->
<!-- </CCardHeader>-->
<!-- <CCardBody>-->
<!-- <canvas id="myChart" width="400" height="400"></canvas>-->
<!-- </CCardBody>-->
<!-- </CCard>-->
<CCard>
<CCardHeader>
<slot name="header">
<span>{{ list_title }}</span>
</slot>
</CCardHeader>
<CCardBody>
<CRow>
<CCol sm="6">
<div class="mt-3">
<span>
<i class="fal fa-money-bill-wave"></i>
جمع کل:
</span>
<span>{{reports.total.toLocaleString() + ' ریال'}}</span>
</div>
<div class="mt-3">
<span>
<i class="fal fa-money-bill-wave"></i>
جمع پرداخت آنلاین:
</span>
<span>{{reports.payOnline.toLocaleString() + ' ریال'}}</span>
</div>
<div class="mt-3">
<span>
<i class="fal fa-money-bill-wave"></i>
جمع هزینه ارسال:
</span>
<span>{{reports.routePrice.toLocaleString() + ' ریال'}}</span>
</div>
</CCol>
<CCol sm="6">
<div class="mt-3">
<span>
<i class="fal fa-money-bill-wave"></i>
جمع کل مبلغ استفاده شده کیف پول:
</span>
<span>{{reports.bagCost.toLocaleString() + ' ریال'}}</span>
</div>
<div class="mt-3">
<span>
<i class="fal fa-money-bill-wave"></i>
جمع امتیاز استفاده شده:
</span>
<span>{{reports.scorePoint}}</span>
</div>
<div class="mt-3">
<span>
<i class="fal fa-money-bill-wave"></i>
جمع ارزش امتیازات استفاده شده:
</span>
<span>{{reports.scoreCost.toLocaleString() + ' ریال'}}</span>
</div>
</CCol>
</CRow>
</CCardBody>
</CCard>
</div>
</template>
<script>
import moment from 'moment-jalaali'
export default {
data() {
return {
title: 'گزارشات',
list_title: 'گزارش',
// base data
reports: null,
startDate : '',
endDate : '',
// validation
validation: {}
}
},
watch: {
},
computed: {
},
methods: {
jDate(date) {
return moment(date, 'X').format('jYYYY/jMM/jDD')
},
getReports(){
this.validation = {}
const data = {
startDate : this.startDate,
endDate :this.endDate
}
this.$axios.$post(`/api/admin/order/report`, data)
.then(response => {
this.reports = response
})
.catch(err => {
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
if (err.response.status === 422) {
this.validation = err.response.data.validation
this.$message({
type: 'error',
message: 'اطلاعات رو بررسی و دوباره تلاش کنید'
})
} else {
this.$message({
type: 'error',
message: err.response.data.message
})
}
})
}
},
head() {
return {
title: this.title
}
},
// async mounted() {
// const counts = {};
// // this.customers.forEach(function (x) { counts[x.job] = (counts[x.job] || 0) + 1; });
// let keys = [1,2,3,4,5,6,7];
// let values = [10,15,4,5,68,15,1];
//
// const CHART_COLORS = {
// red: 'rgb(255, 99, 132)',
// orange: 'rgb(255, 159, 64)',
// yellow: 'rgb(255, 205, 86)',
// green: 'rgb(75, 192, 192)',
// blue: 'rgb(54, 162, 235)',
// purple: 'rgb(153, 102, 255)',
// grey: 'rgb(201, 203, 207)'
// };
//
// const ctx = document.getElementById('myChart');
// const myChart = new Chart(ctx, {
// type: 'line',
// data: {
// labels: keys,
// datasets: [{
// // label: '# of Votes',
// data: values,
// borderColor: 'rgb(54, 162, 235)',
// fill: false,
// borderWidth: 2
// }]
// },
// options: {
// responsive: true,
// legend: {
// position: 'top',
// },
// scales: {
// y: {
// beginAtZero: true
// }
// }
// }
// });
// },
layout: 'admin',
async asyncData({$axios, query, error, params}) {
try {
const reports = await $axios.$post(`/api/admin/order/report/${params?.branch}`)
return {
reports
}
} catch (e) {
if (e?.response?.status === 401) {
error({
status: 401,
message: 'شما اجازه دسترسی به این صفحه را ندارید لطفا دوباره وارد شوید'
})
} else {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات بوجود آمده است",
});
}
}
}
}
</script>
<style lang="scss">
.el-button:focus {
outline-color: #39f !important;
}
</style>
+508
View File
@@ -0,0 +1,508 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="success" class="mr-auto" @click="addInfo">بروزرسانی</CButton>
</CustomSubHeader>
<CRow>
<CCol sm="12">
<CCard>
<CCardBody>
<CCol>
<!-- <h5 style="margin-bottom: 16px"></h5>-->
<CCol sm="12">
<el-checkbox v-model="storeInfo.useSpecialMenu" label="نمایش منو سرآشپز"/>
</CCol>
<CCol class="mt-2" sm="6">
<CInput
v-if="$auth.user.permissions.includes('development')"
:class="validation.updateApp ? 'err' : null"
class="input-direction"
label="ورژن اپلیکیشن"
:description="validation.updateApp ? validation.updateApp.msg : null"
v-model="storeInfo.updateApp"
/>
</CCol>
</CCol>
</CCardBody>
</CCard>
</CCol>
<CCol sm="12">
<CCard>
<CCardBody>
<CCol>
<h5 style="margin-bottom: 16px">پیام مدیر</h5>
<CCol sm="12">
<CInput
:class="validation.message ? 'err' : null"
label="پیام روز"
:description="validation.message ? validation.message.msg : null"
v-model="storeInfo.message"
/>
</CCol>
</CCol>
</CCardBody>
</CCard>
</CCol>
<CCol sm="6">
<CCard>
<CCardBody>
<CCol>
<h5 style="margin-bottom: 16px">اطلاعات عمومی</h5>
<CCol sm="12">
<CTextarea
:class="validation.caption ? 'err' : null"
label="توضیحات"
:description="validation.caption ? validation.caption.msg : null"
v-model="storeInfo.caption"
/>
</CCol>
<CCol sm="12">
<CInput
class="input-direction"
:class="validation.email ? 'err' : null"
label="ایمیل"
:description="validation.email ? validation.email.msg : null"
v-model="storeInfo.email"
/>
</CCol>
<CCol sm="12">
<CInput
class="input-direction"
:class="validation.tel ? 'err' : null"
label="تلفن"
:description="validation.tel ? validation.tel.msg : null"
v-model="storeInfo.tel"
/>
</CCol>
<CCol sm="12">
<CInput
:class="validation.address ? 'err' : null"
label="آدرس"
:description="validation.address ? validation.address.msg : null"
v-model="storeInfo.address"
/>
</CCol>
</CCol>
</CCardBody>
</CCard>
</CCol>
<CCol sm="6">
<CCard>
<CCardBody>
<CCol>
<h5 style="margin-bottom: 16px">شبکه های اجتماعی</h5>
<CCol sm="12">
<CInput
class="input-direction"
:class="validation.socials ? 'err' : null"
label="واتساپ"
:description="validation.socials ? validation.socials.msg : null"
v-model="storeInfo.socials.whatsaap"
/>
</CCol>
<CCol sm="12">
<CInput
class="input-direction"
:class="validation.socials ? 'err' : null"
label="تویتر"
:description="validation.socials ? validation.socials.msg : null"
v-model="storeInfo.socials.twitter"
/>
</CCol>
<CCol sm="12">
<CInput
class="input-direction"
:class="validation.socials ? 'err' : null"
label="فیس بوک"
:description="validation.socials ? validation.socials.msg : null"
v-model="storeInfo.socials.facebook"
/>
</CCol>
<CCol sm="12">
<CInput
:class="validation.socials ? 'err' : null"
class="input-direction"
label="اینستاگرام"
:description="validation.socials ? validation.socials.msg : null"
v-model="storeInfo.socials.instagram"
/>
</CCol>
<CCol sm="12">
<CInput
:class="validation.socials ? 'err' : null"
class="input-direction"
label="گوگل پلاس"
:description="validation.socials ? validation.socials.msg : null"
v-model="storeInfo.socials.googlePlus"
/>
</CCol>
</CCol>
</CCardBody>
</CCard>
</CCol>
</CRow>
<CRow>
<CCard>
<CCardBody>
<h5 style="margin-bottom: 16px">تنظیمات هزینه ارسال و مالیات</h5>
<CCol>
<CCol sm="6">
<el-checkbox v-model="storeInfo.tax" label="گرفتن مالیات از مشتری"/>
</CCol>
<CCol sm="6">
<el-checkbox v-model="storeInfo.shippingType" label="هزینه ارسال ثابت باشد"/>
</CCol>
<CCol sm="6">
<CInput
:class="validation.socials ? 'err' : null"
label="هزینه ارسال به ریال(به ازای هر کیلومتر در صورت ثابت نبودن)"
placeholder=""
:description="validation.shippingCost ? validation.shippingCost.msg : null"
v-model="storeInfo.shippingCost"
/>
</CCol>
<el-divider/>
<CCol sm="6">
<CInput
:class="validation.limitPrice ? 'err' : null"
label="حداقل مبلغ خرید(ریال)"
placeholder=""
:description="validation.limitPrice ? validation.limitPrice.msg : null"
v-model="storeInfo.limitPrice"
/>
</CCol>
</CCol>
</CCardBody>
</CCard>
</CRow>
<CRow>
<CCard>
<CCardBody>
<h5 style="margin-bottom: 16px">تنظیمات امتیازات</h5>
<CCol>
<CRow>
<CCol sm="12">
<el-checkbox class="mb-4" v-model="storeInfo.usePointWhenPay" label="اجازه استفاده از امتیاز هنگام پرداخت"/>
</CCol>
<CCol sm="12" class="mb-3">
<span>به ازای هر</span>
<CInput
type="number"
style="display: inline-block"
:class="validation.totalPricePoint ? 'err' : null"
placeholder="قیمت به ریال وارد شود"
:description="validation.totalPricePoint ? validation.totalPricePoint.msg : null"
v-model="storeInfo.totalPricePoint"
/>
<span><b>ریال</b> خرید مقدار</span>
<CInput
type="number"
style="display: inline-block"
:class="validation.pointForBuy ? 'err' : null"
placeholder=""
:description="validation.pointForBuy ? validation.pointForBuy.msg : null"
v-model="storeInfo.pointForBuy"
/>
<span>امتیاز به مشتری داده شود</span>
</CCol>
<CCol sm="12" class="mb-3">
<span>هر</span>
<CInput
type="number"
style="display: inline-block"
:class="validation.pointForChange ? 'err' : null"
placeholder=""
:description="validation.pointForChange ? validation.pointForChange.msg : null"
v-model="storeInfo.pointForChange"
/>
<span>امتیاز برابر با</span>
<CInput
type="number"
style="display: inline-block"
:class="validation.priceForChange ? 'err' : null"
placeholder=""
:description="validation.priceForChange ? validation.priceForChange.msg : null"
v-model="storeInfo.priceForChange"
/>
<span><b>ریال</b> می باشد</span>
</CCol>
<el-divider/>
<CCol sm="6">
<CInput
:class="validation.userRegistrationScore ? 'err' : null"
label="امتیاز ثبت نام"
placeholder=""
:description="validation.userRegistrationScore ? validation.userRegistrationScore.msg : null"
v-model="storeInfo.userRegistrationScore"
/>
<!-- <CInput-->
<!-- :class="validation.userEmailVerifyScore ? 'err' : null"-->
<!-- label="امتیاز وارد کردن ایمیل"-->
<!-- placeholder=""-->
<!-- :description="validation.userEmailVerifyScore ? validation.userEmailVerifyScore.msg : null"-->
<!-- v-model="storeInfo.userEmailVerifyScore"-->
<!-- />-->
<CInput
:class="validation.pointBirthDate ? 'err' : null"
label="امتیاز تاریخ تولد"
placeholder=""
:description="validation.pointBirthDate ? validation.pointBirthDate.msg : null"
v-model="storeInfo.pointBirthDate"
/>
</CCol>
<CCol sm="6">
<CInput
:class="validation.pointMarriageDate ? 'err' : null"
label="امتیاز تاریخ ازدواج"
placeholder=""
:description="validation.pointMarriageDate ? validation.pointMarriageDate.msg : null"
v-model="storeInfo.pointMarriageDate"
/>
<CInput
:class="validation.invitePoint ? 'err' : null"
label="امتیاز دعوت کردن"
placeholder=""
:description="validation.invitePoint ? validation.invitePoint.msg : null"
v-model="storeInfo.invitePoint"
/>
</CCol>
</CRow>
</CCol>
</CCardBody>
</CCard>
</CRow>
<CRow>
<CCard>
<CCardBody>
<h5 style="margin-bottom: 16px">تنظیمات ساعت کار رستوران</h5>
<CCol>
<CRow>
<CCol sm="6">
<el-checkbox v-model="storeInfo.closeStore" label="فروشگاه تعطیل است"/>
</CCol>
<CRow v-if="!storeInfo.closeStore" class="mb-5">
<CCol sm="6">
<CCol col="md-3" class="mb-2">
<span>ساعت شروع</span>
</CCol>
<CCol col="md-9">
<date-picker type="time" format="HH:mm" display-format="HH:mm" clearable v-model="storeInfo.firstStartTime"></date-picker>
<p class="text-danger" v-if="validation.firstStartTime">
{{ validation.firstStartTime.msg }}
</p>
</CCol>
</CCol>
<CCol sm="6">
<CCol col="md-3" class="mb-2">
<span>ساعت پایان</span>
</CCol>
<CCol col="md-9">
<date-picker type="time" format="HH:mm" display-format="HH:mm" clearable v-model="storeInfo.firstEndTime"></date-picker>
<p class="text-danger" v-if="validation.firstEndTime">
{{ validation.firstEndTime.msg }}
</p>
</CCol>
</CCol>
</CRow>
<CRow v-if="!storeInfo.closeStore">
<el-divider/>
<CCol sm="6">
<CCol col="md-3" class="mb-2">
<span>ساعت شروع</span>
</CCol>
<CCol col="md-9">
<date-picker type="time" format="HH:mm" display-format="HH:mm" clearable v-model="storeInfo.secondStartTime"></date-picker>
<p class="text-danger" v-if="validation.secondStartTime">
{{ validation.secondStartTime.msg }}
</p>
</CCol>
</CCol>
<CCol sm="6">
<CCol col="md-3" class="mb-2">
<span>ساعت پایان</span>
</CCol>
<CCol col="md-9">
<date-picker type="time" format="HH:mm" display-format="HH:mm" clearable v-model="storeInfo.secondEndTime"></date-picker>
<p class="text-danger" v-if="validation.secondEndTime">
{{ validation.secondEndTime.msg }}
</p>
</CCol>
</CCol>
</CRow>
</CRow>
</CCol>
</CCardBody>
</CCard>
</CRow>
<CRow>
<CCard>
<CCardHeader>
<h5>مشخص کردن مکان رستوران روی نقشه</h5>
</CCardHeader>
<CCardBody class="text-center">
<template>
<no-ssr>
<mapir class="d-inline-flex" id="map" :min-zoom="12" :max-zoom="18" :zoom="15" logo-position="top-left" :center="storeInfo.location.coordinates || center" @click="mapOnClick" :apiKey="apiKey">
<mapNavigationControl position="top-right"/>
<mapGeolocateControl position="top-right"/>
<mapMarker
:coordinates.sync="storeInfo.location.coordinates || center"
color="red"
@click="markerOnClick"
:draggable="true"
@dragend="getlatLng"
/>
</mapir>
</no-ssr>
</template>
</CCardBody>
</CCard>
</CRow>
</div>
</template>
<script>
import moment from 'moment-jalaali'
let mapirVue = {}
if (process.client)
mapirVue = require('mapir-vue')
export default {
components: {
'mapir': mapirVue.mapir,
'mapMarker': mapirVue.mapMarker,
'mapNavigationControl': mapirVue.mapNavigationControl,
'mapGeolocateControl': mapirVue.mapGeolocateControl,
},
data() {
return {
apiKey: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImRiYjIwMmRhYzAxYzFjNzgwYjgxNWQyZDgyMWNmNmY1Njk0MThhMGE3N2Q1M2Y0OTZkYzQzYTgxMmNmN2U3ZWJjNzI5MjY5YjkxMjA4MTYyIn0.eyJhdWQiOiIxNDk3OSIsImp0aSI6ImRiYjIwMmRhYzAxYzFjNzgwYjgxNWQyZDgyMWNmNmY1Njk0MThhMGE3N2Q1M2Y0OTZkYzQzYTgxMmNmN2U3ZWJjNzI5MjY5YjkxMjA4MTYyIiwiaWF0IjoxNjI3MzI2Mzc0LCJuYmYiOjE2MjczMjYzNzQsImV4cCI6MTYyOTkxODM3NCwic3ViIjoiIiwic2NvcGVzIjpbImJhc2ljIl19.hyKNSy4fmPps6yIdm33Wof-mES9ujh5lmI3VFWyecbkNCm9ATPwsZ9s53A3a1wPJmHfLBXpCcob5NGL-GjZlVfqfRBiReRMr_iniCjUOnqENfFwVEJutxI-xrzVe7PZzOgx1Vr6WwSUHvQ36eJSS1lBlHlqCgwRbkG0hs4YdZsKhzhfYdlAluNw9djjUAMbRWZVL0EluP9CYko4w8tB0KHUZMZYGQcevCfb_3OU9ygHo7B--Z5aTPfm7IK4eP0gHsZ_t857B3tu3ZJB1mkgxc2R9gZUflKqj1ZqkYiR0uMGP-571enXh6pYQLXL2k-gOxLIedCaE6XytxVXhENnotA',
title: 'اطلاعات فروشگاه',
list_title: 'لیست',
// base data
storeInfo: null,
center: [49.6848857, 34.0821617],
// validation
validation: {}
}
},
methods: {
mapOnClick(e) {
this.storeInfo.location = {
type: 'Point',
coordinates: [e.actualEvent.lngLat.lng , e.actualEvent.lngLat.lat]
}
},
markerOnClick(e) {
},
getlatLng(e) {
},
addInfo() {
this.validation = {}
this.storeInfo.timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
this.$axios.post(`/api/admin/store/${this.$route.params.branch}`, this.storeInfo)
.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);
});
},
jDate(date) {
return moment(date, 'X').format('jYYYY/jMM/jDD')
}
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({$axios, error , params}) {
try {
const store = await $axios.get(`/api/admin/store/${params.branch}`)
return {
storeInfo: store.data
}
} 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">
.el-button:focus {
outline-color: #39f !important;
}
#map {
width: 100vh;
height: 50vh;
}
.holder-logo{
left: 0;
}
.mapboxgl-ctrl-attrib-button{
display: none;
}
</style>
+382
View File
@@ -0,0 +1,382 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="primary" class="mr-auto" :to="{name: 'admin-branch-users'}">برگشت به صفحه قبل</CButton>
<CButton v-if="$route.params.profile === '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>
<CCard>
<CCardBody>
<CRow>
<CCol lg="6">
<CForm>
<template v-if="$route.params.profile !== 'new'">
<h4>مشخصات کاربر</h4>
<el-divider/>
</template>
<CRow>
<CCol sm="12">
<CInput
:class="validation.first_name ? 'err' : null"
label="نام"
:description="validation.first_name ? validation.first_name.msg : null"
v-model="user.first_name"
/>
</CCol>
<CCol sm="12">
<CInput
:class="validation.last_name ? 'err' : null"
label="نام خانوادگی"
:description="validation.last_name ? validation.last_name.msg : null"
v-model="user.last_name"
/>
</CCol>
<CCol sm="12">
<CInput
:class="validation.username ? 'err' : null"
label="نام کاربری"
:description="validation.username ? validation.username.msg : null"
v-model="user.username"
/>
<p class="form-err" v-if="validation.username">{{ validation.username.msg }}</p>
</CCol>
<CCol sm="12">
<CInput
:class="validation.mobile_number ? 'err' : null"
label="تلفن همراه"
v-model="user.mobile_number"
:description="validation.mobile_number ? validation.mobile_number.msg : null"
placeholder="اختیاری"
/>
</CCol>
<CCol sm="12">
<CInput
:class="validation.email ? 'err' : null"
label="ایمیل"
v-model="user.email"
:description="validation.email ? validation.email.msg : null"
placeholder="اختیاری"
/>
</CCol>
<template v-if="$route.params.profile === 'new'">
<CCol sm="12">
<CInput
:class="validation.password ? 'err' : null"
label="کلمه عبور"
type="password"
:description="validation.password ? validation.password.msg : null"
v-model="user.password"
/>
</CCol>
<CCol sm="12">
<CInput
:class="validation.password_confirmation ? 'err' : null"
label="تکرار کلمه عبور"
type="password"
:description="validation.password_confirmation ? validation.password_confirmation.msg : null"
v-model="user.password_confirmation"
/>
</CCol>
</template>
</CRow>
<el-divider/>
<h6>انتخاب شعبه قابل دسترسی</h6>
<el-select v-model="user.branches" multiple placeholder="انتخاب کنید" style="width: 100%;">
<el-option v-for="item in branches" :key="item._id" :label="item.title" :value="item._id"/>
</el-select>
<p style="margin-top : 5px !important ; color : red" class="form-err" v-if="validation.branches">{{ validation.branches.msg }}</p>
<el-divider/>
<h6>دسترسی های کاربر</h6>
<div class="user-permissions">
<el-tag
class="ml-2 mb-2"
style="cursor: pointer"
v-for="(item,index) in user.permissions"
:key="index + Math.random() + 1"
closable
disable-transitions
@close="removePermission(item)"
>{{ getPermissionName(item) }}
</el-tag>
</div>
</CForm>
</CCol>
<CCol lg="6">
<CForm>
<CRow>
<CCol sm="12">
<h4>عکس پروفایل</h4>
<el-divider/>
<CCol>
<img :src="user.profile_pic" style="width: 100%;max-width: 250px;" alt="">
</CCol>
<input type="file" ref="profile_pic" @change="imagePreview">
<p style="margin-top : 5px !important ;" class="form-err" v-if="validation.profile_pic">{{ validation.profile_pic.msg }}</p>
<p class="mt-3 text-muted">عکس 500*500 باشد. در غیر این صورت اتوماتیک بریده می شود.</p>
<CCol>
</CCol>
<p style="margin-top : 0px !important ; " class="form-err" v-if="validation.password_confirmation">{{ validation.password_confirmation.msg }}</p>
</CCol>
<template v-if="$route.params.profile !== 'new'">
<CCol sm="12" class="mt-5">
<h4>تغییر کلمه عبور</h4>
<el-divider/>
<CInput
:class="validation.password ? 'err' : null"
label="کلمه عبور"
type="password"
:description="validation.password ? validation.password.msg : null"
v-model="newPass.password"
/>
</CCol>
<CCol sm="12">
<CInput
:class="validation.password_confirmation ? 'err' : null"
label="تکرار کلمه عبور"
type="password"
:description="validation.password_confirmation ? validation.password_confirmation.msg : null"
v-model="newPass.password_confirmation"
/>
<CButton size="sm" color="success" class="mr-1 mt-3" @click="updatePassword">تغییر کلمه عبور</CButton>
</CCol>
</template>
</CRow>
</CForm>
</CCol>
</CRow>
</CCardBody>
</CCard>
<CCard>
<CCardBody>
<h6>لیست کل دسترسی ها</h6>
<div class="permissions">
<el-tag
class="ml-2 mb-2"
style="cursor: pointer"
v-for="(item,index) in permissions"
:key="index + Math.random() + 2"
:type="hasPermission(item.value) ? 'success' : 'primary'"
disable-transitions
@click="addPermission(item.value)"
>{{ item.name }}
</el-tag>
</div>
</CCardBody>
</CCard>
</CCol>
</CRow>
</div>
</template>
<script>
import axiosUploadProcess from "@/mixins/axiosUploadProcess"
export default {
data() {
return {
user: null,
permissions: null,
branches: null,
newPass: {
password: '',
password_confirmation: ''
},
validation: {}
}
},
mixins: [axiosUploadProcess],
computed: {
title() {
return this.$route.params.profile === 'new' ? 'افزودن کاربر' : 'مشاهده پروفایل کاربر'
}
},
methods: {
getPermissionName(value) {
return this.permissions.filter(item => item.value === value)[0].name
},
addPermission(val) {
if (!this.user.permissions.includes(val)) this.user.permissions.push(val)
else this.$message({
type: 'warning',
message: 'کاربر از قبل این دسترسی را دارد'
})
},
removePermission(val) {
this.user.permissions = this.user.permissions.filter(item => item !== val)
},
hasPermission(val) {
return this.user.permissions.includes(val)
},
imagePreview(e) {
this.user.profile_pic = URL.createObjectURL(e.target.files[0])
},
post() {
this.validation = {}
const data = new FormData()
data.append("first_name", this.user.first_name)
data.append("last_name", this.user.last_name)
data.append("mobile_number", this.user.mobile_number)
data.append("email", this.user.email)
data.append("username", this.user.username)
data.append("permissions", JSON.stringify(this.user.permissions))
data.append("branches", JSON.stringify(this.user.branches))
data.append("password", this.user.password)
data.append("password_confirmation", this.user.password_confirmation)
if (this.$refs.profile_pic.files[0]) data.append("profile_pic", this.$refs.profile_pic.files[0])
this.$axios.post(`/api/admin/admin`, data, this.axiosConfig)
.then(response => {
this.$message({
type: 'success',
message: 'کاربر با موفقیت ایجاد شد.'
})
this.$router.push({name: 'admin-branch-users'})
})
.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("first_name", this.user.first_name)
data.append("last_name", this.user.last_name)
data.append("mobile_number", this.user.mobile_number)
data.append("email", this.user.email)
data.append("username", this.user.username)
data.append("permissions", JSON.stringify(this.user.permissions))
data.append("branches", JSON.stringify(this.user.branches))
data.append("password", this.user.password)
data.append("password_confirmation", this.user.password_confirmation)
if (this.$refs.profile_pic.files[0]) data.append("profile_pic", this.$refs.profile_pic.files[0])
this.$axios.put(`/api/admin/admin/${this.user._id}`, data, this.axiosConfig)
.then(response => {
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 === 422) this.validation = err.response.data.validation
else console.log(err.response.data)
})
},
updatePassword() {
this.validation = {}
this.$axios.put(`/api/admin/changeAdminPasswordByAdmin/${this.user._id}`, this.newPass)
.then(response => {
this.$message({
type: 'success',
message: 'کلمه عبور بروزرسانی شد.'
})
this.newPass = {
password: '',
password_confirmation: ''
}
})
.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 permissions = await $axios.get('/api/admin/permissions')
const branches = await $axios.$get('/api/admin/store/getAll')
if (params.profile !== 'new') {
const user = await $axios.get(`/api/admin/admin/${params.profile}`)
return {
permissions: permissions.data,
user: user.data,
branches
}
} else {
return {
permissions: permissions.data,
branches,
user: {
first_name: '',
last_name: '',
mobile_number: '',
email: '',
username: '',
password: '',
password_confirmation: '',
profile_pic: '',
permissions: [],
branches: []
}
}
}
} 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>
+161
View File
@@ -0,0 +1,161 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="success" :to="{name: 'admin-branch-users-profile',params:{profile: 'new'}}"
class="mr-auto">افزودن</CButton>
</CustomSubHeader>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>{{ list_title }}</span>
</slot>
</CCardHeader>
<CCardBody>
<el-table
:data="users.docs"
style="width: 100%">
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
prop="first_name"
label="نام"
width="">
</el-table-column>
<el-table-column
prop="last_name"
label="نام خانوادگی"
width="">
</el-table-column>
<el-table-column
prop="username"
label="نام کاربری"
width="">
</el-table-column>
<el-table-column
label="ویرایش"
width="110"
align="center">
<template slot-scope="scope">
<CButton color="danger" variant="outline" :key="scope.row._id + Math.random()" @click="deleteUser(scope.row._id)">
<i class="far fa-trash-alt"></i>
</CButton>
<CButton color="success" variant="outline" :key="scope.row._id"
:to="{name: 'admin-branch-users-profile',params: {profile: scope.row._id}}">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
<CCard class="col" v-if="users.totalDocs>5">
<CRow alignHorizontal="center" style="padding : 10px">
<el-pagination :hide-on-single-page="true" layout="prev, pager, next" :page-size="users.limit"
@current-change="handleCurrentChange" :current-page.sync="users.page" :total="users.totalDocs">
</el-pagination>
</CRow>
</CCard>
</div>
</template>
<script>
export default {
data() {
return {
title: 'لیست کاربران',
list_title: 'لیست',
users: null
}
},
computed: {
pageQuery() {
return this.$route.query.page;
}
},
watch:{
pageQuery(newPage, oldPage) {
this.$nuxt.refresh();
}
},
methods: {
handleCurrentChange(page) {
// if (!_.isEmpty(this.search)) {
// this.handleSearch(page);
// } else {
this.$router.push({
name: "admin-branch-users",
query: {
page: page
}
});
// }
},
deleteUser(id) {
this.$confirm('کاربر حذف شود؟', 'هشدار', {
confirmButtonText: 'بله',
cancelButtonText: 'لغو',
type: 'warning'
}).then(async () => {
this.$axios.delete(`/api/admin/admin/${id}`)
.then(res => {
this.$message({
type: 'success',
message: 'کاربر با موفقیت حذف شد'
})
this.users.docs = this.users.docs.filter(item => item._id !== id)
})
.catch(err => {
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
console.log(err.response.data)
})
}).catch(() => {
this.$message({
type: 'warning',
message: 'عملیات لغو شد'
})
})
}
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({$axios, query , error , params}) {
try {
const users = await $axios.get(`/api/admin/admins/${params?.branch}?page=${query.page}`)
return {
users: users.data
}
} catch (e) {
if (e?.response?.status === 401) {
error({
status: 401,
message: 'شما اجازه دسترسی به این صفحه را ندارید لطفا دوباره وارد شوید'
})
} else {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات بوجود آمده است",
});
}
}
}
}
</script>
@@ -0,0 +1,108 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="primary" class="mr-auto" :to="{name: 'admin-contact-us-messages'}">برگشت به صفحه قبل</CButton>
</CustomSubHeader>
<CCard>
<CCardHeader>
<slot name="header">
<!-- <i class="fal fa-bars"></i>-->
<!-- <span>{{ list_title }}</span>-->
</slot>
</CCardHeader>
<CCardBody>
<CRow>
<CCol md="6">
<CForm class="message">
<CRow>
<CCol sm="12">
<CInput
label="نام"
:value="message.name"
disabled
/>
<CInput
label="شماره تماس"
:value="message.phone"
disabled
/>
<CInput
label="ایمیل"
:value="message.email"
disabled
/>
<CTextarea
label="پیام"
disabled=""
:value="message.message"
rows="10"
/>
<p class="form-err" v-if="validation.caption">{{ validation.caption.msg }}</p>
</CCol>
</CRow>
</CForm>
</CCol>
</CRow>
</CCardBody>
</CCard>
</div>
</template>
<script>
export default {
data() {
return {
title: 'مشاهده پیام',
message: null,
validation: {}
}
},
computed: {},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({$axios, params, error}) {
try {
const message = await $axios.get(`/api/admin/contactUsMessages/${params.message}`)
return {
message: message.data
}
} 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">
.message {
input:disabled, textarea:disabled {
color: #000 !important;
}
}
</style>
+143
View File
@@ -0,0 +1,143 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
</CustomSubHeader>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>{{ list_title }}</span>
</slot>
</CCardHeader>
<CCardBody>
<el-table
:data="messages.docs"
style="width: 100%"
:row-class-name="readStatus">
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
prop="name"
label="نام"
width="">
</el-table-column>
<el-table-column
prop="email"
label="ایمیل"
width="">
</el-table-column>
<el-table-column
prop="phone"
label="شماره تماس"
width=""
class-name="phoneNumber">
</el-table-column>
<el-table-column
label="مشاهده"
width="80"
align="center">
<template slot-scope="scope">
<CButton color="success" variant="outline" :key="scope.row._id" :to="{name: 'admin-contact-us-messages-message',params: {message: scope.row._id}}">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
<CCard class="col" v-if="messages.totalDocs>20">
<CRow alignHorizontal="center" style="padding : 10px">
<el-pagination :hide-on-single-page="true" layout="prev, pager, next" :page-size="messages.limit"
@current-change="handleCurrentChange" :current-page.sync="messages.page" :total="messages.totalDocs">
</el-pagination>
</CRow>
</CCard>
</div>
</template>
<script>
export default {
data() {
return {
title: 'لیست اسلایدهای صفحه اصلی',
list_title: 'لیست',
messages: null,
}
},
computed: {
pageQuery() {
return this.$route.query.page;
}
},
watch: {
pageQuery(newPage, oldPage) {
this.$nuxt.refresh();
}
},
methods: {
handleCurrentChange(page) {
// if (!_.isEmpty(this.search)) {
// this.handleSearch(page);
// } else {
this.$router.push({
name: "admin-contact-us-messages",
query: {
page: page
}
});
// }
},
readStatus({row, rowIndex}) {
return row.read ? null : 'unread'
}
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({$axios, query, error}) {
try {
const messages = await $axios.get(`/api/admin/contactUsMessages?page=${query.page || 1}`)
return {
messages: messages.data
}
} catch (e) {
if (e?.response?.status === 401) {
error({
status: 401,
message: 'شما اجازه دسترسی به این صفحه را ندارید لطفا دوباره وارد شوید'
})
} else {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات بوجود آمده است",
});
}
}
}
}
</script>
<style lang="scss">
.phoneNumber {
div {
direction: ltr;
text-align: right;
}
}
.unread {
background: rgba(255, 173, 0, 0.12) !important;
}
</style>
+186
View File
@@ -0,0 +1,186 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="primary" class="mr-auto" :to="{name: 'admin-gallery'}">برگشت به صفحه قبل</CButton>
<CButton size="sm" v-if="newPage" color="success" class="mr-1" @click="add">افزودن</CButton>
<CButton size="sm" v-else color="success" class="mr-1" @click="update">بروزرسانی</CButton>
</CustomSubHeader>
<CCard>
<CCardHeader>
<slot name="header">
<!-- <i class="fal fa-bars"></i>-->
<!-- <span>{{ list_title }}</span>-->
</slot>
</CCardHeader>
<CCardBody>
<CRow>
<CCol md="6">
<CForm>
<CRow>
<CCol sm="12">
<CTextarea
:class="validation.caption ? 'err' : null"
label="توضیحات"
v-model="image.caption"
rows="10"
/>
<p class="form-err" v-if="validation.caption">{{ validation.caption.msg }}</p>
</CCol>
</CRow>
</CForm>
</CCol>
<CCol md="6">
<h4>تصویر:</h4>
<el-divider/>
<img :src="image.image" alt="" style="width: 100%">
<input type="file" ref="image" @change="preview">
<p class="form-err" style="color: red" v-if="validation.image">{{ validation.image.msg }}</p>
</CCol>
</CRow>
</CCardBody>
</CCard>
</div>
</template>
<script>
import axiosUploadProcess from "@/mixins/axiosUploadProcess"
export default {
data() {
return {
image: null,
validation: {}
}
},
mixins: [axiosUploadProcess],
computed: {
title() {
return this.$route.params.image === 'new' ? 'افزودن تصویر' : 'ویرایش تصویر'
},
newPage() {
return this.$route.params.image === 'new'
}
},
methods: {
add() {
this.validation = {}
const data = new FormData()
data.append('caption', this.image.caption)
data.append('image', this.$refs.image.files[0])
this.$axios.post(`/api/admin/gallery`, data, this.axiosConfig)
.then(response => {
this.$message({
message: 'اسلاید با موفقیت ثبت شد.',
type: 'success'
})
this.$router.push({name: 'admin-gallery'})
})
.catch(err => {
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
if (err.response.status === 422) {
this.validation = err.response.data.validation
this.$message({
type: 'error',
message: 'اطلاعات رو بررسی و دوباره تلاش کنید'
})
} else {
this.$alert(err.response.data.error.message, 'خطا', {
confirmButtonText: 'باشه'
})
}
})
},
update() {
this.validation = {}
const data = new FormData()
data.append('caption', this.image.caption)
if (this.$refs.image.files[0]) data.append('image', this.$refs.image.files[0])
this.$axios.put(`/api/admin/gallery/${this.image._id}`, data, this.axiosConfig)
.then(response => {
this.$message({
message: 'تغییرات با موفقیت انجام شد.',
type: 'success'
})
this.$refs.image.value = null
this.$nuxt.refresh()
})
.catch(err => {
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
if (err.response.status === 422) {
this.validation = err.response.data.validation
this.$message({
type: 'error',
message: 'اطلاعات رو بررسی و دوباره تلاش کنید'
})
} else {
this.$alert(err.response.data.error.message, 'خطا', {
confirmButtonText: 'باشه'
})
}
})
},
preview(event) {
this.image.image = URL.createObjectURL(event.target.files[0])
}
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({$axios, params, error}) {
try {
if (params.image !== 'new') {
const image = await $axios.get(`/api/public/gallery/${params.image}`)
return {
image: image.data
}
} else {
return {
image: {
caption: '',
image: ''
}
}
}
} 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>
+127
View File
@@ -0,0 +1,127 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="success" :to="{name: 'admin-gallery-image',params:{image: 'new'}}" class="mr-auto">افزودن</CButton>
</CustomSubHeader>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>{{ list_title }}</span>
</slot>
</CCardHeader>
<CCardBody>
<el-table
:data="gallery"
style="width: 100%">
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
label="تصویر"
width="200">
<template slot-scope="scope">
<img :src="scope.row.thumb" style="width: 100%" alt="">
</template>
</el-table-column>
<el-table-column
prop="shortCaption"
label="توضیحات"
width="">
</el-table-column>
<el-table-column
label="ویرایش"
width="110"
align="center">
<template slot-scope="scope">
<CButton color="danger" variant="outline" :key="scope.row._id + Math.random()" @click="remove(scope.row._id)">
<i class="far fa-trash-alt"></i>
</CButton>
<CButton color="success" variant="outline" :key="scope.row._id" :to="{name: 'admin-gallery-image',params: {image: scope.row._id}}">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
</div>
</template>
<script>
export default {
data() {
return {
title: 'لیست گالری تصاویر',
list_title: 'لیست',
gallery: null,
}
},
computed: {},
methods: {
remove(id) {
this.$confirm('این تصویر حذف شود؟', 'هشدار', {
confirmButtonText: 'بله',
cancelButtonText: 'لغو',
type: 'warning'
}).then(async () => {
this.$axios.delete(`/api/admin/gallery/${id}`)
.then(res => {
this.$message({
type: 'success',
message: 'تصویر با موفقیت حذف شد'
})
this.gallery = this.gallery.filter(item => item._id !== id)
})
.catch(err => {
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
console.log(err.response.data)
})
}).catch(() => {
this.$message({
type: 'warning',
message: 'عملیات لغو شد'
})
})
}
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({$axios, error}) {
try {
const gallery = await $axios.get('/api/public/gallery')
return {
gallery: gallery.data
}
} catch (e) {
if (e?.response?.status === 401) {
error({
status: 401,
message: 'شما اجازه دسترسی به این صفحه را ندارید لطفا دوباره وارد شوید'
})
} else {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات بوجود آمده است",
});
}
}
}
}
</script>
+190
View File
@@ -0,0 +1,190 @@
<template>
<div>
<!-- <TheSidebar :branch="branches"/>-->
<CRow class="d-flex flex-row" :class="branches.length ? '' : 'justify-content-center'">
<!-- <CCol class="col-12 col-md-6 col-xl-4">-->
<!-- <CCard class="my-card" @click="addBranch()">-->
<!-- <CCardBody class="d-flex flex-column justify-content-center align-items-center">-->
<!-- <i class="far fa-plus" style="font-size: 28px"></i>-->
<!-- <p class="mt-4">اضافه کردن شعبه</p>-->
<!-- </CCardBody>-->
<!-- </CCard>-->
<!-- </CCol>-->
<CCol class="col-12 col-md-6 col-xl-4" v-for="(item , index) in branches" :key="index">
<CCard class="my-card-dynamic">
<NuxtLink class="link-style" :to="{name : 'admin-branch' , params:{branch: item._id}}">
<CCardBody class="d-flex flex-row align-items-center">
<template>
<!-- <el-image v-if="!item.logo.includes('undefined')" style="width: 100px; height: 100px" :src="$config.apiUrl + item.logo" fit="contain"></el-image>-->
<el-image style="width: 100px; height: 100px;" src="/favicon.png" fit="contain"></el-image>
</template>
<p class="mt-4 mr-4 list-services">{{ item.title }}</p>
</CCardBody>
</NuxtLink>
<CCardFooter class="d-flex justify-content-between align-items-center">
<!-- <NuxtLink v-if="hasPermission('super-admin') || hasPermission('branch')" class="btn btn-info" :to="{name : 'admin-branches-branch' , params:{branch: item._id}}">بروزرسانی</NuxtLink>-->
<div>
<span class="ml-2" v-if="item.active">فعال</span>
<span class="ml-2" v-else>غیر فعال</span>
<span><i class="fad fa-circle" :style="item.active ? 'color: #0ce10c' : 'color: red'"></i></span>
</div>
</CCardFooter>
</CCard>
</CCol>
</CRow>
</div>
</template>
<script>
import moment from "moment-jalaali"
// import login from "@/pages/admin/login";
import axiosUploadProcess from "@/mixins/axiosUploadProcess";
// import HorizontalScroll from 'vue-horizontal-scroll'
// import 'vue-horizontal-scroll/dist/vue-horizontal-scroll.css'
import TheSidebar from "@/components/admin/TheSidebar";
export default {
components: {TheSidebar},
data() {
return {
mark: '',
title: 'داشبورد',
list_title: 'لیست',
branches: [],
loading: false,
validation: {},
}
},
computed: {
colorTheme: {
get() {
return `rgba(${this.hexToRgb(this.branches.colorTheme)} ,1)`
},
set(value) {
this.branches.colorTheme = value
}
},
},
methods: {
jDate(date) {
return moment(date).format("jYYYY/jMM/jDD")
},
imagePreview(e) {
this.branches.logo = URL.createObjectURL(e.target.files[0]);
},
addInfo() {
this.validation = {};
const data = new FormData();
data.append("title", this.branches?.title?.trim());
data.append("caption", this.branches?.caption?.trim());
data.append("email", this.branches.email);
data.append("tel", this.branches.tel);
data.append("location", '[49.67720236907016,34.07654928061605]');
data.append("address", this.branches.address);
data.append("socials", JSON.stringify(this.branches.socials));
data.append("colorTheme", this.branches.colorTheme);
if (this.$refs.logo.files[0]) data.append("logo", this.$refs.logo.files[0]);
this.$axios
.post(`/api/admin/store`, data, this.axiosConfig)
.then((response) => {
this.$message({
type: "success",
message: "اطلاعات شما با موفقیت ثبت شد",
});
window.location.replace('/admin')
})
.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.validation = err.response.data.validation;
this.$message({
type: 'warning',
message: 'پارامتر هارو بررسی کنید'
})
} else console.log(err.response.data);
});
},
addBranch() {
this.$router.push({name : 'admin-branches-branch' , params:{branch: 'new'}})
},
status(store) {
},
hasPermission(permission) {
if (this.$auth.loggedIn) return this.$auth.user.permissions.includes(permission)
else return false
},
},
head() {
return {
title: this.title,
// link: [
// {rel: 'icon', type: 'image/x-icon', href: '/favicon.png'}
// ],
}
},
layout: 'admin',
mixins: [axiosUploadProcess],
async asyncData({$axios, $store, error}) {
try {
const requests = [
$axios.$get(`/api/admin/store/getAll`),
]
const fetch = await Promise.all(requests)
const [branches] = fetch
return {
branches
}
} catch (e) {
console.log(e.message)
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>
+139
View File
@@ -0,0 +1,139 @@
<template>
<CRow class="justify-content-center">
<CCol lg="5">
<CCardGroup>
<CCard class="p-4">
<CCardBody>
<CForm @submit.prevent="doLogin">
<h1 class="text-muted text-center mb-5">پنل مدیریت کافه رستوران برگ</h1>
<CInput
:class="validation.username ? 'err' : null"
placeholder="نام کاربری"
:description="validation.username ? validation.username.msg : null"
autocomplete="username email"
v-model="login.username"
>
<template #prepend-content>
<CIcon name="cil-user"/>
</template>
</CInput>
<div class="butt">
<CInput
:class="validation.password ? 'err' : null"
placeholder="کلمه عبور"
:type="passwordState"
:description="validation.password ? validation.password.msg : null"
autocomplete="curent-password"
v-model="login.password"
>
<template #prepend-content>
<CIcon name="cil-lock-locked"/>
</template>
</CInput>
<i @click="showPass = !showPass" class="far fa-eye"></i>
</div>
<CInputCheckbox label="مرا به خاطر بسپار" @update:checked="val => login.remember_me = val"/>
<p class="text-muted mt-3" style="font-size: 11px;">*درصورتی که گزینه "مرا به خاطر بسپار" را فعال نکنید بعد از 1 ساعت باید دوباره وارد سیستم شوید.</p>
<CRow>
<CCol col="12" class="text-right mt-2">
<CButton color="primary" type="submit" class="px-4">ورود</CButton>
</CCol>
<!-- <CCol col="6" class="text-right">-->
<!-- <CButton color="link" class="px-0">Forgot password?</CButton>-->
<!-- <CButton color="link" class="d-lg-none">Register now!</CButton>-->
<!-- </CCol>-->
</CRow>
</CForm>
</CCardBody>
</CCard>
<!-- <CCard-->
<!-- color="primary"-->
<!-- text-color="white"-->
<!-- class="text-center py-5 d-md-down-none"-->
<!-- body-wrapper>-->
<!-- <CCardBody>-->
<!-- <h2>Sign up</h2>-->
<!-- <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>-->
<!-- <CButton-->
<!-- color="light"-->
<!-- variant="outline"-->
<!-- size="lg"-->
<!-- >-->
<!-- Register Now!-->
<!-- </CButton>-->
<!-- </CCardBody>-->
<!-- </CCard>-->
</CCardGroup>
</CCol>
</CRow>
</template>
<script>
export default {
data() {
return {
showPass: false,
login: {
username: '',
password: '',
remember_me: false
},
validation: {}
}
},
computed: {
passwordState() {
return this.showPass ? "text" : "password"
},
branchId(){
return this.$store?.state?.admin?.branchId
}
},
methods: {
doLogin() {
this.validation = {}
this?.$auth?.logout()
this.$auth.loginWith('local', {
data: this.login
})
.then(response => {
window.location.replace(`/admin`)
})
.catch(err => {
if (err?.response?.status === 422) this.validation = err?.response?.data?.validation
else console.log(err?.message)
})
}
},
layout: 'admin-auth'
}
</script>
<style lang="scss">
.butt {
position: relative;
i {
position: absolute;
left: 7px;
top: 11px;
z-index: 3;
cursor: pointer;
color: rgba(#000, 0.5);
-webkit-transition: 0.2s;
-moz-transition: 0.2s;
-ms-transition: 0.2s;
-o-transition: 0.2s;
transition: 0.2s;
&:hover {
color: #000;
}
}
}
</style>
+186
View File
@@ -0,0 +1,186 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="primary" class="mr-auto" :to="{name: 'admin-slider'}">برگشت به صفحه قبل</CButton>
<CButton size="sm" v-if="newPage" color="success" class="mr-1" @click="add">افزودن</CButton>
<CButton size="sm" v-else color="success" class="mr-1" @click="update">بروزرسانی</CButton>
</CustomSubHeader>
<CCard>
<CCardHeader>
<slot name="header">
<!-- <i class="fal fa-bars"></i>-->
<!-- <span>{{ list_title }}</span>-->
</slot>
</CCardHeader>
<CCardBody>
<CRow>
<CCol md="6">
<CForm>
<CRow>
<CCol sm="12">
<CTextarea
:class="validation.caption ? 'err' : null"
label="توضیحات"
v-model="slide.caption"
rows="10"
/>
<p class="form-err" v-if="validation.caption">{{ validation.caption.msg }}</p>
</CCol>
</CRow>
</CForm>
</CCol>
<CCol md="6">
<h4>تصویر:</h4>
<el-divider/>
<img :src="slide.image" alt="" style="width: 100%">
<input type="file" ref="image" @change="preview">
<p class="form-err" style="color: red" v-if="validation.image">{{ validation.image.msg }}</p>
</CCol>
</CRow>
</CCardBody>
</CCard>
</div>
</template>
<script>
import axiosUploadProcess from "@/mixins/axiosUploadProcess"
export default {
data() {
return {
slide: null,
validation: {}
}
},
mixins: [axiosUploadProcess],
computed: {
title() {
return this.$route.params.slide === 'new' ? 'افزودن اسلاید' : 'ویرایش اسلاید'
},
newPage() {
return this.$route.params.slide === 'new'
}
},
methods: {
add() {
this.validation = {}
const data = new FormData()
data.append('caption', this.slide.caption)
data.append('image', this.$refs.image.files[0])
this.$axios.post(`/api/admin/slider`, data, this.axiosConfig)
.then(response => {
this.$message({
message: 'اسلاید با موفقیت ثبت شد.',
type: 'success'
})
this.$router.push({name: 'admin-slider'})
})
.catch(err => {
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
if (err.response.status === 422) {
this.validation = err.response.data.validation
this.$message({
type: 'error',
message: 'اطلاعات رو بررسی و دوباره تلاش کنید'
})
} else {
this.$alert(err.response.data.error.message, 'خطا', {
confirmButtonText: 'باشه'
})
}
})
},
update() {
this.validation = {}
const data = new FormData()
data.append('caption', this.slide.caption)
if (this.$refs.image.files[0]) data.append('image', this.$refs.image.files[0])
this.$axios.put(`/api/admin/slider/${this.slide._id}`, data, this.axiosConfig)
.then(response => {
this.$message({
message: 'تغییرات با موفقیت انجام شد.',
type: 'success'
})
this.$refs.image.value = null
this.$nuxt.refresh()
})
.catch(err => {
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
if (err.response.status === 422) {
this.validation = err.response.data.validation
this.$message({
type: 'error',
message: 'اطلاعات رو بررسی و دوباره تلاش کنید'
})
} else {
this.$alert(err.response.data.error.message, 'خطا', {
confirmButtonText: 'باشه'
})
}
})
},
preview(event) {
this.slide.image = URL.createObjectURL(event.target.files[0])
}
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({$axios, params, error}) {
try {
if (params.slide !== 'new') {
const slide = await $axios.get(`/api/public/slider/${params.slide}`)
return {
slide: slide.data
}
} else {
return {
slide: {
caption: '',
image: ''
}
}
}
} 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>
+127
View File
@@ -0,0 +1,127 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="success" :to="{name: 'admin-slider-slide',params:{slide: 'new'}}" class="mr-auto">افزودن</CButton>
</CustomSubHeader>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>{{ list_title }}</span>
</slot>
</CCardHeader>
<CCardBody>
<el-table
:data="slides"
style="width: 100%">
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
label="تصویر"
width="200">
<template slot-scope="scope">
<img :src="scope.row.image" style="width: 100%" alt="">
</template>
</el-table-column>
<el-table-column
prop="caption"
label="توضیحات"
width="">
</el-table-column>
<el-table-column
label="ویرایش"
width="110"
align="center">
<template slot-scope="scope">
<CButton color="danger" variant="outline" :key="scope.row._id + Math.random()" @click="remove(scope.row._id)">
<i class="far fa-trash-alt"></i>
</CButton>
<CButton color="success" variant="outline" :key="scope.row._id" :to="{name: 'admin-slider-slide',params: {slide: scope.row._id}}">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
</div>
</template>
<script>
export default {
data() {
return {
title: 'لیست اسلایدهای صفحه اصلی',
list_title: 'لیست',
slides: null,
}
},
computed: {},
methods: {
remove(id) {
this.$confirm('اسلاید حذف شود؟', 'هشدار', {
confirmButtonText: 'بله',
cancelButtonText: 'لغو',
type: 'warning'
}).then(async () => {
this.$axios.delete(`/api/admin/slider/${id}`)
.then(res => {
this.$message({
type: 'success',
message: 'اسلاید با موفقیت حذف شد'
})
this.slides = this.slides.filter(item => item._id !== id)
})
.catch(err => {
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
console.log(err.response.data)
})
}).catch(() => {
this.$message({
type: 'warning',
message: 'عملیات لغو شد'
})
})
}
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({$axios, error}) {
try {
const slides = await $axios.get(`/api/public/slider`)
return {
slides: slides.data
}
} catch (e) {
if (e?.response?.status === 401) {
error({
status: 401,
message: 'شما اجازه دسترسی به این صفحه را ندارید لطفا دوباره وارد شوید'
})
} else {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات بوجود آمده است",
});
}
}
}
}
</script>
+128
View File
@@ -0,0 +1,128 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="primary" class="mr-auto" :to="{name: 'admin-subscribers'}">برگشت به صفحه قبل</CButton>
</CustomSubHeader>
<CRow>
<CCol>
<CCard>
<CCardBody>
<CRow>
<CCol lg="6">
<CForm>
<template v-if="$route.params.profile !== 'new'">
<h4>اطلاعات فرم</h4>
<el-divider/>
</template>
<CRow>
<CCol sm="12">
<CInput
label="نام"
disabled
:value="subscriber.full_name"
/>
</CCol>
<CCol sm="12">
<CInput
label="تاریخ ازدواج"
disabled
:value="subscriber.birth_date"
/>
</CCol>
<CCol sm="12">
<CInput
label="شماره تماس"
disabled
class="subs_phone_number"
:value="subscriber.mobile"
/>
</CCol>
<CCol sm="12">
<CInput
label="ایمیل"
disabled
:value="subscriber.email"
/>
</CCol>
<CCol sm="12">
<CTextarea
label="آدرس"
disabled
:value="subscriber.address"
/>
</CCol>
</CRow>
</CForm>
</CCol>
</CRow>
</CCardBody>
</CCard>
</CCol>
</CRow>
</div>
</template>
<script>
export default {
data() {
return {
title: 'اطلاعات فرم',
subscriber: null
}
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({$axios, params, error}) {
try {
const subscriber = await $axios.get(`/api/admin/subscriber/${params.subscriber}`)
return {
subscriber: subscriber.data
}
} 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>
.subs_phone_number input{
direction: ltr !important;
text-align: right;
}
</style>
+139
View File
@@ -0,0 +1,139 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
</CustomSubHeader>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>{{ list_title }}</span>
</slot>
</CCardHeader>
<CCardBody>
<el-table
:data="subscribers"
style="width: 100%">
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
prop="full_name"
label="نام"
width="">
</el-table-column>
<el-table-column
prop="mobile"
label="شماره تماس"
width=""
class-name="subs_phone_number"
>
</el-table-column>
<el-table-column
prop="email"
label="ایمیل"
width="">
</el-table-column>
<el-table-column
label="ویرایش"
width="110"
align="center">
<template slot-scope="scope">
<CButton color="danger" variant="outline" :key="scope.row._id + Math.random()" @click="remove(scope.row._id)">
<i class="far fa-trash-alt"></i>
</CButton>
<CButton color="success" variant="outline" :key="scope.row._id" :to="{name: 'admin-subscribers-subscriber',params: {subscriber: scope.row._id}}">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
</div>
</template>
<script>
export default {
data() {
return {
title: 'امور مشترکین',
list_title: 'لیست',
subscribers: null
}
},
computed: {},
methods: {
remove(id) {
this.$confirm('حذف شود؟', 'هشدار', {
confirmButtonText: 'بله',
cancelButtonText: 'لغو',
type: 'warning'
}).then(async () => {
this.$axios.delete(`/api/admin/subscriber/${id}`)
.then(res => {
this.$message({
type: 'success',
message: 'با موفقیت حذف شد'
})
this.subscribers = this.subscribers.filter(item => item._id !== id)
})
.catch(err => {
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
console.log(err.response.data)
})
}).catch(() => {
this.$message({
type: 'warning',
message: 'عملیات لغو شد'
})
})
}
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({$axios, error}) {
try {
const subscribers = await $axios.get(`/api/admin/subscribers`)
return {
subscribers: subscribers.data
}
} catch (e) {
if (e?.response?.status === 401) {
error({
status: 401,
message: 'شما اجازه دسترسی به این صفحه را ندارید لطفا دوباره وارد شوید'
})
} else {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات بوجود آمده است",
});
}
}
}
}
</script>
<style>
.subs_phone_number .cell{
direction: ltr;
text-align: right;
}
</style>