back-end done

This commit is contained in:
Amir Mohamadi
2020-12-10 16:36:48 +03:30
parent 80a7abafb7
commit bc5e617778
92 changed files with 5217 additions and 3379 deletions
+26 -10
View File
@@ -1,22 +1,17 @@
<template>
<div class="page blog-details--page">
<Hero :title="staticData.hero"/>
<Hero :title="categoryName(post.category)"/>
<section class="s1">
<div class="container">
<div class="panel">
<div class="date-category">
<span class="category">
<span>{{staticData.t1}}</span>
<span>News</span>
<span>{{categoryName(post.category)}}</span>
</span>
<span class="date">30/05/2020</span>
</div>
<div class="content">
<h2>لیست مقالات و اخبار</h2>
<br>
<br>
<p>ما می خواهیم اطلاعات بیشتری در مورد ما بدانید ، بنابراین ما اخبار ، رویدادها یا تحولات گریتینگ اراک ریل و صنعتی را که ما به آن تعلق داریم برای شما ارسال می کنیم ،بنابراین شما می دانید که چگونه ما در جای خود قرار گرفته ایم.</p>
<span class="date">{{jDate(post.created_at)}}</span>
</div>
<div class="content" v-html="post.post_details[$route.params.lang].description"></div>
<div class="share">
<p>{{staticData.t2}}</p>
<ul>
@@ -60,16 +55,37 @@
</template>
<script>
import moment from "moment-jalaali"
export default {
data() {
return {
domain: 'https://www.arakrail.com/'
post: null,
blogCategories: null,
domain: 'https://www.arakrail.com'
}
},
computed: {
staticData() {
return this.$store.state.staticData.blog_details[this.$route.params.lang]
}
},
methods: {
categoryName(id) {
return this.blogCategories.filter(item => item._id === id)[0].blogCategory_details[this.$route.params.lang].name
},
jDate(date) {
if (this.$route.params.lang === 'fa') return moment(date).format('jYYYY/jMM/jDD')
else return date.split(' ')[0]
},
},
async asyncData({$axios, params}) {
const post = await $axios.get(`/api/public/blog/${params.post}`)
const blogCategories = await $axios.get(`/api/public/blogCategories`)
return {
post: post.data,
blogCategories: blogCategories.data
}
}
}
</script>
+55 -33
View File
@@ -16,10 +16,12 @@
<div class="filters">
<h2 class="title">{{staticData.t3}}</h2>
<ul>
<li>همه</li>
<li>مقالات</li>
<li>اخبار</li>
<li>آموزش ها</li>
<li @click="filtering(false)">
<p class="active">همه</p>
</li>
<li v-for="item in blogCategories" :key="item._id" @click="filtering(item._id)">
<p>{{item.blogCategory_details[$route.params.lang].name}}</p>
</li>
</ul>
</div>
</div>
@@ -29,49 +31,34 @@
<section class="s3">
<div class="container">
<div class="row">
<div class="col-12 clearfix post">
<div class="row" v-if="filtered_posts.length">
<div class="col-12 clearfix post" v-for="item in filtered_posts" :key="item._id">
<div class="panel">
<div class="imgBox imgBox-reverse">
<div class="img">
<img src="~/assets/img/blog/blog-post.jpg" alt="">
<img :src="item.thumb" :alt="item.post_details[$route.params.lang].title">
</div>
</div>
<div class="txtBox">
<div class="date-category">
<span class="category">
<span>{{staticData.t4}}</span>
<span>News</span>
<span>{{categoryName(item.category)}}</span>
</span>
<span class="date">30/05/2020</span>
<span class="date">{{jDate(item.created_at)}}</span>
</div>
<h4>گریتینگ چیست</h4>
<p>گریتینگ چیست در این نوشته به پاسخ به سوال گریتینگ چیست خواهیم پرداخت گریتینگ در اصل به صفحات مشبکی گفته میشود که به دلیل داشتن خصوصیات بارزی مانند وزن پایین تر, امکان عبور هوا و نور, قیمت تمام شده پایین تر, ظاهری زیباتر و مزایای بسیار دیگری نسبت به سایر محصولات مشابه خود امروزه جایگاه ویژه ای در صنایع گوناگون و همچنین شهرسازی بدست آورده است و هر روزه بر کاربرد آن افزوده میشود. با توجه به این افزایش کاربرد امروز گریتینگ ها را در []</p>
<nuxt-link :to="{name: 'lang-blog-post',params: {lang: $route.params.lang,post: 1}}" class="btn btn-primary">{{staticData.t5}}</nuxt-link>
<h4>{{item.post_details[$route.params.lang].title}}</h4>
<p>{{item.post_details[$route.params.lang].short_description}}</p>
<nuxt-link :to="{name: 'lang-blog-post',params: {lang: $route.params.lang,post: item._id}}" class="btn btn-primary">{{staticData.t5}}</nuxt-link>
</div>
</div>
</div>
<div class="col-12 clearfix post">
<div class="panel">
<div class="imgBox imgBox-reverse">
<div class="img">
<img src="~/assets/img/blog/blog-post.jpg" alt="">
</div>
</div>
<div class="txtBox">
<div class="date-category">
<span class="category">
<span>Category /</span>
<span>News</span>
</span>
<span class="date">30/05/2020</span>
</div>
<h4>گریتینگ چیست</h4>
<p>گریتینگ چیست در این نوشته به پاسخ به سوال گریتینگ چیست خواهیم پرداخت گریتینگ در اصل به صفحات مشبکی گفته میشود که به دلیل داشتن خصوصیات بارزی مانند وزن پایین تر, امکان عبور هوا و نور, قیمت تمام شده پایین تر, ظاهری زیباتر و مزایای بسیار دیگری نسبت به سایر محصولات مشابه خود امروزه جایگاه ویژه ای در صنایع گوناگون و همچنین شهرسازی بدست آورده است و هر روزه بر کاربرد آن افزوده میشود. با توجه به این افزایش کاربرد امروز گریتینگ ها را در []</p>
<nuxt-link :to="{name: 'lang-blog-post',params: {lang: $route.params.lang,post: 2}}" class="btn btn-primary">{{staticData.t5}}</nuxt-link>
</div>
</div>
</div>
<div class="row" v-else>
<div class="col-12">
<p class="no-post">هیچ پستی در این دسته بندی موجود نمیباشد.</p>
</div>
</div>
</div>
@@ -80,10 +67,45 @@
</template>
<script>
import moment from 'moment-jalaali'
export default {
data() {
return {
posts: null,
blogCategories: null,
filter: false
}
},
computed: {
staticData() {
return this.$store.state.staticData.blog[this.$route.params.lang]
},
filtered_posts() {
if (!this.filter) return this.posts
else return this.posts.filter(item => item.category === this.filter)
}
},
methods: {
categoryName(id) {
return this.blogCategories.filter(item => item._id === id)[0].blogCategory_details[this.$route.params.lang].name
},
jDate(date) {
if (this.$route.params.lang === 'fa') return moment(date).format('jYYYY/jMM/jDD')
else return date.split(' ')[0]
},
filtering(key) {
this.filter = key
$('.blog--page .filters p').removeClass('active')
$(event.target).addClass('active')
}
},
async asyncData({$axios, store}) {
let posts = await $axios.get(`/api/public/blog`)
const blogCategories = await $axios.get(`/api/public/blogCategories`)
return {
posts: posts.data,
blogCategories: blogCategories.data
}
}
}
+49 -16
View File
@@ -69,46 +69,45 @@
<div class="row">
<div class="col-12">
<h2>{{staticData.t6}}</h2>
<form class="form">
<form class="form" @submit.prevent="upload">
<div class="row">
<div class="col-12">
<div class="formRow center-align">
<div class="formRow center-align" :class="validation.reason ? 'err' : null">
<select name="reason" v-model="formData.reason">
<option disabled selected :value="false">{{staticData.t7}}</option>
<option value="wtf">دلیل خاصی ندارم والا هوثلم سر رفته بود</option>
<option value="">2</option>
<option value="">3</option>
<option v-for="item in reasons" :key="item._id" :value="item.reason_details.fa.reason">{{item.reason_details[$route.params.lang].reason}}</option>
</select>
<p v-if="validation.reason">{{validation.reason.msg}}</p>
</div>
</div>
<div class="col-6">
<div class="formRow err">
<div class="formRow" :class="validation.first_name ? 'err' : null">
<input type="text" :placeholder="staticData.t8" name="first_name" v-model="formData.first_name">
<p>err</p>
<p v-if="validation.first_name">{{validation.first_name.msg}}</p>
</div>
</div>
<div class="col-6">
<div class="formRow">
<div class="formRow" :class="validation.last_name ? 'err' : null">
<input type="text" :placeholder="staticData.t9" name="last_name" v-model="formData.last_name">
<p>err</p>
<p v-if="validation.last_name">{{validation.last_name.msg}}</p>
</div>
</div>
<div class="col-6">
<div class="formRow">
<div class="formRow" :class="validation.phone_number ? 'err' : null">
<input type="text" :placeholder="staticData.t10" name="phone_number" v-model="formData.phone_number">
<p>err</p>
<p v-if="validation.phone_number">{{validation.phone_number.msg}}</p>
</div>
</div>
<div class="col-6">
<div class="formRow">
<div class="formRow" :class="validation.email ? 'err' : null">
<input type="text" :placeholder="staticData.t11" name="email" v-model="formData.email">
<p>err</p>
<p v-if="validation.email">{{validation.email.msg}}</p>
</div>
</div>
<div class="col-12">
<div class="formRow">
<div class="formRow" :class="validation.message ? 'err' : null">
<textarea :placeholder="staticData.t12" name="message" v-model="formData.message"></textarea>
<p>err</p>
<p v-if="validation.message">{{validation.message.msg}}</p>
</div>
</div>
<div class="col-12">
@@ -138,13 +137,47 @@
email: '',
message: '',
locale: this.$route.params.lang
}
},
reasons: null,
validation: {}
}
},
computed: {
staticData() {
return this.$store.state.staticData.contact[this.$route.params.lang]
}
},
methods: {
upload() {
this.validation = {}
const data = this.formData
this.$axios.post(`/api/public/contact`, data)
.then(res => {
this.$message({
message: this.staticData.t14,
type: 'success'
})
this.formData = {
reason: false,
first_name: '',
last_name: '',
phone_number: '',
email: '',
message: '',
locale: this.$route.params.lang
}
})
.catch(err => {
if (err.response.status === 422) this.validation = err.response.data.validation
else console.log(err.response.data.message)
})
}
},
async asyncData({$axios}) {
const reasons = await $axios.get(`/api/public/contact/reason`)
return {
reasons: reasons.data
}
}
}
</script>
+26 -56
View File
@@ -2,25 +2,11 @@
<div class="page home--page">
<div id="slider">
<div class="hero clearfix">
<div class="bg"></div>
<div class="hero clearfix" v-for="item in slider" :key="item._id">
<div class="bg" :style="{backgroundImage: `url(${item.image})`}"></div>
<div class="txt--home">
<h1>{{staticData.hero.t1}}</h1>
<p>{{staticData.hero.t2}}</p>
</div>
</div>
<div class="hero clearfix">
<div class="bg"></div>
<div class="txt--home">
<h1>{{staticData.hero.t1}}</h1>
<p>{{staticData.hero.t2}}</p>
</div>
</div>
<div class="hero clearfix">
<div class="bg"></div>
<div class="txt--home">
<h1>{{staticData.hero.t1}}</h1>
<p>{{staticData.hero.t2}}</p>
<h1>{{item.slider_details[$route.params.lang].title}}</h1>
<p>{{item.slider_details[$route.params.lang].caption}}</p>
</div>
</div>
</div>
@@ -41,6 +27,7 @@
</div>
</div>
</section>
<section class="s1-2">
<img src="~/assets/img/home/hp-s1-i2.jpg" alt="" class="section-bg">
<div class="container">
@@ -58,6 +45,7 @@
</div>
</div>
</section>
<section class="s2">
<img src="~/assets/img/home/hp-s2-i1.jpg" alt="" class="section-bg">
<div class="container">
@@ -99,6 +87,7 @@
</div>
</div>
</section>
<section class="s3">
<img src="~/assets/img/home/hp-s3-i1.jpg" alt="" class="section-bg">
<div class="container clearfix">
@@ -112,11 +101,11 @@
</div>
<div class="products">
<div class="parts p2 row">
<div class="col-4" v-for="item in products">
<nuxt-link :to="{name: 'lang-products-product',params: {lang: $route.params.lang,product: item.url}}">
<div class="col-4" v-for="(item,index) in products" :key="item._id" v-if="index <= 5">
<nuxt-link :to="{name: 'lang-products-product',params: {lang: $route.params.lang,product: item._id}}">
<div class="imgBox">
<img :src="require(`~/assets/img/home/${item.img}`)" alt="">
<p>{{item.txt}}</p>
<img :src="item.cover" :alt="item.product_details[$route.params.lang].name">
<p>{{item.product_details[$route.params.lang].name}}</p>
</div>
</nuxt-link>
</div>
@@ -132,7 +121,7 @@
<div class="txt">
<h2 class="title title-shape">{{staticData.s4.t1}} <span>{{staticData.s4.t2}}</span></h2>
<p>{{staticData.s4.t3}}</p>
<a :href="catalog_link" target="_blank" download="catalog.pdf" class="btn btn-reverse-fill">{{staticData.s4.link}}</a>
<a :href="catalog.file" target="_blank" class="btn btn-reverse-fill">{{staticData.s4.link}}</a>
</div>
</section>
<CustomersCommunication/>
@@ -160,39 +149,9 @@
export default {
data() {
return {
products: [
{
img: 'hp-s3-i5.jpg',
txt: 'گریتینگ پله',
url: '1'
},
{
img: 'hp-s3-i6.jpg',
txt: 'گریتینگ گالوانیزه',
url: '2'
},
{
img: 'hp-s3-i7.jpg',
txt: 'گریتینگ آلومینیوم',
url: '3'
},
{
img: 'hp-s3-i8.jpg',
txt: 'گریتینگ الکتروفورج',
url: '4'
},
{
img: 'hp-s3-i9.jpg',
txt: 'پنل گریتینگ',
url: '5'
},
{
img: 'hp-s3-i10.jpg',
txt: 'گریتینگ تسمه در تسمه',
url: '6'
}
],
catalog_link: this.$store.state.staticData.catalog_link,
slider: null,
products: null,
catalog: null,
calc_app_link: this.$store.state.staticData.calc_app_link,
validation: []
}
@@ -232,6 +191,17 @@
autoplay: true,
autoplaySpeed: 6000
})
},
async asyncData({$axios}) {
const slider = await $axios.get('/api/public/slider')
const products = await $axios.get(`/api/public/products`)
const catalog = await $axios.get('/api/public/catalog')
return {
slider: slider.data,
products: products.data,
catalog: catalog.data
}
}
}
</script>
+55 -55
View File
@@ -4,41 +4,26 @@
<section class="s1">
<div class="container">
<div class="panel">
<h2 class="title">گریتینگ تولید شده به روش الکتروفورج با چهار پهلوی تابیده</h2>
<p>استفاده از تجهیزات مدرن تولید و تیم مهندسی قوی موجب شده تا شرکت اراک ریل دارای گسترده ترین رنج محصولات گریتینگ را داشته باشد و همچنین ما را قادر می سازد تا در صورت نیاز، محصول را مطابق با نیاز شما طراحی کرده و مطابق با استانداردهای بین اللملی تولید کنیم</p>
<h2 class="title">{{productDetails.page_title}}</h2>
<p>{{productDetails.page_description}}</p>
<div class="image-preview">
<img src="~/assets/img/products/product-01.jpg" alt="">
<img :src="product.cover" ref="preview" :alt="productDetails.name">
</div>
</div>
<div class="images-carousel">
<div id="images">
<div class="imgBox">
<img src="~/assets/img/products/product-01.jpg" alt="">
<img :src="product.cover" :alt="productDetails.name" @click="view(product.cover)">
</div>
<div class="imgBox">
<img src="~/assets/img/products/product-01.jpg" alt="">
</div>
<div class="imgBox">
<img src="~/assets/img/products/product-01.jpg" alt="">
</div>
<div class="imgBox">
<img src="~/assets/img/products/product-01.jpg" alt="">
</div>
<div class="imgBox">
<img src="~/assets/img/products/product-01.jpg" alt="">
</div>
<div class="imgBox">
<img src="~/assets/img/products/product-01.jpg" alt="">
</div>
<div class="imgBox">
<img src="~/assets/img/products/product-01.jpg" alt="">
<div class="imgBox" v-for="item in product.images" :key="item._id">
<img :src="item.image" :alt="productDetails.name" @click="view(item.image)">
</div>
</div>
</div>
</div>
</section>
<section class="s2">
<section class="s2" v-if="product.more_section">
<div class="container">
<div class="panel">
<div class="parts p1">
@@ -48,12 +33,12 @@
<!-- image left -->
<div class="parts row align-items-center">
<div class="col-6">
<h2 class="title title-subtitle">خط برش تسمه</h2>
<p>خط برش اولین مرحله از فرآیند تولید است که در آن ، کویل های فولادی به صورت طولی مطابق با الزامات گریتینگهای فلزی تولید می شوند ، تسمه از کویلهای برش خورده آماده شده و به صورت ساده و یا دندانه دار برای استفاده در مرحله بعدی بسته بندی می گردد.</p>
<h2 class="title title-subtitle">{{productDetails.more_title1}}</h2>
<p>{{productDetails.more_description1}}</p>
</div>
<div class="col-6">
<div class="imgBox imgBox-shape">
<img src="~/assets/img/services/s2-i1.jpg" alt="">
<img :src="product.more_section_image1" :alt="productDetails.more_title1">
</div>
</div>
</div>
@@ -62,12 +47,12 @@
<div class="parts row align-items-center">
<div class="col-6">
<div class="imgBox imgBox-reverse imgBox-shape-reverse">
<img src="~/assets/img/services/s2-i2.jpg" alt="">
<img :src="product.more_section_image2" :alt="productDetails.more_title2">
</div>
</div>
<div class="col-6">
<h2 class="title title-subtitle">تولید پنل گریتینگ الکتروفورج</h2>
<p>در این مرحله تسمه ها به همراه چهار پهلوی تابیده شده در سیستم قرارداده شده و دستگاه الکتروفورج با ایجاد همزمان جریان بالای الکتریکی و فشار مکانیکی، سبب می شود تا تسمه های باربر و رابط در نقاط اتصال به دمای ذوب نزدیک شده و دو قطعه کاملا در هم فرو رفته و اتصال کاملا یکنواخت و یک پارچه ای ایجاد گردد.</p>
<h2 class="title title-subtitle">{{productDetails.more_title2}}</h2>
<p>{{productDetails.more_description2}}</p>
</div>
</div>
@@ -75,54 +60,46 @@
</div>
</section>
<section class="s3">
<section class="s3"
v-if="!product.render_image1.includes('undefined') ||
!product.render_image2.includes('undefined') ||
product.download_section">
<div class="container">
<div class="panel">
<div class="parts p1">
<div class="parts p1" v-if="!product.render_image1.includes('undefined') || !product.render_image1.includes('undefined')">
<h2 class="title">نمایش گرافیکی مشخصات</h2>
<p>در شماتیک زیر مشخصات اولیه گریتینگ نمایش داده شده است</p>
</div>
<div class="row parts p2">
<div class="row parts p2" v-if="!product.render_image1.includes('undefined') || !product.render_image2.includes('undefined')">
<div class="col-6 mb-5">
<img src="~/assets/img/products/pd-s3-i1.jpg" alt="">
<p>نمایش ایزومتریک گریتینگ الکتروفورج</p>
<img :src="product.render_image1" :alt="productDetails.name" v-if="!product.render_image1.includes('undefined')">
<p v-if="!product.render_image1.includes('undefined')">{{productDetails.render_caption1}}</p>
</div>
<div class="col-6 mb-5">
<img src="~/assets/img/products/pd-s3-i2.jpg" alt="">
<p>نمای روبرو از گریتینگ الکتروفورج</p>
<img :src="product.render_image2" :alt="productDetails.name" v-if="!product.render_image2.includes('undefined')">
<p v-if="!product.render_image2.includes('undefined')">{{productDetails.render_caption2}}</p>
</div>
<div class="col-12 mb-5">
<img src="~/assets/img/products/chart.jpg" alt="">
<img :src="product.chart_image" :alt="productDetails.name" v-if="!product.chart_image.includes('undefined')">
</div>
</div>
<div class="row parts p3">
<div class="row parts p3" v-if="productDetails.chart_title">
<div class="col-12">
<h2 class="title">جدول مشخصات گامها و ضخامتهای گریتینگها قابل تولید</h2>
<p>با توجه به شماتیک گریتینگ ارائه شده در نمای بالا، تنوع گسترده ای از گریتینگها به روش الکتروفورج قابل تولید می باشد.
مشخصات زیر گریتینگهای متداول به لحاظ تولید در شرکت اراک ریل بوده و در صورت نیاز کارشناسان این شرکت آماده مشاوره در این زمینه باشند.</p>
<h2 class="title">{{productDetails.chart_title}}</h2>
<p>{{productDetails.chart_description}}</p>
</div>
</div>
<div class="row parts p4">
<div class="row parts p4" v-if="product.download_section">
<div class="col-12">
<h2>فایل های قابل دانلود</h2>
<div class="files">
<div class="file">
<div class="file" v-for="item in product.pdf_files" :key="item._id">
<pdf-icon/>
<p>نام فایل</p>
<a href="" target="_blank" class="btn btn-primary-fill">دانلود</a>
</div>
<div class="file">
<pdf-icon/>
<p>نام فایل</p>
<a href="" target="_blank" class="btn btn-primary-fill">دانلود</a>
</div>
<div class="file">
<pdf-icon/>
<p>نام فایل</p>
<a href="" target="_blank" class="btn btn-primary-fill">دانلود</a>
<p>{{item.pdf_details[$route.params.lang].name}}</p>
<a :href="item.file" :download="item.pdf_details[$route.params.lang].name" target="_blank" class="btn btn-primary-fill">دانلود</a>
</div>
</div>
</div>
@@ -146,16 +123,39 @@
<script>
if (process.client) require('slick-carousel')
export default {
data() {
return {
product: null
}
},
computed: {
staticData() {
return this.$store.state.staticData.products_details[this.$route.params.lang]
},
productDetails() {
return this.product.product_details[this.$route.params.lang]
}
},
methods: {
view(image) {
// console.log(image)
this.$refs.preview.src = image
}
},
mounted() {
$('#images').slick({
slidesToShow: 4,
rtl: this.$route.params.lang === 'fa'
rtl: this.$route.params.lang === 'fa',
infinite: false
})
},
async asyncData({$axios, params}) {
let product = await $axios.get(`/api/public/product/${params.product}`)
let productCategories = await $axios.get(`/api/public/productCategories`)
return {
product: product.data,
productCategories: productCategories.data
}
}
}
</script>
+53 -53
View File
@@ -11,59 +11,34 @@
</section>
<section class="s2">
<div class="container">
<!-- <div class="filters">-->
<!-- <h2 class="title title-subtitle">{{staticData.s2.t1}}</h2>-->
<!-- <ul>-->
<!-- <li-->
<!-- v-for="item in staticData.s2.filters"-->
<!-- :key="item.key"-->
<!-- @click="filter(item.key)">-->
<!-- <p>{{item.txt}}</p>-->
<!-- </li>-->
<!-- </ul>-->
<!-- </div>-->
<div class="row">
<div class="col-3 mb-5">
<nuxt-link :to="{name: 'lang-products-product',params: {lang: $route.params.lang,product: 1}}" class="product">
<img src="~/assets/img/products/product-01.jpg" alt="">
<h4>گریتینگ</h4>
<p>توضیحات کوتاه</p>
<div class="filters">
<h2 class="title title-subtitle">{{staticData.s2.t1}}</h2>
<ul>
<li @click="filtering(false)">
<p class="active">همه</p>
</li>
<li
v-for="item in productCategories"
:key="item._id"
@click="filtering(item._id)">
<p>{{item.category_details[$route.params.lang].name}}</p>
</li>
</ul>
</div>
<div class="row" v-if="filtered_products.length">
<div class="col-3 mb-5" v-for="item in filtered_products" :key="item._id">
<nuxt-link :to="{name: 'lang-products-product',params: {lang: $route.params.lang,product: item._id}}" class="product">
<img :src="item.cover" :alt="item.product_details[$route.params.lang].name">
<h4>{{item.product_details[$route.params.lang].name}}</h4>
<p>{{item.product_details[$route.params.lang].short_description}}</p>
</nuxt-link>
</div>
<div class="col-3 mb-5">
<nuxt-link :to="{name: 'lang-products-product',params: {lang: $route.params.lang,product: 2}}" class="product">
<img src="~/assets/img/products/product-01.jpg" alt="">
<h4>گریتینگ</h4>
<p>توضیحات کوتاه</p>
</nuxt-link>
</div>
<div class="col-3 mb-5">
<nuxt-link :to="{name: 'lang-products-product',params: {lang: $route.params.lang,product: 3}}" class="product">
<img src="~/assets/img/products/product-01.jpg" alt="">
<h4>گریتینگ</h4>
<p>توضیحات کوتاه</p>
</nuxt-link>
</div>
<div class="col-3 mb-5">
<nuxt-link :to="{name: 'lang-products-product',params: {lang: $route.params.lang,product: 4}}" class="product">
<img src="~/assets/img/products/product-01.jpg" alt="">
<h4>گریتینگ</h4>
<p>توضیحات کوتاه</p>
</nuxt-link>
</div>
<div class="col-3 mb-5">
<nuxt-link :to="{name: 'lang-products-product',params: {lang: $route.params.lang,product: ''}}" class="product">
<img src="~/assets/img/products/product-01.jpg" alt="">
<h4>گریتینگ</h4>
<p>توضیحات کوتاه</p>
</nuxt-link>
</div>
<div class="col-3 mb-5">
<nuxt-link :to="{name: 'lang-products-product',params: {lang: $route.params.lang,product: ''}}" class="product">
<img src="~/assets/img/products/product-01.jpg" alt="">
<h4>گریتینگ</h4>
<p>توضیحات کوتاه</p>
</nuxt-link>
</div>
<div class="row" v-else>
<div class="col-12">
<p class="no-product">هیچ محصولی در این دسته بندی موجود نمیباشد.</p>
</div>
</div>
</div>
@@ -76,7 +51,7 @@
<span class="subtitle">{{staticData.s3.t2}}</span>
</h2>
<p>{{staticData.s3.t3}}</p>
<a href="" target="_blank" class="btn btn-reverse-fill">{{staticData.s3.t4}}</a>
<a :href="catalog.file" target="_blank" class="btn btn-reverse-fill">{{staticData.s3.t4}}</a>
</div>
</div>
</section>
@@ -85,14 +60,39 @@
<script>
export default {
data() {
return {
products: null,
productCategories: null,
catalog: null,
filter: false
}
},
computed: {
staticData() {
return this.$store.state.staticData.products[this.$route.params.lang]
},
filtered_products() {
if (!this.filter) return this.products
else return this.products.filter(item => item.category === this.filter)
}
},
methods: {
filter(key) {
filtering(key) {
this.filter = key
$('.products--page .filters p').removeClass('active')
$(event.target).addClass('active')
}
},
async asyncData({$axios, store}) {
const products = await $axios.get(`/api/public/products`)
const productCategories = await $axios.get(`/api/public/productCategories`)
const catalog = await $axios.get('/api/public/catalog')
return {
products: products.data,
productCategories: productCategories.data,
catalog: catalog.data
}
}
}
+39 -101
View File
@@ -10,92 +10,23 @@
<div class="projects">
<div class="project">
<div id="project1">
<div class="imgBox">
<img class="bg" src="~/assets/img/products/product-01.jpg" alt="">
<img class="img" src="~/assets/img/products/product-01.jpg" alt="">
</div>
<div class="imgBox">
<img class="bg" src="~/assets/img/products/product-01.jpg" alt="">
<img class="img" src="~/assets/img/products/product-01.jpg" alt="">
</div>
<div class="imgBox">
<img class="bg" src="~/assets/img/products/product-01.jpg" alt="">
<img class="img" src="~/assets/img/products/product-01.jpg" alt="">
</div>
<div class="imgBox">
<img class="bg" src="~/assets/img/products/product-01.jpg" alt="">
<img class="img" src="~/assets/img/products/product-01.jpg" alt="">
</div>
<div class="imgBox">
<img class="bg" src="~/assets/img/products/product-01.jpg" alt="">
<img class="img" src="~/assets/img/products/product-01.jpg" alt="">
<div class="project" v-for="(item,index) in projects" :key="item._id">
<div :id="`project_${index}`">
<div class="imgBox" v-for="image in item.images" :key="image._id">
<img class="bg" :src="image.image" alt="">
<img class="img" :src="image.image" alt="">
</div>
</div>
<div class="caption">
<h4>پروژه ی فلان جا</h4>
<p>1399/07/04</p>
</div>
</div>
<div class="project">
<div id="project2">
<div class="imgBox">
<img class="bg" src="~/assets/img/products/product-01.jpg" alt="">
<img class="img" src="~/assets/img/products/product-01.jpg" alt="">
</div>
<div class="imgBox">
<img class="bg" src="~/assets/img/products/product-01.jpg" alt="">
<img class="img" src="~/assets/img/products/product-01.jpg" alt="">
</div>
<div class="imgBox">
<img class="bg" src="~/assets/img/products/product-01.jpg" alt="">
<img class="img" src="~/assets/img/products/product-01.jpg" alt="">
</div>
<div class="imgBox">
<img class="bg" src="~/assets/img/products/product-01.jpg" alt="">
<img class="img" src="~/assets/img/products/product-01.jpg" alt="">
</div>
<div class="imgBox">
<img class="bg" src="~/assets/img/products/product-01.jpg" alt="">
<img class="img" src="~/assets/img/products/product-01.jpg" alt="">
</div>
</div>
<div class="caption">
<h4>پروژه ی فلان جا</h4>
<p>1399/07/04</p>
</div>
</div>
<div class="project">
<div id="project3">
<div class="imgBox">
<img class="bg" src="~/assets/img/products/product-01.jpg" alt="">
<img class="img" src="~/assets/img/products/product-01.jpg" alt="">
</div>
<div class="imgBox">
<img class="bg" src="~/assets/img/products/product-01.jpg" alt="">
<img class="img" src="~/assets/img/products/product-01.jpg" alt="">
</div>
<div class="imgBox">
<img class="bg" src="~/assets/img/products/product-01.jpg" alt="">
<img class="img" src="~/assets/img/products/product-01.jpg" alt="">
</div>
<div class="imgBox">
<img class="bg" src="~/assets/img/products/product-01.jpg" alt="">
<img class="img" src="~/assets/img/products/product-01.jpg" alt="">
</div>
<div class="imgBox">
<img class="bg" src="~/assets/img/products/product-01.jpg" alt="">
<img class="img" src="~/assets/img/products/product-01.jpg" alt="">
</div>
</div>
<div class="caption">
<h4>پروژه ی فلان جا</h4>
<p>1399/07/04</p>
<h4>{{item.project_details[$route.params.lang].name}}</h4>
<p class="description">{{item.project_details[$route.params.lang].description}}</p>
<p>
<span>{{staticData.t6}}</span>
<span>{{jDate(item.date)}}</span>
</p>
</div>
</div>
</div>
</div>
</div>
@@ -114,35 +45,42 @@
</template>
<script>
import moment from "moment-jalaali"
if (process.client) require('slick-carousel')
export default {
data() {
return {
projects: null
}
},
computed: {
staticData() {
return this.$store.state.staticData.projects[this.$route.params.lang]
}
},
methods: {
jDate(date) {
if (this.$route.params.lang === 'fa') return moment(date).format('jYYYY/jMM/jDD')
else return date.split(' ')[0]
}
},
mounted() {
$('#project1').slick({
slidesToShow: 1,
centerMode: true,
centerPadding: '150px',
infinite: true,
arrows: true
})
$('#project2').slick({
slidesToShow: 1,
centerMode: true,
centerPadding: '150px',
infinite: true,
arrows: true
})
$('#project3').slick({
slidesToShow: 1,
centerMode: true,
centerPadding: '150px',
infinite: true,
arrows: true
this.projects.forEach((item, index) => {
$(`#project_${index}`).slick({
slidesToShow: 1,
centerMode: true,
centerPadding: '150px',
infinite: true,
arrows: true
})
})
},
async asyncData({$axios}) {
const projects = await $axios.get(`/api/public/projects`)
return {
projects: projects.data
}
}
}
</script>
+187
View File
@@ -0,0 +1,187 @@
<template>
<div class="container-fluid">
<div class="row">
<admin-title-bar :title="title">
<el-button @click="$router.back()" type="primary">برگشت به صفحه قبل</el-button>
<el-button type="success" @click="upload">بروزرسانی</el-button>
</admin-title-bar>
<div class="col-12">
<admin-panel>
<h2>تصویر</h2>
<el-divider></el-divider>
<img :src="post.cover" alt="" style="width: 100%">
<input type="file" ref="cover" @change="preview">
<p class="err" v-if="validation.cover">{{validation.cover.msg}}</p>
<el-form class="secondTitle">
<el-form-item prop="category" :class="validation.category ? 'is-error' : ''" label="دسته بندی">
<el-select v-model="post.category" placeholder="انتخاب کنید">
<el-option
v-for="item in blogCategories"
:key="item._id"
:label="item.blogCategory_details.fa.name"
:value="item._id">
</el-option>
</el-select>
<p class="err" v-if="validation.category">{{validation.category.msg}}</p>
</el-form-item>
<el-form-item prop="published" label="وضعیت انتشار پست">
<el-switch v-model="post.published" style="margin-right: 15px;"></el-switch>
</el-form-item>
</el-form>
</admin-panel>
</div>
<!-- fa -->
<div class="col-6">
<admin-panel>
<h2>فارسی</h2>
<el-divider></el-divider>
<el-form>
<el-form-item prop="title" :class="validation.fa_title ? 'is-error' : ''" label="عنوان">
<el-input v-model="post.post_details.fa.title"></el-input>
<p class="err" v-if="validation.fa_title">{{validation.fa_title.msg}}</p>
</el-form-item>
<el-form-item prop="short_description" :class="validation.fa_short_description ? 'is-error' : ''" label="توضیح کوتاه">
<el-input type="textarea" v-model="post.post_details.fa.short_description"></el-input>
<p class="err" v-if="validation.fa_short_description">{{validation.fa_short_description.msg}}</p>
</el-form-item>
</el-form>
<el-divider></el-divider>
<h6 style="margin-bottom: 30px;">توضیحات پست</h6>
<client-only>
<ckeditor v-model="post.post_details.fa.description" :config="editorConfig"></ckeditor>
<p class="err" v-if="validation.fa_description">{{validation.fa_description.msg}}</p>
</client-only>
</admin-panel>
</div>
<!-- en -->
<div class="col-6">
<admin-panel>
<h2>انگلیسی</h2>
<el-divider></el-divider>
<el-form>
<el-form-item prop="title" :class="validation.en_title ? 'is-error' : ''" label="عنوان">
<el-input v-model="post.post_details.en.title"></el-input>
<p class="err" v-if="validation.en_title">{{validation.en_title.msg}}</p>
</el-form-item>
<el-form-item prop="short_description" :class="validation.en_short_description ? 'is-error' : ''" label="توضیح کوتاه">
<el-input type="textarea" v-model="post.post_details.en.short_description"></el-input>
<p class="err" v-if="validation.en_short_description">{{validation.en_short_description.msg}}</p>
</el-form-item>
</el-form>
<el-divider></el-divider>
<h6 style="margin-bottom: 30px;">توضیحات پست</h6>
<client-only>
<ckeditor v-model="post.post_details.en.description" :config="editorConfig"></ckeditor>
<p class="err" v-if="validation.en_description">{{validation.en_description.msg}}</p>
</client-only>
</admin-panel>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
post: null,
blogCategories: null,
editorConfig: {
language: 'en',
extraPlugins: ['bidi']
},
validation: {},
uploading: false,
uploadProgress: null
}
},
computed: {
title() {
if (!this.uploading) {
return 'ویرایش پست'
} else {
return this.uploadProgress
}
}
},
methods: {
upload() {
this.validation = {}
const data = new FormData()
data.append('fa_title', this.post.post_details.fa.title)
data.append('en_title', this.post.post_details.en.title)
data.append('fa_description', this.post.post_details.fa.description)
data.append('en_description', this.post.post_details.en.description)
data.append('fa_short_description', this.post.post_details.fa.short_description)
data.append('en_short_description', this.post.post_details.en.short_description)
data.append('published', this.post.published)
data.append('category', this.post.category)
if (this.$refs.cover.files[0]) data.append('cover', this.$refs.cover.files[0])
const axiosConfig = {
onUploadProgress: progressEvent => {
this.uploading = true
this.uploadProgress = 'درحال آپلود ' + Math.floor(((progressEvent.loaded / progressEvent.total) * 100)) + '%'
if ((progressEvent.loaded / progressEvent.total) * 100 === 100) {
this.uploading = false
}
}
}
this.$axios.put(`/api/private/blog/${this.post._id}`, data, axiosConfig)
.then(response => {
this.$message({
message: 'پست با موفقیت بروزرسانی شد.',
type: 'success'
})
}).catch(error => {
if (error.response.status === 422) {
this.validation = error.response.data.validation
this.$message({
type: 'error',
message: 'اطلاعات رو بررسی و دوباره تلاش کنید'
})
} else {
this.$alert(error.response.data.message, 'خطا', {
confirmButtonText: 'باشه',
})
}
})
},
preview(event) {
this.post.cover = URL.createObjectURL(event.target.files[0]);
}
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({$axios, params}) {
const post = await $axios.get(`/api/public/blog/${params.post}`)
const blogCategories = await $axios.get(`/api/public/blogCategories`)
return {
post: post.data,
blogCategories: blogCategories.data
}
}
}
</script>
+102
View File
@@ -0,0 +1,102 @@
<template>
<div class="container-fluid">
<div class="row">
<admin-title-bar :title="title">
<el-button @click="$router.back()" type="primary">برگشت به صفحه قبل</el-button>
<el-button type="success" @click="upload">بروزرسانی</el-button>
</admin-title-bar>
<div class="col-6">
<admin-panel>
<el-form>
<el-form-item prop="title" :class="validation.fa_name ? 'is-error' : ''" label="نام فارسی">
<el-input v-model="formData.blogCategory_details.fa.name"></el-input>
<p class="err" v-if="validation.fa_name">{{validation.fa_name.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.en_name ? 'is-error' : ''" label="نام انگلیسی">
<el-input v-model="formData.blogCategory_details.en.name"></el-input>
<p class="err" v-if="validation.en_name">{{validation.en_name.msg}}</p>
</el-form-item>
</el-form>
</admin-panel>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
formData: null,
validation: {},
uploading: false,
uploadProgress: null
}
},
computed: {
title() {
if (!this.uploading) {
return 'اصلاح دسته بندی'
} else {
return this.uploadProgress
}
}
},
methods: {
upload() {
this.validation = ''
const data = {
fa_name: this.formData.blogCategory_details.fa.name,
en_name: this.formData.blogCategory_details.en.name
}
const axiosConfig = {
onUploadProgress: progressEvent => {
this.uploading = true
this.uploadProgress = 'درحال آپلود ' + Math.floor(((progressEvent.loaded / progressEvent.total) * 100)) + '%'
if ((progressEvent.loaded / progressEvent.total) * 100 === 100) {
this.uploading = false
}
}
}
this.$axios.put(`/api/private/blogCategories/${this.formData._id}`, data, axiosConfig)
.then(response => {
if (response.data) {
this.$message({
message: 'دسته بندی با موفقیت بروزرسانی شد.',
type: 'success'
})
}
}).catch(error => {
if (error.response.status === 422) {
this.validation = error.response.data.validation
this.$message({
type: 'error',
message: 'اطلاعات رو بررسی و دوباره تلاش کنید'
})
} else {
this.$alert(error.response.data.message, 'خطا', {
confirmButtonText: 'باشه',
})
}
})
}
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({$axios, params}) {
const category = await $axios.get(`/api/public/blogCategories/${params.category}`)
return {
formData: category.data
}
}
}
</script>
+97
View File
@@ -0,0 +1,97 @@
<template>
<div class="container-fluid">
<div class="row">
<admin-title-bar :title="title">
<nuxt-link :to="{name: 'admin-blog-category-new'}">
<el-button type="success">جدید</el-button>
</nuxt-link>
</admin-title-bar>
<div class="col-12">
<admin-panel>
<el-table
:data="blogCategories"
style="width: 100%">
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
prop="blogCategory_details.fa.name"
label="نام دسته بندی"
width="">
</el-table-column>
<el-table-column
label="ویرایش"
width="150"
align="left">
<template slot-scope="scope">
<el-button type="warning" plain icon="el-icon-edit" @click="edit(scope.row._id)"></el-button>
<el-button type="danger" plain icon="el-icon-delete" @click="del(scope.row._id)"></el-button>
</template>
</el-table-column>
</el-table>
</admin-panel>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
title: 'دسته بندی بلاگ',
blogCategories: null
}
},
head() {
return {
title: this.title,
}
},
methods: {
edit(id) {
this.$router.push(`/admin/blog/category/${id}`)
},
del(id) {
this.$confirm('این آیتم حذف شود؟', 'هشدار', {
confirmButtonText: 'بله',
cancelButtonText: 'لغو',
type: 'warning'
}).then(() => {
this.$axios.delete(`/api/private/blogCategories/${id}`)
.then(response => {
this.blogCategories = this.blogCategories.filter(item => {
return item._id !== id
})
this.$message({
type: 'success',
message: 'آیتم حذف شد'
});
})
.catch(err => {
this.$alert(err.response.data.message, 'خطا', {
confirmButtonText: 'OK'
})
})
}).catch(() => {
this.$message({
type: 'warning',
message: 'عملیات لغو شد'
});
});
}
},
layout: 'admin',
async asyncData({$axios}) {
let blogCategories = await $axios.get(`/api/public/blogCategories`)
return {
blogCategories: blogCategories.data
}
}
}
</script>
+107
View File
@@ -0,0 +1,107 @@
<template>
<div class="container-fluid">
<div class="row">
<admin-title-bar :title="title">
<el-button @click="$router.back()" type="primary">برگشت به صفحه قبل</el-button>
<el-button type="success" @click="upload">ایجاد</el-button>
</admin-title-bar>
<div class="col-6">
<admin-panel>
<el-form>
<el-form-item prop="title" :class="validation.fa_name ? 'is-error' : ''" label="نام فارسی">
<el-input v-model="formData.blogCategory_details.fa.name"></el-input>
<p class="err" v-if="validation.fa_name">{{validation.fa_name.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.en_name ? 'is-error' : ''" label="نام انگلیسی">
<el-input v-model="formData.blogCategory_details.en.name"></el-input>
<p class="err" v-if="validation.en_name">{{validation.en_name.msg}}</p>
</el-form-item>
</el-form>
</admin-panel>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
formData: {
blogCategory_details: {
fa: {
name: ''
},
en: {
name: ''
}
}
},
validation: {},
uploading: false,
uploadProgress: null
}
},
computed: {
title() {
if (!this.uploading) {
return 'افزودن دسته بندی'
} else {
return this.uploadProgress
}
}
},
methods: {
upload() {
this.validation = {}
const data = {
fa_name: this.formData.blogCategory_details.fa.name,
en_name: this.formData.blogCategory_details.en.name
}
const axiosConfig = {
onUploadProgress: progressEvent => {
this.uploading = true
this.uploadProgress = 'درحال آپلود ' + Math.floor(((progressEvent.loaded / progressEvent.total) * 100)) + '%'
if ((progressEvent.loaded / progressEvent.total) * 100 === 100) {
this.uploading = false
}
}
}
this.$axios.post(`/api/private/blogCategories`, data, axiosConfig)
.then(response => {
if (response.data) {
this.$message({
message: 'دسته بندی با موفقیت ثبت شد.',
type: 'success'
});
this.$router.push({name: 'admin-blog-category'})
}
}).catch(error => {
if (error.response.status === 422) {
this.validation = error.response.data.validation
this.$message({
type: 'error',
message: 'اطلاعات رو بررسی و دوباره تلاش کنید'
})
} else {
this.$alert(error.response.data.message, 'خطا', {
confirmButtonText: 'باشه',
})
}
})
}
},
head() {
return {
title: this.title
}
},
layout: 'admin'
}
</script>
+132
View File
@@ -0,0 +1,132 @@
<template>
<div class="container-fluid">
<div class="row">
<admin-title-bar :title="title">
<nuxt-link :to="{name: 'admin-blog-new'}">
<el-button type="success">جدید</el-button>
</nuxt-link>
</admin-title-bar>
<div class="col-12">
<admin-panel>
<el-table
:data="posts"
style="width: 100%">
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
prop="thumb"
label="تصویر"
width="230">
<template slot-scope="scope">
<el-image
style="width: 100%; height: 100%"
:src="scope.row.thumb"
fit="fit">
</el-image>
</template>
</el-table-column>
<el-table-column
prop="post_details.fa.title"
label="عنوان"
width="">
</el-table-column>
<el-table-column
prop="category"
label="دسته بندی"
width="">
<template slot-scope="scope">
{{categoryName(scope.row.category)}}
</template>
</el-table-column>
<el-table-column
prop="published"
label="وضعیت انتشار"
width="">
<template slot-scope="scope">
<p v-if="scope.row.published" style="color: green;">منتشر شده</p>
<p v-else style="color: red;">منتشر نشده</p>
</template>
</el-table-column>
<el-table-column
label="ویرایش"
width="150"
align="left">
<template slot-scope="scope">
<el-button type="warning" plain icon="el-icon-edit" @click="edit(scope.row._id)"></el-button>
<el-button type="danger" plain icon="el-icon-delete" @click="del(scope.row._id)"></el-button>
</template>
</el-table-column>
</el-table>
</admin-panel>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
title: 'لیست بلاگ',
posts: null,
blogCategories: null
}
},
head() {
return {
title: this.title,
}
},
methods: {
categoryName(categoryID) {
return this.blogCategories.filter(item => {
return item._id === categoryID
})[0].blogCategory_details.fa.name
},
edit(id) {
this.$router.push(`/admin/blog/${id}`)
},
del(id) {
this.$confirm('این پست حذف شود؟', 'هشدار', {
confirmButtonText: 'بله',
cancelButtonText: 'لغو',
type: 'warning'
}).then(() => {
this.$axios.delete(`/api/private/blog/${id}`)
.then(response => {
this.posts = this.posts.filter(item => {
return item._id !== id
})
this.$message({
type: 'success',
message: 'آیتم حذف شد'
})
})
}).catch(() => {
this.$message({
type: 'warning',
message: 'عملیات لغو شد'
});
});
}
},
layout: 'admin',
async asyncData({$axios, store}) {
let posts = await $axios.get(`/api/public/blog`)
const blogCategories = await $axios.get(`/api/public/blogCategories`)
return {
posts: posts.data,
blogCategories: blogCategories.data
}
}
}
</script>
+203
View File
@@ -0,0 +1,203 @@
<template>
<div class="container-fluid">
<div class="row">
<admin-title-bar :title="title">
<el-button @click="$router.back()" type="primary">برگشت به صفحه قبل</el-button>
<el-button type="success" @click="upload">ایجاد</el-button>
</admin-title-bar>
<div class="col-12">
<admin-panel>
<h2>تصویر</h2>
<el-divider></el-divider>
<img :src="post.cover" alt="" style="width: 100%">
<input type="file" ref="cover" @change="preview">
<p class="err" v-if="validation.cover">{{validation.cover.msg}}</p>
<el-form class="secondTitle">
<el-form-item prop="category" :class="validation.category ? 'is-error' : ''" label="دسته بندی">
<el-select v-model="post.category" placeholder="انتخاب کنید">
<el-option
v-for="item in blogCategories"
:key="item._id"
:label="item.blogCategory_details.fa.name"
:value="item._id">
</el-option>
</el-select>
<p class="err" v-if="validation.category">{{validation.category.msg}}</p>
</el-form-item>
<el-form-item prop="published" label="وضعیت انتشار پست">
<el-switch v-model="post.published" style="margin-right: 15px;"></el-switch>
</el-form-item>
</el-form>
</admin-panel>
</div>
<!-- fa -->
<div class="col-6">
<admin-panel>
<h2>فارسی</h2>
<el-divider></el-divider>
<el-form>
<el-form-item prop="title" :class="validation.fa_title ? 'is-error' : ''" label="عنوان">
<el-input v-model="post.post_details.fa.title"></el-input>
<p class="err" v-if="validation.fa_title">{{validation.fa_title.msg}}</p>
</el-form-item>
<el-form-item prop="short_description" :class="validation.fa_short_description ? 'is-error' : ''" label="توضیح کوتاه">
<el-input type="textarea" v-model="post.post_details.fa.short_description"></el-input>
<p class="err" v-if="validation.fa_short_description">{{validation.fa_short_description.msg}}</p>
</el-form-item>
</el-form>
<el-divider></el-divider>
<h6 style="margin-bottom: 30px;">توضیحات پست</h6>
<client-only>
<ckeditor v-model="post.post_details.fa.description" :config="editorConfig"></ckeditor>
<p class="err" v-if="validation.fa_description">{{validation.fa_description.msg}}</p>
</client-only>
</admin-panel>
</div>
<!-- en -->
<div class="col-6">
<admin-panel>
<h2>انگلیسی</h2>
<el-divider></el-divider>
<el-form>
<el-form-item prop="title" :class="validation.en_title ? 'is-error' : ''" label="عنوان">
<el-input v-model="post.post_details.en.title"></el-input>
<p class="err" v-if="validation.en_title">{{validation.en_title.msg}}</p>
</el-form-item>
<el-form-item prop="short_description" :class="validation.en_short_description ? 'is-error' : ''" label="توضیح کوتاه">
<el-input type="textarea" v-model="post.post_details.en.short_description"></el-input>
<p class="err" v-if="validation.en_short_description">{{validation.en_short_description.msg}}</p>
</el-form-item>
</el-form>
<el-divider></el-divider>
<h6 style="margin-bottom: 30px;">توضیحات پست</h6>
<client-only>
<ckeditor v-model="post.post_details.en.description" :config="editorConfig"></ckeditor>
<p class="err" v-if="validation.en_description">{{validation.en_description.msg}}</p>
</client-only>
</admin-panel>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
post: {
post_details: {
fa: {
title: '',
description: '',
short_description: ''
},
en: {
title: '',
description: '',
short_description: ''
}
},
published: true,
category: '',
cover: ''
},
blogCategories: null,
editorConfig: {
language: 'en',
extraPlugins: ['bidi']
},
validation: {},
uploading: false,
uploadProgress: null
}
},
computed: {
title() {
if (!this.uploading) {
return 'افزودن پست'
} else {
return this.uploadProgress
}
}
},
methods: {
upload() {
this.validation = {}
const data = new FormData()
data.append('fa_title', this.post.post_details.fa.title)
data.append('en_title', this.post.post_details.en.title)
data.append('fa_description', this.post.post_details.fa.description)
data.append('en_description', this.post.post_details.en.description)
data.append('fa_short_description', this.post.post_details.fa.short_description)
data.append('en_short_description', this.post.post_details.en.short_description)
data.append('published', this.post.published)
data.append('category', this.post.category)
data.append('cover', this.$refs.cover.files[0])
const axiosConfig = {
onUploadProgress: progressEvent => {
this.uploading = true
this.uploadProgress = 'درحال آپلود ' + Math.floor(((progressEvent.loaded / progressEvent.total) * 100)) + '%'
if ((progressEvent.loaded / progressEvent.total) * 100 === 100) {
this.uploading = false
}
}
}
this.$axios.post(`/api/private/blog`, data, axiosConfig)
.then(response => {
if (response.data) {
this.$message({
message: 'پست با موفقیت ثبت شد.',
type: 'success'
});
this.$router.push({name: 'admin-blog'})
}
}).catch(error => {
if (error.response.status === 422) {
this.validation = error.response.data.validation
this.$message({
type: 'error',
message: 'اطلاعات رو بررسی و دوباره تلاش کنید'
})
} else {
this.$alert(error.response.data.message, 'خطا', {
confirmButtonText: 'باشه',
})
}
})
},
preview(event) {
this.post.cover = URL.createObjectURL(event.target.files[0]);
}
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({$axios, store}) {
const blogCategories = await $axios.get(`/api/public/blogCategories`)
return {
blogCategories: blogCategories.data
}
}
}
</script>
+90
View File
@@ -0,0 +1,90 @@
<template>
<div class="container-fluid">
<div class="row">
<admin-title-bar :title="title"></admin-title-bar>
<div class="col-6">
<admin-panel>
<h2>افزودن یا بروزرسانی کاتالوگ:</h2>
<el-divider></el-divider>
<el-form>
<input type="file" ref="file">
<el-button @click="upload" type="success">افزودن</el-button>
<p style="color: red;" v-if="validation.pdf">{{validation.pdf.msg}}</p>
</el-form>
<el-divider></el-divider>
<a v-if="catalog && catalog.file" :href="catalog.file" target="_blank">
<el-button>دانلود و مشاهده کاتالوگ فعلی</el-button>
</a>
</admin-panel>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
catalog: null,
validation: {},
uploading: false,
uploadProgress: null
}
},
head() {
return {
title: this.title,
}
},
computed: {
title() {
if (!this.uploading) {
return 'آپلود کاتالوگ اصلی سایت'
} else {
return this.uploadProgress
}
}
},
methods: {
upload() {
this.validation = {}
const data = new FormData()
data.append('pdf', this.$refs.file.files[0])
const axiosConfig = {
onUploadProgress: progressEvent => {
this.uploading = true
this.uploadProgress = 'درحال آپلود ' + Math.floor(((progressEvent.loaded / progressEvent.total) * 100)) + '%'
if ((progressEvent.loaded / progressEvent.total) * 100 === 100) {
this.uploading = false
}
}
}
this.$axios.post(`/api/private/catalog`, data, axiosConfig)
.then(res => {
this.$message({
type: 'success',
message: 'کاتالوگ با موفقیت آپلود شد'
})
this.$refs.file.value = null
this.catalog = res.data
})
.catch(err => {
if (err.response.status === 422) this.validation = err.response.data.validation
else console.log(err.response.data)
})
}
},
layout: 'admin',
async asyncData({$axios}) {
let catalog = await $axios.get('/api/public/catalog')
return {
catalog: catalog.data
}
}
}
</script>
+18
View File
@@ -0,0 +1,18 @@
<template>
<div class="container-fluid">
<div class="row">
<admin-title-bar title="صفحه اصلی پنل"/>
<div class="col-12">
<h1>به پنل مدیریت خوش آمدید.</h1>
</div>
</div>
</div>
</template>
<script>
export default {
mounted() {
},
layout: 'admin'
}
</script>
+57
View File
@@ -0,0 +1,57 @@
<template>
<div class="col-12">
<el-form @submit.native.prevent="loginFunction">
<div class="container">
<div class="row">
<div class="col-12">
<admin-panel style="width: 50%;margin: 300px auto 0">
<h1 style="text-align: center;">ورود به پنل مدیریت</h1>
<el-divider></el-divider>
<el-form-item prop="username" :class="validation.username ? 'is-error' : ''" label="نام کاربری">
<el-input v-model="login.username"></el-input>
<p class="err" v-if="validation.username">{{validation.username.msg}}</p>
</el-form-item>
<el-form-item prop="password" :class="validation.password ? 'is-error' : ''" label="پسورد">
<el-input v-model="login.password" type="password"></el-input>
<p class="err" v-if="validation.password">{{validation.password.msg}}</p>
</el-form-item>
<el-checkbox v-model="login.remember_me" style="display: block;margin-top: 30px;margin-bottom: 15px;">مرا به خاطر بسپار</el-checkbox>
<el-button size="small" native-type="submit">ورود</el-button>
</admin-panel>
<h1 v-if="$auth.loggedIn">{{$auth.user.name}}</h1>
</div>
</div>
</div>
</el-form>
</div>
</template>
<script>
export default {
data() {
return {
login: {
username: '',
password: '',
remember_me: false
},
validation: {}
}
},
methods: {
loginFunction() {
this.validation = {}
this.$auth.loginWith('local', {data: this.login})
.then(res => {
this.$router.push('/admin')
})
.catch(err => {
this.validation = err.response.data.validation
})
}
},
layout: 'admin'
}
</script>
+79
View File
@@ -0,0 +1,79 @@
<template>
<div class="container-fluid">
<div class="row">
<admin-title-bar :title="title">
<el-button @click="$router.back()" type="primary">برگشت به صفحه قبل</el-button>
</admin-title-bar>
<div class="col-6">
<admin-panel>
<el-form class="message">
<el-form-item prop="title" label="دلیل ارتباط">
<el-input :value="message.reason" disabled></el-input>
</el-form-item>
<el-form-item prop="title" label="نام">
<el-input :value="message.first_name" disabled></el-input>
</el-form-item>
<el-form-item prop="title" label="نام خانوادگی">
<el-input :value="message.last_name" disabled></el-input>
</el-form-item>
<el-form-item label="شماره تماس">
<el-input :value="message.phone_number" disabled></el-input>
</el-form-item>
<el-form-item label="ایمیل">
<el-input :value="message.email" disabled></el-input>
</el-form-item>
<el-form-item label="پیام">
<el-input type="textarea" disabled :value="message.message"></el-input>
</el-form-item>
</el-form>
</admin-panel>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
title: 'خواندن پیام',
message: null,
user: null
}
},
mounted() {
this.$axios.get('/api/private/contact')
.then(response => {
let unread = response.data.filter(item => {
return !item.read
})
this.$store.commit('admin/unreadCount', unread.length)
})
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({$axios, params}) {
const message = await $axios.get(`/api/private/contact/${params.message}`)
return {
message: message.data
}
}
}
</script>
<style>
.message input:disabled, .message textarea:disabled{
color: #000 !important;
}
</style>
+187
View File
@@ -0,0 +1,187 @@
<template>
<div class="container-fluid">
<div class="row">
<admin-title-bar :title="title"></admin-title-bar>
<div class="col-12">
<admin-panel>
<div class="row">
<div class="col-6">
<h2>افزودن دلایل تماس:</h2>
<el-divider></el-divider>
<el-form>
<el-form-item :class="validation.fa_reason ? 'is-error' : null" label="فارسی">
<el-input v-model="newReason.fa"></el-input>
<p class="err" v-if="validation.fa_reason">{{validation.fa_reason.msg}}</p>
</el-form-item>
<el-form-item :class="validation.en_reason ? 'is-error' : null" label="انگلیسی">
<el-input v-model="newReason.en"></el-input>
<p class="err" v-if="validation.en_reason">{{validation.en_reason.msg}}</p>
</el-form-item>
<el-button @click="addReason" type="success">افزودن</el-button>
</el-form>
</div>
<div class="col-6">
<el-tag
v-for="item in reasons"
:key="item._id"
closable
@close="removeReason(item._id)"
type="primary"
style="margin-left: 10px;">
{{item.reason_details.fa.reason}} | {{item.reason_details.en.reason}}
</el-tag>
</div>
</div>
</admin-panel>
</div>
<div class="col-12">
<admin-panel>
<el-table
:data="messages"
style="width: 100%"
:row-class-name="readStatus">
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
label="نام"
width="">
<template slot-scope="scope">
{{fullName(scope.row.first_name,scope.row.last_name)}}
</template>
</el-table-column>
<el-table-column
prop="email"
label="ایمیل"
width="">
</el-table-column>
<el-table-column
prop="phone_number"
label="شماره تماس"
width=""
class-name="phoneNumber">
</el-table-column>
<el-table-column
prop="reason"
label="دلیل تماس"
width=""
class-name="phoneNumber">
</el-table-column>
<el-table-column
label="مشاهده"
width="80"
align="left">
<template slot-scope="scope">
<el-button type="success" plain icon="el-icon-view" @click="$router.push({name: 'admin-messages-message',params: {message: scope.row._id}})"></el-button>
</template>
</el-table-column>
</el-table>
</admin-panel>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
title: 'لیست پیام های ارتباط با ما',
messages: null,
reasons: null,
newReason: {
fa: '',
en: ''
},
validation: {}
}
},
head() {
return {
title: this.title,
}
},
methods: {
readStatus({row, rowIndex}) {
return row.read ? null : 'unread'
},
fullName(first, last) {
return first + ' ' + last
},
addReason() {
this.validation = {}
const data = {
fa_reason: this.newReason.fa,
en_reason: this.newReason.en,
}
this.$axios.post(`/api/private/contact/reason`, data)
.then(res => {
this.reasons = res.data
this.newReason = {
fa: '',
en: ''
}
})
.catch(err => {
if (err.response.status === 422) this.validation = err.response.data.validation
else console.log(err.response.data.message)
})
},
removeReason(id) {
this.$confirm('این مورد حذف شود؟', 'هشدار', {
confirmButtonText: 'بله',
cancelButtonText: 'لغو',
type: 'warning'
}).then(() => {
this.$axios.delete(`/api/private/contact/reason/${id}`)
.then(res => {
this.$message({
message: 'با موفقیت حذف شد.',
type: 'error'
})
this.reasons = this.reasons.filter(item => {
return item._id !== id
})
})
.catch(err => {
console.log(err.response)
})
}).catch(() => {
this.$message({
type: 'warning',
message: 'عملیات لغو شد'
})
})
}
},
layout: 'admin',
async asyncData({$axios}) {
let messages = await $axios.get('/api/private/contact')
let reasons = await $axios.get('/api/public/contact/reason')
return {
messages: messages.data,
reasons: reasons.data
}
}
}
</script>
<style>
.phoneNumber div{
direction: ltr;
text-align: right
}
.unread{
background: rgb(255, 173, 0, 0.12) !important;
}
</style>
+694
View File
@@ -0,0 +1,694 @@
<template>
<div class="container-fluid">
<div class="row">
<admin-title-bar :title="title">
<el-button @click="$router.back()" type="primary">برگشت به صفحه قبل</el-button>
<el-button type="success" @click="upload">بروزرسانی</el-button>
</admin-title-bar>
<div class="col-6">
<admin-panel>
<el-form>
<el-form-item prop="category" :class="validation.category ? 'is-error' : ''" label="دسته بندی">
<el-select v-model="formData.category" placeholder="انتخاب کنید">
<el-option
v-for="item in productCategories"
:key="item._id"
:label="item.category_details.fa.name"
:value="item._id">
</el-option>
</el-select>
<p class="err" v-if="validation.category">{{validation.category.msg}}</p>
</el-form-item>
<el-form-item prop="published" label="بخش دوم نمایش داده شود">
<el-switch v-model="formData.more_section" style="margin-right: 15px;"></el-switch>
</el-form-item>
<el-form-item prop="published" label="دارای فایل های قابل دانلود باشد">
<el-switch v-model="formData.download_section" style="margin-right: 15px;"></el-switch>
</el-form-item>
</el-form>
</admin-panel>
</div>
<div class="col-6">
<admin-panel>
<h2>کاور</h2>
<el-divider></el-divider>
<img :src="formData.cover" alt="" style="width: 100%;max-width: 300px;display: block">
<input type="file" ref="cover" @change="previewCover">
<p class="err" v-if="validation.cover">{{validation.cover.msg}}</p>
<p v-else style="margin-top: 20px;color: green;">ابعاد تصویر باید 470px عرض و 395px ارتفاع باشد، در غیر این صورت عکس به صورت اوتوماتیک برش خواهد خورد.</p>
</admin-panel>
</div>
<div class="col-6">
<admin-panel>
<el-form>
<h2 style="color: #000;font-weight: bold;font-size: 30px;">فارسی</h2>
<el-divider></el-divider>
<el-form-item prop="title" :class="validation.fa_name ? 'is-error' : ''" label="نام">
<el-input v-model="formData.product_details.fa.name"></el-input>
<p class="err" v-if="validation.fa_name">{{validation.fa_name.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.fa_short_description ? 'is-error' : ''" label="توضیح کوتاه">
<el-input type="textarea" v-model="formData.product_details.fa.short_description"></el-input>
<p class="err" v-if="validation.fa_short_description">{{validation.fa_short_description.msg}}</p>
</el-form-item>
<h3>بخش اول صفحه</h3>
<el-divider></el-divider>
<el-form-item prop="title" :class="validation.fa_page_title ? 'is-error' : ''" label="عنوان">
<el-input type="textarea" v-model="formData.product_details.fa.page_title"></el-input>
<p class="err" v-if="validation.fa_page_title">{{validation.fa_page_title.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.fa_page_description ? 'is-error' : ''" label="توضیحات">
<el-input type="textarea" v-model="formData.product_details.fa.page_description"></el-input>
<p class="err" v-if="validation.fa_page_description">{{validation.fa_page_description.msg}}</p>
</el-form-item>
<h3>بخش دوم صفحه</h3>
<el-divider></el-divider>
<el-form-item prop="title" :class="validation.fa_more_title1 ? 'is-error' : ''" label="عنوان اول">
<el-input v-model="formData.product_details.fa.more_title1"></el-input>
<p class="err" v-if="validation.fa_more_title1">{{validation.fa_more_title1.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.fa_more_description1 ? 'is-error' : ''" label="توضیح اول">
<el-input type="textarea" v-model="formData.product_details.fa.more_description1"></el-input>
<p class="err" v-if="validation.fa_more_description1">{{validation.fa_more_description1.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.fa_more_title2 ? 'is-error' : ''" label="عنوان دوم">
<el-input v-model="formData.product_details.fa.more_title2"></el-input>
<p class="err" v-if="validation.fa_more_title2">{{validation.fa_more_title2.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.fa_more_description2 ? 'is-error' : ''" label="توضیح دوم">
<el-input type="textarea" v-model="formData.product_details.fa.more_description2"></el-input>
<p class="err" v-if="validation.fa_more_description2">{{validation.fa_more_description2.msg}}</p>
</el-form-item>
<h3>بخش سوم صفحه (جدول و توضیحات)</h3>
<el-divider></el-divider>
<el-form-item prop="title" :class="validation.fa_chart_title ? 'is-error' : ''" label="عنوان جدول">
<el-input v-model="formData.product_details.fa.chart_title"></el-input>
<p class="err" v-if="validation.fa_chart_title">{{validation.fa_chart_title.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.fa_chart_description ? 'is-error' : ''" label="توضیحات جدول">
<el-input type="textarea" v-model="formData.product_details.fa.chart_description"></el-input>
<p class="err" v-if="validation.fa_chart_description">{{validation.fa_chart_description.msg}}</p>
</el-form-item>
</el-form>
</admin-panel>
</div>
<div class="col-6">
<admin-panel>
<el-form>
<h2 style="color: #000;font-weight: bold;font-size: 30px;">انگلیسی</h2>
<el-divider></el-divider>
<el-form-item prop="title" :class="validation.en_name ? 'is-error' : ''" label="نام">
<el-input v-model="formData.product_details.en.name"></el-input>
<p class="err" v-if="validation.en_name">{{validation.en_name.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.en_short_description ? 'is-error' : ''" label="توضیح کوتاه">
<el-input type="textarea" v-model="formData.product_details.en.short_description"></el-input>
<p class="err" v-if="validation.en_short_description">{{validation.en_short_description.msg}}</p>
</el-form-item>
<h3>بخش اول صفحه</h3>
<el-divider></el-divider>
<el-form-item prop="title" :class="validation.en_page_title ? 'is-error' : ''" label="عنوان">
<el-input type="textarea" v-model="formData.product_details.en.page_title"></el-input>
<p class="err" v-if="validation.en_page_title">{{validation.en_page_title.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.en_page_description ? 'is-error' : ''" label="توضیحات">
<el-input type="textarea" v-model="formData.product_details.en.page_description"></el-input>
<p class="err" v-if="validation.en_page_description">{{validation.en_page_description.msg}}</p>
</el-form-item>
<h3>بخش دوم صفحه</h3>
<el-divider></el-divider>
<el-form-item prop="title" :class="validation.en_more_title1 ? 'is-error' : ''" label="عنوان اول">
<el-input v-model="formData.product_details.en.more_title1"></el-input>
<p class="err" v-if="validation.en_more_title1">{{validation.en_more_title1.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.en_more_description1 ? 'is-error' : ''" label="توضیح اول">
<el-input type="textarea" v-model="formData.product_details.en.more_description1"></el-input>
<p class="err" v-if="validation.en_more_description1">{{validation.en_more_description1.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.en_more_title2 ? 'is-error' : ''" label="عنوان دوم">
<el-input v-model="formData.product_details.en.more_title2"></el-input>
<p class="err" v-if="validation.en_more_title2">{{validation.en_more_title2.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.en_more_description2 ? 'is-error' : ''" label="توضیح دوم">
<el-input type="textarea" v-model="formData.product_details.en.more_description2"></el-input>
<p class="err" v-if="validation.en_more_description2">{{validation.en_more_description2.msg}}</p>
</el-form-item>
<h3>بخش سوم صفحه (جدول و توضیحات)</h3>
<el-divider></el-divider>
<el-form-item prop="title" :class="validation.en_chart_title ? 'is-error' : ''" label="عنوان جدول">
<el-input v-model="formData.product_details.en.chart_title"></el-input>
<p class="err" v-if="validation.en_chart_title">{{validation.en_chart_title.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.en_chart_description ? 'is-error' : ''" label="توضیحات جدول">
<el-input type="textarea" v-model="formData.product_details.en.chart_description"></el-input>
<p class="err" v-if="validation.en_chart_description">{{validation.en_chart_description.msg}}</p>
</el-form-item>
</el-form>
</admin-panel>
</div>
<div class="col-6">
<admin-panel>
<h2>عکس اول بخش دوم</h2>
<el-divider></el-divider>
<img :src="formData.more_section_image1" alt="" style="width: 100%;max-width: 300px;display: block">
<input type="file" ref="more_section_image1" @change="previewMore_section_image1">
<p class="err" v-if="validation.more_section_image1">{{validation.more_section_image1.msg}}</p>
<p v-else style="margin-top: 20px;color: green;">ابعاد تصویر باید 778px عرض و 395px ارتفاع باشد، در غیر این صورت عکس به صورت اوتوماتیک برش خواهد خورد.</p>
<h2 class="secondTitle">عکس دوم بخش دوم</h2>
<el-divider></el-divider>
<img :src="formData.more_section_image2" alt="" style="width: 100%;max-width: 300px;display: block">
<input type="file" ref="more_section_image2" @change="previewMore_section_image2">
<p class="err" v-if="validation.more_section_image2">{{validation.more_section_image2.msg}}</p>
<p v-else style="margin-top: 20px;color: green;">ابعاد تصویر باید 778px عرض و 395px ارتفاع باشد، در غیر این صورت عکس به صورت اوتوماتیک برش خواهد خورد.</p>
<!-- -->
<h2 class="secondTitle">عکس اول شماتیک بخش سوم</h2>
<el-divider></el-divider>
<img :src="formData.render_image1" alt="" style="width: 100%;max-width: 300px;display: block">
<input type="file" ref="render_image1" @change="previewRender_image1">
<p class="err" v-if="validation.render_image1">{{validation.render_image1.msg}}</p>
<p v-else style="margin-top: 20px;color: green;">ابعاد تصویر باید 300px عرض و 300px ارتفاع باشد، در غیر این صورت عکس به صورت اوتوماتیک برش خواهد خورد.</p>
<el-form style="margin-top: 30px;">
<el-form-item prop="title" :class="validation.fa_render_caption1 ? 'is-error' : ''" label="کپشن فارسی">
<el-input v-model="formData.product_details.fa.render_caption1"></el-input>
<p class="err" v-if="validation.fa_render_caption1">{{validation.fa_render_caption1.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.en_render_caption1 ? 'is-error' : ''" label="کپشن انگلیسی">
<el-input v-model="formData.product_details.en.render_caption1"></el-input>
<p class="err" v-if="validation.en_render_caption1">{{validation.en_render_caption1.msg}}</p>
</el-form-item>
</el-form>
<!-- -->
<h2 class="secondTitle">عکس دوم شماتیک بخش سوم</h2>
<el-divider></el-divider>
<img :src="formData.render_image2" alt="" style="width: 100%;max-width: 300px;display: block">
<input type="file" ref="render_image2" @change="previewRender_image2">
<p class="err" v-if="validation.render_image2">{{validation.render_image2.msg}}</p>
<p v-else style="margin-top: 20px;color: green;">ابعاد تصویر باید 300px عرض و 300px ارتفاع باشد، در غیر این صورت عکس به صورت اوتوماتیک برش خواهد خورد.</p>
<el-form style="margin-top: 30px;">
<el-form-item prop="title" :class="validation.fa_render_caption2 ? 'is-error' : ''" label="کپشن فارسی">
<el-input v-model="formData.product_details.fa.render_caption2"></el-input>
<p class="err" v-if="validation.fa_render_caption2">{{validation.fa_render_caption2.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.en_render_caption2 ? 'is-error' : ''" label="کپشن انگلیسی">
<el-input v-model="formData.product_details.en.render_caption2"></el-input>
<p class="err" v-if="validation.en_render_caption2">{{validation.en_render_caption2.msg}}</p>
</el-form-item>
</el-form>
<!-- -->
<h2 class="secondTitle">عکس جدول مشخصات محصول</h2>
<el-divider></el-divider>
<img :src="formData.chart_image" alt="" style="width: 100%;max-width: 300px;display: block">
<input type="file" ref="chart_image" @change="previewChart_image">
<p class="err" v-if="validation.chart_image">{{validation.chart_image.msg}}</p>
</admin-panel>
</div>
<div class="col-6">
<admin-panel>
<h2>تصاویر دیگر محصول</h2>
<el-divider></el-divider>
<div class="newImg">
<img :src="productImage" alt="" style="width: 100%;max-width: 300px;display: block">
<input type="file" ref="gallery" @change="previewGallery">
<p class="err" v-if="validation.images && validation.images.image">{{validation.images.image.msg}}</p>
<p v-else style="margin-top: 20px;color: green;">ابعاد تصویر باید 470px عرض و 395px ارتفاع باشد، در غیر این صورت عکس به صورت اوتوماتیک برش خواهد خورد.</p>
<el-button type="primary" @click="addImage" style="margin-top: 10px;">افزودن</el-button>
</div>
<div class="images">
<div class="imgBox" v-for="item in formData.images" :key="item._id">
<img :src="item.image" alt="">
<el-button type="danger" plain icon="el-icon-delete" class="dlt" v-if="item._id" @click="delImage(item._id)"></el-button>
</div>
</div>
</admin-panel>
</div>
<div class="col-6">
<admin-panel>
<h2>افزودن فایل PDF</h2>
<el-divider></el-divider>
<div class="pdf">
<input type="file" ref="pdf">
<p class="err" style="display: inline-block" v-if="validation.pdf">{{validation.pdf.msg}}</p>
<el-button type="primary" @click="addPDF" style="margin-top: 10px;">افزودن</el-button>
<el-form style="margin-top: 30px;">
<el-form-item prop="title" :class="validation.fa_pdf ? 'is-error' : ''" label="عنوان فارسی">
<el-input v-model="fa_pdf"></el-input>
<p class="err" v-if="validation.fa_pdf">{{validation.fa_pdf.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.en_pdf ? 'is-error' : ''" label="عنوان انگلیسی">
<el-input v-model="en_pdf"></el-input>
<p class="err" v-if="validation.en_pdf">{{validation.en_pdf.msg}}</p>
</el-form-item>
</el-form>
</div>
<div class="PDF_Files">
<div class="file" v-for="item in formData.pdf_files" :key="item._id">
<a :href="item.file" :download="item.pdf_details.en.name" target="_blank">
<i class="fas fa-file-pdf"></i>
<b>فارسی: </b>
<span>{{item.pdf_details.fa.name}}</span>
<br>
<!-- -->
<b>انگلیسی: </b>
<span>{{item.pdf_details.en.name}}</span>
</a>
<el-button type="danger" plain icon="el-icon-delete" @click="delPDF(item._id)"></el-button>
</div>
</div>
</admin-panel>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
formData: null,
productImage: '',
fa_pdf: '',
en_pdf: '',
productCategories: null,
validation: {},
uploading: false,
uploadProgress: null
}
},
computed: {
title() {
if (!this.uploading) {
return 'ویرایش محصول'
} else {
return this.uploadProgress
}
}
},
methods: {
upload() {
this.validation = ''
const data = new FormData()
data.append('fa_name', this.formData.product_details.fa.name)
data.append('fa_short_description', this.formData.product_details.fa.short_description)
data.append('fa_page_title', this.formData.product_details.fa.page_title)
data.append('fa_page_description', this.formData.product_details.fa.page_description)
data.append('fa_more_title1', this.formData.product_details.fa.more_title1)
data.append('fa_more_description1', this.formData.product_details.fa.more_description1)
data.append('fa_more_title2', this.formData.product_details.fa.more_title2)
data.append('fa_more_description2', this.formData.product_details.fa.more_description2)
data.append('fa_render_caption1', this.formData.product_details.fa.render_caption1)
data.append('fa_render_caption2', this.formData.product_details.fa.render_caption2)
data.append('fa_chart_title', this.formData.product_details.fa.chart_title)
data.append('fa_chart_description', this.formData.product_details.fa.chart_description)
data.append('en_name', this.formData.product_details.en.name)
data.append('en_short_description', this.formData.product_details.en.short_description)
data.append('en_page_title', this.formData.product_details.en.page_title)
data.append('en_page_description', this.formData.product_details.en.page_description)
data.append('en_more_title1', this.formData.product_details.en.more_title1)
data.append('en_more_description1', this.formData.product_details.en.more_description1)
data.append('en_more_title2', this.formData.product_details.en.more_title2)
data.append('en_more_description2', this.formData.product_details.en.more_description2)
data.append('en_render_caption1', this.formData.product_details.en.render_caption1)
data.append('en_render_caption2', this.formData.product_details.en.render_caption2)
data.append('en_chart_title', this.formData.product_details.en.chart_title)
data.append('en_chart_description', this.formData.product_details.en.chart_description)
data.append('category', this.formData.category)
data.append('download_section', this.formData.download_section)
data.append('more_section', this.formData.more_section)
if (this.$refs.cover.files[0]) data.append('cover', this.$refs.cover.files[0])
if (this.$refs.more_section_image1.files[0]) data.append('more_section_image1', this.$refs.more_section_image1.files[0])
if (this.$refs.more_section_image2.files[0]) data.append('more_section_image2', this.$refs.more_section_image2.files[0])
if (this.$refs.render_image1.files[0]) data.append('render_image1', this.$refs.render_image1.files[0])
if (this.$refs.render_image2.files[0]) data.append('render_image2', this.$refs.render_image2.files[0])
if (this.$refs.chart_image.files[0]) data.append('chart_image', this.$refs.chart_image.files[0])
const axiosConfig = {
onUploadProgress: progressEvent => {
this.uploading = true
this.uploadProgress = 'درحال آپلود ' + Math.floor(((progressEvent.loaded / progressEvent.total) * 100)) + '%'
if ((progressEvent.loaded / progressEvent.total) * 100 === 100) {
this.uploading = false
}
}
}
this.$axios.put(`/api/private/products/${this.formData._id}`, data, axiosConfig)
.then(response => {
this.formData = response.data
this.$message({
message: 'محصول با موفقیت بروزرسانی شد.',
type: 'success'
})
// clear file inputs
this.$refs.cover.value = null
this.$refs.more_section_image1.value = null
this.$refs.more_section_image2.value = null
this.$refs.render_image1.value = null
this.$refs.render_image2.value = null
this.$refs.chart_image.value = null
}).catch(error => {
if (error.response.status === 422) {
this.validation = error.response.data.validation
this.$message({
type: 'error',
message: 'اطلاعات رو بررسی و دوباره تلاش کنید'
})
} else {
this.$alert(error.response.data.message, 'خطا', {
confirmButtonText: 'باشه',
})
}
})
},
addImage() {
this.validation.images = {}
const data = new FormData()
data.append('product_id', this.formData._id)
data.append('image', this.$refs.gallery.files[0])
this.$axios.post(`/api/private/productImage`, data)
.then(res => {
this.$message({
type: 'success',
message: 'تصویر جدید با موفقیت افزوده شد.'
})
this.$refs.gallery.value = null
this.productImage = ''
this.formData = res.data
})
.catch(err => {
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
})
}
})
},
delImage(id) {
this.$confirm('این آیتم حذف شود؟', 'هشدار', {
confirmButtonText: 'بله',
cancelButtonText: 'لغو',
type: 'warning'
}).then(() => {
this.$axios.delete(`/api/private//productImage/${id}`)
.then(res => {
this.$message({
type: 'success',
message: 'تصویر با موفقیت حذف شد.'
})
this.formData.images = this.formData.images.filter(item => {
return item._id !== id
})
})
.catch(err => {
this.$message({
type: 'error',
message: err.response.data.message
})
})
}).catch(() => {
this.$message({
type: 'warning',
message: 'عملیات لغو شد'
})
})
},
addPDF() {
this.validation = {}
const data = new FormData()
data.append('product_id', this.formData._id)
data.append('fa_pdf', this.fa_pdf)
data.append('en_pdf', this.en_pdf)
data.append('pdf', this.$refs.pdf.files[0])
this.$axios.post(`/api/private/productPDF`, data)
.then(res => {
this.$message({
type: 'success',
message: 'فایل جدید با موفقیت افزوده شد.'
})
this.fa_pdf = ''
this.en_pdf = ''
this.$refs.pdf.value = null
this.formData = res.data
})
.catch(err => {
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
})
}
})
},
delPDF(id) {
this.$confirm('این آیتم حذف شود؟', 'هشدار', {
confirmButtonText: 'بله',
cancelButtonText: 'لغو',
type: 'warning'
}).then(() => {
this.$axios.delete(`/api/private//productPDF/${id}`)
.then(res => {
this.$message({
type: 'success',
message: 'فایل با موفقیت حذف شد.'
})
this.formData.pdf_files = this.formData.pdf_files.filter(item => {
return item._id !== id
})
})
.catch(err => {
this.$message({
type: 'error',
message: err.response.data.message
})
})
}).catch(() => {
this.$message({
type: 'warning',
message: 'عملیات لغو شد'
})
})
},
previewCover(event) {
this.formData.cover = URL.createObjectURL(event.target.files[0])
},
previewMore_section_image1(event) {
this.formData.more_section_image1 = URL.createObjectURL(event.target.files[0])
},
previewMore_section_image2(event) {
this.formData.more_section_image2 = URL.createObjectURL(event.target.files[0])
},
previewRender_image1(event) {
this.formData.render_image1 = URL.createObjectURL(event.target.files[0])
},
previewRender_image2(event) {
this.formData.render_image1 = URL.createObjectURL(event.target.files[0])
},
previewGallery(event) {
this.productImage = URL.createObjectURL(event.target.files[0])
},
previewChart_image(event) {
this.formData.chart_image = URL.createObjectURL(event.target.files[0])
}
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({$axios, params}) {
let product = await $axios.get(`/api/public/product/${params.product}`)
let productCategories = await $axios.get(`/api/public/productCategories`)
return {
formData: product.data,
productCategories: productCategories.data
}
}
}
</script>
<style scoped lang="scss">
.features {
ul {
li {
padding: 45px 15px 15px;
background: #e7e7e7;
border-radius: 5px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
position: relative;
margin-bottom: 10px;
h6 {
margin-top: 10px;
}
p {
margin-top: 5px;
}
.dlt {
position: absolute;
left: 15px;
top: 15px;
}
}
}
.el-divider__text {
background: #e7e7e7;
}
.el-divider {
background: #c8cad0;
}
}
.images {
width: 100%;
margin-top: 30px;
.imgBox {
border: 1px solid rgba(0, 0, 0, 0.05);
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
-webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1);
-moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1);
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1);
width: 200px;
position: relative;
display: inline-block;
margin: 5px;
img {
width: 100%;
}
.dlt {
position: absolute;
bottom: 0;
right: 0;
}
}
}
.PDF_Files {
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 5px;
padding: 15px;
margin-top: 30px;
.file {
margin-bottom: 20px;
background: rgba(#000, 0.03);
padding: 5px;
position: relative;
&:last-child {
margin-bottom: 0;
}
i {
display: block;
height: 100%;
width: 50px;
float: right;
font-size: 50px;
}
}
.el-button {
display: block;
position: absolute;
top: 50%;
left: 10px;
transform: translateY(-50%);
-webkit-transform: translateY(-50%);
-moz-transform: translateY(-50%);
-ms-transform: translateY(-50%);
-o-transform: translateY(-50%);
}
}
</style>
+104
View File
@@ -0,0 +1,104 @@
<template>
<div class="container-fluid">
<div class="row">
<admin-title-bar :title="title">
<el-button @click="$router.back()" type="primary">برگشت به صفحه قبل</el-button>
<el-button type="success" @click="upload">بروزرسانی</el-button>
</admin-title-bar>
<div class="col-6">
<admin-panel>
<el-form>
<el-form-item prop="title" :class="validation.fa_name ? 'is-error' : ''" label="نام فارسی">
<el-input v-model="formData.category_details.fa.name"></el-input>
<p class="err" v-if="validation.fa_name">{{validation.fa_name.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.en_name ? 'is-error' : ''" label="نام انگلیسی">
<el-input v-model="formData.category_details.en.name"></el-input>
<p class="err" v-if="validation.en_name">{{validation.en_name.msg}}</p>
</el-form-item>
</el-form>
</admin-panel>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
formData: null,
validation: {},
uploading: false,
uploadProgress: null
}
},
computed: {
title() {
if (!this.uploading) {
return 'اصلاح دسته بندی'
} else {
return this.uploadProgress
}
}
},
methods: {
upload() {
this.validation = {}
const data = new FormData()
data.append('fa_name', this.formData.category_details.fa.name)
data.append('en_name', this.formData.category_details.en.name)
const axiosConfig = {
onUploadProgress: progressEvent => {
this.uploading = true
this.uploadProgress = 'درحال آپلود ' + Math.floor(((progressEvent.loaded / progressEvent.total) * 100)) + '%'
if ((progressEvent.loaded / progressEvent.total) * 100 === 100) {
this.uploading = false
}
}
}
this.$axios.put(`/api/private/productCategories/${this.formData._id}`, data, axiosConfig)
.then(response => {
this.$message({
message: 'دسته بندی با موفقیت بروزرسانی شد.',
type: 'success'
})
}).catch(error => {
if (error.response.status === 422) {
this.validation = error.response.data.validation
this.$message({
type: 'error',
message: 'اطلاعات رو بررسی و دوباره تلاش کنید'
})
} else {
this.$alert(error.response.data.message, 'خطا', {
confirmButtonText: 'باشه',
})
}
})
}
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({$axios, params}) {
const category = await $axios.get(`/api/public/productCategories/${params.category}`)
return {
formData: category.data
}
}
}
</script>
+98
View File
@@ -0,0 +1,98 @@
<template>
<div class="container-fluid">
<div class="row">
<admin-title-bar :title="title">
<nuxt-link :to="{name: 'admin-products-category-new'}">
<el-button type="success">جدید</el-button>
</nuxt-link>
</admin-title-bar>
<div class="col-12">
<admin-panel>
<el-table
:data="categories"
style="width: 100%">
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
prop="category_details.fa.name"
label="نام دسته بندی"
width="">
</el-table-column>
<el-table-column
label="ویرایش"
width="150"
align="left">
<template slot-scope="scope">
<el-button type="warning" plain icon="el-icon-edit" @click="edit(scope.row._id)"></el-button>
<el-button type="danger" plain icon="el-icon-delete" @click="del(scope.row._id)"></el-button>
</template>
</el-table-column>
</el-table>
</admin-panel>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
title: 'دسته بندی محصولات',
categories: null
}
},
head() {
return {
title: this.title,
}
},
methods: {
edit(id) {
this.$router.push(`/admin/products/category/${id}`)
},
del(id) {
this.$confirm('این آیتم حذف شود؟', 'هشدار', {
confirmButtonText: 'بله',
cancelButtonText: 'لغو',
type: 'warning'
}).then(() => {
this.$axios.delete(`/api/private/productCategories/${id}`)
.then(response => {
this.categories = this.categories.filter(item => {
return item._id !== id
})
this.$message({
type: 'success',
message: 'آیتم حذف شد'
})
})
.catch(err => {
this.$message({
type: 'error',
message: err.response.data.message
})
})
}).catch(() => {
this.$message({
type: 'warning',
message: 'عملیات لغو شد'
});
});
}
},
layout: 'admin',
async asyncData({$axios}) {
let categories = await $axios.get(`/api/public/productCategories`);
return {
categories: categories.data
}
}
}
</script>
+102
View File
@@ -0,0 +1,102 @@
<template>
<div class="container-fluid">
<div class="row">
<admin-title-bar :title="title">
<el-button @click="$router.back()" type="primary">برگشت به صفحه قبل</el-button>
<el-button type="success" @click="upload">ایجاد</el-button>
</admin-title-bar>
<div class="col-6">
<admin-panel>
<el-form>
<el-form-item prop="title" :class="validation.fa_name ? 'is-error' : ''" label="نام فارسی">
<el-input v-model="formData.fa_name"></el-input>
<p class="err" v-if="validation.fa_name">{{validation.fa_name.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.en_name ? 'is-error' : ''" label="نام انگلیسی">
<el-input v-model="formData.en_name"></el-input>
<p class="err" v-if="validation.en_name">{{validation.en_name.msg}}</p>
</el-form-item>
</el-form>
</admin-panel>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
formData: {
fa_name: '',
en_name: ''
},
validation: {},
uploading: false,
uploadProgress: null
}
},
computed: {
title() {
if (!this.uploading) {
return 'افزودن دسته بندی'
} else {
return this.uploadProgress
}
}
},
methods: {
upload() {
this.validation = ''
const data = new FormData();
data.append('fa_name', this.formData.fa_name)
data.append('en_name', this.formData.en_name)
const axiosConfig = {
onUploadProgress: progressEvent => {
this.uploading = true
this.uploadProgress = 'درحال آپلود ' + Math.floor(((progressEvent.loaded / progressEvent.total) * 100)) + '%'
if ((progressEvent.loaded / progressEvent.total) * 100 === 100) {
this.uploading = false
}
}
}
this.$axios.post(`/api/private/productCategories`, data, axiosConfig)
.then(response => {
if (response.data) {
this.$message({
message: 'دسته بندی با موفقیت ثبت شد.',
type: 'success'
});
this.$router.push({name: 'admin-products-category'})
}
}).catch(error => {
if (error.response.status === 422) {
this.validation = error.response.data.validation
this.$message({
type: 'error',
message: 'اطلاعات رو بررسی و دوباره تلاش کنید'
})
} else {
this.$alert(error.response.data.message, 'خطا', {
confirmButtonText: 'باشه',
})
}
})
}
},
head() {
return {
title: this.title
}
},
layout: 'admin'
}
</script>
+129
View File
@@ -0,0 +1,129 @@
<template>
<div class="container-fluid">
<div class="row">
<admin-title-bar :title="title">
<nuxt-link :to="{name: 'admin-products-new'}">
<el-button type="success">جدید</el-button>
</nuxt-link>
</admin-title-bar>
<div class="col-lg-12">
<admin-panel>
<el-table
:data="products"
style="width: 100%">
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
label="تصویر"
width="230">
<template slot-scope="scope">
<el-image
style="width: 100%; height: 100%"
:src="scope.row.cover"
fit="fit">
</el-image>
</template>
</el-table-column>
<el-table-column
prop="product_details.fa.name"
label="نام"
width="">
</el-table-column>
<el-table-column
prop="category"
label="دسته بندی"
width="">
<template slot-scope="scope">
{{categoryName(scope.row.category)}}
</template>
</el-table-column>
<el-table-column
label="ویرایش"
width="150"
align="left">
<template slot-scope="scope">
<el-button type="warning" plain icon="el-icon-edit" @click="edit(scope.row._id)"></el-button>
<el-button type="danger" plain icon="el-icon-delete" @click="del(scope.row._id)"></el-button>
</template>
</el-table-column>
</el-table>
</admin-panel>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
title: 'لیست محصولات',
products: null,
productCategories: null
}
},
head() {
return {
title: this.title,
}
},
methods: {
categoryName(id) {
let category = this.productCategories.filter(item => {
return item._id === id
})
return category[0].category_details.fa.name
},
edit(id) {
this.$router.push(`/admin/products/${id}`)
},
del(id) {
this.$confirm('این محصول حذف شود؟', 'هشدار', {
confirmButtonText: 'بله',
cancelButtonText: 'لغو',
type: 'warning'
}).then(() => {
this.$axios.delete(`/api/private/products/${id}`)
.then(response => {
this.products = this.products.filter(item => {
return item._id !== id
})
this.$message({
type: 'success',
message: 'آیتم حذف شد'
})
})
.catch(err => {
this.$message({
type: 'error',
message: err.response.data.message
})
})
}).catch(() => {
this.$message({
type: 'warning',
message: 'عملیات لغو شد'
});
});
}
},
layout: 'admin',
async asyncData({$axios, store}) {
let products = await $axios.get(`/api/public/products`)
let productCategories = await $axios.get(`/api/public/productCategories`)
return {
products: products.data,
productCategories: productCategories.data
}
}
}
</script>
+439
View File
@@ -0,0 +1,439 @@
<template>
<div class="container-fluid">
<div class="row">
<admin-title-bar :title="title">
<el-button @click="$router.back()" type="primary">برگشت به صفحه قبل</el-button>
<el-button type="success" @click="upload">ایجاد</el-button>
</admin-title-bar>
<div class="col-6">
<admin-panel>
<p style="margin-bottom: 50px;color: green;font-weight: bold;font-size: 20px;">ابتدا محصول را ثبت کرده، سپس در مرحله بعد عکس های بیشتر و ویژگی های محصول را وارد کنید.</p>
<el-form>
<el-form-item prop="category" :class="validation.category ? 'is-error' : ''" label="دسته بندی">
<el-select v-model="formData.category" placeholder="انتخاب کنید">
<el-option
v-for="item in productCategories"
:key="item._id"
:label="item.category_details.fa.name"
:value="item._id">
</el-option>
</el-select>
<p class="err" v-if="validation.category">{{validation.category.msg}}</p>
</el-form-item>
<el-form-item prop="published" label="بخش دوم نمایش داده شود">
<el-switch v-model="formData.more_section" style="margin-right: 15px;"></el-switch>
</el-form-item>
<el-form-item prop="published" label="دارای فایل های قابل دانلود باشد">
<el-switch v-model="formData.download_section" style="margin-right: 15px;"></el-switch>
</el-form-item>
</el-form>
</admin-panel>
</div>
<div class="col-6">
<admin-panel>
<h2>کاور</h2>
<el-divider></el-divider>
<img :src="formData.cover" alt="" style="width: 100%;max-width: 300px;display: block">
<input type="file" ref="cover" @change="previewCover">
<p class="err" v-if="validation.cover">{{validation.cover.msg}}</p>
<p v-else style="margin-top: 20px;color: green;">ابعاد تصویر باید 470px عرض و 395px ارتفاع باشد، در غیر این صورت عکس به صورت اوتوماتیک برش خواهد خورد.</p>
</admin-panel>
</div>
<div class="col-6">
<admin-panel>
<el-form>
<h2 style="color: #000;font-weight: bold;font-size: 30px;">فارسی</h2>
<el-divider></el-divider>
<el-form-item prop="title" :class="validation.fa_name ? 'is-error' : ''" label="نام">
<el-input v-model="formData.product_details.fa.name"></el-input>
<p class="err" v-if="validation.fa_name">{{validation.fa_name.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.fa_short_description ? 'is-error' : ''" label="توضیح کوتاه">
<el-input type="textarea" v-model="formData.product_details.fa.short_description"></el-input>
<p class="err" v-if="validation.fa_short_description">{{validation.fa_short_description.msg}}</p>
</el-form-item>
<h3>بخش اول صفحه</h3>
<el-divider></el-divider>
<el-form-item prop="title" :class="validation.fa_page_title ? 'is-error' : ''" label="عنوان">
<el-input type="textarea" v-model="formData.product_details.fa.page_title"></el-input>
<p class="err" v-if="validation.fa_page_title">{{validation.fa_page_title.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.fa_page_description ? 'is-error' : ''" label="توضیحات">
<el-input type="textarea" v-model="formData.product_details.fa.page_description"></el-input>
<p class="err" v-if="validation.fa_page_description">{{validation.fa_page_description.msg}}</p>
</el-form-item>
<h3>بخش دوم صفحه</h3>
<el-divider></el-divider>
<el-form-item prop="title" :class="validation.fa_more_title1 ? 'is-error' : ''" label="عنوان اول">
<el-input v-model="formData.product_details.fa.more_title1"></el-input>
<p class="err" v-if="validation.fa_more_title1">{{validation.fa_more_title1.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.fa_more_description1 ? 'is-error' : ''" label="توضیح اول">
<el-input type="textarea" v-model="formData.product_details.fa.more_description1"></el-input>
<p class="err" v-if="validation.fa_more_description1">{{validation.fa_more_description1.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.fa_more_title2 ? 'is-error' : ''" label="عنوان دوم">
<el-input v-model="formData.product_details.fa.more_title2"></el-input>
<p class="err" v-if="validation.fa_more_title2">{{validation.fa_more_title2.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.fa_more_description2 ? 'is-error' : ''" label="توضیح دوم">
<el-input type="textarea" v-model="formData.product_details.fa.more_description2"></el-input>
<p class="err" v-if="validation.fa_more_description2">{{validation.fa_more_description2.msg}}</p>
</el-form-item>
<h3>بخش سوم صفحه (جدول و توضیحات)</h3>
<el-divider></el-divider>
<el-form-item prop="title" :class="validation.fa_chart_title ? 'is-error' : ''" label="عنوان جدول">
<el-input v-model="formData.product_details.fa.chart_title"></el-input>
<p class="err" v-if="validation.fa_chart_title">{{validation.fa_chart_title.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.fa_chart_description ? 'is-error' : ''" label="توضیحات جدول">
<el-input type="textarea" v-model="formData.product_details.fa.chart_description"></el-input>
<p class="err" v-if="validation.fa_chart_description">{{validation.fa_chart_description.msg}}</p>
</el-form-item>
</el-form>
</admin-panel>
</div>
<div class="col-6">
<admin-panel>
<el-form>
<h2 style="color: #000;font-weight: bold;font-size: 30px;">انگلیسی</h2>
<el-divider></el-divider>
<el-form-item prop="title" :class="validation.en_name ? 'is-error' : ''" label="نام">
<el-input v-model="formData.product_details.en.name"></el-input>
<p class="err" v-if="validation.en_name">{{validation.en_name.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.en_short_description ? 'is-error' : ''" label="توضیح کوتاه">
<el-input type="textarea" v-model="formData.product_details.en.short_description"></el-input>
<p class="err" v-if="validation.en_short_description">{{validation.en_short_description.msg}}</p>
</el-form-item>
<h3>بخش اول صفحه</h3>
<el-divider></el-divider>
<el-form-item prop="title" :class="validation.en_page_title ? 'is-error' : ''" label="عنوان">
<el-input type="textarea" v-model="formData.product_details.en.page_title"></el-input>
<p class="err" v-if="validation.en_page_title">{{validation.en_page_title.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.en_page_description ? 'is-error' : ''" label="توضیحات">
<el-input type="textarea" v-model="formData.product_details.en.page_description"></el-input>
<p class="err" v-if="validation.en_page_description">{{validation.en_page_description.msg}}</p>
</el-form-item>
<h3>بخش دوم صفحه</h3>
<el-divider></el-divider>
<el-form-item prop="title" :class="validation.en_more_title1 ? 'is-error' : ''" label="عنوان اول">
<el-input v-model="formData.product_details.en.more_title1"></el-input>
<p class="err" v-if="validation.en_more_title1">{{validation.en_more_title1.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.en_more_description1 ? 'is-error' : ''" label="توضیح اول">
<el-input type="textarea" v-model="formData.product_details.en.more_description1"></el-input>
<p class="err" v-if="validation.en_more_description1">{{validation.en_more_description1.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.en_more_title2 ? 'is-error' : ''" label="عنوان دوم">
<el-input v-model="formData.product_details.en.more_title2"></el-input>
<p class="err" v-if="validation.en_more_title2">{{validation.en_more_title2.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.en_more_description2 ? 'is-error' : ''" label="توضیح دوم">
<el-input type="textarea" v-model="formData.product_details.en.more_description2"></el-input>
<p class="err" v-if="validation.en_more_description2">{{validation.en_more_description2.msg}}</p>
</el-form-item>
<h3>بخش سوم صفحه (جدول و توضیحات)</h3>
<el-divider></el-divider>
<el-form-item prop="title" :class="validation.en_chart_title ? 'is-error' : ''" label="عنوان جدول">
<el-input v-model="formData.product_details.en.chart_title"></el-input>
<p class="err" v-if="validation.en_chart_title">{{validation.en_chart_title.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.en_chart_description ? 'is-error' : ''" label="توضیحات جدول">
<el-input type="textarea" v-model="formData.product_details.en.chart_description"></el-input>
<p class="err" v-if="validation.en_chart_description">{{validation.en_chart_description.msg}}</p>
</el-form-item>
</el-form>
</admin-panel>
</div>
<div class="col-6">
<admin-panel>
<h2>عکس اول بخش دوم</h2>
<el-divider></el-divider>
<img :src="formData.more_section_image1" alt="" style="width: 100%;max-width: 300px;display: block">
<input type="file" ref="more_section_image1" @change="previewMore_section_image1">
<p class="err" v-if="validation.more_section_image1">{{validation.more_section_image1.msg}}</p>
<p v-else style="margin-top: 20px;color: green;">ابعاد تصویر باید 778px عرض و 395px ارتفاع باشد، در غیر این صورت عکس به صورت اوتوماتیک برش خواهد خورد.</p>
<h2 class="secondTitle">عکس دوم بخش دوم</h2>
<el-divider></el-divider>
<img :src="formData.more_section_image2" alt="" style="width: 100%;max-width: 300px;display: block">
<input type="file" ref="more_section_image2" @change="previewMore_section_image2">
<p class="err" v-if="validation.more_section_image2">{{validation.more_section_image2.msg}}</p>
<p v-else style="margin-top: 20px;color: green;">ابعاد تصویر باید 778px عرض و 395px ارتفاع باشد، در غیر این صورت عکس به صورت اوتوماتیک برش خواهد خورد.</p>
<!-- -->
<h2 class="secondTitle">عکس اول شماتیک بخش سوم</h2>
<el-divider></el-divider>
<img :src="formData.render_image1" alt="" style="width: 100%;max-width: 300px;display: block">
<input type="file" ref="render_image1" @change="previewRender_image1">
<p class="err" v-if="validation.render_image1">{{validation.render_image1.msg}}</p>
<p v-else style="margin-top: 20px;color: green;">ابعاد تصویر باید 300px عرض و 300px ارتفاع باشد، در غیر این صورت عکس به صورت اوتوماتیک برش خواهد خورد.</p>
<el-form>
<el-form-item prop="title" :class="validation.fa_render_caption1 ? 'is-error' : ''" label="کپشن فارسی">
<el-input v-model="formData.product_details.fa.render_caption1"></el-input>
<p class="err" v-if="validation.fa_render_caption1">{{validation.fa_render_caption1.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.en_render_caption1 ? 'is-error' : ''" label="کپشن انگلیسی">
<el-input v-model="formData.product_details.en.render_caption1"></el-input>
<p class="err" v-if="validation.en_render_caption1">{{validation.en_render_caption1.msg}}</p>
</el-form-item>
</el-form>
<!-- -->
<h2 class="secondTitle">عکس دوم شماتیک بخش سوم</h2>
<el-divider></el-divider>
<img :src="formData.render_image2" alt="" style="width: 100%;max-width: 300px;display: block">
<input type="file" ref="render_image2" @change="previewRender_image2">
<p class="err" v-if="validation.render_image2">{{validation.render_image2.msg}}</p>
<p v-else style="margin-top: 20px;color: green;">ابعاد تصویر باید 300px عرض و 300px ارتفاع باشد، در غیر این صورت عکس به صورت اوتوماتیک برش خواهد خورد.</p>
<el-form>
<el-form-item prop="title" :class="validation.fa_render_caption2 ? 'is-error' : ''" label="کپشن فارسی">
<el-input v-model="formData.product_details.fa.render_caption2"></el-input>
<p class="err" v-if="validation.fa_render_caption2">{{validation.fa_render_caption2.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.en_render_caption2 ? 'is-error' : ''" label="کپشن انگلیسی">
<el-input v-model="formData.product_details.en.render_caption2"></el-input>
<p class="err" v-if="validation.en_render_caption2">{{validation.en_render_caption2.msg}}</p>
</el-form-item>
</el-form>
<!-- -->
<h2 class="secondTitle">عکس جدول مشخصات محصول</h2>
<el-divider></el-divider>
<img :src="formData.chart_image" alt="" style="width: 100%;max-width: 300px;display: block">
<input type="file" ref="chart_image" @change="previewChart_image">
<p class="err" v-if="validation.chart_image">{{validation.chart_image.msg}}</p>
</admin-panel>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
formData: {
cover: '',
more_section_image1: '',
more_section_image2: '',
render_image1: '',
render_image2: '',
chart_image: '',
category: '',
more_section: true,
download_section: true,
product_details: {
fa: {
name: '',
short_description: '',
page_title: '',
page_description: '',
more_title1: '',
more_description1: '',
more_title2: '',
more_description2: '',
render_caption1: '',
render_caption2: '',
chart_title: '',
chart_description: ''
},
en: {
name: '',
short_description: '',
page_title: '',
page_description: '',
more_title1: '',
more_description1: '',
more_title2: '',
more_description2: '',
render_caption1: '',
render_caption2: '',
chart_title: '',
chart_description: ''
}
}
},
productCategories: null,
validation: {},
uploading: false,
uploadProgress: null
}
},
computed: {
title() {
if (!this.uploading) {
return 'افزودن محصول'
} else {
return this.uploadProgress
}
}
},
watch: {
async locale(newVal, oldVal) {
let productCategories = await this.$axios.get(`/api/public/productCategories/${newVal}`)
this.productCategories = productCategories.data
}
},
methods: {
upload() {
this.validation = ''
const data = new FormData();
data.append('fa_name', this.formData.product_details.fa.name)
data.append('fa_short_description', this.formData.product_details.fa.short_description)
data.append('fa_page_title', this.formData.product_details.fa.page_title)
data.append('fa_page_description', this.formData.product_details.fa.page_description)
data.append('fa_more_title1', this.formData.product_details.fa.more_title1)
data.append('fa_more_description1', this.formData.product_details.fa.more_description1)
data.append('fa_more_title2', this.formData.product_details.fa.more_title2)
data.append('fa_more_description2', this.formData.product_details.fa.more_description2)
data.append('fa_render_caption1', this.formData.product_details.fa.render_caption1)
data.append('fa_render_caption2', this.formData.product_details.fa.render_caption2)
data.append('fa_chart_title', this.formData.product_details.fa.chart_title)
data.append('fa_chart_description', this.formData.product_details.fa.chart_description)
data.append('en_name', this.formData.product_details.en.name)
data.append('en_short_description', this.formData.product_details.en.short_description)
data.append('en_page_title', this.formData.product_details.en.page_title)
data.append('en_page_description', this.formData.product_details.en.page_description)
data.append('en_more_title1', this.formData.product_details.en.more_title1)
data.append('en_more_description1', this.formData.product_details.en.more_description1)
data.append('en_more_title2', this.formData.product_details.en.more_title2)
data.append('en_more_description2', this.formData.product_details.en.more_description2)
data.append('en_render_caption1', this.formData.product_details.en.render_caption1)
data.append('en_render_caption2', this.formData.product_details.en.render_caption2)
data.append('en_chart_title', this.formData.product_details.en.chart_title)
data.append('en_chart_description', this.formData.product_details.en.chart_description)
data.append('category', this.formData.category)
data.append('download_section', this.formData.download_section)
data.append('more_section', this.formData.more_section)
data.append('cover', this.$refs.cover.files[0])
data.append('more_section_image1', this.$refs.more_section_image1.files[0])
data.append('more_section_image2', this.$refs.more_section_image2.files[0])
data.append('render_image1', this.$refs.render_image1.files[0])
data.append('render_image2', this.$refs.render_image2.files[0])
data.append('chart_image', this.$refs.chart_image.files[0])
const axiosConfig = {
onUploadProgress: progressEvent => {
this.uploading = true
this.uploadProgress = 'درحال آپلود ' + Math.floor(((progressEvent.loaded / progressEvent.total) * 100)) + '%'
if ((progressEvent.loaded / progressEvent.total) * 100 === 100) {
this.uploading = false
}
}
}
this.$axios.post(`/api/private/products`, data, axiosConfig)
.then(response => {
if (response.data) {
this.$message({
message: 'محصول با موفقیت ثبت شد.',
type: 'success'
})
this.$router.push(`/admin/products/${response.data._id}`)
}
}).catch(error => {
if (error.response.status === 422) {
this.validation = error.response.data.validation
this.$message({
type: 'error',
message: 'اطلاعات رو بررسی و دوباره تلاش کنید'
})
} else {
this.$alert(error.response.data.message, 'خطا', {
confirmButtonText: 'باشه',
})
}
})
},
previewCover(event) {
this.formData.cover = URL.createObjectURL(event.target.files[0]);
},
previewMore_section_image1(event) {
this.formData.more_section_image1 = URL.createObjectURL(event.target.files[0]);
},
previewMore_section_image2(event) {
this.formData.more_section_image2 = URL.createObjectURL(event.target.files[0]);
},
previewRender_image1(event) {
this.formData.render_image1 = URL.createObjectURL(event.target.files[0]);
},
previewRender_image2(event) {
this.formData.render_image1 = URL.createObjectURL(event.target.files[0]);
},
previewChart_image(event) {
this.formData.chart_image = URL.createObjectURL(event.target.files[0]);
}
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({$axios, store}) {
let productCategories = await $axios.get(`/api/public/productCategories`)
return {
productCategories: productCategories.data
}
}
}
</script>
+237
View File
@@ -0,0 +1,237 @@
<template>
<div class="container-fluid">
<div class="row">
<admin-title-bar :title="title">
<el-button @click="$router.back()" type="primary">برگشت به صفحه قبل</el-button>
<el-button type="success" @click="upload">بروزرسانی</el-button>
</admin-title-bar>
<div class="col-12">
<admin-panel>
<el-form>
<el-form-item prop="title" :class="validation.fa_name ? 'is-error' : ''" label="نام فارسی">
<el-input v-model="formData.project_details.fa.name"></el-input>
<p class="err" v-if="validation.fa_name">{{validation.fa_name.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.en_name ? 'is-error' : ''" label="نام انگلیسی">
<el-input v-model="formData.project_details.en.name"></el-input>
<p class="err" v-if="validation.en_name">{{validation.en_name.msg}}</p>
</el-form-item>
<el-divider></el-divider>
<el-form-item prop="title" :class="validation.fa_description ? 'is-error' : ''" label="توضیح فارسی">
<el-input type="textarea" v-model="formData.project_details.fa.description"></el-input>
<p class="err" v-if="validation.fa_description">{{validation.fa_description.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.en_description ? 'is-error' : ''" label="توضیح انگلیسی">
<el-input type="textarea" v-model="formData.project_details.en.description"></el-input>
<p class="err" v-if="validation.en_description">{{validation.en_description.msg}}</p>
</el-form-item>
<el-divider></el-divider>
<el-form-item prop="date" :class="validation.date ? 'is-error' : ''" label="تاریخ اجرا">
<date-picker v-model="formData.date" format="YYYY-MM-DD" display-format="jYYYY/jMM/jDD"></date-picker>
<p class="err" v-if="validation.date">{{validation.date.msg}}</p>
</el-form-item>
</el-form>
</admin-panel>
</div>
<div class="col-12">
<admin-panel>
<h2>تصاویر</h2>
<el-divider></el-divider>
<div class="newImg">
<img :src="image" alt="" style="width: 100%;max-width: 300px;display: block">
<input type="file" ref="image" @change="previewGallery">
<p class="err" v-if="validation.image">{{validation.image.msg}}</p>
<el-button type="primary" @click="addImage" style="margin-top: 10px;">افزودن</el-button>
</div>
<div class="images">
<div class="imgBox" v-for="item in formData.images" :key="item._id">
<img :src="item.image" alt="">
<el-button type="danger" plain icon="el-icon-delete" class="dlt" v-if="item._id" @click="delImage(item._id)"></el-button>
</div>
</div>
</admin-panel>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
formData: null,
image: '',
validation: {},
uploading: false,
uploadProgress: null
}
},
computed: {
title() {
if (!this.uploading) {
return 'ویرایش پروژه'
} else {
return this.uploadProgress
}
}
},
methods: {
upload() {
this.validation = {}
const data = new FormData()
data.append('fa_name', this.formData.project_details.fa.name)
data.append('fa_description', this.formData.project_details.fa.description)
data.append('en_name', this.formData.project_details.en.name)
data.append('en_description', this.formData.project_details.en.description)
data.append('date', this.formData.date)
const axiosConfig = {
onUploadProgress: progressEvent => {
this.uploading = true
this.uploadProgress = 'درحال آپلود ' + Math.floor(((progressEvent.loaded / progressEvent.total) * 100)) + '%'
if ((progressEvent.loaded / progressEvent.total) * 100 === 100) {
this.uploading = false
}
}
}
this.$axios.put(`/api/private/projects/${this.formData._id}`, data, axiosConfig)
.then(response => {
this.$message({
message: 'پروژه با موفقیت بروزرسانی شد.',
type: 'success'
})
}).catch(error => {
if (error.response.status === 422) {
this.validation = error.response.data.validation
this.$message({
type: 'error',
message: 'اطلاعات رو بررسی و دوباره تلاش کنید'
})
} else {
this.$alert(error.response.data.message, 'خطا', {
confirmButtonText: 'باشه',
})
}
})
},
addImage() {
this.validation = {}
const data = new FormData()
data.append('image', this.$refs.image.files[0])
this.$axios.post(`/api/private/projects/images/${this.formData._id}`, data)
.then(res => {
this.$message({
type: 'success',
message: 'تصویر جدید با موفقیت افزوده شد.'
})
this.$refs.image.value = null
this.image = ''
this.formData = res.data
})
.catch(err => {
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
})
}
})
},
delImage(id) {
this.$confirm('این آیتم حذف شود؟', 'هشدار', {
confirmButtonText: 'بله',
cancelButtonText: 'لغو',
type: 'warning'
}).then(() => {
this.$axios.delete(`/api/private/projects/images/${id}`)
.then(res => {
this.$message({
type: 'success',
message: 'تصویر با موفقیت حذف شد.'
})
this.formData.images = this.formData.images.filter(item => {
return item._id !== id
})
})
.catch(err => {
this.$message({
type: 'error',
message: err.response.data.message
})
})
}).catch(() => {
this.$message({
type: 'warning',
message: 'عملیات لغو شد'
})
})
},
previewGallery(event) {
this.image = URL.createObjectURL(event.target.files[0])
}
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({$axios, params}) {
let project = await $axios.get(`/api/public/projects/${params.project}`)
return {
formData: project.data
}
}
}
</script>
<style scoped lang="scss">
.images {
width: 100%;
margin-top: 30px;
.imgBox {
border: 1px solid rgba(0, 0, 0, 0.05);
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
-webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1);
-moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1);
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1);
width: 200px;
position: relative;
display: inline-block;
margin: 5px;
img {
width: 100%;
}
.dlt {
position: absolute;
bottom: 0;
right: 0;
}
}
}
</style>
+125
View File
@@ -0,0 +1,125 @@
<template>
<div class="container-fluid">
<div class="row">
<admin-title-bar :title="title">
<nuxt-link :to="{name: 'admin-projects-new'}">
<el-button type="success">جدید</el-button>
</nuxt-link>
</admin-title-bar>
<div class="col-12">
<admin-panel>
<el-table
:data="projects"
style="width: 100%">
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
label="تصویر"
width="230">
<template slot-scope="scope" v-if="scope.row.images[0]">
<el-image
style="width: 100%; height: 100%"
:src="scope.row.images[0].image"
fit="fit">
</el-image>
</template>
</el-table-column>
<el-table-column
prop="project_details.fa.name"
label="نام"
width="">
</el-table-column>
<el-table-column
prop="date"
label="تاریخ اجرا"
width="">
<template slot-scope="scope">
{{jDate(scope.row.date)}}
</template>
</el-table-column>
<el-table-column
label="ویرایش"
width="150"
align="left">
<template slot-scope="scope">
<el-button type="warning" plain icon="el-icon-edit" @click="edit(scope.row._id)"></el-button>
<el-button type="danger" plain icon="el-icon-delete" @click="del(scope.row._id)"></el-button>
</template>
</el-table-column>
</el-table>
</admin-panel>
</div>
</div>
</div>
</template>
<script>
import moment from "moment-jalaali"
export default {
data() {
return {
title: 'لیست پروژه ها',
projects: null
}
},
head() {
return {
title: this.title,
}
},
methods: {
jDate(date) {
return moment(date).format('jYYYY/jMM/jDD')
},
edit(id) {
this.$router.push(`/admin/projects/${id}`)
},
del(id) {
this.$confirm('این پروژه حذف شود؟', 'هشدار', {
confirmButtonText: 'بله',
cancelButtonText: 'لغو',
type: 'warning'
}).then(() => {
this.$axios.delete(`/api/private/projects/${id}`)
.then(response => {
this.projects = this.projects.filter(item => {
return item._id !== id
})
this.$message({
type: 'success',
message: 'آیتم حذف شد'
})
})
.catch(err => {
this.$message({
type: 'error',
message: err.response.data.message
})
})
}).catch(() => {
this.$message({
type: 'warning',
message: 'عملیات لغو شد'
});
});
}
},
layout: 'admin',
async asyncData({$axios, store}) {
let projects = await $axios.get(`/api/public/projects`)
return {
projects: projects.data
}
}
}
</script>
+137
View File
@@ -0,0 +1,137 @@
<template>
<div class="container-fluid">
<div class="row">
<admin-title-bar :title="title">
<el-button @click="$router.back()" type="primary">برگشت به صفحه قبل</el-button>
<el-button type="success" @click="upload">ایجاد</el-button>
</admin-title-bar>
<div class="col-12">
<admin-panel>
<el-form>
<p style="margin-bottom: 50px;color: green;font-weight: bold;font-size: 20px;">ابتدا پروژه را ثبت کرده، سپس در مرحله بعد عکس ها را وارد کنید.</p>
<el-divider></el-divider>
<el-form-item prop="title" :class="validation.fa_name ? 'is-error' : ''" label="نام فارسی">
<el-input v-model="formData.project_details.fa.name"></el-input>
<p class="err" v-if="validation.fa_name">{{validation.fa_name.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.en_name ? 'is-error' : ''" label="نام انگلیسی">
<el-input v-model="formData.project_details.en.name"></el-input>
<p class="err" v-if="validation.en_name">{{validation.en_name.msg}}</p>
</el-form-item>
<el-divider></el-divider>
<el-form-item prop="title" :class="validation.fa_description ? 'is-error' : ''" label="توضیح فارسی">
<el-input type="textarea" v-model="formData.project_details.fa.description"></el-input>
<p class="err" v-if="validation.fa_description">{{validation.fa_description.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.en_description ? 'is-error' : ''" label="توضیح انگلیسی">
<el-input type="textarea" v-model="formData.project_details.en.description"></el-input>
<p class="err" v-if="validation.en_description">{{validation.en_description.msg}}</p>
</el-form-item>
<el-divider></el-divider>
<el-form-item prop="date" :class="validation.date ? 'is-error' : ''" label="تاریخ اجرا">
<date-picker v-model="formData.date" format="YYYY-MM-DD" display-format="jYYYY/jMM/jDD"></date-picker>
<p class="err" v-if="validation.date">{{validation.date.msg}}</p>
</el-form-item>
</el-form>
</admin-panel>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
formData: {
date: '',
project_details: {
fa: {
name: '',
description: ''
},
en: {
name: '',
description: ''
}
}
},
validation: {},
uploading: false,
uploadProgress: null
}
},
computed: {
title() {
if (!this.uploading) {
return 'افزودن محصول'
} else {
return this.uploadProgress
}
}
},
methods: {
upload() {
this.validation = {}
const data = new FormData()
data.append('fa_name', this.formData.project_details.fa.name)
data.append('fa_description', this.formData.project_details.fa.description)
data.append('en_name', this.formData.project_details.en.name)
data.append('en_description', this.formData.project_details.en.description)
data.append('date', this.formData.date)
const axiosConfig = {
onUploadProgress: progressEvent => {
this.uploading = true
this.uploadProgress = 'درحال آپلود ' + Math.floor(((progressEvent.loaded / progressEvent.total) * 100)) + '%'
if ((progressEvent.loaded / progressEvent.total) * 100 === 100) {
this.uploading = false
}
}
}
this.$axios.post(`/api/private/projects`, data, axiosConfig)
.then(response => {
if (response.data) {
this.$message({
message: 'پروژه با موفقیت ثبت شد.',
type: 'success'
})
this.$router.push(`/admin/projects/${response.data._id}`)
}
}).catch(error => {
if (error.response.status === 422) {
this.validation = error.response.data.validation
this.$message({
type: 'error',
message: 'اطلاعات رو بررسی و دوباره تلاش کنید'
})
} else {
this.$alert(error.response.data.message, 'خطا', {
confirmButtonText: 'باشه',
})
}
})
}
},
head() {
return {
title: this.title
}
},
layout: 'admin'
}
</script>
+131
View File
@@ -0,0 +1,131 @@
<template>
<div class="container-fluid">
<div class="row">
<admin-title-bar :title="title">
<el-button @click="$router.back()" type="primary">برگشت به صفحه قبل</el-button>
<el-button type="success" @click="upload">بروز رسانی</el-button>
</admin-title-bar>
<div class="col-6">
<admin-panel>
<el-form>
<el-form-item prop="title" :class="validation.fa_title ? 'is-error' : ''" label="عنوان فارسی">
<el-input v-model="formData.fa_title"></el-input>
<p class="err" v-if="validation.fa_title">{{validation.fa_title.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.en_title ? 'is-error' : ''" label="عنوان انگلیسی">
<el-input v-model="formData.en_title"></el-input>
<p class="err" v-if="validation.en_title">{{validation.en_title.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.fa_caption ? 'is-error' : ''" label="توضیحات فارسی">
<el-input v-model="formData.fa_caption"></el-input>
<p class="err" v-if="validation.fa_caption">{{validation.fa_caption.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.en_caption ? 'is-error' : ''" label="توضیحات انگلیسی">
<el-input v-model="formData.en_caption"></el-input>
<p class="err" v-if="validation.en_caption">{{validation.en_caption.msg}}</p>
</el-form-item>
</el-form>
</admin-panel>
</div>
<div class="col-6">
<admin-panel>
<h2 class="secondTitle">تصویر</h2>
<el-divider></el-divider>
<img :src="formData.image" alt="" style="width: 100%">
<input type="file" ref="image" @change="preview">
<p class="err" v-if="validation.image">{{validation.image.msg}}</p>
</admin-panel>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
formData: null,
validation: {},
uploading: false,
uploadProgress: null
}
},
computed: {
title() {
if (!this.uploading) {
return 'ویرایش اسلاید'
} else {
return this.uploadProgress
}
}
},
methods: {
upload() {
this.validation = ''
const data = new FormData()
data.append('fa_title', this.formData.fa_title)
data.append('en_title', this.formData.en_title)
data.append('fa_caption', this.formData.fa_caption)
data.append('en_caption', this.formData.en_caption)
if (this.$refs.image.files[0]) {
data.append('image', this.$refs.image.files[0])
}
const axiosConfig = {
onUploadProgress: progressEvent => {
this.uploading = true
this.uploadProgress = 'درحال آپلود ' + Math.floor(((progressEvent.loaded / progressEvent.total) * 100)) + '%'
if ((progressEvent.loaded / progressEvent.total) * 100 === 100) {
this.uploading = false
}
}
}
this.$axios.put(`/api/private/slider/${this.formData._id}`, data, axiosConfig)
.then(response => {
if (response.data) {
this.$message({
message: 'تغییرات با موفقیت انجام شد.',
type: 'success'
});
}
}).catch(error => {
if (error.response.status === 422) {
this.validation = error.response.data.validation
this.$message({
type: 'error',
message: 'اطلاعات رو بررسی و دوباره تلاش کنید'
})
} else {
this.$alert(error.response.data.error.message, 'خطا', {
confirmButtonText: 'باشه',
})
}
})
},
preview(event) {
this.formData.image = URL.createObjectURL(event.target.files[0]);
}
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({$axios, route}) {
const slide = await $axios.get(`/api/public/slider/${route.params.slide}`)
return {
formData: slide.data
}
}
}
</script>
+114
View File
@@ -0,0 +1,114 @@
<template>
<div class="container-fluid">
<div class="row">
<admin-title-bar :title="title">
<nuxt-link :to="{name: 'admin-slider-new'}">
<el-button type="success">جدید</el-button>
</nuxt-link>
</admin-title-bar>
<div class="col-12">
<admin-panel>
<el-table
v-if="slides"
:data="slides"
style="width: 100%">
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
prop="image"
label="تصویر"
width="230">
<template slot-scope="scope">
<el-image
style="width: 100%; height: 100%"
:src="scope.row.image"
fit="fit">
</el-image>
</template>
</el-table-column>
<el-table-column
prop="slider_details.fa.title"
label="عنوان"
width="">
</el-table-column>
<el-table-column
label="ویرایش"
width="150"
align="left">
<template slot-scope="scope">
<el-button type="warning" plain icon="el-icon-edit" @click="edit(scope.row._id)"></el-button>
<el-button type="danger" plain icon="el-icon-delete" @click="del(scope.row._id)"></el-button>
</template>
</el-table-column>
</el-table>
</admin-panel>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
title: 'اسلایدر',
slides: null,
}
},
head() {
return {
title: this.title,
}
},
methods: {
edit(id) {
this.$router.push(`/admin/slider/${id}`)
},
del(id) {
this.$confirm('این تصویر حذف شود؟', 'هشدار', {
confirmButtonText: 'بله',
cancelButtonText: 'لغو',
type: 'warning'
}).then(() => {
this.$axios.delete(`/api/private/slider/${id}`).then(response => {
this.slides = this.slides.filter(item => {
return item._id !== id
})
this.$message({
type: 'success',
message: 'تصویر حذف شد'
});
})
}).catch(() => {
this.$message({
type: 'warning',
message: 'عملیات لغو شد'
});
});
}
},
layout: 'admin',
async asyncData({$axios, store}) {
let slides = await $axios.get(`/api/public/slider`)
return {
slides: slides.data
}
}
}
</script>
<style>
.el-table .el-table__body-wrapper .el-table__row .is-left{
text-align: left !important;
}
</style>
+129
View File
@@ -0,0 +1,129 @@
<template>
<div class="container-fluid">
<div class="row">
<admin-title-bar :title="title">
<el-button @click="$router.back()" type="primary">برگشت به صفحه قبل</el-button>
<el-button type="success" @click="upload">ایجاد</el-button>
</admin-title-bar>
<div class="col-6">
<admin-panel>
<el-form>
<el-form-item prop="title" :class="validation.fa_title ? 'is-error' : ''" label="عنوان فارسی">
<el-input v-model="formData.fa_title"></el-input>
<p class="err" v-if="validation.fa_title">{{validation.fa_title.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.en_title ? 'is-error' : ''" label="عنوان انگلیسی">
<el-input v-model="formData.en_title"></el-input>
<p class="err" v-if="validation.en_title">{{validation.en_title.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.fa_caption ? 'is-error' : ''" label="توضیحات فارسی">
<el-input v-model="formData.fa_caption"></el-input>
<p class="err" v-if="validation.fa_caption">{{validation.fa_caption.msg}}</p>
</el-form-item>
<el-form-item prop="title" :class="validation.en_caption ? 'is-error' : ''" label="توضیحات انگلیسی">
<el-input v-model="formData.en_caption"></el-input>
<p class="err" v-if="validation.en_caption">{{validation.en_caption.msg}}</p>
</el-form-item>
</el-form>
</admin-panel>
</div>
<div class="col-6">
<admin-panel>
<h2 class="secondTitle">تصویر</h2>
<el-divider></el-divider>
<img :src="formData.image" alt="" style="width: 100%">
<input type="file" ref="image" @change="preview">
<p class="err" v-if="validation.image">{{validation.image.msg}}</p>
</admin-panel>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
formData: {
fa_title: '',
en_title: '',
fa_caption: '',
en_caption: '',
image: ''
},
validation: {},
uploading: false,
uploadProgress: null
}
},
computed: {
title() {
if (!this.uploading) {
return 'افزودن اسلاید'
} else {
return this.uploadProgress
}
}
},
methods: {
upload() {
this.validation = ''
const data = new FormData()
data.append('fa_title', this.formData.fa_title)
data.append('en_title', this.formData.en_title)
data.append('fa_caption', this.formData.fa_caption)
data.append('en_caption', this.formData.en_caption)
data.append('image', this.$refs.image.files[0])
const axiosConfig = {
onUploadProgress: progressEvent => {
this.uploading = true
this.uploadProgress = 'درحال آپلود ' + Math.floor(((progressEvent.loaded / progressEvent.total) * 100)) + '%'
if ((progressEvent.loaded / progressEvent.total) * 100 === 100) {
this.uploading = false
}
}
}
this.$axios.post(`/api/private/slider`, data, axiosConfig)
.then(response => {
if (response.data) {
this.$message({
message: 'اسلاید با موفقیت ثبت شد.',
type: 'success'
});
this.$router.push({name: 'admin-slider'})
}
}).catch(error => {
if (error.response.status === 422) {
this.validation = error.response.data.validation
this.$message({
type: 'error',
message: 'اطلاعات رو بررسی و دوباره تلاش کنید'
})
} else {
this.$alert(error.response.data.error.message, 'خطا', {
confirmButtonText: 'باشه',
})
}
})
},
preview(event) {
this.formData.image = URL.createObjectURL(event.target.files[0]);
}
},
head() {
return {
title: this.title
}
},
layout: 'admin'
}
</script>